diff options
author | David Brownell <david-b@pacbell.net> | 2007-07-31 03:39:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-31 18:39:44 -0400 |
commit | 082c8cb4e5e68c0fd29cc10c59db94d2284fd2b0 (patch) | |
tree | 5f4ec8042b29272f0fd0c28b2cc2c0bb63f38dc0 /drivers/spi | |
parent | 2604288f45605d1b2844f001dc3141149667b3d1 (diff) |
spi device setup gets better error checking
This updates some error reporting paths in SPI device setup:
- Move validation logic for SPI chipselects to spi_new_device(),
which is where it should always have been.
- In spi_new_device(), emit error messages if the device can't
be created. This is LOTS better than a silent failure; though
eventually, the calling convention should probably change to
use the <linux/err.h> conventions.
- Includes one previously-missing check: SPI masters must always
have at least one chipselect, even for dedicated busses which
always keep it selected!
It also adds a FIXME (IDR for dynamic ID allocation) so the issue doesn't live
purely in my mailbox.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi.c | 45 |
1 files changed, 30 insertions, 15 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index b05de30b5d9b..e84d21597943 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
@@ -200,6 +200,8 @@ static DEFINE_MUTEX(board_lock); | |||
200 | * platforms may not be able to use spi_register_board_info though, and | 200 | * platforms may not be able to use spi_register_board_info though, and |
201 | * this is exported so that for example a USB or parport based adapter | 201 | * this is exported so that for example a USB or parport based adapter |
202 | * driver could add devices (which it would learn about out-of-band). | 202 | * driver could add devices (which it would learn about out-of-band). |
203 | * | ||
204 | * Returns the new device, or NULL. | ||
203 | */ | 205 | */ |
204 | struct spi_device *spi_new_device(struct spi_master *master, | 206 | struct spi_device *spi_new_device(struct spi_master *master, |
205 | struct spi_board_info *chip) | 207 | struct spi_board_info *chip) |
@@ -208,7 +210,20 @@ struct spi_device *spi_new_device(struct spi_master *master, | |||
208 | struct device *dev = master->cdev.dev; | 210 | struct device *dev = master->cdev.dev; |
209 | int status; | 211 | int status; |
210 | 212 | ||
211 | /* NOTE: caller did any chip->bus_num checks necessary */ | 213 | /* NOTE: caller did any chip->bus_num checks necessary. |
214 | * | ||
215 | * Also, unless we change the return value convention to use | ||
216 | * error-or-pointer (not NULL-or-pointer), troubleshootability | ||
217 | * suggests syslogged diagnostics are best here (ugh). | ||
218 | */ | ||
219 | |||
220 | /* Chipselects are numbered 0..max; validate. */ | ||
221 | if (chip->chip_select >= master->num_chipselect) { | ||
222 | dev_err(dev, "cs%d > max %d\n", | ||
223 | chip->chip_select, | ||
224 | master->num_chipselect); | ||
225 | return NULL; | ||
226 | } | ||
212 | 227 | ||
213 | if (!spi_master_get(master)) | 228 | if (!spi_master_get(master)) |
214 | return NULL; | 229 | return NULL; |
@@ -236,10 +251,10 @@ struct spi_device *spi_new_device(struct spi_master *master, | |||
236 | proxy->controller_state = NULL; | 251 | proxy->controller_state = NULL; |
237 | proxy->dev.release = spidev_release; | 252 | proxy->dev.release = spidev_release; |
238 | 253 | ||
239 | /* drivers may modify this default i/o setup */ | 254 | /* drivers may modify this initial i/o setup */ |
240 | status = master->setup(proxy); | 255 | status = master->setup(proxy); |
241 | if (status < 0) { | 256 | if (status < 0) { |
242 | dev_dbg(dev, "can't %s %s, status %d\n", | 257 | dev_err(dev, "can't %s %s, status %d\n", |
243 | "setup", proxy->dev.bus_id, status); | 258 | "setup", proxy->dev.bus_id, status); |
244 | goto fail; | 259 | goto fail; |
245 | } | 260 | } |
@@ -249,7 +264,7 @@ struct spi_device *spi_new_device(struct spi_master *master, | |||
249 | */ | 264 | */ |
250 | status = device_register(&proxy->dev); | 265 | status = device_register(&proxy->dev); |
251 | if (status < 0) { | 266 | if (status < 0) { |
252 | dev_dbg(dev, "can't %s %s, status %d\n", | 267 | dev_err(dev, "can't %s %s, status %d\n", |
253 | "add", proxy->dev.bus_id, status); | 268 | "add", proxy->dev.bus_id, status); |
254 | goto fail; | 269 | goto fail; |
255 | } | 270 | } |
@@ -306,7 +321,6 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n) | |||
306 | static void scan_boardinfo(struct spi_master *master) | 321 | static void scan_boardinfo(struct spi_master *master) |
307 | { | 322 | { |
308 | struct boardinfo *bi; | 323 | struct boardinfo *bi; |
309 | struct device *dev = master->cdev.dev; | ||
310 | 324 | ||
311 | mutex_lock(&board_lock); | 325 | mutex_lock(&board_lock); |
312 | list_for_each_entry(bi, &board_list, list) { | 326 | list_for_each_entry(bi, &board_list, list) { |
@@ -316,17 +330,9 @@ static void scan_boardinfo(struct spi_master *master) | |||
316 | for (n = bi->n_board_info; n > 0; n--, chip++) { | 330 | for (n = bi->n_board_info; n > 0; n--, chip++) { |
317 | if (chip->bus_num != master->bus_num) | 331 | if (chip->bus_num != master->bus_num) |
318 | continue; | 332 | continue; |
319 | /* some controllers only have one chip, so they | 333 | /* NOTE: this relies on spi_new_device to |
320 | * might not use chipselects. otherwise, the | 334 | * issue diagnostics when given bogus inputs |
321 | * chipselects are numbered 0..max. | ||
322 | */ | 335 | */ |
323 | if (chip->chip_select >= master->num_chipselect | ||
324 | && master->num_chipselect) { | ||
325 | dev_dbg(dev, "cs%d > max %d\n", | ||
326 | chip->chip_select, | ||
327 | master->num_chipselect); | ||
328 | continue; | ||
329 | } | ||
330 | (void) spi_new_device(master, chip); | 336 | (void) spi_new_device(master, chip); |
331 | } | 337 | } |
332 | } | 338 | } |
@@ -419,8 +425,17 @@ int spi_register_master(struct spi_master *master) | |||
419 | if (!dev) | 425 | if (!dev) |
420 | return -ENODEV; | 426 | return -ENODEV; |
421 | 427 | ||
428 | /* even if it's just one always-selected device, there must | ||
429 | * be at least one chipselect | ||
430 | */ | ||
431 | if (master->num_chipselect == 0) | ||
432 | return -EINVAL; | ||
433 | |||
422 | /* convention: dynamically assigned bus IDs count down from the max */ | 434 | /* convention: dynamically assigned bus IDs count down from the max */ |
423 | if (master->bus_num < 0) { | 435 | if (master->bus_num < 0) { |
436 | /* FIXME switch to an IDR based scheme, something like | ||
437 | * I2C now uses, so we can't run out of "dynamic" IDs | ||
438 | */ | ||
424 | master->bus_num = atomic_dec_return(&dyn_bus_id); | 439 | master->bus_num = atomic_dec_return(&dyn_bus_id); |
425 | dynamic = 1; | 440 | dynamic = 1; |
426 | } | 441 | } |