1 /* $OpenBSD: ociic.c,v 1.2 2021/06/23 13:39:12 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 struct ociic_softc { 57 struct device sc_dev; 58 bus_space_tag_t sc_iot; 59 bus_space_handle_t sc_ioh; 60 61 int sc_node; 62 struct i2c_controller sc_ic; 63 }; 64 65 static inline uint8_t 66 ociic_read(struct ociic_softc *sc, bus_size_t reg) 67 { 68 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, reg); 69 } 70 71 static inline void 72 ociic_write(struct ociic_softc *sc, bus_size_t reg, uint8_t value) 73 { 74 bus_space_write_1(sc->sc_iot, sc->sc_ioh, reg, value); 75 } 76 77 static inline void 78 ociic_set(struct ociic_softc *sc, bus_size_t reg, uint8_t bits) 79 { 80 ociic_write(sc, reg, ociic_read(sc, reg) | bits); 81 } 82 83 static inline void 84 ociic_clr(struct ociic_softc *sc, bus_size_t reg, uint8_t bits) 85 { 86 ociic_write(sc, reg, ociic_read(sc, reg) & ~bits); 87 } 88 89 int ociic_match(struct device *, void *, void *); 90 void ociic_attach(struct device *, struct device *, void *); 91 92 struct cfattach ociic_ca = { 93 sizeof (struct ociic_softc), ociic_match, ociic_attach 94 }; 95 96 struct cfdriver ociic_cd = { 97 NULL, "ociic", DV_DULL 98 }; 99 100 int ociic_acquire_bus(void *, int); 101 void ociic_release_bus(void *, int); 102 int ociic_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t, 103 void *, size_t, int); 104 105 void ociic_bus_scan(struct device *, struct i2cbus_attach_args *, void *); 106 107 int 108 ociic_match(struct device *parent, void *match, void *aux) 109 { 110 struct fdt_attach_args *faa = aux; 111 112 return OF_is_compatible(faa->fa_node, "sifive,i2c0"); 113 } 114 115 void 116 ociic_attach(struct device *parent, struct device *self, void *aux) 117 { 118 struct ociic_softc *sc = (struct ociic_softc *)self; 119 struct fdt_attach_args *faa = aux; 120 struct i2cbus_attach_args iba; 121 uint32_t clock_speed, bus_speed; 122 uint32_t div; 123 124 if (faa->fa_nreg < 1) { 125 printf(": no registers\n"); 126 return; 127 } 128 129 sc->sc_iot = faa->fa_iot; 130 sc->sc_node = faa->fa_node; 131 132 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 133 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 134 printf(": can't map registers\n"); 135 return; 136 } 137 138 printf("\n"); 139 140 pinctrl_byname(sc->sc_node, "default"); 141 clock_enable_all(sc->sc_node); 142 143 ociic_clr(sc, I2C_CTR, I2C_CTR_EN); 144 145 clock_speed = clock_get_frequency(sc->sc_node, NULL); 146 bus_speed = OF_getpropint(sc->sc_node, "clock-frequency", 100000); 147 148 if (clock_speed > 0) { 149 div = (clock_speed / (5 * bus_speed)); 150 if (div > 0) 151 div -= 1; 152 if (div > 0xffff) 153 div = 0xffff; 154 155 ociic_write(sc, I2C_PRER_LO, div & 0xff); 156 ociic_write(sc, I2C_PRER_HI, div >> 8); 157 } 158 159 sc->sc_ic.ic_cookie = sc; 160 sc->sc_ic.ic_acquire_bus = ociic_acquire_bus; 161 sc->sc_ic.ic_release_bus = ociic_release_bus; 162 sc->sc_ic.ic_exec = ociic_exec; 163 164 /* Configure its children */ 165 memset(&iba, 0, sizeof(iba)); 166 iba.iba_name = "iic"; 167 iba.iba_tag = &sc->sc_ic; 168 iba.iba_bus_scan = ociic_bus_scan; 169 iba.iba_bus_scan_arg = &sc->sc_node; 170 171 config_found(&sc->sc_dev, &iba, iicbus_print); 172 } 173 174 int 175 ociic_acquire_bus(void *cookie, int flags) 176 { 177 struct ociic_softc *sc = cookie; 178 179 ociic_set(sc, I2C_CTR, I2C_CTR_EN); 180 return 0; 181 } 182 183 void 184 ociic_release_bus(void *cookie, int flags) 185 { 186 struct ociic_softc *sc = cookie; 187 188 ociic_clr(sc, I2C_CTR, I2C_CTR_EN); 189 } 190 191 int 192 ociic_unbusy(struct ociic_softc *sc) 193 { 194 uint8_t stat; 195 int timo; 196 197 for (timo = 50000; timo > 0; timo--) { 198 stat = ociic_read(sc, I2C_SR); 199 if ((stat & I2C_SR_BUSY) == 0) 200 break; 201 delay(10); 202 } 203 if (timo == 0) { 204 ociic_write(sc, I2C_CR, I2C_CR_STO); 205 return ETIMEDOUT; 206 } 207 208 return 0; 209 } 210 211 int 212 ociic_wait(struct ociic_softc *sc, int ack) 213 { 214 uint8_t stat; 215 int timo; 216 217 for (timo = 50000; timo > 0; timo--) { 218 stat = ociic_read(sc, I2C_SR); 219 if ((stat & I2C_SR_TIP) == 0) 220 break; 221 if ((stat & I2C_SR_AL)) 222 break; 223 delay(10); 224 } 225 if (timo == 0) { 226 ociic_write(sc, I2C_CR, I2C_CR_STO); 227 return ETIMEDOUT; 228 } 229 230 if (stat & I2C_SR_AL) { 231 ociic_write(sc, I2C_CR, I2C_CR_STO); 232 return EIO; 233 } 234 if (ack && (stat & I2C_SR_RXNACK)) { 235 ociic_write(sc, I2C_CR, I2C_CR_STO); 236 return EIO; 237 } 238 239 return 0; 240 } 241 242 int 243 ociic_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmd, 244 size_t cmdlen, void *buf, size_t buflen, int flags) 245 { 246 struct ociic_softc *sc = cookie; 247 int error, i; 248 249 error = ociic_unbusy(sc); 250 if (error) 251 return error; 252 253 if (cmdlen > 0) { 254 ociic_write(sc, I2C_TXR, addr << 1); 255 ociic_write(sc, I2C_CR, I2C_CR_STA | I2C_CR_WR); 256 error = ociic_wait(sc, 1); 257 if (error) 258 return error; 259 260 for (i = 0; i < cmdlen; i++) { 261 ociic_write(sc, I2C_TXR, ((uint8_t *)cmd)[i]); 262 ociic_write(sc, I2C_CR, I2C_CR_WR); 263 error = ociic_wait(sc, 1); 264 if (error) 265 return error; 266 } 267 } 268 269 if (I2C_OP_READ_P(op)) { 270 ociic_write(sc, I2C_TXR, addr << 1 | 1); 271 ociic_write(sc, I2C_CR, I2C_CR_STA | I2C_CR_WR); 272 error = ociic_wait(sc, 1); 273 if (error) 274 return error; 275 276 for (i = 0; i < buflen; i++) { 277 ociic_write(sc, I2C_CR, I2C_CR_RD | 278 (i == (buflen - 1) ? I2C_CR_NACK : 0)); 279 error = ociic_wait(sc, 0); 280 if (error) 281 return error; 282 ((uint8_t *)buf)[i] = ociic_read(sc, I2C_RXR); 283 } 284 } else { 285 if (cmdlen == 0) { 286 ociic_write(sc, I2C_TXR, addr << 1); 287 ociic_write(sc, I2C_CR, I2C_CR_STA | I2C_CR_WR); 288 } 289 290 for (i = 0; i < buflen; i++) { 291 ociic_write(sc, I2C_TXR, ((uint8_t *)buf)[i]); 292 ociic_write(sc, I2C_CR, I2C_CR_WR); 293 error = ociic_wait(sc, 1); 294 if (error) 295 return error; 296 } 297 } 298 299 if (I2C_OP_STOP_P(op)) 300 ociic_write(sc, I2C_CR, I2C_CR_STO); 301 302 return 0; 303 } 304 305 void 306 ociic_bus_scan(struct device *self, struct i2cbus_attach_args *iba, void *arg) 307 { 308 int iba_node = *(int *)arg; 309 struct i2c_attach_args ia; 310 char name[32], status[32]; 311 uint32_t reg[1]; 312 int node; 313 314 for (node = OF_child(iba_node); node; node = OF_peer(node)) { 315 memset(name, 0, sizeof(name)); 316 memset(status, 0, sizeof(status)); 317 memset(reg, 0, sizeof(reg)); 318 319 if (OF_getprop(node, "compatible", name, sizeof(name)) == -1) 320 continue; 321 if (name[0] == '\0') 322 continue; 323 324 if (OF_getprop(node, "status", status, sizeof(status)) > 0 && 325 strcmp(status, "disabled") == 0) 326 continue; 327 328 if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg)) 329 continue; 330 331 memset(&ia, 0, sizeof(ia)); 332 ia.ia_tag = iba->iba_tag; 333 ia.ia_addr = bemtoh32(®[0]); 334 ia.ia_name = name; 335 ia.ia_cookie = &node; 336 config_found(self, &ia, iic_print); 337 } 338 } 339