1*601e1783Sthorpej /* $NetBSD: emdtv_i2c.c,v 1.2 2019/12/22 23:23:32 thorpej Exp $ */
251f58a8aSjmcneill
351f58a8aSjmcneill /*-
451f58a8aSjmcneill * Copyright (c) 2008, 2010 Jared D. McNeill <jmcneill@invisible.ca>
551f58a8aSjmcneill * All rights reserved.
651f58a8aSjmcneill *
751f58a8aSjmcneill * Redistribution and use in source and binary forms, with or without
851f58a8aSjmcneill * modification, are permitted provided that the following conditions
951f58a8aSjmcneill * are met:
1051f58a8aSjmcneill * 1. Redistributions of source code must retain the above copyright
1151f58a8aSjmcneill * notice, this list of conditions and the following disclaimer.
1251f58a8aSjmcneill * 2. Redistributions in binary form must reproduce the above copyright
1351f58a8aSjmcneill * notice, this list of conditions and the following disclaimer in the
1451f58a8aSjmcneill * documentation and/or other materials provided with the distribution.
1551f58a8aSjmcneill *
1651f58a8aSjmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1751f58a8aSjmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1851f58a8aSjmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1951f58a8aSjmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2051f58a8aSjmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2151f58a8aSjmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2251f58a8aSjmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2351f58a8aSjmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2451f58a8aSjmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2551f58a8aSjmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2651f58a8aSjmcneill * POSSIBILITY OF SUCH DAMAGE.
2751f58a8aSjmcneill */
2851f58a8aSjmcneill
2951f58a8aSjmcneill #include <sys/cdefs.h>
30*601e1783Sthorpej __KERNEL_RCSID(0, "$NetBSD: emdtv_i2c.c,v 1.2 2019/12/22 23:23:32 thorpej Exp $");
3151f58a8aSjmcneill
3251f58a8aSjmcneill #include <sys/param.h>
3351f58a8aSjmcneill #include <sys/systm.h>
3451f58a8aSjmcneill #include <sys/device.h>
3551f58a8aSjmcneill #include <sys/conf.h>
3651f58a8aSjmcneill
3751f58a8aSjmcneill #include <dev/usb/usb.h>
3851f58a8aSjmcneill #include <dev/usb/usbdi.h>
3951f58a8aSjmcneill #include <dev/usb/usbdi_util.h>
4051f58a8aSjmcneill #include <dev/usb/usbdevs.h>
4151f58a8aSjmcneill
4251f58a8aSjmcneill #include <dev/i2c/i2cvar.h>
4351f58a8aSjmcneill
4451f58a8aSjmcneill #include <dev/usb/emdtvvar.h>
4551f58a8aSjmcneill #include <dev/usb/emdtvreg.h>
4651f58a8aSjmcneill
4751f58a8aSjmcneill static int emdtv_i2c_exec(void *, i2c_op_t, i2c_addr_t,
4851f58a8aSjmcneill const void *, size_t, void *, size_t, int);
4951f58a8aSjmcneill
5051f58a8aSjmcneill static int emdtv_i2c_check(struct emdtv_softc *, i2c_addr_t);
5151f58a8aSjmcneill static int emdtv_i2c_recv(struct emdtv_softc *, i2c_addr_t,
5251f58a8aSjmcneill uint8_t *, size_t);
5351f58a8aSjmcneill static int emdtv_i2c_send(struct emdtv_softc *, i2c_addr_t,
5451f58a8aSjmcneill const uint8_t *, size_t, bool);
5551f58a8aSjmcneill
5651f58a8aSjmcneill int
emdtv_i2c_attach(struct emdtv_softc * sc)5751f58a8aSjmcneill emdtv_i2c_attach(struct emdtv_softc *sc)
5851f58a8aSjmcneill {
59*601e1783Sthorpej iic_tag_init(&sc->sc_i2c);
6051f58a8aSjmcneill sc->sc_i2c.ic_cookie = sc;
6151f58a8aSjmcneill sc->sc_i2c.ic_exec = emdtv_i2c_exec;
6251f58a8aSjmcneill
6351f58a8aSjmcneill return 0;
6451f58a8aSjmcneill }
6551f58a8aSjmcneill
6651f58a8aSjmcneill int
emdtv_i2c_detach(struct emdtv_softc * sc,int flags)6751f58a8aSjmcneill emdtv_i2c_detach(struct emdtv_softc *sc, int flags)
6851f58a8aSjmcneill {
69*601e1783Sthorpej iic_tag_fini(&sc->sc_i2c);
7051f58a8aSjmcneill
7151f58a8aSjmcneill return 0;
7251f58a8aSjmcneill }
7351f58a8aSjmcneill
7451f58a8aSjmcneill static int
emdtv_i2c_exec(void * opaque,i2c_op_t op,i2c_addr_t addr,const void * cmd,size_t cmdlen,void * vbuf,size_t buflen,int flags)7551f58a8aSjmcneill emdtv_i2c_exec(void *opaque, i2c_op_t op, i2c_addr_t addr,
7651f58a8aSjmcneill const void *cmd, size_t cmdlen, void *vbuf, size_t buflen, int flags)
7751f58a8aSjmcneill {
7851f58a8aSjmcneill struct emdtv_softc *sc = opaque;
7951f58a8aSjmcneill int error;
8051f58a8aSjmcneill
8151f58a8aSjmcneill if (I2C_OP_READ_P(op)) {
8251f58a8aSjmcneill if (buflen == 0)
8351f58a8aSjmcneill error = emdtv_i2c_check(sc, addr);
8451f58a8aSjmcneill else
8551f58a8aSjmcneill error = emdtv_i2c_recv(sc, addr, vbuf, buflen);
8651f58a8aSjmcneill } else {
8751f58a8aSjmcneill error = emdtv_i2c_send(sc, addr, cmd, cmdlen,
8851f58a8aSjmcneill I2C_OP_STOP_P(op));
8951f58a8aSjmcneill error = 0;
9051f58a8aSjmcneill }
9151f58a8aSjmcneill
9251f58a8aSjmcneill return error;
9351f58a8aSjmcneill }
9451f58a8aSjmcneill
9551f58a8aSjmcneill static int
emdtv_i2c_check(struct emdtv_softc * sc,i2c_addr_t addr)9651f58a8aSjmcneill emdtv_i2c_check(struct emdtv_softc *sc, i2c_addr_t addr)
9751f58a8aSjmcneill {
9851f58a8aSjmcneill emdtv_read_1(sc, EM28XX_UR_I2C, addr);
9951f58a8aSjmcneill if (emdtv_read_1(sc, UR_GET_STATUS, EM28XX_REG_I2C_STATUS) != 0) {
10051f58a8aSjmcneill device_printf(sc->sc_dev, "%s failed\n", __func__);
10151f58a8aSjmcneill return ENXIO;
10251f58a8aSjmcneill }
10351f58a8aSjmcneill return 0;
10451f58a8aSjmcneill }
10551f58a8aSjmcneill
10651f58a8aSjmcneill static int
emdtv_i2c_recv(struct emdtv_softc * sc,i2c_addr_t addr,uint8_t * datap,size_t len)10751f58a8aSjmcneill emdtv_i2c_recv(struct emdtv_softc *sc, i2c_addr_t addr, uint8_t *datap,
10851f58a8aSjmcneill size_t len)
10951f58a8aSjmcneill {
11051f58a8aSjmcneill emdtv_read_multi_1(sc, EM28XX_UR_I2C, addr, datap, len);
11151f58a8aSjmcneill if (emdtv_read_1(sc, UR_GET_STATUS, EM28XX_REG_I2C_STATUS) != 0) {
11251f58a8aSjmcneill device_printf(sc->sc_dev, "%s failed\n", __func__);
11351f58a8aSjmcneill return ENXIO;
11451f58a8aSjmcneill }
11551f58a8aSjmcneill return 0;
11651f58a8aSjmcneill }
11751f58a8aSjmcneill
11851f58a8aSjmcneill static int
emdtv_i2c_send(struct emdtv_softc * sc,i2c_addr_t addr,const uint8_t * datap,size_t len,bool stop)11951f58a8aSjmcneill emdtv_i2c_send(struct emdtv_softc *sc, i2c_addr_t addr, const uint8_t *datap,
12051f58a8aSjmcneill size_t len, bool stop)
12151f58a8aSjmcneill {
12251f58a8aSjmcneill int off = (stop == false ? 1 : 0);
12351f58a8aSjmcneill emdtv_write_multi_1(sc, EM28XX_UR_I2C + off, addr, datap, len);
12451f58a8aSjmcneill if (emdtv_read_1(sc, UR_GET_STATUS, EM28XX_REG_I2C_STATUS) != 0) {
12551f58a8aSjmcneill device_printf(sc->sc_dev, "%s failed\n", __func__);
12651f58a8aSjmcneill return ENXIO;
12751f58a8aSjmcneill }
12851f58a8aSjmcneill return 0;
12951f58a8aSjmcneill }
130