• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <linux/kernel.h>
2 #include <linux/types.h>
3 #include <linux/module.h>
4 #include <linux/init.h>
5 #include <linux/gpio.h>
6 #include <linux/err.h>
7 #include <linux/device.h>
8 #include <linux/delay.h>
9 #include <linux/of_gpio.h>
10 #include <linux/clk.h>
11 #include <linux/rfkill.h>
12 #include <linux/regulator/consumer.h>
13 #include <linux/platform_device.h>
14 #include "internal.h"
15 #include "sunxi-rfkill.h"
16 
17 static struct sunxi_bt_platdata *bluetooth_data;
18 static const struct of_device_id sunxi_bt_ids[];
19 
20 static int sunxi_bt_on(struct sunxi_bt_platdata *data, bool on_off);
21 static DEFINE_MUTEX(sunxi_bluetooth_mutex);
22 
sunxi_bluetooth_set_power(bool on_off)23 void sunxi_bluetooth_set_power(bool on_off)
24 {
25 	struct platform_device *pdev;
26 	int ret = 0;
27 
28 	if (!bluetooth_data)
29 		return;
30 
31 	pdev = bluetooth_data->pdev;
32 	mutex_lock(&sunxi_bluetooth_mutex);
33 	rfkill_poweren_set(WL_DEV_BLUETOOTH, on_off);
34 	if (on_off != bluetooth_data->power_state) {
35 		ret = sunxi_bt_on(bluetooth_data, on_off);
36 		if (ret)
37 			dev_err(&pdev->dev, "set power failed\n");
38 	}
39 	rfkill_chipen_set(WL_DEV_BLUETOOTH, on_off);
40 	mutex_unlock(&sunxi_bluetooth_mutex);
41 }
42 EXPORT_SYMBOL_GPL(sunxi_bluetooth_set_power);
43 
sunxi_bt_on(struct sunxi_bt_platdata * data,bool on_off)44 static int sunxi_bt_on(struct sunxi_bt_platdata *data, bool on_off)
45 {
46 	struct platform_device *pdev = data->pdev;
47 	struct device *dev = &pdev->dev;
48 	int ret = 0, i;
49 
50 	if (on_off) {
51 		for (i = 0; i < CLK_MAX; i++) {
52 			if (!IS_ERR_OR_NULL(data->clk[i]))
53 				clk_prepare_enable(data->clk[i]);
54 		}
55 
56 		for (i = 0; i < PWR_MAX; i++) {
57 			if (!IS_ERR_OR_NULL(data->power[i])) {
58 				if (data->power_vol[i]) {
59 					ret = regulator_set_voltage(data->power[i],
60 							data->power_vol[i], data->power_vol[i]);
61 					if (ret < 0) {
62 						dev_err(dev, "bt power[%d] (%s) set voltage failed\n",
63 								i, data->power_name[i]);
64 						return ret;
65 					}
66 
67 					ret = regulator_get_voltage(data->power[i]);
68 					if (ret != data->power_vol[i]) {
69 						dev_err(dev, "bt power[%d] (%s) get voltage failed\n",
70 								i, data->power_name[i]);
71 						return ret;
72 					}
73 				}
74 
75 				ret = regulator_enable(data->power[i]);
76 				if (ret < 0) {
77 					dev_err(dev, "bt power[%d] (%s) enable failed\n",
78 								i, data->power_name[i]);
79 					return ret;
80 				}
81 			}
82 		}
83 
84 		if (gpio_is_valid(data->gpio_bt_rst)) {
85 			mdelay(10);
86 			gpio_set_value(data->gpio_bt_rst, !data->gpio_bt_rst_assert);
87 		}
88 	} else {
89 		if (gpio_is_valid(data->gpio_bt_rst))
90 			gpio_set_value(data->gpio_bt_rst, data->gpio_bt_rst_assert);
91 
92 		for (i = 0; i < PWR_MAX; i++) {
93 			if (!IS_ERR_OR_NULL(data->power[i])) {
94 				ret = regulator_disable(data->power[i]);
95 				if (ret < 0) {
96 					dev_err(dev, "bt power[%d] (%s) disable failed\n",
97 								i, data->power_name[i]);
98 					return ret;
99 				}
100 			}
101 		}
102 
103 		for (i = 0; i < CLK_MAX; i++) {
104 			if (!IS_ERR_OR_NULL(data->clk[i]))
105 				clk_disable_unprepare(data->clk[i]);
106 		}
107 	}
108 
109 	data->power_state = on_off;
110 	dev_info(dev, "bt power %s success\n", on_off ? "on" : "off");
111 
112 	return 0;
113 }
114 
sunxi_bt_set_block(void * data,bool blocked)115 static int sunxi_bt_set_block(void *data, bool blocked)
116 {
117 	struct sunxi_bt_platdata *platdata = data;
118 	struct platform_device *pdev = platdata->pdev;
119 	int ret;
120 
121 	if (!bluetooth_data)
122 		return 0;
123 
124 	if (blocked != platdata->power_state) {
125 		dev_warn(&pdev->dev, "block state already is %d\n", blocked);
126 		return 0;
127 	}
128 
129 	dev_info(&pdev->dev, "set block: %d\n", blocked);
130 	rfkill_poweren_set(WL_DEV_BLUETOOTH, !blocked);
131 	ret = sunxi_bt_on(platdata, !blocked);
132 	if (ret) {
133 		dev_err(&pdev->dev, "set block failed\n");
134 		return ret;
135 	}
136 
137 	rfkill_chipen_set(WL_DEV_BLUETOOTH, !blocked);
138 
139 	return 0;
140 }
141 
142 static const struct rfkill_ops sunxi_bt_rfkill_ops = {
143 	.set_block = sunxi_bt_set_block,
144 };
145 
sunxi_bt_init(struct platform_device * pdev)146 int sunxi_bt_init(struct platform_device *pdev)
147 {
148 	struct device_node *np = of_find_matching_node(pdev->dev.of_node, sunxi_bt_ids);
149 	struct device *dev = &pdev->dev;
150 	struct sunxi_bt_platdata *data;
151 	enum of_gpio_flags config;
152 	int ret = 0;
153 	int count, i;
154 
155 	if (!dev)
156 		return -ENOMEM;
157 
158 	if (!np)
159 		return 0;
160 
161 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
162 	data->pdev = pdev;
163 
164 	count = of_property_count_strings(np, "bt_power");
165 	if (count <= 0) {
166 		dev_warn(dev, "Missing bt_power.\n");
167 	} else {
168 		if (count > PWR_MAX) {
169 			dev_warn(dev, "bt power count large than max(%d).\n", PWR_MAX);
170 			count = PWR_MAX;
171 		}
172 		ret = of_property_read_string_array(np, "bt_power",
173 					(const char **)data->power_name, count);
174 		if (ret < 0)
175 			return -ENOMEM;
176 
177 		ret = of_property_read_u32_array(np, "bt_power_vol",
178 					(u32 *)data->power_vol, count);
179 		if (ret < 0)
180 			dev_warn(dev, "Missing bt_power_vol config.\n");
181 
182 		for (i = 0; i < count; i++) {
183 			data->power[i] = regulator_get(dev, data->power_name[i]);
184 			if (IS_ERR_OR_NULL(data->power[i]))
185 				return -ENOMEM;
186 
187 			dev_info(dev, "bt power[%d] (%s) voltage: %dmV\n",
188 					i, data->power_name[i], data->power_vol[i] / 1000);
189 		}
190 	}
191 
192 	count = of_property_count_strings(np, "clock-names");
193 	if (count <= 0) {
194 		count = CLK_MAX;
195 		for (i = 0; i < count; i++) {
196 			data->clk[i] = of_clk_get(np, i);
197 			if (IS_ERR_OR_NULL(data->clk[i]))
198 				break;
199 			data->clk_name[i] = devm_kzalloc(dev, 16, GFP_KERNEL);
200 			sprintf(data->clk_name[i], "clk%d", i);
201 			dev_info(dev, "bt clock[%d] (%s)\n", i, data->clk_name[i]);
202 		}
203 	} else {
204 		if (count > CLK_MAX) {
205 			dev_warn(dev, "bt clocks count large than max(%d > %d).\n",
206 						count, CLK_MAX);
207 			count = CLK_MAX;
208 		}
209 		ret = of_property_read_string_array(np, "clock-names",
210 					(const char **)data->clk_name, count);
211 		if (ret < 0)
212 			return -ENOMEM;
213 
214 		for (i = 0; i < count; i++) {
215 			data->clk[i] = of_clk_get(np, i);
216 			if (IS_ERR_OR_NULL(data->clk[i]))
217 				return -ENOMEM;
218 			dev_info(dev, "bt clock[%d] (%s)\n", i, data->clk_name[i]);
219 		}
220 	}
221 
222 	data->gpio_bt_rst = of_get_named_gpio_flags(np, "bt_rst_n", 0, &config);
223 	if (!gpio_is_valid(data->gpio_bt_rst)) {
224 		dev_err(dev, "get gpio bt_rst failed\n");
225 	} else {
226 		data->gpio_bt_rst_assert = (config == OF_GPIO_ACTIVE_LOW) ? 0 : 1;
227 		dev_info(dev, "bt_rst gpio=%d assert=%d\n", data->gpio_bt_rst, data->gpio_bt_rst_assert);
228 
229 		ret = devm_gpio_request(dev, data->gpio_bt_rst, "bt_rst");
230 		if (ret < 0) {
231 			dev_err(dev, "can't request bt_rst gpio %d\n",
232 				data->gpio_bt_rst);
233 			return ret;
234 		}
235 
236 		ret = gpio_direction_output(data->gpio_bt_rst, data->gpio_bt_rst_assert);
237 		if (ret < 0) {
238 			dev_err(dev, "can't request output direction bt_rst gpio %d\n",
239 				data->gpio_bt_rst);
240 			return ret;
241 		}
242 	}
243 
244 	data->rfkill = rfkill_alloc("sunxi-bt", dev, RFKILL_TYPE_BLUETOOTH,
245 				&sunxi_bt_rfkill_ops, data);
246 	if (!data->rfkill)
247 		return -ENOMEM;
248 
249 	rfkill_set_states(data->rfkill, true, false);
250 
251 	ret = rfkill_register(data->rfkill);
252 	if (ret)
253 		goto fail_rfkill;
254 
255 	data->power_state = 0;
256 	bluetooth_data = data;
257 	return 0;
258 
259 fail_rfkill:
260 	if (data->rfkill)
261 		rfkill_destroy(data->rfkill);
262 
263 	return ret;
264 }
265 
sunxi_bt_deinit(struct platform_device * pdev)266 int sunxi_bt_deinit(struct platform_device *pdev)
267 {
268 	struct sunxi_bt_platdata *data = bluetooth_data;
269 	struct rfkill *rfk;
270 	int i;
271 
272 	if (!data)
273 		return 0;
274 
275 	rfk = data->rfkill;
276 	if (rfk) {
277 		rfkill_unregister(rfk);
278 		rfkill_destroy(rfk);
279 	}
280 
281 	if (data->power_state)
282 		sunxi_bluetooth_set_power(0);
283 
284 	for (i = 0; i < PWR_MAX; i++) {
285 		if (!IS_ERR_OR_NULL(data->power[i]))
286 			regulator_put(data->power[i]);
287 	}
288 
289 	bluetooth_data = NULL;
290 
291 	return 0;
292 }
293 
294 static const struct of_device_id sunxi_bt_ids[] = {
295 	{ .compatible = "allwinner,sunxi-bt" },
296 	{ /* Sentinel */ }
297 };
298 
299 MODULE_DESCRIPTION("sunxi bluetooth driver");
300 MODULE_LICENSE("GPL");
301