xref: /linux/drivers/spi/spi-rb4xx.c (revision 07fdad3a93756b872da7b53647715c48d0f4a2d0)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * SPI controller driver for the Mikrotik RB4xx boards
4  *
5  * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
6  * Copyright (C) 2015 Bert Vermeulen <bert@biot.com>
7  *
8  * This file was based on the patches for Linux 2.6.27.39 published by
9  * MikroTik for their RouterBoard 4xx series devices.
10  */
11 
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/clk.h>
16 #include <linux/spi/spi.h>
17 #include <linux/of.h>
18 
19 #define AR71XX_SPI_REG_FS		0x00	/* Function Select */
20 #define AR71XX_SPI_REG_CTRL		0x04	/* SPI Control */
21 #define AR71XX_SPI_REG_IOC		0x08	/* SPI I/O Control */
22 #define AR71XX_SPI_REG_RDS		0x0c	/* Read Data Shift */
23 
24 #define AR71XX_SPI_FS_GPIO		BIT(0)	/* Enable GPIO mode */
25 
26 #define AR71XX_SPI_IOC_DO		BIT(0)	/* Data Out pin */
27 #define AR71XX_SPI_IOC_CLK		BIT(8)	/* CLK pin */
28 #define AR71XX_SPI_IOC_CS(n)		BIT(16 + (n))
29 
30 struct rb4xx_spi {
31 	void __iomem *base;
32 	struct clk *clk;
33 };
34 
35 static inline u32 rb4xx_read(struct rb4xx_spi *rbspi, u32 reg)
36 {
37 	return __raw_readl(rbspi->base + reg);
38 }
39 
40 static inline void rb4xx_write(struct rb4xx_spi *rbspi, u32 reg, u32 value)
41 {
42 	__raw_writel(value, rbspi->base + reg);
43 }
44 
45 static inline void do_spi_clk(struct rb4xx_spi *rbspi, u32 spi_ioc, int value)
46 {
47 	u32 regval;
48 
49 	regval = spi_ioc;
50 	if (value & BIT(0))
51 		regval |= AR71XX_SPI_IOC_DO;
52 
53 	rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval);
54 	rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval | AR71XX_SPI_IOC_CLK);
55 }
56 
57 static void do_spi_byte(struct rb4xx_spi *rbspi, u32 spi_ioc, u8 byte)
58 {
59 	int i;
60 
61 	for (i = 7; i >= 0; i--)
62 		do_spi_clk(rbspi, spi_ioc, byte >> i);
63 }
64 
65 /* The CS2 pin is used to clock in a second bit per clock cycle. */
66 static inline void do_spi_clk_two(struct rb4xx_spi *rbspi, u32 spi_ioc,
67 				   u8 value)
68 {
69 	u32 regval;
70 
71 	regval = spi_ioc;
72 	if (value & BIT(1))
73 		regval |= AR71XX_SPI_IOC_DO;
74 	if (value & BIT(0))
75 		regval |= AR71XX_SPI_IOC_CS(2);
76 
77 	rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval);
78 	rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval | AR71XX_SPI_IOC_CLK);
79 }
80 
81 /* Two bits at a time, msb first */
82 static void do_spi_byte_two(struct rb4xx_spi *rbspi, u32 spi_ioc, u8 byte)
83 {
84 	do_spi_clk_two(rbspi, spi_ioc, byte >> 6);
85 	do_spi_clk_two(rbspi, spi_ioc, byte >> 4);
86 	do_spi_clk_two(rbspi, spi_ioc, byte >> 2);
87 	do_spi_clk_two(rbspi, spi_ioc, byte >> 0);
88 }
89 
90 static void rb4xx_set_cs(struct spi_device *spi, bool enable)
91 {
92 	struct rb4xx_spi *rbspi = spi_controller_get_devdata(spi->controller);
93 
94 	/*
95 	 * Setting CS is done along with bitbanging the actual values,
96 	 * since it's all on the same hardware register. However the
97 	 * CPLD needs CS deselected after every command.
98 	 */
99 	if (enable)
100 		rb4xx_write(rbspi, AR71XX_SPI_REG_IOC,
101 			    AR71XX_SPI_IOC_CS(0) | AR71XX_SPI_IOC_CS(1));
102 }
103 
104 static int rb4xx_transfer_one(struct spi_controller *host,
105 			      struct spi_device *spi, struct spi_transfer *t)
106 {
107 	struct rb4xx_spi *rbspi = spi_controller_get_devdata(host);
108 	int i;
109 	u32 spi_ioc;
110 	u8 *rx_buf;
111 	const u8 *tx_buf;
112 
113 	/*
114 	 * Prime the SPI register with the SPI device selected. The m25p80 boot
115 	 * flash and CPLD share the CS0 pin. This works because the CPLD's
116 	 * command set was designed to almost not clash with that of the
117 	 * boot flash.
118 	 */
119 	if (spi_get_chipselect(spi, 0) == 2)
120 		/* MMC */
121 		spi_ioc = AR71XX_SPI_IOC_CS(0);
122 	else
123 		/* Boot flash and CPLD */
124 		spi_ioc = AR71XX_SPI_IOC_CS(1);
125 
126 	tx_buf = t->tx_buf;
127 	rx_buf = t->rx_buf;
128 	for (i = 0; i < t->len; ++i) {
129 		if (t->tx_nbits == SPI_NBITS_DUAL)
130 			/* CPLD can use two-wire transfers */
131 			do_spi_byte_two(rbspi, spi_ioc, tx_buf[i]);
132 		else
133 			do_spi_byte(rbspi, spi_ioc, tx_buf[i]);
134 		if (!rx_buf)
135 			continue;
136 		rx_buf[i] = rb4xx_read(rbspi, AR71XX_SPI_REG_RDS);
137 	}
138 	spi_finalize_current_transfer(host);
139 
140 	return 0;
141 }
142 
143 static int rb4xx_spi_probe(struct platform_device *pdev)
144 {
145 	struct spi_controller *host;
146 	struct clk *ahb_clk;
147 	struct rb4xx_spi *rbspi;
148 	int err;
149 	void __iomem *spi_base;
150 
151 	spi_base = devm_platform_ioremap_resource(pdev, 0);
152 	if (IS_ERR(spi_base))
153 		return PTR_ERR(spi_base);
154 
155 	host = devm_spi_alloc_host(&pdev->dev, sizeof(*rbspi));
156 	if (!host)
157 		return -ENOMEM;
158 
159 	ahb_clk = devm_clk_get_enabled(&pdev->dev, "ahb");
160 	if (IS_ERR(ahb_clk))
161 		return PTR_ERR(ahb_clk);
162 
163 	host->dev.of_node = pdev->dev.of_node;
164 	host->bus_num = 0;
165 	host->num_chipselect = 3;
166 	host->mode_bits = SPI_TX_DUAL;
167 	host->bits_per_word_mask = SPI_BPW_MASK(8);
168 	host->flags = SPI_CONTROLLER_MUST_TX;
169 	host->transfer_one = rb4xx_transfer_one;
170 	host->set_cs = rb4xx_set_cs;
171 
172 	rbspi = spi_controller_get_devdata(host);
173 	rbspi->base = spi_base;
174 	rbspi->clk = ahb_clk;
175 
176 	err = devm_spi_register_controller(&pdev->dev, host);
177 	if (err) {
178 		dev_err(&pdev->dev, "failed to register SPI host\n");
179 		return err;
180 	}
181 
182 	/* Enable SPI */
183 	rb4xx_write(rbspi, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
184 
185 	return 0;
186 }
187 
188 static const struct of_device_id rb4xx_spi_dt_match[] = {
189 	{ .compatible = "mikrotik,rb4xx-spi" },
190 	{ },
191 };
192 MODULE_DEVICE_TABLE(of, rb4xx_spi_dt_match);
193 
194 static struct platform_driver rb4xx_spi_drv = {
195 	.probe = rb4xx_spi_probe,
196 	.driver = {
197 		.name = "rb4xx-spi",
198 		.of_match_table = rb4xx_spi_dt_match,
199 	},
200 };
201 
202 module_platform_driver(rb4xx_spi_drv);
203 
204 MODULE_DESCRIPTION("Mikrotik RB4xx SPI controller driver");
205 MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
206 MODULE_AUTHOR("Bert Vermeulen <bert@biot.com>");
207 MODULE_LICENSE("GPL v2");
208