On 4 October 2012 13:30, Uwe Kleine-König <u.kleine-koenig@xxxxxxxxxxxxxx> wrote: Hi Uwe, Please see if following fixup looks fine to you: fixup! i2c/adapter: Add bus recovery infrastructure --- drivers/i2c/i2c-core.c | 33 ++++++++++++++------------------- include/linux/i2c.h | 22 ++++++++++++---------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index bdc249a..393d5f7 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -107,24 +107,14 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) #endif /* CONFIG_HOTPLUG */ /* i2c bus recovery routines */ -static inline void set_scl_value(struct i2c_adapter *adap, int val) +static void set_scl_gpio_value(struct i2c_adapter *adap, int val) { - struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; - - if (bri->is_gpio_recovery) - gpio_set_value(bri->scl_gpio, val); - else - bri->set_scl(adap, val); + gpio_set_value(adap->bus_recovery_info->scl_gpio, val); } -static inline int get_sda_value(struct i2c_adapter *adap) +static int get_sda_gpio_value(struct i2c_adapter *adap) { - struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; - - if (bri->is_gpio_recovery) - return gpio_get_value(bri->sda_gpio); - else - return bri->get_sda(adap); + return gpio_get_value(adap->bus_recovery_info->sda_gpio); } static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap) @@ -152,8 +142,7 @@ static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap) ret = bri->get_gpio(bri->sda_gpio); if (unlikely(ret || - gpio_request_one(bri->sda_gpio, bri->sda_gpio_flags, - "i2c-sda"))) { + gpio_request_one(bri->sda_gpio, GPIOF_IN, "i2c-sda"))) { /* work without sda polling */ dev_warn(dev, "can't get sda: %d. Skip sda polling\n", bri->sda_gpio); @@ -190,7 +179,7 @@ static int i2c_recover_bus(struct i2c_adapter *adap) { struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; unsigned long delay = 1000000; - int i, ret, val = 1; + int i, ret, val = 0; if (bri->is_gpio_recovery) { ret = i2c_get_gpios_for_recovery(adap); @@ -201,12 +190,12 @@ static int i2c_recover_bus(struct i2c_adapter *adap) delay = DIV_ROUND_UP(delay, bri->clock_rate_khz * 2); for (i = 0; i < bri->clock_cnt * 2; i++, val = !val) { - set_scl_value(adap, val); + bri->set_scl(adap, val); ndelay(delay); /* break if sda got high, check only when scl line is high */ if (!bri->skip_sda_polling && val) - if (unlikely(get_sda_value(adap))) + if (unlikely(bri->get_sda(adap))) break; } @@ -1030,6 +1019,12 @@ static int i2c_register_adapter(struct i2c_adapter *adap) bri->recover_bus = i2c_recover_bus; if (bri->is_gpio_recovery) { + if (!bri->scl_gpio_flags) + bri->scl_gpio_flags = GPIOF_OPEN_DRAIN | + GPIOF_OUT_INIT_HIGH; + + bri->set_scl = set_scl_gpio_value; + bri->get_sda = get_sda_gpio_value; dev_info(&adap->dev, "registered for gpio bus recovery\n"); } else if (bri->set_scl) { diff --git a/include/linux/i2c.h b/include/linux/i2c.h index c43e5c4..dd470a1 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -382,10 +382,10 @@ struct i2c_algorithm { * scl type recovery. * @clock_cnt: count of max clocks to be generated. Required for both gpio and * scl type recovery. - * @set_scl: controller specific scl configuration routine. Only required if - * is_gpio_recovery == false - * @get_sda: controller specific sda read routine. Only required if - * is_gpio_recovery == false and skip_sda_polling == false. + * @set_scl: controller specific routine, if is_gpio_recovery == false. + * set_scl_gpio_value otherwise + * @get_sda: controller specific routine, if is_gpio_recovery == false. + * get_sda_gpio_value otherwise * @get_gpio: called before recover_bus() to get padmux configured for scl line. * as gpio. Only required if is_gpio_recovery == true. Return 0 on success. * @put_gpio: called after recover_bus() to get padmux configured for scl line @@ -394,10 +394,9 @@ struct i2c_algorithm { * true. * @sda_gpio: gpio number of the sda line. Only required if is_gpio_recovery == * true and skip_sda_polling == false. - * @scl_gpio_flags: flag for gpio_request_one of scl_gpio. 0 implies - * GPIOF_OUT_INIT_LOW. - * @sda_gpio_flags: flag for gpio_request_one of sda_gpio. 0 implies - * GPIOF_OUT_INIT_LOW. + * @scl_gpio_flags: flag for gpio_request_one of scl_gpio. If passed as 0, + * (GPIOF_OPEN_DRAIN | GPIOF_OUT_INIT_HIGH) is used instead. + * These is no need of sda_gpio_flags, as we always read it in input mode. */ struct i2c_bus_recovery_info { int (*recover_bus)(struct i2c_adapter *); @@ -406,7 +405,11 @@ struct i2c_bus_recovery_info { u32 clock_rate_khz; u8 clock_cnt; - /* scl/sda recovery */ + /* + * Fn pointers for recovery, will point either to: + * - set_scl_gpio_value and get_sda_gpio_value for gpio recovery + * - Controller specific routines, otherwise + */ void (*set_scl)(struct i2c_adapter *, int val); int (*get_sda)(struct i2c_adapter *); @@ -416,7 +419,6 @@ struct i2c_bus_recovery_info { unsigned scl_gpio; unsigned sda_gpio; unsigned long scl_gpio_flags; - unsigned long sda_gpio_flags; }; /* -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html