1 /*
2 * Copyright (C) 2022 Unionman Technology Co., Ltd.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include <linux/module.h>
20 #include <linux/platform_device.h>
21 #include <linux/delay.h>
22 #include <linux/string.h>
23 #include <linux/ctype.h>
24 #include <linux/leds.h>
25 #include <linux/gpio.h>
26 #include <linux/rfkill.h>
27 #include <linux/slab.h>
28 #include <linux/of.h>
29 #include <linux/pinctrl/consumer.h>
30 #include <linux/amlogic/aml_gpio_consumer.h>
31 #include <linux/of_gpio.h>
32 #include <linux/amlogic/cpu_version.h>
33 #include <linux/amlogic/iomap.h>
34 #include <linux/io.h>
35 #include <linux/amlogic/bt_device.h>
36 #include <linux/random.h>
37 #include "../../drivers/gpio/gpiolib.h"
38
39 #include <linux/interrupt.h>
40 #include <linux/pm_wakeup.h>
41 #include <linux/pm_wakeirq.h>
42
43 #ifdef CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND
44 #include <linux/amlogic/pm.h>
45 static struct early_suspend bt_early_suspend;
46 #endif
47
48 #define BT_RFKILL "bt_rfkill"
49
50 char bt_addr[18] = "";
51 static struct class *bt_addr_class;
52 static int btpower_evt;
bt_addr_show(struct class * cls,struct class_attribute * attr,char * _buf)53 static ssize_t bt_addr_show(struct class *cls, struct class_attribute *attr, char *_buf)
54 {
55 char local_addr[6];
56
57 if (!_buf) {
58 return -EINVAL;
59 }
60
61 if (strlen(bt_addr) == 0) {
62 local_addr[0] = 0x22;
63 local_addr[1] = 0x22;
64 local_addr[2L] = prandom_u32();
65 local_addr[3L] = prandom_u32();
66 local_addr[4L] = prandom_u32();
67 local_addr[5L] = prandom_u32();
68 sprintf(bt_addr, "%02x:%02x:%02x:%02x:%02x:%02x", local_addr[0], local_addr[1], local_addr[2L],
69 local_addr[3L], local_addr[4L], local_addr[5L]);
70 }
71
72 return sprintf(_buf, "%s\n", bt_addr);
73 }
bt_addr_store(struct class * cls,struct class_attribute * attr,const char __user * buf,size_t count)74 static ssize_t bt_addr_store(struct class *cls, struct class_attribute *attr, const char __user *buf, size_t count)
75 {
76 int ret = -EINVAL;
77
78 if (!buf) {
79 return ret;
80 }
81
82 snprintf(bt_addr, sizeof(bt_addr), "%s", buf);
83
84 if (bt_addr[strlen(bt_addr) - 1] == '\n') {
85 bt_addr[strlen(bt_addr) - 1] = '\0';
86 }
87
88 pr_info("bt_addr=%s\n", bt_addr);
89 return count;
90 }
91 static CLASS_ATTR_RW(bt_addr);
92
93 struct bt_device_runtime_data {
94 struct rfkill *bt_rfk;
95 struct bt_dev_data *pdata;
96 };
97
bt_device_off(struct bt_dev_data * pdata)98 static void bt_device_off(struct bt_dev_data *pdata)
99 {
100 if (pdata->power_down_disable == 0) {
101 if (pdata->power_off_flag > 0) {
102 if (pdata->gpio_reset > 0) {
103 if ((pdata->power_on_pin_OD) && (pdata->power_low_level)) {
104 gpio_direction_input(pdata->gpio_reset);
105 } else {
106 gpio_direction_output(pdata->gpio_reset, pdata->power_low_level);
107 }
108 }
109 if (pdata->gpio_en > 0) {
110 if ((pdata->power_on_pin_OD) && (pdata->power_low_level)) {
111 gpio_direction_input(pdata->gpio_en);
112 } else {
113 gpio_direction_output(pdata->gpio_en, 0);
114 }
115 }
116 msleep(20L);
117 }
118 }
119 }
120
bt_device_init(struct bt_dev_data * pdata)121 static void bt_device_init(struct bt_dev_data *pdata)
122 {
123 int tmp = 0;
124
125 if (pdata->gpio_reset > 0) {
126 gpio_request(pdata->gpio_reset, BT_RFKILL);
127 }
128
129 if (pdata->gpio_en > 0) {
130 gpio_request(pdata->gpio_en, BT_RFKILL);
131 }
132
133 if (pdata->gpio_hostwake > 0) {
134 gpio_request(pdata->gpio_hostwake, BT_RFKILL);
135 gpio_direction_output(pdata->gpio_hostwake, 1);
136 }
137
138 tmp = pdata->power_down_disable;
139 pdata->power_down_disable = 0;
140 bt_device_off(pdata);
141 pdata->power_down_disable = tmp;
142 }
143
bt_device_deinit(struct bt_dev_data * pdata)144 static void bt_device_deinit(struct bt_dev_data *pdata)
145 {
146 if (pdata->gpio_reset > 0) {
147 gpio_free(pdata->gpio_reset);
148 }
149
150 if (pdata->gpio_en > 0) {
151 gpio_free(pdata->gpio_en);
152 }
153
154 if (pdata->gpio_hostwake > 0) {
155 gpio_free(pdata->gpio_hostwake);
156 }
157 }
158
bt_device_on(struct bt_dev_data * pdata)159 static void bt_device_on(struct bt_dev_data *pdata)
160 {
161 if (pdata->power_down_disable == 0) {
162 if (pdata->gpio_reset > 0) {
163 if ((pdata->power_on_pin_OD) && (pdata->power_low_level)) {
164 gpio_direction_input(pdata->gpio_reset);
165 } else {
166 gpio_direction_output(pdata->gpio_reset, pdata->power_low_level);
167 }
168 }
169
170 if (pdata->gpio_en > 0) {
171 if ((pdata->power_on_pin_OD) && (pdata->power_low_level)) {
172 gpio_direction_input(pdata->gpio_en);
173 } else {
174 gpio_direction_output(pdata->gpio_en, 0);
175 }
176 }
177 msleep(200L);
178 }
179
180 if (pdata->gpio_reset > 0) {
181 if ((pdata->power_on_pin_OD) && (!pdata->power_low_level)) {
182 gpio_direction_input(pdata->gpio_reset);
183 } else {
184 gpio_direction_output(pdata->gpio_reset, !pdata->power_low_level);
185 }
186 }
187
188 if (pdata->gpio_en > 0) {
189 if ((pdata->power_on_pin_OD) && (!pdata->power_low_level)) {
190 gpio_direction_input(pdata->gpio_en);
191 } else {
192 gpio_direction_output(pdata->gpio_en, 1);
193 }
194 }
195 msleep(200L);
196 }
197
bt_set_block(void * data,bool blocked)198 static int bt_set_block(void *data, bool blocked)
199 {
200 struct bt_dev_data *pdata = data;
201
202 if (!blocked) {
203 pr_info("BT: ON\n");
204 bt_device_on(pdata);
205 } else {
206 pr_info("BT: OFF\n");
207 bt_device_off(pdata);
208 }
209
210 return 0;
211 }
212
213 static const struct rfkill_ops bt_rfkill_ops = {
214 .set_block = bt_set_block,
215 };
216
217 #ifdef CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND
bt_earlysuspend(struct early_suspend * h)218 static void bt_earlysuspend(struct early_suspend *h)
219 {
220 }
221
bt_lateresume(struct early_suspend * h)222 static void bt_lateresume(struct early_suspend *h)
223 {
224 }
225 #endif
226
bt_suspend(struct platform_device * pdev,pm_message_t state)227 static int bt_suspend(struct platform_device *pdev, pm_message_t state)
228 {
229 return 0;
230 }
231
bt_resume(struct platform_device * pdev)232 static int bt_resume(struct platform_device *pdev)
233 {
234 return 0;
235 }
236
bt_probe(struct platform_device * pdev)237 static int bt_probe(struct platform_device *pdev)
238 {
239 int ret = 0;
240 const void *prop;
241 struct rfkill *bt_rfk;
242 struct bt_dev_data *pdata = NULL;
243 struct bt_device_runtime_data *prdata;
244
245 #ifdef CONFIG_OF
246 if (pdev && pdev->dev.of_node) {
247 const char *str;
248
249 pdata = kzalloc(sizeof(struct bt_dev_data), GFP_KERNEL);
250 ret = of_property_read_string(pdev->dev.of_node, "gpio_reset", &str);
251 if (ret) {
252 pr_warn("not get gpio_reset\n");
253 pdata->gpio_reset = 0;
254 } else {
255 pdata->gpio_reset = of_get_named_gpio_flags(pdev->dev.of_node, "gpio_reset", 0, NULL);
256 }
257
258 ret = of_property_read_string(pdev->dev.of_node, "gpio_en", &str);
259 if (ret) {
260 pr_warn("not get gpio_en\n");
261 pdata->gpio_en = 0;
262 } else {
263 pdata->gpio_en = of_get_named_gpio_flags(pdev->dev.of_node, "gpio_en", 0, NULL);
264 }
265 ret = of_property_read_string(pdev->dev.of_node, "gpio_hostwake", &str);
266 if (ret) {
267 pr_warn("not get gpio_hostwake\n");
268 pdata->gpio_hostwake = 0;
269 } else {
270 pdata->gpio_hostwake = of_get_named_gpio_flags(pdev->dev.of_node, "gpio_hostwake", 0, NULL);
271 }
272
273 prop = of_get_property(pdev->dev.of_node, "power_low_level", NULL);
274 if (prop) {
275 pr_info("power on valid level is low");
276 pdata->power_low_level = 1;
277 } else {
278 pr_info("power on valid level is high");
279 pdata->power_low_level = 0;
280 pdata->power_on_pin_OD = 0;
281 }
282
283 ret = of_property_read_u32(pdev->dev.of_node, "power_on_pin_OD", &pdata->power_on_pin_OD);
284 if (ret) {
285 pdata->power_on_pin_OD = 0;
286 }
287 pr_info("bt: power_on_pin_OD = %d;\n", pdata->power_on_pin_OD);
288
289 ret = of_property_read_u32(pdev->dev.of_node, "power_off_flag", &pdata->power_off_flag);
290 if (ret) {
291 pdata->power_off_flag = 1;
292 }
293 pr_info("bt: power_off_flag = %d;\n", pdata->power_off_flag);
294
295 ret = of_property_read_u32(pdev->dev.of_node, "power_down_disable", &pdata->power_down_disable);
296 if (ret) {
297 pdata->power_down_disable = 0;
298 }
299 pr_info("bt: power down = %d;\n", pdata->power_down_disable);
300 } else if (pdev) {
301 pdata = (struct bt_dev_data *)(pdev->dev.platform_data);
302 } else {
303 ret = -ENOENT;
304 goto err_res;
305 }
306 #else
307 pdata = (struct bt_dev_data *)(pdev->dev.platform_data);
308 #endif
309 bt_addr_class = class_create(THIS_MODULE, "bt_addr");
310 ret = class_create_file(bt_addr_class, &class_attr_bt_addr);
311
312 bt_device_init(pdata);
313 if (pdata->power_down_disable == 1) {
314 pdata->power_down_disable = 0;
315 bt_device_on(pdata);
316 pdata->power_down_disable = 1;
317 }
318
319 bt_rfk = rfkill_alloc("bluetooth", &pdev->dev, RFKILL_TYPE_BLUETOOTH, &bt_rfkill_ops, pdata);
320 if (!bt_rfk) {
321 pr_info("rfk alloc fail\n");
322 ret = -ENOMEM;
323 goto err_rfk_alloc;
324 }
325
326 rfkill_init_sw_state(bt_rfk, false);
327 ret = rfkill_register(bt_rfk);
328 if (ret) {
329 pr_err("rfkill_register fail\n");
330 goto err_rfkill;
331 }
332
333 prdata = kmalloc(sizeof(struct bt_device_runtime_data), GFP_KERNEL);
334 if (!prdata) {
335 goto err_rfkill;
336 }
337
338 prdata->bt_rfk = bt_rfk;
339 prdata->pdata = pdata;
340 platform_set_drvdata(pdev, prdata);
341
342 #ifdef CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND
343 bt_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
344 bt_early_suspend.suspend = bt_earlysuspend;
345 bt_early_suspend.resume = bt_lateresume;
346 bt_early_suspend.param = pdev;
347 register_early_suspend(&bt_early_suspend);
348 #endif
349
350 return 0;
351
352 err_rfkill:
353 rfkill_destroy(bt_rfk);
354 err_rfk_alloc:
355 bt_device_deinit(pdata);
356 err_res:
357 return ret;
358 }
359
bt_remove(struct platform_device * pdev)360 static int bt_remove(struct platform_device *pdev)
361 {
362 struct bt_device_runtime_data *prdata = platform_get_drvdata(pdev);
363 struct rfkill *rfk = NULL;
364 struct bt_dev_data *pdata = NULL;
365
366 platform_set_drvdata(pdev, NULL);
367
368 if (prdata) {
369 rfk = prdata->bt_rfk;
370 pdata = prdata->pdata;
371 }
372
373 if (pdata) {
374 bt_device_deinit(pdata);
375 kfree(pdata);
376 }
377
378 if (rfk) {
379 rfkill_unregister(rfk);
380 rfkill_destroy(rfk);
381 }
382 rfk = NULL;
383
384 return 0;
385 }
386
387 #ifdef CONFIG_OF
388 static const struct of_device_id bt_dev_dt_match[] = {
389 {
390 .compatible = "amlogic, bt-dev",
391 },
392 {},
393 };
394 #else
395 #define bt_dev_dt_match NULL
396 #endif
397
398 static struct platform_driver bt_driver = {
399 .driver =
400 {
401 .name = "bluetooth",
402 .of_match_table = bt_dev_dt_match,
403 },
404 .probe = bt_probe,
405 .remove = bt_remove,
406 .suspend = bt_suspend,
407 .resume = bt_resume,
408 };
409
bt_init(void)410 static int __init bt_init(void)
411 {
412 pr_info("bt_init\n");
413 return platform_driver_register(&bt_driver);
414 }
415
bt_exit(void)416 static void __exit bt_exit(void)
417 {
418 platform_driver_unregister(&bt_driver);
419 }
420
421 module_init(bt_init);
422 module_exit(bt_exit);
423 MODULE_DESCRIPTION("bt rfkill");
424 MODULE_AUTHOR("");
425 MODULE_LICENSE("GPL v2");
426
427 /**************** bt mac *****************/
mac_addr_set(char * line)428 static int __init mac_addr_set(char *line)
429 {
430 if (line) {
431 pr_info("try to read bt mac from emmc key!\n");
432 strncpy(bt_addr, line, sizeof(bt_addr) - 1);
433 bt_addr[sizeof(bt_addr) - 1] = '\0';
434 }
435
436 return 1;
437 }
438
439 __setup("mac_bt=", mac_addr_set);
440