aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2007-07-31 03:39:45 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-31 18:39:44 -0400
commit082c8cb4e5e68c0fd29cc10c59db94d2284fd2b0 (patch)
tree5f4ec8042b29272f0fd0c28b2cc2c0bb63f38dc0
parent2604288f45605d1b2844f001dc3141149667b3d1 (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.c45
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 */
204struct spi_device *spi_new_device(struct spi_master *master, 206struct 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)
306static void scan_boardinfo(struct spi_master *master) 321static 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 }