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