summaryrefslogtreecommitdiff
path: root/drivers/spi/spi-imx.c
diff options
context:
space:
mode:
authorJames Morris <james.l.morris@oracle.com>2017-11-29 12:47:41 +1100
committerJames Morris <james.l.morris@oracle.com>2017-11-29 12:47:41 +1100
commitcf40a76e7d5874bb25f4404eecc58a2e033af885 (patch)
tree8fd81cbea03c87b3d41d7ae5b1d11eadd35d6ef5 /drivers/spi/spi-imx.c
parentab5348c9c23cd253f5902980d2d8fe067dc24c82 (diff)
parent4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323 (diff)
Merge tag 'v4.15-rc1' into next-seccomp
Linux 4.15-rc1
Diffstat (limited to 'drivers/spi/spi-imx.c')
-rw-r--r--drivers/spi/spi-imx.c472
1 files changed, 409 insertions, 63 deletions
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index f9698b7aeb3b..79ddefe4180d 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -53,9 +53,13 @@
/* generic defines to abstract from the different register layouts */
#define MXC_INT_RR (1 << 0) /* Receive data ready interrupt */
#define MXC_INT_TE (1 << 1) /* Transmit FIFO empty interrupt */
+#define MXC_INT_RDR BIT(4) /* Receive date threshold interrupt */
/* The maximum bytes that a sdma BD can transfer.*/
#define MAX_SDMA_BD_BYTES (1 << 15)
+#define MX51_ECSPI_CTRL_MAX_BURST 512
+/* The maximum bytes that IMX53_ECSPI can transfer in slave mode.*/
+#define MX53_MAX_TRANSFER_BYTES 512
enum spi_imx_devtype {
IMX1_CSPI,
@@ -63,7 +67,8 @@ enum spi_imx_devtype {
IMX27_CSPI,
IMX31_CSPI,
IMX35_CSPI, /* CSPI on all i.mx except above */
- IMX51_ECSPI, /* ECSPI on i.mx51 and later */
+ IMX51_ECSPI, /* ECSPI on i.mx51 */
+ IMX53_ECSPI, /* ECSPI on i.mx53 and later */
};
struct spi_imx_data;
@@ -74,6 +79,11 @@ struct spi_imx_devtype_data {
void (*trigger)(struct spi_imx_data *);
int (*rx_available)(struct spi_imx_data *);
void (*reset)(struct spi_imx_data *);
+ void (*disable)(struct spi_imx_data *);
+ bool has_dmamode;
+ bool has_slavemode;
+ unsigned int fifo_size;
+ bool dynamic_burst;
enum spi_imx_devtype devtype;
};
@@ -94,12 +104,19 @@ struct spi_imx_data {
unsigned int bits_per_word;
unsigned int spi_drctl;
- unsigned int count;
+ unsigned int count, remainder;
void (*tx)(struct spi_imx_data *);
void (*rx)(struct spi_imx_data *);
void *rx_buf;
const void *tx_buf;
unsigned int txfifo; /* number of words pushed in tx FIFO */
+ unsigned int dynamic_burst, read_u32;
+ unsigned int word_mask;
+
+ /* Slave mode */
+ bool slave_mode;
+ bool slave_aborted;
+ unsigned int slave_burst;
/* DMA */
bool usedma;
@@ -125,9 +142,9 @@ static inline int is_imx51_ecspi(struct spi_imx_data *d)
return d->devtype_data->devtype == IMX51_ECSPI;
}
-static inline unsigned spi_imx_get_fifosize(struct spi_imx_data *d)
+static inline int is_imx53_ecspi(struct spi_imx_data *d)
{
- return is_imx51_ecspi(d) ? 64 : 8;
+ return d->devtype_data->devtype == IMX53_ECSPI;
}
#define MXC_SPI_BUF_RX(type) \
@@ -214,12 +231,15 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
if (!master->dma_rx)
return false;
+ if (spi_imx->slave_mode)
+ return false;
+
bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
if (bytes_per_word != 1 && bytes_per_word != 2 && bytes_per_word != 4)
return false;
- for (i = spi_imx_get_fifosize(spi_imx) / 2; i > 0; i--) {
+ for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
if (!(transfer->len % (i * bytes_per_word)))
break;
}
@@ -228,6 +248,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
return false;
spi_imx->wml = i;
+ spi_imx->dynamic_burst = 0;
return true;
}
@@ -242,6 +263,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
#define MX51_ECSPI_CTRL_PREDIV_OFFSET 12
#define MX51_ECSPI_CTRL_CS(cs) ((cs) << 18)
#define MX51_ECSPI_CTRL_BL_OFFSET 20
+#define MX51_ECSPI_CTRL_BL_MASK (0xfff << 20)
#define MX51_ECSPI_CONFIG 0x0c
#define MX51_ECSPI_CONFIG_SCLKPHA(cs) (1 << ((cs) + 0))
@@ -253,6 +275,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
#define MX51_ECSPI_INT 0x10
#define MX51_ECSPI_INT_TEEN (1 << 0)
#define MX51_ECSPI_INT_RREN (1 << 3)
+#define MX51_ECSPI_INT_RDREN (1 << 4)
#define MX51_ECSPI_DMA 0x14
#define MX51_ECSPI_DMA_TX_WML(wml) ((wml) & 0x3f)
@@ -269,6 +292,144 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
#define MX51_ECSPI_TESTREG 0x20
#define MX51_ECSPI_TESTREG_LBC BIT(31)
+static void spi_imx_buf_rx_swap_u32(struct spi_imx_data *spi_imx)
+{
+ unsigned int val = readl(spi_imx->base + MXC_CSPIRXDATA);
+#ifdef __LITTLE_ENDIAN
+ unsigned int bytes_per_word;
+#endif
+
+ if (spi_imx->rx_buf) {
+#ifdef __LITTLE_ENDIAN
+ bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
+ if (bytes_per_word == 1)
+ val = cpu_to_be32(val);
+ else if (bytes_per_word == 2)
+ val = (val << 16) | (val >> 16);
+#endif
+ val &= spi_imx->word_mask;
+ *(u32 *)spi_imx->rx_buf = val;
+ spi_imx->rx_buf += sizeof(u32);
+ }
+}
+
+static void spi_imx_buf_rx_swap(struct spi_imx_data *spi_imx)
+{
+ unsigned int bytes_per_word;
+
+ bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
+ if (spi_imx->read_u32) {
+ spi_imx_buf_rx_swap_u32(spi_imx);
+ return;
+ }
+
+ if (bytes_per_word == 1)
+ spi_imx_buf_rx_u8(spi_imx);
+ else if (bytes_per_word == 2)
+ spi_imx_buf_rx_u16(spi_imx);
+}
+
+static void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx)
+{
+ u32 val = 0;
+#ifdef __LITTLE_ENDIAN
+ unsigned int bytes_per_word;
+#endif
+
+ if (spi_imx->tx_buf) {
+ val = *(u32 *)spi_imx->tx_buf;
+ val &= spi_imx->word_mask;
+ spi_imx->tx_buf += sizeof(u32);
+ }
+
+ spi_imx->count -= sizeof(u32);
+#ifdef __LITTLE_ENDIAN
+ bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
+
+ if (bytes_per_word == 1)
+ val = cpu_to_be32(val);
+ else if (bytes_per_word == 2)
+ val = (val << 16) | (val >> 16);
+#endif
+ writel(val, spi_imx->base + MXC_CSPITXDATA);
+}
+
+static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx)
+{
+ u32 ctrl, val;
+ unsigned int bytes_per_word;
+
+ if (spi_imx->count == spi_imx->remainder) {
+ ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
+ ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
+ if (spi_imx->count > MX51_ECSPI_CTRL_MAX_BURST) {
+ spi_imx->remainder = spi_imx->count %
+ MX51_ECSPI_CTRL_MAX_BURST;
+ val = MX51_ECSPI_CTRL_MAX_BURST * 8 - 1;
+ } else if (spi_imx->count >= sizeof(u32)) {
+ spi_imx->remainder = spi_imx->count % sizeof(u32);
+ val = (spi_imx->count - spi_imx->remainder) * 8 - 1;
+ } else {
+ spi_imx->remainder = 0;
+ val = spi_imx->bits_per_word - 1;
+ spi_imx->read_u32 = 0;
+ }
+
+ ctrl |= (val << MX51_ECSPI_CTRL_BL_OFFSET);
+ writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
+ }
+
+ if (spi_imx->count >= sizeof(u32)) {
+ spi_imx_buf_tx_swap_u32(spi_imx);
+ return;
+ }
+
+ bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
+
+ if (bytes_per_word == 1)
+ spi_imx_buf_tx_u8(spi_imx);
+ else if (bytes_per_word == 2)
+ spi_imx_buf_tx_u16(spi_imx);
+}
+
+static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx)
+{
+ u32 val = be32_to_cpu(readl(spi_imx->base + MXC_CSPIRXDATA));
+
+ if (spi_imx->rx_buf) {
+ int n_bytes = spi_imx->slave_burst % sizeof(val);
+
+ if (!n_bytes)
+ n_bytes = sizeof(val);
+
+ memcpy(spi_imx->rx_buf,
+ ((u8 *)&val) + sizeof(val) - n_bytes, n_bytes);
+
+ spi_imx->rx_buf += n_bytes;
+ spi_imx->slave_burst -= n_bytes;
+ }
+}
+
+static void mx53_ecspi_tx_slave(struct spi_imx_data *spi_imx)
+{
+ u32 val = 0;
+ int n_bytes = spi_imx->count % sizeof(val);
+
+ if (!n_bytes)
+ n_bytes = sizeof(val);
+
+ if (spi_imx->tx_buf) {
+ memcpy(((u8 *)&val) + sizeof(val) - n_bytes,
+ spi_imx->tx_buf, n_bytes);
+ val = cpu_to_be32(val);
+ spi_imx->tx_buf += n_bytes;
+ }
+
+ spi_imx->count -= n_bytes;
+
+ writel(val, spi_imx->base + MXC_CSPITXDATA);
+}
+
/* MX51 eCSPI */
static unsigned int mx51_ecspi_clkdiv(struct spi_imx_data *spi_imx,
unsigned int fspi, unsigned int *fres)
@@ -318,6 +479,9 @@ static void mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int enable)
if (enable & MXC_INT_RR)
val |= MX51_ECSPI_INT_RREN;
+ if (enable & MXC_INT_RDR)
+ val |= MX51_ECSPI_INT_RDREN;
+
writel(val, spi_imx->base + MX51_ECSPI_INT);
}
@@ -330,6 +494,15 @@ static void mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
writel(reg, spi_imx->base + MX51_ECSPI_CTRL);
}
+static void mx51_ecspi_disable(struct spi_imx_data *spi_imx)
+{
+ u32 ctrl;
+
+ ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
+ ctrl &= ~MX51_ECSPI_CTRL_ENABLE;
+ writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
+}
+
static int mx51_ecspi_config(struct spi_device *spi)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
@@ -337,14 +510,11 @@ static int mx51_ecspi_config(struct spi_device *spi)
u32 clk = spi_imx->speed_hz, delay, reg;
u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG);
- /*
- * The hardware seems to have a race condition when changing modes. The
- * current assumption is that the selection of the channel arrives
- * earlier in the hardware than the mode bits when they are written at
- * the same time.
- * So set master mode for all channels as we do not support slave mode.
- */
- ctrl |= MX51_ECSPI_CTRL_MODE_MASK;
+ /* set Master or Slave mode */
+ if (spi_imx->slave_mode)
+ ctrl &= ~MX51_ECSPI_CTRL_MODE_MASK;
+ else
+ ctrl |= MX51_ECSPI_CTRL_MODE_MASK;
/*
* Enable SPI_RDY handling (falling edge/level triggered).
@@ -359,9 +529,22 @@ static int mx51_ecspi_config(struct spi_device *spi)
/* set chip select to use */
ctrl |= MX51_ECSPI_CTRL_CS(spi->chip_select);
- ctrl |= (spi_imx->bits_per_word - 1) << MX51_ECSPI_CTRL_BL_OFFSET;
+ if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx))
+ ctrl |= (spi_imx->slave_burst * 8 - 1)
+ << MX51_ECSPI_CTRL_BL_OFFSET;
+ else
+ ctrl |= (spi_imx->bits_per_word - 1)
+ << MX51_ECSPI_CTRL_BL_OFFSET;
- cfg |= MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select);
+ /*
+ * eCSPI burst completion by Chip Select signal in Slave mode
+ * is not functional for imx53 Soc, config SPI burst completed when
+ * BURST_LENGTH + 1 bits are received
+ */
+ if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx))
+ cfg &= ~MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select);
+ else
+ cfg |= MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select);
if (spi->mode & SPI_CPHA)
cfg |= MX51_ECSPI_CONFIG_SCLKPHA(spi->chip_select);
@@ -513,8 +696,8 @@ static int mx31_config(struct spi_device *spi)
reg |= MX31_CSPICTRL_POL;
if (spi->mode & SPI_CS_HIGH)
reg |= MX31_CSPICTRL_SSPOL;
- if (spi->cs_gpio < 0)
- reg |= (spi->cs_gpio + 32) <<
+ if (!gpio_is_valid(spi->cs_gpio))
+ reg |= (spi->chip_select) <<
(is_imx35_cspi(spi_imx) ? MX35_CSPICTRL_CS_SHIFT :
MX31_CSPICTRL_CS_SHIFT);
@@ -605,8 +788,8 @@ static int mx21_config(struct spi_device *spi)
reg |= MX21_CSPICTRL_POL;
if (spi->mode & SPI_CS_HIGH)
reg |= MX21_CSPICTRL_SSPOL;
- if (spi->cs_gpio < 0)
- reg |= (spi->cs_gpio + 32) << MX21_CSPICTRL_CS_SHIFT;
+ if (!gpio_is_valid(spi->cs_gpio))
+ reg |= spi->chip_select << MX21_CSPICTRL_CS_SHIFT;
writel(reg, spi_imx->base + MXC_CSPICTRL);
@@ -693,6 +876,10 @@ static struct spi_imx_devtype_data imx1_cspi_devtype_data = {
.trigger = mx1_trigger,
.rx_available = mx1_rx_available,
.reset = mx1_reset,
+ .fifo_size = 8,
+ .has_dmamode = false,
+ .dynamic_burst = false,
+ .has_slavemode = false,
.devtype = IMX1_CSPI,
};
@@ -702,6 +889,10 @@ static struct spi_imx_devtype_data imx21_cspi_devtype_data = {
.trigger = mx21_trigger,
.rx_available = mx21_rx_available,
.reset = mx21_reset,
+ .fifo_size = 8,
+ .has_dmamode = false,
+ .dynamic_burst = false,
+ .has_slavemode = false,
.devtype = IMX21_CSPI,
};
@@ -712,6 +903,10 @@ static struct spi_imx_devtype_data imx27_cspi_devtype_data = {
.trigger = mx21_trigger,
.rx_available = mx21_rx_available,
.reset = mx21_reset,
+ .fifo_size = 8,
+ .has_dmamode = false,
+ .dynamic_burst = false,
+ .has_slavemode = false,
.devtype = IMX27_CSPI,
};
@@ -721,6 +916,10 @@ static struct spi_imx_devtype_data imx31_cspi_devtype_data = {
.trigger = mx31_trigger,
.rx_available = mx31_rx_available,
.reset = mx31_reset,
+ .fifo_size = 8,
+ .has_dmamode = false,
+ .dynamic_burst = false,
+ .has_slavemode = false,
.devtype = IMX31_CSPI,
};
@@ -731,6 +930,10 @@ static struct spi_imx_devtype_data imx35_cspi_devtype_data = {
.trigger = mx31_trigger,
.rx_available = mx31_rx_available,
.reset = mx31_reset,
+ .fifo_size = 8,
+ .has_dmamode = true,
+ .dynamic_burst = false,
+ .has_slavemode = false,
.devtype = IMX35_CSPI,
};
@@ -740,9 +943,27 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
.trigger = mx51_ecspi_trigger,
.rx_available = mx51_ecspi_rx_available,
.reset = mx51_ecspi_reset,
+ .fifo_size = 64,
+ .has_dmamode = true,
+ .dynamic_burst = true,
+ .has_slavemode = true,
+ .disable = mx51_ecspi_disable,
.devtype = IMX51_ECSPI,
};
+static struct spi_imx_devtype_data imx53_ecspi_devtype_data = {
+ .intctrl = mx51_ecspi_intctrl,
+ .config = mx51_ecspi_config,
+ .trigger = mx51_ecspi_trigger,
+ .rx_available = mx51_ecspi_rx_available,
+ .reset = mx51_ecspi_reset,
+ .fifo_size = 64,
+ .has_dmamode = true,
+ .has_slavemode = true,
+ .disable = mx51_ecspi_disable,
+ .devtype = IMX53_ECSPI,
+};
+
static const struct platform_device_id spi_imx_devtype[] = {
{
.name = "imx1-cspi",
@@ -763,6 +984,9 @@ static const struct platform_device_id spi_imx_devtype[] = {
.name = "imx51-ecspi",
.driver_data = (kernel_ulong_t) &imx51_ecspi_devtype_data,
}, {
+ .name = "imx53-ecspi",
+ .driver_data = (kernel_ulong_t) &imx53_ecspi_devtype_data,
+ }, {
/* sentinel */
}
};
@@ -774,6 +998,7 @@ static const struct of_device_id spi_imx_dt_ids[] = {
{ .compatible = "fsl,imx31-cspi", .data = &imx31_cspi_devtype_data, },
{ .compatible = "fsl,imx35-cspi", .data = &imx35_cspi_devtype_data, },
{ .compatible = "fsl,imx51-ecspi", .data = &imx51_ecspi_devtype_data, },
+ { .compatible = "fsl,imx53-ecspi", .data = &imx53_ecspi_devtype_data, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, spi_imx_dt_ids);
@@ -783,6 +1008,9 @@ static void spi_imx_chipselect(struct spi_device *spi, int is_active)
int active = is_active != BITBANG_CS_INACTIVE;
int dev_is_lowactive = !(spi->mode & SPI_CS_HIGH);
+ if (spi->mode & SPI_NO_CS)
+ return;
+
if (!gpio_is_valid(spi->cs_gpio))
return;
@@ -791,21 +1019,25 @@ static void spi_imx_chipselect(struct spi_device *spi, int is_active)
static void spi_imx_push(struct spi_imx_data *spi_imx)
{
- while (spi_imx->txfifo < spi_imx_get_fifosize(spi_imx)) {
+ while (spi_imx->txfifo < spi_imx->devtype_data->fifo_size) {
if (!spi_imx->count)
break;
+ if (spi_imx->txfifo && (spi_imx->count == spi_imx->remainder))
+ break;
spi_imx->tx(spi_imx);
spi_imx->txfifo++;
}
- spi_imx->devtype_data->trigger(spi_imx);
+ if (!spi_imx->slave_mode)
+ spi_imx->devtype_data->trigger(spi_imx);
}
static irqreturn_t spi_imx_isr(int irq, void *dev_id)
{
struct spi_imx_data *spi_imx = dev_id;
- while (spi_imx->devtype_data->rx_available(spi_imx)) {
+ while (spi_imx->txfifo &&
+ spi_imx->devtype_data->rx_available(spi_imx)) {
spi_imx->rx(spi_imx);
spi_imx->txfifo--;
}
@@ -887,15 +1119,37 @@ static int spi_imx_setupxfer(struct spi_device *spi,
spi_imx->speed_hz = t->speed_hz;
/* Initialize the functions for transfer */
- if (spi_imx->bits_per_word <= 8) {
- spi_imx->rx = spi_imx_buf_rx_u8;
- spi_imx->tx = spi_imx_buf_tx_u8;
- } else if (spi_imx->bits_per_word <= 16) {
- spi_imx->rx = spi_imx_buf_rx_u16;
- spi_imx->tx = spi_imx_buf_tx_u16;
+ if (spi_imx->devtype_data->dynamic_burst && !spi_imx->slave_mode) {
+ u32 mask;
+
+ spi_imx->dynamic_burst = 0;
+ spi_imx->remainder = 0;
+ spi_imx->read_u32 = 1;
+
+ mask = (1 << spi_imx->bits_per_word) - 1;
+ spi_imx->rx = spi_imx_buf_rx_swap;
+ spi_imx->tx = spi_imx_buf_tx_swap;
+ spi_imx->dynamic_burst = 1;
+ spi_imx->remainder = t->len;
+
+ if (spi_imx->bits_per_word <= 8)
+ spi_imx->word_mask = mask << 24 | mask << 16
+ | mask << 8 | mask;
+ else if (spi_imx->bits_per_word <= 16)
+ spi_imx->word_mask = mask << 16 | mask;
+ else
+ spi_imx->word_mask = mask;
} else {
- spi_imx->rx = spi_imx_buf_rx_u32;
- spi_imx->tx = spi_imx_buf_tx_u32;
+ if (spi_imx->bits_per_word <= 8) {
+ spi_imx->rx = spi_imx_buf_rx_u8;
+ spi_imx->tx = spi_imx_buf_tx_u8;
+ } else if (spi_imx->bits_per_word <= 16) {
+ spi_imx->rx = spi_imx_buf_rx_u16;
+ spi_imx->tx = spi_imx_buf_tx_u16;
+ } else {
+ spi_imx->rx = spi_imx_buf_rx_u32;
+ spi_imx->tx = spi_imx_buf_tx_u32;
+ }
}
if (spi_imx_can_dma(spi_imx->bitbang.master, spi, t))
@@ -909,6 +1163,12 @@ static int spi_imx_setupxfer(struct spi_device *spi,
return ret;
}
+ if (is_imx53_ecspi(spi_imx) && spi_imx->slave_mode) {
+ spi_imx->rx = mx53_ecspi_rx_slave;
+ spi_imx->tx = mx53_ecspi_tx_slave;
+ spi_imx->slave_burst = t->len;
+ }
+
spi_imx->devtype_data->config(spi);
return 0;
@@ -938,7 +1198,7 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
if (of_machine_is_compatible("fsl,imx6dl"))
return 0;
- spi_imx->wml = spi_imx_get_fifosize(spi_imx) / 2;
+ spi_imx->wml = spi_imx->devtype_data->fifo_size / 2;
/* Prepare for TX DMA: */
master->dma_tx = dma_request_slave_channel_reason(dev, "tx");
@@ -1093,11 +1353,61 @@ static int spi_imx_pio_transfer(struct spi_device *spi,
return transfer->len;
}
+static int spi_imx_pio_transfer_slave(struct spi_device *spi,
+ struct spi_transfer *transfer)
+{
+ struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
+ int ret = transfer->len;
+
+ if (is_imx53_ecspi(spi_imx) &&
+ transfer->len > MX53_MAX_TRANSFER_BYTES) {
+ dev_err(&spi->dev, "Transaction too big, max size is %d bytes\n",
+ MX53_MAX_TRANSFER_BYTES);
+ return -EMSGSIZE;
+ }
+
+ spi_imx->tx_buf = transfer->tx_buf;
+ spi_imx->rx_buf = transfer->rx_buf;
+ spi_imx->count = transfer->len;
+ spi_imx->txfifo = 0;
+
+ reinit_completion(&spi_imx->xfer_done);
+ spi_imx->slave_aborted = false;
+
+ spi_imx_push(spi_imx);
+
+ spi_imx->devtype_data->intctrl(spi_imx, MXC_INT_TE | MXC_INT_RDR);
+
+ if (wait_for_completion_interruptible(&spi_imx->xfer_done) ||
+ spi_imx->slave_aborted) {
+ dev_dbg(&spi->dev, "interrupted\n");
+ ret = -EINTR;
+ }
+
+ /* ecspi has a HW issue when works in Slave mode,
+ * after 64 words writtern to TXFIFO, even TXFIFO becomes empty,
+ * ECSPI_TXDATA keeps shift out the last word data,
+ * so we have to disable ECSPI when in slave mode after the
+ * transfer completes
+ */
+ if (spi_imx->devtype_data->disable)
+ spi_imx->devtype_data->disable(spi_imx);
+
+ return ret;
+}
+
static int spi_imx_transfer(struct spi_device *spi,
struct spi_transfer *transfer)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
+ /* flush rxfifo before transfer */
+ while (spi_imx->devtype_data->rx_available(spi_imx))
+ spi_imx->rx(spi_imx);
+
+ if (spi_imx->slave_mode)
+ return spi_imx_pio_transfer_slave(spi, transfer);
+
if (spi_imx->usedma)
return spi_imx_dma_transfer(spi_imx, transfer);
else
@@ -1109,6 +1419,9 @@ static int spi_imx_setup(struct spi_device *spi)
dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", __func__,
spi->mode, spi->bits_per_word, spi->max_speed_hz);
+ if (spi->mode & SPI_NO_CS)
+ return 0;
+
if (gpio_is_valid(spi->cs_gpio))
gpio_direction_output(spi->cs_gpio,
spi->mode & SPI_CS_HIGH ? 0 : 1);
@@ -1151,6 +1464,16 @@ spi_imx_unprepare_message(struct spi_master *master, struct spi_message *msg)
return 0;
}
+static int spi_imx_slave_abort(struct spi_master *master)
+{
+ struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
+
+ spi_imx->slave_aborted = true;
+ complete(&spi_imx->xfer_done);
+
+ return 0;
+}
+
static int spi_imx_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -1162,13 +1485,23 @@ static int spi_imx_probe(struct platform_device *pdev)
struct spi_imx_data *spi_imx;
struct resource *res;
int i, ret, irq, spi_drctl;
+ const struct spi_imx_devtype_data *devtype_data = of_id ? of_id->data :
+ (struct spi_imx_devtype_data *)pdev->id_entry->driver_data;
+ bool slave_mode;
if (!np && !mxc_platform_info) {
dev_err(&pdev->dev, "can't get the platform data\n");
return -EINVAL;
}
- master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data));
+ slave_mode = devtype_data->has_slavemode &&
+ of_property_read_bool(np, "spi-slave");
+ if (slave_mode)
+ master = spi_alloc_slave(&pdev->dev,
+ sizeof(struct spi_imx_data));
+ else
+ master = spi_alloc_master(&pdev->dev,
+ sizeof(struct spi_imx_data));
if (!master)
return -ENOMEM;
@@ -1186,20 +1519,29 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx = spi_master_get_devdata(master);
spi_imx->bitbang.master = master;
spi_imx->dev = &pdev->dev;
+ spi_imx->slave_mode = slave_mode;
- spi_imx->devtype_data = of_id ? of_id->data :
- (struct spi_imx_devtype_data *)pdev->id_entry->driver_data;
+ spi_imx->devtype_data = devtype_data;
+ /* Get number of chip selects, either platform data or OF */
if (mxc_platform_info) {
master->num_chipselect = mxc_platform_info->num_chipselect;
- master->cs_gpios = devm_kzalloc(&master->dev,
- sizeof(int) * master->num_chipselect, GFP_KERNEL);
- if (!master->cs_gpios)
- return -ENOMEM;
+ if (mxc_platform_info->chipselect) {
+ master->cs_gpios = devm_kzalloc(&master->dev,
+ sizeof(int) * master->num_chipselect, GFP_KERNEL);
+ if (!master->cs_gpios)
+ return -ENOMEM;
+
+ for (i = 0; i < master->num_chipselect; i++)
+ master->cs_gpios[i] = mxc_platform_info->chipselect[i];
+ }
+ } else {
+ u32 num_cs;
- for (i = 0; i < master->num_chipselect; i++)
- master->cs_gpios[i] = mxc_platform_info->chipselect[i];
- }
+ if (!of_property_read_u32(np, "num-cs", &num_cs))
+ master->num_chipselect = num_cs;
+ /* If not preset, default value of 1 is used */
+ }
spi_imx->bitbang.chipselect = spi_imx_chipselect;
spi_imx->bitbang.setup_transfer = spi_imx_setupxfer;
@@ -1208,8 +1550,11 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx->bitbang.master->cleanup = spi_imx_cleanup;
spi_imx->bitbang.master->prepare_message = spi_imx_prepare_message;
spi_imx->bitbang.master->unprepare_message = spi_imx_unprepare_message;
- spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
- if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx))
+ spi_imx->bitbang.master->slave_abort = spi_imx_slave_abort;
+ spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
+ | SPI_NO_CS;
+ if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx) ||
+ is_imx53_ecspi(spi_imx))
spi_imx->bitbang.master->mode_bits |= SPI_LOOP | SPI_READY;
spi_imx->spi_drctl = spi_drctl;
@@ -1262,7 +1607,7 @@ static int spi_imx_probe(struct platform_device *pdev)
* Only validated on i.mx35 and i.mx6 now, can remove the constraint
* if validated on other chips.
*/
- if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx)) {
+ if (spi_imx->devtype_data->has_dmamode) {
ret = spi_imx_sdma_init(&pdev->dev, spi_imx, master);
if (ret == -EPROBE_DEFER)
goto out_clk_put;
@@ -1277,37 +1622,38 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx->devtype_data->intctrl(spi_imx, 0);
master->dev.of_node = pdev->dev.of_node;
+
+ /* Request GPIO CS lines, if any */
+ if (!spi_imx->slave_mode && master->cs_gpios) {
+ for (i = 0; i < master->num_chipselect; i++) {
+ if (!gpio_is_valid(master->cs_gpios[i]))
+ continue;
+
+ ret = devm_gpio_request(&pdev->dev,
+ master->cs_gpios[i],
+ DRIVER_NAME);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't get CS GPIO %i\n",
+ master->cs_gpios[i]);
+ goto out_spi_bitbang;
+ }
+ }
+ }
+
ret = spi_bitbang_start(&spi_imx->bitbang);
if (ret) {
dev_err(&pdev->dev, "bitbang start failed with %d\n", ret);
goto out_clk_put;
}
- if (!master->cs_gpios) {
- dev_err(&pdev->dev, "No CS GPIOs available\n");
- ret = -EINVAL;
- goto out_clk_put;
- }
-
- for (i = 0; i < master->num_chipselect; i++) {
- if (!gpio_is_valid(master->cs_gpios[i]))
- continue;
-
- ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i],
- DRIVER_NAME);
- if (ret) {
- dev_err(&pdev->dev, "Can't get CS GPIO %i\n",
- master->cs_gpios[i]);
- goto out_clk_put;
- }
- }
-
dev_info(&pdev->dev, "probed\n");
clk_disable(spi_imx->clk_ipg);
clk_disable(spi_imx->clk_per);
return ret;
+out_spi_bitbang:
+ spi_bitbang_stop(&spi_imx->bitbang);
out_clk_put:
clk_disable_unprepare(spi_imx->clk_ipg);
out_put_per: