📄 i2c-algo-biths.c
字号:
/* ------------------------------------------------------------------------- *//* 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 + -