1/* 2 * Bluetooth built-in chip control 3 * 4 * Copyright (c) 2008 Dmitry Baryshkov 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 */ 11 12#include <linux/kernel.h> 13#include <linux/module.h> 14#include <linux/platform_device.h> 15#include <linux/gpio.h> 16#include <linux/delay.h> 17#include <linux/rfkill.h> 18 19#include <mach/tosa_bt.h> 20 21static void tosa_bt_on(struct tosa_bt_data *data) 22{ 23 gpio_set_value(data->gpio_reset, 0); 24 gpio_set_value(data->gpio_pwr, 1); 25 gpio_set_value(data->gpio_reset, 1); 26 mdelay(20); 27 gpio_set_value(data->gpio_reset, 0); 28} 29 30static void tosa_bt_off(struct tosa_bt_data *data) 31{ 32 gpio_set_value(data->gpio_reset, 1); 33 mdelay(10); 34 gpio_set_value(data->gpio_pwr, 0); 35 gpio_set_value(data->gpio_reset, 0); 36} 37 38static int tosa_bt_set_block(void *data, bool blocked) 39{ 40 pr_info("BT_RADIO going: %s\n", blocked ? "off" : "on"); 41 42 if (!blocked) { 43 pr_info("TOSA_BT: going ON\n"); 44 tosa_bt_on(data); 45 } else { 46 pr_info("TOSA_BT: going OFF\n"); 47 tosa_bt_off(data); 48 } 49 50 return 0; 51} 52 53static const struct rfkill_ops tosa_bt_rfkill_ops = { 54 .set_block = tosa_bt_set_block, 55}; 56 57static int tosa_bt_probe(struct platform_device *dev) 58{ 59 int rc; 60 struct rfkill *rfk; 61 62 struct tosa_bt_data *data = dev->dev.platform_data; 63 64 rc = gpio_request(data->gpio_reset, "Bluetooth reset"); 65 if (rc) 66 goto err_reset; 67 rc = gpio_direction_output(data->gpio_reset, 0); 68 if (rc) 69 goto err_reset_dir; 70 rc = gpio_request(data->gpio_pwr, "Bluetooth power"); 71 if (rc) 72 goto err_pwr; 73 rc = gpio_direction_output(data->gpio_pwr, 0); 74 if (rc) 75 goto err_pwr_dir; 76 77 rfk = rfkill_alloc("tosa-bt", &dev->dev, RFKILL_TYPE_BLUETOOTH, 78 &tosa_bt_rfkill_ops, data); 79 if (!rfk) { 80 rc = -ENOMEM; 81 goto err_rfk_alloc; 82 } 83 84 rfkill_set_led_trigger_name(rfk, "tosa-bt"); 85 86 rc = rfkill_register(rfk); 87 if (rc) 88 goto err_rfkill; 89 90 platform_set_drvdata(dev, rfk); 91 92 return 0; 93 94err_rfkill: 95 rfkill_destroy(rfk); 96err_rfk_alloc: 97 tosa_bt_off(data); 98err_pwr_dir: 99 gpio_free(data->gpio_pwr); 100err_pwr: 101err_reset_dir: 102 gpio_free(data->gpio_reset); 103err_reset: 104 return rc; 105} 106 107static int __devexit tosa_bt_remove(struct platform_device *dev) 108{ 109 struct tosa_bt_data *data = dev->dev.platform_data; 110 struct rfkill *rfk = platform_get_drvdata(dev); 111 112 platform_set_drvdata(dev, NULL); 113 114 if (rfk) { 115 rfkill_unregister(rfk); 116 rfkill_destroy(rfk); 117 } 118 rfk = NULL; 119 120 tosa_bt_off(data); 121 122 gpio_free(data->gpio_pwr); 123 gpio_free(data->gpio_reset); 124 125 return 0; 126} 127 128static struct platform_driver tosa_bt_driver = { 129 .probe = tosa_bt_probe, 130 .remove = __devexit_p(tosa_bt_remove), 131 132 .driver = { 133 .name = "tosa-bt", 134 .owner = THIS_MODULE, 135 }, 136}; 137 138 139static int __init tosa_bt_init(void) 140{ 141 return platform_driver_register(&tosa_bt_driver); 142} 143 144static void __exit tosa_bt_exit(void) 145{ 146 platform_driver_unregister(&tosa_bt_driver); 147} 148 149module_init(tosa_bt_init); 150module_exit(tosa_bt_exit); 151