summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/udc/atmel_usba_udc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/udc/atmel_usba_udc.c')
-rw-r--r--drivers/usb/gadget/udc/atmel_usba_udc.c348
1 files changed, 236 insertions, 112 deletions
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c
index 660712e0bf98..0c6f2ad81d37 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -18,6 +18,7 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/ctype.h>
+#include <linux/usb.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/delay.h>
@@ -93,7 +94,7 @@ static ssize_t queue_dbg_read(struct file *file, char __user *buf,
inode_lock(file_inode(file));
list_for_each_entry_safe(req, tmp_req, queue, queue) {
- len = snprintf(tmpbuf, sizeof(tmpbuf),
+ len = scnprintf(tmpbuf, sizeof(tmpbuf),
"%8p %08x %c%c%c %5d %c%c%c\n",
req->req.buf, req->req.length,
req->req.no_interrupt ? 'i' : 'I',
@@ -103,7 +104,6 @@ static ssize_t queue_dbg_read(struct file *file, char __user *buf,
req->submitted ? 'F' : 'f',
req->using_dma ? 'D' : 'd',
req->last_transaction ? 'L' : 'l');
- len = min(len, sizeof(tmpbuf));
if (len > nbytes)
break;
@@ -184,15 +184,14 @@ static int regs_dbg_release(struct inode *inode, struct file *file)
return 0;
}
-const struct file_operations queue_dbg_fops = {
+static const struct file_operations queue_dbg_fops = {
.owner = THIS_MODULE,
.open = queue_dbg_open,
- .llseek = no_llseek,
.read = queue_dbg_read,
.release = queue_dbg_release,
};
-const struct file_operations regs_dbg_fops = {
+static const struct file_operations regs_dbg_fops = {
.owner = THIS_MODULE,
.open = regs_dbg_open,
.llseek = generic_file_llseek,
@@ -226,7 +225,7 @@ static void usba_init_debugfs(struct usba_udc *udc)
struct dentry *root;
struct resource *regs_resource;
- root = debugfs_create_dir(udc->gadget.name, NULL);
+ root = debugfs_create_dir(udc->gadget.name, usb_debug_root);
udc->debugfs_root = root;
regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM,
@@ -327,6 +326,7 @@ static int usba_config_fifo_table(struct usba_udc *udc)
switch (fifo_mode) {
default:
fifo_mode = 0;
+ fallthrough;
case 0:
udc->fifo_cfg = NULL;
n = 0;
@@ -358,8 +358,20 @@ static inline u32 usba_int_enb_get(struct usba_udc *udc)
return udc->int_enb_cache;
}
-static inline void usba_int_enb_set(struct usba_udc *udc, u32 val)
+static inline void usba_int_enb_set(struct usba_udc *udc, u32 mask)
{
+ u32 val;
+
+ val = udc->int_enb_cache | mask;
+ usba_writel(udc, INT_ENB, val);
+ udc->int_enb_cache = val;
+}
+
+static inline void usba_int_enb_clear(struct usba_udc *udc, u32 mask)
+{
+ u32 val;
+
+ val = udc->int_enb_cache & ~mask;
usba_writel(udc, INT_ENB, val);
udc->int_enb_cache = val;
}
@@ -436,9 +448,11 @@ static void submit_request(struct usba_ep *ep, struct usba_request *req)
next_fifo_transaction(ep, req);
if (req->last_transaction) {
usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
- usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+ if (ep_is_control(ep))
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
} else {
- usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+ if (ep_is_control(ep))
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
}
}
@@ -629,14 +643,12 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
if (ep->can_dma) {
u32 ctrl;
- usba_int_enb_set(udc, usba_int_enb_get(udc) |
- USBA_BF(EPT_INT, 1 << ep->index) |
+ usba_int_enb_set(udc, USBA_BF(EPT_INT, 1 << ep->index) |
USBA_BF(DMA_INT, 1 << ep->index));
ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA;
usba_ep_writel(ep, CTL_ENB, ctrl);
} else {
- usba_int_enb_set(udc, usba_int_enb_get(udc) |
- USBA_BF(EPT_INT, 1 << ep->index));
+ usba_int_enb_set(udc, USBA_BF(EPT_INT, 1 << ep->index));
}
spin_unlock_irqrestore(&udc->lock, flags);
@@ -662,13 +674,7 @@ static int usba_ep_disable(struct usb_ep *_ep)
if (!ep->ep.desc) {
spin_unlock_irqrestore(&udc->lock, flags);
- /* REVISIT because this driver disables endpoints in
- * reset_all_endpoints() before calling disconnect(),
- * most gadget drivers would trigger this non-error ...
- */
- if (udc->gadget.speed != USB_SPEED_UNKNOWN)
- DBG(DBG_ERR, "ep_disable: %s not enabled\n",
- ep->ep.name);
+ DBG(DBG_ERR, "ep_disable: %s not enabled\n", ep->ep.name);
return -EINVAL;
}
ep->ep.desc = NULL;
@@ -680,8 +686,7 @@ static int usba_ep_disable(struct usb_ep *_ep)
usba_dma_readl(ep, STATUS);
}
usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE);
- usba_int_enb_set(udc, usba_int_enb_get(udc) &
- ~USBA_BF(EPT_INT, 1 << ep->index));
+ usba_int_enb_clear(udc, USBA_BF(EPT_INT, 1 << ep->index));
request_complete_list(ep, &req_list, -ESHUTDOWN);
@@ -853,21 +858,24 @@ static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
{
struct usba_ep *ep = to_usba_ep(_ep);
struct usba_udc *udc = ep->udc;
- struct usba_request *req;
+ struct usba_request *req = NULL;
+ struct usba_request *iter;
unsigned long flags;
u32 status;
DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n",
- ep->ep.name, req);
+ ep->ep.name, _req);
spin_lock_irqsave(&udc->lock, flags);
- list_for_each_entry(req, &ep->queue, queue) {
- if (&req->req == _req)
- break;
+ list_for_each_entry(iter, &ep->queue, queue) {
+ if (&iter->req != _req)
+ continue;
+ req = iter;
+ break;
}
- if (&req->req != _req) {
+ if (!req) {
spin_unlock_irqrestore(&udc->lock, flags);
return -EINVAL;
}
@@ -1021,6 +1029,7 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
return 0;
}
+static int atmel_usba_pullup(struct usb_gadget *gadget, int is_on);
static int atmel_usba_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver);
static int atmel_usba_stop(struct usb_gadget *gadget);
@@ -1048,16 +1057,19 @@ found_ep:
switch (usb_endpoint_type(desc)) {
case USB_ENDPOINT_XFER_CONTROL:
+ ep->nr_banks = 1;
break;
case USB_ENDPOINT_XFER_ISOC:
ep->fifo_size = 1024;
- ep->nr_banks = 2;
+ if (ep->udc->ep_prealloc)
+ ep->nr_banks = 2;
break;
case USB_ENDPOINT_XFER_BULK:
ep->fifo_size = 512;
- ep->nr_banks = 1;
+ if (ep->udc->ep_prealloc)
+ ep->nr_banks = 1;
break;
case USB_ENDPOINT_XFER_INT:
@@ -1067,7 +1079,8 @@ found_ep:
else
ep->fifo_size =
roundup_pow_of_two(le16_to_cpu(desc->wMaxPacketSize));
- ep->nr_banks = 1;
+ if (ep->udc->ep_prealloc)
+ ep->nr_banks = 1;
break;
}
@@ -1083,8 +1096,6 @@ found_ep:
USBA_BF(EPT_SIZE, fls(ep->fifo_size - 1) - 3);
ep->ept_cfg |= USBA_BF(BK_NUMBER, ep->nr_banks);
-
- ep->udc->configured_ep++;
}
return _ep;
@@ -1094,6 +1105,7 @@ static const struct usb_gadget_ops usba_udc_ops = {
.get_frame = usba_udc_get_frame,
.wakeup = usba_udc_wakeup,
.set_selfpowered = usba_udc_set_selfpowered,
+ .pullup = atmel_usba_pullup,
.udc_start = atmel_usba_start,
.udc_stop = atmel_usba_stop,
.match_ep = atmel_usba_match_ep,
@@ -1109,7 +1121,7 @@ static struct usb_endpoint_descriptor usba_ep0_desc = {
.bInterval = 1,
};
-static struct usb_gadget usba_gadget_template = {
+static const struct usb_gadget usba_gadget_template = {
.ops = &usba_udc_ops,
.max_speed = USB_SPEED_HIGH,
.name = "atmel_usba_udc",
@@ -1694,6 +1706,9 @@ static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep)
}
}
+static int start_clock(struct usba_udc *udc);
+static void stop_clock(struct usba_udc *udc);
+
static irqreturn_t usba_udc_irq(int irq, void *devid)
{
struct usba_udc *udc = devid;
@@ -1708,10 +1723,13 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
DBG(DBG_INT, "irq, status=%#08x\n", status);
if (status & USBA_DET_SUSPEND) {
+ usba_writel(udc, INT_CLR, USBA_DET_SUSPEND|USBA_WAKE_UP);
+ usba_int_enb_set(udc, USBA_WAKE_UP);
+ usba_int_enb_clear(udc, USBA_DET_SUSPEND);
+ udc->suspended = true;
toggle_bias(udc, 0);
- usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
- usba_int_enb_set(udc, int_enb | USBA_WAKE_UP);
udc->bias_pulse_needed = true;
+ stop_clock(udc);
DBG(DBG_BUS, "Suspend detected\n");
if (udc->gadget.speed != USB_SPEED_UNKNOWN
&& udc->driver && udc->driver->suspend) {
@@ -1722,14 +1740,17 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
}
if (status & USBA_WAKE_UP) {
+ start_clock(udc);
toggle_bias(udc, 1);
usba_writel(udc, INT_CLR, USBA_WAKE_UP);
- usba_int_enb_set(udc, int_enb & ~USBA_WAKE_UP);
DBG(DBG_BUS, "Wake Up CPU detected\n");
}
if (status & USBA_END_OF_RESUME) {
+ udc->suspended = false;
usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
+ usba_int_enb_clear(udc, USBA_WAKE_UP);
+ usba_int_enb_set(udc, USBA_DET_SUSPEND);
generate_bias_pulse(udc);
DBG(DBG_BUS, "Resume detected\n");
if (udc->gadget.speed != USB_SPEED_UNKNOWN
@@ -1744,6 +1765,8 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
if (dma_status) {
int i;
+ usba_int_enb_set(udc, USBA_DET_SUSPEND);
+
for (i = 1; i <= USBA_NR_DMAS; i++)
if (dma_status & (1 << i))
usba_dma_irq(udc, &udc->usba_ep[i]);
@@ -1753,6 +1776,8 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
if (ep_status) {
int i;
+ usba_int_enb_set(udc, USBA_DET_SUSPEND);
+
for (i = 0; i < udc->num_ep; i++)
if (ep_status & (1 << i)) {
if (ep_is_control(&udc->usba_ep[i]))
@@ -1764,9 +1789,11 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
if (status & USBA_END_OF_RESET) {
struct usba_ep *ep0, *ep;
- int i, n;
+ int i;
- usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
+ usba_writel(udc, INT_CLR,
+ USBA_END_OF_RESET|USBA_END_OF_RESUME
+ |USBA_DET_SUSPEND|USBA_WAKE_UP);
generate_bias_pulse(udc);
reset_all_endpoints(udc);
@@ -1793,7 +1820,12 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
| USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
usba_ep_writel(ep0, CTL_ENB,
USBA_EPT_ENABLE | USBA_RX_SETUP);
- usba_int_enb_set(udc, int_enb | USBA_BF(EPT_INT, 1) |
+
+ /* If we get reset while suspended... */
+ udc->suspended = false;
+ usba_int_enb_clear(udc, USBA_WAKE_UP);
+
+ usba_int_enb_set(udc, USBA_BF(EPT_INT, 1) |
USBA_DET_SUSPEND | USBA_END_OF_RESUME);
/*
@@ -1805,13 +1837,14 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
"ODD: EP0 configuration is invalid!\n");
/* Preallocate other endpoints */
- n = fifo_mode ? udc->num_ep : udc->configured_ep;
- for (i = 1; i < n; i++) {
+ for (i = 1; i < udc->num_ep; i++) {
ep = &udc->usba_ep[i];
- usba_ep_writel(ep, CFG, ep->ept_cfg);
- if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED))
- dev_err(&udc->pdev->dev,
- "ODD: EP%d configuration is invalid!\n", i);
+ if (ep->ep.claimed) {
+ usba_ep_writel(ep, CFG, ep->ept_cfg);
+ if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED))
+ dev_err(&udc->pdev->dev,
+ "ODD: EP%d configuration is invalid!\n", i);
+ }
}
}
@@ -1827,6 +1860,8 @@ static int start_clock(struct usba_udc *udc)
if (udc->clocked)
return 0;
+ pm_stay_awake(&udc->pdev->dev);
+
ret = clk_prepare_enable(udc->pclk);
if (ret)
return ret;
@@ -1849,6 +1884,8 @@ static void stop_clock(struct usba_udc *udc)
clk_disable_unprepare(udc->pclk);
udc->clocked = false;
+
+ pm_relax(&udc->pdev->dev);
}
static int usba_start(struct usba_udc *udc)
@@ -1860,9 +1897,19 @@ static int usba_start(struct usba_udc *udc)
if (ret)
return ret;
+ if (udc->suspended)
+ return 0;
+
spin_lock_irqsave(&udc->lock, flags);
toggle_bias(udc, 1);
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
+ /* Clear all requested and pending interrupts... */
+ usba_writel(udc, INT_ENB, 0);
+ udc->int_enb_cache = 0;
+ usba_writel(udc, INT_CLR,
+ USBA_END_OF_RESET|USBA_END_OF_RESUME
+ |USBA_DET_SUSPEND|USBA_WAKE_UP);
+ /* ...and enable just 'reset' IRQ to get us started */
usba_int_enb_set(udc, USBA_END_OF_RESET);
spin_unlock_irqrestore(&udc->lock, flags);
@@ -1873,6 +1920,9 @@ static void usba_stop(struct usba_udc *udc)
{
unsigned long flags;
+ if (udc->suspended)
+ return;
+
spin_lock_irqsave(&udc->lock, flags);
udc->gadget.speed = USB_SPEED_UNKNOWN;
reset_all_endpoints(udc);
@@ -1900,10 +1950,11 @@ static irqreturn_t usba_vbus_irq_thread(int irq, void *devid)
if (vbus) {
usba_start(udc);
} else {
- usba_stop(udc);
-
+ udc->suspended = false;
if (udc->driver->disconnect)
udc->driver->disconnect(&udc->gadget);
+
+ usba_stop(udc);
}
udc->vbus_prev = vbus;
}
@@ -1912,6 +1963,24 @@ static irqreturn_t usba_vbus_irq_thread(int irq, void *devid)
return IRQ_HANDLED;
}
+static int atmel_usba_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget);
+ unsigned long flags;
+ u32 ctrl;
+
+ spin_lock_irqsave(&udc->lock, flags);
+ ctrl = usba_readl(udc, CTRL);
+ if (is_on)
+ ctrl &= ~USBA_DETACH;
+ else
+ ctrl |= USBA_DETACH;
+ usba_writel(udc, CTRL, ctrl);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
static int atmel_usba_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver)
{
@@ -1960,9 +2029,7 @@ static int atmel_usba_stop(struct usb_gadget *gadget)
if (udc->vbus_pin)
disable_irq(gpiod_to_irq(udc->vbus_pin));
- if (fifo_mode == 0)
- udc->configured_ep = 1;
-
+ udc->suspended = false;
usba_stop(udc);
udc->driver = NULL;
@@ -1991,48 +2058,116 @@ static const struct usba_udc_errata at91sam9g45_errata = {
.pulse_bias = at91sam9g45_pulse_bias,
};
+static const struct usba_ep_config ep_config_sam9[] = {
+ { .nr_banks = 1 }, /* ep 0 */
+ { .nr_banks = 2, .can_dma = 1, .can_isoc = 1 }, /* ep 1 */
+ { .nr_banks = 2, .can_dma = 1, .can_isoc = 1 }, /* ep 2 */
+ { .nr_banks = 3, .can_dma = 1 }, /* ep 3 */
+ { .nr_banks = 3, .can_dma = 1 }, /* ep 4 */
+ { .nr_banks = 3, .can_dma = 1, .can_isoc = 1 }, /* ep 5 */
+ { .nr_banks = 3, .can_dma = 1, .can_isoc = 1 }, /* ep 6 */
+};
+
+static const struct usba_ep_config ep_config_sama5[] = {
+ { .nr_banks = 1 }, /* ep 0 */
+ { .nr_banks = 3, .can_dma = 1, .can_isoc = 1 }, /* ep 1 */
+ { .nr_banks = 3, .can_dma = 1, .can_isoc = 1 }, /* ep 2 */
+ { .nr_banks = 2, .can_dma = 1, .can_isoc = 1 }, /* ep 3 */
+ { .nr_banks = 2, .can_dma = 1, .can_isoc = 1 }, /* ep 4 */
+ { .nr_banks = 2, .can_dma = 1, .can_isoc = 1 }, /* ep 5 */
+ { .nr_banks = 2, .can_dma = 1, .can_isoc = 1 }, /* ep 6 */
+ { .nr_banks = 2, .can_dma = 1, .can_isoc = 1 }, /* ep 7 */
+ { .nr_banks = 2, .can_isoc = 1 }, /* ep 8 */
+ { .nr_banks = 2, .can_isoc = 1 }, /* ep 9 */
+ { .nr_banks = 2, .can_isoc = 1 }, /* ep 10 */
+ { .nr_banks = 2, .can_isoc = 1 }, /* ep 11 */
+ { .nr_banks = 2, .can_isoc = 1 }, /* ep 12 */
+ { .nr_banks = 2, .can_isoc = 1 }, /* ep 13 */
+ { .nr_banks = 2, .can_isoc = 1 }, /* ep 14 */
+ { .nr_banks = 2, .can_isoc = 1 }, /* ep 15 */
+};
+
+static const struct usba_udc_config udc_at91sam9rl_cfg = {
+ .errata = &at91sam9rl_errata,
+ .config = ep_config_sam9,
+ .num_ep = ARRAY_SIZE(ep_config_sam9),
+ .ep_prealloc = true,
+};
+
+static const struct usba_udc_config udc_at91sam9g45_cfg = {
+ .errata = &at91sam9g45_errata,
+ .config = ep_config_sam9,
+ .num_ep = ARRAY_SIZE(ep_config_sam9),
+ .ep_prealloc = true,
+};
+
+static const struct usba_udc_config udc_sama5d3_cfg = {
+ .config = ep_config_sama5,
+ .num_ep = ARRAY_SIZE(ep_config_sama5),
+ .ep_prealloc = true,
+};
+
+static const struct usba_udc_config udc_sam9x60_cfg = {
+ .num_ep = ARRAY_SIZE(ep_config_sam9),
+ .config = ep_config_sam9,
+ .ep_prealloc = false,
+};
+
static const struct of_device_id atmel_udc_dt_ids[] = {
- { .compatible = "atmel,at91sam9rl-udc", .data = &at91sam9rl_errata },
- { .compatible = "atmel,at91sam9g45-udc", .data = &at91sam9g45_errata },
- { .compatible = "atmel,sama5d3-udc" },
+ { .compatible = "atmel,at91sam9rl-udc", .data = &udc_at91sam9rl_cfg },
+ { .compatible = "atmel,at91sam9g45-udc", .data = &udc_at91sam9g45_cfg },
+ { .compatible = "atmel,sama5d3-udc", .data = &udc_sama5d3_cfg },
+ { .compatible = "microchip,sam9x60-udc", .data = &udc_sam9x60_cfg },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, atmel_udc_dt_ids);
+static const struct of_device_id atmel_pmc_dt_ids[] = {
+ { .compatible = "atmel,at91sam9g45-pmc" },
+ { .compatible = "atmel,at91sam9rl-pmc" },
+ { .compatible = "atmel,at91sam9x5-pmc" },
+ { /* sentinel */ }
+};
+
static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
struct usba_udc *udc)
{
- u32 val;
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match;
struct device_node *pp;
int i, ret;
struct usba_ep *eps, *ep;
+ const struct usba_udc_config *udc_config;
match = of_match_node(atmel_udc_dt_ids, np);
if (!match)
return ERR_PTR(-EINVAL);
- udc->errata = match->data;
- udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9g45-pmc");
- if (IS_ERR(udc->pmc))
- udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9rl-pmc");
- if (IS_ERR(udc->pmc))
- udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9x5-pmc");
- if (udc->errata && IS_ERR(udc->pmc))
- return ERR_CAST(udc->pmc);
+ udc_config = match->data;
+ udc->ep_prealloc = udc_config->ep_prealloc;
+ udc->errata = udc_config->errata;
+ if (udc->errata) {
+ pp = of_find_matching_node_and_match(NULL, atmel_pmc_dt_ids,
+ NULL);
+ if (!pp)
+ return ERR_PTR(-ENODEV);
+
+ udc->pmc = syscon_node_to_regmap(pp);
+ of_node_put(pp);
+ if (IS_ERR(udc->pmc))
+ return ERR_CAST(udc->pmc);
+ }
udc->num_ep = 0;
udc->vbus_pin = devm_gpiod_get_optional(&pdev->dev, "atmel,vbus",
GPIOD_IN);
+ if (IS_ERR(udc->vbus_pin))
+ return ERR_CAST(udc->vbus_pin);
if (fifo_mode == 0) {
- pp = NULL;
- while ((pp = of_get_next_child(np, pp)))
- udc->num_ep++;
- udc->configured_ep = 1;
+ udc->num_ep = udc_config->num_ep;
} else {
udc->num_ep = usba_config_fifo_table(udc);
}
@@ -2046,54 +2181,39 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
INIT_LIST_HEAD(&eps[0].ep.ep_list);
- pp = NULL;
i = 0;
- while ((pp = of_get_next_child(np, pp)) && i < udc->num_ep) {
+ while (i < udc->num_ep) {
+ const struct usba_ep_config *ep_cfg = &udc_config->config[i];
+
ep = &eps[i];
- ret = of_property_read_u32(pp, "reg", &val);
- if (ret) {
- dev_err(&pdev->dev, "of_probe: reg error(%d)\n", ret);
- goto err;
- }
- ep->index = fifo_mode ? udc->fifo_cfg[i].hw_ep_num : val;
+ ep->index = fifo_mode ? udc->fifo_cfg[i].hw_ep_num : i;
+
+ /* Only the first EP is 64 bytes */
+ if (ep->index == 0)
+ ep->fifo_size = 64;
+ else
+ ep->fifo_size = 1024;
- ret = of_property_read_u32(pp, "atmel,fifo-size", &val);
- if (ret) {
- dev_err(&pdev->dev, "of_probe: fifo-size error(%d)\n", ret);
- goto err;
- }
if (fifo_mode) {
- if (val < udc->fifo_cfg[i].fifo_size) {
+ if (ep->fifo_size < udc->fifo_cfg[i].fifo_size)
dev_warn(&pdev->dev,
- "Using max fifo-size value from DT\n");
- ep->fifo_size = val;
- } else {
+ "Using default max fifo-size value\n");
+ else
ep->fifo_size = udc->fifo_cfg[i].fifo_size;
- }
- } else {
- ep->fifo_size = val;
}
- ret = of_property_read_u32(pp, "atmel,nb-banks", &val);
- if (ret) {
- dev_err(&pdev->dev, "of_probe: nb-banks error(%d)\n", ret);
- goto err;
- }
+ ep->nr_banks = ep_cfg->nr_banks;
if (fifo_mode) {
- if (val < udc->fifo_cfg[i].nr_banks) {
+ if (ep->nr_banks < udc->fifo_cfg[i].nr_banks)
dev_warn(&pdev->dev,
- "Using max nb-banks value from DT\n");
- ep->nr_banks = val;
- } else {
+ "Using default max nb-banks value\n");
+ else
ep->nr_banks = udc->fifo_cfg[i].nr_banks;
- }
- } else {
- ep->nr_banks = val;
}
- ep->can_dma = of_property_read_bool(pp, "atmel,can-dma");
- ep->can_isoc = of_property_read_bool(pp, "atmel,can-isoc");
+ ep->can_dma = ep_cfg->can_dma;
+ ep->can_isoc = ep_cfg->can_isoc;
sprintf(ep->name, "ep%d", ep->index);
ep->ep.name = ep->name;
@@ -2163,15 +2283,13 @@ static int usba_udc_probe(struct platform_device *pdev)
udc->gadget = usba_gadget_template;
INIT_LIST_HEAD(&udc->gadget.ep_list);
- res = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID);
- udc->regs = devm_ioremap_resource(&pdev->dev, res);
+ udc->regs = devm_platform_get_and_ioremap_resource(pdev, CTRL_IOMEM_ID, &res);
if (IS_ERR(udc->regs))
return PTR_ERR(udc->regs);
dev_info(&pdev->dev, "MMIO registers at %pR mapped at %p\n",
res, udc->regs);
- res = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID);
- udc->fifo = devm_ioremap_resource(&pdev->dev, res);
+ udc->fifo = devm_platform_get_and_ioremap_resource(pdev, FIFO_IOMEM_ID, &res);
if (IS_ERR(udc->fifo))
return PTR_ERR(udc->fifo);
dev_info(&pdev->dev, "FIFO at %pR mapped at %p\n", res, udc->fifo);
@@ -2247,7 +2365,7 @@ static int usba_udc_probe(struct platform_device *pdev)
return 0;
}
-static int usba_udc_remove(struct platform_device *pdev)
+static void usba_udc_remove(struct platform_device *pdev)
{
struct usba_udc *udc;
int i;
@@ -2260,8 +2378,6 @@ static int usba_udc_remove(struct platform_device *pdev)
for (i = 1; i < udc->num_ep; i++)
usba_ep_cleanup_debugfs(&udc->usba_ep[i]);
usba_cleanup_debugfs(udc);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -2276,6 +2392,7 @@ static int usba_udc_suspend(struct device *dev)
mutex_lock(&udc->vbus_mutex);
if (!device_may_wakeup(dev)) {
+ udc->suspended = false;
usba_stop(udc);
goto out;
}
@@ -2285,10 +2402,13 @@ static int usba_udc_suspend(struct device *dev)
* to request vbus irq, assuming always on.
*/
if (udc->vbus_pin) {
+ /* FIXME: right to stop here...??? */
usba_stop(udc);
enable_irq_wake(gpiod_to_irq(udc->vbus_pin));
}
+ enable_irq_wake(udc->irq);
+
out:
mutex_unlock(&udc->vbus_mutex);
return 0;
@@ -2302,8 +2422,12 @@ static int usba_udc_resume(struct device *dev)
if (!udc->driver)
return 0;
- if (device_may_wakeup(dev) && udc->vbus_pin)
- disable_irq_wake(gpiod_to_irq(udc->vbus_pin));
+ if (device_may_wakeup(dev)) {
+ if (udc->vbus_pin)
+ disable_irq_wake(gpiod_to_irq(udc->vbus_pin));
+
+ disable_irq_wake(udc->irq);
+ }
/* If Vbus is present, enable the controller and wait for reset */
mutex_lock(&udc->vbus_mutex);
@@ -2319,6 +2443,7 @@ static int usba_udc_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(usba_udc_pm_ops, usba_udc_suspend, usba_udc_resume);
static struct platform_driver udc_driver = {
+ .probe = usba_udc_probe,
.remove = usba_udc_remove,
.driver = {
.name = "atmel_usba_udc",
@@ -2326,8 +2451,7 @@ static struct platform_driver udc_driver = {
.of_match_table = atmel_udc_dt_ids,
},
};
-
-module_platform_driver_probe(udc_driver, usba_udc_probe);
+module_platform_driver(udc_driver);
MODULE_DESCRIPTION("Atmel USBA UDC driver");
MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");