1
2
3
4
5
6
7
8
9#include <linux/gpio/machine.h>
10#include <linux/pci.h>
11#include <linux/platform_device.h>
12
13#include <asm/cpu_device_id.h>
14#include <asm/intel-family.h>
15#include <asm/intel-mid.h>
16
17struct bt_sfi_data {
18 struct device *dev;
19 const char *name;
20 int (*setup)(struct bt_sfi_data *ddata);
21};
22
23static struct gpiod_lookup_table tng_bt_sfi_gpio_table = {
24 .dev_id = "hci_bcm",
25 .table = {
26 GPIO_LOOKUP("0000:00:0c.0", -1, "device-wakeup", GPIO_ACTIVE_HIGH),
27 GPIO_LOOKUP("0000:00:0c.0", -1, "shutdown", GPIO_ACTIVE_HIGH),
28 GPIO_LOOKUP("0000:00:0c.0", -1, "host-wakeup", GPIO_ACTIVE_HIGH),
29 { },
30 },
31};
32
33#define TNG_BT_SFI_GPIO_DEVICE_WAKEUP "bt_wakeup"
34#define TNG_BT_SFI_GPIO_SHUTDOWN "BT-reset"
35#define TNG_BT_SFI_GPIO_HOST_WAKEUP "bt_uart_enable"
36
37static int __init tng_bt_sfi_setup(struct bt_sfi_data *ddata)
38{
39 struct gpiod_lookup_table *table = &tng_bt_sfi_gpio_table;
40 struct gpiod_lookup *lookup = table->table;
41 struct pci_dev *pdev;
42
43
44 pdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(4, 1));
45 if (!pdev)
46 return -ENODEV;
47
48 ddata->dev = &pdev->dev;
49 ddata->name = table->dev_id;
50
51 lookup[0].chip_hwnum = get_gpio_by_name(TNG_BT_SFI_GPIO_DEVICE_WAKEUP);
52 lookup[1].chip_hwnum = get_gpio_by_name(TNG_BT_SFI_GPIO_SHUTDOWN);
53 lookup[2].chip_hwnum = get_gpio_by_name(TNG_BT_SFI_GPIO_HOST_WAKEUP);
54
55 gpiod_add_lookup_table(table);
56 return 0;
57}
58
59static struct bt_sfi_data tng_bt_sfi_data __initdata = {
60 .setup = tng_bt_sfi_setup,
61};
62
63static const struct x86_cpu_id bt_sfi_cpu_ids[] = {
64 X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_MID, &tng_bt_sfi_data),
65 {}
66};
67
68static int __init bt_sfi_init(void)
69{
70 struct platform_device_info info;
71 struct platform_device *pdev;
72 const struct x86_cpu_id *id;
73 struct bt_sfi_data *ddata;
74 int ret;
75
76 id = x86_match_cpu(bt_sfi_cpu_ids);
77 if (!id)
78 return -ENODEV;
79
80 ddata = (struct bt_sfi_data *)id->driver_data;
81 if (!ddata)
82 return -ENODEV;
83
84 ret = ddata->setup(ddata);
85 if (ret)
86 return ret;
87
88 memset(&info, 0, sizeof(info));
89 info.fwnode = ddata->dev->fwnode;
90 info.parent = ddata->dev;
91 info.name = ddata->name,
92 info.id = PLATFORM_DEVID_NONE,
93
94 pdev = platform_device_register_full(&info);
95 if (IS_ERR(pdev))
96 return PTR_ERR(pdev);
97
98 dev_info(ddata->dev, "Registered Bluetooth device: %s\n", ddata->name);
99 return 0;
100}
101device_initcall(bt_sfi_init);
102