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