diff options
Diffstat (limited to 'drivers/spi/spi_qsd.c')
| -rw-r--r-- | drivers/spi/spi_qsd.c | 87 |
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); |
