--- zzzz-none-000/linux-2.6.39.4/drivers/usb/musb/musb_core.c 2011-08-03 19:43:28.000000000 +0000 +++ puma6-atom-6490-729/linux-2.6.39.4/drivers/usb/musb/musb_core.c 2021-11-10 13:38:17.000000000 +0000 @@ -104,7 +104,7 @@ #define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON) -unsigned musb_debug; +unsigned musb_debug = 0; module_param_named(debug, musb_debug, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug message level. Default = 0"); @@ -219,82 +219,118 @@ /* * Load an endpoint's FIFO */ -void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) +static void musb_fifo_io(u8 * fifo, u8 * buf, u16 len, char is_read) { - void __iomem *fifo = hw_ep->fifo; - - prefetch((u8 *)src); - - DBG(4, "%cX ep%d fifo %p count %d buf %p\n", - 'T', hw_ep->epnum, fifo, len, src); - - /* we can't assume unaligned reads work */ - if (likely((0x01 & (unsigned long) src) == 0)) { - u16 index = 0; - - /* best case is 32bit-aligned source address */ - if ((0x02 & (unsigned long) src) == 0) { - if (len >= 4) { - writesl(fifo, src + index, len >> 2); - index += len & ~0x03; - } - if (len & 0x02) { - musb_writew(fifo, 0, *(u16 *)&src[index]); - index += 2; - } - } else { - if (len >= 2) { - writesw(fifo, src + index, len >> 1); - index += len & ~0x01; - } - } - if (len & 0x01) - musb_writeb(fifo, 0, src[index]); - } else { - /* byte aligned */ - writesb(fifo, src, len); - } -} - -#if !defined(CONFIG_USB_MUSB_AM35X) -/* - * Unload an endpoint's FIFO - */ -void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) -{ - void __iomem *fifo = hw_ep->fifo; - - DBG(4, "%cX ep%d fifo %p count %d buf %p\n", - 'R', hw_ep->epnum, fifo, len, dst); - - /* we can't assume unaligned writes work */ - if (likely((0x01 & (unsigned long) dst) == 0)) { - u16 index = 0; - - /* best case is 32bit-aligned destination address */ - if ((0x02 & (unsigned long) dst) == 0) { - if (len >= 4) { - readsl(fifo, dst, len >> 2); - index = len & ~0x03; - } - if (len & 0x02) { - *(u16 *)&dst[index] = musb_readw(fifo, 0); - index += 2; - } - } else { - if (len >= 2) { - readsw(fifo, dst, len >> 1); - index = len & ~0x01; - } - } - if (len & 0x01) - dst[index] = musb_readb(fifo, 0); - } else { - /* byte aligned */ - readsb(fifo, dst, len); - } + u16 index = 0; + /* protection from infinite loop */ + if (len == 0) return; + + char size = ((unsigned long)buf & 0x04) ? 4 : + ((unsigned long)buf & 0x02) ? 2 : 1; +#ifndef CONFIG_CPU_LITTLE_ENDIAN + u32 *pTemp = (u32 *) buf; + u16 *pTmp16 = (u16 *) buf; +#endif + size = (len >= size) ? size : (len >= (size >> 1)) ? (size >> 1) : 1; + if (size == 1) { + if (is_read) + readsb(fifo, (void *__iomem)buf, len); + else + writesb(fifo, (void *__iomem)buf, len); + return; + } +#ifndef CONFIG_CPU_LITTLE_ENDIAN + while (len >= size) { + switch (size) { + case 4: + if (is_read) + *pTemp = cpu_to_le32(*(u32 *) fifo); + else + *(u32 *) fifo = cpu_to_le32(*pTemp); + pTemp++; + break; + case 2: + if (is_read) + *pTmp16 = cpu_to_le16(*(u16 *) fifo); + else + *(u16 *) fifo = cpu_to_le16(*pTmp16); + pTmp16++; + break; + } + len -= size; + index += size; + } +#else + switch (size) { + case 4: + if (is_read) + readsl(fifo, buf, len >> 2); + else + writesl(fifo, (void *__iomem)(buf), len >> 2); + index += len & ~0x03; + break; + case 2: + if (is_read) + readsw(fifo, buf, len >> 1); + else + writesw(fifo, (void *__iomem)(buf), len >> 1); + index += len & ~0x01; + break; + } +#endif + if (len & 0x02) { + if (is_read) + *(u16 *) & buf[index] = + cpu_to_le16(musb_readw(fifo, 0)); + else + musb_writew(fifo, 0, + cpu_to_le16(*(u16 *) & buf[index])); + index += 2; + } + if (len & 0x01) { + if (is_read) + buf[index] = musb_readb(fifo, 0); + else + musb_writeb(fifo, 0, buf[index]); + } +} +void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 wCount, const u8 * pSource) +{ + void __iomem *fifo = hw_ep->fifo; + prefetch((u8 *) pSource); + DBG(4, "%cX ep%d fifo %p count %d buf %p\n", + 'T', hw_ep->epnum, fifo, wCount, pSource); + /* we can't assume unaligned reads work */ + if (likely((0x01 & (unsigned long)pSource) == 0)) { + /* best case is 32bit-aligned source address */ + if ((0x02 & (unsigned long)pSource) == 0) { + musb_fifo_io(fifo, (u8 *) pSource, wCount, 0); + } else { + musb_fifo_io(fifo, (u8 *) pSource, wCount, 0); + } + } else { + musb_fifo_io(fifo, (u8 *) pSource, wCount, 0); + } +} + +void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 wCount, u8 * pDest) +{ + void __iomem *fifo = hw_ep->fifo; + DBG(4, "%cX ep%d fifo %p count %d buf %p\n", + 'R', hw_ep->epnum, fifo, wCount, pDest); + + /* we can't assume unaligned writes work */ + if (likely((0x01 & (unsigned long)pDest) == 0)) { + /* best case is 32bit-aligned destination address */ + if ((0x02 & (unsigned long)pDest) == 0) { + musb_fifo_io(fifo, pDest, wCount, 1); + } else { + musb_fifo_io(fifo, pDest, wCount, 1); + } + } else { + musb_fifo_io(fifo, pDest, wCount, 1); + } } -#endif #endif /* normal PIO */ @@ -1100,8 +1136,10 @@ { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, { .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, }, -{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, }, +{ .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 256, }, }; /* mode 3 - fits in 4KB */ @@ -1742,6 +1780,58 @@ } static DEVICE_ATTR(mode, 0644, musb_mode_show, musb_mode_store); +#ifdef CONFIG_PM +static int musb_resume(struct device *dev); +static int musb_suspend(struct device *dev); +extern puma5_usb_power_up(struct musb *); +extern puma5_usb_power_down(struct musb *); + +static ssize_t +musb_power_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct musb *musb = dev_to_musb(dev); + unsigned long flags; + unsigned int val; + spin_lock_irqsave(&musb->lock, flags); + val = musb->power_status; + spin_unlock_irqrestore(&musb->lock, flags); + return sprintf(buf, "%d\n", val); +} + +static ssize_t +musb_power_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + struct musb *musb = dev_to_musb(dev); + unsigned long flags; + unsigned short status = 1; + unsigned short val; + if (sscanf(buf, "%hu", &val) < 1) { + dev_err(dev, "Invalid power value\n"); + return -EINVAL; + } + + spin_lock_irqsave(&musb->lock, flags); + if (val == 3) { + musb->power_status = val; + musb_suspend(dev); + } else if (val == 0) { + musb->power_status = val; + musb_resume(dev); + } else { + status = 0; + } + spin_unlock_irqrestore(&musb->lock, flags); + if (status == 0) { + dev_err(dev, "Wrong power value\n"); + return -EINVAL; + } + + return n; +} +static DEVICE_ATTR(musbpower, 0644, musb_power_show, musb_power_store); +#endif + static ssize_t musb_vbus_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) @@ -1820,6 +1910,9 @@ #ifdef CONFIG_USB_GADGET_MUSB_HDRC &dev_attr_srp.attr, #endif +#ifdef CONFIG_PM + &dev_attr_musbpower.attr, +#endif NULL }; @@ -2173,6 +2266,7 @@ return -ENODEV; base = ioremap(iomem->start, resource_size(iomem)); + base = (void *)iomem->start; if (!base) { dev_err(dev, "ioremap failed\n"); return -ENOMEM; @@ -2357,19 +2451,82 @@ unsigned long flags; struct musb *musb = dev_to_musb(&pdev->dev); +#ifndef CONFIG_MACH_PUMA5 + if (!musb->clock) + return 0; +#endif + + musb_save_context(musb); + spin_lock_irqsave(&musb->lock, flags); if (is_peripheral_active(musb)) { /* FIXME force disconnect unless we know USB will wake * the system up quickly enough to respond ... */ +#ifdef CONFIG_MACH_PUMA5 + puma5_usb_power_down(musb); + printk("suspend: usb power down\n"); +#endif } else if (is_host_active(musb)) { +#ifdef CONFIG_MACH_PUMA5 + printk("host suspend: usb power down\n"); + musb_stop(musb); + mdelay(100); + puma5_usb_power_down(musb); +#endif /* we know all the children are suspended; sometimes * they will even be wakeup-enabled. */ } +#ifndef CONFIG_MACH_PUMA5 + if (musb->set_clock) + musb->set_clock(musb->clock, 0); + else + clk_disable(musb->clock); +#endif + spin_unlock_irqrestore(&musb->lock, flags); + return 0; +} + +static int musb_resume(struct device *dev) +{ + unsigned long flags; + struct platform_device *pdev = to_platform_device(dev); + struct musb *musb = dev_to_musb(&pdev->dev); + +#ifndef CONFIG_MACH_PUMA5 + if (!musb->clock) + return 0; +#endif + + spin_lock_irqsave(&musb->lock, flags); + +#ifndef CONFIG_MACH_PUMA5 + if (musb->set_clock) + musb->set_clock(musb->clock, 1); + else + clk_enable(musb->clock); +#endif + + /* for static cmos like DaVinci, register values were preserved + * unless for some reason the whole soc powered down and we're + * not treating that as a whole-system restart (e.g. swsusp) + */ + + if (is_peripheral_active(musb)) { +#ifdef CONFIG_MACH_PUMA5 + printk("resume: usb power up\n"); + puma5_usb_power_up(musb); +#endif + } else if (is_host_active(musb)) { +#ifdef CONFIG_MACH_PUMA5 + printk("host resume: usb power up\n"); + puma5_usb_power_up(musb); + musb_start(musb); +#endif + } - musb_save_context(musb); spin_unlock_irqrestore(&musb->lock, flags); return 0;