1 /*
2  * Bluetooth platform data initialization file
3  *
4  * (C) Copyright 2017 Intel Corporation
5  * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; version 2
10  * of the License.
11  */
12 
13 #include <linux/gpio/machine.h>
14 #include <linux/pci.h>
15 #include <linux/platform_device.h>
16 
17 #include <asm/cpu_device_id.h>
18 #include <asm/intel-family.h>
19 #include <asm/intel-mid.h>
20 
21 struct bt_sfi_data {
22 	struct device *dev;
23 	const char *name;
24 	int (*setup)(struct bt_sfi_data *ddata);
25 };
26 
27 static struct gpiod_lookup_table tng_bt_sfi_gpio_table = {
28 	.dev_id	= "hci_bcm",
29 	.table	= {
30 		GPIO_LOOKUP("0000:00:0c.0", -1, "device-wakeup", GPIO_ACTIVE_HIGH),
31 		GPIO_LOOKUP("0000:00:0c.0", -1, "shutdown",      GPIO_ACTIVE_HIGH),
32 		GPIO_LOOKUP("0000:00:0c.0", -1, "host-wakeup",   GPIO_ACTIVE_HIGH),
33 		{ },
34 	},
35 };
36 
37 #define TNG_BT_SFI_GPIO_DEVICE_WAKEUP	"bt_wakeup"
38 #define TNG_BT_SFI_GPIO_SHUTDOWN	"BT-reset"
39 #define TNG_BT_SFI_GPIO_HOST_WAKEUP	"bt_uart_enable"
40 
tng_bt_sfi_setup(struct bt_sfi_data * ddata)41 static int __init tng_bt_sfi_setup(struct bt_sfi_data *ddata)
42 {
43 	struct gpiod_lookup_table *table = &tng_bt_sfi_gpio_table;
44 	struct gpiod_lookup *lookup = table->table;
45 	struct pci_dev *pdev;
46 
47 	/* Connected to /dev/ttyS0 */
48 	pdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(4, 1));
49 	if (!pdev)
50 		return -ENODEV;
51 
52 	ddata->dev = &pdev->dev;
53 	ddata->name = table->dev_id;
54 
55 	lookup[0].chip_hwnum = get_gpio_by_name(TNG_BT_SFI_GPIO_DEVICE_WAKEUP);
56 	lookup[1].chip_hwnum = get_gpio_by_name(TNG_BT_SFI_GPIO_SHUTDOWN);
57 	lookup[2].chip_hwnum = get_gpio_by_name(TNG_BT_SFI_GPIO_HOST_WAKEUP);
58 
59 	gpiod_add_lookup_table(table);
60 	return 0;
61 }
62 
63 static struct bt_sfi_data tng_bt_sfi_data __initdata = {
64 	.setup	= tng_bt_sfi_setup,
65 };
66 
67 #define ICPU(model, ddata)	\
68 	{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (kernel_ulong_t)&ddata }
69 
70 static const struct x86_cpu_id bt_sfi_cpu_ids[] = {
71 	ICPU(INTEL_FAM6_ATOM_MERRIFIELD, tng_bt_sfi_data),
72 	{}
73 };
74 
bt_sfi_init(void)75 static int __init bt_sfi_init(void)
76 {
77 	struct platform_device_info info;
78 	struct platform_device *pdev;
79 	const struct x86_cpu_id *id;
80 	struct bt_sfi_data *ddata;
81 	int ret;
82 
83 	id = x86_match_cpu(bt_sfi_cpu_ids);
84 	if (!id)
85 		return -ENODEV;
86 
87 	ddata = (struct bt_sfi_data *)id->driver_data;
88 	if (!ddata)
89 		return -ENODEV;
90 
91 	ret = ddata->setup(ddata);
92 	if (ret)
93 		return ret;
94 
95 	memset(&info, 0, sizeof(info));
96 	info.fwnode	= ddata->dev->fwnode;
97 	info.parent	= ddata->dev;
98 	info.name	= ddata->name,
99 	info.id		= PLATFORM_DEVID_NONE,
100 
101 	pdev = platform_device_register_full(&info);
102 	if (IS_ERR(pdev))
103 		return PTR_ERR(pdev);
104 
105 	dev_info(ddata->dev, "Registered Bluetooth device: %s\n", ddata->name);
106 	return 0;
107 }
108 device_initcall(bt_sfi_init);
109