xref: /netbsd-src/sys/dev/usb/emdtv_i2c.c (revision 601e1783806444af16ed66b5dc3a6fef98f1fbec)
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