From 7c40df9d116d8c4f075bb06a83a43d3ac733cbcb Mon Sep 17 00:00:00 2001 From: James Ward Date: Sat, 1 Jul 2023 17:17:07 -0400 Subject: [PATCH 1/6] feat: use the gpio descriptor interface this updates the interactions with gpio pins to use the newer gpio descriptor API in the kernel rather than the deprecated gpio-by-int interface this means that the gpio pins can be configured as part of the device tree rather than during compile time --- drm_iface.c | 81 ++++++++++++++++++++++++++++++++++++++++++++--------- drm_iface.h | 2 +- sharp.dts | 5 ++++ 3 files changed, 74 insertions(+), 14 deletions(-) diff --git a/drm_iface.c b/drm_iface.c index a276eee..d546b57 100644 --- a/drm_iface.c +++ b/drm_iface.c @@ -6,7 +6,7 @@ */ #include -#include +#include #include #include #include @@ -61,6 +61,10 @@ struct sharp_memory_panel { unsigned char *trailer_buf; char indicators[MAX_INDICATORS]; + + struct gpio_desc *gpio_scs; + struct gpio_desc *gpio_disp; + struct gpio_desc *gpio_vcom; }; static struct sharp_memory_panel* g_panel = NULL; @@ -78,7 +82,7 @@ static void vcom_timer_callback(struct timer_list *t) // Toggle the GPIO pin vcom_setting = (vcom_setting) ? 0 : 1; - gpio_set_value(GPIO_VCOM, vcom_setting); + gpiod_set_value(panel->gpio_vcom, 1); // Reschedule the timer mod_timer(&panel->vcom_timer, jiffies + msecs_to_jiffies(1000)); @@ -98,9 +102,18 @@ static int sharp_memory_spi_clear_screen(struct sharp_memory_panel *panel) // Write clear screen command ndelay(80); - gpio_set_value(GPIO_SCS, 1); + + if (panel->gpio_scs) + { + gpiod_set_value(panel->gpio_scs, 1); + } + rc = spi_sync_transfer(panel->spi, panel->spi_3_xfers, 2); - gpio_set_value(GPIO_SCS, 0); + + if (panel->gpio_scs) + { + gpiod_set_value(panel->gpio_scs, 0); + } return rc; } @@ -133,9 +146,18 @@ static int sharp_memory_spi_write_tagged_lines(struct sharp_memory_panel *panel, panel->spi_3_xfers[2].len = 1; ndelay(80); - gpio_set_value(GPIO_SCS, 1); + + if (panel->gpio_scs) + { + gpiod_set_value(panel->gpio_scs, 1); + } + rc = spi_sync_transfer(panel->spi, panel->spi_3_xfers, 3); - gpio_set_value(GPIO_SCS, 0); + + if (panel->gpio_scs) + { + gpiod_set_value(panel->gpio_scs, 0); + } return rc; } @@ -331,9 +353,12 @@ static void power_off(struct sharp_memory_panel *panel) printk(KERN_INFO "sharp_memory: powering off\n"); /* Turn off power and all signals */ - gpio_set_value(GPIO_SCS, 0); - gpio_set_value(GPIO_DISP, 0); - gpio_set_value(GPIO_VCOM, 0); + if (panel->gpio_scs) + { + gpiod_set_value(panel->gpio_scs, 0); + } + gpiod_set_value(panel->gpio_disp, 0); + gpiod_set_value(panel->gpio_vcom, 0); } static void sharp_memory_pipe_enable(struct drm_simple_display_pipe *pipe, @@ -355,14 +380,17 @@ static void sharp_memory_pipe_enable(struct drm_simple_display_pipe *pipe, } // Power up sequence - gpio_set_value(GPIO_SCS, 0); - gpio_set_value(GPIO_DISP, 1); - gpio_set_value(GPIO_VCOM, 0); + if (panel->gpio_scs) + { + gpiod_set_value(panel->gpio_scs, 0); + } + gpiod_set_value(panel->gpio_disp, 1); + gpiod_set_value(panel->gpio_vcom, 0); usleep_range(5000, 10000); // Clear display if (sharp_memory_spi_clear_screen(panel)) { - gpio_set_value(GPIO_DISP, 0); // Power down display, VCOM is not running + gpiod_set_value(panel->gpio_disp, 0); // Power down display, VCOM is not running goto out_exit; } @@ -499,6 +527,19 @@ int drm_probe(struct spi_device *spi) } } + // Initialize GPIO + panel->gpio_scs = devm_gpiod_get_optional(dev, "scs", GPIOD_OUT_LOW); + if (IS_ERR(panel->gpio_scs)) + return dev_err_probe(dev, PTR_ERR(panel->gpio_scs), "Failed to get GPIO 'scs'\n"); + + panel->gpio_disp = devm_gpiod_get(dev, "disp", GPIOD_OUT_HIGH); + if (IS_ERR(panel->gpio_disp)) + return dev_err_probe(dev, PTR_ERR(panel->gpio_disp), "Failed to get GPIO 'disp'\n"); + + panel->gpio_vcom = devm_gpiod_get(dev, "vcom", GPIOD_OUT_LOW); + if (IS_ERR(panel->gpio_vcom)) + return dev_err_probe(dev, PTR_ERR(panel->gpio_vcom), "Failed to get GPIO 'vcom'\n"); + // Allocate panel storage panel = devm_drm_dev_alloc(dev, &sharp_memory_driver, struct sharp_memory_panel, drm); @@ -577,6 +618,8 @@ int drm_probe(struct spi_device *spi) void drm_remove(struct spi_device *spi) { struct drm_device *drm; + struct device *dev; + struct sharp_memory_panel *panel; printk(KERN_INFO "sharp_memory: drm_remove\n"); @@ -586,6 +629,18 @@ void drm_remove(struct spi_device *spi) // Get DRM and panel device from SPI drm = spi_get_drvdata(spi); + // Clean up the GPIO descriptors + dev = &spi->dev; + panel = drm_to_panel(drm) + + if (panel->gpio_scs) + { + devm_gpiod_put(dev, panel->gpio_scs) + } + devm_gpiod_put(dev, panel->gpio_disp) + devm_gpiod_put(dev, panel->gpio_vcom) + + drm_dev_unplug(drm); drm_atomic_helper_shutdown(drm); } diff --git a/drm_iface.h b/drm_iface.h index 8e79b06..eb83305 100644 --- a/drm_iface.h +++ b/drm_iface.h @@ -2,7 +2,7 @@ #define DRM_IFACE_H_ #include -#include +#include #include #include #include diff --git a/sharp.dts b/sharp.dts index 10d8327..3d818d7 100644 --- a/sharp.dts +++ b/sharp.dts @@ -48,6 +48,11 @@ reg = <0>; pinctrl-names = "default"; pinctrl-0 = <&sharp_pins>; + + vcom-gpios = <&gpio 23 0>; + disp-gpios = <&gpio 22 0>; + scs-gpios = <&gpio 8 0>; + spi-cs-high = <1>; spi-max-frequency = <8000000>; buswidth = <8>; From 6383900718aaee2ee292679601ba22050e2c82b0 Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 11 Jul 2023 01:16:49 -0400 Subject: [PATCH 2/6] fix: add missing semicolons --- drm_iface.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drm_iface.c b/drm_iface.c index d546b57..9f08d3e 100644 --- a/drm_iface.c +++ b/drm_iface.c @@ -635,10 +635,10 @@ void drm_remove(struct spi_device *spi) if (panel->gpio_scs) { - devm_gpiod_put(dev, panel->gpio_scs) + devm_gpiod_put(dev, panel->gpio_scs); } - devm_gpiod_put(dev, panel->gpio_disp) - devm_gpiod_put(dev, panel->gpio_vcom) + devm_gpiod_put(dev, panel->gpio_disp); + devm_gpiod_put(dev, panel->gpio_vcom); drm_dev_unplug(drm); From 6ef6fd88a52abf637ffb0b7687a7694f260a5af2 Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 11 Jul 2023 02:42:51 -0400 Subject: [PATCH 3/6] fix: pull gpio after we initialize the panel struct --- drm_iface.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drm_iface.c b/drm_iface.c index 9f08d3e..43686e8 100644 --- a/drm_iface.c +++ b/drm_iface.c @@ -527,6 +527,15 @@ int drm_probe(struct spi_device *spi) } } + // Allocate panel storage + panel = devm_drm_dev_alloc(dev, &sharp_memory_driver, + struct sharp_memory_panel, drm); + if (IS_ERR(panel)) { + printk(KERN_ERR "sharp_memory: failed to allocate panel\n"); + return PTR_ERR(panel); + } + g_panel = panel; + // Initialize GPIO panel->gpio_scs = devm_gpiod_get_optional(dev, "scs", GPIOD_OUT_LOW); if (IS_ERR(panel->gpio_scs)) @@ -540,15 +549,6 @@ int drm_probe(struct spi_device *spi) if (IS_ERR(panel->gpio_vcom)) return dev_err_probe(dev, PTR_ERR(panel->gpio_vcom), "Failed to get GPIO 'vcom'\n"); - // Allocate panel storage - panel = devm_drm_dev_alloc(dev, &sharp_memory_driver, - struct sharp_memory_panel, drm); - if (IS_ERR(panel)) { - printk(KERN_ERR "sharp_memory: failed to allocate panel\n"); - return PTR_ERR(panel); - } - g_panel = panel; - // Initalize DRM mode drm = &panel->drm; ret = drmm_mode_config_init(drm); From d90237bf9a669d69b7cd319f149c8afacde7c8fc Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 11 Jul 2023 03:00:56 -0400 Subject: [PATCH 4/6] chore: drop manual SPI Chip Select management the screen works fine without this because the SPI kernel handling does chip selection for us --- drm_iface.c | 37 ------------------------------------- sharp.dts | 1 - 2 files changed, 38 deletions(-) diff --git a/drm_iface.c b/drm_iface.c index 43686e8..7e96f96 100644 --- a/drm_iface.c +++ b/drm_iface.c @@ -35,10 +35,6 @@ #include "indicators.h" -#define GPIO_DISP 22 -#define GPIO_SCS 8 -#define GPIO_VCOM 23 - #define CMD_WRITE_LINE 0b10000000 #define CMD_CLEAR_SCREEN 0b00100000 @@ -62,7 +58,6 @@ struct sharp_memory_panel { char indicators[MAX_INDICATORS]; - struct gpio_desc *gpio_scs; struct gpio_desc *gpio_disp; struct gpio_desc *gpio_vcom; }; @@ -103,18 +98,8 @@ static int sharp_memory_spi_clear_screen(struct sharp_memory_panel *panel) // Write clear screen command ndelay(80); - if (panel->gpio_scs) - { - gpiod_set_value(panel->gpio_scs, 1); - } - rc = spi_sync_transfer(panel->spi, panel->spi_3_xfers, 2); - if (panel->gpio_scs) - { - gpiod_set_value(panel->gpio_scs, 0); - } - return rc; } @@ -147,18 +132,8 @@ static int sharp_memory_spi_write_tagged_lines(struct sharp_memory_panel *panel, ndelay(80); - if (panel->gpio_scs) - { - gpiod_set_value(panel->gpio_scs, 1); - } - rc = spi_sync_transfer(panel->spi, panel->spi_3_xfers, 3); - if (panel->gpio_scs) - { - gpiod_set_value(panel->gpio_scs, 0); - } - return rc; } @@ -353,10 +328,6 @@ static void power_off(struct sharp_memory_panel *panel) printk(KERN_INFO "sharp_memory: powering off\n"); /* Turn off power and all signals */ - if (panel->gpio_scs) - { - gpiod_set_value(panel->gpio_scs, 0); - } gpiod_set_value(panel->gpio_disp, 0); gpiod_set_value(panel->gpio_vcom, 0); } @@ -537,10 +508,6 @@ int drm_probe(struct spi_device *spi) g_panel = panel; // Initialize GPIO - panel->gpio_scs = devm_gpiod_get_optional(dev, "scs", GPIOD_OUT_LOW); - if (IS_ERR(panel->gpio_scs)) - return dev_err_probe(dev, PTR_ERR(panel->gpio_scs), "Failed to get GPIO 'scs'\n"); - panel->gpio_disp = devm_gpiod_get(dev, "disp", GPIOD_OUT_HIGH); if (IS_ERR(panel->gpio_disp)) return dev_err_probe(dev, PTR_ERR(panel->gpio_disp), "Failed to get GPIO 'disp'\n"); @@ -633,10 +600,6 @@ void drm_remove(struct spi_device *spi) dev = &spi->dev; panel = drm_to_panel(drm) - if (panel->gpio_scs) - { - devm_gpiod_put(dev, panel->gpio_scs); - } devm_gpiod_put(dev, panel->gpio_disp); devm_gpiod_put(dev, panel->gpio_vcom); diff --git a/sharp.dts b/sharp.dts index 3d818d7..2e16032 100644 --- a/sharp.dts +++ b/sharp.dts @@ -51,7 +51,6 @@ vcom-gpios = <&gpio 23 0>; disp-gpios = <&gpio 22 0>; - scs-gpios = <&gpio 8 0>; spi-cs-high = <1>; spi-max-frequency = <8000000>; From 41df18cb2b8d13a1e0c7eee10993255f4aa2e29b Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 11 Jul 2023 03:04:42 -0400 Subject: [PATCH 5/6] chore: fix whitespace issues (spaces instead of tabs) --- drm_iface.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drm_iface.c b/drm_iface.c index 7e96f96..7ebaeef 100644 --- a/drm_iface.c +++ b/drm_iface.c @@ -508,12 +508,12 @@ int drm_probe(struct spi_device *spi) g_panel = panel; // Initialize GPIO - panel->gpio_disp = devm_gpiod_get(dev, "disp", GPIOD_OUT_HIGH); - if (IS_ERR(panel->gpio_disp)) + panel->gpio_disp = devm_gpiod_get(dev, "disp", GPIOD_OUT_HIGH); + if (IS_ERR(panel->gpio_disp)) return dev_err_probe(dev, PTR_ERR(panel->gpio_disp), "Failed to get GPIO 'disp'\n"); - panel->gpio_vcom = devm_gpiod_get(dev, "vcom", GPIOD_OUT_LOW); - if (IS_ERR(panel->gpio_vcom)) + panel->gpio_vcom = devm_gpiod_get(dev, "vcom", GPIOD_OUT_LOW); + if (IS_ERR(panel->gpio_vcom)) return dev_err_probe(dev, PTR_ERR(panel->gpio_vcom), "Failed to get GPIO 'vcom'\n"); // Initalize DRM mode From c8095e4f59d11dc4a242fe7b0aca957fd58908db Mon Sep 17 00:00:00 2001 From: James Ward Date: Tue, 11 Jul 2023 20:14:16 -0400 Subject: [PATCH 6/6] fix: drop spurious scs & fix missing semicolon --- drm_iface.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drm_iface.c b/drm_iface.c index 7ebaeef..9b5c006 100644 --- a/drm_iface.c +++ b/drm_iface.c @@ -351,10 +351,6 @@ static void sharp_memory_pipe_enable(struct drm_simple_display_pipe *pipe, } // Power up sequence - if (panel->gpio_scs) - { - gpiod_set_value(panel->gpio_scs, 0); - } gpiod_set_value(panel->gpio_disp, 1); gpiod_set_value(panel->gpio_vcom, 0); usleep_range(5000, 10000); @@ -598,7 +594,7 @@ void drm_remove(struct spi_device *spi) // Clean up the GPIO descriptors dev = &spi->dev; - panel = drm_to_panel(drm) + panel = drm_to_panel(drm); devm_gpiod_put(dev, panel->gpio_disp); devm_gpiod_put(dev, panel->gpio_vcom);