Loading Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.txt +2 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,8 @@ Optional properties: - spi-cpha: Empty property indicating device requires shifted clock phase (CPHA) mode. - qcom,slv-ctrl : Set this flag to configure QUPV3 as SPI slave controller. Other optional properties described in Documentation/devicetree/bindings/spi/spi-bus.txt Loading arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi +9 −0 Original line number Diff line number Diff line Loading @@ -207,3 +207,12 @@ &qupv3_se7_4uart { status = "ok"; }; &qupv3_se2_i2c { status = "disabled"; }; &qupv3_se2_spi { status = "ok"; qcom,slv-ctrl; }; arch/arm64/boot/dts/qcom/sm6150.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ sdhc2 = &sdhc_2; /* SDC2 SD Card slot */ spi0 = &qupv3_se4_spi; spi2 = &qupv3_se2_spi; i2c0 = &qupv3_se5_i2c; i2c1 = &qupv3_se1_i2c; i2c2 = &qupv3_se3_i2c; Loading drivers/spi/spi-geni-qcom.c +104 −9 Original line number Diff line number Diff line Loading @@ -41,6 +41,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)) Loading Loading @@ -133,6 +135,7 @@ struct spi_geni_master { int tx_fifo_width; int tx_wm; bool setup; bool slave_setup; u32 cur_speed_hz; int cur_word_len; unsigned int tx_rem_bytes; Loading @@ -158,6 +161,35 @@ struct spi_geni_master { bool dis_autosuspend; }; static void spi_slv_setup(struct spi_geni_master *mas); static ssize_t show_slave_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 *spi = platform_get_drvdata(pdev); struct spi_geni_master *geni_mas; geni_mas = spi_master_get_devdata(spi); if (geni_mas) ret = snprintf(buf, sizeof(int), "%d\n", spi->slave_state); return ret; } static ssize_t set_slave_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { return 1; } static DEVICE_ATTR(spi_slave_state, 0644, show_slave_state, set_slave_state); static struct spi_master *get_spi_master(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); Loading @@ -166,6 +198,27 @@ static struct spi_master *get_spi_master(struct device *dev) return spi; } 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 int get_spi_clk_cfg(u32 speed_hz, struct spi_geni_master *mas, int *clk_idx, int *clk_div) { Loading Loading @@ -256,8 +309,10 @@ static int setup_fifo_params(struct spi_device *spi_slv, if (mode & SPI_CPOL) cpol |= CPOL; if (!spi->slave) { if (mode & SPI_CPHA) cpha |= CPHA; } if (spi_slv->mode & SPI_CS_HIGH) demux_output_inv |= BIT(spi_slv->chip_select); Loading Loading @@ -757,7 +812,7 @@ static int spi_geni_unprepare_message(struct spi_master *spi_mas, static int spi_geni_prepare_transfer_hardware(struct spi_master *spi) { struct spi_geni_master *mas = spi_master_get_devdata(spi); int ret = 0, count = 0; int ret = 0, count = 0, proto; u32 max_speed = spi->cur_msg->spi->max_speed_hz; struct se_geni_rsc *rsc = &mas->spi_rsc; Loading Loading @@ -790,18 +845,36 @@ static int spi_geni_prepare_transfer_hardware(struct spi_master *spi) GENI_SE_ERR(mas->ipc, false, NULL, "resume usage count mismatch:%d", count); } if (spi->slave) { proto = get_se_proto(mas->base); if (mas->slave_setup) goto setup_ipc; if (unlikely(proto != SPI_SLAVE)) { dev_err(mas->dev, "Invalid proto %d\n", proto); return -ENXIO; } } if (unlikely(!mas->setup)) { int proto = get_se_proto(mas->base); unsigned int major; unsigned int minor; unsigned int step; int hw_ver; if (unlikely(proto != SPI)) { proto = get_se_proto(mas->base); if ((unlikely(proto != SPI)) && (!spi->slave)) { dev_err(mas->dev, "Invalid proto %d\n", proto); return -ENXIO; } dev_info(mas->dev, "proto %d\n", proto); geni_se_init(mas->base, 0x0, (mas->tx_fifo_depth - 2)); mb(); /*ensure all writes are done*/ if (spi->slave) spi_slv_setup(mas); mas->tx_fifo_depth = get_tx_fifo_depth(mas->base); mas->rx_fifo_depth = get_rx_fifo_depth(mas->base); mas->tx_fifo_width = get_tx_fifo_width(mas->base); Loading Loading @@ -863,6 +936,8 @@ static int spi_geni_prepare_transfer_hardware(struct spi_master *spi) mas->tx_fifo_depth, mas->rx_fifo_depth, mas->tx_fifo_width); mas->setup = true; if (spi->slave) mas->slave_setup = true; hw_ver = geni_se_qupv3_hw_version(mas->wrapper_dev, &major, &minor, &step); if (hw_ver) Loading Loading @@ -959,6 +1034,7 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, else if (xfer->rx_buf) m_cmd = SPI_RX_ONLY; if (!spi->slave) spi_tx_cfg &= ~CS_TOGGLE; if (!(mas->cur_word_len % MIN_WORD_LEN)) { trans_len = Loading Loading @@ -1000,6 +1076,7 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, } } 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, Loading Loading @@ -1086,8 +1163,13 @@ static int spi_geni_transfer_one(struct spi_master *spi, if (mas->cur_xfer_mode != GSI_DMA) { reinit_completion(&mas->xfer_done); setup_fifo_xfer(xfer, mas, slv->mode, spi); if (spi->slave) spi->slave_state = true; timeout = wait_for_completion_timeout(&mas->xfer_done, msecs_to_jiffies(SPI_XFER_TIMEOUT_MS)); if (spi->slave) spi->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", Loading Loading @@ -1157,7 +1239,10 @@ static int spi_geni_transfer_one(struct spi_master *spi, dmaengine_terminate_all(mas->tx); return ret; err_fifo_geni_transfer_one: if (!spi->slave) handle_fifo_timeout(mas, xfer); if (spi->slave) geni_se_dump_dbg_regs(&mas->spi_rsc, mas->base, mas->ipc); return ret; } Loading Loading @@ -1341,7 +1426,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) { Loading Loading @@ -1482,6 +1567,13 @@ static int spi_geni_probe(struct platform_device *pdev) goto spi_geni_probe_unmap; } 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); spi->num_chipselect = SPI_NUM_CHIPSELECT; Loading @@ -1508,6 +1600,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; } 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); Loading @@ -1521,6 +1615,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); spi_unregister_master(master); se_geni_resources_off(&geni_mas->spi_rsc); pm_runtime_put_noidle(&pdev->dev); Loading include/linux/qcom-geni-se.h +6 −1 Original line number Diff line number Diff line Loading @@ -35,7 +35,8 @@ enum se_protocol_types { SPI, UART, I2C, I3C I3C, SPI_SLAVE }; /** Loading Loading @@ -86,6 +87,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) Loading Loading @@ -118,6 +121,8 @@ 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)) /* GENI_OUTPUT_CTRL fields */ #define DEFAULT_IO_OUTPUT_CTRL_MSK (GENMASK(6, 0)) Loading Loading
Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.txt +2 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,8 @@ Optional properties: - spi-cpha: Empty property indicating device requires shifted clock phase (CPHA) mode. - qcom,slv-ctrl : Set this flag to configure QUPV3 as SPI slave controller. Other optional properties described in Documentation/devicetree/bindings/spi/spi-bus.txt Loading
arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi +9 −0 Original line number Diff line number Diff line Loading @@ -207,3 +207,12 @@ &qupv3_se7_4uart { status = "ok"; }; &qupv3_se2_i2c { status = "disabled"; }; &qupv3_se2_spi { status = "ok"; qcom,slv-ctrl; };
arch/arm64/boot/dts/qcom/sm6150.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ sdhc2 = &sdhc_2; /* SDC2 SD Card slot */ spi0 = &qupv3_se4_spi; spi2 = &qupv3_se2_spi; i2c0 = &qupv3_se5_i2c; i2c1 = &qupv3_se1_i2c; i2c2 = &qupv3_se3_i2c; Loading
drivers/spi/spi-geni-qcom.c +104 −9 Original line number Diff line number Diff line Loading @@ -41,6 +41,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)) Loading Loading @@ -133,6 +135,7 @@ struct spi_geni_master { int tx_fifo_width; int tx_wm; bool setup; bool slave_setup; u32 cur_speed_hz; int cur_word_len; unsigned int tx_rem_bytes; Loading @@ -158,6 +161,35 @@ struct spi_geni_master { bool dis_autosuspend; }; static void spi_slv_setup(struct spi_geni_master *mas); static ssize_t show_slave_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 *spi = platform_get_drvdata(pdev); struct spi_geni_master *geni_mas; geni_mas = spi_master_get_devdata(spi); if (geni_mas) ret = snprintf(buf, sizeof(int), "%d\n", spi->slave_state); return ret; } static ssize_t set_slave_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { return 1; } static DEVICE_ATTR(spi_slave_state, 0644, show_slave_state, set_slave_state); static struct spi_master *get_spi_master(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); Loading @@ -166,6 +198,27 @@ static struct spi_master *get_spi_master(struct device *dev) return spi; } 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 int get_spi_clk_cfg(u32 speed_hz, struct spi_geni_master *mas, int *clk_idx, int *clk_div) { Loading Loading @@ -256,8 +309,10 @@ static int setup_fifo_params(struct spi_device *spi_slv, if (mode & SPI_CPOL) cpol |= CPOL; if (!spi->slave) { if (mode & SPI_CPHA) cpha |= CPHA; } if (spi_slv->mode & SPI_CS_HIGH) demux_output_inv |= BIT(spi_slv->chip_select); Loading Loading @@ -757,7 +812,7 @@ static int spi_geni_unprepare_message(struct spi_master *spi_mas, static int spi_geni_prepare_transfer_hardware(struct spi_master *spi) { struct spi_geni_master *mas = spi_master_get_devdata(spi); int ret = 0, count = 0; int ret = 0, count = 0, proto; u32 max_speed = spi->cur_msg->spi->max_speed_hz; struct se_geni_rsc *rsc = &mas->spi_rsc; Loading Loading @@ -790,18 +845,36 @@ static int spi_geni_prepare_transfer_hardware(struct spi_master *spi) GENI_SE_ERR(mas->ipc, false, NULL, "resume usage count mismatch:%d", count); } if (spi->slave) { proto = get_se_proto(mas->base); if (mas->slave_setup) goto setup_ipc; if (unlikely(proto != SPI_SLAVE)) { dev_err(mas->dev, "Invalid proto %d\n", proto); return -ENXIO; } } if (unlikely(!mas->setup)) { int proto = get_se_proto(mas->base); unsigned int major; unsigned int minor; unsigned int step; int hw_ver; if (unlikely(proto != SPI)) { proto = get_se_proto(mas->base); if ((unlikely(proto != SPI)) && (!spi->slave)) { dev_err(mas->dev, "Invalid proto %d\n", proto); return -ENXIO; } dev_info(mas->dev, "proto %d\n", proto); geni_se_init(mas->base, 0x0, (mas->tx_fifo_depth - 2)); mb(); /*ensure all writes are done*/ if (spi->slave) spi_slv_setup(mas); mas->tx_fifo_depth = get_tx_fifo_depth(mas->base); mas->rx_fifo_depth = get_rx_fifo_depth(mas->base); mas->tx_fifo_width = get_tx_fifo_width(mas->base); Loading Loading @@ -863,6 +936,8 @@ static int spi_geni_prepare_transfer_hardware(struct spi_master *spi) mas->tx_fifo_depth, mas->rx_fifo_depth, mas->tx_fifo_width); mas->setup = true; if (spi->slave) mas->slave_setup = true; hw_ver = geni_se_qupv3_hw_version(mas->wrapper_dev, &major, &minor, &step); if (hw_ver) Loading Loading @@ -959,6 +1034,7 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, else if (xfer->rx_buf) m_cmd = SPI_RX_ONLY; if (!spi->slave) spi_tx_cfg &= ~CS_TOGGLE; if (!(mas->cur_word_len % MIN_WORD_LEN)) { trans_len = Loading Loading @@ -1000,6 +1076,7 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, } } 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, Loading Loading @@ -1086,8 +1163,13 @@ static int spi_geni_transfer_one(struct spi_master *spi, if (mas->cur_xfer_mode != GSI_DMA) { reinit_completion(&mas->xfer_done); setup_fifo_xfer(xfer, mas, slv->mode, spi); if (spi->slave) spi->slave_state = true; timeout = wait_for_completion_timeout(&mas->xfer_done, msecs_to_jiffies(SPI_XFER_TIMEOUT_MS)); if (spi->slave) spi->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", Loading Loading @@ -1157,7 +1239,10 @@ static int spi_geni_transfer_one(struct spi_master *spi, dmaengine_terminate_all(mas->tx); return ret; err_fifo_geni_transfer_one: if (!spi->slave) handle_fifo_timeout(mas, xfer); if (spi->slave) geni_se_dump_dbg_regs(&mas->spi_rsc, mas->base, mas->ipc); return ret; } Loading Loading @@ -1341,7 +1426,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) { Loading Loading @@ -1482,6 +1567,13 @@ static int spi_geni_probe(struct platform_device *pdev) goto spi_geni_probe_unmap; } 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); spi->num_chipselect = SPI_NUM_CHIPSELECT; Loading @@ -1508,6 +1600,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; } 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); Loading @@ -1521,6 +1615,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); spi_unregister_master(master); se_geni_resources_off(&geni_mas->spi_rsc); pm_runtime_put_noidle(&pdev->dev); Loading
include/linux/qcom-geni-se.h +6 −1 Original line number Diff line number Diff line Loading @@ -35,7 +35,8 @@ enum se_protocol_types { SPI, UART, I2C, I3C I3C, SPI_SLAVE }; /** Loading Loading @@ -86,6 +87,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) Loading Loading @@ -118,6 +121,8 @@ 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)) /* GENI_OUTPUT_CTRL fields */ #define DEFAULT_IO_OUTPUT_CTRL_MSK (GENMASK(6, 0)) Loading