1 From fe3c05491370965eb821aedc95f771b86ebab3ab Mon Sep 17 00:00:00 2001
2 From: Dmitry Baryshkov <dbaryshkov@gmail.com>
3 Date: Wed, 9 Jan 2008 02:01:44 +0300
4 Subject: [PATCH 45/64] Update tmio_ohci:
6 Basic support for ohci suspend/resume.
8 Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
10 drivers/mfd/tc6393xb.c | 40 ++++++++
11 drivers/usb/host/ohci-tmio.c | 206 +++++++++++++++++++++++++++++++++++++++---
12 2 files changed, 235 insertions(+), 11 deletions(-)
14 diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
15 index 9439f39..5d17687 100644
16 --- a/drivers/mfd/tc6393xb.c
17 +++ b/drivers/mfd/tc6393xb.c
18 @@ -224,6 +224,44 @@ static int tc6393xb_ohci_enable(struct platform_device *ohci)
22 +static int tc6393xb_ohci_suspend(struct platform_device *ohci)
24 + struct platform_device *dev = to_platform_device(ohci->dev.parent);
25 + struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
26 + struct tc6393xb_scr __iomem *scr = tc6393xb->scr;
27 + union tc6393xb_scr_ccr ccr;
28 + unsigned long flags;
30 + spin_lock_irqsave(&tc6393xb->lock, flags);
32 + ccr.raw = ioread16(&scr->ccr);
33 + ccr.bits.usbcken = 0;
34 + iowrite16(ccr.raw, &scr->ccr);
36 + spin_unlock_irqrestore(&tc6393xb->lock, flags);
41 +static int tc6393xb_ohci_resume(struct platform_device *ohci)
43 + struct platform_device *dev = to_platform_device(ohci->dev.parent);
44 + struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
45 + struct tc6393xb_scr __iomem *scr = tc6393xb->scr;
46 + union tc6393xb_scr_ccr ccr;
47 + unsigned long flags;
49 + spin_lock_irqsave(&tc6393xb->lock, flags);
51 + ccr.raw = ioread16(&scr->ccr);
52 + ccr.bits.usbcken = 1;
53 + iowrite16(ccr.raw, &scr->ccr);
55 + spin_unlock_irqrestore(&tc6393xb->lock, flags);
60 static int tc6393xb_fb_disable(struct platform_device *fb)
62 struct platform_device *dev = to_platform_device(fb->dev.parent);
63 @@ -423,6 +461,8 @@ static struct mfd_cell tc6393xb_cells[] = {
65 .enable = tc6393xb_ohci_enable,
66 .disable = tc6393xb_ohci_disable,
67 + .suspend = tc6393xb_ohci_suspend,
68 + .resume = tc6393xb_ohci_resume,
69 .num_resources = ARRAY_SIZE(tc6393xb_ohci_resources),
70 .resources = tc6393xb_ohci_resources,
72 diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c
73 index be609f3..65e3cd3 100644
74 --- a/drivers/usb/host/ohci-tmio.c
75 +++ b/drivers/usb/host/ohci-tmio.c
76 @@ -75,10 +75,13 @@ struct tmio_uhccr {
78 } __attribute__((packed));
80 +#define MAX_TMIO_OHCI_PORTS 3
82 #define UHCCR_PM_GKEN 0x0001
83 #define UHCCR_PM_CKRNEN 0x0002
84 #define UHCCR_PM_USBPW1 0x0004
85 #define UHCCR_PM_USBPW2 0x0008
86 +#define UHCCR_PM_USBPW3 0x0008
87 #define UHCCR_PM_PMEE 0x0100
88 #define UHCCR_PM_PMES 0x8000
90 @@ -86,44 +89,96 @@ struct tmio_uhccr {
93 struct tmio_uhccr __iomem *ccr;
94 + spinlock_t lock; /* protects RMW cycles and disabled_ports data */
95 + bool disabled_ports[MAX_TMIO_OHCI_PORTS];
98 #define hcd_to_tmio(hcd) ((struct tmio_hcd *)(hcd_to_ohci(hcd) + 1))
99 #define ohci_to_tmio(ohci) ((struct tmio_hcd *)(ohci + 1))
101 +struct indexed_device_attribute{
102 + struct device_attribute dev_attr;
105 +#define to_indexed_dev_attr(_dev_attr) \
106 + container_of(_dev_attr, struct indexed_device_attribute, dev_attr)
108 +#define INDEXED_ATTR(_name, _mode, _show, _store, _index) \
109 + { .dev_attr = __ATTR(_name ## _index, _mode, _show, _store), \
112 +#define INDEXED_DEVICE_ATTR(_name, _mode, _show, _store, _index) \
113 +struct indexed_device_attribute dev_attr_##_name ## _index \
114 + = INDEXED_ATTR(_name, _mode, _show, _store, _index)
116 +static bool disabled_tmio_ports[MAX_TMIO_OHCI_PORTS];
117 +module_param_array(disabled_tmio_ports, bool, NULL, 0644);
118 +MODULE_PARM_DESC(disabled_tmio_ports,
119 + "disable specified TC6393 usb ports (default: all enabled)");
121 /*-------------------------------------------------------------------------*/
123 +static void tmio_write_pm(struct platform_device *dev)
125 + struct usb_hcd *hcd = platform_get_drvdata(dev);
126 + struct tmio_hcd *tmio = hcd_to_tmio(hcd);
127 + struct tmio_uhccr __iomem *ccr = tmio->ccr;
129 + unsigned long flags;
131 + spin_lock_irqsave(&tmio->lock, flags);
133 + pm = UHCCR_PM_GKEN | UHCCR_PM_CKRNEN |
134 + UHCCR_PM_PMEE | UHCCR_PM_PMES;
136 + if (tmio->disabled_ports[0])
137 + pm |= UHCCR_PM_USBPW1;
138 + if (tmio->disabled_ports[1])
139 + pm |= UHCCR_PM_USBPW2;
140 + if (tmio->disabled_ports[2])
141 + pm |= UHCCR_PM_USBPW3;
143 + iowrite16(pm, &ccr->pm);
144 + spin_unlock_irqrestore(&tmio->lock, flags);
147 static void tmio_stop_hc(struct platform_device *dev)
149 struct mfd_cell *cell = mfd_get_cell(dev);
150 struct usb_hcd *hcd = platform_get_drvdata(dev);
151 + struct ohci_hcd *ohci = hcd_to_ohci(hcd);
152 struct tmio_hcd *tmio = hcd_to_tmio(hcd);
153 struct tmio_uhccr __iomem *ccr = tmio->ccr;
156 - pm = UHCCR_PM_GKEN | UHCCR_PM_CKRNEN | UHCCR_PM_USBPW1 | UHCCR_PM_USBPW2;
157 + pm = UHCCR_PM_GKEN | UHCCR_PM_CKRNEN;
158 + switch (ohci->num_ports) {
160 + dev_err(&dev->dev, "Unsupported amount of ports: %d\n", ohci->num_ports);
162 + pm |= UHCCR_PM_USBPW3;
164 + pm |= UHCCR_PM_USBPW2;
166 + pm |= UHCCR_PM_USBPW1;
168 iowrite8(0, &ccr->intc);
169 iowrite8(0, &ccr->ilme);
170 iowrite16(0, &ccr->basel);
171 iowrite16(0, &ccr->baseh);
172 - iowrite16(pm, &ccr->pm);
173 + iowrite16(pm, &ccr->pm);
178 static void tmio_start_hc(struct platform_device *dev)
180 - struct mfd_cell *cell = mfd_get_cell(dev);
181 struct usb_hcd *hcd = platform_get_drvdata(dev);
182 struct tmio_hcd *tmio = hcd_to_tmio(hcd);
183 struct tmio_uhccr __iomem *ccr = tmio->ccr;
185 unsigned long base = hcd->rsrc_start;
187 - pm = UHCCR_PM_CKRNEN | UHCCR_PM_GKEN | UHCCR_PM_PMEE | UHCCR_PM_PMES;
190 - iowrite16(pm, &ccr->pm);
191 + tmio_write_pm(dev);
192 iowrite16(base, &ccr->basel);
193 iowrite16(base >> 16, &ccr->baseh);
194 iowrite8(1, &ccr->ilme);
195 @@ -133,9 +188,56 @@ static void tmio_start_hc(struct platform_device *dev)
196 ioread8(&ccr->revid), hcd->rsrc_start, hcd->irq);
199 +static ssize_t tmio_disabled_port_show(struct device *dev,
200 + struct device_attribute *attr,
203 + struct usb_hcd *hcd = dev_get_drvdata(dev);
204 + struct tmio_hcd *tmio = hcd_to_tmio(hcd);
205 + int index = to_indexed_dev_attr(attr)->index;
206 + return snprintf(buf, PAGE_SIZE, "%c",
207 + tmio->disabled_ports[index-1]? 'Y': 'N');
210 +static ssize_t tmio_disabled_port_store(struct device *dev,
211 + struct device_attribute *attr,
212 + const char *buf, size_t count)
214 + struct usb_hcd *hcd = dev_get_drvdata(dev);
215 + struct tmio_hcd *tmio = hcd_to_tmio(hcd);
216 + int index = to_indexed_dev_attr(attr)->index;
222 + case 'y': case 'Y': case '1':
223 + tmio->disabled_ports[index-1] = true;
225 + case 'n': case 'N': case '0':
226 + tmio->disabled_ports[index-1] = false;
232 + tmio_write_pm(to_platform_device(dev));
238 +static INDEXED_DEVICE_ATTR(disabled_usb_port, S_IRUGO | S_IWUSR,
239 + tmio_disabled_port_show, tmio_disabled_port_store, 1);
240 +static INDEXED_DEVICE_ATTR(disabled_usb_port, S_IRUGO | S_IWUSR,
241 + tmio_disabled_port_show, tmio_disabled_port_store, 2);
242 +static INDEXED_DEVICE_ATTR(disabled_usb_port, S_IRUGO | S_IWUSR,
243 + tmio_disabled_port_show, tmio_disabled_port_store, 3);
245 static int usb_hcd_tmio_probe(const struct hc_driver *driver,
246 struct platform_device *dev)
248 + struct mfd_cell *cell = mfd_get_cell(dev);
249 struct resource *config = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_CONFIG);
250 struct resource *regs = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_CONTROL);
251 struct resource *sram = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_SRAM);
252 @@ -159,6 +261,12 @@ static int usb_hcd_tmio_probe(const struct hc_driver *driver,
254 tmio = hcd_to_tmio(hcd);
256 + spin_lock_init(&tmio->lock);
258 + memcpy(tmio->disabled_ports,
259 + disabled_tmio_ports,
260 + sizeof(disabled_tmio_ports));
262 tmio->ccr = ioremap(config->start, config->end - config->start + 1);
265 @@ -183,17 +291,46 @@ static int usb_hcd_tmio_probe(const struct hc_driver *driver,
267 goto err_dmabounce_register_dev;
269 + retval = cell->enable(dev);
274 ohci = hcd_to_ohci(hcd);
277 retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
281 + switch (ohci->num_ports) {
283 + dev_err(&dev->dev, "Unsupported amount of ports: %d\n",
286 + retval |= device_create_file(&dev->dev,
287 + &dev_attr_disabled_usb_port3.dev_attr);
289 + retval |= device_create_file(&dev->dev,
290 + &dev_attr_disabled_usb_port2.dev_attr);
292 + retval |= device_create_file(&dev->dev,
293 + &dev_attr_disabled_usb_port1.dev_attr);
300 + device_remove_file(&dev->dev, &dev_attr_disabled_usb_port3.dev_attr);
301 + device_remove_file(&dev->dev, &dev_attr_disabled_usb_port2.dev_attr);
302 + device_remove_file(&dev->dev, &dev_attr_disabled_usb_port1.dev_attr);
304 + usb_remove_hcd(hcd);
308 + cell->disable(dev);
310 dmabounce_unregister_dev(&dev->dev);
311 err_dmabounce_register_dev:
312 dma_release_declared_memory(&dev->dev);
313 @@ -212,6 +349,9 @@ static void usb_hcd_tmio_remove(struct usb_hcd *hcd, struct platform_device *dev
315 struct tmio_hcd *tmio = hcd_to_tmio(hcd);
317 + device_remove_file(&dev->dev, &dev_attr_disabled_usb_port3.dev_attr);
318 + device_remove_file(&dev->dev, &dev_attr_disabled_usb_port2.dev_attr);
319 + device_remove_file(&dev->dev, &dev_attr_disabled_usb_port1.dev_attr);
322 dmabounce_unregister_dev(&dev->dev);
323 @@ -297,13 +437,22 @@ static u64 dma_mask = DMA_32BIT_MASK;
324 static int ohci_hcd_tmio_drv_probe(struct platform_device *dev)
326 struct resource *sram = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_SRAM);
329 dev->dev.dma_mask = &dma_mask;
330 dev->dev.coherent_dma_mask = DMA_32BIT_MASK;
332 + /* FIXME: move dmabounce checkers to tc6393xb core? */
333 dmabounce_register_checker(tmio_dmabounce_check, sram);
335 - return usb_hcd_tmio_probe(&ohci_tmio_hc_driver, dev);
336 + retval = usb_hcd_tmio_probe(&ohci_tmio_hc_driver, dev);
341 + dmabounce_remove_checker(tmio_dmabounce_check, sram);
346 static int ohci_hcd_tmio_drv_remove(struct platform_device *dev)
347 @@ -323,14 +472,31 @@ static int ohci_hcd_tmio_drv_remove(struct platform_device *dev)
349 static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t state)
351 + struct mfd_cell *cell = mfd_get_cell(dev);
352 struct usb_hcd *hcd = platform_get_drvdata(dev);
353 struct ohci_hcd *ohci = hcd_to_ohci(hcd);
354 + struct tmio_hcd *tmio = hcd_to_tmio(hcd);
355 + struct tmio_uhccr __iomem *ccr = tmio->ccr;
356 + unsigned long flags;
360 if (time_before(jiffies, ohci->next_statechange))
362 ohci->next_statechange = jiffies;
365 + spin_lock_irqsave(&tmio->lock, flags);
367 + misc = ioread8(&ccr->misc);
368 + misc |= 1 << 3; /* USSUSP */
369 + iowrite8(misc, &ccr->misc);
371 + spin_unlock_irqrestore(&tmio->lock, flags);
373 + ret = cell->suspend(dev);
377 hcd->state = HC_STATE_SUSPENDED;
378 dev->dev.power.power_state = PMSG_SUSPEND;
380 @@ -339,15 +505,33 @@ static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t s
382 static int ohci_hcd_tmio_drv_resume(struct platform_device *dev)
384 + struct mfd_cell *cell = mfd_get_cell(dev);
385 struct usb_hcd *hcd = platform_get_drvdata(dev);
386 struct ohci_hcd *ohci = hcd_to_ohci(hcd);
387 + struct tmio_hcd *tmio = hcd_to_tmio(hcd);
388 + struct tmio_uhccr __iomem *ccr = tmio->ccr;
389 + unsigned long flags;
393 if (time_before(jiffies, ohci->next_statechange))
395 ohci->next_statechange = jiffies;
397 + ret = cell->resume(dev);
403 + spin_lock_irqsave(&tmio->lock, flags);
405 + misc = ioread8(&ccr->misc);
406 + misc &= ~(1 << 3); /* USSUSP */
407 + iowrite8(misc, &ccr->misc);
409 + spin_unlock_irqrestore(&tmio->lock, flags);
411 dev->dev.power.power_state = PMSG_ON;
412 usb_hcd_resume_root_hub(hcd);