2005-04-17 02:20:36 +04:00
/* ------------------------------------------------------------------------- */
/* i2c-iop3xx.c i2c driver algorithms for Intel XScale IOP3xx & IXP46x */
/* ------------------------------------------------------------------------- */
/* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd
* < Peter dot Milne at D hyphen TACQ dot com >
*
2012-07-04 23:14:16 +04:00
* With acknowledgements to i2c - algo - ibm_ocp . c by
2005-04-17 02:20:36 +04:00
* Ian DaSilva , MontaVista Software , Inc . idasilva @ mvista . com
*
* And i2c - algo - pcf . c , which was created by Simon G . Vogl and Hans Berglund :
*
* Copyright ( C ) 1995 - 1997 Simon G . Vogl , 1998 - 2000 Hans Berglund
2012-07-04 23:14:16 +04:00
*
2005-11-02 01:31:12 +03:00
* And which acknowledged Kyösti Mälkki < kmalkki @ cc . hut . fi > ,
2005-04-17 02:20:36 +04:00
* Frodo Looijaard < frodol @ dds . nl > , Martin Bailey < mbailey @ littlefeet - inc . com >
*
* Major cleanup by Deepak Saxena < dsaxena @ plexity . net > , 01 / 2005 :
*
* - Use driver model to pass per - chip info instead of hardcoding and # ifdefs
* - Use ioremap / __raw_readl / __raw_writel instead of direct dereference
* - Make it work with IXP46x chips
* - Cleanup function names , coding style , etc
*
2006-07-01 19:03:20 +04:00
* - writing to slave address causes latchup on iop331 .
* fix : driver refuses to address self .
*
2005-04-17 02:20:36 +04:00
* 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 , version 2.
*/
# include <linux/interrupt.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/delay.h>
# include <linux/slab.h>
# include <linux/errno.h>
2005-10-29 22:07:23 +04:00
# include <linux/platform_device.h>
2005-04-17 02:20:36 +04:00
# include <linux/i2c.h>
2010-05-21 20:41:01 +04:00
# include <linux/io.h>
2012-07-04 23:16:12 +04:00
# include <linux/gpio.h>
2005-04-17 02:20:36 +04:00
# include "i2c-iop3xx.h"
/* global unit counter */
2005-09-25 18:23:07 +04:00
static int i2c_id ;
2005-04-17 02:20:36 +04:00
2012-07-04 23:14:16 +04:00
static inline unsigned char
iic_cook_addr ( struct i2c_msg * msg )
2005-04-17 02:20:36 +04:00
{
unsigned char addr ;
2016-04-03 21:44:53 +03:00
addr = i2c_8bit_addr_from_msg ( msg ) ;
2005-04-17 02:20:36 +04:00
2012-07-04 23:14:16 +04:00
return addr ;
2005-04-17 02:20:36 +04:00
}
2012-07-04 23:14:16 +04:00
static void
2005-04-17 02:20:36 +04:00
iop3xx_i2c_reset ( struct i2c_algo_iop3xx_data * iop3xx_adap )
{
/* Follows devman 9.3 */
__raw_writel ( IOP3XX_ICR_UNIT_RESET , iop3xx_adap - > ioaddr + CR_OFFSET ) ;
__raw_writel ( IOP3XX_ISR_CLEARBITS , iop3xx_adap - > ioaddr + SR_OFFSET ) ;
__raw_writel ( 0 , iop3xx_adap - > ioaddr + CR_OFFSET ) ;
2012-07-04 23:14:16 +04:00
}
2005-04-17 02:20:36 +04:00
2012-07-04 23:14:16 +04:00
static void
2005-04-17 02:20:36 +04:00
iop3xx_i2c_enable ( struct i2c_algo_iop3xx_data * iop3xx_adap )
{
u32 cr = IOP3XX_ICR_GCD | IOP3XX_ICR_SCLEN | IOP3XX_ICR_UE ;
2012-07-04 23:14:16 +04:00
/*
2005-05-04 04:21:25 +04:00
* Every time unit enable is asserted , GPOD needs to be cleared
2006-09-19 02:23:07 +04:00
* on IOP3XX to avoid data corruption on the bus .
2005-04-17 02:20:36 +04:00
*/
2007-02-13 19:12:04 +03:00
# if defined(CONFIG_ARCH_IOP32X) || defined(CONFIG_ARCH_IOP33X)
2006-09-19 02:23:07 +04:00
if ( iop3xx_adap - > id = = 0 ) {
2012-07-04 23:16:12 +04:00
gpio_set_value ( 7 , 0 ) ;
gpio_set_value ( 6 , 0 ) ;
2006-09-19 02:23:07 +04:00
} else {
2012-07-04 23:16:12 +04:00
gpio_set_value ( 5 , 0 ) ;
gpio_set_value ( 4 , 0 ) ;
2006-09-19 02:23:07 +04:00
}
2005-04-17 02:20:36 +04:00
# endif
/* NB SR bits not same position as CR IE bits :-( */
2012-07-04 23:14:16 +04:00
iop3xx_adap - > SR_enabled =
2005-04-17 02:20:36 +04:00
IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD |
IOP3XX_ISR_RXFULL | IOP3XX_ISR_TXEMPTY ;
cr | = IOP3XX_ICR_ALD_IE | IOP3XX_ICR_BERR_IE |
IOP3XX_ICR_RXFULL_IE | IOP3XX_ICR_TXEMPTY_IE ;
__raw_writel ( cr , iop3xx_adap - > ioaddr + CR_OFFSET ) ;
}
2012-07-04 23:14:16 +04:00
static void
2005-04-17 02:20:36 +04:00
iop3xx_i2c_transaction_cleanup ( struct i2c_algo_iop3xx_data * iop3xx_adap )
{
unsigned long cr = __raw_readl ( iop3xx_adap - > ioaddr + CR_OFFSET ) ;
2012-07-04 23:14:16 +04:00
cr & = ~ ( IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE |
2005-04-17 02:20:36 +04:00
IOP3XX_ICR_MSTOP | IOP3XX_ICR_SCLEN ) ;
__raw_writel ( cr , iop3xx_adap - > ioaddr + CR_OFFSET ) ;
}
2012-07-04 23:14:16 +04:00
/*
* NB : the handler has to clear the source of the interrupt !
2005-04-17 02:20:36 +04:00
* Then it passes the SR flags of interest to BH via adap data
*/
2012-07-04 23:14:16 +04:00
static irqreturn_t
iop3xx_i2c_irq_handler ( int this_irq , void * dev_id )
2005-04-17 02:20:36 +04:00
{
struct i2c_algo_iop3xx_data * iop3xx_adap = dev_id ;
u32 sr = __raw_readl ( iop3xx_adap - > ioaddr + SR_OFFSET ) ;
if ( ( sr & = iop3xx_adap - > SR_enabled ) ) {
__raw_writel ( sr , iop3xx_adap - > ioaddr + SR_OFFSET ) ;
iop3xx_adap - > SR_received | = sr ;
wake_up_interruptible ( & iop3xx_adap - > waitq ) ;
}
return IRQ_HANDLED ;
}
/* check all error conditions, clear them , report most important */
2012-07-04 23:14:16 +04:00
static int
2005-04-17 02:20:36 +04:00
iop3xx_i2c_error ( u32 sr )
{
int rc = 0 ;
if ( ( sr & IOP3XX_ISR_BERRD ) ) {
if ( ! rc ) rc = - I2C_ERR_BERR ;
}
if ( ( sr & IOP3XX_ISR_ALD ) ) {
2012-07-04 23:14:16 +04:00
if ( ! rc ) rc = - I2C_ERR_ALD ;
2005-04-17 02:20:36 +04:00
}
2012-07-04 23:14:16 +04:00
return rc ;
2005-04-17 02:20:36 +04:00
}
2012-07-04 23:14:16 +04:00
static inline u32
2005-04-17 02:20:36 +04:00
iop3xx_i2c_get_srstat ( struct i2c_algo_iop3xx_data * iop3xx_adap )
{
unsigned long flags ;
u32 sr ;
spin_lock_irqsave ( & iop3xx_adap - > lock , flags ) ;
sr = iop3xx_adap - > SR_received ;
iop3xx_adap - > SR_received = 0 ;
spin_unlock_irqrestore ( & iop3xx_adap - > lock , flags ) ;
return sr ;
}
/*
* sleep until interrupted , then recover and analyse the SR
* saved by handler
*/
typedef int ( * compare_func ) ( unsigned test , unsigned mask ) ;
/* returns 1 on correct comparison */
2012-07-04 23:14:16 +04:00
static int
iop3xx_i2c_wait_event ( struct i2c_algo_iop3xx_data * iop3xx_adap ,
2005-04-17 02:20:36 +04:00
unsigned flags , unsigned * status ,
compare_func compare )
{
unsigned sr = 0 ;
int interrupted ;
int done ;
int rc = 0 ;
do {
interrupted = wait_event_interruptible_timeout (
iop3xx_adap - > waitq ,
2005-11-02 01:31:12 +03:00
( done = compare ( sr = iop3xx_i2c_get_srstat ( iop3xx_adap ) , flags ) ) ,
2013-06-29 01:35:52 +04:00
1 * HZ
2005-04-17 02:20:36 +04:00
) ;
if ( ( rc = iop3xx_i2c_error ( sr ) ) < 0 ) {
* status = sr ;
return rc ;
} else if ( ! interrupted ) {
* status = sr ;
return - ETIMEDOUT ;
}
} while ( ! done ) ;
* status = sr ;
return 0 ;
}
/*
2012-07-04 23:14:16 +04:00
* Concrete compare_funcs
2005-04-17 02:20:36 +04:00
*/
2012-07-04 23:14:16 +04:00
static int
2005-04-17 02:20:36 +04:00
all_bits_clear ( unsigned test , unsigned mask )
{
return ( test & mask ) = = 0 ;
}
2012-07-04 23:14:16 +04:00
static int
2005-04-17 02:20:36 +04:00
any_bits_set ( unsigned test , unsigned mask )
{
return ( test & mask ) ! = 0 ;
}
2012-07-04 23:14:16 +04:00
static int
2005-04-17 02:20:36 +04:00
iop3xx_i2c_wait_tx_done ( struct i2c_algo_iop3xx_data * iop3xx_adap , int * status )
{
2012-07-04 23:14:16 +04:00
return iop3xx_i2c_wait_event (
iop3xx_adap ,
2005-04-17 02:20:36 +04:00
IOP3XX_ISR_TXEMPTY | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD ,
status , any_bits_set ) ;
}
2012-07-04 23:14:16 +04:00
static int
2005-04-17 02:20:36 +04:00
iop3xx_i2c_wait_rx_done ( struct i2c_algo_iop3xx_data * iop3xx_adap , int * status )
{
2012-07-04 23:14:16 +04:00
return iop3xx_i2c_wait_event (
iop3xx_adap ,
2005-04-17 02:20:36 +04:00
IOP3XX_ISR_RXFULL | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD ,
status , any_bits_set ) ;
}
2012-07-04 23:14:16 +04:00
static int
2005-04-17 02:20:36 +04:00
iop3xx_i2c_wait_idle ( struct i2c_algo_iop3xx_data * iop3xx_adap , int * status )
{
2012-07-04 23:14:16 +04:00
return iop3xx_i2c_wait_event (
2005-04-17 02:20:36 +04:00
iop3xx_adap , IOP3XX_ISR_UNITBUSY , status , all_bits_clear ) ;
}
2012-07-04 23:14:16 +04:00
static int
iop3xx_i2c_send_target_addr ( struct i2c_algo_iop3xx_data * iop3xx_adap ,
2005-04-17 02:20:36 +04:00
struct i2c_msg * msg )
{
unsigned long cr = __raw_readl ( iop3xx_adap - > ioaddr + CR_OFFSET ) ;
int status ;
int rc ;
2006-07-01 19:03:20 +04:00
/* avoid writing to my slave address (hangs on 80331),
* forbidden in Intel developer manual
*/
if ( msg - > addr = = MYSAR ) {
return - EBUSY ;
}
2005-04-17 02:20:36 +04:00
__raw_writel ( iic_cook_addr ( msg ) , iop3xx_adap - > ioaddr + DBR_OFFSET ) ;
2012-07-04 23:14:16 +04:00
2005-04-17 02:20:36 +04:00
cr & = ~ ( IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK ) ;
cr | = IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE ;
__raw_writel ( cr , iop3xx_adap - > ioaddr + CR_OFFSET ) ;
rc = iop3xx_i2c_wait_tx_done ( iop3xx_adap , & status ) ;
return rc ;
}
2012-07-04 23:14:16 +04:00
static int
iop3xx_i2c_write_byte ( struct i2c_algo_iop3xx_data * iop3xx_adap , char byte ,
2005-04-17 02:20:36 +04:00
int stop )
{
unsigned long cr = __raw_readl ( iop3xx_adap - > ioaddr + CR_OFFSET ) ;
int status ;
int rc = 0 ;
__raw_writel ( byte , iop3xx_adap - > ioaddr + DBR_OFFSET ) ;
cr & = ~ IOP3XX_ICR_MSTART ;
if ( stop ) {
cr | = IOP3XX_ICR_MSTOP ;
} else {
cr & = ~ IOP3XX_ICR_MSTOP ;
}
cr | = IOP3XX_ICR_TBYTE ;
__raw_writel ( cr , iop3xx_adap - > ioaddr + CR_OFFSET ) ;
rc = iop3xx_i2c_wait_tx_done ( iop3xx_adap , & status ) ;
return rc ;
2012-07-04 23:14:16 +04:00
}
2005-04-17 02:20:36 +04:00
2012-07-04 23:14:16 +04:00
static int
iop3xx_i2c_read_byte ( struct i2c_algo_iop3xx_data * iop3xx_adap , char * byte ,
2005-04-17 02:20:36 +04:00
int stop )
{
unsigned long cr = __raw_readl ( iop3xx_adap - > ioaddr + CR_OFFSET ) ;
int status ;
int rc = 0 ;
cr & = ~ IOP3XX_ICR_MSTART ;
if ( stop ) {
cr | = IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK ;
} else {
cr & = ~ ( IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK ) ;
}
cr | = IOP3XX_ICR_TBYTE ;
__raw_writel ( cr , iop3xx_adap - > ioaddr + CR_OFFSET ) ;
rc = iop3xx_i2c_wait_rx_done ( iop3xx_adap , & status ) ;
* byte = __raw_readl ( iop3xx_adap - > ioaddr + DBR_OFFSET ) ;
return rc ;
}
2012-07-04 23:14:16 +04:00
static int
2005-04-17 02:20:36 +04:00
iop3xx_i2c_writebytes ( struct i2c_adapter * i2c_adap , const char * buf , int count )
{
struct i2c_algo_iop3xx_data * iop3xx_adap = i2c_adap - > algo_data ;
int ii ;
int rc = 0 ;
2012-07-04 23:14:16 +04:00
for ( ii = 0 ; rc = = 0 & & ii ! = count ; + + ii )
2005-04-17 02:20:36 +04:00
rc = iop3xx_i2c_write_byte ( iop3xx_adap , buf [ ii ] , ii = = count - 1 ) ;
return rc ;
}
2012-07-04 23:14:16 +04:00
static int
2005-04-17 02:20:36 +04:00
iop3xx_i2c_readbytes ( struct i2c_adapter * i2c_adap , char * buf , int count )
{
struct i2c_algo_iop3xx_data * iop3xx_adap = i2c_adap - > algo_data ;
int ii ;
int rc = 0 ;
for ( ii = 0 ; rc = = 0 & & ii ! = count ; + + ii )
rc = iop3xx_i2c_read_byte ( iop3xx_adap , & buf [ ii ] , ii = = count - 1 ) ;
2012-07-04 23:14:16 +04:00
2005-04-17 02:20:36 +04:00
return rc ;
}
/*
* Description : This function implements combined transactions . Combined
* transactions consist of combinations of reading and writing blocks of data .
* FROM THE SAME ADDRESS
* Each transfer ( i . e . a read or a write ) is separated by a repeated start
* condition .
*/
2012-07-04 23:14:16 +04:00
static int
iop3xx_i2c_handle_msg ( struct i2c_adapter * i2c_adap , struct i2c_msg * pmsg )
2005-04-17 02:20:36 +04:00
{
struct i2c_algo_iop3xx_data * iop3xx_adap = i2c_adap - > algo_data ;
int rc ;
rc = iop3xx_i2c_send_target_addr ( iop3xx_adap , pmsg ) ;
if ( rc < 0 ) {
return rc ;
}
if ( ( pmsg - > flags & I2C_M_RD ) ) {
return iop3xx_i2c_readbytes ( i2c_adap , pmsg - > buf , pmsg - > len ) ;
} else {
return iop3xx_i2c_writebytes ( i2c_adap , pmsg - > buf , pmsg - > len ) ;
}
}
/*
* master_xfer ( ) - main read / write entry
*/
2012-07-04 23:14:16 +04:00
static int
iop3xx_i2c_master_xfer ( struct i2c_adapter * i2c_adap , struct i2c_msg * msgs ,
2005-04-17 02:20:36 +04:00
int num )
{
struct i2c_algo_iop3xx_data * iop3xx_adap = i2c_adap - > algo_data ;
int im = 0 ;
int ret = 0 ;
int status ;
iop3xx_i2c_wait_idle ( iop3xx_adap , & status ) ;
iop3xx_i2c_reset ( iop3xx_adap ) ;
iop3xx_i2c_enable ( iop3xx_adap ) ;
for ( im = 0 ; ret = = 0 & & im ! = num ; im + + ) {
ret = iop3xx_i2c_handle_msg ( i2c_adap , & msgs [ im ] ) ;
}
iop3xx_i2c_transaction_cleanup ( iop3xx_adap ) ;
2012-07-04 23:14:16 +04:00
2005-04-17 02:20:36 +04:00
if ( ret )
return ret ;
2012-07-04 23:14:16 +04:00
return im ;
2005-04-17 02:20:36 +04:00
}
2012-07-04 23:14:16 +04:00
static u32
2005-04-17 02:20:36 +04:00
iop3xx_i2c_func ( struct i2c_adapter * adap )
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL ;
}
2006-09-04 00:39:46 +04:00
static const struct i2c_algorithm iop3xx_i2c_algo = {
2005-04-17 02:20:36 +04:00
. master_xfer = iop3xx_i2c_master_xfer ,
. functionality = iop3xx_i2c_func ,
} ;
2012-07-04 23:14:16 +04:00
static int
2005-11-10 01:32:44 +03:00
iop3xx_i2c_remove ( struct platform_device * pdev )
2005-04-17 02:20:36 +04:00
{
2005-11-10 01:32:44 +03:00
struct i2c_adapter * padapter = platform_get_drvdata ( pdev ) ;
2012-07-04 23:14:16 +04:00
struct i2c_algo_iop3xx_data * adapter_data =
2005-04-17 02:20:36 +04:00
( struct i2c_algo_iop3xx_data * ) padapter - > algo_data ;
struct resource * res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
unsigned long cr = __raw_readl ( adapter_data - > ioaddr + CR_OFFSET ) ;
/*
* Disable the actual HW unit
*/
cr & = ~ ( IOP3XX_ICR_ALD_IE | IOP3XX_ICR_BERR_IE |
IOP3XX_ICR_RXFULL_IE | IOP3XX_ICR_TXEMPTY_IE ) ;
__raw_writel ( cr , adapter_data - > ioaddr + CR_OFFSET ) ;
2010-11-29 13:33:39 +03:00
iounmap ( adapter_data - > ioaddr ) ;
2005-04-17 02:20:36 +04:00
release_mem_region ( res - > start , IOP3XX_I2C_IO_SIZE ) ;
kfree ( adapter_data ) ;
kfree ( padapter ) ;
return 0 ;
}
2012-07-04 23:14:16 +04:00
static int
2005-11-10 01:32:44 +03:00
iop3xx_i2c_probe ( struct platform_device * pdev )
2005-04-17 02:20:36 +04:00
{
struct resource * res ;
2006-01-19 20:56:29 +03:00
int ret , irq ;
2005-04-17 02:20:36 +04:00
struct i2c_adapter * new_adapter ;
struct i2c_algo_iop3xx_data * adapter_data ;
2005-10-18 01:09:43 +04:00
new_adapter = kzalloc ( sizeof ( struct i2c_adapter ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! new_adapter ) {
ret = - ENOMEM ;
goto out ;
}
2005-10-18 01:09:43 +04:00
adapter_data = kzalloc ( sizeof ( struct i2c_algo_iop3xx_data ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! adapter_data ) {
ret = - ENOMEM ;
goto free_adapter ;
}
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! res ) {
ret = - ENODEV ;
goto free_both ;
}
if ( ! request_mem_region ( res - > start , IOP3XX_I2C_IO_SIZE , pdev - > name ) ) {
ret = - EBUSY ;
goto free_both ;
}
/* set the adapter enumeration # */
adapter_data - > id = i2c_id + + ;
2010-11-29 13:33:39 +03:00
adapter_data - > ioaddr = ioremap ( res - > start , IOP3XX_I2C_IO_SIZE ) ;
2005-04-17 02:20:36 +04:00
if ( ! adapter_data - > ioaddr ) {
ret = - ENOMEM ;
goto release_region ;
}
2006-01-19 20:56:29 +03:00
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 ) {
ret = - ENXIO ;
goto unmap ;
}
ret = request_irq ( irq , iop3xx_i2c_irq_handler , 0 ,
2005-04-17 02:20:36 +04:00
pdev - > name , adapter_data ) ;
2005-11-02 01:31:12 +03:00
if ( ret ) {
2005-04-17 02:20:36 +04:00
ret = - EIO ;
goto unmap ;
}
memcpy ( new_adapter - > name , pdev - > name , strlen ( pdev - > name ) ) ;
new_adapter - > owner = THIS_MODULE ;
2008-07-15 00:38:29 +04:00
new_adapter - > class = I2C_CLASS_HWMON | I2C_CLASS_SPD ;
2005-04-17 02:20:36 +04:00
new_adapter - > dev . parent = & pdev - > dev ;
2007-07-12 16:12:30 +04:00
new_adapter - > nr = pdev - > id ;
2005-04-17 02:20:36 +04:00
/*
* Default values . . . should these come in from board code ?
*/
2009-03-28 23:34:43 +03:00
new_adapter - > timeout = HZ ;
2005-04-17 02:20:36 +04:00
new_adapter - > algo = & iop3xx_i2c_algo ;
init_waitqueue_head ( & adapter_data - > waitq ) ;
spin_lock_init ( & adapter_data - > lock ) ;
iop3xx_i2c_reset ( adapter_data ) ;
iop3xx_i2c_enable ( adapter_data ) ;
2005-11-10 01:32:44 +03:00
platform_set_drvdata ( pdev , new_adapter ) ;
2005-04-17 02:20:36 +04:00
new_adapter - > algo_data = adapter_data ;
2007-07-12 16:12:30 +04:00
i2c_add_numbered_adapter ( new_adapter ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
unmap :
2010-11-29 13:33:39 +03:00
iounmap ( adapter_data - > ioaddr ) ;
2005-04-17 02:20:36 +04:00
release_region :
release_mem_region ( res - > start , IOP3XX_I2C_IO_SIZE ) ;
free_both :
kfree ( adapter_data ) ;
free_adapter :
kfree ( new_adapter ) ;
out :
return ret ;
}
2005-11-10 01:32:44 +03:00
static struct platform_driver iop3xx_i2c_driver = {
2005-04-17 02:20:36 +04:00
. probe = iop3xx_i2c_probe ,
2005-11-10 01:32:44 +03:00
. remove = iop3xx_i2c_remove ,
. driver = {
. name = " IOP3xx-I2C " ,
} ,
2005-04-17 02:20:36 +04:00
} ;
2012-01-12 23:32:04 +04:00
module_platform_driver ( iop3xx_i2c_driver ) ;
2005-04-17 02:20:36 +04:00
MODULE_AUTHOR ( " D-TACQ Solutions Ltd <www.d-tacq.com> " ) ;
MODULE_DESCRIPTION ( " IOP3xx iic algorithm and driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
2008-04-23 00:16:49 +04:00
MODULE_ALIAS ( " platform:IOP3xx-I2C " ) ;