mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-09-21 20:22:13 +08:00
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: Alexandru Ardelean <alexandru.ardelean@analog.com> Link: https://lore.kernel.org/r/20190926105147.7839-8-alexandru.ardelean@analog.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
ec3fa72fa8
commit
6c613f68aa
@ -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)
|
|||||||
*/
|
*/
|
||||||
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,
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
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);
|
|||||||
* 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 {
|
|||||||
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,
|
|||||||
* @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 {
|
|||||||
#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;
|
||||||
|
Loading…
Reference in New Issue
Block a user