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 rc = rfkill_register(rfk); 85 if (rc) 86 goto err_rfkill; 87 88 platform_set_drvdata(dev, rfk); 89 90 return 0; 91 92err_rfkill: 93 rfkill_destroy(rfk); 94err_rfk_alloc: 95 tosa_bt_off(data); 96err_pwr_dir: 97 gpio_free(data->gpio_pwr); 98err_pwr: 99err_reset_dir: 100 gpio_free(data->gpio_reset); 101err_reset: 102 return rc; 103} 104 105static int tosa_bt_remove(struct platform_device *dev) 106{ 107 struct tosa_bt_data *data = dev->dev.platform_data; 108 struct rfkill *rfk = platform_get_drvdata(dev); 109 110 platform_set_drvdata(dev, NULL); 111 112 if (rfk) { 113 rfkill_unregister(rfk); 114 rfkill_destroy(rfk); 115 } 116 rfk = NULL; 117 118 tosa_bt_off(data); 119 120 gpio_free(data->gpio_pwr); 121 gpio_free(data->gpio_reset); 122 123 return 0; 124} 125 126static struct platform_driver tosa_bt_driver = { 127 .probe = tosa_bt_probe, 128 .remove = tosa_bt_remove, 129 130 .driver = { 131 .name = "tosa-bt", 132 }, 133}; 134 135 136static int __init tosa_bt_init(void) 137{ 138 return platform_driver_register(&tosa_bt_driver); 139} 140 141static void __exit tosa_bt_exit(void) 142{ 143 platform_driver_unregister(&tosa_bt_driver); 144} 145 146module_init(tosa_bt_init); 147module_exit(tosa_bt_exit); 148