diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c index 799a91d..5ccb3f2 100644 --- a/drivers/spi/spi_imx.c +++ b/drivers/spi/spi_imx.c @@ -59,6 +59,7 @@ struct spi_imx_config { int cs; }; +#define SPI_IMX_FLEXIBLE struct spi_imx_data { struct spi_bitbang bitbang; @@ -70,8 +71,14 @@ struct spi_imx_data { int *chipselect; unsigned int count; - void (*tx)(struct spi_imx_data *); +#ifndef SPI_IMX_FLEXIBLE + void (*tx)(struct spi_imx_data *); void (*rx)(struct spi_imx_data *); +#else + int rxsize; + int txsize; + int bytes; +#endif void *rx_buf; const void *tx_buf; unsigned int txfifo; /* number of words pushed in tx FIFO */ @@ -83,6 +90,7 @@ struct spi_imx_data { int (*rx_available)(struct spi_imx_data *); }; +#ifndef SPI_IMX_FLEXIBLE #define MXC_SPI_BUF_RX(type) \ static void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx) \ { \ @@ -142,6 +150,76 @@ static void spi_imx_buf_tx_u24(struct spi_imx_data *spi_imx) writel(val, spi_imx->base + MXC_CSPITXDATA); } +#else +static void spi_imx_transmit(struct spi_imx_data *spi_imx) +{ + u32 val = 0; + int cnt = min(4,spi_imx->txsize); + + if (spi_imx->tx_buf) { + const u8 *data = (const u8 *)spi_imx->tx_buf; + if(!cnt) spi_imx->txsize = spi_imx->bytes; + switch(cnt) { + case 1: + val = data[0]; + break; + case 2: + val = data[0] << 8 | data[1]; + break; + case 3: + val = data[0] << 16 | data[1] << 8 | data[2]; + break; + case 4: + val = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; + break; + } + spi_imx->tx_buf += cnt; + + } + spi_imx->count -= cnt; + spi_imx->txsize -= cnt; + if(spi_imx->txsize <= 0) { + spi_imx->txsize = spi_imx->bytes; + } + + writel(val, spi_imx->base + MXC_CSPITXDATA); +} +static void spi_imx_receive(struct spi_imx_data *spi_imx) +{ + unsigned int val = readl(spi_imx->base + MXC_CSPIRXDATA); + int cnt = min(4,spi_imx->rxsize); + + if (spi_imx->rx_buf) { + u8 *data = (u8 *)spi_imx->rx_buf; + switch(cnt) { + case 1: + data[0] = val & 0xff; + break; + case 2: + data[0] = (val >> 8) & 0xff; + data[1] = val & 0xff; + break; + case 3: + data[0] = (val >> 16) & 0xff; + data[1] = (val >> 8) & 0xff; + data[2] = val & 0xff; + break; + case 4: + data[0] = (val >> 24) & 0xff; + data[1] = (val >> 16) & 0xff; + data[2] = (val >> 8) & 0xff; + data[3] = val & 0xff; + break; + } + spi_imx->rx_buf += cnt; + } + spi_imx->rxsize -= cnt; + if(spi_imx->rxsize <= 0) { + spi_imx->rxsize = spi_imx->bytes; + } +} +#endif + /* First entry is reserved, second entry is valid only if SDHC_SPIEN is set * (which is currently not the case in this driver) @@ -400,7 +478,11 @@ static void spi_imx_push(struct spi_imx_data *spi_imx) while (spi_imx->txfifo < 8) { if (!spi_imx->count) break; +#ifndef SPI_IMX_FLEXIBLE spi_imx->tx(spi_imx); +#else + spi_imx_transmit(spi_imx); +#endif spi_imx->txfifo++; } @@ -412,7 +494,11 @@ static irqreturn_t spi_imx_isr(int irq, void *dev_id) struct spi_imx_data *spi_imx = dev_id; while (spi_imx->rx_available(spi_imx)) { +#ifndef SPI_IMX_FLEXIBLE spi_imx->rx(spi_imx); +#else + spi_imx_receive(spi_imx); +#endif spi_imx->txfifo--; } @@ -453,6 +539,7 @@ static int spi_imx_setupxfer(struct spi_device *spi, if (!config.speed_hz) config.speed_hz = spi->max_speed_hz; +#ifndef SPI_IMX_FLEXIBLE /* Initialize the functions for transfer */ if (config.bpw <= 8) { spi_imx->rx = spi_imx_buf_rx_u8; @@ -468,6 +555,13 @@ static int spi_imx_setupxfer(struct spi_device *spi, spi_imx->tx = spi_imx_buf_tx_u32; } else BUG(); +#else + spi_imx->bytes = DIV_ROUND_UP(config.bpw,8); + spi_imx->txsize = DIV_ROUND_UP(config.bpw,8); + spi_imx->rxsize = DIV_ROUND_UP(config.bpw,8); + /* spi_imx->rx = spi_imx_receive; */ + /* spi_imx->tx = spi_imx_transmit; */ +#endif spi_imx->config(spi_imx, &config);