--- /dev/null
+/*
+ * 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");
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,
},
};
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),
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,
},
};
};
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,
}
.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,
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)
}
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