Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Bluetooth built-in chip control
0004  *
0005  * Copyright (c) 2008 Dmitry Baryshkov
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/gpio.h>
0012 #include <linux/delay.h>
0013 #include <linux/rfkill.h>
0014 
0015 #include "tosa_bt.h"
0016 
0017 static void tosa_bt_on(struct tosa_bt_data *data)
0018 {
0019     gpio_set_value(data->gpio_reset, 0);
0020     gpio_set_value(data->gpio_pwr, 1);
0021     gpio_set_value(data->gpio_reset, 1);
0022     mdelay(20);
0023     gpio_set_value(data->gpio_reset, 0);
0024 }
0025 
0026 static void tosa_bt_off(struct tosa_bt_data *data)
0027 {
0028     gpio_set_value(data->gpio_reset, 1);
0029     mdelay(10);
0030     gpio_set_value(data->gpio_pwr, 0);
0031     gpio_set_value(data->gpio_reset, 0);
0032 }
0033 
0034 static int tosa_bt_set_block(void *data, bool blocked)
0035 {
0036     pr_info("BT_RADIO going: %s\n", blocked ? "off" : "on");
0037 
0038     if (!blocked) {
0039         pr_info("TOSA_BT: going ON\n");
0040         tosa_bt_on(data);
0041     } else {
0042         pr_info("TOSA_BT: going OFF\n");
0043         tosa_bt_off(data);
0044     }
0045 
0046     return 0;
0047 }
0048 
0049 static const struct rfkill_ops tosa_bt_rfkill_ops = {
0050     .set_block = tosa_bt_set_block,
0051 };
0052 
0053 static int tosa_bt_probe(struct platform_device *dev)
0054 {
0055     int rc;
0056     struct rfkill *rfk;
0057 
0058     struct tosa_bt_data *data = dev->dev.platform_data;
0059 
0060     rc = gpio_request(data->gpio_reset, "Bluetooth reset");
0061     if (rc)
0062         goto err_reset;
0063     rc = gpio_direction_output(data->gpio_reset, 0);
0064     if (rc)
0065         goto err_reset_dir;
0066     rc = gpio_request(data->gpio_pwr, "Bluetooth power");
0067     if (rc)
0068         goto err_pwr;
0069     rc = gpio_direction_output(data->gpio_pwr, 0);
0070     if (rc)
0071         goto err_pwr_dir;
0072 
0073     rfk = rfkill_alloc("tosa-bt", &dev->dev, RFKILL_TYPE_BLUETOOTH,
0074                &tosa_bt_rfkill_ops, data);
0075     if (!rfk) {
0076         rc = -ENOMEM;
0077         goto err_rfk_alloc;
0078     }
0079 
0080     rc = rfkill_register(rfk);
0081     if (rc)
0082         goto err_rfkill;
0083 
0084     platform_set_drvdata(dev, rfk);
0085 
0086     return 0;
0087 
0088 err_rfkill:
0089     rfkill_destroy(rfk);
0090 err_rfk_alloc:
0091     tosa_bt_off(data);
0092 err_pwr_dir:
0093     gpio_free(data->gpio_pwr);
0094 err_pwr:
0095 err_reset_dir:
0096     gpio_free(data->gpio_reset);
0097 err_reset:
0098     return rc;
0099 }
0100 
0101 static int tosa_bt_remove(struct platform_device *dev)
0102 {
0103     struct tosa_bt_data *data = dev->dev.platform_data;
0104     struct rfkill *rfk = platform_get_drvdata(dev);
0105 
0106     platform_set_drvdata(dev, NULL);
0107 
0108     if (rfk) {
0109         rfkill_unregister(rfk);
0110         rfkill_destroy(rfk);
0111     }
0112     rfk = NULL;
0113 
0114     tosa_bt_off(data);
0115 
0116     gpio_free(data->gpio_pwr);
0117     gpio_free(data->gpio_reset);
0118 
0119     return 0;
0120 }
0121 
0122 static struct platform_driver tosa_bt_driver = {
0123     .probe = tosa_bt_probe,
0124     .remove = tosa_bt_remove,
0125 
0126     .driver = {
0127         .name = "tosa-bt",
0128     },
0129 };
0130 module_platform_driver(tosa_bt_driver);
0131 
0132 MODULE_LICENSE("GPL");
0133 MODULE_AUTHOR("Dmitry Baryshkov");
0134 MODULE_DESCRIPTION("Bluetooth built-in chip control");