From 10386109e9541eb5697e8da1a8e66fb7b0160c12 Mon Sep 17 00:00:00 2001 From: Rama Krishna Phani A Date: Tue, 30 Oct 2018 10:02:26 +0530 Subject: [PATCH] spi: spi-msm-geni: Add spi slave mode support to QUPv3 Propagate SPI slave change from 4.14 to 5.4. 'commit db7d4f6203927b ("spi: spi-geni-qcom: Add spi slave mode support to QUPv3")'. Change-Id: I353198be51525572d8916ebbaab66db8e797c245 Signed-off-by: Rama Krishna Phani A Signed-off-by: Ashish Kori --- drivers/spi/spi-msm-geni.c | 111 +++++++++++++++++++++++++++++++++--- include/linux/msm-geni-se.h | 9 ++- 2 files changed, 109 insertions(+), 11 deletions(-) diff --git a/drivers/spi/spi-msm-geni.c b/drivers/spi/spi-msm-geni.c index 1ddd20a4b56f..1a063ee28f27 100644 --- a/drivers/spi/spi-msm-geni.c +++ b/drivers/spi/spi-msm-geni.c @@ -35,6 +35,8 @@ #define SE_SPI_RX_TRANS_LEN (0x270) #define SE_SPI_PRE_POST_CMD_DLY (0x274) #define SE_SPI_DELAY_COUNTERS (0x278) +#define SE_SPI_SLAVE_EN (0x2BC) +#define SPI_SLAVE_EN BIT(0) /* SE_SPI_CPHA register fields */ #define CPHA (BIT(0)) @@ -169,8 +171,59 @@ struct spi_geni_master { u32 miso_sampling_ctrl_val; bool gpi_reset; /* GPI channel reset*/ bool disable_dma; + bool slave_setup; + bool slave_state; }; +static void spi_slv_setup(struct spi_geni_master *mas); + +static ssize_t spi_slave_state_show(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 *spi = platform_get_drvdata(pdev); + struct spi_geni_master *geni_mas; + + geni_mas = spi_master_get_devdata(spi); + + if (geni_mas) + ret = scnprintf(buf, sizeof(int), "%d\n", + geni_mas->slave_state); + return ret; +} + +static ssize_t spi_slave_state_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return 1; +} + +static DEVICE_ATTR_RW(spi_slave_state); + +static void spi_slv_setup(struct spi_geni_master *mas) +{ + geni_write_reg(SPI_SLAVE_EN, mas->base, SE_SPI_SLAVE_EN); + + geni_write_reg(1, mas->base, GENI_OUTPUT_CTRL); + + geni_write_reg(START_TRIGGER, mas->base, SE_GENI_CFG_SEQ_START); + /* ensure data is written to hardware register */ + wmb(); + dev_info(mas->dev, "spi slave setup done\n"); +} + +static int spi_slv_abort(struct spi_master *spi) +{ + struct spi_geni_master *mas = spi_master_get_devdata(spi); + + complete_all(&mas->tx_cb); + complete_all(&mas->rx_cb); + return 0; +} + static struct spi_master *get_spi_master(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -271,8 +324,10 @@ static int setup_fifo_params(struct spi_device *spi_slv, if (mode & SPI_CPOL) cpol |= CPOL; - if (mode & SPI_CPHA) - cpha |= CPHA; + if (!spi->slave) { + if (mode & SPI_CPHA) + cpha |= CPHA; + } if (spi_slv->mode & SPI_CS_HIGH) demux_output_inv |= BIT(spi_slv->chip_select); @@ -1059,10 +1114,28 @@ static int spi_geni_mas_setup(struct spi_master *spi) int hw_ver; int ret = 0; - if (unlikely(proto != SPI)) { - dev_err(mas->dev, "Invalid proto %d\n", proto); - return -ENXIO; + if (spi->slave) { + if (mas->slave_setup) + goto setup_ipc; + proto = get_se_proto(mas->base); + if (unlikely(proto != SPI_SLAVE)) { + dev_err(mas->dev, "Invalid proto %d\n", proto); + return -ENXIO; + } } + + if (unlikely(!mas->setup)) { + proto = get_se_proto(mas->base); + + if ((unlikely(proto != SPI)) && (!spi->slave)) { + dev_err(mas->dev, "Invalid proto %d\n", proto); + return -ENXIO; + } + + if (spi->slave) + spi_slv_setup(mas); + } + geni_se_init(mas->base, 0x0, (mas->tx_fifo_depth - 2)); mas->tx_fifo_depth = get_tx_fifo_depth(mas->base); mas->rx_fifo_depth = get_rx_fifo_depth(mas->base); @@ -1186,6 +1259,7 @@ static int spi_geni_prepare_transfer_hardware(struct spi_master *spi) u32 max_speed = spi->cur_msg->spi->max_speed_hz; struct se_geni_rsc *rsc = &mas->spi_rsc; + /* Adjust the IB based on the max speed of the slave in kHz.*/ rsc->ib = (max_speed * DEFAULT_BUS_WIDTH) / 1000; @@ -1316,7 +1390,9 @@ static int setup_fifo_xfer(struct spi_transfer *xfer, else if (xfer->rx_buf) m_cmd = SPI_RX_ONLY; - spi_tx_cfg &= ~CS_TOGGLE; + if (!spi->slave) + spi_tx_cfg &= ~CS_TOGGLE; + if (!(mas->cur_word_len % MIN_WORD_LEN)) { trans_len = ((xfer->len << 3) / mas->cur_word_len) & TRANS_LEN_MSK; @@ -1356,7 +1432,8 @@ static int setup_fifo_xfer(struct spi_transfer *xfer, mas->cur_xfer_mode = FIFO_MODE; geni_se_select_mode(mas->base, mas->cur_xfer_mode); - geni_write_reg(spi_tx_cfg, mas->base, SE_SPI_TRANS_CFG); + if (!spi->slave) + geni_write_reg(spi_tx_cfg, mas->base, SE_SPI_TRANS_CFG); geni_setup_m_cmd(mas->base, m_cmd, m_param); GENI_SE_DBG(mas->ipc, false, mas->dev, "%s: trans_len %d xferlen%d tx_cfg 0x%x cmd 0x%x cs%d mode%d\n", @@ -1488,8 +1565,13 @@ static int spi_geni_transfer_one(struct spi_master *spi, goto err_fifo_geni_transfer_one; } + if (spi->slave) + mas->slave_state = true; timeout = wait_for_completion_timeout(&mas->xfer_done, msecs_to_jiffies(SPI_XFER_TIMEOUT_MS)); + if (spi->slave) + mas->slave_state = false; + if (!timeout) { GENI_SE_ERR(mas->ipc, true, mas->dev, "Xfer[len %d tx %pK rx %pK n %d] timed out.\n", @@ -1575,7 +1657,8 @@ err_gsi_geni_transfer_one: } return ret; err_fifo_geni_transfer_one: - handle_fifo_timeout(mas, xfer); + if (!spi->slave) + handle_fifo_timeout(mas, xfer); return ret; } @@ -1763,7 +1846,7 @@ static int spi_geni_probe(struct platform_device *pdev) struct resource *res; struct platform_device *wrapper_pdev; struct device_node *wrapper_ph_node; - bool rt_pri; + bool rt_pri, slave_en; spi = spi_alloc_master(&pdev->dev, sizeof(struct spi_geni_master)); if (!spi) { @@ -1952,6 +2035,13 @@ static int spi_geni_probe(struct platform_device *pdev) geni_mas->disable_dma = of_property_read_bool(pdev->dev.of_node, "qcom,disable-dma"); + slave_en = of_property_read_bool(pdev->dev.of_node, + "qcom,slv-ctrl"); + if (slave_en) { + spi->slave = true; + spi->slave_abort = spi_slv_abort; + } + spi->mode_bits = (SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_CS_HIGH); spi->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); @@ -1979,6 +2069,8 @@ static int spi_geni_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to register SPI master\n"); goto spi_geni_probe_unmap; } + ret = sysfs_create_file(&(geni_mas->dev->kobj), + &dev_attr_spi_slave_state.attr); return ret; spi_geni_probe_unmap: devm_iounmap(&pdev->dev, geni_mas->base); @@ -1992,6 +2084,7 @@ static int spi_geni_remove(struct platform_device *pdev) struct spi_master *master = platform_get_drvdata(pdev); struct spi_geni_master *geni_mas = spi_master_get_devdata(master); + sysfs_remove_file(&pdev->dev.kobj, &dev_attr_spi_slave_state.attr); se_geni_resources_off(&geni_mas->spi_rsc); spi_unregister_master(master); pm_runtime_put_noidle(&pdev->dev); diff --git a/include/linux/msm-geni-se.h b/include/linux/msm-geni-se.h index 5b5de47d6d34..a0179a802c63 100644 --- a/include/linux/msm-geni-se.h +++ b/include/linux/msm-geni-se.h @@ -24,7 +24,8 @@ enum se_protocol_types { SPI, UART, I2C, - I3C + I3C, + SPI_SLAVE }; /** @@ -93,6 +94,8 @@ struct se_geni_rsc { #define GENI_FW_REVISION_RO (0x68) #define GENI_FW_S_REVISION_RO (0x6C) #define SE_GENI_CLK_SEL (0x7C) +#define SE_GENI_CFG_SEQ_START (0x84) +#define SE_GENI_CFG_REG (0x200) #define SE_GENI_BYTE_GRAN (0x254) #define SE_GENI_DMA_MODE_EN (0x258) #define SE_GENI_TX_PACKING_CFG0 (0x260) @@ -125,10 +128,12 @@ struct se_geni_rsc { #define SE_HW_PARAM_1 (0xE28) #define SE_DMA_GENERAL_CFG (0xE30) #define SE_DMA_DEBUG_REG0 (0xE40) +#define SLAVE_MODE_EN (BIT(3)) +#define START_TRIGGER (BIT(0)) #define QUPV3_HW_VER (0x4) /* GENI_OUTPUT_CTRL fields */ -#define DEFAULT_IO_OUTPUT_CTRL_MSK (GENMASK(6, 0)) +#define DEFAULT_IO_OUTPUT_CTRL_MSK (GENMASK(6, 0)) /* GENI_FORCE_DEFAULT_REG fields */ #define FORCE_DEFAULT (BIT(0))