@ -11,9 +11,19 @@
# include <malloc.h>
# include <dm/device-internal.h>
# include <dm/lists.h>
# include <dm/pinctrl.h>
# ifdef CONFIG_DM_GPIO
# include <asm/gpio.h>
# endif
# define I2C_MAX_OFFSET_LEN 4
enum {
PIN_SDA = 0 ,
PIN_SCL ,
PIN_COUNT ,
} ;
/* Useful debugging function */
void i2c_dump_msgs ( struct i2c_msg * msg , int nmsgs )
{
@ -445,20 +455,110 @@ int i2c_get_chip_offset_len(struct udevice *dev)
return chip - > offset_len ;
}
# ifdef CONFIG_DM_GPIO
static void i2c_gpio_set_pin ( struct gpio_desc * pin , int bit )
{
if ( bit )
dm_gpio_set_dir_flags ( pin , GPIOD_IS_IN ) ;
else
dm_gpio_set_dir_flags ( pin , GPIOD_IS_OUT |
GPIOD_ACTIVE_LOW |
GPIOD_IS_OUT_ACTIVE ) ;
}
static int i2c_gpio_get_pin ( struct gpio_desc * pin )
{
return dm_gpio_get_value ( pin ) ;
}
static int i2c_deblock_gpio_loop ( struct gpio_desc * sda_pin ,
struct gpio_desc * scl_pin )
{
int counter = 9 ;
int ret = 0 ;
i2c_gpio_set_pin ( sda_pin , 1 ) ;
i2c_gpio_set_pin ( scl_pin , 1 ) ;
udelay ( 5 ) ;
/* Toggle SCL until slave release SDA */
while ( counter - - > = 0 ) {
i2c_gpio_set_pin ( scl_pin , 1 ) ;
udelay ( 5 ) ;
i2c_gpio_set_pin ( scl_pin , 0 ) ;
udelay ( 5 ) ;
if ( i2c_gpio_get_pin ( sda_pin ) )
break ;
}
/* Then, send I2C stop */
i2c_gpio_set_pin ( sda_pin , 0 ) ;
udelay ( 5 ) ;
i2c_gpio_set_pin ( scl_pin , 1 ) ;
udelay ( 5 ) ;
i2c_gpio_set_pin ( sda_pin , 1 ) ;
udelay ( 5 ) ;
if ( ! i2c_gpio_get_pin ( sda_pin ) | | ! i2c_gpio_get_pin ( scl_pin ) )
ret = - EREMOTEIO ;
return ret ;
}
static int i2c_deblock_gpio ( struct udevice * bus )
{
struct gpio_desc gpios [ PIN_COUNT ] ;
int ret , ret0 ;
ret = gpio_request_list_by_name ( bus , " gpios " , gpios ,
ARRAY_SIZE ( gpios ) , GPIOD_IS_IN ) ;
if ( ret ! = ARRAY_SIZE ( gpios ) ) {
debug ( " %s: I2C Node '%s' has no 'gpios' property %s \n " ,
__func__ , dev_read_name ( bus ) , bus - > name ) ;
if ( ret > = 0 ) {
gpio_free_list ( bus , gpios , ret ) ;
ret = - ENOENT ;
}
goto out ;
}
ret = pinctrl_select_state ( bus , " gpio " ) ;
if ( ret ) {
debug ( " %s: I2C Node '%s' has no 'gpio' pinctrl state. %s \n " ,
__func__ , dev_read_name ( bus ) , bus - > name ) ;
goto out_no_pinctrl ;
}
ret0 = i2c_deblock_gpio_loop ( & gpios [ PIN_SDA ] , & gpios [ PIN_SCL ] ) ;
ret = pinctrl_select_state ( bus , " default " ) ;
if ( ret ) {
debug ( " %s: I2C Node '%s' has no 'default' pinctrl state. %s \n " ,
__func__ , dev_read_name ( bus ) , bus - > name ) ;
}
ret = ! ret ? ret0 : ret ;
out_no_pinctrl :
gpio_free_list ( bus , gpios , ARRAY_SIZE ( gpios ) ) ;
out :
return ret ;
}
# else
static int i2c_deblock_gpio ( struct udevice * bus )
{
return - ENOSYS ;
}
# endif // CONFIG_DM_GPIO
int i2c_deblock ( struct udevice * bus )
{
struct dm_i2c_ops * ops = i2c_get_ops ( bus ) ;
/*
* We could implement a software deblocking here if we could get
* access to the GPIOs used by I2C , and switch them to GPIO mode
* and then back to I2C . This is somewhat beyond our powers in
* driver model at present , so for now just fail .
*
* See https : //patchwork.ozlabs.org/patch/399040/
*/
if ( ! ops - > deblock )
return - ENOSYS ;
return i2c_deblock_gpio ( bus ) ;
return ops - > deblock ( bus ) ;
}