diff options
author | David Brownell <david-b@pacbell.net> | 2006-01-08 16:34:23 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-01-13 19:29:54 -0500 |
commit | b885244eb2628e0b8206e7edaaa6a314da78e9a4 (patch) | |
tree | e548fb3a94603c4a5406920c97246a78fe16b64a /drivers/spi/spi.c | |
parent | 1d6432fe10c3e724e307dd7137cd293a0edcae80 (diff) |
[PATCH] spi: add spi_driver to SPI framework
This is a refresh of the "Simple SPI Framework" found in 2.6.15-rc3-mm1
which makes the following changes:
* There's now a "struct spi_driver". This increase the footprint
of the core a bit, since it now includes code to do what the driver
core was previously handling directly. Documentation and comments
were updated to match.
* spi_alloc_master() now does class_device_initialize(), so it can
at least be refcounted before spi_register_master(). To match,
spi_register_master() switched over to class_device_add().
* States explicitly that after transfer errors, spi_devices will be
deselected. We want fault recovery procedures to work the same
for all controller drivers.
* Minor tweaks: controller_data no longer points to readonly data;
prevent some potential cast-from-null bugs with container_of calls;
clarifies some existing kerneldoc,
And a few small cleanups.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/spi/spi.c')
-rw-r--r-- | drivers/spi/spi.c | 118 |
1 files changed, 86 insertions, 32 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 7cd356b17644..2ecb86cb3689 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
@@ -26,13 +26,9 @@ | |||
26 | #include <linux/spi/spi.h> | 26 | #include <linux/spi/spi.h> |
27 | 27 | ||
28 | 28 | ||
29 | /* SPI bustype and spi_master class are registered during early boot, | 29 | /* SPI bustype and spi_master class are registered after board init code |
30 | * usually before board init code provides the SPI device tables, and | 30 | * provides the SPI device tables, ensuring that both are present by the |
31 | * are available later when driver init code needs them. | 31 | * time controller driver registration causes spi_devices to "enumerate". |
32 | * | ||
33 | * Drivers for SPI devices started out like those for platform bus | ||
34 | * devices. But both have changed in 2.6.15; maybe this should get | ||
35 | * an "spi_driver" structure at some point (not currently needed) | ||
36 | */ | 32 | */ |
37 | static void spidev_release(struct device *dev) | 33 | static void spidev_release(struct device *dev) |
38 | { | 34 | { |
@@ -83,10 +79,7 @@ static int spi_uevent(struct device *dev, char **envp, int num_envp, | |||
83 | 79 | ||
84 | #ifdef CONFIG_PM | 80 | #ifdef CONFIG_PM |
85 | 81 | ||
86 | /* Suspend/resume in "struct device_driver" don't really need that | 82 | /* |
87 | * strange third parameter, so we just make it a constant and expect | ||
88 | * SPI drivers to ignore it just like most platform drivers do. | ||
89 | * | ||
90 | * NOTE: the suspend() method for an spi_master controller driver | 83 | * NOTE: the suspend() method for an spi_master controller driver |
91 | * should verify that all its child devices are marked as suspended; | 84 | * should verify that all its child devices are marked as suspended; |
92 | * suspend requests delivered through sysfs power/state files don't | 85 | * suspend requests delivered through sysfs power/state files don't |
@@ -94,13 +87,14 @@ static int spi_uevent(struct device *dev, char **envp, int num_envp, | |||
94 | */ | 87 | */ |
95 | static int spi_suspend(struct device *dev, pm_message_t message) | 88 | static int spi_suspend(struct device *dev, pm_message_t message) |
96 | { | 89 | { |
97 | int value; | 90 | int value; |
91 | struct spi_driver *drv = to_spi_driver(dev->driver); | ||
98 | 92 | ||
99 | if (!dev->driver || !dev->driver->suspend) | 93 | if (!drv || !drv->suspend) |
100 | return 0; | 94 | return 0; |
101 | 95 | ||
102 | /* suspend will stop irqs and dma; no more i/o */ | 96 | /* suspend will stop irqs and dma; no more i/o */ |
103 | value = dev->driver->suspend(dev, message); | 97 | value = drv->suspend(to_spi_device(dev), message); |
104 | if (value == 0) | 98 | if (value == 0) |
105 | dev->power.power_state = message; | 99 | dev->power.power_state = message; |
106 | return value; | 100 | return value; |
@@ -108,13 +102,14 @@ static int spi_suspend(struct device *dev, pm_message_t message) | |||
108 | 102 | ||
109 | static int spi_resume(struct device *dev) | 103 | static int spi_resume(struct device *dev) |
110 | { | 104 | { |
111 | int value; | 105 | int value; |
106 | struct spi_driver *drv = to_spi_driver(dev->driver); | ||
112 | 107 | ||
113 | if (!dev->driver || !dev->driver->resume) | 108 | if (!drv || !drv->resume) |
114 | return 0; | 109 | return 0; |
115 | 110 | ||
116 | /* resume may restart the i/o queue */ | 111 | /* resume may restart the i/o queue */ |
117 | value = dev->driver->resume(dev); | 112 | value = drv->resume(to_spi_device(dev)); |
118 | if (value == 0) | 113 | if (value == 0) |
119 | dev->power.power_state = PMSG_ON; | 114 | dev->power.power_state = PMSG_ON; |
120 | return value; | 115 | return value; |
@@ -135,6 +130,41 @@ struct bus_type spi_bus_type = { | |||
135 | }; | 130 | }; |
136 | EXPORT_SYMBOL_GPL(spi_bus_type); | 131 | EXPORT_SYMBOL_GPL(spi_bus_type); |
137 | 132 | ||
133 | |||
134 | static int spi_drv_probe(struct device *dev) | ||
135 | { | ||
136 | const struct spi_driver *sdrv = to_spi_driver(dev->driver); | ||
137 | |||
138 | return sdrv->probe(to_spi_device(dev)); | ||
139 | } | ||
140 | |||
141 | static int spi_drv_remove(struct device *dev) | ||
142 | { | ||
143 | const struct spi_driver *sdrv = to_spi_driver(dev->driver); | ||
144 | |||
145 | return sdrv->remove(to_spi_device(dev)); | ||
146 | } | ||
147 | |||
148 | static void spi_drv_shutdown(struct device *dev) | ||
149 | { | ||
150 | const struct spi_driver *sdrv = to_spi_driver(dev->driver); | ||
151 | |||
152 | sdrv->shutdown(to_spi_device(dev)); | ||
153 | } | ||
154 | |||
155 | int spi_register_driver(struct spi_driver *sdrv) | ||
156 | { | ||
157 | sdrv->driver.bus = &spi_bus_type; | ||
158 | if (sdrv->probe) | ||
159 | sdrv->driver.probe = spi_drv_probe; | ||
160 | if (sdrv->remove) | ||
161 | sdrv->driver.remove = spi_drv_remove; | ||
162 | if (sdrv->shutdown) | ||
163 | sdrv->driver.shutdown = spi_drv_shutdown; | ||
164 | return driver_register(&sdrv->driver); | ||
165 | } | ||
166 | EXPORT_SYMBOL_GPL(spi_register_driver); | ||
167 | |||
138 | /*-------------------------------------------------------------------------*/ | 168 | /*-------------------------------------------------------------------------*/ |
139 | 169 | ||
140 | /* SPI devices should normally not be created by SPI device drivers; that | 170 | /* SPI devices should normally not be created by SPI device drivers; that |
@@ -208,13 +238,15 @@ spi_new_device(struct spi_master *master, struct spi_board_info *chip) | |||
208 | if (status < 0) { | 238 | if (status < 0) { |
209 | dev_dbg(dev, "can't %s %s, status %d\n", | 239 | dev_dbg(dev, "can't %s %s, status %d\n", |
210 | "add", proxy->dev.bus_id, status); | 240 | "add", proxy->dev.bus_id, status); |
211 | fail: | 241 | goto fail; |
212 | class_device_put(&master->cdev); | ||
213 | kfree(proxy); | ||
214 | return NULL; | ||
215 | } | 242 | } |
216 | dev_dbg(dev, "registered child %s\n", proxy->dev.bus_id); | 243 | dev_dbg(dev, "registered child %s\n", proxy->dev.bus_id); |
217 | return proxy; | 244 | return proxy; |
245 | |||
246 | fail: | ||
247 | class_device_put(&master->cdev); | ||
248 | kfree(proxy); | ||
249 | return NULL; | ||
218 | } | 250 | } |
219 | EXPORT_SYMBOL_GPL(spi_new_device); | 251 | EXPORT_SYMBOL_GPL(spi_new_device); |
220 | 252 | ||
@@ -237,11 +269,11 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n) | |||
237 | { | 269 | { |
238 | struct boardinfo *bi; | 270 | struct boardinfo *bi; |
239 | 271 | ||
240 | bi = kmalloc (sizeof (*bi) + n * sizeof (*info), GFP_KERNEL); | 272 | bi = kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL); |
241 | if (!bi) | 273 | if (!bi) |
242 | return -ENOMEM; | 274 | return -ENOMEM; |
243 | bi->n_board_info = n; | 275 | bi->n_board_info = n; |
244 | memcpy(bi->board_info, info, n * sizeof (*info)); | 276 | memcpy(bi->board_info, info, n * sizeof *info); |
245 | 277 | ||
246 | down(&board_lock); | 278 | down(&board_lock); |
247 | list_add_tail(&bi->list, &board_list); | 279 | list_add_tail(&bi->list, &board_list); |
@@ -330,6 +362,7 @@ spi_alloc_master(struct device *dev, unsigned size) | |||
330 | if (!master) | 362 | if (!master) |
331 | return NULL; | 363 | return NULL; |
332 | 364 | ||
365 | class_device_initialize(&master->cdev); | ||
333 | master->cdev.class = &spi_master_class; | 366 | master->cdev.class = &spi_master_class; |
334 | master->cdev.dev = get_device(dev); | 367 | master->cdev.dev = get_device(dev); |
335 | class_set_devdata(&master->cdev, &master[1]); | 368 | class_set_devdata(&master->cdev, &master[1]); |
@@ -366,7 +399,7 @@ spi_register_master(struct spi_master *master) | |||
366 | /* convention: dynamically assigned bus IDs count down from the max */ | 399 | /* convention: dynamically assigned bus IDs count down from the max */ |
367 | if (master->bus_num == 0) { | 400 | if (master->bus_num == 0) { |
368 | master->bus_num = atomic_dec_return(&dyn_bus_id); | 401 | master->bus_num = atomic_dec_return(&dyn_bus_id); |
369 | dynamic = 0; | 402 | dynamic = 1; |
370 | } | 403 | } |
371 | 404 | ||
372 | /* register the device, then userspace will see it. | 405 | /* register the device, then userspace will see it. |
@@ -374,11 +407,9 @@ spi_register_master(struct spi_master *master) | |||
374 | */ | 407 | */ |
375 | snprintf(master->cdev.class_id, sizeof master->cdev.class_id, | 408 | snprintf(master->cdev.class_id, sizeof master->cdev.class_id, |
376 | "spi%u", master->bus_num); | 409 | "spi%u", master->bus_num); |
377 | status = class_device_register(&master->cdev); | 410 | status = class_device_add(&master->cdev); |
378 | if (status < 0) { | 411 | if (status < 0) |
379 | class_device_put(&master->cdev); | ||
380 | goto done; | 412 | goto done; |
381 | } | ||
382 | dev_dbg(dev, "registered master %s%s\n", master->cdev.class_id, | 413 | dev_dbg(dev, "registered master %s%s\n", master->cdev.class_id, |
383 | dynamic ? " (dynamic)" : ""); | 414 | dynamic ? " (dynamic)" : ""); |
384 | 415 | ||
@@ -491,6 +522,7 @@ static u8 *buf; | |||
491 | * This performs a half duplex MicroWire style transaction with the | 522 | * This performs a half duplex MicroWire style transaction with the |
492 | * device, sending txbuf and then reading rxbuf. The return value | 523 | * device, sending txbuf and then reading rxbuf. The return value |
493 | * is zero for success, else a negative errno status code. | 524 | * is zero for success, else a negative errno status code. |
525 | * This call may only be used from a context that may sleep. | ||
494 | * | 526 | * |
495 | * Parameters to this routine are always copied using a small buffer, | 527 | * Parameters to this routine are always copied using a small buffer, |
496 | * large transfers should use use spi_{async,sync}() calls with | 528 | * large transfers should use use spi_{async,sync}() calls with |
@@ -553,16 +585,38 @@ EXPORT_SYMBOL_GPL(spi_write_then_read); | |||
553 | 585 | ||
554 | static int __init spi_init(void) | 586 | static int __init spi_init(void) |
555 | { | 587 | { |
588 | int status; | ||
589 | |||
556 | buf = kmalloc(SPI_BUFSIZ, SLAB_KERNEL); | 590 | buf = kmalloc(SPI_BUFSIZ, SLAB_KERNEL); |
557 | if (!buf) | 591 | if (!buf) { |
558 | return -ENOMEM; | 592 | status = -ENOMEM; |
593 | goto err0; | ||
594 | } | ||
595 | |||
596 | status = bus_register(&spi_bus_type); | ||
597 | if (status < 0) | ||
598 | goto err1; | ||
559 | 599 | ||
560 | bus_register(&spi_bus_type); | 600 | status = class_register(&spi_master_class); |
561 | class_register(&spi_master_class); | 601 | if (status < 0) |
602 | goto err2; | ||
562 | return 0; | 603 | return 0; |
604 | |||
605 | err2: | ||
606 | bus_unregister(&spi_bus_type); | ||
607 | err1: | ||
608 | kfree(buf); | ||
609 | buf = NULL; | ||
610 | err0: | ||
611 | return status; | ||
563 | } | 612 | } |
613 | |||
564 | /* board_info is normally registered in arch_initcall(), | 614 | /* board_info is normally registered in arch_initcall(), |
565 | * but even essential drivers wait till later | 615 | * but even essential drivers wait till later |
616 | * | ||
617 | * REVISIT only boardinfo really needs static linking. the rest (device and | ||
618 | * driver registration) _could_ be dynamically linked (modular) ... costs | ||
619 | * include needing to have boardinfo data structures be much more public. | ||
566 | */ | 620 | */ |
567 | subsys_initcall(spi_init); | 621 | subsys_initcall(spi_init); |
568 | 622 | ||