]>
Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
16b32fd0 DB |
2 | /* |
3 | * Bluetooth built-in chip control | |
4 | * | |
5 | * Copyright (c) 2008 Dmitry Baryshkov | |
16b32fd0 DB |
6 | */ |
7 | ||
8 | #include <linux/kernel.h> | |
9 | #include <linux/module.h> | |
10 | #include <linux/platform_device.h> | |
11 | #include <linux/gpio.h> | |
12 | #include <linux/delay.h> | |
13 | #include <linux/rfkill.h> | |
14 | ||
4c25c5d2 | 15 | #include "tosa_bt.h" |
16b32fd0 DB |
16 | |
17 | static void tosa_bt_on(struct tosa_bt_data *data) | |
18 | { | |
19 | gpio_set_value(data->gpio_reset, 0); | |
20 | gpio_set_value(data->gpio_pwr, 1); | |
21 | gpio_set_value(data->gpio_reset, 1); | |
22 | mdelay(20); | |
23 | gpio_set_value(data->gpio_reset, 0); | |
24 | } | |
25 | ||
26 | static void tosa_bt_off(struct tosa_bt_data *data) | |
27 | { | |
28 | gpio_set_value(data->gpio_reset, 1); | |
29 | mdelay(10); | |
30 | gpio_set_value(data->gpio_pwr, 0); | |
31 | gpio_set_value(data->gpio_reset, 0); | |
32 | } | |
33 | ||
19d337df | 34 | static int tosa_bt_set_block(void *data, bool blocked) |
16b32fd0 | 35 | { |
19d337df | 36 | pr_info("BT_RADIO going: %s\n", blocked ? "off" : "on"); |
16b32fd0 | 37 | |
19d337df | 38 | if (!blocked) { |
16b32fd0 DB |
39 | pr_info("TOSA_BT: going ON\n"); |
40 | tosa_bt_on(data); | |
41 | } else { | |
42 | pr_info("TOSA_BT: going OFF\n"); | |
43 | tosa_bt_off(data); | |
44 | } | |
19d337df | 45 | |
16b32fd0 DB |
46 | return 0; |
47 | } | |
48 | ||
19d337df JB |
49 | static const struct rfkill_ops tosa_bt_rfkill_ops = { |
50 | .set_block = tosa_bt_set_block, | |
51 | }; | |
52 | ||
16b32fd0 DB |
53 | static int tosa_bt_probe(struct platform_device *dev) |
54 | { | |
55 | int rc; | |
56 | struct rfkill *rfk; | |
57 | ||
58 | struct tosa_bt_data *data = dev->dev.platform_data; | |
59 | ||
60 | rc = gpio_request(data->gpio_reset, "Bluetooth reset"); | |
61 | if (rc) | |
62 | goto err_reset; | |
63 | rc = gpio_direction_output(data->gpio_reset, 0); | |
64 | if (rc) | |
65 | goto err_reset_dir; | |
66 | rc = gpio_request(data->gpio_pwr, "Bluetooth power"); | |
67 | if (rc) | |
68 | goto err_pwr; | |
69 | rc = gpio_direction_output(data->gpio_pwr, 0); | |
70 | if (rc) | |
71 | goto err_pwr_dir; | |
72 | ||
19d337df JB |
73 | rfk = rfkill_alloc("tosa-bt", &dev->dev, RFKILL_TYPE_BLUETOOTH, |
74 | &tosa_bt_rfkill_ops, data); | |
16b32fd0 DB |
75 | if (!rfk) { |
76 | rc = -ENOMEM; | |
77 | goto err_rfk_alloc; | |
78 | } | |
79 | ||
16b32fd0 DB |
80 | rc = rfkill_register(rfk); |
81 | if (rc) | |
82 | goto err_rfkill; | |
83 | ||
84 | platform_set_drvdata(dev, rfk); | |
85 | ||
86 | return 0; | |
87 | ||
88 | err_rfkill: | |
19d337df | 89 | rfkill_destroy(rfk); |
16b32fd0 DB |
90 | err_rfk_alloc: |
91 | tosa_bt_off(data); | |
92 | err_pwr_dir: | |
93 | gpio_free(data->gpio_pwr); | |
94 | err_pwr: | |
95 | err_reset_dir: | |
96 | gpio_free(data->gpio_reset); | |
97 | err_reset: | |
98 | return rc; | |
99 | } | |
100 | ||
351a102d | 101 | static int tosa_bt_remove(struct platform_device *dev) |
16b32fd0 DB |
102 | { |
103 | struct tosa_bt_data *data = dev->dev.platform_data; | |
104 | struct rfkill *rfk = platform_get_drvdata(dev); | |
105 | ||
106 | platform_set_drvdata(dev, NULL); | |
107 | ||
19d337df | 108 | if (rfk) { |
16b32fd0 | 109 | rfkill_unregister(rfk); |
19d337df JB |
110 | rfkill_destroy(rfk); |
111 | } | |
16b32fd0 DB |
112 | rfk = NULL; |
113 | ||
114 | tosa_bt_off(data); | |
115 | ||
116 | gpio_free(data->gpio_pwr); | |
117 | gpio_free(data->gpio_reset); | |
118 | ||
119 | return 0; | |
120 | } | |
121 | ||
122 | static struct platform_driver tosa_bt_driver = { | |
123 | .probe = tosa_bt_probe, | |
351a102d | 124 | .remove = tosa_bt_remove, |
16b32fd0 DB |
125 | |
126 | .driver = { | |
127 | .name = "tosa-bt", | |
16b32fd0 DB |
128 | }, |
129 | }; | |
9754c8ef | 130 | module_platform_driver(tosa_bt_driver); |
33436478 AB |
131 | |
132 | MODULE_LICENSE("GPL"); | |
133 | MODULE_AUTHOR("Dmitry Baryshkov"); | |
134 | MODULE_DESCRIPTION("Bluetooth built-in chip control"); |