1*890573d8Smk /* $OpenBSD: gscsio.c,v 1.12 2010/02/16 00:05:23 mk Exp $ */ 2d1b1be5aSgrange /* 3d1b1be5aSgrange * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org> 4d1b1be5aSgrange * 5d1b1be5aSgrange * Permission to use, copy, modify, and distribute this software for any 6d1b1be5aSgrange * purpose with or without fee is hereby granted, provided that the above 7d1b1be5aSgrange * copyright notice and this permission notice appear in all copies. 8d1b1be5aSgrange * 9d1b1be5aSgrange * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10d1b1be5aSgrange * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11d1b1be5aSgrange * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12d1b1be5aSgrange * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13d1b1be5aSgrange * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14d1b1be5aSgrange * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15d1b1be5aSgrange * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16d1b1be5aSgrange */ 17d1b1be5aSgrange 18d1b1be5aSgrange /* 19d1b1be5aSgrange * National Semiconductor Geode SC1100 Super I/O. 20d1b1be5aSgrange * Only ACCESS.bus logical device is supported. 21d1b1be5aSgrange */ 22d1b1be5aSgrange 23d1b1be5aSgrange #include <sys/param.h> 24d1b1be5aSgrange #include <sys/systm.h> 25d1b1be5aSgrange #include <sys/device.h> 26d1b1be5aSgrange #include <sys/kernel.h> 273e55d5feSjsg #include <sys/rwlock.h> 28d1b1be5aSgrange #include <sys/proc.h> 29d1b1be5aSgrange 30d1b1be5aSgrange #include <machine/bus.h> 31d1b1be5aSgrange 32d1b1be5aSgrange #include <dev/i2c/i2cvar.h> 33d1b1be5aSgrange 34d1b1be5aSgrange #include <dev/isa/isareg.h> 35d1b1be5aSgrange #include <dev/isa/isavar.h> 36d1b1be5aSgrange 37d1b1be5aSgrange #include <dev/isa/gscsioreg.h> 38d1b1be5aSgrange 39d1b1be5aSgrange struct gscsio_softc { 40d1b1be5aSgrange struct device sc_dev; 41d1b1be5aSgrange 42d1b1be5aSgrange bus_space_tag_t sc_iot; 43d1b1be5aSgrange bus_space_handle_t sc_ioh; 44d1b1be5aSgrange 45450b0ab0Sgrange int sc_ld_en[GSCSIO_LDN_LAST + 1]; 46450b0ab0Sgrange bus_space_handle_t sc_ld_ioh0[GSCSIO_LDN_LAST + 1]; 47450b0ab0Sgrange bus_space_handle_t sc_ld_ioh1[GSCSIO_LDN_LAST + 1]; 48d1b1be5aSgrange 49d1b1be5aSgrange /* ACCESS.bus */ 50d1b1be5aSgrange struct gscsio_acb { 51d1b1be5aSgrange void *sc; 52d1b1be5aSgrange bus_space_handle_t ioh; 533e55d5feSjsg struct rwlock buslock; 54d1b1be5aSgrange } sc_acb[2]; 55d1b1be5aSgrange struct i2c_controller sc_acb1_tag; 56d1b1be5aSgrange struct i2c_controller sc_acb2_tag; 57d1b1be5aSgrange }; 58d1b1be5aSgrange 59d1b1be5aSgrange /* Supported logical devices description */ 60d1b1be5aSgrange static const struct { 61d1b1be5aSgrange const char *ld_name; 62d1b1be5aSgrange int ld_num; 63d1b1be5aSgrange int ld_iosize0; 64d1b1be5aSgrange int ld_iosize1; 65d1b1be5aSgrange } gscsio_ld[] = { 66d1b1be5aSgrange { "ACB1", GSCSIO_LDN_ACB1, 6, 0 }, 67d1b1be5aSgrange { "ACB2", GSCSIO_LDN_ACB2, 6, 0 }, 68d1b1be5aSgrange }; 69d1b1be5aSgrange 70d1b1be5aSgrange int gscsio_probe(struct device *, void *, void *); 71d1b1be5aSgrange void gscsio_attach(struct device *, struct device *, void *); 72d1b1be5aSgrange 73d1b1be5aSgrange void gscsio_acb_init(struct gscsio_acb *, i2c_tag_t); 74d1b1be5aSgrange int gscsio_acb_wait(struct gscsio_acb *, int, int); 75d1b1be5aSgrange void gscsio_acb_reset(struct gscsio_acb *acb); 76d1b1be5aSgrange 77d1b1be5aSgrange int gscsio_acb_acquire_bus(void *, int); 78d1b1be5aSgrange void gscsio_acb_release_bus(void *, int); 79d1b1be5aSgrange int gscsio_acb_send_start(void *, int); 80d1b1be5aSgrange int gscsio_acb_send_stop(void *, int); 81*890573d8Smk int gscsio_acb_initiate_xfer(void *, i2c_addr_t, int); 82d1b1be5aSgrange int gscsio_acb_read_byte(void *, uint8_t *, int); 83d1b1be5aSgrange int gscsio_acb_write_byte(void *, uint8_t, int); 84d1b1be5aSgrange 85d1b1be5aSgrange struct cfattach gscsio_ca = { 86d1b1be5aSgrange sizeof(struct gscsio_softc), 87d1b1be5aSgrange gscsio_probe, 88d1b1be5aSgrange gscsio_attach 89d1b1be5aSgrange }; 90d1b1be5aSgrange 91d1b1be5aSgrange struct cfdriver gscsio_cd = { 92d1b1be5aSgrange NULL, "gscsio", DV_DULL 93d1b1be5aSgrange }; 94d1b1be5aSgrange 95d1b1be5aSgrange #define ACB_READ(reg) \ 96d1b1be5aSgrange bus_space_read_1(sc->sc_iot, acb->ioh, (reg)) 97d1b1be5aSgrange #define ACB_WRITE(reg, val) \ 98d1b1be5aSgrange bus_space_write_1(sc->sc_iot, acb->ioh, (reg), (val)) 99d1b1be5aSgrange 100d1b1be5aSgrange static __inline u_int8_t 101d1b1be5aSgrange idxread(bus_space_tag_t iot, bus_space_handle_t ioh, int idx) 102d1b1be5aSgrange { 103d1b1be5aSgrange bus_space_write_1(iot, ioh, GSCSIO_IDX, idx); 104d1b1be5aSgrange 105d1b1be5aSgrange return (bus_space_read_1(iot, ioh, GSCSIO_DAT)); 106d1b1be5aSgrange } 107d1b1be5aSgrange 108d1b1be5aSgrange static __inline void 109d1b1be5aSgrange idxwrite(bus_space_tag_t iot, bus_space_handle_t ioh, int idx, u_int8_t data) 110d1b1be5aSgrange { 111d1b1be5aSgrange bus_space_write_1(iot, ioh, GSCSIO_IDX, idx); 112d1b1be5aSgrange bus_space_write_1(iot, ioh, GSCSIO_DAT, data); 113d1b1be5aSgrange } 114d1b1be5aSgrange 1150c86ea5fSmickey int 1160c86ea5fSmickey gscsio_probe(struct device *parent, void *match, void *aux) 117d1b1be5aSgrange { 1180c86ea5fSmickey struct isa_attach_args *ia = aux; 1190c86ea5fSmickey bus_space_tag_t iot; 120d1b1be5aSgrange bus_space_handle_t ioh; 1210c86ea5fSmickey int iobase; 122d1b1be5aSgrange int rv = 0; 123d1b1be5aSgrange 1240c86ea5fSmickey iot = ia->ia_iot; 1250c86ea5fSmickey iobase = ia->ipa_io[0].base; 1260c86ea5fSmickey if (bus_space_map(iot, iobase, GSCSIO_IOSIZE, 0, &ioh)) 127d1b1be5aSgrange return (0); 128d1b1be5aSgrange if (idxread(iot, ioh, GSCSIO_ID) == GSCSIO_ID_SC1100) 129d1b1be5aSgrange rv = 1; 130d1b1be5aSgrange bus_space_unmap(iot, ioh, GSCSIO_IOSIZE); 131d1b1be5aSgrange 1320c86ea5fSmickey if (rv) { 133d1b1be5aSgrange ia->ipa_nio = 1; 134d1b1be5aSgrange ia->ipa_io[0].length = GSCSIO_IOSIZE; 135d1b1be5aSgrange ia->ipa_nmem = 0; 136d1b1be5aSgrange ia->ipa_nirq = 0; 137d1b1be5aSgrange ia->ipa_ndrq = 0; 1380c86ea5fSmickey } 139d1b1be5aSgrange 1400c86ea5fSmickey return (rv); 141d1b1be5aSgrange } 142d1b1be5aSgrange 143d1b1be5aSgrange void 144d1b1be5aSgrange gscsio_attach(struct device *parent, struct device *self, void *aux) 145d1b1be5aSgrange { 146d1b1be5aSgrange struct gscsio_softc *sc = (void *)self; 147d1b1be5aSgrange struct isa_attach_args *ia = aux; 148d1b1be5aSgrange int i; 149d1b1be5aSgrange int iobase; 150d1b1be5aSgrange 151d1b1be5aSgrange sc->sc_iot = ia->ia_iot; 152d1b1be5aSgrange if (bus_space_map(sc->sc_iot, ia->ipa_io[0].base, GSCSIO_IOSIZE, 153d1b1be5aSgrange 0, &sc->sc_ioh)) { 154e10c952fSsthen printf(": can't map i/o space\n"); 155d1b1be5aSgrange return; 156d1b1be5aSgrange } 157d1b1be5aSgrange printf(": SC1100 SIO rev %d:", 158d1b1be5aSgrange idxread(sc->sc_iot, sc->sc_ioh, GSCSIO_REV)); 159d1b1be5aSgrange 160d1b1be5aSgrange /* Configure all supported logical devices */ 161d1b1be5aSgrange for (i = 0; i < sizeof (gscsio_ld) / sizeof(gscsio_ld[0]); i++) { 162d1b1be5aSgrange sc->sc_ld_en[gscsio_ld[i].ld_num] = 0; 163d1b1be5aSgrange 164d1b1be5aSgrange /* Select the device and check if it's activated */ 165d1b1be5aSgrange idxwrite(sc->sc_iot, sc->sc_ioh, GSCSIO_LDN, 166d1b1be5aSgrange gscsio_ld[i].ld_num); 167d1b1be5aSgrange if ((idxread(sc->sc_iot, sc->sc_ioh, GSCSIO_ACT) & 168d1b1be5aSgrange GSCSIO_ACT_EN) == 0) 169d1b1be5aSgrange continue; 170d1b1be5aSgrange 171d1b1be5aSgrange /* Map I/O space 0 if necessary */ 172d1b1be5aSgrange if (gscsio_ld[i].ld_iosize0 != 0) { 173d1b1be5aSgrange iobase = idxread(sc->sc_iot, sc->sc_ioh, 174d1b1be5aSgrange GSCSIO_IO0_MSB); 175d1b1be5aSgrange iobase <<= 8; 176d1b1be5aSgrange iobase |= idxread(sc->sc_iot, sc->sc_ioh, 177d1b1be5aSgrange GSCSIO_IO0_LSB); 178d1b1be5aSgrange if (bus_space_map(sc->sc_iot, iobase, 179d1b1be5aSgrange gscsio_ld[i].ld_iosize0, 0, 180d1b1be5aSgrange &sc->sc_ld_ioh0[gscsio_ld[i].ld_num])) 181d1b1be5aSgrange continue; 182d1b1be5aSgrange } 183d1b1be5aSgrange 184d1b1be5aSgrange /* Map I/O space 1 if necessary */ 185d1b1be5aSgrange if (gscsio_ld[i].ld_iosize1 != 0) { 186d1b1be5aSgrange iobase = idxread(sc->sc_iot, sc->sc_ioh, 187d1b1be5aSgrange GSCSIO_IO1_MSB); 188d1b1be5aSgrange iobase <<= 8; 189d1b1be5aSgrange iobase |= idxread(sc->sc_iot, sc->sc_ioh, 190d1b1be5aSgrange GSCSIO_IO1_LSB); 191d1b1be5aSgrange if (bus_space_map(sc->sc_iot, iobase, 192d1b1be5aSgrange gscsio_ld[i].ld_iosize1, 0, 193d1b1be5aSgrange &sc->sc_ld_ioh0[gscsio_ld[i].ld_num])) { 194d1b1be5aSgrange bus_space_unmap(sc->sc_iot, 195d1b1be5aSgrange sc->sc_ld_ioh0[gscsio_ld[i].ld_num], 196d1b1be5aSgrange gscsio_ld[i].ld_iosize0); 197d1b1be5aSgrange continue; 198d1b1be5aSgrange } 199d1b1be5aSgrange } 200d1b1be5aSgrange 201d1b1be5aSgrange sc->sc_ld_en[gscsio_ld[i].ld_num] = 1; 202d1b1be5aSgrange printf(" %s", gscsio_ld[i].ld_name); 203d1b1be5aSgrange } 204d1b1be5aSgrange printf("\n"); 205d1b1be5aSgrange 206d1b1be5aSgrange /* Initialize ACCESS.bus 1 */ 207d1b1be5aSgrange if (sc->sc_ld_en[GSCSIO_LDN_ACB1]) { 208d1b1be5aSgrange sc->sc_acb[0].sc = sc; 209d1b1be5aSgrange sc->sc_acb[0].ioh = sc->sc_ld_ioh0[GSCSIO_LDN_ACB1]; 2103e55d5feSjsg rw_init(&sc->sc_acb[0].buslock, "iiclk"); 211d1b1be5aSgrange gscsio_acb_init(&sc->sc_acb[0], &sc->sc_acb1_tag); 212d1b1be5aSgrange } 213d1b1be5aSgrange 214d1b1be5aSgrange /* Initialize ACCESS.bus 2 */ 215d1b1be5aSgrange if (sc->sc_ld_en[GSCSIO_LDN_ACB2]) { 216d1b1be5aSgrange sc->sc_acb[1].sc = sc; 217d1b1be5aSgrange sc->sc_acb[1].ioh = sc->sc_ld_ioh0[GSCSIO_LDN_ACB2]; 2183e55d5feSjsg rw_init(&sc->sc_acb[1].buslock, "iiclk"); 219d1b1be5aSgrange gscsio_acb_init(&sc->sc_acb[1], &sc->sc_acb2_tag); 220d1b1be5aSgrange } 221d1b1be5aSgrange } 222d1b1be5aSgrange 223d1b1be5aSgrange void 224d1b1be5aSgrange gscsio_acb_init(struct gscsio_acb *acb, i2c_tag_t tag) 225d1b1be5aSgrange { 226d1b1be5aSgrange struct gscsio_softc *sc = acb->sc; 227d1b1be5aSgrange struct i2cbus_attach_args iba; 228d1b1be5aSgrange 229d1b1be5aSgrange /* Enable ACB and configure clock frequency */ 230d1b1be5aSgrange ACB_WRITE(GSCSIO_ACB_CTL2, GSCSIO_ACB_CTL2_EN | 231d1b1be5aSgrange (GSCSIO_ACB_FREQ << GSCSIO_ACB_CTL2_FREQ_SHIFT)); 232d1b1be5aSgrange 233d1b1be5aSgrange /* Select polling mode */ 234d1b1be5aSgrange ACB_WRITE(GSCSIO_ACB_CTL1, ACB_READ(GSCSIO_ACB_CTL1) & 235d1b1be5aSgrange ~GSCSIO_ACB_CTL1_INTEN); 236d1b1be5aSgrange 237d1b1be5aSgrange /* Disable slave address */ 238d1b1be5aSgrange ACB_WRITE(GSCSIO_ACB_ADDR, ACB_READ(GSCSIO_ACB_ADDR) & 239d1b1be5aSgrange ~GSCSIO_ACB_ADDR_SAEN); 240d1b1be5aSgrange 241d1b1be5aSgrange /* Attach I2C framework */ 242d1b1be5aSgrange tag->ic_cookie = acb; 243d1b1be5aSgrange tag->ic_acquire_bus = gscsio_acb_acquire_bus; 244d1b1be5aSgrange tag->ic_release_bus = gscsio_acb_release_bus; 245d1b1be5aSgrange tag->ic_send_start = gscsio_acb_send_start; 246d1b1be5aSgrange tag->ic_send_stop = gscsio_acb_send_stop; 247d1b1be5aSgrange tag->ic_initiate_xfer = gscsio_acb_initiate_xfer; 248d1b1be5aSgrange tag->ic_read_byte = gscsio_acb_read_byte; 249d1b1be5aSgrange tag->ic_write_byte = gscsio_acb_write_byte; 250d1b1be5aSgrange 251f57d9f10Sgrange bzero(&iba, sizeof(iba)); 252d1b1be5aSgrange iba.iba_name = "iic"; 253d1b1be5aSgrange iba.iba_tag = tag; 254d1b1be5aSgrange config_found(&sc->sc_dev, &iba, iicbus_print); 255d1b1be5aSgrange } 256d1b1be5aSgrange 257d1b1be5aSgrange int 258d1b1be5aSgrange gscsio_acb_wait(struct gscsio_acb *acb, int bits, int flags) 259d1b1be5aSgrange { 260d1b1be5aSgrange struct gscsio_softc *sc = acb->sc; 261d1b1be5aSgrange u_int8_t st; 262d1b1be5aSgrange int i; 263d1b1be5aSgrange 264d1b1be5aSgrange for (i = 0; i < 100; i++) { 265d1b1be5aSgrange st = ACB_READ(GSCSIO_ACB_ST); 266d1b1be5aSgrange if (st & GSCSIO_ACB_ST_BER) { 267d1b1be5aSgrange printf("%s: bus error, flags=0x%x\n", 268d1b1be5aSgrange sc->sc_dev.dv_xname, flags); 269d1b1be5aSgrange gscsio_acb_reset(acb); 270d1b1be5aSgrange return (EIO); 271d1b1be5aSgrange } 272d1b1be5aSgrange if (st & GSCSIO_ACB_ST_NEGACK) { 2736102b6a0Sgrange #if 0 274d1b1be5aSgrange printf("%s: negative ack, flags=0x%x\n", 275d1b1be5aSgrange sc->sc_dev.dv_xname, flags); 2766102b6a0Sgrange #endif 277d1b1be5aSgrange gscsio_acb_reset(acb); 278d1b1be5aSgrange return (EIO); 279d1b1be5aSgrange } 280d1b1be5aSgrange if ((st & bits) == bits) 281d1b1be5aSgrange break; 282d1b1be5aSgrange delay(10); 283d1b1be5aSgrange } 284d1b1be5aSgrange if ((st & bits) != bits) { 285d1b1be5aSgrange printf("%s: timeout, flags=0x%x\n", 286d1b1be5aSgrange sc->sc_dev.dv_xname, flags); 287d1b1be5aSgrange gscsio_acb_reset(acb); 288d1b1be5aSgrange return (ETIMEDOUT); 289d1b1be5aSgrange } 290d1b1be5aSgrange 291d1b1be5aSgrange return (0); 292d1b1be5aSgrange } 293d1b1be5aSgrange 294d1b1be5aSgrange void 295d1b1be5aSgrange gscsio_acb_reset(struct gscsio_acb *acb) 296d1b1be5aSgrange { 297d1b1be5aSgrange struct gscsio_softc *sc = acb->sc; 298d1b1be5aSgrange u_int8_t st, ctl; 299d1b1be5aSgrange 300d1b1be5aSgrange /* Clear MASTER, NEGACK and BER */ 301d1b1be5aSgrange st = ACB_READ(GSCSIO_ACB_ST); 302d1b1be5aSgrange st |= GSCSIO_ACB_ST_MASTER | GSCSIO_ACB_ST_NEGACK | GSCSIO_ACB_ST_BER; 303d1b1be5aSgrange ACB_WRITE(GSCSIO_ACB_ST, st); 304d1b1be5aSgrange 305d1b1be5aSgrange /* Disable and re-enable ACB */ 306d1b1be5aSgrange ACB_WRITE(GSCSIO_ACB_CTL2, 0); 307d1b1be5aSgrange ACB_WRITE(GSCSIO_ACB_CTL2, GSCSIO_ACB_CTL2_EN | 308d1b1be5aSgrange (GSCSIO_ACB_FREQ << GSCSIO_ACB_CTL2_FREQ_SHIFT)); 309d1b1be5aSgrange 310d1b1be5aSgrange /* Send stop */ 311d1b1be5aSgrange ctl = ACB_READ(GSCSIO_ACB_CTL1); 312d1b1be5aSgrange ctl |= GSCSIO_ACB_CTL1_STOP; 313d1b1be5aSgrange ACB_WRITE(GSCSIO_ACB_CTL1, ctl); 314d1b1be5aSgrange } 315d1b1be5aSgrange 316d1b1be5aSgrange int 317d1b1be5aSgrange gscsio_acb_acquire_bus(void *cookie, int flags) 318d1b1be5aSgrange { 319d1b1be5aSgrange struct gscsio_acb *acb = cookie; 320d1b1be5aSgrange 32175cdda3eSgrange if (cold || flags & I2C_F_POLL) 322d1b1be5aSgrange return (0); 323d1b1be5aSgrange 3243e55d5feSjsg return (rw_enter(&acb->buslock, RW_WRITE | RW_INTR)); 325d1b1be5aSgrange } 326d1b1be5aSgrange 327d1b1be5aSgrange void 328d1b1be5aSgrange gscsio_acb_release_bus(void *cookie, int flags) 329d1b1be5aSgrange { 330d1b1be5aSgrange struct gscsio_acb *acb = cookie; 331d1b1be5aSgrange 33275cdda3eSgrange if (cold || flags & I2C_F_POLL) 333d1b1be5aSgrange return; 334d1b1be5aSgrange 3353e55d5feSjsg rw_exit(&acb->buslock); 336d1b1be5aSgrange } 337d1b1be5aSgrange 338d1b1be5aSgrange int 339d1b1be5aSgrange gscsio_acb_send_start(void *cookie, int flags) 340d1b1be5aSgrange { 341d1b1be5aSgrange struct gscsio_acb *acb = cookie; 342d1b1be5aSgrange struct gscsio_softc *sc = acb->sc; 343d1b1be5aSgrange u_int8_t ctl; 344d1b1be5aSgrange 345d1b1be5aSgrange ctl = ACB_READ(GSCSIO_ACB_CTL1); 346d1b1be5aSgrange ctl |= GSCSIO_ACB_CTL1_START; 347d1b1be5aSgrange ACB_WRITE(GSCSIO_ACB_CTL1, ctl); 348d1b1be5aSgrange 349d1b1be5aSgrange return (0); 350d1b1be5aSgrange } 351d1b1be5aSgrange 352d1b1be5aSgrange int 353d1b1be5aSgrange gscsio_acb_send_stop(void *cookie, int flags) 354d1b1be5aSgrange { 355d1b1be5aSgrange struct gscsio_acb *acb = cookie; 356d1b1be5aSgrange struct gscsio_softc *sc = acb->sc; 357d1b1be5aSgrange u_int8_t ctl; 358d1b1be5aSgrange 359d1b1be5aSgrange ctl = ACB_READ(GSCSIO_ACB_CTL1); 360d1b1be5aSgrange ctl |= GSCSIO_ACB_CTL1_STOP; 361d1b1be5aSgrange ACB_WRITE(GSCSIO_ACB_CTL1, ctl); 362d1b1be5aSgrange 363d1b1be5aSgrange return (0); 364d1b1be5aSgrange } 365d1b1be5aSgrange 366d1b1be5aSgrange int 367*890573d8Smk gscsio_acb_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) 368d1b1be5aSgrange { 369d1b1be5aSgrange struct gscsio_acb *acb = cookie; 370d1b1be5aSgrange struct gscsio_softc *sc = acb->sc; 371d1b1be5aSgrange u_int8_t ctl; 372d1b1be5aSgrange int dir; 373d1b1be5aSgrange int error; 374d1b1be5aSgrange 375d1b1be5aSgrange /* Issue start condition */ 376d1b1be5aSgrange ctl = ACB_READ(GSCSIO_ACB_CTL1); 377d1b1be5aSgrange ctl |= GSCSIO_ACB_CTL1_START; 378d1b1be5aSgrange ACB_WRITE(GSCSIO_ACB_CTL1, ctl); 379d1b1be5aSgrange 380d1b1be5aSgrange /* Wait for bus mastership */ 381d1b1be5aSgrange if ((error = gscsio_acb_wait(acb, 382d1b1be5aSgrange GSCSIO_ACB_ST_MASTER | GSCSIO_ACB_ST_SDAST, flags))) 383d1b1be5aSgrange return (error); 384d1b1be5aSgrange 385d1b1be5aSgrange /* Send address byte */ 386d1b1be5aSgrange dir = (flags & I2C_F_READ ? 1 : 0); 387d1b1be5aSgrange ACB_WRITE(GSCSIO_ACB_SDA, (addr << 1) | dir); 388d1b1be5aSgrange 389d1b1be5aSgrange return (0); 390d1b1be5aSgrange } 391d1b1be5aSgrange 392d1b1be5aSgrange int 393d1b1be5aSgrange gscsio_acb_read_byte(void *cookie, uint8_t *bytep, int flags) 394d1b1be5aSgrange { 395d1b1be5aSgrange struct gscsio_acb *acb = cookie; 396d1b1be5aSgrange struct gscsio_softc *sc = acb->sc; 397d1b1be5aSgrange u_int8_t ctl; 398d1b1be5aSgrange int error; 399d1b1be5aSgrange 400d1b1be5aSgrange /* Wait for the bus to be ready */ 401d1b1be5aSgrange if ((error = gscsio_acb_wait(acb, GSCSIO_ACB_ST_SDAST, flags))) 402d1b1be5aSgrange return (error); 403d1b1be5aSgrange 404d1b1be5aSgrange /* Acknowledge the last byte */ 405d1b1be5aSgrange if (flags & I2C_F_LAST) { 406d1b1be5aSgrange ctl = ACB_READ(GSCSIO_ACB_CTL1); 407d1b1be5aSgrange ctl |= GSCSIO_ACB_CTL1_ACK; 408d1b1be5aSgrange ACB_WRITE(GSCSIO_ACB_CTL1, ctl); 409d1b1be5aSgrange } 410d1b1be5aSgrange 411d1b1be5aSgrange /* Read data byte */ 412d1b1be5aSgrange *bytep = ACB_READ(GSCSIO_ACB_SDA); 413d1b1be5aSgrange 414d1b1be5aSgrange return (0); 415d1b1be5aSgrange } 416d1b1be5aSgrange 417d1b1be5aSgrange int 418d1b1be5aSgrange gscsio_acb_write_byte(void *cookie, uint8_t byte, int flags) 419d1b1be5aSgrange { 420d1b1be5aSgrange struct gscsio_acb *acb = cookie; 421d1b1be5aSgrange struct gscsio_softc *sc = acb->sc; 422d1b1be5aSgrange u_int8_t ctl; 423d1b1be5aSgrange int error; 424d1b1be5aSgrange 425d1b1be5aSgrange /* Wait for the bus to be ready */ 426d1b1be5aSgrange if ((error = gscsio_acb_wait(acb, GSCSIO_ACB_ST_SDAST, flags))) 427d1b1be5aSgrange return (error); 428d1b1be5aSgrange 429d1b1be5aSgrange /* Send stop after the last byte */ 430d1b1be5aSgrange if (flags & I2C_F_STOP) { 431d1b1be5aSgrange ctl = ACB_READ(GSCSIO_ACB_CTL1); 432d1b1be5aSgrange ctl |= GSCSIO_ACB_CTL1_STOP; 433d1b1be5aSgrange ACB_WRITE(GSCSIO_ACB_CTL1, ctl); 434d1b1be5aSgrange } 435d1b1be5aSgrange 436d1b1be5aSgrange /* Write data byte */ 437d1b1be5aSgrange ACB_WRITE(GSCSIO_ACB_SDA, byte); 438d1b1be5aSgrange 439d1b1be5aSgrange return (0); 440d1b1be5aSgrange } 441