Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0+
  2
  3/*
  4 * Cisco Meraki MX100 (Tinkerbell) board platform driver
  5 *
  6 * Based off of arch/x86/platform/meraki/tink.c from the
  7 * Meraki GPL release meraki-firmware-sources-r23-20150601
  8 *
  9 * Format inspired by platform/x86/pcengines-apuv2.c
 10 *
 11 * Copyright (C) 2021 Chris Blake <chrisrblake93@gmail.com>
 12 */
 13
 14#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
 15
 16#include <linux/dmi.h>
 17#include <linux/err.h>
 18#include <linux/gpio_keys.h>
 19#include <linux/gpio/machine.h>
 20#include <linux/input.h>
 21#include <linux/io.h>
 22#include <linux/kernel.h>
 23#include <linux/leds.h>
 24#include <linux/module.h>
 25#include <linux/platform_device.h>
 26
 27#define TINK_GPIO_DRIVER_NAME "gpio_ich"
 28
 29/* LEDs */
 30static const struct gpio_led tink_leds[] = {
 31	{
 32		.name = "mx100:green:internet",
 33		.default_trigger = "default-on",
 34	},
 35	{
 36		.name = "mx100:green:lan2",
 37	},
 38	{
 39		.name = "mx100:green:lan3",
 40	},
 41	{
 42		.name = "mx100:green:lan4",
 43	},
 44	{
 45		.name = "mx100:green:lan5",
 46	},
 47	{
 48		.name = "mx100:green:lan6",
 49	},
 50	{
 51		.name = "mx100:green:lan7",
 52	},
 53	{
 54		.name = "mx100:green:lan8",
 55	},
 56	{
 57		.name = "mx100:green:lan9",
 58	},
 59	{
 60		.name = "mx100:green:lan10",
 61	},
 62	{
 63		.name = "mx100:green:lan11",
 64	},
 65	{
 66		.name = "mx100:green:ha",
 67	},
 68	{
 69		.name = "mx100:orange:ha",
 70	},
 71	{
 72		.name = "mx100:green:usb",
 73	},
 74	{
 75		.name = "mx100:orange:usb",
 76	},
 77};
 78
 79static const struct gpio_led_platform_data tink_leds_pdata = {
 80	.num_leds	= ARRAY_SIZE(tink_leds),
 81	.leds		= tink_leds,
 82};
 83
 84static struct gpiod_lookup_table tink_leds_table = {
 85	.dev_id = "leds-gpio",
 86	.table = {
 87		GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 11,
 88				NULL, 0, GPIO_ACTIVE_LOW),
 89		GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 18,
 90				NULL, 1, GPIO_ACTIVE_HIGH),
 91		GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 20,
 92				NULL, 2, GPIO_ACTIVE_HIGH),
 93		GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 22,
 94				NULL, 3, GPIO_ACTIVE_HIGH),
 95		GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 23,
 96				NULL, 4, GPIO_ACTIVE_HIGH),
 97		GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 32,
 98				NULL, 5, GPIO_ACTIVE_HIGH),
 99		GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 34,
100				NULL, 6, GPIO_ACTIVE_HIGH),
101		GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 35,
102				NULL, 7, GPIO_ACTIVE_HIGH),
103		GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 36,
104				NULL, 8, GPIO_ACTIVE_HIGH),
105		GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 37,
106				NULL, 9, GPIO_ACTIVE_HIGH),
107		GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 48,
108				NULL, 10, GPIO_ACTIVE_HIGH),
109		GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 16,
110				NULL, 11, GPIO_ACTIVE_LOW),
111		GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 7,
112				NULL, 12, GPIO_ACTIVE_LOW),
113		GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 21,
114				NULL, 13, GPIO_ACTIVE_LOW),
115		GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 19,
116				NULL, 14, GPIO_ACTIVE_LOW),
117		{} /* Terminating entry */
118	}
119};
120
121/* Reset Button */
122static struct gpio_keys_button tink_buttons[] = {
123	{
124		.desc			= "Reset",
125		.type			= EV_KEY,
126		.code			= KEY_RESTART,
127		.active_low             = 1,
128		.debounce_interval      = 100,
129	},
130};
131
132static const struct gpio_keys_platform_data tink_buttons_pdata = {
133	.buttons	= tink_buttons,
134	.nbuttons	= ARRAY_SIZE(tink_buttons),
135	.poll_interval  = 20,
136	.rep		= 0,
137	.name		= "mx100-keys",
138};
139
140static struct gpiod_lookup_table tink_keys_table = {
141	.dev_id = "gpio-keys-polled",
142	.table = {
143		GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 60,
144				NULL, 0, GPIO_ACTIVE_LOW),
145		{} /* Terminating entry */
146	}
147};
148
149/* Board setup */
150static const struct dmi_system_id tink_systems[] __initconst = {
151	{
152		.matches = {
153			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Cisco"),
154			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "MX100-HW"),
155		},
156	},
157	{} /* Terminating entry */
158};
159MODULE_DEVICE_TABLE(dmi, tink_systems);
160
161static struct platform_device *tink_leds_pdev;
162static struct platform_device *tink_keys_pdev;
163
164static struct platform_device * __init tink_create_dev(
165	const char *name, const void *pdata, size_t sz)
166{
167	struct platform_device *pdev;
168
169	pdev = platform_device_register_data(NULL,
170		name, PLATFORM_DEVID_NONE, pdata, sz);
171	if (IS_ERR(pdev))
172		pr_err("failed registering %s: %ld\n", name, PTR_ERR(pdev));
173
174	return pdev;
175}
176
177static int __init tink_board_init(void)
178{
179	int ret;
180
181	if (!dmi_first_match(tink_systems))
182		return -ENODEV;
183
184	/*
185	 * We need to make sure that GPIO60 isn't set to native mode as is default since it's our
186	 * Reset Button. To do this, write to GPIO_USE_SEL2 to have GPIO60 set to GPIO mode.
187	 * This is documented on page 1609 of the PCH datasheet, order number 327879-005US
188	 */
189	outl(inl(0x530) | BIT(28), 0x530);
190
191	gpiod_add_lookup_table(&tink_leds_table);
192	gpiod_add_lookup_table(&tink_keys_table);
193
194	tink_leds_pdev = tink_create_dev("leds-gpio",
195		&tink_leds_pdata, sizeof(tink_leds_pdata));
196	if (IS_ERR(tink_leds_pdev)) {
197		ret = PTR_ERR(tink_leds_pdev);
198		goto err;
199	}
200
201	tink_keys_pdev = tink_create_dev("gpio-keys-polled",
202		&tink_buttons_pdata, sizeof(tink_buttons_pdata));
203	if (IS_ERR(tink_keys_pdev)) {
204		ret = PTR_ERR(tink_keys_pdev);
205		platform_device_unregister(tink_leds_pdev);
206		goto err;
207	}
208
209	return 0;
210
211err:
212	gpiod_remove_lookup_table(&tink_keys_table);
213	gpiod_remove_lookup_table(&tink_leds_table);
214	return ret;
215}
216module_init(tink_board_init);
217
218static void __exit tink_board_exit(void)
219{
220	platform_device_unregister(tink_keys_pdev);
221	platform_device_unregister(tink_leds_pdev);
222	gpiod_remove_lookup_table(&tink_keys_table);
223	gpiod_remove_lookup_table(&tink_leds_table);
224}
225module_exit(tink_board_exit);
226
227MODULE_AUTHOR("Chris Blake <chrisrblake93@gmail.com>");
228MODULE_DESCRIPTION("Cisco Meraki MX100 Platform Driver");
229MODULE_LICENSE("GPL");
230MODULE_ALIAS("platform:meraki-mx100");