2009-12-12 03:16:32 +03:00
/*
* Helper module for board specific I2C bus registration
*
* Copyright ( C ) 2009 Nokia Corporation .
*
* 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
*
*/
2012-10-06 00:25:59 +04:00
# include "soc.h"
2012-10-03 04:41:35 +04:00
# include "omap_hwmod.h"
2012-10-03 04:25:48 +04:00
# include "omap_device.h"
2012-12-19 10:53:10 +04:00
# include "omap-pm.h"
2009-12-12 03:16:32 +03:00
2012-10-30 06:57:44 +04:00
# include "prm.h"
# include "common.h"
2009-12-12 03:16:32 +03:00
# include "mux.h"
2012-10-08 20:11:22 +04:00
# include "i2c.h"
2009-12-12 03:16:32 +03:00
2011-07-10 15:27:16 +04:00
/* In register I2C_CON, Bit 15 is the I2C enable bit */
# define I2C_EN BIT(15)
# define OMAP2_I2C_CON_OFFSET 0x24
# define OMAP4_I2C_CON_OFFSET 0xA4
2012-10-08 20:11:22 +04:00
# define MAX_OMAP_I2C_HWMOD_NAME_LEN 16
static void __init omap2_i2c_mux_pins ( int bus_id )
2009-12-12 03:16:32 +03:00
{
2010-07-05 17:31:40 +04:00
char mux_name [ sizeof ( " i2c2_scl.i2c2_scl " ) ] ;
2009-12-12 03:16:32 +03:00
/* First I2C bus is not muxable */
2010-07-05 17:31:40 +04:00
if ( bus_id = = 1 )
return ;
2009-12-12 03:16:32 +03:00
2010-07-05 17:31:40 +04:00
sprintf ( mux_name , " i2c%i_scl.i2c%i_scl " , bus_id , bus_id ) ;
omap_mux_init_signal ( mux_name , OMAP_PIN_INPUT ) ;
sprintf ( mux_name , " i2c%i_sda.i2c%i_sda " , bus_id , bus_id ) ;
omap_mux_init_signal ( mux_name , OMAP_PIN_INPUT ) ;
2009-12-12 03:16:32 +03:00
}
2011-07-10 15:27:16 +04:00
/**
* omap_i2c_reset - reset the omap i2c module .
* @ oh : struct omap_hwmod *
*
* The i2c moudle in omap2 , omap3 had a special sequence to reset . The
* sequence is :
* - Disable the I2C .
* - Write to SOFTRESET bit .
* - Enable the I2C .
* - Poll on the RESETDONE bit .
* The sequence is implemented in below function . This is called for 2420 ,
* 2430 and omap3 .
*/
int omap_i2c_reset ( struct omap_hwmod * oh )
{
u32 v ;
u16 i2c_con ;
int c = 0 ;
if ( oh - > class - > rev = = OMAP_I2C_IP_VERSION_2 ) {
i2c_con = OMAP4_I2C_CON_OFFSET ;
} else if ( oh - > class - > rev = = OMAP_I2C_IP_VERSION_1 ) {
i2c_con = OMAP2_I2C_CON_OFFSET ;
} else {
WARN ( 1 , " Cannot reset I2C block %s: unsupported revision \n " ,
oh - > name ) ;
return - EINVAL ;
}
/* Disable I2C */
v = omap_hwmod_read ( oh , i2c_con ) ;
v & = ~ I2C_EN ;
omap_hwmod_write ( v , oh , i2c_con ) ;
/* Write to the SOFTRESET bit */
omap_hwmod_softreset ( oh ) ;
/* Enable I2C */
v = omap_hwmod_read ( oh , i2c_con ) ;
v | = I2C_EN ;
omap_hwmod_write ( v , oh , i2c_con ) ;
/* Poll on RESETDONE bit */
omap_test_timeout ( ( omap_hwmod_read ( oh ,
oh - > class - > sysc - > syss_offs )
& SYSS_RESETDONE_MASK ) ,
MAX_MODULE_SOFTRESET_WAIT , c ) ;
if ( c = = MAX_MODULE_SOFTRESET_WAIT )
pr_warning ( " %s: %s: softreset failed (waited %d usec) \n " ,
__func__ , oh - > name , MAX_MODULE_SOFTRESET_WAIT ) ;
else
pr_debug ( " %s: %s: softreset in %d usec \n " , __func__ ,
oh - > name , c ) ;
return 0 ;
}
2012-10-08 20:11:22 +04:00
2012-10-30 03:17:59 +04:00
static int __init omap_i2c_nr_ports ( void )
{
int ports = 0 ;
if ( cpu_is_omap24xx ( ) )
ports = 2 ;
else if ( cpu_is_omap34xx ( ) )
ports = 3 ;
else if ( cpu_is_omap44xx ( ) )
ports = 4 ;
return ports ;
}
2012-12-19 04:51:10 +04:00
/*
* XXX This function is a temporary compatibility wrapper - only
* needed until the I2C driver can be converted to call
* omap_pm_set_max_dev_wakeup_lat ( ) and handle a return code .
*/
static void omap_pm_set_max_mpu_wakeup_lat_compat ( struct device * dev , long t )
{
omap_pm_set_max_mpu_wakeup_lat ( dev , t ) ;
}
2012-10-08 20:11:22 +04:00
static const char name [ ] = " omap_i2c " ;
int __init omap_i2c_add_bus ( struct omap_i2c_bus_platform_data * i2c_pdata ,
int bus_id )
{
int l ;
struct omap_hwmod * oh ;
struct platform_device * pdev ;
char oh_name [ MAX_OMAP_I2C_HWMOD_NAME_LEN ] ;
struct omap_i2c_bus_platform_data * pdata ;
struct omap_i2c_dev_attr * dev_attr ;
2012-10-30 03:17:59 +04:00
if ( bus_id > omap_i2c_nr_ports ( ) )
return - EINVAL ;
2012-10-08 20:11:22 +04:00
omap2_i2c_mux_pins ( bus_id ) ;
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 ;
}
pdata = i2c_pdata ;
/*
* pass the hwmod class ' s CPU - specific knowledge of I2C IP revision in
* use , and functionality implementation flags , up to the OMAP I2C
* driver via platform data
*/
pdata - > rev = oh - > class - > rev ;
dev_attr = ( struct omap_i2c_dev_attr * ) oh - > dev_attr ;
pdata - > flags = dev_attr - > flags ;
2012-12-19 04:51:10 +04:00
/*
* When waiting for completion of a i2c transfer , we need to
* set a wake up latency constraint for the MPU . This is to
* ensure quick enough wakeup from idle , when transfer
* completes .
* Only omap3 has support for constraints
*/
if ( cpu_is_omap34xx ( ) )
pdata - > set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat ;
2012-10-08 20:11:22 +04:00
pdev = omap_device_build ( name , bus_id , oh , pdata ,
2013-01-26 11:48:53 +04:00
sizeof ( struct omap_i2c_bus_platform_data ) ) ;
2012-10-08 20:11:22 +04:00
WARN ( IS_ERR ( pdev ) , " Could not build omap_device for %s \n " , name ) ;
return PTR_RET ( pdev ) ;
}
2013-01-11 23:24:19 +04:00
static int __init omap_i2c_cmdline ( void )
{
return omap_register_i2c_bus_cmdline ( ) ;
}
omap_subsys_initcall ( omap_i2c_cmdline ) ;