Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

spi-geni-qcom: Add SPI device mode support for GENI

Merge series from Praveen Talari <quic_ptalari@quicinc.com>:

This series adds spi device mode functionality to geni based Qupv3.
The common header file contains spi slave related registers and masks.

Praveen Talari (2):
soc: qcom: geni-se: Add SPI Device mode support for GENI based QuPv3
spi: spi-geni-qcom: Add SPI Device mode support for GENI based QuPv3
---
v6 -> v7:
- Corrected author mail

v5 -> v6:
- Added code comments
- Dropped get_spi_master api

v4 -> v5:
- Addressed review comments in driver

v3 -> v4:
- Used existing property spi-slave
- Hence dropped dt-binding changes

v2 -> v3:
- Modified commit message
- Addressed comment on dt-binding

v1 -> v2:
- Added dt-binding change for spi slave
- Modified commit message
- Addressed review comments in driver

drivers/spi/spi-geni-qcom.c | 53 ++++++++++++++++++++++++++++----
include/linux/soc/qcom/geni-se.h | 9 ++++++
2 files changed, 56 insertions(+), 6 deletions(-)

--
2.17.1

+56 -6
+47 -6
drivers/spi/spi-geni-qcom.c
··· 12 12 #include <linux/platform_device.h> 13 13 #include <linux/pm_opp.h> 14 14 #include <linux/pm_runtime.h> 15 + #include <linux/property.h> 15 16 #include <linux/soc/qcom/geni-se.h> 16 17 #include <linux/spi/spi.h> 17 18 #include <linux/spinlock.h> ··· 52 51 #define SPI_INTER_WORDS_DELAY_MSK GENMASK(9, 0) 53 52 #define SPI_CS_CLK_DELAY_MSK GENMASK(19, 10) 54 53 #define SPI_CS_CLK_DELAY_SHFT 10 54 + 55 + #define SE_SPI_SLAVE_EN (0x2BC) 56 + #define SPI_SLAVE_EN BIT(0) 55 57 56 58 /* M_CMD OP codes for SPI */ 57 59 #define SPI_TX_ONLY 1 ··· 103 99 int cur_xfer_mode; 104 100 }; 105 101 102 + static void spi_slv_setup(struct spi_geni_master *mas) 103 + { 104 + struct geni_se *se = &mas->se; 105 + 106 + writel(SPI_SLAVE_EN, se->base + SE_SPI_SLAVE_EN); 107 + writel(GENI_IO_MUX_0_EN, se->base + GENI_OUTPUT_CTRL); 108 + writel(START_TRIGGER, se->base + SE_GENI_CFG_SEQ_START); 109 + dev_dbg(mas->dev, "spi slave setup done\n"); 110 + } 111 + 106 112 static int get_spi_clk_cfg(unsigned int speed_hz, 107 113 struct spi_geni_master *mas, 108 114 unsigned int *clk_idx, ··· 154 140 const struct spi_transfer *xfer; 155 141 156 142 spin_lock_irq(&mas->lock); 157 - reinit_completion(&mas->cancel_done); 158 143 if (mas->cur_xfer_mode == GENI_SE_FIFO) 159 144 writel(0, se->base + SE_GENI_TX_WATERMARK_REG); 160 145 161 146 xfer = mas->cur_xfer; 162 147 mas->cur_xfer = NULL; 148 + 149 + if (spi->slave) { 150 + /* 151 + * skip CMD Cancel sequnece since spi slave 152 + * doesn`t support CMD Cancel sequnece 153 + */ 154 + spin_unlock_irq(&mas->lock); 155 + goto unmap_if_dma; 156 + } 157 + 158 + reinit_completion(&mas->cancel_done); 163 159 geni_se_cancel_m_cmd(se); 164 160 spin_unlock_irq(&mas->lock); 165 161 ··· 566 542 if (mas->cur_xfer_mode == GENI_GPI_DMA) 567 543 return true; 568 544 545 + /* Set SE DMA mode for SPI slave. */ 546 + if (ctlr->slave) 547 + return true; 548 + 569 549 len = get_xfer_len_in_words(xfer, mas); 570 550 fifo_size = mas->tx_fifo_depth * mas->fifo_width_bits / mas->cur_bits_per_word; 571 551 ··· 647 619 648 620 static int spi_geni_init(struct spi_geni_master *mas) 649 621 { 622 + struct spi_master *spi = dev_get_drvdata(mas->dev); 650 623 struct geni_se *se = &mas->se; 651 624 unsigned int proto, major, minor, ver; 652 625 u32 spi_tx_cfg, fifo_disable; ··· 656 627 pm_runtime_get_sync(mas->dev); 657 628 658 629 proto = geni_se_read_proto(se); 659 - if (proto != GENI_SE_SPI) { 630 + 631 + if (spi->slave) { 632 + if (proto != GENI_SE_SPI_SLAVE) { 633 + dev_err(mas->dev, "Invalid proto %d\n", proto); 634 + goto out_pm; 635 + } 636 + spi_slv_setup(mas); 637 + } else if (proto != GENI_SE_SPI) { 660 638 dev_err(mas->dev, "Invalid proto %d\n", proto); 661 639 goto out_pm; 662 640 } ··· 715 679 } 716 680 717 681 /* We always control CS manually */ 718 - spi_tx_cfg = readl(se->base + SE_SPI_TRANS_CFG); 719 - spi_tx_cfg &= ~CS_TOGGLE; 720 - writel(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG); 682 + if (!spi->slave) { 683 + spi_tx_cfg = readl(se->base + SE_SPI_TRANS_CFG); 684 + spi_tx_cfg &= ~CS_TOGGLE; 685 + writel(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG); 686 + } 721 687 722 688 out_pm: 723 689 pm_runtime_put(mas->dev); ··· 1112 1074 pm_runtime_set_autosuspend_delay(&pdev->dev, 250); 1113 1075 pm_runtime_enable(dev); 1114 1076 1077 + if (device_property_read_bool(&pdev->dev, "spi-slave")) 1078 + spi->slave = true; 1079 + 1115 1080 ret = geni_icc_get(&mas->se, NULL); 1116 1081 if (ret) 1117 1082 goto spi_geni_probe_runtime_disable; ··· 1135 1094 * for dma (gsi) mode, the gsi will set cs based on params passed in 1136 1095 * TRE 1137 1096 */ 1138 - if (mas->cur_xfer_mode == GENI_SE_FIFO) 1097 + if (!spi->slave && mas->cur_xfer_mode == GENI_SE_FIFO) 1139 1098 spi->set_cs = spi_geni_set_cs; 1140 1099 1141 1100 /*
+9
include/linux/soc/qcom/geni-se.h
··· 35 35 GENI_SE_UART, 36 36 GENI_SE_I2C, 37 37 GENI_SE_I3C, 38 + GENI_SE_SPI_SLAVE, 38 39 }; 39 40 40 41 struct geni_wrapper; ··· 74 73 75 74 /* Common SE registers */ 76 75 #define GENI_FORCE_DEFAULT_REG 0x20 76 + #define GENI_OUTPUT_CTRL 0x24 77 77 #define SE_GENI_STATUS 0x40 78 78 #define GENI_SER_M_CLK_CFG 0x48 79 79 #define GENI_SER_S_CLK_CFG 0x4c 80 80 #define GENI_IF_DISABLE_RO 0x64 81 81 #define GENI_FW_REVISION_RO 0x68 82 82 #define SE_GENI_CLK_SEL 0x7c 83 + #define SE_GENI_CFG_SEQ_START 0x84 83 84 #define SE_GENI_DMA_MODE_EN 0x258 84 85 #define SE_GENI_M_CMD0 0x600 85 86 #define SE_GENI_M_CMD_CTRL_REG 0x604 ··· 114 111 /* GENI_FORCE_DEFAULT_REG fields */ 115 112 #define FORCE_DEFAULT BIT(0) 116 113 114 + /* GENI_OUTPUT_CTRL fields */ 115 + #define GENI_IO_MUX_0_EN BIT(0) 116 + 117 117 /* GENI_STATUS fields */ 118 118 #define M_GENI_CMD_ACTIVE BIT(0) 119 119 #define S_GENI_CMD_ACTIVE BIT(12) ··· 135 129 136 130 /* GENI_CLK_SEL fields */ 137 131 #define CLK_SEL_MSK GENMASK(2, 0) 132 + 133 + /* SE_GENI_CFG_SEQ_START fields */ 134 + #define START_TRIGGER BIT(0) 138 135 139 136 /* SE_GENI_DMA_MODE_EN */ 140 137 #define GENI_DMA_MODE_EN BIT(0)