Add driver for Seiko Instruments Inc. 4.3" WVGA (800 x RGB x 480) TFT with Touch-Panel.
Datasheet available at: http://www.glyn.de/data/glyn/media/doc/43wvf1g-0.pdf
Seiko 43WVF1G panel has two power supplies: avdd and dvdd and they require a specific power on/down sequence. For this reason the simple panel driver cannot be used to drive this panel, so create a new one heavily based on simple panel.
Based on initial patch submission from Breno Lima.
Signed-off-by: Marco Franchi marco.franchi@nxp.com --- Changes since v1: -Change supply names to dvdd-supply and avdd-supply .../bindings/display/panel/seiko,43wvf1g.txt | 23 ++ drivers/gpu/drm/panel/Kconfig | 9 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-seiko-43wvf1g.c | 372 +++++++++++++++++++++ 4 files changed, 405 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/seiko,43wvf1g.txt create mode 100644 drivers/gpu/drm/panel/panel-seiko-43wvf1g.c
diff --git a/Documentation/devicetree/bindings/display/panel/seiko,43wvf1g.txt b/Documentation/devicetree/bindings/display/panel/seiko,43wvf1g.txt new file mode 100644 index 0000000..aae57ef --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/seiko,43wvf1g.txt @@ -0,0 +1,23 @@ +Seiko Instruments Inc. 4.3" WVGA (800 x RGB x 480) TFT with Touch-Panel + +Required properties: +- compatible: should be "sii,43wvf1g". +- "dvdd-supply": 3v3 digital regulator. +- "avdd-supply": 5v analog regulator. + +Optional properties: +- backlight: phandle for the backlight control. + +Example: + + panel { + compatible = "sii,43wvf1g"; + backlight = <&backlight_display>; + dvdd-supply = <®_lcd_3v3>; + avdd-supply = <®_lcd_5v>; + port { + panel_in: endpoint { + remote-endpoint = <&display_out>; + }; + }; + }; diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index d84a031..09b0717 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -86,6 +86,15 @@ config DRM_PANEL_SAMSUNG_S6E8AA0 select DRM_MIPI_DSI select VIDEOMODE_HELPERS
+config DRM_PANEL_SEIKO_43WVF1G + tristate "Seiko 43WVF1G panel" + depends on OF + depends on BACKLIGHT_CLASS_DEVICE + select VIDEOMODE_HELPERS + help + Say Y here if you want to enable support for the Seiko + 43WVF1G controller for 800x480 LCD panels + config DRM_PANEL_SHARP_LQ101R1SX01 tristate "Sharp LQ101R1SX01 panel" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 9f6610d..183c6bf 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o +obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o diff --git a/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c b/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c new file mode 100644 index 0000000..71c09ed --- /dev/null +++ b/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c @@ -0,0 +1,372 @@ +/* + * Copyright (C) 2017 NXP Semiconductors. + * Author: Marco Franchi marco.franchi@nxp.com + * + * Based on Panel Simple driver by Thierry Reding treding@nvidia.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + */ + +#include <linux/backlight.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regulator/consumer.h> + +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_panel.h> + +#include <video/display_timing.h> +#include <video/videomode.h> + +struct seiko_panel_desc { + const struct drm_display_mode *modes; + unsigned int num_modes; + const struct display_timing *timings; + unsigned int num_timings; + + unsigned int bpc; + + /** + * @width: width (in millimeters) of the panel's active display area + * @height: height (in millimeters) of the panel's active display area + */ + struct { + unsigned int width; + unsigned int height; + } size; + + u32 bus_format; + u32 bus_flags; +}; + +struct seiko_panel { + struct drm_panel base; + bool prepared; + bool enabled; + const struct seiko_panel_desc *desc; + struct backlight_device *backlight; + struct regulator *dvdd; + struct regulator *avdd; +}; + +static inline struct seiko_panel *to_seiko_panel(struct drm_panel *panel) +{ + return container_of(panel, struct seiko_panel, base); +} + +static int seiko_panel_get_fixed_modes(struct seiko_panel *panel) +{ + struct drm_connector *connector = panel->base.connector; + struct drm_device *drm = panel->base.drm; + struct drm_display_mode *mode; + unsigned int i, num = 0; + + if (!panel->desc) + return 0; + + for (i = 0; i < panel->desc->num_timings; i++) { + const struct display_timing *dt = &panel->desc->timings[i]; + struct videomode vm; + + videomode_from_timing(dt, &vm); + mode = drm_mode_create(drm); + if (!mode) { + dev_err(drm->dev, "failed to add mode %ux%u\n", + dt->hactive.typ, dt->vactive.typ); + continue; + } + + drm_display_mode_from_videomode(&vm, mode); + + mode->type |= DRM_MODE_TYPE_DRIVER; + + if (panel->desc->num_timings == 1) + mode->type |= DRM_MODE_TYPE_PREFERRED; + + drm_mode_probed_add(connector, mode); + num++; + } + + for (i = 0; i < panel->desc->num_modes; i++) { + const struct drm_display_mode *m = &panel->desc->modes[i]; + + mode = drm_mode_duplicate(drm, m); + if (!mode) { + dev_err(drm->dev, "failed to add mode %ux%u@%u\n", + m->hdisplay, m->vdisplay, m->vrefresh); + continue; + } + + mode->type |= DRM_MODE_TYPE_DRIVER; + + if (panel->desc->num_modes == 1) + mode->type |= DRM_MODE_TYPE_PREFERRED; + + drm_mode_set_name(mode); + + drm_mode_probed_add(connector, mode); + num++; + } + + connector->display_info.bpc = panel->desc->bpc; + connector->display_info.width_mm = panel->desc->size.width; + connector->display_info.height_mm = panel->desc->size.height; + if (panel->desc->bus_format) + drm_display_info_set_bus_formats(&connector->display_info, + &panel->desc->bus_format, 1); + connector->display_info.bus_flags = panel->desc->bus_flags; + + return num; +} + +static int seiko_panel_disable(struct drm_panel *panel) +{ + struct seiko_panel *p = to_seiko_panel(panel); + + if (!p->enabled) + return 0; + + if (p->backlight) { + p->backlight->props.power = FB_BLANK_POWERDOWN; + p->backlight->props.state |= BL_CORE_FBBLANK; + backlight_update_status(p->backlight); + } + + p->enabled = false; + + return 0; +} + +static int seiko_panel_unprepare(struct drm_panel *panel) +{ + struct seiko_panel *p = to_seiko_panel(panel); + + if (!p->prepared) + return 0; + + regulator_disable(p->avdd); + + /* Add a 100ms delay as per the panel datasheet */ + msleep(100); + + regulator_disable(p->dvdd); + + p->prepared = false; + + return 0; +} + +static int seiko_panel_prepare(struct drm_panel *panel) +{ + struct seiko_panel *p = to_seiko_panel(panel); + int err; + + if (p->prepared) + return 0; + + err = regulator_enable(p->dvdd); + if (err < 0) { + dev_err(panel->dev, "failed to enable dvdd: %d\n", err); + return err; + } + + /* Add a 100ms delay as per the panel datasheet */ + msleep(100); + + err = regulator_enable(p->avdd); + if (err < 0) { + dev_err(panel->dev, "failed to enable avdd: %d\n", err); + goto disable_dvdd; + } + + p->prepared = true; + + return 0; + +disable_dvdd: + regulator_disable(p->dvdd); + return err; +} + +static int seiko_panel_enable(struct drm_panel *panel) +{ + struct seiko_panel *p = to_seiko_panel(panel); + + if (p->enabled) + return 0; + + if (p->backlight) { + p->backlight->props.state &= ~BL_CORE_FBBLANK; + p->backlight->props.power = FB_BLANK_UNBLANK; + backlight_update_status(p->backlight); + } + + p->enabled = true; + + return 0; +} + +static int seiko_panel_get_modes(struct drm_panel *panel) +{ + struct seiko_panel *p = to_seiko_panel(panel); + + /* add hard-coded panel modes */ + return seiko_panel_get_fixed_modes(p); +} + +static int seiko_panel_get_timings(struct drm_panel *panel, + unsigned int num_timings, + struct display_timing *timings) +{ + struct seiko_panel *p = to_seiko_panel(panel); + unsigned int i; + + if (p->desc->num_timings < num_timings) + num_timings = p->desc->num_timings; + + if (timings) + for (i = 0; i < num_timings; i++) + timings[i] = p->desc->timings[i]; + + return p->desc->num_timings; +} + +static const struct drm_panel_funcs seiko_panel_funcs = { + .disable = seiko_panel_disable, + .unprepare = seiko_panel_unprepare, + .prepare = seiko_panel_prepare, + .enable = seiko_panel_enable, + .get_modes = seiko_panel_get_modes, + .get_timings = seiko_panel_get_timings, +}; + +static int seiko_panel_probe(struct device *dev, + const struct seiko_panel_desc *desc) +{ + struct device_node *backlight; + struct seiko_panel *panel; + int err; + + panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL); + if (!panel) + return -ENOMEM; + + panel->enabled = false; + panel->prepared = false; + panel->desc = desc; + + panel->dvdd = devm_regulator_get(dev, "dvdd"); + if (IS_ERR(panel->dvdd)) + return PTR_ERR(panel->dvdd); + + panel->avdd = devm_regulator_get(dev, "avdd"); + if (IS_ERR(panel->avdd)) + return PTR_ERR(panel->avdd); + + backlight = of_parse_phandle(dev->of_node, "backlight", 0); + if (backlight) { + panel->backlight = of_find_backlight_by_node(backlight); + of_node_put(backlight); + + if (!panel->backlight) + return -EPROBE_DEFER; + } + + drm_panel_init(&panel->base); + panel->base.dev = dev; + panel->base.funcs = &seiko_panel_funcs; + + err = drm_panel_add(&panel->base); + if (err < 0) + return err; + + dev_set_drvdata(dev, panel); + + return 0; +} + +static int seiko_panel_remove(struct platform_device *pdev) +{ + struct seiko_panel *panel = dev_get_drvdata(&pdev->dev); + + drm_panel_detach(&panel->base); + drm_panel_remove(&panel->base); + + seiko_panel_disable(&panel->base); + + if (panel->backlight) + put_device(&panel->backlight->dev); + + return 0; +} + +static void seiko_panel_shutdown(struct platform_device *pdev) +{ + struct seiko_panel *panel = dev_get_drvdata(&pdev->dev); + + seiko_panel_disable(&panel->base); +} + +static const struct display_timing seiko_43wvf1g_timing = { + .pixelclock = { 33500000, 33500000, 33500000 }, + .hactive = { 800, 800, 800 }, + .hfront_porch = { 164, 164, 164 }, + .hback_porch = { 89, 89, 89 }, + .hsync_len = { 10, 10, 10 }, + .vactive = { 480, 480, 480 }, + .vfront_porch = { 10, 10, 10 }, + .vback_porch = { 23, 23, 23 }, + .vsync_len = { 10, 10, 10 }, + .flags = DISPLAY_FLAGS_DE_LOW, +}; + +static const struct seiko_panel_desc seiko_43wvf1g = { + .timings = &seiko_43wvf1g_timing, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 93, + .height = 57, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_NEGEDGE, +}; + +static const struct of_device_id platform_of_match[] = { + { + .compatible = "sii,43wvf1g", + .data = &seiko_43wvf1g, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, platform_of_match); + +static int seiko_panel_platform_probe(struct platform_device *pdev) +{ + const struct of_device_id *id; + + id = of_match_node(platform_of_match, pdev->dev.of_node); + if (!id) + return -ENODEV; + + return seiko_panel_probe(&pdev->dev, id->data); +} + +static struct platform_driver seiko_panel_platform_driver = { + .driver = { + .name = "seiko_panel", + .of_match_table = platform_of_match, + }, + .probe = seiko_panel_platform_probe, + .remove = seiko_panel_remove, + .shutdown = seiko_panel_shutdown, +}; +module_platform_driver(seiko_panel_platform_driver); + +MODULE_AUTHOR("Marco Franchi <marco.franchi@nxp.com"); +MODULE_DESCRIPTION("Seiko 43WVF1G panel driver"); +MODULE_LICENSE("GPL v2");
Thierry,
2017-07-20 13:12 GMT-03:00 Marco Franchi marco.franchi@nxp.com:
Add driver for Seiko Instruments Inc. 4.3" WVGA (800 x RGB x 480) TFT with Touch-Panel.
Datasheet available at: http://www.glyn.de/data/glyn/media/doc/43wvf1g-0.pdf
Seiko 43WVF1G panel has two power supplies: avdd and dvdd and they require a specific power on/down sequence. For this reason the simple panel driver cannot be used to drive this panel, so create a new one heavily based on simple panel.
Based on initial patch submission from Breno Lima.
Signed-off-by: Marco Franchi marco.franchi@nxp.com
Changes since v1: -Change supply names to dvdd-supply and avdd-supply
I tried pingin Rob with no sucess so far. Given that this is a very simples LCD driver, could you please apply it directly? Thanks
On Thu, Jul 27, 2017 at 11:26 AM, Marco Frank marcofrk@gmail.com wrote:
Thierry,
2017-07-20 13:12 GMT-03:00 Marco Franchi marco.franchi@nxp.com:
Add driver for Seiko Instruments Inc. 4.3" WVGA (800 x RGB x 480) TFT with Touch-Panel.
Datasheet available at: http://www.glyn.de/data/glyn/media/doc/43wvf1g-0.pdf
Seiko 43WVF1G panel has two power supplies: avdd and dvdd and they require a specific power on/down sequence. For this reason the simple panel driver cannot be used to drive this panel, so create a new one heavily based on simple panel.
Based on initial patch submission from Breno Lima.
Signed-off-by: Marco Franchi marco.franchi@nxp.com
Changes since v1: -Change supply names to dvdd-supply and avdd-supply
I tried pingin Rob with no sucess so far. Given that this is a very simples LCD driver, could you please apply it directly? Thanks
If you don't send to the right lists (i.e. the DT list), then it doesn't get into my queue (patchwork) and likely I won't see it.
Rob
Rob, Thierry,
2017-07-20 13:12 GMT-03:00 Marco Franchi marco.franchi@nxp.com:
Add driver for Seiko Instruments Inc. 4.3" WVGA (800 x RGB x 480) TFT with Touch-Panel.
Datasheet available at: http://www.glyn.de/data/glyn/media/doc/43wvf1g-0.pdf
Seiko 43WVF1G panel has two power supplies: avdd and dvdd and they require a specific power on/down sequence. For this reason the simple panel driver cannot be used to drive this panel, so create a new one heavily based on simple panel.
Based on initial patch submission from Breno Lima.
Signed-off-by: Marco Franchi marco.franchi@nxp.com
Changes since v1: -Change supply names to dvdd-supply and avdd-supply
Any comments? If there is anything I can do to help, please let me know.
On Thu, Jul 20, 2017 at 01:12:59PM -0300, Marco Franchi wrote:
Add driver for Seiko Instruments Inc. 4.3" WVGA (800 x RGB x 480) TFT with Touch-Panel.
Datasheet available at: http://www.glyn.de/data/glyn/media/doc/43wvf1g-0.pdf
Seiko 43WVF1G panel has two power supplies: avdd and dvdd and they require a specific power on/down sequence. For this reason the simple panel driver cannot be used to drive this panel, so create a new one heavily based on simple panel.
Based on initial patch submission from Breno Lima.
Signed-off-by: Marco Franchi marco.franchi@nxp.com
Changes since v1: -Change supply names to dvdd-supply and avdd-supply .../bindings/display/panel/seiko,43wvf1g.txt | 23 ++ drivers/gpu/drm/panel/Kconfig | 9 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-seiko-43wvf1g.c | 372 +++++++++++++++++++++ 4 files changed, 405 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/seiko,43wvf1g.txt create mode 100644 drivers/gpu/drm/panel/panel-seiko-43wvf1g.c
I've applied, though somewhat reluctantly, this to drm-misc-next without Rob's Acked-by, but the device tree bindings look trivial enough.
Thanks, Thierry
Hi Thierry,
On Fri, Aug 18, 2017 at 12:08 PM, Thierry Reding thierry.reding@gmail.com wrote:
I've applied, though somewhat reluctantly, this to drm-misc-next without Rob's Acked-by, but the device tree bindings look trivial enough.
Was it really applied? I am not able to find this patch in linux-next.
Thanks
On Tue, Aug 29, 2017 at 02:29:08PM -0300, Fabio Estevam wrote:
Hi Thierry,
On Fri, Aug 18, 2017 at 12:08 PM, Thierry Reding thierry.reding@gmail.com wrote:
I've applied, though somewhat reluctantly, this to drm-misc-next without Rob's Acked-by, but the device tree bindings look trivial enough.
Was it really applied? I am not able to find this patch in linux-next.
Yeah, this is still in drm-misc-next, but due to bad timing on my part it missed the window for 4.14 by just a couple of minutes.
Apologies for that. It should show up in linux-next shortly after 4.14-rc1.
Thierry
Hi Thierry,
On Wed, Aug 30, 2017 at 11:12 AM, Thierry Reding thierry.reding@gmail.com wrote:
On Tue, Aug 29, 2017 at 02:29:08PM -0300, Fabio Estevam wrote:
Hi Thierry,
On Fri, Aug 18, 2017 at 12:08 PM, Thierry Reding thierry.reding@gmail.com wrote:
I've applied, though somewhat reluctantly, this to drm-misc-next without Rob's Acked-by, but the device tree bindings look trivial enough.
Was it really applied? I am not able to find this patch in linux-next.
Yeah, this is still in drm-misc-next, but due to bad timing on my part it missed the window for 4.14 by just a couple of minutes.
Apologies for that. It should show up in linux-next shortly after 4.14-rc1.
Still does not show up in linux-next. Could you please double check it?
dri-devel@lists.freedesktop.org