From ac01e97d644da8e947ffa1bde5083290fe2e36e7 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 25 Mar 2009 00:18:35 +0000 Subject: spi/bfin_spi: fix resources leakage Re-order setup() a bit so we don't leak memory/dma/gpio resources upon errors. Also make sure we don't call kfree() twice on the same object. Signed-off-by: Daniel Mack Signed-off-by: Bryan Wu Signed-off-by: Yi Li Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 120 +++++++++++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 45 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 10a6dc3..4f20b92 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -1006,20 +1006,24 @@ static u16 ssel[][MAX_SPI_SSEL] = { /* first setup for new devices */ static int bfin_spi_setup(struct spi_device *spi) { - struct bfin5xx_spi_chip *chip_info = NULL; - struct chip_data *chip; + struct bfin5xx_spi_chip *chip_info; + struct chip_data *chip = NULL; struct driver_data *drv_data = spi_master_get_devdata(spi->master); - int ret; + int ret = -EINVAL; if (spi->bits_per_word != 8 && spi->bits_per_word != 16) - return -EINVAL; + goto error; /* Only alloc (or use chip_info) on first setup */ + chip_info = NULL; chip = spi_get_ctldata(spi); if (chip == NULL) { - chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); - if (!chip) - return -ENOMEM; + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) { + dev_err(&spi->dev, "cannot allocate chip data\n"); + ret = -ENOMEM; + goto error; + } chip->enable_dma = 0; chip_info = spi->controller_data; @@ -1036,7 +1040,7 @@ static int bfin_spi_setup(struct spi_device *spi) if (chip_info->ctl_reg & (SPE|MSTR|CPOL|CPHA|LSBF|SIZE)) { dev_err(&spi->dev, "do not set bits in ctl_reg " "that the SPI framework manages\n"); - return -EINVAL; + goto error; } chip->enable_dma = chip_info->enable_dma != 0 @@ -1060,26 +1064,6 @@ static int bfin_spi_setup(struct spi_device *spi) chip->ctl_reg |= MSTR; /* - * if any one SPI chip is registered and wants DMA, request the - * DMA channel for it - */ - if (chip->enable_dma && !drv_data->dma_requested) { - /* register dma irq handler */ - if (request_dma(drv_data->dma_channel, "BFIN_SPI_DMA") < 0) { - dev_dbg(&spi->dev, - "Unable to request BlackFin SPI DMA channel\n"); - return -ENODEV; - } - if (set_dma_callback(drv_data->dma_channel, - bfin_spi_dma_irq_handler, drv_data) < 0) { - dev_dbg(&spi->dev, "Unable to set dma callback\n"); - return -EPERM; - } - dma_disable_irq(drv_data->dma_channel); - drv_data->dma_requested = 1; - } - - /* * Notice: for blackfin, the speed_hz is the value of register * SPI_BAUD, not the real baudrate */ @@ -1087,16 +1071,6 @@ static int bfin_spi_setup(struct spi_device *spi) chip->flag = 1 << (spi->chip_select); chip->chip_select_num = spi->chip_select; - if (chip->chip_select_num == 0) { - ret = gpio_request(chip->cs_gpio, spi->modalias); - if (ret) { - if (drv_data->dma_requested) - free_dma(drv_data->dma_channel); - return ret; - } - gpio_direction_output(chip->cs_gpio, 1); - } - switch (chip->bits_per_word) { case 8: chip->n_bytes = 1; @@ -1123,9 +1097,39 @@ static int bfin_spi_setup(struct spi_device *spi) default: dev_err(&spi->dev, "%d bits_per_word is not supported\n", chip->bits_per_word); - if (chip_info) - kfree(chip); - return -ENODEV; + goto error; + } + + /* + * if any one SPI chip is registered and wants DMA, request the + * DMA channel for it + */ + if (chip->enable_dma && !drv_data->dma_requested) { + /* register dma irq handler */ + ret = request_dma(drv_data->dma_channel, "BFIN_SPI_DMA"); + if (ret) { + dev_err(&spi->dev, + "Unable to request BlackFin SPI DMA channel\n"); + goto error; + } + drv_data->dma_requested = 1; + + ret = set_dma_callback(drv_data->dma_channel, + bfin_spi_dma_irq_handler, drv_data); + if (ret) { + dev_err(&spi->dev, "Unable to set dma callback\n"); + goto error; + } + dma_disable_irq(drv_data->dma_channel); + } + + if (chip->chip_select_num == 0) { + 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); } dev_dbg(&spi->dev, "setup spi chip %s, width is %d, dma is %d\n", @@ -1136,14 +1140,38 @@ static int bfin_spi_setup(struct spi_device *spi) spi_set_ctldata(spi, chip); dev_dbg(&spi->dev, "chip select number is %d\n", chip->chip_select_num); - if ((chip->chip_select_num > 0) - && (chip->chip_select_num <= spi->master->num_chipselect)) - peripheral_request(ssel[spi->master->bus_num] - [chip->chip_select_num-1], spi->modalias); + if (chip->chip_select_num > 0 && + chip->chip_select_num <= spi->master->num_chipselect) { + ret = peripheral_request(ssel[spi->master->bus_num] + [chip->chip_select_num-1], spi->modalias); + if (ret) { + dev_err(&spi->dev, "peripheral_request() error\n"); + goto pin_error; + } + } bfin_spi_cs_deactive(drv_data, chip); return 0; + + pin_error: + if (chip->chip_select_num == 0) + gpio_free(chip->cs_gpio); + else + peripheral_free(ssel[spi->master->bus_num] + [chip->chip_select_num - 1]); + error: + if (chip) { + if (drv_data->dma_requested) + free_dma(drv_data->dma_channel); + drv_data->dma_requested = 0; + + kfree(chip); + /* prevent free 'chip' twice */ + spi_set_ctldata(spi, NULL); + } + + return ret; } /* @@ -1166,6 +1194,8 @@ static void bfin_spi_cleanup(struct spi_device *spi) gpio_free(chip->cs_gpio); kfree(chip); + /* prevent free 'chip' twice */ + spi_set_ctldata(spi, NULL); } static inline int bfin_spi_init_queue(struct driver_data *drv_data) -- cgit v1.1 From 60d0071b609ecb0aebe12aaedf34fe552da12c5b Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Mon, 18 May 2009 10:01:16 +0000 Subject: spi/bfin_spi: work around anomaly 05000119 Anomaly 05000119 states that the DMA_RUN bit with peripherals isn't reliable. However, the way the driver is currently written (DMA IRQ callback), we don't need the polling in the first place, so drop it. Signed-off-by: Sonic Zhang Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 4f20b92..61c2ebf 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -540,10 +540,6 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id) clear_dma_irqstat(drv_data->dma_channel); - /* Wait for DMA to complete */ - while (get_dma_curr_irqstat(drv_data->dma_channel) & DMA_RUN) - cpu_relax(); - /* * wait for the last transaction shifted out. HRM states: * at this point there may still be data in the SPI DMA FIFO waiting -- cgit v1.1 From bb8beecd98de45f821a3360e0b061fc1f8da947c Mon Sep 17 00:00:00 2001 From: Wolfgang Muees Date: Fri, 22 May 2009 01:11:02 +0000 Subject: spi/bfin_spi: force sane master-mode state at boot We should make sure the SPI controller is in a sane state in case the boot loader left it in a crappy state. Such as DMA pending which causes interrupts to fire on us. When setting a sane initial state, do not default to slave mode. If we do, then the SPI peripheral may implicitly take over the SPISS pin which other things might be using. For example, the BF533-STAMP uses this pin as a GPIO to control switching between ethernet and flash. If the SPI peripheral controls the output state instead, the ethernet is no longer accessible. URL: http://blackfin.uclinux.org/gf/tracker/5630 Signed-off-by: Wolfgang Muees Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 61c2ebf..b835254 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -1354,6 +1354,12 @@ static int __init bfin_spi_probe(struct platform_device *pdev) goto out_error_queue_alloc; } + /* Reset SPI registers. If these registers were used by the boot loader, + * the sky may fall on your head if you enable the dma controller. + */ + write_CTRL(drv_data, BIT_CTL_CPHA | BIT_CTL_MASTER); + write_FLAG(drv_data, 0xFF00); + /* Register with the SPI framework */ platform_set_drvdata(pdev, drv_data); status = spi_register_master(master); -- cgit v1.1 From f6a6d96685be6e784849d067b44acb831f595417 Mon Sep 17 00:00:00 2001 From: Yi Li Date: Wed, 3 Jun 2009 09:46:22 +0000 Subject: spi/bfin_spi: utilize the SPI interrupt in PIO mode The current behavior in PIO mode is to poll the SPI status registers which can obviously lead to higher latencies when doing a lot of SPI traffic. There is a SPI interrupt which can be used instead to signal individual completion of transactions. Signed-off-by: Yi Li Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 235 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 185 insertions(+), 50 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index b835254..3736c35 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -92,6 +92,9 @@ struct driver_data { dma_addr_t rx_dma; dma_addr_t tx_dma; + int irq_requested; + int spi_irq; + size_t rx_map_len; size_t tx_map_len; u8 n_bytes; @@ -115,6 +118,7 @@ struct chip_data { u16 cs_chg_udelay; /* Some devices require > 255usec delay */ u32 cs_gpio; u16 idle_tx_val; + u8 pio_interrupt; /* use spi data irq */ void (*write) (struct driver_data *); void (*read) (struct driver_data *); void (*duplex) (struct driver_data *); @@ -525,6 +529,79 @@ static void bfin_spi_giveback(struct driver_data *drv_data) msg->complete(msg->context); } +/* spi data irq handler */ +static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id) +{ + struct driver_data *drv_data = dev_id; + struct chip_data *chip = drv_data->cur_chip; + struct spi_message *msg = drv_data->cur_msg; + int n_bytes = drv_data->n_bytes; + + /* wait until transfer finished. */ + while (!(read_STAT(drv_data) & BIT_STAT_RXS)) + cpu_relax(); + + if ((drv_data->tx && drv_data->tx >= drv_data->tx_end) || + (drv_data->rx && drv_data->rx >= (drv_data->rx_end - n_bytes))) { + /* last read */ + if (drv_data->rx) { + dev_dbg(&drv_data->pdev->dev, "last read\n"); + if (n_bytes == 2) + *(u16 *) (drv_data->rx) = read_RDBR(drv_data); + else if (n_bytes == 1) + *(u8 *) (drv_data->rx) = read_RDBR(drv_data); + drv_data->rx += n_bytes; + } + + msg->actual_length += drv_data->len_in_bytes; + if (drv_data->cs_change) + bfin_spi_cs_deactive(drv_data, chip); + /* Move to next transfer */ + msg->state = bfin_spi_next_transfer(drv_data); + + disable_irq(drv_data->spi_irq); + + /* Schedule transfer tasklet */ + tasklet_schedule(&drv_data->pump_transfers); + return IRQ_HANDLED; + } + + if (drv_data->rx && drv_data->tx) { + /* duplex */ + dev_dbg(&drv_data->pdev->dev, "duplex: write_TDBR\n"); + if (drv_data->n_bytes == 2) { + *(u16 *) (drv_data->rx) = read_RDBR(drv_data); + write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); + } else if (drv_data->n_bytes == 1) { + *(u8 *) (drv_data->rx) = read_RDBR(drv_data); + write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); + } + } else if (drv_data->rx) { + /* read */ + dev_dbg(&drv_data->pdev->dev, "read: write_TDBR\n"); + if (drv_data->n_bytes == 2) + *(u16 *) (drv_data->rx) = read_RDBR(drv_data); + else if (drv_data->n_bytes == 1) + *(u8 *) (drv_data->rx) = read_RDBR(drv_data); + write_TDBR(drv_data, chip->idle_tx_val); + } else if (drv_data->tx) { + /* write */ + dev_dbg(&drv_data->pdev->dev, "write: write_TDBR\n"); + bfin_spi_dummy_read(drv_data); + if (drv_data->n_bytes == 2) + write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); + else if (drv_data->n_bytes == 1) + write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); + } + + if (drv_data->tx) + drv_data->tx += n_bytes; + if (drv_data->rx) + drv_data->rx += n_bytes; + + return IRQ_HANDLED; +} + static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id) { struct driver_data *drv_data = dev_id; @@ -700,6 +777,7 @@ static void bfin_spi_pump_transfers(unsigned long data) default: /* No change, the same as default setting */ + transfer->bits_per_word = chip->bits_per_word; drv_data->n_bytes = chip->n_bytes; width = chip->width; drv_data->write = drv_data->tx ? chip->write : bfin_spi_null_writer; @@ -842,60 +920,86 @@ static void bfin_spi_pump_transfers(unsigned long data) dma_enable_irq(drv_data->dma_channel); local_irq_restore(flags); - } else { - /* IO mode write then read */ - dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n"); + return; + } - /* we always use SPI_WRITE mode. SPI_READ mode - seems to have problems with setting up the - output value in TDBR prior to the transfer. */ + if (chip->pio_interrupt) { + /* use write mode. spi irq should have been disabled */ + cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD)); write_CTRL(drv_data, (cr | CFG_SPI_WRITE)); - if (full_duplex) { - /* full duplex mode */ - BUG_ON((drv_data->tx_end - drv_data->tx) != - (drv_data->rx_end - drv_data->rx)); - dev_dbg(&drv_data->pdev->dev, - "IO duplex: cr is 0x%x\n", cr); - - drv_data->duplex(drv_data); - - if (drv_data->tx != drv_data->tx_end) - tranf_success = 0; - } else if (drv_data->tx != NULL) { - /* write only half duplex */ - dev_dbg(&drv_data->pdev->dev, - "IO write: cr is 0x%x\n", cr); + /* discard old RX data and clear RXS */ + bfin_spi_dummy_read(drv_data); - drv_data->write(drv_data); + /* start transfer */ + if (drv_data->tx == NULL) + write_TDBR(drv_data, chip->idle_tx_val); + else { + if (transfer->bits_per_word == 8) + write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); + else if (transfer->bits_per_word == 16) + write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); + drv_data->tx += drv_data->n_bytes; + } - if (drv_data->tx != drv_data->tx_end) - tranf_success = 0; - } else if (drv_data->rx != NULL) { - /* read only half duplex */ - dev_dbg(&drv_data->pdev->dev, - "IO read: cr is 0x%x\n", cr); + /* once TDBR is empty, interrupt is triggered */ + enable_irq(drv_data->spi_irq); + return; + } - drv_data->read(drv_data); - if (drv_data->rx != drv_data->rx_end) - tranf_success = 0; - } + /* IO mode */ + dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n"); + + /* we always use SPI_WRITE mode. SPI_READ mode + seems to have problems with setting up the + output value in TDBR prior to the transfer. */ + write_CTRL(drv_data, (cr | CFG_SPI_WRITE)); + + if (full_duplex) { + /* full duplex mode */ + BUG_ON((drv_data->tx_end - drv_data->tx) != + (drv_data->rx_end - drv_data->rx)); + dev_dbg(&drv_data->pdev->dev, + "IO duplex: cr is 0x%x\n", cr); + + drv_data->duplex(drv_data); + + if (drv_data->tx != drv_data->tx_end) + tranf_success = 0; + } else if (drv_data->tx != NULL) { + /* write only half duplex */ + dev_dbg(&drv_data->pdev->dev, + "IO write: cr is 0x%x\n", cr); + + drv_data->write(drv_data); + + if (drv_data->tx != drv_data->tx_end) + tranf_success = 0; + } else if (drv_data->rx != NULL) { + /* read only half duplex */ + dev_dbg(&drv_data->pdev->dev, + "IO read: cr is 0x%x\n", cr); + + drv_data->read(drv_data); + if (drv_data->rx != drv_data->rx_end) + tranf_success = 0; + } - if (!tranf_success) { - dev_dbg(&drv_data->pdev->dev, - "IO write error!\n"); - message->state = ERROR_STATE; - } else { - /* Update total byte transfered */ - message->actual_length += drv_data->len_in_bytes; - /* Move to next transfer of this msg */ - message->state = bfin_spi_next_transfer(drv_data); - if (drv_data->cs_change) - bfin_spi_cs_deactive(drv_data, chip); - } - /* Schedule next transfer tasklet */ - tasklet_schedule(&drv_data->pump_transfers); + if (!tranf_success) { + dev_dbg(&drv_data->pdev->dev, + "IO write error!\n"); + message->state = ERROR_STATE; + } else { + /* Update total byte transfered */ + message->actual_length += drv_data->len_in_bytes; + /* Move to next transfer of this msg */ + message->state = bfin_spi_next_transfer(drv_data); + if (drv_data->cs_change) + bfin_spi_cs_deactive(drv_data, chip); } + + /* Schedule next transfer tasklet */ + tasklet_schedule(&drv_data->pump_transfers); } /* pop a msg from queue and kick off real transfer */ @@ -1047,6 +1151,7 @@ static int bfin_spi_setup(struct spi_device *spi) chip->cs_chg_udelay = chip_info->cs_chg_udelay; chip->cs_gpio = chip_info->cs_gpio; chip->idle_tx_val = chip_info->idle_tx_val; + chip->pio_interrupt = chip_info->pio_interrupt; } /* translate common spi framework into our register */ @@ -1096,6 +1201,11 @@ static int bfin_spi_setup(struct spi_device *spi) goto error; } + if (chip->enable_dma && chip->pio_interrupt) { + dev_err(&spi->dev, "enable_dma is set, " + "do not set pio_interrupt\n"); + goto error; + } /* * if any one SPI chip is registered and wants DMA, request the * DMA channel for it @@ -1119,6 +1229,18 @@ static int bfin_spi_setup(struct spi_device *spi) dma_disable_irq(drv_data->dma_channel); } + if (chip->pio_interrupt && !drv_data->irq_requested) { + ret = request_irq(drv_data->spi_irq, bfin_spi_pio_irq_handler, + IRQF_DISABLED, "BFIN_SPI", drv_data); + if (ret) { + dev_err(&spi->dev, "Unable to register spi IRQ\n"); + goto error; + } + drv_data->irq_requested = 1; + /* we use write mode, spi irq has to be disabled here */ + disable_irq(drv_data->spi_irq); + } + if (chip->chip_select_num == 0) { ret = gpio_request(chip->cs_gpio, spi->modalias); if (ret) { @@ -1328,11 +1450,19 @@ static int __init bfin_spi_probe(struct platform_device *pdev) goto out_error_ioremap; } - drv_data->dma_channel = platform_get_irq(pdev, 0); - if (drv_data->dma_channel < 0) { + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (res == NULL) { dev_err(dev, "No DMA channel specified\n"); status = -ENOENT; - goto out_error_no_dma_ch; + goto out_error_free_io; + } + drv_data->dma_channel = res->start; + + drv_data->spi_irq = platform_get_irq(pdev, 0); + if (drv_data->spi_irq < 0) { + dev_err(dev, "No spi pio irq specified\n"); + status = -ENOENT; + goto out_error_free_io; } /* Initial and start queue */ @@ -1375,7 +1505,7 @@ static int __init bfin_spi_probe(struct platform_device *pdev) out_error_queue_alloc: bfin_spi_destroy_queue(drv_data); -out_error_no_dma_ch: +out_error_free_io: iounmap((void *) drv_data->regs_base); out_error_ioremap: out_error_get_res: @@ -1407,6 +1537,11 @@ static int __devexit bfin_spi_remove(struct platform_device *pdev) free_dma(drv_data->dma_channel); } + if (drv_data->irq_requested) { + free_irq(drv_data->spi_irq, drv_data); + drv_data->irq_requested = 0; + } + /* Disconnect from the SPI framework */ spi_unregister_master(drv_data->master); -- cgit v1.1 From 8221610e9990e7ee542a4e508d278302af8a9e75 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 17 Jun 2009 10:10:53 +0000 Subject: spi/bfin_spi: fix CS handling The CS helper functions were toggling both the Flag Enable and the Flag Value bits, but the Flag Value bit is ignored if the corresponding Flag Enable bit is cleared. So under high speed transactions, the CS sometimes would not toggle properly. Since it makes no sense to toggle the Flag Enable bit dynamically when we actually want to control the Flag Value, do this when setting up the device and then only handle toggling of the CS value during runtime. Signed-off-by: Barry Song Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 3736c35..6150a8c 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -188,8 +188,7 @@ static void bfin_spi_cs_active(struct driver_data *drv_data, struct chip_data *c if (likely(chip->chip_select_num)) { u16 flag = read_FLAG(drv_data); - flag |= chip->flag; - flag &= ~(chip->flag << 8); + flag &= ~chip->flag; write_FLAG(drv_data, flag); } else { @@ -202,8 +201,7 @@ static void bfin_spi_cs_deactive(struct driver_data *drv_data, struct chip_data if (likely(chip->chip_select_num)) { u16 flag = read_FLAG(drv_data); - flag &= ~chip->flag; - flag |= (chip->flag << 8); + flag |= chip->flag; write_FLAG(drv_data, flag); } else { @@ -215,6 +213,25 @@ static void bfin_spi_cs_deactive(struct driver_data *drv_data, struct chip_data udelay(chip->cs_chg_udelay); } +/* enable or disable the pin muxed by GPIO and SPI CS to work as SPI CS */ +static inline void bfin_spi_cs_enable(struct driver_data *drv_data, struct chip_data *chip) +{ + u16 flag = read_FLAG(drv_data); + + flag |= (chip->flag >> 8); + + write_FLAG(drv_data, flag); +} + +static inline void bfin_spi_cs_disable(struct driver_data *drv_data, struct chip_data *chip) +{ + u16 flag = read_FLAG(drv_data); + + flag &= ~(chip->flag >> 8); + + write_FLAG(drv_data, flag); +} + /* stop controller and re-config current chip*/ static void bfin_spi_restore_state(struct driver_data *drv_data) { @@ -1169,7 +1186,7 @@ static int bfin_spi_setup(struct spi_device *spi) * SPI_BAUD, not the real baudrate */ chip->baud = hz_to_spi_baud(spi->max_speed_hz); - chip->flag = 1 << (spi->chip_select); + chip->flag = (1 << (spi->chip_select)) << 8; chip->chip_select_num = spi->chip_select; switch (chip->bits_per_word) { @@ -1268,6 +1285,7 @@ static int bfin_spi_setup(struct spi_device *spi) } } + bfin_spi_cs_enable(drv_data, chip); bfin_spi_cs_deactive(drv_data, chip); return 0; @@ -1299,14 +1317,17 @@ static int bfin_spi_setup(struct spi_device *spi) static void bfin_spi_cleanup(struct spi_device *spi) { struct chip_data *chip = spi_get_ctldata(spi); + struct driver_data *drv_data = spi_master_get_devdata(spi->master); if (!chip) return; if ((chip->chip_select_num > 0) - && (chip->chip_select_num <= spi->master->num_chipselect)) + && (chip->chip_select_num <= spi->master->num_chipselect)) { peripheral_free(ssel[spi->master->bus_num] [chip->chip_select_num-1]); + bfin_spi_cs_disable(drv_data, chip); + } if (chip->chip_select_num == 0) gpio_free(chip->cs_gpio); -- cgit v1.1 From 201bbc6fd84c67b4021f454d3e4c30d5cd77f702 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 23 Sep 2009 20:56:10 +0000 Subject: spi/bfin_spi: drop custom cs_change_per_word support As David points out, the cs_change_per_word option isn't standard, nor is anyone actually using it. So punt all of the dead code considering it makes up ~10% of the code size. Reported-by: David Brownell Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 148 ++++------------------------------------------ 1 file changed, 12 insertions(+), 136 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 6150a8c..f4023a7 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -114,7 +114,6 @@ struct chip_data { u8 width; /* 0 or 1 */ u8 enable_dma; u8 bits_per_word; /* 8 or 16 */ - u8 cs_change_per_word; u16 cs_chg_udelay; /* Some devices require > 255usec delay */ u32 cs_gpio; u16 idle_tx_val; @@ -309,24 +308,6 @@ static void bfin_spi_u8_writer(struct driver_data *drv_data) } } -static void bfin_spi_u8_cs_chg_writer(struct driver_data *drv_data) -{ - struct chip_data *chip = drv_data->cur_chip; - - /* clear RXS (we check for RXS inside the loop) */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->tx < drv_data->tx_end) { - bfin_spi_cs_active(drv_data, chip); - write_TDBR(drv_data, (*(u8 *) (drv_data->tx++))); - /* make sure transfer finished before deactiving CS */ - while (!(read_STAT(drv_data) & BIT_STAT_RXS)) - cpu_relax(); - bfin_spi_dummy_read(drv_data); - bfin_spi_cs_deactive(drv_data, chip); - } -} - static void bfin_spi_u8_reader(struct driver_data *drv_data) { u16 tx_val = drv_data->cur_chip->idle_tx_val; @@ -342,24 +323,6 @@ static void bfin_spi_u8_reader(struct driver_data *drv_data) } } -static void bfin_spi_u8_cs_chg_reader(struct driver_data *drv_data) -{ - struct chip_data *chip = drv_data->cur_chip; - u16 tx_val = chip->idle_tx_val; - - /* discard old RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->rx < drv_data->rx_end) { - bfin_spi_cs_active(drv_data, chip); - write_TDBR(drv_data, tx_val); - while (!(read_STAT(drv_data) & BIT_STAT_RXS)) - cpu_relax(); - *(u8 *) (drv_data->rx++) = read_RDBR(drv_data); - bfin_spi_cs_deactive(drv_data, chip); - } -} - static void bfin_spi_u8_duplex(struct driver_data *drv_data) { /* discard old RX data and clear RXS */ @@ -373,23 +336,6 @@ static void bfin_spi_u8_duplex(struct driver_data *drv_data) } } -static void bfin_spi_u8_cs_chg_duplex(struct driver_data *drv_data) -{ - struct chip_data *chip = drv_data->cur_chip; - - /* discard old RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->rx < drv_data->rx_end) { - bfin_spi_cs_active(drv_data, chip); - write_TDBR(drv_data, (*(u8 *) (drv_data->tx++))); - while (!(read_STAT(drv_data) & BIT_STAT_RXS)) - cpu_relax(); - *(u8 *) (drv_data->rx++) = read_RDBR(drv_data); - bfin_spi_cs_deactive(drv_data, chip); - } -} - static void bfin_spi_u16_writer(struct driver_data *drv_data) { /* clear RXS (we check for RXS inside the loop) */ @@ -407,25 +353,6 @@ static void bfin_spi_u16_writer(struct driver_data *drv_data) } } -static void bfin_spi_u16_cs_chg_writer(struct driver_data *drv_data) -{ - struct chip_data *chip = drv_data->cur_chip; - - /* clear RXS (we check for RXS inside the loop) */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->tx < drv_data->tx_end) { - bfin_spi_cs_active(drv_data, chip); - write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); - drv_data->tx += 2; - /* make sure transfer finished before deactiving CS */ - while (!(read_STAT(drv_data) & BIT_STAT_RXS)) - cpu_relax(); - bfin_spi_dummy_read(drv_data); - bfin_spi_cs_deactive(drv_data, chip); - } -} - static void bfin_spi_u16_reader(struct driver_data *drv_data) { u16 tx_val = drv_data->cur_chip->idle_tx_val; @@ -442,25 +369,6 @@ static void bfin_spi_u16_reader(struct driver_data *drv_data) } } -static void bfin_spi_u16_cs_chg_reader(struct driver_data *drv_data) -{ - struct chip_data *chip = drv_data->cur_chip; - u16 tx_val = chip->idle_tx_val; - - /* discard old RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->rx < drv_data->rx_end) { - bfin_spi_cs_active(drv_data, chip); - write_TDBR(drv_data, tx_val); - while (!(read_STAT(drv_data) & BIT_STAT_RXS)) - cpu_relax(); - *(u16 *) (drv_data->rx) = read_RDBR(drv_data); - drv_data->rx += 2; - bfin_spi_cs_deactive(drv_data, chip); - } -} - static void bfin_spi_u16_duplex(struct driver_data *drv_data) { /* discard old RX data and clear RXS */ @@ -476,25 +384,6 @@ static void bfin_spi_u16_duplex(struct driver_data *drv_data) } } -static void bfin_spi_u16_cs_chg_duplex(struct driver_data *drv_data) -{ - struct chip_data *chip = drv_data->cur_chip; - - /* discard old RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->rx < drv_data->rx_end) { - bfin_spi_cs_active(drv_data, chip); - write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); - drv_data->tx += 2; - while (!(read_STAT(drv_data) & BIT_STAT_RXS)) - cpu_relax(); - *(u16 *) (drv_data->rx) = read_RDBR(drv_data); - drv_data->rx += 2; - bfin_spi_cs_deactive(drv_data, chip); - } -} - /* test if ther is more transfer to be done */ static void *bfin_spi_next_transfer(struct driver_data *drv_data) { @@ -773,23 +662,17 @@ static void bfin_spi_pump_transfers(unsigned long data) case 8: drv_data->n_bytes = 1; width = CFG_SPI_WORDSIZE8; - drv_data->read = chip->cs_change_per_word ? - bfin_spi_u8_cs_chg_reader : bfin_spi_u8_reader; - drv_data->write = chip->cs_change_per_word ? - bfin_spi_u8_cs_chg_writer : bfin_spi_u8_writer; - drv_data->duplex = chip->cs_change_per_word ? - bfin_spi_u8_cs_chg_duplex : bfin_spi_u8_duplex; + drv_data->read = bfin_spi_u8_reader; + drv_data->write = bfin_spi_u8_writer; + drv_data->duplex = bfin_spi_u8_duplex; break; case 16: drv_data->n_bytes = 2; width = CFG_SPI_WORDSIZE16; - drv_data->read = chip->cs_change_per_word ? - bfin_spi_u16_cs_chg_reader : bfin_spi_u16_reader; - drv_data->write = chip->cs_change_per_word ? - bfin_spi_u16_cs_chg_writer : bfin_spi_u16_writer; - drv_data->duplex = chip->cs_change_per_word ? - bfin_spi_u16_cs_chg_duplex : bfin_spi_u16_duplex; + drv_data->read = bfin_spi_u16_reader; + drv_data->write = bfin_spi_u16_writer; + drv_data->duplex = bfin_spi_u16_duplex; break; default: @@ -1164,7 +1047,6 @@ static int bfin_spi_setup(struct spi_device *spi) && drv_data->master_info->enable_dma; chip->ctl_reg = chip_info->ctl_reg; chip->bits_per_word = chip_info->bits_per_word; - chip->cs_change_per_word = chip_info->cs_change_per_word; chip->cs_chg_udelay = chip_info->cs_chg_udelay; chip->cs_gpio = chip_info->cs_gpio; chip->idle_tx_val = chip_info->idle_tx_val; @@ -1193,23 +1075,17 @@ static int bfin_spi_setup(struct spi_device *spi) case 8: chip->n_bytes = 1; chip->width = CFG_SPI_WORDSIZE8; - chip->read = chip->cs_change_per_word ? - bfin_spi_u8_cs_chg_reader : bfin_spi_u8_reader; - chip->write = chip->cs_change_per_word ? - bfin_spi_u8_cs_chg_writer : bfin_spi_u8_writer; - chip->duplex = chip->cs_change_per_word ? - bfin_spi_u8_cs_chg_duplex : bfin_spi_u8_duplex; + chip->read = bfin_spi_u8_reader; + chip->write = bfin_spi_u8_writer; + chip->duplex = bfin_spi_u8_duplex; break; case 16: chip->n_bytes = 2; chip->width = CFG_SPI_WORDSIZE16; - chip->read = chip->cs_change_per_word ? - bfin_spi_u16_cs_chg_reader : bfin_spi_u16_reader; - chip->write = chip->cs_change_per_word ? - bfin_spi_u16_cs_chg_writer : bfin_spi_u16_writer; - chip->duplex = chip->cs_change_per_word ? - bfin_spi_u16_cs_chg_duplex : bfin_spi_u16_duplex; + chip->read = bfin_spi_u16_reader; + chip->write = bfin_spi_u16_writer; + chip->duplex = bfin_spi_u16_duplex; break; default: -- cgit v1.1 From 5cc0159a5779f297d1b987d5f6d0feb6dc36a27a Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 23 Sep 2009 23:24:59 +0000 Subject: spi/bfin_spi: punt useless null read/write funcs The chip ops should always be initialized, so having null fallback functions are useless. Reported-by: David Brownell Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 47 +++++------------------------------------------ 1 file changed, 5 insertions(+), 42 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index f4023a7..5e07f49 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -255,43 +255,6 @@ static inline void bfin_spi_dummy_read(struct driver_data *drv_data) (void) read_RDBR(drv_data); } -static void bfin_spi_null_writer(struct driver_data *drv_data) -{ - u8 n_bytes = drv_data->n_bytes; - u16 tx_val = drv_data->cur_chip->idle_tx_val; - - /* clear RXS (we check for RXS inside the loop) */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->tx < drv_data->tx_end) { - write_TDBR(drv_data, tx_val); - drv_data->tx += n_bytes; - /* wait until transfer finished. - checking SPIF or TXS may not guarantee transfer completion */ - while (!(read_STAT(drv_data) & BIT_STAT_RXS)) - cpu_relax(); - /* discard RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - } -} - -static void bfin_spi_null_reader(struct driver_data *drv_data) -{ - u8 n_bytes = drv_data->n_bytes; - u16 tx_val = drv_data->cur_chip->idle_tx_val; - - /* discard old RX data and clear RXS */ - bfin_spi_dummy_read(drv_data); - - while (drv_data->rx < drv_data->rx_end) { - write_TDBR(drv_data, tx_val); - drv_data->rx += n_bytes; - while (!(read_STAT(drv_data) & BIT_STAT_RXS)) - cpu_relax(); - bfin_spi_dummy_read(drv_data); - } -} - static void bfin_spi_u8_writer(struct driver_data *drv_data) { /* clear RXS (we check for RXS inside the loop) */ @@ -680,9 +643,9 @@ static void bfin_spi_pump_transfers(unsigned long data) transfer->bits_per_word = chip->bits_per_word; drv_data->n_bytes = chip->n_bytes; width = chip->width; - drv_data->write = drv_data->tx ? chip->write : bfin_spi_null_writer; - drv_data->read = drv_data->rx ? chip->read : bfin_spi_null_reader; - drv_data->duplex = chip->duplex ? chip->duplex : bfin_spi_null_writer; + drv_data->write = chip->write; + drv_data->read = chip->read; + drv_data->duplex = chip->duplex; break; } cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD)); @@ -695,8 +658,8 @@ static void bfin_spi_pump_transfers(unsigned long data) drv_data->len = transfer->len; } dev_dbg(&drv_data->pdev->dev, - "transfer: drv_data->write is %p, chip->write is %p, null_wr is %p\n", - drv_data->write, chip->write, bfin_spi_null_writer); + "transfer: drv_data->write is %p, chip->write is %p\n", + drv_data->write, chip->write); /* speed and width has been set on per message */ message->state = RUNNING_STATE; -- cgit v1.1 From ab09e0406ffd42d26fc9a6dcbb626f9eb1da9160 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 23 Sep 2009 23:32:34 +0000 Subject: spi/bfin_spi: fix up some unused/misleading comments Reported-by: David Brownell Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 5e07f49..045c82a 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -44,9 +44,6 @@ MODULE_LICENSE("GPL"); #define QUEUE_RUNNING 0 #define QUEUE_STOPPED 1 -/* Value to send if no TX value is supplied */ -#define SPI_IDLE_TXVAL 0x0000 - struct driver_data { /* Driver model hookup */ struct platform_device *pdev; @@ -581,7 +578,7 @@ static void bfin_spi_pump_transfers(unsigned long data) udelay(previous->delay_usecs); } - /* Setup the transfer state based on the type of transfer */ + /* Flush any existing transfers that may be sitting in the hardware */ if (bfin_spi_flush(drv_data) == 0) { dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n"); message->status = -EIO; @@ -661,7 +658,6 @@ static void bfin_spi_pump_transfers(unsigned long data) "transfer: drv_data->write is %p, chip->write is %p\n", drv_data->write, chip->write); - /* speed and width has been set on per message */ message->state = RUNNING_STATE; dma_config = 0; @@ -966,7 +962,7 @@ static u16 ssel[][MAX_SPI_SSEL] = { P_SPI2_SSEL6, P_SPI2_SSEL7}, }; -/* first setup for new devices */ +/* setup for devices (may be called multiple times -- not just first setup) */ static int bfin_spi_setup(struct spi_device *spi) { struct bfin5xx_spi_chip *chip_info; -- cgit v1.1 From f4f50c3ff7815d83dcbb19341f35db2f408ac4f8 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 24 Sep 2009 00:41:49 +0000 Subject: spi/bfin_spi: convert queue run state to true/false No point in creating our own version of true/false defines when there is already a standard stdbool available to us. Reported-by: David Brownell Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 045c82a..40d9f64 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -41,8 +41,6 @@ MODULE_LICENSE("GPL"); #define RUNNING_STATE ((void *)1) #define DONE_STATE ((void *)2) #define ERROR_STATE ((void *)-1) -#define QUEUE_RUNNING 0 -#define QUEUE_STOPPED 1 struct driver_data { /* Driver model hookup */ @@ -66,7 +64,7 @@ struct driver_data { spinlock_t lock; struct list_head queue; int busy; - int run; + bool running; /* Message Transfer pump */ struct tasklet_struct pump_transfers; @@ -871,7 +869,7 @@ static void bfin_spi_pump_messages(struct work_struct *work) /* Lock queue and check for queue work */ spin_lock_irqsave(&drv_data->lock, flags); - if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) { + if (list_empty(&drv_data->queue) || !drv_data->running) { /* pumper kicked off but no work to do */ drv_data->busy = 0; spin_unlock_irqrestore(&drv_data->lock, flags); @@ -926,7 +924,7 @@ static int bfin_spi_transfer(struct spi_device *spi, struct spi_message *msg) spin_lock_irqsave(&drv_data->lock, flags); - if (drv_data->run == QUEUE_STOPPED) { + if (!drv_data->running) { spin_unlock_irqrestore(&drv_data->lock, flags); return -ESHUTDOWN; } @@ -938,7 +936,7 @@ static int bfin_spi_transfer(struct spi_device *spi, struct spi_message *msg) dev_dbg(&spi->dev, "adding an msg in transfer() \n"); list_add_tail(&msg->queue, &drv_data->queue); - if (drv_data->run == QUEUE_RUNNING && !drv_data->busy) + if (drv_data->running && !drv_data->busy) queue_work(drv_data->workqueue, &drv_data->pump_messages); spin_unlock_irqrestore(&drv_data->lock, flags); @@ -1177,7 +1175,7 @@ static inline int bfin_spi_init_queue(struct driver_data *drv_data) INIT_LIST_HEAD(&drv_data->queue); spin_lock_init(&drv_data->lock); - drv_data->run = QUEUE_STOPPED; + drv_data->running = false; drv_data->busy = 0; /* init transfer tasklet */ @@ -1200,12 +1198,12 @@ static inline int bfin_spi_start_queue(struct driver_data *drv_data) spin_lock_irqsave(&drv_data->lock, flags); - if (drv_data->run == QUEUE_RUNNING || drv_data->busy) { + if (drv_data->running || drv_data->busy) { spin_unlock_irqrestore(&drv_data->lock, flags); return -EBUSY; } - drv_data->run = QUEUE_RUNNING; + drv_data->running = true; drv_data->cur_msg = NULL; drv_data->cur_transfer = NULL; drv_data->cur_chip = NULL; @@ -1230,7 +1228,7 @@ static inline int bfin_spi_stop_queue(struct driver_data *drv_data) * execution path (pump_messages) would be required to call wake_up or * friends on every SPI message. Do this instead */ - drv_data->run = QUEUE_STOPPED; + drv_data->running = false; while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) { spin_unlock_irqrestore(&drv_data->lock, flags); msleep(10); -- cgit v1.1 From 9c4542c7a3082bf74f00145355ef407ac82c0b3f Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 24 Sep 2009 01:04:04 +0000 Subject: spi/bfin_spi: convert read/write/duplex funcs to a dedicated ops structure Rather than having to look up the same 3 sets of functions at the same time, just use an ops structure so we only need to set one pointer. Reported-by: David Brownell Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 58 ++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 26 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 40d9f64..b0de61a 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -42,6 +42,14 @@ MODULE_LICENSE("GPL"); #define DONE_STATE ((void *)2) #define ERROR_STATE ((void *)-1) +struct driver_data; + +struct transfer_ops { + void (*write) (struct driver_data *); + void (*read) (struct driver_data *); + void (*duplex) (struct driver_data *); +}; + struct driver_data { /* Driver model hookup */ struct platform_device *pdev; @@ -94,9 +102,7 @@ struct driver_data { size_t tx_map_len; u8 n_bytes; int cs_change; - void (*write) (struct driver_data *); - void (*read) (struct driver_data *); - void (*duplex) (struct driver_data *); + const struct transfer_ops *ops; }; struct chip_data { @@ -113,9 +119,7 @@ struct chip_data { u32 cs_gpio; u16 idle_tx_val; u8 pio_interrupt; /* use spi data irq */ - void (*write) (struct driver_data *); - void (*read) (struct driver_data *); - void (*duplex) (struct driver_data *); + const struct transfer_ops *ops; }; #define DEFINE_SPI_REG(reg, off) \ @@ -294,6 +298,12 @@ static void bfin_spi_u8_duplex(struct driver_data *drv_data) } } +static const struct transfer_ops bfin_transfer_ops_u8 = { + .write = bfin_spi_u8_writer, + .read = bfin_spi_u8_reader, + .duplex = bfin_spi_u8_duplex, +}; + static void bfin_spi_u16_writer(struct driver_data *drv_data) { /* clear RXS (we check for RXS inside the loop) */ @@ -342,6 +352,12 @@ static void bfin_spi_u16_duplex(struct driver_data *drv_data) } } +static const struct transfer_ops bfin_transfer_ops_u16 = { + .write = bfin_spi_u16_writer, + .read = bfin_spi_u16_reader, + .duplex = bfin_spi_u16_duplex, +}; + /* test if ther is more transfer to be done */ static void *bfin_spi_next_transfer(struct driver_data *drv_data) { @@ -620,17 +636,13 @@ static void bfin_spi_pump_transfers(unsigned long data) case 8: drv_data->n_bytes = 1; width = CFG_SPI_WORDSIZE8; - drv_data->read = bfin_spi_u8_reader; - drv_data->write = bfin_spi_u8_writer; - drv_data->duplex = bfin_spi_u8_duplex; + drv_data->ops = &bfin_transfer_ops_u8; break; case 16: drv_data->n_bytes = 2; width = CFG_SPI_WORDSIZE16; - drv_data->read = bfin_spi_u16_reader; - drv_data->write = bfin_spi_u16_writer; - drv_data->duplex = bfin_spi_u16_duplex; + drv_data->ops = &bfin_transfer_ops_u16; break; default: @@ -638,9 +650,7 @@ static void bfin_spi_pump_transfers(unsigned long data) transfer->bits_per_word = chip->bits_per_word; drv_data->n_bytes = chip->n_bytes; width = chip->width; - drv_data->write = chip->write; - drv_data->read = chip->read; - drv_data->duplex = chip->duplex; + drv_data->ops = chip->ops; break; } cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD)); @@ -653,8 +663,8 @@ static void bfin_spi_pump_transfers(unsigned long data) drv_data->len = transfer->len; } dev_dbg(&drv_data->pdev->dev, - "transfer: drv_data->write is %p, chip->write is %p\n", - drv_data->write, chip->write); + "transfer: drv_data->ops is %p, chip->ops is %p, u8_ops is %p\n", + drv_data->ops, chip->ops, &bfin_transfer_ops_u8); message->state = RUNNING_STATE; dma_config = 0; @@ -819,7 +829,7 @@ static void bfin_spi_pump_transfers(unsigned long data) dev_dbg(&drv_data->pdev->dev, "IO duplex: cr is 0x%x\n", cr); - drv_data->duplex(drv_data); + drv_data->ops->duplex(drv_data); if (drv_data->tx != drv_data->tx_end) tranf_success = 0; @@ -828,7 +838,7 @@ static void bfin_spi_pump_transfers(unsigned long data) dev_dbg(&drv_data->pdev->dev, "IO write: cr is 0x%x\n", cr); - drv_data->write(drv_data); + drv_data->ops->write(drv_data); if (drv_data->tx != drv_data->tx_end) tranf_success = 0; @@ -837,7 +847,7 @@ static void bfin_spi_pump_transfers(unsigned long data) dev_dbg(&drv_data->pdev->dev, "IO read: cr is 0x%x\n", cr); - drv_data->read(drv_data); + drv_data->ops->read(drv_data); if (drv_data->rx != drv_data->rx_end) tranf_success = 0; } @@ -1032,17 +1042,13 @@ static int bfin_spi_setup(struct spi_device *spi) case 8: chip->n_bytes = 1; chip->width = CFG_SPI_WORDSIZE8; - chip->read = bfin_spi_u8_reader; - chip->write = bfin_spi_u8_writer; - chip->duplex = bfin_spi_u8_duplex; + chip->ops = &bfin_transfer_ops_u8; break; case 16: chip->n_bytes = 2; chip->width = CFG_SPI_WORDSIZE16; - chip->read = bfin_spi_u16_reader; - chip->write = bfin_spi_u16_writer; - chip->duplex = bfin_spi_u16_duplex; + chip->ops = &bfin_transfer_ops_u16; break; default: -- cgit v1.1 From b9f139a7a6a8b24e61ad94c3334eb26f34a4cb63 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 24 Sep 2009 01:27:47 +0000 Subject: spi/bfin_spi: convert struct names to something more logical The current structure names are a bit confusing as to what they represent, so use better names. Reported-by: David Brownell Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 100 +++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 50 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index b0de61a..9a1801b 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -42,15 +42,15 @@ MODULE_LICENSE("GPL"); #define DONE_STATE ((void *)2) #define ERROR_STATE ((void *)-1) -struct driver_data; +struct master_data; struct transfer_ops { - void (*write) (struct driver_data *); - void (*read) (struct driver_data *); - void (*duplex) (struct driver_data *); + void (*write) (struct master_data *); + void (*read) (struct master_data *); + void (*duplex) (struct master_data *); }; -struct driver_data { +struct master_data { /* Driver model hookup */ struct platform_device *pdev; @@ -80,7 +80,7 @@ struct driver_data { /* Current message transfer state info */ struct spi_message *cur_msg; struct spi_transfer *cur_transfer; - struct chip_data *cur_chip; + struct slave_data *cur_chip; size_t len_in_bytes; size_t len; void *tx; @@ -105,7 +105,7 @@ struct driver_data { const struct transfer_ops *ops; }; -struct chip_data { +struct slave_data { u16 ctl_reg; u16 baud; u16 flag; @@ -123,9 +123,9 @@ struct chip_data { }; #define DEFINE_SPI_REG(reg, off) \ -static inline u16 read_##reg(struct driver_data *drv_data) \ +static inline u16 read_##reg(struct master_data *drv_data) \ { return bfin_read16(drv_data->regs_base + off); } \ -static inline void write_##reg(struct driver_data *drv_data, u16 v) \ +static inline void write_##reg(struct master_data *drv_data, u16 v) \ { bfin_write16(drv_data->regs_base + off, v); } DEFINE_SPI_REG(CTRL, 0x00) @@ -136,7 +136,7 @@ DEFINE_SPI_REG(RDBR, 0x10) DEFINE_SPI_REG(BAUD, 0x14) DEFINE_SPI_REG(SHAW, 0x18) -static void bfin_spi_enable(struct driver_data *drv_data) +static void bfin_spi_enable(struct master_data *drv_data) { u16 cr; @@ -144,7 +144,7 @@ static void bfin_spi_enable(struct driver_data *drv_data) write_CTRL(drv_data, (cr | BIT_CTL_ENABLE)); } -static void bfin_spi_disable(struct driver_data *drv_data) +static void bfin_spi_disable(struct master_data *drv_data) { u16 cr; @@ -167,7 +167,7 @@ static u16 hz_to_spi_baud(u32 speed_hz) return spi_baud; } -static int bfin_spi_flush(struct driver_data *drv_data) +static int bfin_spi_flush(struct master_data *drv_data) { unsigned long limit = loops_per_jiffy << 1; @@ -181,7 +181,7 @@ static int bfin_spi_flush(struct driver_data *drv_data) } /* Chip select operation functions for cs_change flag */ -static void bfin_spi_cs_active(struct driver_data *drv_data, struct chip_data *chip) +static void bfin_spi_cs_active(struct master_data *drv_data, struct slave_data *chip) { if (likely(chip->chip_select_num)) { u16 flag = read_FLAG(drv_data); @@ -194,7 +194,7 @@ static void bfin_spi_cs_active(struct driver_data *drv_data, struct chip_data *c } } -static void bfin_spi_cs_deactive(struct driver_data *drv_data, struct chip_data *chip) +static void bfin_spi_cs_deactive(struct master_data *drv_data, struct slave_data *chip) { if (likely(chip->chip_select_num)) { u16 flag = read_FLAG(drv_data); @@ -212,7 +212,7 @@ static void bfin_spi_cs_deactive(struct driver_data *drv_data, struct chip_data } /* enable or disable the pin muxed by GPIO and SPI CS to work as SPI CS */ -static inline void bfin_spi_cs_enable(struct driver_data *drv_data, struct chip_data *chip) +static inline void bfin_spi_cs_enable(struct master_data *drv_data, struct slave_data *chip) { u16 flag = read_FLAG(drv_data); @@ -221,7 +221,7 @@ static inline void bfin_spi_cs_enable(struct driver_data *drv_data, struct chip_ write_FLAG(drv_data, flag); } -static inline void bfin_spi_cs_disable(struct driver_data *drv_data, struct chip_data *chip) +static inline void bfin_spi_cs_disable(struct master_data *drv_data, struct slave_data *chip) { u16 flag = read_FLAG(drv_data); @@ -231,9 +231,9 @@ static inline void bfin_spi_cs_disable(struct driver_data *drv_data, struct chip } /* stop controller and re-config current chip*/ -static void bfin_spi_restore_state(struct driver_data *drv_data) +static void bfin_spi_restore_state(struct master_data *drv_data) { - struct chip_data *chip = drv_data->cur_chip; + struct slave_data *chip = drv_data->cur_chip; /* Clear status and disable clock */ write_STAT(drv_data, BIT_STAT_CLR); @@ -249,12 +249,12 @@ static void bfin_spi_restore_state(struct driver_data *drv_data) } /* used to kick off transfer in rx mode and read unwanted RX data */ -static inline void bfin_spi_dummy_read(struct driver_data *drv_data) +static inline void bfin_spi_dummy_read(struct master_data *drv_data) { (void) read_RDBR(drv_data); } -static void bfin_spi_u8_writer(struct driver_data *drv_data) +static void bfin_spi_u8_writer(struct master_data *drv_data) { /* clear RXS (we check for RXS inside the loop) */ bfin_spi_dummy_read(drv_data); @@ -270,7 +270,7 @@ static void bfin_spi_u8_writer(struct driver_data *drv_data) } } -static void bfin_spi_u8_reader(struct driver_data *drv_data) +static void bfin_spi_u8_reader(struct master_data *drv_data) { u16 tx_val = drv_data->cur_chip->idle_tx_val; @@ -285,7 +285,7 @@ static void bfin_spi_u8_reader(struct driver_data *drv_data) } } -static void bfin_spi_u8_duplex(struct driver_data *drv_data) +static void bfin_spi_u8_duplex(struct master_data *drv_data) { /* discard old RX data and clear RXS */ bfin_spi_dummy_read(drv_data); @@ -304,7 +304,7 @@ static const struct transfer_ops bfin_transfer_ops_u8 = { .duplex = bfin_spi_u8_duplex, }; -static void bfin_spi_u16_writer(struct driver_data *drv_data) +static void bfin_spi_u16_writer(struct master_data *drv_data) { /* clear RXS (we check for RXS inside the loop) */ bfin_spi_dummy_read(drv_data); @@ -321,7 +321,7 @@ static void bfin_spi_u16_writer(struct driver_data *drv_data) } } -static void bfin_spi_u16_reader(struct driver_data *drv_data) +static void bfin_spi_u16_reader(struct master_data *drv_data) { u16 tx_val = drv_data->cur_chip->idle_tx_val; @@ -337,7 +337,7 @@ static void bfin_spi_u16_reader(struct driver_data *drv_data) } } -static void bfin_spi_u16_duplex(struct driver_data *drv_data) +static void bfin_spi_u16_duplex(struct master_data *drv_data) { /* discard old RX data and clear RXS */ bfin_spi_dummy_read(drv_data); @@ -359,7 +359,7 @@ static const struct transfer_ops bfin_transfer_ops_u16 = { }; /* test if ther is more transfer to be done */ -static void *bfin_spi_next_transfer(struct driver_data *drv_data) +static void *bfin_spi_next_transfer(struct master_data *drv_data) { struct spi_message *msg = drv_data->cur_msg; struct spi_transfer *trans = drv_data->cur_transfer; @@ -378,9 +378,9 @@ static void *bfin_spi_next_transfer(struct driver_data *drv_data) * caller already set message->status; * dma and pio irqs are blocked give finished message back */ -static void bfin_spi_giveback(struct driver_data *drv_data) +static void bfin_spi_giveback(struct master_data *drv_data) { - struct chip_data *chip = drv_data->cur_chip; + struct slave_data *chip = drv_data->cur_chip; struct spi_transfer *last_transfer; unsigned long flags; struct spi_message *msg; @@ -412,8 +412,8 @@ static void bfin_spi_giveback(struct driver_data *drv_data) /* spi data irq handler */ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id) { - struct driver_data *drv_data = dev_id; - struct chip_data *chip = drv_data->cur_chip; + struct master_data *drv_data = dev_id; + struct slave_data *chip = drv_data->cur_chip; struct spi_message *msg = drv_data->cur_msg; int n_bytes = drv_data->n_bytes; @@ -484,8 +484,8 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id) static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id) { - struct driver_data *drv_data = dev_id; - struct chip_data *chip = drv_data->cur_chip; + struct master_data *drv_data = dev_id; + struct slave_data *chip = drv_data->cur_chip; struct spi_message *msg = drv_data->cur_msg; unsigned long timeout; unsigned short dmastat = get_dma_curr_irqstat(drv_data->dma_channel); @@ -548,11 +548,11 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id) static void bfin_spi_pump_transfers(unsigned long data) { - struct driver_data *drv_data = (struct driver_data *)data; + struct master_data *drv_data = (struct master_data *)data; struct spi_message *message = NULL; struct spi_transfer *transfer = NULL; struct spi_transfer *previous = NULL; - struct chip_data *chip = NULL; + struct slave_data *chip = NULL; u8 width; u16 cr, dma_width, dma_config; u32 tranf_success = 1; @@ -872,10 +872,10 @@ static void bfin_spi_pump_transfers(unsigned long data) /* pop a msg from queue and kick off real transfer */ static void bfin_spi_pump_messages(struct work_struct *work) { - struct driver_data *drv_data; + struct master_data *drv_data; unsigned long flags; - drv_data = container_of(work, struct driver_data, pump_messages); + drv_data = container_of(work, struct master_data, pump_messages); /* Lock queue and check for queue work */ spin_lock_irqsave(&drv_data->lock, flags); @@ -929,7 +929,7 @@ static void bfin_spi_pump_messages(struct work_struct *work) */ static int bfin_spi_transfer(struct spi_device *spi, struct spi_message *msg) { - struct driver_data *drv_data = spi_master_get_devdata(spi->master); + struct master_data *drv_data = spi_master_get_devdata(spi->master); unsigned long flags; spin_lock_irqsave(&drv_data->lock, flags); @@ -974,8 +974,8 @@ static u16 ssel[][MAX_SPI_SSEL] = { static int bfin_spi_setup(struct spi_device *spi) { struct bfin5xx_spi_chip *chip_info; - struct chip_data *chip = NULL; - struct driver_data *drv_data = spi_master_get_devdata(spi->master); + struct slave_data *chip = NULL; + struct master_data *drv_data = spi_master_get_devdata(spi->master); int ret = -EINVAL; if (spi->bits_per_word != 8 && spi->bits_per_word != 16) @@ -1155,8 +1155,8 @@ static int bfin_spi_setup(struct spi_device *spi) */ static void bfin_spi_cleanup(struct spi_device *spi) { - struct chip_data *chip = spi_get_ctldata(spi); - struct driver_data *drv_data = spi_master_get_devdata(spi->master); + struct slave_data *chip = spi_get_ctldata(spi); + struct master_data *drv_data = spi_master_get_devdata(spi->master); if (!chip) return; @@ -1176,7 +1176,7 @@ static void bfin_spi_cleanup(struct spi_device *spi) spi_set_ctldata(spi, NULL); } -static inline int bfin_spi_init_queue(struct driver_data *drv_data) +static inline int bfin_spi_init_queue(struct master_data *drv_data) { INIT_LIST_HEAD(&drv_data->queue); spin_lock_init(&drv_data->lock); @@ -1198,7 +1198,7 @@ static inline int bfin_spi_init_queue(struct driver_data *drv_data) return 0; } -static inline int bfin_spi_start_queue(struct driver_data *drv_data) +static inline int bfin_spi_start_queue(struct master_data *drv_data) { unsigned long flags; @@ -1220,7 +1220,7 @@ static inline int bfin_spi_start_queue(struct driver_data *drv_data) return 0; } -static inline int bfin_spi_stop_queue(struct driver_data *drv_data) +static inline int bfin_spi_stop_queue(struct master_data *drv_data) { unsigned long flags; unsigned limit = 500; @@ -1249,7 +1249,7 @@ static inline int bfin_spi_stop_queue(struct driver_data *drv_data) return status; } -static inline int bfin_spi_destroy_queue(struct driver_data *drv_data) +static inline int bfin_spi_destroy_queue(struct master_data *drv_data) { int status; @@ -1267,14 +1267,14 @@ static int __init bfin_spi_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct bfin5xx_spi_master *platform_info; struct spi_master *master; - struct driver_data *drv_data = 0; + struct master_data *drv_data = 0; struct resource *res; int status = 0; platform_info = dev->platform_data; /* Allocate master with space for drv_data */ - master = spi_alloc_master(dev, sizeof(struct driver_data) + 16); + master = spi_alloc_master(dev, sizeof(struct master_data) + 16); if (!master) { dev_err(&pdev->dev, "can not alloc spi_master\n"); return -ENOMEM; @@ -1377,7 +1377,7 @@ out_error_get_res: /* stop hardware and remove the driver */ static int __devexit bfin_spi_remove(struct platform_device *pdev) { - struct driver_data *drv_data = platform_get_drvdata(pdev); + struct master_data *drv_data = platform_get_drvdata(pdev); int status = 0; if (!drv_data) @@ -1416,7 +1416,7 @@ static int __devexit bfin_spi_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int bfin_spi_suspend(struct platform_device *pdev, pm_message_t state) { - struct driver_data *drv_data = platform_get_drvdata(pdev); + struct master_data *drv_data = platform_get_drvdata(pdev); int status = 0; status = bfin_spi_stop_queue(drv_data); @@ -1431,7 +1431,7 @@ static int bfin_spi_suspend(struct platform_device *pdev, pm_message_t state) static int bfin_spi_resume(struct platform_device *pdev) { - struct driver_data *drv_data = platform_get_drvdata(pdev); + struct master_data *drv_data = platform_get_drvdata(pdev); int status = 0; /* Enable the SPI interface */ -- cgit v1.1 From 2a045131db69c207b9e3f9614b2c9b0f2e82bcb7 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 24 Sep 2009 01:28:54 +0000 Subject: spi/bfin_spi: drop extra memory we don't need The driver that we based ours on uses a little extra memory behind the normal driver state, but we don't. So drop this useless bit of memory. Reported-by: David Brownell Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 9a1801b..ffff099 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -1267,14 +1267,14 @@ static int __init bfin_spi_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct bfin5xx_spi_master *platform_info; struct spi_master *master; - struct master_data *drv_data = 0; + struct master_data *drv_data; struct resource *res; int status = 0; platform_info = dev->platform_data; /* Allocate master with space for drv_data */ - master = spi_alloc_master(dev, sizeof(struct master_data) + 16); + master = spi_alloc_master(dev, sizeof(*drv_data)); if (!master) { dev_err(&pdev->dev, "can not alloc spi_master\n"); return -ENOMEM; -- cgit v1.1 From 90008a641dd832cc2e2c4d21b7da94de91e9d0a4 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 15 Oct 2009 04:13:29 +0000 Subject: spi/bfin_spi: use the SPI namespaced bit names This lets us push the short SPI MMR bit names out of the global namespace. Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index ffff099..07044d7 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -504,8 +504,8 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id) * register until it goes low for 2 successive reads */ if (drv_data->tx != NULL) { - while ((read_STAT(drv_data) & TXS) || - (read_STAT(drv_data) & TXS)) + while ((read_STAT(drv_data) & BIT_STAT_TXS) || + (read_STAT(drv_data) & BIT_STAT_TXS)) cpu_relax(); } @@ -514,14 +514,14 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id) dmastat, read_STAT(drv_data)); timeout = jiffies + HZ; - while (!(read_STAT(drv_data) & SPIF)) + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) if (!time_before(jiffies, timeout)) { dev_warn(&drv_data->pdev->dev, "timeout waiting for SPIF"); break; } else cpu_relax(); - if ((dmastat & DMA_ERR) && (spistat & RBSY)) { + if ((dmastat & DMA_ERR) && (spistat & BIT_STAT_RBSY)) { msg->state = ERROR_STATE; dev_err(&drv_data->pdev->dev, "dma receive: fifo/buffer overflow\n"); } else { @@ -1000,11 +1000,12 @@ static int bfin_spi_setup(struct spi_device *spi) if (chip_info) { /* Make sure people stop trying to set fields via ctl_reg * when they should actually be using common SPI framework. - * Currently we let through: WOM EMISO PSSE GM SZ TIMOD. + * Currently we let through: WOM EMISO PSSE GM SZ. * Not sure if a user actually needs/uses any of these, * but let's assume (for now) they do. */ - if (chip_info->ctl_reg & (SPE|MSTR|CPOL|CPHA|LSBF|SIZE)) { + if (chip_info->ctl_reg & ~(BIT_CTL_OPENDRAIN | BIT_CTL_EMISO | \ + BIT_CTL_PSSE | BIT_CTL_GM | BIT_CTL_SZ)) { dev_err(&spi->dev, "do not set bits in ctl_reg " "that the SPI framework manages\n"); goto error; @@ -1022,13 +1023,13 @@ static int bfin_spi_setup(struct spi_device *spi) /* translate common spi framework into our register */ if (spi->mode & SPI_CPOL) - chip->ctl_reg |= CPOL; + chip->ctl_reg |= BIT_CTL_CPOL; if (spi->mode & SPI_CPHA) - chip->ctl_reg |= CPHA; + chip->ctl_reg |= BIT_CTL_CPHA; if (spi->mode & SPI_LSB_FIRST) - chip->ctl_reg |= LSBF; + chip->ctl_reg |= BIT_CTL_LSBF; /* we dont support running in slave mode (yet?) */ - chip->ctl_reg |= MSTR; + chip->ctl_reg |= BIT_CTL_MASTER; /* * Notice: for blackfin, the speed_hz is the value of register -- cgit v1.1 From d3cc71f71ae13596cb988e16bfa2b15f09fb7347 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Tue, 17 Nov 2009 09:45:59 +0000 Subject: spi/bfin_spi: redo GPIO CS handling The common SPI layers take care of detecting CS conflicts and preventing two devices from claiming the same CS. This causes problems for the GPIO CS support we currently have as we are using CS0 to mean "GPIO CS". But if we have multiple devices using a GPIO CS, the common SPI layers see multiple devices using the virtual "CS0" and reject any such attempts. To make both work, we introduce an offset define. This represents the max number of hardware CS values that the SPI peripheral supports. If the CS is below this limit, we know we can use the hardware CS. If it's above, we treat it as a GPIO CS. This keeps the CS unique as seen by the common code and prevents conflicts. Signed-off-by: Barry Song Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 07044d7..278fe0a 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -183,7 +183,7 @@ static int bfin_spi_flush(struct master_data *drv_data) /* Chip select operation functions for cs_change flag */ static void bfin_spi_cs_active(struct master_data *drv_data, struct slave_data *chip) { - if (likely(chip->chip_select_num)) { + if (likely(chip->chip_select_num < MAX_CTRL_CS)) { u16 flag = read_FLAG(drv_data); flag &= ~chip->flag; @@ -196,7 +196,7 @@ static void bfin_spi_cs_active(struct master_data *drv_data, struct slave_data * static void bfin_spi_cs_deactive(struct master_data *drv_data, struct slave_data *chip) { - if (likely(chip->chip_select_num)) { + if (likely(chip->chip_select_num < MAX_CTRL_CS)) { u16 flag = read_FLAG(drv_data); flag |= chip->flag; @@ -214,20 +214,24 @@ static void bfin_spi_cs_deactive(struct master_data *drv_data, struct slave_data /* enable or disable the pin muxed by GPIO and SPI CS to work as SPI CS */ static inline void bfin_spi_cs_enable(struct master_data *drv_data, struct slave_data *chip) { - u16 flag = read_FLAG(drv_data); + if (chip->chip_select_num < MAX_CTRL_CS) { + u16 flag = read_FLAG(drv_data); - flag |= (chip->flag >> 8); + flag |= (chip->flag >> 8); - write_FLAG(drv_data, flag); + write_FLAG(drv_data, flag); + } } static inline void bfin_spi_cs_disable(struct master_data *drv_data, struct slave_data *chip) { - u16 flag = read_FLAG(drv_data); + if (chip->chip_select_num < MAX_CTRL_CS) { + u16 flag = read_FLAG(drv_data); - flag &= ~(chip->flag >> 8); + flag &= ~(chip->flag >> 8); - write_FLAG(drv_data, flag); + write_FLAG(drv_data, flag); + } } /* stop controller and re-config current chip*/ @@ -1016,7 +1020,6 @@ static int bfin_spi_setup(struct spi_device *spi) chip->ctl_reg = chip_info->ctl_reg; chip->bits_per_word = chip_info->bits_per_word; chip->cs_chg_udelay = chip_info->cs_chg_udelay; - chip->cs_gpio = chip_info->cs_gpio; chip->idle_tx_val = chip_info->idle_tx_val; chip->pio_interrupt = chip_info->pio_interrupt; } @@ -1036,8 +1039,11 @@ static int bfin_spi_setup(struct spi_device *spi) * SPI_BAUD, not the real baudrate */ chip->baud = hz_to_spi_baud(spi->max_speed_hz); - chip->flag = (1 << (spi->chip_select)) << 8; chip->chip_select_num = spi->chip_select; + if (chip->chip_select_num < MAX_CTRL_CS) + chip->flag = (1 << spi->chip_select) << 8; + else + chip->cs_gpio = chip->chip_select_num - MAX_CTRL_CS; switch (chip->bits_per_word) { case 8: @@ -1098,7 +1104,7 @@ static int bfin_spi_setup(struct spi_device *spi) disable_irq(drv_data->spi_irq); } - if (chip->chip_select_num == 0) { + 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"); @@ -1115,8 +1121,7 @@ static int bfin_spi_setup(struct spi_device *spi) spi_set_ctldata(spi, chip); dev_dbg(&spi->dev, "chip select number is %d\n", chip->chip_select_num); - if (chip->chip_select_num > 0 && - chip->chip_select_num <= spi->master->num_chipselect) { + if (chip->chip_select_num < MAX_CTRL_CS) { ret = peripheral_request(ssel[spi->master->bus_num] [chip->chip_select_num-1], spi->modalias); if (ret) { @@ -1131,7 +1136,7 @@ static int bfin_spi_setup(struct spi_device *spi) return 0; pin_error: - if (chip->chip_select_num == 0) + if (chip->chip_select_num >= MAX_CTRL_CS) gpio_free(chip->cs_gpio); else peripheral_free(ssel[spi->master->bus_num] @@ -1162,14 +1167,11 @@ static void bfin_spi_cleanup(struct spi_device *spi) if (!chip) return; - if ((chip->chip_select_num > 0) - && (chip->chip_select_num <= spi->master->num_chipselect)) { + if (chip->chip_select_num < MAX_CTRL_CS) { peripheral_free(ssel[spi->master->bus_num] [chip->chip_select_num-1]); bfin_spi_cs_disable(drv_data, chip); - } - - if (chip->chip_select_num == 0) + } else gpio_free(chip->cs_gpio); kfree(chip); -- cgit v1.1 From b052fd0a44354c655eb98fd715ef52857631dfef Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 18 Nov 2009 09:43:21 +0000 Subject: spi/bfin_spi: save/restore state when suspending/resuming We can't rely on the SPI_CTL/SPI_FLG registers retaining their state when suspending, so save/restore their entire values. Signed-off-by: Barry Song Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 278fe0a..c23ac3b 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -101,6 +101,9 @@ struct master_data { size_t rx_map_len; size_t tx_map_len; u8 n_bytes; + u16 ctrl_reg; + u16 flag_reg; + int cs_change; const struct transfer_ops *ops; }; @@ -1426,8 +1429,14 @@ static int bfin_spi_suspend(struct platform_device *pdev, pm_message_t state) if (status != 0) return status; - /* stop hardware */ - bfin_spi_disable(drv_data); + drv_data->ctrl_reg = read_CTRL(drv_data); + drv_data->flag_reg = read_FLAG(drv_data); + + /* + * reset SPI_CTL and SPI_FLG registers + */ + write_CTRL(drv_data, BIT_CTL_CPHA | BIT_CTL_MASTER); + write_FLAG(drv_data, 0xFF00); return 0; } @@ -1437,8 +1446,8 @@ static int bfin_spi_resume(struct platform_device *pdev) struct master_data *drv_data = platform_get_drvdata(pdev); int status = 0; - /* Enable the SPI interface */ - bfin_spi_enable(drv_data); + write_CTRL(drv_data, drv_data->ctrl_reg); + write_FLAG(drv_data, drv_data->flag_reg); /* Start the queue running */ status = bfin_spi_start_queue(drv_data); -- cgit v1.1 From 9677b0de10433d31e05864dfb4bf33d0c27f752a Mon Sep 17 00:00:00 2001 From: Barry Song Date: Mon, 30 Nov 2009 03:49:41 +0000 Subject: spi/bfin_spi: sync hardware state before reprogramming everything Sometimes under load, the Blackfin core is able to send SPI register updates out before the controller is actually disabled. So when we go to reprogram the entire state (to switch to a different slave), make sure we sync after disabling the controller. Signed-off-by: Barry Song Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index c23ac3b..54f9dbb 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -247,6 +247,8 @@ static void bfin_spi_restore_state(struct master_data *drv_data) bfin_spi_disable(drv_data); dev_dbg(&drv_data->pdev->dev, "restoring spi ctl state\n"); + SSYNC(); + /* Load the registers */ write_CTRL(drv_data, chip->ctl_reg); write_BAUD(drv_data, chip->baud); -- cgit v1.1 From 7370ed6b91c37d7022a89a820b0fcd3156fa87fc Mon Sep 17 00:00:00 2001 From: Yi Li Date: Mon, 7 Dec 2009 08:07:01 +0000 Subject: spi/bfin_spi: use nosync when disabling the IRQ from the IRQ handler Using disable_irq() on the IRQ whose handler we are currently executing in can easily lead to a hang. So use the nosync variant here. Signed-off-by: Yi Li Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 54f9dbb..d446524 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -448,7 +448,7 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id) /* Move to next transfer */ msg->state = bfin_spi_next_transfer(drv_data); - disable_irq(drv_data->spi_irq); + disable_irq_nosync(drv_data->spi_irq); /* Schedule transfer tasklet */ tasklet_schedule(&drv_data->pump_transfers); -- cgit v1.1 From 033f44bd0ebca1809e8274237a64263d909f01a7 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 18 Dec 2009 17:38:04 +0000 Subject: spi/bfin_spi: push all size checks into the transfer function This reduces duplication between the setup/transfer functions and keeps values cached during setup from overriding values changed on a transfer basis (like bits_per_word). Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 57 ++++++++++++----------------------------------- 1 file changed, 14 insertions(+), 43 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index d446524..830c705 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -114,10 +114,7 @@ struct slave_data { u16 flag; u8 chip_select_num; - u8 n_bytes; - u8 width; /* 0 or 1 */ u8 enable_dma; - u8 bits_per_word; /* 8 or 16 */ u16 cs_chg_udelay; /* Some devices require > 255usec delay */ u32 cs_gpio; u16 idle_tx_val; @@ -562,6 +559,7 @@ static void bfin_spi_pump_transfers(unsigned long data) struct spi_transfer *transfer = NULL; struct spi_transfer *previous = NULL; struct slave_data *chip = NULL; + unsigned int bits_per_word; u8 width; u16 cr, dma_width, dma_config; u32 tranf_success = 1; @@ -641,26 +639,15 @@ static void bfin_spi_pump_transfers(unsigned long data) drv_data->cs_change = transfer->cs_change; /* Bits per word setup */ - switch (transfer->bits_per_word) { - case 8: + bits_per_word = transfer->bits_per_word ? : message->spi->bits_per_word; + if (bits_per_word == 8) { drv_data->n_bytes = 1; width = CFG_SPI_WORDSIZE8; drv_data->ops = &bfin_transfer_ops_u8; - break; - - case 16: + } else { drv_data->n_bytes = 2; width = CFG_SPI_WORDSIZE16; drv_data->ops = &bfin_transfer_ops_u16; - break; - - default: - /* No change, the same as default setting */ - transfer->bits_per_word = chip->bits_per_word; - drv_data->n_bytes = chip->n_bytes; - width = chip->width; - drv_data->ops = chip->ops; - break; } cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD)); cr |= (width << 8); @@ -811,9 +798,9 @@ static void bfin_spi_pump_transfers(unsigned long data) if (drv_data->tx == NULL) write_TDBR(drv_data, chip->idle_tx_val); else { - if (transfer->bits_per_word == 8) + if (bits_per_word == 8) write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); - else if (transfer->bits_per_word == 16) + else write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); drv_data->tx += drv_data->n_bytes; } @@ -987,9 +974,6 @@ static int bfin_spi_setup(struct spi_device *spi) struct master_data *drv_data = spi_master_get_devdata(spi->master); int ret = -EINVAL; - if (spi->bits_per_word != 8 && spi->bits_per_word != 16) - goto error; - /* Only alloc (or use chip_info) on first setup */ chip_info = NULL; chip = spi_get_ctldata(spi); @@ -1023,10 +1007,16 @@ static int bfin_spi_setup(struct spi_device *spi) chip->enable_dma = chip_info->enable_dma != 0 && drv_data->master_info->enable_dma; chip->ctl_reg = chip_info->ctl_reg; - chip->bits_per_word = chip_info->bits_per_word; chip->cs_chg_udelay = chip_info->cs_chg_udelay; chip->idle_tx_val = chip_info->idle_tx_val; chip->pio_interrupt = chip_info->pio_interrupt; + spi->bits_per_word = chip_info->bits_per_word; + } + + if (spi->bits_per_word != 8 && spi->bits_per_word != 16) { + dev_err(&spi->dev, "%d bits_per_word is not supported\n", + spi->bits_per_word); + goto error; } /* translate common spi framework into our register */ @@ -1050,25 +1040,6 @@ static int bfin_spi_setup(struct spi_device *spi) else chip->cs_gpio = chip->chip_select_num - MAX_CTRL_CS; - switch (chip->bits_per_word) { - case 8: - chip->n_bytes = 1; - chip->width = CFG_SPI_WORDSIZE8; - chip->ops = &bfin_transfer_ops_u8; - break; - - case 16: - chip->n_bytes = 2; - chip->width = CFG_SPI_WORDSIZE16; - chip->ops = &bfin_transfer_ops_u16; - break; - - default: - dev_err(&spi->dev, "%d bits_per_word is not supported\n", - chip->bits_per_word); - goto error; - } - if (chip->enable_dma && chip->pio_interrupt) { dev_err(&spi->dev, "enable_dma is set, " "do not set pio_interrupt\n"); @@ -1119,7 +1090,7 @@ static int bfin_spi_setup(struct spi_device *spi) } dev_dbg(&spi->dev, "setup spi chip %s, width is %d, dma is %d\n", - spi->modalias, chip->width, chip->enable_dma); + spi->modalias, spi->bits_per_word, chip->enable_dma); dev_dbg(&spi->dev, "ctl_reg is 0x%x, flag_reg is 0x%x\n", chip->ctl_reg, chip->flag); -- cgit v1.1 From 5b47bcd48b3bd53c86040321de0d348aadebed87 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 18 Dec 2009 17:43:31 +0000 Subject: spi/bfin_spi: reset ctl_reg bits when setup is run again on a device During runtime, the spi setup function may be called multiple times on the same device in order to reconfigure some settings on the fly. When this happens, we need to reset the ctl_reg bits so that changing the mode works as expected. Reported-by: Andy Getzendanner Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 830c705..376f2f0 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -972,6 +972,7 @@ static int bfin_spi_setup(struct spi_device *spi) struct bfin5xx_spi_chip *chip_info; struct slave_data *chip = NULL; struct master_data *drv_data = spi_master_get_devdata(spi->master); + u16 bfin_ctl_reg; int ret = -EINVAL; /* Only alloc (or use chip_info) on first setup */ @@ -989,6 +990,10 @@ static int bfin_spi_setup(struct spi_device *spi) chip_info = spi->controller_data; } + /* Let people set non-standard bits directly */ + bfin_ctl_reg = BIT_CTL_OPENDRAIN | BIT_CTL_EMISO | + BIT_CTL_PSSE | BIT_CTL_GM | BIT_CTL_SZ; + /* chip_info isn't always needed */ if (chip_info) { /* Make sure people stop trying to set fields via ctl_reg @@ -997,13 +1002,11 @@ static int bfin_spi_setup(struct spi_device *spi) * Not sure if a user actually needs/uses any of these, * but let's assume (for now) they do. */ - if (chip_info->ctl_reg & ~(BIT_CTL_OPENDRAIN | BIT_CTL_EMISO | \ - BIT_CTL_PSSE | BIT_CTL_GM | BIT_CTL_SZ)) { + if (chip_info->ctl_reg & ~bfin_ctl_reg) { dev_err(&spi->dev, "do not set bits in ctl_reg " "that the SPI framework manages\n"); goto error; } - chip->enable_dma = chip_info->enable_dma != 0 && drv_data->master_info->enable_dma; chip->ctl_reg = chip_info->ctl_reg; @@ -1011,6 +1014,9 @@ static int bfin_spi_setup(struct spi_device *spi) chip->idle_tx_val = chip_info->idle_tx_val; chip->pio_interrupt = chip_info->pio_interrupt; spi->bits_per_word = chip_info->bits_per_word; + } else { + /* force a default base state */ + chip->ctl_reg &= bfin_ctl_reg; } if (spi->bits_per_word != 8 && spi->bits_per_word != 16) { -- cgit v1.1 From 5e8592dca303fb429d1641c205fe509f4b781ca2 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 18 Dec 2009 18:00:10 +0000 Subject: spi/bfin_spi: combine duplicate SPI_CTL read/write logic While combining things, also switch to the proper SPI bit define names. This lets us punt the rarely used SPI defines. Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 376f2f0..b3450b7 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -560,8 +560,7 @@ static void bfin_spi_pump_transfers(unsigned long data) struct spi_transfer *previous = NULL; struct slave_data *chip = NULL; unsigned int bits_per_word; - u8 width; - u16 cr, dma_width, dma_config; + u16 cr, cr_width, dma_width, dma_config; u32 tranf_success = 1; u8 full_duplex = 0; @@ -642,22 +641,19 @@ static void bfin_spi_pump_transfers(unsigned long data) bits_per_word = transfer->bits_per_word ? : message->spi->bits_per_word; if (bits_per_word == 8) { drv_data->n_bytes = 1; - width = CFG_SPI_WORDSIZE8; + drv_data->len = transfer->len; + cr_width = 0; drv_data->ops = &bfin_transfer_ops_u8; } else { drv_data->n_bytes = 2; - width = CFG_SPI_WORDSIZE16; + drv_data->len = (transfer->len) >> 1; + cr_width = BIT_CTL_WORDSIZE; drv_data->ops = &bfin_transfer_ops_u16; } - cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD)); - cr |= (width << 8); + cr = read_CTRL(drv_data) & ~(BIT_CTL_TIMOD | BIT_CTL_WORDSIZE); + cr |= cr_width; write_CTRL(drv_data, cr); - if (width == CFG_SPI_WORDSIZE16) { - drv_data->len = (transfer->len) >> 1; - } else { - drv_data->len = transfer->len; - } dev_dbg(&drv_data->pdev->dev, "transfer: drv_data->ops is %p, chip->ops is %p, u8_ops is %p\n", drv_data->ops, chip->ops, &bfin_transfer_ops_u8); @@ -672,13 +668,12 @@ static void bfin_spi_pump_transfers(unsigned long data) write_BAUD(drv_data, chip->baud); write_STAT(drv_data, BIT_STAT_CLR); - cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD)); if (drv_data->cs_change) bfin_spi_cs_active(drv_data, chip); dev_dbg(&drv_data->pdev->dev, "now pumping a transfer: width is %d, len is %d\n", - width, transfer->len); + cr_width, transfer->len); /* * Try to map dma buffer and do a dma transfer. If successful use, @@ -697,7 +692,7 @@ static void bfin_spi_pump_transfers(unsigned long data) /* config dma channel */ dev_dbg(&drv_data->pdev->dev, "doing dma transfer\n"); set_dma_x_count(drv_data->dma_channel, drv_data->len); - if (width == CFG_SPI_WORDSIZE16) { + if (cr_width == BIT_CTL_WORDSIZE) { set_dma_x_modify(drv_data->dma_channel, 2); dma_width = WDSIZE_16; } else { @@ -786,10 +781,16 @@ static void bfin_spi_pump_transfers(unsigned long data) return; } + /* + * We always use SPI_WRITE mode (transfer starts with TDBR write). + * SPI_READ mode (transfer starts with RDBR read) seems to have + * problems with setting up the output value in TDBR prior to the + * start of the transfer. + */ + write_CTRL(drv_data, cr | BIT_CTL_TXMOD); + if (chip->pio_interrupt) { - /* use write mode. spi irq should have been disabled */ - cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD)); - write_CTRL(drv_data, (cr | CFG_SPI_WRITE)); + /* SPI irq should have been disabled by now */ /* discard old RX data and clear RXS */ bfin_spi_dummy_read(drv_data); @@ -813,11 +814,6 @@ static void bfin_spi_pump_transfers(unsigned long data) /* IO mode */ dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n"); - /* we always use SPI_WRITE mode. SPI_READ mode - seems to have problems with setting up the - output value in TDBR prior to the transfer. */ - write_CTRL(drv_data, (cr | CFG_SPI_WRITE)); - if (full_duplex) { /* full duplex mode */ BUG_ON((drv_data->tx_end - drv_data->tx) != -- cgit v1.1 From a75bd65b2189d711938d0fa7d9a79df47ddd66fa Mon Sep 17 00:00:00 2001 From: Barry Song Date: Fri, 22 Jan 2010 10:07:30 +0000 Subject: spi/bfin_spi: use dma_disable_irq_nosync() in irq handler Using disable_irq() on the IRQ whose handler we are currently executing in can easily lead to a hang. So use the nosync variant here. Signed-off-by: Barry Song Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index b3450b7..18b313a 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -547,7 +547,7 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id) dev_dbg(&drv_data->pdev->dev, "disable dma channel irq%d\n", drv_data->dma_channel); - dma_disable_irq(drv_data->dma_channel); + dma_disable_irq_nosync(drv_data->dma_channel); return IRQ_HANDLED; } -- cgit v1.1 From 7715aad4ef5cccb318942a0c47aef8a39d6130d7 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 25 Feb 2010 10:00:55 +0000 Subject: spi/bfin_spi: reject unsupported SPI modes Who knows what people will try! Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 18b313a..a91e556 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -1022,6 +1022,10 @@ static int bfin_spi_setup(struct spi_device *spi) } /* translate common spi framework into our register */ + if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) { + dev_err(&spi->dev, "unsupported spi modes detected\n"); + goto error; + } if (spi->mode & SPI_CPOL) chip->ctl_reg |= BIT_CTL_CPOL; if (spi->mode & SPI_CPHA) -- cgit v1.1 From e35954053c1a2ede37f6ed1b28d626dba43dc79d Mon Sep 17 00:00:00 2001 From: Rob Maris Date: Tue, 6 Apr 2010 04:12:00 +0000 Subject: spi/bfin_spi: fix typo in comment Signed-off-by: Rob Maris Signed-off-by: Barry Song Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index a91e556..550aaf7 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -364,7 +364,7 @@ static const struct transfer_ops bfin_transfer_ops_u16 = { .duplex = bfin_spi_u16_duplex, }; -/* test if ther is more transfer to be done */ +/* test if there is more transfer to be done */ static void *bfin_spi_next_transfer(struct master_data *drv_data) { struct spi_message *msg = drv_data->cur_msg; -- cgit v1.1 From e72dcde72c712708e2145ab0ecff539ff4a4c7fb Mon Sep 17 00:00:00 2001 From: Rob Maris Date: Tue, 6 Apr 2010 04:17:08 +0000 Subject: spi/bfin_spi: cs should be always low when a new transfer begins Signed-off-by: Rob Maris Signed-off-by: Barry Song Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 550aaf7..7882afc 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -668,8 +668,7 @@ static void bfin_spi_pump_transfers(unsigned long data) write_BAUD(drv_data, chip->baud); write_STAT(drv_data, BIT_STAT_CLR); - if (drv_data->cs_change) - bfin_spi_cs_active(drv_data, chip); + bfin_spi_cs_active(drv_data, chip); dev_dbg(&drv_data->pdev->dev, "now pumping a transfer: width is %d, len is %d\n", -- cgit v1.1 From 4190f6a51f3f9c7c8298202d31b3ead9381c33f1 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Tue, 6 Apr 2010 03:36:24 +0000 Subject: spi/bfin_spi: warn when CS is driven by hardware (CPHA=0) When the hardware is controlling the CS, there are some SPI options we are unable to support. So issue a warning in the hopes that the user will change to a SPI mode where we can support things sanely. Signed-off-by: Barry Song Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 7882afc..21de860 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -1040,9 +1040,14 @@ static int bfin_spi_setup(struct spi_device *spi) */ chip->baud = hz_to_spi_baud(spi->max_speed_hz); chip->chip_select_num = spi->chip_select; - if (chip->chip_select_num < MAX_CTRL_CS) + if (chip->chip_select_num < MAX_CTRL_CS) { + if (!(spi->mode & SPI_CPHA)) + dev_warn(&spi->dev, "Warning: SPI CPHA not set:" + " Slave Select not under software control!\n" + " See Documentation/blackfin/bfin-spi-notes.txt"); + chip->flag = (1 << spi->chip_select) << 8; - else + } else chip->cs_gpio = chip->chip_select_num - MAX_CTRL_CS; if (chip->enable_dma && chip->pio_interrupt) { -- cgit v1.1 From 2e768659df35ea337cb57ea3573c918d31e07894 Mon Sep 17 00:00:00 2001 From: Bob Liu Date: Fri, 17 Sep 2010 03:46:22 +0000 Subject: spi/bfin_spi: check per-transfer bits_per_word Currently, if the bits_per_word when doing a transfer is not 8bits, we always treat it as 16bits when we should actually be returning an error. Signed-off-by: Bob Liu Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 21de860..bd18214 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -644,11 +644,16 @@ static void bfin_spi_pump_transfers(unsigned long data) drv_data->len = transfer->len; cr_width = 0; drv_data->ops = &bfin_transfer_ops_u8; - } else { + } else if (bits_per_word == 16) { drv_data->n_bytes = 2; drv_data->len = (transfer->len) >> 1; cr_width = BIT_CTL_WORDSIZE; drv_data->ops = &bfin_transfer_ops_u16; + } else { + dev_err(&drv_data->pdev->dev, "transfer: unsupported bits_per_word\n"); + message->status = -EINVAL; + bfin_spi_giveback(drv_data); + return; } cr = read_CTRL(drv_data) & ~(BIT_CTL_TIMOD | BIT_CTL_WORDSIZE); cr |= cr_width; -- cgit v1.1 From 6f7c17f4f91513247dfec52d6968cd70d5251b38 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 1 Jul 2010 14:34:10 +0000 Subject: spi/bfin_spi: init early Some systems using this bus sometimes have very basic devices on them such as regulators. So we need to be loaded even earlier in case the devices are used by things such as early board init code. Therefore register in subsys_initcall(). Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index bd18214..d17ab37 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -1466,7 +1466,7 @@ static int __init bfin_spi_init(void) { return platform_driver_probe(&bfin_spi_driver, bfin_spi_probe); } -module_init(bfin_spi_init); +subsys_initcall(bfin_spi_init); static void __exit bfin_spi_exit(void) { -- cgit v1.1 From 9c0a788b4315b83f6138ffa15c56ccf541106e58 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 18 Oct 2010 02:45:22 -0400 Subject: spi/bfin_spi: namespace local structs Signed-off-by: Mike Frysinger --- drivers/spi/spi_bfin5xx.c | 119 ++++++++++++++++++++++++---------------------- 1 file changed, 61 insertions(+), 58 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index d17ab37..ab483a0 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -1,7 +1,7 @@ /* * Blackfin On-Chip SPI Driver * - * Copyright 2004-2007 Analog Devices Inc. + * Copyright 2004-2010 Analog Devices Inc. * * Enter bugs at http://blackfin.uclinux.org/ * @@ -42,15 +42,15 @@ MODULE_LICENSE("GPL"); #define DONE_STATE ((void *)2) #define ERROR_STATE ((void *)-1) -struct master_data; +struct bfin_spi_master_data; -struct transfer_ops { - void (*write) (struct master_data *); - void (*read) (struct master_data *); - void (*duplex) (struct master_data *); +struct bfin_spi_transfer_ops { + void (*write) (struct bfin_spi_master_data *); + void (*read) (struct bfin_spi_master_data *); + void (*duplex) (struct bfin_spi_master_data *); }; -struct master_data { +struct bfin_spi_master_data { /* Driver model hookup */ struct platform_device *pdev; @@ -80,7 +80,7 @@ struct master_data { /* Current message transfer state info */ struct spi_message *cur_msg; struct spi_transfer *cur_transfer; - struct slave_data *cur_chip; + struct bfin_spi_slave_data *cur_chip; size_t len_in_bytes; size_t len; void *tx; @@ -105,10 +105,10 @@ struct master_data { u16 flag_reg; int cs_change; - const struct transfer_ops *ops; + const struct bfin_spi_transfer_ops *ops; }; -struct slave_data { +struct bfin_spi_slave_data { u16 ctl_reg; u16 baud; u16 flag; @@ -119,13 +119,13 @@ struct slave_data { u32 cs_gpio; u16 idle_tx_val; u8 pio_interrupt; /* use spi data irq */ - const struct transfer_ops *ops; + const struct bfin_spi_transfer_ops *ops; }; #define DEFINE_SPI_REG(reg, off) \ -static inline u16 read_##reg(struct master_data *drv_data) \ +static inline u16 read_##reg(struct bfin_spi_master_data *drv_data) \ { return bfin_read16(drv_data->regs_base + off); } \ -static inline void write_##reg(struct master_data *drv_data, u16 v) \ +static inline void write_##reg(struct bfin_spi_master_data *drv_data, u16 v) \ { bfin_write16(drv_data->regs_base + off, v); } DEFINE_SPI_REG(CTRL, 0x00) @@ -136,7 +136,7 @@ DEFINE_SPI_REG(RDBR, 0x10) DEFINE_SPI_REG(BAUD, 0x14) DEFINE_SPI_REG(SHAW, 0x18) -static void bfin_spi_enable(struct master_data *drv_data) +static void bfin_spi_enable(struct bfin_spi_master_data *drv_data) { u16 cr; @@ -144,7 +144,7 @@ static void bfin_spi_enable(struct master_data *drv_data) write_CTRL(drv_data, (cr | BIT_CTL_ENABLE)); } -static void bfin_spi_disable(struct master_data *drv_data) +static void bfin_spi_disable(struct bfin_spi_master_data *drv_data) { u16 cr; @@ -167,7 +167,7 @@ static u16 hz_to_spi_baud(u32 speed_hz) return spi_baud; } -static int bfin_spi_flush(struct master_data *drv_data) +static int bfin_spi_flush(struct bfin_spi_master_data *drv_data) { unsigned long limit = loops_per_jiffy << 1; @@ -181,7 +181,7 @@ static int bfin_spi_flush(struct master_data *drv_data) } /* Chip select operation functions for cs_change flag */ -static void bfin_spi_cs_active(struct master_data *drv_data, struct slave_data *chip) +static void bfin_spi_cs_active(struct bfin_spi_master_data *drv_data, struct bfin_spi_slave_data *chip) { if (likely(chip->chip_select_num < MAX_CTRL_CS)) { u16 flag = read_FLAG(drv_data); @@ -194,7 +194,8 @@ static void bfin_spi_cs_active(struct master_data *drv_data, struct slave_data * } } -static void bfin_spi_cs_deactive(struct master_data *drv_data, struct slave_data *chip) +static void bfin_spi_cs_deactive(struct bfin_spi_master_data *drv_data, + struct bfin_spi_slave_data *chip) { if (likely(chip->chip_select_num < MAX_CTRL_CS)) { u16 flag = read_FLAG(drv_data); @@ -212,7 +213,8 @@ static void bfin_spi_cs_deactive(struct master_data *drv_data, struct slave_data } /* enable or disable the pin muxed by GPIO and SPI CS to work as SPI CS */ -static inline void bfin_spi_cs_enable(struct master_data *drv_data, struct slave_data *chip) +static inline void bfin_spi_cs_enable(struct bfin_spi_master_data *drv_data, + struct bfin_spi_slave_data *chip) { if (chip->chip_select_num < MAX_CTRL_CS) { u16 flag = read_FLAG(drv_data); @@ -223,7 +225,8 @@ static inline void bfin_spi_cs_enable(struct master_data *drv_data, struct slave } } -static inline void bfin_spi_cs_disable(struct master_data *drv_data, struct slave_data *chip) +static inline void bfin_spi_cs_disable(struct bfin_spi_master_data *drv_data, + struct bfin_spi_slave_data *chip) { if (chip->chip_select_num < MAX_CTRL_CS) { u16 flag = read_FLAG(drv_data); @@ -235,9 +238,9 @@ static inline void bfin_spi_cs_disable(struct master_data *drv_data, struct slav } /* stop controller and re-config current chip*/ -static void bfin_spi_restore_state(struct master_data *drv_data) +static void bfin_spi_restore_state(struct bfin_spi_master_data *drv_data) { - struct slave_data *chip = drv_data->cur_chip; + struct bfin_spi_slave_data *chip = drv_data->cur_chip; /* Clear status and disable clock */ write_STAT(drv_data, BIT_STAT_CLR); @@ -255,12 +258,12 @@ static void bfin_spi_restore_state(struct master_data *drv_data) } /* used to kick off transfer in rx mode and read unwanted RX data */ -static inline void bfin_spi_dummy_read(struct master_data *drv_data) +static inline void bfin_spi_dummy_read(struct bfin_spi_master_data *drv_data) { (void) read_RDBR(drv_data); } -static void bfin_spi_u8_writer(struct master_data *drv_data) +static void bfin_spi_u8_writer(struct bfin_spi_master_data *drv_data) { /* clear RXS (we check for RXS inside the loop) */ bfin_spi_dummy_read(drv_data); @@ -276,7 +279,7 @@ static void bfin_spi_u8_writer(struct master_data *drv_data) } } -static void bfin_spi_u8_reader(struct master_data *drv_data) +static void bfin_spi_u8_reader(struct bfin_spi_master_data *drv_data) { u16 tx_val = drv_data->cur_chip->idle_tx_val; @@ -291,7 +294,7 @@ static void bfin_spi_u8_reader(struct master_data *drv_data) } } -static void bfin_spi_u8_duplex(struct master_data *drv_data) +static void bfin_spi_u8_duplex(struct bfin_spi_master_data *drv_data) { /* discard old RX data and clear RXS */ bfin_spi_dummy_read(drv_data); @@ -304,13 +307,13 @@ static void bfin_spi_u8_duplex(struct master_data *drv_data) } } -static const struct transfer_ops bfin_transfer_ops_u8 = { +static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u8 = { .write = bfin_spi_u8_writer, .read = bfin_spi_u8_reader, .duplex = bfin_spi_u8_duplex, }; -static void bfin_spi_u16_writer(struct master_data *drv_data) +static void bfin_spi_u16_writer(struct bfin_spi_master_data *drv_data) { /* clear RXS (we check for RXS inside the loop) */ bfin_spi_dummy_read(drv_data); @@ -327,7 +330,7 @@ static void bfin_spi_u16_writer(struct master_data *drv_data) } } -static void bfin_spi_u16_reader(struct master_data *drv_data) +static void bfin_spi_u16_reader(struct bfin_spi_master_data *drv_data) { u16 tx_val = drv_data->cur_chip->idle_tx_val; @@ -343,7 +346,7 @@ static void bfin_spi_u16_reader(struct master_data *drv_data) } } -static void bfin_spi_u16_duplex(struct master_data *drv_data) +static void bfin_spi_u16_duplex(struct bfin_spi_master_data *drv_data) { /* discard old RX data and clear RXS */ bfin_spi_dummy_read(drv_data); @@ -358,14 +361,14 @@ static void bfin_spi_u16_duplex(struct master_data *drv_data) } } -static const struct transfer_ops bfin_transfer_ops_u16 = { +static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u16 = { .write = bfin_spi_u16_writer, .read = bfin_spi_u16_reader, .duplex = bfin_spi_u16_duplex, }; /* test if there is more transfer to be done */ -static void *bfin_spi_next_transfer(struct master_data *drv_data) +static void *bfin_spi_next_transfer(struct bfin_spi_master_data *drv_data) { struct spi_message *msg = drv_data->cur_msg; struct spi_transfer *trans = drv_data->cur_transfer; @@ -384,9 +387,9 @@ static void *bfin_spi_next_transfer(struct master_data *drv_data) * caller already set message->status; * dma and pio irqs are blocked give finished message back */ -static void bfin_spi_giveback(struct master_data *drv_data) +static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data) { - struct slave_data *chip = drv_data->cur_chip; + struct bfin_spi_slave_data *chip = drv_data->cur_chip; struct spi_transfer *last_transfer; unsigned long flags; struct spi_message *msg; @@ -418,8 +421,8 @@ static void bfin_spi_giveback(struct master_data *drv_data) /* spi data irq handler */ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id) { - struct master_data *drv_data = dev_id; - struct slave_data *chip = drv_data->cur_chip; + struct bfin_spi_master_data *drv_data = dev_id; + struct bfin_spi_slave_data *chip = drv_data->cur_chip; struct spi_message *msg = drv_data->cur_msg; int n_bytes = drv_data->n_bytes; @@ -490,8 +493,8 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id) static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id) { - struct master_data *drv_data = dev_id; - struct slave_data *chip = drv_data->cur_chip; + struct bfin_spi_master_data *drv_data = dev_id; + struct bfin_spi_slave_data *chip = drv_data->cur_chip; struct spi_message *msg = drv_data->cur_msg; unsigned long timeout; unsigned short dmastat = get_dma_curr_irqstat(drv_data->dma_channel); @@ -554,11 +557,11 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id) static void bfin_spi_pump_transfers(unsigned long data) { - struct master_data *drv_data = (struct master_data *)data; + struct bfin_spi_master_data *drv_data = (struct bfin_spi_master_data *)data; struct spi_message *message = NULL; struct spi_transfer *transfer = NULL; struct spi_transfer *previous = NULL; - struct slave_data *chip = NULL; + struct bfin_spi_slave_data *chip = NULL; unsigned int bits_per_word; u16 cr, cr_width, dma_width, dma_config; u32 tranf_success = 1; @@ -643,12 +646,12 @@ static void bfin_spi_pump_transfers(unsigned long data) drv_data->n_bytes = 1; drv_data->len = transfer->len; cr_width = 0; - drv_data->ops = &bfin_transfer_ops_u8; + drv_data->ops = &bfin_bfin_spi_transfer_ops_u8; } else if (bits_per_word == 16) { drv_data->n_bytes = 2; drv_data->len = (transfer->len) >> 1; cr_width = BIT_CTL_WORDSIZE; - drv_data->ops = &bfin_transfer_ops_u16; + drv_data->ops = &bfin_bfin_spi_transfer_ops_u16; } else { dev_err(&drv_data->pdev->dev, "transfer: unsupported bits_per_word\n"); message->status = -EINVAL; @@ -661,7 +664,7 @@ static void bfin_spi_pump_transfers(unsigned long data) dev_dbg(&drv_data->pdev->dev, "transfer: drv_data->ops is %p, chip->ops is %p, u8_ops is %p\n", - drv_data->ops, chip->ops, &bfin_transfer_ops_u8); + drv_data->ops, chip->ops, &bfin_bfin_spi_transfer_ops_u8); message->state = RUNNING_STATE; dma_config = 0; @@ -868,10 +871,10 @@ static void bfin_spi_pump_transfers(unsigned long data) /* pop a msg from queue and kick off real transfer */ static void bfin_spi_pump_messages(struct work_struct *work) { - struct master_data *drv_data; + struct bfin_spi_master_data *drv_data; unsigned long flags; - drv_data = container_of(work, struct master_data, pump_messages); + drv_data = container_of(work, struct bfin_spi_master_data, pump_messages); /* Lock queue and check for queue work */ spin_lock_irqsave(&drv_data->lock, flags); @@ -925,7 +928,7 @@ static void bfin_spi_pump_messages(struct work_struct *work) */ static int bfin_spi_transfer(struct spi_device *spi, struct spi_message *msg) { - struct master_data *drv_data = spi_master_get_devdata(spi->master); + struct bfin_spi_master_data *drv_data = spi_master_get_devdata(spi->master); unsigned long flags; spin_lock_irqsave(&drv_data->lock, flags); @@ -970,8 +973,8 @@ static u16 ssel[][MAX_SPI_SSEL] = { static int bfin_spi_setup(struct spi_device *spi) { struct bfin5xx_spi_chip *chip_info; - struct slave_data *chip = NULL; - struct master_data *drv_data = spi_master_get_devdata(spi->master); + struct bfin_spi_slave_data *chip = NULL; + struct bfin_spi_master_data *drv_data = spi_master_get_devdata(spi->master); u16 bfin_ctl_reg; int ret = -EINVAL; @@ -1152,8 +1155,8 @@ static int bfin_spi_setup(struct spi_device *spi) */ static void bfin_spi_cleanup(struct spi_device *spi) { - struct slave_data *chip = spi_get_ctldata(spi); - struct master_data *drv_data = spi_master_get_devdata(spi->master); + struct bfin_spi_slave_data *chip = spi_get_ctldata(spi); + struct bfin_spi_master_data *drv_data = spi_master_get_devdata(spi->master); if (!chip) return; @@ -1170,7 +1173,7 @@ static void bfin_spi_cleanup(struct spi_device *spi) spi_set_ctldata(spi, NULL); } -static inline int bfin_spi_init_queue(struct master_data *drv_data) +static inline int bfin_spi_init_queue(struct bfin_spi_master_data *drv_data) { INIT_LIST_HEAD(&drv_data->queue); spin_lock_init(&drv_data->lock); @@ -1192,7 +1195,7 @@ static inline int bfin_spi_init_queue(struct master_data *drv_data) return 0; } -static inline int bfin_spi_start_queue(struct master_data *drv_data) +static inline int bfin_spi_start_queue(struct bfin_spi_master_data *drv_data) { unsigned long flags; @@ -1214,7 +1217,7 @@ static inline int bfin_spi_start_queue(struct master_data *drv_data) return 0; } -static inline int bfin_spi_stop_queue(struct master_data *drv_data) +static inline int bfin_spi_stop_queue(struct bfin_spi_master_data *drv_data) { unsigned long flags; unsigned limit = 500; @@ -1243,7 +1246,7 @@ static inline int bfin_spi_stop_queue(struct master_data *drv_data) return status; } -static inline int bfin_spi_destroy_queue(struct master_data *drv_data) +static inline int bfin_spi_destroy_queue(struct bfin_spi_master_data *drv_data) { int status; @@ -1261,7 +1264,7 @@ static int __init bfin_spi_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct bfin5xx_spi_master *platform_info; struct spi_master *master; - struct master_data *drv_data; + struct bfin_spi_master_data *drv_data; struct resource *res; int status = 0; @@ -1371,7 +1374,7 @@ out_error_get_res: /* stop hardware and remove the driver */ static int __devexit bfin_spi_remove(struct platform_device *pdev) { - struct master_data *drv_data = platform_get_drvdata(pdev); + struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev); int status = 0; if (!drv_data) @@ -1410,7 +1413,7 @@ static int __devexit bfin_spi_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int bfin_spi_suspend(struct platform_device *pdev, pm_message_t state) { - struct master_data *drv_data = platform_get_drvdata(pdev); + struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev); int status = 0; status = bfin_spi_stop_queue(drv_data); @@ -1431,7 +1434,7 @@ static int bfin_spi_suspend(struct platform_device *pdev, pm_message_t state) static int bfin_spi_resume(struct platform_device *pdev) { - struct master_data *drv_data = platform_get_drvdata(pdev); + struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev); int status = 0; write_CTRL(drv_data, drv_data->ctrl_reg); -- cgit v1.1