diff --git a/target/linux/generic/backport-4.14/085-v4.16-0001-i2c-gpio-Enable-working-over-slow-can_sleep-GPIOs.patch b/target/linux/generic/backport-4.14/085-v4.16-0001-i2c-gpio-Enable-working-over-slow-can_sleep-GPIOs.patch new file mode 100644 index 0000000000..ead6675e0b --- /dev/null +++ b/target/linux/generic/backport-4.14/085-v4.16-0001-i2c-gpio-Enable-working-over-slow-can_sleep-GPIOs.patch @@ -0,0 +1,84 @@ +From f11a04464ae57e8db1bb7634547842b43e36a898 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= +Date: Fri, 22 Dec 2017 22:47:16 +0100 +Subject: i2c: gpio: Enable working over slow can_sleep GPIOs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +"Slow" GPIOs (usually those connected over an SPI or an I2C bus) are, +well, slow in their operation. It is generally a good idea to avoid +using them for time-critical operation, but sometimes the hardware just +sucks, and the software has to cope. In addition to that, the I2C bus +itself does not actually define any strict timing limits; the bus is +free to go all the way down to DC. The timeouts (and therefore the +slowest acceptable frequency) are present only in SMBus. + +The `can_sleep` is IMHO a wrong concept to use here. My SPI-to-quad-UART +chip (MAX14830) is connected via a 26MHz SPI bus, and it happily drives +SCL at 200kHz (5µs pulses) during my benchmarks. That's faster than the +maximal allowed speed of the traditional I2C. + +The previous version of this code did not really block operation over +slow GPIO pins, anyway. Instead, it just resorted to printing a warning +with a backtrace each time a GPIO pin was accessed, thereby slowing +things down even more. + +Finally, it's not just me. A similar patch was originally submitted in +2015 [1]. + +[1] https://patchwork.ozlabs.org/patch/450956/ + +Signed-off-by: Jan Kundrát +Acked-by: Uwe Kleine-König +Signed-off-by: Wolfram Sang +--- + drivers/i2c/busses/i2c-gpio.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +--- a/drivers/i2c/busses/i2c-gpio.c ++++ b/drivers/i2c/busses/i2c-gpio.c +@@ -44,7 +44,7 @@ static void i2c_gpio_setsda_val(void *da + { + struct i2c_gpio_platform_data *pdata = data; + +- gpio_set_value(pdata->sda_pin, state); ++ gpio_set_value_cansleep(pdata->sda_pin, state); + } + + /* Toggle SCL by changing the direction of the pin. */ +@@ -68,21 +68,21 @@ static void i2c_gpio_setscl_val(void *da + { + struct i2c_gpio_platform_data *pdata = data; + +- gpio_set_value(pdata->scl_pin, state); ++ gpio_set_value_cansleep(pdata->scl_pin, state); + } + + static int i2c_gpio_getsda(void *data) + { + struct i2c_gpio_platform_data *pdata = data; + +- return gpio_get_value(pdata->sda_pin); ++ return gpio_get_value_cansleep(pdata->sda_pin); + } + + static int i2c_gpio_getscl(void *data) + { + struct i2c_gpio_platform_data *pdata = data; + +- return gpio_get_value(pdata->scl_pin); ++ return gpio_get_value_cansleep(pdata->scl_pin); + } + + static int of_i2c_gpio_get_pins(struct device_node *np, +@@ -175,6 +175,9 @@ static int i2c_gpio_probe(struct platfor + memcpy(pdata, dev_get_platdata(&pdev->dev), sizeof(*pdata)); + } + ++ if (gpiod_cansleep(gpio_to_desc(pdata->sda_pin)) || gpiod_cansleep(gpio_to_desc(pdata->scl_pin))) ++ dev_warn(&pdev->dev, "Slow GPIO pins might wreak havoc into I2C/SMBus bus timing"); ++ + if (pdata->sda_is_open_drain) { + gpio_direction_output(pdata->sda_pin, 1); + bit_data->setsda = i2c_gpio_setsda_val; diff --git a/target/linux/generic/backport-4.9/085-v4.16-0001-i2c-gpio-Enable-working-over-slow-can_sleep-GPIOs.patch b/target/linux/generic/backport-4.9/085-v4.16-0001-i2c-gpio-Enable-working-over-slow-can_sleep-GPIOs.patch new file mode 100644 index 0000000000..ead6675e0b --- /dev/null +++ b/target/linux/generic/backport-4.9/085-v4.16-0001-i2c-gpio-Enable-working-over-slow-can_sleep-GPIOs.patch @@ -0,0 +1,84 @@ +From f11a04464ae57e8db1bb7634547842b43e36a898 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= +Date: Fri, 22 Dec 2017 22:47:16 +0100 +Subject: i2c: gpio: Enable working over slow can_sleep GPIOs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +"Slow" GPIOs (usually those connected over an SPI or an I2C bus) are, +well, slow in their operation. It is generally a good idea to avoid +using them for time-critical operation, but sometimes the hardware just +sucks, and the software has to cope. In addition to that, the I2C bus +itself does not actually define any strict timing limits; the bus is +free to go all the way down to DC. The timeouts (and therefore the +slowest acceptable frequency) are present only in SMBus. + +The `can_sleep` is IMHO a wrong concept to use here. My SPI-to-quad-UART +chip (MAX14830) is connected via a 26MHz SPI bus, and it happily drives +SCL at 200kHz (5µs pulses) during my benchmarks. That's faster than the +maximal allowed speed of the traditional I2C. + +The previous version of this code did not really block operation over +slow GPIO pins, anyway. Instead, it just resorted to printing a warning +with a backtrace each time a GPIO pin was accessed, thereby slowing +things down even more. + +Finally, it's not just me. A similar patch was originally submitted in +2015 [1]. + +[1] https://patchwork.ozlabs.org/patch/450956/ + +Signed-off-by: Jan Kundrát +Acked-by: Uwe Kleine-König +Signed-off-by: Wolfram Sang +--- + drivers/i2c/busses/i2c-gpio.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +--- a/drivers/i2c/busses/i2c-gpio.c ++++ b/drivers/i2c/busses/i2c-gpio.c +@@ -44,7 +44,7 @@ static void i2c_gpio_setsda_val(void *da + { + struct i2c_gpio_platform_data *pdata = data; + +- gpio_set_value(pdata->sda_pin, state); ++ gpio_set_value_cansleep(pdata->sda_pin, state); + } + + /* Toggle SCL by changing the direction of the pin. */ +@@ -68,21 +68,21 @@ static void i2c_gpio_setscl_val(void *da + { + struct i2c_gpio_platform_data *pdata = data; + +- gpio_set_value(pdata->scl_pin, state); ++ gpio_set_value_cansleep(pdata->scl_pin, state); + } + + static int i2c_gpio_getsda(void *data) + { + struct i2c_gpio_platform_data *pdata = data; + +- return gpio_get_value(pdata->sda_pin); ++ return gpio_get_value_cansleep(pdata->sda_pin); + } + + static int i2c_gpio_getscl(void *data) + { + struct i2c_gpio_platform_data *pdata = data; + +- return gpio_get_value(pdata->scl_pin); ++ return gpio_get_value_cansleep(pdata->scl_pin); + } + + static int of_i2c_gpio_get_pins(struct device_node *np, +@@ -175,6 +175,9 @@ static int i2c_gpio_probe(struct platfor + memcpy(pdata, dev_get_platdata(&pdev->dev), sizeof(*pdata)); + } + ++ if (gpiod_cansleep(gpio_to_desc(pdata->sda_pin)) || gpiod_cansleep(gpio_to_desc(pdata->scl_pin))) ++ dev_warn(&pdev->dev, "Slow GPIO pins might wreak havoc into I2C/SMBus bus timing"); ++ + if (pdata->sda_is_open_drain) { + gpio_direction_output(pdata->sda_pin, 1); + bit_data->setsda = i2c_gpio_setsda_val;