Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Wolfram Sang and committed by
Wolfram Sang
7ca5f6be 0b71026c

+26 -4
+23 -4
drivers/i2c/i2c-core-base.c
··· 158 158 gpiod_set_value_cansleep(adap->bus_recovery_info->sda_gpiod, val); 159 159 } 160 160 161 + static int i2c_generic_bus_free(struct i2c_adapter *adap) 162 + { 163 + struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; 164 + int ret = -EOPNOTSUPP; 165 + 166 + if (bri->get_bus_free) 167 + ret = bri->get_bus_free(adap); 168 + else if (bri->get_sda) 169 + ret = bri->get_sda(adap); 170 + 171 + if (ret < 0) 172 + return ret; 173 + 174 + return ret ? 0 : -EBUSY; 175 + } 176 + 161 177 /* 162 178 * We are generating clock pulses. ndelay() determines durating of clk pulses. 163 179 * We will generate clock with rate 100 KHz and so duration of both clock levels ··· 185 169 int i2c_generic_scl_recovery(struct i2c_adapter *adap) 186 170 { 187 171 struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; 188 - int i = 0, val = 1, ret = 0; 172 + int i = 0, val = 1, ret; 189 173 190 174 if (bri->prepare_recovery) 191 175 bri->prepare_recovery(adap); ··· 223 207 bri->set_sda(adap, val); 224 208 ndelay(RECOVERY_NDELAY / 2); 225 209 226 - /* Break if SDA is high */ 227 - if (val && bri->get_sda) { 228 - ret = bri->get_sda(adap) ? 0 : -EBUSY; 210 + if (val) { 211 + ret = i2c_generic_bus_free(adap); 229 212 if (ret == 0) 230 213 break; 231 214 } 232 215 } 216 + 217 + /* If we can't check bus status, assume recovery worked */ 218 + if (ret == -EOPNOTSUPP) 219 + ret = 0; 233 220 234 221 if (bri->unprepare_recovery) 235 222 bri->unprepare_recovery(adap);
+3
include/linux/i2c.h
··· 587 587 * @set_sda: This sets/clears the SDA line. This or get_sda() is mandatory for 588 588 * generic SCL recovery. Populated internally, if sda_gpio is a valid GPIO, 589 589 * for generic GPIO recovery. 590 + * @get_bus_free: Returns the bus free state as seen from the IP core in case it 591 + * has a more complex internal logic than just reading SDA. Optional. 590 592 * @prepare_recovery: This will be called before starting recovery. Platform may 591 593 * configure padmux here for SDA/SCL line or something else they want. 592 594 * @unprepare_recovery: This will be called after completing recovery. Platform ··· 603 601 void (*set_scl)(struct i2c_adapter *adap, int val); 604 602 int (*get_sda)(struct i2c_adapter *adap); 605 603 void (*set_sda)(struct i2c_adapter *adap, int val); 604 + int (*get_bus_free)(struct i2c_adapter *adap); 606 605 607 606 void (*prepare_recovery)(struct i2c_adapter *adap); 608 607 void (*unprepare_recovery)(struct i2c_adapter *adap);