tosa-bt.c (2647B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Bluetooth built-in chip control 4 * 5 * Copyright (c) 2008 Dmitry Baryshkov 6 */ 7 8#include <linux/kernel.h> 9#include <linux/module.h> 10#include <linux/platform_device.h> 11#include <linux/gpio.h> 12#include <linux/delay.h> 13#include <linux/rfkill.h> 14 15#include "tosa_bt.h" 16 17static void tosa_bt_on(struct tosa_bt_data *data) 18{ 19 gpio_set_value(data->gpio_reset, 0); 20 gpio_set_value(data->gpio_pwr, 1); 21 gpio_set_value(data->gpio_reset, 1); 22 mdelay(20); 23 gpio_set_value(data->gpio_reset, 0); 24} 25 26static void tosa_bt_off(struct tosa_bt_data *data) 27{ 28 gpio_set_value(data->gpio_reset, 1); 29 mdelay(10); 30 gpio_set_value(data->gpio_pwr, 0); 31 gpio_set_value(data->gpio_reset, 0); 32} 33 34static int tosa_bt_set_block(void *data, bool blocked) 35{ 36 pr_info("BT_RADIO going: %s\n", blocked ? "off" : "on"); 37 38 if (!blocked) { 39 pr_info("TOSA_BT: going ON\n"); 40 tosa_bt_on(data); 41 } else { 42 pr_info("TOSA_BT: going OFF\n"); 43 tosa_bt_off(data); 44 } 45 46 return 0; 47} 48 49static const struct rfkill_ops tosa_bt_rfkill_ops = { 50 .set_block = tosa_bt_set_block, 51}; 52 53static int tosa_bt_probe(struct platform_device *dev) 54{ 55 int rc; 56 struct rfkill *rfk; 57 58 struct tosa_bt_data *data = dev->dev.platform_data; 59 60 rc = gpio_request(data->gpio_reset, "Bluetooth reset"); 61 if (rc) 62 goto err_reset; 63 rc = gpio_direction_output(data->gpio_reset, 0); 64 if (rc) 65 goto err_reset_dir; 66 rc = gpio_request(data->gpio_pwr, "Bluetooth power"); 67 if (rc) 68 goto err_pwr; 69 rc = gpio_direction_output(data->gpio_pwr, 0); 70 if (rc) 71 goto err_pwr_dir; 72 73 rfk = rfkill_alloc("tosa-bt", &dev->dev, RFKILL_TYPE_BLUETOOTH, 74 &tosa_bt_rfkill_ops, data); 75 if (!rfk) { 76 rc = -ENOMEM; 77 goto err_rfk_alloc; 78 } 79 80 rc = rfkill_register(rfk); 81 if (rc) 82 goto err_rfkill; 83 84 platform_set_drvdata(dev, rfk); 85 86 return 0; 87 88err_rfkill: 89 rfkill_destroy(rfk); 90err_rfk_alloc: 91 tosa_bt_off(data); 92err_pwr_dir: 93 gpio_free(data->gpio_pwr); 94err_pwr: 95err_reset_dir: 96 gpio_free(data->gpio_reset); 97err_reset: 98 return rc; 99} 100 101static int tosa_bt_remove(struct platform_device *dev) 102{ 103 struct tosa_bt_data *data = dev->dev.platform_data; 104 struct rfkill *rfk = platform_get_drvdata(dev); 105 106 platform_set_drvdata(dev, NULL); 107 108 if (rfk) { 109 rfkill_unregister(rfk); 110 rfkill_destroy(rfk); 111 } 112 rfk = NULL; 113 114 tosa_bt_off(data); 115 116 gpio_free(data->gpio_pwr); 117 gpio_free(data->gpio_reset); 118 119 return 0; 120} 121 122static struct platform_driver tosa_bt_driver = { 123 .probe = tosa_bt_probe, 124 .remove = tosa_bt_remove, 125 126 .driver = { 127 .name = "tosa-bt", 128 }, 129}; 130module_platform_driver(tosa_bt_driver); 131 132MODULE_LICENSE("GPL"); 133MODULE_AUTHOR("Dmitry Baryshkov"); 134MODULE_DESCRIPTION("Bluetooth built-in chip control");