From 7582eb9be85f35271fd2569681a88a5b243e9380 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 22 Apr 2010 17:39:34 -0600 Subject: [PATCH] viafb: Turn GPIO and i2c into proper platform devices Another step toward making this thing a real multifunction device driver. Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Cc: Harald Welte Acked-by: Florian Tobias Schandinat Signed-off-by: Jonathan Corbet --- drivers/video/via/via-core.c | 91 +++++++++++++++++++++++++++++------- drivers/video/via/via-core.h | 1 + drivers/video/via/via-gpio.c | 55 +++++++++++++++------- drivers/video/via/via-gpio.h | 5 +- drivers/video/via/via_i2c.c | 29 ++++++++++-- drivers/video/via/via_i2c.h | 6 +-- 6 files changed, 143 insertions(+), 44 deletions(-) diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c index a1b5dae285a4..5a78ef9cb382 100644 --- a/drivers/video/via/via-core.c +++ b/drivers/video/via/via-core.c @@ -190,6 +190,70 @@ static void __devexit via_pci_teardown_mmio(struct viafb_dev *vdev) iounmap(vdev->engine_mmio); } +/* + * Create our subsidiary devices. + */ +static struct viafb_subdev_info { + char *name; + struct platform_device *platdev; +} viafb_subdevs[] = { + { + .name = "viafb-gpio", + }, + { + .name = "viafb-i2c", + } +}; +#define N_SUBDEVS ARRAY_SIZE(viafb_subdevs) + +static int __devinit via_create_subdev(struct viafb_dev *vdev, + struct viafb_subdev_info *info) +{ + int ret; + + info->platdev = platform_device_alloc(info->name, -1); + if (!info->platdev) { + dev_err(&vdev->pdev->dev, "Unable to allocate pdev %s\n", + info->name); + return -ENOMEM; + } + info->platdev->dev.parent = &vdev->pdev->dev; + info->platdev->dev.platform_data = vdev; + ret = platform_device_add(info->platdev); + if (ret) { + dev_err(&vdev->pdev->dev, "Unable to add pdev %s\n", + info->name); + platform_device_put(info->platdev); + info->platdev = NULL; + } + return ret; +} + +static int __devinit via_setup_subdevs(struct viafb_dev *vdev) +{ + int i; + + /* + * Ignore return values. Even if some of the devices + * fail to be created, we'll still be able to use some + * of the rest. + */ + for (i = 0; i < N_SUBDEVS; i++) + via_create_subdev(vdev, viafb_subdevs + i); + return 0; +} + +static void __devexit via_teardown_subdevs(void) +{ + int i; + + for (i = 0; i < N_SUBDEVS; i++) + if (viafb_subdevs[i].platdev) { + viafb_subdevs[i].platdev->dev.platform_data = NULL; + platform_device_unregister(viafb_subdevs[i].platdev); + } +} + static int __devinit via_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -205,33 +269,25 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, memset(&global_dev, 0, sizeof(global_dev)); global_dev.pdev = pdev; global_dev.chip_type = ent->driver_data; + global_dev.port_cfg = adap_configs; spin_lock_init(&global_dev.reg_lock); ret = via_pci_setup_mmio(&global_dev); if (ret) goto out_disable; /* - * Create the I2C busses. Bailing out on failure seems extreme, - * but that's what the code did before. + * Create our subdevices. Continue even if some things fail. */ - ret = viafb_create_i2c_busses(&global_dev, adap_configs); - if (ret) - goto out_teardown; + via_setup_subdevs(&global_dev); /* * Set up the framebuffer. */ ret = via_fb_pci_probe(&global_dev); if (ret) - goto out_i2c; - /* - * Create the GPIOs. We continue whether or not this succeeds; - * the framebuffer might be useful even without GPIO ports. - */ - ret = viafb_create_gpios(&global_dev, adap_configs); + goto out_subdevs; return 0; -out_i2c: - viafb_delete_i2c_busses(); -out_teardown: +out_subdevs: + via_teardown_subdevs(); via_pci_teardown_mmio(&global_dev); out_disable: pci_disable_device(pdev); @@ -240,8 +296,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, static void __devexit via_pci_remove(struct pci_dev *pdev) { - viafb_destroy_gpios(); - viafb_delete_i2c_busses(); + via_teardown_subdevs(); via_fb_pci_remove(pdev); via_pci_teardown_mmio(&global_dev); pci_disable_device(pdev); @@ -289,12 +344,16 @@ static int __init via_core_init(void) ret = viafb_init(); if (ret) return ret; + viafb_i2c_init(); + viafb_gpio_init(); return pci_register_driver(&via_driver); } static void __exit via_core_exit(void) { pci_unregister_driver(&via_driver); + viafb_gpio_exit(); + viafb_i2c_exit(); viafb_exit(); } diff --git a/drivers/video/via/via-core.h b/drivers/video/via/via-core.h index d004290dc8f1..ac89c2aa98b5 100644 --- a/drivers/video/via/via-core.h +++ b/drivers/video/via/via-core.h @@ -63,6 +63,7 @@ struct via_port_cfg { struct viafb_dev { struct pci_dev *pdev; int chip_type; + struct via_port_cfg *port_cfg; /* * Spinlock for access to device registers. Not yet * globally used. diff --git a/drivers/video/via/via-gpio.c b/drivers/video/via/via-gpio.c index 6b361177bf03..44537be1f070 100644 --- a/drivers/video/via/via-gpio.c +++ b/drivers/video/via/via-gpio.c @@ -7,6 +7,7 @@ #include #include +#include #include "via-core.h" #include "via-gpio.h" #include "global.h" @@ -172,12 +173,27 @@ static void viafb_gpio_disable(struct viafb_gpio *gpio) via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02); } - - - -int viafb_create_gpios(struct viafb_dev *vdev, - const struct via_port_cfg *port_cfg) +/* + * Look up a specific gpio and return the number it was assigned. + */ +int viafb_gpio_lookup(const char *name) { + int i; + + for (i = 0; i < gpio_config.gpio_chip.ngpio; i++) + if (!strcmp(name, gpio_config.active_gpios[i]->vg_name)) + return gpio_config.gpio_chip.base + i; + return -1; +} +EXPORT_SYMBOL_GPL(viafb_gpio_lookup); + +/* + * Platform device stuff. + */ +static __devinit int viafb_gpio_probe(struct platform_device *platdev) +{ + struct viafb_dev *vdev = platdev->dev.platform_data; + struct via_port_cfg *port_cfg = vdev->port_cfg; int i, ngpio = 0, ret; struct viafb_gpio *gpio; unsigned long flags; @@ -222,11 +238,10 @@ int viafb_create_gpios(struct viafb_dev *vdev, gpio_config.gpio_chip.ngpio = 0; } return ret; -/* Port enable ? */ } -int viafb_destroy_gpios(void) +static int viafb_gpio_remove(struct platform_device *platdev) { unsigned long flags; int ret = 0, i; @@ -253,16 +268,20 @@ int viafb_destroy_gpios(void) return ret; } -/* - * Look up a specific gpio and return the number it was assigned. - */ -int viafb_gpio_lookup(const char *name) -{ - int i; +static struct platform_driver via_gpio_driver = { + .driver = { + .name = "viafb-gpio", + }, + .probe = viafb_gpio_probe, + .remove = viafb_gpio_remove, +}; - for (i = 0; i < gpio_config.gpio_chip.ngpio; i++) - if (!strcmp(name, gpio_config.active_gpios[i]->vg_name)) - return gpio_config.gpio_chip.base + i; - return -1; +int viafb_gpio_init(void) +{ + return platform_driver_register(&via_gpio_driver); +} + +void viafb_gpio_exit(void) +{ + platform_driver_unregister(&via_gpio_driver); } -EXPORT_SYMBOL_GPL(viafb_gpio_lookup); diff --git a/drivers/video/via/via-gpio.h b/drivers/video/via/via-gpio.h index 7b53f966eb4b..8281aea3dd6d 100644 --- a/drivers/video/via/via-gpio.h +++ b/drivers/video/via/via-gpio.h @@ -8,8 +8,7 @@ #ifndef __VIA_GPIO_H__ #define __VIA_GPIO_H__ -extern int viafb_create_gpios(struct viafb_dev *vdev, - const struct via_port_cfg *port_cfg); -extern int viafb_destroy_gpios(void); extern int viafb_gpio_lookup(const char *name); +extern int viafb_gpio_init(void); +extern void viafb_gpio_exit(void); #endif diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c index 116fd3e62934..3ff60b280d88 100644 --- a/drivers/video/via/via_i2c.c +++ b/drivers/video/via/via_i2c.c @@ -19,6 +19,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include #include "via-core.h" #include "via_i2c.h" #include "global.h" @@ -185,11 +186,14 @@ static int create_i2c_bus(struct i2c_adapter *adapter, return i2c_bit_add_bus(adapter); } -int viafb_create_i2c_busses(struct viafb_dev *dev, struct via_port_cfg *configs) +static int viafb_i2c_probe(struct platform_device *platdev) { int i, ret; + struct via_port_cfg *configs; + + i2c_vdev = platdev->dev.platform_data; + configs = i2c_vdev->port_cfg; - i2c_vdev = dev; for (i = 0; i < VIAFB_NUM_PORTS; i++) { struct via_port_cfg *adap_cfg = configs++; struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i]; @@ -211,7 +215,7 @@ int viafb_create_i2c_busses(struct viafb_dev *dev, struct via_port_cfg *configs) return 0; } -void viafb_delete_i2c_busses(void) +static int viafb_i2c_remove(struct platform_device *platdev) { int i; @@ -224,4 +228,23 @@ void viafb_delete_i2c_busses(void) if (i2c_stuff->adapter.algo_data == &i2c_stuff->algo) i2c_del_adapter(&i2c_stuff->adapter); } + return 0; +} + +static struct platform_driver via_i2c_driver = { + .driver = { + .name = "viafb-i2c", + }, + .probe = viafb_i2c_probe, + .remove = viafb_i2c_remove, +}; + +int viafb_i2c_init(void) +{ + return platform_driver_register(&via_i2c_driver); +} + +void viafb_i2c_exit(void) +{ + platform_driver_unregister(&via_i2c_driver); } diff --git a/drivers/video/via/via_i2c.h b/drivers/video/via/via_i2c.h index 0685de9a0c7a..b2332cce9d18 100644 --- a/drivers/video/via/via_i2c.h +++ b/drivers/video/via/via_i2c.h @@ -35,8 +35,6 @@ int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata); int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data); int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len); -struct viafb_par; -int viafb_create_i2c_busses(struct viafb_dev *vdev, struct via_port_cfg *cfg); -void viafb_delete_i2c_busses(void); -struct i2c_adapter *viafb_find_adapter(enum viafb_i2c_adap which); +extern int viafb_i2c_init(void); +extern void viafb_i2c_exit(void); #endif /* __VIA_I2C_H__ */