0001
0002
0003
0004
0005
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");