drivers/spi: Add support for TX or RX only modes on DW driver
As for RX only, computing the NDF will be used for EEPROM mode. Only a way to determine EEPROM mode is missing. Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
This commit is contained in:
parent
7f4378e232
commit
57a1f7b4f1
4 changed files with 73 additions and 11 deletions
|
@ -248,6 +248,26 @@ static int spi_dw_configure(const struct spi_dw_config *info,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t spi_dw_compute_ndf(const struct spi_buf *rx_bufs,
|
||||
size_t rx_count, u8_t dfs)
|
||||
{
|
||||
u32_t len = 0;
|
||||
|
||||
for (; rx_count; rx_bufs++, rx_count--) {
|
||||
if (len > (UINT16_MAX - rx_bufs->len)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
len += rx_bufs->len;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
return (len / dfs) - 1;
|
||||
}
|
||||
error:
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
static int transceive(struct device *dev,
|
||||
const struct spi_config *config,
|
||||
const struct spi_buf_set *tx_bufs,
|
||||
|
@ -257,9 +277,9 @@ static int transceive(struct device *dev,
|
|||
{
|
||||
const struct spi_dw_config *info = dev->config->config_info;
|
||||
struct spi_dw_data *spi = dev->driver_data;
|
||||
u32_t rx_thsld = DW_SPI_RXFTLR_DFLT;
|
||||
u32_t imask = DW_SPI_IMR_UNMASK;
|
||||
int ret = 0;
|
||||
u32_t tmod = DW_SPI_CTRLR0_TMOD_TX_RX;
|
||||
u32_t reg_data;
|
||||
int ret;
|
||||
|
||||
/* Check status */
|
||||
if (test_bit_ssienr(info->regs) || test_bit_sr_busy(info->regs)) {
|
||||
|
@ -275,6 +295,30 @@ static int transceive(struct device *dev,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (!rx_bufs || !rx_bufs->buffers) {
|
||||
tmod = DW_SPI_CTRLR0_TMOD_TX;
|
||||
} else if (!tx_bufs || !tx_bufs->buffers) {
|
||||
tmod = DW_SPI_CTRLR0_TMOD_RX;
|
||||
}
|
||||
|
||||
/* ToDo: add a way to determine EEPROM mode */
|
||||
|
||||
if (tmod >= DW_SPI_CTRLR0_TMOD_RX) {
|
||||
reg_data = spi_dw_compute_ndf(rx_bufs->buffers,
|
||||
rx_bufs->count, spi->dfs);
|
||||
if (reg_data == UINT32_MAX) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
write_ctrlr1(reg_data, info->regs);
|
||||
} else {
|
||||
write_ctrlr1(0, info->regs);
|
||||
}
|
||||
|
||||
/* Updating TMOD in CTRLR0 register */
|
||||
write_ctrlr0(read_ctrlr0(info->regs) | tmod, info->regs);
|
||||
|
||||
/* Set buffers info */
|
||||
spi_context_buffers_setup(&spi->ctx, tx_bufs, rx_bufs, spi->dfs);
|
||||
|
||||
|
@ -284,20 +328,18 @@ static int transceive(struct device *dev,
|
|||
write_txftlr(DW_SPI_TXFTLR_DFLT, info->regs);
|
||||
|
||||
/* Does Rx thresholds needs to be lower? */
|
||||
reg_data = DW_SPI_RXFTLR_DFLT;
|
||||
if (spi->ctx.rx_len && spi->ctx.rx_len < DW_SPI_FIFO_DEPTH) {
|
||||
rx_thsld = spi->ctx.rx_len - 1;
|
||||
reg_data = spi->ctx.rx_len - 1;
|
||||
}
|
||||
|
||||
/* Rx Threshold */
|
||||
write_rxftlr(rx_thsld, info->regs);
|
||||
|
||||
if (!rx_bufs) {
|
||||
/* if there is no rx buffer, keep all rx interrupts masked */
|
||||
imask &= DW_SPI_IMR_MASK_RX;
|
||||
}
|
||||
write_rxftlr(reg_data, info->regs);
|
||||
|
||||
/* Enable interrupts */
|
||||
write_imr(imask, info->regs);
|
||||
reg_data = !rx_bufs ?
|
||||
DW_SPI_IMR_UNMASK & DW_SPI_IMR_MASK_RX : DW_SPI_IMR_UNMASK;
|
||||
write_imr(reg_data, info->regs);
|
||||
|
||||
spi_context_cs_control(&spi->ctx, true);
|
||||
|
||||
|
|
|
@ -124,6 +124,12 @@ struct spi_dw_data {
|
|||
#define DW_SPI_CTRLR0_SCPOL BIT(DW_SPI_CTRLR0_SCPOL_BIT)
|
||||
#define DW_SPI_CTRLR0_SRL BIT(DW_SPI_CTRLR0_SRL_BIT)
|
||||
|
||||
#define DW_SPI_CTRLR0_TMOD_SHIFT (8)
|
||||
#define DW_SPI_CTRLR0_TMOD_TX_RX (0)
|
||||
#define DW_SPI_CTRLR0_TMOD_TX (1 << DW_SPI_CTRLR0_TMOD_SHIFT)
|
||||
#define DW_SPI_CTRLR0_TMOD_RX (2 << DW_SPI_CTRLR0_TMOD_SHIFT)
|
||||
#define DW_SPI_CTRLR0_TMOD_EEPROM (3 << DW_SPI_CTRLR0_TMOD_SHIFT)
|
||||
|
||||
#define DW_SPI_CTRLR0_DFS_16(__bpw) ((__bpw) - 1)
|
||||
#define DW_SPI_CTRLR0_DFS_32(__bpw) (((__bpw) - 1) << 16)
|
||||
|
||||
|
|
|
@ -59,6 +59,11 @@ extern "C" {
|
|||
* *_b function only used for creating proper ser one
|
||||
*/
|
||||
DEFINE_MM_REG_READ(ctrlr0_b, DW_SPI_REG_CTRLR0, 16)
|
||||
static inline u32_t read_ctrlr0(u32_t addr)
|
||||
{
|
||||
return read_ctrlr0_b(addr);
|
||||
}
|
||||
|
||||
DEFINE_MM_REG_WRITE(ctrlr0_b, DW_SPI_REG_CTRLR0, 16)
|
||||
static inline void write_ctrlr0(u32_t data, u32_t addr)
|
||||
{
|
||||
|
@ -66,6 +71,13 @@ static inline void write_ctrlr0(u32_t data, u32_t addr)
|
|||
data, addr);
|
||||
}
|
||||
|
||||
DEFINE_MM_REG_READ(ctrlr1_b, DW_SPI_REG_CTRLR0, 32)
|
||||
DEFINE_MM_REG_WRITE(ctrlr1_b, DW_SPI_REG_CTRLR0, 32)
|
||||
static inline void write_ctrlr1(u32_t data, u32_s addr)
|
||||
{
|
||||
write_ctrlr1_b((read_ctrlr1_b(addr) & (data << 16)), addr);
|
||||
}
|
||||
|
||||
DEFINE_MM_REG_READ(ssienr_b, DW_SPI_REG_SSIENR, 8)
|
||||
DEFINE_MM_REG_WRITE(ssienr_b, DW_SPI_REG_SSIENR, 8)
|
||||
static inline void write_ser(u32_t data, u32_t addr)
|
||||
|
|
|
@ -42,6 +42,8 @@ extern "C" {
|
|||
|
||||
/* Register helpers */
|
||||
DEFINE_MM_REG_WRITE(ctrlr0, DW_SPI_REG_CTRLR0, 32)
|
||||
DEFINE_MM_REG_READ(ctrlr0, DW_SPI_REG_CTRLR0, 32)
|
||||
DEFINE_MM_REG_WRITE(ctrlr1, DW_SPI_REG_CTRLR1, 16)
|
||||
DEFINE_MM_REG_WRITE(ser, DW_SPI_REG_SER, 8)
|
||||
DEFINE_MM_REG_WRITE(txftlr, DW_SPI_REG_TXFTLR, 32)
|
||||
DEFINE_MM_REG_WRITE(rxftlr, DW_SPI_REG_RXFTLR, 32)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue