1 // SPDX-License-Identifier: GPL-2.0+
4 * Cisco Meraki MX100 (Tinkerbell) board platform driver
6 * Based off of arch/x86/platform/meraki/tink.c from the
7 * Meraki GPL release meraki-firmware-sources-r23-20150601
9 * Format inspired by platform/x86/pcengines-apuv2.c
11 * Copyright (C) 2021 Chris Blake <chrisrblake93@gmail.com>
14 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
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>
22 #include <linux/kernel.h>
23 #include <linux/leds.h>
24 #include <linux/module.h>
25 #include <linux/platform_device.h>
27 #define TINK_GPIO_DRIVER_NAME "gpio_ich"
30 static const struct gpio_led tink_leds
[] = {
32 .name
= "mx100:green:internet",
33 .default_trigger
= "default-on",
36 .name
= "mx100:green:lan2",
39 .name
= "mx100:green:lan3",
42 .name
= "mx100:green:lan4",
45 .name
= "mx100:green:lan5",
48 .name
= "mx100:green:lan6",
51 .name
= "mx100:green:lan7",
54 .name
= "mx100:green:lan8",
57 .name
= "mx100:green:lan9",
60 .name
= "mx100:green:lan10",
63 .name
= "mx100:green:lan11",
66 .name
= "mx100:green:ha",
69 .name
= "mx100:orange:ha",
72 .name
= "mx100:green:usb",
75 .name
= "mx100:orange:usb",
79 static const struct gpio_led_platform_data tink_leds_pdata
= {
80 .num_leds
= ARRAY_SIZE(tink_leds
),
84 static struct gpiod_lookup_table tink_leds_table
= {
85 .dev_id
= "leds-gpio",
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 */
122 static struct gpio_keys_button tink_buttons
[] = {
128 .debounce_interval
= 100,
132 static const struct gpio_keys_platform_data tink_buttons_pdata
= {
133 .buttons
= tink_buttons
,
134 .nbuttons
= ARRAY_SIZE(tink_buttons
),
137 .name
= "mx100-keys",
140 static struct gpiod_lookup_table tink_keys_table
= {
141 .dev_id
= "gpio-keys-polled",
143 GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME
, 60,
144 NULL
, 0, GPIO_ACTIVE_LOW
),
145 {} /* Terminating entry */
150 static const struct dmi_system_id tink_systems
[] __initconst
= {
153 DMI_EXACT_MATCH(DMI_SYS_VENDOR
, "Cisco"),
154 DMI_EXACT_MATCH(DMI_PRODUCT_NAME
, "MX100-HW"),
157 {} /* Terminating entry */
159 MODULE_DEVICE_TABLE(dmi
, tink_systems
);
161 static struct platform_device
*tink_leds_pdev
;
162 static struct platform_device
*tink_keys_pdev
;
164 static struct platform_device
* __init
tink_create_dev(
165 const char *name
, const void *pdata
, size_t sz
)
167 struct platform_device
*pdev
;
169 pdev
= platform_device_register_data(NULL
,
170 name
, PLATFORM_DEVID_NONE
, pdata
, sz
);
172 pr_err("failed registering %s: %ld\n", name
, PTR_ERR(pdev
));
177 static int __init
tink_board_init(void)
181 if (!dmi_first_match(tink_systems
))
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
189 outl(inl(0x530) | BIT(28), 0x530);
191 gpiod_add_lookup_table(&tink_leds_table
);
192 gpiod_add_lookup_table(&tink_keys_table
);
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
);
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
);
212 gpiod_remove_lookup_table(&tink_keys_table
);
213 gpiod_remove_lookup_table(&tink_leds_table
);
216 module_init(tink_board_init
);
218 static void __exit
tink_board_exit(void)
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
);
225 module_exit(tink_board_exit
);
227 MODULE_AUTHOR("Chris Blake <chrisrblake93@gmail.com>");
228 MODULE_DESCRIPTION("Cisco Meraki MX100 Platform Driver");
229 MODULE_LICENSE("GPL");
230 MODULE_ALIAS("platform:meraki-mx100");