1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * J-Core SPI controller driver |
4 | * |
5 | * Copyright (C) 2012-2016 Smart Energy Instruments, Inc. |
6 | * |
7 | * Current version by Rich Felker |
8 | * Based loosely on initial version by Oleksandr G Zhadan |
9 | * |
10 | */ |
11 | #include <linux/init.h> |
12 | #include <linux/interrupt.h> |
13 | #include <linux/errno.h> |
14 | #include <linux/module.h> |
15 | #include <linux/platform_device.h> |
16 | #include <linux/spi/spi.h> |
17 | #include <linux/clk.h> |
18 | #include <linux/err.h> |
19 | #include <linux/io.h> |
20 | #include <linux/of.h> |
21 | #include <linux/delay.h> |
22 | |
23 | #define DRV_NAME "jcore_spi" |
24 | |
25 | #define CTRL_REG 0x0 |
26 | #define DATA_REG 0x4 |
27 | |
28 | #define JCORE_SPI_CTRL_XMIT 0x02 |
29 | #define JCORE_SPI_STAT_BUSY 0x02 |
30 | #define JCORE_SPI_CTRL_LOOP 0x08 |
31 | #define JCORE_SPI_CTRL_CS_BITS 0x15 |
32 | |
33 | #define JCORE_SPI_WAIT_RDY_MAX_LOOP 2000000 |
34 | |
35 | struct jcore_spi { |
36 | struct spi_controller *host; |
37 | void __iomem *base; |
38 | unsigned int cs_reg; |
39 | unsigned int speed_reg; |
40 | unsigned int speed_hz; |
41 | unsigned int clock_freq; |
42 | }; |
43 | |
44 | static int jcore_spi_wait(void __iomem *ctrl_reg) |
45 | { |
46 | unsigned timeout = JCORE_SPI_WAIT_RDY_MAX_LOOP; |
47 | |
48 | do { |
49 | if (!(readl(addr: ctrl_reg) & JCORE_SPI_STAT_BUSY)) |
50 | return 0; |
51 | cpu_relax(); |
52 | } while (--timeout); |
53 | |
54 | return -EBUSY; |
55 | } |
56 | |
57 | static void jcore_spi_program(struct jcore_spi *hw) |
58 | { |
59 | void __iomem *ctrl_reg = hw->base + CTRL_REG; |
60 | |
61 | if (jcore_spi_wait(ctrl_reg)) |
62 | dev_err(hw->host->dev.parent, |
63 | "timeout waiting to program ctrl reg.\n" ); |
64 | |
65 | writel(val: hw->cs_reg | hw->speed_reg, addr: ctrl_reg); |
66 | } |
67 | |
68 | static void jcore_spi_chipsel(struct spi_device *spi, bool value) |
69 | { |
70 | struct jcore_spi *hw = spi_controller_get_devdata(ctlr: spi->controller); |
71 | u32 csbit = 1U << (2 * spi_get_chipselect(spi, idx: 0)); |
72 | |
73 | dev_dbg(hw->host->dev.parent, "chipselect %d\n" , spi_get_chipselect(spi, 0)); |
74 | |
75 | if (value) |
76 | hw->cs_reg |= csbit; |
77 | else |
78 | hw->cs_reg &= ~csbit; |
79 | |
80 | jcore_spi_program(hw); |
81 | } |
82 | |
83 | static void jcore_spi_baudrate(struct jcore_spi *hw, int speed) |
84 | { |
85 | if (speed == hw->speed_hz) |
86 | return; |
87 | hw->speed_hz = speed; |
88 | if (speed >= hw->clock_freq / 2) |
89 | hw->speed_reg = 0; |
90 | else |
91 | hw->speed_reg = ((hw->clock_freq / 2 / speed) - 1) << 27; |
92 | jcore_spi_program(hw); |
93 | dev_dbg(hw->host->dev.parent, "speed=%d reg=0x%x\n" , |
94 | speed, hw->speed_reg); |
95 | } |
96 | |
97 | static int jcore_spi_txrx(struct spi_controller *host, struct spi_device *spi, |
98 | struct spi_transfer *t) |
99 | { |
100 | struct jcore_spi *hw = spi_controller_get_devdata(ctlr: host); |
101 | |
102 | void __iomem *ctrl_reg = hw->base + CTRL_REG; |
103 | void __iomem *data_reg = hw->base + DATA_REG; |
104 | u32 xmit; |
105 | |
106 | /* data buffers */ |
107 | const unsigned char *tx; |
108 | unsigned char *rx; |
109 | unsigned int len; |
110 | unsigned int count; |
111 | |
112 | jcore_spi_baudrate(hw, speed: t->speed_hz); |
113 | |
114 | xmit = hw->cs_reg | hw->speed_reg | JCORE_SPI_CTRL_XMIT; |
115 | tx = t->tx_buf; |
116 | rx = t->rx_buf; |
117 | len = t->len; |
118 | |
119 | for (count = 0; count < len; count++) { |
120 | if (jcore_spi_wait(ctrl_reg)) |
121 | break; |
122 | |
123 | writel(val: tx ? *tx++ : 0, addr: data_reg); |
124 | writel(val: xmit, addr: ctrl_reg); |
125 | |
126 | if (jcore_spi_wait(ctrl_reg)) |
127 | break; |
128 | |
129 | if (rx) |
130 | *rx++ = readl(addr: data_reg); |
131 | } |
132 | |
133 | spi_finalize_current_transfer(ctlr: host); |
134 | |
135 | if (count < len) |
136 | return -EREMOTEIO; |
137 | |
138 | return 0; |
139 | } |
140 | |
141 | static int jcore_spi_probe(struct platform_device *pdev) |
142 | { |
143 | struct device_node *node = pdev->dev.of_node; |
144 | struct jcore_spi *hw; |
145 | struct spi_controller *host; |
146 | struct resource *res; |
147 | u32 clock_freq; |
148 | struct clk *clk; |
149 | int err = -ENODEV; |
150 | |
151 | host = spi_alloc_host(dev: &pdev->dev, size: sizeof(struct jcore_spi)); |
152 | if (!host) |
153 | return err; |
154 | |
155 | /* Setup the host state. */ |
156 | host->num_chipselect = 3; |
157 | host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; |
158 | host->transfer_one = jcore_spi_txrx; |
159 | host->set_cs = jcore_spi_chipsel; |
160 | host->dev.of_node = node; |
161 | host->bus_num = pdev->id; |
162 | |
163 | hw = spi_controller_get_devdata(ctlr: host); |
164 | hw->host = host; |
165 | platform_set_drvdata(pdev, data: hw); |
166 | |
167 | /* Find and map our resources */ |
168 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
169 | if (!res) |
170 | goto exit_busy; |
171 | if (!devm_request_mem_region(&pdev->dev, res->start, |
172 | resource_size(res), pdev->name)) |
173 | goto exit_busy; |
174 | hw->base = devm_ioremap(dev: &pdev->dev, offset: res->start, |
175 | size: resource_size(res)); |
176 | if (!hw->base) |
177 | goto exit_busy; |
178 | |
179 | /* |
180 | * The SPI clock rate controlled via a configurable clock divider |
181 | * which is applied to the reference clock. A 50 MHz reference is |
182 | * most suitable for obtaining standard SPI clock rates, but some |
183 | * designs may have a different reference clock, and the DT must |
184 | * make the driver aware so that it can properly program the |
185 | * requested rate. If the clock is omitted, 50 MHz is assumed. |
186 | */ |
187 | clock_freq = 50000000; |
188 | clk = devm_clk_get(dev: &pdev->dev, id: "ref_clk" ); |
189 | if (!IS_ERR(ptr: clk)) { |
190 | if (clk_prepare_enable(clk) == 0) { |
191 | clock_freq = clk_get_rate(clk); |
192 | clk_disable_unprepare(clk); |
193 | } else |
194 | dev_warn(&pdev->dev, "could not enable ref_clk\n" ); |
195 | } |
196 | hw->clock_freq = clock_freq; |
197 | |
198 | /* Initialize all CS bits to high. */ |
199 | hw->cs_reg = JCORE_SPI_CTRL_CS_BITS; |
200 | jcore_spi_baudrate(hw, speed: 400000); |
201 | |
202 | /* Register our spi controller */ |
203 | err = devm_spi_register_controller(dev: &pdev->dev, ctlr: host); |
204 | if (err) |
205 | goto exit; |
206 | |
207 | return 0; |
208 | |
209 | exit_busy: |
210 | err = -EBUSY; |
211 | exit: |
212 | spi_controller_put(ctlr: host); |
213 | return err; |
214 | } |
215 | |
216 | static const struct of_device_id jcore_spi_of_match[] = { |
217 | { .compatible = "jcore,spi2" }, |
218 | {}, |
219 | }; |
220 | MODULE_DEVICE_TABLE(of, jcore_spi_of_match); |
221 | |
222 | static struct platform_driver jcore_spi_driver = { |
223 | .probe = jcore_spi_probe, |
224 | .driver = { |
225 | .name = DRV_NAME, |
226 | .of_match_table = jcore_spi_of_match, |
227 | }, |
228 | }; |
229 | |
230 | module_platform_driver(jcore_spi_driver); |
231 | |
232 | MODULE_DESCRIPTION("J-Core SPI driver" ); |
233 | MODULE_AUTHOR("Rich Felker <dalias@libc.org>" ); |
234 | MODULE_LICENSE("GPL" ); |
235 | MODULE_ALIAS("platform:" DRV_NAME); |
236 | |