1 // SPDX-License-Identifier: (GPL-2.0) 2 // 3 // Microchip CoreSPI controller driver 4 // 5 // Copyright (c) 2025 Microchip Technology Inc. and its subsidiaries 6 // 7 // Author: Prajna Rajendra Kumar <prajna.rajendrakumar@microchip.com> 8 9 #include <linux/clk.h> 10 #include <linux/delay.h> 11 #include <linux/err.h> 12 #include <linux/init.h> 13 #include <linux/interrupt.h> 14 #include <linux/io.h> 15 #include <linux/module.h> 16 #include <linux/of.h> 17 #include <linux/platform_device.h> 18 #include <linux/spi/spi.h> 19 20 #define MCHP_CORESPI_MAX_CS (8) 21 #define MCHP_CORESPI_DEFAULT_FIFO_DEPTH (4) 22 #define MCHP_CORESPI_DEFAULT_MOTOROLA_MODE (3) 23 24 #define MCHP_CORESPI_CONTROL_ENABLE BIT(0) 25 #define MCHP_CORESPI_CONTROL_MASTER BIT(1) 26 #define MCHP_CORESPI_CONTROL_TX_DATA_INT BIT(3) 27 #define MCHP_CORESPI_CONTROL_RX_OVER_INT BIT(4) 28 #define MCHP_CORESPI_CONTROL_TX_UNDER_INT BIT(5) 29 #define MCHP_CORESPI_CONTROL_FRAMEURUN BIT(6) 30 #define MCHP_CORESPI_CONTROL_OENOFF BIT(7) 31 32 #define MCHP_CORESPI_STATUS_ACTIVE BIT(7) 33 #define MCHP_CORESPI_STATUS_SSEL BIT(6) 34 #define MCHP_CORESPI_STATUS_TXFIFO_UNDERFLOW BIT(5) 35 #define MCHP_CORESPI_STATUS_RXFIFO_FULL BIT(4) 36 #define MCHP_CORESPI_STATUS_TXFIFO_FULL BIT(3) 37 #define MCHP_CORESPI_STATUS_RXFIFO_EMPTY BIT(2) 38 #define MCHP_CORESPI_STATUS_DONE BIT(1) 39 #define MCHP_CORESPI_STATUS_FIRSTFRAME BIT(0) 40 41 #define MCHP_CORESPI_INT_TXDONE BIT(0) 42 #define MCHP_CORESPI_INT_RX_CHANNEL_OVERFLOW BIT(2) 43 #define MCHP_CORESPI_INT_TX_CHANNEL_UNDERRUN BIT(3) 44 #define MCHP_CORESPI_INT_CMDINT BIT(4) 45 #define MCHP_CORESPI_INT_SSEND BIT(5) 46 #define MCHP_CORESPI_INT_DATA_RX BIT(6) 47 #define MCHP_CORESPI_INT_TXRFM BIT(7) 48 49 #define MCHP_CORESPI_CONTROL2_INTEN_TXRFMT BIT(7) 50 #define MCHP_CORESPI_CONTROL2_INTEN_DATA_RX BIT(6) 51 #define MCHP_CORESPI_CONTROL2_INTEN_SSEND BIT(5) 52 #define MCHP_CORESPI_CONTROL2_INTEN_CMD BIT(4) 53 54 #define INT_ENABLE_MASK (MCHP_CORESPI_CONTROL_TX_DATA_INT | MCHP_CORESPI_CONTROL_RX_OVER_INT | \ 55 MCHP_CORESPI_CONTROL_TX_UNDER_INT) 56 57 #define MCHP_CORESPI_REG_CONTROL (0x00) 58 #define MCHP_CORESPI_REG_INTCLEAR (0x04) 59 #define MCHP_CORESPI_REG_RXDATA (0x08) 60 #define MCHP_CORESPI_REG_TXDATA (0x0c) 61 #define MCHP_CORESPI_REG_INTMASK (0X10) 62 #define MCHP_CORESPI_REG_INTRAW (0X14) 63 #define MCHP_CORESPI_REG_CONTROL2 (0x18) 64 #define MCHP_CORESPI_REG_COMMAND (0x1c) 65 #define MCHP_CORESPI_REG_STAT (0x20) 66 #define MCHP_CORESPI_REG_SSEL (0x24) 67 #define MCHP_CORESPI_REG_TXDATA_LAST (0X28) 68 #define MCHP_CORESPI_REG_CLK_DIV (0x2c) 69 70 struct mchp_corespi { 71 void __iomem *regs; 72 struct clk *clk; 73 const u8 *tx_buf; 74 u8 *rx_buf; 75 u32 clk_gen; 76 int irq; 77 unsigned int tx_len; 78 unsigned int rx_len; 79 u32 fifo_depth; 80 }; 81 82 static inline void mchp_corespi_disable(struct mchp_corespi *spi) 83 { 84 u8 control = readb(spi->regs + MCHP_CORESPI_REG_CONTROL); 85 86 control &= ~MCHP_CORESPI_CONTROL_ENABLE; 87 88 writeb(control, spi->regs + MCHP_CORESPI_REG_CONTROL); 89 } 90 91 static inline void mchp_corespi_read_fifo(struct mchp_corespi *spi, u32 fifo_max) 92 { 93 for (int i = 0; i < fifo_max; i++) { 94 u32 data; 95 96 while (readb(spi->regs + MCHP_CORESPI_REG_STAT) & 97 MCHP_CORESPI_STATUS_RXFIFO_EMPTY) 98 ; 99 100 /* On TX-only transfers always perform a dummy read */ 101 data = readb(spi->regs + MCHP_CORESPI_REG_RXDATA); 102 if (spi->rx_buf) 103 *spi->rx_buf++ = data; 104 105 spi->rx_len--; 106 } 107 } 108 109 static void mchp_corespi_enable_ints(struct mchp_corespi *spi) 110 { 111 u8 control = readb(spi->regs + MCHP_CORESPI_REG_CONTROL); 112 113 control |= INT_ENABLE_MASK; 114 writeb(control, spi->regs + MCHP_CORESPI_REG_CONTROL); 115 } 116 117 static void mchp_corespi_disable_ints(struct mchp_corespi *spi) 118 { 119 u8 control = readb(spi->regs + MCHP_CORESPI_REG_CONTROL); 120 121 control &= ~INT_ENABLE_MASK; 122 writeb(control, spi->regs + MCHP_CORESPI_REG_CONTROL); 123 } 124 125 static inline void mchp_corespi_write_fifo(struct mchp_corespi *spi, u32 fifo_max) 126 { 127 for (int i = 0; i < fifo_max; i++) { 128 if (readb(spi->regs + MCHP_CORESPI_REG_STAT) & 129 MCHP_CORESPI_STATUS_TXFIFO_FULL) 130 break; 131 132 /* On RX-only transfers always perform a dummy write */ 133 if (spi->tx_buf) 134 writeb(*spi->tx_buf++, spi->regs + MCHP_CORESPI_REG_TXDATA); 135 else 136 writeb(0xaa, spi->regs + MCHP_CORESPI_REG_TXDATA); 137 138 spi->tx_len--; 139 } 140 } 141 142 static void mchp_corespi_set_cs(struct spi_device *spi, bool disable) 143 { 144 struct mchp_corespi *corespi = spi_controller_get_devdata(spi->controller); 145 u32 reg; 146 147 reg = readb(corespi->regs + MCHP_CORESPI_REG_SSEL); 148 reg &= ~BIT(spi_get_chipselect(spi, 0)); 149 reg |= !disable << spi_get_chipselect(spi, 0); 150 151 writeb(reg, corespi->regs + MCHP_CORESPI_REG_SSEL); 152 } 153 154 static int mchp_corespi_setup(struct spi_device *spi) 155 { 156 if (spi_get_csgpiod(spi, 0)) 157 return 0; 158 159 if (spi->mode & (SPI_CS_HIGH)) { 160 dev_err(&spi->dev, "unable to support active-high CS in Motorola mode\n"); 161 return -EOPNOTSUPP; 162 } 163 164 if (spi->mode & SPI_MODE_X_MASK & ~spi->controller->mode_bits) { 165 dev_err(&spi->dev, "incompatible CPOL/CPHA, must match controller's Motorola mode\n"); 166 return -EINVAL; 167 } 168 169 return 0; 170 } 171 172 static void mchp_corespi_init(struct spi_controller *host, struct mchp_corespi *spi) 173 { 174 u8 control = readb(spi->regs + MCHP_CORESPI_REG_CONTROL); 175 176 /* Master mode changes require core to be disabled.*/ 177 control = (control & ~MCHP_CORESPI_CONTROL_ENABLE) | MCHP_CORESPI_CONTROL_MASTER; 178 179 writeb(control, spi->regs + MCHP_CORESPI_REG_CONTROL); 180 181 mchp_corespi_enable_ints(spi); 182 183 control = readb(spi->regs + MCHP_CORESPI_REG_CONTROL); 184 control |= MCHP_CORESPI_CONTROL_ENABLE; 185 186 writeb(control, spi->regs + MCHP_CORESPI_REG_CONTROL); 187 } 188 189 static irqreturn_t mchp_corespi_interrupt(int irq, void *dev_id) 190 { 191 struct spi_controller *host = dev_id; 192 struct mchp_corespi *spi = spi_controller_get_devdata(host); 193 u8 intfield = readb(spi->regs + MCHP_CORESPI_REG_INTMASK) & 0xff; 194 bool finalise = false; 195 196 /* Interrupt line may be shared and not for us at all */ 197 if (intfield == 0) 198 return IRQ_NONE; 199 200 if (intfield & MCHP_CORESPI_INT_TXDONE) 201 writeb(MCHP_CORESPI_INT_TXDONE, spi->regs + MCHP_CORESPI_REG_INTCLEAR); 202 203 if (intfield & MCHP_CORESPI_INT_RX_CHANNEL_OVERFLOW) { 204 writeb(MCHP_CORESPI_INT_RX_CHANNEL_OVERFLOW, 205 spi->regs + MCHP_CORESPI_REG_INTCLEAR); 206 finalise = true; 207 dev_err(&host->dev, 208 "RX OVERFLOW: rxlen: %u, txlen: %u\n", 209 spi->rx_len, spi->tx_len); 210 } 211 212 if (intfield & MCHP_CORESPI_INT_TX_CHANNEL_UNDERRUN) { 213 writeb(MCHP_CORESPI_INT_TX_CHANNEL_UNDERRUN, 214 spi->regs + MCHP_CORESPI_REG_INTCLEAR); 215 finalise = true; 216 dev_err(&host->dev, 217 "TX UNDERFLOW: rxlen: %u, txlen: %u\n", 218 spi->rx_len, spi->tx_len); 219 } 220 221 if (finalise) 222 spi_finalize_current_transfer(host); 223 224 return IRQ_HANDLED; 225 } 226 227 static int mchp_corespi_set_clk_div(struct mchp_corespi *spi, 228 unsigned long target_hz) 229 { 230 unsigned long pclk_hz, spi_hz; 231 u32 clk_div; 232 233 /* Get peripheral clock rate */ 234 pclk_hz = clk_get_rate(spi->clk); 235 if (!pclk_hz) 236 return -EINVAL; 237 238 /* 239 * Calculate clock rate generated by SPI master 240 * Formula: SPICLK = PCLK / (2 * (CLK_DIV + 1)) 241 */ 242 clk_div = DIV_ROUND_UP(pclk_hz, 2 * target_hz) - 1; 243 244 if (clk_div > 0xFF) 245 return -EINVAL; 246 247 spi_hz = pclk_hz / (2 * (clk_div + 1)); 248 249 if (spi_hz > target_hz) 250 return -EINVAL; 251 252 writeb(clk_div, spi->regs + MCHP_CORESPI_REG_CLK_DIV); 253 254 return 0; 255 } 256 257 static int mchp_corespi_transfer_one(struct spi_controller *host, 258 struct spi_device *spi_dev, 259 struct spi_transfer *xfer) 260 { 261 struct mchp_corespi *spi = spi_controller_get_devdata(host); 262 int ret; 263 264 ret = mchp_corespi_set_clk_div(spi, (unsigned long)xfer->speed_hz); 265 if (ret) { 266 dev_err(&host->dev, "failed to set clock divider for target %u Hz\n", 267 xfer->speed_hz); 268 return ret; 269 } 270 271 spi->tx_buf = xfer->tx_buf; 272 spi->rx_buf = xfer->rx_buf; 273 spi->tx_len = xfer->len; 274 spi->rx_len = xfer->len; 275 276 while (spi->tx_len) { 277 unsigned int fifo_max = min(spi->tx_len, spi->fifo_depth); 278 279 mchp_corespi_write_fifo(spi, fifo_max); 280 mchp_corespi_read_fifo(spi, fifo_max); 281 } 282 283 spi_finalize_current_transfer(host); 284 return 1; 285 } 286 287 static int mchp_corespi_probe(struct platform_device *pdev) 288 { 289 const char *protocol = "motorola"; 290 struct device *dev = &pdev->dev; 291 struct spi_controller *host; 292 struct mchp_corespi *spi; 293 struct resource *res; 294 u32 num_cs, mode, frame_size; 295 bool assert_ssel; 296 int ret = 0; 297 298 host = devm_spi_alloc_host(dev, sizeof(*spi)); 299 if (!host) 300 return -ENOMEM; 301 302 platform_set_drvdata(pdev, host); 303 304 if (of_property_read_u32(dev->of_node, "num-cs", &num_cs)) 305 num_cs = MCHP_CORESPI_MAX_CS; 306 307 /* 308 * Protocol: CFG_MODE 309 * CoreSPI can be configured for Motorola, TI or NSC. 310 * The current driver supports only Motorola mode. 311 */ 312 ret = of_property_read_string(dev->of_node, "microchip,protocol-configuration", 313 &protocol); 314 if (ret && ret != -EINVAL) 315 return dev_err_probe(dev, ret, "Error reading protocol-configuration\n"); 316 if (strcmp(protocol, "motorola") != 0) 317 return dev_err_probe(dev, -EINVAL, 318 "CoreSPI: protocol '%s' not supported by this driver\n", 319 protocol); 320 321 /* 322 * Motorola mode (0-3): CFG_MOT_MODE 323 * Mode is fixed in the IP configurator. 324 */ 325 ret = of_property_read_u32(dev->of_node, "microchip,motorola-mode", &mode); 326 if (ret) 327 mode = MCHP_CORESPI_DEFAULT_MOTOROLA_MODE; 328 else if (mode > 3) 329 return dev_err_probe(dev, -EINVAL, 330 "invalid 'microchip,motorola-mode' value %u\n", mode); 331 332 /* 333 * Frame size: CFG_FRAME_SIZE 334 * The hardware allows frame sizes <= APB data width. 335 * However, this driver currently only supports 8-bit frames. 336 */ 337 ret = of_property_read_u32(dev->of_node, "microchip,frame-size", &frame_size); 338 if (!ret && frame_size != 8) 339 return dev_err_probe(dev, -EINVAL, 340 "CoreSPI: frame size %u not supported by this driver\n", 341 frame_size); 342 343 /* 344 * SSEL: CFG_MOT_SSEL 345 * CoreSPI deasserts SSEL when the TX FIFO empties. 346 * To prevent CS deassertion when TX FIFO drains, the ssel-active property 347 * keeps CS asserted for the full SPI transfer. 348 */ 349 assert_ssel = of_property_read_bool(dev->of_node, "microchip,ssel-active"); 350 if (!assert_ssel) 351 return dev_err_probe(dev, -EINVAL, 352 "hardware must enable 'microchip,ssel-active' to keep CS asserted for the SPI transfer\n"); 353 354 spi = spi_controller_get_devdata(host); 355 356 host->num_chipselect = num_cs; 357 host->mode_bits = mode; 358 host->setup = mchp_corespi_setup; 359 host->use_gpio_descriptors = true; 360 host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); 361 host->transfer_one = mchp_corespi_transfer_one; 362 host->set_cs = mchp_corespi_set_cs; 363 host->dev.of_node = dev->of_node; 364 365 ret = of_property_read_u32(dev->of_node, "fifo-depth", &spi->fifo_depth); 366 if (ret) 367 spi->fifo_depth = MCHP_CORESPI_DEFAULT_FIFO_DEPTH; 368 369 spi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 370 if (IS_ERR(spi->regs)) 371 return PTR_ERR(spi->regs); 372 373 spi->irq = platform_get_irq(pdev, 0); 374 if (spi->irq < 0) 375 return spi->irq; 376 377 ret = devm_request_irq(dev, spi->irq, mchp_corespi_interrupt, IRQF_SHARED, 378 dev_name(dev), host); 379 if (ret) 380 return dev_err_probe(dev, ret, "could not request irq\n"); 381 382 spi->clk = devm_clk_get_enabled(dev, NULL); 383 if (IS_ERR(spi->clk)) 384 return dev_err_probe(dev, PTR_ERR(spi->clk), "could not get clk\n"); 385 386 mchp_corespi_init(host, spi); 387 388 ret = devm_spi_register_controller(dev, host); 389 if (ret) { 390 mchp_corespi_disable_ints(spi); 391 mchp_corespi_disable(spi); 392 return dev_err_probe(dev, ret, "unable to register host for CoreSPI controller\n"); 393 } 394 395 return 0; 396 } 397 398 static void mchp_corespi_remove(struct platform_device *pdev) 399 { 400 struct spi_controller *host = platform_get_drvdata(pdev); 401 struct mchp_corespi *spi = spi_controller_get_devdata(host); 402 403 mchp_corespi_disable_ints(spi); 404 mchp_corespi_disable(spi); 405 } 406 407 /* 408 * Platform driver data structure 409 */ 410 411 #if defined(CONFIG_OF) 412 static const struct of_device_id mchp_corespi_dt_ids[] = { 413 { .compatible = "microchip,corespi-rtl-v5" }, 414 { /* sentinel */ } 415 }; 416 MODULE_DEVICE_TABLE(of, mchp_corespi_dt_ids); 417 #endif 418 419 static struct platform_driver mchp_corespi_driver = { 420 .probe = mchp_corespi_probe, 421 .driver = { 422 .name = "microchip-corespi", 423 .of_match_table = of_match_ptr(mchp_corespi_dt_ids), 424 }, 425 .remove = mchp_corespi_remove, 426 }; 427 module_platform_driver(mchp_corespi_driver); 428 MODULE_DESCRIPTION("Microchip CoreSPI controller driver"); 429 MODULE_AUTHOR("Prajna Rajendra Kumar <prajna.rajendrakumar@microchip.com>"); 430 MODULE_LICENSE("GPL"); 431