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

Merge series "spi: Add support for Realtek RTL838x/RTL839x SoC SPI" from Bert Vermeulen <bert@biot.com>:

v5:
- Changed SoC compatible to list exact models

v4:
- Added SoC series-specific compatible matches.

v3:
- Added cpu_relax() to busy loop.
- Dropped .remove callback from driver struct.
- Use (variations of) realtek-rtl as prefix.
- Dropped Kconfig entry, and use MACH_REALTEK_RTL setting to build the
driver, since there's no point booting without the SPI-connected flash.

v2:
- Rewrote from spi-nor driver to regular spi driver, implementing only
set_cs() and transfer_one(). (Thanks Chuanhong Guo!)

Bert Vermeulen (2):
dt-bindings: spi: Realtek RTL838x/RTL839x SPI controller
spi: realtek-rtl: Add support for Realtek RTL838x/RTL839x SPI
controllers

.../bindings/spi/realtek,rtl-spi.yaml | 41 ++++
drivers/spi/Makefile | 1 +
drivers/spi/spi-realtek-rtl.c | 209 ++++++++++++++++++
3 files changed, 251 insertions(+)
create mode 100644 Documentation/devicetree/bindings/spi/realtek,rtl-spi.yaml
create mode 100644 drivers/spi/spi-realtek-rtl.c

--
2.25.1

+251
+41
Documentation/devicetree/bindings/spi/realtek,rtl-spi.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/spi/realtek,rtl-spi.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Realtek RTL838x/RTL839x SPI controller 8 + 9 + maintainers: 10 + - Bert Vermeulen <bert@biot.com> 11 + - Birger Koblitz <mail@birger-koblitz.de> 12 + 13 + allOf: 14 + - $ref: "spi-controller.yaml#" 15 + 16 + properties: 17 + compatible: 18 + oneOf: 19 + - const: realtek,rtl8380-spi 20 + - const: realtek,rtl8382-spi 21 + - const: realtek,rtl8391-spi 22 + - const: realtek,rtl8392-spi 23 + - const: realtek,rtl8393-spi 24 + 25 + reg: 26 + maxItems: 1 27 + 28 + required: 29 + - compatible 30 + - reg 31 + 32 + unevaluatedProperties: false 33 + 34 + examples: 35 + - | 36 + spi: spi@1200 { 37 + compatible = "realtek,rtl8382-spi"; 38 + reg = <0x1200 0x100>; 39 + #address-cells = <1>; 40 + #size-cells = <0>; 41 + };
+1
drivers/spi/Makefile
··· 93 93 obj-$(CONFIG_SPI_QUP) += spi-qup.o 94 94 obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o 95 95 obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o 96 + obj-$(CONFIG_MACH_REALTEK_RTL) += spi-realtek-rtl.o 96 97 obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o 97 98 obj-$(CONFIG_SPI_RSPI) += spi-rspi.o 98 99 obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
+209
drivers/spi/spi-realtek-rtl.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include <linux/module.h> 4 + #include <linux/platform_device.h> 5 + #include <linux/mod_devicetable.h> 6 + #include <linux/spi/spi.h> 7 + 8 + struct rtspi { 9 + void __iomem *base; 10 + }; 11 + 12 + /* SPI Flash Configuration Register */ 13 + #define RTL_SPI_SFCR 0x00 14 + #define RTL_SPI_SFCR_RBO BIT(28) 15 + #define RTL_SPI_SFCR_WBO BIT(27) 16 + 17 + /* SPI Flash Control and Status Register */ 18 + #define RTL_SPI_SFCSR 0x08 19 + #define RTL_SPI_SFCSR_CSB0 BIT(31) 20 + #define RTL_SPI_SFCSR_CSB1 BIT(30) 21 + #define RTL_SPI_SFCSR_RDY BIT(27) 22 + #define RTL_SPI_SFCSR_CS BIT(24) 23 + #define RTL_SPI_SFCSR_LEN_MASK ~(0x03 << 28) 24 + #define RTL_SPI_SFCSR_LEN1 (0x00 << 28) 25 + #define RTL_SPI_SFCSR_LEN4 (0x03 << 28) 26 + 27 + /* SPI Flash Data Register */ 28 + #define RTL_SPI_SFDR 0x0c 29 + 30 + #define REG(x) (rtspi->base + x) 31 + 32 + 33 + static void rt_set_cs(struct spi_device *spi, bool active) 34 + { 35 + struct rtspi *rtspi = spi_controller_get_devdata(spi->controller); 36 + u32 value; 37 + 38 + /* CS0 bit is active low */ 39 + value = readl(REG(RTL_SPI_SFCSR)); 40 + if (active) 41 + value |= RTL_SPI_SFCSR_CSB0; 42 + else 43 + value &= ~RTL_SPI_SFCSR_CSB0; 44 + writel(value, REG(RTL_SPI_SFCSR)); 45 + } 46 + 47 + static void set_size(struct rtspi *rtspi, int size) 48 + { 49 + u32 value; 50 + 51 + value = readl(REG(RTL_SPI_SFCSR)); 52 + value &= RTL_SPI_SFCSR_LEN_MASK; 53 + if (size == 4) 54 + value |= RTL_SPI_SFCSR_LEN4; 55 + else if (size == 1) 56 + value |= RTL_SPI_SFCSR_LEN1; 57 + writel(value, REG(RTL_SPI_SFCSR)); 58 + } 59 + 60 + static inline void wait_ready(struct rtspi *rtspi) 61 + { 62 + while (!(readl(REG(RTL_SPI_SFCSR)) & RTL_SPI_SFCSR_RDY)) 63 + cpu_relax(); 64 + } 65 + static void send4(struct rtspi *rtspi, const u32 *buf) 66 + { 67 + wait_ready(rtspi); 68 + set_size(rtspi, 4); 69 + writel(*buf, REG(RTL_SPI_SFDR)); 70 + } 71 + 72 + static void send1(struct rtspi *rtspi, const u8 *buf) 73 + { 74 + wait_ready(rtspi); 75 + set_size(rtspi, 1); 76 + writel(buf[0] << 24, REG(RTL_SPI_SFDR)); 77 + } 78 + 79 + static void rcv4(struct rtspi *rtspi, u32 *buf) 80 + { 81 + wait_ready(rtspi); 82 + set_size(rtspi, 4); 83 + *buf = readl(REG(RTL_SPI_SFDR)); 84 + } 85 + 86 + static void rcv1(struct rtspi *rtspi, u8 *buf) 87 + { 88 + wait_ready(rtspi); 89 + set_size(rtspi, 1); 90 + *buf = readl(REG(RTL_SPI_SFDR)) >> 24; 91 + } 92 + 93 + static int transfer_one(struct spi_controller *ctrl, struct spi_device *spi, 94 + struct spi_transfer *xfer) 95 + { 96 + struct rtspi *rtspi = spi_controller_get_devdata(ctrl); 97 + void *rx_buf; 98 + const void *tx_buf; 99 + int cnt; 100 + 101 + tx_buf = xfer->tx_buf; 102 + rx_buf = xfer->rx_buf; 103 + cnt = xfer->len; 104 + if (tx_buf) { 105 + while (cnt >= 4) { 106 + send4(rtspi, tx_buf); 107 + tx_buf += 4; 108 + cnt -= 4; 109 + } 110 + while (cnt) { 111 + send1(rtspi, tx_buf); 112 + tx_buf++; 113 + cnt--; 114 + } 115 + } else if (rx_buf) { 116 + while (cnt >= 4) { 117 + rcv4(rtspi, rx_buf); 118 + rx_buf += 4; 119 + cnt -= 4; 120 + } 121 + while (cnt) { 122 + rcv1(rtspi, rx_buf); 123 + rx_buf++; 124 + cnt--; 125 + } 126 + } 127 + 128 + spi_finalize_current_transfer(ctrl); 129 + 130 + return 0; 131 + } 132 + 133 + static void init_hw(struct rtspi *rtspi) 134 + { 135 + u32 value; 136 + 137 + /* Turn on big-endian byte ordering */ 138 + value = readl(REG(RTL_SPI_SFCR)); 139 + value |= RTL_SPI_SFCR_RBO | RTL_SPI_SFCR_WBO; 140 + writel(value, REG(RTL_SPI_SFCR)); 141 + 142 + value = readl(REG(RTL_SPI_SFCSR)); 143 + /* Permanently disable CS1, since it's never used */ 144 + value |= RTL_SPI_SFCSR_CSB1; 145 + /* Select CS0 for use */ 146 + value &= RTL_SPI_SFCSR_CS; 147 + writel(value, REG(RTL_SPI_SFCSR)); 148 + } 149 + 150 + static int realtek_rtl_spi_probe(struct platform_device *pdev) 151 + { 152 + struct spi_controller *ctrl; 153 + struct rtspi *rtspi; 154 + int err; 155 + 156 + ctrl = devm_spi_alloc_master(&pdev->dev, sizeof(*rtspi)); 157 + if (!ctrl) { 158 + dev_err(&pdev->dev, "Error allocating SPI controller\n"); 159 + return -ENOMEM; 160 + } 161 + platform_set_drvdata(pdev, ctrl); 162 + rtspi = spi_controller_get_devdata(ctrl); 163 + 164 + rtspi->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); 165 + if (IS_ERR(rtspi->base)) { 166 + dev_err(&pdev->dev, "Could not map SPI register address"); 167 + return -ENOMEM; 168 + } 169 + 170 + init_hw(rtspi); 171 + 172 + ctrl->dev.of_node = pdev->dev.of_node; 173 + ctrl->flags = SPI_CONTROLLER_HALF_DUPLEX; 174 + ctrl->set_cs = rt_set_cs; 175 + ctrl->transfer_one = transfer_one; 176 + 177 + err = devm_spi_register_controller(&pdev->dev, ctrl); 178 + if (err) { 179 + dev_err(&pdev->dev, "Could not register SPI controller\n"); 180 + return -ENODEV; 181 + } 182 + 183 + return 0; 184 + } 185 + 186 + 187 + static const struct of_device_id realtek_rtl_spi_of_ids[] = { 188 + { .compatible = "realtek,rtl8380-spi" }, 189 + { .compatible = "realtek,rtl8382-spi" }, 190 + { .compatible = "realtek,rtl8391-spi" }, 191 + { .compatible = "realtek,rtl8392-spi" }, 192 + { .compatible = "realtek,rtl8393-spi" }, 193 + { /* sentinel */ } 194 + }; 195 + MODULE_DEVICE_TABLE(of, realtek_rtl_spi_of_ids); 196 + 197 + static struct platform_driver realtek_rtl_spi_driver = { 198 + .probe = realtek_rtl_spi_probe, 199 + .driver = { 200 + .name = "realtek-rtl-spi", 201 + .of_match_table = realtek_rtl_spi_of_ids, 202 + }, 203 + }; 204 + 205 + module_platform_driver(realtek_rtl_spi_driver); 206 + 207 + MODULE_LICENSE("GPL v2"); 208 + MODULE_AUTHOR("Bert Vermeulen <bert@biot.com>"); 209 + MODULE_DESCRIPTION("Realtek RTL SPI driver");