Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f0bceab4 authored by Boris Brezillon's avatar Boris Brezillon Committed by Nicolas Ferre
Browse files

usb: gadget: at91_udc: Rework for multi-platform kernel support



cpu_is_at91xxx are a set of macros defined in mach/cpu.h and are here used
to detect the SoC we are booting on.
Use compatible string + a caps structure to replace those cpu_is_xxx tests.

Remove all mach and asm headers (which are now unused).

Signed-off-by: default avatarBoris Brezillon <boris.brezillon@free-electrons.com>
Acked-by: default avatarAlexandre Belloni <alexandre.belloni@free-electrons.com>
Acked-by: default avatarFelipe Balbi <balbi@ti.com>
Signed-off-by: default avatarNicolas Ferre <nicolas.ferre@atmel.com>
parent 422cde25
Loading
Loading
Loading
Loading
+211 −77
Original line number Original line Diff line number Diff line
@@ -31,16 +31,9 @@
#include <linux/of.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_gpio.h>
#include <linux/platform_data/atmel.h>
#include <linux/platform_data/atmel.h>

#include <linux/regmap.h>
#include <asm/byteorder.h>
#include <linux/mfd/syscon.h>
#include <mach/hardware.h>
#include <linux/mfd/syscon/atmel-matrix.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/gpio.h>

#include <mach/cpu.h>
#include <mach/at91sam9261_matrix.h>
#include <mach/at91_matrix.h>


#include "at91_udc.h"
#include "at91_udc.h"


@@ -915,8 +908,6 @@ static void clk_off(struct at91_udc *udc)
 */
 */
static void pullup(struct at91_udc *udc, int is_on)
static void pullup(struct at91_udc *udc, int is_on)
{
{
	int	active = !udc->board.pullup_active_low;

	if (!udc->enabled || !udc->vbus)
	if (!udc->enabled || !udc->vbus)
		is_on = 0;
		is_on = 0;
	DBG("%sactive\n", is_on ? "" : "in");
	DBG("%sactive\n", is_on ? "" : "in");
@@ -925,40 +916,15 @@ static void pullup(struct at91_udc *udc, int is_on)
		clk_on(udc);
		clk_on(udc);
		at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
		at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
		at91_udp_write(udc, AT91_UDP_TXVC, 0);
		at91_udp_write(udc, AT91_UDP_TXVC, 0);
		if (cpu_is_at91rm9200())
			gpio_set_value(udc->board.pullup_pin, active);
		else if (cpu_is_at91sam9260() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
			u32	txvc = at91_udp_read(udc, AT91_UDP_TXVC);

			txvc |= AT91_UDP_TXVC_PUON;
			at91_udp_write(udc, AT91_UDP_TXVC, txvc);
		} else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
			u32	usbpucr;

			usbpucr = at91_matrix_read(AT91_MATRIX_USBPUCR);
			usbpucr |= AT91_MATRIX_USBPUCR_PUON;
			at91_matrix_write(AT91_MATRIX_USBPUCR, usbpucr);
		}
	} else {
	} else {
		stop_activity(udc);
		stop_activity(udc);
		at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
		at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
		at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
		at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
		if (cpu_is_at91rm9200())
			gpio_set_value(udc->board.pullup_pin, !active);
		else if (cpu_is_at91sam9260() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
			u32	txvc = at91_udp_read(udc, AT91_UDP_TXVC);

			txvc &= ~AT91_UDP_TXVC_PUON;
			at91_udp_write(udc, AT91_UDP_TXVC, txvc);
		} else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
			u32	usbpucr;

			usbpucr = at91_matrix_read(AT91_MATRIX_USBPUCR);
			usbpucr &= ~AT91_MATRIX_USBPUCR_PUON;
			at91_matrix_write(AT91_MATRIX_USBPUCR, usbpucr);
		}
		clk_off(udc);
		clk_off(udc);
	}
	}

	if (udc->caps && udc->caps->pullup)
		udc->caps->pullup(udc, is_on);
}
}


/* vbus is here!  turn everything on that's ready */
/* vbus is here!  turn everything on that's ready */
@@ -1683,12 +1649,202 @@ static void at91udc_shutdown(struct platform_device *dev)
	spin_unlock_irqrestore(&udc->lock, flags);
	spin_unlock_irqrestore(&udc->lock, flags);
}
}


static void at91udc_of_init(struct at91_udc *udc,
static int at91rm9200_udc_init(struct at91_udc *udc)
				     struct device_node *np)
{
	struct at91_ep *ep;
	int ret;
	int i;

	for (i = 0; i < NUM_ENDPOINTS; i++) {
		ep = &udc->ep[i];

		switch (i) {
		case 0:
		case 3:
			ep->maxpacket = 8;
			break;
		case 1 ... 2:
			ep->maxpacket = 64;
			break;
		case 4 ... 5:
			ep->maxpacket = 256;
			break;
		}
	}

	if (!gpio_is_valid(udc->board.pullup_pin)) {
		DBG("no D+ pullup?\n");
		return -ENODEV;
	}

	ret = devm_gpio_request(&udc->pdev->dev, udc->board.pullup_pin,
				"udc_pullup");
	if (ret) {
		DBG("D+ pullup is busy\n");
		return ret;
	}

	gpio_direction_output(udc->board.pullup_pin,
			      udc->board.pullup_active_low);

	return 0;
}

static void at91rm9200_udc_pullup(struct at91_udc *udc, int is_on)
{
	int active = !udc->board.pullup_active_low;

	if (is_on)
		gpio_set_value(udc->board.pullup_pin, active);
	else
		gpio_set_value(udc->board.pullup_pin, !active);
}

static const struct at91_udc_caps at91rm9200_udc_caps = {
	.init = at91rm9200_udc_init,
	.pullup = at91rm9200_udc_pullup,
};

static int at91sam9260_udc_init(struct at91_udc *udc)
{
	struct at91_ep *ep;
	int i;

	for (i = 0; i < NUM_ENDPOINTS; i++) {
		ep = &udc->ep[i];

		switch (i) {
		case 0 ... 3:
			ep->maxpacket = 64;
			break;
		case 4 ... 5:
			ep->maxpacket = 512;
			break;
		}
	}

	return 0;
}

static void at91sam9260_udc_pullup(struct at91_udc *udc, int is_on)
{
	u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);

	if (is_on)
		txvc |= AT91_UDP_TXVC_PUON;
	else
		txvc &= ~AT91_UDP_TXVC_PUON;

	at91_udp_write(udc, AT91_UDP_TXVC, txvc);
}

static const struct at91_udc_caps at91sam9260_udc_caps = {
	.init = at91sam9260_udc_init,
	.pullup = at91sam9260_udc_pullup,
};

static int at91sam9261_udc_init(struct at91_udc *udc)
{
	struct at91_ep *ep;
	int i;

	for (i = 0; i < NUM_ENDPOINTS; i++) {
		ep = &udc->ep[i];

		switch (i) {
		case 0:
			ep->maxpacket = 8;
			break;
		case 1 ... 3:
			ep->maxpacket = 64;
			break;
		case 4 ... 5:
			ep->maxpacket = 256;
			break;
		}
	}

	udc->matrix = syscon_regmap_lookup_by_phandle(udc->pdev->dev.of_node,
						      "atmel,matrix");
	if (IS_ERR(udc->matrix))
		return PTR_ERR(udc->matrix);

	return 0;
}

static void at91sam9261_udc_pullup(struct at91_udc *udc, int is_on)
{
	u32 usbpucr = 0;

	if (is_on)
		usbpucr = AT91_MATRIX_USBPUCR_PUON;

	regmap_update_bits(udc->matrix, AT91SAM9261_MATRIX_USBPUCR,
			   AT91_MATRIX_USBPUCR_PUON, usbpucr);
}

static const struct at91_udc_caps at91sam9261_udc_caps = {
	.init = at91sam9261_udc_init,
	.pullup = at91sam9261_udc_pullup,
};

static int at91sam9263_udc_init(struct at91_udc *udc)
{
	struct at91_ep *ep;
	int i;

	for (i = 0; i < NUM_ENDPOINTS; i++) {
		ep = &udc->ep[i];

		switch (i) {
		case 0:
		case 1:
		case 2:
		case 3:
			ep->maxpacket = 64;
			break;
		case 4:
		case 5:
			ep->maxpacket = 256;
			break;
		}
	}

	return 0;
}

static const struct at91_udc_caps at91sam9263_udc_caps = {
	.init = at91sam9263_udc_init,
	.pullup = at91sam9260_udc_pullup,
};

static const struct of_device_id at91_udc_dt_ids[] = {
	{
		.compatible = "atmel,at91rm9200-udc",
		.data = &at91rm9200_udc_caps,
	},
	{
		.compatible = "atmel,at91sam9260-udc",
		.data = &at91sam9260_udc_caps,
	},
	{
		.compatible = "atmel,at91sam9261-udc",
		.data = &at91sam9261_udc_caps,
	},
	{
		.compatible = "atmel,at91sam9263-udc",
		.data = &at91sam9263_udc_caps,
	},
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, at91_udc_dt_ids);

static void at91udc_of_init(struct at91_udc *udc, struct device_node *np)
{
{
	struct at91_udc_data *board = &udc->board;
	struct at91_udc_data *board = &udc->board;
	u32 val;
	const struct of_device_id *match;
	enum of_gpio_flags flags;
	enum of_gpio_flags flags;
	u32 val;


	if (of_property_read_u32(np, "atmel,vbus-polled", &val) == 0)
	if (of_property_read_u32(np, "atmel,vbus-polled", &val) == 0)
		board->vbus_polled = 1;
		board->vbus_polled = 1;
@@ -1701,6 +1857,10 @@ static void at91udc_of_init(struct at91_udc *udc,
						  &flags);
						  &flags);


	board->pullup_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
	board->pullup_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;

	match = of_match_node(at91_udc_dt_ids, np);
	if (match)
		udc->caps = match->data;
}
}


static int at91udc_probe(struct platform_device *pdev)
static int at91udc_probe(struct platform_device *pdev)
@@ -1709,6 +1869,8 @@ static int at91udc_probe(struct platform_device *pdev)
	struct at91_udc	*udc;
	struct at91_udc	*udc;
	int		retval;
	int		retval;
	struct resource	*res;
	struct resource	*res;
	struct at91_ep	*ep;
	int		i;


	/* init software state */
	/* init software state */
	udc = &controller;
	udc = &controller;
@@ -1718,40 +1880,19 @@ static int at91udc_probe(struct platform_device *pdev)
	udc->enabled = 0;
	udc->enabled = 0;
	spin_lock_init(&udc->lock);
	spin_lock_init(&udc->lock);


	/* rm9200 needs manual D+ pullup; off by default */
	if (cpu_is_at91rm9200()) {
		if (!gpio_is_valid(udc->board.pullup_pin)) {
			DBG("no D+ pullup?\n");
			return -ENODEV;
		}
		retval = devm_gpio_request(dev, udc->board.pullup_pin,
					   "udc_pullup");
		if (retval) {
			DBG("D+ pullup is busy\n");
			return retval;
		}
		gpio_direction_output(udc->board.pullup_pin,
				udc->board.pullup_active_low);
	}


	/* newer chips have more FIFO memory than rm9200 */
	if (cpu_is_at91sam9260() || cpu_is_at91sam9g20()) {
		udc->ep[0].maxpacket = 64;
		udc->ep[3].maxpacket = 64;
		udc->ep[4].maxpacket = 512;
		udc->ep[5].maxpacket = 512;
	} else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
		udc->ep[3].maxpacket = 64;
	} else if (cpu_is_at91sam9263()) {
		udc->ep[0].maxpacket = 64;
		udc->ep[3].maxpacket = 64;
	}


	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	udc->udp_baseaddr = devm_ioremap_resource(dev, res);
	udc->udp_baseaddr = devm_ioremap_resource(dev, res);
	if (IS_ERR(udc->udp_baseaddr))
	if (IS_ERR(udc->udp_baseaddr))
		return PTR_ERR(udc->udp_baseaddr);
		return PTR_ERR(udc->udp_baseaddr);


	if (udc->caps && udc->caps->init) {
		retval = udc->caps->init(udc);
		if (retval)
			return retval;
	}

	udc_reinit(udc);
	udc_reinit(udc);


	/* get interface and function clocks */
	/* get interface and function clocks */
@@ -1920,13 +2061,6 @@ static int at91udc_resume(struct platform_device *pdev)
#define	at91udc_resume	NULL
#define	at91udc_resume	NULL
#endif
#endif


static const struct of_device_id at91_udc_dt_ids[] = {
	{ .compatible = "atmel,at91rm9200-udc" },
	{ /* sentinel */ }
};

MODULE_DEVICE_TABLE(of, at91_udc_dt_ids);

static struct platform_driver at91_udc_driver = {
static struct platform_driver at91_udc_driver = {
	.remove		= __exit_p(at91udc_remove),
	.remove		= __exit_p(at91udc_remove),
	.shutdown	= at91udc_shutdown,
	.shutdown	= at91udc_shutdown,
+7 −0
Original line number Original line Diff line number Diff line
@@ -107,6 +107,11 @@ struct at91_ep {
	unsigned			fifo_bank:1;
	unsigned			fifo_bank:1;
};
};


struct at91_udc_caps {
	int (*init)(struct at91_udc *udc);
	void (*pullup)(struct at91_udc *udc, int is_on);
};

/*
/*
 * driver is non-SMP, and just blocks IRQs whenever it needs
 * driver is non-SMP, and just blocks IRQs whenever it needs
 * access protection for chip registers or driver state
 * access protection for chip registers or driver state
@@ -115,6 +120,7 @@ struct at91_udc {
	struct usb_gadget		gadget;
	struct usb_gadget		gadget;
	struct at91_ep			ep[NUM_ENDPOINTS];
	struct at91_ep			ep[NUM_ENDPOINTS];
	struct usb_gadget_driver	*driver;
	struct usb_gadget_driver	*driver;
	const struct at91_udc_caps	*caps;
	unsigned			vbus:1;
	unsigned			vbus:1;
	unsigned			enabled:1;
	unsigned			enabled:1;
	unsigned			clocked:1;
	unsigned			clocked:1;
@@ -134,6 +140,7 @@ struct at91_udc {
	spinlock_t			lock;
	spinlock_t			lock;
	struct timer_list		vbus_timer;
	struct timer_list		vbus_timer;
	struct work_struct		vbus_timer_work;
	struct work_struct		vbus_timer_work;
	struct regmap			*matrix;
};
};


static inline struct at91_udc *to_udc(struct usb_gadget *g)
static inline struct at91_udc *to_udc(struct usb_gadget *g)