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 | 878 | ||||
| -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, 598 insertions, 1148 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,801 +1,301 @@ -#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 - */ -static size_t hw_register_read(struct ci13xxx *ci, u32 *buf, size_t size) -{ -	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 + * ci_device_show: prints information about device capabilities and status   */ -static int hw_intr_clear(struct ci13xxx *ci, int n) +static int ci_device_show(struct seq_file *s, void *data)  { -	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__); -		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); +	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 : "")); -/** - * 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__); +	if (!ci->driver)  		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; +	return 0;  } -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) +static int ci_device_open(struct inode *inode, struct file *file)  { -	*idx = (*idx - 1) & (DBG_DATA_MAX-1); +	return single_open(file, ci_device_show, inode->i_private);  } -/** - * dbg_inc: increments debug event index - * @idx: buffer index - */ -static void dbg_inc(unsigned *idx) -{ -	*idx = (*idx + 1) & (DBG_DATA_MAX-1); -} +static const struct file_operations ci_device_fops = { +	.open		= ci_device_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= single_release, +};  /** - * dbg_print:  prints the common part of the event - * @addr:   endpoint address - * @name:   event name - * @status: status - * @extra:  extra information + * ci_port_test_show: reads port test mode   */ -static void dbg_print(u8 addr, const char *name, int status, const char *extra) +static int ci_port_test_show(struct seq_file *s, void *data)  { -	struct timeval tval; -	unsigned int stamp; +	struct ci13xxx *ci = s->private;  	unsigned long flags; +	unsigned mode; -	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); -	} -} +	spin_lock_irqsave(&ci->lock, flags); +	mode = hw_port_test_get(ci); +	spin_unlock_irqrestore(&ci->lock, flags); -/** - * 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]; +	seq_printf(s, "mode = %u\n", mode); -	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 + * ci_port_test_write: writes port test mode   */ -static ssize_t show_events(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 seq_file *s = file->private_data; +	struct ci13xxx *ci = s->private;  	unsigned long flags; -	unsigned i, j, n = 0; - -	if (attr == NULL || buf == NULL) { -		dev_err(dev->parent, "[%s] EINVAL\n", __func__); -		return 0; -	} +	unsigned mode; +	char buf[32]; +	int ret; -	read_lock_irqsave(&dbg_data.lck, flags); +	if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) +		return -EFAULT; -	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]); +	if (sscanf(buf, "%u", &mode) != 1) +		return -EINVAL; -	read_unlock_irqrestore(&dbg_data.lck, flags); +	spin_lock_irqsave(&ci->lock, flags); +	ret = hw_port_test_set(ci, mode); +	spin_unlock_irqrestore(&ci->lock, flags); -	return n; +	return ret ? ret : count;  } -/** - * 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) +static int ci_port_test_open(struct inode *inode, struct file *file)  { -	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; +	return single_open(file, ci_port_test_show, inode->i_private);  } -static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events); + +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_inters: interrupt status, enable status and historic - * - * Check "device.h" for details + * ci_qheads_show: DMA contents of all queue heads   */ -static ssize_t show_inters(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; -	u32 intr; -	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;  	}  	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"); +	for (i = 0; i < ci->hw_ep_max/2; i++) { +		struct ci13xxx_ep *mEpRx = &ci->ci13xxx_ep[i]; +		struct ci13xxx_ep *mEpTx = +			&ci->ci13xxx_ep[i + ci->hw_ep_max/2]; +		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;  } -/** - * 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) +static int ci_qheads_open(struct inode *inode, struct file *file)  { -	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; -	} - -	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 single_open(file, ci_qheads_show, inode->i_private);  } -static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters); + +static const struct file_operations ci_qheads_fops = { +	.open		= ci_qheads_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= single_release, +};  /** - * show_port_test: reads port test mode - * - * Check "device.h" for details + * ci_requests_show: DMA contents of all requests currently queued (all endpts)   */ -static ssize_t show_port_test(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; -	unsigned mode; +	struct list_head   *ptr = NULL; +	struct ci13xxx_req *req = NULL; +	unsigned i, j, qsize = sizeof(struct ci13xxx_td)/sizeof(u32); -	if (attr == NULL || buf == NULL) { -		dev_err(ci->dev, "EINVAL\n"); +	if (ci->role != CI_ROLE_GADGET) { +		seq_printf(s, "not in gadget mode\n");  		return 0;  	}  	spin_lock_irqsave(&ci->lock, flags); -	mode = hw_port_test_get(ci); -	spin_unlock_irqrestore(&ci->lock, flags); - -	return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode); -} - -/** - * 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) -{ -	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); -	unsigned long flags; -	unsigned mode; +	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 (attr == NULL || buf == NULL) { -		dev_err(ci->dev, "[%s] EINVAL\n", __func__); -		goto done; -	} +			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")); -	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"); +			for (j = 0; j < qsize; j++) +				seq_printf(s, " %04X:    %08X\n", j, +					   *((u32 *)req->ptr + j)); +		}  	spin_unlock_irqrestore(&ci->lock, flags); - done: -	return count; +	return 0;  } -static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR, -		   show_port_test, store_port_test); -/** - * show_qheads: DMA contents of all queue heads - * - * Check "device.h" for details - */ -static ssize_t show_qheads(struct device *dev, struct device_attribute *attr, -			   char *buf) +static int ci_requests_open(struct inode *inode, struct file *file)  { -	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); -	unsigned long flags; -	unsigned i, j, n = 0; +	return single_open(file, ci_requests_show, inode->i_private); +} -	if (attr == NULL || buf == NULL) { -		dev_err(ci->dev, "[%s] EINVAL\n", __func__); -		return 0; -	} +static const struct file_operations ci_requests_fops = { +	.open		= ci_requests_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= single_release, +}; -	spin_lock_irqsave(&ci->lock, flags); -	for (i = 0; i < ci->hw_ep_max/2; i++) { -		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)); -		} -	} -	spin_unlock_irqrestore(&ci->lock, flags); +static int ci_role_show(struct seq_file *s, void *data) +{ +	struct ci13xxx *ci = s->private; -	return n; +	seq_printf(s, "%s\n", ci_role(ci)->name); + +	return 0;  } -static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL); -/** - * show_registers: dumps all registers - * - * Check "device.h" for details - */ -#define DUMP_ENTRIES	512 -static ssize_t show_registers(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; -	u32 *dump; -	unsigned i, k, n = 0; +	struct seq_file *s = file->private_data; +	struct ci13xxx *ci = s->private; +	enum ci_role role; +	char buf[8]; +	int ret; -	if (attr == NULL || buf == NULL) { -		dev_err(ci->dev, "[%s] EINVAL\n", __func__); -		return 0; -	} +	if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) +		return -EFAULT; -	dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL); -	if (!dump) { -		dev_err(ci->dev, "%s: out of memory\n", __func__); -		return 0; -	} +	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); -	k = hw_register_read(ci, dump, DUMP_ENTRIES); -	spin_unlock_irqrestore(&ci->lock, flags); +	if (role == CI_ROLE_END || role == ci->role) +		return -EINVAL; -	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); +	ci_role_stop(ci); +	ret = ci_role_start(ci, role); -	return n; +	return ret ? ret : count;  } -/** - * 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_role_open(struct inode *inode, struct file *file)  { -	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); -	unsigned long addr, data, flags; - -	if (attr == NULL || buf == NULL) { -		dev_err(ci->dev, "[%s] EINVAL\n", __func__); -		goto done; -	} - -	if (sscanf(buf, "%li %li", &addr, &data) != 2) { -		dev_err(ci->dev, -			"<addr> <data>: write data to register address\n"); -		goto done; -	} - -	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); - - done: -	return count; +	return single_open(file, ci_role_show, inode->i_private);  } -static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR, -		   show_registers, store_registers); + +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, +};  /** - * show_requests: DMA contents of all requests currently queued (all endpts) + * dbg_create_files: initializes the attribute interface + * @ci: device   * - * Check "device.h" for details + * This function returns an error code   */ -static ssize_t show_requests(struct device *dev, struct device_attribute *attr, -			     char *buf) +int dbg_create_files(struct ci13xxx *ci)  { -	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); +	struct dentry *dent; -	if (attr == NULL || buf == NULL) { -		dev_err(ci->dev, "[%s] EINVAL\n", __func__); -		return 0; -	} +	ci->debugfs = debugfs_create_dir(dev_name(ci->dev), NULL); +	if (!ci->debugfs) +		return -ENOMEM; -	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); +	dent = debugfs_create_file("device", S_IRUGO, ci->debugfs, ci, +				   &ci_device_fops); +	if (!dent) +		goto err; -			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")); +	dent = debugfs_create_file("port_test", S_IRUGO | S_IWUSR, ci->debugfs, +				   ci, &ci_port_test_fops); +	if (!dent) +		goto err; -			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); +	dent = debugfs_create_file("qheads", S_IRUGO, ci->debugfs, ci, +				   &ci_qheads_fops); +	if (!dent) +		goto err; -	return n; -} -static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL); +	dent = debugfs_create_file("requests", S_IRUGO, ci->debugfs, ci, +				   &ci_requests_fops); +	if (!dent) +		goto err; -/** - * dbg_create_files: initializes the attribute interface - * @dev: device - * - * This function returns an error code - */ -int dbg_create_files(struct device *dev) -{ -	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; +	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 f64fbea1cf2..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->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->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->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>");  |