Merge commit 'main-jb-2012.08.03-B4' into t114-0806
[linux-2.6.git] / arch / arm / mach-tegra / tegra_usb_modem_power.c
1 /*
2  * arch/arm/mach-tegra/tegra_usb_modem_power.c
3  *
4  * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20
21 #include <linux/module.h>
22 #include <linux/init.h>
23 #include <linux/interrupt.h>
24 #include <linux/platform_device.h>
25 #include <linux/platform_data/tegra_usb.h>
26 #include <linux/workqueue.h>
27 #include <linux/gpio.h>
28 #include <linux/usb.h>
29 #include <linux/err.h>
30 #include <linux/pm_runtime.h>
31 #include <linux/suspend.h>
32 #include <linux/slab.h>
33 #include <linux/wakelock.h>
34 #include <linux/pm_qos.h>
35 #include <mach/gpio-tegra.h>
36 #include <mach/tegra_usb_modem_power.h>
37
38 #define BOOST_CPU_FREQ_MIN      1200000
39 #define BOOST_CPU_FREQ_TIMEOUT  5000
40
41 #define WAKELOCK_TIMEOUT_FOR_USB_ENUM           (HZ * 10)
42 #define WAKELOCK_TIMEOUT_FOR_REMOTE_WAKE        (HZ)
43
44 struct tegra_usb_modem {
45         struct tegra_usb_modem_power_platform_data *pdata;
46         unsigned int wake_cnt;  /* remote wakeup counter */
47         unsigned int wake_irq;  /* remote wakeup irq */
48         unsigned int boot_irq;  /* modem boot irq */
49         struct mutex lock;
50         struct wake_lock wake_lock;     /* modem wake lock */
51         unsigned int vid;       /* modem vendor id */
52         unsigned int pid;       /* modem product id */
53         struct usb_device *udev;        /* modem usb device */
54         struct usb_device *parent;      /* parent device */
55         struct usb_interface *intf;     /* first modem usb interface */
56         struct workqueue_struct *wq;    /* modem workqueue */
57         struct delayed_work recovery_work;      /* modem recovery work */
58         struct pm_qos_request cpu_boost_req; /* min CPU freq request */
59         struct work_struct cpu_boost_work;      /* CPU freq boost work */
60         struct delayed_work cpu_unboost_work;   /* CPU freq unboost work */
61         const struct tegra_modem_operations *ops;       /* modem operations */
62         unsigned int capability;        /* modem capability */
63         int system_suspend;     /* system suspend flag */
64         struct notifier_block pm_notifier;      /* pm event notifier */
65         struct notifier_block usb_notifier;     /* usb event notifier */
66         int sysfs_file_created;
67         int short_autosuspend_enabled;
68 };
69
70 static struct platform_device *hc = NULL;       /* USB host controller */
71 static struct mutex hc_lock;
72 static const struct platform_device *hc_device;
73 static const struct tegra_usb_platform_data *hc_pdata;
74
75 /* supported modems */
76 static const struct usb_device_id modem_list[] = {
77         {USB_DEVICE(0x1983, 0x0310),    /* Icera 450 rev1 */
78          .driver_info = TEGRA_MODEM_AUTOSUSPEND,
79          },
80         {USB_DEVICE(0x1983, 0x0321),    /* Icera 450 rev2 */
81          .driver_info = TEGRA_MODEM_AUTOSUSPEND,
82          },
83         {USB_DEVICE(0x1983, 0x0327),    /* Icera 450 5AE */
84          .driver_info = TEGRA_MODEM_AUTOSUSPEND,
85          },
86         {}
87 };
88
89 static void cpu_freq_unboost(struct work_struct *ws)
90 {
91         struct tegra_usb_modem *modem = container_of(ws, struct tegra_usb_modem,
92                                                      cpu_unboost_work.work);
93
94         pm_qos_update_request(&modem->cpu_boost_req, PM_QOS_DEFAULT_VALUE);
95 }
96
97 static void cpu_freq_boost(struct work_struct *ws)
98 {
99         struct tegra_usb_modem *modem = container_of(ws, struct tegra_usb_modem,
100                                                      cpu_boost_work);
101
102         cancel_delayed_work_sync(&modem->cpu_unboost_work);
103         pm_qos_update_request(&modem->cpu_boost_req, BOOST_CPU_FREQ_MIN);
104         queue_delayed_work(modem->wq, &modem->cpu_unboost_work,
105                               msecs_to_jiffies(BOOST_CPU_FREQ_TIMEOUT));
106 }
107
108 static irqreturn_t tegra_usb_modem_wake_thread(int irq, void *data)
109 {
110         struct tegra_usb_modem *modem = (struct tegra_usb_modem *)data;
111
112         mutex_lock(&modem->lock);
113         if (modem->udev && modem->udev->state != USB_STATE_NOTATTACHED) {
114                 pr_info("modem wake (%u)\n", ++(modem->wake_cnt));
115
116                 if (!modem->system_suspend) {
117                         wake_lock_timeout(&modem->wake_lock,
118                                           WAKELOCK_TIMEOUT_FOR_REMOTE_WAKE);
119
120                         usb_lock_device(modem->udev);
121                         if (usb_autopm_get_interface(modem->intf) == 0)
122                                 usb_autopm_put_interface_async(modem->intf);
123                         usb_unlock_device(modem->udev);
124                 }
125 #ifdef CONFIG_PM
126                 if (modem->capability & TEGRA_MODEM_AUTOSUSPEND &&
127                     modem->short_autosuspend_enabled) {
128                         pm_runtime_set_autosuspend_delay(&modem->udev->dev,
129                                         modem->pdata->autosuspend_delay);
130                         modem->short_autosuspend_enabled = 0;
131                 }
132 #endif
133         }
134         mutex_unlock(&modem->lock);
135
136         return IRQ_HANDLED;
137 }
138
139 static irqreturn_t tegra_usb_modem_boot_thread(int irq, void *data)
140 {
141         struct tegra_usb_modem *modem = (struct tegra_usb_modem *)data;
142
143         if (gpio_get_value(modem->pdata->boot_gpio))
144                 pr_info("BB_RST_OUT high\n");
145         else
146                 pr_info("BB_RST_OUT low\n");
147
148         /* hold wait lock to complete the enumeration */
149         wake_lock_timeout(&modem->wake_lock, WAKELOCK_TIMEOUT_FOR_USB_ENUM);
150
151         /* boost CPU freq */
152         if (!work_pending(&modem->cpu_boost_work))
153                 queue_work(modem->wq, &modem->cpu_boost_work);
154
155         /* USB disconnect maybe on going... */
156         mutex_lock(&modem->lock);
157         if (modem->udev && modem->udev->state != USB_STATE_NOTATTACHED)
158                 pr_warn("Device is not disconnected!\n");
159         mutex_unlock(&modem->lock);
160
161         return IRQ_HANDLED;
162 }
163
164 static void tegra_usb_modem_recovery(struct work_struct *ws)
165 {
166         struct tegra_usb_modem *modem = container_of(ws, struct tegra_usb_modem,
167                                                      recovery_work.work);
168
169         mutex_lock(&modem->lock);
170         if (!modem->udev) {     /* assume modem crashed */
171                 if (modem->ops && modem->ops->reset)
172                         modem->ops->reset();
173         }
174         mutex_unlock(&modem->lock);
175 }
176
177 static void device_add_handler(struct tegra_usb_modem *modem,
178                                struct usb_device *udev)
179 {
180         const struct usb_device_descriptor *desc = &udev->descriptor;
181         struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
182         const struct usb_device_id *id = usb_match_id(intf, modem_list);
183
184         if (id) {
185                 /* hold wakelock to ensure ril has enough time to restart */
186                 wake_lock_timeout(&modem->wake_lock,
187                                   WAKELOCK_TIMEOUT_FOR_USB_ENUM);
188
189                 pr_info("Add device %d <%s %s>\n", udev->devnum,
190                         udev->manufacturer, udev->product);
191
192                 mutex_lock(&modem->lock);
193                 modem->udev = udev;
194                 modem->parent = udev->parent;
195                 modem->intf = intf;
196                 modem->vid = desc->idVendor;
197                 modem->pid = desc->idProduct;
198                 modem->wake_cnt = 0;
199                 modem->capability = id->driver_info;
200                 mutex_unlock(&modem->lock);
201
202                 pr_info("persist_enabled: %u\n", udev->persist_enabled);
203
204 #ifdef CONFIG_PM
205                 if (modem->capability & TEGRA_MODEM_AUTOSUSPEND) {
206                         pm_runtime_set_autosuspend_delay(&udev->dev,
207                                         modem->pdata->autosuspend_delay);
208                         modem->short_autosuspend_enabled = 0;
209                         usb_enable_autosuspend(udev);
210                         pr_info("enable autosuspend for %s %s\n",
211                                 udev->manufacturer, udev->product);
212                 }
213 #endif
214         }
215 }
216
217 static void device_remove_handler(struct tegra_usb_modem *modem,
218                                   struct usb_device *udev)
219 {
220         const struct usb_device_descriptor *desc = &udev->descriptor;
221
222         if (desc->idVendor == modem->vid && desc->idProduct == modem->pid) {
223                 pr_info("Remove device %d <%s %s>\n", udev->devnum,
224                         udev->manufacturer, udev->product);
225
226                 mutex_lock(&modem->lock);
227                 modem->udev = NULL;
228                 modem->intf = NULL;
229                 modem->vid = 0;
230                 mutex_unlock(&modem->lock);
231
232                 if (modem->capability & TEGRA_MODEM_RECOVERY)
233                         queue_delayed_work(modem->wq,
234                                            &modem->recovery_work, HZ * 10);
235         }
236 }
237
238 static int mdm_usb_notifier(struct notifier_block *notifier,
239                             unsigned long usb_event, void *udev)
240 {
241         struct tegra_usb_modem *modem =
242             container_of(notifier, struct tegra_usb_modem, usb_notifier);
243
244         switch (usb_event) {
245         case USB_DEVICE_ADD:
246                 device_add_handler(modem, udev);
247                 break;
248         case USB_DEVICE_REMOVE:
249                 device_remove_handler(modem, udev);
250                 break;
251         }
252         return NOTIFY_OK;
253 }
254
255 static int mdm_pm_notifier(struct notifier_block *notifier,
256                            unsigned long pm_event, void *unused)
257 {
258         struct tegra_usb_modem *modem =
259             container_of(notifier, struct tegra_usb_modem, pm_notifier);
260
261         mutex_lock(&modem->lock);
262         if (!modem->udev) {
263                 mutex_unlock(&modem->lock);
264                 return NOTIFY_DONE;
265         }
266
267         pr_info("%s: event %ld\n", __func__, pm_event);
268         switch (pm_event) {
269         case PM_SUSPEND_PREPARE:
270                 if (wake_lock_active(&modem->wake_lock)) {
271                         pr_warn("%s: wakelock was active, aborting suspend\n",
272                                 __func__);
273                         mutex_unlock(&modem->lock);
274                         return NOTIFY_STOP;
275                 }
276
277                 modem->system_suspend = 1;
278 #ifdef CONFIG_PM
279                 if (modem->capability & TEGRA_MODEM_AUTOSUSPEND &&
280                     modem->udev &&
281                     modem->udev->state != USB_STATE_NOTATTACHED) {
282                         pm_runtime_set_autosuspend_delay(&modem->udev->dev,
283                                         modem->pdata->short_autosuspend_delay);
284                         modem->short_autosuspend_enabled = 1;
285                 }
286 #endif
287                 mutex_unlock(&modem->lock);
288                 return NOTIFY_OK;
289         case PM_POST_SUSPEND:
290                 modem->system_suspend = 0;
291                 mutex_unlock(&modem->lock);
292                 return NOTIFY_OK;
293         }
294
295         mutex_unlock(&modem->lock);
296         return NOTIFY_DONE;
297 }
298
299 static int mdm_request_wakeable_irq(struct tegra_usb_modem *modem,
300                                     irq_handler_t thread_fn,
301                                     unsigned int irq_gpio,
302                                     unsigned long irq_flags,
303                                     const char *label, unsigned int *irq)
304 {
305         int ret;
306
307         ret = gpio_request(irq_gpio, label);
308         if (ret)
309                 return ret;
310
311         /* enable IRQ for GPIO */
312         *irq = gpio_to_irq(irq_gpio);
313
314         /* request threaded irq for GPIO */
315         ret = request_threaded_irq(*irq, NULL, thread_fn, irq_flags, label,
316                                    modem);
317         if (ret)
318                 return ret;
319
320         ret = enable_irq_wake(*irq);
321         if (ret) {
322                 free_irq(*irq, modem);
323                 return ret;
324         }
325
326         return ret;
327 }
328
329 /* load USB host controller */
330 static struct platform_device *tegra_usb_null_ulpi_host_register(void)
331 {
332         struct platform_device *pdev;
333         int val;
334
335         pdev = platform_device_alloc(hc_device->name, hc_device->id);
336         if (!pdev)
337                 return NULL;
338
339         val = platform_device_add_resources(pdev, hc_device->resource,
340                                             hc_device->num_resources);
341         if (val)
342                 goto error;
343
344         pdev->dev.dma_mask = hc_device->dev.dma_mask;
345         pdev->dev.coherent_dma_mask = hc_device->dev.coherent_dma_mask;
346
347         val = platform_device_add_data(pdev, hc_pdata,
348                                        sizeof(struct tegra_usb_platform_data));
349         if (val)
350                 goto error;
351
352         val = platform_device_add(pdev);
353         if (val)
354                 goto error;
355
356         return pdev;
357
358 error:
359         pr_err("%s: err %d\n", __func__, val);
360         platform_device_put(pdev);
361         return NULL;
362 }
363
364 /* unload USB host controller */
365 static void tegra_usb_null_ulpi_host_unregister(struct platform_device *pdev)
366 {
367         platform_device_unregister(pdev);
368 }
369
370 static ssize_t show_usb_host(struct device *dev,
371                              struct device_attribute *attr, char *buf)
372 {
373         return sprintf(buf, "%d\n", (hc) ? 1 : 0);
374 }
375
376 static ssize_t load_unload_usb_host(struct device *dev,
377                                     struct device_attribute *attr,
378                                     const char *buf, size_t count)
379 {
380         int host;
381
382         if (sscanf(buf, "%d", &host) != 1 || host < 0 || host > 1)
383                 return -EINVAL;
384
385         pr_info("%s USB host\n", (host) ? "load" : "unload");
386
387         mutex_lock(&hc_lock);
388         if (host) {
389                 if (!hc)
390                         hc = tegra_usb_null_ulpi_host_register();
391         } else {
392                 if (hc) {
393                         tegra_usb_null_ulpi_host_unregister(hc);
394                         hc = NULL;
395                 }
396         }
397         mutex_unlock(&hc_lock);
398
399         return count;
400 }
401
402 static DEVICE_ATTR(load_host, S_IRUSR | S_IWUSR, show_usb_host,
403                    load_unload_usb_host);
404
405 static int mdm_init(struct tegra_usb_modem *modem, struct platform_device *pdev)
406 {
407         struct tegra_usb_modem_power_platform_data *pdata =
408             pdev->dev.platform_data;
409         int ret = 0;
410
411         modem->pdata = pdata;
412
413         hc_device = pdata->tegra_ehci_device;
414         hc_pdata = pdata->tegra_ehci_pdata;
415         mutex_init(&hc_lock);
416
417         /* get modem operations from platform data */
418         modem->ops = (const struct tegra_modem_operations *)pdata->ops;
419
420         if (modem->ops) {
421                 /* modem init */
422                 if (modem->ops->init) {
423                         ret = modem->ops->init();
424                         if (ret)
425                                 return ret;
426                 }
427
428                 /* start modem */
429                 if (modem->ops->start)
430                         modem->ops->start();
431         }
432
433         /* create sysfs node to load/unload host controller */
434         ret = device_create_file(&pdev->dev, &dev_attr_load_host);
435         if (ret) {
436                 dev_err(&pdev->dev, "can't create sysfs file\n");
437                 goto error;
438         }
439         modem->sysfs_file_created = 1;
440
441         mutex_init(&(modem->lock));
442         wake_lock_init(&modem->wake_lock, WAKE_LOCK_SUSPEND, "mdm_lock");
443
444         /* create work queue platform_driver_registe */
445         modem->wq = create_workqueue("tegra_usb_mdm_queue");
446         INIT_DELAYED_WORK(&modem->recovery_work, tegra_usb_modem_recovery);
447
448         INIT_WORK(&modem->cpu_boost_work, cpu_freq_boost);
449         INIT_DELAYED_WORK(&modem->cpu_unboost_work, cpu_freq_unboost);
450
451         pm_qos_add_request(&modem->cpu_boost_req, PM_QOS_CPU_FREQ_MIN,
452                            PM_QOS_DEFAULT_VALUE);
453
454         /* request remote wakeup irq from platform data */
455         ret = mdm_request_wakeable_irq(modem,
456                                        tegra_usb_modem_wake_thread,
457                                        pdata->wake_gpio,
458                                        pdata->wake_irq_flags,
459                                        "mdm_wake", &modem->wake_irq);
460         if (ret) {
461                 dev_err(&pdev->dev, "request wake irq error\n");
462                 goto error;
463         }
464
465         /* request boot irq from platform data */
466         ret = mdm_request_wakeable_irq(modem,
467                                        tegra_usb_modem_boot_thread,
468                                        pdata->boot_gpio,
469                                        pdata->boot_irq_flags,
470                                        "mdm_boot", &modem->boot_irq);
471         if (ret) {
472                 dev_err(&pdev->dev, "request boot irq error\n");
473                 goto error;
474         }
475
476         modem->pm_notifier.notifier_call = mdm_pm_notifier;
477         modem->usb_notifier.notifier_call = mdm_usb_notifier;
478
479         usb_register_notify(&modem->usb_notifier);
480         register_pm_notifier(&modem->pm_notifier);
481
482         return ret;
483 error:
484         if (modem->sysfs_file_created)
485                 device_remove_file(&pdev->dev, &dev_attr_load_host);
486
487         if (modem->wake_irq) {
488                 disable_irq_wake(modem->wake_irq);
489                 free_irq(modem->wake_irq, modem);
490         }
491
492         if (modem->boot_irq) {
493                 disable_irq_wake(modem->boot_irq);
494                 free_irq(modem->boot_irq, modem);
495         }
496
497         return ret;
498 }
499
500 static int tegra_usb_modem_probe(struct platform_device *pdev)
501 {
502         struct tegra_usb_modem_power_platform_data *pdata =
503             pdev->dev.platform_data;
504         struct tegra_usb_modem *modem;
505         int ret = 0;
506
507         if (!pdata) {
508                 dev_dbg(&pdev->dev, "platform_data not available\n");
509                 return -EINVAL;
510         }
511
512         modem = kzalloc(sizeof(struct tegra_usb_modem), GFP_KERNEL);
513         if (!modem) {
514                 dev_dbg(&pdev->dev, "failed to allocate memory\n");
515                 return -ENOMEM;
516         }
517
518         ret = mdm_init(modem, pdev);
519         if (ret) {
520                 kfree(modem);
521                 return ret;
522         }
523
524         dev_set_drvdata(&pdev->dev, modem);
525
526         return ret;
527 }
528
529 static int __exit tegra_usb_modem_remove(struct platform_device *pdev)
530 {
531         struct tegra_usb_modem *modem = platform_get_drvdata(pdev);
532
533         unregister_pm_notifier(&modem->pm_notifier);
534         usb_unregister_notify(&modem->usb_notifier);
535
536         if (modem->wake_irq) {
537                 disable_irq_wake(modem->wake_irq);
538                 free_irq(modem->wake_irq, modem);
539         }
540
541         if (modem->boot_irq) {
542                 disable_irq_wake(modem->boot_irq);
543                 free_irq(modem->boot_irq, modem);
544         }
545
546         if (modem->sysfs_file_created)
547                 device_remove_file(&pdev->dev, &dev_attr_load_host);
548
549         cancel_work_sync(&modem->cpu_boost_work);
550         cancel_delayed_work_sync(&modem->cpu_unboost_work);
551         destroy_workqueue(modem->wq);
552
553         pm_qos_remove_request(&modem->cpu_boost_req);
554
555         kfree(modem);
556         return 0;
557 }
558
559 #ifdef CONFIG_PM
560 static int tegra_usb_modem_suspend(struct platform_device *pdev,
561                                    pm_message_t state)
562 {
563         struct tegra_usb_modem *modem = platform_get_drvdata(pdev);
564
565         /* send L3 hint to modem */
566         if (modem->ops && modem->ops->suspend)
567                 modem->ops->suspend();
568         return 0;
569 }
570
571 static int tegra_usb_modem_resume(struct platform_device *pdev)
572 {
573         struct tegra_usb_modem *modem = platform_get_drvdata(pdev);
574
575         /* send L3->L0 hint to modem */
576         if (modem->ops && modem->ops->resume)
577                 modem->ops->resume();
578         return 0;
579 }
580 #endif
581
582 static struct platform_driver tegra_usb_modem_power_driver = {
583         .driver = {
584                    .name = "tegra_usb_modem_power",
585                    .owner = THIS_MODULE,
586                    },
587         .probe = tegra_usb_modem_probe,
588         .remove = __exit_p(tegra_usb_modem_remove),
589 #ifdef CONFIG_PM
590         .suspend = tegra_usb_modem_suspend,
591         .resume = tegra_usb_modem_resume,
592 #endif
593 };
594
595 static int __init tegra_usb_modem_power_init(void)
596 {
597         return platform_driver_register(&tegra_usb_modem_power_driver);
598 }
599
600 subsys_initcall(tegra_usb_modem_power_init);
601
602 static void __exit tegra_usb_modem_power_exit(void)
603 {
604         platform_driver_unregister(&tegra_usb_modem_power_driver);
605 }
606
607 module_exit(tegra_usb_modem_power_exit);
608
609 MODULE_DESCRIPTION("Tegra usb modem power management driver");
610 MODULE_LICENSE("GPL");