xref: /openbsd-src/sys/dev/i2c/i2c_bitbang.c (revision 5b133f3f277e80f096764111e64f3a1284acb179)
1*5b133f3fSguenther /*	$OpenBSD: i2c_bitbang.c,v 1.5 2023/03/08 04:43:08 guenther Exp $	*/
23a4cbe1aSgrange /*	$NetBSD: i2c_bitbang.c,v 1.1 2003/09/30 00:35:31 thorpej Exp $	*/
33a4cbe1aSgrange 
43a4cbe1aSgrange /*
53a4cbe1aSgrange  * Copyright (c) 2003 Wasabi Systems, Inc.
63a4cbe1aSgrange  * All rights reserved.
73a4cbe1aSgrange  *
83a4cbe1aSgrange  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
93a4cbe1aSgrange  *
103a4cbe1aSgrange  * Redistribution and use in source and binary forms, with or without
113a4cbe1aSgrange  * modification, are permitted provided that the following conditions
123a4cbe1aSgrange  * are met:
133a4cbe1aSgrange  * 1. Redistributions of source code must retain the above copyright
143a4cbe1aSgrange  *    notice, this list of conditions and the following disclaimer.
153a4cbe1aSgrange  * 2. Redistributions in binary form must reproduce the above copyright
163a4cbe1aSgrange  *    notice, this list of conditions and the following disclaimer in the
173a4cbe1aSgrange  *    documentation and/or other materials provided with the distribution.
183a4cbe1aSgrange  * 3. All advertising materials mentioning features or use of this software
193a4cbe1aSgrange  *    must display the following acknowledgement:
203a4cbe1aSgrange  *      This product includes software developed for the NetBSD Project by
213a4cbe1aSgrange  *      Wasabi Systems, Inc.
223a4cbe1aSgrange  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
233a4cbe1aSgrange  *    or promote products derived from this software without specific prior
243a4cbe1aSgrange  *    written permission.
253a4cbe1aSgrange  *
263a4cbe1aSgrange  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
273a4cbe1aSgrange  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
283a4cbe1aSgrange  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
293a4cbe1aSgrange  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
303a4cbe1aSgrange  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
313a4cbe1aSgrange  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
323a4cbe1aSgrange  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
333a4cbe1aSgrange  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
343a4cbe1aSgrange  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
353a4cbe1aSgrange  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
363a4cbe1aSgrange  * POSSIBILITY OF SUCH DAMAGE.
373a4cbe1aSgrange  */
383a4cbe1aSgrange 
393a4cbe1aSgrange /*
403a4cbe1aSgrange  * Common module for bit-bang'ing an I2C bus.
413a4cbe1aSgrange  */
423a4cbe1aSgrange 
433a4cbe1aSgrange #include <sys/param.h>
443a4cbe1aSgrange 
453a4cbe1aSgrange #include <dev/i2c/i2cvar.h>
463a4cbe1aSgrange #include <dev/i2c/i2c_bitbang.h>
473a4cbe1aSgrange 
483a4cbe1aSgrange #define	BB_SET(x)	ops->ibo_set_bits(v, (x))
493a4cbe1aSgrange #define	BB_DIR(x)	ops->ibo_set_dir(v, (x))
503a4cbe1aSgrange #define	BB_READ		ops->ibo_read_bits(v)
513a4cbe1aSgrange 
523a4cbe1aSgrange #define	SDA		ops->ibo_bits[I2C_BIT_SDA]	/* i2c signal */
533a4cbe1aSgrange #define	SCL		ops->ibo_bits[I2C_BIT_SCL]	/* i2c signal */
543a4cbe1aSgrange #define	OUTPUT		ops->ibo_bits[I2C_BIT_OUTPUT]	/* SDA is output */
553a4cbe1aSgrange #define	INPUT		ops->ibo_bits[I2C_BIT_INPUT]	/* SDA is input */
563a4cbe1aSgrange 
573bfc9b60Skettenis #define SCL_BAIL_COUNT	1000
583bfc9b60Skettenis 
593bfc9b60Skettenis int i2c_wait_for_scl(void *, i2c_bitbang_ops_t);
603bfc9b60Skettenis 
613bfc9b60Skettenis int
i2c_wait_for_scl(void * v,i2c_bitbang_ops_t ops)623bfc9b60Skettenis i2c_wait_for_scl(void *v, i2c_bitbang_ops_t ops)
633bfc9b60Skettenis {
643bfc9b60Skettenis 	int bail = 0;
653bfc9b60Skettenis 
663bfc9b60Skettenis 	while(((BB_READ & SCL) == 0) && bail < SCL_BAIL_COUNT) {
673bfc9b60Skettenis 		delay(1);
683bfc9b60Skettenis 		bail++;
693bfc9b60Skettenis 	}
703bfc9b60Skettenis 	if (bail == SCL_BAIL_COUNT) {
713bfc9b60Skettenis 		i2c_bitbang_send_stop(v, 0, ops);
723bfc9b60Skettenis 		return (EIO);
733bfc9b60Skettenis 	}
743bfc9b60Skettenis 
753bfc9b60Skettenis 	return (0);
763bfc9b60Skettenis }
773bfc9b60Skettenis 
783a4cbe1aSgrange int
i2c_bitbang_send_start(void * v,int flags,i2c_bitbang_ops_t ops)793a4cbe1aSgrange i2c_bitbang_send_start(void *v, int flags, i2c_bitbang_ops_t ops)
803a4cbe1aSgrange {
813a4cbe1aSgrange 
823a4cbe1aSgrange 	BB_DIR(OUTPUT);
833a4cbe1aSgrange 
843a4cbe1aSgrange 	BB_SET(SDA | SCL);
853a4cbe1aSgrange 	delay(5);		/* bus free time (4.7 uS) */
863a4cbe1aSgrange 	BB_SET(      SCL);
873bfc9b60Skettenis 	if (i2c_wait_for_scl(v, ops) != 0)
883bfc9b60Skettenis 		return (EIO);
893a4cbe1aSgrange 	delay(4);		/* start hold time (4.0 uS) */
903a4cbe1aSgrange 	BB_SET(        0);
913a4cbe1aSgrange 	delay(5);		/* clock low time (4.7 uS) */
923a4cbe1aSgrange 
933a4cbe1aSgrange 	return (0);
943a4cbe1aSgrange }
953a4cbe1aSgrange 
963a4cbe1aSgrange int
i2c_bitbang_send_stop(void * v,int flags,i2c_bitbang_ops_t ops)973a4cbe1aSgrange i2c_bitbang_send_stop(void *v, int flags, i2c_bitbang_ops_t ops)
983a4cbe1aSgrange {
993a4cbe1aSgrange 
1003a4cbe1aSgrange 	BB_DIR(OUTPUT);
1013a4cbe1aSgrange 
1023a4cbe1aSgrange 	BB_SET(      SCL);
1033a4cbe1aSgrange 	delay(4);		/* stop setup time (4.0 uS) */
1043a4cbe1aSgrange 	BB_SET(SDA | SCL);
1053a4cbe1aSgrange 
1063a4cbe1aSgrange 	return (0);
1073a4cbe1aSgrange }
1083a4cbe1aSgrange 
1093a4cbe1aSgrange int
i2c_bitbang_initiate_xfer(void * v,i2c_addr_t addr,int flags,i2c_bitbang_ops_t ops)1103a4cbe1aSgrange i2c_bitbang_initiate_xfer(void *v, i2c_addr_t addr, int flags,
1113a4cbe1aSgrange     i2c_bitbang_ops_t ops)
1123a4cbe1aSgrange {
1133a4cbe1aSgrange 	int i2caddr;
1143a4cbe1aSgrange 
1153a4cbe1aSgrange 	/* XXX Only support 7-bit addressing for now. */
1163a4cbe1aSgrange 	if ((addr & 0x78) == 0x78)
1173a4cbe1aSgrange 		return (EINVAL);
1183a4cbe1aSgrange 
1193a4cbe1aSgrange 	i2caddr = (addr << 1) | ((flags & I2C_F_READ) ? 1 : 0);
1203a4cbe1aSgrange 
1213a4cbe1aSgrange 	(void) i2c_bitbang_send_start(v, flags, ops);
1223a4cbe1aSgrange 	return (i2c_bitbang_write_byte(v, i2caddr, flags & ~I2C_F_STOP, ops));
1233a4cbe1aSgrange }
1243a4cbe1aSgrange 
1253a4cbe1aSgrange int
i2c_bitbang_read_byte(void * v,uint8_t * valp,int flags,i2c_bitbang_ops_t ops)1263a4cbe1aSgrange i2c_bitbang_read_byte(void *v, uint8_t *valp, int flags,
1273a4cbe1aSgrange     i2c_bitbang_ops_t ops)
1283a4cbe1aSgrange {
1293a4cbe1aSgrange 	int i;
1303a4cbe1aSgrange 	uint8_t val = 0;
1313a4cbe1aSgrange 	uint32_t bit;
1323a4cbe1aSgrange 
1333a4cbe1aSgrange 	BB_DIR(INPUT);
1343a4cbe1aSgrange 	BB_SET(SDA      );
1353a4cbe1aSgrange 
1363a4cbe1aSgrange 	for (i = 0; i < 8; i++) {
1373a4cbe1aSgrange 		val <<= 1;
1383a4cbe1aSgrange 		BB_SET(SDA | SCL);
1393bfc9b60Skettenis 		if (i2c_wait_for_scl(v, ops) != 0)
1403bfc9b60Skettenis 			return (EIO);
1413a4cbe1aSgrange 		delay(4);	/* clock high time (4.0 uS) */
1423a4cbe1aSgrange 		if (BB_READ & SDA)
1433a4cbe1aSgrange 			val |= 1;
1443a4cbe1aSgrange 		BB_SET(SDA      );
1453a4cbe1aSgrange 		delay(5);	/* clock low time (4.7 uS) */
1463a4cbe1aSgrange 	}
1473a4cbe1aSgrange 
1483a4cbe1aSgrange 	bit = (flags & I2C_F_LAST) ? SDA : 0;
1493a4cbe1aSgrange 	BB_DIR(OUTPUT);
1503a4cbe1aSgrange 	BB_SET(bit      );
1513a4cbe1aSgrange 	delay(1);	/* data setup time (250 nS) */
1523a4cbe1aSgrange 	BB_SET(bit | SCL);
1533bfc9b60Skettenis 	if (i2c_wait_for_scl(v, ops) != 0)
1543bfc9b60Skettenis 		return (EIO);
1553a4cbe1aSgrange 	delay(4);	/* clock high time (4.0 uS) */
1563a4cbe1aSgrange 	BB_SET(bit      );
1573a4cbe1aSgrange 	delay(5);	/* clock low time (4.7 uS) */
1583a4cbe1aSgrange 
1593a4cbe1aSgrange 	BB_DIR(INPUT);
1603a4cbe1aSgrange 	BB_SET(SDA      );
1613a4cbe1aSgrange 	delay(5);
1623a4cbe1aSgrange 
1633a4cbe1aSgrange 	if ((flags & (I2C_F_STOP | I2C_F_LAST)) == (I2C_F_STOP | I2C_F_LAST))
1643a4cbe1aSgrange 		(void) i2c_bitbang_send_stop(v, flags, ops);
1653a4cbe1aSgrange 
1663a4cbe1aSgrange 	*valp = val;
1673a4cbe1aSgrange 	return (0);
1683a4cbe1aSgrange }
1693a4cbe1aSgrange 
1703a4cbe1aSgrange int
i2c_bitbang_write_byte(void * v,uint8_t val,int flags,i2c_bitbang_ops_t ops)1713a4cbe1aSgrange i2c_bitbang_write_byte(void *v, uint8_t val, int flags,
1723a4cbe1aSgrange     i2c_bitbang_ops_t ops)
1733a4cbe1aSgrange {
1743a4cbe1aSgrange 	uint32_t bit;
1753a4cbe1aSgrange 	uint8_t mask;
1763a4cbe1aSgrange 	int error;
1773a4cbe1aSgrange 
1783a4cbe1aSgrange 	BB_DIR(OUTPUT);
1793a4cbe1aSgrange 
1803a4cbe1aSgrange 	for (mask = 0x80; mask != 0; mask >>= 1) {
1813a4cbe1aSgrange 		bit = (val & mask) ? SDA : 0;
1823a4cbe1aSgrange 		BB_SET(bit      );
1833a4cbe1aSgrange 		delay(1);	/* data setup time (250 nS) */
1843a4cbe1aSgrange 		BB_SET(bit | SCL);
1853bfc9b60Skettenis 		if (i2c_wait_for_scl(v, ops) != 0)
1863bfc9b60Skettenis 			return (EIO);
1873a4cbe1aSgrange 		delay(4);	/* clock high time (4.0 uS) */
1883a4cbe1aSgrange 		BB_SET(bit      );
1893a4cbe1aSgrange 		delay(5);	/* clock low time (4.7 uS) */
1903a4cbe1aSgrange 	}
1913a4cbe1aSgrange 
1923a4cbe1aSgrange 	BB_DIR(INPUT);
1933a4cbe1aSgrange 
1943a4cbe1aSgrange 	BB_SET(SDA      );
1953a4cbe1aSgrange 	delay(5);
1963a4cbe1aSgrange 	BB_SET(SDA | SCL);
1973bfc9b60Skettenis 	if (i2c_wait_for_scl(v, ops) != 0)
1983bfc9b60Skettenis 		return (EIO);
1993a4cbe1aSgrange 	delay(4);
2003a4cbe1aSgrange 	error = (BB_READ & SDA) ? EIO : 0;
2013a4cbe1aSgrange 	BB_SET(SDA      );
2023a4cbe1aSgrange 	delay(5);
2033a4cbe1aSgrange 
2043a4cbe1aSgrange 	if (flags & I2C_F_STOP)
2053a4cbe1aSgrange 		(void) i2c_bitbang_send_stop(v, flags, ops);
2063a4cbe1aSgrange 
2073a4cbe1aSgrange 	return (error);
2083a4cbe1aSgrange }
209