2008-07-14 22:38:27 +02:00
/*
* Freescale CPM1 / CPM2 I2C interface .
* Copyright ( c ) 1999 Dan Malek ( dmalek @ jlc . net ) .
*
* moved into proper i2c interface ;
* Brad Parker ( brad @ heeltoe . com )
*
* Parts from dbox2_i2c . c ( cvs . tuxbox . org )
* ( C ) 2000 - 2001 Felix Domke ( tmbinc @ gmx . net ) , Gillem ( htoa @ gmx . net )
*
* ( C ) 2007 Montavista Software , Inc .
* Vitaly Bordug < vitb @ kernel . crashing . org >
*
* Converted to of_platform_device . Renamed to i2c - cpm . c .
* ( C ) 2007 , 2008 Jochen Friedrich < jochen @ scram . de >
*
* 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 0213 9 , USA .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/delay.h>
# include <linux/slab.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/errno.h>
# include <linux/stddef.h>
# include <linux/i2c.h>
# include <linux/io.h>
# include <linux/dma-mapping.h>
# include <linux/of_device.h>
# include <linux/of_platform.h>
# include <linux/of_i2c.h>
# include <sysdev/fsl_soc.h>
# include <asm/cpm.h>
/* Try to define this if you have an older CPU (earlier than rev D4) */
/* However, better use a GPIO based bitbang driver in this case :/ */
# undef I2C_CHIP_ERRATA
# define CPM_MAX_READ 513
# define CPM_MAXBD 4
# define I2C_EB (0x10) /* Big endian mode */
# define I2C_EB_CPM2 (0x30) /* Big endian mode, memory snoop */
# define DPRAM_BASE ((u8 __iomem __force *)cpm_muram_addr(0))
/* I2C parameter RAM. */
struct i2c_ram {
ushort rbase ; /* Rx Buffer descriptor base address */
ushort tbase ; /* Tx Buffer descriptor base address */
u_char rfcr ; /* Rx function code */
u_char tfcr ; /* Tx function code */
ushort mrblr ; /* Max receive buffer length */
uint rstate ; /* Internal */
uint rdp ; /* Internal */
ushort rbptr ; /* Rx Buffer descriptor pointer */
ushort rbc ; /* Internal */
uint rxtmp ; /* Internal */
uint tstate ; /* Internal */
uint tdp ; /* Internal */
ushort tbptr ; /* Tx Buffer descriptor pointer */
ushort tbc ; /* Internal */
uint txtmp ; /* Internal */
char res1 [ 4 ] ; /* Reserved */
ushort rpbase ; /* Relocation pointer */
char res2 [ 2 ] ; /* Reserved */
} ;
# define I2COM_START 0x80
# define I2COM_MASTER 0x01
# define I2CER_TXE 0x10
# define I2CER_BUSY 0x04
# define I2CER_TXB 0x02
# define I2CER_RXB 0x01
# define I2MOD_EN 0x01
/* I2C Registers */
struct i2c_reg {
u8 i2mod ;
u8 res1 [ 3 ] ;
u8 i2add ;
u8 res2 [ 3 ] ;
u8 i2brg ;
u8 res3 [ 3 ] ;
u8 i2com ;
u8 res4 [ 3 ] ;
u8 i2cer ;
u8 res5 [ 3 ] ;
u8 i2cmr ;
} ;
struct cpm_i2c {
char * base ;
struct of_device * ofdev ;
struct i2c_adapter adap ;
uint dp_addr ;
int version ; /* CPM1=1, CPM2=2 */
int irq ;
int cp_command ;
int freq ;
struct i2c_reg __iomem * i2c_reg ;
struct i2c_ram __iomem * i2c_ram ;
u16 i2c_addr ;
wait_queue_head_t i2c_wait ;
cbd_t __iomem * tbase ;
cbd_t __iomem * rbase ;
u_char * txbuf [ CPM_MAXBD ] ;
u_char * rxbuf [ CPM_MAXBD ] ;
u32 txdma [ CPM_MAXBD ] ;
u32 rxdma [ CPM_MAXBD ] ;
} ;
static irqreturn_t cpm_i2c_interrupt ( int irq , void * dev_id )
{
struct cpm_i2c * cpm ;
struct i2c_reg __iomem * i2c_reg ;
struct i2c_adapter * adap = dev_id ;
int i ;
cpm = i2c_get_adapdata ( dev_id ) ;
i2c_reg = cpm - > i2c_reg ;
/* Clear interrupt. */
i = in_8 ( & i2c_reg - > i2cer ) ;
out_8 ( & i2c_reg - > i2cer , i ) ;
dev_dbg ( & adap - > dev , " Interrupt: %x \n " , i ) ;
wake_up_interruptible ( & cpm - > i2c_wait ) ;
return i ? IRQ_HANDLED : IRQ_NONE ;
}
static void cpm_reset_i2c_params ( struct cpm_i2c * cpm )
{
struct i2c_ram __iomem * i2c_ram = cpm - > i2c_ram ;
/* Set up the I2C parameters in the parameter ram. */
out_be16 ( & i2c_ram - > tbase , ( u8 __iomem * ) cpm - > tbase - DPRAM_BASE ) ;
out_be16 ( & i2c_ram - > rbase , ( u8 __iomem * ) cpm - > rbase - DPRAM_BASE ) ;
if ( cpm - > version = = 1 ) {
out_8 ( & i2c_ram - > tfcr , I2C_EB ) ;
out_8 ( & i2c_ram - > rfcr , I2C_EB ) ;
} else {
out_8 ( & i2c_ram - > tfcr , I2C_EB_CPM2 ) ;
out_8 ( & i2c_ram - > rfcr , I2C_EB_CPM2 ) ;
}
out_be16 ( & i2c_ram - > mrblr , CPM_MAX_READ ) ;
out_be32 ( & i2c_ram - > rstate , 0 ) ;
out_be32 ( & i2c_ram - > rdp , 0 ) ;
out_be16 ( & i2c_ram - > rbptr , 0 ) ;
out_be16 ( & i2c_ram - > rbc , 0 ) ;
out_be32 ( & i2c_ram - > rxtmp , 0 ) ;
out_be32 ( & i2c_ram - > tstate , 0 ) ;
out_be32 ( & i2c_ram - > tdp , 0 ) ;
out_be16 ( & i2c_ram - > tbptr , 0 ) ;
out_be16 ( & i2c_ram - > tbc , 0 ) ;
out_be32 ( & i2c_ram - > txtmp , 0 ) ;
}
static void cpm_i2c_force_close ( struct i2c_adapter * adap )
{
struct cpm_i2c * cpm = i2c_get_adapdata ( adap ) ;
struct i2c_reg __iomem * i2c_reg = cpm - > i2c_reg ;
dev_dbg ( & adap - > dev , " cpm_i2c_force_close() \n " ) ;
cpm_command ( cpm - > cp_command , CPM_CR_CLOSE_RX_BD ) ;
out_8 ( & i2c_reg - > i2cmr , 0x00 ) ; /* Disable all interrupts */
out_8 ( & i2c_reg - > i2cer , 0xff ) ;
}
static void cpm_i2c_parse_message ( struct i2c_adapter * adap ,
struct i2c_msg * pmsg , int num , int tx , int rx )
{
cbd_t __iomem * tbdf ;
cbd_t __iomem * rbdf ;
u_char addr ;
u_char * tb ;
u_char * rb ;
struct cpm_i2c * cpm = i2c_get_adapdata ( adap ) ;
tbdf = cpm - > tbase + tx ;
rbdf = cpm - > rbase + rx ;
addr = pmsg - > addr < < 1 ;
if ( pmsg - > flags & I2C_M_RD )
addr | = 1 ;
tb = cpm - > txbuf [ tx ] ;
rb = cpm - > rxbuf [ rx ] ;
/* Align read buffer */
rb = ( u_char * ) ( ( ( ulong ) rb + 1 ) & ~ 1 ) ;
tb [ 0 ] = addr ; /* Device address byte w/rw flag */
out_be16 ( & tbdf - > cbd_datlen , pmsg - > len + 1 ) ;
out_be16 ( & tbdf - > cbd_sc , 0 ) ;
if ( ! ( pmsg - > flags & I2C_M_NOSTART ) )
setbits16 ( & tbdf - > cbd_sc , BD_I2C_START ) ;
if ( tx + 1 = = num )
setbits16 ( & tbdf - > cbd_sc , BD_SC_LAST | BD_SC_WRAP ) ;
if ( pmsg - > flags & I2C_M_RD ) {
/*
* To read , we need an empty buffer of the proper length .
* All that is used is the first byte for address , the remainder
* is just used for timing ( and doesn ' t really have to exist ) .
*/
dev_dbg ( & adap - > dev , " cpm_i2c_read(abyte=0x%x) \n " , addr ) ;
out_be16 ( & rbdf - > cbd_datlen , 0 ) ;
out_be16 ( & rbdf - > cbd_sc , BD_SC_EMPTY | BD_SC_INTRPT ) ;
if ( rx + 1 = = CPM_MAXBD )
setbits16 ( & rbdf - > cbd_sc , BD_SC_WRAP ) ;
eieio ( ) ;
setbits16 ( & tbdf - > cbd_sc , BD_SC_READY ) ;
} else {
2008-07-14 22:38:28 +02:00
dev_dbg ( & adap - > dev , " cpm_i2c_write(abyte=0x%x) \n " , addr ) ;
2008-07-14 22:38:27 +02:00
memcpy ( tb + 1 , pmsg - > buf , pmsg - > len ) ;
eieio ( ) ;
setbits16 ( & tbdf - > cbd_sc , BD_SC_READY | BD_SC_INTRPT ) ;
}
}
static int cpm_i2c_check_message ( struct i2c_adapter * adap ,
struct i2c_msg * pmsg , int tx , int rx )
{
cbd_t __iomem * tbdf ;
cbd_t __iomem * rbdf ;
u_char * tb ;
u_char * rb ;
struct cpm_i2c * cpm = i2c_get_adapdata ( adap ) ;
tbdf = cpm - > tbase + tx ;
rbdf = cpm - > rbase + rx ;
tb = cpm - > txbuf [ tx ] ;
rb = cpm - > rxbuf [ rx ] ;
/* Align read buffer */
rb = ( u_char * ) ( ( ( uint ) rb + 1 ) & ~ 1 ) ;
eieio ( ) ;
if ( pmsg - > flags & I2C_M_RD ) {
dev_dbg ( & adap - > dev , " tx sc 0x%04x, rx sc 0x%04x \n " ,
in_be16 ( & tbdf - > cbd_sc ) , in_be16 ( & rbdf - > cbd_sc ) ) ;
if ( in_be16 ( & tbdf - > cbd_sc ) & BD_SC_NAK ) {
dev_dbg ( & adap - > dev , " I2C read; No ack \n " ) ;
return - ENXIO ;
}
if ( in_be16 ( & rbdf - > cbd_sc ) & BD_SC_EMPTY ) {
dev_err ( & adap - > dev ,
" I2C read; complete but rbuf empty \n " ) ;
return - EREMOTEIO ;
}
if ( in_be16 ( & rbdf - > cbd_sc ) & BD_SC_OV ) {
dev_err ( & adap - > dev , " I2C read; Overrun \n " ) ;
return - EREMOTEIO ;
}
memcpy ( pmsg - > buf , rb , pmsg - > len ) ;
} else {
dev_dbg ( & adap - > dev , " tx sc %d 0x%04x \n " , tx ,
in_be16 ( & tbdf - > cbd_sc ) ) ;
if ( in_be16 ( & tbdf - > cbd_sc ) & BD_SC_NAK ) {
dev_dbg ( & adap - > dev , " I2C write; No ack \n " ) ;
return - ENXIO ;
}
if ( in_be16 ( & tbdf - > cbd_sc ) & BD_SC_UN ) {
dev_err ( & adap - > dev , " I2C write; Underrun \n " ) ;
return - EIO ;
}
if ( in_be16 ( & tbdf - > cbd_sc ) & BD_SC_CL ) {
dev_err ( & adap - > dev , " I2C write; Collision \n " ) ;
return - EIO ;
}
}
return 0 ;
}
static int cpm_i2c_xfer ( struct i2c_adapter * adap , struct i2c_msg * msgs , int num )
{
struct cpm_i2c * cpm = i2c_get_adapdata ( adap ) ;
struct i2c_reg __iomem * i2c_reg = cpm - > i2c_reg ;
struct i2c_ram __iomem * i2c_ram = cpm - > i2c_ram ;
struct i2c_msg * pmsg ;
int ret , i ;
int tptr ;
int rptr ;
cbd_t __iomem * tbdf ;
cbd_t __iomem * rbdf ;
if ( num > CPM_MAXBD )
return - EINVAL ;
/* Check if we have any oversized READ requests */
for ( i = 0 ; i < num ; i + + ) {
pmsg = & msgs [ i ] ;
if ( pmsg - > len > = CPM_MAX_READ )
return - EINVAL ;
}
/* Reset to use first buffer */
out_be16 ( & i2c_ram - > rbptr , in_be16 ( & i2c_ram - > rbase ) ) ;
out_be16 ( & i2c_ram - > tbptr , in_be16 ( & i2c_ram - > tbase ) ) ;
tbdf = cpm - > tbase ;
rbdf = cpm - > rbase ;
tptr = 0 ;
rptr = 0 ;
while ( tptr < num ) {
pmsg = & msgs [ tptr ] ;
dev_dbg ( & adap - > dev , " R: %d T: %d \n " , rptr , tptr ) ;
cpm_i2c_parse_message ( adap , pmsg , num , tptr , rptr ) ;
if ( pmsg - > flags & I2C_M_RD )
rptr + + ;
tptr + + ;
}
/* Start transfer now */
/* Enable RX/TX/Error interupts */
2008-07-14 22:38:28 +02:00
out_8 ( & i2c_reg - > i2cmr , I2CER_TXE | I2CER_TXB | I2CER_RXB ) ;
2008-07-14 22:38:27 +02:00
out_8 ( & i2c_reg - > i2cer , 0xff ) ; /* Clear interrupt status */
/* Chip bug, set enable here */
setbits8 ( & i2c_reg - > i2mod , I2MOD_EN ) ; /* Enable */
/* Begin transmission */
setbits8 ( & i2c_reg - > i2com , I2COM_START ) ;
tptr = 0 ;
rptr = 0 ;
while ( tptr < num ) {
/* Check for outstanding messages */
dev_dbg ( & adap - > dev , " test ready. \n " ) ;
pmsg = & msgs [ tptr ] ;
if ( pmsg - > flags & I2C_M_RD )
ret = wait_event_interruptible_timeout ( cpm - > i2c_wait ,
! ( in_be16 ( & rbdf [ rptr ] . cbd_sc ) & BD_SC_EMPTY ) ,
1 * HZ ) ;
else
ret = wait_event_interruptible_timeout ( cpm - > i2c_wait ,
! ( in_be16 ( & tbdf [ tptr ] . cbd_sc ) & BD_SC_READY ) ,
1 * HZ ) ;
if ( ret = = 0 ) {
ret = - EREMOTEIO ;
dev_err ( & adap - > dev , " I2C transfer: timeout \n " ) ;
goto out_err ;
}
if ( ret > 0 ) {
dev_dbg ( & adap - > dev , " ready. \n " ) ;
ret = cpm_i2c_check_message ( adap , pmsg , tptr , rptr ) ;
tptr + + ;
if ( pmsg - > flags & I2C_M_RD )
rptr + + ;
if ( ret )
goto out_err ;
}
}
# ifdef I2C_CHIP_ERRATA
/*
* Chip errata , clear enable . This is not needed on rev D4 CPUs .
* Disabling I2C too early may cause too short stop condition
*/
udelay ( 4 ) ;
clrbits8 ( & i2c_reg - > i2mod , I2MOD_EN ) ;
# endif
return ( num ) ;
out_err :
cpm_i2c_force_close ( adap ) ;
# ifdef I2C_CHIP_ERRATA
/*
* Chip errata , clear enable . This is not needed on rev D4 CPUs .
*/
clrbits8 ( & i2c_reg - > i2mod , I2MOD_EN ) ;
# endif
return ret ;
}
static u32 cpm_i2c_func ( struct i2c_adapter * adap )
{
return I2C_FUNC_I2C | ( I2C_FUNC_SMBUS_EMUL & ~ I2C_FUNC_SMBUS_QUICK ) ;
}
/* -----exported algorithm data: ------------------------------------- */
static const struct i2c_algorithm cpm_i2c_algo = {
. master_xfer = cpm_i2c_xfer ,
. functionality = cpm_i2c_func ,
} ;
static const struct i2c_adapter cpm_ops = {
. owner = THIS_MODULE ,
. name = " i2c-cpm " ,
. algo = & cpm_i2c_algo ,
2008-07-14 22:38:29 +02:00
. class = I2C_CLASS_HWMON | I2C_CLASS_SPD ,
2008-07-14 22:38:27 +02:00
} ;
static int __devinit cpm_i2c_setup ( struct cpm_i2c * cpm )
{
struct of_device * ofdev = cpm - > ofdev ;
const u32 * data ;
int len , ret , i ;
void __iomem * i2c_base ;
cbd_t __iomem * tbdf ;
cbd_t __iomem * rbdf ;
unsigned char brg ;
dev_dbg ( & cpm - > ofdev - > dev , " cpm_i2c_setup() \n " ) ;
init_waitqueue_head ( & cpm - > i2c_wait ) ;
cpm - > irq = of_irq_to_resource ( ofdev - > node , 0 , NULL ) ;
if ( cpm - > irq = = NO_IRQ )
return - EINVAL ;
/* Install interrupt handler. */
ret = request_irq ( cpm - > irq , cpm_i2c_interrupt , 0 , " cpm_i2c " ,
& cpm - > adap ) ;
if ( ret )
return ret ;
/* I2C parameter RAM */
i2c_base = of_iomap ( ofdev - > node , 1 ) ;
if ( i2c_base = = NULL ) {
ret = - EINVAL ;
goto out_irq ;
}
if ( of_device_is_compatible ( ofdev - > node , " fsl,cpm1-i2c " ) ) {
/* Check for and use a microcode relocation patch. */
cpm - > i2c_ram = i2c_base ;
cpm - > i2c_addr = in_be16 ( & cpm - > i2c_ram - > rpbase ) ;
/*
* Maybe should use cpm_muram_alloc instead of hardcoding
* this in micropatch . c
*/
if ( cpm - > i2c_addr ) {
cpm - > i2c_ram = cpm_muram_addr ( cpm - > i2c_addr ) ;
iounmap ( i2c_base ) ;
}
cpm - > version = 1 ;
} else if ( of_device_is_compatible ( ofdev - > node , " fsl,cpm2-i2c " ) ) {
cpm - > i2c_addr = cpm_muram_alloc ( sizeof ( struct i2c_ram ) , 64 ) ;
cpm - > i2c_ram = cpm_muram_addr ( cpm - > i2c_addr ) ;
out_be16 ( i2c_base , cpm - > i2c_addr ) ;
iounmap ( i2c_base ) ;
cpm - > version = 2 ;
} else {
iounmap ( i2c_base ) ;
ret = - EINVAL ;
goto out_irq ;
}
/* I2C control/status registers */
cpm - > i2c_reg = of_iomap ( ofdev - > node , 0 ) ;
if ( cpm - > i2c_reg = = NULL ) {
ret = - EINVAL ;
goto out_ram ;
}
data = of_get_property ( ofdev - > node , " fsl,cpm-command " , & len ) ;
if ( ! data | | len ! = 4 ) {
ret = - EINVAL ;
goto out_reg ;
}
cpm - > cp_command = * data ;
data = of_get_property ( ofdev - > node , " linux,i2c-class " , & len ) ;
if ( data & & len = = 4 )
cpm - > adap . class = * data ;
data = of_get_property ( ofdev - > node , " clock-frequency " , & len ) ;
if ( data & & len = = 4 )
cpm - > freq = * data ;
else
cpm - > freq = 60000 ; /* use 60kHz i2c clock by default */
/*
* Allocate space for CPM_MAXBD transmit and receive buffer
* descriptors in the DP ram .
*/
cpm - > dp_addr = cpm_muram_alloc ( sizeof ( cbd_t ) * 2 * CPM_MAXBD , 8 ) ;
if ( ! cpm - > dp_addr ) {
ret = - ENOMEM ;
goto out_reg ;
}
cpm - > tbase = cpm_muram_addr ( cpm - > dp_addr ) ;
cpm - > rbase = cpm_muram_addr ( cpm - > dp_addr + sizeof ( cbd_t ) * CPM_MAXBD ) ;
/* Allocate TX and RX buffers */
tbdf = cpm - > tbase ;
rbdf = cpm - > rbase ;
for ( i = 0 ; i < CPM_MAXBD ; i + + ) {
cpm - > rxbuf [ i ] = dma_alloc_coherent (
NULL , CPM_MAX_READ + 1 , & cpm - > rxdma [ i ] , GFP_KERNEL ) ;
if ( ! cpm - > rxbuf [ i ] ) {
ret = - ENOMEM ;
goto out_muram ;
}
out_be32 ( & rbdf [ i ] . cbd_bufaddr , ( ( cpm - > rxdma [ i ] + 1 ) & ~ 1 ) ) ;
cpm - > txbuf [ i ] = ( unsigned char * ) dma_alloc_coherent (
NULL , CPM_MAX_READ + 1 , & cpm - > txdma [ i ] , GFP_KERNEL ) ;
if ( ! cpm - > txbuf [ i ] ) {
ret = - ENOMEM ;
goto out_muram ;
}
out_be32 ( & tbdf [ i ] . cbd_bufaddr , cpm - > txdma [ i ] ) ;
}
/* Initialize Tx/Rx parameters. */
cpm_reset_i2c_params ( cpm ) ;
2008-07-14 22:38:28 +02:00
dev_dbg ( & cpm - > ofdev - > dev , " i2c_ram 0x%p, i2c_addr 0x%04x, freq %d \n " ,
cpm - > i2c_ram , cpm - > i2c_addr , cpm - > freq ) ;
2008-07-14 22:38:27 +02:00
dev_dbg ( & cpm - > ofdev - > dev , " tbase 0x%04x, rbase 0x%04x \n " ,
( u8 __iomem * ) cpm - > tbase - DPRAM_BASE ,
( u8 __iomem * ) cpm - > rbase - DPRAM_BASE ) ;
cpm_command ( cpm - > cp_command , CPM_CR_INIT_TRX ) ;
/*
* Select an invalid address . Just make sure we don ' t use loopback mode
*/
out_8 ( & cpm - > i2c_reg - > i2add , 0x7f < < 1 ) ;
/*
* PDIV is set to 00 in i2mod , so brgclk / 32 is used as input to the
* i2c baud rate generator . This is divided by 2 x ( DIV + 3 ) to get
* the actual i2c bus frequency .
*/
brg = get_brgfreq ( ) / ( 32 * 2 * cpm - > freq ) - 3 ;
out_8 ( & cpm - > i2c_reg - > i2brg , brg ) ;
out_8 ( & cpm - > i2c_reg - > i2mod , 0x00 ) ;
out_8 ( & cpm - > i2c_reg - > i2com , I2COM_MASTER ) ; /* Master mode */
/* Disable interrupts. */
out_8 ( & cpm - > i2c_reg - > i2cmr , 0 ) ;
out_8 ( & cpm - > i2c_reg - > i2cer , 0xff ) ;
return 0 ;
out_muram :
for ( i = 0 ; i < CPM_MAXBD ; i + + ) {
if ( cpm - > rxbuf [ i ] )
dma_free_coherent ( NULL , CPM_MAX_READ + 1 ,
cpm - > rxbuf [ i ] , cpm - > rxdma [ i ] ) ;
if ( cpm - > txbuf [ i ] )
dma_free_coherent ( NULL , CPM_MAX_READ + 1 ,
cpm - > txbuf [ i ] , cpm - > txdma [ i ] ) ;
}
cpm_muram_free ( cpm - > dp_addr ) ;
out_reg :
iounmap ( cpm - > i2c_reg ) ;
out_ram :
if ( ( cpm - > version = = 1 ) & & ( ! cpm - > i2c_addr ) )
iounmap ( cpm - > i2c_ram ) ;
if ( cpm - > version = = 2 )
cpm_muram_free ( cpm - > i2c_addr ) ;
out_irq :
free_irq ( cpm - > irq , & cpm - > adap ) ;
return ret ;
}
static void cpm_i2c_shutdown ( struct cpm_i2c * cpm )
{
int i ;
/* Shut down I2C. */
clrbits8 ( & cpm - > i2c_reg - > i2mod , I2MOD_EN ) ;
/* Disable interrupts */
out_8 ( & cpm - > i2c_reg - > i2cmr , 0 ) ;
out_8 ( & cpm - > i2c_reg - > i2cer , 0xff ) ;
free_irq ( cpm - > irq , & cpm - > adap ) ;
/* Free all memory */
for ( i = 0 ; i < CPM_MAXBD ; i + + ) {
dma_free_coherent ( NULL , CPM_MAX_READ + 1 ,
cpm - > rxbuf [ i ] , cpm - > rxdma [ i ] ) ;
dma_free_coherent ( NULL , CPM_MAX_READ + 1 ,
cpm - > txbuf [ i ] , cpm - > txdma [ i ] ) ;
}
cpm_muram_free ( cpm - > dp_addr ) ;
iounmap ( cpm - > i2c_reg ) ;
if ( ( cpm - > version = = 1 ) & & ( ! cpm - > i2c_addr ) )
iounmap ( cpm - > i2c_ram ) ;
if ( cpm - > version = = 2 )
cpm_muram_free ( cpm - > i2c_addr ) ;
}
static int __devinit cpm_i2c_probe ( struct of_device * ofdev ,
const struct of_device_id * match )
{
int result , len ;
struct cpm_i2c * cpm ;
const u32 * data ;
cpm = kzalloc ( sizeof ( struct cpm_i2c ) , GFP_KERNEL ) ;
if ( ! cpm )
return - ENOMEM ;
cpm - > ofdev = ofdev ;
dev_set_drvdata ( & ofdev - > dev , cpm ) ;
cpm - > adap = cpm_ops ;
i2c_set_adapdata ( & cpm - > adap , cpm ) ;
cpm - > adap . dev . parent = & ofdev - > dev ;
result = cpm_i2c_setup ( cpm ) ;
if ( result ) {
dev_err ( & ofdev - > dev , " Unable to init hardware \n " ) ;
goto out_free ;
}
/* register new adapter to i2c module... */
data = of_get_property ( ofdev - > node , " linux,i2c-index " , & len ) ;
if ( data & & len = = 4 ) {
cpm - > adap . nr = * data ;
result = i2c_add_numbered_adapter ( & cpm - > adap ) ;
} else
result = i2c_add_adapter ( & cpm - > adap ) ;
if ( result < 0 ) {
dev_err ( & ofdev - > dev , " Unable to register with I2C \n " ) ;
goto out_shut ;
}
dev_dbg ( & ofdev - > dev , " hw routines for %s registered. \n " ,
cpm - > adap . name ) ;
/*
* register OF I2C devices
*/
of_register_i2c_devices ( & cpm - > adap , ofdev - > node ) ;
return 0 ;
out_shut :
cpm_i2c_shutdown ( cpm ) ;
out_free :
dev_set_drvdata ( & ofdev - > dev , NULL ) ;
kfree ( cpm ) ;
return result ;
}
static int __devexit cpm_i2c_remove ( struct of_device * ofdev )
{
struct cpm_i2c * cpm = dev_get_drvdata ( & ofdev - > dev ) ;
i2c_del_adapter ( & cpm - > adap ) ;
cpm_i2c_shutdown ( cpm ) ;
dev_set_drvdata ( & ofdev - > dev , NULL ) ;
kfree ( cpm ) ;
return 0 ;
}
static const struct of_device_id cpm_i2c_match [ ] = {
{
. compatible = " fsl,cpm1-i2c " ,
} ,
{
. compatible = " fsl,cpm2-i2c " ,
} ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , cpm_i2c_match ) ;
static struct of_platform_driver cpm_i2c_driver = {
. match_table = cpm_i2c_match ,
. probe = cpm_i2c_probe ,
. remove = __devexit_p ( cpm_i2c_remove ) ,
. driver = {
. name = " fsl-i2c-cpm " ,
. owner = THIS_MODULE ,
}
} ;
static int __init cpm_i2c_init ( void )
{
return of_register_platform_driver ( & cpm_i2c_driver ) ;
}
static void __exit cpm_i2c_exit ( void )
{
of_unregister_platform_driver ( & cpm_i2c_driver ) ;
}
module_init ( cpm_i2c_init ) ;
module_exit ( cpm_i2c_exit ) ;
MODULE_AUTHOR ( " Jochen Friedrich <jochen@scram.de> " ) ;
MODULE_DESCRIPTION ( " I2C-Bus adapter routines for CPM boards " ) ;
MODULE_LICENSE ( " GPL " ) ;