|
@@ -53,10 +53,13 @@
|
|
/* generic defines to abstract from the different register layouts */
|
|
/* generic defines to abstract from the different register layouts */
|
|
#define MXC_INT_RR (1 << 0) /* Receive data ready interrupt */
|
|
#define MXC_INT_RR (1 << 0) /* Receive data ready interrupt */
|
|
#define MXC_INT_TE (1 << 1) /* Transmit FIFO empty 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.*/
|
|
/* The maximum bytes that a sdma BD can transfer.*/
|
|
#define MAX_SDMA_BD_BYTES (1 << 15)
|
|
#define MAX_SDMA_BD_BYTES (1 << 15)
|
|
#define MX51_ECSPI_CTRL_MAX_BURST 512
|
|
#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 {
|
|
enum spi_imx_devtype {
|
|
IMX1_CSPI,
|
|
IMX1_CSPI,
|
|
@@ -76,7 +79,9 @@ struct spi_imx_devtype_data {
|
|
void (*trigger)(struct spi_imx_data *);
|
|
void (*trigger)(struct spi_imx_data *);
|
|
int (*rx_available)(struct spi_imx_data *);
|
|
int (*rx_available)(struct spi_imx_data *);
|
|
void (*reset)(struct spi_imx_data *);
|
|
void (*reset)(struct spi_imx_data *);
|
|
|
|
+ void (*disable)(struct spi_imx_data *);
|
|
bool has_dmamode;
|
|
bool has_dmamode;
|
|
|
|
+ bool has_slavemode;
|
|
unsigned int fifo_size;
|
|
unsigned int fifo_size;
|
|
bool dynamic_burst;
|
|
bool dynamic_burst;
|
|
enum spi_imx_devtype devtype;
|
|
enum spi_imx_devtype devtype;
|
|
@@ -108,6 +113,11 @@ struct spi_imx_data {
|
|
unsigned int dynamic_burst, read_u32;
|
|
unsigned int dynamic_burst, read_u32;
|
|
unsigned int word_mask;
|
|
unsigned int word_mask;
|
|
|
|
|
|
|
|
+ /* Slave mode */
|
|
|
|
+ bool slave_mode;
|
|
|
|
+ bool slave_aborted;
|
|
|
|
+ unsigned int slave_burst;
|
|
|
|
+
|
|
/* DMA */
|
|
/* DMA */
|
|
bool usedma;
|
|
bool usedma;
|
|
u32 wml;
|
|
u32 wml;
|
|
@@ -221,6 +231,9 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
|
|
if (!master->dma_rx)
|
|
if (!master->dma_rx)
|
|
return false;
|
|
return false;
|
|
|
|
|
|
|
|
+ if (spi_imx->slave_mode)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
|
|
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)
|
|
if (bytes_per_word != 1 && bytes_per_word != 2 && bytes_per_word != 4)
|
|
@@ -262,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 0x10
|
|
#define MX51_ECSPI_INT_TEEN (1 << 0)
|
|
#define MX51_ECSPI_INT_TEEN (1 << 0)
|
|
#define MX51_ECSPI_INT_RREN (1 << 3)
|
|
#define MX51_ECSPI_INT_RREN (1 << 3)
|
|
|
|
+#define MX51_ECSPI_INT_RDREN (1 << 4)
|
|
|
|
|
|
#define MX51_ECSPI_DMA 0x14
|
|
#define MX51_ECSPI_DMA 0x14
|
|
#define MX51_ECSPI_DMA_TX_WML(wml) ((wml) & 0x3f)
|
|
#define MX51_ECSPI_DMA_TX_WML(wml) ((wml) & 0x3f)
|
|
@@ -378,6 +392,44 @@ static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx)
|
|
spi_imx_buf_tx_u16(spi_imx);
|
|
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 */
|
|
/* MX51 eCSPI */
|
|
static unsigned int mx51_ecspi_clkdiv(struct spi_imx_data *spi_imx,
|
|
static unsigned int mx51_ecspi_clkdiv(struct spi_imx_data *spi_imx,
|
|
unsigned int fspi, unsigned int *fres)
|
|
unsigned int fspi, unsigned int *fres)
|
|
@@ -427,6 +479,9 @@ static void mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int enable)
|
|
if (enable & MXC_INT_RR)
|
|
if (enable & MXC_INT_RR)
|
|
val |= MX51_ECSPI_INT_RREN;
|
|
val |= MX51_ECSPI_INT_RREN;
|
|
|
|
|
|
|
|
+ if (enable & MXC_INT_RDR)
|
|
|
|
+ val |= MX51_ECSPI_INT_RDREN;
|
|
|
|
+
|
|
writel(val, spi_imx->base + MX51_ECSPI_INT);
|
|
writel(val, spi_imx->base + MX51_ECSPI_INT);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -439,6 +494,15 @@ static void mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
|
|
writel(reg, spi_imx->base + MX51_ECSPI_CTRL);
|
|
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)
|
|
static int mx51_ecspi_config(struct spi_device *spi)
|
|
{
|
|
{
|
|
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
|
|
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
|
|
@@ -446,14 +510,11 @@ static int mx51_ecspi_config(struct spi_device *spi)
|
|
u32 clk = spi_imx->speed_hz, delay, reg;
|
|
u32 clk = spi_imx->speed_hz, delay, reg;
|
|
u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG);
|
|
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).
|
|
* Enable SPI_RDY handling (falling edge/level triggered).
|
|
@@ -468,9 +529,22 @@ static int mx51_ecspi_config(struct spi_device *spi)
|
|
/* set chip select to use */
|
|
/* set chip select to use */
|
|
ctrl |= MX51_ECSPI_CTRL_CS(spi->chip_select);
|
|
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)
|
|
if (spi->mode & SPI_CPHA)
|
|
cfg |= MX51_ECSPI_CONFIG_SCLKPHA(spi->chip_select);
|
|
cfg |= MX51_ECSPI_CONFIG_SCLKPHA(spi->chip_select);
|
|
@@ -805,6 +879,7 @@ static struct spi_imx_devtype_data imx1_cspi_devtype_data = {
|
|
.fifo_size = 8,
|
|
.fifo_size = 8,
|
|
.has_dmamode = false,
|
|
.has_dmamode = false,
|
|
.dynamic_burst = false,
|
|
.dynamic_burst = false,
|
|
|
|
+ .has_slavemode = false,
|
|
.devtype = IMX1_CSPI,
|
|
.devtype = IMX1_CSPI,
|
|
};
|
|
};
|
|
|
|
|
|
@@ -817,6 +892,7 @@ static struct spi_imx_devtype_data imx21_cspi_devtype_data = {
|
|
.fifo_size = 8,
|
|
.fifo_size = 8,
|
|
.has_dmamode = false,
|
|
.has_dmamode = false,
|
|
.dynamic_burst = false,
|
|
.dynamic_burst = false,
|
|
|
|
+ .has_slavemode = false,
|
|
.devtype = IMX21_CSPI,
|
|
.devtype = IMX21_CSPI,
|
|
};
|
|
};
|
|
|
|
|
|
@@ -830,6 +906,7 @@ static struct spi_imx_devtype_data imx27_cspi_devtype_data = {
|
|
.fifo_size = 8,
|
|
.fifo_size = 8,
|
|
.has_dmamode = false,
|
|
.has_dmamode = false,
|
|
.dynamic_burst = false,
|
|
.dynamic_burst = false,
|
|
|
|
+ .has_slavemode = false,
|
|
.devtype = IMX27_CSPI,
|
|
.devtype = IMX27_CSPI,
|
|
};
|
|
};
|
|
|
|
|
|
@@ -842,6 +919,7 @@ static struct spi_imx_devtype_data imx31_cspi_devtype_data = {
|
|
.fifo_size = 8,
|
|
.fifo_size = 8,
|
|
.has_dmamode = false,
|
|
.has_dmamode = false,
|
|
.dynamic_burst = false,
|
|
.dynamic_burst = false,
|
|
|
|
+ .has_slavemode = false,
|
|
.devtype = IMX31_CSPI,
|
|
.devtype = IMX31_CSPI,
|
|
};
|
|
};
|
|
|
|
|
|
@@ -855,6 +933,7 @@ static struct spi_imx_devtype_data imx35_cspi_devtype_data = {
|
|
.fifo_size = 8,
|
|
.fifo_size = 8,
|
|
.has_dmamode = true,
|
|
.has_dmamode = true,
|
|
.dynamic_burst = false,
|
|
.dynamic_burst = false,
|
|
|
|
+ .has_slavemode = false,
|
|
.devtype = IMX35_CSPI,
|
|
.devtype = IMX35_CSPI,
|
|
};
|
|
};
|
|
|
|
|
|
@@ -867,6 +946,8 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
|
|
.fifo_size = 64,
|
|
.fifo_size = 64,
|
|
.has_dmamode = true,
|
|
.has_dmamode = true,
|
|
.dynamic_burst = true,
|
|
.dynamic_burst = true,
|
|
|
|
+ .has_slavemode = true,
|
|
|
|
+ .disable = mx51_ecspi_disable,
|
|
.devtype = IMX51_ECSPI,
|
|
.devtype = IMX51_ECSPI,
|
|
};
|
|
};
|
|
|
|
|
|
@@ -878,6 +959,8 @@ static struct spi_imx_devtype_data imx53_ecspi_devtype_data = {
|
|
.reset = mx51_ecspi_reset,
|
|
.reset = mx51_ecspi_reset,
|
|
.fifo_size = 64,
|
|
.fifo_size = 64,
|
|
.has_dmamode = true,
|
|
.has_dmamode = true,
|
|
|
|
+ .has_slavemode = true,
|
|
|
|
+ .disable = mx51_ecspi_disable,
|
|
.devtype = IMX53_ECSPI,
|
|
.devtype = IMX53_ECSPI,
|
|
};
|
|
};
|
|
|
|
|
|
@@ -945,14 +1028,16 @@ static void spi_imx_push(struct spi_imx_data *spi_imx)
|
|
spi_imx->txfifo++;
|
|
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)
|
|
static irqreturn_t spi_imx_isr(int irq, void *dev_id)
|
|
{
|
|
{
|
|
struct spi_imx_data *spi_imx = 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->rx(spi_imx);
|
|
spi_imx->txfifo--;
|
|
spi_imx->txfifo--;
|
|
}
|
|
}
|
|
@@ -1034,7 +1119,7 @@ static int spi_imx_setupxfer(struct spi_device *spi,
|
|
spi_imx->speed_hz = t->speed_hz;
|
|
spi_imx->speed_hz = t->speed_hz;
|
|
|
|
|
|
/* Initialize the functions for transfer */
|
|
/* Initialize the functions for transfer */
|
|
- if (spi_imx->devtype_data->dynamic_burst) {
|
|
|
|
|
|
+ if (spi_imx->devtype_data->dynamic_burst && !spi_imx->slave_mode) {
|
|
u32 mask;
|
|
u32 mask;
|
|
|
|
|
|
spi_imx->dynamic_burst = 0;
|
|
spi_imx->dynamic_burst = 0;
|
|
@@ -1078,6 +1163,12 @@ static int spi_imx_setupxfer(struct spi_device *spi,
|
|
return ret;
|
|
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);
|
|
spi_imx->devtype_data->config(spi);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -1262,11 +1353,61 @@ static int spi_imx_pio_transfer(struct spi_device *spi,
|
|
return transfer->len;
|
|
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,
|
|
static int spi_imx_transfer(struct spi_device *spi,
|
|
struct spi_transfer *transfer)
|
|
struct spi_transfer *transfer)
|
|
{
|
|
{
|
|
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
|
|
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)
|
|
if (spi_imx->usedma)
|
|
return spi_imx_dma_transfer(spi_imx, transfer);
|
|
return spi_imx_dma_transfer(spi_imx, transfer);
|
|
else
|
|
else
|
|
@@ -1323,6 +1464,16 @@ spi_imx_unprepare_message(struct spi_master *master, struct spi_message *msg)
|
|
return 0;
|
|
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)
|
|
static int spi_imx_probe(struct platform_device *pdev)
|
|
{
|
|
{
|
|
struct device_node *np = pdev->dev.of_node;
|
|
struct device_node *np = pdev->dev.of_node;
|
|
@@ -1334,13 +1485,23 @@ static int spi_imx_probe(struct platform_device *pdev)
|
|
struct spi_imx_data *spi_imx;
|
|
struct spi_imx_data *spi_imx;
|
|
struct resource *res;
|
|
struct resource *res;
|
|
int i, ret, irq, spi_drctl;
|
|
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) {
|
|
if (!np && !mxc_platform_info) {
|
|
dev_err(&pdev->dev, "can't get the platform data\n");
|
|
dev_err(&pdev->dev, "can't get the platform data\n");
|
|
return -EINVAL;
|
|
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)
|
|
if (!master)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
|
|
|
|
@@ -1358,20 +1519,29 @@ static int spi_imx_probe(struct platform_device *pdev)
|
|
spi_imx = spi_master_get_devdata(master);
|
|
spi_imx = spi_master_get_devdata(master);
|
|
spi_imx->bitbang.master = master;
|
|
spi_imx->bitbang.master = master;
|
|
spi_imx->dev = &pdev->dev;
|
|
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) {
|
|
if (mxc_platform_info) {
|
|
master->num_chipselect = mxc_platform_info->num_chipselect;
|
|
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.chipselect = spi_imx_chipselect;
|
|
spi_imx->bitbang.setup_transfer = spi_imx_setupxfer;
|
|
spi_imx->bitbang.setup_transfer = spi_imx_setupxfer;
|
|
@@ -1380,6 +1550,7 @@ static int spi_imx_probe(struct platform_device *pdev)
|
|
spi_imx->bitbang.master->cleanup = spi_imx_cleanup;
|
|
spi_imx->bitbang.master->cleanup = spi_imx_cleanup;
|
|
spi_imx->bitbang.master->prepare_message = spi_imx_prepare_message;
|
|
spi_imx->bitbang.master->prepare_message = spi_imx_prepare_message;
|
|
spi_imx->bitbang.master->unprepare_message = spi_imx_unprepare_message;
|
|
spi_imx->bitbang.master->unprepare_message = spi_imx_unprepare_message;
|
|
|
|
+ spi_imx->bitbang.master->slave_abort = spi_imx_slave_abort;
|
|
spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
|
|
spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
|
|
| SPI_NO_CS;
|
|
| SPI_NO_CS;
|
|
if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx) ||
|
|
if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx) ||
|
|
@@ -1451,37 +1622,38 @@ static int spi_imx_probe(struct platform_device *pdev)
|
|
spi_imx->devtype_data->intctrl(spi_imx, 0);
|
|
spi_imx->devtype_data->intctrl(spi_imx, 0);
|
|
|
|
|
|
master->dev.of_node = pdev->dev.of_node;
|
|
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);
|
|
ret = spi_bitbang_start(&spi_imx->bitbang);
|
|
if (ret) {
|
|
if (ret) {
|
|
dev_err(&pdev->dev, "bitbang start failed with %d\n", ret);
|
|
dev_err(&pdev->dev, "bitbang start failed with %d\n", ret);
|
|
goto out_clk_put;
|
|
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");
|
|
dev_info(&pdev->dev, "probed\n");
|
|
|
|
|
|
clk_disable(spi_imx->clk_ipg);
|
|
clk_disable(spi_imx->clk_ipg);
|
|
clk_disable(spi_imx->clk_per);
|
|
clk_disable(spi_imx->clk_per);
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
|
|
+out_spi_bitbang:
|
|
|
|
+ spi_bitbang_stop(&spi_imx->bitbang);
|
|
out_clk_put:
|
|
out_clk_put:
|
|
clk_disable_unprepare(spi_imx->clk_ipg);
|
|
clk_disable_unprepare(spi_imx->clk_ipg);
|
|
out_put_per:
|
|
out_put_per:
|