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

spi: Add SPI driver for Mikrotik RB4xx series boards

This driver mediates access between the connected CPLD and other devices
on the bus.

The m25p80-compatible boot flash and (some models) MMC use regular SPI,
bitbanged as required by the SoC. However the SPI-connected CPLD has
a two-wire mode, in which two bits are transferred per SPI clock
cycle. The second bit is transmitted with the SoC's CS2 pin.

Signed-off-by: Bert Vermeulen <bert@biot.com>
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Bert Vermeulen and committed by
Mark Brown
05aec357 c517d838

+217
+6
drivers/spi/Kconfig
··· 429 429 The main usecase of this controller is to use spi flash as boot 430 430 device. 431 431 432 + config SPI_RB4XX 433 + tristate "Mikrotik RB4XX SPI master" 434 + depends on SPI_MASTER && ATH79 435 + help 436 + SPI controller driver for the Mikrotik RB4xx series boards. 437 + 432 438 config SPI_RSPI 433 439 tristate "Renesas RSPI/QSPI controller" 434 440 depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
+1
drivers/spi/Makefile
··· 66 66 obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o 67 67 obj-$(CONFIG_SPI_QUP) += spi-qup.o 68 68 obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o 69 + obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o 69 70 obj-$(CONFIG_SPI_RSPI) += spi-rspi.o 70 71 obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o 71 72 spi-s3c24xx-hw-y := spi-s3c24xx.o
+210
drivers/spi/spi-rb4xx.c
··· 1 + /* 2 + * SPI controller driver for the Mikrotik RB4xx boards 3 + * 4 + * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org> 5 + * Copyright (C) 2015 Bert Vermeulen <bert@biot.com> 6 + * 7 + * This file was based on the patches for Linux 2.6.27.39 published by 8 + * MikroTik for their RouterBoard 4xx series devices. 9 + * 10 + * This program is free software; you can redistribute it and/or modify 11 + * it under the terms of the GNU General Public License version 2 as 12 + * published by the Free Software Foundation. 13 + * 14 + */ 15 + 16 + #include <linux/kernel.h> 17 + #include <linux/module.h> 18 + #include <linux/platform_device.h> 19 + #include <linux/clk.h> 20 + #include <linux/spi/spi.h> 21 + 22 + #include <asm/mach-ath79/ar71xx_regs.h> 23 + 24 + struct rb4xx_spi { 25 + void __iomem *base; 26 + struct clk *clk; 27 + }; 28 + 29 + static inline u32 rb4xx_read(struct rb4xx_spi *rbspi, u32 reg) 30 + { 31 + return __raw_readl(rbspi->base + reg); 32 + } 33 + 34 + static inline void rb4xx_write(struct rb4xx_spi *rbspi, u32 reg, u32 value) 35 + { 36 + __raw_writel(value, rbspi->base + reg); 37 + } 38 + 39 + static inline void do_spi_clk(struct rb4xx_spi *rbspi, u32 spi_ioc, int value) 40 + { 41 + u32 regval; 42 + 43 + regval = spi_ioc; 44 + if (value & BIT(0)) 45 + regval |= AR71XX_SPI_IOC_DO; 46 + 47 + rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval); 48 + rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval | AR71XX_SPI_IOC_CLK); 49 + } 50 + 51 + static void do_spi_byte(struct rb4xx_spi *rbspi, u32 spi_ioc, u8 byte) 52 + { 53 + int i; 54 + 55 + for (i = 7; i >= 0; i--) 56 + do_spi_clk(rbspi, spi_ioc, byte >> i); 57 + } 58 + 59 + /* The CS2 pin is used to clock in a second bit per clock cycle. */ 60 + static inline void do_spi_clk_two(struct rb4xx_spi *rbspi, u32 spi_ioc, 61 + u8 value) 62 + { 63 + u32 regval; 64 + 65 + regval = spi_ioc; 66 + if (value & BIT(1)) 67 + regval |= AR71XX_SPI_IOC_DO; 68 + if (value & BIT(0)) 69 + regval |= AR71XX_SPI_IOC_CS2; 70 + 71 + rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval); 72 + rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval | AR71XX_SPI_IOC_CLK); 73 + } 74 + 75 + /* Two bits at a time, msb first */ 76 + static void do_spi_byte_two(struct rb4xx_spi *rbspi, u32 spi_ioc, u8 byte) 77 + { 78 + do_spi_clk_two(rbspi, spi_ioc, byte >> 6); 79 + do_spi_clk_two(rbspi, spi_ioc, byte >> 4); 80 + do_spi_clk_two(rbspi, spi_ioc, byte >> 2); 81 + do_spi_clk_two(rbspi, spi_ioc, byte >> 0); 82 + } 83 + 84 + static void rb4xx_set_cs(struct spi_device *spi, bool enable) 85 + { 86 + struct rb4xx_spi *rbspi = spi_master_get_devdata(spi->master); 87 + 88 + /* 89 + * Setting CS is done along with bitbanging the actual values, 90 + * since it's all on the same hardware register. However the 91 + * CPLD needs CS deselected after every command. 92 + */ 93 + if (!enable) 94 + rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, 95 + AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1); 96 + } 97 + 98 + static int rb4xx_transfer_one(struct spi_master *master, 99 + struct spi_device *spi, struct spi_transfer *t) 100 + { 101 + struct rb4xx_spi *rbspi = spi_master_get_devdata(master); 102 + int i; 103 + u32 spi_ioc; 104 + u8 *rx_buf; 105 + const u8 *tx_buf; 106 + 107 + /* 108 + * Prime the SPI register with the SPI device selected. The m25p80 boot 109 + * flash and CPLD share the CS0 pin. This works because the CPLD's 110 + * command set was designed to almost not clash with that of the 111 + * boot flash. 112 + */ 113 + if (spi->chip_select == 2) 114 + /* MMC */ 115 + spi_ioc = AR71XX_SPI_IOC_CS0; 116 + else 117 + /* Boot flash and CPLD */ 118 + spi_ioc = AR71XX_SPI_IOC_CS1; 119 + 120 + tx_buf = t->tx_buf; 121 + rx_buf = t->rx_buf; 122 + for (i = 0; i < t->len; ++i) { 123 + if (t->tx_nbits == SPI_NBITS_DUAL) 124 + /* CPLD can use two-wire transfers */ 125 + do_spi_byte_two(rbspi, spi_ioc, tx_buf[i]); 126 + else 127 + do_spi_byte(rbspi, spi_ioc, tx_buf[i]); 128 + if (!rx_buf) 129 + continue; 130 + rx_buf[i] = rb4xx_read(rbspi, AR71XX_SPI_REG_RDS); 131 + } 132 + spi_finalize_current_transfer(master); 133 + 134 + return 0; 135 + } 136 + 137 + static int rb4xx_spi_probe(struct platform_device *pdev) 138 + { 139 + struct spi_master *master; 140 + struct clk *ahb_clk; 141 + struct rb4xx_spi *rbspi; 142 + struct resource *r; 143 + int err; 144 + void __iomem *spi_base; 145 + 146 + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 147 + spi_base = devm_ioremap_resource(&pdev->dev, r); 148 + if (!spi_base) 149 + return PTR_ERR(spi_base); 150 + 151 + master = spi_alloc_master(&pdev->dev, sizeof(*rbspi)); 152 + if (!master) 153 + return -ENOMEM; 154 + 155 + ahb_clk = devm_clk_get(&pdev->dev, "ahb"); 156 + if (IS_ERR(ahb_clk)) 157 + return PTR_ERR(ahb_clk); 158 + 159 + master->bus_num = 0; 160 + master->num_chipselect = 3; 161 + master->mode_bits = SPI_TX_DUAL; 162 + master->bits_per_word_mask = BIT(7); 163 + master->flags = SPI_MASTER_MUST_TX; 164 + master->transfer_one = rb4xx_transfer_one; 165 + master->set_cs = rb4xx_set_cs; 166 + 167 + err = devm_spi_register_master(&pdev->dev, master); 168 + if (err) { 169 + dev_err(&pdev->dev, "failed to register SPI master\n"); 170 + return err; 171 + } 172 + 173 + err = clk_prepare_enable(ahb_clk); 174 + if (err) 175 + return err; 176 + 177 + rbspi = spi_master_get_devdata(master); 178 + rbspi->base = spi_base; 179 + rbspi->clk = ahb_clk; 180 + platform_set_drvdata(pdev, rbspi); 181 + 182 + /* Enable SPI */ 183 + rb4xx_write(rbspi, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO); 184 + 185 + return 0; 186 + } 187 + 188 + static int rb4xx_spi_remove(struct platform_device *pdev) 189 + { 190 + struct rb4xx_spi *rbspi = platform_get_drvdata(pdev); 191 + 192 + clk_disable_unprepare(rbspi->clk); 193 + 194 + return 0; 195 + } 196 + 197 + static struct platform_driver rb4xx_spi_drv = { 198 + .probe = rb4xx_spi_probe, 199 + .remove = rb4xx_spi_remove, 200 + .driver = { 201 + .name = "rb4xx-spi", 202 + }, 203 + }; 204 + 205 + module_platform_driver(rb4xx_spi_drv); 206 + 207 + MODULE_DESCRIPTION("Mikrotik RB4xx SPI controller driver"); 208 + MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); 209 + MODULE_AUTHOR("Bert Vermeulen <bert@biot.com>"); 210 + MODULE_LICENSE("GPL v2");