[BACK]Return to auvitek_i2c.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / usb

Annotation of src/sys/dev/usb/auvitek_i2c.c, Revision 1.6.8.1

1.6.8.1 ! thorpej     1: /* $NetBSD: auvitek_i2c.c,v 1.6 2021/04/24 23:36:59 thorpej Exp $ */
1.1       jmcneill    2:
                      3: /*-
                      4:  * Copyright (c) 2010 Jared D. McNeill <jmcneill@invisible.ca>
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     17:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     18:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     19:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     20:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     21:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     22:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     23:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     24:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     25:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     26:  * POSSIBILITY OF SUCH DAMAGE.
                     27:  */
                     28:
                     29: /*
                     30:  * Auvitek AU0828 USB controller - I2C access ops
                     31:  */
                     32:
                     33: #include <sys/cdefs.h>
1.6.8.1 ! thorpej    34: __KERNEL_RCSID(0, "$NetBSD: auvitek_i2c.c,v 1.6 2021/04/24 23:36:59 thorpej Exp $");
1.4       skrll      35:
                     36: #ifdef _KERNEL_OPT
                     37: #include "opt_usb.h"
                     38: #endif
1.1       jmcneill   39:
                     40: #include <sys/param.h>
                     41: #include <sys/systm.h>
                     42: #include <sys/device.h>
                     43: #include <sys/conf.h>
                     44: #include <sys/bus.h>
                     45: #include <sys/module.h>
                     46:
                     47: #include <dev/usb/usb.h>
                     48: #include <dev/usb/usbdi.h>
                     49: #include <dev/usb/usbdi_util.h>
                     50: #include <dev/usb/usbdevs.h>
                     51:
                     52: #include <dev/i2c/i2cvar.h>
                     53:
                     54: #include <dev/usb/auvitekreg.h>
                     55: #include <dev/usb/auvitekvar.h>
                     56:
1.3       jmcneill   57: /* #define AUVITEK_I2C_DEBUG */
                     58:
1.1       jmcneill   59: static int     auvitek_i2c_exec(void *, i2c_op_t, i2c_addr_t,
                     60:                                 const void *, size_t, void *, size_t, int);
                     61:
                     62: static int     auvitek_i2c_read(struct auvitek_softc *, i2c_addr_t,
                     63:                                 uint8_t *, size_t);
                     64: static int     auvitek_i2c_write(struct auvitek_softc *, i2c_addr_t,
                     65:                                  const uint8_t *, size_t);
                     66: static bool    auvitek_i2c_wait(struct auvitek_softc *);
                     67: static bool    auvitek_i2c_wait_rdack(struct auvitek_softc *);
                     68: static bool    auvitek_i2c_wait_rddone(struct auvitek_softc *);
                     69: static bool    auvitek_i2c_wait_wrdone(struct auvitek_softc *);
                     70:
                     71: int
                     72: auvitek_i2c_attach(struct auvitek_softc *sc)
                     73: {
1.5       thorpej    74:        iic_tag_init(&sc->sc_i2c);
1.1       jmcneill   75:        sc->sc_i2c.ic_cookie = sc;
                     76:        sc->sc_i2c.ic_exec = auvitek_i2c_exec;
                     77:
1.3       jmcneill   78:        auvitek_i2c_rescan(sc, NULL, NULL);
                     79:
1.1       jmcneill   80:        return 0;
                     81: }
                     82:
                     83: int
                     84: auvitek_i2c_detach(struct auvitek_softc *sc, int flags)
                     85: {
1.5       thorpej    86:        iic_tag_fini(&sc->sc_i2c);
1.1       jmcneill   87:
1.3       jmcneill   88:        if (sc->sc_i2cdev)
                     89:                config_detach(sc->sc_i2cdev, flags);
                     90:
1.1       jmcneill   91:        return 0;
                     92: }
                     93:
1.3       jmcneill   94: void
                     95: auvitek_i2c_rescan(struct auvitek_softc *sc, const char *ifattr,
                     96:     const int *locs)
                     97: {
                     98: #ifdef AUVITEK_I2C_DEBUG
                     99:        struct i2cbus_attach_args iba;
                    100:
                    101:        if (ifattr_match(ifattr, "i2cbus") && sc->sc_i2cdev == NULL) {
                    102:                memset(&iba, 0, sizeof(iba));
                    103:                iba.iba_tag = &sc->sc_i2c;
1.6       thorpej   104:                sc->sc_i2cdev = config_found(sc->sc_dev, &iba, iicbus_print,
1.6.8.1 ! thorpej   105:                    CFARGS(.iattr = "i2cbus"));
1.3       jmcneill  106:        }
                    107: #endif
                    108: }
                    109:
                    110: void
                    111: auvitek_i2c_childdet(struct auvitek_softc *sc, device_t child)
                    112: {
                    113:        if (sc->sc_i2cdev == child)
                    114:                sc->sc_i2cdev = NULL;
                    115: }
                    116:
1.1       jmcneill  117: static int
                    118: auvitek_i2c_exec(void *opaque, i2c_op_t op, i2c_addr_t addr,
                    119:     const void *cmd, size_t cmdlen, void *vbuf, size_t buflen, int flags)
                    120: {
                    121:        struct auvitek_softc *sc = opaque;
                    122:
                    123:        if (I2C_OP_READ_P(op))
                    124:                return auvitek_i2c_read(sc, addr, vbuf, buflen);
                    125:        else
                    126:                return auvitek_i2c_write(sc, addr, cmd, cmdlen);
                    127: }
                    128:
                    129: static int
                    130: auvitek_i2c_read(struct auvitek_softc *sc, i2c_addr_t addr,
                    131:     uint8_t *buf, size_t buflen)
                    132: {
                    133:        uint8_t v;
                    134:        unsigned int i;
                    135:
                    136:        auvitek_write_1(sc, AU0828_REG_I2C_MBMODE, 1);
                    137:        auvitek_write_1(sc, AU0828_REG_I2C_CLKDIV, sc->sc_i2c_clkdiv);
                    138:        auvitek_write_1(sc, AU0828_REG_I2C_DSTADDR, addr << 1);
                    139:
                    140:        if (buflen == 0) {
                    141:                auvitek_write_1(sc, AU0828_REG_I2C_TRIGGER,
                    142:                    AU0828_I2C_TRIGGER_RD);
                    143:                if (auvitek_i2c_wait_rdack(sc) == false)
                    144:                        return EBUSY;
                    145:                return 0;
                    146:        }
                    147:
                    148:        for (i = 0; i < buflen; i++) {
                    149:                v = AU0828_I2C_TRIGGER_RD;
                    150:                if (i < (buflen - 1))
                    151:                        v |= AU0828_I2C_TRIGGER_HOLD;
                    152:                auvitek_write_1(sc, AU0828_REG_I2C_TRIGGER, v);
                    153:
                    154:                if (auvitek_i2c_wait_rddone(sc) == false)
                    155:                        return EBUSY;
                    156:
                    157:                buf[i] = auvitek_read_1(sc, AU0828_REG_I2C_FIFORD);
                    158:        }
                    159:
                    160:        if (auvitek_i2c_wait(sc) == false)
                    161:                return EBUSY;
                    162:
                    163:        return 0;
                    164: }
                    165:
                    166: static int
                    167: auvitek_i2c_write(struct auvitek_softc *sc, i2c_addr_t addr,
                    168:     const uint8_t *buf, size_t buflen)
                    169: {
                    170:        uint8_t v;
                    171:        unsigned int i, fifolen;
                    172:
                    173:        auvitek_write_1(sc, AU0828_REG_I2C_MBMODE, 1);
                    174:        auvitek_write_1(sc, AU0828_REG_I2C_CLKDIV, sc->sc_i2c_clkdiv);
                    175:        auvitek_write_1(sc, AU0828_REG_I2C_DSTADDR, addr << 1);
                    176:
                    177:        if (buflen == 0) {
                    178:                auvitek_write_1(sc, AU0828_REG_I2C_TRIGGER,
                    179:                    AU0828_I2C_TRIGGER_RD);
                    180:                if (auvitek_i2c_wait(sc) == false)
                    181:                        return EBUSY;
                    182:                if (auvitek_i2c_wait_rdack(sc) == false)
                    183:                        return EBUSY;
                    184:                return 0;
                    185:        }
                    186:
                    187:        fifolen = 0;
                    188:        for (i = 0; i < buflen; i++) {
                    189:                v = AU0828_I2C_TRIGGER_WR;
                    190:                if (i < (buflen - 1))
                    191:                        v |= AU0828_I2C_TRIGGER_HOLD;
                    192:
                    193:                auvitek_write_1(sc, AU0828_REG_I2C_FIFOWR, buf[i]);
                    194:                ++fifolen;
                    195:
                    196:                if (fifolen == 4 || i == (buflen - 1)) {
                    197:                        auvitek_write_1(sc, AU0828_REG_I2C_TRIGGER, v);
                    198:                        fifolen = 0;
                    199:
                    200:                        if (auvitek_i2c_wait_wrdone(sc) == false)
                    201:                                return EBUSY;
                    202:                }
                    203:        }
                    204:
                    205:        if (auvitek_i2c_wait(sc) == false)
                    206:                return EBUSY;
                    207:
                    208:        return 0;
                    209: }
                    210:
                    211: static bool
                    212: auvitek_i2c_wait(struct auvitek_softc *sc)
                    213: {
                    214:        uint8_t status;
                    215:        int retry = 1000;
                    216:
                    217:        while (--retry > 0) {
                    218:                status = auvitek_read_1(sc, AU0828_REG_I2C_STATUS);
                    219:                if (!(status & AU0828_I2C_STATUS_BUSY))
                    220:                        break;
                    221:                delay(10);
                    222:        }
                    223:        if (retry == 0)
                    224:                return false;
                    225:
                    226:        return true;
                    227: }
                    228:
                    229: static bool
                    230: auvitek_i2c_wait_rdack(struct auvitek_softc *sc)
                    231: {
                    232:        uint8_t status;
                    233:        int retry = 1000;
                    234:
                    235:        while (--retry > 0) {
                    236:                status = auvitek_read_1(sc, AU0828_REG_I2C_STATUS);
                    237:                if (!(status & AU0828_I2C_STATUS_NO_RD_ACK))
                    238:                        break;
                    239:                delay(10);
                    240:        }
                    241:        if (retry == 0)
                    242:                return false;
                    243:
                    244:        return true;
                    245: }
                    246:
                    247: static bool
                    248: auvitek_i2c_wait_rddone(struct auvitek_softc *sc)
                    249: {
                    250:        uint8_t status;
                    251:        int retry = 1000;
                    252:
                    253:        while (--retry > 0) {
                    254:                status = auvitek_read_1(sc, AU0828_REG_I2C_STATUS);
                    255:                if (status & AU0828_I2C_STATUS_RD_DONE)
                    256:                        break;
                    257:                delay(10);
                    258:        }
                    259:        if (retry == 0)
                    260:                return false;
                    261:
                    262:        return true;
                    263: }
                    264:
                    265: static bool
                    266: auvitek_i2c_wait_wrdone(struct auvitek_softc *sc)
                    267: {
                    268:        uint8_t status;
                    269:        int retry = 1000;
                    270:
                    271:        while (--retry > 0) {
                    272:                status = auvitek_read_1(sc, AU0828_REG_I2C_STATUS);
                    273:                if (status & AU0828_I2C_STATUS_WR_DONE)
                    274:                        break;
                    275:                delay(10);
                    276:        }
                    277:        if (retry == 0)
                    278:                return false;
                    279:
                    280:        return true;
                    281: }

CVSweb <webmaster@jp.NetBSD.org>