arm: tegra: comms: Intel XMM6260 flashless boot.
[linux-2.6.git] / arch / arm / mach-tegra / baseband-xmm-power.c
1 /*
2  * arch/arm/mach-tegra/baseband-xmm-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 <mach/usb_phy.h>
27 #include "board.h"
28 #include "devices.h"
29 #include "gpio-names.h"
30 #include "baseband-xmm-power.h"
31
32 MODULE_LICENSE("GPL");
33
34 unsigned long enum_delay_ms = 1000;
35
36 module_param(enum_delay_ms, ulong, 0644);
37 MODULE_PARM_DESC(enum_delay_ms, "baseband xmm power"
38                         " - delay in ms between modem on and enumeration");
39
40 /* Currently no baseband initiated suspend */
41 #define BB_INITIATED_L2_SUSPEND 0
42
43 static struct gpio tegra_baseband_gpios[] = {
44         { -1, GPIOF_OUT_INIT_LOW,  "BB_RSTn" },
45         { -1, GPIOF_OUT_INIT_LOW,  "BB_ON"   },
46         { -1, GPIOF_OUT_INIT_LOW,  "IPC_BB_WAKE" },
47         { -1, GPIOF_IN,            "IPC_AP_WAKE" },
48         { -1, GPIOF_OUT_INIT_HIGH, "IPC_HSIC_ACTIVE" },
49         { -1, GPIOF_IN,            "IPC_HSIC_SUS_REQ" },
50 };
51
52 #if BB_INITIATED_L2_SUSPEND
53 static enum {
54         IPC_HSIC_SUS_REQ_UNINIT,
55         IPC_HSIC_SUS_REQ_IRQ_READY,
56         IPC_HSIC_SUS_REQ_INIT,
57         IPC_HSIC_SUS_REQ_L,
58         IPC_HSIC_SUS_REQ_H,
59 } ipc_hsic_sus_req_state;
60 #endif
61
62 static enum {
63         IPC_AP_WAKE_UNINIT,
64         IPC_AP_WAKE_IRQ_READY,
65         IPC_AP_WAKE_INIT1,
66         IPC_AP_WAKE_INIT2,
67         IPC_AP_WAKE_L,
68         IPC_AP_WAKE_H,
69 } ipc_ap_wake_state;
70
71 static enum {
72         BBXMM_PS_UNINIT   = 0,
73         BBXMM_PS_INIT     = 1,
74         BBXMM_PS_L0       = 2,
75         BBXMM_PS_L0TOL2   = 3,
76         BBXMM_PS_L2       = 4,
77         BBXMM_PS_L2TOL0   = 5,
78         BBXMM_PS_L2TOL3   = 6,
79         BBXMM_PS_L3       = 7,
80         BBXMM_PS_L3TOL0   = 8,
81         BBXMM_PS_LAST     = -1,
82 } baseband_xmm_powerstate;
83
84 static struct workqueue_struct *workqueue;
85 static struct work_struct init1_work;
86 static struct work_struct init2_work;
87 static struct baseband_power_platform_data *baseband_power_driver_data;
88
89 static void baseband_xmm_set_power_status(unsigned int status)
90 {
91         baseband_xmm_powerstate = status;
92         pr_debug("BB XMM POWER STATE = %d\n", status);
93 }
94
95 #if BB_INITIATED_L2_SUSPEND
96 static irqreturn_t ipc_hsic_sus_req_irq(int irq, void *dev_id)
97 {
98         int value;
99
100         pr_debug("%s\n", __func__);
101
102         if (ipc_hsic_sus_req_state < IPC_HSIC_SUS_REQ_IRQ_READY) {
103                 pr_err("%s - spurious irq\n", __func__);
104         } else {
105                 value = gpio_get_value(baseband_power_driver_data->
106                         modem.xmm.ipc_hsic_sus_req);
107                 if (!value) {
108                         pr_debug("%s - falling\n", __func__);
109                         ipc_hsic_sus_req_state = IPC_HSIC_SUS_REQ_L;
110                 } else {
111                         pr_debug("%s - rising\n", __func__);
112                         ipc_hsic_sus_req_state = IPC_HSIC_SUS_REQ_H;
113                 }
114         }
115
116         return IRQ_HANDLED;
117 }
118
119 #endif
120
121 static irqreturn_t ipc_ap_wake_irq(int irq, void *dev_id)
122 {
123         int value;
124
125         pr_debug("%s\n", __func__);
126
127         if (ipc_ap_wake_state < IPC_AP_WAKE_IRQ_READY) {
128                 pr_err("%s - spurious irq\n", __func__);
129         } else if (ipc_ap_wake_state == IPC_AP_WAKE_IRQ_READY) {
130                 value = gpio_get_value(baseband_power_driver_data->
131                         modem.xmm.ipc_ap_wake);
132                 if (!value) {
133                         pr_debug("%s - IPC_AP_WAKE_INIT1 - got falling edge\n",
134                                 __func__);
135                         /* go to IPC_AP_WAKE_INIT1 state */
136                         ipc_ap_wake_state = IPC_AP_WAKE_INIT1;
137                         /* queue work */
138                         queue_work(workqueue, &init1_work);
139                 } else {
140                         pr_debug("%s - IPC_AP_WAKE_INIT1 - wait for falling edge\n",
141                                 __func__);
142                 }
143         } else if (ipc_ap_wake_state == IPC_AP_WAKE_INIT1) {
144                 value = gpio_get_value(baseband_power_driver_data->
145                         modem.xmm.ipc_ap_wake);
146                 if (!value) {
147                         pr_debug("%s - IPC_AP_WAKE_INIT2 - wait for rising edge\n",
148                                 __func__);
149                 } else {
150                         pr_debug("%s - IPC_AP_WAKE_INIT2 - got rising edge\n",
151                                 __func__);
152                         /* go to IPC_AP_WAKE_INIT2 state */
153                         ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
154                         /* queue work */
155                         queue_work(workqueue, &init2_work);
156                 }
157         } else {
158                 value = gpio_get_value(baseband_power_driver_data->
159                         modem.xmm.ipc_ap_wake);
160                 if (!value) {
161                         pr_debug("%s - falling\n", __func__);
162                         pr_debug("gpio host wakeup done <-\n");
163                         /* Set the slave wakeup request */
164                         gpio_set_value(baseband_power_driver_data->
165                                 modem.xmm.ipc_bb_wake, 0);
166                         pr_debug("gpio slave wakeup done ->\n");
167                         ipc_ap_wake_state = IPC_AP_WAKE_L;
168                         baseband_xmm_set_power_status(BBXMM_PS_L0);
169                 } else {
170                         pr_debug("%s - rising\n", __func__);
171                         ipc_ap_wake_state = IPC_AP_WAKE_H;
172                 }
173         }
174
175         return IRQ_HANDLED;
176 }
177
178 static void baseband_xmm_power_init1_work(struct work_struct *work)
179 {
180         int value;
181
182         pr_debug("%s {\n", __func__);
183
184         /* check if IPC_HSIC_ACTIVE high */
185         value = gpio_get_value(baseband_power_driver_data->
186                 modem.xmm.ipc_hsic_active);
187         if (value != 1) {
188                 pr_err("%s - expected IPC_HSIC_ACTIVE high!\n", __func__);
189                 return;
190         }
191
192         /* wait 100 ms */
193         mdelay(100);
194
195         /* set IPC_HSIC_ACTIVE low */
196         gpio_set_value(baseband_power_driver_data->
197                 modem.xmm.ipc_hsic_active, 0);
198
199         /* wait 10 ms */
200         mdelay(10);
201
202         /* set IPC_HSIC_ACTIVE high */
203         gpio_set_value(baseband_power_driver_data->
204                 modem.xmm.ipc_hsic_active, 1);
205
206         /* wait 20 ms */
207         mdelay(20);
208
209         pr_debug("%s }\n", __func__);
210 }
211
212 static void baseband_xmm_power_init2_work(struct work_struct *work)
213 {
214         pr_debug("%s\n", __func__);
215
216         /* register usb host controller */
217         platform_device_register(baseband_power_driver_data->
218                 modem.xmm.hsic_device);
219
220         baseband_xmm_set_power_status(BBXMM_PS_L0);
221
222 }
223
224 static int baseband_xmm_power_driver_probe(struct platform_device *device)
225 {
226         struct baseband_power_platform_data *data
227             = (struct baseband_power_platform_data *) device->dev.platform_data;
228         int err;
229
230         pr_debug("%s\n", __func__);
231
232         baseband_xmm_powerstate = BBXMM_PS_UNINIT;
233         /* check if supported modem */
234         if (data->baseband_type != BASEBAND_XMM) {
235                 pr_err("unsuppported modem\n");
236                 return -ENODEV;
237         }
238
239         /* save platform data */
240         baseband_power_driver_data = data;
241
242         /* request baseband gpio(s) */
243         tegra_baseband_gpios[0].gpio = data->modem.xmm.bb_rst;
244         tegra_baseband_gpios[1].gpio = data->modem.xmm.bb_on;
245         tegra_baseband_gpios[2].gpio = data->modem.xmm.ipc_bb_wake;
246         tegra_baseband_gpios[3].gpio = data->modem.xmm.ipc_ap_wake;
247         tegra_baseband_gpios[4].gpio = data->modem.xmm.ipc_hsic_active;
248         tegra_baseband_gpios[5].gpio = data->modem.xmm.ipc_hsic_sus_req;
249         err = gpio_request_array(tegra_baseband_gpios,
250                 ARRAY_SIZE(tegra_baseband_gpios));
251         if (err < 0) {
252                 pr_err("%s - request gpio(s) failed\n", __func__);
253                 return err;
254         }
255
256         /* request baseband irq(s) */
257 #if BB_INITIATED_L2_SUSPEND
258         if (enum_delay_ms) {
259                 ipc_hsic_sus_req_state = IPC_HSIC_SUS_REQ_UNINIT;
260                 err = request_irq(gpio_to_irq(data->modem.xmm.ipc_hsic_sus_req),
261                         ipc_hsic_sus_req_irq,
262                         IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
263                         "IPC_HSIC_SUS_REQ_IRQ",
264                         NULL);
265                 if (err < 0) {
266                         pr_err("%s - request irq IPC_HSIC_SUS_REQ_IRQ failed\n",
267                                 __func__);
268                         return err;
269                 }
270                 ipc_hsic_sus_req_state = IPC_HSIC_SUS_REQ_IRQ_READY;
271         }
272 #endif
273         if (enum_delay_ms) {
274                 ipc_ap_wake_state = IPC_AP_WAKE_UNINIT;
275                 err = request_irq(gpio_to_irq(data->modem.xmm.ipc_ap_wake),
276                         ipc_ap_wake_irq,
277                         IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
278                         "IPC_AP_WAKE_IRQ",
279                         NULL);
280                 if (err < 0) {
281                         pr_err("%s - request irq IPC_AP_WAKE_IRQ failed\n",
282                                 __func__);
283                         return err;
284                 }
285                 ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY;
286         }
287
288         /* init work queue */
289         workqueue = create_singlethread_workqueue
290                 ("baseband_xmm_power_workqueue");
291         if (!workqueue) {
292                 pr_err("cannot create workqueue\n");
293                 return -1;
294         }
295
296         baseband_xmm_powerstate = BBXMM_PS_INIT;
297         INIT_WORK(&init1_work, baseband_xmm_power_init1_work);
298         INIT_WORK(&init2_work, baseband_xmm_power_init2_work);
299
300         /* reset / power on sequence */
301         mdelay(40);
302         gpio_set_value(data->modem.xmm.bb_rst, 1);
303         mdelay(1);
304         gpio_set_value(data->modem.xmm.bb_on, 1);
305         udelay(40);
306         gpio_set_value(data->modem.xmm.bb_on, 0);
307
308         /* optional delay
309          * 0 = flashless
310          *   ==> causes next step to enumerate modem boot rom (058b / 0041)
311          * some delay > boot rom timeout
312          *   ==> causes next step to enumerate modem software (1519 / 0020)
313          *       (requires modem to be flash version, not flashless version)
314         */
315         if (enum_delay_ms)
316                 mdelay(enum_delay_ms);
317
318         /* register usb host controller */
319         if (!enum_delay_ms)
320                 platform_device_register(data->modem.xmm.hsic_device);
321
322         return 0;
323 }
324
325 static int baseband_xmm_power_driver_remove(struct platform_device *device)
326 {
327         struct baseband_power_platform_data *data
328          = (struct baseband_power_platform_data *) device->dev.platform_data;
329
330         pr_debug("%s\n", __func__);
331
332         /* free baseband irq(s) */
333         if (enum_delay_ms) {
334                 free_irq(gpio_to_irq(data->modem.xmm.ipc_ap_wake), NULL);
335 #if BB_INITIATED_L2_SUSPEND
336                 free_irq(gpio_to_irq(data->modem.xmm.ipc_hsic_sus_req), NULL);
337 #endif
338         }
339
340         /* free baseband gpio(s) */
341         gpio_free_array(tegra_baseband_gpios,
342                 ARRAY_SIZE(tegra_baseband_gpios));
343
344         /* unregister usb host controller */
345         platform_device_unregister(baseband_power_driver_data->
346                 modem.xmm.hsic_device);
347
348         return 0;
349 }
350
351 static int baseband_xmm_power_driver_suspend(struct platform_device *device,
352         pm_message_t state)
353 {
354         struct baseband_power_platform_data *data
355          = (struct baseband_power_platform_data *) device->dev.platform_data;
356
357         pr_debug("%s\n", __func__);
358
359         /* Indiate host active low to CP*/
360         gpio_set_value(data->modem.xmm.ipc_hsic_active, 0);
361         pr_debug("gpio host active low->\n");
362
363         baseband_xmm_set_power_status(BBXMM_PS_L3);
364
365         return 0;
366 }
367
368 static int baseband_xmm_power_driver_resume(struct platform_device *device)
369 {
370         struct baseband_power_platform_data *data
371          = (struct baseband_power_platform_data *) device->dev.platform_data;
372         int value;
373
374         pr_debug("%s\n", __func__);
375
376         /* wake bb */
377         gpio_set_value(data->modem.xmm.ipc_bb_wake, 1);
378
379         pr_debug("waiting for host wakeup\n");
380         do {
381                 mdelay(1);
382                 value = gpio_get_value(baseband_power_driver_data
383                         ->modem.xmm.ipc_ap_wake);
384         } while (!value);
385         pr_debug("gpio host wakeup high <-\n");
386
387         /* signal bb to resume hsic */
388         gpio_set_value(data->modem.xmm.ipc_hsic_active, 1);
389
390         baseband_xmm_set_power_status(BBXMM_PS_L3TOL0);
391
392         return 0;
393 }
394
395 static struct platform_driver baseband_power_driver = {
396         .probe = baseband_xmm_power_driver_probe,
397         .remove = baseband_xmm_power_driver_remove,
398 #ifdef CONFIG_PM
399         .suspend = baseband_xmm_power_driver_suspend,
400         .resume = baseband_xmm_power_driver_resume,
401 #endif
402         .driver = {
403                 .name = "baseband_xmm_power",
404         },
405 };
406
407 static int __init baseband_xmm_power_init(void)
408 {
409         pr_debug("%s\n", __func__);
410         return platform_driver_register(&baseband_power_driver);
411 }
412
413 static void __exit baseband_xmm_power_exit(void)
414 {
415         pr_debug("%s\n", __func__);
416         platform_driver_unregister(&baseband_power_driver);
417 }
418
419 module_init(baseband_xmm_power_init)
420 module_exit(baseband_xmm_power_exit)