Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

William Breathitt Gray and committed by
Greg Kroah-Hartman
cc736607 86ea8a95

+33 -64
+5 -4
drivers/gpio/Kconfig
··· 614 614 615 615 config GPIO_WS16C48 616 616 tristate "WinSystems WS16C48 GPIO support" 617 + depends on ISA 617 618 select GPIOLIB_IRQCHIP 618 619 help 619 - Enables GPIO support for the WinSystems WS16C48. The base port address 620 - for the device may be configured via the ws16c48_base module 621 - parameter. The interrupt line number for the device may be configured 622 - via the ws16c48_irq module parameter. 620 + Enables GPIO support for the WinSystems WS16C48. The base port 621 + addresses for the devices may be configured via the base module 622 + parameter. The interrupt line numbers for the devices may be 623 + configured via the irq module parameter. 623 624 624 625 endmenu 625 626
+28 -60
drivers/gpio/gpio-ws16c48.c
··· 19 19 #include <linux/ioport.h> 20 20 #include <linux/interrupt.h> 21 21 #include <linux/irqdesc.h> 22 + #include <linux/isa.h> 22 23 #include <linux/kernel.h> 23 24 #include <linux/module.h> 24 25 #include <linux/moduleparam.h> 25 - #include <linux/platform_device.h> 26 26 #include <linux/spinlock.h> 27 27 28 - static unsigned ws16c48_base; 29 - module_param(ws16c48_base, uint, 0); 30 - MODULE_PARM_DESC(ws16c48_base, "WinSystems WS16C48 base address"); 31 - static unsigned ws16c48_irq; 32 - module_param(ws16c48_irq, uint, 0); 33 - MODULE_PARM_DESC(ws16c48_irq, "WinSystems WS16C48 interrupt line number"); 28 + #define WS16C48_EXTENT 16 29 + #define MAX_NUM_WS16C48 max_num_isa_dev(WS16C48_EXTENT) 30 + 31 + static unsigned int base[MAX_NUM_WS16C48]; 32 + static unsigned int num_ws16c48; 33 + module_param_array(base, uint, &num_ws16c48, 0); 34 + MODULE_PARM_DESC(base, "WinSystems WS16C48 base addresses"); 35 + 36 + static unsigned int irq[MAX_NUM_WS16C48]; 37 + module_param_array(irq, uint, NULL, 0); 38 + MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers"); 34 39 35 40 /** 36 41 * struct ws16c48_gpio - GPIO device private data structure ··· 303 298 return IRQ_HANDLED; 304 299 } 305 300 306 - static int __init ws16c48_probe(struct platform_device *pdev) 301 + static int ws16c48_probe(struct device *dev, unsigned int id) 307 302 { 308 - struct device *dev = &pdev->dev; 309 303 struct ws16c48_gpio *ws16c48gpio; 310 - const unsigned base = ws16c48_base; 311 - const unsigned extent = 16; 312 304 const char *const name = dev_name(dev); 313 305 int err; 314 - const unsigned irq = ws16c48_irq; 315 306 316 307 ws16c48gpio = devm_kzalloc(dev, sizeof(*ws16c48gpio), GFP_KERNEL); 317 308 if (!ws16c48gpio) 318 309 return -ENOMEM; 319 310 320 - if (!devm_request_region(dev, base, extent, name)) { 311 + if (!devm_request_region(dev, base[id], WS16C48_EXTENT, name)) { 321 312 dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", 322 - base, base + extent); 313 + base[id], base[id] + WS16C48_EXTENT); 323 314 return -EBUSY; 324 315 } 325 316 ··· 329 328 ws16c48gpio->chip.direction_output = ws16c48_gpio_direction_output; 330 329 ws16c48gpio->chip.get = ws16c48_gpio_get; 331 330 ws16c48gpio->chip.set = ws16c48_gpio_set; 332 - ws16c48gpio->base = base; 333 - ws16c48gpio->irq = irq; 331 + ws16c48gpio->base = base[id]; 332 + ws16c48gpio->irq = irq[id]; 334 333 335 334 spin_lock_init(&ws16c48gpio->lock); 336 335 ··· 343 342 } 344 343 345 344 /* Disable IRQ by default */ 346 - outb(0x80, base + 7); 347 - outb(0, base + 8); 348 - outb(0, base + 9); 349 - outb(0, base + 10); 350 - outb(0xC0, base + 7); 345 + outb(0x80, base[id] + 7); 346 + outb(0, base[id] + 8); 347 + outb(0, base[id] + 9); 348 + outb(0, base[id] + 10); 349 + outb(0xC0, base[id] + 7); 351 350 352 351 err = gpiochip_irqchip_add(&ws16c48gpio->chip, &ws16c48_irqchip, 0, 353 352 handle_edge_irq, IRQ_TYPE_NONE); ··· 356 355 goto err_gpiochip_remove; 357 356 } 358 357 359 - err = request_irq(irq, ws16c48_irq_handler, IRQF_SHARED, name, 358 + err = request_irq(irq[id], ws16c48_irq_handler, IRQF_SHARED, name, 360 359 ws16c48gpio); 361 360 if (err) { 362 361 dev_err(dev, "IRQ handler registering failed (%d)\n", err); ··· 370 369 return err; 371 370 } 372 371 373 - static int ws16c48_remove(struct platform_device *pdev) 372 + static int ws16c48_remove(struct device *dev, unsigned int id) 374 373 { 375 - struct ws16c48_gpio *const ws16c48gpio = platform_get_drvdata(pdev); 374 + struct ws16c48_gpio *const ws16c48gpio = dev_get_drvdata(dev); 376 375 377 376 free_irq(ws16c48gpio->irq, ws16c48gpio); 378 377 gpiochip_remove(&ws16c48gpio->chip); ··· 380 379 return 0; 381 380 } 382 381 383 - static struct platform_device *ws16c48_device; 384 - 385 - static struct platform_driver ws16c48_driver = { 382 + static struct isa_driver ws16c48_driver = { 383 + .probe = ws16c48_probe, 386 384 .driver = { 387 385 .name = "ws16c48" 388 386 }, 389 387 .remove = ws16c48_remove 390 388 }; 391 389 392 - static void __exit ws16c48_exit(void) 393 - { 394 - platform_device_unregister(ws16c48_device); 395 - platform_driver_unregister(&ws16c48_driver); 396 - } 397 - 398 - static int __init ws16c48_init(void) 399 - { 400 - int err; 401 - 402 - ws16c48_device = platform_device_alloc(ws16c48_driver.driver.name, -1); 403 - if (!ws16c48_device) 404 - return -ENOMEM; 405 - 406 - err = platform_device_add(ws16c48_device); 407 - if (err) 408 - goto err_platform_device; 409 - 410 - err = platform_driver_probe(&ws16c48_driver, ws16c48_probe); 411 - if (err) 412 - goto err_platform_driver; 413 - 414 - return 0; 415 - 416 - err_platform_driver: 417 - platform_device_del(ws16c48_device); 418 - err_platform_device: 419 - platform_device_put(ws16c48_device); 420 - return err; 421 - } 422 - 423 - module_init(ws16c48_init); 424 - module_exit(ws16c48_exit); 390 + module_isa_driver(ws16c48_driver, num_ws16c48); 425 391 426 392 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 427 393 MODULE_DESCRIPTION("WinSystems WS16C48 GPIO driver");