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