2009-03-28 23:34:42 +03:00
/*
* 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 .
*
* With some changes from Kyö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
*/
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/delay.h>
# include <linux/errno.h>
# include <linux/i2c.h>
# include <linux/i2c-algo-pcf.h>
# include "i2c-algo-pcf.h"
2009-03-28 23:34:42 +03:00
# 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 */
2005-04-17 02:20:36 +04:00
# define DEF_TIMEOUT 16
2009-03-28 23:34:42 +03:00
/*
* module parameters :
2005-04-17 02:20:36 +04:00
*/
static int i2c_debug ;
2009-03-28 23:34:42 +03:00
/* setting states on the bus with the right timing: */
2005-04-17 02:20:36 +04:00
# 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)
2009-03-28 23:34:42 +03:00
/* other auxiliary functions */
2005-04-17 02:20:36 +04:00
2009-03-28 23:34:42 +03:00
static void i2c_start ( struct i2c_algo_pcf_data * adap )
2005-04-17 02:20:36 +04:00
{
2009-03-28 23:34:42 +03:00
DEBPROTO ( printk ( KERN_DEBUG " S " ) ) ;
2005-04-17 02:20:36 +04:00
set_pcf ( adap , 1 , I2C_PCF_START ) ;
}
2009-03-28 23:34:42 +03:00
static void i2c_repstart ( struct i2c_algo_pcf_data * adap )
2005-04-17 02:20:36 +04:00
{
DEBPROTO ( printk ( " Sr " ) ) ;
set_pcf ( adap , 1 , I2C_PCF_REPSTART ) ;
}
2009-03-28 23:34:42 +03:00
static void i2c_stop ( struct i2c_algo_pcf_data * adap )
2005-04-17 02:20:36 +04:00
{
DEBPROTO ( printk ( " P \n " ) ) ;
set_pcf ( adap , 1 , I2C_PCF_STOP ) ;
}
2008-07-15 00:38:31 +04:00
static void handle_lab ( struct i2c_algo_pcf_data * adap , const int * status )
{
DEB2 ( printk ( KERN_INFO
" i2c-algo-pcf.o: lost arbitration (CSR 0x%02x) \n " ,
2009-03-28 23:34:42 +03:00
* status ) ) ;
/*
* Cleanup from LAB - - reset and enable ESO .
2008-07-15 00:38:31 +04:00
* 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 ) ;
2009-03-28 23:34:42 +03:00
/*
* We pause for a time period sufficient for any running
2008-07-15 00:38:31 +04:00
* I2C transaction to complete - - the arbitration logic won ' t
* work properly until the next START is seen .
* It is assumed the bus driver or client has set a proper value .
*
* REVISIT : should probably use msleep instead of mdelay if we
* know we can sleep .
*/
if ( adap - > lab_mdelay )
mdelay ( adap - > lab_mdelay ) ;
DEB2 ( printk ( KERN_INFO
" i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x) \n " ,
get_pcf ( adap , 1 ) ) ) ;
}
2009-03-28 23:34:42 +03:00
static int wait_for_bb ( struct i2c_algo_pcf_data * adap )
{
2005-04-17 02:20:36 +04:00
int timeout = DEF_TIMEOUT ;
int status ;
status = get_pcf ( adap , 1 ) ;
2009-03-28 23:34:42 +03:00
2009-03-28 23:34:42 +03:00
while ( ! ( status & I2C_PCF_BB ) & & - - timeout ) {
2005-04-17 02:20:36 +04:00
udelay ( 100 ) ; /* wait for 100 us */
status = get_pcf ( adap , 1 ) ;
}
2009-03-28 23:34:42 +03:00
2009-03-28 23:34:42 +03:00
if ( timeout = = 0 ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " Timeout waiting for Bus Busy \n " ) ;
2009-03-28 23:34:42 +03:00
return - ETIMEDOUT ;
}
2005-04-17 02:20:36 +04:00
2009-03-28 23:34:42 +03:00
return 0 ;
2009-03-28 23:34:42 +03:00
}
2005-04-17 02:20:36 +04:00
2009-03-28 23:34:42 +03:00
static int wait_for_pin ( struct i2c_algo_pcf_data * adap , int * status )
{
2005-04-17 02:20:36 +04:00
int timeout = DEF_TIMEOUT ;
* status = get_pcf ( adap , 1 ) ;
2009-03-28 23:34:42 +03:00
2009-03-28 23:34:42 +03:00
while ( ( * status & I2C_PCF_PIN ) & & - - timeout ) {
2008-10-22 22:21:29 +04:00
adap - > waitforpin ( adap - > data ) ;
2005-04-17 02:20:36 +04:00
* status = get_pcf ( adap , 1 ) ;
}
if ( * status & I2C_PCF_LAB ) {
2008-07-15 00:38:31 +04:00
handle_lab ( adap , status ) ;
2009-03-28 23:34:42 +03:00
return - EINTR ;
2005-04-17 02:20:36 +04:00
}
2009-03-28 23:34:42 +03:00
2009-03-28 23:34:42 +03:00
if ( timeout = = 0 )
return - ETIMEDOUT ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2009-03-28 23:34:42 +03:00
/*
2005-04-17 02:20:36 +04:00
* 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 ;
2009-03-28 23:34:42 +03:00
DEB3 ( printk ( KERN_DEBUG " i2c-algo-pcf.o: PCF state 0x%02x \n " ,
get_pcf ( adap , 1 ) ) ) ;
2005-04-17 02:20:36 +04:00
/* S1=0x80: S0 selected, serial interface off */
set_pcf ( adap , 1 , I2C_PCF_PIN ) ;
2009-03-28 23:34:42 +03:00
/*
* check to see S1 now used as R / W ctrl -
* PCF8584 does that when ESO is zero
*/
2005-04-17 02:20:36 +04:00
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 ) ) ;
2010-01-29 00:09:43 +03:00
return - ENXIO ; /* definitely not PCF8584 */
2005-04-17 02:20:36 +04:00
}
2009-03-28 23:34:42 +03:00
/* load own address in S0, effective address is (own << 1) */
2005-04-17 02:20:36 +04:00
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 ;
}
2009-03-28 23:34:42 +03:00
/* S1=0xA0, next byte in S2 */
2005-04-17 02:20:36 +04:00
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 ;
}
2009-03-28 23:34:42 +03:00
/* load clock register S2 */
2005-04-17 02:20:36 +04:00
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 ;
}
2009-03-28 23:34:42 +03:00
/* Enable serial interface, idle, S0 selected */
2005-04-17 02:20:36 +04:00
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 ;
}
2009-03-28 23:34:42 +03:00
2008-10-22 22:21:30 +04:00
printk ( KERN_DEBUG " i2c-algo-pcf.o: detected and initialized PCF8584. \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int pcf_sendbytes ( struct i2c_adapter * i2c_adap , const char * buf ,
2009-03-28 23:34:42 +03:00
int count , int last )
2005-04-17 02:20:36 +04:00
{
struct i2c_algo_pcf_data * adap = i2c_adap - > algo_data ;
int wrcount , status , timeout ;
2009-03-28 23:34:42 +03:00
2005-04-17 02:20:36 +04:00
for ( wrcount = 0 ; wrcount < count ; + + wrcount ) {
DEB2 ( dev_dbg ( & i2c_adap - > dev , " i2c_write: writing %2.2X \n " ,
2009-03-28 23:34:42 +03:00
buf [ wrcount ] & 0xff ) ) ;
2005-04-17 02:20:36 +04:00
i2c_outb ( adap , buf [ wrcount ] ) ;
timeout = wait_for_pin ( adap , & status ) ;
if ( timeout ) {
2009-03-28 23:34:42 +03:00
if ( timeout = = - EINTR )
return - EINTR ; /* arbitration lost */
2005-04-17 02:20:36 +04:00
i2c_stop ( adap ) ;
dev_err ( & i2c_adap - > dev , " i2c_write: error - timeout. \n " ) ;
return - EREMOTEIO ; /* got a better one ?? */
}
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 ?? */
}
}
2009-03-28 23:34:42 +03:00
if ( last )
2005-04-17 02:20:36 +04:00
i2c_stop ( adap ) ;
2009-03-28 23:34:42 +03:00
else
2005-04-17 02:20:36 +04:00
i2c_repstart ( adap ) ;
2009-03-28 23:34:42 +03:00
return wrcount ;
2005-04-17 02:20:36 +04:00
}
static int pcf_readbytes ( struct i2c_adapter * i2c_adap , char * buf ,
2009-03-28 23:34:42 +03:00
int count , int last )
2005-04-17 02:20:36 +04:00
{
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 ) ) ) {
2009-03-28 23:34:42 +03:00
if ( wfp = = - EINTR )
return - EINTR ; /* arbitration lost */
2005-04-17 02:20:36 +04:00
i2c_stop ( adap ) ;
dev_err ( & i2c_adap - > dev , " pcf_readbytes timed out. \n " ) ;
2009-03-28 23:34:42 +03:00
return - 1 ;
2005-04-17 02:20:36 +04:00
}
if ( ( status & I2C_PCF_LRB ) & & ( i ! = count ) ) {
i2c_stop ( adap ) ;
dev_err ( & i2c_adap - > dev , " i2c_read: i2c_inb, No ack. \n " ) ;
2009-03-28 23:34:42 +03:00
return - 1 ;
2005-04-17 02:20:36 +04:00
}
2009-03-28 23:34:42 +03:00
2005-04-17 02:20:36 +04:00
if ( i = = count - 1 ) {
set_pcf ( adap , 1 , I2C_PCF_ESO ) ;
2009-03-28 23:34:42 +03:00
} else if ( i = = count ) {
if ( last )
2005-04-17 02:20:36 +04:00
i2c_stop ( adap ) ;
2009-03-28 23:34:42 +03:00
else
2005-04-17 02:20:36 +04:00
i2c_repstart ( adap ) ;
2009-03-28 23:34:42 +03:00
}
2005-04-17 02:20:36 +04:00
2009-03-28 23:34:42 +03:00
if ( i )
2005-04-17 02:20:36 +04:00
buf [ i - 1 ] = i2c_inb ( adap ) ;
2009-03-28 23:34:42 +03:00
else
2005-04-17 02:20:36 +04:00
i2c_inb ( adap ) ; /* dummy read */
}
2009-03-28 23:34:42 +03:00
return i - 1 ;
2005-04-17 02:20:36 +04:00
}
2008-01-27 20:14:46 +03:00
static int pcf_doAddress ( struct i2c_algo_pcf_data * adap ,
struct i2c_msg * msg )
2005-04-17 02:20:36 +04:00
{
2018-05-16 10:16:46 +03:00
unsigned char addr = i2c_8bit_addr_from_msg ( msg ) ;
2008-01-27 20:14:46 +03:00
2018-05-16 10:16:46 +03:00
if ( msg - > flags & I2C_M_REV_DIR_ADDR )
2008-01-27 20:14:46 +03:00
addr ^ = 1 ;
i2c_outb ( adap , addr ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int pcf_xfer ( struct i2c_adapter * i2c_adap ,
2009-03-28 23:34:42 +03:00
struct i2c_msg * msgs ,
2005-04-17 02:20:36 +04:00
int num )
{
struct i2c_algo_pcf_data * adap = i2c_adap - > algo_data ;
struct i2c_msg * pmsg ;
int i ;
int ret = 0 , timeout , status ;
2009-03-28 23:34:42 +03:00
2008-10-22 22:21:30 +04:00
if ( adap - > xfer_begin )
adap - > xfer_begin ( adap - > data ) ;
2005-04-17 02:20:36 +04:00
/* Check for bus busy */
timeout = wait_for_bb ( adap ) ;
if ( timeout ) {
DEB2 ( printk ( KERN_ERR " i2c-algo-pcf.o: "
2009-03-28 23:34:42 +03:00
" Timeout waiting for BB in pcf_xfer \n " ) ; )
2008-10-22 22:21:30 +04:00
i = - EIO ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2009-03-28 23:34:42 +03:00
2005-04-17 02:20:36 +04:00
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 " ,
2009-03-28 23:34:42 +03:00
pmsg - > len , pmsg - > addr , i + 1 , num ) ; )
2008-01-27 20:14:46 +03:00
ret = pcf_doAddress ( adap , pmsg ) ;
2005-04-17 02:20:36 +04:00
/* Send START */
2009-03-28 23:34:42 +03:00
if ( i = = 0 )
i2c_start ( adap ) ;
2005-04-17 02:20:36 +04:00
/* Wait for PIN (pending interrupt NOT) */
timeout = wait_for_pin ( adap , & status ) ;
if ( timeout ) {
if ( timeout = = - EINTR ) {
/* arbitration lost */
2008-10-22 22:21:30 +04:00
i = - EINTR ;
goto out ;
2005-04-17 02:20:36 +04:00
}
i2c_stop ( adap ) ;
DEB2 ( printk ( KERN_ERR " i2c-algo-pcf.o: Timeout waiting "
" for PIN(1) in pcf_xfer \n " ) ; )
2008-10-22 22:21:30 +04:00
i = - EREMOTEIO ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2009-03-28 23:34:42 +03:00
2005-04-17 02:20:36 +04:00
/* 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 " ) ; )
2008-10-22 22:21:30 +04:00
i = - EREMOTEIO ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2009-03-28 23:34:42 +03:00
2005-04-17 02:20:36 +04:00
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 ) ; )
2009-03-28 23:34:42 +03:00
2005-04-17 02:20:36 +04:00
if ( pmsg - > flags & I2C_M_RD ) {
ret = pcf_readbytes ( i2c_adap , pmsg - > buf , pmsg - > len ,
2009-03-28 23:34:42 +03:00
( i + 1 = = num ) ) ;
2005-04-17 02:20:36 +04:00
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 ) ) ;
}
2009-03-28 23:34:42 +03:00
} else {
2005-04-17 02:20:36 +04:00
ret = pcf_sendbytes ( i2c_adap , pmsg - > buf , pmsg - > len ,
2009-03-28 23:34:42 +03:00
( i + 1 = = num ) ) ;
2005-04-17 02:20:36 +04:00
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 ) ) ;
}
}
}
2008-10-22 22:21:30 +04:00
out :
if ( adap - > xfer_end )
adap - > xfer_end ( adap - > data ) ;
2009-03-28 23:34:42 +03:00
return i ;
2005-04-17 02:20:36 +04:00
}
static u32 pcf_func ( struct i2c_adapter * adap )
{
2009-03-28 23:34:42 +03:00
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
2008-01-27 20:14:46 +03:00
I2C_FUNC_PROTOCOL_MANGLING ;
2005-04-17 02:20:36 +04:00
}
2009-03-28 23:34:42 +03:00
/* exported algorithm data: */
2006-09-04 00:38:52 +04:00
static const struct i2c_algorithm pcf_algo = {
2005-04-17 02:20:36 +04:00
. master_xfer = pcf_xfer ,
. functionality = pcf_func ,
} ;
2009-03-28 23:34:42 +03:00
/*
* registering functions to load algorithms at runtime
2005-04-17 02:20:36 +04:00
*/
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 ;
2006-07-01 19:16:06 +04:00
if ( ( rval = pcf_init_8584 ( pcf_adap ) ) )
return rval ;
rval = i2c_add_adapter ( adap ) ;
2005-04-17 02:20:36 +04:00
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 ,
2009-03-28 23:34:42 +03:00
" debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol " ) ;