TI Wl128x support of bluesleep & Wake on BT Driver changes
[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 <linux/ti_wilink_st.h>
60 #include "hci_uart.h"
61
62 /*
63  * Defines
64  */
65
66 #define VERSION  "1.1"
67
68 #define POLARITY_LOW 0
69 #define POLARITY_HIGH 1
70
71 struct bluesleep_info {
72         unsigned host_wake_irq;
73         struct uart_port *uport;
74         struct wake_lock wake_lock;
75         int irq_polarity;
76         int has_ext_wake;
77 };
78
79
80 /* state variable names and bit positions */
81 #define FLAG_RESET              0x00
82 #define BT_ACTIVE               0x02
83 #define BT_SUSPEND              0x04
84
85
86 /* work function */
87 static void hostwake_sleep_work(struct work_struct *work);
88
89 /* work queue */
90 DECLARE_DELAYED_WORK(ti_sleep_workqueue, hostwake_sleep_work);
91
92 /* Macros for handling sleep work */
93 #define hostwake_workqueue()     schedule_delayed_work(&ti_sleep_workqueue, 0)
94
95 static struct bluesleep_info *bsi;
96
97 /* module usage */
98 static atomic_t open_count = ATOMIC_INIT(1);
99
100 /*
101  * Global variables
102  */
103 /** Global state flags */
104 static unsigned long flags;
105
106 /** Tasklet to respond to change in hostwake line */
107 static struct tasklet_struct hostwake_task;
108
109 /** Lock for state transitions */
110 static spinlock_t rw_lock;
111
112 /*
113  * Local functions
114  */
115 static void hsuart_power(int on)
116 {
117         pr_debug("%s", __func__);
118
119         if (on) {
120                 tegra_uart_request_clock_on(bsi->uport);
121                 tegra_uart_set_mctrl(bsi->uport, TIOCM_RTS);
122         } else {
123                 tegra_uart_set_mctrl(bsi->uport, 0);
124                 tegra_uart_request_clock_off(bsi->uport);
125         }
126 }
127
128
129
130 /**
131  * @brief@  main sleep work handling function which update the flags
132  * and activate and deactivate UART .
133  */
134
135 static void hostwake_sleep_work(struct work_struct *work)
136 {
137         int retval ;    
138         pr_debug("%s", __func__);
139         free_irq(bsi->host_wake_irq, "tibluesleep");
140         /*Activating UART */
141         if (test_bit(BT_SUSPEND, &flags)) {
142                 BT_DBG("Activate UART");
143                 hsuart_power(1);
144
145         }
146         bsi->has_ext_wake = 0;
147         clear_bit(BT_SUSPEND, &flags);
148         set_bit(BT_ACTIVE, &flags);
149
150 }
151
152
153 /**
154  * A tasklet function that runs in tasklet context 
155  * @param data Not used.
156  */
157 static void bluesleep_hostwake_task(unsigned long data)
158 {
159         pr_debug("%s", __func__);
160         disable_irq(bsi->host_wake_irq);
161         spin_lock(&rw_lock);
162         hostwake_workqueue();
163         spin_unlock(&rw_lock);
164
165 }
166
167
168 /**
169  * Schedules a tasklet to run when receiving an interrupt on the
170  * <code>HOST_WAKE</code> GPIO pin.
171  * @param irq Not used.
172  * @param dev_id Not used.
173  */
174 static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id)
175 {
176
177         pr_debug("%s", __func__);
178         /* schedule a tasklet to handle the change in the host wake line */
179         bsi->has_ext_wake = 1;
180         tasklet_schedule(&hostwake_task);
181         return IRQ_HANDLED;
182 }
183
184 /**
185  * Starts the Sleep-Mode Protocol on the Host.
186  * @return On success, 0. On error, -1, and <code>errno</code> is set
187  * appropriately.
188  */
189
190   int bluesleep_start(struct uart_port *uport)
191 {
192         int retval;
193
194         bsi->uport = uport;
195
196         pr_debug("%s", __func__);
197
198         if (test_bit(BT_SUSPEND, &flags)) {
199
200
201                 BT_DBG("bluesleep_acquire irq");
202                 if (bsi->irq_polarity == POLARITY_LOW) {
203                         retval = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
204                                         IRQF_DISABLED | IRQF_TRIGGER_FALLING,
205                                         "bluetooth hostwake", "tibluesleep");
206                 } else  {
207                         retval = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
208                                         IRQF_DISABLED | IRQF_TRIGGER_RISING,
209                                         "bluetooth hostwake", "tibluesleep");
210                 }
211                 if (retval  < 0) {
212                         BT_ERR("Couldn't acquire BT_HOST_WAKE IRQ");
213                         goto fail;
214                 }
215
216         retval = enable_irq_wake(bsi->host_wake_irq);
217         if (retval < 0) {
218                 BT_ERR("Couldn't enable BT_HOST_WAKE as wakeup interrupt retval %d\n",retval);
219                 free_irq(bsi->host_wake_irq, NULL);
220                 goto fail;
221         }
222
223         }
224
225         return 0;
226 fail:
227         atomic_inc(&open_count);
228
229         return retval;
230 }
231
232 /**
233  * Stops the Sleep-Mode Protocol on the Host.
234  */
235   void bluesleep_stop(void)
236 {
237
238         pr_debug("%s", __func__);
239
240         if (disable_irq_wake(bsi->host_wake_irq))
241                 BT_ERR("Couldn't disable hostwake IRQ wakeup mode\n");
242
243         free_irq(bsi->host_wake_irq, NULL);
244
245 }
246
247 static int bluesleep_probe(struct platform_device *pdev)
248 {
249         int ret;
250         struct resource *res;
251
252         struct kim_data_s *kim_gdata;
253         struct st_data_s *core_data;
254         kim_gdata = dev_get_drvdata(&pdev->dev);
255         core_data = kim_gdata->core_data;
256         struct uart_state *state = (struct uart_state *)core_data->tty->driver_data;    
257
258
259         bsi = kzalloc(sizeof(struct bluesleep_info), GFP_KERNEL);
260         if (!bsi)
261                 return -ENOMEM;
262
263
264         res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
265                                                 "host_wake");
266         if (!res) {
267                 BT_ERR("couldn't find host_wake irq\n");
268                 ret = -ENODEV;
269                 goto free_bsi;
270         }
271
272         bsi->host_wake_irq = res->start;        
273
274         if (bsi->host_wake_irq < 0) {
275                 BT_ERR("couldn't find host_wake irq");
276                 ret = -ENODEV;
277                 goto free_bsi;
278         }
279         if (res->flags & IORESOURCE_IRQ_LOWEDGE)
280                 bsi->irq_polarity = POLARITY_LOW;/*low edge (falling edge)*/
281         else
282                 bsi->irq_polarity = POLARITY_HIGH;/*anything else*/
283
284         wake_lock_init(&bsi->wake_lock, WAKE_LOCK_SUSPEND, "bluesleep");
285         clear_bit(BT_SUSPEND, &flags);
286         set_bit(BT_ACTIVE, &flags);
287
288         return 0;
289
290
291 free_bsi:
292         kfree(bsi);
293         return ret;
294 }
295
296 static int bluesleep_remove(struct platform_device *pdev)
297 {
298         pr_debug("%s", __func__);
299         kfree(bsi);
300         return 0;
301 }
302
303
304 static int bluesleep_resume(struct platform_device *pdev)
305 {
306
307         pr_debug("%s", __func__);
308         if (test_bit(BT_SUSPEND, &flags)) {
309         
310                 if ((bsi->uport != NULL) && (bsi->has_ext_wake)) {
311                         tegra_uart_request_clock_on(bsi->uport);
312                         tegra_uart_set_mctrl(bsi->uport, TIOCM_RTS);
313                         
314
315                 }
316                 clear_bit(BT_SUSPEND, &flags);
317                 set_bit(BT_ACTIVE, &flags);
318         }
319
320         return 0;
321 }
322
323 static int bluesleep_suspend(struct platform_device *pdev, pm_message_t state)
324 {
325         pr_debug("%s", __func__);
326         set_bit(BT_SUSPEND, &flags);
327         return 0;
328 }
329
330 static struct platform_driver bluesleep_driver = {
331         .probe = bluesleep_probe,
332         .remove = bluesleep_remove,
333         .suspend = bluesleep_suspend,
334         .resume = bluesleep_resume,
335         .driver = {
336                 .name = "tibluesleep",
337                 .owner = THIS_MODULE,
338         },
339 };
340 /**
341  * Initializes the module.
342  * @return On success, 0. On error, -1, and <code>errno</code> is set
343  * appropriately.
344  */
345 static int __init bluesleep_init(void)
346 {
347         int retval;
348         struct proc_dir_entry *ent;
349
350         BT_INFO("BlueSleep Mode Driver Ver %s", VERSION);
351
352         retval = platform_driver_register(&bluesleep_driver);
353         if (retval)
354                 return retval;
355
356         if (bsi == NULL)
357                 return 0;
358
359         flags = FLAG_RESET; /* clear all status bits */
360
361         /* Initialize spinlock. */
362         spin_lock_init(&rw_lock);
363
364         /* initialize host wake tasklet */
365         tasklet_init(&hostwake_task, bluesleep_hostwake_task, 0);
366
367         return 0;
368 fail:
369         return retval;
370 }
371
372 /**
373  * Cleans up the module.
374  */
375
376 static void __exit bluesleep_exit(void)
377 {
378         if (bsi == NULL)
379                 return;
380         /* assert bt wake */
381         free_irq(bsi->host_wake_irq, NULL);
382         platform_driver_unregister(&bluesleep_driver);
383
384 }
385
386 module_init(bluesleep_init);
387 module_exit(bluesleep_exit);
388
389 MODULE_DESCRIPTION("TI Bluetooth Sleep Mode Driver ver %s " VERSION);
390 #ifdef MODULE_LICENSE
391 MODULE_LICENSE("GPL");
392 #endif