Add rfkill for BCM 4329 for bluetooth.
authorJaikumar Ganesh <jaikumar@google.com>
Fri, 11 Jun 2010 17:57:11 +0000 (10:57 -0700)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:33:09 +0000 (16:33 -0700)
Signed-off-by: Jaikumar Ganesh <jaikumar@google.com>
arch/arm/mach-tegra/Makefile
arch/arm/mach-tegra/board-stingray-rfkill.c [new file with mode: 0644]
arch/arm/mach-tegra/board-stingray.c

index c3b38bbf4727d128df5153d9e7dc3ce0525aa7ce..d0273a0bea3a532486a6d900e6a6a5459c8ffea0 100644 (file)
@@ -62,3 +62,4 @@ obj-${CONFIG_MACH_STINGRAY}             += board-stingray-sensors.o
 obj-${CONFIG_MACH_STINGRAY}             += board-stingray-wlan_nvs.o
 obj-${CONFIG_MACH_STINGRAY}             += board-stingray-touch.o
 obj-${CONFIG_MACH_STINGRAY}             += board-stingray-spi.o
+obj-${CONFIG_MACH_STINGRAY}             += board-stingray-rfkill.o
diff --git a/arch/arm/mach-tegra/board-stingray-rfkill.c b/arch/arm/mach-tegra/board-stingray-rfkill.c
new file mode 100644 (file)
index 0000000..bdad693
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Bluetooth Broadcomm rfkill power control via GPIO
+ *
+ *  Copyright (C) 2010 Google, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/rfkill.h>
+#include <linux/platform_device.h>
+#include <asm/mach-types.h>
+
+#include "gpio-names.h"
+
+#define BT_SHUTDOWN_GPIO TEGRA_GPIO_PI7
+#define BT_RESET_GPIO TEGRA_GPIO_PU0
+
+static struct rfkill *bt_rfkill;
+
+static int bcm4329_bt_rfkill_set_power(void *data, bool blocked)
+{
+       if (blocked) {
+               gpio_direction_output(BT_SHUTDOWN_GPIO, 0);
+               gpio_direction_output(BT_RESET_GPIO, 0);
+       } else {
+               gpio_direction_output(BT_RESET_GPIO, 1);
+               gpio_direction_output(BT_SHUTDOWN_GPIO, 1);
+       }
+
+       return 0;
+}
+
+static const struct rfkill_ops bcm4329_bt_rfkill_ops = {
+       .set_block = bcm4329_bt_rfkill_set_power,
+};
+
+static int bcm4329_rfkill_probe(struct platform_device *pdev)
+{
+       int rc = 0;
+       bool default_state = true;  /* off */
+
+       tegra_gpio_enable(BT_RESET_GPIO);
+       rc = gpio_request(BT_RESET_GPIO, "bcm4329_nreset_gpip");
+       if (unlikely(rc))
+               return rc;
+
+
+       tegra_gpio_enable(BT_SHUTDOWN_GPIO);
+       rc = gpio_request(BT_SHUTDOWN_GPIO, "bcm4329_nshutdown_gpio");
+       if (unlikely(rc))
+               return rc;
+
+       bcm4329_bt_rfkill_set_power(NULL, default_state);
+
+       bt_rfkill = rfkill_alloc("bcm4329 Bluetooth", &pdev->dev,
+                               RFKILL_TYPE_BLUETOOTH, &bcm4329_bt_rfkill_ops,
+                               NULL);
+
+       if (unlikely(!bt_rfkill))
+               return -ENOMEM;
+
+       rfkill_set_states(bt_rfkill, default_state, false);
+
+       rc = rfkill_register(bt_rfkill);
+
+       if (unlikely(rc))
+               rfkill_destroy(bt_rfkill);
+
+       return 0;
+}
+
+static int bcm4329_rfkill_remove(struct platform_device *pdev)
+{
+       rfkill_unregister(bt_rfkill);
+       rfkill_destroy(bt_rfkill);
+       gpio_free(BT_SHUTDOWN_GPIO);
+       gpio_free(BT_RESET_GPIO);
+
+       return 0;
+}
+
+static struct platform_driver bcm4329_rfkill_platform_driver = {
+       .probe = bcm4329_rfkill_probe,
+       .remove = bcm4329_rfkill_remove,
+       .driver = {
+                  .name = "bcm4329_rfkill",
+                  .owner = THIS_MODULE,
+                  },
+};
+
+static int __init bcm4329_rfkill_init(void)
+{
+       if (!machine_is_stingray())
+               return 0;
+       return platform_driver_register(&bcm4329_rfkill_platform_driver);
+}
+
+static void __exit bcm4329_rfkill_exit(void)
+{
+       platform_driver_unregister(&bcm4329_rfkill_platform_driver);
+}
+
+module_init(bcm4329_rfkill_init);
+module_exit(bcm4329_rfkill_exit);
+
+MODULE_ALIAS("platform:bcm4329");
+MODULE_DESCRIPTION("bcm4329_rfkill");
+MODULE_AUTHOR("Jaikumar Ganesh <jaikumar@google.com>");
+MODULE_LICENSE("GPL");
index fa3985e15c352e3f1dfeb28c1ad9c95c5231a0fb..c9d44eca83804edf900d7644cb2880b44683123a 100644 (file)
@@ -179,14 +179,14 @@ static u64 tegra_otg_dmamask = DMA_BIT_MASK(32);
 
 static struct resource tegra_otg_resources[] = {
        [0] = {
-               .start  = TEGRA_USB_BASE,
-               .end    = TEGRA_USB_BASE + TEGRA_USB_SIZE - 1,
-               .flags  = IORESOURCE_MEM,
+               .start  = TEGRA_USB_BASE,
+               .end    = TEGRA_USB_BASE + TEGRA_USB_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = INT_USB,
-               .end    = INT_USB,
-               .flags  = IORESOURCE_IRQ,
+               .start  = INT_USB,
+               .end    = INT_USB,
+               .flags  = IORESOURCE_IRQ,
        },
 };
 
@@ -212,24 +212,24 @@ static char *usb_functions_adb[] = { "mtp", "adb" };
 
 static struct android_usb_product usb_products[] = {
        {
-               .product_id     = 0xDEAD,
-               .num_functions  = ARRAY_SIZE(usb_functions),
-               .functions      = usb_functions,
+               .product_id     = 0xDEAD,
+               .num_functions  = ARRAY_SIZE(usb_functions),
+               .functions      = usb_functions,
        },
        {
-               .product_id     = 0xBEEF,
-               .num_functions  = ARRAY_SIZE(usb_functions_adb),
-               .functions      = usb_functions_adb,
+               .product_id     = 0xBEEF,
+               .num_functions  = ARRAY_SIZE(usb_functions_adb),
+               .functions      = usb_functions_adb,
        },
 };
 
 /* standard android USB platform data */
 static struct android_usb_platform_data andusb_plat = {
-       .vendor_id                      = 0x18d1,
-       .product_id                     = 0xDEAD,
-       .manufacturer_name      = "Google",
-       .product_name           = "Stingray!",
-       .serial_number          = "0000",
+       .vendor_id              = 0x18d1,
+       .product_id             = 0xDEAD,
+       .manufacturer_name      = "Google",
+       .product_name           = "Stingray!",
+       .serial_number          = "0000",
        .num_products = ARRAY_SIZE(usb_products),
        .products = usb_products,
        .num_functions = ARRAY_SIZE(usb_functions_adb),
@@ -238,10 +238,10 @@ static struct android_usb_platform_data andusb_plat = {
 
 
 static struct platform_device androidusb_device = {
-       .name   = "android_usb",
-       .id     = -1,
-       .dev    = {
-               .platform_data  = &andusb_plat,
+       .name   = "android_usb",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &andusb_plat,
        },
 };
 
@@ -283,22 +283,22 @@ static struct resource bq24617_resources_m1_p0[] = {
 };
 
 static struct platform_device bq24617_device = {
-       .name   = "bq24617",
-       .id     = -1,
-       .resource      = bq24617_resources,
-       .num_resources = ARRAY_SIZE(bq24617_resources),
+       .name           = "bq24617",
+       .id             = -1,
+       .resource       = bq24617_resources,
+       .num_resources  = ARRAY_SIZE(bq24617_resources),
 };
 
 static struct resource tegra_gart_resources[] = {
     {
-        .name = "mc",
-        .flags = IORESOURCE_MEM,
+       .name = "mc",
+       .flags = IORESOURCE_MEM,
        .start = TEGRA_MC_BASE,
        .end = TEGRA_MC_BASE + TEGRA_MC_SIZE - 1,
     },
     {
-        .name = "gart",
-        .flags = IORESOURCE_MEM,
+       .name = "gart",
+       .flags = IORESOURCE_MEM,
        .start = 0x58000000,
        .end = 0x58000000 - 1 + 32 * 1024 * 1024,
     }
@@ -312,11 +312,17 @@ static struct platform_device tegra_gart_dev = {
     .resource = tegra_gart_resources
 };
 
+static struct platform_device bcm4329_rfkill = {
+       .name = "bcm4329_rfkill",
+       .id = -1,
+};
+
 static struct platform_device *stingray_devices[] __initdata = {
        &debug_uart,
        &tegra_otg,
        &androidusb_device,
        &bq24617_device,
+       &bcm4329_rfkill,
        &hs_uarta,
        &hs_uartc,
        &hs_uartd,
@@ -382,6 +388,30 @@ static void stingray_sdhci_init(void)
        platform_device_register(&tegra_sdhci_device4);
 }
 
+#define ATAG_BDADDR 0x43294329 /* stingray bluetooth address tag */
+#define ATAG_BDADDR_SIZE 4
+#define BDADDR_STR_SIZE 18
+
+static char bdaddr[BDADDR_STR_SIZE];
+
+module_param_string(bdaddr, bdaddr, sizeof(bdaddr), 0400);
+MODULE_PARM_DESC(bdaddr, "bluetooth address");
+
+static int __init parse_tag_bdaddr(const struct tag *tag)
+{
+       unsigned char *b = (unsigned char *)&tag->u;
+
+       if (tag->hdr.size != ATAG_BDADDR_SIZE)
+               return -EINVAL;
+
+       snprintf(bdaddr, BDADDR_STR_SIZE, "%02X:%02X:%02X:%02X:%02X:%02X",
+                       b[0], b[1], b[2], b[3], b[4], b[5]);
+
+       return 0;
+}
+
+__tagtable(ATAG_BDADDR, parse_tag_bdaddr);
+
 
 static void __init tegra_stingray_fixup(struct machine_desc *desc, struct tag *tags,
                                 char **cmdline, struct meminfo *mi)
@@ -496,12 +526,12 @@ static void __init tegra_stingray_init(void)
 }
 
 MACHINE_START(STINGRAY, "stingray")
-       .boot_params  = 0x00000100,
-       .phys_io        = IO_APB_PHYS,
-       .io_pg_offst    = ((IO_APB_VIRT) >> 18) & 0xfffc,
+       .boot_params    = 0x00000100,
+       .phys_io        = IO_APB_PHYS,
+       .io_pg_offst    = ((IO_APB_VIRT) >> 18) & 0xfffc,
        .fixup          = tegra_stingray_fixup,
-       .init_irq       = tegra_init_irq,
-       .init_machine   = tegra_stingray_init,
-       .map_io         = tegra_map_common_io,
-       .timer          = &tegra_timer,
+       .init_irq       = tegra_init_irq,
+       .init_machine   = tegra_stingray_init,
+       .map_io         = tegra_map_common_io,
+       .timer          = &tegra_timer,
 MACHINE_END