|
@@ -31,16 +31,9 @@
|
|
|
#include <linux/of.h>
|
|
|
#include <linux/of_gpio.h>
|
|
|
#include <linux/platform_data/atmel.h>
|
|
|
-
|
|
|
-#include <asm/byteorder.h>
|
|
|
-#include <mach/hardware.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 <linux/regmap.h>
|
|
|
+#include <linux/mfd/syscon.h>
|
|
|
+#include <linux/mfd/syscon/atmel-matrix.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)
|
|
|
{
|
|
|
- int active = !udc->board.pullup_active_low;
|
|
|
-
|
|
|
if (!udc->enabled || !udc->vbus)
|
|
|
is_on = 0;
|
|
|
DBG("%sactive\n", is_on ? "" : "in");
|
|
@@ -925,40 +916,15 @@ static void pullup(struct at91_udc *udc, int is_on)
|
|
|
clk_on(udc);
|
|
|
at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
|
|
|
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 {
|
|
|
stop_activity(udc);
|
|
|
at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
|
|
|
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);
|
|
|
}
|
|
|
+
|
|
|
+ if (udc->caps && udc->caps->pullup)
|
|
|
+ udc->caps->pullup(udc, is_on);
|
|
|
}
|
|
|
|
|
|
/* 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);
|
|
|
}
|
|
|
|
|
|
-static void at91udc_of_init(struct at91_udc *udc,
|
|
|
- struct device_node *np)
|
|
|
+static int at91rm9200_udc_init(struct at91_udc *udc)
|
|
|
+{
|
|
|
+ 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;
|
|
|
- u32 val;
|
|
|
+ const struct of_device_id *match;
|
|
|
enum of_gpio_flags flags;
|
|
|
+ u32 val;
|
|
|
|
|
|
if (of_property_read_u32(np, "atmel,vbus-polled", &val) == 0)
|
|
|
board->vbus_polled = 1;
|
|
@@ -1701,6 +1857,10 @@ static void at91udc_of_init(struct at91_udc *udc,
|
|
|
&flags);
|
|
|
|
|
|
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)
|
|
@@ -1709,6 +1869,8 @@ static int at91udc_probe(struct platform_device *pdev)
|
|
|
struct at91_udc *udc;
|
|
|
int retval;
|
|
|
struct resource *res;
|
|
|
+ struct at91_ep *ep;
|
|
|
+ int i;
|
|
|
|
|
|
/* init software state */
|
|
|
udc = &controller;
|
|
@@ -1718,40 +1880,19 @@ static int at91udc_probe(struct platform_device *pdev)
|
|
|
udc->enabled = 0;
|
|
|
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);
|
|
|
udc->udp_baseaddr = devm_ioremap_resource(dev, res);
|
|
|
if (IS_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);
|
|
|
|
|
|
/* get interface and function clocks */
|
|
@@ -1920,13 +2061,6 @@ static int at91udc_resume(struct platform_device *pdev)
|
|
|
#define at91udc_resume NULL
|
|
|
#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 = {
|
|
|
.remove = __exit_p(at91udc_remove),
|
|
|
.shutdown = at91udc_shutdown,
|