spi: dw: refactor to use SPI core message handling
v4 cover spi: dw: refactor to use SPI core message handling
This patch series is dedicated to refactoring of spi-dw driver to use SPI core message handling. The driver has been tested in PIO mode on Intel Medfield device in loopback mode.
Note, the patch 3/3 depends on [1].
[1] http://www.spinics.net/lists/linux-spi/msg02982.html
Changelog v4:
- rename spi_disable_intr() -> spi_reset_chip() which is more proper (patch 1/3)
- simplify patch 2/3
Changelog v3:
- introduce patch 1/3 and 2/3 to make state of the SPI controller consistent
- return 1 instead of transfer length from transfer_one()
- use newly introduced handle_err()
Changelog v2:
- remove leftovers from spi-dw.h
- remove unused members of dw_spi, i.e. cur_dev, max_bits_per_word
- reuse chip->cs_control directly
Andy Shevchenko (3):
spi: dw: make sure SPI controller is enabled
spi: dw: program registers as soon as possible
spi: dw: move to SPI core message handling
drivers/spi/spi-dw-mid.c | 4 +- drivers/spi/spi-dw.c | 226 +++++++++++++---------------------------------- drivers/spi/spi-dw.h | 38 +++----- 3 files changed, 77 insertions(+), 191 deletions(-)
Signature · 6 lines
2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): 1425301137-8043-1-git-send-email-andriy.shevchenko-VuQAYsv1563Yd54FQh9/[email protected]
PATCH v4 1/3 spi: dw: make sure SPI controller is enabled
The error handling is partially broken since the controller is disabled on error and is not re-enabled until condition occurs, i.e. mode (poll, PIO/DMA), chip (cs_change), or speed (clk_div) is changed. In the result of these changes we will have a predictable state of the SPi controller independently on how successfull was a previous transfer.
The patch disables interrupts and re-enables the SPI controller wherever it needs to be done. Thus most of the time the SPI controller is kept enabled. The runtime PM, when it will be implemented, must take care of the controller disabling and re-enabling.
--- drivers/spi/spi-dw.c | 7 ++----- drivers/spi/spi-dw.h | 12 ++++++++++++ 2 files changed, 14 insertions(+), 5 deletions(-)
drivers/spi/spi-dw.c +2 -5
@@ -272,8 +272,7 @@ static void giveback(struct dw_spi *dws)static void int_error_stop (struct dw_spi *dws,const char *msg) { -/* Stop the hw */ -spi_enable_chip (dws,0 ); +spi_reset_chip (dws);dev_err (&dws->master->dev,"%s\n" , msg); dws->cur_msg->state =ERROR_STATE ;
@@ -606,9 +605,7 @@ static void dw_spi_cleanup(struct spi_device *spi)/* Restart the controller, disable all interrupts, clean rx fifo */ static void spi_hw_init (struct device *dev,struct dw_spi *dws) { -spi_enable_chip (dws,0 ); -spi_mask_intr (dws,0xff ); -spi_enable_chip (dws,1 ); +spi_reset_chip (dws);/* * Try to detect the FIFO depth if not set by interface driver,
drivers/spi/spi-dw.h +12 -0
@@ -217,6 +217,18 @@ static inline void spi_umask_intr(struct dw_spi *dws, u32 mask) }/* +* This does disable the SPI controller, interrupts, and re-enable the +* controller back. Transmit and receive FIFO buffers are cleared when the +* device is disabled. +*/ +static inline void spi_reset_chip (struct dw_spi *dws) +{ +spi_enable_chip (dws,0 ); +spi_mask_intr (dws,0xff ); +spi_enable_chip (dws,1 ); +} + +/* * Each SPI slave device to work with dw_api controller should * has such a structure claiming its working mode (PIO/DMA etc), * which can be save in the "controller_data" member of the
Signature · 6 lines
2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): 1425301137-8043-2-git-send-email-andriy.shevchenko-VuQAYsv1563Yd54FQh9/[email protected]
Mark Brown
AppliedRe: [PATCH v4 1/3] spi: dw: make sure SPI controller is enabled
Quoted 5 lines · Andy Shevchenko
The error handling is partially broken since the controller is disabled on error and is not re-enabled until condition occurs, i.e. mode (poll, PIO/DMA), chip (
cs_change), or speed (clk_div) is changed. In the result of these changes we will have a predictable state of the SPi controller independently on how successfull was a previous transfer.
Applied, thanks.
PATCH v4 2/3 spi: dw: program registers as soon as possible
In reply to a message not in the archiveThis patch refactors the code in pump_transfers() to reprogram the registers immediately when we have a new configuration data. The behaviour is slightly modified:
- chip is always disabled and reenabled
- CTRL0 is always reprogrammed
This change allows to do a further refactoring and simplier conversion to use SPI core DMA routines in the future.
--- drivers/spi/spi-dw.c | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-)
drivers/spi/spi-dw.c +15 -23
@@ -409,6 +409,8 @@ static void pump_transfers(unsigned long data)if (chip != dws->prev_chip) cs_change =1 ; +spi_enable_chip (dws,0 ); + cr0 = chip->cr0;/* Handle per transfer options for bpw and speed */
@@ -423,6 +425,8 @@ static void pump_transfers(unsigned long data) chip->speed_hz = speed; chip->clk_div = clk_div; + +spi_set_clk (dws, chip->clk_div); } }if (transfer->bits_per_word) {
@@ -451,44 +455,32 @@ static void pump_transfers(unsigned long data) cr0 |= (chip->tmode <<SPI_TMOD_OFFSET ); } +dw_writew (dws,DW_SPI_CTRL0 , cr0); +spi_chip_sel (dws, spi,1 ); +/* Check if current transfer is a DMA transaction */ dws->dma_mapped =map_dma_buffers (dws); +/* For poll mode just disable all interrupts */ +spi_mask_intr (dws,0xff ); +/* * Interrupt mode * we only need set the TXEI IRQ, as TX/RX always happen syncronizely */ if (!dws->dma_mapped && !chip->poll_mode) { txlevel =min_t (u16, dws->fifo_len /2 , dws->len / dws->n_bytes); +dw_writew (dws,DW_SPI_TXFLTR , txlevel); +/* Set the interrupt mask */ imask |=SPI_INT_TXEI |SPI_INT_TXOI |SPI_INT_RXUI |SPI_INT_RXOI ; +spi_umask_intr (dws, imask); + dws->transfer_handler = interrupt_transfer; } -/* -* Reprogram registers only if -* 1. chip select changes -* 2. clk_div is changed -* 3. control value changes -*/ -if (dw_readw (dws,DW_SPI_CTRL0 ) != cr0 || cs_change || clk_div || imask) { -spi_enable_chip (dws,0 ); - -dw_writew (dws,DW_SPI_CTRL0 , cr0); - -spi_set_clk (dws, chip->clk_div); -spi_chip_sel (dws, spi,1 ); - -/* Set the interrupt mask, for poll mode just disable all int */ -spi_mask_intr (dws,0xff ); -if (imask) -spi_umask_intr (dws, imask); -if (txlevel) -dw_writew (dws,DW_SPI_TXFLTR , txlevel); - -spi_enable_chip (dws,1 ); - } +spi_enable_chip (dws,1 );if (cs_change) dws->prev_chip = chip;
Signature · 6 lines
2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): 1425301137-8043-3-git-send-email-andriy.shevchenko-VuQAYsv1563Yd54FQh9/[email protected]
Mark Brown
AppliedRe: [PATCH v4 2/3] spi: dw: program registers as soon as possible
Quoted 3 lines · Andy Shevchenko
This patch refactors the code in
pump_transfers()to reprogram the registers immediately when we have a new configuration data. The behaviour is slightly modified:
Applied, thanks.
PATCH v4 3/3 spi: dw: move to SPI core message handling
In reply to a message not in the archiveThis patch removes a lot of duplicate code since SPI core provides a nice message handling.
--- drivers/spi/spi-dw-mid.c | 4 +- drivers/spi/spi-dw.c | 183 ++++++++++++----------------------------------- drivers/spi/spi-dw.h | 26 ------- 3 files changed, 49 insertions(+), 164 deletions(-)
drivers/spi/spi-dw-mid.c +2 -2
@@ -110,7 +110,7 @@ static void dw_spi_dma_tx_done(void *arg)if (test_and_clear_bit (TX_BUSY , &dws->dma_chan_busy) &BIT (RX_BUSY ))return ; -dw_spi_xfer_done (dws); +spi_finalize_current_transfer (dws->master); }static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx (struct dw_spi *dws)
@@ -155,7 +155,7 @@ static void dw_spi_dma_rx_done(void *arg)if (test_and_clear_bit (RX_BUSY , &dws->dma_chan_busy) &BIT (TX_BUSY ))return ; -dw_spi_xfer_done (dws); +spi_finalize_current_transfer (dws->master); }static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx (struct dw_spi *dws)
drivers/spi/spi-dw.c +47 -136
319 lines not on this page · raw message
drivers/spi/spi-dw.h +0 -26
@@ -96,7 +96,6 @@ struct dw_spi_dma_ops {struct dw_spi {struct spi_master *master; -struct spi_device *cur_dev;enum dw_ssi_type type;char name[16 ];
@@ -109,13 +108,7 @@ struct dw_spi {u16 bus_num;u16 num_cs;/* supported slave numbers */ -/* Message Transfer pump */ -struct tasklet_struct pump_transfers; -/* Current message transfer state info */ -struct spi_message *cur_msg; -struct spi_transfer *cur_transfer; -struct chip_data *cur_chip;struct chip_data *prev_chip;size_t len;void *tx;
@@ -128,10 +121,8 @@ struct dw_spi {size_t rx_map_len;size_t tx_map_len;u8 n_bytes;/* current is a 1/2 bytes op */ -u8 max_bits_per_word;/* maxim is 16b */ u32 dma_width;irqreturn_t (*transfer_handler)(struct dw_spi *dws); -void (*cs_control)(u32 command);/* Dma info */ int dma_inited;
@@ -182,22 +173,6 @@ static inline void spi_set_clk(struct dw_spi *dws, u16 div)dw_writel (dws,DW_SPI_BAUDR , div); } -static inline void spi_chip_sel (struct dw_spi *dws,struct spi_device *spi, -int active) -{ -u16 cs = spi->chip_select; -int gpio_val = active ? (spi->mode &SPI_CS_HIGH ) : - !(spi->mode &SPI_CS_HIGH ); - -if (dws->cs_control) - dws->cs_control (active); -if (gpio_is_valid (spi->cs_gpio)) -gpio_set_value (spi->cs_gpio, gpio_val); - -if (active) -dw_writel (dws,DW_SPI_SER ,1 << cs); -} -/* Disable IRQ bits */ static inline void spi_mask_intr (struct dw_spi *dws,u32 mask) {
@@ -245,7 +220,6 @@ extern int dw_spi_add_host(struct device *dev, struct dw_spi *dws);extern void dw_spi_remove_host (struct dw_spi *dws);extern int dw_spi_suspend_host (struct dw_spi *dws);extern int dw_spi_resume_host (struct dw_spi *dws); -extern void dw_spi_xfer_done (struct dw_spi *dws);/* platform related setup */ extern int dw_spi_mid_init (struct dw_spi *dws);/* Intel MID platforms */
Signature · 6 lines
2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): 1425301137-8043-4-git-send-email-andriy.shevchenko-VuQAYsv1563Yd54FQh9/[email protected]
Mark Brown
AppliedRe: [PATCH v4 3/3] spi: dw: move to SPI core message handling
Quoted 2 lines · Andy Shevchenko
This patch removes a lot of duplicate code since SPI core provides a nice message handling.
Applied, thanks.
Quoted 7 lines · Andy Shevchenko
This patch series is dedicated to refactoring of spi-dw driver to use SPI core message handling. The driver has been tested in PIO mode on Intel Medfield device in loopback mode.
Note, the patch 3/3 depends on [1].
Please ensure that your e-mails are readable by humans - if you're referencing some other patch include a human readable description. I frequently read mail with no internet access (eg, on planes or trains) where that link would mean nothing.
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 11 lines · Mark Brown
Quoted 7 lines · Andy Shevchenko
This patch series is dedicated to refactoring of spi-dw driver to use SPI core message handling. The driver has been tested in PIO mode on Intel Medfield device in loopback mode.
Note, the patch 3/3 depends on [1].
Please ensure that your e-mails are readable by humans - if you're referencing some other patch include a human readable description.
Noted! Thanks for tip.
Signature · 7 lines
Andy Shevchenko <[email protected]> Intel Finland Oy -- To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html