From 7978b8c385a86f0b5b9304e81a1dfb5dcaf21528 Mon Sep 17 00:00:00 2001 From: Brian Niebuhr Date: Fri, 13 Aug 2010 10:11:03 +0530 Subject: spi: davinci: enable both activation and deactivation of chip-selects Let davinci_spi_chipselect() perform both activation and deactivation of chip selects. This lets spi_bitbang fully control chip select activation, as intended by the SPI API. With this change, the chip select activation code need not be duplicated in davinci_spi_bufs_{pio|dma}(). Also, keeping chip select active control is removed as a platform data and simply controlled using information from spi_bitbang on whether chip slect should be activated or de-activated. Signed-off-by: Brian Niebuhr Tested-By: Michael Williamson Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/dm355.c | 1 - arch/arm/mach-davinci/dm365.c | 1 - arch/arm/mach-davinci/include/mach/spi.h | 1 - 3 files changed, 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index 9be261beae7..6a76dfa60ef 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -413,7 +413,6 @@ static struct davinci_spi_platform_data dm355_spi0_pdata = { .version = SPI_VERSION_1, .num_chipselect = 2, .clk_internal = 1, - .cs_hold = 1, .intr_level = 0, .poll_mode = 1, /* 0 -> interrupt mode 1-> polling mode */ .c2tdelay = 0, diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index a12065e8726..cd623db8d7d 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -626,7 +626,6 @@ static struct davinci_spi_platform_data dm365_spi0_pdata = { .version = SPI_VERSION_1, .num_chipselect = 2, .clk_internal = 1, - .cs_hold = 1, .intr_level = 0, .poll_mode = 1, /* 0 -> interrupt mode 1-> polling mode */ .c2tdelay = 0, diff --git a/arch/arm/mach-davinci/include/mach/spi.h b/arch/arm/mach-davinci/include/mach/spi.h index 910efbf099c..2cb326e536b 100644 --- a/arch/arm/mach-davinci/include/mach/spi.h +++ b/arch/arm/mach-davinci/include/mach/spi.h @@ -33,7 +33,6 @@ struct davinci_spi_platform_data { u8 wait_enable; u8 timer_disable; u8 clk_internal; - u8 cs_hold; u8 intr_level; u8 poll_mode; u8 use_dma; -- cgit v1.2.3-70-g09d2 From 23853973d9b76eb8b3cf46157689bc6187e141d9 Mon Sep 17 00:00:00 2001 From: Brian Niebuhr Date: Fri, 13 Aug 2010 10:57:44 +0530 Subject: spi: davinci: enable GPIO lines to be used as chip selects Sometimes, the chip selects provided by SPI module are muxed with other functionality and cannot be used in some designs. In such cases, it becomes convenient to use an available GPIO line as chip select. This patch enables the DaVinci SPI driver to treat specific GPIO lines as chip selects based on information provided in platform data. Signed-off-by: Brian Niebuhr Tested-By: Michael Williamson Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/include/mach/spi.h | 3 +++ drivers/spi/davinci_spi.c | 39 ++++++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 7 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-davinci/include/mach/spi.h b/arch/arm/mach-davinci/include/mach/spi.h index 2cb326e536b..734d1fb9961 100644 --- a/arch/arm/mach-davinci/include/mach/spi.h +++ b/arch/arm/mach-davinci/include/mach/spi.h @@ -19,6 +19,8 @@ #ifndef __ARCH_ARM_DAVINCI_SPI_H #define __ARCH_ARM_DAVINCI_SPI_H +#define SPI_INTERN_CS 0xFF + enum { SPI_VERSION_1, /* For DM355/DM365/DM6467 */ SPI_VERSION_2, /* For DA8xx */ @@ -38,6 +40,7 @@ struct davinci_spi_platform_data { u8 use_dma; u8 c2tdelay; u8 t2cdelay; + u8 *chip_sel; }; #endif /* __ARCH_ARM_DAVINCI_SPI_H */ diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 82dddf83daf..d5d7014e6ae 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -238,20 +238,32 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) struct davinci_spi_platform_data *pdata; u8 chip_sel = spi->chip_select; u16 spidat1_cfg = CS_DEFAULT; + bool gpio_chipsel = false; davinci_spi = spi_master_get_devdata(spi->master); pdata = davinci_spi->pdata; + if (pdata->chip_sel && chip_sel < pdata->num_chipselect && + pdata->chip_sel[chip_sel] != SPI_INTERN_CS) + gpio_chipsel = true; + /* * Board specific chip select logic decides the polarity and cs * line for the controller */ - if (value == BITBANG_CS_ACTIVE) { - spidat1_cfg |= SPIDAT1_CSHOLD_MASK; - spidat1_cfg &= ~(0x1 << chip_sel); - } + if (gpio_chipsel) { + if (value == BITBANG_CS_ACTIVE) + gpio_set_value(pdata->chip_sel[chip_sel], 0); + else + gpio_set_value(pdata->chip_sel[chip_sel], 1); + } else { + if (value == BITBANG_CS_ACTIVE) { + spidat1_cfg |= SPIDAT1_CSHOLD_MASK; + spidat1_cfg &= ~(0x1 << chip_sel); + } - iowrite16(spidat1_cfg, davinci_spi->base + SPIDAT1 + 2); + iowrite16(spidat1_cfg, davinci_spi->base + SPIDAT1 + 2); + } } /** @@ -546,6 +558,7 @@ static void davinci_spi_cleanup(struct spi_device *spi) static int davinci_spi_bufs_prep(struct spi_device *spi, struct davinci_spi *davinci_spi) { + struct davinci_spi_platform_data *pdata; int op_mode = 0; /* @@ -558,8 +571,12 @@ static int davinci_spi_bufs_prep(struct spi_device *spi, op_mode = SPIPC0_DIFUN_MASK | SPIPC0_DOFUN_MASK | SPIPC0_CLKFUN_MASK; - if (!(spi->mode & SPI_NO_CS)) - op_mode |= 1 << spi->chip_select; + if (!(spi->mode & SPI_NO_CS)) { + pdata = davinci_spi->pdata; + if (!pdata->chip_sel || + pdata->chip_sel[spi->chip_select] == SPI_INTERN_CS) + op_mode |= 1 << spi->chip_select; + } if (spi->mode & SPI_READY) op_mode |= SPIPC0_SPIENA_MASK; @@ -1101,6 +1118,14 @@ static int davinci_spi_probe(struct platform_device *pdev) udelay(100); iowrite32(1, davinci_spi->base + SPIGCR0); + /* initialize chip selects */ + if (pdata->chip_sel) { + for (i = 0; i < pdata->num_chipselect; i++) { + if (pdata->chip_sel[i] != SPI_INTERN_CS) + gpio_direction_output(pdata->chip_sel[i], 1); + } + } + /* Clock internal */ if (davinci_spi->pdata->clk_internal) set_io_bits(davinci_spi->base + SPIGCR1, -- cgit v1.2.3-70-g09d2 From 472880c73da124b6cb5cbc31a36754aa62935afe Mon Sep 17 00:00:00 2001 From: Brian Niebuhr Date: Mon, 16 Aug 2010 10:28:53 +0530 Subject: spi: davinci: remove 'wait_enable' platform data member The SPI_READY bit of struct spi_device:mode serves the purpose of letting the SPI master know if the slave can signal if it is ready for transfer or not. The 'wait_enable' platform data was duplicating this functionality. Use the framework provided method of indicating this capability. Signed-off-by: Brian Niebuhr Tested-By: Michael Williamson Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/include/mach/spi.h | 1 - drivers/spi/davinci_spi.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-davinci/include/mach/spi.h b/arch/arm/mach-davinci/include/mach/spi.h index 734d1fb9961..fe699140269 100644 --- a/arch/arm/mach-davinci/include/mach/spi.h +++ b/arch/arm/mach-davinci/include/mach/spi.h @@ -32,7 +32,6 @@ struct davinci_spi_platform_data { u8 wdelay; u8 odd_parity; u8 parity_enable; - u8 wait_enable; u8 timer_disable; u8 clk_internal; u8 intr_level; diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 17269ad54a9..54808577c12 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -522,7 +522,7 @@ static int davinci_spi_setup(struct spi_device *spi) SPIFMT_PARITYENA_MASK, spi->chip_select); - if (davinci_spi->pdata->wait_enable) + if (spi->mode & SPI_READY) set_fmt_bits(davinci_spi->base, SPIFMT_WAITENA_MASK, spi->chip_select); -- cgit v1.2.3-70-g09d2 From 53a31b07c5aea4001bbb36ddd5ef2addffc7ccbd Mon Sep 17 00:00:00 2001 From: Brian Niebuhr Date: Mon, 16 Aug 2010 15:05:51 +0530 Subject: spi: davinci: make chip-slect specific parameters really chip-select specific Some chip-select specific paramterers like wdelay, parity, usage of chip-select timers (and the actual timer values) are included in platform data forcing the same behaviour across all chip-selects. Create a new davinci_spi_config data structure which can be passed along using controller_data member of spi_device data structure on a per-device basis. Signed-off-by: Brian Niebuhr Tested-By: Michael Williamson Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/dm355.c | 3 -- arch/arm/mach-davinci/dm365.c | 3 -- arch/arm/mach-davinci/include/mach/spi.h | 13 ++++--- drivers/spi/davinci_spi.c | 67 ++++++++++++++++++-------------- 4 files changed, 45 insertions(+), 41 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index 6a76dfa60ef..a6d9b72190f 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -413,10 +413,7 @@ static struct davinci_spi_platform_data dm355_spi0_pdata = { .version = SPI_VERSION_1, .num_chipselect = 2, .clk_internal = 1, - .intr_level = 0, .poll_mode = 1, /* 0 -> interrupt mode 1-> polling mode */ - .c2tdelay = 0, - .t2cdelay = 0, }; static struct platform_device dm355_spi0_device = { .name = "spi_davinci", diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index cd623db8d7d..80dd159134c 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -626,10 +626,7 @@ static struct davinci_spi_platform_data dm365_spi0_pdata = { .version = SPI_VERSION_1, .num_chipselect = 2, .clk_internal = 1, - .intr_level = 0, .poll_mode = 1, /* 0 -> interrupt mode 1-> polling mode */ - .c2tdelay = 0, - .t2cdelay = 0, }; static struct resource dm365_spi0_resources[] = { diff --git a/arch/arm/mach-davinci/include/mach/spi.h b/arch/arm/mach-davinci/include/mach/spi.h index fe699140269..29c19c425b0 100644 --- a/arch/arm/mach-davinci/include/mach/spi.h +++ b/arch/arm/mach-davinci/include/mach/spi.h @@ -29,17 +29,20 @@ enum { struct davinci_spi_platform_data { u8 version; u8 num_chipselect; - u8 wdelay; - u8 odd_parity; - u8 parity_enable; - u8 timer_disable; u8 clk_internal; u8 intr_level; u8 poll_mode; u8 use_dma; + u8 *chip_sel; +}; + +struct davinci_spi_config { + u8 wdelay; + u8 odd_parity; + u8 parity_enable; + u8 timer_disable; u8 c2tdelay; u8 t2cdelay; - u8 *chip_sel; }; #endif /* __ARCH_ARM_DAVINCI_SPI_H */ diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 54808577c12..d4320f78407 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -156,6 +156,8 @@ struct davinci_spi { struct davinci_spi_slave slave[SPI_MAX_CHIPSELECT]; }; +static struct davinci_spi_config davinci_spi_default_cfg; + static unsigned use_dma; static void davinci_spi_rx_buf_u8(u32 data, struct davinci_spi *davinci_spi) @@ -434,8 +436,12 @@ static int davinci_spi_setup(struct spi_device *spi) int retval; struct davinci_spi *davinci_spi; struct davinci_spi_dma *davinci_spi_dma; + struct davinci_spi_config *spicfg; davinci_spi = spi_master_get_devdata(spi->master); + spicfg = (struct davinci_spi_config *)spi->controller_data; + if (!spicfg) + spicfg = &davinci_spi_default_cfg; /* if bits per word length is zero then set it default 8 */ if (!spi->bits_per_word) @@ -496,31 +502,34 @@ static int davinci_spi_setup(struct spi_device *spi) */ if (davinci_spi->version == SPI_VERSION_2) { + clear_fmt_bits(davinci_spi->base, SPIFMT_WDELAY_MASK, - spi->chip_select); + spi->chip_select); set_fmt_bits(davinci_spi->base, - (davinci_spi->pdata->wdelay - << SPIFMT_WDELAY_SHIFT) - & SPIFMT_WDELAY_MASK, - spi->chip_select); + (spicfg->wdelay << SPIFMT_WDELAY_SHIFT) & + SPIFMT_WDELAY_MASK, spi->chip_select); - if (davinci_spi->pdata->odd_parity) - set_fmt_bits(davinci_spi->base, - SPIFMT_ODD_PARITY_MASK, - spi->chip_select); + if (spicfg->odd_parity) + set_fmt_bits(davinci_spi->base, SPIFMT_ODD_PARITY_MASK, + spi->chip_select); else clear_fmt_bits(davinci_spi->base, SPIFMT_ODD_PARITY_MASK, spi->chip_select); - if (davinci_spi->pdata->parity_enable) - set_fmt_bits(davinci_spi->base, - SPIFMT_PARITYENA_MASK, - spi->chip_select); + if (spicfg->parity_enable) + set_fmt_bits(davinci_spi->base, SPIFMT_PARITYENA_MASK, + spi->chip_select); else - clear_fmt_bits(davinci_spi->base, - SPIFMT_PARITYENA_MASK, - spi->chip_select); + clear_fmt_bits(davinci_spi->base, SPIFMT_PARITYENA_MASK, + spi->chip_select); + + if (spicfg->timer_disable) + set_fmt_bits(davinci_spi->base, SPIFMT_DISTIMER_MASK, + spi->chip_select); + else + clear_fmt_bits(davinci_spi->base, SPIFMT_DISTIMER_MASK, + spi->chip_select); if (spi->mode & SPI_READY) set_fmt_bits(davinci_spi->base, @@ -531,14 +540,6 @@ static int davinci_spi_setup(struct spi_device *spi) SPIFMT_WAITENA_MASK, spi->chip_select); - if (davinci_spi->pdata->timer_disable) - set_fmt_bits(davinci_spi->base, - SPIFMT_DISTIMER_MASK, - spi->chip_select); - else - clear_fmt_bits(davinci_spi->base, - SPIFMT_DISTIMER_MASK, - spi->chip_select); } retval = davinci_spi_setup_transfer(spi, NULL); @@ -662,9 +663,13 @@ static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t) u32 tx_data, data1_reg_val; u32 buf_val, flg_val; struct davinci_spi_platform_data *pdata; + struct davinci_spi_config *spicfg; davinci_spi = spi_master_get_devdata(spi->master); pdata = davinci_spi->pdata; + spicfg = (struct davinci_spi_config *)spi->controller_data; + if (!spicfg) + spicfg = &davinci_spi_default_cfg; davinci_spi->tx = t->tx_buf; davinci_spi->rx = t->rx_buf; @@ -684,8 +689,8 @@ static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t) /* Enable SPI */ set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK); - iowrite32(0 | (pdata->c2tdelay << SPI_C2TDELAY_SHIFT) | - (pdata->t2cdelay << SPI_T2CDELAY_SHIFT), + iowrite32((spicfg->c2tdelay << SPI_C2TDELAY_SHIFT) | + (spicfg->t2cdelay << SPI_T2CDELAY_SHIFT), davinci_spi->base + SPIDELAY); count = davinci_spi->count; @@ -792,12 +797,14 @@ static int davinci_spi_bufs_dma(struct spi_device *spi, struct spi_transfer *t) struct davinci_spi_dma *davinci_spi_dma; int word_len, data_type, ret; unsigned long tx_reg, rx_reg; - struct davinci_spi_platform_data *pdata; + struct davinci_spi_config *spicfg; struct device *sdev; davinci_spi = spi_master_get_devdata(spi->master); - pdata = davinci_spi->pdata; sdev = davinci_spi->bitbang.master->dev.parent; + spicfg = (struct davinci_spi_config *)spi->controller_data; + if (!spicfg) + spicfg = &davinci_spi_default_cfg; davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select]; @@ -834,8 +841,8 @@ static int davinci_spi_bufs_dma(struct spi_device *spi, struct spi_transfer *t) return ret; /* Put delay val if required */ - iowrite32(0 | (pdata->c2tdelay << SPI_C2TDELAY_SHIFT) | - (pdata->t2cdelay << SPI_T2CDELAY_SHIFT), + iowrite32((spicfg->c2tdelay << SPI_C2TDELAY_SHIFT) | + (spicfg->t2cdelay << SPI_T2CDELAY_SHIFT), davinci_spi->base + SPIDELAY); count = davinci_spi->count; /* the number of elements */ -- cgit v1.2.3-70-g09d2 From 7abbf23c5903e14b0cff1cdeab906eab164be767 Mon Sep 17 00:00:00 2001 From: Brian Niebuhr Date: Thu, 19 Aug 2010 15:07:38 +0530 Subject: spi: davinci: add support for wait enable timeouts Just enabling WAITENA in SPIFMTn register waits for the enable signal from the slave indefinitely. Allow support for finite waiting by adding support for c2e delay (maximum time for addressed slave to respond) and t2e delay (maximum time for slave to respond after transmit data finished). While at it, modify the T2C and C2T defines by prepending the register name as is the convention followed for other register field elsewhere in the driver. Signed-off-by: Brian Niebuhr Tested-By: Michael Williamson Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/include/mach/spi.h | 2 ++ drivers/spi/davinci_spi.c | 36 ++++++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 9 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-davinci/include/mach/spi.h b/arch/arm/mach-davinci/include/mach/spi.h index 29c19c425b0..483b055da44 100644 --- a/arch/arm/mach-davinci/include/mach/spi.h +++ b/arch/arm/mach-davinci/include/mach/spi.h @@ -43,6 +43,8 @@ struct davinci_spi_config { u8 timer_disable; u8 c2tdelay; u8 t2cdelay; + u8 t2edelay; + u8 c2edelay; }; #endif /* __ARCH_ARM_DAVINCI_SPI_H */ diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index d09b63cf58b..e94c63813e9 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -78,6 +78,16 @@ #define SPIBUF_TXFULL_MASK BIT(29) #define SPIBUF_RXEMPTY_MASK BIT(31) +/* SPIDELAY */ +#define SPIDELAY_C2TDELAY_SHIFT 24 +#define SPIDELAY_C2TDELAY_MASK (0xFF << SPIDELAY_C2TDELAY_SHIFT) +#define SPIDELAY_T2CDELAY_SHIFT 16 +#define SPIDELAY_T2CDELAY_MASK (0xFF << SPIDELAY_T2CDELAY_SHIFT) +#define SPIDELAY_T2EDELAY_SHIFT 8 +#define SPIDELAY_T2EDELAY_MASK (0xFF << SPIDELAY_T2EDELAY_SHIFT) +#define SPIDELAY_C2EDELAY_SHIFT 0 +#define SPIDELAY_C2EDELAY_MASK 0xFF + /* Error Masks */ #define SPIFLG_DLEN_ERR_MASK BIT(0) #define SPIFLG_TIMEOUT_MASK BIT(1) @@ -95,9 +105,6 @@ #define SPIINT_TX_INTR BIT(9) #define SPIINT_DMA_REQ_EN BIT(16) -#define SPI_T2CDELAY_SHIFT 16 -#define SPI_C2TDELAY_SHIFT 24 - /* SPI Controller registers */ #define SPIGCR0 0x00 #define SPIGCR1 0x04 @@ -363,6 +370,8 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, if (davinci_spi->version == SPI_VERSION_2) { + u32 delay = 0; + spifmt |= ((spicfg->wdelay << SPIFMT_WDELAY_SHIFT) & SPIFMT_WDELAY_MASK); @@ -372,15 +381,24 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, if (spicfg->parity_enable) spifmt |= SPIFMT_PARITYENA_MASK; - if (spicfg->timer_disable) + if (spicfg->timer_disable) { spifmt |= SPIFMT_DISTIMER_MASK; - else - iowrite32((spicfg->c2tdelay << SPI_C2TDELAY_SHIFT) | - (spicfg->t2cdelay << SPI_T2CDELAY_SHIFT), - davinci_spi->base + SPIDELAY); + } else { + delay |= (spicfg->c2tdelay << SPIDELAY_C2TDELAY_SHIFT) + & SPIDELAY_C2TDELAY_MASK; + delay |= (spicfg->t2cdelay << SPIDELAY_T2CDELAY_SHIFT) + & SPIDELAY_T2CDELAY_MASK; + } - if (spi->mode & SPI_READY) + if (spi->mode & SPI_READY) { spifmt |= SPIFMT_WAITENA_MASK; + delay |= (spicfg->t2edelay << SPIDELAY_T2EDELAY_SHIFT) + & SPIDELAY_T2EDELAY_MASK; + delay |= (spicfg->c2edelay << SPIDELAY_C2EDELAY_SHIFT) + & SPIDELAY_C2EDELAY_MASK; + } + + iowrite32(delay, davinci_spi->base + SPIDELAY); } iowrite32(spifmt, davinci_spi->base + SPIFMT0); -- cgit v1.2.3-70-g09d2 From cf90fe73504764cbcc2552c7ea69b1866059db30 Mon Sep 17 00:00:00 2001 From: Brian Niebuhr Date: Fri, 20 Aug 2010 17:02:49 +0530 Subject: spi: davinci: remove non-useful interrupt mode support The interrupt mode support as it stands is another version of poll mode. Even when interrupt mode is selected, the code tight loops on interrupt status register, rendering it totally useless. A completion variable is initialized, but never used. Remove this fake interrupt mode since users can anyway use poll mode with no functional difference. A usefully implemented interrupt mode support can be added later. Signed-off-by: Brian Niebuhr Tested-By: Michael Williamson Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/dm355.c | 1 - arch/arm/mach-davinci/dm365.c | 1 - arch/arm/mach-davinci/include/mach/spi.h | 2 - drivers/spi/davinci_spi.c | 126 +++++-------------------------- 4 files changed, 19 insertions(+), 111 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index a6d9b72190f..e311f29ffb5 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -413,7 +413,6 @@ static struct davinci_spi_platform_data dm355_spi0_pdata = { .version = SPI_VERSION_1, .num_chipselect = 2, .clk_internal = 1, - .poll_mode = 1, /* 0 -> interrupt mode 1-> polling mode */ }; static struct platform_device dm355_spi0_device = { .name = "spi_davinci", diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index 80dd159134c..1e5012e196b 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -626,7 +626,6 @@ static struct davinci_spi_platform_data dm365_spi0_pdata = { .version = SPI_VERSION_1, .num_chipselect = 2, .clk_internal = 1, - .poll_mode = 1, /* 0 -> interrupt mode 1-> polling mode */ }; static struct resource dm365_spi0_resources[] = { diff --git a/arch/arm/mach-davinci/include/mach/spi.h b/arch/arm/mach-davinci/include/mach/spi.h index 483b055da44..e68afe23885 100644 --- a/arch/arm/mach-davinci/include/mach/spi.h +++ b/arch/arm/mach-davinci/include/mach/spi.h @@ -30,8 +30,6 @@ struct davinci_spi_platform_data { u8 version; u8 num_chipselect; u8 clk_internal; - u8 intr_level; - u8 poll_mode; u8 use_dma; u8 *chip_sel; }; diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 54d06f409b6..198f062da37 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -59,8 +59,6 @@ #define SPIPC0_SPIENA_MASK BIT(8) /* nREADY */ #define SPIINT_MASKALL 0x0101035F -#define SPI_INTLVL_1 0x000001FFu -#define SPI_INTLVL_0 0x00000000u /* SPIDAT1 (upper 16 bit defines) */ #define SPIDAT1_CSHOLD_MASK BIT(12) @@ -92,14 +90,8 @@ #define SPIFLG_DESYNC_MASK BIT(3) #define SPIFLG_BITERR_MASK BIT(4) #define SPIFLG_OVRRUN_MASK BIT(6) -#define SPIFLG_RX_INTR_MASK BIT(8) -#define SPIFLG_TX_INTR_MASK BIT(9) #define SPIFLG_BUF_INIT_ACTIVE_MASK BIT(24) -#define SPIINT_BITERR_INTR BIT(4) -#define SPIINT_OVRRUN_INTR BIT(6) -#define SPIINT_RX_INTR BIT(8) -#define SPIINT_TX_INTR BIT(9) #define SPIINT_DMA_REQ_EN BIT(16) /* SPI Controller registers */ @@ -136,8 +128,6 @@ struct davinci_spi { resource_size_t pbase; void __iomem *base; size_t region_size; - u32 irq; - struct completion done; const void *tx; void *rx; @@ -611,7 +601,7 @@ static int davinci_spi_check_error(struct davinci_spi *davinci_spi, static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t) { struct davinci_spi *davinci_spi; - int int_status, count, ret; + int status, count, ret; u8 conv; u32 tx_data, data1_reg_val; u32 buf_val, flg_val; @@ -627,8 +617,6 @@ static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t) conv = davinci_spi->bytes_per_word[spi->chip_select]; data1_reg_val = ioread32(davinci_spi->base + SPIDAT1); - INIT_COMPLETION(davinci_spi->done); - ret = davinci_spi_bufs_prep(spi, davinci_spi); if (ret) return ret; @@ -638,9 +626,10 @@ static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t) count = t->len / conv; + clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL); + /* Determine the command to execute READ or WRITE */ if (t->tx_buf) { - clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL); while (1) { tx_data = davinci_spi->get_tx(davinci_spi); @@ -668,45 +657,25 @@ static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t) break; } } else { - if (pdata->poll_mode) { - while (1) { - /* keeps the serial clock going */ - if ((ioread32(davinci_spi->base + SPIBUF) - & SPIBUF_TXFULL_MASK) == 0) - iowrite32(data1_reg_val, - davinci_spi->base + SPIDAT1); + while (1) { + /* keeps the serial clock going */ + if ((ioread32(davinci_spi->base + SPIBUF) + & SPIBUF_TXFULL_MASK) == 0) + iowrite32(data1_reg_val, + davinci_spi->base + SPIDAT1); while (ioread32(davinci_spi->base + SPIBUF) & - SPIBUF_RXEMPTY_MASK) + SPIBUF_RXEMPTY_MASK) cpu_relax(); - flg_val = ioread32(davinci_spi->base + SPIFLG); - buf_val = ioread32(davinci_spi->base + SPIBUF); - - davinci_spi->get_rx(buf_val, davinci_spi); - - count--; - if (count <= 0) - break; - } - } else { /* Receive in Interrupt mode */ - int i; - - for (i = 0; i < count; i++) { - set_io_bits(davinci_spi->base + SPIINT, - SPIINT_BITERR_INTR - | SPIINT_OVRRUN_INTR - | SPIINT_RX_INTR); + flg_val = ioread32(davinci_spi->base + SPIFLG); + buf_val = ioread32(davinci_spi->base + SPIBUF); - iowrite32(data1_reg_val, - davinci_spi->base + SPIDAT1); + davinci_spi->get_rx(buf_val, davinci_spi); - while (ioread32(davinci_spi->base + SPIINT) & - SPIINT_RX_INTR) - cpu_relax(); - } - iowrite32((data1_reg_val & 0x0ffcffff), - davinci_spi->base + SPIDAT1); + count--; + if (count <= 0) + break; } } @@ -714,9 +683,9 @@ static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t) * Check for bit error, desync error,parity error,timeout error and * receive overflow errors */ - int_status = ioread32(davinci_spi->base + SPIFLG); + status = ioread32(davinci_spi->base + SPIFLG); - ret = davinci_spi_check_error(davinci_spi, int_status); + ret = davinci_spi_check_error(davinci_spi, status); if (ret != 0) return ret; @@ -853,38 +822,6 @@ static int davinci_spi_bufs_dma(struct spi_device *spi, struct spi_transfer *t) return t->len; } -/** - * davinci_spi_irq - IRQ handler for DaVinci SPI - * @irq: IRQ number for this SPI Master - * @context_data: structure for SPI Master controller davinci_spi - */ -static irqreturn_t davinci_spi_irq(s32 irq, void *context_data) -{ - struct davinci_spi *davinci_spi = context_data; - u32 int_status, rx_data = 0; - irqreturn_t ret = IRQ_NONE; - - int_status = ioread32(davinci_spi->base + SPIFLG); - - while ((int_status & SPIFLG_RX_INTR_MASK)) { - if (likely(int_status & SPIFLG_RX_INTR_MASK)) { - ret = IRQ_HANDLED; - - rx_data = ioread32(davinci_spi->base + SPIBUF); - davinci_spi->get_rx(rx_data, davinci_spi); - - /* Disable Receive Interrupt */ - iowrite32(~(SPIINT_RX_INTR | SPIINT_TX_INTR), - davinci_spi->base + SPIINT); - } else - (void)davinci_spi_check_error(davinci_spi, int_status); - - int_status = ioread32(davinci_spi->base + SPIFLG); - } - - return ret; -} - /** * davinci_spi_probe - probe function for SPI Master Controller * @pdev: platform_device structure which contains plateform specific data @@ -943,22 +880,11 @@ static int davinci_spi_probe(struct platform_device *pdev) goto release_region; } - davinci_spi->irq = platform_get_irq(pdev, 0); - if (davinci_spi->irq <= 0) { - ret = -EINVAL; - goto unmap_io; - } - - ret = request_irq(davinci_spi->irq, davinci_spi_irq, IRQF_DISABLED, - dev_name(&pdev->dev), davinci_spi); - if (ret) - goto unmap_io; - /* Allocate tmp_buf for tx_buf */ davinci_spi->tmp_buf = kzalloc(SPI_BUFSIZ, GFP_KERNEL); if (davinci_spi->tmp_buf == NULL) { ret = -ENOMEM; - goto irq_free; + goto unmap_io; } davinci_spi->bitbang.master = spi_master_get(master); @@ -1034,8 +960,6 @@ static int davinci_spi_probe(struct platform_device *pdev) davinci_spi->get_rx = davinci_spi_rx_buf_u8; davinci_spi->get_tx = davinci_spi_tx_buf_u8; - init_completion(&davinci_spi->done); - /* Reset In/OUT SPI module */ iowrite32(0, davinci_spi->base + SPIGCR0); udelay(100); @@ -1062,21 +986,12 @@ static int davinci_spi_probe(struct platform_device *pdev) /* master mode default */ set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_MASTER_MASK); - if (davinci_spi->pdata->intr_level) - iowrite32(SPI_INTLVL_1, davinci_spi->base + SPILVL); - else - iowrite32(SPI_INTLVL_0, davinci_spi->base + SPILVL); - ret = spi_bitbang_start(&davinci_spi->bitbang); if (ret) goto free_clk; dev_info(&pdev->dev, "Controller at 0x%p\n", davinci_spi->base); - if (!pdata->poll_mode) - dev_info(&pdev->dev, "Operating in interrupt mode" - " using IRQ %d\n", davinci_spi->irq); - return ret; free_clk: @@ -1086,8 +1001,6 @@ put_master: spi_master_put(master); free_tmp_buf: kfree(davinci_spi->tmp_buf); -irq_free: - free_irq(davinci_spi->irq, davinci_spi); unmap_io: iounmap(davinci_spi->base); release_region: @@ -1121,7 +1034,6 @@ static int __exit davinci_spi_remove(struct platform_device *pdev) clk_put(davinci_spi->clk); spi_master_put(master); kfree(davinci_spi->tmp_buf); - free_irq(davinci_spi->irq, davinci_spi); iounmap(davinci_spi->base); release_mem_region(davinci_spi->pbase, davinci_spi->region_size); -- cgit v1.2.3-70-g09d2 From e0d205e9914476e96596c5339fa440fb314ef03b Mon Sep 17 00:00:00 2001 From: Brian Niebuhr Date: Thu, 2 Sep 2010 16:52:06 +0530 Subject: spi: davinci: add support for interrupt mode Add support for SPI interrupt mode operation. Define a per chip-select "io type" variable which specifies if the transfers on this chip-select should happen in interrupt mode or polled mode. Introduce a new function davinci_spi_process_events() to help consolidate the code between interrupt mode processing and polled mode processing. Signed-off-by: Brian Niebuhr Tested-By: Michael Williamson Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/include/mach/spi.h | 4 + drivers/spi/davinci_spi.c | 145 ++++++++++++++++++++++++------- 2 files changed, 119 insertions(+), 30 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-davinci/include/mach/spi.h b/arch/arm/mach-davinci/include/mach/spi.h index e68afe23885..ab45b89a0c5 100644 --- a/arch/arm/mach-davinci/include/mach/spi.h +++ b/arch/arm/mach-davinci/include/mach/spi.h @@ -30,6 +30,7 @@ struct davinci_spi_platform_data { u8 version; u8 num_chipselect; u8 clk_internal; + u8 intr_line; u8 use_dma; u8 *chip_sel; }; @@ -38,6 +39,9 @@ struct davinci_spi_config { u8 wdelay; u8 odd_parity; u8 parity_enable; +#define SPI_IO_TYPE_INTR 0 +#define SPI_IO_TYPE_POLL 1 + u8 io_type; u8 timer_disable; u8 c2tdelay; u8 t2cdelay; diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index cd37697850c..45cc1a77a51 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -59,6 +59,9 @@ #define SPIPC0_SPIENA_MASK BIT(8) /* nREADY */ #define SPIINT_MASKALL 0x0101035F +#define SPIINT_MASKINT 0x0000015F +#define SPI_INTLVL_1 0x000001FF +#define SPI_INTLVL_0 0x00000000 /* SPIDAT1 (upper 16 bit defines) */ #define SPIDAT1_CSHOLD_MASK BIT(12) @@ -132,10 +135,14 @@ struct davinci_spi { resource_size_t pbase; void __iomem *base; size_t region_size; + u32 irq; + struct completion done; const void *tx; void *rx; u8 *tmp_buf; + int rcount; + int wcount; struct davinci_spi_dma *dma_channels; struct davinci_spi_platform_data *pdata; @@ -593,6 +600,43 @@ static int davinci_spi_check_error(struct davinci_spi *davinci_spi, return 0; } +/** + * davinci_spi_process_events - check for and handle any SPI controller events + * @davinci_spi: the controller data + * + * This function will check the SPIFLG register and handle any events that are + * detected there + */ +static int davinci_spi_process_events(struct davinci_spi *davinci_spi) +{ + u32 buf, status, errors = 0, data1_reg_val; + + buf = ioread32(davinci_spi->base + SPIBUF); + + if (davinci_spi->rcount > 0 && !(buf & SPIBUF_RXEMPTY_MASK)) { + davinci_spi->get_rx(buf & 0xFFFF, davinci_spi); + davinci_spi->rcount--; + } + + status = ioread32(davinci_spi->base + SPIFLG); + + if (unlikely(status & SPIFLG_ERROR_MASK)) { + errors = status & SPIFLG_ERROR_MASK; + goto out; + } + + if (davinci_spi->wcount > 0 && !(buf & SPIBUF_TXFULL_MASK)) { + data1_reg_val = ioread32(davinci_spi->base + SPIDAT1); + davinci_spi->wcount--; + data1_reg_val &= ~0xFFFF; + data1_reg_val |= 0xFFFF & davinci_spi->get_tx(davinci_spi); + iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1); + } + +out: + return errors; +} + /** * davinci_spi_bufs - functions which will handle transfer data * @spi: spi device on which data transfer to be done @@ -606,18 +650,22 @@ static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t) { struct davinci_spi *davinci_spi; int ret; - int rcount, wcount; u32 tx_data, data1_reg_val; u32 errors = 0; + struct davinci_spi_config *spicfg; struct davinci_spi_platform_data *pdata; davinci_spi = spi_master_get_devdata(spi->master); pdata = davinci_spi->pdata; + spicfg = (struct davinci_spi_config *)spi->controller_data; + if (!spicfg) + spicfg = &davinci_spi_default_cfg; davinci_spi->tx = t->tx_buf; davinci_spi->rx = t->rx_buf; - wcount = t->len / davinci_spi->bytes_per_word[spi->chip_select]; - rcount = wcount; + davinci_spi->wcount = t->len / + davinci_spi->bytes_per_word[spi->chip_select]; + davinci_spi->rcount = davinci_spi->wcount; ret = davinci_spi_bufs_prep(spi, davinci_spi); if (ret) @@ -628,42 +676,32 @@ static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t) /* Enable SPI */ set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK); - clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL); + if (spicfg->io_type == SPI_IO_TYPE_INTR) { + set_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKINT); + INIT_COMPLETION(davinci_spi->done); + } /* start the transfer */ - wcount--; + davinci_spi->wcount--; tx_data = davinci_spi->get_tx(davinci_spi); data1_reg_val &= 0xFFFF0000; data1_reg_val |= tx_data & 0xFFFF; iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1); - while (rcount > 0 || wcount > 0) { - - u32 buf, status; - - buf = ioread32(davinci_spi->base + SPIBUF); - - if (!(buf & SPIBUF_RXEMPTY_MASK)) { - davinci_spi->get_rx(buf & 0xFFFF, davinci_spi); - rcount--; - } - - status = ioread32(davinci_spi->base + SPIFLG); - - if (unlikely(status & SPIFLG_ERROR_MASK)) { - errors = status & SPIFLG_ERROR_MASK; - break; - } - - if (wcount > 0 && !(buf & SPIBUF_TXFULL_MASK)) { - wcount--; - tx_data = davinci_spi->get_tx(davinci_spi); - data1_reg_val &= ~0xFFFF; - data1_reg_val |= 0xFFFF & tx_data; - iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1); + /* Wait for the transfer to complete */ + if (spicfg->io_type == SPI_IO_TYPE_INTR) { + wait_for_completion_interruptible(&(davinci_spi->done)); + } else { + while (davinci_spi->rcount > 0 || davinci_spi->wcount > 0) { + errors = davinci_spi_process_events(davinci_spi); + if (errors) + break; + cpu_relax(); } } + clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL); + /* * Check for bit error, desync error,parity error,timeout error and * receive overflow errors @@ -678,6 +716,32 @@ static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t) return t->len; } +/** + * davinci_spi_irq - Interrupt handler for SPI Master Controller + * @irq: IRQ number for this SPI Master + * @context_data: structure for SPI Master controller davinci_spi + * + * ISR will determine that interrupt arrives either for READ or WRITE command. + * According to command it will do the appropriate action. It will check + * transfer length and if it is not zero then dispatch transfer command again. + * If transfer length is zero then it will indicate the COMPLETION so that + * davinci_spi_bufs function can go ahead. + */ +static irqreturn_t davinci_spi_irq(s32 irq, void *context_data) +{ + struct davinci_spi *davinci_spi = context_data; + int status; + + status = davinci_spi_process_events(davinci_spi); + if (unlikely(status != 0)) + clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKINT); + + if ((!davinci_spi->rcount && !davinci_spi->wcount) || status) + complete(&davinci_spi->done); + + return IRQ_HANDLED; +} + static int davinci_spi_bufs_dma(struct spi_device *spi, struct spi_transfer *t) { struct davinci_spi *davinci_spi; @@ -866,11 +930,22 @@ static int davinci_spi_probe(struct platform_device *pdev) goto release_region; } + davinci_spi->irq = platform_get_irq(pdev, 0); + if (davinci_spi->irq <= 0) { + ret = -EINVAL; + goto unmap_io; + } + + ret = request_irq(davinci_spi->irq, davinci_spi_irq, 0, + dev_name(&pdev->dev), davinci_spi); + if (ret) + goto unmap_io; + /* Allocate tmp_buf for tx_buf */ davinci_spi->tmp_buf = kzalloc(SPI_BUFSIZ, GFP_KERNEL); if (davinci_spi->tmp_buf == NULL) { ret = -ENOMEM; - goto unmap_io; + goto irq_free; } davinci_spi->bitbang.master = spi_master_get(master); @@ -946,6 +1021,8 @@ static int davinci_spi_probe(struct platform_device *pdev) davinci_spi->get_rx = davinci_spi_rx_buf_u8; davinci_spi->get_tx = davinci_spi_tx_buf_u8; + init_completion(&davinci_spi->done); + /* Reset In/OUT SPI module */ iowrite32(0, davinci_spi->base + SPIGCR0); udelay(100); @@ -967,6 +1044,11 @@ static int davinci_spi_probe(struct platform_device *pdev) clear_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_CLKMOD_MASK); + if (pdata->intr_line) + iowrite32(SPI_INTLVL_1, davinci_spi->base + SPILVL); + else + iowrite32(SPI_INTLVL_0, davinci_spi->base + SPILVL); + iowrite32(CS_DEFAULT, davinci_spi->base + SPIDEF); /* master mode default */ @@ -987,6 +1069,8 @@ put_master: spi_master_put(master); free_tmp_buf: kfree(davinci_spi->tmp_buf); +irq_free: + free_irq(davinci_spi->irq, davinci_spi); unmap_io: iounmap(davinci_spi->base); release_region: @@ -1020,6 +1104,7 @@ static int __exit davinci_spi_remove(struct platform_device *pdev) clk_put(davinci_spi->clk); spi_master_put(master); kfree(davinci_spi->tmp_buf); + free_irq(davinci_spi->irq, davinci_spi); iounmap(davinci_spi->base); release_mem_region(davinci_spi->pbase, davinci_spi->region_size); -- cgit v1.2.3-70-g09d2 From c29e3c60e75d1cc1262ac8af379738b6fd851f33 Mon Sep 17 00:00:00 2001 From: Brian Niebuhr Date: Tue, 28 Sep 2010 13:59:26 +0530 Subject: spi: davinci: always start transmit DMA Due to the full duplex nature of the SPI bus, the SPI master on DaVinci needs transmit to be active even if the tranfer is only meant to collect receive data. The current code achieves this by using a temporary zeroed buffer to provide DMA data in case the transfer does not have a transmit buffer provided. However, the transmit DMA is started only if transmit buffer is provided rendering the temporary buffer unused. Instead the code relies on a write to SPIDAT1 register to trigger transmit operation. This however only sends two bytes of data. Fix this by starting transmit DMA always. This changes exposes a bug on DM355 where the CSHOLD bit in SPIDAT1 needs to be written to in between transfers. Handle that by introducing a "cshold_bug" platform data which is set to true for DM355. Signed-off-by: Brian Niebuhr Tested-By: Michael Williamson Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/dm355.c | 1 + arch/arm/mach-davinci/include/mach/spi.h | 1 + drivers/spi/davinci_spi.c | 22 +++++++++------------- 3 files changed, 11 insertions(+), 13 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index e311f29ffb5..27ee870b2d2 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -413,6 +413,7 @@ static struct davinci_spi_platform_data dm355_spi0_pdata = { .version = SPI_VERSION_1, .num_chipselect = 2, .clk_internal = 1, + .cshold_bug = true, }; static struct platform_device dm355_spi0_device = { .name = "spi_davinci", diff --git a/arch/arm/mach-davinci/include/mach/spi.h b/arch/arm/mach-davinci/include/mach/spi.h index ab45b89a0c5..68db6d5daaf 100644 --- a/arch/arm/mach-davinci/include/mach/spi.h +++ b/arch/arm/mach-davinci/include/mach/spi.h @@ -33,6 +33,7 @@ struct davinci_spi_platform_data { u8 intr_line; u8 use_dma; u8 *chip_sel; + bool cshold_bug; }; struct davinci_spi_config { diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 4aa522134a9..a5f03dd8d8d 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -719,13 +719,14 @@ static int davinci_spi_bufs_dma(struct spi_device *spi, struct spi_transfer *t) struct davinci_spi *davinci_spi; int int_status = 0; int count, temp_count; - u32 data1_reg_val; struct davinci_spi_dma *davinci_spi_dma; int data_type, ret; unsigned long tx_reg, rx_reg; + struct davinci_spi_platform_data *pdata; struct device *sdev; davinci_spi = spi_master_get_devdata(spi->master); + pdata = davinci_spi->pdata; sdev = davinci_spi->bitbang.master->dev.parent; davinci_spi_dma = &davinci_spi->dma_channels; @@ -739,8 +740,6 @@ static int davinci_spi_bufs_dma(struct spi_device *spi, struct spi_transfer *t) /* convert len to words based on bits_per_word */ data_type = davinci_spi->bytes_per_word[spi->chip_select]; - data1_reg_val = ioread32(davinci_spi->base + SPIDAT1); - init_completion(&davinci_spi_dma->dma_rx_completion); init_completion(&davinci_spi_dma->dma_tx_completion); @@ -781,9 +780,6 @@ static int davinci_spi_bufs_dma(struct spi_device *spi, struct spi_transfer *t) edma_set_dest_index(davinci_spi_dma->dma_tx_channel, 0, 0); if (t->rx_buf) { - /* initiate transaction */ - iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1); - t->rx_dma = dma_map_single(&spi->dev, (void *)t->rx_buf, count, DMA_FROM_DEVICE); if (dma_mapping_error(&spi->dev, t->rx_dma)) { @@ -805,18 +801,18 @@ static int davinci_spi_bufs_dma(struct spi_device *spi, struct spi_transfer *t) data_type, 0); } - if ((t->tx_buf) || (t->rx_buf)) - edma_start(davinci_spi_dma->dma_tx_channel); + if (pdata->cshold_bug) { + u16 spidat1 = ioread16(davinci_spi->base + SPIDAT1 + 2); + iowrite16(spidat1, davinci_spi->base + SPIDAT1 + 2); + } if (t->rx_buf) edma_start(davinci_spi_dma->dma_rx_channel); - if ((t->rx_buf) || (t->tx_buf)) - davinci_spi_set_dma_req(spi, 1); + edma_start(davinci_spi_dma->dma_tx_channel); + davinci_spi_set_dma_req(spi, 1); - if (t->tx_buf) - wait_for_completion_interruptible( - &davinci_spi_dma->dma_tx_completion); + wait_for_completion_interruptible(&davinci_spi_dma->dma_tx_completion); if (t->rx_buf) wait_for_completion_interruptible( -- cgit v1.2.3-70-g09d2 From 903ca25b219e28e3513ca4c2ff379fcdf19e057e Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Fri, 1 Oct 2010 14:51:40 +0530 Subject: spi: davinci: do not allocate DMA channels during SPI device setup Do not allocate (and de-allocate) SPI DMA channels during setup (and cleanup) for each SPI device. Instead, allocate the DMA channels once duing probe and use them for the life time of the driver. This makes sense since there are dedicated DMA channels meant for SPI use. This also helps remove the unnecessary DMA "sync_dev" variables being used to store DMA channel information. Also, the "use_dma" platform variable is now eliminated since it is possible to check if the platform supports DMA or not based upon whether DMA resources can be found or not. Tested-By: Michael Williamson Tested-By: Brian Niebuhr Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/include/mach/spi.h | 1 - drivers/spi/davinci_spi.c | 153 +++++++++++-------------------- 2 files changed, 51 insertions(+), 103 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-davinci/include/mach/spi.h b/arch/arm/mach-davinci/include/mach/spi.h index 68db6d5daaf..f7586a03678 100644 --- a/arch/arm/mach-davinci/include/mach/spi.h +++ b/arch/arm/mach-davinci/include/mach/spi.h @@ -31,7 +31,6 @@ struct davinci_spi_platform_data { u8 num_chipselect; u8 clk_internal; u8 intr_line; - u8 use_dma; u8 *chip_sel; bool cshold_bug; }; diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 9695f98b03b..6db47860102 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -116,8 +116,6 @@ struct davinci_spi_dma { int dma_tx_channel; int dma_rx_channel; - int dma_tx_sync_dev; - int dma_rx_sync_dev; enum dma_event_q eventq; struct completion dma_tx_completion; @@ -153,8 +151,6 @@ struct davinci_spi { static struct davinci_spi_config davinci_spi_default_cfg; -static unsigned use_dma; - static void davinci_spi_rx_buf_u8(u32 data, struct davinci_spi *davinci_spi) { if (davinci_spi->rx) { @@ -391,12 +387,7 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, static void davinci_spi_dma_rx_callback(unsigned lch, u16 ch_status, void *data) { - struct spi_device *spi = (struct spi_device *)data; - struct davinci_spi *davinci_spi; - struct davinci_spi_dma *davinci_spi_dma; - - davinci_spi = spi_master_get_devdata(spi->master); - davinci_spi_dma = &davinci_spi->dma_channels; + struct davinci_spi_dma *davinci_spi_dma = data; if (ch_status == DMA_COMPLETE) edma_stop(davinci_spi_dma->dma_rx_channel); @@ -408,12 +399,7 @@ static void davinci_spi_dma_rx_callback(unsigned lch, u16 ch_status, void *data) static void davinci_spi_dma_tx_callback(unsigned lch, u16 ch_status, void *data) { - struct spi_device *spi = (struct spi_device *)data; - struct davinci_spi *davinci_spi; - struct davinci_spi_dma *davinci_spi_dma; - - davinci_spi = spi_master_get_devdata(spi->master); - davinci_spi_dma = &davinci_spi->dma_channels; + struct davinci_spi_dma *davinci_spi_dma = data; if (ch_status == DMA_COMPLETE) edma_stop(davinci_spi_dma->dma_tx_channel); @@ -423,39 +409,6 @@ static void davinci_spi_dma_tx_callback(unsigned lch, u16 ch_status, void *data) complete(&davinci_spi_dma->dma_tx_completion); } -static int davinci_spi_request_dma(struct spi_device *spi) -{ - struct davinci_spi *davinci_spi; - struct davinci_spi_dma *davinci_spi_dma; - struct device *sdev; - int r; - - davinci_spi = spi_master_get_devdata(spi->master); - davinci_spi_dma = &davinci_spi->dma_channels; - sdev = davinci_spi->bitbang.master->dev.parent; - - r = edma_alloc_channel(davinci_spi_dma->dma_rx_sync_dev, - davinci_spi_dma_rx_callback, spi, - davinci_spi_dma->eventq); - if (r < 0) { - dev_dbg(sdev, "Unable to request DMA channel for SPI RX\n"); - return -EAGAIN; - } - davinci_spi_dma->dma_rx_channel = r; - r = edma_alloc_channel(davinci_spi_dma->dma_tx_sync_dev, - davinci_spi_dma_tx_callback, spi, - davinci_spi_dma->eventq); - if (r < 0) { - edma_free_channel(davinci_spi_dma->dma_rx_channel); - davinci_spi_dma->dma_rx_channel = -1; - dev_dbg(sdev, "Unable to request DMA channel for SPI TX\n"); - return -EAGAIN; - } - davinci_spi_dma->dma_tx_channel = r; - - return 0; -} - /** * davinci_spi_setup - This functions will set default transfer method * @spi: spi device on which data transfer to be done @@ -466,7 +419,6 @@ static int davinci_spi_setup(struct spi_device *spi) { int retval = 0; struct davinci_spi *davinci_spi; - struct davinci_spi_dma *davinci_spi_dma; struct davinci_spi_platform_data *pdata; davinci_spi = spi_master_get_devdata(spi->master); @@ -494,33 +446,9 @@ static int davinci_spi_setup(struct spi_device *spi) clear_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_LOOPBACK_MASK); - if (use_dma) { - davinci_spi_dma = &davinci_spi->dma_channels; - - if ((davinci_spi_dma->dma_rx_channel == -1) || - (davinci_spi_dma->dma_tx_channel == -1)) - retval = davinci_spi_request_dma(spi); - } - return retval; } -static void davinci_spi_cleanup(struct spi_device *spi) -{ - if (use_dma) { - struct davinci_spi *davinci_spi = - spi_master_get_devdata(spi->master); - struct davinci_spi_dma *davinci_spi_dma = - &davinci_spi->dma_channels; - - if ((davinci_spi_dma->dma_rx_channel != -1) - && (davinci_spi_dma->dma_tx_channel != -1)) { - edma_free_channel(davinci_spi_dma->dma_tx_channel); - edma_free_channel(davinci_spi_dma->dma_rx_channel); - } - } -} - static int davinci_spi_check_error(struct davinci_spi *davinci_spi, int int_status) { @@ -842,6 +770,30 @@ static int davinci_spi_bufs_dma(struct spi_device *spi, struct spi_transfer *t) return t->len; } +static int davinci_spi_request_dma(struct davinci_spi_dma *davinci_spi_dma) +{ + int r; + + r = edma_alloc_channel(davinci_spi_dma->dma_rx_channel, + davinci_spi_dma_rx_callback, davinci_spi_dma, + davinci_spi_dma->eventq); + if (r < 0) { + pr_err("Unable to request DMA channel for SPI RX\n"); + return -EAGAIN; + } + + r = edma_alloc_channel(davinci_spi_dma->dma_tx_channel, + davinci_spi_dma_tx_callback, davinci_spi_dma, + davinci_spi_dma->eventq); + if (r < 0) { + edma_free_channel(davinci_spi_dma->dma_rx_channel); + pr_err("Unable to request DMA channel for SPI TX\n"); + return -EAGAIN; + } + + return 0; +} + /** * davinci_spi_probe - probe function for SPI Master Controller * @pdev: platform_device structure which contains plateform specific data @@ -928,45 +880,39 @@ static int davinci_spi_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->num_chipselect = pdata->num_chipselect; master->setup = davinci_spi_setup; - master->cleanup = davinci_spi_cleanup; davinci_spi->bitbang.chipselect = davinci_spi_chipselect; davinci_spi->bitbang.setup_transfer = davinci_spi_setup_transfer; davinci_spi->version = pdata->version; - use_dma = pdata->use_dma; davinci_spi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP; if (davinci_spi->version == SPI_VERSION_2) davinci_spi->bitbang.flags |= SPI_READY; - if (use_dma) { - r = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (r) - dma_rx_chan = r->start; - r = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (r) - dma_tx_chan = r->start; - r = platform_get_resource(pdev, IORESOURCE_DMA, 2); - if (r) - dma_eventq = r->start; - } - - if (!use_dma || - dma_rx_chan == SPI_NO_RESOURCE || - dma_tx_chan == SPI_NO_RESOURCE || - dma_eventq == SPI_NO_RESOURCE) { - davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_pio; - use_dma = 0; - } else { - davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_dma; - - davinci_spi->dma_channels.dma_rx_channel = -1; - davinci_spi->dma_channels.dma_rx_sync_dev = dma_rx_chan; - davinci_spi->dma_channels.dma_tx_channel = -1; - davinci_spi->dma_channels.dma_tx_sync_dev = dma_tx_chan; + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (r) + dma_rx_chan = r->start; + r = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (r) + dma_tx_chan = r->start; + r = platform_get_resource(pdev, IORESOURCE_DMA, 2); + if (r) + dma_eventq = r->start; + + davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_pio; + if (dma_rx_chan != SPI_NO_RESOURCE && + dma_tx_chan != SPI_NO_RESOURCE && + dma_eventq != SPI_NO_RESOURCE) { + davinci_spi->dma_channels.dma_rx_channel = dma_rx_chan; + davinci_spi->dma_channels.dma_tx_channel = dma_tx_chan; davinci_spi->dma_channels.eventq = dma_eventq; + ret = davinci_spi_request_dma(&davinci_spi->dma_channels); + if (ret) + goto free_clk; + + davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_dma; dev_info(&pdev->dev, "DaVinci SPI driver in EDMA mode\n" "Using RX channel = %d , TX channel = %d and " "event queue = %d", dma_rx_chan, dma_tx_chan, @@ -1015,12 +961,15 @@ static int davinci_spi_probe(struct platform_device *pdev) ret = spi_bitbang_start(&davinci_spi->bitbang); if (ret) - goto free_clk; + goto free_dma; dev_info(&pdev->dev, "Controller at 0x%p\n", davinci_spi->base); return ret; +free_dma: + edma_free_channel(davinci_spi->dma_channels.dma_tx_channel); + edma_free_channel(davinci_spi->dma_channels.dma_rx_channel); free_clk: clk_disable(davinci_spi->clk); clk_put(davinci_spi->clk); -- cgit v1.2.3-70-g09d2 From 87467bd9052725283b9a9f4b1b310fed8744fb1e Mon Sep 17 00:00:00 2001 From: Brian Niebuhr Date: Wed, 6 Oct 2010 17:03:10 +0530 Subject: spi: davinci: let DMA operation be specified on per-device basis Let DMA operation be specified on a per-device basis instead of selecting it once during probe. A side effect of this is the need to combine the PIO and DMA buffer txrx_bufs routine. This is good since they anyway share some common functionality. Signed-off-by: Brian Niebuhr Tested-By: Michael Williamson Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/include/mach/spi.h | 1 + drivers/spi/davinci_spi.c | 342 ++++++++++++++----------------- 2 files changed, 156 insertions(+), 187 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-davinci/include/mach/spi.h b/arch/arm/mach-davinci/include/mach/spi.h index f7586a03678..b3ab7d04943 100644 --- a/arch/arm/mach-davinci/include/mach/spi.h +++ b/arch/arm/mach-davinci/include/mach/spi.h @@ -41,6 +41,7 @@ struct davinci_spi_config { u8 parity_enable; #define SPI_IO_TYPE_INTR 0 #define SPI_IO_TYPE_POLL 1 +#define SPI_IO_TYPE_DMA 2 u8 io_type; u8 timer_disable; u8 c2tdelay; diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 6094e3a0785..5fe298099a1 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -500,6 +500,25 @@ out: return errors; } +static void davinci_spi_dma_callback(unsigned lch, u16 status, void *data) +{ + struct davinci_spi *davinci_spi = data; + struct davinci_spi_dma *davinci_spi_dma = &davinci_spi->dma_channels; + + edma_stop(lch); + + if (status == DMA_COMPLETE) { + if (lch == davinci_spi_dma->dma_rx_channel) + davinci_spi->rcount = 0; + if (lch == davinci_spi_dma->dma_tx_channel) + davinci_spi->wcount = 0; + } + + if ((!davinci_spi->wcount && !davinci_spi->rcount) || + (status != DMA_COMPLETE)) + complete(&davinci_spi->done); +} + /** * davinci_spi_bufs - functions which will handle transfer data * @spi: spi device on which data transfer to be done @@ -509,25 +528,30 @@ out: * of SPI controller and then wait until the completion will be marked * by the IRQ Handler. */ -static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t) +static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) { struct davinci_spi *davinci_spi; - int ret; + int data_type, ret; u32 tx_data, data1_reg_val; u32 errors = 0; struct davinci_spi_config *spicfg; struct davinci_spi_platform_data *pdata; + unsigned uninitialized_var(rx_buf_count); + struct device *sdev; davinci_spi = spi_master_get_devdata(spi->master); pdata = davinci_spi->pdata; spicfg = (struct davinci_spi_config *)spi->controller_data; if (!spicfg) spicfg = &davinci_spi_default_cfg; + sdev = davinci_spi->bitbang.master->dev.parent; + + /* convert len to words based on bits_per_word */ + data_type = davinci_spi->bytes_per_word[spi->chip_select]; davinci_spi->tx = t->tx_buf; davinci_spi->rx = t->rx_buf; - davinci_spi->wcount = t->len / - davinci_spi->bytes_per_word[spi->chip_select]; + davinci_spi->wcount = t->len / data_type; davinci_spi->rcount = davinci_spi->wcount; data1_reg_val = ioread32(davinci_spi->base + SPIDAT1); @@ -535,20 +559,117 @@ static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t) /* Enable SPI */ set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK); - if (spicfg->io_type == SPI_IO_TYPE_INTR) { + INIT_COMPLETION(davinci_spi->done); + + if (spicfg->io_type == SPI_IO_TYPE_INTR) set_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKINT); - INIT_COMPLETION(davinci_spi->done); - } - /* start the transfer */ - davinci_spi->wcount--; - tx_data = davinci_spi->get_tx(davinci_spi); - data1_reg_val &= 0xFFFF0000; - data1_reg_val |= tx_data & 0xFFFF; - iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1); + if (spicfg->io_type != SPI_IO_TYPE_DMA) { + /* start the transfer */ + davinci_spi->wcount--; + tx_data = davinci_spi->get_tx(davinci_spi); + data1_reg_val &= 0xFFFF0000; + data1_reg_val |= tx_data & 0xFFFF; + iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1); + } else { + struct davinci_spi_dma *davinci_spi_dma; + unsigned long tx_reg, rx_reg; + struct edmacc_param param; + void *rx_buf; + + davinci_spi_dma = &davinci_spi->dma_channels; + + tx_reg = (unsigned long)davinci_spi->pbase + SPIDAT1; + rx_reg = (unsigned long)davinci_spi->pbase + SPIBUF; + + /* + * Transmit DMA setup + * + * If there is transmit data, map the transmit buffer, set it + * as the source of data and set the source B index to data + * size. If there is no transmit data, set the transmit register + * as the source of data, and set the source B index to zero. + * + * The destination is always the transmit register itself. And + * the destination never increments. + */ + + if (t->tx_buf) { + t->tx_dma = dma_map_single(&spi->dev, (void *)t->tx_buf, + davinci_spi->wcount, DMA_TO_DEVICE); + if (dma_mapping_error(&spi->dev, t->tx_dma)) { + dev_dbg(sdev, "Unable to DMA map %d bytes" + "TX buffer\n", + davinci_spi->wcount); + return -ENOMEM; + } + } + + param.opt = TCINTEN | EDMA_TCC(davinci_spi_dma->dma_tx_channel); + param.src = t->tx_buf ? t->tx_dma : tx_reg; + param.a_b_cnt = davinci_spi->wcount << 16 | data_type; + param.dst = tx_reg; + param.src_dst_bidx = t->tx_buf ? data_type : 0; + param.link_bcntrld = 0xffff; + param.src_dst_cidx = 0; + param.ccnt = 1; + edma_write_slot(davinci_spi_dma->dma_tx_channel, ¶m); + edma_link(davinci_spi_dma->dma_tx_channel, + davinci_spi_dma->dummy_param_slot); + + /* + * Receive DMA setup + * + * If there is receive buffer, use it to receive data. If there + * is none provided, use a temporary receive buffer. Set the + * destination B index to 0 so effectively only one byte is used + * in the temporary buffer (address does not increment). + * + * The source of receive data is the receive data register. The + * source address never increments. + */ + + if (t->rx_buf) { + rx_buf = t->rx_buf; + rx_buf_count = davinci_spi->rcount; + } else { + rx_buf = davinci_spi->rx_tmp_buf; + rx_buf_count = sizeof(davinci_spi->rx_tmp_buf); + } + + t->rx_dma = dma_map_single(&spi->dev, rx_buf, rx_buf_count, + DMA_FROM_DEVICE); + if (dma_mapping_error(&spi->dev, t->rx_dma)) { + dev_dbg(sdev, "Couldn't DMA map a %d bytes RX buffer\n", + rx_buf_count); + if (t->tx_buf) + dma_unmap_single(NULL, t->tx_dma, + davinci_spi->wcount, + DMA_TO_DEVICE); + return -ENOMEM; + } + + param.opt = TCINTEN | EDMA_TCC(davinci_spi_dma->dma_rx_channel); + param.src = rx_reg; + param.a_b_cnt = davinci_spi->rcount << 16 | data_type; + param.dst = t->rx_dma; + param.src_dst_bidx = (t->rx_buf ? data_type : 0) << 16; + param.link_bcntrld = 0xffff; + param.src_dst_cidx = 0; + param.ccnt = 1; + edma_write_slot(davinci_spi_dma->dma_rx_channel, ¶m); + + if (pdata->cshold_bug) + iowrite16(data1_reg_val >> 16, + davinci_spi->base + SPIDAT1 + 2); + + edma_start(davinci_spi_dma->dma_rx_channel); + edma_start(davinci_spi_dma->dma_tx_channel); + set_io_bits(davinci_spi->base + SPIINT, SPIINT_DMA_REQ_EN); + } /* Wait for the transfer to complete */ - if (spicfg->io_type == SPI_IO_TYPE_INTR) { + if (spicfg->io_type != SPI_IO_TYPE_POLL) { wait_for_completion_interruptible(&(davinci_spi->done)); } else { while (davinci_spi->rcount > 0 || davinci_spi->wcount > 0) { @@ -560,6 +681,17 @@ static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t) } clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL); + if (spicfg->io_type == SPI_IO_TYPE_DMA) { + + if (t->tx_buf) + dma_unmap_single(NULL, t->tx_dma, davinci_spi->wcount, + DMA_TO_DEVICE); + + dma_unmap_single(NULL, t->rx_dma, rx_buf_count, + DMA_FROM_DEVICE); + + clear_io_bits(davinci_spi->base + SPIINT, SPIINT_DMA_REQ_EN); + } /* * Check for bit error, desync error,parity error,timeout error and @@ -572,6 +704,11 @@ static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t) return ret; } + if (davinci_spi->rcount != 0 || davinci_spi->wcount != 0) { + dev_err(sdev, "SPI data transfer error\n"); + return -EIO; + } + return t->len; } @@ -601,174 +738,6 @@ static irqreturn_t davinci_spi_irq(s32 irq, void *context_data) return IRQ_HANDLED; } -static void davinci_spi_dma_callback(unsigned lch, u16 status, void *data) -{ - struct davinci_spi *davinci_spi = data; - struct davinci_spi_dma *davinci_spi_dma = &davinci_spi->dma_channels; - - edma_stop(lch); - - if (status == DMA_COMPLETE) { - if (lch == davinci_spi_dma->dma_rx_channel) - davinci_spi->rcount = 0; - if (lch == davinci_spi_dma->dma_tx_channel) - davinci_spi->wcount = 0; - } - - if ((!davinci_spi->wcount && !davinci_spi->rcount) || - (status != DMA_COMPLETE)) - complete(&davinci_spi->done); -} - -static int davinci_spi_bufs_dma(struct spi_device *spi, struct spi_transfer *t) -{ - struct davinci_spi *davinci_spi; - int int_status = 0; - unsigned rx_buf_count; - struct davinci_spi_dma *davinci_spi_dma; - int data_type, ret; - unsigned long tx_reg, rx_reg; - struct davinci_spi_platform_data *pdata; - void *rx_buf; - struct device *sdev; - struct edmacc_param param; - - davinci_spi = spi_master_get_devdata(spi->master); - pdata = davinci_spi->pdata; - sdev = davinci_spi->bitbang.master->dev.parent; - - davinci_spi_dma = &davinci_spi->dma_channels; - - /* convert len to words based on bits_per_word */ - data_type = davinci_spi->bytes_per_word[spi->chip_select]; - - tx_reg = (unsigned long)davinci_spi->pbase + SPIDAT1; - rx_reg = (unsigned long)davinci_spi->pbase + SPIBUF; - - davinci_spi->tx = t->tx_buf; - davinci_spi->rx = t->rx_buf; - davinci_spi->wcount = t->len / data_type; - davinci_spi->rcount = davinci_spi->wcount; - - INIT_COMPLETION(davinci_spi->done); - - /* disable all interrupts for dma transfers */ - clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL); - /* Enable SPI */ - set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK); - - /* - * Transmit DMA setup - * - * If there is transmit data, map the transmit buffer, set it as the - * source of data and set the source B index to data size. - * If there is no transmit data, set the transmit register as the - * source of data, and set the source B index to zero. - * - * The destination is always the transmit register itself. And the - * destination never increments. - */ - - if (t->tx_buf) { - t->tx_dma = dma_map_single(&spi->dev, (void *)t->tx_buf, - davinci_spi->wcount, DMA_TO_DEVICE); - if (dma_mapping_error(&spi->dev, t->tx_dma)) { - dev_dbg(sdev, "Unable to DMA map %d bytes TX buffer\n", - davinci_spi->wcount); - return -ENOMEM; - } - } - - param.opt = TCINTEN | EDMA_TCC(davinci_spi_dma->dma_tx_channel); - param.src = t->tx_buf ? t->tx_dma : tx_reg; - param.a_b_cnt = davinci_spi->wcount << 16 | data_type; - param.dst = tx_reg; - param.src_dst_bidx = t->tx_buf ? data_type : 0; - param.link_bcntrld = 0xffff; - param.src_dst_cidx = 0; - param.ccnt = 1; - edma_write_slot(davinci_spi_dma->dma_tx_channel, ¶m); - edma_link(davinci_spi_dma->dma_tx_channel, - davinci_spi_dma->dummy_param_slot); - - /* - * Receive DMA setup - * - * If there is receive buffer, use it to receive data. If there - * is none provided, use a temporary receive buffer. Set the - * destination B index to 0 so effectively only one byte is used - * in the temporary buffer (address does not increment). - * - * The source of receive data is the receive data register. The - * source address never increments. - */ - - if (t->rx_buf) { - rx_buf = t->rx_buf; - rx_buf_count = davinci_spi->rcount; - } else { - rx_buf = davinci_spi->rx_tmp_buf; - rx_buf_count = sizeof(davinci_spi->rx_tmp_buf); - } - - t->rx_dma = dma_map_single(&spi->dev, rx_buf, rx_buf_count, - DMA_FROM_DEVICE); - if (dma_mapping_error(&spi->dev, t->rx_dma)) { - dev_dbg(sdev, "Couldn't DMA map a %d bytes RX buffer\n", - rx_buf_count); - if (t->tx_buf) - dma_unmap_single(NULL, t->tx_dma, davinci_spi->wcount, - DMA_TO_DEVICE); - return -ENOMEM; - } - - param.opt = TCINTEN | EDMA_TCC(davinci_spi_dma->dma_rx_channel); - param.src = rx_reg; - param.a_b_cnt = davinci_spi->rcount << 16 | data_type; - param.dst = t->rx_dma; - param.src_dst_bidx = (t->rx_buf ? data_type : 0) << 16; - param.link_bcntrld = 0xffff; - param.src_dst_cidx = 0; - param.ccnt = 1; - edma_write_slot(davinci_spi_dma->dma_rx_channel, ¶m); - - if (pdata->cshold_bug) { - u16 spidat1 = ioread16(davinci_spi->base + SPIDAT1 + 2); - iowrite16(spidat1, davinci_spi->base + SPIDAT1 + 2); - } - - edma_start(davinci_spi_dma->dma_rx_channel); - edma_start(davinci_spi_dma->dma_tx_channel); - set_io_bits(davinci_spi->base + SPIINT, SPIINT_DMA_REQ_EN); - - wait_for_completion_interruptible(&davinci_spi->done); - - if (t->tx_buf) - dma_unmap_single(NULL, t->tx_dma, davinci_spi->wcount, - DMA_TO_DEVICE); - - dma_unmap_single(NULL, t->rx_dma, rx_buf_count, DMA_FROM_DEVICE); - - clear_io_bits(davinci_spi->base + SPIINT, SPIINT_DMA_REQ_EN); - - /* - * Check for bit error, desync error,parity error,timeout error and - * receive overflow errors - */ - int_status = ioread32(davinci_spi->base + SPIFLG); - - ret = davinci_spi_check_error(davinci_spi, int_status); - if (ret != 0) - return ret; - - if (davinci_spi->rcount != 0 || davinci_spi->wcount != 0) { - dev_err(sdev, "SPI data transfer error\n"); - return -EIO; - } - - return t->len; -} - static int davinci_spi_request_dma(struct davinci_spi *davinci_spi) { int r; @@ -918,7 +887,7 @@ static int davinci_spi_probe(struct platform_device *pdev) if (r) dma_eventq = r->start; - davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_pio; + davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs; if (dma_rx_chan != SPI_NO_RESOURCE && dma_tx_chan != SPI_NO_RESOURCE && dma_eventq != SPI_NO_RESOURCE) { @@ -930,10 +899,9 @@ static int davinci_spi_probe(struct platform_device *pdev) if (ret) goto free_clk; - davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_dma; - dev_info(&pdev->dev, "DaVinci SPI driver in EDMA mode\n" - "Using RX channel = %d , TX channel = %d and " - "event queue = %d", dma_rx_chan, dma_tx_chan, + dev_info(&pdev->dev, "DMA: supported\n"); + dev_info(&pdev->dev, "DMA: RX channel: %d, TX channel: %d, " + "event queue: %d\n", dma_rx_chan, dma_tx_chan, dma_eventq); } -- cgit v1.2.3-70-g09d2 From 3409e408ab0d7171ae81d198110a1f293852959f Mon Sep 17 00:00:00 2001 From: Brian Niebuhr Date: Wed, 6 Oct 2010 18:13:31 +0530 Subject: spi: davinci: remove non-useful "clk_internal" platform data The "clk_internal" platform data member which contols the CLKMOD bit in Global Control Register 1 is not useful since CLKMOD needs be set to 1 *always* to ensure master mode operation. Remove this platform data. Signed-off-by: Brian Niebuhr Tested-By: Michael Williamson Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/dm355.c | 1 - arch/arm/mach-davinci/dm365.c | 1 - arch/arm/mach-davinci/include/mach/spi.h | 1 - drivers/spi/davinci_spi.c | 9 +-------- 4 files changed, 1 insertion(+), 11 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index 27ee870b2d2..c0c501a4c13 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -412,7 +412,6 @@ static struct resource dm355_spi0_resources[] = { static struct davinci_spi_platform_data dm355_spi0_pdata = { .version = SPI_VERSION_1, .num_chipselect = 2, - .clk_internal = 1, .cshold_bug = true, }; static struct platform_device dm355_spi0_device = { diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index 1e5012e196b..8b8204fa757 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -625,7 +625,6 @@ static u64 dm365_spi0_dma_mask = DMA_BIT_MASK(32); static struct davinci_spi_platform_data dm365_spi0_pdata = { .version = SPI_VERSION_1, .num_chipselect = 2, - .clk_internal = 1, }; static struct resource dm365_spi0_resources[] = { diff --git a/arch/arm/mach-davinci/include/mach/spi.h b/arch/arm/mach-davinci/include/mach/spi.h index b3ab7d04943..1f8b7866bea 100644 --- a/arch/arm/mach-davinci/include/mach/spi.h +++ b/arch/arm/mach-davinci/include/mach/spi.h @@ -29,7 +29,6 @@ enum { struct davinci_spi_platform_data { u8 version; u8 num_chipselect; - u8 clk_internal; u8 intr_line; u8 *chip_sel; bool cshold_bug; diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 5fe298099a1..2e74fcd2f42 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -927,14 +927,6 @@ static int davinci_spi_probe(struct platform_device *pdev) } } - /* Clock internal */ - if (davinci_spi->pdata->clk_internal) - set_io_bits(davinci_spi->base + SPIGCR1, - SPIGCR1_CLKMOD_MASK); - else - clear_io_bits(davinci_spi->base + SPIGCR1, - SPIGCR1_CLKMOD_MASK); - if (pdata->intr_line) iowrite32(SPI_INTLVL_1, davinci_spi->base + SPILVL); else @@ -943,6 +935,7 @@ static int davinci_spi_probe(struct platform_device *pdev) iowrite32(CS_DEFAULT, davinci_spi->base + SPIDEF); /* master mode default */ + set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_CLKMOD_MASK); set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_MASTER_MASK); ret = spi_bitbang_start(&davinci_spi->bitbang); -- cgit v1.2.3-70-g09d2 From 035540f6ea2394bdd9675552d31e1125cd0e402e Mon Sep 17 00:00:00 2001 From: Brian Niebuhr Date: Wed, 6 Oct 2010 18:32:40 +0530 Subject: spi: davinci: add additional comments Add comments describing the platform data members and per-chip-select SPI configuration structure. Also, add some comments describing the what happens during the driver probe. Signed-off-by: Brian Niebuhr Tested-By: Michael Williamson Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/include/mach/spi.h | 32 ++++++++++++++++++++++++++++++++ drivers/spi/davinci_spi.c | 7 +++++++ 2 files changed, 39 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-davinci/include/mach/spi.h b/arch/arm/mach-davinci/include/mach/spi.h index 1f8b7866bea..38f4da5ca13 100644 --- a/arch/arm/mach-davinci/include/mach/spi.h +++ b/arch/arm/mach-davinci/include/mach/spi.h @@ -26,6 +26,20 @@ enum { SPI_VERSION_2, /* For DA8xx */ }; +/** + * davinci_spi_platform_data - Platform data for SPI master device on DaVinci + * + * @version: version of the SPI IP. Different DaVinci devices have slightly + * varying versions of the same IP. + * @num_chipselect: number of chipselects supported by this SPI master + * @intr_line: interrupt line used to connect the SPI IP to the ARM interrupt + * controller withn the SoC. Possible values are 0 and 1. + * @chip_sel: list of GPIOs which can act as chip-selects for the SPI. + * SPI_INTERN_CS denotes internal SPI chip-select. Not necessary + * to populate if all chip-selects are internal. + * @cshold_bug: set this to true if the SPI controller on your chip requires + * a write to CSHOLD bit in between transfers (like in DM355). + */ struct davinci_spi_platform_data { u8 version; u8 num_chipselect; @@ -34,6 +48,24 @@ struct davinci_spi_platform_data { bool cshold_bug; }; +/** + * davinci_spi_config - Per-chip-select configuration for SPI slave devices + * + * @wdelay: amount of delay between transmissions. Measured in number of + * SPI module clocks. + * @odd_parity: polarity of parity flag at the end of transmit data stream. + * 0 - odd parity, 1 - even parity. + * @parity_enable: enable transmission of parity at end of each transmit + * data stream. + * @io_type: type of IO transfer. Choose between polled, interrupt and DMA. + * @timer_disable: disable chip-select timers (setup and hold) + * @c2tdelay: chip-select setup time. Measured in number of SPI module clocks. + * @t2cdelay: chip-select hold time. Measured in number of SPI module clocks. + * @t2edelay: transmit data finished to SPI ENAn pin inactive time. Measured + * in number of SPI clocks. + * @c2edelay: chip-select active to SPI ENAn signal active time. Measured in + * number of SPI clocks. + */ struct davinci_spi_config { u8 wdelay; u8 odd_parity; diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 2ec5fd2f2e7..f40f1be1528 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -787,6 +787,13 @@ rx_dma_failed: /** * davinci_spi_probe - probe function for SPI Master Controller * @pdev: platform_device structure which contains plateform specific data + * + * According to Linux Device Model this function will be invoked by Linux + * with platform_device struct which contains the device specific info. + * This function will map the SPI controller's memory, register IRQ, + * Reset SPI controller and setting its registers to default value. + * It will invoke spi_bitbang_start to create work queue so that client driver + * can register transfer method to work queue. */ static int davinci_spi_probe(struct platform_device *pdev) { -- cgit v1.2.3-70-g09d2 From 4a25605fb71f02b4f80091df91f777225a0309c5 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 22 Nov 2010 17:12:15 -0800 Subject: spi/pxa2xx: Use define for SSSR_TFL_MASK instead of plain numbers Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Dirk Brandewie --- arch/arm/plat-pxa/include/plat/ssp.h | 3 ++- drivers/spi/pxa2xx_spi.c | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/plat-pxa/include/plat/ssp.h b/arch/arm/plat-pxa/include/plat/ssp.h index fe43150690e..21c12ca8073 100644 --- a/arch/arm/plat-pxa/include/plat/ssp.h +++ b/arch/arm/plat-pxa/include/plat/ssp.h @@ -82,7 +82,8 @@ #define SSSR_TFS (1 << 5) /* Transmit FIFO Service Request */ #define SSSR_RFS (1 << 6) /* Receive FIFO Service Request */ #define SSSR_ROR (1 << 7) /* Receive FIFO Overrun */ - +#define SSSR_TFL_MASK (0xf << 8) /* Transmit FIFO Level mask */ +#define SSSR_RFL_MASK (0xf << 12) /* Receive FIFO Level mask */ /* extra bits in PXA255, PXA26x and PXA27x SSP ports */ #define SSCR0_TISSP (1 << 4) /* TI Sync Serial Protocol */ diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 1865c23f217..55083445aae 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -224,7 +224,7 @@ static int null_writer(struct driver_data *drv_data) void __iomem *reg = drv_data->ioaddr; u8 n_bytes = drv_data->n_bytes; - if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) + if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK) || (drv_data->tx == drv_data->tx_end)) return 0; @@ -252,7 +252,7 @@ static int u8_writer(struct driver_data *drv_data) { void __iomem *reg = drv_data->ioaddr; - if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) + if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK) || (drv_data->tx == drv_data->tx_end)) return 0; @@ -279,7 +279,7 @@ static int u16_writer(struct driver_data *drv_data) { void __iomem *reg = drv_data->ioaddr; - if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) + if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK) || (drv_data->tx == drv_data->tx_end)) return 0; @@ -306,7 +306,7 @@ static int u32_writer(struct driver_data *drv_data) { void __iomem *reg = drv_data->ioaddr; - if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) + if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK) || (drv_data->tx == drv_data->tx_end)) return 0; -- cgit v1.2.3-70-g09d2 From 8348c259dd6a6019a8fa01b0a3443409480f7b9d Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 22 Nov 2010 17:12:15 -0800 Subject: arm/pxa2xx: reorgazine SSP and SPI header files The PXA-SPI driver relies on some files / defines which are arm specific and are within the ARM tree. The CE4100 SoC which is x86 has also the SPI core. This patch moves the ssp and spi files from arm/mach-pxa and plat-pxa to include/linux where the CE4100 can access them. This move got verified by building the following defconfigs: cm_x2xx_defconfig corgi_defconfig em_x270_defconfig ezx_defconfig imote2_defconfig pxa3xx_defconfig spitz_defconfig zeus_defconfig raumfeld_defconfig magician_defconfig Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Dirk Brandewie --- Documentation/spi/pxa2xx | 4 +- arch/arm/mach-pxa/cm-x255.c | 2 +- arch/arm/mach-pxa/cm-x270.c | 2 +- arch/arm/mach-pxa/corgi.c | 2 +- arch/arm/mach-pxa/devices.c | 2 +- arch/arm/mach-pxa/em-x270.c | 2 +- arch/arm/mach-pxa/hx4700.c | 2 +- arch/arm/mach-pxa/icontrol.c | 2 +- arch/arm/mach-pxa/include/mach/pxa2xx_spi.h | 47 ------- arch/arm/mach-pxa/littleton.c | 2 +- arch/arm/mach-pxa/lubbock.c | 2 +- arch/arm/mach-pxa/pcm027.c | 2 +- arch/arm/mach-pxa/poodle.c | 2 +- arch/arm/mach-pxa/spitz.c | 3 +- arch/arm/mach-pxa/stargate2.c | 2 +- arch/arm/mach-pxa/tosa.c | 2 +- arch/arm/mach-pxa/trizeps4.c | 1 - arch/arm/mach-pxa/z2.c | 2 +- arch/arm/mach-pxa/zeus.c | 2 +- arch/arm/plat-pxa/include/plat/ssp.h | 187 ---------------------------- arch/arm/plat-pxa/ssp.c | 2 +- drivers/spi/pxa2xx_spi.c | 4 +- include/linux/pxa2xx_ssp.h | 187 ++++++++++++++++++++++++++++ include/linux/spi/pxa2xx_spi.h | 49 ++++++++ sound/soc/pxa/pxa-ssp.c | 2 +- 25 files changed, 257 insertions(+), 259 deletions(-) delete mode 100644 arch/arm/mach-pxa/include/mach/pxa2xx_spi.h delete mode 100644 arch/arm/plat-pxa/include/plat/ssp.h create mode 100644 include/linux/pxa2xx_ssp.h create mode 100644 include/linux/spi/pxa2xx_spi.h (limited to 'arch') diff --git a/Documentation/spi/pxa2xx b/Documentation/spi/pxa2xx index 6bb916d57c9..68a4fe3818a 100644 --- a/Documentation/spi/pxa2xx +++ b/Documentation/spi/pxa2xx @@ -19,7 +19,7 @@ Declaring PXA2xx Master Controllers ----------------------------------- Typically a SPI master is defined in the arch/.../mach-*/board-*.c as a "platform device". The master configuration is passed to the driver via a table -found in arch/arm/mach-pxa/include/mach/pxa2xx_spi.h: +found in include/linux/spi/pxa2xx_spi.h: struct pxa2xx_spi_master { enum pxa_ssp_type ssp_type; @@ -94,7 +94,7 @@ using the "spi_board_info" structure found in "linux/spi/spi.h". See Each slave device attached to the PXA must provide slave specific configuration information via the structure "pxa2xx_spi_chip" found in -"arch/arm/mach-pxa/include/mach/pxa2xx_spi.h". The pxa2xx_spi master controller driver +"include/linux/spi/pxa2xx_spi.h". The pxa2xx_spi master controller driver will uses the configuration whenever the driver communicates with the slave device. All fields are optional. diff --git a/arch/arm/mach-pxa/cm-x255.c b/arch/arm/mach-pxa/cm-x255.c index f1a7703d771..93f59f877fc 100644 --- a/arch/arm/mach-pxa/cm-x255.c +++ b/arch/arm/mach-pxa/cm-x255.c @@ -17,13 +17,13 @@ #include #include +#include #include #include #include #include -#include #include "generic.h" diff --git a/arch/arm/mach-pxa/cm-x270.c b/arch/arm/mach-pxa/cm-x270.c index a9926bb7592..b88d601a809 100644 --- a/arch/arm/mach-pxa/cm-x270.c +++ b/arch/arm/mach-pxa/cm-x270.c @@ -19,12 +19,12 @@ #include