2 * drivers/misc/bluedroid_pm.c
4 * Copyright (c) 2012-2013, NVIDIA Corporation. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include <linux/err.h>
22 #include <linux/types.h>
23 #include <linux/uaccess.h>
25 #include <linux/gpio.h>
26 #include <linux/init.h>
27 #include <linux/kernel.h>
28 #include <linux/miscdevice.h>
29 #include <linux/module.h>
30 #include <linux/proc_fs.h>
31 #include <linux/regulator/consumer.h>
32 #include <linux/rfkill.h>
33 #include <linux/platform_device.h>
34 #include <linux/clk.h>
35 #include <linux/interrupt.h>
36 #include <linux/wakelock.h>
37 #include <linux/pm_qos.h>
39 #define PROC_DIR "bluetooth/sleep"
41 /* 5 seconds of Min CPU configurations during resume */
42 #define DEFAULT_RESUME_CPU_TIMEOUT 5000000
44 struct bluedroid_pm_data {
50 int resume_min_frequency;
51 unsigned host_wake_irq;
52 struct regulator *vdd_3v3;
53 struct regulator *vdd_1v8;
54 struct rfkill *rfkill;
55 struct wake_lock wake_lock;
56 struct pm_qos_request resume_cpu_freq_req;
59 struct proc_dir_entry *proc_bt_dir, *bluetooth_sleep_dir;
60 static bool bluedroid_pm_blocked = 1;
62 static int create_bt_proc_interface(void *drv_data);
63 static void remove_bt_proc_interface(void);
65 static irqreturn_t bluedroid_pm_hostwake_isr(int irq, void *dev_id)
67 /* schedule a tasklet to handle the change in the host wake line */
71 static int bluedroid_pm_rfkill_set_power(void *data, bool blocked)
73 struct bluedroid_pm_data *bluedroid_pm = data;
75 * check if BT gpio_shutdown line status and current request are same.
76 * If same, then return, else perform requested operation.
78 if (gpio_get_value(bluedroid_pm->gpio_shutdown) == !blocked)
82 if (bluedroid_pm->gpio_shutdown)
83 gpio_set_value(bluedroid_pm->gpio_shutdown, 0);
84 if (bluedroid_pm->gpio_reset)
85 gpio_set_value(bluedroid_pm->gpio_reset, 0);
86 if (bluedroid_pm->vdd_3v3)
87 regulator_disable(bluedroid_pm->vdd_3v3);
88 if (bluedroid_pm->vdd_1v8)
89 regulator_disable(bluedroid_pm->vdd_1v8);
90 if (bluedroid_pm->ext_wake)
91 wake_unlock(&bluedroid_pm->wake_lock);
92 pm_qos_remove_request(&bluedroid_pm->resume_cpu_freq_req);
94 if (bluedroid_pm->vdd_3v3)
95 regulator_enable(bluedroid_pm->vdd_3v3);
96 if (bluedroid_pm->vdd_1v8)
97 regulator_enable(bluedroid_pm->vdd_1v8);
98 if (bluedroid_pm->gpio_shutdown)
99 gpio_set_value(bluedroid_pm->gpio_shutdown, 1);
100 if (bluedroid_pm->gpio_reset)
101 gpio_set_value(bluedroid_pm->gpio_reset, 1);
102 pm_qos_add_request(&bluedroid_pm->resume_cpu_freq_req,
103 PM_QOS_CPU_FREQ_MIN, PM_QOS_DEFAULT_VALUE);
105 bluedroid_pm->is_blocked = blocked;
109 static const struct rfkill_ops bluedroid_pm_rfkill_ops = {
110 .set_block = bluedroid_pm_rfkill_set_power,
114 * This API is added to set block state by ext driver,
115 * when bluedroid_pm rfkill is not used but host_wake functionality to be used.
116 * Eg: btwilink driver
118 void bluedroid_pm_set_ext_state(bool blocked)
120 bluedroid_pm_blocked = blocked;
122 EXPORT_SYMBOL(bluedroid_pm_set_ext_state);
124 static int bluedroid_pm_probe(struct platform_device *pdev)
126 static struct bluedroid_pm_data *bluedroid_pm;
127 struct rfkill *rfkill;
128 struct resource *res;
130 bool enable = false; /* off */
132 bluedroid_pm = kzalloc(sizeof(*bluedroid_pm), GFP_KERNEL);
136 bluedroid_pm->vdd_3v3 = regulator_get(&pdev->dev, "vdd_bt_3v3");
137 if (IS_ERR_OR_NULL(bluedroid_pm->vdd_3v3)) {
138 pr_warn("%s: regulator vdd_bt_3v3 not available\n", __func__);
139 bluedroid_pm->vdd_3v3 = NULL;
141 bluedroid_pm->vdd_1v8 = regulator_get(&pdev->dev, "vddio_bt_1v8");
142 if (IS_ERR_OR_NULL(bluedroid_pm->vdd_1v8)) {
143 pr_warn("%s: regulator vddio_bt_1v8 not available\n", __func__);
144 bluedroid_pm->vdd_1v8 = NULL;
147 res = platform_get_resource_byname(pdev, IORESOURCE_IO, "reset_gpio");
149 bluedroid_pm->gpio_reset = res->start;
150 ret = gpio_request(bluedroid_pm->gpio_reset, "reset_gpio");
152 pr_err("%s: Failed to get reset gpio\n", __func__);
155 gpio_direction_output(bluedroid_pm->gpio_reset, enable);
157 pr_debug("%s: Reset gpio not registered.\n", __func__);
158 bluedroid_pm->gpio_reset = 0;
161 res = platform_get_resource_byname(pdev, IORESOURCE_IO,
164 bluedroid_pm->gpio_shutdown = res->start;
165 ret = gpio_request(bluedroid_pm->gpio_shutdown,
168 pr_err("%s: Failed to get shutdown gpio\n", __func__);
171 gpio_direction_output(bluedroid_pm->gpio_shutdown, enable);
173 pr_debug("%s: shutdown gpio not registered\n", __func__);
174 bluedroid_pm->gpio_shutdown = 0;
178 * make sure at-least one of the GPIO or regulators avaiable to
179 * register with rfkill is defined
181 if (bluedroid_pm->gpio_reset || bluedroid_pm->gpio_shutdown ||
182 bluedroid_pm->vdd_1v8 || bluedroid_pm->vdd_3v3) {
183 rfkill = rfkill_alloc(pdev->name, &pdev->dev,
184 RFKILL_TYPE_BLUETOOTH, &bluedroid_pm_rfkill_ops,
187 if (unlikely(!rfkill))
190 bluedroid_pm->is_blocked = !enable;
191 rfkill_set_states(rfkill, bluedroid_pm->is_blocked, false);
193 ret = rfkill_register(rfkill);
196 rfkill_destroy(rfkill);
200 bluedroid_pm->rfkill = rfkill;
203 res = platform_get_resource_byname(pdev, IORESOURCE_IO,
206 bluedroid_pm->host_wake = res->start;
207 ret = gpio_request(bluedroid_pm->host_wake, "bt_host_wake");
209 pr_err("%s: Failed to get host_wake gpio\n", __func__);
212 /* configure host_wake as input */
213 gpio_direction_input(bluedroid_pm->host_wake);
215 pr_debug("%s: gpio_host_wake not registered\n", __func__);
216 bluedroid_pm->host_wake = 0;
220 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "host_wake");
222 pr_err("%s : found host_wake irq\n", __func__);
223 bluedroid_pm->host_wake_irq = res->start;
224 ret = request_irq(bluedroid_pm->host_wake_irq,
225 bluedroid_pm_hostwake_isr,
226 IRQF_DISABLED | IRQF_TRIGGER_RISING,
227 "bluetooth hostwake", bluedroid_pm);
229 pr_err("%s: Failed to get host_wake irq\n", __func__);
233 pr_debug("%s: host_wake not registered\n", __func__);
234 bluedroid_pm->host_wake_irq = 0;
237 res = platform_get_resource_byname(pdev, IORESOURCE_IO,
240 bluedroid_pm->ext_wake = res->start;
241 ret = gpio_request(bluedroid_pm->ext_wake, "bt_ext_wake");
243 pr_err("%s: Failed to get ext_wake gpio\n", __func__);
246 /* configure ext_wake as output mode*/
247 gpio_direction_output(bluedroid_pm->ext_wake, 1);
248 if (create_bt_proc_interface(bluedroid_pm)) {
249 pr_err("%s: Failed to create proc interface", __func__);
252 /* initialize wake lock */
253 wake_lock_init(&bluedroid_pm->wake_lock, WAKE_LOCK_SUSPEND,
256 pr_debug("%s: gpio_ext_wake not registered\n", __func__);
257 bluedroid_pm->ext_wake = 0;
260 res = platform_get_resource_byname(pdev, IORESOURCE_IO,
263 bluedroid_pm->resume_min_frequency = res->start;
265 platform_set_drvdata(pdev, bluedroid_pm);
266 pr_debug("RFKILL BT driver successfully registered");
270 if (bluedroid_pm->vdd_3v3)
271 regulator_put(bluedroid_pm->vdd_3v3);
272 if (bluedroid_pm->vdd_1v8)
273 regulator_put(bluedroid_pm->vdd_1v8);
274 if (bluedroid_pm->gpio_shutdown)
275 gpio_free(bluedroid_pm->gpio_shutdown);
276 if (bluedroid_pm->gpio_reset)
277 gpio_free(bluedroid_pm->gpio_reset);
278 if (bluedroid_pm->ext_wake)
279 gpio_free(bluedroid_pm->ext_wake);
280 if (bluedroid_pm->host_wake)
281 gpio_free(bluedroid_pm->host_wake);
282 if (bluedroid_pm->rfkill) {
283 rfkill_unregister(bluedroid_pm->rfkill);
284 rfkill_destroy(bluedroid_pm->rfkill);
285 kfree(bluedroid_pm->rfkill);
291 static int bluedroid_pm_remove(struct platform_device *pdev)
293 struct bluedroid_pm_data *bluedroid_pm = platform_get_drvdata(pdev);
295 if (bluedroid_pm->host_wake)
296 gpio_free(bluedroid_pm->host_wake);
297 if (bluedroid_pm->host_wake_irq)
298 free_irq(bluedroid_pm->host_wake_irq, NULL);
299 if (bluedroid_pm->ext_wake) {
300 wake_lock_destroy(&bluedroid_pm->wake_lock);
301 gpio_free(bluedroid_pm->ext_wake);
302 remove_bt_proc_interface();
304 if (bluedroid_pm->gpio_reset || bluedroid_pm->gpio_shutdown ||
305 bluedroid_pm->vdd_1v8 || bluedroid_pm->vdd_3v3) {
306 rfkill_unregister(bluedroid_pm->rfkill);
307 rfkill_destroy(bluedroid_pm->rfkill);
308 kfree(bluedroid_pm->rfkill);
310 if (bluedroid_pm->gpio_shutdown)
311 gpio_free(bluedroid_pm->gpio_shutdown);
312 if (bluedroid_pm->gpio_reset)
313 gpio_free(bluedroid_pm->gpio_reset);
314 if (bluedroid_pm->vdd_3v3)
315 regulator_put(bluedroid_pm->vdd_3v3);
316 if (bluedroid_pm->vdd_1v8)
317 regulator_put(bluedroid_pm->vdd_1v8);
323 static int bluedroid_pm_suspend(struct platform_device *pdev,
326 struct bluedroid_pm_data *bluedroid_pm = platform_get_drvdata(pdev);
327 if (bluedroid_pm->host_wake)
328 if (!bluedroid_pm->is_blocked || !bluedroid_pm_blocked)
329 enable_irq_wake(bluedroid_pm->host_wake_irq);
334 static int bluedroid_pm_resume(struct platform_device *pdev)
336 struct bluedroid_pm_data *bluedroid_pm = platform_get_drvdata(pdev);
337 if (bluedroid_pm->host_wake)
338 if (!bluedroid_pm->is_blocked || !bluedroid_pm_blocked) {
339 disable_irq_wake(bluedroid_pm->host_wake_irq);
340 if (bluedroid_pm->resume_min_frequency)
341 pm_qos_update_request_timeout(
342 &bluedroid_pm->resume_cpu_freq_req,
343 bluedroid_pm->resume_min_frequency,
344 DEFAULT_RESUME_CPU_TIMEOUT);
349 static struct platform_driver bluedroid_pm_driver = {
350 .probe = bluedroid_pm_probe,
351 .remove = bluedroid_pm_remove,
352 .suspend = bluedroid_pm_suspend,
353 .resume = bluedroid_pm_resume,
355 .name = "bluedroid_pm",
356 .owner = THIS_MODULE,
360 static int lpm_read_proc(char *page, char **start, off_t offset,
361 int count, int *eof, void *data)
364 return sprintf(page, "lpm_read");
367 static int lpm_write_proc(struct file *file, const char *buffer,
368 unsigned long count, void *data)
371 struct bluedroid_pm_data *bluedroid_pm = data;
376 buf = kmalloc(count, GFP_KERNEL);
380 if (copy_from_user(buf, buffer, count)) {
385 if (!bluedroid_pm->is_blocked) {
387 gpio_set_value(bluedroid_pm->ext_wake, 0);
388 wake_unlock(&bluedroid_pm->wake_lock);
389 } else if (buf[0] == '1') {
390 gpio_set_value(bluedroid_pm->ext_wake, 1);
391 wake_lock(&bluedroid_pm->wake_lock);
402 static void remove_bt_proc_interface(void)
404 remove_proc_entry("lpm", bluetooth_sleep_dir);
405 remove_proc_entry("sleep", proc_bt_dir);
406 remove_proc_entry("bluetooth", 0);
409 static int create_bt_proc_interface(void *drv_data)
412 struct proc_dir_entry *ent;
414 proc_bt_dir = proc_mkdir("bluetooth", NULL);
415 if (proc_bt_dir == NULL) {
416 pr_err("Unable to create /proc/bluetooth directory");
420 bluetooth_sleep_dir = proc_mkdir("sleep", proc_bt_dir);
421 if (proc_bt_dir == NULL) {
422 pr_err("Unable to create /proc/bluetooth directory");
426 /* Creating read/write "btwake" entry */
427 ent = create_proc_entry("lpm", 0622, bluetooth_sleep_dir);
429 pr_err("Unable to create /proc/%s/btwake entry", PROC_DIR);
433 ent->read_proc = lpm_read_proc;
434 ent->write_proc = lpm_write_proc;
435 ent->data = drv_data;
438 remove_proc_entry("lpm", bluetooth_sleep_dir);
439 remove_proc_entry("sleep", proc_bt_dir);
440 remove_proc_entry("bluetooth", 0);
444 static int __init bluedroid_pm_init(void)
446 return platform_driver_register(&bluedroid_pm_driver);
449 static void __exit bluedroid_pm_exit(void)
451 platform_driver_unregister(&bluedroid_pm_driver);
454 module_init(bluedroid_pm_init);
455 module_exit(bluedroid_pm_exit);
457 MODULE_DESCRIPTION("bluedroid PM");
458 MODULE_AUTHOR("NVIDIA");
459 MODULE_LICENSE("GPL");