aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/tegra-baseband/bb-power.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/misc/tegra-baseband/bb-power.c
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/misc/tegra-baseband/bb-power.c')
-rw-r--r--drivers/misc/tegra-baseband/bb-power.c337
1 files changed, 337 insertions, 0 deletions
diff --git a/drivers/misc/tegra-baseband/bb-power.c b/drivers/misc/tegra-baseband/bb-power.c
new file mode 100644
index 00000000000..9210a8f3e84
--- /dev/null
+++ b/drivers/misc/tegra-baseband/bb-power.c
@@ -0,0 +1,337 @@
1/*
2 * drivers/misc/tegra-baseband/bb-power.c
3 *
4 * Copyright (C) 2011 NVIDIA Corporation
5 *
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.
9 *
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.
14 *
15 */
16
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>
26#include <linux/fs.h>
27#include <linux/usb.h>
28#include <linux/uaccess.h>
29#include <linux/platform_data/tegra_usb.h>
30#include <mach/usb_phy.h>
31#include <mach/tegra-bb-power.h>
32#include "bb-power.h"
33
34static struct tegra_bb_callback *callback;
35static int attr_load_val;
36static struct tegra_bb_power_mdata *mdata;
37static bb_get_cblist get_cblist[] = {
38 NULL,
39 NULL,
40 NULL,
41 M7400_CB,
42};
43
44static int tegra_bb_power_gpio_init(struct tegra_bb_power_gdata *gdata)
45{
46 int ret;
47 int irq;
48 unsigned gpio_id;
49 const char *gpio_label;
50 unsigned long gpio_flags;
51 struct tegra_bb_gpio_data *gpiolist;
52 struct tegra_bb_gpio_irqdata *gpioirq;
53
54 gpiolist = gdata->gpio;
55 for (; gpiolist->data.gpio != GPIO_INVALID; ++gpiolist) {
56 gpio_id = (gpiolist->data.gpio);
57 gpio_label = (gpiolist->data.label);
58 gpio_flags = (gpiolist->data.flags);
59
60 /* Request the gpio */
61 ret = gpio_request(gpio_id, gpio_label);
62 if (ret) {
63 pr_err("%s: Error: gpio_request for gpio %d failed.\n",
64 __func__, gpio_id);
65 return ret;
66 }
67
68 /* Set gpio direction, as requested */
69 if (gpio_flags == GPIOF_IN)
70 gpio_direction_input(gpio_id);
71 else
72 gpio_direction_output(gpio_id, (!gpio_flags ? 0 : 1));
73
74 /* Enable the gpio */
75 tegra_gpio_enable(gpio_id);
76
77 /* Create a sysfs node, if requested */
78 if (gpiolist->doexport)
79 gpio_export(gpio_id, false);
80 }
81
82 gpioirq = gdata->gpioirq;
83 for (; gpioirq->id != GPIO_INVALID; ++gpioirq) {
84
85 /* Create interrupt handler, if requested */
86 if (gpioirq->handler != NULL) {
87 irq = gpio_to_irq(gpioirq->id);
88 ret = request_threaded_irq(irq, NULL, gpioirq->handler,
89 gpioirq->flags, gpioirq->name, gpioirq->cookie);
90 if (ret < 0) {
91 pr_err("%s: Error: threaded_irq req fail.\n"
92 , __func__);
93 return ret;
94 }
95
96 if (gpioirq->wake_capable) {
97 ret = enable_irq_wake(irq);
98 if (ret) {
99 pr_err("%s: Error: irqwake req fail.\n",
100 __func__);
101 return ret;
102 }
103 }
104 }
105 }
106 return 0;
107}
108
109static int tegra_bb_power_gpio_deinit(struct tegra_bb_power_gdata *gdata)
110{
111 struct tegra_bb_gpio_data *gpiolist;
112 struct tegra_bb_gpio_irqdata *gpioirq;
113
114 gpiolist = gdata->gpio;
115 for (; gpiolist->data.gpio != GPIO_INVALID; ++gpiolist) {
116
117 /* Free the gpio */
118 gpio_free(gpiolist->data.gpio);
119 }
120
121 gpioirq = gdata->gpioirq;
122 for (; gpioirq->id != GPIO_INVALID; ++gpioirq) {
123
124 /* Free the irq */
125 free_irq(gpio_to_irq(gpioirq->id), gpioirq->cookie);
126 }
127 return 0;
128}
129
130static ssize_t tegra_bb_attr_write(struct device *dev,
131 struct device_attribute *attr,
132 const char *buf, size_t count)
133{
134 int val;
135
136 if (sscanf(buf, "%d", &val) != 1)
137 return -EINVAL;
138
139 if (callback && callback->attrib) {
140 if (!callback->attrib(dev, val))
141 attr_load_val = val;
142 }
143 return count;
144}
145
146static ssize_t tegra_bb_attr_read(struct device *dev,
147 struct device_attribute *attr, char *buf)
148{
149 return sprintf(buf, "%d", attr_load_val);
150}
151
152static DEVICE_ATTR(load, S_IRUSR | S_IWUSR | S_IRGRP,
153 tegra_bb_attr_read, tegra_bb_attr_write);
154
155static void tegra_usbdevice_added(struct usb_device *udev)
156{
157 const struct usb_device_descriptor *desc = &udev->descriptor;
158
159 if (desc->idVendor == mdata->vid &&
160 desc->idProduct == mdata->pid) {
161 pr_debug("%s: Device %s added.\n", udev->product, __func__);
162
163 if (mdata->wake_capable)
164 device_set_wakeup_enable(&udev->dev, true);
165 if (mdata->autosuspend_ready)
166 usb_enable_autosuspend(udev);
167 if (mdata->reg_cb)
168 mdata->reg_cb(udev);
169 }
170}
171
172static void tegra_usbdevice_removed(struct usb_device *udev)
173{
174 const struct usb_device_descriptor *desc = &udev->descriptor;
175
176 if (desc->idVendor == mdata->vid &&
177 desc->idProduct == mdata->pid) {
178 pr_debug("%s: Device %s removed.\n", udev->product, __func__);
179 }
180}
181
182static int tegra_usb_notify(struct notifier_block *self, unsigned long action,
183 void *dev)
184{
185 switch (action) {
186 case USB_DEVICE_ADD:
187 tegra_usbdevice_added((struct usb_device *)dev);
188 break;
189 case USB_DEVICE_REMOVE:
190 tegra_usbdevice_removed((struct usb_device *)dev);
191 break;
192 }
193 return NOTIFY_OK;
194}
195
196static struct notifier_block tegra_usb_nb = {
197 .notifier_call = tegra_usb_notify,
198};
199
200static int tegra_bb_power_probe(struct platform_device *device)
201{
202 struct device *dev = &device->dev;
203 struct tegra_bb_pdata *pdata;
204 struct tegra_bb_power_data *data;
205 struct tegra_bb_power_gdata *gdata;
206 int err;
207 unsigned int bb_id;
208
209 pdata = (struct tegra_bb_pdata *) dev->platform_data;
210 if (!pdata) {
211 pr_err("%s - Error: platform data is empty.\n", __func__);
212 return -ENODEV;
213 }
214
215 /* Obtain BB specific callback list */
216 bb_id = pdata->bb_id;
217 if (get_cblist[bb_id] != NULL) {
218 callback = (struct tegra_bb_callback *) get_cblist[bb_id]();
219 if (callback && callback->init) {
220 data = (struct tegra_bb_power_data *)
221 callback->init((void *)pdata);
222
223 gdata = data->gpio_data;
224 if (!gdata) {
225 pr_err("%s - Error: Gpio data is empty.\n",
226 __func__);
227 return -ENODEV;
228 }
229
230 /* Initialize gpio as required */
231 tegra_bb_power_gpio_init(gdata);
232
233 mdata = data->modem_data;
234 if (mdata && mdata->vid && mdata->pid)
235 /* Register to notifications from usb core */
236 usb_register_notify(&tegra_usb_nb);
237 } else {
238 pr_err("%s - Error: init callback is empty.\n",
239 __func__);
240 return -ENODEV;
241 }
242 } else {
243 pr_err("%s - Error: callback data is empty.\n", __func__);
244 return -ENODEV;
245 }
246
247 /* Create the control sysfs node */
248 err = device_create_file(dev, &dev_attr_load);
249 if (err < 0) {
250 pr_err("%s - Error: device_create_file failed.\n", __func__);
251 return -ENODEV;
252 }
253 attr_load_val = 0;
254
255 return 0;
256}
257
258static int tegra_bb_power_remove(struct platform_device *device)
259{
260 struct device *dev = &device->dev;
261 struct tegra_bb_power_data *data;
262 struct tegra_bb_power_gdata *gdata;
263
264 /* BB specific callback */
265 if (callback && callback->deinit) {
266 data = (struct tegra_bb_power_data *)
267 callback->deinit();
268
269 /* Deinitialize gpios */
270 gdata = data->gpio_data;
271 if (gdata)
272 tegra_bb_power_gpio_deinit(gdata);
273 else {
274 pr_err("%s - Error: Gpio data is empty.\n", __func__);
275 return -ENODEV;
276 }
277
278 mdata = data->modem_data;
279 if (mdata && mdata->vid && mdata->pid)
280 /* Register to notifications from usb core */
281 usb_unregister_notify(&tegra_usb_nb);
282 }
283
284 /* Remove the control sysfs node */
285 device_remove_file(dev, &dev_attr_load);
286
287 return 0;
288}
289
290#ifdef CONFIG_PM
291static int tegra_bb_power_suspend(struct platform_device *device,
292 pm_message_t state)
293{
294 /* BB specific callback */
295 if (callback && callback->power)
296 callback->power(PWRSTATE_L2L3);
297 return 0;
298}
299
300static int tegra_bb_power_resume(struct platform_device *device)
301{
302 /* BB specific callback */
303 if (callback && callback->power)
304 callback->power(PWRSTATE_L3L0);
305 return 0;
306}
307#endif
308
309static struct platform_driver tegra_bb_power_driver = {
310 .probe = tegra_bb_power_probe,
311 .remove = tegra_bb_power_remove,
312#ifdef CONFIG_PM
313 .suspend = tegra_bb_power_suspend,
314 .resume = tegra_bb_power_resume,
315#endif
316 .driver = {
317 .name = "tegra_baseband_power",
318 },
319};
320
321static int __init tegra_baseband_power_init(void)
322{
323 pr_debug("%s\n", __func__);
324 return platform_driver_register(&tegra_bb_power_driver);
325}
326
327static void __exit tegra_baseband_power_exit(void)
328{
329 pr_debug("%s\n", __func__);
330 platform_driver_unregister(&tegra_bb_power_driver);
331}
332
333module_init(tegra_baseband_power_init)
334module_exit(tegra_baseband_power_exit)
335MODULE_AUTHOR("NVIDIA Corporation");
336MODULE_DESCRIPTION("Tegra modem power management driver");
337MODULE_LICENSE("GPL");