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 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 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 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 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 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 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 184 ociic_acquire_bus(void *cookie, int flags) 185 { 186 return 0; 187 } 188 189 void 190 ociic_release_bus(void *cookie, int flags) 191 { 192 } 193 194 int 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 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 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 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