2007-11-07 07:54:31 +03:00
/*
* linux / arch / arm / plat - omap / i2c . c
*
* Helper module for board specific I2C bus registration
*
* Copyright ( C ) 2007 Nokia Corporation .
*
2009-05-25 22:08:43 +04:00
* Contact : Jarkko Nikula < jhnikula @ gmail . com >
2007-11-07 07:54:31 +03:00
*
* 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 .
*
* 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 . , 51 Franklin St , Fifth Floor , Boston , MA
* 02110 - 1301 USA
*
*/
# include <linux/kernel.h>
# include <linux/platform_device.h>
# include <linux/i2c.h>
2010-09-21 18:07:15 +04:00
# include <linux/slab.h>
# include <linux/err.h>
# include <linux/clk.h>
2010-05-11 22:35:08 +04:00
[ARM] fix AT91, davinci, h720x, ks8695, msm, mx2, mx3, netx, omap1, omap2, pxa, s3c
arch/arm/mach-at91/at91cap9.c:337: error: 'NR_AIC_IRQS' undeclared here (not in a function)
arch/arm/mach-at91/at91rm9200.c:301: error: 'NR_AIC_IRQS' undeclared here (not in a function)
arch/arm/mach-at91/at91sam9260.c:351: error: 'NR_AIC_IRQS' undeclared here (not in a function)
arch/arm/mach-at91/at91sam9261.c:287: error: 'NR_AIC_IRQS' undeclared here (not in a function)
arch/arm/mach-at91/at91sam9263.c:312: error: 'NR_AIC_IRQS' undeclared here (not in a function)
arch/arm/mach-at91/at91sam9rl.c:304: error: 'NR_AIC_IRQS' undeclared here (not in a function)
arch/arm/mach-h720x/h7202-eval.c:38: error: implicit declaration of function 'IRQ_CHAINED_GPIOB'
arch/arm/mach-ks8695/devices.c:46: error: 'KS8695_IRQ_WAN_RX_STATUS' undeclared here (not in a function)
arch/arm/mach-msm/devices.c:28: error: 'INT_UART1' undeclared here (not in a function)
arch/arm/mach-mx2/devices.c:233: error: 'MXC_GPIO_IRQ_START' undeclared here (not in a function)
arch/arm/mach-mx3/devices.c:128: error: 'MXC_GPIO_IRQ_START' undeclared here (not in a function)
arch/arm/mach-omap1/mcbsp.c:140: error: 'INT_730_McBSP1RX' undeclared here (not in a function)
arch/arm/mach-omap1/mcbsp.c:165: error: 'INT_McBSP1RX' undeclared here (not in a function)
arch/arm/mach-omap1/mcbsp.c:200: error: 'INT_McBSP1RX' undeclared here (not in a function)
arch/arm/mach-omap2/board-apollon.c:286: error: implicit declaration of function 'omap_set_gpio_direction'
arch/arm/mach-omap2/mcbsp.c:154: error: 'INT_24XX_MCBSP1_IRQ_RX' undeclared here (not in a function)
arch/arm/mach-omap2/mcbsp.c:181: error: 'INT_24XX_MCBSP1_IRQ_RX' undeclared here (not in a function)
arch/arm/mach-pxa/e350.c:36: error: 'IRQ_BOARD_START' undeclared here (not in a function)
arch/arm/plat-s3c/dev-i2c0.c:32: error: 'IRQ_IIC' undeclared here (not in a function)
...
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2009-01-08 13:01:47 +03:00
# include <mach/irqs.h>
2010-02-22 23:29:36 +03:00
# include <plat/i2c.h>
2010-09-21 18:07:15 +04:00
# include <plat/omap_device.h>
2007-11-07 07:54:31 +03:00
# define OMAP_I2C_SIZE 0x3f
# define OMAP1_I2C_BASE 0xfffb3800
2012-09-05 04:43:29 +04:00
# define OMAP1_INT_I2C (32 + 4)
2007-11-07 07:54:31 +03:00
2010-12-09 17:24:16 +03:00
static const char name [ ] = " omap_i2c " ;
2007-11-07 07:54:31 +03:00
# define I2C_RESOURCE_BUILDER(base, irq) \
{ \
. start = ( base ) , \
. end = ( base ) + OMAP_I2C_SIZE , \
. flags = IORESOURCE_MEM , \
} , \
{ \
. start = ( irq ) , \
. flags = IORESOURCE_IRQ , \
} ,
static struct resource i2c_resources [ ] [ 2 ] = {
{ I2C_RESOURCE_BUILDER ( 0 , 0 ) } ,
} ;
# define I2C_DEV_BUILDER(bus_id, res, data) \
{ \
. id = ( bus_id ) , \
. name = name , \
. num_resources = ARRAY_SIZE ( res ) , \
. resource = ( res ) , \
. dev = { \
. platform_data = ( data ) , \
} , \
}
2010-09-21 18:07:15 +04:00
# define MAX_OMAP_I2C_HWMOD_NAME_LEN 16
# define OMAP_I2C_MAX_CONTROLLERS 4
static struct omap_i2c_bus_platform_data i2c_pdata [ OMAP_I2C_MAX_CONTROLLERS ] ;
2007-11-07 07:54:31 +03:00
static struct platform_device omap_i2c_devices [ ] = {
2010-05-11 22:35:08 +04:00
I2C_DEV_BUILDER ( 1 , i2c_resources [ 0 ] , & i2c_pdata [ 0 ] ) ,
2007-11-07 07:54:31 +03:00
} ;
2009-03-24 04:07:48 +03:00
# define OMAP_I2C_CMDLINE_SETUP (BIT(31))
2009-03-24 04:07:47 +03:00
static int __init omap_i2c_nr_ports ( void )
{
int ports = 0 ;
if ( cpu_class_is_omap1 ( ) )
ports = 1 ;
else if ( cpu_is_omap24xx ( ) )
ports = 2 ;
else if ( cpu_is_omap34xx ( ) )
ports = 3 ;
2010-05-20 22:36:43 +04:00
else if ( cpu_is_omap44xx ( ) )
ports = 4 ;
2009-03-24 04:07:47 +03:00
return ports ;
}
2010-09-21 18:07:15 +04:00
static inline int omap1_i2c_add_bus ( int bus_id )
2009-03-24 04:07:48 +03:00
{
2010-09-21 18:07:15 +04:00
struct platform_device * pdev ;
struct omap_i2c_bus_platform_data * pdata ;
2010-12-07 07:30:57 +03:00
struct resource * res ;
2010-09-21 18:07:15 +04:00
2010-05-20 22:36:43 +04:00
omap1_i2c_mux_pins ( bus_id ) ;
2010-09-21 18:07:15 +04:00
pdev = & omap_i2c_devices [ bus_id - 1 ] ;
2010-12-07 07:30:57 +03:00
res = pdev - > resource ;
res [ 0 ] . start = OMAP1_I2C_BASE ;
res [ 0 ] . end = res [ 0 ] . start + OMAP_I2C_SIZE ;
2012-09-05 04:43:29 +04:00
res [ 1 ] . start = OMAP1_INT_I2C ;
2010-09-21 18:07:15 +04:00
pdata = & i2c_pdata [ bus_id - 1 ] ;
2011-05-30 18:43:06 +04:00
/* all OMAP1 have IP version 1 register set */
pdata - > rev = OMAP_I2C_IP_VERSION_1 ;
2011-05-30 18:43:09 +04:00
/* all OMAP1 I2C are implemented like this */
pdata - > flags = OMAP_I2C_FLAG_NO_FIFO |
OMAP_I2C_FLAG_SIMPLE_CLOCK |
OMAP_I2C_FLAG_16BIT_DATA_REG |
OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK ;
/* how the cpu bus is wired up differs for 7xx only */
if ( cpu_is_omap7xx ( ) )
pdata - > flags | = OMAP_I2C_FLAG_BUS_SHIFT_1 ;
else
pdata - > flags | = OMAP_I2C_FLAG_BUS_SHIFT_2 ;
2010-05-20 22:36:43 +04:00
return platform_device_register ( pdev ) ;
}
2010-09-21 18:07:15 +04:00
2011-01-28 03:39:41 +03:00
# ifdef CONFIG_ARCH_OMAP2PLUS
2010-09-21 18:07:15 +04:00
static inline int omap2_i2c_add_bus ( int bus_id )
{
int l ;
struct omap_hwmod * oh ;
2011-07-22 00:48:45 +04:00
struct platform_device * pdev ;
2010-09-21 18:07:15 +04:00
char oh_name [ MAX_OMAP_I2C_HWMOD_NAME_LEN ] ;
struct omap_i2c_bus_platform_data * pdata ;
2011-05-30 18:43:08 +04:00
struct omap_i2c_dev_attr * dev_attr ;
2010-05-20 22:36:43 +04:00
2010-09-21 18:07:15 +04:00
omap2_i2c_mux_pins ( bus_id ) ;
2010-05-20 22:36:43 +04:00
2010-09-21 18:07:15 +04:00
l = snprintf ( oh_name , MAX_OMAP_I2C_HWMOD_NAME_LEN , " i2c%d " , bus_id ) ;
WARN ( l > = MAX_OMAP_I2C_HWMOD_NAME_LEN ,
" String buffer overflow in I2C%d device setup \n " , bus_id ) ;
oh = omap_hwmod_lookup ( oh_name ) ;
if ( ! oh ) {
pr_err ( " Could not look up %s \n " , oh_name ) ;
return - EEXIST ;
2009-03-24 04:07:48 +03:00
}
2010-09-21 18:07:15 +04:00
pdata = & i2c_pdata [ bus_id - 1 ] ;
2011-05-30 18:43:06 +04:00
/*
* pass the hwmod class ' s CPU - specific knowledge of I2C IP revision in
2011-05-30 18:43:08 +04:00
* use , and functionality implementation flags , up to the OMAP I2C
* driver via platform data
2011-05-30 18:43:06 +04:00
*/
pdata - > rev = oh - > class - > rev ;
2011-05-30 18:43:08 +04:00
dev_attr = ( struct omap_i2c_dev_attr * ) oh - > dev_attr ;
pdata - > flags = dev_attr - > flags ;
2011-07-22 00:48:45 +04:00
pdev = omap_device_build ( name , bus_id , oh , pdata ,
2010-09-21 18:07:15 +04:00
sizeof ( struct omap_i2c_bus_platform_data ) ,
2011-08-10 17:30:09 +04:00
NULL , 0 , 0 ) ;
2011-07-22 00:48:45 +04:00
WARN ( IS_ERR ( pdev ) , " Could not build omap_device for %s \n " , name ) ;
2010-09-21 18:07:15 +04:00
2011-11-02 15:54:03 +04:00
return PTR_RET ( pdev ) ;
2009-03-24 04:07:48 +03:00
}
2010-12-08 03:25:40 +03:00
# else
static inline int omap2_i2c_add_bus ( int bus_id )
{
return 0 ;
}
# endif
2009-03-24 04:07:48 +03:00
2010-05-20 22:36:43 +04:00
static int __init omap_i2c_add_bus ( int bus_id )
{
if ( cpu_class_is_omap1 ( ) )
2010-09-21 18:07:15 +04:00
return omap1_i2c_add_bus ( bus_id ) ;
2010-05-20 22:36:43 +04:00
else
2010-09-21 18:07:15 +04:00
return omap2_i2c_add_bus ( bus_id ) ;
2010-05-20 22:36:43 +04:00
}
2009-03-24 04:07:47 +03:00
/**
* omap_i2c_bus_setup - Process command line options for the I2C bus speed
* @ str : String of options
*
* This function allow to override the default I2C bus speed for given I2C
* bus with a command line option .
*
* Format : i2c_bus = bus_id , clkrate ( in kHz )
*
* Returns 1 on success , 0 otherwise .
*/
static int __init omap_i2c_bus_setup ( char * str )
{
int ports ;
int ints [ 3 ] ;
ports = omap_i2c_nr_ports ( ) ;
get_options ( str , 3 , ints ) ;
if ( ints [ 0 ] < 2 | | ints [ 1 ] < 1 | | ints [ 1 ] > ports )
return 0 ;
2010-05-11 22:35:08 +04:00
i2c_pdata [ ints [ 1 ] - 1 ] . clkrate = ints [ 2 ] ;
i2c_pdata [ ints [ 1 ] - 1 ] . clkrate | = OMAP_I2C_CMDLINE_SETUP ;
2009-03-24 04:07:47 +03:00
return 1 ;
}
__setup ( " i2c_bus= " , omap_i2c_bus_setup ) ;
2009-03-24 04:07:48 +03:00
/*
* Register busses defined in command line but that are not registered with
* omap_register_i2c_bus from board initialization code .
*/
static int __init omap_register_i2c_bus_cmdline ( void )
{
int i , err = 0 ;
2010-05-11 22:35:08 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( i2c_pdata ) ; i + + )
if ( i2c_pdata [ i ] . clkrate & OMAP_I2C_CMDLINE_SETUP ) {
i2c_pdata [ i ] . clkrate & = ~ OMAP_I2C_CMDLINE_SETUP ;
2009-03-24 04:07:48 +03:00
err = omap_i2c_add_bus ( i + 1 ) ;
if ( err )
goto out ;
}
out :
return err ;
}
subsys_initcall ( omap_register_i2c_bus_cmdline ) ;
2009-03-24 04:07:46 +03:00
/**
2010-02-22 23:29:36 +03:00
* omap_register_i2c_bus - register I2C bus with device descriptors
2009-03-24 04:07:46 +03:00
* @ bus_id : bus id counting from number 1
* @ clkrate : clock rate of the bus in kHz
* @ info : pointer into I2C device descriptor table or NULL
* @ len : number of descriptors in the table
*
* Returns 0 on success or an error code .
*/
2010-02-22 23:29:36 +03:00
int __init omap_register_i2c_bus ( int bus_id , u32 clkrate ,
2007-11-07 07:54:31 +03:00
struct i2c_board_info const * info ,
unsigned len )
{
2009-03-24 04:07:47 +03:00
int err ;
2007-11-07 07:54:31 +03:00
2009-03-24 04:07:47 +03:00
BUG_ON ( bus_id < 1 | | bus_id > omap_i2c_nr_ports ( ) ) ;
2007-11-07 07:54:31 +03:00
if ( info ) {
err = i2c_register_board_info ( bus_id , info , len ) ;
if ( err )
return err ;
}
2010-05-11 22:35:08 +04:00
if ( ! i2c_pdata [ bus_id - 1 ] . clkrate )
i2c_pdata [ bus_id - 1 ] . clkrate = clkrate ;
i2c_pdata [ bus_id - 1 ] . clkrate & = ~ OMAP_I2C_CMDLINE_SETUP ;
2007-11-07 07:54:31 +03:00
2009-03-24 04:07:48 +03:00
return omap_i2c_add_bus ( bus_id ) ;
2007-11-07 07:54:31 +03:00
}