0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0015
0016 #include <linux/dmi.h>
0017 #include <linux/err.h>
0018 #include <linux/gpio_keys.h>
0019 #include <linux/gpio/machine.h>
0020 #include <linux/input.h>
0021 #include <linux/io.h>
0022 #include <linux/kernel.h>
0023 #include <linux/leds.h>
0024 #include <linux/module.h>
0025 #include <linux/platform_device.h>
0026
0027 #define TINK_GPIO_DRIVER_NAME "gpio_ich"
0028
0029
0030 static const struct gpio_led tink_leds[] = {
0031 {
0032 .name = "mx100:green:internet",
0033 .default_trigger = "default-on",
0034 },
0035 {
0036 .name = "mx100:green:lan2",
0037 },
0038 {
0039 .name = "mx100:green:lan3",
0040 },
0041 {
0042 .name = "mx100:green:lan4",
0043 },
0044 {
0045 .name = "mx100:green:lan5",
0046 },
0047 {
0048 .name = "mx100:green:lan6",
0049 },
0050 {
0051 .name = "mx100:green:lan7",
0052 },
0053 {
0054 .name = "mx100:green:lan8",
0055 },
0056 {
0057 .name = "mx100:green:lan9",
0058 },
0059 {
0060 .name = "mx100:green:lan10",
0061 },
0062 {
0063 .name = "mx100:green:lan11",
0064 },
0065 {
0066 .name = "mx100:green:ha",
0067 },
0068 {
0069 .name = "mx100:orange:ha",
0070 },
0071 {
0072 .name = "mx100:green:usb",
0073 },
0074 {
0075 .name = "mx100:orange:usb",
0076 },
0077 };
0078
0079 static const struct gpio_led_platform_data tink_leds_pdata = {
0080 .num_leds = ARRAY_SIZE(tink_leds),
0081 .leds = tink_leds,
0082 };
0083
0084 static struct gpiod_lookup_table tink_leds_table = {
0085 .dev_id = "leds-gpio",
0086 .table = {
0087 GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 11,
0088 NULL, 0, GPIO_ACTIVE_LOW),
0089 GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 18,
0090 NULL, 1, GPIO_ACTIVE_HIGH),
0091 GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 20,
0092 NULL, 2, GPIO_ACTIVE_HIGH),
0093 GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 22,
0094 NULL, 3, GPIO_ACTIVE_HIGH),
0095 GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 23,
0096 NULL, 4, GPIO_ACTIVE_HIGH),
0097 GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 32,
0098 NULL, 5, GPIO_ACTIVE_HIGH),
0099 GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 34,
0100 NULL, 6, GPIO_ACTIVE_HIGH),
0101 GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 35,
0102 NULL, 7, GPIO_ACTIVE_HIGH),
0103 GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 36,
0104 NULL, 8, GPIO_ACTIVE_HIGH),
0105 GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 37,
0106 NULL, 9, GPIO_ACTIVE_HIGH),
0107 GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 48,
0108 NULL, 10, GPIO_ACTIVE_HIGH),
0109 GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 16,
0110 NULL, 11, GPIO_ACTIVE_LOW),
0111 GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 7,
0112 NULL, 12, GPIO_ACTIVE_LOW),
0113 GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 21,
0114 NULL, 13, GPIO_ACTIVE_LOW),
0115 GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 19,
0116 NULL, 14, GPIO_ACTIVE_LOW),
0117 {}
0118 }
0119 };
0120
0121
0122 static struct gpio_keys_button tink_buttons[] = {
0123 {
0124 .desc = "Reset",
0125 .type = EV_KEY,
0126 .code = KEY_RESTART,
0127 .active_low = 1,
0128 .debounce_interval = 100,
0129 },
0130 };
0131
0132 static const struct gpio_keys_platform_data tink_buttons_pdata = {
0133 .buttons = tink_buttons,
0134 .nbuttons = ARRAY_SIZE(tink_buttons),
0135 .poll_interval = 20,
0136 .rep = 0,
0137 .name = "mx100-keys",
0138 };
0139
0140 static struct gpiod_lookup_table tink_keys_table = {
0141 .dev_id = "gpio-keys-polled",
0142 .table = {
0143 GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 60,
0144 NULL, 0, GPIO_ACTIVE_LOW),
0145 {}
0146 }
0147 };
0148
0149
0150 static const struct dmi_system_id tink_systems[] __initconst = {
0151 {
0152 .matches = {
0153 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Cisco"),
0154 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "MX100-HW"),
0155 },
0156 },
0157 {}
0158 };
0159 MODULE_DEVICE_TABLE(dmi, tink_systems);
0160
0161 static struct platform_device *tink_leds_pdev;
0162 static struct platform_device *tink_keys_pdev;
0163
0164 static struct platform_device * __init tink_create_dev(
0165 const char *name, const void *pdata, size_t sz)
0166 {
0167 struct platform_device *pdev;
0168
0169 pdev = platform_device_register_data(NULL,
0170 name, PLATFORM_DEVID_NONE, pdata, sz);
0171 if (IS_ERR(pdev))
0172 pr_err("failed registering %s: %ld\n", name, PTR_ERR(pdev));
0173
0174 return pdev;
0175 }
0176
0177 static int __init tink_board_init(void)
0178 {
0179 int ret;
0180
0181 if (!dmi_first_match(tink_systems))
0182 return -ENODEV;
0183
0184
0185
0186
0187
0188
0189 outl(inl(0x530) | BIT(28), 0x530);
0190
0191 gpiod_add_lookup_table(&tink_leds_table);
0192 gpiod_add_lookup_table(&tink_keys_table);
0193
0194 tink_leds_pdev = tink_create_dev("leds-gpio",
0195 &tink_leds_pdata, sizeof(tink_leds_pdata));
0196 if (IS_ERR(tink_leds_pdev)) {
0197 ret = PTR_ERR(tink_leds_pdev);
0198 goto err;
0199 }
0200
0201 tink_keys_pdev = tink_create_dev("gpio-keys-polled",
0202 &tink_buttons_pdata, sizeof(tink_buttons_pdata));
0203 if (IS_ERR(tink_keys_pdev)) {
0204 ret = PTR_ERR(tink_keys_pdev);
0205 platform_device_unregister(tink_leds_pdev);
0206 goto err;
0207 }
0208
0209 return 0;
0210
0211 err:
0212 gpiod_remove_lookup_table(&tink_keys_table);
0213 gpiod_remove_lookup_table(&tink_leds_table);
0214 return ret;
0215 }
0216 module_init(tink_board_init);
0217
0218 static void __exit tink_board_exit(void)
0219 {
0220 platform_device_unregister(tink_keys_pdev);
0221 platform_device_unregister(tink_leds_pdev);
0222 gpiod_remove_lookup_table(&tink_keys_table);
0223 gpiod_remove_lookup_table(&tink_leds_table);
0224 }
0225 module_exit(tink_board_exit);
0226
0227 MODULE_AUTHOR("Chris Blake <chrisrblake93@gmail.com>");
0228 MODULE_DESCRIPTION("Cisco Meraki MX100 Platform Driver");
0229 MODULE_LICENSE("GPL");
0230 MODULE_ALIAS("platform:meraki-mx100");