2011-05-24 15:19:48 +02:00
/*
* Coral - P ( A ) / Lime I2C adapter driver
*
* ( C ) 2011 DENX Software Engineering , Anatolij Gustschin < agust @ denx . de >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
*/
# include <linux/fb.h>
# include <linux/i2c.h>
# include <linux/io.h>
2011-05-26 11:09:10 +10:00
# include <linux/delay.h>
2011-07-10 13:20:26 -04:00
# include <linux/export.h>
2011-05-24 15:19:48 +02:00
# include "mb862xxfb.h"
# include "mb862xx_reg.h"
static int mb862xx_i2c_wait_event ( struct i2c_adapter * adap )
{
struct mb862xxfb_par * par = adap - > algo_data ;
u32 reg ;
do {
2011-09-01 17:53:41 +02:00
udelay ( 10 ) ;
2011-05-24 15:19:48 +02:00
reg = inreg ( i2c , GC_I2C_BCR ) ;
if ( reg & ( I2C_INT | I2C_BER ) )
break ;
} while ( 1 ) ;
return ( reg & I2C_BER ) ? 0 : 1 ;
}
static int mb862xx_i2c_do_address ( struct i2c_adapter * adap , int addr )
{
struct mb862xxfb_par * par = adap - > algo_data ;
outreg ( i2c , GC_I2C_DAR , addr ) ;
outreg ( i2c , GC_I2C_CCR , I2C_CLOCK_AND_ENABLE ) ;
outreg ( i2c , GC_I2C_BCR , par - > i2c_rs ? I2C_REPEATED_START : I2C_START ) ;
if ( ! mb862xx_i2c_wait_event ( adap ) )
return - EIO ;
par - > i2c_rs = ! ( inreg ( i2c , GC_I2C_BSR ) & I2C_LRB ) ;
return par - > i2c_rs ;
}
static int mb862xx_i2c_write_byte ( struct i2c_adapter * adap , u8 byte )
{
struct mb862xxfb_par * par = adap - > algo_data ;
outreg ( i2c , GC_I2C_DAR , byte ) ;
outreg ( i2c , GC_I2C_BCR , I2C_START ) ;
if ( ! mb862xx_i2c_wait_event ( adap ) )
return - EIO ;
return ! ( inreg ( i2c , GC_I2C_BSR ) & I2C_LRB ) ;
}
static int mb862xx_i2c_read_byte ( struct i2c_adapter * adap , u8 * byte , int last )
{
struct mb862xxfb_par * par = adap - > algo_data ;
outreg ( i2c , GC_I2C_BCR , I2C_START | ( last ? 0 : I2C_ACK ) ) ;
if ( ! mb862xx_i2c_wait_event ( adap ) )
return 0 ;
* byte = inreg ( i2c , GC_I2C_DAR ) ;
return 1 ;
}
2012-05-02 17:34:16 -07:00
static void mb862xx_i2c_stop ( struct i2c_adapter * adap )
2011-05-24 15:19:48 +02:00
{
struct mb862xxfb_par * par = adap - > algo_data ;
outreg ( i2c , GC_I2C_BCR , I2C_STOP ) ;
outreg ( i2c , GC_I2C_CCR , I2C_DISABLE ) ;
par - > i2c_rs = 0 ;
}
static int mb862xx_i2c_read ( struct i2c_adapter * adap , struct i2c_msg * m )
{
int i , ret = 0 ;
int last = m - > len - 1 ;
for ( i = 0 ; i < m - > len ; i + + ) {
if ( ! mb862xx_i2c_read_byte ( adap , & m - > buf [ i ] , i = = last ) ) {
ret = - EIO ;
break ;
}
}
return ret ;
}
static int mb862xx_i2c_write ( struct i2c_adapter * adap , struct i2c_msg * m )
{
int i , ret = 0 ;
for ( i = 0 ; i < m - > len ; i + + ) {
if ( ! mb862xx_i2c_write_byte ( adap , m - > buf [ i ] ) ) {
ret = - EIO ;
break ;
}
}
return ret ;
}
static int mb862xx_xfer ( struct i2c_adapter * adap , struct i2c_msg * msgs ,
int num )
{
struct mb862xxfb_par * par = adap - > algo_data ;
struct i2c_msg * m ;
int addr ;
int i = 0 , err = 0 ;
dev_dbg ( par - > dev , " %s: %d msgs \n " , __func__ , num ) ;
for ( i = 0 ; i < num ; i + + ) {
m = & msgs [ i ] ;
if ( ! m - > len ) {
dev_dbg ( par - > dev , " %s: null msgs \n " , __func__ ) ;
continue ;
}
addr = m - > addr ;
if ( m - > flags & I2C_M_RD )
addr | = 1 ;
err = mb862xx_i2c_do_address ( adap , addr ) ;
if ( err < 0 )
break ;
if ( m - > flags & I2C_M_RD )
err = mb862xx_i2c_read ( adap , m ) ;
else
err = mb862xx_i2c_write ( adap , m ) ;
}
if ( i )
mb862xx_i2c_stop ( adap ) ;
return ( err < 0 ) ? err : i ;
}
static u32 mb862xx_func ( struct i2c_adapter * adap )
{
return I2C_FUNC_SMBUS_BYTE_DATA ;
}
static const struct i2c_algorithm mb862xx_algo = {
. master_xfer = mb862xx_xfer ,
. functionality = mb862xx_func ,
} ;
static struct i2c_adapter mb862xx_i2c_adapter = {
. name = " MB862xx I2C adapter " ,
. algo = & mb862xx_algo ,
. owner = THIS_MODULE ,
} ;
int mb862xx_i2c_init ( struct mb862xxfb_par * par )
{
int ret ;
mb862xx_i2c_adapter . algo_data = par ;
par - > adap = & mb862xx_i2c_adapter ;
ret = i2c_add_adapter ( par - > adap ) ;
if ( ret < 0 ) {
dev_err ( par - > dev , " failed to add %s \n " ,
mb862xx_i2c_adapter . name ) ;
}
return ret ;
}
void mb862xx_i2c_exit ( struct mb862xxfb_par * par )
{
if ( par - > adap ) {
i2c_del_adapter ( par - > adap ) ;
par - > adap = NULL ;
}
}