1 /* $NetBSD: pcf8584.c,v 1.12 2015/12/16 08:04:58 jdc Exp $ */ 2 /* $OpenBSD: pcf8584.c,v 1.9 2007/10/20 18:46:21 kettenis Exp $ */ 3 4 /* 5 * Copyright (c) 2006 David Gwynne <dlg@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/systm.h> 22 #include <sys/device.h> 23 #include <sys/malloc.h> 24 #include <sys/kernel.h> 25 #include <sys/rwlock.h> 26 #include <sys/proc.h> 27 #include <sys/bus.h> 28 29 #include <dev/i2c/i2cvar.h> 30 31 #include <dev/ic/pcf8584var.h> 32 33 #define PCF_S0 0x00 34 #define PCF_S1 0x01 35 #define PCF_S2 0x02 36 #define PCF_S3 0x03 37 38 #define PCF_CTRL_ACK (1<<0) 39 #define PCF_CTRL_STO (1<<1) 40 #define PCF_CTRL_STA (1<<2) 41 #define PCF_CTRL_ENI (1<<3) 42 #define PCF_CTRL_ES2 (1<<4) 43 #define PCF_CTRL_ES1 (1<<5) 44 #define PCF_CTRL_ESO (1<<6) 45 #define PCF_CTRL_PIN (1<<7) 46 47 #define PCF_CTRL_START (PCF_CTRL_PIN | PCF_CTRL_ESO | \ 48 PCF_CTRL_STA | PCF_CTRL_ACK) 49 #define PCF_CTRL_STOP (PCF_CTRL_PIN | PCF_CTRL_ESO | \ 50 PCF_CTRL_STO | PCF_CTRL_ACK) 51 #define PCF_CTRL_REPSTART (PCF_CTRL_ESO | PCF_CTRL_STA | PCF_CTRL_ACK) 52 #define PCF_CTRL_IDLE (PCF_CTRL_PIN | PCF_CTRL_ESO | PCF_CTRL_ACK) 53 54 #define PCF_STAT_nBB (1<<0) 55 #define PCF_STAT_LAB (1<<1) 56 #define PCF_STAT_AAS (1<<2) 57 #define PCF_STAT_AD0 (1<<3) 58 #define PCF_STAT_LRB (1<<3) 59 #define PCF_STAT_BER (1<<4) 60 #define PCF_STAT_STS (1<<5) 61 #define PCF_STAT_PIN (1<<7) 62 63 void pcfiic_init(struct pcfiic_softc *); 64 int pcfiic_i2c_acquire_bus(void *, int); 65 void pcfiic_i2c_release_bus(void *, int); 66 int pcfiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, 67 size_t, void *, size_t, int); 68 69 int pcfiic_xmit(struct pcfiic_softc *, u_int8_t, const u_int8_t *, 70 size_t); 71 int pcfiic_recv(struct pcfiic_softc *, u_int8_t, u_int8_t *, 72 size_t); 73 74 u_int8_t pcfiic_read(struct pcfiic_softc *, bus_size_t); 75 void pcfiic_write(struct pcfiic_softc *, bus_size_t, u_int8_t); 76 void pcfiic_choose_bus(struct pcfiic_softc *, u_int8_t); 77 int pcfiic_wait_nBB(struct pcfiic_softc *); 78 int pcfiic_wait_pin(struct pcfiic_softc *, volatile u_int8_t *); 79 80 void 81 pcfiic_init(struct pcfiic_softc *sc) 82 { 83 /* init S1 */ 84 pcfiic_write(sc, PCF_S1, PCF_CTRL_PIN); 85 /* own address */ 86 pcfiic_write(sc, PCF_S0, sc->sc_addr); 87 88 /* select clock reg */ 89 pcfiic_write(sc, PCF_S1, PCF_CTRL_PIN|PCF_CTRL_ES1); 90 pcfiic_write(sc, PCF_S0, sc->sc_clock); 91 92 pcfiic_write(sc, PCF_S1, PCF_CTRL_IDLE); 93 94 delay(200000); /* Multi-Master mode, wait for longest i2c message */ 95 } 96 97 void 98 pcfiic_attach(struct pcfiic_softc *sc, i2c_addr_t addr, u_int8_t clock, 99 int swapregs) 100 { 101 struct i2cbus_attach_args iba; 102 103 if (swapregs) { 104 sc->sc_regmap[PCF_S1] = PCF_S0; 105 sc->sc_regmap[PCF_S0] = PCF_S1; 106 } else { 107 sc->sc_regmap[PCF_S0] = PCF_S0; 108 sc->sc_regmap[PCF_S1] = PCF_S1; 109 } 110 sc->sc_clock = clock; 111 sc->sc_addr = addr; 112 113 pcfiic_init(sc); 114 115 printf("\n"); 116 117 if (sc->sc_master) 118 pcfiic_choose_bus(sc, 0); 119 120 rw_init(&sc->sc_lock); 121 sc->sc_i2c.ic_cookie = sc; 122 sc->sc_i2c.ic_acquire_bus = pcfiic_i2c_acquire_bus; 123 sc->sc_i2c.ic_release_bus = pcfiic_i2c_release_bus; 124 sc->sc_i2c.ic_exec = pcfiic_i2c_exec; 125 126 bzero(&iba, sizeof(iba)); 127 iba.iba_tag = &sc->sc_i2c; 128 config_found(sc->sc_dev, &iba, iicbus_print); 129 } 130 131 int 132 pcfiic_intr(void *arg) 133 { 134 return (0); 135 } 136 137 int 138 pcfiic_i2c_acquire_bus(void *arg, int flags) 139 { 140 struct pcfiic_softc *sc = arg; 141 142 if (cold || sc->sc_poll || (flags & I2C_F_POLL)) 143 return (0); 144 145 rw_enter(&sc->sc_lock, RW_WRITER); 146 return 0; 147 } 148 149 void 150 pcfiic_i2c_release_bus(void *arg, int flags) 151 { 152 struct pcfiic_softc *sc = arg; 153 154 if (cold || sc->sc_poll || (flags & I2C_F_POLL)) 155 return; 156 157 rw_exit(&sc->sc_lock); 158 } 159 160 int 161 pcfiic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr, 162 const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) 163 { 164 struct pcfiic_softc *sc = arg; 165 int ret = 0; 166 167 #if 0 168 printf("%s: exec op: %d addr: 0x%x cmdlen: %d len: %d flags 0x%x\n", 169 device_xname(sc->sc_dev), op, addr, (int)cmdlen, (int)len, flags); 170 #endif 171 172 if (cold || sc->sc_poll) 173 flags |= I2C_F_POLL; 174 175 if (sc->sc_master) 176 pcfiic_choose_bus(sc, addr >> 7); 177 178 /* 179 * If we are writing, write address, cmdbuf, buf. 180 * If we are reading, write address, cmdbuf, then read address, buf. 181 */ 182 if (I2C_OP_WRITE_P(op)) { 183 if (len > 0) { 184 uint8_t *tmp; 185 186 tmp = malloc(cmdlen + len, M_DEVBUF, 187 flags & I2C_F_POLL ? M_NOWAIT : M_WAITOK); 188 if (tmp == NULL) 189 return (1); 190 memcpy(tmp, cmdbuf, cmdlen); 191 memcpy(tmp + cmdlen, buf, len); 192 ret = pcfiic_xmit(sc, addr & 0x7f, tmp, cmdlen + len); 193 free(tmp, M_DEVBUF); 194 } else 195 ret = pcfiic_xmit(sc, addr & 0x7f, cmdbuf, cmdlen); 196 } else { 197 if (pcfiic_xmit(sc, addr & 0x7f, cmdbuf, cmdlen) != 0) 198 return (1); 199 ret = pcfiic_recv(sc, addr & 0x7f, buf, len); 200 } 201 return (ret); 202 } 203 204 int 205 pcfiic_xmit(struct pcfiic_softc *sc, u_int8_t addr, const u_int8_t *buf, 206 size_t len) 207 { 208 int i, err = 0; 209 volatile u_int8_t r; 210 211 if (pcfiic_wait_nBB(sc) != 0) 212 return (1); 213 214 pcfiic_write(sc, PCF_S0, addr << 1); 215 pcfiic_write(sc, PCF_S1, PCF_CTRL_START); 216 217 for (i = 0; i <= len; i++) { 218 if (pcfiic_wait_pin(sc, &r) != 0) { 219 pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP); 220 return (1); 221 } 222 223 if (r & PCF_STAT_LRB) { 224 err = 1; 225 break; 226 } 227 228 if (i < len) 229 pcfiic_write(sc, PCF_S0, buf[i]); 230 } 231 pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP); 232 return (err); 233 } 234 235 int 236 pcfiic_recv(struct pcfiic_softc *sc, u_int8_t addr, u_int8_t *buf, size_t len) 237 { 238 int i = 0, err = 0; 239 volatile u_int8_t r; 240 241 if (pcfiic_wait_nBB(sc) != 0) 242 return (1); 243 244 pcfiic_write(sc, PCF_S0, (addr << 1) | 0x01); 245 pcfiic_write(sc, PCF_S1, PCF_CTRL_START); 246 247 for (i = 0; i <= len; i++) { 248 if (pcfiic_wait_pin(sc, &r) != 0) { 249 pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP); 250 return (1); 251 } 252 253 if ((i != len) && (r & PCF_STAT_LRB)) { 254 pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP); 255 return (1); 256 } 257 258 if (i == len - 1) { 259 pcfiic_write(sc, PCF_S1, PCF_CTRL_ESO); 260 } else if (i == len) { 261 pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP); 262 } 263 264 r = pcfiic_read(sc, PCF_S0); 265 if (i > 0) 266 buf[i - 1] = r; 267 } 268 return (err); 269 } 270 271 u_int8_t 272 pcfiic_read(struct pcfiic_softc *sc, bus_size_t r) 273 { 274 bus_space_barrier(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], 1, 275 BUS_SPACE_BARRIER_READ); 276 return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r])); 277 } 278 279 void 280 pcfiic_write(struct pcfiic_softc *sc, bus_size_t r, u_int8_t v) 281 { 282 bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], v); 283 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, PCF_S1); 284 } 285 286 void 287 pcfiic_choose_bus(struct pcfiic_softc *sc, u_int8_t bus) 288 { 289 bus_space_write_1(sc->sc_iot, sc->sc_ioh2, 0, bus); 290 bus_space_barrier(sc->sc_iot, sc->sc_ioh2, 0, 1, 291 BUS_SPACE_BARRIER_WRITE); 292 } 293 294 int 295 pcfiic_wait_nBB(struct pcfiic_softc *sc) 296 { 297 int i; 298 299 for (i = 0; i < 1000; i++) { 300 if (pcfiic_read(sc, PCF_S1) & PCF_STAT_nBB) 301 return (0); 302 delay(1000); 303 } 304 return (1); 305 } 306 307 int 308 pcfiic_wait_pin(struct pcfiic_softc *sc, volatile u_int8_t *r) 309 { 310 int i; 311 312 for (i = 0; i < 1000; i++) { 313 *r = pcfiic_read(sc, PCF_S1); 314 if ((*r & PCF_STAT_PIN) == 0) 315 return (0); 316 delay(1000); 317 } 318 return (1); 319 } 320