root/drivers/platform/x86/pcengines-apuv2.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. apu_create_pdev
  2. apu_board_init
  3. apu_board_exit

   1 // SPDX-License-Identifier: GPL-2.0+
   2 
   3 /*
   4  * PC-Engines APUv2/APUv3 board platform driver
   5  * for gpio buttons and LEDs
   6  *
   7  * Copyright (C) 2018 metux IT consult
   8  * Author: Enrico Weigelt <info@metux.net>
   9  */
  10 
  11 #define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
  12 
  13 #include <linux/dmi.h>
  14 #include <linux/err.h>
  15 #include <linux/kernel.h>
  16 #include <linux/leds.h>
  17 #include <linux/module.h>
  18 #include <linux/platform_device.h>
  19 #include <linux/gpio_keys.h>
  20 #include <linux/gpio/machine.h>
  21 #include <linux/input.h>
  22 #include <linux/platform_data/gpio/gpio-amd-fch.h>
  23 
  24 /*
  25  * NOTE: this driver only supports APUv2/3 - not APUv1, as this one
  26  * has completely different register layouts
  27  */
  28 
  29 /* register mappings */
  30 #define APU2_GPIO_REG_LED1              AMD_FCH_GPIO_REG_GPIO57
  31 #define APU2_GPIO_REG_LED2              AMD_FCH_GPIO_REG_GPIO58
  32 #define APU2_GPIO_REG_LED3              AMD_FCH_GPIO_REG_GPIO59_DEVSLP1
  33 #define APU2_GPIO_REG_MODESW            AMD_FCH_GPIO_REG_GPIO32_GE1
  34 #define APU2_GPIO_REG_SIMSWAP           AMD_FCH_GPIO_REG_GPIO33_GE2
  35 #define APU2_GPIO_REG_MPCIE2            AMD_FCH_GPIO_REG_GPIO59_DEVSLP0
  36 #define APU2_GPIO_REG_MPCIE3            AMD_FCH_GPIO_REG_GPIO51
  37 
  38 /* order in which the gpio lines are defined in the register list */
  39 #define APU2_GPIO_LINE_LED1             0
  40 #define APU2_GPIO_LINE_LED2             1
  41 #define APU2_GPIO_LINE_LED3             2
  42 #define APU2_GPIO_LINE_MODESW           3
  43 #define APU2_GPIO_LINE_SIMSWAP          4
  44 #define APU2_GPIO_LINE_MPCIE2           5
  45 #define APU2_GPIO_LINE_MPCIE3           6
  46 
  47 /* gpio device */
  48 
  49 static int apu2_gpio_regs[] = {
  50         [APU2_GPIO_LINE_LED1]           = APU2_GPIO_REG_LED1,
  51         [APU2_GPIO_LINE_LED2]           = APU2_GPIO_REG_LED2,
  52         [APU2_GPIO_LINE_LED3]           = APU2_GPIO_REG_LED3,
  53         [APU2_GPIO_LINE_MODESW]         = APU2_GPIO_REG_MODESW,
  54         [APU2_GPIO_LINE_SIMSWAP]        = APU2_GPIO_REG_SIMSWAP,
  55         [APU2_GPIO_LINE_MPCIE2]         = APU2_GPIO_REG_MPCIE2,
  56         [APU2_GPIO_LINE_MPCIE3]         = APU2_GPIO_REG_MPCIE3,
  57 };
  58 
  59 static const char * const apu2_gpio_names[] = {
  60         [APU2_GPIO_LINE_LED1]           = "front-led1",
  61         [APU2_GPIO_LINE_LED2]           = "front-led2",
  62         [APU2_GPIO_LINE_LED3]           = "front-led3",
  63         [APU2_GPIO_LINE_MODESW]         = "front-button",
  64         [APU2_GPIO_LINE_SIMSWAP]        = "simswap",
  65         [APU2_GPIO_LINE_MPCIE2]         = "mpcie2_reset",
  66         [APU2_GPIO_LINE_MPCIE3]         = "mpcie3_reset",
  67 };
  68 
  69 static const struct amd_fch_gpio_pdata board_apu2 = {
  70         .gpio_num       = ARRAY_SIZE(apu2_gpio_regs),
  71         .gpio_reg       = apu2_gpio_regs,
  72         .gpio_names     = apu2_gpio_names,
  73 };
  74 
  75 /* gpio leds device */
  76 
  77 static const struct gpio_led apu2_leds[] = {
  78         { .name = "apu:green:1" },
  79         { .name = "apu:green:2" },
  80         { .name = "apu:green:3" },
  81         { .name = "apu:simswap" },
  82 };
  83 
  84 static const struct gpio_led_platform_data apu2_leds_pdata = {
  85         .num_leds       = ARRAY_SIZE(apu2_leds),
  86         .leds           = apu2_leds,
  87 };
  88 
  89 static struct gpiod_lookup_table gpios_led_table = {
  90         .dev_id = "leds-gpio",
  91         .table = {
  92                 GPIO_LOOKUP_IDX(AMD_FCH_GPIO_DRIVER_NAME, APU2_GPIO_LINE_LED1,
  93                                 NULL, 0, GPIO_ACTIVE_LOW),
  94                 GPIO_LOOKUP_IDX(AMD_FCH_GPIO_DRIVER_NAME, APU2_GPIO_LINE_LED2,
  95                                 NULL, 1, GPIO_ACTIVE_LOW),
  96                 GPIO_LOOKUP_IDX(AMD_FCH_GPIO_DRIVER_NAME, APU2_GPIO_LINE_LED3,
  97                                 NULL, 2, GPIO_ACTIVE_LOW),
  98                 GPIO_LOOKUP_IDX(AMD_FCH_GPIO_DRIVER_NAME, APU2_GPIO_LINE_SIMSWAP,
  99                                 NULL, 3, GPIO_ACTIVE_LOW),
 100         }
 101 };
 102 
 103 /* gpio keyboard device */
 104 
 105 static struct gpio_keys_button apu2_keys_buttons[] = {
 106         {
 107                 .code                   = KEY_RESTART,
 108                 .active_low             = 1,
 109                 .desc                   = "front button",
 110                 .type                   = EV_KEY,
 111                 .debounce_interval      = 10,
 112                 .value                  = 1,
 113         },
 114 };
 115 
 116 static const struct gpio_keys_platform_data apu2_keys_pdata = {
 117         .buttons        = apu2_keys_buttons,
 118         .nbuttons       = ARRAY_SIZE(apu2_keys_buttons),
 119         .poll_interval  = 100,
 120         .rep            = 0,
 121         .name           = "apu2-keys",
 122 };
 123 
 124 static struct gpiod_lookup_table gpios_key_table = {
 125         .dev_id = "gpio-keys-polled",
 126         .table = {
 127                 GPIO_LOOKUP_IDX(AMD_FCH_GPIO_DRIVER_NAME, APU2_GPIO_LINE_MODESW,
 128                                 NULL, 0, GPIO_ACTIVE_LOW),
 129         }
 130 };
 131 
 132 /* board setup */
 133 
 134 /* note: matching works on string prefix, so "apu2" must come before "apu" */
 135 static const struct dmi_system_id apu_gpio_dmi_table[] __initconst = {
 136 
 137         /* APU2 w/ legacy bios < 4.0.8 */
 138         {
 139                 .ident          = "apu2",
 140                 .matches        = {
 141                         DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
 142                         DMI_MATCH(DMI_BOARD_NAME, "APU2")
 143                 },
 144                 .driver_data    = (void *)&board_apu2,
 145         },
 146         /* APU2 w/ legacy bios >= 4.0.8 */
 147         {
 148                 .ident          = "apu2",
 149                 .matches        = {
 150                         DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
 151                         DMI_MATCH(DMI_BOARD_NAME, "apu2")
 152                 },
 153                 .driver_data    = (void *)&board_apu2,
 154         },
 155         /* APU2 w/ maainline bios */
 156         {
 157                 .ident          = "apu2",
 158                 .matches        = {
 159                         DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
 160                         DMI_MATCH(DMI_BOARD_NAME, "PC Engines apu2")
 161                 },
 162                 .driver_data    = (void *)&board_apu2,
 163         },
 164 
 165         /* APU3 w/ legacy bios < 4.0.8 */
 166         {
 167                 .ident          = "apu3",
 168                 .matches        = {
 169                         DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
 170                         DMI_MATCH(DMI_BOARD_NAME, "APU3")
 171                 },
 172                 .driver_data = (void *)&board_apu2,
 173         },
 174         /* APU3 w/ legacy bios >= 4.0.8 */
 175         {
 176                 .ident       = "apu3",
 177                 .matches     = {
 178                         DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
 179                         DMI_MATCH(DMI_BOARD_NAME, "apu3")
 180                 },
 181                 .driver_data = (void *)&board_apu2,
 182         },
 183         /* APU3 w/ mainline bios */
 184         {
 185                 .ident       = "apu3",
 186                 .matches     = {
 187                         DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
 188                         DMI_MATCH(DMI_BOARD_NAME, "PC Engines apu3")
 189                 },
 190                 .driver_data = (void *)&board_apu2,
 191         },
 192         {}
 193 };
 194 
 195 static struct platform_device *apu_gpio_pdev;
 196 static struct platform_device *apu_leds_pdev;
 197 static struct platform_device *apu_keys_pdev;
 198 
 199 static struct platform_device * __init apu_create_pdev(
 200         const char *name,
 201         const void *pdata,
 202         size_t sz)
 203 {
 204         struct platform_device *pdev;
 205 
 206         pdev = platform_device_register_resndata(NULL,
 207                 name,
 208                 PLATFORM_DEVID_NONE,
 209                 NULL,
 210                 0,
 211                 pdata,
 212                 sz);
 213 
 214         if (IS_ERR(pdev))
 215                 pr_err("failed registering %s: %ld\n", name, PTR_ERR(pdev));
 216 
 217         return pdev;
 218 }
 219 
 220 static int __init apu_board_init(void)
 221 {
 222         const struct dmi_system_id *id;
 223 
 224         id = dmi_first_match(apu_gpio_dmi_table);
 225         if (!id) {
 226                 pr_err("failed to detect apu board via dmi\n");
 227                 return -ENODEV;
 228         }
 229 
 230         gpiod_add_lookup_table(&gpios_led_table);
 231         gpiod_add_lookup_table(&gpios_key_table);
 232 
 233         apu_gpio_pdev = apu_create_pdev(
 234                 AMD_FCH_GPIO_DRIVER_NAME,
 235                 id->driver_data,
 236                 sizeof(struct amd_fch_gpio_pdata));
 237 
 238         apu_leds_pdev = apu_create_pdev(
 239                 "leds-gpio",
 240                 &apu2_leds_pdata,
 241                 sizeof(apu2_leds_pdata));
 242 
 243         apu_keys_pdev = apu_create_pdev(
 244                 "gpio-keys-polled",
 245                 &apu2_keys_pdata,
 246                 sizeof(apu2_keys_pdata));
 247 
 248         return 0;
 249 }
 250 
 251 static void __exit apu_board_exit(void)
 252 {
 253         gpiod_remove_lookup_table(&gpios_led_table);
 254         gpiod_remove_lookup_table(&gpios_key_table);
 255 
 256         platform_device_unregister(apu_keys_pdev);
 257         platform_device_unregister(apu_leds_pdev);
 258         platform_device_unregister(apu_gpio_pdev);
 259 }
 260 
 261 module_init(apu_board_init);
 262 module_exit(apu_board_exit);
 263 
 264 MODULE_AUTHOR("Enrico Weigelt, metux IT consult <info@metux.net>");
 265 MODULE_DESCRIPTION("PC Engines APUv2/APUv3 board GPIO/LED/keys driver");
 266 MODULE_LICENSE("GPL");
 267 MODULE_DEVICE_TABLE(dmi, apu_gpio_dmi_table);
 268 MODULE_ALIAS("platform:pcengines-apuv2");
 269 MODULE_SOFTDEP("pre: platform:" AMD_FCH_GPIO_DRIVER_NAME " platform:leds-gpio platform:gpio_keys_polled");

/* [<][>][^][v][top][bottom][index][help] */