⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c-algo-biths.c

📁 I2C总线LINUX驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ------------------------------------------------------------------------- *//* i2c-algo-biths.c i2c driver algorithms for bit-shift adapters	     *//* ------------------------------------------------------------------------- *//*   Copyright (C) 1995-2000 Simon G. Vogl     Copyright (C) 2002-2003 Ky鰏ti M鋖kki    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     *//* ------------------------------------------------------------------------- *//* $Id: i2c-algo-biths.c,v 1.16 2005/03/11 20:37:33 khali Exp $ */#include <linux/kernel.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/sched.h>#include "i2c.h"#include "i2c-algo-biths.h"/* ----- global defines ----------------------------------------------- *//* If non-zero, adapter code written for original i2c-algo-bit can be used unmodified.  * As this export same symbols, you should either remove i2c-algo-bit.o from depmod * directories, or load this module manually. */#ifndef ALGO_BIT_COMPATIBILITY#define ALGO_BIT_COMPATIBILITY 0#endif#define FATAL_BUS	0#define MODULE_STATUS	1#define FATAL_MSG	2#define FATAL_PROTOCOL	3#define ALL_MSG		4#define ALL_PROTOCOL	5#define BIT_LEVEL	9#define DEB1(x)		if (i2c_debug>=MODULE_STATUS) (x);static void proto_s(char *d, const char *s) { strcat(d, s); }static void proto_x(char *d, const char *x, unsigned char y) { while (*d) d++; sprintf(d, x, y); }#define PROTO_S(x)	if (adap->dstr) proto_s(adap->dstr, x)#define PROTO_B(x)	if ((adap->dstr) && (i2c_debug>=BIT_LEVEL)) proto_s(adap->dstr, x)#define PROTO_X(x,y)	if (adap->dstr) proto_x(adap->dstr, x, y)#define PROTO_MAX_DUMP 1024  // 50 x ".oooooooo [xx] .i[xx]"/* ----- global variables ---------------------------------------------	*//* module parameters: */static int i2c_debug; static int bit_test;	/* see if the line-setting functions work	*//* Bus timing for 50/50 duty cycle :  T_setup + T_hold = T_scllo = T_sclhi *//* Run setscl/setsda with a special flag */#define T_min   0		/* after any SCL SDA change	*/#define T_sclhi _HS_DBL_DT	/* SCL high			*/#define T_scllo	_HS_DBL_DT	/* SCL low 			*/#define T_setup 0		/* SDA change to SCL rise	*/#define T_hold  0		/* SCL fall to SDA change	*/#define _sf(a)		adap->ctrl|=(a)#define _cf(a)		adap->ctrl&=~(a)#define ___setscl(b)	if (b) _sf(_HS_SCL); else _cf(_HS_SCL); i2c_setscl(adap)#define ___setsda(b)	if (b) _sf(_HS_SDA); else _cf(_HS_SDA); i2c_setsda(adap)#define __setdt(x,dt)	if (dt) _sf(dt); x; if (dt) _cf(dt)#define __setscl(b,dt)	__setdt(___setscl(b),dt)#define __setsda(b,dt)	__setdt(___setsda(b),dt)#define __getscl()	i2c_getscl(adap)#define __getsda()	i2c_getsda(adap)#define RETURN_ON_FAILURE(x)		x; if (adap->errors) return#define TRY(x) RETURN_ON_FAILURE(x)#define _setscl(b,dt)	RETURN_ON_FAILURE(__setscl(b,dt))#define _setsda(b,dt)	RETURN_ON_FAILURE(__setsda(b,dt))#define _getscl		__getscl#define _getsda		__getsda#define _sclhi(dt)	_setscl(1,dt)#define _scllo(dt)	_setscl(0,dt)#define _sdahi(dt)	_setsda(1,dt)#define _sdalo(dt)	_setsda(0,dt)/* --- setting states on the bus with the right timing: ---------------	*/static int i2c_sda_set(struct i2c_algo_biths_data *adap, int rdcount){	int sda;	/* allow some rise/fall time */	while ( rdcount-- ) {		sda = adap->getsda(adap->hw_data);		if (adap->ctrl & _HS_SDA) {			if (sda)				return 0;			if (!rdcount) {				adap->errors |= _HS_SDA_ARB;				return -1;			}		} else { /* !(adap->ctrl & _HS_SDA) */			if (!sda)				return 0;			if (!rdcount) {				adap->errors |= _HS_HW_FAIL;				return -1;			}		}	}	return 0;}static void i2c_setsda(struct i2c_algo_biths_data *adap){	adap->setstate(adap); 	adap->setsda(adap->hw_data, adap->hw_state);	if ( !(adap->ctrl & _HS_SDA_FREE) && ! i2c_sda_set(adap, 10)) {		return;	}	adap->set_timer(adap);	adap->run_timer(adap);}static int i2c_getscl(struct i2c_algo_biths_data *adap){	return adap->getscl(adap->hw_data);}static int i2c_getsda(struct i2c_algo_biths_data *adap){	return adap->getsda(adap->hw_data);}/* * Raise scl line, and do check for delays. This is necessary for slower * devices. */static void i2c_setscl(struct i2c_algo_biths_data *adap){#ifndef HW_CANNOT_READ_SCL /* Not all adapters have scl sense line... */	int rdcount = 10;	adap->setstate(adap);	adap->setscl(adap->hw_data, adap->hw_state);	if (adap->ctrl & _HS_SCL) {		unsigned long start;		/* allow some rise time */		while (rdcount && !adap->getscl(adap->hw_data)) rdcount--;		/* else clock synchronisation, give more time */		start = jiffies;		while (!rdcount && !adap->getscl(adap->hw_data)) {			if ( time_after(jiffies, start+adap->timeout) ) {				adap->errors |= _HS_TIMEOUT; /* scl undef */				return;			}#ifdef cond_resched			cond_resched();#else			if (current->need_resched) {				set_current_state(TASK_UNINTERRUPTIBLE);				schedule_timeout(1);			}#endif		}		adap->set_timer(adap);		/* test for SDA arbitration when SCL is high */		if ( !(adap->ctrl & _HS_SDA_FREE) && ! i2c_sda_set(adap, 1)) {			return;		}	} else {		/* allow some fall time */		while (rdcount && adap->getscl(adap->hw_data)) rdcount--;		if ( !rdcount ) {			adap->errors |= _HS_HW_FAIL;			return;		}		adap->set_timer(adap);	}#else	adap->setstate(adap);	adap->setscl(adap->hw_data, adap->hw_state);	adap->set_timer(adap);#endif /* HW_CANNOT_READ_SCL */	adap->run_timer(adap);}/* start, repstart */static void i2c_start(struct i2c_algo_biths_data *adap){	PROTO_S("S");	/* assert: scl, sda undef */	adap->errors = 0;	_sdahi(T_setup);	_sclhi(T_min);	_sdalo(T_min);	_scllo(T_hold);	/* assert: scl, sda low */}static void i2c_stop(struct i2c_algo_biths_data *adap){	PROTO_S(" P");	/* scl undef after error, sda, scl freedom unknown */	adap->ctrl &= ~(_HS_SDA_FREE | _HS_DBL_DT);	if (adap->errors) {		adap->errors = 0;		_scllo(T_hold);	}	/* assert: scl low, sda undef */	_sdalo(T_setup);	_sclhi(T_min);	_sdahi(T_min);	/* assert: scl, sda high */}static void i2c_outbits(struct i2c_algo_biths_data *adap, int i) {	/* assert: scl is low */	PROTO_B(".");	while  (i--) {		PROTO_B("o");		_setsda(adap->shiftreg & 0x80, T_setup);		_sclhi(T_sclhi);		_scllo(T_hold);		adap->shiftreg<<=1;	}	/* assert: scl is low */}static void i2c_inbits(struct i2c_algo_biths_data *adap, int i){	/* assert: scl is low, sda undef */	adap->ctrl |= _HS_SDA_FREE;	PROTO_B(".");	while  (i--) {		PROTO_B("i");		_sdahi(T_setup); 		_sclhi(T_sclhi);			adap->shiftreg<<=1;		if (_getsda())			adap->shiftreg |= 0x01;		_scllo(T_hold);	}	adap->ctrl &= ~_HS_SDA_FREE;	/* assert: scl is low */}static void i2c_outb(struct i2c_algo_biths_data *adap, unsigned short flags,		     char *buf, int *count) {	while (*count) {		adap->shiftreg = *buf;		TRY(i2c_outbits(adap, 8));		PROTO_X(" %02X ", *buf);		buf++;	    		/* read ack: SDA should be pulled down by slave */		TRY(i2c_inbits(adap, 1));	    		if (! (adap->shiftreg & 0x01)) { 			PROTO_S("[A]");		} else if (flags & I2C_M_IGNORE_NAK) {			PROTO_S("[NA]");		} else {			PROTO_S("[NA]");			adap->errors |= _HS_NAK;		}		if (adap->errors) return;		(*count)--;	}}static void i2c_inb(struct i2c_algo_biths_data *adap, unsigned short flags,		    char *buf, int *count) {	while (*count) {		TRY(i2c_inbits(adap, 8));		*buf = adap->shiftreg;		PROTO_X(" [%02X] ", *buf);		buf++;	    		if (! (flags & I2C_M_NO_RD_ACK)) {			if (*count == 1) /* was last */				adap->shiftreg = 0x80;			else				adap->shiftreg = 0x00;			TRY(i2c_outbits(adap,1));			if (*count == 1) {				PROTO_S("NA");			} else {				PROTO_S("A");			}		}		(*count)--;	}}static void debug_protocol(struct i2c_algo_biths_data *adap, int retval){	if (! adap->dstr) return;	if ( ((retval<0) && (i2c_debug>=FATAL_PROTOCOL)) || 	     (i2c_debug>=ALL_PROTOCOL) ) {		printk(KERN_DEBUG "i2c-algo-biths.o: %s: %s\n", adap->name, adap->dstr); 	}	*adap->dstr = 0;}static const char * i2c_strerr(int retval){ 	switch (retval) {	    case 2:		    return "ack";			    case 1:		    return "no ack (ignored)";	    case 0:		    return "not reached";	    case -EREMOTEIO:		    return "no ack";	    case -ETIMEDOUT:		    return "SCL rise timeout";	 	    case -ECOMM:		    return "SDA arbitration";	    case -ENODEV:		    return "SCL/SDA failure";	    default:		    return "unknown";	}}static int errflag(int flags){	if (! flags)		return 2;	if (flags & _HS_HW_FAIL)		return -ENODEV;	if (flags & _HS_SDA_ARB)		return -ECOMM;	if (flags & _HS_TIMEOUT)		return -ETIMEDOUT;	if (flags & _HS_NAK)		return -EREMOTEIO;	return -1;}static void debug_printout(struct i2c_adapter *i2c_adap, int num, int retval){ 	if ( ((retval<0) && (i2c_debug>=FATAL_MSG)) ||	     (i2c_debug>=ALL_MSG) ) {		printk(KERN_ERR "i2c-algo-biths.o: %s: msg #%d %s\n", i2c_adap->name, num, i2c_strerr(retval));	}}/* * Sanity check for the adapter hardware */static int test_bus(struct i2c_algo_biths_data *adap){	int sscl, ssda, gscl, gsda, i=0;	int errors;	int test[][2] = {{1,1}, {0,1}, {1,1}, {1,0}, {1,1}, {-1,-1}}; // SDA, SCL pair

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -