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. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQEcBAABAgAGBQJUt/HQAAoJEAf03oE53VmQsOkIANEa9DB+Yi8JDGnSdKqYgS+O aXWNwAR5+nH1c0SajSFpngdt87ZFexNh6qyX3qHNePTuzXsr5LkfmvuukyM/EIsE mLFxG7SBYR22ZmI2gSnmWUu1xRHhvi0HeqXtLLsdonv1MkqoJ3tG2oppqhmt7o7f hcnPlZUqAxzIlTMzA0O6QXOnKGmrtVSXQQt5RhhAw+5z19HdVlWY5gKOSBa/FaEF sVlfS5PS9irDizrWYaODhAAyrPmzeBB3ItY5q9pv4G7jOh9B1j7U9PWvAYEdpNwv OS49eUqh7AwWQz644hm/46cdSZ0dpF6K7BNq7m566vl/gsfXwhrT5zMxIX92DWg= =vIsP -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
6b59907abc
|
@ -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>;
|
||||
};
|
|
@ -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>;
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
udc->udp_baseaddr = ioremap(res->start, resource_size(res));
|
||||
if (!udc->udp_baseaddr) {
|
||||
retval = -ENOMEM;
|
||||
goto fail0a;
|
||||
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,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
|
@ -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_ */
|
Loading…
Reference in New Issue