diff options
author | Jonathan Corbet <corbet@lwn.net> | 2010-04-22 19:39:34 -0400 |
---|---|---|
committer | Jonathan Corbet <corbet@lwn.net> | 2010-05-07 19:17:37 -0400 |
commit | 7582eb9be85f35271fd2569681a88a5b243e9380 (patch) | |
tree | 84a234364b9e314e7b25800d473e6047da379a56 /drivers/video | |
parent | 75b035ace904761b8a340b524533a36e37313b29 (diff) |
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 <laforge@gnumonks.org>
Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/via/via-core.c | 91 | ||||
-rw-r--r-- | drivers/video/via/via-core.h | 1 | ||||
-rw-r--r-- | drivers/video/via/via-gpio.c | 49 | ||||
-rw-r--r-- | drivers/video/via/via-gpio.h | 5 | ||||
-rw-r--r-- | drivers/video/via/via_i2c.c | 29 | ||||
-rw-r--r-- | drivers/video/via/via_i2c.h | 6 |
6 files changed, 140 insertions, 41 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) | |||
190 | iounmap(vdev->engine_mmio); | 190 | iounmap(vdev->engine_mmio); |
191 | } | 191 | } |
192 | 192 | ||
193 | /* | ||
194 | * Create our subsidiary devices. | ||
195 | */ | ||
196 | static struct viafb_subdev_info { | ||
197 | char *name; | ||
198 | struct platform_device *platdev; | ||
199 | } viafb_subdevs[] = { | ||
200 | { | ||
201 | .name = "viafb-gpio", | ||
202 | }, | ||
203 | { | ||
204 | .name = "viafb-i2c", | ||
205 | } | ||
206 | }; | ||
207 | #define N_SUBDEVS ARRAY_SIZE(viafb_subdevs) | ||
208 | |||
209 | static int __devinit via_create_subdev(struct viafb_dev *vdev, | ||
210 | struct viafb_subdev_info *info) | ||
211 | { | ||
212 | int ret; | ||
213 | |||
214 | info->platdev = platform_device_alloc(info->name, -1); | ||
215 | if (!info->platdev) { | ||
216 | dev_err(&vdev->pdev->dev, "Unable to allocate pdev %s\n", | ||
217 | info->name); | ||
218 | return -ENOMEM; | ||
219 | } | ||
220 | info->platdev->dev.parent = &vdev->pdev->dev; | ||
221 | info->platdev->dev.platform_data = vdev; | ||
222 | ret = platform_device_add(info->platdev); | ||
223 | if (ret) { | ||
224 | dev_err(&vdev->pdev->dev, "Unable to add pdev %s\n", | ||
225 | info->name); | ||
226 | platform_device_put(info->platdev); | ||
227 | info->platdev = NULL; | ||
228 | } | ||
229 | return ret; | ||
230 | } | ||
231 | |||
232 | static int __devinit via_setup_subdevs(struct viafb_dev *vdev) | ||
233 | { | ||
234 | int i; | ||
235 | |||
236 | /* | ||
237 | * Ignore return values. Even if some of the devices | ||
238 | * fail to be created, we'll still be able to use some | ||
239 | * of the rest. | ||
240 | */ | ||
241 | for (i = 0; i < N_SUBDEVS; i++) | ||
242 | via_create_subdev(vdev, viafb_subdevs + i); | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static void __devexit via_teardown_subdevs(void) | ||
247 | { | ||
248 | int i; | ||
249 | |||
250 | for (i = 0; i < N_SUBDEVS; i++) | ||
251 | if (viafb_subdevs[i].platdev) { | ||
252 | viafb_subdevs[i].platdev->dev.platform_data = NULL; | ||
253 | platform_device_unregister(viafb_subdevs[i].platdev); | ||
254 | } | ||
255 | } | ||
256 | |||
193 | 257 | ||
194 | static int __devinit via_pci_probe(struct pci_dev *pdev, | 258 | static int __devinit via_pci_probe(struct pci_dev *pdev, |
195 | const struct pci_device_id *ent) | 259 | const struct pci_device_id *ent) |
@@ -205,33 +269,25 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, | |||
205 | memset(&global_dev, 0, sizeof(global_dev)); | 269 | memset(&global_dev, 0, sizeof(global_dev)); |
206 | global_dev.pdev = pdev; | 270 | global_dev.pdev = pdev; |
207 | global_dev.chip_type = ent->driver_data; | 271 | global_dev.chip_type = ent->driver_data; |
272 | global_dev.port_cfg = adap_configs; | ||
208 | spin_lock_init(&global_dev.reg_lock); | 273 | spin_lock_init(&global_dev.reg_lock); |
209 | ret = via_pci_setup_mmio(&global_dev); | 274 | ret = via_pci_setup_mmio(&global_dev); |
210 | if (ret) | 275 | if (ret) |
211 | goto out_disable; | 276 | goto out_disable; |
212 | /* | 277 | /* |
213 | * Create the I2C busses. Bailing out on failure seems extreme, | 278 | * Create our subdevices. Continue even if some things fail. |
214 | * but that's what the code did before. | ||
215 | */ | 279 | */ |
216 | ret = viafb_create_i2c_busses(&global_dev, adap_configs); | 280 | via_setup_subdevs(&global_dev); |
217 | if (ret) | ||
218 | goto out_teardown; | ||
219 | /* | 281 | /* |
220 | * Set up the framebuffer. | 282 | * Set up the framebuffer. |
221 | */ | 283 | */ |
222 | ret = via_fb_pci_probe(&global_dev); | 284 | ret = via_fb_pci_probe(&global_dev); |
223 | if (ret) | 285 | if (ret) |
224 | goto out_i2c; | 286 | goto out_subdevs; |
225 | /* | ||
226 | * Create the GPIOs. We continue whether or not this succeeds; | ||
227 | * the framebuffer might be useful even without GPIO ports. | ||
228 | */ | ||
229 | ret = viafb_create_gpios(&global_dev, adap_configs); | ||
230 | return 0; | 287 | return 0; |
231 | 288 | ||
232 | out_i2c: | 289 | out_subdevs: |
233 | viafb_delete_i2c_busses(); | 290 | via_teardown_subdevs(); |
234 | out_teardown: | ||
235 | via_pci_teardown_mmio(&global_dev); | 291 | via_pci_teardown_mmio(&global_dev); |
236 | out_disable: | 292 | out_disable: |
237 | pci_disable_device(pdev); | 293 | pci_disable_device(pdev); |
@@ -240,8 +296,7 @@ out_disable: | |||
240 | 296 | ||
241 | static void __devexit via_pci_remove(struct pci_dev *pdev) | 297 | static void __devexit via_pci_remove(struct pci_dev *pdev) |
242 | { | 298 | { |
243 | viafb_destroy_gpios(); | 299 | via_teardown_subdevs(); |
244 | viafb_delete_i2c_busses(); | ||
245 | via_fb_pci_remove(pdev); | 300 | via_fb_pci_remove(pdev); |
246 | via_pci_teardown_mmio(&global_dev); | 301 | via_pci_teardown_mmio(&global_dev); |
247 | pci_disable_device(pdev); | 302 | pci_disable_device(pdev); |
@@ -289,12 +344,16 @@ static int __init via_core_init(void) | |||
289 | ret = viafb_init(); | 344 | ret = viafb_init(); |
290 | if (ret) | 345 | if (ret) |
291 | return ret; | 346 | return ret; |
347 | viafb_i2c_init(); | ||
348 | viafb_gpio_init(); | ||
292 | return pci_register_driver(&via_driver); | 349 | return pci_register_driver(&via_driver); |
293 | } | 350 | } |
294 | 351 | ||
295 | static void __exit via_core_exit(void) | 352 | static void __exit via_core_exit(void) |
296 | { | 353 | { |
297 | pci_unregister_driver(&via_driver); | 354 | pci_unregister_driver(&via_driver); |
355 | viafb_gpio_exit(); | ||
356 | viafb_i2c_exit(); | ||
298 | viafb_exit(); | 357 | viafb_exit(); |
299 | } | 358 | } |
300 | 359 | ||
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 { | |||
63 | struct viafb_dev { | 63 | struct viafb_dev { |
64 | struct pci_dev *pdev; | 64 | struct pci_dev *pdev; |
65 | int chip_type; | 65 | int chip_type; |
66 | struct via_port_cfg *port_cfg; | ||
66 | /* | 67 | /* |
67 | * Spinlock for access to device registers. Not yet | 68 | * Spinlock for access to device registers. Not yet |
68 | * globally used. | 69 | * 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 @@ | |||
7 | 7 | ||
8 | #include <linux/spinlock.h> | 8 | #include <linux/spinlock.h> |
9 | #include <linux/gpio.h> | 9 | #include <linux/gpio.h> |
10 | #include <linux/platform_device.h> | ||
10 | #include "via-core.h" | 11 | #include "via-core.h" |
11 | #include "via-gpio.h" | 12 | #include "via-gpio.h" |
12 | #include "global.h" | 13 | #include "global.h" |
@@ -172,12 +173,27 @@ static void viafb_gpio_disable(struct viafb_gpio *gpio) | |||
172 | via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02); | 173 | via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02); |
173 | } | 174 | } |
174 | 175 | ||
176 | /* | ||
177 | * Look up a specific gpio and return the number it was assigned. | ||
178 | */ | ||
179 | int viafb_gpio_lookup(const char *name) | ||
180 | { | ||
181 | int i; | ||
175 | 182 | ||
183 | for (i = 0; i < gpio_config.gpio_chip.ngpio; i++) | ||
184 | if (!strcmp(name, gpio_config.active_gpios[i]->vg_name)) | ||
185 | return gpio_config.gpio_chip.base + i; | ||
186 | return -1; | ||
187 | } | ||
188 | EXPORT_SYMBOL_GPL(viafb_gpio_lookup); | ||
176 | 189 | ||
177 | 190 | /* | |
178 | int viafb_create_gpios(struct viafb_dev *vdev, | 191 | * Platform device stuff. |
179 | const struct via_port_cfg *port_cfg) | 192 | */ |
193 | static __devinit int viafb_gpio_probe(struct platform_device *platdev) | ||
180 | { | 194 | { |
195 | struct viafb_dev *vdev = platdev->dev.platform_data; | ||
196 | struct via_port_cfg *port_cfg = vdev->port_cfg; | ||
181 | int i, ngpio = 0, ret; | 197 | int i, ngpio = 0, ret; |
182 | struct viafb_gpio *gpio; | 198 | struct viafb_gpio *gpio; |
183 | unsigned long flags; | 199 | unsigned long flags; |
@@ -222,11 +238,10 @@ int viafb_create_gpios(struct viafb_dev *vdev, | |||
222 | gpio_config.gpio_chip.ngpio = 0; | 238 | gpio_config.gpio_chip.ngpio = 0; |
223 | } | 239 | } |
224 | return ret; | 240 | return ret; |
225 | /* Port enable ? */ | ||
226 | } | 241 | } |
227 | 242 | ||
228 | 243 | ||
229 | int viafb_destroy_gpios(void) | 244 | static int viafb_gpio_remove(struct platform_device *platdev) |
230 | { | 245 | { |
231 | unsigned long flags; | 246 | unsigned long flags; |
232 | int ret = 0, i; | 247 | int ret = 0, i; |
@@ -253,16 +268,20 @@ out: | |||
253 | return ret; | 268 | return ret; |
254 | } | 269 | } |
255 | 270 | ||
256 | /* | 271 | static struct platform_driver via_gpio_driver = { |
257 | * Look up a specific gpio and return the number it was assigned. | 272 | .driver = { |
258 | */ | 273 | .name = "viafb-gpio", |
259 | int viafb_gpio_lookup(const char *name) | 274 | }, |
275 | .probe = viafb_gpio_probe, | ||
276 | .remove = viafb_gpio_remove, | ||
277 | }; | ||
278 | |||
279 | int viafb_gpio_init(void) | ||
260 | { | 280 | { |
261 | int i; | 281 | return platform_driver_register(&via_gpio_driver); |
282 | } | ||
262 | 283 | ||
263 | for (i = 0; i < gpio_config.gpio_chip.ngpio; i++) | 284 | void viafb_gpio_exit(void) |
264 | if (!strcmp(name, gpio_config.active_gpios[i]->vg_name)) | 285 | { |
265 | return gpio_config.gpio_chip.base + i; | 286 | platform_driver_unregister(&via_gpio_driver); |
266 | return -1; | ||
267 | } | 287 | } |
268 | 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 @@ | |||
8 | #ifndef __VIA_GPIO_H__ | 8 | #ifndef __VIA_GPIO_H__ |
9 | #define __VIA_GPIO_H__ | 9 | #define __VIA_GPIO_H__ |
10 | 10 | ||
11 | extern int viafb_create_gpios(struct viafb_dev *vdev, | ||
12 | const struct via_port_cfg *port_cfg); | ||
13 | extern int viafb_destroy_gpios(void); | ||
14 | extern int viafb_gpio_lookup(const char *name); | 11 | extern int viafb_gpio_lookup(const char *name); |
12 | extern int viafb_gpio_init(void); | ||
13 | extern void viafb_gpio_exit(void); | ||
15 | #endif | 14 | #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 @@ | |||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/platform_device.h> | ||
22 | #include "via-core.h" | 23 | #include "via-core.h" |
23 | #include "via_i2c.h" | 24 | #include "via_i2c.h" |
24 | #include "global.h" | 25 | #include "global.h" |
@@ -185,11 +186,14 @@ static int create_i2c_bus(struct i2c_adapter *adapter, | |||
185 | return i2c_bit_add_bus(adapter); | 186 | return i2c_bit_add_bus(adapter); |
186 | } | 187 | } |
187 | 188 | ||
188 | int viafb_create_i2c_busses(struct viafb_dev *dev, struct via_port_cfg *configs) | 189 | static int viafb_i2c_probe(struct platform_device *platdev) |
189 | { | 190 | { |
190 | int i, ret; | 191 | int i, ret; |
192 | struct via_port_cfg *configs; | ||
193 | |||
194 | i2c_vdev = platdev->dev.platform_data; | ||
195 | configs = i2c_vdev->port_cfg; | ||
191 | 196 | ||
192 | i2c_vdev = dev; | ||
193 | for (i = 0; i < VIAFB_NUM_PORTS; i++) { | 197 | for (i = 0; i < VIAFB_NUM_PORTS; i++) { |
194 | struct via_port_cfg *adap_cfg = configs++; | 198 | struct via_port_cfg *adap_cfg = configs++; |
195 | struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i]; | 199 | 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) | |||
211 | return 0; | 215 | return 0; |
212 | } | 216 | } |
213 | 217 | ||
214 | void viafb_delete_i2c_busses(void) | 218 | static int viafb_i2c_remove(struct platform_device *platdev) |
215 | { | 219 | { |
216 | int i; | 220 | int i; |
217 | 221 | ||
@@ -224,4 +228,23 @@ void viafb_delete_i2c_busses(void) | |||
224 | if (i2c_stuff->adapter.algo_data == &i2c_stuff->algo) | 228 | if (i2c_stuff->adapter.algo_data == &i2c_stuff->algo) |
225 | i2c_del_adapter(&i2c_stuff->adapter); | 229 | i2c_del_adapter(&i2c_stuff->adapter); |
226 | } | 230 | } |
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static struct platform_driver via_i2c_driver = { | ||
235 | .driver = { | ||
236 | .name = "viafb-i2c", | ||
237 | }, | ||
238 | .probe = viafb_i2c_probe, | ||
239 | .remove = viafb_i2c_remove, | ||
240 | }; | ||
241 | |||
242 | int viafb_i2c_init(void) | ||
243 | { | ||
244 | return platform_driver_register(&via_i2c_driver); | ||
245 | } | ||
246 | |||
247 | void viafb_i2c_exit(void) | ||
248 | { | ||
249 | platform_driver_unregister(&via_i2c_driver); | ||
227 | } | 250 | } |
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); | |||
35 | int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data); | 35 | int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data); |
36 | int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len); | 36 | int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len); |
37 | 37 | ||
38 | struct viafb_par; | 38 | extern int viafb_i2c_init(void); |
39 | int viafb_create_i2c_busses(struct viafb_dev *vdev, struct via_port_cfg *cfg); | 39 | extern void viafb_i2c_exit(void); |
40 | void viafb_delete_i2c_busses(void); | ||
41 | struct i2c_adapter *viafb_find_adapter(enum viafb_i2c_adap which); | ||
42 | #endif /* __VIA_I2C_H__ */ | 40 | #endif /* __VIA_I2C_H__ */ |