Creation of Cybook 2416 (actually Gen4) repository
This commit is contained in:
53
drivers/i2c/algos/Kconfig
Normal file
53
drivers/i2c/algos/Kconfig
Normal file
@@ -0,0 +1,53 @@
|
||||
#
|
||||
# Character device configuration
|
||||
#
|
||||
|
||||
menu "I2C Algorithms"
|
||||
depends on I2C
|
||||
|
||||
config I2C_ALGOBIT
|
||||
tristate "I2C bit-banging interfaces"
|
||||
depends on I2C
|
||||
help
|
||||
This allows you to use a range of I2C adapters called bit-banging
|
||||
adapters. Say Y if you own an I2C adapter belonging to this class
|
||||
and then say Y to the specific driver for you adapter below.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-algo-bit.
|
||||
|
||||
config I2C_ALGOPCF
|
||||
tristate "I2C PCF 8584 interfaces"
|
||||
depends on I2C
|
||||
help
|
||||
This allows you to use a range of I2C adapters called PCF adapters.
|
||||
Say Y if you own an I2C adapter belonging to this class and then say
|
||||
Y to the specific driver for you adapter below.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-algo-pcf.
|
||||
|
||||
config I2C_ALGOPCA
|
||||
tristate "I2C PCA 9564 interfaces"
|
||||
depends on I2C
|
||||
help
|
||||
This allows you to use a range of I2C adapters called PCA adapters.
|
||||
Say Y if you own an I2C adapter belonging to this class and then say
|
||||
Y to the specific driver for you adapter below.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-algo-pca.
|
||||
|
||||
config I2C_ALGO8XX
|
||||
tristate "MPC8xx CPM I2C interface"
|
||||
depends on 8xx && I2C
|
||||
|
||||
config I2C_ALGO_SGI
|
||||
tristate "I2C SGI interfaces"
|
||||
depends on I2C && (SGI_IP22 || SGI_IP32 || X86_VISWS)
|
||||
help
|
||||
Supports the SGI interfaces like the ones found on SGI Indy VINO
|
||||
or SGI O2 MACE.
|
||||
|
||||
endmenu
|
||||
|
||||
12
drivers/i2c/algos/Makefile
Normal file
12
drivers/i2c/algos/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
#
|
||||
# Makefile for the i2c algorithms
|
||||
#
|
||||
|
||||
obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o
|
||||
obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o
|
||||
obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o
|
||||
obj-$(CONFIG_I2C_ALGO_SGI) += i2c-algo-sgi.o
|
||||
|
||||
ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
|
||||
EXTRA_CFLAGS += -DDEBUG
|
||||
endif
|
||||
554
drivers/i2c/algos/i2c-algo-bit.c
Normal file
554
drivers/i2c/algos/i2c-algo-bit.c
Normal file
@@ -0,0 +1,554 @@
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* i2c-algo-bit.c i2c driver algorithms for bit-shift adapters */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Copyright (C) 1995-2000 Simon G. Vogl
|
||||
|
||||
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. */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* With some changes from Frodo Looijaard <frodol@dds.nl>, Ky<4B>sti M<>lkki
|
||||
<kmalkki@cc.hut.fi> and Jean Delvare <khali@linux-fr.org> */
|
||||
|
||||
#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 <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
|
||||
|
||||
/* ----- global defines ----------------------------------------------- */
|
||||
#define DEB(x) if (i2c_debug>=1) x;
|
||||
#define DEB2(x) if (i2c_debug>=2) x;
|
||||
#define DEBSTAT(x) if (i2c_debug>=3) x; /* print several statistical values*/
|
||||
#define DEBPROTO(x) if (i2c_debug>=9) { x; }
|
||||
/* debug the protocol by showing transferred bits */
|
||||
|
||||
|
||||
/* ----- global variables --------------------------------------------- */
|
||||
|
||||
/* module parameters:
|
||||
*/
|
||||
static int i2c_debug;
|
||||
static int bit_test; /* see if the line-setting functions work */
|
||||
|
||||
/* --- setting states on the bus with the right timing: --------------- */
|
||||
|
||||
#define setsda(adap,val) adap->setsda(adap->data, val)
|
||||
#define setscl(adap,val) adap->setscl(adap->data, val)
|
||||
#define getsda(adap) adap->getsda(adap->data)
|
||||
#define getscl(adap) adap->getscl(adap->data)
|
||||
|
||||
static inline void sdalo(struct i2c_algo_bit_data *adap)
|
||||
{
|
||||
setsda(adap,0);
|
||||
udelay(adap->udelay);
|
||||
}
|
||||
|
||||
static inline void sdahi(struct i2c_algo_bit_data *adap)
|
||||
{
|
||||
setsda(adap,1);
|
||||
udelay(adap->udelay);
|
||||
}
|
||||
|
||||
static inline void scllo(struct i2c_algo_bit_data *adap)
|
||||
{
|
||||
setscl(adap,0);
|
||||
udelay(adap->udelay);
|
||||
}
|
||||
|
||||
/*
|
||||
* Raise scl line, and do checking for delays. This is necessary for slower
|
||||
* devices.
|
||||
*/
|
||||
static int sclhi(struct i2c_algo_bit_data *adap)
|
||||
{
|
||||
unsigned long start;
|
||||
|
||||
setscl(adap,1);
|
||||
|
||||
/* Not all adapters have scl sense line... */
|
||||
if (!adap->getscl)
|
||||
goto done;
|
||||
|
||||
start=jiffies;
|
||||
while (! getscl(adap) ) {
|
||||
/* the hw knows how to read the clock line,
|
||||
* so we wait until it actually gets high.
|
||||
* This is safer as some chips may hold it low
|
||||
* while they are processing data internally.
|
||||
*/
|
||||
if (time_after_eq(jiffies, start+adap->timeout)) {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
cond_resched();
|
||||
}
|
||||
DEBSTAT(printk(KERN_DEBUG "needed %ld jiffies\n", jiffies-start));
|
||||
|
||||
done:
|
||||
udelay(adap->udelay);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* --- other auxiliary functions -------------------------------------- */
|
||||
static void i2c_start(struct i2c_algo_bit_data *adap)
|
||||
{
|
||||
/* assert: scl, sda are high */
|
||||
DEBPROTO(printk("S "));
|
||||
sdalo(adap);
|
||||
scllo(adap);
|
||||
}
|
||||
|
||||
static void i2c_repstart(struct i2c_algo_bit_data *adap)
|
||||
{
|
||||
/* scl, sda may not be high */
|
||||
DEBPROTO(printk(" Sr "));
|
||||
setsda(adap,1);
|
||||
sclhi(adap);
|
||||
|
||||
sdalo(adap);
|
||||
scllo(adap);
|
||||
}
|
||||
|
||||
|
||||
static void i2c_stop(struct i2c_algo_bit_data *adap)
|
||||
{
|
||||
DEBPROTO(printk("P\n"));
|
||||
/* assert: scl is low */
|
||||
sdalo(adap);
|
||||
sclhi(adap);
|
||||
sdahi(adap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* send a byte without start cond., look for arbitration,
|
||||
check ackn. from slave */
|
||||
/* returns:
|
||||
* 1 if the device acknowledged
|
||||
* 0 if the device did not ack
|
||||
* -ETIMEDOUT if an error occurred (while raising the scl line)
|
||||
*/
|
||||
static int i2c_outb(struct i2c_adapter *i2c_adap, char c)
|
||||
{
|
||||
int i;
|
||||
int sb;
|
||||
int ack;
|
||||
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
|
||||
|
||||
/* assert: scl is low */
|
||||
for ( i=7 ; i>=0 ; i-- ) {
|
||||
sb = c & ( 1 << i );
|
||||
setsda(adap,sb);
|
||||
udelay(adap->udelay);
|
||||
DEBPROTO(printk(KERN_DEBUG "%d",sb!=0));
|
||||
if (sclhi(adap)<0) { /* timed out */
|
||||
sdahi(adap); /* we don't want to block the net */
|
||||
DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at bit #%d\n", c&0xff, i));
|
||||
return -ETIMEDOUT;
|
||||
};
|
||||
/* do arbitration here:
|
||||
* if ( sb && ! getsda(adap) ) -> ouch! Get out of here.
|
||||
*/
|
||||
setscl(adap, 0 );
|
||||
udelay(adap->udelay);
|
||||
}
|
||||
sdahi(adap);
|
||||
if (sclhi(adap)<0){ /* timeout */
|
||||
DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at ack\n", c&0xff));
|
||||
return -ETIMEDOUT;
|
||||
};
|
||||
/* read ack: SDA should be pulled down by slave */
|
||||
ack=getsda(adap); /* ack: sda is pulled low ->success. */
|
||||
DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x , getsda() = %d\n", c & 0xff, ack));
|
||||
|
||||
DEBPROTO( printk(KERN_DEBUG "[%2.2x]",c&0xff) );
|
||||
DEBPROTO(if (0==ack){ printk(KERN_DEBUG " A ");} else printk(KERN_DEBUG " NA ") );
|
||||
scllo(adap);
|
||||
return 0==ack; /* return 1 if device acked */
|
||||
/* assert: scl is low (sda undef) */
|
||||
}
|
||||
|
||||
|
||||
static int i2c_inb(struct i2c_adapter *i2c_adap)
|
||||
{
|
||||
/* read byte via i2c port, without start/stop sequence */
|
||||
/* acknowledge is sent in i2c_read. */
|
||||
int i;
|
||||
unsigned char indata=0;
|
||||
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
|
||||
|
||||
/* assert: scl is low */
|
||||
sdahi(adap);
|
||||
for (i=0;i<8;i++) {
|
||||
if (sclhi(adap)<0) { /* timeout */
|
||||
DEB2(printk(KERN_DEBUG " i2c_inb: timeout at bit #%d\n", 7-i));
|
||||
return -ETIMEDOUT;
|
||||
};
|
||||
indata *= 2;
|
||||
if ( getsda(adap) )
|
||||
indata |= 0x01;
|
||||
scllo(adap);
|
||||
}
|
||||
/* assert: scl is low */
|
||||
DEB2(printk(KERN_DEBUG "i2c_inb: 0x%02x\n", indata & 0xff));
|
||||
|
||||
DEBPROTO(printk(KERN_DEBUG " 0x%02x", indata & 0xff));
|
||||
return (int) (indata & 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sanity check for the adapter hardware - check the reaction of
|
||||
* the bus lines only if it seems to be idle.
|
||||
*/
|
||||
static int test_bus(struct i2c_algo_bit_data *adap, char* name) {
|
||||
int scl,sda;
|
||||
|
||||
if (adap->getscl==NULL)
|
||||
printk(KERN_INFO "i2c-algo-bit.o: Testing SDA only, "
|
||||
"SCL is not readable.\n");
|
||||
|
||||
sda=getsda(adap);
|
||||
scl=(adap->getscl==NULL?1:getscl(adap));
|
||||
printk(KERN_DEBUG "i2c-algo-bit.o: (0) scl=%d, sda=%d\n",scl,sda);
|
||||
if (!scl || !sda ) {
|
||||
printk(KERN_WARNING "i2c-algo-bit.o: %s seems to be busy.\n", name);
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
sdalo(adap);
|
||||
sda=getsda(adap);
|
||||
scl=(adap->getscl==NULL?1:getscl(adap));
|
||||
printk(KERN_DEBUG "i2c-algo-bit.o: (1) scl=%d, sda=%d\n",scl,sda);
|
||||
if ( 0 != sda ) {
|
||||
printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck high!\n");
|
||||
goto bailout;
|
||||
}
|
||||
if ( 0 == scl ) {
|
||||
printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low "
|
||||
"while pulling SDA low!\n");
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
sdahi(adap);
|
||||
sda=getsda(adap);
|
||||
scl=(adap->getscl==NULL?1:getscl(adap));
|
||||
printk(KERN_DEBUG "i2c-algo-bit.o: (2) scl=%d, sda=%d\n",scl,sda);
|
||||
if ( 0 == sda ) {
|
||||
printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck low!\n");
|
||||
goto bailout;
|
||||
}
|
||||
if ( 0 == scl ) {
|
||||
printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low "
|
||||
"while pulling SDA high!\n");
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
scllo(adap);
|
||||
sda=getsda(adap);
|
||||
scl=(adap->getscl==NULL?0:getscl(adap));
|
||||
printk(KERN_DEBUG "i2c-algo-bit.o: (3) scl=%d, sda=%d\n",scl,sda);
|
||||
if ( 0 != scl ) {
|
||||
printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck high!\n");
|
||||
goto bailout;
|
||||
}
|
||||
if ( 0 == sda ) {
|
||||
printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low "
|
||||
"while pulling SCL low!\n");
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
sclhi(adap);
|
||||
sda=getsda(adap);
|
||||
scl=(adap->getscl==NULL?1:getscl(adap));
|
||||
printk(KERN_DEBUG "i2c-algo-bit.o: (4) scl=%d, sda=%d\n",scl,sda);
|
||||
if ( 0 == scl ) {
|
||||
printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck low!\n");
|
||||
goto bailout;
|
||||
}
|
||||
if ( 0 == sda ) {
|
||||
printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low "
|
||||
"while pulling SCL high!\n");
|
||||
goto bailout;
|
||||
}
|
||||
printk(KERN_INFO "i2c-algo-bit.o: %s passed test.\n",name);
|
||||
return 0;
|
||||
bailout:
|
||||
sdahi(adap);
|
||||
sclhi(adap);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* ----- Utility functions
|
||||
*/
|
||||
|
||||
/* try_address tries to contact a chip for a number of
|
||||
* times before it gives up.
|
||||
* return values:
|
||||
* 1 chip answered
|
||||
* 0 chip did not answer
|
||||
* -x transmission error
|
||||
*/
|
||||
static int try_address(struct i2c_adapter *i2c_adap,
|
||||
unsigned char addr, int retries)
|
||||
{
|
||||
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
|
||||
int i,ret = -1;
|
||||
for (i=0;i<=retries;i++) {
|
||||
ret = i2c_outb(i2c_adap,addr);
|
||||
if (ret==1)
|
||||
break; /* success! */
|
||||
i2c_stop(adap);
|
||||
udelay(5/*adap->udelay*/);
|
||||
if (i==retries) /* no success */
|
||||
break;
|
||||
i2c_start(adap);
|
||||
udelay(adap->udelay);
|
||||
}
|
||||
DEB2(if (i)
|
||||
printk(KERN_DEBUG "i2c-algo-bit.o: Used %d tries to %s client at 0x%02x : %s\n",
|
||||
i+1, addr & 1 ? "read" : "write", addr>>1,
|
||||
ret==1 ? "success" : ret==0 ? "no ack" : "failed, timeout?" )
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
|
||||
{
|
||||
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
|
||||
char c;
|
||||
const char *temp = msg->buf;
|
||||
int count = msg->len;
|
||||
unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
|
||||
int retval;
|
||||
int wrcount=0;
|
||||
|
||||
while (count > 0) {
|
||||
c = *temp;
|
||||
DEB2(dev_dbg(&i2c_adap->dev, "sendbytes: writing %2.2X\n", c&0xff));
|
||||
retval = i2c_outb(i2c_adap,c);
|
||||
if ((retval>0) || (nak_ok && (retval==0))) { /* ok or ignored NAK */
|
||||
count--;
|
||||
temp++;
|
||||
wrcount++;
|
||||
} else { /* arbitration or no acknowledge */
|
||||
dev_err(&i2c_adap->dev, "sendbytes: error - bailout.\n");
|
||||
i2c_stop(adap);
|
||||
return (retval<0)? retval : -EFAULT;
|
||||
/* got a better one ?? */
|
||||
}
|
||||
}
|
||||
return wrcount;
|
||||
}
|
||||
|
||||
static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
|
||||
{
|
||||
int inval;
|
||||
int rdcount=0; /* counts bytes read */
|
||||
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
|
||||
char *temp = msg->buf;
|
||||
int count = msg->len;
|
||||
|
||||
while (count > 0) {
|
||||
inval = i2c_inb(i2c_adap);
|
||||
if (inval>=0) {
|
||||
*temp = inval;
|
||||
rdcount++;
|
||||
} else { /* read timed out */
|
||||
printk(KERN_ERR "i2c-algo-bit.o: readbytes: i2c_inb timed out.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
temp++;
|
||||
count--;
|
||||
|
||||
if (msg->flags & I2C_M_NO_RD_ACK)
|
||||
continue;
|
||||
|
||||
if ( count > 0 ) { /* send ack */
|
||||
sdalo(adap);
|
||||
DEBPROTO(printk(" Am "));
|
||||
} else {
|
||||
sdahi(adap); /* neg. ack on last byte */
|
||||
DEBPROTO(printk(" NAm "));
|
||||
}
|
||||
if (sclhi(adap)<0) { /* timeout */
|
||||
sdahi(adap);
|
||||
printk(KERN_ERR "i2c-algo-bit.o: readbytes: Timeout at ack\n");
|
||||
return -ETIMEDOUT;
|
||||
};
|
||||
scllo(adap);
|
||||
sdahi(adap);
|
||||
}
|
||||
return rdcount;
|
||||
}
|
||||
|
||||
/* doAddress initiates the transfer by generating the start condition (in
|
||||
* try_address) and transmits the address in the necessary format to handle
|
||||
* reads, writes as well as 10bit-addresses.
|
||||
* returns:
|
||||
* 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set
|
||||
* -x an error occurred (like: -EREMOTEIO if the device did not answer, or
|
||||
* -ETIMEDOUT, for example if the lines are stuck...)
|
||||
*/
|
||||
static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
|
||||
{
|
||||
unsigned short flags = msg->flags;
|
||||
unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
|
||||
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
|
||||
|
||||
unsigned char addr;
|
||||
int ret, retries;
|
||||
|
||||
retries = nak_ok ? 0 : i2c_adap->retries;
|
||||
|
||||
if ( (flags & I2C_M_TEN) ) {
|
||||
/* a ten bit address */
|
||||
addr = 0xf0 | (( msg->addr >> 7) & 0x03);
|
||||
DEB2(printk(KERN_DEBUG "addr0: %d\n",addr));
|
||||
/* try extended address code...*/
|
||||
ret = try_address(i2c_adap, addr, retries);
|
||||
if ((ret != 1) && !nak_ok) {
|
||||
printk(KERN_ERR "died at extended address code.\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
/* the remaining 8 bit address */
|
||||
ret = i2c_outb(i2c_adap,msg->addr & 0x7f);
|
||||
if ((ret != 1) && !nak_ok) {
|
||||
/* the chip did not ack / xmission error occurred */
|
||||
printk(KERN_ERR "died at 2nd address code.\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
if ( flags & I2C_M_RD ) {
|
||||
i2c_repstart(adap);
|
||||
/* okay, now switch into reading mode */
|
||||
addr |= 0x01;
|
||||
ret = try_address(i2c_adap, addr, retries);
|
||||
if ((ret!=1) && !nak_ok) {
|
||||
printk(KERN_ERR "died at extended address code.\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
}
|
||||
} else { /* normal 7bit address */
|
||||
addr = ( msg->addr << 1 );
|
||||
if (flags & I2C_M_RD )
|
||||
addr |= 1;
|
||||
if (flags & I2C_M_REV_DIR_ADDR )
|
||||
addr ^= 1;
|
||||
ret = try_address(i2c_adap, addr, retries);
|
||||
if ((ret!=1) && !nak_ok)
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bit_xfer(struct i2c_adapter *i2c_adap,
|
||||
struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct i2c_msg *pmsg;
|
||||
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
|
||||
|
||||
int i,ret;
|
||||
unsigned short nak_ok;
|
||||
|
||||
i2c_start(adap);
|
||||
for (i=0;i<num;i++) {
|
||||
pmsg = &msgs[i];
|
||||
nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;
|
||||
if (!(pmsg->flags & I2C_M_NOSTART)) {
|
||||
if (i) {
|
||||
i2c_repstart(adap);
|
||||
}
|
||||
ret = bit_doAddress(i2c_adap, pmsg);
|
||||
if ((ret != 0) && !nak_ok) {
|
||||
DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: NAK from device addr %2.2x msg #%d\n"
|
||||
,msgs[i].addr,i));
|
||||
return (ret<0) ? ret : -EREMOTEIO;
|
||||
}
|
||||
}
|
||||
if (pmsg->flags & I2C_M_RD ) {
|
||||
/* read bytes into buffer*/
|
||||
ret = readbytes(i2c_adap, pmsg);
|
||||
DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: read %d bytes.\n",ret));
|
||||
if (ret < pmsg->len ) {
|
||||
return (ret<0)? ret : -EREMOTEIO;
|
||||
}
|
||||
} else {
|
||||
/* write bytes from buffer */
|
||||
ret = sendbytes(i2c_adap, pmsg);
|
||||
DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: wrote %d bytes.\n",ret));
|
||||
if (ret < pmsg->len ) {
|
||||
return (ret<0) ? ret : -EREMOTEIO;
|
||||
}
|
||||
}
|
||||
}
|
||||
i2c_stop(adap);
|
||||
return num;
|
||||
}
|
||||
|
||||
static u32 bit_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
|
||||
I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
|
||||
}
|
||||
|
||||
|
||||
/* -----exported algorithm data: ------------------------------------- */
|
||||
|
||||
static const struct i2c_algorithm i2c_bit_algo = {
|
||||
.master_xfer = bit_xfer,
|
||||
.functionality = bit_func,
|
||||
};
|
||||
|
||||
/*
|
||||
* registering functions to load algorithms at runtime
|
||||
*/
|
||||
int i2c_bit_add_bus(struct i2c_adapter *adap)
|
||||
{
|
||||
struct i2c_algo_bit_data *bit_adap = adap->algo_data;
|
||||
|
||||
if (bit_test) {
|
||||
int ret = test_bus(bit_adap, adap->name);
|
||||
if (ret<0)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
DEB2(dev_dbg(&adap->dev, "hw routines registered.\n"));
|
||||
|
||||
/* register new adapter to i2c module... */
|
||||
adap->algo = &i2c_bit_algo;
|
||||
|
||||
adap->timeout = 100; /* default values, should */
|
||||
adap->retries = 3; /* be replaced by defines */
|
||||
|
||||
return i2c_add_adapter(adap);
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_bit_add_bus);
|
||||
|
||||
MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
|
||||
MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_param(bit_test, bool, 0);
|
||||
module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
|
||||
|
||||
MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck");
|
||||
MODULE_PARM_DESC(i2c_debug,
|
||||
"debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol");
|
||||
390
drivers/i2c/algos/i2c-algo-pca.c
Normal file
390
drivers/i2c/algos/i2c-algo-pca.c
Normal file
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
* i2c-algo-pca.c i2c driver algorithms for PCA9564 adapters
|
||||
* Copyright (C) 2004 Arcom Control Systems
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-pca.h>
|
||||
#include "i2c-algo-pca.h"
|
||||
|
||||
#define DRIVER "i2c-algo-pca"
|
||||
|
||||
#define DEB1(fmt, args...) do { if (i2c_debug>=1) printk(fmt, ## args); } while(0)
|
||||
#define DEB2(fmt, args...) do { if (i2c_debug>=2) printk(fmt, ## args); } while(0)
|
||||
#define DEB3(fmt, args...) do { if (i2c_debug>=3) printk(fmt, ## args); } while(0)
|
||||
|
||||
static int i2c_debug;
|
||||
|
||||
#define pca_outw(adap, reg, val) adap->write_byte(adap, reg, val)
|
||||
#define pca_inw(adap, reg) adap->read_byte(adap, reg)
|
||||
|
||||
#define pca_status(adap) pca_inw(adap, I2C_PCA_STA)
|
||||
#define pca_clock(adap) adap->get_clock(adap)
|
||||
#define pca_own(adap) adap->get_own(adap)
|
||||
#define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val)
|
||||
#define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON)
|
||||
#define pca_wait(adap) adap->wait_for_interrupt(adap)
|
||||
|
||||
/*
|
||||
* Generate a start condition on the i2c bus.
|
||||
*
|
||||
* returns after the start condition has occurred
|
||||
*/
|
||||
static void pca_start(struct i2c_algo_pca_data *adap)
|
||||
{
|
||||
int sta = pca_get_con(adap);
|
||||
DEB2("=== START\n");
|
||||
sta |= I2C_PCA_CON_STA;
|
||||
sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI);
|
||||
pca_set_con(adap, sta);
|
||||
pca_wait(adap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a repeated start condition on the i2c bus
|
||||
*
|
||||
* return after the repeated start condition has occurred
|
||||
*/
|
||||
static void pca_repeated_start(struct i2c_algo_pca_data *adap)
|
||||
{
|
||||
int sta = pca_get_con(adap);
|
||||
DEB2("=== REPEATED START\n");
|
||||
sta |= I2C_PCA_CON_STA;
|
||||
sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI);
|
||||
pca_set_con(adap, sta);
|
||||
pca_wait(adap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a stop condition on the i2c bus
|
||||
*
|
||||
* returns after the stop condition has been generated
|
||||
*
|
||||
* STOPs do not generate an interrupt or set the SI flag, since the
|
||||
* part returns the idle state (0xf8). Hence we don't need to
|
||||
* pca_wait here.
|
||||
*/
|
||||
static void pca_stop(struct i2c_algo_pca_data *adap)
|
||||
{
|
||||
int sta = pca_get_con(adap);
|
||||
DEB2("=== STOP\n");
|
||||
sta |= I2C_PCA_CON_STO;
|
||||
sta &= ~(I2C_PCA_CON_STA|I2C_PCA_CON_SI);
|
||||
pca_set_con(adap, sta);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the slave address and R/W bit
|
||||
*
|
||||
* returns after the address has been sent
|
||||
*/
|
||||
static void pca_address(struct i2c_algo_pca_data *adap,
|
||||
struct i2c_msg *msg)
|
||||
{
|
||||
int sta = pca_get_con(adap);
|
||||
int addr;
|
||||
|
||||
addr = ( (0x7f & msg->addr) << 1 );
|
||||
if (msg->flags & I2C_M_RD )
|
||||
addr |= 1;
|
||||
DEB2("=== SLAVE ADDRESS %#04x+%c=%#04x\n",
|
||||
msg->addr, msg->flags & I2C_M_RD ? 'R' : 'W', addr);
|
||||
|
||||
pca_outw(adap, I2C_PCA_DAT, addr);
|
||||
|
||||
sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI);
|
||||
pca_set_con(adap, sta);
|
||||
|
||||
pca_wait(adap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Transmit a byte.
|
||||
*
|
||||
* Returns after the byte has been transmitted
|
||||
*/
|
||||
static void pca_tx_byte(struct i2c_algo_pca_data *adap,
|
||||
__u8 b)
|
||||
{
|
||||
int sta = pca_get_con(adap);
|
||||
DEB2("=== WRITE %#04x\n", b);
|
||||
pca_outw(adap, I2C_PCA_DAT, b);
|
||||
|
||||
sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI);
|
||||
pca_set_con(adap, sta);
|
||||
|
||||
pca_wait(adap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive a byte
|
||||
*
|
||||
* returns immediately.
|
||||
*/
|
||||
static void pca_rx_byte(struct i2c_algo_pca_data *adap,
|
||||
__u8 *b, int ack)
|
||||
{
|
||||
*b = pca_inw(adap, I2C_PCA_DAT);
|
||||
DEB2("=== READ %#04x %s\n", *b, ack ? "ACK" : "NACK");
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup ACK or NACK for next received byte and wait for it to arrive.
|
||||
*
|
||||
* Returns after next byte has arrived.
|
||||
*/
|
||||
static void pca_rx_ack(struct i2c_algo_pca_data *adap,
|
||||
int ack)
|
||||
{
|
||||
int sta = pca_get_con(adap);
|
||||
|
||||
sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI|I2C_PCA_CON_AA);
|
||||
|
||||
if ( ack )
|
||||
sta |= I2C_PCA_CON_AA;
|
||||
|
||||
pca_set_con(adap, sta);
|
||||
pca_wait(adap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the i2c bus / SIO
|
||||
*/
|
||||
static void pca_reset(struct i2c_algo_pca_data *adap)
|
||||
{
|
||||
/* apparently only an external reset will do it. not a lot can be done */
|
||||
printk(KERN_ERR DRIVER ": Haven't figured out how to do a reset yet\n");
|
||||
}
|
||||
|
||||
static int pca_xfer(struct i2c_adapter *i2c_adap,
|
||||
struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
struct i2c_algo_pca_data *adap = i2c_adap->algo_data;
|
||||
struct i2c_msg *msg = NULL;
|
||||
int curmsg;
|
||||
int numbytes = 0;
|
||||
int state;
|
||||
int ret;
|
||||
int timeout = 100;
|
||||
|
||||
while ((state = pca_status(adap)) != 0xf8 && timeout--) {
|
||||
msleep(10);
|
||||
}
|
||||
if (state != 0xf8) {
|
||||
dev_dbg(&i2c_adap->dev, "bus is not idle. status is %#04x\n", state);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
DEB1("{{{ XFER %d messages\n", num);
|
||||
|
||||
if (i2c_debug>=2) {
|
||||
for (curmsg = 0; curmsg < num; curmsg++) {
|
||||
int addr, i;
|
||||
msg = &msgs[curmsg];
|
||||
|
||||
addr = (0x7f & msg->addr) ;
|
||||
|
||||
if (msg->flags & I2C_M_RD )
|
||||
printk(KERN_INFO " [%02d] RD %d bytes from %#02x [%#02x, ...]\n",
|
||||
curmsg, msg->len, addr, (addr<<1) | 1);
|
||||
else {
|
||||
printk(KERN_INFO " [%02d] WR %d bytes to %#02x [%#02x%s",
|
||||
curmsg, msg->len, addr, addr<<1,
|
||||
msg->len == 0 ? "" : ", ");
|
||||
for(i=0; i < msg->len; i++)
|
||||
printk("%#04x%s", msg->buf[i], i == msg->len - 1 ? "" : ", ");
|
||||
printk("]\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
curmsg = 0;
|
||||
ret = -EREMOTEIO;
|
||||
while (curmsg < num) {
|
||||
state = pca_status(adap);
|
||||
|
||||
DEB3("STATE is 0x%02x\n", state);
|
||||
msg = &msgs[curmsg];
|
||||
|
||||
switch (state) {
|
||||
case 0xf8: /* On reset or stop the bus is idle */
|
||||
pca_start(adap);
|
||||
break;
|
||||
|
||||
case 0x08: /* A START condition has been transmitted */
|
||||
case 0x10: /* A repeated start condition has been transmitted */
|
||||
pca_address(adap, msg);
|
||||
break;
|
||||
|
||||
case 0x18: /* SLA+W has been transmitted; ACK has been received */
|
||||
case 0x28: /* Data byte in I2CDAT has been transmitted; ACK has been received */
|
||||
if (numbytes < msg->len) {
|
||||
pca_tx_byte(adap, msg->buf[numbytes]);
|
||||
numbytes++;
|
||||
break;
|
||||
}
|
||||
curmsg++; numbytes = 0;
|
||||
if (curmsg == num)
|
||||
pca_stop(adap);
|
||||
else
|
||||
pca_repeated_start(adap);
|
||||
break;
|
||||
|
||||
case 0x20: /* SLA+W has been transmitted; NOT ACK has been received */
|
||||
DEB2("NOT ACK received after SLA+W\n");
|
||||
pca_stop(adap);
|
||||
goto out;
|
||||
|
||||
case 0x40: /* SLA+R has been transmitted; ACK has been received */
|
||||
pca_rx_ack(adap, msg->len > 1);
|
||||
break;
|
||||
|
||||
case 0x50: /* Data bytes has been received; ACK has been returned */
|
||||
if (numbytes < msg->len) {
|
||||
pca_rx_byte(adap, &msg->buf[numbytes], 1);
|
||||
numbytes++;
|
||||
pca_rx_ack(adap, numbytes < msg->len - 1);
|
||||
break;
|
||||
}
|
||||
curmsg++; numbytes = 0;
|
||||
if (curmsg == num)
|
||||
pca_stop(adap);
|
||||
else
|
||||
pca_repeated_start(adap);
|
||||
break;
|
||||
|
||||
case 0x48: /* SLA+R has been transmitted; NOT ACK has been received */
|
||||
DEB2("NOT ACK received after SLA+R\n");
|
||||
pca_stop(adap);
|
||||
goto out;
|
||||
|
||||
case 0x30: /* Data byte in I2CDAT has been transmitted; NOT ACK has been received */
|
||||
DEB2("NOT ACK received after data byte\n");
|
||||
goto out;
|
||||
|
||||
case 0x38: /* Arbitration lost during SLA+W, SLA+R or data bytes */
|
||||
DEB2("Arbitration lost\n");
|
||||
goto out;
|
||||
|
||||
case 0x58: /* Data byte has been received; NOT ACK has been returned */
|
||||
if ( numbytes == msg->len - 1 ) {
|
||||
pca_rx_byte(adap, &msg->buf[numbytes], 0);
|
||||
curmsg++; numbytes = 0;
|
||||
if (curmsg == num)
|
||||
pca_stop(adap);
|
||||
else
|
||||
pca_repeated_start(adap);
|
||||
} else {
|
||||
DEB2("NOT ACK sent after data byte received. "
|
||||
"Not final byte. numbytes %d. len %d\n",
|
||||
numbytes, msg->len);
|
||||
pca_stop(adap);
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
case 0x70: /* Bus error - SDA stuck low */
|
||||
DEB2("BUS ERROR - SDA Stuck low\n");
|
||||
pca_reset(adap);
|
||||
goto out;
|
||||
case 0x90: /* Bus error - SCL stuck low */
|
||||
DEB2("BUS ERROR - SCL Stuck low\n");
|
||||
pca_reset(adap);
|
||||
goto out;
|
||||
case 0x00: /* Bus error during master or slave mode due to illegal START or STOP condition */
|
||||
DEB2("BUS ERROR - Illegal START or STOP\n");
|
||||
pca_reset(adap);
|
||||
goto out;
|
||||
default:
|
||||
printk(KERN_ERR DRIVER ": unhandled SIO state 0x%02x\n", state);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ret = curmsg;
|
||||
out:
|
||||
DEB1(KERN_CRIT "}}} transfered %d/%d messages. "
|
||||
"status is %#04x. control is %#04x\n",
|
||||
curmsg, num, pca_status(adap),
|
||||
pca_get_con(adap));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 pca_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static int pca_init(struct i2c_algo_pca_data *adap)
|
||||
{
|
||||
static int freqs[] = {330,288,217,146,88,59,44,36};
|
||||
int own, clock;
|
||||
|
||||
own = pca_own(adap);
|
||||
clock = pca_clock(adap);
|
||||
DEB1(KERN_INFO DRIVER ": own address is %#04x\n", own);
|
||||
DEB1(KERN_INFO DRIVER ": clock freqeuncy is %dkHz\n", freqs[clock]);
|
||||
|
||||
pca_outw(adap, I2C_PCA_ADR, own << 1);
|
||||
|
||||
pca_set_con(adap, I2C_PCA_CON_ENSIO | clock);
|
||||
udelay(500); /* 500 <20>s for oscilator to stabilise */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm pca_algo = {
|
||||
.master_xfer = pca_xfer,
|
||||
.functionality = pca_func,
|
||||
};
|
||||
|
||||
/*
|
||||
* registering functions to load algorithms at runtime
|
||||
*/
|
||||
int i2c_pca_add_bus(struct i2c_adapter *adap)
|
||||
{
|
||||
struct i2c_algo_pca_data *pca_adap = adap->algo_data;
|
||||
int rval;
|
||||
|
||||
/* register new adapter to i2c module... */
|
||||
adap->algo = &pca_algo;
|
||||
|
||||
adap->timeout = 100; /* default values, should */
|
||||
adap->retries = 3; /* be replaced by defines */
|
||||
|
||||
if ((rval = pca_init(pca_adap)))
|
||||
return rval;
|
||||
|
||||
rval = i2c_add_adapter(adap);
|
||||
|
||||
return rval;
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_pca_add_bus);
|
||||
|
||||
MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
|
||||
MODULE_DESCRIPTION("I2C-Bus PCA9564 algorithm");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_param(i2c_debug, int, 0);
|
||||
26
drivers/i2c/algos/i2c-algo-pca.h
Normal file
26
drivers/i2c/algos/i2c-algo-pca.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef I2C_PCA9564_H
|
||||
#define I2C_PCA9564_H 1
|
||||
|
||||
#define I2C_PCA_STA 0x00 /* STATUS Read Only */
|
||||
#define I2C_PCA_TO 0x00 /* TIMEOUT Write Only */
|
||||
#define I2C_PCA_DAT 0x01 /* DATA Read/Write */
|
||||
#define I2C_PCA_ADR 0x02 /* OWN ADR Read/Write */
|
||||
#define I2C_PCA_CON 0x03 /* CONTROL Read/Write */
|
||||
|
||||
#define I2C_PCA_CON_AA 0x80 /* Assert Acknowledge */
|
||||
#define I2C_PCA_CON_ENSIO 0x40 /* Enable */
|
||||
#define I2C_PCA_CON_STA 0x20 /* Start */
|
||||
#define I2C_PCA_CON_STO 0x10 /* Stop */
|
||||
#define I2C_PCA_CON_SI 0x08 /* Serial Interrupt */
|
||||
#define I2C_PCA_CON_CR 0x07 /* Clock Rate (MASK) */
|
||||
|
||||
#define I2C_PCA_CON_330kHz 0x00
|
||||
#define I2C_PCA_CON_288kHz 0x01
|
||||
#define I2C_PCA_CON_217kHz 0x02
|
||||
#define I2C_PCA_CON_146kHz 0x03
|
||||
#define I2C_PCA_CON_88kHz 0x04
|
||||
#define I2C_PCA_CON_59kHz 0x05
|
||||
#define I2C_PCA_CON_44kHz 0x06
|
||||
#define I2C_PCA_CON_36kHz 0x07
|
||||
|
||||
#endif /* I2C_PCA9564_H */
|
||||
497
drivers/i2c/algos/i2c-algo-pcf.c
Normal file
497
drivers/i2c/algos/i2c-algo-pcf.c
Normal file
@@ -0,0 +1,497 @@
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* i2c-algo-pcf.c i2c driver algorithms for PCF8584 adapters */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Copyright (C) 1995-1997 Simon G. Vogl
|
||||
1998-2000 Hans Berglund
|
||||
|
||||
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. */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* With some changes from Ky<4B>sti M<>lkki <kmalkki@cc.hut.fi> and
|
||||
Frodo Looijaard <frodol@dds.nl> ,and also from Martin Bailey
|
||||
<mbailey@littlefeet-inc.com> */
|
||||
|
||||
/* Partially rewriten by Oleg I. Vdovikin <vdovikin@jscc.ru> to handle multiple
|
||||
messages, proper stop/repstart signaling during receive,
|
||||
added detect code */
|
||||
|
||||
#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/i2c.h>
|
||||
#include <linux/i2c-algo-pcf.h>
|
||||
#include "i2c-algo-pcf.h"
|
||||
|
||||
|
||||
#define DEB2(x) if (i2c_debug>=2) x
|
||||
#define DEB3(x) if (i2c_debug>=3) x /* print several statistical values*/
|
||||
#define DEBPROTO(x) if (i2c_debug>=9) x;
|
||||
/* debug the protocol by showing transferred bits */
|
||||
#define DEF_TIMEOUT 16
|
||||
|
||||
/* module parameters:
|
||||
*/
|
||||
static int i2c_debug;
|
||||
|
||||
/* --- setting states on the bus with the right timing: --------------- */
|
||||
|
||||
#define set_pcf(adap, ctl, val) adap->setpcf(adap->data, ctl, val)
|
||||
#define get_pcf(adap, ctl) adap->getpcf(adap->data, ctl)
|
||||
#define get_own(adap) adap->getown(adap->data)
|
||||
#define get_clock(adap) adap->getclock(adap->data)
|
||||
#define i2c_outb(adap, val) adap->setpcf(adap->data, 0, val)
|
||||
#define i2c_inb(adap) adap->getpcf(adap->data, 0)
|
||||
|
||||
/* --- other auxiliary functions -------------------------------------- */
|
||||
|
||||
static void i2c_start(struct i2c_algo_pcf_data *adap)
|
||||
{
|
||||
DEBPROTO(printk("S "));
|
||||
set_pcf(adap, 1, I2C_PCF_START);
|
||||
}
|
||||
|
||||
static void i2c_repstart(struct i2c_algo_pcf_data *adap)
|
||||
{
|
||||
DEBPROTO(printk(" Sr "));
|
||||
set_pcf(adap, 1, I2C_PCF_REPSTART);
|
||||
}
|
||||
|
||||
|
||||
static void i2c_stop(struct i2c_algo_pcf_data *adap)
|
||||
{
|
||||
DEBPROTO(printk("P\n"));
|
||||
set_pcf(adap, 1, I2C_PCF_STOP);
|
||||
}
|
||||
|
||||
static int wait_for_bb(struct i2c_algo_pcf_data *adap) {
|
||||
|
||||
int timeout = DEF_TIMEOUT;
|
||||
int status;
|
||||
|
||||
status = get_pcf(adap, 1);
|
||||
#ifndef STUB_I2C
|
||||
while (timeout-- && !(status & I2C_PCF_BB)) {
|
||||
udelay(100); /* wait for 100 us */
|
||||
status = get_pcf(adap, 1);
|
||||
}
|
||||
#endif
|
||||
if (timeout <= 0) {
|
||||
printk(KERN_ERR "Timeout waiting for Bus Busy\n");
|
||||
}
|
||||
|
||||
return (timeout<=0);
|
||||
}
|
||||
|
||||
|
||||
static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) {
|
||||
|
||||
int timeout = DEF_TIMEOUT;
|
||||
|
||||
*status = get_pcf(adap, 1);
|
||||
#ifndef STUB_I2C
|
||||
while (timeout-- && (*status & I2C_PCF_PIN)) {
|
||||
adap->waitforpin();
|
||||
*status = get_pcf(adap, 1);
|
||||
}
|
||||
if (*status & I2C_PCF_LAB) {
|
||||
DEB2(printk(KERN_INFO
|
||||
"i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n",
|
||||
*status));
|
||||
/* Cleanup from LAB-- reset and enable ESO.
|
||||
* This resets the PCF8584; since we've lost the bus, no
|
||||
* further attempts should be made by callers to clean up
|
||||
* (no i2c_stop() etc.)
|
||||
*/
|
||||
set_pcf(adap, 1, I2C_PCF_PIN);
|
||||
set_pcf(adap, 1, I2C_PCF_ESO);
|
||||
/* TODO: we should pause for a time period sufficient for any
|
||||
* running I2C transaction to complete-- the arbitration
|
||||
* logic won't work properly until the next START is seen.
|
||||
*/
|
||||
DEB2(printk(KERN_INFO
|
||||
"i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n",
|
||||
get_pcf(adap,1)));
|
||||
return(-EINTR);
|
||||
}
|
||||
#endif
|
||||
if (timeout <= 0)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This should perform the 'PCF8584 initialization sequence' as described
|
||||
* in the Philips IC12 data book (1995, Aug 29).
|
||||
* There should be a 30 clock cycle wait after reset, I assume this
|
||||
* has been fulfilled.
|
||||
* There should be a delay at the end equal to the longest I2C message
|
||||
* to synchronize the BB-bit (in multimaster systems). How long is
|
||||
* this? I assume 1 second is always long enough.
|
||||
*
|
||||
* vdovikin: added detect code for PCF8584
|
||||
*/
|
||||
static int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
|
||||
{
|
||||
unsigned char temp;
|
||||
|
||||
DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: PCF state 0x%02x\n", get_pcf(adap, 1)));
|
||||
|
||||
/* S1=0x80: S0 selected, serial interface off */
|
||||
set_pcf(adap, 1, I2C_PCF_PIN);
|
||||
/* check to see S1 now used as R/W ctrl -
|
||||
PCF8584 does that when ESO is zero */
|
||||
if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) {
|
||||
DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp));
|
||||
return -ENXIO; /* definetly not PCF8584 */
|
||||
}
|
||||
|
||||
/* load own address in S0, effective address is (own << 1) */
|
||||
i2c_outb(adap, get_own(adap));
|
||||
/* check it's really written */
|
||||
if ((temp = i2c_inb(adap)) != get_own(adap)) {
|
||||
DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp));
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* S1=0xA0, next byte in S2 */
|
||||
set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1);
|
||||
/* check to see S2 now selected */
|
||||
if (((temp = get_pcf(adap, 1)) & 0x7f) != I2C_PCF_ES1) {
|
||||
DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp));
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* load clock register S2 */
|
||||
i2c_outb(adap, get_clock(adap));
|
||||
/* check it's really written, the only 5 lowest bits does matter */
|
||||
if (((temp = i2c_inb(adap)) & 0x1f) != get_clock(adap)) {
|
||||
DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp));
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* Enable serial interface, idle, S0 selected */
|
||||
set_pcf(adap, 1, I2C_PCF_IDLE);
|
||||
|
||||
/* check to see PCF is really idled and we can access status register */
|
||||
if ((temp = get_pcf(adap, 1)) != (I2C_PCF_PIN | I2C_PCF_BB)) {
|
||||
DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp));
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "i2c-algo-pcf.o: deteted and initialized PCF8584.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ----- Utility functions
|
||||
*/
|
||||
|
||||
static inline int try_address(struct i2c_algo_pcf_data *adap,
|
||||
unsigned char addr, int retries)
|
||||
{
|
||||
int i, status, ret = -1;
|
||||
int wfp;
|
||||
for (i=0;i<retries;i++) {
|
||||
i2c_outb(adap, addr);
|
||||
i2c_start(adap);
|
||||
status = get_pcf(adap, 1);
|
||||
if ((wfp = wait_for_pin(adap, &status)) >= 0) {
|
||||
if ((status & I2C_PCF_LRB) == 0) {
|
||||
i2c_stop(adap);
|
||||
break; /* success! */
|
||||
}
|
||||
}
|
||||
if (wfp == -EINTR) {
|
||||
/* arbitration lost */
|
||||
udelay(adap->udelay);
|
||||
return -EINTR;
|
||||
}
|
||||
i2c_stop(adap);
|
||||
udelay(adap->udelay);
|
||||
}
|
||||
DEB2(if (i) printk(KERN_DEBUG "i2c-algo-pcf.o: needed %d retries for %d\n",i,
|
||||
addr));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
|
||||
int count, int last)
|
||||
{
|
||||
struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
|
||||
int wrcount, status, timeout;
|
||||
|
||||
for (wrcount=0; wrcount<count; ++wrcount) {
|
||||
DEB2(dev_dbg(&i2c_adap->dev, "i2c_write: writing %2.2X\n",
|
||||
buf[wrcount]&0xff));
|
||||
i2c_outb(adap, buf[wrcount]);
|
||||
timeout = wait_for_pin(adap, &status);
|
||||
if (timeout) {
|
||||
if (timeout == -EINTR) {
|
||||
/* arbitration lost */
|
||||
return -EINTR;
|
||||
}
|
||||
i2c_stop(adap);
|
||||
dev_err(&i2c_adap->dev, "i2c_write: error - timeout.\n");
|
||||
return -EREMOTEIO; /* got a better one ?? */
|
||||
}
|
||||
#ifndef STUB_I2C
|
||||
if (status & I2C_PCF_LRB) {
|
||||
i2c_stop(adap);
|
||||
dev_err(&i2c_adap->dev, "i2c_write: error - no ack.\n");
|
||||
return -EREMOTEIO; /* got a better one ?? */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (last) {
|
||||
i2c_stop(adap);
|
||||
}
|
||||
else {
|
||||
i2c_repstart(adap);
|
||||
}
|
||||
|
||||
return (wrcount);
|
||||
}
|
||||
|
||||
|
||||
static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf,
|
||||
int count, int last)
|
||||
{
|
||||
int i, status;
|
||||
struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
|
||||
int wfp;
|
||||
|
||||
/* increment number of bytes to read by one -- read dummy byte */
|
||||
for (i = 0; i <= count; i++) {
|
||||
|
||||
if ((wfp = wait_for_pin(adap, &status))) {
|
||||
if (wfp == -EINTR) {
|
||||
/* arbitration lost */
|
||||
return -EINTR;
|
||||
}
|
||||
i2c_stop(adap);
|
||||
dev_err(&i2c_adap->dev, "pcf_readbytes timed out.\n");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#ifndef STUB_I2C
|
||||
if ((status & I2C_PCF_LRB) && (i != count)) {
|
||||
i2c_stop(adap);
|
||||
dev_err(&i2c_adap->dev, "i2c_read: i2c_inb, No ack.\n");
|
||||
return (-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (i == count - 1) {
|
||||
set_pcf(adap, 1, I2C_PCF_ESO);
|
||||
} else
|
||||
if (i == count) {
|
||||
if (last) {
|
||||
i2c_stop(adap);
|
||||
} else {
|
||||
i2c_repstart(adap);
|
||||
}
|
||||
};
|
||||
|
||||
if (i) {
|
||||
buf[i - 1] = i2c_inb(adap);
|
||||
} else {
|
||||
i2c_inb(adap); /* dummy read */
|
||||
}
|
||||
}
|
||||
|
||||
return (i - 1);
|
||||
}
|
||||
|
||||
|
||||
static inline int pcf_doAddress(struct i2c_algo_pcf_data *adap,
|
||||
struct i2c_msg *msg, int retries)
|
||||
{
|
||||
unsigned short flags = msg->flags;
|
||||
unsigned char addr;
|
||||
int ret;
|
||||
if ( (flags & I2C_M_TEN) ) {
|
||||
/* a ten bit address */
|
||||
addr = 0xf0 | (( msg->addr >> 7) & 0x03);
|
||||
DEB2(printk(KERN_DEBUG "addr0: %d\n",addr));
|
||||
/* try extended address code...*/
|
||||
ret = try_address(adap, addr, retries);
|
||||
if (ret!=1) {
|
||||
printk(KERN_ERR "died at extended address code.\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
/* the remaining 8 bit address */
|
||||
i2c_outb(adap,msg->addr & 0x7f);
|
||||
/* Status check comes here */
|
||||
if (ret != 1) {
|
||||
printk(KERN_ERR "died at 2nd address code.\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
if ( flags & I2C_M_RD ) {
|
||||
i2c_repstart(adap);
|
||||
/* okay, now switch into reading mode */
|
||||
addr |= 0x01;
|
||||
ret = try_address(adap, addr, retries);
|
||||
if (ret!=1) {
|
||||
printk(KERN_ERR "died at extended address code.\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
}
|
||||
} else { /* normal 7bit address */
|
||||
addr = ( msg->addr << 1 );
|
||||
if (flags & I2C_M_RD )
|
||||
addr |= 1;
|
||||
if (flags & I2C_M_REV_DIR_ADDR )
|
||||
addr ^= 1;
|
||||
i2c_outb(adap, addr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcf_xfer(struct i2c_adapter *i2c_adap,
|
||||
struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
|
||||
struct i2c_msg *pmsg;
|
||||
int i;
|
||||
int ret=0, timeout, status;
|
||||
|
||||
|
||||
/* Check for bus busy */
|
||||
timeout = wait_for_bb(adap);
|
||||
if (timeout) {
|
||||
DEB2(printk(KERN_ERR "i2c-algo-pcf.o: "
|
||||
"Timeout waiting for BB in pcf_xfer\n");)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
for (i = 0;ret >= 0 && i < num; i++) {
|
||||
pmsg = &msgs[i];
|
||||
|
||||
DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: Doing %s %d bytes to 0x%02x - %d of %d messages\n",
|
||||
pmsg->flags & I2C_M_RD ? "read" : "write",
|
||||
pmsg->len, pmsg->addr, i + 1, num);)
|
||||
|
||||
ret = pcf_doAddress(adap, pmsg, i2c_adap->retries);
|
||||
|
||||
/* Send START */
|
||||
if (i == 0) {
|
||||
i2c_start(adap);
|
||||
}
|
||||
|
||||
/* Wait for PIN (pending interrupt NOT) */
|
||||
timeout = wait_for_pin(adap, &status);
|
||||
if (timeout) {
|
||||
if (timeout == -EINTR) {
|
||||
/* arbitration lost */
|
||||
return (-EINTR);
|
||||
}
|
||||
i2c_stop(adap);
|
||||
DEB2(printk(KERN_ERR "i2c-algo-pcf.o: Timeout waiting "
|
||||
"for PIN(1) in pcf_xfer\n");)
|
||||
return (-EREMOTEIO);
|
||||
}
|
||||
|
||||
#ifndef STUB_I2C
|
||||
/* Check LRB (last rcvd bit - slave ack) */
|
||||
if (status & I2C_PCF_LRB) {
|
||||
i2c_stop(adap);
|
||||
DEB2(printk(KERN_ERR "i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");)
|
||||
return (-EREMOTEIO);
|
||||
}
|
||||
#endif
|
||||
|
||||
DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n",
|
||||
i, msgs[i].addr, msgs[i].flags, msgs[i].len);)
|
||||
|
||||
/* Read */
|
||||
if (pmsg->flags & I2C_M_RD) {
|
||||
/* read bytes into buffer*/
|
||||
ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len,
|
||||
(i + 1 == num));
|
||||
|
||||
if (ret != pmsg->len) {
|
||||
DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: "
|
||||
"only read %d bytes.\n",ret));
|
||||
} else {
|
||||
DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: read %d bytes.\n",ret));
|
||||
}
|
||||
} else { /* Write */
|
||||
ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len,
|
||||
(i + 1 == num));
|
||||
|
||||
if (ret != pmsg->len) {
|
||||
DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: "
|
||||
"only wrote %d bytes.\n",ret));
|
||||
} else {
|
||||
DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: wrote %d bytes.\n",ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (i);
|
||||
}
|
||||
|
||||
static u32 pcf_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
|
||||
I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
|
||||
}
|
||||
|
||||
/* -----exported algorithm data: ------------------------------------- */
|
||||
|
||||
static const struct i2c_algorithm pcf_algo = {
|
||||
.master_xfer = pcf_xfer,
|
||||
.functionality = pcf_func,
|
||||
};
|
||||
|
||||
/*
|
||||
* registering functions to load algorithms at runtime
|
||||
*/
|
||||
int i2c_pcf_add_bus(struct i2c_adapter *adap)
|
||||
{
|
||||
struct i2c_algo_pcf_data *pcf_adap = adap->algo_data;
|
||||
int rval;
|
||||
|
||||
DEB2(dev_dbg(&adap->dev, "hw routines registered.\n"));
|
||||
|
||||
/* register new adapter to i2c module... */
|
||||
adap->algo = &pcf_algo;
|
||||
|
||||
adap->timeout = 100; /* default values, should */
|
||||
adap->retries = 3; /* be replaced by defines */
|
||||
|
||||
if ((rval = pcf_init_8584(pcf_adap)))
|
||||
return rval;
|
||||
|
||||
rval = i2c_add_adapter(adap);
|
||||
|
||||
return rval;
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_pcf_add_bus);
|
||||
|
||||
MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
|
||||
MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(i2c_debug,
|
||||
"debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol");
|
||||
76
drivers/i2c/algos/i2c-algo-pcf.h
Normal file
76
drivers/i2c/algos/i2c-algo-pcf.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* i2c-pcf8584.h: PCF 8584 global defines */
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Copyright (C) 1996 Simon G. Vogl
|
||||
1999 Hans Berglund
|
||||
|
||||
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. */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/* With some changes from Frodo Looijaard <frodol@dds.nl> */
|
||||
|
||||
#ifndef I2C_PCF8584_H
|
||||
#define I2C_PCF8584_H 1
|
||||
|
||||
/* ----- Control register bits ---------------------------------------- */
|
||||
#define I2C_PCF_PIN 0x80
|
||||
#define I2C_PCF_ESO 0x40
|
||||
#define I2C_PCF_ES1 0x20
|
||||
#define I2C_PCF_ES2 0x10
|
||||
#define I2C_PCF_ENI 0x08
|
||||
#define I2C_PCF_STA 0x04
|
||||
#define I2C_PCF_STO 0x02
|
||||
#define I2C_PCF_ACK 0x01
|
||||
|
||||
#define I2C_PCF_START (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK)
|
||||
#define I2C_PCF_STOP (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK)
|
||||
#define I2C_PCF_REPSTART ( I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK)
|
||||
#define I2C_PCF_IDLE (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ACK)
|
||||
|
||||
/* ----- Status register bits ----------------------------------------- */
|
||||
/*#define I2C_PCF_PIN 0x80 as above*/
|
||||
|
||||
#define I2C_PCF_INI 0x40 /* 1 if not initialized */
|
||||
#define I2C_PCF_STS 0x20
|
||||
#define I2C_PCF_BER 0x10
|
||||
#define I2C_PCF_AD0 0x08
|
||||
#define I2C_PCF_LRB 0x08
|
||||
#define I2C_PCF_AAS 0x04
|
||||
#define I2C_PCF_LAB 0x02
|
||||
#define I2C_PCF_BB 0x01
|
||||
|
||||
/* ----- Chip clock frequencies --------------------------------------- */
|
||||
#define I2C_PCF_CLK3 0x00
|
||||
#define I2C_PCF_CLK443 0x10
|
||||
#define I2C_PCF_CLK6 0x14
|
||||
#define I2C_PCF_CLK 0x18
|
||||
#define I2C_PCF_CLK12 0x1c
|
||||
|
||||
/* ----- transmission frequencies ------------------------------------- */
|
||||
#define I2C_PCF_TRNS90 0x00 /* 90 kHz */
|
||||
#define I2C_PCF_TRNS45 0x01 /* 45 kHz */
|
||||
#define I2C_PCF_TRNS11 0x02 /* 11 kHz */
|
||||
#define I2C_PCF_TRNS15 0x03 /* 1.5 kHz */
|
||||
|
||||
|
||||
/* ----- Access to internal registers according to ES1,ES2 ------------ */
|
||||
/* they are mapped to the data port ( a0 = 0 ) */
|
||||
/* available when ESO == 0 : */
|
||||
|
||||
#define I2C_PCF_OWNADR 0
|
||||
#define I2C_PCF_INTREG I2C_PCF_ES2
|
||||
#define I2C_PCF_CLKREG I2C_PCF_ES1
|
||||
|
||||
#endif /* I2C_PCF8584_H */
|
||||
178
drivers/i2c/algos/i2c-algo-sgi.c
Normal file
178
drivers/i2c/algos/i2c-algo-sgi.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* i2c-algo-sgi.c: i2c driver algorithms for SGI adapters.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-sgi.h>
|
||||
|
||||
|
||||
#define SGI_I2C_FORCE_IDLE (0 << 0)
|
||||
#define SGI_I2C_NOT_IDLE (1 << 0)
|
||||
#define SGI_I2C_WRITE (0 << 1)
|
||||
#define SGI_I2C_READ (1 << 1)
|
||||
#define SGI_I2C_RELEASE_BUS (0 << 2)
|
||||
#define SGI_I2C_HOLD_BUS (1 << 2)
|
||||
#define SGI_I2C_XFER_DONE (0 << 4)
|
||||
#define SGI_I2C_XFER_BUSY (1 << 4)
|
||||
#define SGI_I2C_ACK (0 << 5)
|
||||
#define SGI_I2C_NACK (1 << 5)
|
||||
#define SGI_I2C_BUS_OK (0 << 7)
|
||||
#define SGI_I2C_BUS_ERR (1 << 7)
|
||||
|
||||
#define get_control() adap->getctrl(adap->data)
|
||||
#define set_control(val) adap->setctrl(adap->data, val)
|
||||
#define read_data() adap->rdata(adap->data)
|
||||
#define write_data(val) adap->wdata(adap->data, val)
|
||||
|
||||
|
||||
static int wait_xfer_done(struct i2c_algo_sgi_data *adap)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adap->xfer_timeout; i++) {
|
||||
if ((get_control() & SGI_I2C_XFER_BUSY) == 0)
|
||||
return 0;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int wait_ack(struct i2c_algo_sgi_data *adap)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (wait_xfer_done(adap))
|
||||
return -ETIMEDOUT;
|
||||
for (i = 0; i < adap->ack_timeout; i++) {
|
||||
if ((get_control() & SGI_I2C_NACK) == 0)
|
||||
return 0;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int force_idle(struct i2c_algo_sgi_data *adap)
|
||||
{
|
||||
int i;
|
||||
|
||||
set_control(SGI_I2C_FORCE_IDLE);
|
||||
for (i = 0; i < adap->xfer_timeout; i++) {
|
||||
if ((get_control() & SGI_I2C_NOT_IDLE) == 0)
|
||||
goto out;
|
||||
udelay(1);
|
||||
}
|
||||
return -ETIMEDOUT;
|
||||
out:
|
||||
if (get_control() & SGI_I2C_BUS_ERR)
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_address(struct i2c_algo_sgi_data *adap, unsigned int addr,
|
||||
int rd)
|
||||
{
|
||||
if (rd)
|
||||
set_control(SGI_I2C_NOT_IDLE);
|
||||
/* Check if bus is idle, eventually force it to do so */
|
||||
if (get_control() & SGI_I2C_NOT_IDLE)
|
||||
if (force_idle(adap))
|
||||
return -EIO;
|
||||
/* Write out the i2c chip address and specify operation */
|
||||
set_control(SGI_I2C_HOLD_BUS | SGI_I2C_WRITE | SGI_I2C_NOT_IDLE);
|
||||
if (rd)
|
||||
addr |= 1;
|
||||
write_data(addr);
|
||||
if (wait_ack(adap))
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_read(struct i2c_algo_sgi_data *adap, unsigned char *buf,
|
||||
unsigned int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
set_control(SGI_I2C_HOLD_BUS | SGI_I2C_READ | SGI_I2C_NOT_IDLE);
|
||||
for (i = 0; i < len; i++) {
|
||||
if (wait_xfer_done(adap))
|
||||
return -EIO;
|
||||
buf[i] = read_data();
|
||||
}
|
||||
set_control(SGI_I2C_RELEASE_BUS | SGI_I2C_FORCE_IDLE);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int i2c_write(struct i2c_algo_sgi_data *adap, unsigned char *buf,
|
||||
unsigned int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* We are already in write state */
|
||||
for (i = 0; i < len; i++) {
|
||||
write_data(buf[i]);
|
||||
if (wait_ack(adap))
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sgi_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
struct i2c_algo_sgi_data *adap = i2c_adap->algo_data;
|
||||
struct i2c_msg *p;
|
||||
int i, err = 0;
|
||||
|
||||
for (i = 0; !err && i < num; i++) {
|
||||
p = &msgs[i];
|
||||
err = do_address(adap, p->addr, p->flags & I2C_M_RD);
|
||||
if (err || !p->len)
|
||||
continue;
|
||||
if (p->flags & I2C_M_RD)
|
||||
err = i2c_read(adap, p->buf, p->len);
|
||||
else
|
||||
err = i2c_write(adap, p->buf, p->len);
|
||||
}
|
||||
|
||||
return (err < 0) ? err : i;
|
||||
}
|
||||
|
||||
static u32 sgi_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm sgi_algo = {
|
||||
.master_xfer = sgi_xfer,
|
||||
.functionality = sgi_func,
|
||||
};
|
||||
|
||||
/*
|
||||
* registering functions to load algorithms at runtime
|
||||
*/
|
||||
int i2c_sgi_add_bus(struct i2c_adapter *adap)
|
||||
{
|
||||
adap->algo = &sgi_algo;
|
||||
|
||||
return i2c_add_adapter(adap);
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_sgi_add_bus);
|
||||
|
||||
MODULE_AUTHOR("Ladislav Michl <ladis@linux-mips.org>");
|
||||
MODULE_DESCRIPTION("I2C-Bus SGI algorithm");
|
||||
MODULE_LICENSE("GPL");
|
||||
Reference in New Issue
Block a user