Skip to content

Commit 7582031

Browse files
codrin989wsakernel
authored andcommitted
i2c: core: add generic I2C GPIO recovery
Multiple I2C bus drivers use similar bindings to obtain information needed for I2C recovery. For example, for platforms using device-tree, the properties look something like this: &i2c { ... pinctrl-names = "default", "gpio"; pinctrl-0 = <&pinctrl_i2c_default>; pinctrl-1 = <&pinctrl_i2c_gpio>; sda-gpios = <&pio 0 GPIO_ACTIVE_HIGH>; scl-gpios = <&pio 1 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ... } For this reason, we can add this common initialization in the core. This way, other I2C bus drivers will be able to support GPIO recovery just by providing a pointer to platform's pinctrl and calling i2c_recover_bus() when SDA is stuck low. Signed-off-by: Codrin Ciubotariu <[email protected]> [wsa: inverted one logic for better readability, minor update to kdoc] Signed-off-by: Wolfram Sang <[email protected]>
1 parent db36e82 commit 7582031

File tree

2 files changed

+137
-0
lines changed

2 files changed

+137
-0
lines changed

drivers/i2c/i2c-core-base.c

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <linux/of_device.h>
3333
#include <linux/of.h>
3434
#include <linux/of_irq.h>
35+
#include <linux/pinctrl/consumer.h>
3536
#include <linux/pm_domain.h>
3637
#include <linux/pm_runtime.h>
3738
#include <linux/pm_wakeirq.h>
@@ -181,6 +182,8 @@ int i2c_generic_scl_recovery(struct i2c_adapter *adap)
181182

182183
if (bri->prepare_recovery)
183184
bri->prepare_recovery(adap);
185+
if (bri->pinctrl)
186+
pinctrl_select_state(bri->pinctrl, bri->pins_gpio);
184187

185188
/*
186189
* If we can set SDA, we will always create a STOP to ensure additional
@@ -236,6 +239,8 @@ int i2c_generic_scl_recovery(struct i2c_adapter *adap)
236239

237240
if (bri->unprepare_recovery)
238241
bri->unprepare_recovery(adap);
242+
if (bri->pinctrl)
243+
pinctrl_select_state(bri->pinctrl, bri->pins_default);
239244

240245
return ret;
241246
}
@@ -251,6 +256,125 @@ int i2c_recover_bus(struct i2c_adapter *adap)
251256
}
252257
EXPORT_SYMBOL_GPL(i2c_recover_bus);
253258

259+
static void i2c_gpio_init_pinctrl_recovery(struct i2c_adapter *adap)
260+
{
261+
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
262+
struct device *dev = &adap->dev;
263+
struct pinctrl *p = bri->pinctrl;
264+
265+
/*
266+
* we can't change states without pinctrl, so remove the states if
267+
* populated
268+
*/
269+
if (!p) {
270+
bri->pins_default = NULL;
271+
bri->pins_gpio = NULL;
272+
return;
273+
}
274+
275+
if (!bri->pins_default) {
276+
bri->pins_default = pinctrl_lookup_state(p,
277+
PINCTRL_STATE_DEFAULT);
278+
if (IS_ERR(bri->pins_default)) {
279+
dev_dbg(dev, PINCTRL_STATE_DEFAULT " state not found for GPIO recovery\n");
280+
bri->pins_default = NULL;
281+
}
282+
}
283+
if (!bri->pins_gpio) {
284+
bri->pins_gpio = pinctrl_lookup_state(p, "gpio");
285+
if (IS_ERR(bri->pins_gpio))
286+
bri->pins_gpio = pinctrl_lookup_state(p, "recovery");
287+
288+
if (IS_ERR(bri->pins_gpio)) {
289+
dev_dbg(dev, "no gpio or recovery state found for GPIO recovery\n");
290+
bri->pins_gpio = NULL;
291+
}
292+
}
293+
294+
/* for pinctrl state changes, we need all the information */
295+
if (bri->pins_default && bri->pins_gpio) {
296+
dev_info(dev, "using pinctrl states for GPIO recovery");
297+
} else {
298+
bri->pinctrl = NULL;
299+
bri->pins_default = NULL;
300+
bri->pins_gpio = NULL;
301+
}
302+
}
303+
304+
static int i2c_gpio_init_generic_recovery(struct i2c_adapter *adap)
305+
{
306+
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
307+
struct device *dev = &adap->dev;
308+
struct gpio_desc *gpiod;
309+
int ret = 0;
310+
311+
/*
312+
* don't touch the recovery information if the driver is not using
313+
* generic SCL recovery
314+
*/
315+
if (bri->recover_bus && bri->recover_bus != i2c_generic_scl_recovery)
316+
return 0;
317+
318+
/*
319+
* pins might be taken as GPIO, so we should inform pinctrl about
320+
* this and move the state to GPIO
321+
*/
322+
if (bri->pinctrl)
323+
pinctrl_select_state(bri->pinctrl, bri->pins_gpio);
324+
325+
/*
326+
* if there is incomplete or no recovery information, see if generic
327+
* GPIO recovery is available
328+
*/
329+
if (!bri->scl_gpiod) {
330+
gpiod = devm_gpiod_get(dev, "scl", GPIOD_OUT_HIGH_OPEN_DRAIN);
331+
if (PTR_ERR(gpiod) == -EPROBE_DEFER) {
332+
ret = -EPROBE_DEFER;
333+
goto cleanup_pinctrl_state;
334+
}
335+
if (!IS_ERR(gpiod)) {
336+
bri->scl_gpiod = gpiod;
337+
bri->recover_bus = i2c_generic_scl_recovery;
338+
dev_info(dev, "using generic GPIOs for recovery\n");
339+
}
340+
}
341+
342+
/* SDA GPIOD line is optional, so we care about DEFER only */
343+
if (!bri->sda_gpiod) {
344+
/*
345+
* We have SCL. Pull SCL low and wait a bit so that SDA glitches
346+
* have no effect.
347+
*/
348+
gpiod_direction_output(bri->scl_gpiod, 0);
349+
udelay(10);
350+
gpiod = devm_gpiod_get(dev, "sda", GPIOD_IN);
351+
352+
/* Wait a bit in case of a SDA glitch, and then release SCL. */
353+
udelay(10);
354+
gpiod_direction_output(bri->scl_gpiod, 1);
355+
356+
if (PTR_ERR(gpiod) == -EPROBE_DEFER) {
357+
ret = -EPROBE_DEFER;
358+
goto cleanup_pinctrl_state;
359+
}
360+
if (!IS_ERR(gpiod))
361+
bri->sda_gpiod = gpiod;
362+
}
363+
364+
cleanup_pinctrl_state:
365+
/* change the state of the pins back to their default state */
366+
if (bri->pinctrl)
367+
pinctrl_select_state(bri->pinctrl, bri->pins_default);
368+
369+
return ret;
370+
}
371+
372+
static int i2c_gpio_init_recovery(struct i2c_adapter *adap)
373+
{
374+
i2c_gpio_init_pinctrl_recovery(adap);
375+
return i2c_gpio_init_generic_recovery(adap);
376+
}
377+
254378
static void i2c_init_recovery(struct i2c_adapter *adap)
255379
{
256380
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
@@ -259,6 +383,8 @@ static void i2c_init_recovery(struct i2c_adapter *adap)
259383
if (!bri)
260384
return;
261385

386+
i2c_gpio_init_recovery(adap);
387+
262388
if (!bri->recover_bus) {
263389
err_str = "no recover_bus() found";
264390
goto err;

include/linux/i2c.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,14 @@ struct i2c_timings {
606606
* may configure padmux here for SDA/SCL line or something else they want.
607607
* @scl_gpiod: gpiod of the SCL line. Only required for GPIO recovery.
608608
* @sda_gpiod: gpiod of the SDA line. Only required for GPIO recovery.
609+
* @pinctrl: pinctrl used by GPIO recovery to change the state of the I2C pins.
610+
* Optional.
611+
* @pins_default: default pinctrl state of SCL/SDA lines, when they are assigned
612+
* to the I2C bus. Optional. Populated internally for GPIO recovery, if
613+
* state with the name PINCTRL_STATE_DEFAULT is found and pinctrl is valid.
614+
* @pins_gpio: recovery pinctrl state of SCL/SDA lines, when they are used as
615+
* GPIOs. Optional. Populated internally for GPIO recovery, if this state
616+
* is called "gpio" or "recovery" and pinctrl is valid.
609617
*/
610618
struct i2c_bus_recovery_info {
611619
int (*recover_bus)(struct i2c_adapter *adap);
@@ -622,6 +630,9 @@ struct i2c_bus_recovery_info {
622630
/* gpio recovery */
623631
struct gpio_desc *scl_gpiod;
624632
struct gpio_desc *sda_gpiod;
633+
struct pinctrl *pinctrl;
634+
struct pinctrl_state *pins_default;
635+
struct pinctrl_state *pins_gpio;
625636
};
626637

627638
int i2c_recover_bus(struct i2c_adapter *adap);

0 commit comments

Comments
 (0)