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 | |
| 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>
| -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 | } |
