summaryrefslogtreecommitdiffstats
path: root/drivers/usb/chipidea
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/chipidea')
-rw-r--r--drivers/usb/chipidea/Makefile2
-rw-r--r--drivers/usb/chipidea/ci.h19
-rw-r--r--drivers/usb/chipidea/ci13xxx_imx.c12
-rw-r--r--drivers/usb/chipidea/ci13xxx_imx.h3
-rw-r--r--drivers/usb/chipidea/ci13xxx_pci.c6
-rw-r--r--drivers/usb/chipidea/core.c66
-rw-r--r--drivers/usb/chipidea/debug.c888
-rw-r--r--drivers/usb/chipidea/debug.h34
-rw-r--r--drivers/usb/chipidea/udc.c299
-rw-r--r--drivers/usb/chipidea/udc.h4
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c261
-rw-r--r--drivers/usb/chipidea/usbmisc_imx6q.c162
12 files changed, 603 insertions, 1153 deletions
diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile
index d92ca325b10..4ab83e98219 100644
--- a/drivers/usb/chipidea/Makefile
+++ b/drivers/usb/chipidea/Makefile
@@ -17,5 +17,5 @@ ifneq ($(CONFIG_PCI),)
endif
ifneq ($(CONFIG_OF_DEVICE),)
- obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_imx.o usbmisc_imx6q.o
+ obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_imx.o usbmisc_imx.o
endif
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index e25d1263da1..b0a6bce064c 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -21,6 +21,7 @@
/******************************************************************************
* DEFINE
*****************************************************************************/
+#define TD_PAGE_COUNT 5
#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */
#define ENDPT_MAX 32
@@ -129,6 +130,7 @@ struct hw_bank {
* @vbus_active: is VBUS active
* @transceiver: pointer to USB PHY, if any
* @hcd: pointer to usb_hcd for ehci host driver
+ * @debugfs: root dentry for this controller in debugfs
*/
struct ci13xxx {
struct device *dev;
@@ -139,7 +141,6 @@ struct ci13xxx {
enum ci_role role;
bool is_otg;
struct work_struct work;
- struct work_struct vbus_work;
struct workqueue_struct *wq;
struct dma_pool *qh_pool;
@@ -165,6 +166,7 @@ struct ci13xxx {
bool global_phy;
struct usb_phy *transceiver;
struct usb_hcd *hcd;
+ struct dentry *debugfs;
};
static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
@@ -234,19 +236,6 @@ enum ci13xxx_regs {
};
/**
- * ffs_nr: find first (least significant) bit set
- * @x: the word to search
- *
- * This function returns bit number (instead of position)
- */
-static inline int ffs_nr(u32 x)
-{
- int n = ffs(x);
-
- return n ? n-1 : 32;
-}
-
-/**
* hw_read: reads from a hw register
* @reg: register index
* @mask: bitfield mask
@@ -304,7 +293,7 @@ static inline u32 hw_test_and_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
u32 val = hw_read(ci, reg, ~0);
hw_write(ci, reg, mask, data);
- return (val & mask) >> ffs_nr(mask);
+ return (val & mask) >> __ffs(mask);
}
int hw_device_reset(struct ci13xxx *ci, u32 mode);
diff --git a/drivers/usb/chipidea/ci13xxx_imx.c b/drivers/usb/chipidea/ci13xxx_imx.c
index 8c291220be7..8faec9dbbb8 100644
--- a/drivers/usb/chipidea/ci13xxx_imx.c
+++ b/drivers/usb/chipidea/ci13xxx_imx.c
@@ -79,6 +79,9 @@ int usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev)
if (of_find_property(np, "disable-over-current", NULL))
usbdev->disable_oc = 1;
+ if (of_find_property(np, "external-vbus-divider", NULL))
+ usbdev->evdo = 1;
+
return 0;
}
EXPORT_SYMBOL_GPL(usbmisc_get_init_data);
@@ -202,6 +205,15 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
goto err;
}
+ if (usbmisc_ops && usbmisc_ops->post) {
+ ret = usbmisc_ops->post(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "usbmisc post failed, ret=%d\n", ret);
+ goto put_np;
+ }
+ }
+
data->ci_pdev = plat_ci;
platform_set_drvdata(pdev, data);
diff --git a/drivers/usb/chipidea/ci13xxx_imx.h b/drivers/usb/chipidea/ci13xxx_imx.h
index 9cd2e910b1c..550bfa45762 100644
--- a/drivers/usb/chipidea/ci13xxx_imx.h
+++ b/drivers/usb/chipidea/ci13xxx_imx.h
@@ -13,6 +13,8 @@
struct usbmisc_ops {
/* It's called once when probe a usb device */
int (*init)(struct device *dev);
+ /* It's called once after adding a usb device */
+ int (*post)(struct device *dev);
};
struct usbmisc_usb_device {
@@ -20,6 +22,7 @@ struct usbmisc_usb_device {
int index;
unsigned int disable_oc:1; /* over current detect disabled */
+ unsigned int evdo:1; /* set external vbus divider option */
};
int usbmisc_set_ops(const struct usbmisc_ops *ops);
diff --git a/drivers/usb/chipidea/ci13xxx_pci.c b/drivers/usb/chipidea/ci13xxx_pci.c
index 9b227e39299..4e1fc61b9d9 100644
--- a/drivers/usb/chipidea/ci13xxx_pci.c
+++ b/drivers/usb/chipidea/ci13xxx_pci.c
@@ -23,17 +23,17 @@
/******************************************************************************
* PCI block
*****************************************************************************/
-struct ci13xxx_platform_data pci_platdata = {
+static struct ci13xxx_platform_data pci_platdata = {
.name = UDC_DRIVER_NAME,
.capoffset = DEF_CAPOFFSET,
};
-struct ci13xxx_platform_data langwell_pci_platdata = {
+static struct ci13xxx_platform_data langwell_pci_platdata = {
.name = UDC_DRIVER_NAME,
.capoffset = 0,
};
-struct ci13xxx_platform_data penwell_pci_platdata = {
+static struct ci13xxx_platform_data penwell_pci_platdata = {
.name = UDC_DRIVER_NAME,
.capoffset = 0,
.power_budget = 200,
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 57cae1f897b..450107e5f65 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -51,15 +51,12 @@
*/
#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/dmapool.h>
#include <linux/dma-mapping.h>
-#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/idr.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
@@ -158,7 +155,7 @@ int hw_port_test_set(struct ci13xxx *ci, u8 mode)
if (mode > TEST_MODE_MAX)
return -EINVAL;
- hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC));
+ hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << __ffs(PORTSC_PTC));
return 0;
}
@@ -169,7 +166,7 @@ int hw_port_test_set(struct ci13xxx *ci, u8 mode)
*/
u8 hw_port_test_get(struct ci13xxx *ci)
{
- return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC);
+ return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC);
}
static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
@@ -181,11 +178,11 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
ci->hw_bank.cap = ci->hw_bank.abs;
ci->hw_bank.cap += ci->platdata->capoffset;
- ci->hw_bank.op = ci->hw_bank.cap + ioread8(ci->hw_bank.cap);
+ ci->hw_bank.op = ci->hw_bank.cap + (ioread32(ci->hw_bank.cap) & 0xff);
hw_alloc_regmap(ci, false);
reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) >>
- ffs_nr(HCCPARAMS_LEN);
+ __ffs(HCCPARAMS_LEN);
ci->hw_bank.lpm = reg;
hw_alloc_regmap(ci, !!reg);
ci->hw_bank.size = ci->hw_bank.op - ci->hw_bank.abs;
@@ -193,7 +190,7 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
ci->hw_bank.size /= sizeof(u32);
reg = hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DEN) >>
- ffs_nr(DCCPARAMS_DEN);
+ __ffs(DCCPARAMS_DEN);
ci->hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */
if (ci->hw_ep_max > ENDPT_MAX)
@@ -283,38 +280,6 @@ static void ci_role_work(struct work_struct *work)
}
}
-static ssize_t show_role(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct ci13xxx *ci = dev_get_drvdata(dev);
-
- return sprintf(buf, "%s\n", ci_role(ci)->name);
-}
-
-static ssize_t store_role(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ci13xxx *ci = dev_get_drvdata(dev);
- enum ci_role role;
- int ret;
-
- for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
- if (ci->roles[role] && !strcmp(buf, ci->roles[role]->name))
- break;
-
- if (role == CI_ROLE_END || role == ci->role)
- return -EINVAL;
-
- ci_role_stop(ci);
- ret = ci_role_start(ci, role);
- if (ret)
- return ret;
-
- return count;
-}
-
-static DEVICE_ATTR(role, S_IRUSR | S_IWUSR, show_role, store_role);
-
static irqreturn_t ci_irq(int irq, void *data)
{
struct ci13xxx *ci = data;
@@ -410,11 +375,9 @@ static int ci_hdrc_probe(struct platform_device *pdev)
return -ENODEV;
}
- base = devm_request_and_ioremap(dev, res);
- if (!base) {
- dev_err(dev, "can't request and ioremap resource\n");
- return -ENOMEM;
- }
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL);
if (!ci) {
@@ -489,17 +452,14 @@ static int ci_hdrc_probe(struct platform_device *pdev)
if (ret)
goto stop;
- ret = device_create_file(dev, &dev_attr_role);
- if (ret)
- goto rm_attr;
-
if (ci->is_otg)
hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE);
- return ret;
+ ret = dbg_create_files(ci);
+ if (!ret)
+ return 0;
-rm_attr:
- device_remove_file(dev, &dev_attr_role);
+ free_irq(ci->irq, ci);
stop:
ci_role_stop(ci);
rm_wq:
@@ -513,9 +473,9 @@ static int ci_hdrc_remove(struct platform_device *pdev)
{
struct ci13xxx *ci = platform_get_drvdata(pdev);
+ dbg_remove_files(ci);
flush_workqueue(ci->wq);
destroy_workqueue(ci->wq);
- device_remove_file(ci->dev, &dev_attr_role);
free_irq(ci->irq, ci);
ci_role_stop(ci);
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index a62c4a47d52..36a7063a6cb 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -1,590 +1,126 @@
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dmapool.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/chipidea.h>
#include "ci.h"
#include "udc.h"
#include "bits.h"
#include "debug.h"
-/* Interrupt statistics */
-#define ISR_MASK 0x1F
-static struct isr_statistics {
- u32 test;
- u32 ui;
- u32 uei;
- u32 pci;
- u32 uri;
- u32 sli;
- u32 none;
- struct {
- u32 cnt;
- u32 buf[ISR_MASK+1];
- u32 idx;
- } hndl;
-} isr_statistics;
-
-void dbg_interrupt(u32 intmask)
-{
- if (!intmask) {
- isr_statistics.none++;
- return;
- }
-
- isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intmask;
- isr_statistics.hndl.idx &= ISR_MASK;
- isr_statistics.hndl.cnt++;
-
- if (USBi_URI & intmask)
- isr_statistics.uri++;
- if (USBi_PCI & intmask)
- isr_statistics.pci++;
- if (USBi_UEI & intmask)
- isr_statistics.uei++;
- if (USBi_UI & intmask)
- isr_statistics.ui++;
- if (USBi_SLI & intmask)
- isr_statistics.sli++;
-}
-
/**
- * hw_register_read: reads all device registers (execute without interruption)
- * @buf: destination buffer
- * @size: buffer size
- *
- * This function returns number of registers read
+ * ci_device_show: prints information about device capabilities and status
*/
-static size_t hw_register_read(struct ci13xxx *ci, u32 *buf, size_t size)
+static int ci_device_show(struct seq_file *s, void *data)
{
- unsigned i;
-
- if (size > ci->hw_bank.size)
- size = ci->hw_bank.size;
-
- for (i = 0; i < size; i++)
- buf[i] = hw_read(ci, i * sizeof(u32), ~0);
-
- return size;
-}
-
-/**
- * hw_register_write: writes to register
- * @addr: register address
- * @data: register value
- *
- * This function returns an error code
- */
-static int hw_register_write(struct ci13xxx *ci, u16 addr, u32 data)
-{
- /* align */
- addr /= sizeof(u32);
-
- if (addr >= ci->hw_bank.size)
- return -EINVAL;
-
- /* align */
- addr *= sizeof(u32);
-
- hw_write(ci, addr, ~0, data);
- return 0;
-}
-
-/**
- * hw_intr_clear: disables interrupt & clears interrupt status (execute without
- * interruption)
- * @n: interrupt bit
- *
- * This function returns an error code
- */
-static int hw_intr_clear(struct ci13xxx *ci, int n)
-{
- if (n >= REG_BITS)
- return -EINVAL;
-
- hw_write(ci, OP_USBINTR, BIT(n), 0);
- hw_write(ci, OP_USBSTS, BIT(n), BIT(n));
- return 0;
-}
-
-/**
- * hw_intr_force: enables interrupt & forces interrupt status (execute without
- * interruption)
- * @n: interrupt bit
- *
- * This function returns an error code
- */
-static int hw_intr_force(struct ci13xxx *ci, int n)
-{
- if (n >= REG_BITS)
- return -EINVAL;
-
- hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
- hw_write(ci, OP_USBINTR, BIT(n), BIT(n));
- hw_write(ci, OP_USBSTS, BIT(n), BIT(n));
- hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, 0);
- return 0;
-}
-
-/**
- * show_device: prints information about device capabilities and status
- *
- * Check "device.h" for details
- */
-static ssize_t show_device(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+ struct ci13xxx *ci = s->private;
struct usb_gadget *gadget = &ci->gadget;
- int n = 0;
- if (attr == NULL || buf == NULL) {
- dev_err(ci->dev, "[%s] EINVAL\n", __func__);
+ seq_printf(s, "speed = %d\n", gadget->speed);
+ seq_printf(s, "max_speed = %d\n", gadget->max_speed);
+ seq_printf(s, "is_otg = %d\n", gadget->is_otg);
+ seq_printf(s, "is_a_peripheral = %d\n", gadget->is_a_peripheral);
+ seq_printf(s, "b_hnp_enable = %d\n", gadget->b_hnp_enable);
+ seq_printf(s, "a_hnp_support = %d\n", gadget->a_hnp_support);
+ seq_printf(s, "a_alt_hnp_support = %d\n", gadget->a_alt_hnp_support);
+ seq_printf(s, "name = %s\n",
+ (gadget->name ? gadget->name : ""));
+
+ if (!ci->driver)
return 0;
- }
-
- n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n",
- gadget->speed);
- n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n",
- gadget->max_speed);
- n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n",
- gadget->is_otg);
- n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n",
- gadget->is_a_peripheral);
- n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable = %d\n",
- gadget->b_hnp_enable);
- n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support = %d\n",
- gadget->a_hnp_support);
- n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n",
- gadget->a_alt_hnp_support);
- n += scnprintf(buf + n, PAGE_SIZE - n, "name = %s\n",
- (gadget->name ? gadget->name : ""));
-
- return n;
-}
-static DEVICE_ATTR(device, S_IRUSR, show_device, NULL);
-
-/**
- * show_driver: prints information about attached gadget (if any)
- *
- * Check "device.h" for details
- */
-static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
- struct usb_gadget_driver *driver = ci->driver;
- int n = 0;
-
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- if (driver == NULL)
- return scnprintf(buf, PAGE_SIZE,
- "There is no gadget attached!\n");
- n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n",
- (driver->function ? driver->function : ""));
- n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n",
- driver->max_speed);
+ seq_printf(s, "gadget function = %s\n",
+ (ci->driver->function ? ci->driver->function : ""));
+ seq_printf(s, "gadget max speed = %d\n", ci->driver->max_speed);
- return n;
-}
-static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL);
-
-/* Maximum event message length */
-#define DBG_DATA_MSG 64UL
-
-/* Maximum event messages */
-#define DBG_DATA_MAX 128UL
-
-/* Event buffer descriptor */
-static struct {
- char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */
- unsigned idx; /* index */
- unsigned tty; /* print to console? */
- rwlock_t lck; /* lock */
-} dbg_data = {
- .idx = 0,
- .tty = 0,
- .lck = __RW_LOCK_UNLOCKED(dbg_data.lck)
-};
-
-/**
- * dbg_dec: decrements debug event index
- * @idx: buffer index
- */
-static void dbg_dec(unsigned *idx)
-{
- *idx = (*idx - 1) & (DBG_DATA_MAX-1);
-}
-
-/**
- * dbg_inc: increments debug event index
- * @idx: buffer index
- */
-static void dbg_inc(unsigned *idx)
-{
- *idx = (*idx + 1) & (DBG_DATA_MAX-1);
-}
-
-/**
- * dbg_print: prints the common part of the event
- * @addr: endpoint address
- * @name: event name
- * @status: status
- * @extra: extra information
- */
-static void dbg_print(u8 addr, const char *name, int status, const char *extra)
-{
- struct timeval tval;
- unsigned int stamp;
- unsigned long flags;
-
- write_lock_irqsave(&dbg_data.lck, flags);
-
- do_gettimeofday(&tval);
- stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s */
- stamp = stamp * 1000000 + tval.tv_usec;
-
- scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
- "%04X\t? %02X %-7.7s %4i ?\t%s\n",
- stamp, addr, name, status, extra);
-
- dbg_inc(&dbg_data.idx);
-
- write_unlock_irqrestore(&dbg_data.lck, flags);
-
- if (dbg_data.tty != 0)
- pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n",
- stamp, addr, name, status, extra);
-}
-
-/**
- * dbg_done: prints a DONE event
- * @addr: endpoint address
- * @td: transfer descriptor
- * @status: status
- */
-void dbg_done(u8 addr, const u32 token, int status)
-{
- char msg[DBG_DATA_MSG];
-
- scnprintf(msg, sizeof(msg), "%d %02X",
- (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES),
- (int)(token & TD_STATUS) >> ffs_nr(TD_STATUS));
- dbg_print(addr, "DONE", status, msg);
-}
-
-/**
- * dbg_event: prints a generic event
- * @addr: endpoint address
- * @name: event name
- * @status: status
- */
-void dbg_event(u8 addr, const char *name, int status)
-{
- if (name != NULL)
- dbg_print(addr, name, status, "");
-}
-
-/*
- * dbg_queue: prints a QUEUE event
- * @addr: endpoint address
- * @req: USB request
- * @status: status
- */
-void dbg_queue(u8 addr, const struct usb_request *req, int status)
-{
- char msg[DBG_DATA_MSG];
-
- if (req != NULL) {
- scnprintf(msg, sizeof(msg),
- "%d %d", !req->no_interrupt, req->length);
- dbg_print(addr, "QUEUE", status, msg);
- }
-}
-
-/**
- * dbg_setup: prints a SETUP event
- * @addr: endpoint address
- * @req: setup request
- */
-void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
-{
- char msg[DBG_DATA_MSG];
-
- if (req != NULL) {
- scnprintf(msg, sizeof(msg),
- "%02X %02X %04X %04X %d", req->bRequestType,
- req->bRequest, le16_to_cpu(req->wValue),
- le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength));
- dbg_print(addr, "SETUP", 0, msg);
- }
+ return 0;
}
-/**
- * show_events: displays the event buffer
- *
- * Check "device.h" for details
- */
-static ssize_t show_events(struct device *dev, struct device_attribute *attr,
- char *buf)
+static int ci_device_open(struct inode *inode, struct file *file)
{
- unsigned long flags;
- unsigned i, j, n = 0;
-
- if (attr == NULL || buf == NULL) {
- dev_err(dev->parent, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- read_lock_irqsave(&dbg_data.lck, flags);
-
- i = dbg_data.idx;
- for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) {
- n += strlen(dbg_data.buf[i]);
- if (n >= PAGE_SIZE) {
- n -= strlen(dbg_data.buf[i]);
- break;
- }
- }
- for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i))
- j += scnprintf(buf + j, PAGE_SIZE - j,
- "%s", dbg_data.buf[i]);
-
- read_unlock_irqrestore(&dbg_data.lck, flags);
-
- return n;
+ return single_open(file, ci_device_show, inode->i_private);
}
-/**
- * store_events: configure if events are going to be also printed to console
- *
- * Check "device.h" for details
- */
-static ssize_t store_events(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- unsigned tty;
-
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- goto done;
- }
-
- if (sscanf(buf, "%u", &tty) != 1 || tty > 1) {
- dev_err(dev, "<1|0>: enable|disable console log\n");
- goto done;
- }
-
- dbg_data.tty = tty;
- dev_info(dev, "tty = %u", dbg_data.tty);
-
- done:
- return count;
-}
-static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events);
+static const struct file_operations ci_device_fops = {
+ .open = ci_device_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
/**
- * show_inters: interrupt status, enable status and historic
- *
- * Check "device.h" for details
+ * ci_port_test_show: reads port test mode
*/
-static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
- char *buf)
+static int ci_port_test_show(struct seq_file *s, void *data)
{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+ struct ci13xxx *ci = s->private;
unsigned long flags;
- u32 intr;
- unsigned i, j, n = 0;
-
- if (attr == NULL || buf == NULL) {
- dev_err(ci->dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
+ unsigned mode;
spin_lock_irqsave(&ci->lock, flags);
-
- /*n += scnprintf(buf + n, PAGE_SIZE - n,
- "status = %08x\n", hw_read_intr_status(ci));
- n += scnprintf(buf + n, PAGE_SIZE - n,
- "enable = %08x\n", hw_read_intr_enable(ci));*/
-
- n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
- isr_statistics.test);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? ui = %d\n",
- isr_statistics.ui);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n",
- isr_statistics.uei);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n",
- isr_statistics.pci);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n",
- isr_statistics.uri);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n",
- isr_statistics.sli);
- n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
- isr_statistics.none);
- n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n",
- isr_statistics.hndl.cnt);
-
- for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) {
- i &= ISR_MASK;
- intr = isr_statistics.hndl.buf[i];
-
- if (USBi_UI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "ui ");
- intr &= ~USBi_UI;
- if (USBi_UEI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "uei ");
- intr &= ~USBi_UEI;
- if (USBi_PCI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "pci ");
- intr &= ~USBi_PCI;
- if (USBi_URI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "uri ");
- intr &= ~USBi_URI;
- if (USBi_SLI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "sli ");
- intr &= ~USBi_SLI;
- if (intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "??? ");
- if (isr_statistics.hndl.buf[i])
- n += scnprintf(buf + n, PAGE_SIZE - n, "\n");
- }
-
+ mode = hw_port_test_get(ci);
spin_unlock_irqrestore(&ci->lock, flags);
- return n;
-}
-
-/**
- * store_inters: enable & force or disable an individual interrutps
- * (to be used for test purposes only)
- *
- * Check "device.h" for details
- */
-static ssize_t store_inters(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- unsigned en, bit;
-
- if (attr == NULL || buf == NULL) {
- dev_err(ci->dev, "EINVAL\n");
- goto done;
- }
+ seq_printf(s, "mode = %u\n", mode);
- if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) {
- dev_err(ci->dev, "<1|0> <bit>: enable|disable interrupt\n");
- goto done;
- }
-
- spin_lock_irqsave(&ci->lock, flags);
- if (en) {
- if (hw_intr_force(ci, bit))
- dev_err(dev, "invalid bit number\n");
- else
- isr_statistics.test++;
- } else {
- if (hw_intr_clear(ci, bit))
- dev_err(dev, "invalid bit number\n");
- }
- spin_unlock_irqrestore(&ci->lock, flags);
-
- done:
- return count;
+ return 0;
}
-static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters);
/**
- * show_port_test: reads port test mode
- *
- * Check "device.h" for details
+ * ci_port_test_write: writes port test mode
*/
-static ssize_t show_port_test(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+ struct seq_file *s = file->private_data;
+ struct ci13xxx *ci = s->private;
unsigned long flags;
unsigned mode;
+ char buf[32];
+ int ret;
- if (attr == NULL || buf == NULL) {
- dev_err(ci->dev, "EINVAL\n");
- return 0;
- }
+ if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ if (sscanf(buf, "%u", &mode) != 1)
+ return -EINVAL;
spin_lock_irqsave(&ci->lock, flags);
- mode = hw_port_test_get(ci);
+ ret = hw_port_test_set(ci, mode);
spin_unlock_irqrestore(&ci->lock, flags);
- return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode);
+ return ret ? ret : count;
}
-/**
- * store_port_test: writes port test mode
- *
- * Check "device.h" for details
- */
-static ssize_t store_port_test(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static int ci_port_test_open(struct inode *inode, struct file *file)
{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- unsigned mode;
-
- if (attr == NULL || buf == NULL) {
- dev_err(ci->dev, "[%s] EINVAL\n", __func__);
- goto done;
- }
-
- if (sscanf(buf, "%u", &mode) != 1) {
- dev_err(ci->dev, "<mode>: set port test mode");
- goto done;
- }
-
- spin_lock_irqsave(&ci->lock, flags);
- if (hw_port_test_set(ci, mode))
- dev_err(ci->dev, "invalid mode\n");
- spin_unlock_irqrestore(&ci->lock, flags);
-
- done:
- return count;
+ return single_open(file, ci_port_test_show, inode->i_private);
}
-static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR,
- show_port_test, store_port_test);
+
+static const struct file_operations ci_port_test_fops = {
+ .open = ci_port_test_open,
+ .write = ci_port_test_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
/**
- * show_qheads: DMA contents of all queue heads
- *
- * Check "device.h" for details
+ * ci_qheads_show: DMA contents of all queue heads
*/
-static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
- char *buf)
+static int ci_qheads_show(struct seq_file *s, void *data)
{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+ struct ci13xxx *ci = s->private;
unsigned long flags;
- unsigned i, j, n = 0;
+ unsigned i, j;
- if (attr == NULL || buf == NULL) {
- dev_err(ci->dev, "[%s] EINVAL\n", __func__);
+ if (ci->role != CI_ROLE_GADGET) {
+ seq_printf(s, "not in gadget mode\n");
return 0;
}
@@ -593,209 +129,173 @@ static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
struct ci13xxx_ep *mEpRx = &ci->ci13xxx_ep[i];
struct ci13xxx_ep *mEpTx =
&ci->ci13xxx_ep[i + ci->hw_ep_max/2];
- n += scnprintf(buf + n, PAGE_SIZE - n,
- "EP=%02i: RX=%08X TX=%08X\n",
- i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
- for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) {
- n += scnprintf(buf + n, PAGE_SIZE - n,
- " %04X: %08X %08X\n", j,
- *((u32 *)mEpRx->qh.ptr + j),
- *((u32 *)mEpTx->qh.ptr + j));
- }
+ seq_printf(s, "EP=%02i: RX=%08X TX=%08X\n",
+ i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
+ for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++)
+ seq_printf(s, " %04X: %08X %08X\n", j,
+ *((u32 *)mEpRx->qh.ptr + j),
+ *((u32 *)mEpTx->qh.ptr + j));
}
spin_unlock_irqrestore(&ci->lock, flags);
- return n;
+ return 0;
+}
+
+static int ci_qheads_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ci_qheads_show, inode->i_private);
}
-static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
+
+static const struct file_operations ci_qheads_fops = {
+ .open = ci_qheads_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
/**
- * show_registers: dumps all registers
- *
- * Check "device.h" for details
+ * ci_requests_show: DMA contents of all requests currently queued (all endpts)
*/
-#define DUMP_ENTRIES 512
-static ssize_t show_registers(struct device *dev,
- struct device_attribute *attr, char *buf)
+static int ci_requests_show(struct seq_file *s, void *data)
{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+ struct ci13xxx *ci = s->private;
unsigned long flags;
- u32 *dump;
- unsigned i, k, n = 0;
-
- if (attr == NULL || buf == NULL) {
- dev_err(ci->dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
+ struct list_head *ptr = NULL;
+ struct ci13xxx_req *req = NULL;
+ unsigned i, j, qsize = sizeof(struct ci13xxx_td)/sizeof(u32);
- dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
- if (!dump) {
- dev_err(ci->dev, "%s: out of memory\n", __func__);
+ if (ci->role != CI_ROLE_GADGET) {
+ seq_printf(s, "not in gadget mode\n");
return 0;
}
spin_lock_irqsave(&ci->lock, flags);
- k = hw_register_read(ci, dump, DUMP_ENTRIES);
- spin_unlock_irqrestore(&ci->lock, flags);
+ for (i = 0; i < ci->hw_ep_max; i++)
+ list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue) {
+ req = list_entry(ptr, struct ci13xxx_req, queue);
- for (i = 0; i < k; i++) {
- n += scnprintf(buf + n, PAGE_SIZE - n,
- "reg[0x%04X] = 0x%08X\n",
- i * (unsigned)sizeof(u32), dump[i]);
- }
- kfree(dump);
+ seq_printf(s, "EP=%02i: TD=%08X %s\n",
+ i % (ci->hw_ep_max / 2), (u32)req->dma,
+ ((i < ci->hw_ep_max/2) ? "RX" : "TX"));
+
+ for (j = 0; j < qsize; j++)
+ seq_printf(s, " %04X: %08X\n", j,
+ *((u32 *)req->ptr + j));
+ }
+ spin_unlock_irqrestore(&ci->lock, flags);
- return n;
+ return 0;
}
-/**
- * store_registers: writes value to register address
- *
- * Check "device.h" for details
- */
-static ssize_t store_registers(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static int ci_requests_open(struct inode *inode, struct file *file)
{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long addr, data, flags;
+ return single_open(file, ci_requests_show, inode->i_private);
+}
- if (attr == NULL || buf == NULL) {
- dev_err(ci->dev, "[%s] EINVAL\n", __func__);
- goto done;
- }
+static const struct file_operations ci_requests_fops = {
+ .open = ci_requests_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
- if (sscanf(buf, "%li %li", &addr, &data) != 2) {
- dev_err(ci->dev,
- "<addr> <data>: write data to register address\n");
- goto done;
- }
+static int ci_role_show(struct seq_file *s, void *data)
+{
+ struct ci13xxx *ci = s->private;
- spin_lock_irqsave(&ci->lock, flags);
- if (hw_register_write(ci, addr, data))
- dev_err(ci->dev, "invalid address range\n");
- spin_unlock_irqrestore(&ci->lock, flags);
+ seq_printf(s, "%s\n", ci_role(ci)->name);
- done:
- return count;
+ return 0;
}
-static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR,
- show_registers, store_registers);
-/**
- * show_requests: DMA contents of all requests currently queued (all endpts)
- *
- * Check "device.h" for details
- */
-static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- struct list_head *ptr = NULL;
- struct ci13xxx_req *req = NULL;
- unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
-
- if (attr == NULL || buf == NULL) {
- dev_err(ci->dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
+ struct seq_file *s = file->private_data;
+ struct ci13xxx *ci = s->private;
+ enum ci_role role;
+ char buf[8];
+ int ret;
+
+ if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
+ if (ci->roles[role] &&
+ !strncmp(buf, ci->roles[role]->name,
+ strlen(ci->roles[role]->name)))
+ break;
- spin_lock_irqsave(&ci->lock, flags);
- for (i = 0; i < ci->hw_ep_max; i++)
- list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue)
- {
- req = list_entry(ptr, struct ci13xxx_req, queue);
+ if (role == CI_ROLE_END || role == ci->role)
+ return -EINVAL;
- n += scnprintf(buf + n, PAGE_SIZE - n,
- "EP=%02i: TD=%08X %s\n",
- i % ci->hw_ep_max/2, (u32)req->dma,
- ((i < ci->hw_ep_max/2) ? "RX" : "TX"));
+ ci_role_stop(ci);
+ ret = ci_role_start(ci, role);
- for (j = 0; j < qSize; j++)
- n += scnprintf(buf + n, PAGE_SIZE - n,
- " %04X: %08X\n", j,
- *((u32 *)req->ptr + j));
- }
- spin_unlock_irqrestore(&ci->lock, flags);
+ return ret ? ret : count;
+}
- return n;
+static int ci_role_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ci_role_show, inode->i_private);
}
-static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL);
+
+static const struct file_operations ci_role_fops = {
+ .open = ci_role_open,
+ .write = ci_role_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
/**
* dbg_create_files: initializes the attribute interface
- * @dev: device
+ * @ci: device
*
* This function returns an error code
*/
-int dbg_create_files(struct device *dev)
+int dbg_create_files(struct ci13xxx *ci)
{
- int retval = 0;
-
- if (dev == NULL)
- return -EINVAL;
- retval = device_create_file(dev, &dev_attr_device);
- if (retval)
- goto done;
- retval = device_create_file(dev, &dev_attr_driver);
- if (retval)
- goto rm_device;
- retval = device_create_file(dev, &dev_attr_events);
- if (retval)
- goto rm_driver;
- retval = device_create_file(dev, &dev_attr_inters);
- if (retval)
- goto rm_events;
- retval = device_create_file(dev, &dev_attr_port_test);
- if (retval)
- goto rm_inters;
- retval = device_create_file(dev, &dev_attr_qheads);
- if (retval)
- goto rm_port_test;
- retval = device_create_file(dev, &dev_attr_registers);
- if (retval)
- goto rm_qheads;
- retval = device_create_file(dev, &dev_attr_requests);
- if (retval)
- goto rm_registers;
- return 0;
-
- rm_registers:
- device_remove_file(dev, &dev_attr_registers);
- rm_qheads:
- device_remove_file(dev, &dev_attr_qheads);
- rm_port_test:
- device_remove_file(dev, &dev_attr_port_test);
- rm_inters:
- device_remove_file(dev, &dev_attr_inters);
- rm_events:
- device_remove_file(dev, &dev_attr_events);
- rm_driver:
- device_remove_file(dev, &dev_attr_driver);
- rm_device:
- device_remove_file(dev, &dev_attr_device);
- done:
- return retval;
+ struct dentry *dent;
+
+ ci->debugfs = debugfs_create_dir(dev_name(ci->dev), NULL);
+ if (!ci->debugfs)
+ return -ENOMEM;
+
+ dent = debugfs_create_file("device", S_IRUGO, ci->debugfs, ci,
+ &ci_device_fops);
+ if (!dent)
+ goto err;
+
+ dent = debugfs_create_file("port_test", S_IRUGO | S_IWUSR, ci->debugfs,
+ ci, &ci_port_test_fops);
+ if (!dent)
+ goto err;
+
+ dent = debugfs_create_file("qheads", S_IRUGO, ci->debugfs, ci,
+ &ci_qheads_fops);
+ if (!dent)
+ goto err;
+
+ dent = debugfs_create_file("requests", S_IRUGO, ci->debugfs, ci,
+ &ci_requests_fops);
+ if (!dent)
+ goto err;
+
+ dent = debugfs_create_file("role", S_IRUGO | S_IWUSR, ci->debugfs, ci,
+ &ci_role_fops);
+ if (dent)
+ return 0;
+err:
+ debugfs_remove_recursive(ci->debugfs);
+ return -ENOMEM;
}
/**
* dbg_remove_files: destroys the attribute interface
- * @dev: device
- *
- * This function returns an error code
+ * @ci: device
*/
-int dbg_remove_files(struct device *dev)
+void dbg_remove_files(struct ci13xxx *ci)
{
- if (dev == NULL)
- return -EINVAL;
- device_remove_file(dev, &dev_attr_requests);
- device_remove_file(dev, &dev_attr_registers);
- device_remove_file(dev, &dev_attr_qheads);
- device_remove_file(dev, &dev_attr_port_test);
- device_remove_file(dev, &dev_attr_inters);
- device_remove_file(dev, &dev_attr_events);
- device_remove_file(dev, &dev_attr_driver);
- device_remove_file(dev, &dev_attr_device);
- return 0;
+ debugfs_remove_recursive(ci->debugfs);
}
diff --git a/drivers/usb/chipidea/debug.h b/drivers/usb/chipidea/debug.h
index 80d96865775..7ca6ca0a24a 100644
--- a/drivers/usb/chipidea/debug.h
+++ b/drivers/usb/chipidea/debug.h
@@ -14,42 +14,16 @@
#define __DRIVERS_USB_CHIPIDEA_DEBUG_H
#ifdef CONFIG_USB_CHIPIDEA_DEBUG
-void dbg_interrupt(u32 intmask);
-void dbg_done(u8 addr, const u32 token, int status);
-void dbg_event(u8 addr, const char *name, int status);
-void dbg_queue(u8 addr, const struct usb_request *req, int status);
-void dbg_setup(u8 addr, const struct usb_ctrlrequest *req);
-int dbg_create_files(struct device *dev);
-int dbg_remove_files(struct device *dev);
+int dbg_create_files(struct ci13xxx *ci);
+void dbg_remove_files(struct ci13xxx *ci);
#else
-static inline void dbg_interrupt(u32 intmask)
-{
-}
-
-static inline void dbg_done(u8 addr, const u32 token, int status)
-{
-}
-
-static inline void dbg_event(u8 addr, const char *name, int status)
-{
-}
-
-static inline void dbg_queue(u8 addr, const struct usb_request *req, int status)
-{
-}
-
-static inline void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
-{
-}
-
-static inline int dbg_create_files(struct device *dev)
+static inline int dbg_create_files(struct ci13xxx *ci)
{
return 0;
}
-static inline int dbg_remove_files(struct device *dev)
+static inline void dbg_remove_files(struct ci13xxx *ci)
{
- return 0;
}
#endif
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 2f45bba8561..519ead2443c 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -13,14 +13,8 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dmapool.h>
-#include <linux/dma-mapping.h>
#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
+#include <linux/irqreturn.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
@@ -146,7 +140,7 @@ static int hw_ep_enable(struct ci13xxx *ci, int num, int dir, int type)
if (dir) {
mask = ENDPTCTRL_TXT; /* type */
- data = type << ffs_nr(mask);
+ data = type << __ffs(mask);
mask |= ENDPTCTRL_TXS; /* unstall */
mask |= ENDPTCTRL_TXR; /* reset data toggle */
@@ -155,7 +149,7 @@ static int hw_ep_enable(struct ci13xxx *ci, int num, int dir, int type)
data |= ENDPTCTRL_TXE;
} else {
mask = ENDPTCTRL_RXT; /* type */
- data = type << ffs_nr(mask);
+ data = type << __ffs(mask);
mask |= ENDPTCTRL_RXS; /* unstall */
mask |= ENDPTCTRL_RXR; /* reset data toggle */
@@ -305,18 +299,6 @@ static u32 hw_test_and_clear_intr_active(struct ci13xxx *ci)
return reg;
}
-static void hw_enable_vbus_intr(struct ci13xxx *ci)
-{
- hw_write(ci, OP_OTGSC, OTGSC_AVVIS, OTGSC_AVVIS);
- hw_write(ci, OP_OTGSC, OTGSC_AVVIE, OTGSC_AVVIE);
- queue_work(ci->wq, &ci->vbus_work);
-}
-
-static void hw_disable_vbus_intr(struct ci13xxx *ci)
-{
- hw_write(ci, OP_OTGSC, OTGSC_AVVIE, 0);
-}
-
/**
* hw_test_and_clear_setup_guard: test & clear setup guard (execute without
* interruption)
@@ -349,7 +331,7 @@ static int hw_test_and_set_setup_guard(struct ci13xxx *ci)
static void hw_usb_set_address(struct ci13xxx *ci, u8 value)
{
hw_write(ci, OP_DEVICEADDR, DEVICEADDR_USBADR,
- value << ffs_nr(DEVICEADDR_USBADR));
+ value << __ffs(DEVICEADDR_USBADR));
}
/**
@@ -383,16 +365,6 @@ static int hw_usb_reset(struct ci13xxx *ci)
return 0;
}
-static void vbus_work(struct work_struct *work)
-{
- struct ci13xxx *ci = container_of(work, struct ci13xxx, vbus_work);
-
- if (hw_read(ci, OP_OTGSC, OTGSC_AVV))
- usb_gadget_vbus_connect(&ci->gadget);
- else
- usb_gadget_vbus_disconnect(&ci->gadget);
-}
-
/******************************************************************************
* UTIL block
*****************************************************************************/
@@ -432,10 +404,10 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
return -ENOMEM;
memset(mReq->zptr, 0, sizeof(*mReq->zptr));
- mReq->zptr->next = TD_TERMINATE;
- mReq->zptr->token = TD_STATUS_ACTIVE;
+ mReq->zptr->next = cpu_to_le32(TD_TERMINATE);
+ mReq->zptr->token = cpu_to_le32(TD_STATUS_ACTIVE);
if (!mReq->req.no_interrupt)
- mReq->zptr->token |= TD_IOC;
+ mReq->zptr->token |= cpu_to_le32(TD_IOC);
}
ret = usb_gadget_map_request(&ci->gadget, &mReq->req, mEp->dir);
if (ret)
@@ -446,32 +418,37 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
* TODO - handle requests which spawns into several TDs
*/
memset(mReq->ptr, 0, sizeof(*mReq->ptr));
- mReq->ptr->token = length << ffs_nr(TD_TOTAL_BYTES);
- mReq->ptr->token &= TD_TOTAL_BYTES;
- mReq->ptr->token |= TD_STATUS_ACTIVE;
+ mReq->ptr->token = cpu_to_le32(length << __ffs(TD_TOTAL_BYTES));
+ mReq->ptr->token &= cpu_to_le32(TD_TOTAL_BYTES);
+ mReq->ptr->token |= cpu_to_le32(TD_STATUS_ACTIVE);
if (mReq->zptr) {
- mReq->ptr->next = mReq->zdma;
+ mReq->ptr->next = cpu_to_le32(mReq->zdma);
} else {
- mReq->ptr->next = TD_TERMINATE;
+ mReq->ptr->next = cpu_to_le32(TD_TERMINATE);
if (!mReq->req.no_interrupt)
- mReq->ptr->token |= TD_IOC;
+ mReq->ptr->token |= cpu_to_le32(TD_IOC);
+ }
+ mReq->ptr->page[0] = cpu_to_le32(mReq->req.dma);
+ for (i = 1; i < TD_PAGE_COUNT; i++) {
+ u32 page = mReq->req.dma + i * CI13XXX_PAGE_SIZE;
+ page &= ~TD_RESERVED_MASK;
+ mReq->ptr->page[i] = cpu_to_le32(page);
}
- mReq->ptr->page[0] = mReq->req.dma;
- for (i = 1; i < 5; i++)
- mReq->ptr->page[i] =
- (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK;
+
+ wmb();
if (!list_empty(&mEp->qh.queue)) {
struct ci13xxx_req *mReqPrev;
int n = hw_ep_bit(mEp->num, mEp->dir);
int tmp_stat;
+ u32 next = mReq->dma & TD_ADDR_MASK;
mReqPrev = list_entry(mEp->qh.queue.prev,
struct ci13xxx_req, queue);
if (mReqPrev->zptr)
- mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK;
+ mReqPrev->zptr->next = cpu_to_le32(next);
else
- mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK;
+ mReqPrev->ptr->next = cpu_to_le32(next);
wmb();
if (hw_read(ci, OP_ENDPTPRIME, BIT(n)))
goto done;
@@ -485,9 +462,9 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
}
/* QH configuration */
- mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */
- mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */
- mEp->qh.ptr->cap |= QH_ZLT;
+ mEp->qh.ptr->td.next = cpu_to_le32(mReq->dma); /* TERMINATE = 0 */
+ mEp->qh.ptr->td.token &=
+ cpu_to_le32(~(TD_STATUS_HALTED|TD_STATUS_ACTIVE));
wmb(); /* synchronize before ep prime */
@@ -506,14 +483,16 @@ done:
*/
static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
{
+ u32 tmptoken = le32_to_cpu(mReq->ptr->token);
+
if (mReq->req.status != -EALREADY)
return -EINVAL;
- if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0)
+ if ((TD_STATUS_ACTIVE & tmptoken) != 0)
return -EBUSY;
if (mReq->zptr) {
- if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
+ if ((cpu_to_le32(TD_STATUS_ACTIVE) & mReq->zptr->token) != 0)
return -EBUSY;
dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
mReq->zptr = NULL;
@@ -523,7 +502,7 @@ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
usb_gadget_unmap_request(&mEp->ci->gadget, &mReq->req, mEp->dir);
- mReq->req.status = mReq->ptr->token & TD_STATUS;
+ mReq->req.status = tmptoken & TD_STATUS;
if ((TD_STATUS_HALTED & mReq->req.status) != 0)
mReq->req.status = -1;
else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0)
@@ -531,8 +510,8 @@ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0)
mReq->req.status = -1;
- mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES;
- mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES);
+ mReq->req.actual = tmptoken & TD_TOTAL_BYTES;
+ mReq->req.actual >>= __ffs(TD_TOTAL_BYTES);
mReq->req.actual = mReq->req.length - mReq->req.actual;
mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual;
@@ -561,6 +540,12 @@ __acquires(mEp->lock)
struct ci13xxx_req *mReq = \
list_entry(mEp->qh.queue.next,
struct ci13xxx_req, queue);
+
+ if (mReq->zptr) {
+ dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
+ mReq->zptr = NULL;
+ }
+
list_del_init(&mReq->queue);
mReq->req.status = -ESHUTDOWN;
@@ -629,8 +614,6 @@ __acquires(ci->lock)
{
int retval;
- dbg_event(0xFF, "BUS RST", 0);
-
spin_unlock(&ci->lock);
retval = _gadget_stop_activity(&ci->gadget);
if (retval)
@@ -668,6 +651,59 @@ static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
}
/**
+ * _ep_queue: queues (submits) an I/O request to an endpoint
+ *
+ * Caller must hold lock
+ */
+static int _ep_queue(struct usb_ep *ep, struct usb_request *req,
+ gfp_t __maybe_unused gfp_flags)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+ struct ci13xxx *ci = mEp->ci;
+ int retval = 0;
+
+ if (ep == NULL || req == NULL || mEp->ep.desc == NULL)
+ return -EINVAL;
+
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+ if (req->length)
+ mEp = (ci->ep0_dir == RX) ?
+ ci->ep0out : ci->ep0in;
+ if (!list_empty(&mEp->qh.queue)) {
+ _ep_nuke(mEp);
+ retval = -EOVERFLOW;
+ dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n",
+ _usb_addr(mEp));
+ }
+ }
+
+ /* first nuke then test link, e.g. previous status has not sent */
+ if (!list_empty(&mReq->queue)) {
+ dev_err(mEp->ci->dev, "request already in queue\n");
+ return -EBUSY;
+ }
+
+ if (req->length > (TD_PAGE_COUNT - 1) * CI13XXX_PAGE_SIZE) {
+ dev_err(mEp->ci->dev, "request bigger than one td\n");
+ return -EMSGSIZE;
+ }
+
+ /* push request */
+ mReq->req.status = -EINPROGRESS;
+ mReq->req.actual = 0;
+
+ retval = _hardware_enqueue(mEp, mReq);
+
+ if (retval == -EALREADY)
+ retval = 0;
+ if (!retval)
+ list_add_tail(&mReq->queue, &mEp->qh.queue);
+
+ return retval;
+}
+
+/**
* isr_get_status_response: get_status request response
* @ci: ci struct
* @setup: setup request packet
@@ -714,9 +750,7 @@ __acquires(mEp->lock)
}
/* else do nothing; reserved for future use */
- spin_unlock(mEp->lock);
- retval = usb_ep_queue(&mEp->ep, req, gfp_flags);
- spin_lock(mEp->lock);
+ retval = _ep_queue(&mEp->ep, req, gfp_flags);
if (retval)
goto err_free_buf;
@@ -763,8 +797,6 @@ isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
* This function returns an error code
*/
static int isr_setup_status_phase(struct ci13xxx *ci)
-__releases(mEp->lock)
-__acquires(mEp->lock)
{
int retval;
struct ci13xxx_ep *mEp;
@@ -773,9 +805,7 @@ __acquires(mEp->lock)
ci->status->context = ci;
ci->status->complete = isr_setup_status_complete;
- spin_unlock(mEp->lock);
- retval = usb_ep_queue(&mEp->ep, ci->status, GFP_ATOMIC);
- spin_lock(mEp->lock);
+ retval = _ep_queue(&mEp->ep, ci->status, GFP_ATOMIC);
return retval;
}
@@ -801,7 +831,6 @@ __acquires(mEp->lock)
if (retval < 0)
break;
list_del_init(&mReq->queue);
- dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
if (mReq->req.complete != NULL) {
spin_unlock(mEp->lock);
if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
@@ -814,8 +843,6 @@ __acquires(mEp->lock)
if (retval == -EBUSY)
retval = 0;
- if (retval < 0)
- dbg_event(_usb_addr(mEp), "DONE", retval);
return retval;
}
@@ -847,8 +874,6 @@ __acquires(ci->lock)
if (err > 0) /* needs status phase */
err = isr_setup_status_phase(ci);
if (err < 0) {
- dbg_event(_usb_addr(mEp),
- "ERROR", err);
spin_unlock(&ci->lock);
if (usb_ep_set_halt(&mEp->ep))
dev_err(ci->dev,
@@ -884,8 +909,6 @@ __acquires(ci->lock)
ci->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
- dbg_setup(_usb_addr(mEp), &req);
-
switch (req.bRequest) {
case USB_REQ_CLEAR_FEATURE:
if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
@@ -997,8 +1020,6 @@ delegate:
}
if (err < 0) {
- dbg_event(_usb_addr(mEp), "ERROR", err);
-
spin_unlock(&ci->lock);
if (usb_ep_set_halt(&mEp->ep))
dev_err(ci->dev, "error: ep_set_halt\n");
@@ -1021,6 +1042,7 @@ static int ep_enable(struct usb_ep *ep,
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
int retval = 0;
unsigned long flags;
+ u32 cap = 0;
if (ep == NULL || desc == NULL)
return -EINVAL;
@@ -1040,20 +1062,15 @@ static int ep_enable(struct usb_ep *ep,
mEp->ep.maxpacket = usb_endpoint_maxp(desc);
- dbg_event(_usb_addr(mEp), "ENABLE", 0);
-
- mEp->qh.ptr->cap = 0;
-
if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
- mEp->qh.ptr->cap |= QH_IOS;
- else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
- mEp->qh.ptr->cap &= ~QH_MULT;
- else
- mEp->qh.ptr->cap &= ~QH_ZLT;
+ cap |= QH_IOS;
+ if (mEp->num)
+ cap |= QH_ZLT;
+ cap |= (mEp->ep.maxpacket << __ffs(QH_MAX_PKT)) & QH_MAX_PKT;
+
+ mEp->qh.ptr->cap = cpu_to_le32(cap);
- mEp->qh.ptr->cap |=
- (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
- mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */
+ mEp->qh.ptr->td.next |= cpu_to_le32(TD_TERMINATE); /* needed? */
/*
* Enable endpoints in the HW other than ep0 as ep0
@@ -1088,8 +1105,6 @@ static int ep_disable(struct usb_ep *ep)
direction = mEp->dir;
do {
- dbg_event(_usb_addr(mEp), "DISABLE", 0);
-
retval |= _ep_nuke(mEp);
retval |= hw_ep_disable(mEp->ci, mEp->num, mEp->dir);
@@ -1129,8 +1144,6 @@ static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
}
}
- dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL);
-
return (mReq == NULL) ? NULL : &mReq->req;
}
@@ -1158,8 +1171,6 @@ static void ep_free_request(struct usb_ep *ep, struct usb_request *req)
dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma);
kfree(mReq);
- dbg_event(_usb_addr(mEp), "FREE", 0);
-
spin_unlock_irqrestore(mEp->lock, flags);
}
@@ -1172,8 +1183,6 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
gfp_t __maybe_unused gfp_flags)
{
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
- struct ci13xxx *ci = mEp->ci;
int retval = 0;
unsigned long flags;
@@ -1181,48 +1190,7 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
return -EINVAL;
spin_lock_irqsave(mEp->lock, flags);
-
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
- if (req->length)
- mEp = (ci->ep0_dir == RX) ?
- ci->ep0out : ci->ep0in;
- if (!list_empty(&mEp->qh.queue)) {
- _ep_nuke(mEp);
- retval = -EOVERFLOW;
- dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n",
- _usb_addr(mEp));
- }
- }
-
- /* first nuke then test link, e.g. previous status has not sent */
- if (!list_empty(&mReq->queue)) {
- retval = -EBUSY;
- dev_err(mEp->ci->dev, "request already in queue\n");
- goto done;
- }
-
- if (req->length > 4 * CI13XXX_PAGE_SIZE) {
- req->length = 4 * CI13XXX_PAGE_SIZE;
- retval = -EMSGSIZE;
- dev_warn(mEp->ci->dev, "request length truncated\n");
- }
-
- dbg_queue(_usb_addr(mEp), req, retval);
-
- /* push request */
- mReq->req.status = -EINPROGRESS;
- mReq->req.actual = 0;
-
- retval = _hardware_enqueue(mEp, mReq);
-
- if (retval == -EALREADY) {
- dbg_event(_usb_addr(mEp), "QUEUE", retval);
- retval = 0;
- }
- if (!retval)
- list_add_tail(&mReq->queue, &mEp->qh.queue);
-
- done:
+ retval = _ep_queue(ep, req, gfp_flags);
spin_unlock_irqrestore(mEp->lock, flags);
return retval;
}
@@ -1245,8 +1213,6 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
spin_lock_irqsave(mEp->lock, flags);
- dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
-
hw_ep_flush(mEp->ci, mEp->num, mEp->dir);
/* pop request */
@@ -1293,7 +1259,6 @@ static int ep_set_halt(struct usb_ep *ep, int value)
direction = mEp->dir;
do {
- dbg_event(_usb_addr(mEp), "HALT", value);
retval |= hw_ep_set_halt(mEp->ci, mEp->num, mEp->dir, value);
if (!value)
@@ -1322,10 +1287,7 @@ static int ep_set_wedge(struct usb_ep *ep)
return -EINVAL;
spin_lock_irqsave(mEp->lock, flags);
-
- dbg_event(_usb_addr(mEp), "WEDGE", 0);
mEp->wedge = 1;
-
spin_unlock_irqrestore(mEp->lock, flags);
return usb_ep_set_halt(ep);
@@ -1348,7 +1310,6 @@ static void ep_fifo_flush(struct usb_ep *ep)
spin_lock_irqsave(mEp->lock, flags);
- dbg_event(_usb_addr(mEp), "FFLUSH", 0);
hw_ep_flush(mEp->ci, mEp->num, mEp->dir);
spin_unlock_irqrestore(mEp->lock, flags);
@@ -1392,7 +1353,6 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
if (is_active) {
pm_runtime_get_sync(&_gadget->dev);
hw_device_reset(ci, USBMODE_CM_DC);
- hw_enable_vbus_intr(ci);
hw_device_state(ci, ci->ep0out->qh.dma);
} else {
hw_device_state(ci, 0);
@@ -1567,10 +1527,8 @@ static int ci13xxx_start(struct usb_gadget *gadget,
pm_runtime_get_sync(&ci->gadget.dev);
if (ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) {
if (ci->vbus_active) {
- if (ci->platdata->flags & CI13XXX_REGS_SHARED) {
+ if (ci->platdata->flags & CI13XXX_REGS_SHARED)
hw_device_reset(ci, USBMODE_CM_DC);
- hw_enable_vbus_intr(ci);
- }
} else {
pm_runtime_put_sync(&ci->gadget.dev);
goto done;
@@ -1642,7 +1600,6 @@ static irqreturn_t udc_irq(struct ci13xxx *ci)
}
}
intr = hw_test_and_clear_intr_active(ci);
- dbg_interrupt(intr);
if (intr) {
/* order defines priority - do NOT change it */
@@ -1676,29 +1633,12 @@ static irqreturn_t udc_irq(struct ci13xxx *ci)
} else {
retval = IRQ_NONE;
}
-
- intr = hw_read(ci, OP_OTGSC, ~0);
- hw_write(ci, OP_OTGSC, ~0, intr);
-
- if (intr & (OTGSC_AVVIE & OTGSC_AVVIS))
- queue_work(ci->wq, &ci->vbus_work);
-
spin_unlock(&ci->lock);
return retval;
}
/**
- * udc_release: driver release function
- * @dev: device
- *
- * Currently does nothing
- */
-static void udc_release(struct device *dev)
-{
-}
-
-/**
* udc_start: initialize gadget role
* @ci: chipidea controller
*/
@@ -1717,12 +1657,6 @@ static int udc_start(struct ci13xxx *ci)
INIT_LIST_HEAD(&ci->gadget.ep_list);
- dev_set_name(&ci->gadget.dev, "gadget");
- ci->gadget.dev.dma_mask = dev->dma_mask;
- ci->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask;
- ci->gadget.dev.parent = dev;
- ci->gadget.dev.release = udc_release;
-
/* alloc resources */
ci->qh_pool = dma_pool_create("ci13xxx_qh", dev,
sizeof(struct ci13xxx_qh),
@@ -1758,24 +1692,13 @@ static int udc_start(struct ci13xxx *ci)
retval = hw_device_reset(ci, USBMODE_CM_DC);
if (retval)
goto put_transceiver;
- hw_enable_vbus_intr(ci);
- }
-
- retval = device_register(&ci->gadget.dev);
- if (retval) {
- put_device(&ci->gadget.dev);
- goto put_transceiver;
}
- retval = dbg_create_files(&ci->gadget.dev);
- if (retval)
- goto unreg_device;
-
if (!IS_ERR_OR_NULL(ci->transceiver)) {
retval = otg_set_peripheral(ci->transceiver->otg,
&ci->gadget);
if (retval)
- goto remove_dbg;
+ goto put_transceiver;
}
retval = usb_add_gadget_udc(dev, &ci->gadget);
@@ -1795,10 +1718,6 @@ remove_trans:
}
dev_err(dev, "error = %i\n", retval);
-remove_dbg:
- dbg_remove_files(&ci->gadget.dev);
-unreg_device:
- device_unregister(&ci->gadget.dev);
put_transceiver:
if (!IS_ERR_OR_NULL(ci->transceiver) && ci->global_phy)
usb_put_phy(ci->transceiver);
@@ -1821,9 +1740,6 @@ static void udc_stop(struct ci13xxx *ci)
if (ci == NULL)
return;
- hw_disable_vbus_intr(ci);
- cancel_work_sync(&ci->vbus_work);
-
usb_del_gadget_udc(&ci->gadget);
destroy_eps(ci);
@@ -1836,8 +1752,6 @@ static void udc_stop(struct ci13xxx *ci)
if (ci->global_phy)
usb_put_phy(ci->transceiver);
}
- dbg_remove_files(&ci->gadget.dev);
- device_unregister(&ci->gadget.dev);
/* my kobject is dynamic, I swear! */
memset(&ci->gadget, 0, sizeof(ci->gadget));
}
@@ -1864,7 +1778,6 @@ int ci_hdrc_gadget_init(struct ci13xxx *ci)
rdrv->irq = udc_irq;
rdrv->name = "gadget";
ci->roles[CI_ROLE_GADGET] = rdrv;
- INIT_WORK(&ci->vbus_work, vbus_work);
return 0;
}
diff --git a/drivers/usb/chipidea/udc.h b/drivers/usb/chipidea/udc.h
index 4ff2384d7ca..d12e8b59b11 100644
--- a/drivers/usb/chipidea/udc.h
+++ b/drivers/usb/chipidea/udc.h
@@ -40,7 +40,7 @@ struct ci13xxx_td {
#define TD_CURR_OFFSET (0x0FFFUL << 0)
#define TD_FRAME_NUM (0x07FFUL << 0)
#define TD_RESERVED_MASK (0x0FFFUL << 0)
-} __attribute__ ((packed));
+} __attribute__ ((packed, aligned(4)));
/* DMA layout of queue heads */
struct ci13xxx_qh {
@@ -57,7 +57,7 @@ struct ci13xxx_qh {
/* 9 */
u32 RESERVED;
struct usb_ctrlrequest setup;
-} __attribute__ ((packed));
+} __attribute__ ((packed, aligned(4)));
/**
* struct ci13xxx_req - usb request representation
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
new file mode 100644
index 00000000000..714a6bd810e
--- /dev/null
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include "ci13xxx_imx.h"
+
+#define USB_DEV_MAX 4
+
+#define MX25_USB_PHY_CTRL_OFFSET 0x08
+#define MX25_BM_EXTERNAL_VBUS_DIVIDER BIT(23)
+
+#define MX53_USB_OTG_PHY_CTRL_0_OFFSET 0x08
+#define MX53_USB_UH2_CTRL_OFFSET 0x14
+#define MX53_USB_UH3_CTRL_OFFSET 0x18
+#define MX53_BM_OVER_CUR_DIS_H1 BIT(5)
+#define MX53_BM_OVER_CUR_DIS_OTG BIT(8)
+#define MX53_BM_OVER_CUR_DIS_UHx BIT(30)
+
+#define MX6_BM_OVER_CUR_DIS BIT(7)
+
+struct imx_usbmisc {
+ void __iomem *base;
+ spinlock_t lock;
+ struct clk *clk;
+ struct usbmisc_usb_device usbdev[USB_DEV_MAX];
+ const struct usbmisc_ops *ops;
+};
+
+static struct imx_usbmisc *usbmisc;
+
+static struct usbmisc_usb_device *get_usbdev(struct device *dev)
+{
+ int i, ret;
+
+ for (i = 0; i < USB_DEV_MAX; i++) {
+ if (usbmisc->usbdev[i].dev == dev)
+ return &usbmisc->usbdev[i];
+ else if (!usbmisc->usbdev[i].dev)
+ break;
+ }
+
+ if (i >= USB_DEV_MAX)
+ return ERR_PTR(-EBUSY);
+
+ ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return &usbmisc->usbdev[i];
+}
+
+static int usbmisc_imx25_post(struct device *dev)
+{
+ struct usbmisc_usb_device *usbdev;
+ void __iomem *reg;
+ unsigned long flags;
+ u32 val;
+
+ usbdev = get_usbdev(dev);
+ if (IS_ERR(usbdev))
+ return PTR_ERR(usbdev);
+
+ reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
+
+ if (usbdev->evdo) {
+ spin_lock_irqsave(&usbmisc->lock, flags);
+ val = readl(reg);
+ writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg);
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+ usleep_range(5000, 10000); /* needed to stabilize voltage */
+ }
+
+ return 0;
+}
+
+static int usbmisc_imx53_init(struct device *dev)
+{
+ struct usbmisc_usb_device *usbdev;
+ void __iomem *reg = NULL;
+ unsigned long flags;
+ u32 val = 0;
+
+ usbdev = get_usbdev(dev);
+ if (IS_ERR(usbdev))
+ return PTR_ERR(usbdev);
+
+ if (usbdev->disable_oc) {
+ spin_lock_irqsave(&usbmisc->lock, flags);
+ switch (usbdev->index) {
+ case 0:
+ reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
+ val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG;
+ break;
+ case 1:
+ reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
+ val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1;
+ break;
+ case 2:
+ reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET;
+ val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
+ break;
+ case 3:
+ reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET;
+ val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
+ break;
+ }
+ if (reg && val)
+ writel(val, reg);
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+ }
+
+ return 0;
+}
+
+static int usbmisc_imx6q_init(struct device *dev)
+{
+
+ struct usbmisc_usb_device *usbdev;
+ unsigned long flags;
+ u32 reg;
+
+ usbdev = get_usbdev(dev);
+ if (IS_ERR(usbdev))
+ return PTR_ERR(usbdev);
+
+ if (usbdev->disable_oc) {
+ spin_lock_irqsave(&usbmisc->lock, flags);
+ reg = readl(usbmisc->base + usbdev->index * 4);
+ writel(reg | MX6_BM_OVER_CUR_DIS,
+ usbmisc->base + usbdev->index * 4);
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+ }
+
+ return 0;
+}
+
+static const struct usbmisc_ops imx25_usbmisc_ops = {
+ .post = usbmisc_imx25_post,
+};
+
+static const struct usbmisc_ops imx53_usbmisc_ops = {
+ .init = usbmisc_imx53_init,
+};
+
+static const struct usbmisc_ops imx6q_usbmisc_ops = {
+ .init = usbmisc_imx6q_init,
+};
+
+static const struct of_device_id usbmisc_imx_dt_ids[] = {
+ {
+ .compatible = "fsl,imx25-usbmisc",
+ .data = &imx25_usbmisc_ops,
+ },
+ {
+ .compatible = "fsl,imx53-usbmisc",
+ .data = &imx53_usbmisc_ops,
+ },
+ {
+ .compatible = "fsl,imx6q-usbmisc",
+ .data = &imx6q_usbmisc_ops,
+ },
+ { /* sentinel */ }
+};
+
+static int usbmisc_imx_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct imx_usbmisc *data;
+ int ret;
+ struct of_device_id *tmp_dev;
+
+ if (usbmisc)
+ return -EBUSY;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ spin_lock_init(&data->lock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(data->base))
+ return PTR_ERR(data->base);
+
+ data->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(data->clk)) {
+ dev_err(&pdev->dev,
+ "failed to get clock, err=%ld\n", PTR_ERR(data->clk));
+ return PTR_ERR(data->clk);
+ }
+
+ ret = clk_prepare_enable(data->clk);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "clk_prepare_enable failed, err=%d\n", ret);
+ return ret;
+ }
+
+ tmp_dev = (struct of_device_id *)
+ of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
+ data->ops = (const struct usbmisc_ops *)tmp_dev->data;
+ usbmisc = data;
+ ret = usbmisc_set_ops(data->ops);
+ if (ret) {
+ usbmisc = NULL;
+ clk_disable_unprepare(data->clk);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int usbmisc_imx_remove(struct platform_device *pdev)
+{
+ usbmisc_unset_ops(usbmisc->ops);
+ clk_disable_unprepare(usbmisc->clk);
+ usbmisc = NULL;
+ return 0;
+}
+
+static struct platform_driver usbmisc_imx_driver = {
+ .probe = usbmisc_imx_probe,
+ .remove = usbmisc_imx_remove,
+ .driver = {
+ .name = "usbmisc_imx",
+ .owner = THIS_MODULE,
+ .of_match_table = usbmisc_imx_dt_ids,
+ },
+};
+
+int usbmisc_imx_drv_init(void)
+{
+ return platform_driver_register(&usbmisc_imx_driver);
+}
+subsys_initcall(usbmisc_imx_drv_init);
+
+void usbmisc_imx_drv_exit(void)
+{
+ platform_driver_unregister(&usbmisc_imx_driver);
+}
+module_exit(usbmisc_imx_drv_exit);
+
+MODULE_ALIAS("platform:usbmisc-imx");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("driver for imx usb non-core registers");
+MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
diff --git a/drivers/usb/chipidea/usbmisc_imx6q.c b/drivers/usb/chipidea/usbmisc_imx6q.c
deleted file mode 100644
index a1bce391e82..00000000000
--- a/drivers/usb/chipidea/usbmisc_imx6q.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2012 Freescale Semiconductor, Inc.
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/module.h>
-#include <linux/of_platform.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/io.h>
-
-#include "ci13xxx_imx.h"
-
-#define USB_DEV_MAX 4
-
-#define BM_OVER_CUR_DIS BIT(7)
-
-struct imx6q_usbmisc {
- void __iomem *base;
- spinlock_t lock;
- struct clk *clk;
- struct usbmisc_usb_device usbdev[USB_DEV_MAX];
-};
-
-static struct imx6q_usbmisc *usbmisc;
-
-static struct usbmisc_usb_device *get_usbdev(struct device *dev)
-{
- int i, ret;
-
- for (i = 0; i < USB_DEV_MAX; i++) {
- if (usbmisc->usbdev[i].dev == dev)
- return &usbmisc->usbdev[i];
- else if (!usbmisc->usbdev[i].dev)
- break;
- }
-
- if (i >= USB_DEV_MAX)
- return ERR_PTR(-EBUSY);
-
- ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]);
- if (ret)
- return ERR_PTR(ret);
-
- return &usbmisc->usbdev[i];
-}
-
-static int usbmisc_imx6q_init(struct device *dev)
-{
-
- struct usbmisc_usb_device *usbdev;
- unsigned long flags;
- u32 reg;
-
- usbdev = get_usbdev(dev);
- if (IS_ERR(usbdev))
- return PTR_ERR(usbdev);
-
- if (usbdev->disable_oc) {
- spin_lock_irqsave(&usbmisc->lock, flags);
- reg = readl(usbmisc->base + usbdev->index * 4);
- writel(reg | BM_OVER_CUR_DIS,
- usbmisc->base + usbdev->index * 4);
- spin_unlock_irqrestore(&usbmisc->lock, flags);
- }
-
- return 0;
-}
-
-static const struct usbmisc_ops imx6q_usbmisc_ops = {
- .init = usbmisc_imx6q_init,
-};
-
-static const struct of_device_id usbmisc_imx6q_dt_ids[] = {
- { .compatible = "fsl,imx6q-usbmisc"},
- { /* sentinel */ }
-};
-
-static int usbmisc_imx6q_probe(struct platform_device *pdev)
-{
- struct resource *res;
- struct imx6q_usbmisc *data;
- int ret;
-
- if (usbmisc)
- return -EBUSY;
-
- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- spin_lock_init(&data->lock);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- data->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(data->base))
- return PTR_ERR(data->base);
-
- data->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(data->clk)) {
- dev_err(&pdev->dev,
- "failed to get clock, err=%ld\n", PTR_ERR(data->clk));
- return PTR_ERR(data->clk);
- }
-
- ret = clk_prepare_enable(data->clk);
- if (ret) {
- dev_err(&pdev->dev,
- "clk_prepare_enable failed, err=%d\n", ret);
- return ret;
- }
-
- ret = usbmisc_set_ops(&imx6q_usbmisc_ops);
- if (ret) {
- clk_disable_unprepare(data->clk);
- return ret;
- }
-
- usbmisc = data;
-
- return 0;
-}
-
-static int usbmisc_imx6q_remove(struct platform_device *pdev)
-{
- usbmisc_unset_ops(&imx6q_usbmisc_ops);
- clk_disable_unprepare(usbmisc->clk);
- return 0;
-}
-
-static struct platform_driver usbmisc_imx6q_driver = {
- .probe = usbmisc_imx6q_probe,
- .remove = usbmisc_imx6q_remove,
- .driver = {
- .name = "usbmisc_imx6q",
- .owner = THIS_MODULE,
- .of_match_table = usbmisc_imx6q_dt_ids,
- },
-};
-
-int __init usbmisc_imx6q_drv_init(void)
-{
- return platform_driver_register(&usbmisc_imx6q_driver);
-}
-subsys_initcall(usbmisc_imx6q_drv_init);
-
-void __exit usbmisc_imx6q_drv_exit(void)
-{
- platform_driver_unregister(&usbmisc_imx6q_driver);
-}
-module_exit(usbmisc_imx6q_drv_exit);
-
-MODULE_ALIAS("platform:usbmisc-imx6q");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("driver for imx6q usb non-core registers");
-MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");