1 /* $OpenBSD: imxiic.c,v 1.2 2024/04/14 03:26:25 jsg Exp $ */ 2 /* 3 * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se> 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/device.h> 20 #include <sys/kernel.h> 21 #include <sys/systm.h> 22 23 #include <machine/bus.h> 24 25 #include <dev/ic/imxiicvar.h> 26 27 /* registers */ 28 #define I2C_IADR 0x00 29 #define I2C_IFDR 0x01 30 #define I2C_I2CR 0x02 31 #define I2C_I2SR 0x03 32 #define I2C_I2DR 0x04 33 34 #define I2C_I2CR_RSTA (1 << 2) 35 #define I2C_I2CR_TXAK (1 << 3) 36 #define I2C_I2CR_MTX (1 << 4) 37 #define I2C_I2CR_MSTA (1 << 5) 38 #define I2C_I2CR_IIEN (1 << 6) 39 #define I2C_I2CR_IEN (1 << 7) 40 #define I2C_I2SR_RXAK (1 << 0) 41 #define I2C_I2SR_IIF (1 << 1) 42 #define I2C_I2SR_IAL (1 << 4) 43 #define I2C_I2SR_IBB (1 << 5) 44 45 void imxiic_enable(struct imxiic_softc *, int); 46 void imxiic_clear_iodone(struct imxiic_softc *); 47 void imxiic_setspeed(struct imxiic_softc *, u_int); 48 int imxiic_wait_state(struct imxiic_softc *, uint32_t, uint32_t); 49 int imxiic_read(struct imxiic_softc *, int, const void *, int, 50 void *, int); 51 int imxiic_write(struct imxiic_softc *, int, const void *, int, 52 const void *, int); 53 54 int imxiic_i2c_acquire_bus(void *, int); 55 void imxiic_i2c_release_bus(void *, int); 56 int imxiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t, 57 void *, size_t, int); 58 59 uint8_t imxiic_read_1(struct imxiic_softc *, int); 60 void imxiic_write_1(struct imxiic_softc *, int, uint8_t); 61 62 #define HREAD1(sc, reg) \ 63 imxiic_read_1((sc), (reg)) 64 #define HWRITE1(sc, reg, val) \ 65 imxiic_write_1((sc), (reg), (val)) 66 #define HSET1(sc, reg, bits) \ 67 HWRITE1((sc), (reg), HREAD1((sc), (reg)) | (bits)) 68 #define HCLR1(sc, reg, bits) \ 69 HWRITE1((sc), (reg), HREAD1((sc), (reg)) & ~(bits)) 70 71 struct cfdriver imxiic_cd = { 72 NULL, "imxiic", DV_DULL 73 }; 74 75 void 76 imxiic_enable(struct imxiic_softc *sc, int on) 77 { 78 /* 79 * VF610: write 1 to clear bits 80 * iMX21: write 0 to clear bits 81 */ 82 if (sc->sc_type == I2C_TYPE_VF610) 83 HWRITE1(sc, I2C_I2SR, I2C_I2SR_IAL | I2C_I2SR_IIF); 84 else 85 HWRITE1(sc, I2C_I2SR, 0); 86 87 /* VF610 inverts enable bit meaning */ 88 if (sc->sc_type == I2C_TYPE_VF610) 89 on = !on; 90 if (on) 91 HWRITE1(sc, I2C_I2CR, I2C_I2CR_IEN); 92 else 93 HWRITE1(sc, I2C_I2CR, 0); 94 } 95 96 void 97 imxiic_clear_iodone(struct imxiic_softc *sc) 98 { 99 /* 100 * VF610: write bit to clear bit 101 * iMX21: clear bit, keep rest 102 */ 103 if (sc->sc_type == I2C_TYPE_VF610) 104 HWRITE1(sc, I2C_I2SR, I2C_I2SR_IIF); 105 else 106 HCLR1(sc, I2C_I2SR, I2C_I2SR_IIF); 107 } 108 109 void 110 imxiic_setspeed(struct imxiic_softc *sc, u_int speed) 111 { 112 if (!sc->frequency) { 113 uint32_t div; 114 int i; 115 116 div = (sc->sc_clkrate + speed - 1) / speed; 117 if (div < sc->sc_clk_div[0].div) 118 i = 0; 119 else if (div > sc->sc_clk_div[sc->sc_clk_ndiv - 1].div) 120 i = sc->sc_clk_ndiv - 1; 121 else 122 for (i = 0; sc->sc_clk_div[i].div < div; i++) 123 ; 124 125 sc->frequency = sc->sc_clk_div[i].val; 126 } 127 128 HWRITE1(sc, I2C_IFDR, sc->frequency); 129 } 130 131 int 132 imxiic_wait_state(struct imxiic_softc *sc, uint32_t mask, uint32_t value) 133 { 134 uint32_t state; 135 int timeout; 136 for (timeout = 1000; timeout > 0; timeout--) { 137 if (((state = HREAD1(sc, I2C_I2SR)) & mask) == value) 138 return 0; 139 delay(10); 140 } 141 return ETIMEDOUT; 142 } 143 144 int 145 imxiic_read(struct imxiic_softc *sc, int addr, const void *cmd, int cmdlen, 146 void *data, int len) 147 { 148 int i; 149 150 if (cmdlen > 0) { 151 if (imxiic_write(sc, addr, cmd, cmdlen, NULL, 0)) 152 return (EIO); 153 154 HSET1(sc, I2C_I2CR, I2C_I2CR_RSTA); 155 delay(1); 156 if (imxiic_wait_state(sc, I2C_I2SR_IBB, I2C_I2SR_IBB)) 157 return (EIO); 158 } 159 160 imxiic_clear_iodone(sc); 161 HWRITE1(sc, I2C_I2DR, (addr << 1) | 1); 162 163 if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) 164 return (EIO); 165 imxiic_clear_iodone(sc); 166 if (HREAD1(sc, I2C_I2SR) & I2C_I2SR_RXAK) 167 return (EIO); 168 169 HCLR1(sc, I2C_I2CR, I2C_I2CR_MTX); 170 if (len - 1) 171 HCLR1(sc, I2C_I2CR, I2C_I2CR_TXAK); 172 173 /* dummy read */ 174 HREAD1(sc, I2C_I2DR); 175 176 for (i = 0; i < len; i++) { 177 if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) 178 return (EIO); 179 imxiic_clear_iodone(sc); 180 181 if (i == (len - 1)) { 182 HCLR1(sc, I2C_I2CR, I2C_I2CR_MSTA | I2C_I2CR_MTX); 183 imxiic_wait_state(sc, I2C_I2SR_IBB, 0); 184 sc->stopped = 1; 185 } else if (i == (len - 2)) { 186 HSET1(sc, I2C_I2CR, I2C_I2CR_TXAK); 187 } 188 ((uint8_t*)data)[i] = HREAD1(sc, I2C_I2DR); 189 } 190 191 return 0; 192 } 193 194 int 195 imxiic_write(struct imxiic_softc *sc, int addr, const void *cmd, int cmdlen, 196 const void *data, int len) 197 { 198 int i; 199 200 imxiic_clear_iodone(sc); 201 HWRITE1(sc, I2C_I2DR, addr << 1); 202 203 if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) 204 return (EIO); 205 imxiic_clear_iodone(sc); 206 if (HREAD1(sc, I2C_I2SR) & I2C_I2SR_RXAK) 207 return (EIO); 208 209 for (i = 0; i < cmdlen; i++) { 210 HWRITE1(sc, I2C_I2DR, ((uint8_t*)cmd)[i]); 211 if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) 212 return (EIO); 213 imxiic_clear_iodone(sc); 214 if (HREAD1(sc, I2C_I2SR) & I2C_I2SR_RXAK) 215 return (EIO); 216 } 217 218 for (i = 0; i < len; i++) { 219 HWRITE1(sc, I2C_I2DR, ((uint8_t*)data)[i]); 220 if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) 221 return (EIO); 222 imxiic_clear_iodone(sc); 223 if (HREAD1(sc, I2C_I2SR) & I2C_I2SR_RXAK) 224 return (EIO); 225 } 226 return 0; 227 } 228 229 int 230 imxiic_i2c_acquire_bus(void *cookie, int flags) 231 { 232 struct imxiic_softc *sc = cookie; 233 234 rw_enter(&sc->sc_buslock, RW_WRITE); 235 236 /* set speed */ 237 imxiic_setspeed(sc, sc->sc_bitrate); 238 239 /* enable the controller */ 240 imxiic_enable(sc, 1); 241 242 /* wait for it to be stable */ 243 delay(50); 244 245 return 0; 246 } 247 248 void 249 imxiic_i2c_release_bus(void *cookie, int flags) 250 { 251 struct imxiic_softc *sc = cookie; 252 253 imxiic_enable(sc, 0); 254 255 rw_exit(&sc->sc_buslock); 256 } 257 258 int 259 imxiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, 260 const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) 261 { 262 struct imxiic_softc *sc = cookie; 263 int ret = 0; 264 265 if (!I2C_OP_STOP_P(op)) 266 return EINVAL; 267 268 /* start transaction */ 269 HSET1(sc, I2C_I2CR, I2C_I2CR_MSTA); 270 271 if (imxiic_wait_state(sc, I2C_I2SR_IBB, I2C_I2SR_IBB)) { 272 ret = EIO; 273 goto fail; 274 } 275 276 sc->stopped = 0; 277 278 HSET1(sc, I2C_I2CR, I2C_I2CR_IIEN | I2C_I2CR_MTX | I2C_I2CR_TXAK); 279 280 if (I2C_OP_READ_P(op)) { 281 ret = imxiic_read(sc, addr, cmdbuf, cmdlen, buf, len); 282 } else { 283 ret = imxiic_write(sc, addr, cmdbuf, cmdlen, buf, len); 284 } 285 286 fail: 287 if (!sc->stopped) { 288 HCLR1(sc, I2C_I2CR, I2C_I2CR_MSTA | I2C_I2CR_MTX); 289 imxiic_wait_state(sc, I2C_I2SR_IBB, 0); 290 sc->stopped = 1; 291 } 292 293 return ret; 294 } 295 296 uint8_t 297 imxiic_read_1(struct imxiic_softc *sc, int reg) 298 { 299 reg <<= sc->sc_reg_shift; 300 301 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, reg); 302 } 303 304 void 305 imxiic_write_1(struct imxiic_softc *sc, int reg, uint8_t val) 306 { 307 reg <<= sc->sc_reg_shift; 308 309 bus_space_write_1(sc->sc_iot, sc->sc_ioh, reg, val); 310 } 311