| From d6df1f94bde17e816756511fbd59c55ba1cfca45 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 3 May 2021 20:21:10 +0300 |
| Subject: staging: fbtft: Rectify GPIO handling |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
| |
| [ Upstream commit ec03c2104365ead0a33627c05e685093eed3eaef ] |
| |
| The infamous commit c440eee1a7a1 ("Staging: staging: fbtft: Switch to |
| the GPIO descriptor interface") broke GPIO handling completely. |
| It has already four commits to rectify and it seems not enough. |
| In order to fix the mess here we: |
| |
| 1) Set default to "inactive" for all requested pins |
| |
| 2) Fix CS#, RD#, and WR# pins polarity since it's active low |
| and GPIO descriptor interface takes it into consideration |
| from the Device Tree or ACPI |
| |
| 3) Consolidate chip activation (CS# assertion) under default |
| ->reset() callback |
| |
| To summarize the expectations about polarity for GPIOs: |
| |
| RD# Low |
| WR# Low |
| CS# Low |
| RESET# Low |
| DC or RS High |
| RW High |
| Data 0 .. 15 High |
| |
| See also Adafruit learning course [1] for the example of the schematics. |
| |
| While at it, drop unneeded NULL checks, since GPIO API is tolerant to that. |
| |
| [1]: https://learn.adafruit.com/adafruit-2-8-and-3-2-color-tft-touchscreen-breakout-v2/downloads |
| |
| Fixes: 92e3e884887c ("Staging: fbtft: Fix GPIO handling") |
| Fixes: b918d1c27066 ("Staging: fbtft: Fix reset assertion when using gpio descriptor") |
| Fixes: dbc4f989c878 ("Staging: fbtft: Fix probing of gpio descriptor") |
| Fixes: c440eee1a7a1 ("Staging: fbtft: Switch to the gpio descriptor interface") |
| Cc: Jan Sebastian Gรถtte <linux@jaseg.net> |
| Cc: Nishad Kamdar <nishadkamdar@gmail.com> |
| Reviewed-by: Phil Reid <preid@electromag.com.au> |
| Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
| Link: https://lore.kernel.org/r/20210503172114.27891-2-andriy.shevchenko@linux.intel.com |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/staging/fbtft/fb_agm1264k-fl.c | 20 ++++++++++---------- |
| drivers/staging/fbtft/fb_bd663474.c | 4 ---- |
| drivers/staging/fbtft/fb_ili9163.c | 4 ---- |
| drivers/staging/fbtft/fb_ili9320.c | 1 - |
| drivers/staging/fbtft/fb_ili9325.c | 4 ---- |
| drivers/staging/fbtft/fb_ili9340.c | 1 - |
| drivers/staging/fbtft/fb_s6d1121.c | 4 ---- |
| drivers/staging/fbtft/fb_sh1106.c | 1 - |
| drivers/staging/fbtft/fb_ssd1289.c | 4 ---- |
| drivers/staging/fbtft/fb_ssd1325.c | 2 -- |
| drivers/staging/fbtft/fb_ssd1331.c | 6 ++---- |
| drivers/staging/fbtft/fb_ssd1351.c | 1 - |
| drivers/staging/fbtft/fb_upd161704.c | 4 ---- |
| drivers/staging/fbtft/fb_watterott.c | 1 - |
| drivers/staging/fbtft/fbtft-bus.c | 3 +-- |
| drivers/staging/fbtft/fbtft-core.c | 13 ++++++------- |
| drivers/staging/fbtft/fbtft-io.c | 12 ++++++------ |
| 17 files changed, 25 insertions(+), 60 deletions(-) |
| |
| diff --git a/drivers/staging/fbtft/fb_agm1264k-fl.c b/drivers/staging/fbtft/fb_agm1264k-fl.c |
| index eeeeec97ad27..b545c2ca80a4 100644 |
| --- a/drivers/staging/fbtft/fb_agm1264k-fl.c |
| +++ b/drivers/staging/fbtft/fb_agm1264k-fl.c |
| @@ -84,9 +84,9 @@ static void reset(struct fbtft_par *par) |
| |
| dev_dbg(par->info->device, "%s()\n", __func__); |
| |
| - gpiod_set_value(par->gpio.reset, 0); |
| - udelay(20); |
| gpiod_set_value(par->gpio.reset, 1); |
| + udelay(20); |
| + gpiod_set_value(par->gpio.reset, 0); |
| mdelay(120); |
| } |
| |
| @@ -194,12 +194,12 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...) |
| /* select chip */ |
| if (*buf) { |
| /* cs1 */ |
| - gpiod_set_value(par->CS0, 1); |
| - gpiod_set_value(par->CS1, 0); |
| - } else { |
| - /* cs0 */ |
| gpiod_set_value(par->CS0, 0); |
| gpiod_set_value(par->CS1, 1); |
| + } else { |
| + /* cs0 */ |
| + gpiod_set_value(par->CS0, 1); |
| + gpiod_set_value(par->CS1, 0); |
| } |
| |
| gpiod_set_value(par->RS, 0); /* RS->0 (command mode) */ |
| @@ -397,8 +397,8 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) |
| } |
| kfree(convert_buf); |
| |
| - gpiod_set_value(par->CS0, 1); |
| - gpiod_set_value(par->CS1, 1); |
| + gpiod_set_value(par->CS0, 0); |
| + gpiod_set_value(par->CS1, 0); |
| |
| return ret; |
| } |
| @@ -419,10 +419,10 @@ static int write(struct fbtft_par *par, void *buf, size_t len) |
| for (i = 0; i < 8; ++i) |
| gpiod_set_value(par->gpio.db[i], data & (1 << i)); |
| /* set E */ |
| - gpiod_set_value(par->EPIN, 1); |
| + gpiod_set_value(par->EPIN, 0); |
| udelay(5); |
| /* unset E - write */ |
| - gpiod_set_value(par->EPIN, 0); |
| + gpiod_set_value(par->EPIN, 1); |
| udelay(1); |
| } |
| |
| diff --git a/drivers/staging/fbtft/fb_bd663474.c b/drivers/staging/fbtft/fb_bd663474.c |
| index e2c7646588f8..1629c2c440a9 100644 |
| --- a/drivers/staging/fbtft/fb_bd663474.c |
| +++ b/drivers/staging/fbtft/fb_bd663474.c |
| @@ -12,7 +12,6 @@ |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/init.h> |
| -#include <linux/gpio/consumer.h> |
| #include <linux/delay.h> |
| |
| #include "fbtft.h" |
| @@ -24,9 +23,6 @@ |
| |
| static int init_display(struct fbtft_par *par) |
| { |
| - if (par->gpio.cs) |
| - gpiod_set_value(par->gpio.cs, 0); /* Activate chip */ |
| - |
| par->fbtftops.reset(par); |
| |
| /* Initialization sequence from Lib_UTFT */ |
| diff --git a/drivers/staging/fbtft/fb_ili9163.c b/drivers/staging/fbtft/fb_ili9163.c |
| index 05648c3ffe47..6582a2c90aaf 100644 |
| --- a/drivers/staging/fbtft/fb_ili9163.c |
| +++ b/drivers/staging/fbtft/fb_ili9163.c |
| @@ -11,7 +11,6 @@ |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/init.h> |
| -#include <linux/gpio/consumer.h> |
| #include <linux/delay.h> |
| #include <video/mipi_display.h> |
| |
| @@ -77,9 +76,6 @@ static int init_display(struct fbtft_par *par) |
| { |
| par->fbtftops.reset(par); |
| |
| - if (par->gpio.cs) |
| - gpiod_set_value(par->gpio.cs, 0); /* Activate chip */ |
| - |
| write_reg(par, MIPI_DCS_SOFT_RESET); /* software reset */ |
| mdelay(500); |
| write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE); /* exit sleep */ |
| diff --git a/drivers/staging/fbtft/fb_ili9320.c b/drivers/staging/fbtft/fb_ili9320.c |
| index f2e72d14431d..a8f4c618b754 100644 |
| --- a/drivers/staging/fbtft/fb_ili9320.c |
| +++ b/drivers/staging/fbtft/fb_ili9320.c |
| @@ -8,7 +8,6 @@ |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/init.h> |
| -#include <linux/gpio/consumer.h> |
| #include <linux/spi/spi.h> |
| #include <linux/delay.h> |
| |
| diff --git a/drivers/staging/fbtft/fb_ili9325.c b/drivers/staging/fbtft/fb_ili9325.c |
| index c9aa4cb43123..16d3b17ca279 100644 |
| --- a/drivers/staging/fbtft/fb_ili9325.c |
| +++ b/drivers/staging/fbtft/fb_ili9325.c |
| @@ -10,7 +10,6 @@ |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/init.h> |
| -#include <linux/gpio/consumer.h> |
| #include <linux/delay.h> |
| |
| #include "fbtft.h" |
| @@ -85,9 +84,6 @@ static int init_display(struct fbtft_par *par) |
| { |
| par->fbtftops.reset(par); |
| |
| - if (par->gpio.cs) |
| - gpiod_set_value(par->gpio.cs, 0); /* Activate chip */ |
| - |
| bt &= 0x07; |
| vc &= 0x07; |
| vrh &= 0x0f; |
| diff --git a/drivers/staging/fbtft/fb_ili9340.c b/drivers/staging/fbtft/fb_ili9340.c |
| index 415183c7054a..704236bcaf3f 100644 |
| --- a/drivers/staging/fbtft/fb_ili9340.c |
| +++ b/drivers/staging/fbtft/fb_ili9340.c |
| @@ -8,7 +8,6 @@ |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/init.h> |
| -#include <linux/gpio/consumer.h> |
| #include <linux/delay.h> |
| #include <video/mipi_display.h> |
| |
| diff --git a/drivers/staging/fbtft/fb_s6d1121.c b/drivers/staging/fbtft/fb_s6d1121.c |
| index 8c7de3290343..62f27172f844 100644 |
| --- a/drivers/staging/fbtft/fb_s6d1121.c |
| +++ b/drivers/staging/fbtft/fb_s6d1121.c |
| @@ -12,7 +12,6 @@ |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/init.h> |
| -#include <linux/gpio/consumer.h> |
| #include <linux/delay.h> |
| |
| #include "fbtft.h" |
| @@ -29,9 +28,6 @@ static int init_display(struct fbtft_par *par) |
| { |
| par->fbtftops.reset(par); |
| |
| - if (par->gpio.cs) |
| - gpiod_set_value(par->gpio.cs, 0); /* Activate chip */ |
| - |
| /* Initialization sequence from Lib_UTFT */ |
| |
| write_reg(par, 0x0011, 0x2004); |
| diff --git a/drivers/staging/fbtft/fb_sh1106.c b/drivers/staging/fbtft/fb_sh1106.c |
| index 6f7249493ea3..7b9ab39e1c1a 100644 |
| --- a/drivers/staging/fbtft/fb_sh1106.c |
| +++ b/drivers/staging/fbtft/fb_sh1106.c |
| @@ -9,7 +9,6 @@ |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/init.h> |
| -#include <linux/gpio/consumer.h> |
| #include <linux/delay.h> |
| |
| #include "fbtft.h" |
| diff --git a/drivers/staging/fbtft/fb_ssd1289.c b/drivers/staging/fbtft/fb_ssd1289.c |
| index 7a3fe022cc69..f27bab38b3ec 100644 |
| --- a/drivers/staging/fbtft/fb_ssd1289.c |
| +++ b/drivers/staging/fbtft/fb_ssd1289.c |
| @@ -10,7 +10,6 @@ |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/init.h> |
| -#include <linux/gpio/consumer.h> |
| |
| #include "fbtft.h" |
| |
| @@ -28,9 +27,6 @@ static int init_display(struct fbtft_par *par) |
| { |
| par->fbtftops.reset(par); |
| |
| - if (par->gpio.cs) |
| - gpiod_set_value(par->gpio.cs, 0); /* Activate chip */ |
| - |
| write_reg(par, 0x00, 0x0001); |
| write_reg(par, 0x03, 0xA8A4); |
| write_reg(par, 0x0C, 0x0000); |
| diff --git a/drivers/staging/fbtft/fb_ssd1325.c b/drivers/staging/fbtft/fb_ssd1325.c |
| index 8a3140d41d8b..796a2ac3e194 100644 |
| --- a/drivers/staging/fbtft/fb_ssd1325.c |
| +++ b/drivers/staging/fbtft/fb_ssd1325.c |
| @@ -35,8 +35,6 @@ static int init_display(struct fbtft_par *par) |
| { |
| par->fbtftops.reset(par); |
| |
| - gpiod_set_value(par->gpio.cs, 0); |
| - |
| write_reg(par, 0xb3); |
| write_reg(par, 0xf0); |
| write_reg(par, 0xae); |
| diff --git a/drivers/staging/fbtft/fb_ssd1331.c b/drivers/staging/fbtft/fb_ssd1331.c |
| index 37622c9462aa..ec5eced7f8cb 100644 |
| --- a/drivers/staging/fbtft/fb_ssd1331.c |
| +++ b/drivers/staging/fbtft/fb_ssd1331.c |
| @@ -81,8 +81,7 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...) |
| va_start(args, len); |
| |
| *buf = (u8)va_arg(args, unsigned int); |
| - if (par->gpio.dc) |
| - gpiod_set_value(par->gpio.dc, 0); |
| + gpiod_set_value(par->gpio.dc, 0); |
| ret = par->fbtftops.write(par, par->buf, sizeof(u8)); |
| if (ret < 0) { |
| va_end(args); |
| @@ -104,8 +103,7 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...) |
| return; |
| } |
| } |
| - if (par->gpio.dc) |
| - gpiod_set_value(par->gpio.dc, 1); |
| + gpiod_set_value(par->gpio.dc, 1); |
| va_end(args); |
| } |
| |
| diff --git a/drivers/staging/fbtft/fb_ssd1351.c b/drivers/staging/fbtft/fb_ssd1351.c |
| index 900b28d826b2..cf263a58a148 100644 |
| --- a/drivers/staging/fbtft/fb_ssd1351.c |
| +++ b/drivers/staging/fbtft/fb_ssd1351.c |
| @@ -2,7 +2,6 @@ |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/init.h> |
| -#include <linux/gpio/consumer.h> |
| #include <linux/spi/spi.h> |
| #include <linux/delay.h> |
| |
| diff --git a/drivers/staging/fbtft/fb_upd161704.c b/drivers/staging/fbtft/fb_upd161704.c |
| index c77832ae5e5b..c680160d6380 100644 |
| --- a/drivers/staging/fbtft/fb_upd161704.c |
| +++ b/drivers/staging/fbtft/fb_upd161704.c |
| @@ -12,7 +12,6 @@ |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/init.h> |
| -#include <linux/gpio/consumer.h> |
| #include <linux/delay.h> |
| |
| #include "fbtft.h" |
| @@ -26,9 +25,6 @@ static int init_display(struct fbtft_par *par) |
| { |
| par->fbtftops.reset(par); |
| |
| - if (par->gpio.cs) |
| - gpiod_set_value(par->gpio.cs, 0); /* Activate chip */ |
| - |
| /* Initialization sequence from Lib_UTFT */ |
| |
| /* register reset */ |
| diff --git a/drivers/staging/fbtft/fb_watterott.c b/drivers/staging/fbtft/fb_watterott.c |
| index 76b25df376b8..a57e1f4feef3 100644 |
| --- a/drivers/staging/fbtft/fb_watterott.c |
| +++ b/drivers/staging/fbtft/fb_watterott.c |
| @@ -8,7 +8,6 @@ |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/init.h> |
| -#include <linux/gpio/consumer.h> |
| #include <linux/delay.h> |
| |
| #include "fbtft.h" |
| diff --git a/drivers/staging/fbtft/fbtft-bus.c b/drivers/staging/fbtft/fbtft-bus.c |
| index 63c65dd67b17..3d422bc11641 100644 |
| --- a/drivers/staging/fbtft/fbtft-bus.c |
| +++ b/drivers/staging/fbtft/fbtft-bus.c |
| @@ -135,8 +135,7 @@ int fbtft_write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len) |
| remain = len / 2; |
| vmem16 = (u16 *)(par->info->screen_buffer + offset); |
| |
| - if (par->gpio.dc) |
| - gpiod_set_value(par->gpio.dc, 1); |
| + gpiod_set_value(par->gpio.dc, 1); |
| |
| /* non buffered write */ |
| if (!par->txbuf.buf) |
| diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c |
| index 4f362dad4436..67c3b1975a4d 100644 |
| --- a/drivers/staging/fbtft/fbtft-core.c |
| +++ b/drivers/staging/fbtft/fbtft-core.c |
| @@ -38,8 +38,7 @@ int fbtft_write_buf_dc(struct fbtft_par *par, void *buf, size_t len, int dc) |
| { |
| int ret; |
| |
| - if (par->gpio.dc) |
| - gpiod_set_value(par->gpio.dc, dc); |
| + gpiod_set_value(par->gpio.dc, dc); |
| |
| ret = par->fbtftops.write(par, buf, len); |
| if (ret < 0) |
| @@ -79,7 +78,7 @@ static int fbtft_request_one_gpio(struct fbtft_par *par, |
| int ret = 0; |
| |
| *gpiop = devm_gpiod_get_index_optional(dev, name, index, |
| - GPIOD_OUT_HIGH); |
| + GPIOD_OUT_LOW); |
| if (IS_ERR(*gpiop)) { |
| ret = PTR_ERR(*gpiop); |
| dev_err(dev, |
| @@ -226,11 +225,15 @@ static void fbtft_reset(struct fbtft_par *par) |
| { |
| if (!par->gpio.reset) |
| return; |
| + |
| fbtft_par_dbg(DEBUG_RESET, par, "%s()\n", __func__); |
| + |
| gpiod_set_value_cansleep(par->gpio.reset, 1); |
| usleep_range(20, 40); |
| gpiod_set_value_cansleep(par->gpio.reset, 0); |
| msleep(120); |
| + |
| + gpiod_set_value_cansleep(par->gpio.cs, 1); /* Activate chip */ |
| } |
| |
| static void fbtft_update_display(struct fbtft_par *par, unsigned int start_line, |
| @@ -922,8 +925,6 @@ static int fbtft_init_display_from_property(struct fbtft_par *par) |
| goto out_free; |
| |
| par->fbtftops.reset(par); |
| - if (par->gpio.cs) |
| - gpiod_set_value(par->gpio.cs, 0); /* Activate chip */ |
| |
| index = -1; |
| val = values[++index]; |
| @@ -1018,8 +1019,6 @@ int fbtft_init_display(struct fbtft_par *par) |
| } |
| |
| par->fbtftops.reset(par); |
| - if (par->gpio.cs) |
| - gpiod_set_value(par->gpio.cs, 0); /* Activate chip */ |
| |
| i = 0; |
| while (i < FBTFT_MAX_INIT_SEQUENCE) { |
| diff --git a/drivers/staging/fbtft/fbtft-io.c b/drivers/staging/fbtft/fbtft-io.c |
| index 0863d257d762..de1904a443c2 100644 |
| --- a/drivers/staging/fbtft/fbtft-io.c |
| +++ b/drivers/staging/fbtft/fbtft-io.c |
| @@ -142,12 +142,12 @@ int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len) |
| data = *(u8 *)buf; |
| |
| /* Start writing by pulling down /WR */ |
| - gpiod_set_value(par->gpio.wr, 0); |
| + gpiod_set_value(par->gpio.wr, 1); |
| |
| /* Set data */ |
| #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO |
| if (data == prev_data) { |
| - gpiod_set_value(par->gpio.wr, 0); /* used as delay */ |
| + gpiod_set_value(par->gpio.wr, 1); /* used as delay */ |
| } else { |
| for (i = 0; i < 8; i++) { |
| if ((data & 1) != (prev_data & 1)) |
| @@ -165,7 +165,7 @@ int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len) |
| #endif |
| |
| /* Pullup /WR */ |
| - gpiod_set_value(par->gpio.wr, 1); |
| + gpiod_set_value(par->gpio.wr, 0); |
| |
| #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO |
| prev_data = *(u8 *)buf; |
| @@ -192,12 +192,12 @@ int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len) |
| data = *(u16 *)buf; |
| |
| /* Start writing by pulling down /WR */ |
| - gpiod_set_value(par->gpio.wr, 0); |
| + gpiod_set_value(par->gpio.wr, 1); |
| |
| /* Set data */ |
| #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO |
| if (data == prev_data) { |
| - gpiod_set_value(par->gpio.wr, 0); /* used as delay */ |
| + gpiod_set_value(par->gpio.wr, 1); /* used as delay */ |
| } else { |
| for (i = 0; i < 16; i++) { |
| if ((data & 1) != (prev_data & 1)) |
| @@ -215,7 +215,7 @@ int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len) |
| #endif |
| |
| /* Pullup /WR */ |
| - gpiod_set_value(par->gpio.wr, 1); |
| + gpiod_set_value(par->gpio.wr, 0); |
| |
| #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO |
| prev_data = *(u16 *)buf; |
| -- |
| 2.30.2 |
| |