blob: 0574e4444b64567294d4ab867a5d59d16eb28be4 [file] [log] [blame]
Tim Jiang4ce7d7b2018-05-08 13:34:56 +08001/* Copyright (c) 2009-2010, 2013-2018 The Linux Foundation. All rights reserved.
Mahesh Kumar Sharma41a4d382017-01-17 17:00:51 -08002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12/*
13 * Bluetooth Power Switch Module
14 * controls power to external Bluetooth device
15 * with interface to power management device
16 */
17
18#include <linux/init.h>
19#include <linux/module.h>
20#include <linux/kernel.h>
21#include <linux/platform_device.h>
22#include <linux/rfkill.h>
23#include <linux/gpio.h>
24#include <linux/of_gpio.h>
25#include <linux/delay.h>
26#include <linux/bluetooth-power.h>
27#include <linux/slab.h>
28#include <linux/regulator/consumer.h>
29#include <linux/clk.h>
30
31#if defined(CONFIG_CNSS)
32#include <net/cnss.h>
33#endif
34
35#include "btfm_slim.h"
36#include <linux/fs.h>
37
38#define BT_PWR_DBG(fmt, arg...) pr_debug("%s: " fmt "\n", __func__, ## arg)
39#define BT_PWR_INFO(fmt, arg...) pr_info("%s: " fmt "\n", __func__, ## arg)
40#define BT_PWR_ERR(fmt, arg...) pr_err("%s: " fmt "\n", __func__, ## arg)
41
42
43static const struct of_device_id bt_power_match_table[] = {
44 { .compatible = "qca,ar3002" },
45 { .compatible = "qca,qca6174" },
Tim Jiang4ce7d7b2018-05-08 13:34:56 +080046 { .compatible = "qca,qca9379" },
Mahesh Kumar Sharma41a4d382017-01-17 17:00:51 -080047 { .compatible = "qca,wcn3990" },
48 {}
49};
50
51static struct bluetooth_power_platform_data *bt_power_pdata;
52static struct platform_device *btpdev;
53static bool previous;
54static int pwr_state;
55struct class *bt_class;
56static int bt_major;
57
58static int bt_vreg_init(struct bt_power_vreg_data *vreg)
59{
60 int rc = 0;
61 struct device *dev = &btpdev->dev;
62
63 BT_PWR_DBG("vreg_get for : %s", vreg->name);
64
65 /* Get the regulator handle */
66 vreg->reg = regulator_get(dev, vreg->name);
67 if (IS_ERR(vreg->reg)) {
68 rc = PTR_ERR(vreg->reg);
69 pr_err("%s: regulator_get(%s) failed. rc=%d\n",
70 __func__, vreg->name, rc);
71 goto out;
72 }
73
74 if ((regulator_count_voltages(vreg->reg) > 0)
75 && (vreg->low_vol_level) && (vreg->high_vol_level))
76 vreg->set_voltage_sup = 1;
77
78out:
79 return rc;
80}
81
82static int bt_vreg_enable(struct bt_power_vreg_data *vreg)
83{
84 int rc = 0;
85
86 BT_PWR_DBG("vreg_en for : %s", vreg->name);
87
88 if (!vreg->is_enabled) {
89 if (vreg->set_voltage_sup) {
90 rc = regulator_set_voltage(vreg->reg,
91 vreg->low_vol_level,
92 vreg->high_vol_level);
93 if (rc < 0) {
94 BT_PWR_ERR("vreg_set_vol(%s) failed rc=%d\n",
95 vreg->name, rc);
96 goto out;
97 }
98 }
99
100 if (vreg->load_uA >= 0) {
101 rc = regulator_set_load(vreg->reg,
102 vreg->load_uA);
103 if (rc < 0) {
104 BT_PWR_ERR("vreg_set_mode(%s) failed rc=%d\n",
105 vreg->name, rc);
106 goto out;
107 }
108 }
109
110 rc = regulator_enable(vreg->reg);
111 if (rc < 0) {
112 BT_PWR_ERR("regulator_enable(%s) failed. rc=%d\n",
113 vreg->name, rc);
114 goto out;
115 }
116 vreg->is_enabled = true;
117 }
118out:
119 return rc;
120}
121
122static int bt_vreg_disable(struct bt_power_vreg_data *vreg)
123{
124 int rc = 0;
125
126 if (!vreg)
127 return rc;
128
129 BT_PWR_DBG("vreg_disable for : %s", vreg->name);
130
131 if (vreg->is_enabled) {
132 rc = regulator_disable(vreg->reg);
133 if (rc < 0) {
134 BT_PWR_ERR("regulator_disable(%s) failed. rc=%d\n",
135 vreg->name, rc);
136 goto out;
137 }
138 vreg->is_enabled = false;
139
140 if (vreg->set_voltage_sup) {
141 /* Set the min voltage to 0 */
142 rc = regulator_set_voltage(vreg->reg, 0,
143 vreg->high_vol_level);
144 if (rc < 0) {
145 BT_PWR_ERR("vreg_set_vol(%s) failed rc=%d\n",
146 vreg->name, rc);
147 goto out;
148 }
149 }
150 if (vreg->load_uA >= 0) {
151 rc = regulator_set_load(vreg->reg, 0);
152 if (rc < 0) {
153 BT_PWR_ERR("vreg_set_mode(%s) failed rc=%d\n",
154 vreg->name, rc);
155 }
156 }
157 }
158out:
159 return rc;
160}
161
162static int bt_configure_vreg(struct bt_power_vreg_data *vreg)
163{
164 int rc = 0;
165
166 BT_PWR_DBG("config %s", vreg->name);
167
168 /* Get the regulator handle for vreg */
169 if (!(vreg->reg)) {
170 rc = bt_vreg_init(vreg);
171 if (rc < 0)
172 return rc;
173 }
174 rc = bt_vreg_enable(vreg);
175
176 return rc;
177}
178
179static int bt_clk_enable(struct bt_power_clk_data *clk)
180{
181 int rc = 0;
182
183 BT_PWR_DBG("%s", clk->name);
184
185 /* Get the clock handle for vreg */
186 if (!clk->clk || clk->is_enabled) {
187 BT_PWR_ERR("error - node: %p, clk->is_enabled:%d",
188 clk->clk, clk->is_enabled);
189 return -EINVAL;
190 }
191
192 rc = clk_prepare_enable(clk->clk);
193 if (rc) {
194 BT_PWR_ERR("failed to enable %s, rc(%d)\n", clk->name, rc);
195 return rc;
196 }
197
198 clk->is_enabled = true;
199 return rc;
200}
201
202static int bt_clk_disable(struct bt_power_clk_data *clk)
203{
204 int rc = 0;
205
206 BT_PWR_DBG("%s", clk->name);
207
208 /* Get the clock handle for vreg */
209 if (!clk->clk || !clk->is_enabled) {
210 BT_PWR_ERR("error - node: %p, clk->is_enabled:%d",
211 clk->clk, clk->is_enabled);
212 return -EINVAL;
213 }
214 clk_disable_unprepare(clk->clk);
215
216 clk->is_enabled = false;
217 return rc;
218}
219
220static int bt_configure_gpios(int on)
221{
222 int rc = 0;
223 int bt_reset_gpio = bt_power_pdata->bt_gpio_sys_rst;
224
225 BT_PWR_DBG("bt_gpio= %d on: %d", bt_reset_gpio, on);
226
227 if (on) {
228 rc = gpio_request(bt_reset_gpio, "bt_sys_rst_n");
229 if (rc) {
230 BT_PWR_ERR("unable to request gpio %d (%d)\n",
231 bt_reset_gpio, rc);
232 return rc;
233 }
234
235 rc = gpio_direction_output(bt_reset_gpio, 0);
236 if (rc) {
237 BT_PWR_ERR("Unable to set direction\n");
238 return rc;
239 }
240 msleep(50);
241 rc = gpio_direction_output(bt_reset_gpio, 1);
242 if (rc) {
243 BT_PWR_ERR("Unable to set direction\n");
244 return rc;
245 }
246 msleep(50);
247 } else {
248 gpio_set_value(bt_reset_gpio, 0);
249 msleep(100);
250 }
251 return rc;
252}
253
254static int bluetooth_power(int on)
255{
256 int rc = 0;
257
258 BT_PWR_DBG("on: %d", on);
259
260 if (on) {
261 if (bt_power_pdata->bt_vdd_io) {
262 rc = bt_configure_vreg(bt_power_pdata->bt_vdd_io);
263 if (rc < 0) {
264 BT_PWR_ERR("bt_power vddio config failed");
265 goto out;
266 }
267 }
268 if (bt_power_pdata->bt_vdd_xtal) {
269 rc = bt_configure_vreg(bt_power_pdata->bt_vdd_xtal);
270 if (rc < 0) {
271 BT_PWR_ERR("bt_power vddxtal config failed");
272 goto vdd_xtal_fail;
273 }
274 }
275 if (bt_power_pdata->bt_vdd_core) {
276 rc = bt_configure_vreg(bt_power_pdata->bt_vdd_core);
277 if (rc < 0) {
278 BT_PWR_ERR("bt_power vddcore config failed");
279 goto vdd_core_fail;
280 }
281 }
282 if (bt_power_pdata->bt_vdd_pa) {
283 rc = bt_configure_vreg(bt_power_pdata->bt_vdd_pa);
284 if (rc < 0) {
285 BT_PWR_ERR("bt_power vddpa config failed");
286 goto vdd_pa_fail;
287 }
288 }
289 if (bt_power_pdata->bt_vdd_ldo) {
290 rc = bt_configure_vreg(bt_power_pdata->bt_vdd_ldo);
291 if (rc < 0) {
292 BT_PWR_ERR("bt_power vddldo config failed");
293 goto vdd_ldo_fail;
294 }
295 }
296 if (bt_power_pdata->bt_chip_pwd) {
297 rc = bt_configure_vreg(bt_power_pdata->bt_chip_pwd);
298 if (rc < 0) {
299 BT_PWR_ERR("bt_power chippwd config failed");
300 goto chip_pwd_fail;
301 }
302 }
303 /* Parse dt_info and check if a target requires clock voting.
304 * Enable BT clock when BT is on and disable it when BT is off
305 */
306 if (bt_power_pdata->bt_chip_clk) {
307 rc = bt_clk_enable(bt_power_pdata->bt_chip_clk);
308 if (rc < 0) {
309 BT_PWR_ERR("bt_power gpio config failed");
310 goto clk_fail;
311 }
312 }
313 if (bt_power_pdata->bt_gpio_sys_rst > 0) {
314 rc = bt_configure_gpios(on);
315 if (rc < 0) {
316 BT_PWR_ERR("bt_power gpio config failed");
317 goto gpio_fail;
318 }
319 }
320 } else {
321 if (bt_power_pdata->bt_gpio_sys_rst > 0)
322 bt_configure_gpios(on);
323gpio_fail:
324 if (bt_power_pdata->bt_gpio_sys_rst > 0)
325 gpio_free(bt_power_pdata->bt_gpio_sys_rst);
326 if (bt_power_pdata->bt_chip_clk)
327 bt_clk_disable(bt_power_pdata->bt_chip_clk);
328clk_fail:
329 if (bt_power_pdata->bt_chip_pwd)
330 bt_vreg_disable(bt_power_pdata->bt_chip_pwd);
331chip_pwd_fail:
332 if (bt_power_pdata->bt_vdd_ldo)
333 bt_vreg_disable(bt_power_pdata->bt_vdd_ldo);
334vdd_ldo_fail:
335 if (bt_power_pdata->bt_vdd_pa)
336 bt_vreg_disable(bt_power_pdata->bt_vdd_pa);
337vdd_pa_fail:
338 if (bt_power_pdata->bt_vdd_core)
339 bt_vreg_disable(bt_power_pdata->bt_vdd_core);
340vdd_core_fail:
341 if (bt_power_pdata->bt_vdd_xtal)
342 bt_vreg_disable(bt_power_pdata->bt_vdd_xtal);
343vdd_xtal_fail:
344 if (bt_power_pdata->bt_vdd_io)
345 bt_vreg_disable(bt_power_pdata->bt_vdd_io);
346 }
347out:
348 return rc;
349}
350
351static int bluetooth_toggle_radio(void *data, bool blocked)
352{
353 int ret = 0;
354 int (*power_control)(int enable);
355
356 power_control =
357 ((struct bluetooth_power_platform_data *)data)->bt_power_setup;
358
359 if (previous != blocked)
360 ret = (*power_control)(!blocked);
361 if (!ret)
362 previous = blocked;
363 return ret;
364}
365
366static const struct rfkill_ops bluetooth_power_rfkill_ops = {
367 .set_block = bluetooth_toggle_radio,
368};
369
370#if defined(CONFIG_CNSS) && defined(CONFIG_CLD_LL_CORE)
371static ssize_t enable_extldo(struct device *dev, struct device_attribute *attr,
372 char *buf)
373{
374 int ret;
375 bool enable = false;
376 struct cnss_platform_cap cap;
377
378 ret = cnss_get_platform_cap(&cap);
379 if (ret) {
380 BT_PWR_ERR("Platform capability info from CNSS not available!");
381 enable = false;
382 } else if (!ret && (cap.cap_flag & CNSS_HAS_EXTERNAL_SWREG)) {
383 enable = true;
384 }
385 return snprintf(buf, 6, "%s", (enable ? "true" : "false"));
386}
387#else
388static ssize_t enable_extldo(struct device *dev, struct device_attribute *attr,
389 char *buf)
390{
391 return snprintf(buf, 6, "%s", "false");
392}
393#endif
394
395static DEVICE_ATTR(extldo, 0444, enable_extldo, NULL);
396
397static int bluetooth_power_rfkill_probe(struct platform_device *pdev)
398{
399 struct rfkill *rfkill;
400 int ret;
401
402 rfkill = rfkill_alloc("bt_power", &pdev->dev, RFKILL_TYPE_BLUETOOTH,
403 &bluetooth_power_rfkill_ops,
404 pdev->dev.platform_data);
405
406 if (!rfkill) {
407 dev_err(&pdev->dev, "rfkill allocate failed\n");
408 return -ENOMEM;
409 }
410
411 /* add file into rfkill0 to handle LDO27 */
412 ret = device_create_file(&pdev->dev, &dev_attr_extldo);
413 if (ret < 0)
414 BT_PWR_ERR("device create file error!");
415
416 /* force Bluetooth off during init to allow for user control */
417 rfkill_init_sw_state(rfkill, 1);
418 previous = 1;
419
420 ret = rfkill_register(rfkill);
421 if (ret) {
422 dev_err(&pdev->dev, "rfkill register failed=%d\n", ret);
423 rfkill_destroy(rfkill);
424 return ret;
425 }
426
427 platform_set_drvdata(pdev, rfkill);
428
429 return 0;
430}
431
432static void bluetooth_power_rfkill_remove(struct platform_device *pdev)
433{
434 struct rfkill *rfkill;
435
436 dev_dbg(&pdev->dev, "%s\n", __func__);
437
438 rfkill = platform_get_drvdata(pdev);
439 if (rfkill)
440 rfkill_unregister(rfkill);
441 rfkill_destroy(rfkill);
442 platform_set_drvdata(pdev, NULL);
443}
444
445#define MAX_PROP_SIZE 32
446static int bt_dt_parse_vreg_info(struct device *dev,
447 struct bt_power_vreg_data **vreg_data, const char *vreg_name)
448{
449 int len, ret = 0;
450 const __be32 *prop;
451 char prop_name[MAX_PROP_SIZE];
452 struct bt_power_vreg_data *vreg;
453 struct device_node *np = dev->of_node;
454
455 BT_PWR_DBG("vreg dev tree parse for %s", vreg_name);
456
457 *vreg_data = NULL;
458 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
459 if (of_parse_phandle(np, prop_name, 0)) {
460 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
461 if (!vreg) {
462 dev_err(dev, "No memory for vreg: %s\n", vreg_name);
463 ret = -ENOMEM;
464 goto err;
465 }
466
467 vreg->name = vreg_name;
468
469 /* Parse voltage-level from each node */
470 snprintf(prop_name, MAX_PROP_SIZE,
471 "%s-voltage-level", vreg_name);
472 prop = of_get_property(np, prop_name, &len);
473 if (!prop || (len != (2 * sizeof(__be32)))) {
474 dev_warn(dev, "%s %s property\n",
475 prop ? "invalid format" : "no", prop_name);
476 } else {
477 vreg->low_vol_level = be32_to_cpup(&prop[0]);
478 vreg->high_vol_level = be32_to_cpup(&prop[1]);
479 }
480
481 /* Parse current-level from each node */
482 snprintf(prop_name, MAX_PROP_SIZE,
483 "%s-current-level", vreg_name);
484 ret = of_property_read_u32(np, prop_name, &vreg->load_uA);
485 if (ret < 0) {
486 BT_PWR_DBG("%s property is not valid\n", prop_name);
487 vreg->load_uA = -1;
488 ret = 0;
489 }
490
491 *vreg_data = vreg;
492 BT_PWR_DBG("%s: vol=[%d %d]uV, current=[%d]uA\n",
493 vreg->name, vreg->low_vol_level,
494 vreg->high_vol_level,
495 vreg->load_uA);
496 } else
497 BT_PWR_INFO("%s: is not provided in device tree", vreg_name);
498
499err:
500 return ret;
501}
502
503static int bt_dt_parse_clk_info(struct device *dev,
504 struct bt_power_clk_data **clk_data)
505{
506 int ret = -EINVAL;
507 struct bt_power_clk_data *clk = NULL;
508 struct device_node *np = dev->of_node;
509
510 BT_PWR_DBG("");
511
512 *clk_data = NULL;
513 if (of_parse_phandle(np, "clocks", 0)) {
514 clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL);
515 if (!clk) {
516 BT_PWR_ERR("No memory for clocks");
517 ret = -ENOMEM;
518 goto err;
519 }
520
521 /* Allocated 20 bytes size buffer for clock name string */
522 clk->name = devm_kzalloc(dev, 20, GFP_KERNEL);
523
524 /* Parse clock name from node */
525 ret = of_property_read_string_index(np, "clock-names", 0,
526 &(clk->name));
527 if (ret < 0) {
528 BT_PWR_ERR("reading \"clock-names\" failed");
529 return ret;
530 }
531
532 clk->clk = devm_clk_get(dev, clk->name);
533 if (IS_ERR(clk->clk)) {
534 ret = PTR_ERR(clk->clk);
535 BT_PWR_ERR("failed to get %s, ret (%d)",
536 clk->name, ret);
537 clk->clk = NULL;
538 return ret;
539 }
540
541 *clk_data = clk;
542 } else {
543 BT_PWR_ERR("clocks is not provided in device tree");
544 }
545
546err:
547 return ret;
548}
549
550static int bt_power_populate_dt_pinfo(struct platform_device *pdev)
551{
552 int rc;
553
554 BT_PWR_DBG("");
555
556 if (!bt_power_pdata)
557 return -ENOMEM;
558
559 if (pdev->dev.of_node) {
560 bt_power_pdata->bt_gpio_sys_rst =
561 of_get_named_gpio(pdev->dev.of_node,
562 "qca,bt-reset-gpio", 0);
563 if (bt_power_pdata->bt_gpio_sys_rst < 0)
564 BT_PWR_ERR("bt-reset-gpio not provided in device tree");
565
566 rc = bt_dt_parse_vreg_info(&pdev->dev,
567 &bt_power_pdata->bt_vdd_core,
568 "qca,bt-vdd-core");
569 if (rc < 0)
570 BT_PWR_ERR("bt-vdd-core not provided in device tree");
571
572 rc = bt_dt_parse_vreg_info(&pdev->dev,
573 &bt_power_pdata->bt_vdd_io,
574 "qca,bt-vdd-io");
575 if (rc < 0)
576 BT_PWR_ERR("bt-vdd-io not provided in device tree");
577
578 rc = bt_dt_parse_vreg_info(&pdev->dev,
579 &bt_power_pdata->bt_vdd_xtal,
580 "qca,bt-vdd-xtal");
581 if (rc < 0)
582 BT_PWR_ERR("bt-vdd-xtal not provided in device tree");
583
584 rc = bt_dt_parse_vreg_info(&pdev->dev,
585 &bt_power_pdata->bt_vdd_pa,
586 "qca,bt-vdd-pa");
587 if (rc < 0)
588 BT_PWR_ERR("bt-vdd-pa not provided in device tree");
589
590 rc = bt_dt_parse_vreg_info(&pdev->dev,
591 &bt_power_pdata->bt_vdd_ldo,
592 "qca,bt-vdd-ldo");
593 if (rc < 0)
594 BT_PWR_ERR("bt-vdd-ldo not provided in device tree");
595
596 rc = bt_dt_parse_vreg_info(&pdev->dev,
597 &bt_power_pdata->bt_chip_pwd,
598 "qca,bt-chip-pwd");
599 if (rc < 0)
600 BT_PWR_ERR("bt-chip-pwd not provided in device tree");
601
602 rc = bt_dt_parse_clk_info(&pdev->dev,
603 &bt_power_pdata->bt_chip_clk);
604 if (rc < 0)
605 BT_PWR_ERR("clock not provided in device tree");
606 }
607
608 bt_power_pdata->bt_power_setup = bluetooth_power;
609
610 return 0;
611}
612
613static int bt_power_probe(struct platform_device *pdev)
614{
615 int ret = 0;
616
617 dev_dbg(&pdev->dev, "%s\n", __func__);
618
619 bt_power_pdata =
620 kzalloc(sizeof(struct bluetooth_power_platform_data),
621 GFP_KERNEL);
622
623 if (!bt_power_pdata) {
624 BT_PWR_ERR("Failed to allocate memory");
625 return -ENOMEM;
626 }
627
628 if (pdev->dev.of_node) {
629 ret = bt_power_populate_dt_pinfo(pdev);
630 if (ret < 0) {
631 BT_PWR_ERR("Failed to populate device tree info");
632 goto free_pdata;
633 }
634 pdev->dev.platform_data = bt_power_pdata;
635 } else if (pdev->dev.platform_data) {
636 /* Optional data set to default if not provided */
637 if (!((struct bluetooth_power_platform_data *)
638 (pdev->dev.platform_data))->bt_power_setup)
639 ((struct bluetooth_power_platform_data *)
640 (pdev->dev.platform_data))->bt_power_setup =
641 bluetooth_power;
642
643 memcpy(bt_power_pdata, pdev->dev.platform_data,
644 sizeof(struct bluetooth_power_platform_data));
645 pwr_state = 0;
646 } else {
647 BT_PWR_ERR("Failed to get platform data");
648 goto free_pdata;
649 }
650
651 if (bluetooth_power_rfkill_probe(pdev) < 0)
652 goto free_pdata;
653
654 btpdev = pdev;
655
656 return 0;
657
658free_pdata:
659 kfree(bt_power_pdata);
660 return ret;
661}
662
663static int bt_power_remove(struct platform_device *pdev)
664{
665 dev_dbg(&pdev->dev, "%s\n", __func__);
666
667 bluetooth_power_rfkill_remove(pdev);
668
Bandari Rameshf8b58cc2018-07-09 14:39:05 +0530669 if (bt_power_pdata->bt_chip_pwd)
Mahesh Kumar Sharma41a4d382017-01-17 17:00:51 -0800670 regulator_put(bt_power_pdata->bt_chip_pwd->reg);
671
672 kfree(bt_power_pdata);
673
674 return 0;
675}
676
677int bt_register_slimdev(struct device *dev)
678{
679 BT_PWR_DBG("");
680 if (!bt_power_pdata || (dev == NULL)) {
681 BT_PWR_ERR("Failed to allocate memory");
682 return -EINVAL;
683 }
684 bt_power_pdata->slim_dev = dev;
685 return 0;
686}
687
688static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
689{
690 int ret = 0, pwr_cntrl = 0;
691
692 switch (cmd) {
693 case BT_CMD_SLIM_TEST:
694 if (!bt_power_pdata->slim_dev) {
695 BT_PWR_ERR("slim_dev is null\n");
696 return -EINVAL;
697 }
698 ret = btfm_slim_hw_init(
699 bt_power_pdata->slim_dev->platform_data
700 );
701 break;
702 case BT_CMD_PWR_CTRL:
703 pwr_cntrl = (int)arg;
704 BT_PWR_ERR("BT_CMD_PWR_CTRL pwr_cntrl:%d", pwr_cntrl);
705 if (pwr_state != pwr_cntrl) {
706 ret = bluetooth_power(pwr_cntrl);
707 if (!ret)
708 pwr_state = pwr_cntrl;
709 } else {
710 BT_PWR_ERR("BT chip state is already :%d no change d\n"
711 , pwr_state);
Rupesh Tatiya03a5d4f2017-05-08 10:36:19 +0530712 ret = 0;
Mahesh Kumar Sharma41a4d382017-01-17 17:00:51 -0800713 }
714 break;
715 default:
716 return -EINVAL;
717 }
718 return ret;
719}
720
721static struct platform_driver bt_power_driver = {
722 .probe = bt_power_probe,
723 .remove = bt_power_remove,
724 .driver = {
725 .name = "bt_power",
726 .owner = THIS_MODULE,
727 .of_match_table = bt_power_match_table,
728 },
729};
730
731static const struct file_operations bt_dev_fops = {
732 .owner = THIS_MODULE,
733 .unlocked_ioctl = bt_ioctl,
734 .compat_ioctl = bt_ioctl,
735};
736
737static int __init bluetooth_power_init(void)
738{
739 int ret;
740
741 ret = platform_driver_register(&bt_power_driver);
742
743 bt_major = register_chrdev(0, "bt", &bt_dev_fops);
744 if (bt_major < 0) {
745 BTFMSLIM_ERR("failed to allocate char dev\n");
746 goto chrdev_unreg;
747 }
748
749 bt_class = class_create(THIS_MODULE, "bt-dev");
750 if (IS_ERR(bt_class)) {
751 BTFMSLIM_ERR("coudn't create class");
752 goto chrdev_unreg;
753 }
754
755
756 if (device_create(bt_class, NULL, MKDEV(bt_major, 0),
757 NULL, "btpower") == NULL) {
758 BTFMSLIM_ERR("failed to allocate char dev\n");
759 goto chrdev_unreg;
760 }
761 return 0;
762
763chrdev_unreg:
764 unregister_chrdev(bt_major, "bt");
765 class_destroy(bt_class);
766 return ret;
767}
768
769static void __exit bluetooth_power_exit(void)
770{
771 platform_driver_unregister(&bt_power_driver);
772}
773
774MODULE_LICENSE("GPL v2");
775MODULE_DESCRIPTION("MSM Bluetooth power control driver");
776
777module_init(bluetooth_power_init);
778module_exit(bluetooth_power_exit);