1 /* 2 * Supports for the button array on SoC tablets originally running 3 * Windows 8. 4 * 5 * (C) Copyright 2014 Intel Corporation 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; version 2 10 * of the License. 11 */ 12 13 #include <linux/module.h> 14 #include <linux/input.h> 15 #include <linux/init.h> 16 #include <linux/kernel.h> 17 #include <linux/acpi.h> 18 #include <linux/gpio/consumer.h> 19 #include <linux/gpio_keys.h> 20 #include <linux/input.h> 21 #include <linux/platform_device.h> 22 #include <linux/pnp.h> 23 24 /* 25 * Definition of buttons on the tablet. The ACPI index of each button 26 * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC 27 * Platforms" 28 */ 29 #define MAX_NBUTTONS 5 30 31 struct soc_button_info { 32 const char *name; 33 int acpi_index; 34 unsigned int event_type; 35 unsigned int event_code; 36 bool autorepeat; 37 bool wakeup; 38 }; 39 40 /* 41 * Some of the buttons like volume up/down are auto repeat, while others 42 * are not. To support both, we register two platform devices, and put 43 * buttons into them based on whether the key should be auto repeat. 44 */ 45 #define BUTTON_TYPES 2 46 47 struct soc_button_data { 48 struct platform_device *children[BUTTON_TYPES]; 49 }; 50 51 /* 52 * Get the Nth GPIO number from the ACPI object. 53 */ 54 static int soc_button_lookup_gpio(struct device *dev, int acpi_index) 55 { 56 struct gpio_desc *desc; 57 int gpio; 58 59 desc = gpiod_get_index(dev, KBUILD_MODNAME, acpi_index); 60 if (IS_ERR(desc)) 61 return PTR_ERR(desc); 62 63 gpio = desc_to_gpio(desc); 64 65 gpiod_put(desc); 66 67 return gpio; 68 } 69 70 static struct platform_device * 71 soc_button_device_create(struct pnp_dev *pdev, 72 const struct soc_button_info *button_info, 73 bool autorepeat) 74 { 75 const struct soc_button_info *info; 76 struct platform_device *pd; 77 struct gpio_keys_button *gpio_keys; 78 struct gpio_keys_platform_data *gpio_keys_pdata; 79 int n_buttons = 0; 80 int gpio; 81 int error; 82 83 gpio_keys_pdata = devm_kzalloc(&pdev->dev, 84 sizeof(*gpio_keys_pdata) + 85 sizeof(*gpio_keys) * MAX_NBUTTONS, 86 GFP_KERNEL); 87 gpio_keys = (void *)(gpio_keys_pdata + 1); 88 89 for (info = button_info; info->name; info++) { 90 if (info->autorepeat != autorepeat) 91 continue; 92 93 gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index); 94 if (gpio < 0) 95 continue; 96 97 gpio_keys[n_buttons].type = info->event_type; 98 gpio_keys[n_buttons].code = info->event_code; 99 gpio_keys[n_buttons].gpio = gpio; 100 gpio_keys[n_buttons].active_low = 1; 101 gpio_keys[n_buttons].desc = info->name; 102 gpio_keys[n_buttons].wakeup = info->wakeup; 103 n_buttons++; 104 } 105 106 if (n_buttons == 0) { 107 error = -ENODEV; 108 goto err_free_mem; 109 } 110 111 gpio_keys_pdata->buttons = gpio_keys; 112 gpio_keys_pdata->nbuttons = n_buttons; 113 gpio_keys_pdata->rep = autorepeat; 114 115 pd = platform_device_alloc("gpio-keys", PLATFORM_DEVID_AUTO); 116 if (!pd) { 117 error = -ENOMEM; 118 goto err_free_mem; 119 } 120 121 error = platform_device_add_data(pd, gpio_keys_pdata, 122 sizeof(*gpio_keys_pdata)); 123 if (error) 124 goto err_free_pdev; 125 126 error = platform_device_add(pd); 127 if (error) 128 goto err_free_pdev; 129 130 return pd; 131 132 err_free_pdev: 133 platform_device_put(pd); 134 err_free_mem: 135 devm_kfree(&pdev->dev, gpio_keys_pdata); 136 return ERR_PTR(error); 137 } 138 139 static void soc_button_remove(struct pnp_dev *pdev) 140 { 141 struct soc_button_data *priv = pnp_get_drvdata(pdev); 142 int i; 143 144 for (i = 0; i < BUTTON_TYPES; i++) 145 if (priv->children[i]) 146 platform_device_unregister(priv->children[i]); 147 } 148 149 static int soc_button_pnp_probe(struct pnp_dev *pdev, 150 const struct pnp_device_id *id) 151 { 152 const struct soc_button_info *button_info = (void *)id->driver_data; 153 struct soc_button_data *priv; 154 struct platform_device *pd; 155 int i; 156 int error; 157 158 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 159 if (!priv) 160 return -ENOMEM; 161 162 pnp_set_drvdata(pdev, priv); 163 164 for (i = 0; i < BUTTON_TYPES; i++) { 165 pd = soc_button_device_create(pdev, button_info, i == 0); 166 if (IS_ERR(pd)) { 167 error = PTR_ERR(pd); 168 if (error != -ENODEV) { 169 soc_button_remove(pdev); 170 return error; 171 } 172 } 173 174 priv->children[i] = pd; 175 } 176 177 if (!priv->children[0] && !priv->children[1]) 178 return -ENODEV; 179 180 return 0; 181 } 182 183 static struct soc_button_info soc_button_PNP0C40[] = { 184 { "power", 0, EV_KEY, KEY_POWER, false, true }, 185 { "home", 1, EV_KEY, KEY_HOME, false, true }, 186 { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false }, 187 { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false }, 188 { "rotation_lock", 4, EV_SW, SW_ROTATE_LOCK, false, false }, 189 { } 190 }; 191 192 static const struct pnp_device_id soc_button_pnp_match[] = { 193 { .id = "PNP0C40", .driver_data = (long)soc_button_PNP0C40 }, 194 { .id = "" } 195 }; 196 MODULE_DEVICE_TABLE(pnp, soc_button_pnp_match); 197 198 static struct pnp_driver soc_button_pnp_driver = { 199 .name = KBUILD_MODNAME, 200 .id_table = soc_button_pnp_match, 201 .probe = soc_button_pnp_probe, 202 .remove = soc_button_remove, 203 }; 204 205 static int __init soc_button_init(void) 206 { 207 return pnp_register_driver(&soc_button_pnp_driver); 208 } 209 210 static void __exit soc_button_exit(void) 211 { 212 pnp_unregister_driver(&soc_button_pnp_driver); 213 } 214 215 module_init(soc_button_init); 216 module_exit(soc_button_exit); 217 218 MODULE_LICENSE("GPL"); 219