1 /* $OpenBSD: ociic.c,v 1.4 2024/05/15 22:54:03 kettenis Exp $ */
2 /*
3 * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21
22 #include <machine/intr.h>
23 #include <machine/bus.h>
24 #include <machine/fdt.h>
25
26 #define _I2C_PRIVATE
27 #include <dev/i2c/i2cvar.h>
28
29 #include <dev/ofw/openfirm.h>
30 #include <dev/ofw/ofw_clock.h>
31 #include <dev/ofw/ofw_pinctrl.h>
32 #include <dev/ofw/fdt.h>
33
34 /* Registers */
35 #define I2C_PRER_LO 0x0000
36 #define I2C_PRER_HI 0x0004
37 #define I2C_CTR 0x0008
38 #define I2C_CTR_EN (1 << 7)
39 #define I2C_CTR_IEN (1 << 6)
40 #define I2C_TXR 0x000C
41 #define I2C_RXR 0x000C
42 #define I2C_CR 0x0010
43 #define I2C_CR_STA (1 << 7)
44 #define I2C_CR_STO (1 << 6)
45 #define I2C_CR_RD (1 << 5)
46 #define I2C_CR_WR (1 << 4)
47 #define I2C_CR_NACK (1 << 3)
48 #define I2C_CR_IACK (1 << 0)
49 #define I2C_SR 0x0010
50 #define I2C_SR_RXNACK (1 << 7)
51 #define I2C_SR_BUSY (1 << 6)
52 #define I2C_SR_AL (1 << 5)
53 #define I2C_SR_TIP (1 << 1)
54 #define I2C_SR_IF (1 << 0)
55
56 /*
57 * OpenSBI on the SiFive HiFive Unmatched board implements reboot and
58 * powerdown functionality through the Dialog DA9063 Power Management
59 * IC over I2C. The code expects the I2C controller to be enabled so
60 * we have to make sure we leave it in that state.
61 */
62
63 struct ociic_softc {
64 struct device sc_dev;
65 bus_space_tag_t sc_iot;
66 bus_space_handle_t sc_ioh;
67
68 int sc_node;
69 struct i2c_controller sc_ic;
70 };
71
72 static inline uint8_t
ociic_read(struct ociic_softc * sc,bus_size_t reg)73 ociic_read(struct ociic_softc *sc, bus_size_t reg)
74 {
75 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, reg);
76 }
77
78 static inline void
ociic_write(struct ociic_softc * sc,bus_size_t reg,uint8_t value)79 ociic_write(struct ociic_softc *sc, bus_size_t reg, uint8_t value)
80 {
81 bus_space_write_1(sc->sc_iot, sc->sc_ioh, reg, value);
82 }
83
84 static inline void
ociic_set(struct ociic_softc * sc,bus_size_t reg,uint8_t bits)85 ociic_set(struct ociic_softc *sc, bus_size_t reg, uint8_t bits)
86 {
87 ociic_write(sc, reg, ociic_read(sc, reg) | bits);
88 }
89
90 static inline void
ociic_clr(struct ociic_softc * sc,bus_size_t reg,uint8_t bits)91 ociic_clr(struct ociic_softc *sc, bus_size_t reg, uint8_t bits)
92 {
93 ociic_write(sc, reg, ociic_read(sc, reg) & ~bits);
94 }
95
96 int ociic_match(struct device *, void *, void *);
97 void ociic_attach(struct device *, struct device *, void *);
98
99 const struct cfattach ociic_ca = {
100 sizeof (struct ociic_softc), ociic_match, ociic_attach
101 };
102
103 struct cfdriver ociic_cd = {
104 NULL, "ociic", DV_DULL
105 };
106
107 int ociic_acquire_bus(void *, int);
108 void ociic_release_bus(void *, int);
109 int ociic_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
110 void *, size_t, int);
111
112 void ociic_bus_scan(struct device *, struct i2cbus_attach_args *, void *);
113
114 int
ociic_match(struct device * parent,void * match,void * aux)115 ociic_match(struct device *parent, void *match, void *aux)
116 {
117 struct fdt_attach_args *faa = aux;
118
119 return OF_is_compatible(faa->fa_node, "sifive,i2c0");
120 }
121
122 void
ociic_attach(struct device * parent,struct device * self,void * aux)123 ociic_attach(struct device *parent, struct device *self, void *aux)
124 {
125 struct ociic_softc *sc = (struct ociic_softc *)self;
126 struct fdt_attach_args *faa = aux;
127 struct i2cbus_attach_args iba;
128 uint32_t clock_speed, bus_speed;
129 uint32_t div;
130
131 if (faa->fa_nreg < 1) {
132 printf(": no registers\n");
133 return;
134 }
135
136 sc->sc_iot = faa->fa_iot;
137 sc->sc_node = faa->fa_node;
138
139 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
140 faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
141 printf(": can't map registers\n");
142 return;
143 }
144
145 printf("\n");
146
147 pinctrl_byname(sc->sc_node, "default");
148 clock_enable_all(sc->sc_node);
149
150 ociic_clr(sc, I2C_CTR, I2C_CTR_EN);
151
152 clock_speed = clock_get_frequency(sc->sc_node, NULL);
153 bus_speed = OF_getpropint(sc->sc_node, "clock-frequency", 100000);
154
155 if (clock_speed > 0) {
156 div = (clock_speed / (5 * bus_speed));
157 if (div > 0)
158 div -= 1;
159 if (div > 0xffff)
160 div = 0xffff;
161
162 ociic_write(sc, I2C_PRER_LO, div & 0xff);
163 ociic_write(sc, I2C_PRER_HI, div >> 8);
164 }
165
166 ociic_set(sc, I2C_CTR, I2C_CTR_EN);
167
168 sc->sc_ic.ic_cookie = sc;
169 sc->sc_ic.ic_acquire_bus = ociic_acquire_bus;
170 sc->sc_ic.ic_release_bus = ociic_release_bus;
171 sc->sc_ic.ic_exec = ociic_exec;
172
173 /* Configure its children */
174 memset(&iba, 0, sizeof(iba));
175 iba.iba_name = "iic";
176 iba.iba_tag = &sc->sc_ic;
177 iba.iba_bus_scan = ociic_bus_scan;
178 iba.iba_bus_scan_arg = &sc->sc_node;
179
180 config_found(&sc->sc_dev, &iba, iicbus_print);
181 }
182
183 int
ociic_acquire_bus(void * cookie,int flags)184 ociic_acquire_bus(void *cookie, int flags)
185 {
186 return 0;
187 }
188
189 void
ociic_release_bus(void * cookie,int flags)190 ociic_release_bus(void *cookie, int flags)
191 {
192 }
193
194 int
ociic_unbusy(struct ociic_softc * sc)195 ociic_unbusy(struct ociic_softc *sc)
196 {
197 uint8_t stat;
198 int timo;
199
200 for (timo = 50000; timo > 0; timo--) {
201 stat = ociic_read(sc, I2C_SR);
202 if ((stat & I2C_SR_BUSY) == 0)
203 break;
204 delay(10);
205 }
206 if (timo == 0) {
207 ociic_write(sc, I2C_CR, I2C_CR_STO);
208 return ETIMEDOUT;
209 }
210
211 return 0;
212 }
213
214 int
ociic_wait(struct ociic_softc * sc,int ack)215 ociic_wait(struct ociic_softc *sc, int ack)
216 {
217 uint8_t stat;
218 int timo;
219
220 for (timo = 50000; timo > 0; timo--) {
221 stat = ociic_read(sc, I2C_SR);
222 if ((stat & I2C_SR_TIP) == 0)
223 break;
224 if ((stat & I2C_SR_AL))
225 break;
226 delay(10);
227 }
228 if (timo == 0) {
229 ociic_write(sc, I2C_CR, I2C_CR_STO);
230 return ETIMEDOUT;
231 }
232
233 if (stat & I2C_SR_AL) {
234 ociic_write(sc, I2C_CR, I2C_CR_STO);
235 return EIO;
236 }
237 if (ack && (stat & I2C_SR_RXNACK)) {
238 ociic_write(sc, I2C_CR, I2C_CR_STO);
239 return EIO;
240 }
241
242 return 0;
243 }
244
245 int
ociic_exec(void * cookie,i2c_op_t op,i2c_addr_t addr,const void * cmd,size_t cmdlen,void * buf,size_t buflen,int flags)246 ociic_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmd,
247 size_t cmdlen, void *buf, size_t buflen, int flags)
248 {
249 struct ociic_softc *sc = cookie;
250 int error, i;
251
252 error = ociic_unbusy(sc);
253 if (error)
254 return error;
255
256 if (cmdlen > 0) {
257 ociic_write(sc, I2C_TXR, addr << 1);
258 ociic_write(sc, I2C_CR, I2C_CR_STA | I2C_CR_WR);
259 error = ociic_wait(sc, 1);
260 if (error)
261 return error;
262
263 for (i = 0; i < cmdlen; i++) {
264 ociic_write(sc, I2C_TXR, ((uint8_t *)cmd)[i]);
265 ociic_write(sc, I2C_CR, I2C_CR_WR);
266 error = ociic_wait(sc, 1);
267 if (error)
268 return error;
269 }
270 }
271
272 if (I2C_OP_READ_P(op)) {
273 ociic_write(sc, I2C_TXR, addr << 1 | 1);
274 ociic_write(sc, I2C_CR, I2C_CR_STA | I2C_CR_WR);
275 error = ociic_wait(sc, 1);
276 if (error)
277 return error;
278
279 for (i = 0; i < buflen; i++) {
280 ociic_write(sc, I2C_CR, I2C_CR_RD |
281 (i == (buflen - 1) ? I2C_CR_NACK : 0));
282 error = ociic_wait(sc, 0);
283 if (error)
284 return error;
285 ((uint8_t *)buf)[i] = ociic_read(sc, I2C_RXR);
286 }
287 } else {
288 if (cmdlen == 0) {
289 ociic_write(sc, I2C_TXR, addr << 1);
290 ociic_write(sc, I2C_CR, I2C_CR_STA | I2C_CR_WR);
291 }
292
293 for (i = 0; i < buflen; i++) {
294 ociic_write(sc, I2C_TXR, ((uint8_t *)buf)[i]);
295 ociic_write(sc, I2C_CR, I2C_CR_WR);
296 error = ociic_wait(sc, 1);
297 if (error)
298 return error;
299 }
300 }
301
302 if (I2C_OP_STOP_P(op))
303 ociic_write(sc, I2C_CR, I2C_CR_STO);
304
305 return 0;
306 }
307
308 void
ociic_bus_scan(struct device * self,struct i2cbus_attach_args * iba,void * arg)309 ociic_bus_scan(struct device *self, struct i2cbus_attach_args *iba, void *arg)
310 {
311 int iba_node = *(int *)arg;
312 struct i2c_attach_args ia;
313 char name[32], status[32];
314 uint32_t reg[1];
315 int node;
316
317 for (node = OF_child(iba_node); node; node = OF_peer(node)) {
318 memset(name, 0, sizeof(name));
319 memset(status, 0, sizeof(status));
320 memset(reg, 0, sizeof(reg));
321
322 if (OF_getprop(node, "compatible", name, sizeof(name)) == -1)
323 continue;
324 if (name[0] == '\0')
325 continue;
326
327 if (OF_getprop(node, "status", status, sizeof(status)) > 0 &&
328 strcmp(status, "disabled") == 0)
329 continue;
330
331 if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg))
332 continue;
333
334 memset(&ia, 0, sizeof(ia));
335 ia.ia_tag = iba->iba_tag;
336 ia.ia_addr = bemtoh32(®[0]);
337 ia.ia_name = name;
338 ia.ia_cookie = &node;
339 config_found(self, &ia, iic_print);
340 }
341 }
342