• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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