diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-11-01 07:50:43 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-11-01 07:50:43 -0400 |
commit | 90ae83f7fc32733e5829d806306c0c590f1a383f (patch) | |
tree | 5b4cd7290c70d9899ca7caa99998395218b15cab | |
parent | 47c5ba53bc5e5f88b5d1bbb97acd25afc27f74eb (diff) | |
parent | 65289d6345d93abd860e43fd2119ac176d6cc697 (diff) |
Merge branch 'next-spi' of git://git.secretlab.ca/git/linux-2.6
* 'next-spi' of git://git.secretlab.ca/git/linux-2.6:
spi/pl022: fix erroneous platform data in U300
spi: fixed odd static string conventions in core code
spi/bfin_spi: only request GPIO on first load
spi/bfin_spi: handle error/status changes after data interrupts
spi: enable spi_board_info to be registered after spi_master
-rw-r--r-- | arch/arm/mach-u300/spi.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi.c | 98 | ||||
-rw-r--r-- | drivers/spi/spi_bfin5xx.c | 22 | ||||
-rw-r--r-- | include/linux/spi/spi.h | 3 |
4 files changed, 73 insertions, 52 deletions
diff --git a/arch/arm/mach-u300/spi.c b/arch/arm/mach-u300/spi.c index edb2c0d255c..00869def542 100644 --- a/arch/arm/mach-u300/spi.c +++ b/arch/arm/mach-u300/spi.c @@ -67,7 +67,7 @@ static struct spi_board_info u300_spi_devices[] = { .bus_num = 0, /* Only one bus on this chip */ .chip_select = 0, /* Means SPI_CS_HIGH, change if e.g low CS */ - .mode = SPI_MODE_1 | SPI_LSB_FIRST | SPI_LOOP, + .mode = SPI_MODE_1 | SPI_LOOP, }, #endif }; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index b5a78a1f442..709c836607d 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -29,11 +29,6 @@ #include <linux/spi/spi.h> #include <linux/of_spi.h> - -/* SPI bustype and spi_master class are registered after board init code - * provides the SPI device tables, ensuring that both are present by the - * time controller driver registration causes spi_devices to "enumerate". - */ static void spidev_release(struct device *dev) { struct spi_device *spi = to_spi_device(dev); @@ -202,11 +197,16 @@ EXPORT_SYMBOL_GPL(spi_register_driver); struct boardinfo { struct list_head list; - unsigned n_board_info; - struct spi_board_info board_info[0]; + struct spi_board_info board_info; }; static LIST_HEAD(board_list); +static LIST_HEAD(spi_master_list); + +/* + * Used to protect add/del opertion for board_info list and + * spi_master list, and their matching process + */ static DEFINE_MUTEX(board_lock); /** @@ -300,16 +300,16 @@ int spi_add_device(struct spi_device *spi) */ status = spi_setup(spi); if (status < 0) { - dev_err(dev, "can't %s %s, status %d\n", - "setup", dev_name(&spi->dev), status); + dev_err(dev, "can't setup %s, status %d\n", + dev_name(&spi->dev), status); goto done; } /* Device may be bound to an active driver when this returns */ status = device_add(&spi->dev); if (status < 0) - dev_err(dev, "can't %s %s, status %d\n", - "add", dev_name(&spi->dev), status); + dev_err(dev, "can't add %s, status %d\n", + dev_name(&spi->dev), status); else dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev)); @@ -371,6 +371,20 @@ struct spi_device *spi_new_device(struct spi_master *master, } EXPORT_SYMBOL_GPL(spi_new_device); +static void spi_match_master_to_boardinfo(struct spi_master *master, + struct spi_board_info *bi) +{ + struct spi_device *dev; + + if (master->bus_num != bi->bus_num) + return; + + dev = spi_new_device(master, bi); + if (!dev) + dev_err(master->dev.parent, "can't create new device for %s\n", + bi->modalias); +} + /** * spi_register_board_info - register SPI devices for a given board * @info: array of chip descriptors @@ -393,43 +407,25 @@ EXPORT_SYMBOL_GPL(spi_new_device); int __init spi_register_board_info(struct spi_board_info const *info, unsigned n) { - struct boardinfo *bi; + struct boardinfo *bi; + int i; - bi = kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL); + bi = kzalloc(n * sizeof(*bi), GFP_KERNEL); if (!bi) return -ENOMEM; - bi->n_board_info = n; - memcpy(bi->board_info, info, n * sizeof *info); - mutex_lock(&board_lock); - list_add_tail(&bi->list, &board_list); - mutex_unlock(&board_lock); - return 0; -} + for (i = 0; i < n; i++, bi++, info++) { + struct spi_master *master; -/* FIXME someone should add support for a __setup("spi", ...) that - * creates board info from kernel command lines - */ - -static void scan_boardinfo(struct spi_master *master) -{ - struct boardinfo *bi; - - mutex_lock(&board_lock); - list_for_each_entry(bi, &board_list, list) { - struct spi_board_info *chip = bi->board_info; - unsigned n; - - for (n = bi->n_board_info; n > 0; n--, chip++) { - if (chip->bus_num != master->bus_num) - continue; - /* NOTE: this relies on spi_new_device to - * issue diagnostics when given bogus inputs - */ - (void) spi_new_device(master, chip); - } + memcpy(&bi->board_info, info, sizeof(*info)); + mutex_lock(&board_lock); + list_add_tail(&bi->list, &board_list); + list_for_each_entry(master, &spi_master_list, list) + spi_match_master_to_boardinfo(master, &bi->board_info); + mutex_unlock(&board_lock); } - mutex_unlock(&board_lock); + + return 0; } /*-------------------------------------------------------------------------*/ @@ -512,6 +508,7 @@ int spi_register_master(struct spi_master *master) { static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1); struct device *dev = master->dev.parent; + struct boardinfo *bi; int status = -ENODEV; int dynamic = 0; @@ -547,8 +544,12 @@ int spi_register_master(struct spi_master *master) dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev), dynamic ? " (dynamic)" : ""); - /* populate children from any spi device tables */ - scan_boardinfo(master); + mutex_lock(&board_lock); + list_add_tail(&master->list, &spi_master_list); + list_for_each_entry(bi, &board_list, list) + spi_match_master_to_boardinfo(master, &bi->board_info); + mutex_unlock(&board_lock); + status = 0; /* Register devices from the device tree */ @@ -579,7 +580,12 @@ void spi_unregister_master(struct spi_master *master) { int dummy; - dummy = device_for_each_child(&master->dev, NULL, __unregister); + mutex_lock(&board_lock); + list_del(&master->list); + mutex_unlock(&board_lock); + + dummy = device_for_each_child(master->dev.parent, &master->dev, + __unregister); device_unregister(&master->dev); } EXPORT_SYMBOL_GPL(spi_unregister_master); @@ -652,7 +658,7 @@ int spi_setup(struct spi_device *spi) */ bad_bits = spi->mode & ~spi->master->mode_bits; if (bad_bits) { - dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n", + dev_err(&spi->dev, "setup: unsupported mode bits %x\n", bad_bits); return -EINVAL; } diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index ab483a0ec6d..3f223511127 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -504,6 +504,15 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id) "in dma_irq_handler dmastat:0x%x spistat:0x%x\n", dmastat, spistat); + if (drv_data->rx != NULL) { + u16 cr = read_CTRL(drv_data); + /* discard old RX data and clear RXS */ + bfin_spi_dummy_read(drv_data); + write_CTRL(drv_data, cr & ~BIT_CTL_ENABLE); /* Disable SPI */ + write_CTRL(drv_data, cr & ~BIT_CTL_TIMOD); /* Restore State */ + write_STAT(drv_data, BIT_STAT_CLR); /* Clear Status */ + } + clear_dma_irqstat(drv_data->dma_channel); /* @@ -1099,12 +1108,15 @@ static int bfin_spi_setup(struct spi_device *spi) } if (chip->chip_select_num >= MAX_CTRL_CS) { - ret = gpio_request(chip->cs_gpio, spi->modalias); - if (ret) { - dev_err(&spi->dev, "gpio_request() error\n"); - goto pin_error; + /* Only request on first setup */ + if (spi_get_ctldata(spi) == NULL) { + ret = gpio_request(chip->cs_gpio, spi->modalias); + if (ret) { + dev_err(&spi->dev, "gpio_request() error\n"); + goto pin_error; + } + gpio_direction_output(chip->cs_gpio, 1); } - gpio_direction_output(chip->cs_gpio, 1); } dev_dbg(&spi->dev, "setup spi chip %s, width is %d, dma is %d\n", diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 92e52a1e6af..b4d7710bc38 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -204,6 +204,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) /** * struct spi_master - interface to SPI master controller * @dev: device interface to this driver + * @list: link with the global spi_master list * @bus_num: board-specific (and often SOC-specific) identifier for a * given SPI controller. * @num_chipselect: chipselects are used to distinguish individual @@ -238,6 +239,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) struct spi_master { struct device dev; + struct list_head list; + /* other than negative (== assign one dynamically), bus_num is fully * board-specific. usually that simplifies to being SOC-specific. * example: one SOC has three SPI controllers, numbered 0..2, |