v1.5 branch refresh based upon upstream master @ c8677ca89e53e3be7988d54280fce166cc894a7e
[librecmc/librecmc.git] / package / kernel / leds-apu2 / src / leds-apu2.c
1 /*
2 *  APU2 LED/GPIO Driver
3 *  Copyright (c) 2016 Christian Lamparter <chunkeey (at) googlemail.com>
4 *
5 *  Based on gpio-apu2.c - AMD FCH GPIO support for PC-Engines APU-2 board
6 *
7 *  Copyright (c) 2015  Carsten Spiess <fli4l at carsten-spiess.de>
8 *
9 *  This program is free software; you can redistribute it and/or modify
10 *  it under the terms of the GNU General Public License as published by
11 *  the Free Software Foundation; either version 2 of the License, or
12 *  (at your option) any later version.
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this program; if not, write to the Free Software
21 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include <linux/module.h>
25 #include <linux/types.h>
26 #include <linux/miscdevice.h>
27 #include <linux/gpio.h>
28 #include <linux/init.h>
29 #include <linux/pci.h>
30 #include <linux/ioport.h>
31 #include <linux/platform_device.h>
32 #include <linux/uaccess.h>
33 #include <linux/io.h>
34 #include <linux/version.h>
35 #include <linux/dmi.h>
36 #include <linux/string.h>
37
38 #include <linux/leds.h>
39 #include <linux/input.h>
40 #include <linux/gpio_keys.h>
41
42 #define DEVNAME                 "leds-apu2"
43
44 #define FCH_ACPI_MMIO_BASE      0xFED80000
45 #define FCH_GPIO_BASE           (FCH_ACPI_MMIO_BASE + 0x1500)
46 #define FCH_GPIO_SIZE           0x300
47
48 #define APU_NUM_GPIO            4
49
50 #define GPIO_BIT_DIR            23
51 #define GPIO_BIT_WRITE          22
52 #define GPIO_BIT_READ           16
53
54 /* internal variables */
55 static struct pci_dev *gpio_apu2_pci;
56 static DEFINE_SPINLOCK (gpio_lock);
57
58 /* the watchdog platform device */
59 static struct platform_device *gpio_apu2_platform_device;
60 static struct platform_device *leddev;
61 static struct platform_device *keydev;
62
63 static const struct pci_device_id gpio_apu2_pci_tbl[] ={
64         {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, PCI_ANY_ID, PCI_ANY_ID},
65         { 0, } /* End of list */
66 };
67 MODULE_DEVICE_TABLE (pci, gpio_apu2_pci_tbl);
68
69 /* EGPIO89=GPIO32, AGPIO68=GPIO57, AGPIO69=GPIO58, AGPIO70=GPIO59 */
70 static u8 gpio_offset[APU_NUM_GPIO] = {89, 68, 69, 70};
71
72 static void __iomem *gpio_addr[APU_NUM_GPIO] = {NULL, NULL, NULL, NULL};
73
74 static int gpio_apu2_get_dir (struct gpio_chip *chip, unsigned offset)
75 {
76         u32 val;
77
78         val = ~ioread32 (gpio_addr[offset]);
79
80         return (val >> GPIO_BIT_DIR) & 1;
81 }
82
83 static int gpio_apu2_dir_in (struct gpio_chip *gc, unsigned offset)
84 {
85         u32 val;
86
87         spin_lock_bh (&gpio_lock);
88
89         val = ioread32 (gpio_addr[offset]);
90         val &= ~BIT(GPIO_BIT_DIR);
91         iowrite32 (val, gpio_addr[offset]);
92
93         spin_unlock_bh (&gpio_lock);
94
95         return 0;
96 }
97
98 static int gpio_apu2_dir_out (struct gpio_chip *chip, unsigned offset,
99                 int value)
100 {
101         u32 val;
102
103         spin_lock_bh (&gpio_lock);
104
105         val = ioread32 (gpio_addr[offset]);
106         val |= BIT(GPIO_BIT_DIR);
107         iowrite32 (val, gpio_addr[offset]);
108
109         spin_unlock_bh (&gpio_lock);
110
111         return 0;
112 }
113
114 static int gpio_apu2_get_data (struct gpio_chip *chip, unsigned offset)
115 {
116         u32 val;
117
118         val = ioread32 (gpio_addr[offset]);
119
120         return (val >> GPIO_BIT_READ) & 1;
121 }
122
123 static void gpio_apu2_set_data (struct gpio_chip *chip, unsigned offset, int value)
124 {
125         u32 val;
126
127         spin_lock_bh (&gpio_lock);
128
129         val = ioread32 (gpio_addr[offset]);
130
131         if (value)
132                 val |= BIT(GPIO_BIT_WRITE);
133         else
134                 val &= ~BIT(GPIO_BIT_WRITE);
135
136         iowrite32 (val, gpio_addr[offset]);
137
138         spin_unlock_bh (&gpio_lock);
139 }
140
141 static struct gpio_chip gpio_apu2_chip = {
142         .label = DEVNAME,
143         .owner = THIS_MODULE,
144         .base = -1,
145         .ngpio = APU_NUM_GPIO,
146         .get_direction = gpio_apu2_get_dir,
147         .direction_input = gpio_apu2_dir_in,
148         .direction_output = gpio_apu2_dir_out,
149         .get = gpio_apu2_get_data,
150         .set = gpio_apu2_set_data,
151 };
152
153 /*
154  *
155  */
156 static int gpio_apu2_probe (struct platform_device *dev)
157 {
158         int ret = 0;
159         int i;
160         struct pci_dev *pci_dev = NULL;
161
162         /* Match the PCI device */
163         for_each_pci_dev (pci_dev) {
164                 if (pci_match_id (gpio_apu2_pci_tbl, pci_dev) != NULL) {
165                         gpio_apu2_pci = pci_dev;
166                         break;
167                 }
168         }
169
170         if (!gpio_apu2_pci)
171                 return -ENODEV;
172
173         pr_info ("%s: PCI Revision ID: 0x%x\n", DEVNAME, gpio_apu2_pci->revision);
174
175         /* Determine type of southbridge chipset */
176         if (gpio_apu2_pci->revision < 0x40) {
177                 return -EACCES;
178         }
179
180         /* Request memory region for GPIO's */
181         if (!devm_request_mem_region (&dev->dev, FCH_GPIO_BASE,
182                 FCH_GPIO_SIZE, DEVNAME)){
183                 pr_err ("%s: request GPIO mem region failed\n", DEVNAME);
184                 return -ENXIO;
185         }
186
187         /* Map IO's for GPIO's */
188         for (i = 0; i < APU_NUM_GPIO; i++) {
189                 gpio_addr[i] = devm_ioremap (&dev->dev,
190                         FCH_GPIO_BASE + (gpio_offset[i] * sizeof (u32)), sizeof (u32));
191                 if (!gpio_addr[i]) {
192                         pr_err ("%s: map GPIO%d address failed\n", DEVNAME, gpio_offset[i]);
193                         return -ENXIO;
194                 }
195         }
196
197 #if LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0)
198         gpio_apu2_chip.dev = &dev->dev;
199 #else
200         gpio_apu2_chip.parent = &dev->dev;
201 #endif
202         ret = gpiochip_add (&gpio_apu2_chip);
203         if (ret) {
204                 pr_err ("%s: adding gpiochip failed\n", DEVNAME);
205         }
206
207         return ret;
208 }
209
210 static int gpio_apu2_remove (struct platform_device *dev)
211 {
212 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0)
213         int ret;
214         ret = gpiochip_remove (&gpio_apu2_chip);
215 #else /* LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0) */
216         gpiochip_remove (&gpio_apu2_chip);
217 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0) */
218         return 0;
219 }
220
221 static struct platform_driver gpio_apu2_driver = {
222         .probe = gpio_apu2_probe,
223         .remove = gpio_apu2_remove,
224         .driver = {
225                 .owner = THIS_MODULE,
226                 .name = DEVNAME
227         }
228 };
229
230 static struct gpio_led apu2_leds_gpio[] = {
231         {
232                 .name           = "apu2:green:power",
233                 .gpio           = 509,
234                 .active_low     = 1,
235         },
236         {
237                 .name           = "apu2:green:led2",
238                 .gpio           = 510,
239                 .active_low     = 1,
240         },
241         {
242                 .name           = "apu2:green:led3",
243                 .gpio           = 511,
244                 .active_low     = 1,
245         },
246 };
247
248 static struct gpio_keys_button apu2_gpio_keys[] = {
249         {
250                 .desc           = "Reset button",
251                 .type           = EV_KEY,
252                 .code           = KEY_RESTART,
253                 .debounce_interval = 60,
254                 .gpio           = 508,
255                 .active_low     = 1,
256         },
257 };
258
259 static void register_gpio_keys_polled(int id, unsigned poll_interval,
260                                       unsigned nbuttons,
261                                       struct gpio_keys_button *buttons)
262 {
263         struct gpio_keys_platform_data pdata = { };
264         int err;
265
266         keydev = platform_device_alloc("gpio-keys-polled", id);
267         if (!keydev) {
268                 printk(KERN_ERR "Failed to allocate gpio-keys platform device\n");
269                 return;
270         }
271
272         pdata.poll_interval = poll_interval;
273         pdata.nbuttons = nbuttons;
274         pdata.buttons = buttons;
275
276         err = platform_device_add_data(keydev, &pdata, sizeof(pdata));
277         if (err) {
278                 dev_err(&keydev->dev, "failed to add platform data to key driver (%d)", err);
279                 goto err_put_pdev;
280         }
281
282         err = platform_device_add(keydev);
283         if (err) {
284                 dev_err(&keydev->dev, "failed to register key platform device (%d)", err);
285                 goto err_put_pdev;
286         }
287
288         return;
289
290 err_put_pdev:
291         platform_device_put(keydev);
292         keydev = NULL;
293 }
294
295 static void register_leds_gpio(int id, unsigned num_leds, struct gpio_led *leds)
296 {
297         struct gpio_led_platform_data pdata = { };
298         int err;
299
300         leddev = platform_device_alloc("leds-gpio", id);
301         if (!leddev) {
302                 printk(KERN_ERR "Failed to allocate leds-gpio platform device\n");
303                 return;
304         }
305
306         pdata.num_leds = num_leds;
307         pdata.leds = leds;
308
309         err = platform_device_add_data(leddev, &pdata, sizeof(pdata));
310         if (err) {
311                 dev_err(&leddev->dev, "failed to add platform data to key driver (%d)", err);
312                 goto err_put_pdev;
313         }
314
315         err = platform_device_add(leddev);
316         if (err) {
317                 dev_err(&leddev->dev, "failed to register key platform device (%d)", err);
318                 goto err_put_pdev;
319         }
320
321         return;
322
323 err_put_pdev:
324         platform_device_put(leddev);
325         leddev = NULL;
326 }
327
328 static int __init gpio_apu2_init (void)
329 {
330         int err;
331         const char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
332         const char *board_name = dmi_get_system_info(DMI_BOARD_NAME);
333
334         /* Match the device name/model */
335         if (!board_name \
336                         || !board_vendor \
337                         || strcasecmp(board_vendor, "PC Engines") \
338                         || (strcasecmp(board_name, "apu2") \
339                                 && strcasecmp(board_name, "apu3") \
340                                 && strcasecmp(board_name, "PC Engines apu2") \
341                                 && strcasecmp(board_name, "PC Engines apu3"))) {
342                 err = -ENODEV;
343                 goto exit;
344         }
345
346         pr_info ("%s: load APU2/LED GPIO driver module\n", DEVNAME);
347
348         err = platform_driver_register (&gpio_apu2_driver);
349         if (err)
350                 goto exit;
351
352         gpio_apu2_platform_device = platform_device_register_simple (DEVNAME, -1, NULL, 0);
353         if (IS_ERR(gpio_apu2_platform_device)) {
354                 err = PTR_ERR(gpio_apu2_platform_device);
355                 goto exit_driver;
356         }
357
358         pr_info ("%s: APU2 GPIO/LED driver module loaded\n", DEVNAME);
359
360         register_leds_gpio(-1, ARRAY_SIZE(apu2_leds_gpio), apu2_leds_gpio);
361         register_gpio_keys_polled(-1, 20, ARRAY_SIZE(apu2_gpio_keys), apu2_gpio_keys);
362         return 0;
363
364 exit_driver:
365         platform_driver_unregister (&gpio_apu2_driver);
366 exit:
367         return err;
368 }
369
370 static void __exit gpio_apu2_exit (void)
371 {
372         platform_device_unregister (gpio_apu2_platform_device);
373         platform_device_unregister (leddev);
374         platform_device_unregister (keydev);
375         platform_driver_unregister (&gpio_apu2_driver);
376         pr_info ("%s: APU2 GPIO/LED driver module unloaded\n", DEVNAME);
377 }
378
379 MODULE_AUTHOR ("Carsten Spiess <fli4l at carsten-spiess.de>");
380 MODULE_DESCRIPTION("GPIO driver for AMD FCH on PC-Engines APU-2");
381 MODULE_LICENSE("GPL");
382
383 module_init (gpio_apu2_init);
384 module_exit (gpio_apu2_exit);