d86fd261e6769136170bbaa09ee346259aee0bdc
[linux-2.6.git] / drivers / bluetooth / ti_bluesleep.c
1 /*
2  *  TI Bluesleep driver
3  *      Kernel module responsible for Wake up of Host
4  *  Copyright (C) 2009-2010 Texas Instruments
5
6
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  * You should have received a copy of the GNU General Public License
12  * along with this program; if not, write to the Free Software
13  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
14  *
15  * This program is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18  * for more details.
19  *
20  * Copyright (C) 2006-2007 - Motorola
21  * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
22  *
23  *  Date         Author           Comment
24  * -----------  --------------   --------------------------------
25  * 2006-Apr-28  Motorola         The kernel module for running the Bluetooth(R)
26  *                               Sleep-Mode Protocol from the Host side
27  * 2006-Sep-08  Motorola         Added workqueue for handling sleep work.
28  * 2007-Jan-24  Motorola         Added mbm_handle_ioi() call to ISR.
29  * 2009-Aug-10  Motorola         Changed "add_timer" to "mod_timer" to solve
30  *                               race when flurry of queued work comes in.
31 */
32
33 #include <linux/module.h>       /* kernel module definitions */
34 #include <linux/errno.h>
35 #include <linux/init.h>
36 #include <linux/interrupt.h>
37 #include <linux/kernel.h>
38 #include <linux/notifier.h>
39 #include <linux/proc_fs.h>
40 #include <linux/spinlock.h>
41 #include <linux/timer.h>
42 #include <linux/uaccess.h>
43 #include <linux/version.h>
44 #include <linux/workqueue.h>
45 #include <linux/platform_device.h>
46
47 #include <linux/irq.h>
48 #include <linux/ioport.h>
49 #include <linux/param.h>
50 #include <linux/bitops.h>
51 #include <linux/termios.h>
52 #include <linux/wakelock.h>
53 #include <mach/gpio.h>
54 #include <linux/serial_core.h>
55 #include <linux/tegra_uart.h>
56
57 #include <net/bluetooth/bluetooth.h>
58 #include <net/bluetooth/hci_core.h> /* event notifications */
59 #include "hci_uart.h"
60
61 /*
62  * Defines
63  */
64
65 #define VERSION  "1.1"
66
67 #define POLARITY_LOW 0
68 #define POLARITY_HIGH 1
69
70 struct bluesleep_info {
71         unsigned host_wake_irq;
72         struct uart_port *uport;
73         struct wake_lock wake_lock;
74         int irq_polarity;
75         int has_ext_wake;
76 };
77
78
79 /* state variable names and bit positions */
80 #define FLAG_RESET              0x00
81 #define BT_ACTIVE               0x02
82 #define BT_SUSPEND              0x04
83
84
85 /* work function */
86 static void hostwake_sleep_work(struct work_struct *work);
87
88 /* work queue */
89 DECLARE_DELAYED_WORK(ti_sleep_workqueue, hostwake_sleep_work);
90
91 /* Macros for handling sleep work */
92 #define hostwake_workqueue()     schedule_delayed_work(&ti_sleep_workqueue, 0)
93
94 static struct bluesleep_info *bsi;
95
96 /* module usage */
97 static atomic_t open_count = ATOMIC_INIT(1);
98
99 /*
100  * Global variables
101  */
102 /** Global state flags */
103 static unsigned long flags;
104
105 /** Tasklet to respond to change in hostwake line */
106 static struct tasklet_struct hostwake_task;
107
108 /** Lock for state transitions */
109 static spinlock_t rw_lock;
110
111 /*
112  * Local functions
113  */
114 static void hsuart_power(int on)
115 {
116         pr_debug("%s", __func__);
117
118         if (on) {
119                 tegra_uart_request_clock_on(bsi->uport);
120                 tegra_uart_set_mctrl(bsi->uport, TIOCM_RTS);
121         } else {
122                 tegra_uart_set_mctrl(bsi->uport, 0);
123                 tegra_uart_request_clock_off(bsi->uport);
124         }
125 }
126
127
128
129 /**
130  * @brief@  main sleep work handling function which update the flags
131  * and activate and deactivate UART .
132  */
133
134 static void hostwake_sleep_work(struct work_struct *work)
135 {
136         pr_debug("%s", __func__);
137         free_irq(bsi->host_wake_irq, "tibluesleep");
138         /*Activating UART */
139         if (test_bit(BT_SUSPEND, &flags)) {
140                 BT_DBG("Activate UART");
141                 hsuart_power(1);
142
143         }
144         bsi->has_ext_wake = 0;
145         clear_bit(BT_SUSPEND, &flags);
146         set_bit(BT_ACTIVE, &flags);
147
148 }
149
150
151 /**
152  * A tasklet function that runs in tasklet context
153  * @param data Not used.
154  */
155 static void bluesleep_hostwake_task(unsigned long data)
156 {
157         pr_debug("%s", __func__);
158         disable_irq(bsi->host_wake_irq);
159         spin_lock(&rw_lock);
160         hostwake_workqueue();
161         spin_unlock(&rw_lock);
162 }
163
164
165 /**
166  * Schedules a tasklet to run when receiving an interrupt on the
167  * <code>HOST_WAKE</code> GPIO pin.
168  * @param irq Not used.
169  * @param dev_id Not used.
170  */
171 static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id)
172 {
173
174         pr_debug("%s", __func__);
175         /* schedule a tasklet to handle the change in the host wake line */
176         bsi->has_ext_wake = 1;
177         tasklet_schedule(&hostwake_task);
178         return IRQ_HANDLED;
179 }
180
181 /**
182  * Starts the Sleep-Mode Protocol on the Host.
183  * @return On success, 0. On error, -1, and <code>errno</code> is set
184  * appropriately.
185  */
186
187   int bluesleep_start(struct uart_port *uport)
188 {
189         int retval;
190         bsi->uport = uport;
191         pr_debug("%s", __func__);
192
193         if (test_bit(BT_SUSPEND, &flags)) {
194                 BT_DBG("bluesleep_acquire irq");
195                 if (bsi->irq_polarity == POLARITY_LOW) {
196                         retval = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
197                                         IRQF_DISABLED | IRQF_TRIGGER_FALLING,
198                                         "bluetooth hostwake", "tibluesleep");
199                 } else  {
200                         retval = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
201                                         IRQF_DISABLED | IRQF_TRIGGER_RISING,
202                                         "bluetooth hostwake", "tibluesleep");
203                 }
204                 if (retval  < 0) {
205                         BT_ERR("Couldn't acquire BT_HOST_WAKE IRQ");
206                         goto fail;
207                 }
208
209                 retval = enable_irq_wake(bsi->host_wake_irq);
210                 if (retval < 0) {
211                         BT_ERR("Couldn't enable BT_HOST_WAKE as wakeup"
212                                         "interrupt retval %d\n", retval);
213                         free_irq(bsi->host_wake_irq, NULL);
214                         goto fail;
215                 }
216         }
217
218         return 0;
219 fail:
220         atomic_inc(&open_count);
221         return retval;
222 }
223
224 /**
225  * Stops the Sleep-Mode Protocol on the Host.
226  */
227   void bluesleep_stop(void)
228 {
229
230         pr_debug("%s", __func__);
231
232         if (disable_irq_wake(bsi->host_wake_irq))
233                 BT_ERR("Couldn't disable hostwake IRQ wakeup mode\n");
234
235         free_irq(bsi->host_wake_irq, NULL);
236 }
237
238 static int bluesleep_probe(struct platform_device *pdev)
239 {
240         int ret;
241         struct resource *res;
242
243         bsi = kzalloc(sizeof(struct bluesleep_info), GFP_KERNEL);
244         if (!bsi)
245                 return -ENOMEM;
246
247         res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
248                                                 "host_wake");
249         if (!res) {
250                 BT_ERR("couldn't find host_wake irq\n");
251                 ret = -ENODEV;
252                 goto free_bsi;
253         }
254
255         bsi->host_wake_irq = res->start;
256
257         if (bsi->host_wake_irq < 0) {
258                 BT_ERR("couldn't find host_wake irq");
259                 ret = -ENODEV;
260                 goto free_bsi;
261         }
262         if (res->flags & IORESOURCE_IRQ_LOWEDGE)
263                 bsi->irq_polarity = POLARITY_LOW;/*low edge (falling edge)*/
264         else
265                 bsi->irq_polarity = POLARITY_HIGH;/*anything else*/
266
267         wake_lock_init(&bsi->wake_lock, WAKE_LOCK_SUSPEND, "bluesleep");
268         clear_bit(BT_SUSPEND, &flags);
269         set_bit(BT_ACTIVE, &flags);
270
271         return 0;
272
273 free_bsi:
274         kfree(bsi);
275         return ret;
276 }
277
278 static int bluesleep_remove(struct platform_device *pdev)
279 {
280         pr_debug("%s", __func__);
281         kfree(bsi);
282         return 0;
283 }
284
285
286 static int bluesleep_resume(struct platform_device *pdev)
287 {
288
289         pr_debug("%s", __func__);
290         if (test_bit(BT_SUSPEND, &flags)) {
291
292                 if ((bsi->uport != NULL) && (bsi->has_ext_wake)) {
293                         tegra_uart_request_clock_on(bsi->uport);
294                         tegra_uart_set_mctrl(bsi->uport, TIOCM_RTS);
295                 }
296                 clear_bit(BT_SUSPEND, &flags);
297                 set_bit(BT_ACTIVE, &flags);
298         }
299
300         return 0;
301 }
302
303 static int bluesleep_suspend(struct platform_device *pdev, pm_message_t state)
304 {
305         pr_debug("%s", __func__);
306         set_bit(BT_SUSPEND, &flags);
307         return 0;
308 }
309
310 static struct platform_driver bluesleep_driver = {
311         .probe = bluesleep_probe,
312         .remove = bluesleep_remove,
313         .suspend = bluesleep_suspend,
314         .resume = bluesleep_resume,
315         .driver = {
316                 .name = "tibluesleep",
317                 .owner = THIS_MODULE,
318         },
319 };
320 /**
321  * Initializes the module.
322  * @return On success, 0. On error, -1, and <code>errno</code> is set
323  * appropriately.
324  */
325 static int __init bluesleep_init(void)
326 {
327         int retval;
328
329         BT_INFO("BlueSleep Mode Driver Ver %s", VERSION);
330
331         retval = platform_driver_register(&bluesleep_driver);
332         if (retval)
333                 goto fail;
334
335         if (bsi == NULL)
336                 return 0;
337
338         flags = FLAG_RESET; /* clear all status bits */
339
340         /* Initialize spinlock. */
341         spin_lock_init(&rw_lock);
342
343         /* initialize host wake tasklet */
344         tasklet_init(&hostwake_task, bluesleep_hostwake_task, 0);
345
346         return 0;
347 fail:
348         return retval;
349 }
350
351 /**
352  * Cleans up the module.
353  */
354
355 static void __exit bluesleep_exit(void)
356 {
357         if (bsi == NULL)
358                 return;
359         /* assert bt wake */
360         free_irq(bsi->host_wake_irq, NULL);
361         platform_driver_unregister(&bluesleep_driver);
362
363 }
364
365 module_init(bluesleep_init);
366 module_exit(bluesleep_exit);
367
368 MODULE_DESCRIPTION("TI Bluetooth Sleep Mode Driver ver %s " VERSION);
369 #ifdef MODULE_LICENSE
370 MODULE_LICENSE("GPL");
371 #endif