1 /* $OpenBSD: imxiic.c,v 1.1 2020/11/17 14:30:13 patrick 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 sc->frequency = sc->sc_clk_div[i].val; 125 } 126 127 HWRITE1(sc, I2C_IFDR, sc->frequency); 128 } 129 130 int 131 imxiic_wait_state(struct imxiic_softc *sc, uint32_t mask, uint32_t value) 132 { 133 uint32_t state; 134 int timeout; 135 for (timeout = 1000; timeout > 0; timeout--) { 136 if (((state = HREAD1(sc, I2C_I2SR)) & mask) == value) 137 return 0; 138 delay(10); 139 } 140 return ETIMEDOUT; 141 } 142 143 int 144 imxiic_read(struct imxiic_softc *sc, int addr, const void *cmd, int cmdlen, 145 void *data, int len) 146 { 147 int i; 148 149 if (cmdlen > 0) { 150 if (imxiic_write(sc, addr, cmd, cmdlen, NULL, 0)) 151 return (EIO); 152 153 HSET1(sc, I2C_I2CR, I2C_I2CR_RSTA); 154 delay(1); 155 if (imxiic_wait_state(sc, I2C_I2SR_IBB, I2C_I2SR_IBB)) 156 return (EIO); 157 } 158 159 imxiic_clear_iodone(sc); 160 HWRITE1(sc, I2C_I2DR, (addr << 1) | 1); 161 162 if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) 163 return (EIO); 164 imxiic_clear_iodone(sc); 165 if (HREAD1(sc, I2C_I2SR) & I2C_I2SR_RXAK) 166 return (EIO); 167 168 HCLR1(sc, I2C_I2CR, I2C_I2CR_MTX); 169 if (len - 1) 170 HCLR1(sc, I2C_I2CR, I2C_I2CR_TXAK); 171 172 /* dummy read */ 173 HREAD1(sc, I2C_I2DR); 174 175 for (i = 0; i < len; i++) { 176 if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) 177 return (EIO); 178 imxiic_clear_iodone(sc); 179 180 if (i == (len - 1)) { 181 HCLR1(sc, I2C_I2CR, I2C_I2CR_MSTA | I2C_I2CR_MTX); 182 imxiic_wait_state(sc, I2C_I2SR_IBB, 0); 183 sc->stopped = 1; 184 } else if (i == (len - 2)) { 185 HSET1(sc, I2C_I2CR, I2C_I2CR_TXAK); 186 } 187 ((uint8_t*)data)[i] = HREAD1(sc, I2C_I2DR); 188 } 189 190 return 0; 191 } 192 193 int 194 imxiic_write(struct imxiic_softc *sc, int addr, const void *cmd, int cmdlen, 195 const void *data, int len) 196 { 197 int i; 198 199 imxiic_clear_iodone(sc); 200 HWRITE1(sc, I2C_I2DR, addr << 1); 201 202 if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) 203 return (EIO); 204 imxiic_clear_iodone(sc); 205 if (HREAD1(sc, I2C_I2SR) & I2C_I2SR_RXAK) 206 return (EIO); 207 208 for (i = 0; i < cmdlen; i++) { 209 HWRITE1(sc, I2C_I2DR, ((uint8_t*)cmd)[i]); 210 if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) 211 return (EIO); 212 imxiic_clear_iodone(sc); 213 if (HREAD1(sc, I2C_I2SR) & I2C_I2SR_RXAK) 214 return (EIO); 215 } 216 217 for (i = 0; i < len; i++) { 218 HWRITE1(sc, I2C_I2DR, ((uint8_t*)data)[i]); 219 if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) 220 return (EIO); 221 imxiic_clear_iodone(sc); 222 if (HREAD1(sc, I2C_I2SR) & I2C_I2SR_RXAK) 223 return (EIO); 224 } 225 return 0; 226 } 227 228 int 229 imxiic_i2c_acquire_bus(void *cookie, int flags) 230 { 231 struct imxiic_softc *sc = cookie; 232 233 rw_enter(&sc->sc_buslock, RW_WRITE); 234 235 /* set speed */ 236 imxiic_setspeed(sc, sc->sc_bitrate); 237 238 /* enable the controller */ 239 imxiic_enable(sc, 1); 240 241 /* wait for it to be stable */ 242 delay(50); 243 244 return 0; 245 } 246 247 void 248 imxiic_i2c_release_bus(void *cookie, int flags) 249 { 250 struct imxiic_softc *sc = cookie; 251 252 imxiic_enable(sc, 0); 253 254 rw_exit(&sc->sc_buslock); 255 } 256 257 int 258 imxiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, 259 const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) 260 { 261 struct imxiic_softc *sc = cookie; 262 int ret = 0; 263 264 if (!I2C_OP_STOP_P(op)) 265 return EINVAL; 266 267 /* start transaction */ 268 HSET1(sc, I2C_I2CR, I2C_I2CR_MSTA); 269 270 if (imxiic_wait_state(sc, I2C_I2SR_IBB, I2C_I2SR_IBB)) { 271 ret = EIO; 272 goto fail; 273 } 274 275 sc->stopped = 0; 276 277 HSET1(sc, I2C_I2CR, I2C_I2CR_IIEN | I2C_I2CR_MTX | I2C_I2CR_TXAK); 278 279 if (I2C_OP_READ_P(op)) { 280 ret = imxiic_read(sc, addr, cmdbuf, cmdlen, buf, len); 281 } else { 282 ret = imxiic_write(sc, addr, cmdbuf, cmdlen, buf, len); 283 } 284 285 fail: 286 if (!sc->stopped) { 287 HCLR1(sc, I2C_I2CR, I2C_I2CR_MSTA | I2C_I2CR_MTX); 288 imxiic_wait_state(sc, I2C_I2SR_IBB, 0); 289 sc->stopped = 1; 290 } 291 292 return ret; 293 } 294 295 uint8_t 296 imxiic_read_1(struct imxiic_softc *sc, int reg) 297 { 298 reg <<= sc->sc_reg_shift; 299 300 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, reg); 301 } 302 303 void 304 imxiic_write_1(struct imxiic_softc *sc, int reg, uint8_t val) 305 { 306 reg <<= sc->sc_reg_shift; 307 308 bus_space_write_1(sc->sc_iot, sc->sc_ioh, reg, val); 309 } 310