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

Configure Feed

Select the types of activity you want to include in your feed.

at nocache-cleanup 350 lines 9.8 kB view raw
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/machine.h> 19#include <linux/gpio/property.h> 20#include <linux/input-event-codes.h> 21#include <linux/io.h> 22#include <linux/kernel.h> 23#include <linux/module.h> 24#include <linux/platform_device.h> 25#include <linux/property.h> 26 27#define TINK_GPIO_DRIVER_NAME "gpio_ich" 28 29static const struct software_node gpio_ich_node = { 30 .name = TINK_GPIO_DRIVER_NAME, 31}; 32 33/* LEDs */ 34static const struct software_node tink_gpio_leds_node = { 35 .name = "meraki-mx100-leds", 36}; 37 38static const struct property_entry tink_internet_led_props[] = { 39 PROPERTY_ENTRY_STRING("label", "mx100:green:internet"), 40 PROPERTY_ENTRY_STRING("linux,default-trigger", "default-on"), 41 PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 11, GPIO_ACTIVE_LOW), 42 { } 43}; 44 45static const struct software_node tink_internet_led_node = { 46 .name = "internet-led", 47 .parent = &tink_gpio_leds_node, 48 .properties = tink_internet_led_props, 49}; 50 51static const struct property_entry tink_lan2_led_props[] = { 52 PROPERTY_ENTRY_STRING("label", "mx100:green:lan2"), 53 PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 18, GPIO_ACTIVE_HIGH), 54 { } 55}; 56 57static const struct software_node tink_lan2_led_node = { 58 .name = "lan2-led", 59 .parent = &tink_gpio_leds_node, 60 .properties = tink_lan2_led_props, 61}; 62 63static const struct property_entry tink_lan3_led_props[] = { 64 PROPERTY_ENTRY_STRING("label", "mx100:green:lan3"), 65 PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 20, GPIO_ACTIVE_HIGH), 66 { } 67}; 68 69static const struct software_node tink_lan3_led_node = { 70 .name = "lan3-led", 71 .parent = &tink_gpio_leds_node, 72 .properties = tink_lan3_led_props, 73}; 74 75static const struct property_entry tink_lan4_led_props[] = { 76 PROPERTY_ENTRY_STRING("label", "mx100:green:lan4"), 77 PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 22, GPIO_ACTIVE_HIGH), 78 { } 79}; 80 81static const struct software_node tink_lan4_led_node = { 82 .name = "lan4-led", 83 .parent = &tink_gpio_leds_node, 84 .properties = tink_lan4_led_props, 85}; 86 87static const struct property_entry tink_lan5_led_props[] = { 88 PROPERTY_ENTRY_STRING("label", "mx100:green:lan5"), 89 PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 23, GPIO_ACTIVE_HIGH), 90 { } 91}; 92 93static const struct software_node tink_lan5_led_node = { 94 .name = "lan5-led", 95 .parent = &tink_gpio_leds_node, 96 .properties = tink_lan5_led_props, 97}; 98 99static const struct property_entry tink_lan6_led_props[] = { 100 PROPERTY_ENTRY_STRING("label", "mx100:green:lan6"), 101 PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 32, GPIO_ACTIVE_HIGH), 102 { } 103}; 104 105static const struct software_node tink_lan6_led_node = { 106 .name = "lan6-led", 107 .parent = &tink_gpio_leds_node, 108 .properties = tink_lan6_led_props, 109}; 110 111static const struct property_entry tink_lan7_led_props[] = { 112 PROPERTY_ENTRY_STRING("label", "mx100:green:lan7"), 113 PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 34, GPIO_ACTIVE_HIGH), 114 { } 115}; 116 117static const struct software_node tink_lan7_led_node = { 118 .name = "lan7-led", 119 .parent = &tink_gpio_leds_node, 120 .properties = tink_lan7_led_props, 121}; 122 123static const struct property_entry tink_lan8_led_props[] = { 124 PROPERTY_ENTRY_STRING("label", "mx100:green:lan8"), 125 PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 35, GPIO_ACTIVE_HIGH), 126 { } 127}; 128 129static const struct software_node tink_lan8_led_node = { 130 .name = "lan8-led", 131 .parent = &tink_gpio_leds_node, 132 .properties = tink_lan8_led_props, 133}; 134 135static const struct property_entry tink_lan9_led_props[] = { 136 PROPERTY_ENTRY_STRING("label", "mx100:green:lan9"), 137 PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 36, GPIO_ACTIVE_HIGH), 138 { } 139}; 140 141static const struct software_node tink_lan9_led_node = { 142 .name = "lan9-led", 143 .parent = &tink_gpio_leds_node, 144 .properties = tink_lan9_led_props, 145}; 146 147static const struct property_entry tink_lan10_led_props[] = { 148 PROPERTY_ENTRY_STRING("label", "mx100:green:lan10"), 149 PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 37, GPIO_ACTIVE_HIGH), 150 { } 151}; 152 153static const struct software_node tink_lan10_led_node = { 154 .name = "lan10-led", 155 .parent = &tink_gpio_leds_node, 156 .properties = tink_lan10_led_props, 157}; 158 159static const struct property_entry tink_lan11_led_props[] = { 160 PROPERTY_ENTRY_STRING("label", "mx100:green:lan11"), 161 PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 48, GPIO_ACTIVE_HIGH), 162 { } 163}; 164 165static const struct software_node tink_lan11_led_node = { 166 .name = "lan11-led", 167 .parent = &tink_gpio_leds_node, 168 .properties = tink_lan11_led_props, 169}; 170 171static const struct property_entry tink_ha_green_led_props[] = { 172 PROPERTY_ENTRY_STRING("label", "mx100:green:ha"), 173 PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 16, GPIO_ACTIVE_LOW), 174 { } 175}; 176 177static const struct software_node tink_ha_green_led_node = { 178 .name = "ha-green-led", 179 .parent = &tink_gpio_leds_node, 180 .properties = tink_ha_green_led_props, 181}; 182 183static const struct property_entry tink_ha_orange_led_props[] = { 184 PROPERTY_ENTRY_STRING("label", "mx100:orange:ha"), 185 PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 7, GPIO_ACTIVE_LOW), 186 { } 187}; 188 189static const struct software_node tink_ha_orange_led_node = { 190 .name = "ha-orange-led", 191 .parent = &tink_gpio_leds_node, 192 .properties = tink_ha_orange_led_props, 193}; 194 195static const struct property_entry tink_usb_green_led_props[] = { 196 PROPERTY_ENTRY_STRING("label", "mx100:green:usb"), 197 PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 21, GPIO_ACTIVE_LOW), 198 { } 199}; 200 201static const struct software_node tink_usb_green_led_node = { 202 .name = "usb-green-led", 203 .parent = &tink_gpio_leds_node, 204 .properties = tink_usb_green_led_props, 205}; 206 207static const struct property_entry tink_usb_orange_led_props[] = { 208 PROPERTY_ENTRY_STRING("label", "mx100:orange:usb"), 209 PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 19, GPIO_ACTIVE_LOW), 210 { } 211}; 212 213static const struct software_node tink_usb_orange_led_node = { 214 .name = "usb-orange-led", 215 .parent = &tink_gpio_leds_node, 216 .properties = tink_usb_orange_led_props, 217}; 218 219/* Reset Button */ 220static const struct property_entry tink_gpio_keys_props[] = { 221 PROPERTY_ENTRY_U32("poll-interval", 20), 222 { } 223}; 224 225static const struct software_node tink_gpio_keys_node = { 226 .name = "mx100-keys", 227 .properties = tink_gpio_keys_props, 228}; 229 230static const struct property_entry tink_reset_key_props[] = { 231 PROPERTY_ENTRY_U32("linux,code", KEY_RESTART), 232 PROPERTY_ENTRY_STRING("label", "Reset"), 233 PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 60, GPIO_ACTIVE_LOW), 234 PROPERTY_ENTRY_U32("linux,input-type", EV_KEY), 235 PROPERTY_ENTRY_U32("debounce-interval", 100), 236 { } 237}; 238 239static const struct software_node tink_reset_key_node = { 240 .name = "reset", 241 .parent = &tink_gpio_keys_node, 242 .properties = tink_reset_key_props, 243}; 244 245static const struct software_node *tink_swnodes[] = { 246 &gpio_ich_node, 247 /* LEDs nodes */ 248 &tink_gpio_leds_node, 249 &tink_internet_led_node, 250 &tink_lan2_led_node, 251 &tink_lan3_led_node, 252 &tink_lan4_led_node, 253 &tink_lan5_led_node, 254 &tink_lan6_led_node, 255 &tink_lan7_led_node, 256 &tink_lan8_led_node, 257 &tink_lan9_led_node, 258 &tink_lan10_led_node, 259 &tink_lan11_led_node, 260 &tink_ha_green_led_node, 261 &tink_ha_orange_led_node, 262 &tink_usb_green_led_node, 263 &tink_usb_orange_led_node, 264 /* Keys nodes */ 265 &tink_gpio_keys_node, 266 &tink_reset_key_node, 267 NULL 268}; 269 270/* Board setup */ 271static const struct dmi_system_id tink_systems[] __initconst = { 272 { 273 .matches = { 274 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Cisco"), 275 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "MX100-HW"), 276 }, 277 }, 278 {} /* Terminating entry */ 279}; 280MODULE_DEVICE_TABLE(dmi, tink_systems); 281 282static struct platform_device *tink_leds_pdev; 283static struct platform_device *tink_keys_pdev; 284 285static int __init tink_board_init(void) 286{ 287 struct platform_device_info keys_info = { 288 .name = "gpio-keys-polled", 289 .id = PLATFORM_DEVID_NONE, 290 }; 291 struct platform_device_info leds_info = { 292 .name = "leds-gpio", 293 .id = PLATFORM_DEVID_NONE, 294 }; 295 int err; 296 297 if (!dmi_first_match(tink_systems)) 298 return -ENODEV; 299 300 /* 301 * We need to make sure that GPIO60 isn't set to native mode as is default since it's our 302 * Reset Button. To do this, write to GPIO_USE_SEL2 to have GPIO60 set to GPIO mode. 303 * This is documented on page 1609 of the PCH datasheet, order number 327879-005US 304 */ 305 outl(inl(0x530) | BIT(28), 0x530); 306 307 err = software_node_register_node_group(tink_swnodes); 308 if (err) { 309 pr_err("failed to register software nodes: %d\n", err); 310 return err; 311 } 312 313 leds_info.fwnode = software_node_fwnode(&tink_gpio_leds_node); 314 tink_leds_pdev = platform_device_register_full(&leds_info); 315 if (IS_ERR(tink_leds_pdev)) { 316 err = PTR_ERR(tink_leds_pdev); 317 pr_err("failed to create LED device: %d\n", err); 318 goto err_unregister_swnodes; 319 } 320 321 keys_info.fwnode = software_node_fwnode(&tink_gpio_keys_node); 322 tink_keys_pdev = platform_device_register_full(&keys_info); 323 if (IS_ERR(tink_keys_pdev)) { 324 err = PTR_ERR(tink_keys_pdev); 325 pr_err("failed to create key device: %d\n", err); 326 goto err_unregister_leds; 327 } 328 329 return 0; 330 331err_unregister_leds: 332 platform_device_unregister(tink_leds_pdev); 333err_unregister_swnodes: 334 software_node_unregister_node_group(tink_swnodes); 335 return err; 336} 337module_init(tink_board_init); 338 339static void __exit tink_board_exit(void) 340{ 341 platform_device_unregister(tink_keys_pdev); 342 platform_device_unregister(tink_leds_pdev); 343 software_node_unregister_node_group(tink_swnodes); 344} 345module_exit(tink_board_exit); 346 347MODULE_AUTHOR("Chris Blake <chrisrblake93@gmail.com>"); 348MODULE_DESCRIPTION("Cisco Meraki MX100 Platform Driver"); 349MODULE_LICENSE("GPL"); 350MODULE_ALIAS("platform:meraki-mx100");