2 * drivers/misc/tegra-baseband/bb-power.c
4 * Copyright (C) 2011 NVIDIA Corporation
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
17 #include <linux/kernel.h>
18 #include <linux/init.h>
19 #include <linux/module.h>
20 #include <linux/moduleparam.h>
21 #include <linux/platform_device.h>
22 #include <linux/gpio.h>
23 #include <linux/interrupt.h>
24 #include <linux/workqueue.h>
25 #include <linux/delay.h>
27 #include <linux/uaccess.h>
28 #include <linux/platform_data/tegra_usb.h>
29 #include <mach/usb_phy.h>
30 #include <mach/tegra-bb-power.h>
34 static bool bb_registered;
36 static bb_init_cb init_cb_list[] = {
43 static bb_power_cb power_cb_list[] = {
50 static int tegra_bb_power_gpio_init(struct tegra_bb_power_gdata *gdata)
55 const char *gpio_label;
56 unsigned long gpio_flags;
57 struct tegra_bb_gpio_data *gpiolist;
58 struct tegra_bb_gpio_irqdata *gpioirq;
60 gpiolist = gdata->gpio;
61 for (; gpiolist->data.gpio != GPIO_INVALID; ++gpiolist) {
62 gpio_id = (gpiolist->data.gpio);
63 gpio_label = (gpiolist->data.label);
64 gpio_flags = (gpiolist->data.flags);
66 /* Request the gpio */
67 ret = gpio_request(gpio_id, gpio_label);
69 pr_err("%s: gpio_request for gpio %d failed.\n",
74 /* Set gpio direction, as requested */
75 if (gpio_flags == GPIOF_IN)
76 gpio_direction_input(gpio_id);
78 gpio_direction_output(gpio_id, (!gpio_flags ? 0 : 1));
81 tegra_gpio_enable(gpio_id);
83 /* Create a sysfs node, if requested */
84 if (gpiolist->doexport)
85 gpio_export(gpio_id, false);
88 gpioirq = gdata->gpioirq;
89 for (; gpioirq->id != GPIO_INVALID; ++gpioirq) {
91 /* Create interrupt handler, if requested */
92 if (gpioirq->handler != NULL) {
93 irq = gpio_to_irq(gpioirq->id);
94 ret = request_threaded_irq(irq, NULL, gpioirq->handler,
95 gpioirq->flags, gpioirq->name, gpioirq->cookie);
97 pr_err("%s: request_threaded_irq error\n",
101 ret = enable_irq_wake(irq);
103 pr_err("%s: enable_irq_wake error\n", __func__);
111 static int tegra_bb_power_gpio_deinit(struct tegra_bb_power_gdata *gdata)
113 struct tegra_bb_gpio_data *gpiolist;
114 struct tegra_bb_gpio_irqdata *gpioirq;
116 gpiolist = gdata->gpio;
117 for (; gpiolist->data.gpio != GPIO_INVALID; ++gpiolist) {
120 gpio_free(gpiolist->data.gpio);
123 gpioirq = gdata->gpioirq;
124 for (; gpioirq->id != GPIO_INVALID; ++gpioirq) {
127 free_irq(gpio_to_irq(gpioirq->id), gpioirq->cookie);
132 static int baseband_l2_suspend(void)
134 /* BB specific callback */
135 if (power_cb_list[bb_id] != NULL)
136 power_cb_list[bb_id](CB_CODE_L0L2);
140 static int baseband_l2_resume(void)
142 /* BB specific callback */
143 if (power_cb_list[bb_id] != NULL)
144 power_cb_list[bb_id](CB_CODE_L2L0);
148 static ssize_t tegra_bb_attr_write(struct device *dev,
149 struct device_attribute *attr,
150 const char *buf, size_t count)
152 struct tegra_bb_pdata *pdata;
153 struct tegra_ehci_platform_data *ehci_data;
154 struct tegra_uhsic_config *hsic_config;
157 if (sscanf(buf, "%d", &load) != 1)
160 if (load == 1 && !bb_registered) {
161 pdata = (struct tegra_bb_pdata *) dev->platform_data;
162 ehci_data = (struct tegra_ehci_platform_data *)
163 pdata->device->dev.platform_data;
164 hsic_config = (struct tegra_uhsic_config *)
165 ehci_data->phy_config;
167 /* Register PHY callbacks */
168 hsic_config->postsuspend = baseband_l2_suspend;
169 hsic_config->preresume = baseband_l2_resume;
171 /* Override required settings */
172 ehci_data->power_down_on_bus_suspend = 0;
174 /* Register the ehci device. */
175 platform_device_register(pdata->device);
176 bb_registered = true;
182 static ssize_t tegra_bb_attr_read(struct device *dev,
183 struct device_attribute *attr, char *buf)
186 return sprintf(buf, "%d", ret);
189 static DEVICE_ATTR(load, S_IRUSR | S_IWUSR | S_IRGRP,
190 tegra_bb_attr_read, tegra_bb_attr_write);
192 static int tegra_bb_power_probe(struct platform_device *device)
194 struct device *dev = &device->dev;
195 struct tegra_bb_pdata *pdata;
196 struct tegra_bb_power_gdata *gdata;
199 pdata = (struct tegra_bb_pdata *) dev->platform_data;
201 pr_err("%s - Error: platform data is empty.\n", __func__);
205 /* BB specific callback */
206 bb_id = pdata->bb_id;
207 if (init_cb_list[bb_id] != NULL) {
208 gdata = init_cb_list[pdata->bb_id](pdata, CB_CODE_INIT);
211 pr_err("%s - Error: Gpio data is empty.\n", __func__);
215 /* Initialize gpio as required */
216 tegra_bb_power_gpio_init(gdata);
219 bb_registered = false;
221 /* Create the control sysfs node */
222 err = device_create_file(dev, &dev_attr_load);
224 pr_err("%s - device_create_file failed\n", __func__);
231 static int tegra_bb_power_remove(struct platform_device *device)
233 struct device *dev = &device->dev;
234 struct tegra_bb_pdata *pdata;
235 struct tegra_bb_power_gdata *gdata;
237 /* BB specific callback */
238 if (init_cb_list[bb_id] != NULL) {
239 pdata = (struct tegra_bb_pdata *) dev->platform_data;
240 gdata = init_cb_list[bb_id](pdata, CB_CODE_DEINIT);
242 /* Deinitialize gpios */
244 tegra_bb_power_gpio_deinit(gdata);
247 /* Remove the control sysfs node */
248 device_remove_file(dev, &dev_attr_load);
254 static int tegra_bb_power_suspend(struct platform_device *device,
257 /* BB specific callback */
258 if (power_cb_list[bb_id] != NULL)
259 power_cb_list[bb_id](CB_CODE_L2L3);
264 static int tegra_bb_power_resume(struct platform_device *device)
266 /* BB specific callback */
267 if (power_cb_list[bb_id] != NULL)
268 power_cb_list[bb_id](CB_CODE_L3L0);
274 static struct platform_driver tegra_bb_power_driver = {
275 .probe = tegra_bb_power_probe,
276 .remove = tegra_bb_power_remove,
278 .suspend = tegra_bb_power_suspend,
279 .resume = tegra_bb_power_resume,
282 .name = "tegra_baseband_power",
286 static int __init tegra_baseband_power_init(void)
288 pr_debug("%s\n", __func__);
289 return platform_driver_register(&tegra_bb_power_driver);
292 static void __exit tegra_baseband_power_exit(void)
294 pr_debug("%s\n", __func__);
295 platform_driver_unregister(&tegra_bb_power_driver);
298 module_init(tegra_baseband_power_init)
299 module_exit(tegra_baseband_power_exit)
300 MODULE_AUTHOR("NVIDIA Corporation");
301 MODULE_DESCRIPTION("Tegra modem power management driver");
302 MODULE_LICENSE("GPL");