summaryrefslogtreecommitdiff
path: root/drivers/spi/spi_qsd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/spi_qsd.c')
-rw-r--r--drivers/spi/spi_qsd.c87
1 files changed, 72 insertions, 15 deletions
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 5c56001e36db..aa7386325893 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -55,6 +55,7 @@ static int get_local_resources(struct msm_spi *dd);
static void put_local_resources(struct msm_spi *dd);
static void msm_spi_slv_setup(struct msm_spi *dd);
static inline int msm_spi_wait_valid(struct msm_spi *dd);
+static int reset_core(struct msm_spi *dd);
static inline int msm_spi_configure_gsbi(struct msm_spi *dd,
struct platform_device *pdev)
@@ -551,7 +552,7 @@ static inline int msm_spi_set_state(struct msm_spi *dd,
}
if (msm_spi_wait_valid(dd))
return -EIO;
-
+ atomic_set(&dd->qup_state, state);
return 0;
}
@@ -1491,6 +1492,10 @@ static int msm_spi_process_transfer(struct msm_spi *dd)
}
} while (msm_spi_dma_send_next(dd));
+ if (status && dd->pdata->is_slv_ctrl) {
+ if (reset_core(dd))
+ dev_err(dd->dev, "Reset failed\n");
+ }
msm_spi_udelay(dd->xfrs_delay_usec);
transfer_end:
@@ -1578,14 +1583,15 @@ static int reset_core(struct msm_spi *dd)
* bit.
*/
msm_spi_enable_error_flags(dd);
-
- spi_ioc = readl_relaxed(dd->base + SPI_IO_CONTROL);
- spi_ioc |= SPI_IO_C_NO_TRI_STATE;
- writel_relaxed(spi_ioc , dd->base + SPI_IO_CONTROL);
- /*
- * Ensure that the IO control is written to before returning.
- */
- mb();
+ if (!dd->pdata->is_slv_ctrl) {
+ spi_ioc = readl_relaxed(dd->base + SPI_IO_CONTROL);
+ spi_ioc |= SPI_IO_C_NO_TRI_STATE;
+ writel_relaxed(spi_ioc, dd->base + SPI_IO_CONTROL);
+ /*
+ * Ensure that the IO control is written to before returning.
+ */
+ mb();
+ }
msm_spi_set_state(dd, SPI_OP_STATE_RESET);
return 0;
}
@@ -1793,10 +1799,7 @@ static void msm_spi_slv_setup(struct msm_spi *dd)
u32 irq_en = GENMASK(6, 0);
qup_config &= ~QUP_CFG_MODE;
- qup_config |= QUP_CONFIG_SPI_SLAVE;
- qup_config |= (SPI_EN_EXT_OUT_FLAG | APP_CLK_ON_EN | CORE_CLK_ON_EN
- | FIFO_CLK_ON_EN | CORE_EX_CLK_ON_EN);
- spi_config |= SPI_CFG_SLAVE_OP;
+ qup_config |= SPI_EN_EXT_OUT_FLAG;
writel_relaxed(qup_config, dd->base + QUP_CONFIG);
writel_relaxed(spi_config, dd->base + SPI_CONFIG);
writel_relaxed(irq_en, (dd->base + SPI_SLAVE_IRQ_EN));
@@ -1807,6 +1810,28 @@ static void msm_spi_slv_setup(struct msm_spi *dd)
writel_relaxed(slv_cfg, (dd->base + SPI_SLAVE_CONFIG));
}
/*
+ * Ensure the previous write completed before enabling slave mode.
+ */
+ mb();
+
+ spi_config = readl_relaxed(dd->base + SPI_CONFIG);
+ qup_config = readl_relaxed(dd->base + QUP_CONFIG);
+
+ qup_config |= QUP_CONFIG_SPI_SLAVE;
+ spi_config |= SPI_CFG_SLAVE_OP;
+
+ writel_relaxed(qup_config, dd->base + QUP_CONFIG);
+ writel_relaxed(spi_config, dd->base + SPI_CONFIG);
+ /*
+ * Ensure the previous write completed before enabling clk_on bit.
+ */
+ mb();
+
+ qup_config = readl_relaxed(dd->base + QUP_CONFIG);
+ qup_config |= (APP_CLK_ON_EN | CORE_CLK_ON_EN |
+ FIFO_CLK_ON_EN | CORE_EX_CLK_ON_EN);
+ writel_relaxed(qup_config, dd->base + QUP_CONFIG);
+ /*
* Ensure Slave setup completes before returning.
*/
mb();
@@ -2034,6 +2059,33 @@ static ssize_t set_stats(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(stats, S_IRUGO | S_IWUSR, show_stats, set_stats);
+static ssize_t show_qup_state(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+ struct platform_device *pdev = container_of(dev, struct
+ platform_device, dev);
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct msm_spi *dd;
+
+ dd = spi_master_get_devdata(master);
+ /* This check should not fail */
+ if (dd)
+ ret = snprintf(buf, sizeof(int), "%u\n",
+ atomic_read(&dd->qup_state));
+ return ret;
+}
+
+static ssize_t set_qup_state(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return 1;
+}
+
+static DEVICE_ATTR(spi_qup_state, S_IWUSR | S_IRUGO,
+ show_qup_state, set_qup_state);
+
static struct attribute *dev_attrs[] = {
&dev_attr_stats.attr,
NULL,
@@ -2471,7 +2523,9 @@ static int init_resources(struct platform_device *pdev)
*/
msm_spi_enable_error_flags(dd);
- writel_relaxed(SPI_IO_C_NO_TRI_STATE, dd->base + SPI_IO_CONTROL);
+ if (dd->pdata && !dd->pdata->is_slv_ctrl)
+ writel_relaxed(SPI_IO_C_NO_TRI_STATE,
+ dd->base + SPI_IO_CONTROL);
rc = msm_spi_set_state(dd, SPI_OP_STATE_RESET);
if (rc)
goto err_spi_state;
@@ -2609,6 +2663,7 @@ static int msm_spi_probe(struct platform_device *pdev)
dd->mem_size = resource_size(resource);
dd->dev = &pdev->dev;
+ atomic_set(&dd->qup_state, SPI_OP_STATE_RESET);
if (pdata) {
master->rt = pdata->rt_priority;
if (pdata->dma_config) {
@@ -2682,6 +2737,7 @@ skip_dma_resources:
dev_err(&pdev->dev, "failed to create dev. attrs : %d\n", rc);
goto err_attrs;
}
+ rc = sysfs_create_file(&(dd->dev->kobj), &dev_attr_spi_qup_state.attr);
spi_debugfs_init(dd);
return 0;
@@ -2835,6 +2891,7 @@ static int msm_spi_remove(struct platform_device *pdev)
spi_debugfs_exit(dd);
sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
+ sysfs_remove_file(&pdev->dev.kobj, &dev_attr_spi_qup_state.attr);
if (dd->dma_teardown)
dd->dma_teardown(dd);