/* * Bluetooth built-in chip control * * Copyright (c) 2008 Dmitry Baryshkov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/gpio.h> #include <linux/delay.h> #include <linux/rfkill.h> #include <mach/tosa_bt.h> static void tosa_bt_on(struct tosa_bt_data *data) { gpio_set_value(data->gpio_reset, 0); gpio_set_value(data->gpio_pwr, 1); gpio_set_value(data->gpio_reset, 1); mdelay(20); gpio_set_value(data->gpio_reset, 0); } static void tosa_bt_off(struct tosa_bt_data *data) { gpio_set_value(data->gpio_reset, 1); mdelay(10); gpio_set_value(data->gpio_pwr, 0); gpio_set_value(data->gpio_reset, 0); } static int tosa_bt_set_block(void *data, bool blocked) { pr_info("BT_RADIO going: %s\n", blocked ? "off" : "on"); if (!blocked) { pr_info("TOSA_BT: going ON\n"); tosa_bt_on(data); } else { pr_info("TOSA_BT: going OFF\n"); tosa_bt_off(data); } return 0; } static const struct rfkill_ops tosa_bt_rfkill_ops = { .set_block = tosa_bt_set_block, }; static int tosa_bt_probe(struct platform_device *dev) { int rc; struct rfkill *rfk; struct tosa_bt_data *data = dev->dev.platform_data; rc = gpio_request(data->gpio_reset, "Bluetooth reset"); if (rc) goto err_reset; rc = gpio_direction_output(data->gpio_reset, 0); if (rc) goto err_reset_dir; rc = gpio_request(data->gpio_pwr, "Bluetooth power"); if (rc) goto err_pwr; rc = gpio_direction_output(data->gpio_pwr, 0); if (rc) goto err_pwr_dir; rfk = rfkill_alloc("tosa-bt", &dev->dev, RFKILL_TYPE_BLUETOOTH, &tosa_bt_rfkill_ops, data); if (!rfk) { rc = -ENOMEM; goto err_rfk_alloc; } rc = rfkill_register(rfk); if (rc) goto err_rfkill; platform_set_drvdata(dev, rfk); return 0; err_rfkill: rfkill_destroy(rfk); err_rfk_alloc: tosa_bt_off(data); err_pwr_dir: gpio_free(data->gpio_pwr); err_pwr: err_reset_dir: gpio_free(data->gpio_reset); err_reset: return rc; } static int __devexit tosa_bt_remove(struct platform_device *dev) { struct tosa_bt_data *data = dev->dev.platform_data; struct rfkill *rfk = platform_get_drvdata(dev); platform_set_drvdata(dev, NULL); if (rfk) { rfkill_unregister(rfk); rfkill_destroy(rfk); } rfk = NULL; tosa_bt_off(data); gpio_free(data->gpio_pwr); gpio_free(data->gpio_reset); return 0; } static struct platform_driver tosa_bt_driver = { .probe = tosa_bt_probe, .remove = __devexit_p(tosa_bt_remove), .driver = { .name = "tosa-bt", .owner = THIS_MODULE, }, }; static int __init tosa_bt_init(void) { return platform_driver_register(&tosa_bt_driver); } static void __exit tosa_bt_exit(void) { platform_driver_unregister(&tosa_bt_driver); } module_init(tosa_bt_init); module_exit(tosa_bt_exit);