aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Breathitt Gray <vilhelm.gray@gmail.com>2016-05-01 18:45:24 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-05-02 12:32:04 -0400
commitcc736607c86d39ea078519af0de6ee0fbf3096a6 (patch)
treed6448d60e0c74ee5b751b2d9e69bc69600d9797a
parent86ea8a95a42f752fe0aa1c7ad1bfe8ce9be5d30e (diff)
gpio: ws16c48: Utilize the ISA bus driver
The WinSystems WS16C48 communicates via the ISA bus. As such, it is more appropriate to use the ISA bus driver over the platform driver to control the WinSystems WS16C48 GPIO driver. This patch also adds support for multiple devices via the base and irq module array parameters. Each element of the base array corresponds to a discrete device; each element of the irq array corresponds to the respective device addressed in the respective base array element. Acked-by: Linus Walleij <linus.walleij@linaro.org> Cc: Alexandre Courbot <gnurou@gmail.com> Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/gpio/Kconfig9
-rw-r--r--drivers/gpio/gpio-ws16c48.c88
2 files changed, 33 insertions, 64 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index af3237cef81d..e5c122413843 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -614,12 +614,13 @@ config GPIO_TS5500
614 614
615config GPIO_WS16C48 615config GPIO_WS16C48
616 tristate "WinSystems WS16C48 GPIO support" 616 tristate "WinSystems WS16C48 GPIO support"
617 depends on ISA
617 select GPIOLIB_IRQCHIP 618 select GPIOLIB_IRQCHIP
618 help 619 help
619 Enables GPIO support for the WinSystems WS16C48. The base port address 620 Enables GPIO support for the WinSystems WS16C48. The base port
620 for the device may be configured via the ws16c48_base module 621 addresses for the devices may be configured via the base module
621 parameter. The interrupt line number for the device may be configured 622 parameter. The interrupt line numbers for the devices may be
622 via the ws16c48_irq module parameter. 623 configured via the irq module parameter.
623 624
624endmenu 625endmenu
625 626
diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c
index 51f41e8fd21e..eaa71d440ccf 100644
--- a/drivers/gpio/gpio-ws16c48.c
+++ b/drivers/gpio/gpio-ws16c48.c
@@ -19,18 +19,23 @@
19#include <linux/ioport.h> 19#include <linux/ioport.h>
20#include <linux/interrupt.h> 20#include <linux/interrupt.h>
21#include <linux/irqdesc.h> 21#include <linux/irqdesc.h>
22#include <linux/isa.h>
22#include <linux/kernel.h> 23#include <linux/kernel.h>
23#include <linux/module.h> 24#include <linux/module.h>
24#include <linux/moduleparam.h> 25#include <linux/moduleparam.h>
25#include <linux/platform_device.h>
26#include <linux/spinlock.h> 26#include <linux/spinlock.h>
27 27
28static unsigned ws16c48_base; 28#define WS16C48_EXTENT 16
29module_param(ws16c48_base, uint, 0); 29#define MAX_NUM_WS16C48 max_num_isa_dev(WS16C48_EXTENT)
30MODULE_PARM_DESC(ws16c48_base, "WinSystems WS16C48 base address"); 30
31static unsigned ws16c48_irq; 31static unsigned int base[MAX_NUM_WS16C48];
32module_param(ws16c48_irq, uint, 0); 32static unsigned int num_ws16c48;
33MODULE_PARM_DESC(ws16c48_irq, "WinSystems WS16C48 interrupt line number"); 33module_param_array(base, uint, &num_ws16c48, 0);
34MODULE_PARM_DESC(base, "WinSystems WS16C48 base addresses");
35
36static unsigned int irq[MAX_NUM_WS16C48];
37module_param_array(irq, uint, NULL, 0);
38MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers");
34 39
35/** 40/**
36 * struct ws16c48_gpio - GPIO device private data structure 41 * struct ws16c48_gpio - GPIO device private data structure
@@ -298,23 +303,19 @@ static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id)
298 return IRQ_HANDLED; 303 return IRQ_HANDLED;
299} 304}
300 305
301static int __init ws16c48_probe(struct platform_device *pdev) 306static int ws16c48_probe(struct device *dev, unsigned int id)
302{ 307{
303 struct device *dev = &pdev->dev;
304 struct ws16c48_gpio *ws16c48gpio; 308 struct ws16c48_gpio *ws16c48gpio;
305 const unsigned base = ws16c48_base;
306 const unsigned extent = 16;
307 const char *const name = dev_name(dev); 309 const char *const name = dev_name(dev);
308 int err; 310 int err;
309 const unsigned irq = ws16c48_irq;
310 311
311 ws16c48gpio = devm_kzalloc(dev, sizeof(*ws16c48gpio), GFP_KERNEL); 312 ws16c48gpio = devm_kzalloc(dev, sizeof(*ws16c48gpio), GFP_KERNEL);
312 if (!ws16c48gpio) 313 if (!ws16c48gpio)
313 return -ENOMEM; 314 return -ENOMEM;
314 315
315 if (!devm_request_region(dev, base, extent, name)) { 316 if (!devm_request_region(dev, base[id], WS16C48_EXTENT, name)) {
316 dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", 317 dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
317 base, base + extent); 318 base[id], base[id] + WS16C48_EXTENT);
318 return -EBUSY; 319 return -EBUSY;
319 } 320 }
320 321
@@ -328,8 +329,8 @@ static int __init ws16c48_probe(struct platform_device *pdev)
328 ws16c48gpio->chip.direction_output = ws16c48_gpio_direction_output; 329 ws16c48gpio->chip.direction_output = ws16c48_gpio_direction_output;
329 ws16c48gpio->chip.get = ws16c48_gpio_get; 330 ws16c48gpio->chip.get = ws16c48_gpio_get;
330 ws16c48gpio->chip.set = ws16c48_gpio_set; 331 ws16c48gpio->chip.set = ws16c48_gpio_set;
331 ws16c48gpio->base = base; 332 ws16c48gpio->base = base[id];
332 ws16c48gpio->irq = irq; 333 ws16c48gpio->irq = irq[id];
333 334
334 spin_lock_init(&ws16c48gpio->lock); 335 spin_lock_init(&ws16c48gpio->lock);
335 336
@@ -342,11 +343,11 @@ static int __init ws16c48_probe(struct platform_device *pdev)
342 } 343 }
343 344
344 /* Disable IRQ by default */ 345 /* Disable IRQ by default */
345 outb(0x80, base + 7); 346 outb(0x80, base[id] + 7);
346 outb(0, base + 8); 347 outb(0, base[id] + 8);
347 outb(0, base + 9); 348 outb(0, base[id] + 9);
348 outb(0, base + 10); 349 outb(0, base[id] + 10);
349 outb(0xC0, base + 7); 350 outb(0xC0, base[id] + 7);
350 351
351 err = gpiochip_irqchip_add(&ws16c48gpio->chip, &ws16c48_irqchip, 0, 352 err = gpiochip_irqchip_add(&ws16c48gpio->chip, &ws16c48_irqchip, 0,
352 handle_edge_irq, IRQ_TYPE_NONE); 353 handle_edge_irq, IRQ_TYPE_NONE);
@@ -355,7 +356,7 @@ static int __init ws16c48_probe(struct platform_device *pdev)
355 goto err_gpiochip_remove; 356 goto err_gpiochip_remove;
356 } 357 }
357 358
358 err = request_irq(irq, ws16c48_irq_handler, IRQF_SHARED, name, 359 err = request_irq(irq[id], ws16c48_irq_handler, IRQF_SHARED, name,
359 ws16c48gpio); 360 ws16c48gpio);
360 if (err) { 361 if (err) {
361 dev_err(dev, "IRQ handler registering failed (%d)\n", err); 362 dev_err(dev, "IRQ handler registering failed (%d)\n", err);
@@ -369,9 +370,9 @@ err_gpiochip_remove:
369 return err; 370 return err;
370} 371}
371 372
372static int ws16c48_remove(struct platform_device *pdev) 373static int ws16c48_remove(struct device *dev, unsigned int id)
373{ 374{
374 struct ws16c48_gpio *const ws16c48gpio = platform_get_drvdata(pdev); 375 struct ws16c48_gpio *const ws16c48gpio = dev_get_drvdata(dev);
375 376
376 free_irq(ws16c48gpio->irq, ws16c48gpio); 377 free_irq(ws16c48gpio->irq, ws16c48gpio);
377 gpiochip_remove(&ws16c48gpio->chip); 378 gpiochip_remove(&ws16c48gpio->chip);
@@ -379,48 +380,15 @@ static int ws16c48_remove(struct platform_device *pdev)
379 return 0; 380 return 0;
380} 381}
381 382
382static struct platform_device *ws16c48_device; 383static struct isa_driver ws16c48_driver = {
383 384 .probe = ws16c48_probe,
384static struct platform_driver ws16c48_driver = {
385 .driver = { 385 .driver = {
386 .name = "ws16c48" 386 .name = "ws16c48"
387 }, 387 },
388 .remove = ws16c48_remove 388 .remove = ws16c48_remove
389}; 389};
390 390
391static void __exit ws16c48_exit(void) 391module_isa_driver(ws16c48_driver, num_ws16c48);
392{
393 platform_device_unregister(ws16c48_device);
394 platform_driver_unregister(&ws16c48_driver);
395}
396
397static int __init ws16c48_init(void)
398{
399 int err;
400
401 ws16c48_device = platform_device_alloc(ws16c48_driver.driver.name, -1);
402 if (!ws16c48_device)
403 return -ENOMEM;
404
405 err = platform_device_add(ws16c48_device);
406 if (err)
407 goto err_platform_device;
408
409 err = platform_driver_probe(&ws16c48_driver, ws16c48_probe);
410 if (err)
411 goto err_platform_driver;
412
413 return 0;
414
415err_platform_driver:
416 platform_device_del(ws16c48_device);
417err_platform_device:
418 platform_device_put(ws16c48_device);
419 return err;
420}
421
422module_init(ws16c48_init);
423module_exit(ws16c48_exit);
424 392
425MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 393MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
426MODULE_DESCRIPTION("WinSystems WS16C48 GPIO driver"); 394MODULE_DESCRIPTION("WinSystems WS16C48 GPIO driver");