i2c: recovery: add get_bus_free callback
Some IP cores have an internal 'bus free' logic which may be more advanced than just checking if SDA is high. Add a separate callback to get this status. Filling it is optional. Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
This commit is contained in:
parent
0b71026c69
commit
7ca5f6be79
|
@ -158,6 +158,22 @@ static void set_sda_gpio_value(struct i2c_adapter *adap, int val)
|
||||||
gpiod_set_value_cansleep(adap->bus_recovery_info->sda_gpiod, val);
|
gpiod_set_value_cansleep(adap->bus_recovery_info->sda_gpiod, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int i2c_generic_bus_free(struct i2c_adapter *adap)
|
||||||
|
{
|
||||||
|
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
|
||||||
|
int ret = -EOPNOTSUPP;
|
||||||
|
|
||||||
|
if (bri->get_bus_free)
|
||||||
|
ret = bri->get_bus_free(adap);
|
||||||
|
else if (bri->get_sda)
|
||||||
|
ret = bri->get_sda(adap);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return ret ? 0 : -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We are generating clock pulses. ndelay() determines durating of clk pulses.
|
* We are generating clock pulses. ndelay() determines durating of clk pulses.
|
||||||
* We will generate clock with rate 100 KHz and so duration of both clock levels
|
* We will generate clock with rate 100 KHz and so duration of both clock levels
|
||||||
|
@ -169,7 +185,7 @@ static void set_sda_gpio_value(struct i2c_adapter *adap, int val)
|
||||||
int i2c_generic_scl_recovery(struct i2c_adapter *adap)
|
int i2c_generic_scl_recovery(struct i2c_adapter *adap)
|
||||||
{
|
{
|
||||||
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
|
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
|
||||||
int i = 0, val = 1, ret = 0;
|
int i = 0, val = 1, ret;
|
||||||
|
|
||||||
if (bri->prepare_recovery)
|
if (bri->prepare_recovery)
|
||||||
bri->prepare_recovery(adap);
|
bri->prepare_recovery(adap);
|
||||||
|
@ -207,14 +223,17 @@ int i2c_generic_scl_recovery(struct i2c_adapter *adap)
|
||||||
bri->set_sda(adap, val);
|
bri->set_sda(adap, val);
|
||||||
ndelay(RECOVERY_NDELAY / 2);
|
ndelay(RECOVERY_NDELAY / 2);
|
||||||
|
|
||||||
/* Break if SDA is high */
|
if (val) {
|
||||||
if (val && bri->get_sda) {
|
ret = i2c_generic_bus_free(adap);
|
||||||
ret = bri->get_sda(adap) ? 0 : -EBUSY;
|
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we can't check bus status, assume recovery worked */
|
||||||
|
if (ret == -EOPNOTSUPP)
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
if (bri->unprepare_recovery)
|
if (bri->unprepare_recovery)
|
||||||
bri->unprepare_recovery(adap);
|
bri->unprepare_recovery(adap);
|
||||||
|
|
||||||
|
|
|
@ -587,6 +587,8 @@ struct i2c_timings {
|
||||||
* @set_sda: This sets/clears the SDA line. This or get_sda() is mandatory for
|
* @set_sda: This sets/clears the SDA line. This or get_sda() is mandatory for
|
||||||
* generic SCL recovery. Populated internally, if sda_gpio is a valid GPIO,
|
* generic SCL recovery. Populated internally, if sda_gpio is a valid GPIO,
|
||||||
* for generic GPIO recovery.
|
* for generic GPIO recovery.
|
||||||
|
* @get_bus_free: Returns the bus free state as seen from the IP core in case it
|
||||||
|
* has a more complex internal logic than just reading SDA. Optional.
|
||||||
* @prepare_recovery: This will be called before starting recovery. Platform may
|
* @prepare_recovery: This will be called before starting recovery. Platform may
|
||||||
* configure padmux here for SDA/SCL line or something else they want.
|
* configure padmux here for SDA/SCL line or something else they want.
|
||||||
* @unprepare_recovery: This will be called after completing recovery. Platform
|
* @unprepare_recovery: This will be called after completing recovery. Platform
|
||||||
|
@ -601,6 +603,7 @@ struct i2c_bus_recovery_info {
|
||||||
void (*set_scl)(struct i2c_adapter *adap, int val);
|
void (*set_scl)(struct i2c_adapter *adap, int val);
|
||||||
int (*get_sda)(struct i2c_adapter *adap);
|
int (*get_sda)(struct i2c_adapter *adap);
|
||||||
void (*set_sda)(struct i2c_adapter *adap, int val);
|
void (*set_sda)(struct i2c_adapter *adap, int val);
|
||||||
|
int (*get_bus_free)(struct i2c_adapter *adap);
|
||||||
|
|
||||||
void (*prepare_recovery)(struct i2c_adapter *adap);
|
void (*prepare_recovery)(struct i2c_adapter *adap);
|
||||||
void (*unprepare_recovery)(struct i2c_adapter *adap);
|
void (*unprepare_recovery)(struct i2c_adapter *adap);
|
||||||
|
|
Loading…
Reference in New Issue