Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

platform/x86: add meraki-mx100 platform driver

This adds platform support for the Cisco Meraki MX100 (Tinkerbell)
network appliance. This sets up the network LEDs and Reset
button.

Depends-on: ef0eea5b151ae ("mfd: lpc_ich: Enable GPIO driver for DH89xxCC")
Co-developed-by: Christian Lamparter <chunkeey@gmail.com>
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
Signed-off-by: Chris Blake <chrisrblake93@gmail.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Link: https://lore.kernel.org/r/20210810004021.2538308-1-chrisrblake93@gmail.com
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>

authored by

Chris Blake and committed by
Hans de Goede
636a1e69 f6413ba3

+246
+13
drivers/platform/x86/Kconfig
··· 302 302 If you have an ACPI-WMI compatible Asus Notebook, say Y or M 303 303 here. 304 304 305 + config MERAKI_MX100 306 + tristate "Cisco Meraki MX100 Platform Driver" 307 + depends on GPIOLIB 308 + depends on GPIO_ICH 309 + depends on LEDS_CLASS 310 + select LEDS_GPIO 311 + help 312 + This driver provides support for the front button and LEDs on 313 + the Cisco Meraki MX100 (Tinkerbell) 1U appliance. 314 + 315 + To compile this driver as a module, choose M here: the module 316 + will be called meraki-mx100. 317 + 305 318 config EEEPC_LAPTOP 306 319 tristate "Eee PC Hotkey Driver" 307 320 depends on ACPI
+3
drivers/platform/x86/Makefile
··· 39 39 obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o 40 40 obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o 41 41 42 + # Cisco/Meraki 43 + obj-$(CONFIG_MERAKI_MX100) += meraki-mx100.o 44 + 42 45 # Dell 43 46 obj-$(CONFIG_X86_PLATFORM_DRIVERS_DELL) += dell/ 44 47
+230
drivers/platform/x86/meraki-mx100.c
··· 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 */ 30 + static 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 + 79 + static const struct gpio_led_platform_data tink_leds_pdata = { 80 + .num_leds = ARRAY_SIZE(tink_leds), 81 + .leds = tink_leds, 82 + }; 83 + 84 + static 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 */ 122 + static 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 + 132 + static 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 + 140 + static 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 */ 150 + static 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 + }; 159 + MODULE_DEVICE_TABLE(dmi, tink_systems); 160 + 161 + static struct platform_device *tink_leds_pdev; 162 + static struct platform_device *tink_keys_pdev; 163 + 164 + static 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 + 177 + static 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 + 211 + err: 212 + gpiod_remove_lookup_table(&tink_keys_table); 213 + gpiod_remove_lookup_table(&tink_leds_table); 214 + return ret; 215 + } 216 + module_init(tink_board_init); 217 + 218 + static 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 + } 225 + module_exit(tink_board_exit); 226 + 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");