diff options
Diffstat (limited to 'drivers/usb/chipidea')
-rw-r--r-- | drivers/usb/chipidea/Makefile | 2 | ||||
-rw-r--r-- | drivers/usb/chipidea/ci.h | 19 | ||||
-rw-r--r-- | drivers/usb/chipidea/ci13xxx_imx.c | 12 | ||||
-rw-r--r-- | drivers/usb/chipidea/ci13xxx_imx.h | 3 | ||||
-rw-r--r-- | drivers/usb/chipidea/ci13xxx_pci.c | 6 | ||||
-rw-r--r-- | drivers/usb/chipidea/core.c | 66 | ||||
-rw-r--r-- | drivers/usb/chipidea/debug.c | 888 | ||||
-rw-r--r-- | drivers/usb/chipidea/debug.h | 34 | ||||
-rw-r--r-- | drivers/usb/chipidea/udc.c | 299 | ||||
-rw-r--r-- | drivers/usb/chipidea/udc.h | 4 | ||||
-rw-r--r-- | drivers/usb/chipidea/usbmisc_imx.c | 261 | ||||
-rw-r--r-- | drivers/usb/chipidea/usbmisc_imx6q.c | 162 |
12 files changed, 603 insertions, 1153 deletions
diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index d92ca325b104..4ab83e98219b 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 e25d1263da13..b0a6bce064ca 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 8c291220be7f..8faec9dbbb84 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 9cd2e910b1ca..550bfa457620 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 9b227e39299a..4e1fc61b9d95 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 57cae1f897b2..450107e5f657 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 a62c4a47d52c..36a7063a6cba 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 80d96865775c..7ca6ca0a24a5 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 2f45bba8561d..519ead2443c5 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 4ff2384d7ca8..d12e8b59b110 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 000000000000..714a6bd810ed --- /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 a1bce391e825..000000000000 --- 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>"); |