Commit 6c613f68 authored by Alexandru Ardelean's avatar Alexandru Ardelean Committed by Mark Brown

spi: core,atmel: convert `word_delay_usecs` -> `word_delay` for spi_device

This change does a conversion from the `word_delay_usecs` -> `word_delay`
for the `spi_device` struct.

This allows users to specify inter-word delays in other unit types
(nano-seconds or clock cycles), depending on how users want.

The Atmel SPI driver is the only current user of the `word_delay_usecs`
field (from the `spi_device` struct).
So, it needed a slight conversion to use the `word_delay` as an `spi_delay`
struct.

In SPI core, the only required mechanism is to update the `word_delay`
information per `spi_transfer`. This requires a bit more logic than before,
because it needs that both delays be converted to a common unit
(nano-seconds) for comparison.
Signed-off-by: default avatarAlexandru Ardelean <alexandru.ardelean@analog.com>
Link: https://lore.kernel.org/r/20190926105147.7839-8-alexandru.ardelean@analog.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent ec3fa72f
...@@ -1149,12 +1149,31 @@ atmel_spi_pdc_interrupt(int irq, void *dev_id) ...@@ -1149,12 +1149,31 @@ atmel_spi_pdc_interrupt(int irq, void *dev_id)
return ret; return ret;
} }
static int atmel_word_delay_csr(struct spi_device *spi, struct atmel_spi *as)
{
struct spi_delay *delay = &spi->word_delay;
u32 value = delay->value;
switch (delay->unit) {
case SPI_DELAY_UNIT_NSECS:
value /= 1000;
break;
case SPI_DELAY_UNIT_USECS:
break;
default:
return -EINVAL;
}
return (as->spi_clk / 1000000 * value) >> 5;
}
static int atmel_spi_setup(struct spi_device *spi) static int atmel_spi_setup(struct spi_device *spi)
{ {
struct atmel_spi *as; struct atmel_spi *as;
struct atmel_spi_device *asd; struct atmel_spi_device *asd;
u32 csr; u32 csr;
unsigned int bits = spi->bits_per_word; unsigned int bits = spi->bits_per_word;
int word_delay_csr;
as = spi_master_get_devdata(spi->master); as = spi_master_get_devdata(spi->master);
...@@ -1178,11 +1197,14 @@ static int atmel_spi_setup(struct spi_device *spi) ...@@ -1178,11 +1197,14 @@ static int atmel_spi_setup(struct spi_device *spi)
*/ */
csr |= SPI_BF(DLYBS, 0); csr |= SPI_BF(DLYBS, 0);
word_delay_csr = atmel_word_delay_csr(spi, as);
if (word_delay_csr < 0)
return word_delay_csr;
/* DLYBCT adds delays between words. This is useful for slow devices /* DLYBCT adds delays between words. This is useful for slow devices
* that need a bit of time to setup the next transfer. * that need a bit of time to setup the next transfer.
*/ */
csr |= SPI_BF(DLYBCT, csr |= SPI_BF(DLYBCT, word_delay_csr);
(as->spi_clk / 1000000 * spi->word_delay_usecs) >> 5);
asd = spi->controller_state; asd = spi->controller_state;
if (!asd) { if (!asd) {
......
...@@ -3281,6 +3281,26 @@ void spi_set_cs_timing(struct spi_device *spi, u8 setup, u8 hold, ...@@ -3281,6 +3281,26 @@ void spi_set_cs_timing(struct spi_device *spi, u8 setup, u8 hold,
} }
EXPORT_SYMBOL_GPL(spi_set_cs_timing); EXPORT_SYMBOL_GPL(spi_set_cs_timing);
static int _spi_xfer_word_delay_update(struct spi_transfer *xfer,
struct spi_device *spi)
{
int delay1, delay2;
delay1 = _spi_delay_to_ns(&xfer->word_delay, xfer);
if (delay1 < 0)
return delay1;
delay2 = _spi_delay_to_ns(&spi->word_delay, xfer);
if (delay2 < 0)
return delay2;
if (delay1 < delay2)
memcpy(&xfer->word_delay, &spi->word_delay,
sizeof(xfer->word_delay));
return 0;
}
static int __spi_validate(struct spi_device *spi, struct spi_message *message) static int __spi_validate(struct spi_device *spi, struct spi_message *message)
{ {
struct spi_controller *ctlr = spi->controller; struct spi_controller *ctlr = spi->controller;
...@@ -3416,8 +3436,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) ...@@ -3416,8 +3436,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
return -EINVAL; return -EINVAL;
} }
if (xfer->word_delay_usecs < spi->word_delay_usecs) if (_spi_xfer_word_delay_update(xfer, spi))
xfer->word_delay_usecs = spi->word_delay_usecs; return -EINVAL;
} }
message->status = -EINPROGRESS; message->status = -EINPROGRESS;
......
...@@ -139,7 +139,7 @@ extern int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer); ...@@ -139,7 +139,7 @@ extern int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer);
* the spi_master. * the spi_master.
* @cs_gpiod: gpio descriptor of the chipselect line (optional, NULL when * @cs_gpiod: gpio descriptor of the chipselect line (optional, NULL when
* not using a GPIO line) * not using a GPIO line)
* @word_delay_usecs: microsecond delay to be inserted between consecutive * @word_delay: delay to be inserted between consecutive
* words of a transfer * words of a transfer
* *
* @statistics: statistics for the spi_device * @statistics: statistics for the spi_device
...@@ -189,7 +189,7 @@ struct spi_device { ...@@ -189,7 +189,7 @@ struct spi_device {
const char *driver_override; const char *driver_override;
int cs_gpio; /* LEGACY: chip select gpio */ int cs_gpio; /* LEGACY: chip select gpio */
struct gpio_desc *cs_gpiod; /* chip select gpio desc */ struct gpio_desc *cs_gpiod; /* chip select gpio desc */
uint8_t word_delay_usecs; /* inter-word delay */ struct spi_delay word_delay; /* inter-word delay */
/* the statistics */ /* the statistics */
struct spi_statistics statistics; struct spi_statistics statistics;
...@@ -781,8 +781,6 @@ extern void spi_res_release(struct spi_controller *ctlr, ...@@ -781,8 +781,6 @@ extern void spi_res_release(struct spi_controller *ctlr,
* @delay_usecs: microseconds to delay after this transfer before * @delay_usecs: microseconds to delay after this transfer before
* (optionally) changing the chipselect status, then starting * (optionally) changing the chipselect status, then starting
* the next transfer or completing this @spi_message. * the next transfer or completing this @spi_message.
* @word_delay_usecs: microseconds to inter word delay after each word size
* (set by bits_per_word) transmission.
* @word_delay: inter word delay to be introduced after each word size * @word_delay: inter word delay to be introduced after each word size
* (set by bits_per_word) transmission. * (set by bits_per_word) transmission.
* @effective_speed_hz: the effective SCK-speed that was used to * @effective_speed_hz: the effective SCK-speed that was used to
...@@ -897,7 +895,6 @@ struct spi_transfer { ...@@ -897,7 +895,6 @@ struct spi_transfer {
#define SPI_NBITS_DUAL 0x02 /* 2bits transfer */ #define SPI_NBITS_DUAL 0x02 /* 2bits transfer */
#define SPI_NBITS_QUAD 0x04 /* 4bits transfer */ #define SPI_NBITS_QUAD 0x04 /* 4bits transfer */
u8 bits_per_word; u8 bits_per_word;
u8 word_delay_usecs;
u16 delay_usecs; u16 delay_usecs;
struct spi_delay cs_change_delay; struct spi_delay cs_change_delay;
struct spi_delay word_delay; struct spi_delay word_delay;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment