xref: /openbsd-src/sys/dev/i2c/i2c_exec.c (revision 21dab745d772244ad59a415114e48be2888cfbc8)
1*21dab745Sjsg /*	$OpenBSD: i2c_exec.c,v 1.3 2015/03/14 03:38:47 jsg Exp $	*/
21da3bef2Sgrange /*	$NetBSD: i2c_exec.c,v 1.3 2003/10/29 00:34:58 mycroft Exp $	*/
31da3bef2Sgrange 
41da3bef2Sgrange /*
51da3bef2Sgrange  * Copyright (c) 2003 Wasabi Systems, Inc.
61da3bef2Sgrange  * All rights reserved.
71da3bef2Sgrange  *
81da3bef2Sgrange  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
91da3bef2Sgrange  *
101da3bef2Sgrange  * Redistribution and use in source and binary forms, with or without
111da3bef2Sgrange  * modification, are permitted provided that the following conditions
121da3bef2Sgrange  * are met:
131da3bef2Sgrange  * 1. Redistributions of source code must retain the above copyright
141da3bef2Sgrange  *    notice, this list of conditions and the following disclaimer.
151da3bef2Sgrange  * 2. Redistributions in binary form must reproduce the above copyright
161da3bef2Sgrange  *    notice, this list of conditions and the following disclaimer in the
171da3bef2Sgrange  *    documentation and/or other materials provided with the distribution.
181da3bef2Sgrange  * 3. All advertising materials mentioning features or use of this software
191da3bef2Sgrange  *    must display the following acknowledgement:
201da3bef2Sgrange  *      This product includes software developed for the NetBSD Project by
211da3bef2Sgrange  *      Wasabi Systems, Inc.
221da3bef2Sgrange  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
231da3bef2Sgrange  *    or promote products derived from this software without specific prior
241da3bef2Sgrange  *    written permission.
251da3bef2Sgrange  *
261da3bef2Sgrange  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
271da3bef2Sgrange  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
281da3bef2Sgrange  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
291da3bef2Sgrange  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
301da3bef2Sgrange  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
311da3bef2Sgrange  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
321da3bef2Sgrange  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
331da3bef2Sgrange  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
341da3bef2Sgrange  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
351da3bef2Sgrange  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
361da3bef2Sgrange  * POSSIBILITY OF SUCH DAMAGE.
371da3bef2Sgrange  */
381da3bef2Sgrange 
391da3bef2Sgrange #include <sys/param.h>
401da3bef2Sgrange #include <sys/systm.h>
411da3bef2Sgrange #include <sys/device.h>
421da3bef2Sgrange #include <sys/event.h>
431da3bef2Sgrange 
441da3bef2Sgrange #define	_I2C_PRIVATE
451da3bef2Sgrange #include <dev/i2c/i2cvar.h>
461da3bef2Sgrange 
471da3bef2Sgrange /*
481da3bef2Sgrange  * iic_exec:
491da3bef2Sgrange  *
501da3bef2Sgrange  *	Simplified I2C client interface engine.
511da3bef2Sgrange  *
521da3bef2Sgrange  *	This and the SMBus routines are the preferred interface for
531da3bef2Sgrange  *	client access to I2C/SMBus, since many automated controllers
541da3bef2Sgrange  *	do not provide access to the low-level primitives of the I2C
551da3bef2Sgrange  *	bus protocol.
561da3bef2Sgrange  */
571da3bef2Sgrange int
iic_exec(i2c_tag_t tag,i2c_op_t op,i2c_addr_t addr,const void * vcmd,size_t cmdlen,void * vbuf,size_t buflen,int flags)581da3bef2Sgrange iic_exec(i2c_tag_t tag, i2c_op_t op, i2c_addr_t addr, const void *vcmd,
591da3bef2Sgrange     size_t cmdlen, void *vbuf, size_t buflen, int flags)
601da3bef2Sgrange {
611da3bef2Sgrange 	const uint8_t *cmd = vcmd;
621da3bef2Sgrange 	uint8_t *buf = vbuf;
631da3bef2Sgrange 	int error;
641da3bef2Sgrange 	size_t len;
651da3bef2Sgrange 
661da3bef2Sgrange 	/*
671da3bef2Sgrange 	 * Defer to the controller if it provides an exec function.  Use
681da3bef2Sgrange 	 * it if it does.
691da3bef2Sgrange 	 */
701da3bef2Sgrange 	if (tag->ic_exec != NULL)
711da3bef2Sgrange 		return ((*tag->ic_exec)(tag->ic_cookie, op, addr, cmd,
721da3bef2Sgrange 					cmdlen, buf, buflen, flags));
731da3bef2Sgrange 
741da3bef2Sgrange 	if ((len = cmdlen) != 0) {
751da3bef2Sgrange 		if ((error = iic_initiate_xfer(tag, addr, flags)) != 0)
761da3bef2Sgrange 			goto bad;
771da3bef2Sgrange 		while (len--) {
781da3bef2Sgrange 			if ((error = iic_write_byte(tag, *cmd++, flags)) != 0)
791da3bef2Sgrange 				goto bad;
801da3bef2Sgrange 		}
811da3bef2Sgrange 	}
821da3bef2Sgrange 
831da3bef2Sgrange 	if (I2C_OP_READ_P(op))
841da3bef2Sgrange 		flags |= I2C_F_READ;
851da3bef2Sgrange 
861da3bef2Sgrange 	len = buflen;
871da3bef2Sgrange 	while (len--) {
881da3bef2Sgrange 		if (len == 0 && I2C_OP_STOP_P(op))
891da3bef2Sgrange 			flags |= I2C_F_STOP;
901da3bef2Sgrange 		if (I2C_OP_READ_P(op)) {
911da3bef2Sgrange 			/* Send REPEATED START. */
921da3bef2Sgrange 			if ((len + 1) == buflen &&
931da3bef2Sgrange 			    (error = iic_initiate_xfer(tag, addr, flags)) != 0)
941da3bef2Sgrange 				goto bad;
951da3bef2Sgrange 			/* NACK on last byte. */
961da3bef2Sgrange 			if (len == 0)
971da3bef2Sgrange 				flags |= I2C_F_LAST;
981da3bef2Sgrange 			if ((error = iic_read_byte(tag, buf++, flags)) != 0)
991da3bef2Sgrange 				goto bad;
1001da3bef2Sgrange 		} else  {
1011da3bef2Sgrange 			/* Maybe send START. */
1021da3bef2Sgrange 			if ((len + 1) == buflen && cmdlen == 0 &&
1031da3bef2Sgrange 			    (error = iic_initiate_xfer(tag, addr, flags)) != 0)
1041da3bef2Sgrange 				goto bad;
1051da3bef2Sgrange 			if ((error = iic_write_byte(tag, *buf++, flags)) != 0)
1061da3bef2Sgrange 				goto bad;
1071da3bef2Sgrange 		}
1081da3bef2Sgrange 	}
1091da3bef2Sgrange 
1101da3bef2Sgrange 	return (0);
1111da3bef2Sgrange  bad:
1121da3bef2Sgrange 	iic_send_stop(tag, flags);
1131da3bef2Sgrange 	return (error);
1141da3bef2Sgrange }
1151da3bef2Sgrange 
1161da3bef2Sgrange /*
1171da3bef2Sgrange  * iic_smbus_write_byte:
1181da3bef2Sgrange  *
1191da3bef2Sgrange  *	Perform an SMBus "write byte" operation.
1201da3bef2Sgrange  */
1211da3bef2Sgrange int
iic_smbus_write_byte(i2c_tag_t tag,i2c_addr_t addr,uint8_t cmd,uint8_t val,int flags)1221da3bef2Sgrange iic_smbus_write_byte(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd,
1231da3bef2Sgrange     uint8_t val, int flags)
1241da3bef2Sgrange {
1251da3bef2Sgrange 
1267c8446f1Sderaadt 	return (iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr,
1277c8446f1Sderaadt 	    &cmd, sizeof cmd, &val, sizeof val, flags));
1281da3bef2Sgrange }
1291da3bef2Sgrange 
1301da3bef2Sgrange /*
1311da3bef2Sgrange  * iic_smbus_read_byte:
1321da3bef2Sgrange  *
1331da3bef2Sgrange  *	Perform an SMBus "read byte" operation.
1341da3bef2Sgrange  */
1351da3bef2Sgrange int
iic_smbus_read_byte(i2c_tag_t tag,i2c_addr_t addr,uint8_t cmd,uint8_t * valp,int flags)1361da3bef2Sgrange iic_smbus_read_byte(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd,
1371da3bef2Sgrange     uint8_t *valp, int flags)
1381da3bef2Sgrange {
1391da3bef2Sgrange 
1407c8446f1Sderaadt 	return (iic_exec(tag, I2C_OP_READ_WITH_STOP, addr,
1417c8446f1Sderaadt 	    &cmd, sizeof cmd, valp, sizeof (*valp), flags));
1421da3bef2Sgrange }
1431da3bef2Sgrange 
1441da3bef2Sgrange /*
1451da3bef2Sgrange  * iic_smbus_receive_byte:
1461da3bef2Sgrange  *
1471da3bef2Sgrange  *	Perform an SMBus "receive byte" operation.
1481da3bef2Sgrange  */
1491da3bef2Sgrange int
iic_smbus_receive_byte(i2c_tag_t tag,i2c_addr_t addr,uint8_t * valp,int flags)1501da3bef2Sgrange iic_smbus_receive_byte(i2c_tag_t tag, i2c_addr_t addr, uint8_t *valp,
1511da3bef2Sgrange     int flags)
1521da3bef2Sgrange {
1531da3bef2Sgrange 
1547c8446f1Sderaadt 	return (iic_exec(tag, I2C_OP_READ_WITH_STOP, addr,
1557c8446f1Sderaadt 	    NULL, 0, valp, sizeof (*valp), flags));
1561da3bef2Sgrange }
157