diff options
author | Olof Johansson <olof@lixom.net> | 2015-01-19 11:39:05 -0800 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2015-01-19 11:39:05 -0800 |
commit | 6b59907abc96f2625c0befec09da69e813cef0df (patch) | |
tree | d2ab386aeaa5459929dc31dd1f600659c5e7cb25 | |
parent | 58bdda1b571ffeab50874ca851d7473b3d10d03c (diff) | |
parent | a5514d142e7f5cff8e02a6fb4cfcb3e301c0eb59 (diff) | |
download | linux-stable-6b59907abc96f2625c0befec09da69e813cef0df.tar.gz linux-stable-6b59907abc96f2625c0befec09da69e813cef0df.tar.bz2 linux-stable-6b59907abc96f2625c0befec09da69e813cef0df.zip |
Merge tag 'at91-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/nferre/linux-at91 into next/drivers
Merge "at91: drivers for 3.20 #1" from Nicolas Ferre:
First batch of drivers changes for 3.20:
- Internal AHB bus matrix (Matrix) and Static Memory Controller (SMC) are now
mfd/syscon drivers.
- USB gadget full speed (at91_udc): fixes, simplification and multi-platform awareness
DT enhancement.
* tag 'at91-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/nferre/linux-at91:
usb: gadget: at91_udc: Allocate udc instance
usb: gadget: at91_udc: Update DT binding documentation
usb: gadget: at91_udc: Rework for multi-platform kernel support
usb: gadget: at91_udc: Simplify probe and remove functions
usb: gadget: at91_udc: Remove non-DT handling code
usb: gadget: at91_udc: Document DT clocks and clock-names property
usb: gadget: at91_udc: Drop uclk clock
usb: gadget: at91_udc: Fix clock names
mfd: syscon: Add Atmel SMC binding doc
mfd: syscon: Add atmel-smc registers definition
mfd: syscon: Add Atmel Matrix bus DT binding documentation
mfd: syscon: Add atmel-matrix registers definition
Signed-off-by: Olof Johansson <olof@lixom.net>
-rw-r--r-- | Documentation/devicetree/bindings/mfd/atmel-matrix.txt | 24 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/mfd/atmel-smc.txt | 19 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/usb/atmel-usb.txt | 10 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/Kconfig | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/at91_udc.c | 525 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/at91_udc.h | 9 | ||||
-rw-r--r-- | include/linux/mfd/syscon/atmel-matrix.h | 117 | ||||
-rw-r--r-- | include/linux/mfd/syscon/atmel-smc.h | 173 |
8 files changed, 623 insertions, 255 deletions
diff --git a/Documentation/devicetree/bindings/mfd/atmel-matrix.txt b/Documentation/devicetree/bindings/mfd/atmel-matrix.txt new file mode 100644 index 000000000000..e3ef50ca02a5 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/atmel-matrix.txt @@ -0,0 +1,24 @@ +* Device tree bindings for Atmel Bus Matrix + +The Bus Matrix registers are used to configure Atmel SoCs internal bus +behavior (master/slave priorities, undefined burst length type, ...) + +Required properties: +- compatible: Should be one of the following + "atmel,at91sam9260-matrix", "syscon" + "atmel,at91sam9261-matrix", "syscon" + "atmel,at91sam9263-matrix", "syscon" + "atmel,at91sam9rl-matrix", "syscon" + "atmel,at91sam9g45-matrix", "syscon" + "atmel,at91sam9n12-matrix", "syscon" + "atmel,at91sam9x5-matrix", "syscon" + "atmel,sama5d3-matrix", "syscon" +- reg: Contains offset/length value of the Bus Matrix + memory region. + +Example: + +matrix: matrix@ffffec00 { + compatible = "atmel,sama5d3-matrix", "syscon"; + reg = <0xffffec00 0x200>; +}; diff --git a/Documentation/devicetree/bindings/mfd/atmel-smc.txt b/Documentation/devicetree/bindings/mfd/atmel-smc.txt new file mode 100644 index 000000000000..26eeed373934 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/atmel-smc.txt @@ -0,0 +1,19 @@ +* Device tree bindings for Atmel SMC (Static Memory Controller) + +The SMC registers are used to configure Atmel EBI (External Bus Interface) +to interface with standard memory devices (NAND, NOR, SRAM or specialized +devices like FPGAs). + +Required properties: +- compatible: Should be one of the following + "atmel,at91sam9260-smc", "syscon" + "atmel,sama5d3-smc", "syscon" +- reg: Contains offset/length value of the SMC memory + region. + +Example: + +smc: smc@ffffc000 { + compatible = "atmel,sama5d3-smc", "syscon"; + reg = <0xffffc000 0x1000>; +}; diff --git a/Documentation/devicetree/bindings/usb/atmel-usb.txt b/Documentation/devicetree/bindings/usb/atmel-usb.txt index bc2222ca3f2a..54a81219caae 100644 --- a/Documentation/devicetree/bindings/usb/atmel-usb.txt +++ b/Documentation/devicetree/bindings/usb/atmel-usb.txt @@ -33,9 +33,17 @@ usb1: ehci@00800000 { AT91 USB device controller Required properties: - - compatible: Should be "atmel,at91rm9200-udc" + - compatible: Should be one of the following + "atmel,at91rm9200-udc" + "atmel,at91sam9260-udc" + "atmel,at91sam9261-udc" + "atmel,at91sam9263-udc" - reg: Address and length of the register set for the device - interrupts: Should contain macb interrupt + - clocks: Should reference the peripheral and the AHB clocks + - clock-names: Should contains two strings + "pclk" for the peripheral clock + "hclk" for the AHB clock Optional properties: - atmel,vbus-gpio: If present, specifies a gpio that needs to be diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index b8e213eb36cc..366e551aeff0 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -32,6 +32,7 @@ menu "USB Peripheral Controller" config USB_AT91 tristate "Atmel AT91 USB Device Port" depends on ARCH_AT91 + depends on OF || COMPILE_TEST help Many Atmel AT91 processors (such as the AT91RM2000) have a full speed USB Device Port with support for five configurable diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index c862656d18b8..6d285226ab94 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -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" @@ -66,7 +59,15 @@ #define DRIVER_VERSION "3 May 2006" static const char driver_name [] = "at91_udc"; -static const char ep0name[] = "ep0"; +static const char * const ep_names[] = { + "ep0", + "ep1", + "ep2", + "ep3-int", + "ep4", + "ep5", +}; +#define ep0name ep_names[0] #define VBUS_POLL_TIMEOUT msecs_to_jiffies(1000) @@ -895,8 +896,6 @@ static void clk_on(struct at91_udc *udc) return; udc->clocked = 1; - if (IS_ENABLED(CONFIG_COMMON_CLK)) - clk_enable(udc->uclk); clk_enable(udc->iclk); clk_enable(udc->fclk); } @@ -909,8 +908,6 @@ static void clk_off(struct at91_udc *udc) udc->gadget.speed = USB_SPEED_UNKNOWN; clk_disable(udc->fclk); clk_disable(udc->iclk); - if (IS_ENABLED(CONFIG_COMMON_CLK)) - clk_disable(udc->uclk); } /* @@ -919,8 +916,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"); @@ -929,40 +924,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 */ @@ -1535,74 +1505,6 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) /*-------------------------------------------------------------------------*/ -static struct at91_udc controller = { - .gadget = { - .ops = &at91_udc_ops, - .ep0 = &controller.ep[0].ep, - .name = driver_name, - }, - .ep[0] = { - .ep = { - .name = ep0name, - .ops = &at91_ep_ops, - }, - .udc = &controller, - .maxpacket = 8, - .int_mask = 1 << 0, - }, - .ep[1] = { - .ep = { - .name = "ep1", - .ops = &at91_ep_ops, - }, - .udc = &controller, - .is_pingpong = 1, - .maxpacket = 64, - .int_mask = 1 << 1, - }, - .ep[2] = { - .ep = { - .name = "ep2", - .ops = &at91_ep_ops, - }, - .udc = &controller, - .is_pingpong = 1, - .maxpacket = 64, - .int_mask = 1 << 2, - }, - .ep[3] = { - .ep = { - /* could actually do bulk too */ - .name = "ep3-int", - .ops = &at91_ep_ops, - }, - .udc = &controller, - .maxpacket = 8, - .int_mask = 1 << 3, - }, - .ep[4] = { - .ep = { - .name = "ep4", - .ops = &at91_ep_ops, - }, - .udc = &controller, - .is_pingpong = 1, - .maxpacket = 256, - .int_mask = 1 << 4, - }, - .ep[5] = { - .ep = { - .name = "ep5", - .ops = &at91_ep_ops, - }, - .udc = &controller, - .is_pingpong = 1, - .maxpacket = 256, - .int_mask = 1 << 5, - }, - /* ep6 and ep7 are also reserved (custom silicon might use them) */ -}; - static void at91_vbus_update(struct at91_udc *udc, unsigned value) { value ^= udc->board.vbus_active_low; @@ -1687,12 +1589,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; @@ -1705,6 +1797,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) @@ -1713,97 +1809,67 @@ static int at91udc_probe(struct platform_device *pdev) struct at91_udc *udc; int retval; struct resource *res; + struct at91_ep *ep; + int i; - if (!dev_get_platdata(dev) && !pdev->dev.of_node) { - /* small (so we copy it) but critical! */ - DBG("missing platform_data\n"); - return -ENODEV; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENXIO; - - if (!request_mem_region(res->start, resource_size(res), driver_name)) { - DBG("someone's using UDC memory\n"); - return -EBUSY; - } + udc = devm_kzalloc(dev, sizeof(*udc), GFP_KERNEL); + if (!udc) + return -ENOMEM; /* init software state */ - udc = &controller; udc->gadget.dev.parent = dev; - if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) - at91udc_of_init(udc, pdev->dev.of_node); - else - memcpy(&udc->board, dev_get_platdata(dev), - sizeof(struct at91_udc_data)); + at91udc_of_init(udc, pdev->dev.of_node); udc->pdev = 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"); - retval = -ENODEV; - goto fail0; - } - retval = gpio_request(udc->board.pullup_pin, "udc_pullup"); - if (retval) { - DBG("D+ pullup is busy\n"); - goto fail0; - } - gpio_direction_output(udc->board.pullup_pin, - udc->board.pullup_active_low); - } + udc->gadget.ops = &at91_udc_ops; + udc->gadget.ep0 = &udc->ep[0].ep; + udc->gadget.name = driver_name; + udc->gadget.dev.init_name = "gadget"; - /* 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; + for (i = 0; i < NUM_ENDPOINTS; i++) { + ep = &udc->ep[i]; + ep->ep.name = ep_names[i]; + ep->ep.ops = &at91_ep_ops; + ep->udc = udc; + ep->int_mask = BIT(i); + if (i != 0 && i != 3) + ep->is_pingpong = 1; } - udc->udp_baseaddr = ioremap(res->start, resource_size(res)); - if (!udc->udp_baseaddr) { - retval = -ENOMEM; - goto fail0a; + 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 */ - udc->iclk = clk_get(dev, "udc_clk"); - udc->fclk = clk_get(dev, "udpck"); - if (IS_ENABLED(CONFIG_COMMON_CLK)) - udc->uclk = clk_get(dev, "usb_clk"); - if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk) || - (IS_ENABLED(CONFIG_COMMON_CLK) && IS_ERR(udc->uclk))) { - DBG("clocks missing\n"); - retval = -ENODEV; - goto fail1; - } + udc->iclk = devm_clk_get(dev, "pclk"); + if (IS_ERR(udc->iclk)) + return PTR_ERR(udc->iclk); + + udc->fclk = devm_clk_get(dev, "hclk"); + if (IS_ERR(udc->fclk)) + return PTR_ERR(udc->fclk); /* don't do anything until we have both gadget driver and VBUS */ - if (IS_ENABLED(CONFIG_COMMON_CLK)) { - clk_set_rate(udc->uclk, 48000000); - retval = clk_prepare(udc->uclk); - if (retval) - goto fail1; - } + clk_set_rate(udc->fclk, 48000000); retval = clk_prepare(udc->fclk); if (retval) - goto fail1a; + return retval; retval = clk_prepare_enable(udc->iclk); if (retval) - goto fail1b; + goto err_unprepare_fclk; + at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff); /* Clear all pending interrupts - UDP may be used by bootloader. */ @@ -1812,18 +1878,21 @@ static int at91udc_probe(struct platform_device *pdev) /* request UDC and maybe VBUS irqs */ udc->udp_irq = platform_get_irq(pdev, 0); - retval = request_irq(udc->udp_irq, at91_udc_irq, - 0, driver_name, udc); - if (retval < 0) { + retval = devm_request_irq(dev, udc->udp_irq, at91_udc_irq, 0, + driver_name, udc); + if (retval) { DBG("request irq %d failed\n", udc->udp_irq); - goto fail1c; + goto err_unprepare_iclk; } + if (gpio_is_valid(udc->board.vbus_pin)) { - retval = gpio_request(udc->board.vbus_pin, "udc_vbus"); - if (retval < 0) { + retval = devm_gpio_request(dev, udc->board.vbus_pin, + "udc_vbus"); + if (retval) { DBG("request vbus pin failed\n"); - goto fail2; + goto err_unprepare_iclk; } + gpio_direction_input(udc->board.vbus_pin); /* @@ -1840,12 +1909,13 @@ static int at91udc_probe(struct platform_device *pdev) mod_timer(&udc->vbus_timer, jiffies + VBUS_POLL_TIMEOUT); } else { - if (request_irq(gpio_to_irq(udc->board.vbus_pin), - at91_vbus_irq, 0, driver_name, udc)) { + retval = devm_request_irq(dev, + gpio_to_irq(udc->board.vbus_pin), + at91_vbus_irq, 0, driver_name, udc); + if (retval) { DBG("request vbus irq %d failed\n", udc->board.vbus_pin); - retval = -EBUSY; - goto fail3; + goto err_unprepare_iclk; } } } else { @@ -1854,49 +1924,27 @@ static int at91udc_probe(struct platform_device *pdev) } retval = usb_add_gadget_udc(dev, &udc->gadget); if (retval) - goto fail4; + goto err_unprepare_iclk; dev_set_drvdata(dev, udc); device_init_wakeup(dev, 1); create_debug_file(udc); INFO("%s version %s\n", driver_name, DRIVER_VERSION); return 0; -fail4: - if (gpio_is_valid(udc->board.vbus_pin) && !udc->board.vbus_polled) - free_irq(gpio_to_irq(udc->board.vbus_pin), udc); -fail3: - if (gpio_is_valid(udc->board.vbus_pin)) - gpio_free(udc->board.vbus_pin); -fail2: - free_irq(udc->udp_irq, udc); -fail1c: + +err_unprepare_iclk: clk_unprepare(udc->iclk); -fail1b: +err_unprepare_fclk: clk_unprepare(udc->fclk); -fail1a: - if (IS_ENABLED(CONFIG_COMMON_CLK)) - clk_unprepare(udc->uclk); -fail1: - if (IS_ENABLED(CONFIG_COMMON_CLK) && !IS_ERR(udc->uclk)) - clk_put(udc->uclk); - if (!IS_ERR(udc->fclk)) - clk_put(udc->fclk); - if (!IS_ERR(udc->iclk)) - clk_put(udc->iclk); - iounmap(udc->udp_baseaddr); -fail0a: - if (cpu_is_at91rm9200()) - gpio_free(udc->board.pullup_pin); -fail0: - release_mem_region(res->start, resource_size(res)); + DBG("%s probe failed, %d\n", driver_name, retval); + return retval; } static int __exit at91udc_remove(struct platform_device *pdev) { struct at91_udc *udc = platform_get_drvdata(pdev); - struct resource *res; unsigned long flags; DBG("remove\n"); @@ -1911,29 +1959,9 @@ static int __exit at91udc_remove(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 0); remove_debug_file(udc); - if (gpio_is_valid(udc->board.vbus_pin)) { - free_irq(gpio_to_irq(udc->board.vbus_pin), udc); - gpio_free(udc->board.vbus_pin); - } - free_irq(udc->udp_irq, udc); - iounmap(udc->udp_baseaddr); - - if (cpu_is_at91rm9200()) - gpio_free(udc->board.pullup_pin); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - - if (IS_ENABLED(CONFIG_COMMON_CLK)) - clk_unprepare(udc->uclk); clk_unprepare(udc->fclk); clk_unprepare(udc->iclk); - clk_put(udc->iclk); - clk_put(udc->fclk); - if (IS_ENABLED(CONFIG_COMMON_CLK)) - clk_put(udc->uclk); - return 0; } @@ -1989,15 +2017,6 @@ static int at91udc_resume(struct platform_device *pdev) #define at91udc_resume NULL #endif -#if defined(CONFIG_OF) -static const struct of_device_id at91_udc_dt_ids[] = { - { .compatible = "atmel,at91rm9200-udc" }, - { /* sentinel */ } -}; - -MODULE_DEVICE_TABLE(of, at91_udc_dt_ids); -#endif - static struct platform_driver at91_udc_driver = { .remove = __exit_p(at91udc_remove), .shutdown = at91udc_shutdown, @@ -2005,7 +2024,7 @@ static struct platform_driver at91_udc_driver = { .resume = at91udc_resume, .driver = { .name = (char *) driver_name, - .of_match_table = of_match_ptr(at91_udc_dt_ids), + .of_match_table = at91_udc_dt_ids, }, }; diff --git a/drivers/usb/gadget/udc/at91_udc.h b/drivers/usb/gadget/udc/at91_udc.h index 017524663381..4fc0daa6587f 100644 --- a/drivers/usb/gadget/udc/at91_udc.h +++ b/drivers/usb/gadget/udc/at91_udc.h @@ -107,6 +107,11 @@ struct at91_ep { 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 * access protection for chip registers or driver state @@ -115,6 +120,7 @@ struct at91_udc { struct usb_gadget gadget; struct at91_ep ep[NUM_ENDPOINTS]; struct usb_gadget_driver *driver; + const struct at91_udc_caps *caps; unsigned vbus:1; unsigned enabled:1; unsigned clocked:1; @@ -126,7 +132,7 @@ struct at91_udc { unsigned active_suspend:1; u8 addr; struct at91_udc_data board; - struct clk *iclk, *fclk, *uclk; + struct clk *iclk, *fclk; struct platform_device *pdev; struct proc_dir_entry *pde; void __iomem *udp_baseaddr; @@ -134,6 +140,7 @@ struct at91_udc { spinlock_t lock; struct timer_list vbus_timer; struct work_struct vbus_timer_work; + struct regmap *matrix; }; static inline struct at91_udc *to_udc(struct usb_gadget *g) diff --git a/include/linux/mfd/syscon/atmel-matrix.h b/include/linux/mfd/syscon/atmel-matrix.h new file mode 100644 index 000000000000..8293c3e2a82a --- /dev/null +++ b/include/linux/mfd/syscon/atmel-matrix.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2014 Atmel Corporation. + * + * Memory Controllers (MATRIX, EBI) - System peripherals registers. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _LINUX_MFD_SYSCON_ATMEL_MATRIX_H +#define _LINUX_MFD_SYSCON_ATMEL_MATRIX_H + +#define AT91SAM9260_MATRIX_MCFG 0x00 +#define AT91SAM9260_MATRIX_SCFG 0x40 +#define AT91SAM9260_MATRIX_PRS 0x80 +#define AT91SAM9260_MATRIX_MRCR 0x100 +#define AT91SAM9260_MATRIX_EBICSA 0x11c + +#define AT91SAM9261_MATRIX_MRCR 0x0 +#define AT91SAM9261_MATRIX_SCFG 0x4 +#define AT91SAM9261_MATRIX_TCR 0x24 +#define AT91SAM9261_MATRIX_EBICSA 0x30 +#define AT91SAM9261_MATRIX_USBPUCR 0x34 + +#define AT91SAM9263_MATRIX_MCFG 0x00 +#define AT91SAM9263_MATRIX_SCFG 0x40 +#define AT91SAM9263_MATRIX_PRS 0x80 +#define AT91SAM9263_MATRIX_MRCR 0x100 +#define AT91SAM9263_MATRIX_TCR 0x114 +#define AT91SAM9263_MATRIX_EBI0CSA 0x120 +#define AT91SAM9263_MATRIX_EBI1CSA 0x124 + +#define AT91SAM9RL_MATRIX_MCFG 0x00 +#define AT91SAM9RL_MATRIX_SCFG 0x40 +#define AT91SAM9RL_MATRIX_PRS 0x80 +#define AT91SAM9RL_MATRIX_MRCR 0x100 +#define AT91SAM9RL_MATRIX_TCR 0x114 +#define AT91SAM9RL_MATRIX_EBICSA 0x120 + +#define AT91SAM9G45_MATRIX_MCFG 0x00 +#define AT91SAM9G45_MATRIX_SCFG 0x40 +#define AT91SAM9G45_MATRIX_PRS 0x80 +#define AT91SAM9G45_MATRIX_MRCR 0x100 +#define AT91SAM9G45_MATRIX_TCR 0x110 +#define AT91SAM9G45_MATRIX_DDRMPR 0x118 +#define AT91SAM9G45_MATRIX_EBICSA 0x128 + +#define AT91SAM9N12_MATRIX_MCFG 0x00 +#define AT91SAM9N12_MATRIX_SCFG 0x40 +#define AT91SAM9N12_MATRIX_PRS 0x80 +#define AT91SAM9N12_MATRIX_MRCR 0x100 +#define AT91SAM9N12_MATRIX_EBICSA 0x118 + +#define AT91SAM9X5_MATRIX_MCFG 0x00 +#define AT91SAM9X5_MATRIX_SCFG 0x40 +#define AT91SAM9X5_MATRIX_PRS 0x80 +#define AT91SAM9X5_MATRIX_MRCR 0x100 +#define AT91SAM9X5_MATRIX_EBICSA 0x120 + +#define SAMA5D3_MATRIX_MCFG 0x00 +#define SAMA5D3_MATRIX_SCFG 0x40 +#define SAMA5D3_MATRIX_PRS 0x80 +#define SAMA5D3_MATRIX_MRCR 0x100 + +#define AT91_MATRIX_MCFG(o, x) ((o) + ((x) * 0x4)) +#define AT91_MATRIX_ULBT GENMASK(2, 0) +#define AT91_MATRIX_ULBT_INFINITE (0 << 0) +#define AT91_MATRIX_ULBT_SINGLE (1 << 0) +#define AT91_MATRIX_ULBT_FOUR (2 << 0) +#define AT91_MATRIX_ULBT_EIGHT (3 << 0) +#define AT91_MATRIX_ULBT_SIXTEEN (4 << 0) + +#define AT91_MATRIX_SCFG(o, x) ((o) + ((x) * 0x4)) +#define AT91_MATRIX_SLOT_CYCLE GENMASK(7, 0) +#define AT91_MATRIX_DEFMSTR_TYPE GENMASK(17, 16) +#define AT91_MATRIX_DEFMSTR_TYPE_NONE (0 << 16) +#define AT91_MATRIX_DEFMSTR_TYPE_LAST (1 << 16) +#define AT91_MATRIX_DEFMSTR_TYPE_FIXED (2 << 16) +#define AT91_MATRIX_FIXED_DEFMSTR GENMASK(20, 18) +#define AT91_MATRIX_ARBT GENMASK(25, 24) +#define AT91_MATRIX_ARBT_ROUND_ROBIN (0 << 24) +#define AT91_MATRIX_ARBT_FIXED_PRIORITY (1 << 24) + +#define AT91_MATRIX_ITCM_SIZE GENMASK(3, 0) +#define AT91_MATRIX_ITCM_0 (0 << 0) +#define AT91_MATRIX_ITCM_16 (5 << 0) +#define AT91_MATRIX_ITCM_32 (6 << 0) +#define AT91_MATRIX_ITCM_64 (7 << 0) +#define AT91_MATRIX_DTCM_SIZE GENMASK(7, 4) +#define AT91_MATRIX_DTCM_0 (0 << 4) +#define AT91_MATRIX_DTCM_16 (5 << 4) +#define AT91_MATRIX_DTCM_32 (6 << 4) +#define AT91_MATRIX_DTCM_64 (7 << 4) + +#define AT91_MATRIX_PRAS(o, x) ((o) + ((x) * 0x8)) +#define AT91_MATRIX_PRBS(o, x) ((o) + ((x) * 0x8) + 0x4) +#define AT91_MATRIX_MPR(x) GENMASK(((x) * 0x4) + 1, ((x) * 0x4)) + +#define AT91_MATRIX_RCB(x) BIT(x) + +#define AT91_MATRIX_CSA(cs, val) (val << (cs)) +#define AT91_MATRIX_DBPUC BIT(8) +#define AT91_MATRIX_DBPDC BIT(9) +#define AT91_MATRIX_VDDIOMSEL BIT(16) +#define AT91_MATRIX_VDDIOMSEL_1_8V (0 << 16) +#define AT91_MATRIX_VDDIOMSEL_3_3V (1 << 16) +#define AT91_MATRIX_EBI_IOSR BIT(17) +#define AT91_MATRIX_DDR_IOSR BIT(18) +#define AT91_MATRIX_NFD0_SELECT BIT(24) +#define AT91_MATRIX_DDR_MP_EN BIT(25) +#define AT91_MATRIX_EBI_NUM_CS 8 + +#define AT91_MATRIX_USBPUCR_PUON BIT(30) + +#endif /* _LINUX_MFD_SYSCON_ATMEL_MATRIX_H */ diff --git a/include/linux/mfd/syscon/atmel-smc.h b/include/linux/mfd/syscon/atmel-smc.h new file mode 100644 index 000000000000..be6ebe64eebe --- /dev/null +++ b/include/linux/mfd/syscon/atmel-smc.h @@ -0,0 +1,173 @@ +/* + * Atmel SMC (Static Memory Controller) register offsets and bit definitions. + * + * Copyright (C) 2014 Atmel + * Copyright (C) 2014 Free Electrons + * + * Author: Boris Brezillon <boris.brezillon@free-electrons.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _LINUX_MFD_SYSCON_ATMEL_SMC_H_ +#define _LINUX_MFD_SYSCON_ATMEL_SMC_H_ + +#include <linux/kernel.h> +#include <linux/regmap.h> + +#define AT91SAM9_SMC_GENERIC 0x00 +#define AT91SAM9_SMC_GENERIC_BLK_SZ 0x10 + +#define SAMA5_SMC_GENERIC 0x600 +#define SAMA5_SMC_GENERIC_BLK_SZ 0x14 + +#define AT91SAM9_SMC_SETUP(o) ((o) + 0x00) +#define AT91SAM9_SMC_NWESETUP(x) (x) +#define AT91SAM9_SMC_NCS_WRSETUP(x) ((x) << 8) +#define AT91SAM9_SMC_NRDSETUP(x) ((x) << 16) +#define AT91SAM9_SMC_NCS_NRDSETUP(x) ((x) << 24) + +#define AT91SAM9_SMC_PULSE(o) ((o) + 0x04) +#define AT91SAM9_SMC_NWEPULSE(x) (x) +#define AT91SAM9_SMC_NCS_WRPULSE(x) ((x) << 8) +#define AT91SAM9_SMC_NRDPULSE(x) ((x) << 16) +#define AT91SAM9_SMC_NCS_NRDPULSE(x) ((x) << 24) + +#define AT91SAM9_SMC_CYCLE(o) ((o) + 0x08) +#define AT91SAM9_SMC_NWECYCLE(x) (x) +#define AT91SAM9_SMC_NRDCYCLE(x) ((x) << 16) + +#define AT91SAM9_SMC_MODE(o) ((o) + 0x0c) +#define SAMA5_SMC_MODE(o) ((o) + 0x10) +#define AT91_SMC_READMODE BIT(0) +#define AT91_SMC_READMODE_NCS (0 << 0) +#define AT91_SMC_READMODE_NRD (1 << 0) +#define AT91_SMC_WRITEMODE BIT(1) +#define AT91_SMC_WRITEMODE_NCS (0 << 1) +#define AT91_SMC_WRITEMODE_NWE (1 << 1) +#define AT91_SMC_EXNWMODE GENMASK(5, 4) +#define AT91_SMC_EXNWMODE_DISABLE (0 << 4) +#define AT91_SMC_EXNWMODE_FROZEN (2 << 4) +#define AT91_SMC_EXNWMODE_READY (3 << 4) +#define AT91_SMC_BAT BIT(8) +#define AT91_SMC_BAT_SELECT (0 << 8) +#define AT91_SMC_BAT_WRITE (1 << 8) +#define AT91_SMC_DBW GENMASK(13, 12) +#define AT91_SMC_DBW_8 (0 << 12) +#define AT91_SMC_DBW_16 (1 << 12) +#define AT91_SMC_DBW_32 (2 << 12) +#define AT91_SMC_TDF GENMASK(19, 16) +#define AT91_SMC_TDF_(x) ((((x) - 1) << 16) & AT91_SMC_TDF) +#define AT91_SMC_TDF_MAX 16 +#define AT91_SMC_TDFMODE_OPTIMIZED BIT(20) +#define AT91_SMC_PMEN BIT(24) +#define AT91_SMC_PS GENMASK(29, 28) +#define AT91_SMC_PS_4 (0 << 28) +#define AT91_SMC_PS_8 (1 << 28) +#define AT91_SMC_PS_16 (2 << 28) +#define AT91_SMC_PS_32 (3 << 28) + + +/* + * This function converts a setup timing expressed in nanoseconds into an + * encoded value that can be written in the SMC_SETUP register. + * + * The following formula is described in atmel datasheets (section + * "SMC Setup Register"): + * + * setup length = (128* SETUP[5] + SETUP[4:0]) + * + * where setup length is the timing expressed in cycles. + */ +static inline u32 at91sam9_smc_setup_ns_to_cycles(unsigned int clk_rate, + u32 timing_ns) +{ + u32 clk_period = DIV_ROUND_UP(NSEC_PER_SEC, clk_rate); + u32 coded_cycles = 0; + u32 cycles; + + cycles = DIV_ROUND_UP(timing_ns, clk_period); + if (cycles / 32) { + coded_cycles |= 1 << 5; + if (cycles < 128) + cycles = 0; + } + + coded_cycles |= cycles % 32; + + return coded_cycles; +} + +/* + * This function converts a pulse timing expressed in nanoseconds into an + * encoded value that can be written in the SMC_PULSE register. + * + * The following formula is described in atmel datasheets (section + * "SMC Pulse Register"): + * + * pulse length = (256* PULSE[6] + PULSE[5:0]) + * + * where pulse length is the timing expressed in cycles. + */ +static inline u32 at91sam9_smc_pulse_ns_to_cycles(unsigned int clk_rate, + u32 timing_ns) +{ + u32 clk_period = DIV_ROUND_UP(NSEC_PER_SEC, clk_rate); + u32 coded_cycles = 0; + u32 cycles; + + cycles = DIV_ROUND_UP(timing_ns, clk_period); + if (cycles / 64) { + coded_cycles |= 1 << 6; + if (cycles < 256) + cycles = 0; + } + + coded_cycles |= cycles % 64; + + return coded_cycles; +} + +/* + * This function converts a cycle timing expressed in nanoseconds into an + * encoded value that can be written in the SMC_CYCLE register. + * + * The following formula is described in atmel datasheets (section + * "SMC Cycle Register"): + * + * cycle length = (CYCLE[8:7]*256 + CYCLE[6:0]) + * + * where cycle length is the timing expressed in cycles. + */ +static inline u32 at91sam9_smc_cycle_ns_to_cycles(unsigned int clk_rate, + u32 timing_ns) +{ + u32 clk_period = DIV_ROUND_UP(NSEC_PER_SEC, clk_rate); + u32 coded_cycles = 0; + u32 cycles; + + cycles = DIV_ROUND_UP(timing_ns, clk_period); + if (cycles / 128) { + coded_cycles = cycles / 256; + cycles %= 256; + if (cycles >= 128) { + coded_cycles++; + cycles = 0; + } + + if (coded_cycles > 0x3) { + coded_cycles = 0x3; + cycles = 0x7f; + } + + coded_cycles <<= 7; + } + + coded_cycles |= cycles % 128; + + return coded_cycles; +} + +#endif /* _LINUX_MFD_SYSCON_ATMEL_SMC_H_ */ |