x86/platform/intel-mid: Enable Bluetooth support on Intel Edison
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Thu, 30 Mar 2017 10:04:43 +0000 (13:04 +0300)
committerIngo Molnar <mingo@kernel.org>
Fri, 31 Mar 2017 06:06:29 +0000 (08:06 +0200)
Intel Edison has Wi-Fi + BT module attached and, since it's an SFI-enumerated
platform, needs platform data. Here we add bits to enable the Bluetooth device.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20170330100443.22701-1-andriy.shevchenko@linux.intel.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
arch/x86/platform/intel-mid/device_libs/Makefile
arch/x86/platform/intel-mid/device_libs/platform_bt.c [new file with mode: 0644]

index a7dbec4dce2758261c6e1680b7ed825e5e44a9d1..36f0fdf6079aa1c6df7eebaaed5e626ee7b47b7e 100644 (file)
@@ -2,8 +2,9 @@
 obj-$(subst m,y,$(CONFIG_PINCTRL_MERRIFIELD)) += platform_mrfld_pinctrl.o
 # SDHCI Devices
 obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += platform_mrfld_sd.o
-# WiFi
+# WiFi + BT
 obj-$(subst m,y,$(CONFIG_BRCMFMAC_SDIO)) += platform_bcm43xx.o
+obj-$(subst m,y,$(CONFIG_BT_HCIUART_BCM)) += platform_bt.o
 # IPC Devices
 obj-$(subst m,y,$(CONFIG_MFD_INTEL_MSIC)) += platform_msic.o
 obj-$(subst m,y,$(CONFIG_SND_MFLD_MACHINE)) += platform_msic_audio.o
diff --git a/arch/x86/platform/intel-mid/device_libs/platform_bt.c b/arch/x86/platform/intel-mid/device_libs/platform_bt.c
new file mode 100644 (file)
index 0000000..5a0483e
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Bluetooth platform data initialization file
+ *
+ * (C) Copyright 2017 Intel Corporation
+ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+ *
+ * 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; version 2
+ * of the License.
+ */
+
+#include <linux/gpio/machine.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+#include <asm/cpu_device_id.h>
+#include <asm/intel-family.h>
+#include <asm/intel-mid.h>
+
+struct bt_sfi_data {
+       struct device *dev;
+       const char *name;
+       int (*setup)(struct bt_sfi_data *ddata);
+};
+
+static struct gpiod_lookup_table tng_bt_sfi_gpio_table = {
+       .dev_id = "hci_bcm",
+       .table  = {
+               GPIO_LOOKUP("0000:00:0c.0", -1, "device-wakeup", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("0000:00:0c.0", -1, "shutdown",      GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("0000:00:0c.0", -1, "host-wakeup",   GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
+#define TNG_BT_SFI_GPIO_DEVICE_WAKEUP  "bt_wakeup"
+#define TNG_BT_SFI_GPIO_SHUTDOWN       "BT-reset"
+#define TNG_BT_SFI_GPIO_HOST_WAKEUP    "bt_uart_enable"
+
+static int __init tng_bt_sfi_setup(struct bt_sfi_data *ddata)
+{
+       struct gpiod_lookup_table *table = &tng_bt_sfi_gpio_table;
+       struct gpiod_lookup *lookup = table->table;
+       struct pci_dev *pdev;
+
+       /* Connected to /dev/ttyS0 */
+       pdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(4, 1));
+       if (!pdev)
+               return -ENODEV;
+
+       ddata->dev = &pdev->dev;
+       ddata->name = table->dev_id;
+
+       lookup[0].chip_hwnum = get_gpio_by_name(TNG_BT_SFI_GPIO_DEVICE_WAKEUP);
+       lookup[1].chip_hwnum = get_gpio_by_name(TNG_BT_SFI_GPIO_SHUTDOWN);
+       lookup[2].chip_hwnum = get_gpio_by_name(TNG_BT_SFI_GPIO_HOST_WAKEUP);
+
+       gpiod_add_lookup_table(table);
+       return 0;
+}
+
+static struct bt_sfi_data tng_bt_sfi_data __initdata = {
+       .setup  = tng_bt_sfi_setup,
+};
+
+#define ICPU(model, ddata)     \
+       { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (kernel_ulong_t)&ddata }
+
+static const struct x86_cpu_id bt_sfi_cpu_ids[] = {
+       ICPU(INTEL_FAM6_ATOM_MERRIFIELD, tng_bt_sfi_data),
+       {}
+};
+
+static int __init bt_sfi_init(void)
+{
+       struct platform_device_info info;
+       struct platform_device *pdev;
+       const struct x86_cpu_id *id;
+       struct bt_sfi_data *ddata;
+       int ret;
+
+       id = x86_match_cpu(bt_sfi_cpu_ids);
+       if (!id)
+               return -ENODEV;
+
+       ddata = (struct bt_sfi_data *)id->driver_data;
+       if (!ddata)
+               return -ENODEV;
+
+       ret = ddata->setup(ddata);
+       if (ret)
+               return ret;
+
+       memset(&info, 0, sizeof(info));
+       info.fwnode     = ddata->dev->fwnode;
+       info.parent     = ddata->dev;
+       info.name       = ddata->name,
+       info.id         = PLATFORM_DEVID_NONE,
+
+       pdev = platform_device_register_full(&info);
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
+
+       dev_info(ddata->dev, "Registered Bluetooth device: %s\n", ddata->name);
+       return 0;
+}
+device_initcall(bt_sfi_init);