blob: 0383d8fc756f0ce2fa99f024f3dafa82a872a6fd [file] [log] [blame]
Suraj Sumangalab3190df2010-07-19 12:34:07 +05301/*
2 * Atheros Communication Bluetooth HCIATH3K UART protocol
3 *
4 * HCIATH3K (HCI Atheros AR300x Protocol) is a Atheros Communication's
5 * power management protocol extension to H4 to support AR300x Bluetooth Chip.
6 *
7 * Copyright (c) 2009-2010 Atheros Communications Inc.
Ram Mohan Korukonda0eadc592013-03-19 22:29:45 +05308 * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
Suraj Sumangalab3190df2010-07-19 12:34:07 +05309 *
10 * Acknowledgements:
11 * This file is based on hci_h4.c, which was written
12 * by Maxim Krasnyansky and Marcel Holtmann.
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 *
28 */
29
30#include <linux/module.h>
31#include <linux/kernel.h>
32
33#include <linux/init.h>
34#include <linux/slab.h>
35#include <linux/tty.h>
36#include <linux/errno.h>
37#include <linux/ioctl.h>
38#include <linux/skbuff.h>
Santosh Sajjan55efc7f2012-06-27 19:10:49 +053039#include <linux/platform_device.h>
40#include <linux/gpio.h>
Ram Mohan Korukonda0eadc592013-03-19 22:29:45 +053041#include <linux/of_gpio.h>
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +053042#include <linux/proc_fs.h>
43
Suraj Sumangalab3190df2010-07-19 12:34:07 +053044#include <net/bluetooth/bluetooth.h>
45#include <net/bluetooth/hci_core.h>
46
47#include "hci_uart.h"
Ram Mohan Korukondaeff0e072012-11-19 16:05:52 +053048#ifdef CONFIG_SERIAL_MSM_HS
49#include <mach/msm_serial_hs.h>
50#endif
Suraj Sumangalab3190df2010-07-19 12:34:07 +053051
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +053052static int enableuartsleep = 1;
53module_param(enableuartsleep, int, 0644);
54MODULE_PARM_DESC(enableuartsleep, "Enable Atheros Sleep Protocol");
55
Santosh Sajjan55efc7f2012-06-27 19:10:49 +053056/*
57 * Global variables
58 */
Ram Mohan Korukonda0eadc592013-03-19 22:29:45 +053059
60/** Device table */
61static struct of_device_id bluesleep_match_table[] = {
62 { .compatible = "qca,ar3002_bluesleep" },
63 {}
64};
65
Santosh Sajjan55efc7f2012-06-27 19:10:49 +053066/** Global state flags */
67static unsigned long flags;
68
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +053069/** To Check LPM is enabled */
70static bool is_lpm_enabled;
71
Ram Mohan Korukondaeff0e072012-11-19 16:05:52 +053072/** Workqueue to respond to change in hostwake line */
73static void wakeup_host_work(struct work_struct *work);
Santosh Sajjan55efc7f2012-06-27 19:10:49 +053074
75/** Transmission timer */
76static void bluesleep_tx_timer_expire(unsigned long data);
77static DEFINE_TIMER(tx_timer, bluesleep_tx_timer_expire, 0, 0);
78
79/** Lock for state transitions */
80static spinlock_t rw_lock;
81
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +053082#define PROC_DIR "bluetooth/sleep"
83
Santosh Sajjan55efc7f2012-06-27 19:10:49 +053084#define POLARITY_LOW 0
85#define POLARITY_HIGH 1
86
87struct bluesleep_info {
88 unsigned host_wake; /* wake up host */
89 unsigned ext_wake; /* wake up device */
90 unsigned host_wake_irq;
91 int irq_polarity;
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +053092 struct uart_port *uport;
Santosh Sajjan55efc7f2012-06-27 19:10:49 +053093};
94
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +053095struct work_struct ws_sleep;
96
Santosh Sajjan55efc7f2012-06-27 19:10:49 +053097/* 1 second timeout */
98#define TX_TIMER_INTERVAL 1
99
100/* state variable names and bit positions */
101#define BT_TXEXPIRED 0x01
102#define BT_SLEEPENABLE 0x02
103#define BT_SLEEPCMD 0x03
104
105/* global pointer to a single hci device. */
106static struct bluesleep_info *bsi;
107
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530108struct ath_struct {
109 struct hci_uart *hu;
110 unsigned int cur_sleep;
111
112 struct sk_buff_head txq;
113 struct work_struct ctxtsw;
114};
115
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530116static void hsuart_serial_clock_on(struct uart_port *port)
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530117{
Ram Mohan Korukondaeff0e072012-11-19 16:05:52 +0530118 BT_DBG("");
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530119 if (port)
120 msm_hs_request_clock_on(port);
121 else
122 BT_INFO("Uart has not voted for Clock ON");
Ram Mohan Korukondaeff0e072012-11-19 16:05:52 +0530123}
124
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530125static void hsuart_serial_clock_off(struct uart_port *port)
Ram Mohan Korukondaeff0e072012-11-19 16:05:52 +0530126{
Ram Mohan Korukondaeff0e072012-11-19 16:05:52 +0530127 BT_DBG("");
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530128 if (port)
129 msm_hs_request_clock_off(port);
130 else
131 BT_INFO("Uart has not voted for Clock OFF");
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530132}
133
134static void modify_timer_task(void)
135{
136 spin_lock(&rw_lock);
137 mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ));
138 clear_bit(BT_TXEXPIRED, &flags);
139 spin_unlock(&rw_lock);
140
141}
142
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530143static int ath_wakeup_ar3k(void)
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530144{
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530145 int status = 0;
146 if (test_bit(BT_TXEXPIRED, &flags)) {
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530147 hsuart_serial_clock_on(bsi->uport);
148 BT_DBG("wakeup device\n");
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530149 gpio_set_value(bsi->ext_wake, 0);
Ram Mohan Korukondaeb530d192012-08-08 16:54:51 +0530150 msleep(20);
151 gpio_set_value(bsi->ext_wake, 1);
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530152 }
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530153 if (!is_lpm_enabled)
154 modify_timer_task();
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530155 return status;
156}
157
Ram Mohan Korukondaeff0e072012-11-19 16:05:52 +0530158static void wakeup_host_work(struct work_struct *work)
159{
Ram Mohan Korukondaeff0e072012-11-19 16:05:52 +0530160
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530161 BT_DBG("wake up host");
Ram Mohan Korukondaeff0e072012-11-19 16:05:52 +0530162 if (test_bit(BT_SLEEPENABLE, &flags)) {
163 if (test_bit(BT_TXEXPIRED, &flags))
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530164 hsuart_serial_clock_on(bsi->uport);
Ram Mohan Korukondaeff0e072012-11-19 16:05:52 +0530165 }
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530166 if (!is_lpm_enabled)
167 modify_timer_task();
Ram Mohan Korukondaeff0e072012-11-19 16:05:52 +0530168}
169
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530170static void ath_hci_uart_work(struct work_struct *work)
171{
172 int status;
173 struct ath_struct *ath;
174 struct hci_uart *hu;
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530175
176 ath = container_of(work, struct ath_struct, ctxtsw);
177
178 hu = ath->hu;
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530179
180 /* verify and wake up controller */
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530181 if (test_bit(BT_SLEEPENABLE, &flags))
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530182 status = ath_wakeup_ar3k();
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530183 /* Ready to send Data */
184 clear_bit(HCI_UART_SENDING, &hu->tx_state);
185 hci_uart_tx_wakeup(hu);
186}
187
Ram Mohan Korukondae359d862012-08-18 21:12:17 +0530188static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id)
189{
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530190 /* schedule a work to global shared workqueue to handle
191 * the change in the host wake line
192 */
193 schedule_work(&ws_sleep);
Ram Mohan Korukondaeff0e072012-11-19 16:05:52 +0530194
Ram Mohan Korukondae359d862012-08-18 21:12:17 +0530195 return IRQ_HANDLED;
196}
197
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530198static int ath_bluesleep_gpio_config(int on)
Ram Mohan Korukondae359d862012-08-18 21:12:17 +0530199{
200 int ret = 0;
201
202 BT_INFO("%s config: %d", __func__, on);
203 if (!on) {
204 if (disable_irq_wake(bsi->host_wake_irq))
205 BT_ERR("Couldn't disable hostwake IRQ wakeup mode\n");
206 goto free_host_wake_irq;
207 }
208
209 ret = gpio_request(bsi->host_wake, "bt_host_wake");
210 if (ret < 0) {
211 BT_ERR("failed to request gpio pin %d, error %d\n",
212 bsi->host_wake, ret);
213 goto gpio_config_failed;
214 }
215
216 /* configure host_wake as input */
217 ret = gpio_direction_input(bsi->host_wake);
218 if (ret < 0) {
219 BT_ERR("failed to config GPIO %d as input pin, err %d\n",
220 bsi->host_wake, ret);
221 goto gpio_host_wake;
222 }
223
224 ret = gpio_request(bsi->ext_wake, "bt_ext_wake");
225 if (ret < 0) {
226 BT_ERR("failed to request gpio pin %d, error %d\n",
227 bsi->ext_wake, ret);
228 goto gpio_host_wake;
229 }
230
231 ret = gpio_direction_output(bsi->ext_wake, 1);
232 if (ret < 0) {
233 BT_ERR("failed to config GPIO %d as output pin, err %d\n",
234 bsi->ext_wake, ret);
235 goto gpio_ext_wake;
236 }
237
238 gpio_set_value(bsi->ext_wake, 1);
239
240 /* Initialize spinlock. */
241 spin_lock_init(&rw_lock);
242
243 /* Initialize timer */
244 init_timer(&tx_timer);
245 tx_timer.function = bluesleep_tx_timer_expire;
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530246 tx_timer.data = 0;
Ram Mohan Korukondae359d862012-08-18 21:12:17 +0530247
248 if (bsi->irq_polarity == POLARITY_LOW) {
249 ret = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
250 IRQF_DISABLED | IRQF_TRIGGER_FALLING,
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530251 "bluetooth hostwake", NULL);
Ram Mohan Korukondae359d862012-08-18 21:12:17 +0530252 } else {
253 ret = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
254 IRQF_DISABLED | IRQF_TRIGGER_RISING,
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530255 "bluetooth hostwake", NULL);
Ram Mohan Korukondae359d862012-08-18 21:12:17 +0530256 }
257 if (ret < 0) {
258 BT_ERR("Couldn't acquire BT_HOST_WAKE IRQ");
259 goto delete_timer;
260 }
261
262 ret = enable_irq_wake(bsi->host_wake_irq);
263 if (ret < 0) {
264 BT_ERR("Couldn't enable BT_HOST_WAKE as wakeup interrupt");
265 goto free_host_wake_irq;
266 }
267
268 return 0;
269
270free_host_wake_irq:
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530271 free_irq(bsi->host_wake_irq, NULL);
Ram Mohan Korukondae359d862012-08-18 21:12:17 +0530272delete_timer:
273 del_timer(&tx_timer);
274gpio_ext_wake:
275 gpio_free(bsi->ext_wake);
276gpio_host_wake:
277 gpio_free(bsi->host_wake);
278gpio_config_failed:
279 return ret;
280}
281
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530282static int ath_lpm_start(void)
283{
284 BT_DBG("Start LPM mode");
285
286 if (!bsi) {
287 BT_ERR("HCIATH3K bluesleep info does not exist");
288 return -EIO;
289 }
290
291 bsi->uport = msm_hs_get_uart_port(0);
292 if (!bsi->uport) {
293 BT_ERR("UART Port is not available");
294 return -ENODEV;
295 }
296
297 INIT_WORK(&ws_sleep, wakeup_host_work);
298
299 if (ath_bluesleep_gpio_config(1) < 0) {
300 BT_ERR("HCIATH3K GPIO Config failed");
301 return -EIO;
302 }
303
304 return 0;
305}
306
307static int ath_lpm_stop(void)
308{
309 BT_DBG("Stop LPM mode");
310 cancel_work_sync(&ws_sleep);
311
312 if (bsi) {
313 bsi->uport = NULL;
314 ath_bluesleep_gpio_config(0);
315 }
316
317 return 0;
318}
319
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530320/* Initialize protocol */
321static int ath_open(struct hci_uart *hu)
322{
323 struct ath_struct *ath;
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530324 struct uart_state *state;
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530325
Ram Mohan Korukondae359d862012-08-18 21:12:17 +0530326 BT_DBG("hu %p, bsi %p", hu, bsi);
327
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530328 if (!bsi) {
329 BT_ERR("HCIATH3K bluesleep info does not exist");
Ram Mohan Korukondae359d862012-08-18 21:12:17 +0530330 return -EIO;
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530331 }
Ram Mohan Korukondae359d862012-08-18 21:12:17 +0530332
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530333 ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530334 if (!ath) {
335 BT_ERR("HCIATH3K Memory not enough to init driver");
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530336 return -ENOMEM;
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530337 }
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530338
339 skb_queue_head_init(&ath->txq);
340
341 hu->priv = ath;
342 ath->hu = hu;
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530343 state = hu->tty->driver_data;
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530344
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530345 if (!state) {
346 BT_ERR("HCIATH3K tty driver data does not exist");
347 return -ENXIO;
348 }
349 bsi->uport = state->uart_port;
350
351 if (ath_bluesleep_gpio_config(1) < 0) {
Ram Mohan Korukondaeff0e072012-11-19 16:05:52 +0530352 BT_ERR("HCIATH3K GPIO Config failed");
353 hu->priv = NULL;
354 kfree(ath);
355 return -EIO;
356 }
357
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530358 ath->cur_sleep = enableuartsleep;
359 if (ath->cur_sleep == 1) {
360 set_bit(BT_SLEEPENABLE, &flags);
361 modify_timer_task();
362 }
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530363 INIT_WORK(&ath->ctxtsw, ath_hci_uart_work);
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530364 INIT_WORK(&ws_sleep, wakeup_host_work);
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530365 return 0;
366}
367
368/* Flush protocol data */
369static int ath_flush(struct hci_uart *hu)
370{
371 struct ath_struct *ath = hu->priv;
372
373 BT_DBG("hu %p", hu);
374
375 skb_queue_purge(&ath->txq);
376
377 return 0;
378}
379
380/* Close protocol */
381static int ath_close(struct hci_uart *hu)
382{
383 struct ath_struct *ath = hu->priv;
384
385 BT_DBG("hu %p", hu);
386
387 skb_queue_purge(&ath->txq);
388
389 cancel_work_sync(&ath->ctxtsw);
390
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530391 cancel_work_sync(&ws_sleep);
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530392
Ram Mohan Korukondae359d862012-08-18 21:12:17 +0530393 if (bsi)
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530394 ath_bluesleep_gpio_config(0);
Ram Mohan Korukondaeff0e072012-11-19 16:05:52 +0530395
396 hu->priv = NULL;
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530397 bsi->uport = NULL;
Ram Mohan Korukondaeff0e072012-11-19 16:05:52 +0530398 kfree(ath);
Ram Mohan Korukondae359d862012-08-18 21:12:17 +0530399
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530400 return 0;
401}
402
403#define HCI_OP_ATH_SLEEP 0xFC04
404
405/* Enqueue frame for transmittion */
406static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
407{
408 struct ath_struct *ath = hu->priv;
409
Ram Mohan Korukondae359d862012-08-18 21:12:17 +0530410 BT_DBG("");
411
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530412 if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
Dan Carpenter4ebaa4e2010-07-23 12:11:04 +0200413 kfree_skb(skb);
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530414 return 0;
415 }
416
417 /*
418 * Update power management enable flag with parameters of
419 * HCI sleep enable vendor specific HCI command.
420 */
421 if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) {
422 struct hci_command_hdr *hdr = (void *)skb->data;
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530423 if (__le16_to_cpu(hdr->opcode) == HCI_OP_ATH_SLEEP) {
424 set_bit(BT_SLEEPCMD, &flags);
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530425 ath->cur_sleep = skb->data[HCI_COMMAND_HDR_SIZE];
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530426 }
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530427 }
428
429 BT_DBG("hu %p skb %p", hu, skb);
430
431 /* Prepend skb with frame type */
432 memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
433
434 skb_queue_tail(&ath->txq, skb);
435 set_bit(HCI_UART_SENDING, &hu->tx_state);
436
437 schedule_work(&ath->ctxtsw);
438
439 return 0;
440}
441
442static struct sk_buff *ath_dequeue(struct hci_uart *hu)
443{
444 struct ath_struct *ath = hu->priv;
445
446 return skb_dequeue(&ath->txq);
447}
448
449/* Recv data */
450static int ath_recv(struct hci_uart *hu, void *data, int count)
451{
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530452 struct ath_struct *ath = hu->priv;
453 unsigned int type;
Jiejing Zhang78b4a562011-04-07 20:37:06 +0800454
Ram Mohan Korukondae359d862012-08-18 21:12:17 +0530455 BT_DBG("");
456
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530457 if (hci_recv_stream_fragment(hu->hdev, data, count) < 0)
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530458 BT_ERR("Frame Reassembly Failed");
459
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530460 if (count & test_bit(BT_SLEEPCMD, &flags)) {
461 struct sk_buff *skb = hu->hdev->reassembly[0];
462
463 if (!skb) {
464 struct { char type; } *pkt;
465
466 /* Start of the frame */
467 pkt = data;
468 type = pkt->type;
469 } else
470 type = bt_cb(skb)->pkt_type;
471
472 if (type == HCI_EVENT_PKT) {
473 clear_bit(BT_SLEEPCMD, &flags);
Ram Mohan Korukondae359d862012-08-18 21:12:17 +0530474 BT_INFO("cur_sleep:%d\n", ath->cur_sleep);
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530475 if (ath->cur_sleep == 1)
476 set_bit(BT_SLEEPENABLE, &flags);
477 else
478 clear_bit(BT_SLEEPENABLE, &flags);
479 }
480 if (test_bit(BT_SLEEPENABLE, &flags))
481 modify_timer_task();
482 }
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530483 return count;
484}
485
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530486static void bluesleep_tx_timer_expire(unsigned long data)
487{
Ram Mohan Korukondaeff0e072012-11-19 16:05:52 +0530488
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530489 if (!test_bit(BT_SLEEPENABLE, &flags))
490 return;
Ram Mohan Korukondae359d862012-08-18 21:12:17 +0530491 BT_INFO("Tx timer expired\n");
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530492
493 set_bit(BT_TXEXPIRED, &flags);
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530494 hsuart_serial_clock_off(bsi->uport);
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530495}
496
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530497static struct hci_uart_proto athp = {
498 .id = HCI_UART_ATH3K,
499 .open = ath_open,
500 .close = ath_close,
501 .recv = ath_recv,
502 .enqueue = ath_enqueue,
503 .dequeue = ath_dequeue,
504 .flush = ath_flush,
505};
506
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530507static int lpm_enabled;
508
509static int bluesleep_lpm_set(const char *val, const struct kernel_param *kp)
510{
511 int ret;
512
513 ret = param_set_int(val, kp);
514
515 if (ret) {
516 BT_ERR("HCIATH3K: lpm enable parameter set failed");
517 return ret;
518 }
519
520 BT_DBG("lpm : %d", lpm_enabled);
521
522 if ((lpm_enabled == 0) && is_lpm_enabled) {
523 ath_lpm_stop();
524 clear_bit(BT_SLEEPENABLE, &flags);
525 is_lpm_enabled = false;
526 } else if ((lpm_enabled == 1) && !is_lpm_enabled) {
527 if (ath_lpm_start() < 0) {
528 BT_ERR("HCIATH3K LPM mode failed");
529 return -EIO;
530 }
531 set_bit(BT_SLEEPENABLE, &flags);
532 is_lpm_enabled = true;
533 } else {
534 BT_ERR("HCIATH3K invalid lpm value");
535 return -EINVAL;
536 }
537 return 0;
538
539}
540
541static struct kernel_param_ops bluesleep_lpm_ops = {
542 .set = bluesleep_lpm_set,
543 .get = param_get_int,
544};
545
546module_param_cb(ath_lpm, &bluesleep_lpm_ops,
547 &lpm_enabled, S_IRUGO | S_IWUSR);
548MODULE_PARM_DESC(ath_lpm, "Enable Atheros LPM sleep Protocol");
549
550static int lpm_btwrite;
551
552static int bluesleep_lpm_btwrite(const char *val, const struct kernel_param *kp)
553{
554 int ret;
555
556 ret = param_set_int(val, kp);
557
558 if (ret) {
559 BT_ERR("HCIATH3K: lpm btwrite parameter set failed");
560 return ret;
561 }
562
563 BT_DBG("btwrite : %d", lpm_btwrite);
564 if (is_lpm_enabled) {
565 if (lpm_btwrite == 0) {
566 /*Setting TXEXPIRED bit to make it
567 compatible with current solution*/
568 set_bit(BT_TXEXPIRED, &flags);
569 hsuart_serial_clock_off(bsi->uport);
570 } else if (lpm_btwrite == 1) {
571 ath_wakeup_ar3k();
572 clear_bit(BT_TXEXPIRED, &flags);
573 } else {
574 BT_ERR("HCIATH3K invalid btwrite value");
575 return -EINVAL;
576 }
577 }
578 return 0;
579}
580
581static struct kernel_param_ops bluesleep_lpm_btwrite_ops = {
582 .set = bluesleep_lpm_btwrite,
583 .get = param_get_int,
584};
585
586module_param_cb(ath_btwrite, &bluesleep_lpm_btwrite_ops,
587 &lpm_btwrite, S_IRUGO | S_IWUSR);
588MODULE_PARM_DESC(ath_lpm, "Assert/Deassert the sleep");
Ram Mohan Korukonda0eadc592013-03-19 22:29:45 +0530589
590static int bluesleep_populate_dt_pinfo(struct platform_device *pdev)
591{
592 BT_DBG("");
593
594 if (!bsi)
595 return -ENOMEM;
596
597 bsi->host_wake = of_get_named_gpio(pdev->dev.of_node,
598 "host-wake-gpio", 0);
599 if (bsi->host_wake < 0) {
600 BT_ERR("couldn't find host_wake gpio\n");
601 return -ENODEV;
602 }
603
604 bsi->ext_wake = of_get_named_gpio(pdev->dev.of_node,
605 "ext-wake-gpio", 0);
606 if (bsi->ext_wake < 0) {
607 BT_ERR("couldn't find ext_wake gpio\n");
608 return -ENODEV;
609 }
610
611 return 0;
612}
613
614static int bluesleep_populate_pinfo(struct platform_device *pdev)
615{
616 struct resource *res;
617
618 BT_DBG("");
619
620 res = platform_get_resource_byname(pdev, IORESOURCE_IO,
621 "gpio_host_wake");
622 if (!res) {
623 BT_ERR("couldn't find host_wake gpio\n");
624 return -ENODEV;
625 }
626 bsi->host_wake = res->start;
627
628 res = platform_get_resource_byname(pdev, IORESOURCE_IO,
629 "gpio_ext_wake");
630 if (!res) {
631 BT_ERR("couldn't find ext_wake gpio\n");
632 return -ENODEV;
633 }
634 bsi->ext_wake = res->start;
635
636 return 0;
637}
638
639static int __devinit bluesleep_probe(struct platform_device *pdev)
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530640{
641 int ret;
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530642
Ram Mohan Korukondae359d862012-08-18 21:12:17 +0530643 BT_DBG("");
644
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530645 bsi = kzalloc(sizeof(struct bluesleep_info), GFP_KERNEL);
646 if (!bsi) {
647 ret = -ENOMEM;
648 goto failed;
649 }
650
Ram Mohan Korukonda0eadc592013-03-19 22:29:45 +0530651 if (pdev->dev.of_node) {
652 ret = bluesleep_populate_dt_pinfo(pdev);
653 if (ret < 0) {
654 BT_ERR("Failed to populate device tree info");
655 goto free_bsi;
656 }
657 } else {
658 ret = bluesleep_populate_pinfo(pdev);
659 if (ret < 0) {
660 BT_ERR("Failed to populate device info");
661 goto free_bsi;
662 }
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530663 }
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530664
Ram Mohan Korukonda0eadc592013-03-19 22:29:45 +0530665 BT_DBG("host_wake_gpio: %d ext_wake_gpio: %d",
666 bsi->host_wake, bsi->ext_wake);
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530667
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530668 bsi->host_wake_irq = platform_get_irq_byname(pdev, "host_wake");
669 if (bsi->host_wake_irq < 0) {
670 BT_ERR("couldn't find host_wake irq\n");
671 ret = -ENODEV;
Ram Mohan Korukondae359d862012-08-18 21:12:17 +0530672 goto free_bsi;
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530673 }
674
675 bsi->irq_polarity = POLARITY_LOW; /* low edge (falling edge) */
676
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530677 return 0;
678
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530679free_bsi:
680 kfree(bsi);
Ram Mohan Korukondae359d862012-08-18 21:12:17 +0530681 bsi = NULL;
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530682failed:
683 return ret;
684}
685
686static int bluesleep_remove(struct platform_device *pdev)
687{
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530688 kfree(bsi);
689 return 0;
690}
691
692static struct platform_driver bluesleep_driver = {
Ram Mohan Korukonda0eadc592013-03-19 22:29:45 +0530693 .probe = bluesleep_probe,
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530694 .remove = bluesleep_remove,
695 .driver = {
696 .name = "bluesleep",
697 .owner = THIS_MODULE,
Ram Mohan Korukonda0eadc592013-03-19 22:29:45 +0530698 .of_match_table = bluesleep_match_table,
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530699 },
700};
701
Gustavo F. Padovanf2b94bb2010-07-24 02:04:44 -0300702int __init ath_init(void)
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530703{
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530704 int ret;
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530705
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530706 ret = hci_uart_register_proto(&athp);
707
708 if (!ret)
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530709 BT_INFO("HCIATH3K protocol initialized");
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530710 else {
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530711 BT_ERR("HCIATH3K protocol registration failed");
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530712 return ret;
713 }
Ram Mohan Korukonda0eadc592013-03-19 22:29:45 +0530714
715 ret = platform_driver_register(&bluesleep_driver);
716 if (ret) {
717 BT_ERR("Failed to register bluesleep driver");
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530718 return ret;
Ram Mohan Korukonda0eadc592013-03-19 22:29:45 +0530719 }
720
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530721 return 0;
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530722}
723
Gustavo F. Padovanf2b94bb2010-07-24 02:04:44 -0300724int __exit ath_deinit(void)
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530725{
Santosh Sajjan55efc7f2012-06-27 19:10:49 +0530726 platform_driver_unregister(&bluesleep_driver);
Ram Mohan Korukonda73e3cf62013-03-13 01:19:58 +0530727
Suraj Sumangalab3190df2010-07-19 12:34:07 +0530728 return hci_uart_unregister_proto(&athp);
729}