mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 03:27:44 -04:00
Merge remote-tracking branches 'spi/topic/dw', 'spi/topic/dw-mid', 'spi/topic/fsl-espi' and 'spi/topic/imx' into spi-next
This commit is contained in:
commit
635b9b2e6e
6 changed files with 91 additions and 37 deletions
|
|
@ -283,7 +283,7 @@ static void mid_spi_dma_stop(struct dw_spi *dws)
|
|||
}
|
||||
}
|
||||
|
||||
static struct dw_spi_dma_ops mid_dma_ops = {
|
||||
static const struct dw_spi_dma_ops mid_dma_ops = {
|
||||
.dma_init = mid_spi_dma_init,
|
||||
.dma_exit = mid_spi_dma_exit,
|
||||
.dma_setup = mid_spi_dma_setup,
|
||||
|
|
|
|||
|
|
@ -425,7 +425,7 @@ static int dw_spi_setup(struct spi_device *spi)
|
|||
chip->type = chip_info->type;
|
||||
}
|
||||
|
||||
chip->tmode = 0; /* Tx & Rx */
|
||||
chip->tmode = SPI_TMOD_TR;
|
||||
|
||||
if (gpio_is_valid(spi->cs_gpio)) {
|
||||
ret = gpio_direction_output(spi->cs_gpio,
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ struct dw_spi {
|
|||
struct dma_chan *rxchan;
|
||||
unsigned long dma_chan_busy;
|
||||
dma_addr_t dma_addr; /* phy address of the Data register */
|
||||
struct dw_spi_dma_ops *dma_ops;
|
||||
const struct dw_spi_dma_ops *dma_ops;
|
||||
void *dma_tx;
|
||||
void *dma_rx;
|
||||
|
||||
|
|
|
|||
|
|
@ -643,6 +643,11 @@ static int fsl_espi_runtime_resume(struct device *dev)
|
|||
}
|
||||
#endif
|
||||
|
||||
static size_t fsl_espi_max_transfer_size(struct spi_device *spi)
|
||||
{
|
||||
return SPCOM_TRANLEN_MAX;
|
||||
}
|
||||
|
||||
static struct spi_master * fsl_espi_probe(struct device *dev,
|
||||
struct resource *mem, unsigned int irq)
|
||||
{
|
||||
|
|
@ -670,6 +675,7 @@ static struct spi_master * fsl_espi_probe(struct device *dev,
|
|||
master->cleanup = fsl_espi_cleanup;
|
||||
master->transfer_one_message = fsl_espi_do_one_msg;
|
||||
master->auto_runtime_pm = true;
|
||||
master->max_transfer_size = fsl_espi_max_transfer_size;
|
||||
|
||||
mpc8xxx_spi = spi_master_get_devdata(master);
|
||||
|
||||
|
|
|
|||
|
|
@ -104,9 +104,7 @@ struct spi_imx_data {
|
|||
unsigned int dma_is_inited;
|
||||
unsigned int dma_finished;
|
||||
bool usedma;
|
||||
u32 rx_wml;
|
||||
u32 tx_wml;
|
||||
u32 rxt_wml;
|
||||
u32 wml;
|
||||
struct completion dma_rx_completion;
|
||||
struct completion dma_tx_completion;
|
||||
|
||||
|
|
@ -124,9 +122,14 @@ static inline int is_imx35_cspi(struct spi_imx_data *d)
|
|||
return d->devtype_data->devtype == IMX35_CSPI;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return (d->devtype_data->devtype == IMX51_ECSPI) ? 64 : 8;
|
||||
return is_imx51_ecspi(d) ? 64 : 8;
|
||||
}
|
||||
|
||||
#define MXC_SPI_BUF_RX(type) \
|
||||
|
|
@ -201,9 +204,8 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
|
|||
{
|
||||
struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
|
||||
|
||||
if (spi_imx->dma_is_inited
|
||||
&& transfer->len > spi_imx->rx_wml * sizeof(u32)
|
||||
&& transfer->len > spi_imx->tx_wml * sizeof(u32))
|
||||
if (spi_imx->dma_is_inited &&
|
||||
transfer->len > spi_imx->wml * sizeof(u32))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -244,6 +246,9 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
|
|||
#define MX51_ECSPI_STAT 0x18
|
||||
#define MX51_ECSPI_STAT_RR (1 << 3)
|
||||
|
||||
#define MX51_ECSPI_TESTREG 0x20
|
||||
#define MX51_ECSPI_TESTREG_LBC BIT(31)
|
||||
|
||||
/* MX51 eCSPI */
|
||||
static unsigned int mx51_ecspi_clkdiv(unsigned int fin, unsigned int fspi,
|
||||
unsigned int *fres)
|
||||
|
|
@ -313,7 +318,7 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
|
|||
{
|
||||
u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0, dma = 0;
|
||||
u32 tx_wml_cfg, rx_wml_cfg, rxt_wml_cfg;
|
||||
u32 clk = config->speed_hz, delay;
|
||||
u32 clk = config->speed_hz, delay, reg;
|
||||
|
||||
/*
|
||||
* The hardware seems to have a race condition when changing modes. The
|
||||
|
|
@ -351,7 +356,16 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
|
|||
else
|
||||
cfg &= ~MX51_ECSPI_CONFIG_SSBPOL(config->cs);
|
||||
|
||||
/* CTRL register always go first to bring out controller from reset */
|
||||
writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
|
||||
|
||||
reg = readl(spi_imx->base + MX51_ECSPI_TESTREG);
|
||||
if (config->mode & SPI_LOOP)
|
||||
reg |= MX51_ECSPI_TESTREG_LBC;
|
||||
else
|
||||
reg &= ~MX51_ECSPI_TESTREG_LBC;
|
||||
writel(reg, spi_imx->base + MX51_ECSPI_TESTREG);
|
||||
|
||||
writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG);
|
||||
|
||||
/*
|
||||
|
|
@ -378,10 +392,9 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
|
|||
if (spi_imx->dma_is_inited) {
|
||||
dma = readl(spi_imx->base + MX51_ECSPI_DMA);
|
||||
|
||||
spi_imx->rxt_wml = spi_imx_get_fifosize(spi_imx) / 2;
|
||||
rx_wml_cfg = spi_imx->rx_wml << MX51_ECSPI_DMA_RX_WML_OFFSET;
|
||||
tx_wml_cfg = spi_imx->tx_wml << MX51_ECSPI_DMA_TX_WML_OFFSET;
|
||||
rxt_wml_cfg = spi_imx->rxt_wml << MX51_ECSPI_DMA_RXT_WML_OFFSET;
|
||||
rx_wml_cfg = spi_imx->wml << MX51_ECSPI_DMA_RX_WML_OFFSET;
|
||||
tx_wml_cfg = spi_imx->wml << MX51_ECSPI_DMA_TX_WML_OFFSET;
|
||||
rxt_wml_cfg = spi_imx->wml << MX51_ECSPI_DMA_RXT_WML_OFFSET;
|
||||
dma = (dma & ~MX51_ECSPI_DMA_TX_WML_MASK
|
||||
& ~MX51_ECSPI_DMA_RX_WML_MASK
|
||||
& ~MX51_ECSPI_DMA_RXT_WML_MASK)
|
||||
|
|
@ -832,18 +845,21 @@ 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;
|
||||
|
||||
/* Prepare for TX DMA: */
|
||||
master->dma_tx = dma_request_slave_channel(dev, "tx");
|
||||
if (!master->dma_tx) {
|
||||
dev_err(dev, "cannot get the TX DMA channel!\n");
|
||||
ret = -EINVAL;
|
||||
master->dma_tx = dma_request_slave_channel_reason(dev, "tx");
|
||||
if (IS_ERR(master->dma_tx)) {
|
||||
ret = PTR_ERR(master->dma_tx);
|
||||
dev_dbg(dev, "can't get the TX DMA channel, error %d!\n", ret);
|
||||
master->dma_tx = NULL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
slave_config.direction = DMA_MEM_TO_DEV;
|
||||
slave_config.dst_addr = res->start + MXC_CSPITXDATA;
|
||||
slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
slave_config.dst_maxburst = spi_imx_get_fifosize(spi_imx) / 2;
|
||||
slave_config.dst_maxburst = spi_imx->wml;
|
||||
ret = dmaengine_slave_config(master->dma_tx, &slave_config);
|
||||
if (ret) {
|
||||
dev_err(dev, "error in TX dma configuration.\n");
|
||||
|
|
@ -851,17 +867,18 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
|
|||
}
|
||||
|
||||
/* Prepare for RX : */
|
||||
master->dma_rx = dma_request_slave_channel(dev, "rx");
|
||||
if (!master->dma_rx) {
|
||||
dev_dbg(dev, "cannot get the DMA channel.\n");
|
||||
ret = -EINVAL;
|
||||
master->dma_rx = dma_request_slave_channel_reason(dev, "rx");
|
||||
if (IS_ERR(master->dma_rx)) {
|
||||
ret = PTR_ERR(master->dma_rx);
|
||||
dev_dbg(dev, "can't get the RX DMA channel, error %d\n", ret);
|
||||
master->dma_rx = NULL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
slave_config.direction = DMA_DEV_TO_MEM;
|
||||
slave_config.src_addr = res->start + MXC_CSPIRXDATA;
|
||||
slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
slave_config.src_maxburst = spi_imx_get_fifosize(spi_imx) / 2;
|
||||
slave_config.src_maxburst = spi_imx->wml;
|
||||
ret = dmaengine_slave_config(master->dma_rx, &slave_config);
|
||||
if (ret) {
|
||||
dev_err(dev, "error in RX dma configuration.\n");
|
||||
|
|
@ -874,8 +891,6 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
|
|||
master->max_dma_len = MAX_SDMA_BD_BYTES;
|
||||
spi_imx->bitbang.master->flags = SPI_MASTER_MUST_RX |
|
||||
SPI_MASTER_MUST_TX;
|
||||
spi_imx->tx_wml = spi_imx_get_fifosize(spi_imx) / 2;
|
||||
spi_imx->rx_wml = spi_imx_get_fifosize(spi_imx) / 2;
|
||||
spi_imx->dma_is_inited = 1;
|
||||
|
||||
return 0;
|
||||
|
|
@ -942,14 +957,22 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
|
|||
dma = readl(spi_imx->base + MX51_ECSPI_DMA);
|
||||
dma = dma & (~MX51_ECSPI_DMA_RXT_WML_MASK);
|
||||
/* Change RX_DMA_LENGTH trigger dma fetch tail data */
|
||||
left = transfer->len % spi_imx->rxt_wml;
|
||||
left = transfer->len % spi_imx->wml;
|
||||
if (left)
|
||||
writel(dma | (left << MX51_ECSPI_DMA_RXT_WML_OFFSET),
|
||||
spi_imx->base + MX51_ECSPI_DMA);
|
||||
/*
|
||||
* Set these order to avoid potential RX overflow. The overflow may
|
||||
* happen if we enable SPI HW before starting RX DMA due to rescheduling
|
||||
* for another task and/or interrupt.
|
||||
* So RX DMA enabled first to make sure data would be read out from FIFO
|
||||
* ASAP. TX DMA enabled next to start filling TX FIFO with new data.
|
||||
* And finaly SPI HW enabled to start actual data transfer.
|
||||
*/
|
||||
dma_async_issue_pending(master->dma_rx);
|
||||
dma_async_issue_pending(master->dma_tx);
|
||||
spi_imx->devtype_data->trigger(spi_imx);
|
||||
|
||||
dma_async_issue_pending(master->dma_tx);
|
||||
dma_async_issue_pending(master->dma_rx);
|
||||
/* Wait SDMA to finish the data transfer.*/
|
||||
timeout = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
|
||||
IMX_DMA_TIMEOUT);
|
||||
|
|
@ -958,6 +981,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
|
|||
dev_driver_string(&master->dev),
|
||||
dev_name(&master->dev));
|
||||
dmaengine_terminate_all(master->dma_tx);
|
||||
dmaengine_terminate_all(master->dma_rx);
|
||||
} else {
|
||||
timeout = wait_for_completion_timeout(
|
||||
&spi_imx->dma_rx_completion, IMX_DMA_TIMEOUT);
|
||||
|
|
@ -968,8 +992,9 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
|
|||
spi_imx->devtype_data->reset(spi_imx);
|
||||
dmaengine_terminate_all(master->dma_rx);
|
||||
}
|
||||
dma &= ~MX51_ECSPI_DMA_RXT_WML_MASK;
|
||||
writel(dma |
|
||||
spi_imx->rxt_wml << MX51_ECSPI_DMA_RXT_WML_OFFSET,
|
||||
spi_imx->wml << MX51_ECSPI_DMA_RXT_WML_OFFSET,
|
||||
spi_imx->base + MX51_ECSPI_DMA);
|
||||
}
|
||||
|
||||
|
|
@ -1117,6 +1142,9 @@ static int spi_imx_probe(struct platform_device *pdev)
|
|||
spi_imx = spi_master_get_devdata(master);
|
||||
spi_imx->bitbang.master = master;
|
||||
|
||||
spi_imx->devtype_data = of_id ? of_id->data :
|
||||
(struct spi_imx_devtype_data *)pdev->id_entry->driver_data;
|
||||
|
||||
for (i = 0; i < master->num_chipselect; i++) {
|
||||
int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
|
||||
if (!gpio_is_valid(cs_gpio) && mxc_platform_info)
|
||||
|
|
@ -1142,12 +1170,11 @@ static int spi_imx_probe(struct platform_device *pdev)
|
|||
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_imx51_ecspi(spi_imx))
|
||||
spi_imx->bitbang.master->mode_bits |= SPI_LOOP;
|
||||
|
||||
init_completion(&spi_imx->xfer_done);
|
||||
|
||||
spi_imx->devtype_data = of_id ? of_id->data :
|
||||
(struct spi_imx_devtype_data *) pdev->id_entry->driver_data;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
spi_imx->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(spi_imx->base)) {
|
||||
|
|
@ -1193,9 +1220,15 @@ static int spi_imx_probe(struct platform_device *pdev)
|
|||
* Only validated on i.mx6 now, can remove the constrain if validated on
|
||||
* other chips.
|
||||
*/
|
||||
if (spi_imx->devtype_data == &imx51_ecspi_devtype_data
|
||||
&& spi_imx_sdma_init(&pdev->dev, spi_imx, master, res))
|
||||
dev_err(&pdev->dev, "dma setup error,use pio instead\n");
|
||||
if (is_imx51_ecspi(spi_imx)) {
|
||||
ret = spi_imx_sdma_init(&pdev->dev, spi_imx, master, res);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
goto out_clk_put;
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(&pdev->dev, "dma setup error %d, use pio\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
spi_imx->devtype_data->reset(spi_imx);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue