merge of '178eac00dc5aa8338d42e8e203633bec7817bbf6'
[vuplus_openembedded] / packages / linux / linux-rp-2.6.24 / tosa / 0045-Update-tmio_ohci.patch
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:
5  Ports management.
6  Basic support for ohci suspend/resume.
7
8 Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
9 ---
10  drivers/mfd/tc6393xb.c       |   40 ++++++++
11  drivers/usb/host/ohci-tmio.c |  206 +++++++++++++++++++++++++++++++++++++++---
12  2 files changed, 235 insertions(+), 11 deletions(-)
13
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)
19         return 0;
20  }
21  
22 +static int tc6393xb_ohci_suspend(struct platform_device *ohci)
23 +{
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;
29 +
30 +       spin_lock_irqsave(&tc6393xb->lock, flags);
31 +
32 +       ccr.raw = ioread16(&scr->ccr);
33 +       ccr.bits.usbcken = 0;
34 +       iowrite16(ccr.raw, &scr->ccr);
35 +
36 +       spin_unlock_irqrestore(&tc6393xb->lock, flags);
37 +
38 +       return 0;
39 +}
40 +
41 +static int tc6393xb_ohci_resume(struct platform_device *ohci)
42 +{
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;
48 +
49 +       spin_lock_irqsave(&tc6393xb->lock, flags);
50 +
51 +       ccr.raw = ioread16(&scr->ccr);
52 +       ccr.bits.usbcken = 1;
53 +       iowrite16(ccr.raw, &scr->ccr);
54 +
55 +       spin_unlock_irqrestore(&tc6393xb->lock, flags);
56 +
57 +       return 0;
58 +}
59 +
60  static int tc6393xb_fb_disable(struct platform_device *fb)
61  {
62         struct platform_device          *dev    = to_platform_device(fb->dev.parent);
63 @@ -423,6 +461,8 @@ static struct mfd_cell tc6393xb_cells[] = {
64                 .name = "tmio-ohci",
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,
71         },
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 {
77         u8 x07[3];
78  } __attribute__((packed));
79  
80 +#define MAX_TMIO_OHCI_PORTS    3
81 +
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
89  
90 @@ -86,44 +89,96 @@ struct tmio_uhccr {
91  
92  struct tmio_hcd {
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];
96  };
97  
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))
100  
101 +struct indexed_device_attribute{
102 +       struct device_attribute dev_attr;
103 +       int index;
104 +};
105 +#define to_indexed_dev_attr(_dev_attr) \
106 +       container_of(_dev_attr, struct indexed_device_attribute, dev_attr)
107 +
108 +#define INDEXED_ATTR(_name, _mode, _show, _store, _index)              \
109 +       { .dev_attr = __ATTR(_name ## _index, _mode, _show, _store),    \
110 +         .index = _index }
111 +
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)
115 +
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)");
120 +
121  /*-------------------------------------------------------------------------*/
122  
123 +static void tmio_write_pm(struct platform_device *dev)
124 +{
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;
128 +       u16                             pm;
129 +       unsigned long                   flags;
130 +
131 +       spin_lock_irqsave(&tmio->lock, flags);
132 +
133 +       pm = UHCCR_PM_GKEN | UHCCR_PM_CKRNEN |
134 +            UHCCR_PM_PMEE | UHCCR_PM_PMES;
135 +
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;
142 +
143 +       iowrite16(pm,           &ccr->pm);
144 +       spin_unlock_irqrestore(&tmio->lock, flags);
145 +}
146 +
147  static void tmio_stop_hc(struct platform_device *dev)
148  {
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;
154         u16                             pm;
155  
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) {
159 +               default:
160 +                       dev_err(&dev->dev, "Unsupported amount of ports: %d\n", ohci->num_ports);
161 +               case 3:
162 +                       pm |= UHCCR_PM_USBPW3;
163 +               case 2:
164 +                       pm |= UHCCR_PM_USBPW2;
165 +               case 1:
166 +                       pm |= UHCCR_PM_USBPW1;
167 +       }
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);
174  
175         cell->disable(dev);
176  }
177  
178  static void tmio_start_hc(struct platform_device *dev)
179  {
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;
184 -       u16                             pm;
185         unsigned long                   base    = hcd->rsrc_start;
186  
187 -       pm = UHCCR_PM_CKRNEN | UHCCR_PM_GKEN | UHCCR_PM_PMEE | UHCCR_PM_PMES;
188 -       cell->enable(dev);
189 -
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);
197  }
198  
199 +static ssize_t tmio_disabled_port_show(struct device *dev,
200 +               struct device_attribute *attr,
201 +               char *buf)
202 +{
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');
208 +}
209 +
210 +static ssize_t tmio_disabled_port_store(struct device *dev,
211 +               struct device_attribute *attr,
212 +               const char *buf, size_t count)
213 +{
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;
217 +
218 +       if (!count)
219 +               return -EINVAL;
220 +
221 +       switch (buf[0]) {
222 +       case 'y': case 'Y': case '1':
223 +               tmio->disabled_ports[index-1] = true;
224 +               break;
225 +       case 'n': case 'N': case '0':
226 +               tmio->disabled_ports[index-1] = false;
227 +               break;
228 +       default:
229 +               return -EINVAL;
230 +       }
231 +
232 +       tmio_write_pm(to_platform_device(dev));
233 +
234 +       return 1;
235 +}
236 +
237 +
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);
244 +
245  static int usb_hcd_tmio_probe(const struct hc_driver *driver,
246                 struct platform_device *dev)
247  {
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,
253  
254         tmio            = hcd_to_tmio(hcd);
255  
256 +       spin_lock_init(&tmio->lock);
257 +
258 +       memcpy(tmio->disabled_ports,
259 +                       disabled_tmio_ports,
260 +                       sizeof(disabled_tmio_ports));
261 +
262         tmio->ccr = ioremap(config->start, config->end - config->start + 1);
263         if (!tmio->ccr) {
264                 retval = -ENOMEM;
265 @@ -183,17 +291,46 @@ static int usb_hcd_tmio_probe(const struct hc_driver *driver,
266         if (retval)
267                 goto err_dmabounce_register_dev;
268  
269 +       retval = cell->enable(dev);
270 +       if (retval)
271 +               goto err_enable;
272 +
273         tmio_start_hc(dev);
274         ohci = hcd_to_ohci(hcd);
275         ohci_hcd_init(ohci);
276  
277         retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
278 +       if (retval)
279 +               goto err_add_hcd;
280 +
281 +       switch (ohci->num_ports) {
282 +               default:
283 +                       dev_err(&dev->dev, "Unsupported amount of ports: %d\n",
284 +                                       ohci->num_ports);
285 +               case 3:
286 +                       retval |= device_create_file(&dev->dev,
287 +                                       &dev_attr_disabled_usb_port3.dev_attr);
288 +               case 2:
289 +                       retval |= device_create_file(&dev->dev,
290 +                                       &dev_attr_disabled_usb_port2.dev_attr);
291 +               case 1:
292 +                       retval |= device_create_file(&dev->dev,
293 +                                       &dev_attr_disabled_usb_port1.dev_attr);
294 +       }
295  
296         if (retval == 0)
297                 return retval;
298  
299 -       tmio_stop_hc(dev);
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);
303 +
304 +       usb_remove_hcd(hcd);
305  
306 +err_add_hcd:
307 +       tmio_stop_hc(dev);
308 +       cell->disable(dev);
309 +err_enable:
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
314  {
315         struct tmio_hcd         *tmio   = hcd_to_tmio(hcd);
316  
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);
320         usb_remove_hcd(hcd);
321         tmio_stop_hc(dev);
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)
325  {
326         struct resource         *sram   = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_SRAM);
327 +       int retval;
328  
329         dev->dev.dma_mask = &dma_mask;
330         dev->dev.coherent_dma_mask = DMA_32BIT_MASK;
331  
332 +       /* FIXME: move dmabounce checkers to tc6393xb core? */
333         dmabounce_register_checker(tmio_dmabounce_check, sram);
334  
335 -       return usb_hcd_tmio_probe(&ohci_tmio_hc_driver, dev);
336 +       retval = usb_hcd_tmio_probe(&ohci_tmio_hc_driver, dev);
337 +
338 +       if (retval == 0)
339 +               return retval;
340 +
341 +       dmabounce_remove_checker(tmio_dmabounce_check, sram);
342 +
343 +       return retval;
344  }
345  
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)
348  #ifdef CONFIG_PM
349  static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t state)
350  {
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;
357 +       u8                      misc;
358 +       int                     ret;
359  
360         if (time_before(jiffies, ohci->next_statechange))
361                 msleep(5);
362         ohci->next_statechange = jiffies;
363  
364 -       tmio_stop_hc(dev);
365 +       spin_lock_irqsave(&tmio->lock, flags);
366 +
367 +       misc = ioread8(&ccr->misc);
368 +       misc |= 1 << 3; /* USSUSP */
369 +       iowrite8(misc, &ccr->misc);
370 +
371 +       spin_unlock_irqrestore(&tmio->lock, flags);
372 +
373 +       ret = cell->suspend(dev);
374 +       if (ret)
375 +               return ret;
376 +
377         hcd->state = HC_STATE_SUSPENDED;
378         dev->dev.power.power_state = PMSG_SUSPEND;
379  
380 @@ -339,15 +505,33 @@ static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t s
381  
382  static int ohci_hcd_tmio_drv_resume(struct platform_device *dev)
383  {
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;
390 +       u8                      misc;
391 +       int                     ret;
392  
393         if (time_before(jiffies, ohci->next_statechange))
394                 msleep(5);
395         ohci->next_statechange = jiffies;
396  
397 +       ret = cell->resume(dev);
398 +       if (ret)
399 +               return ret;
400 +
401         tmio_start_hc(dev);
402  
403 +       spin_lock_irqsave(&tmio->lock, flags);
404 +
405 +       misc = ioread8(&ccr->misc);
406 +       misc &= ~(1 << 3); /* USSUSP */
407 +       iowrite8(misc, &ccr->misc);
408 +
409 +       spin_unlock_irqrestore(&tmio->lock, flags);
410 +
411         dev->dev.power.power_state = PMSG_ON;
412         usb_hcd_resume_root_hub(hcd);
413  
414 -- 
415 1.5.3.8
416