Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/panel: Add driver for Seiko 43WVF1G panel

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>
Signed-off-by: Thierry Reding <treding@nvidia.com>
Link: https://patchwork.freedesktop.org/patch/msgid/1500567179-6967-1-git-send-email-marco.franchi@nxp.com

authored by

Marco Franchi and committed by
Thierry Reding
043652aa e1641ed8

+405
+23
Documentation/devicetree/bindings/display/panel/seiko,43wvf1g.txt
··· 1 + Seiko Instruments Inc. 4.3" WVGA (800 x RGB x 480) TFT with Touch-Panel 2 + 3 + Required properties: 4 + - compatible: should be "sii,43wvf1g". 5 + - "dvdd-supply": 3v3 digital regulator. 6 + - "avdd-supply": 5v analog regulator. 7 + 8 + Optional properties: 9 + - backlight: phandle for the backlight control. 10 + 11 + Example: 12 + 13 + panel { 14 + compatible = "sii,43wvf1g"; 15 + backlight = <&backlight_display>; 16 + dvdd-supply = <&reg_lcd_3v3>; 17 + avdd-supply = <&reg_lcd_5v>; 18 + port { 19 + panel_in: endpoint { 20 + remote-endpoint = <&display_out>; 21 + }; 22 + }; 23 + };
+9
drivers/gpu/drm/panel/Kconfig
··· 102 102 select DRM_MIPI_DSI 103 103 select VIDEOMODE_HELPERS 104 104 105 + config DRM_PANEL_SEIKO_43WVF1G 106 + tristate "Seiko 43WVF1G panel" 107 + depends on OF 108 + depends on BACKLIGHT_CLASS_DEVICE 109 + select VIDEOMODE_HELPERS 110 + help 111 + Say Y here if you want to enable support for the Seiko 112 + 43WVF1G controller for 800x480 LCD panels 113 + 105 114 config DRM_PANEL_SHARP_LQ101R1SX01 106 115 tristate "Sharp LQ101R1SX01 panel" 107 116 depends on OF
+1
drivers/gpu/drm/panel/Makefile
··· 9 9 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o 10 10 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o 11 11 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o 12 + obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o 12 13 obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o 13 14 obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o 14 15 obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o
+372
drivers/gpu/drm/panel/panel-seiko-43wvf1g.c
··· 1 + /* 2 + * Copyright (C) 2017 NXP Semiconductors. 3 + * Author: Marco Franchi <marco.franchi@nxp.com> 4 + * 5 + * Based on Panel Simple driver by Thierry Reding <treding@nvidia.com> 6 + * 7 + * This program is free software; you can redistribute it and/or 8 + * modify it under the terms of the GNU General Public License version 9 + * 2 as published by the Free Software Foundation. 10 + */ 11 + 12 + #include <linux/backlight.h> 13 + #include <linux/module.h> 14 + #include <linux/of.h> 15 + #include <linux/regulator/consumer.h> 16 + 17 + #include <drm/drmP.h> 18 + #include <drm/drm_crtc.h> 19 + #include <drm/drm_panel.h> 20 + 21 + #include <video/display_timing.h> 22 + #include <video/videomode.h> 23 + 24 + struct seiko_panel_desc { 25 + const struct drm_display_mode *modes; 26 + unsigned int num_modes; 27 + const struct display_timing *timings; 28 + unsigned int num_timings; 29 + 30 + unsigned int bpc; 31 + 32 + /** 33 + * @width: width (in millimeters) of the panel's active display area 34 + * @height: height (in millimeters) of the panel's active display area 35 + */ 36 + struct { 37 + unsigned int width; 38 + unsigned int height; 39 + } size; 40 + 41 + u32 bus_format; 42 + u32 bus_flags; 43 + }; 44 + 45 + struct seiko_panel { 46 + struct drm_panel base; 47 + bool prepared; 48 + bool enabled; 49 + const struct seiko_panel_desc *desc; 50 + struct backlight_device *backlight; 51 + struct regulator *dvdd; 52 + struct regulator *avdd; 53 + }; 54 + 55 + static inline struct seiko_panel *to_seiko_panel(struct drm_panel *panel) 56 + { 57 + return container_of(panel, struct seiko_panel, base); 58 + } 59 + 60 + static int seiko_panel_get_fixed_modes(struct seiko_panel *panel) 61 + { 62 + struct drm_connector *connector = panel->base.connector; 63 + struct drm_device *drm = panel->base.drm; 64 + struct drm_display_mode *mode; 65 + unsigned int i, num = 0; 66 + 67 + if (!panel->desc) 68 + return 0; 69 + 70 + for (i = 0; i < panel->desc->num_timings; i++) { 71 + const struct display_timing *dt = &panel->desc->timings[i]; 72 + struct videomode vm; 73 + 74 + videomode_from_timing(dt, &vm); 75 + mode = drm_mode_create(drm); 76 + if (!mode) { 77 + dev_err(drm->dev, "failed to add mode %ux%u\n", 78 + dt->hactive.typ, dt->vactive.typ); 79 + continue; 80 + } 81 + 82 + drm_display_mode_from_videomode(&vm, mode); 83 + 84 + mode->type |= DRM_MODE_TYPE_DRIVER; 85 + 86 + if (panel->desc->num_timings == 1) 87 + mode->type |= DRM_MODE_TYPE_PREFERRED; 88 + 89 + drm_mode_probed_add(connector, mode); 90 + num++; 91 + } 92 + 93 + for (i = 0; i < panel->desc->num_modes; i++) { 94 + const struct drm_display_mode *m = &panel->desc->modes[i]; 95 + 96 + mode = drm_mode_duplicate(drm, m); 97 + if (!mode) { 98 + dev_err(drm->dev, "failed to add mode %ux%u@%u\n", 99 + m->hdisplay, m->vdisplay, m->vrefresh); 100 + continue; 101 + } 102 + 103 + mode->type |= DRM_MODE_TYPE_DRIVER; 104 + 105 + if (panel->desc->num_modes == 1) 106 + mode->type |= DRM_MODE_TYPE_PREFERRED; 107 + 108 + drm_mode_set_name(mode); 109 + 110 + drm_mode_probed_add(connector, mode); 111 + num++; 112 + } 113 + 114 + connector->display_info.bpc = panel->desc->bpc; 115 + connector->display_info.width_mm = panel->desc->size.width; 116 + connector->display_info.height_mm = panel->desc->size.height; 117 + if (panel->desc->bus_format) 118 + drm_display_info_set_bus_formats(&connector->display_info, 119 + &panel->desc->bus_format, 1); 120 + connector->display_info.bus_flags = panel->desc->bus_flags; 121 + 122 + return num; 123 + } 124 + 125 + static int seiko_panel_disable(struct drm_panel *panel) 126 + { 127 + struct seiko_panel *p = to_seiko_panel(panel); 128 + 129 + if (!p->enabled) 130 + return 0; 131 + 132 + if (p->backlight) { 133 + p->backlight->props.power = FB_BLANK_POWERDOWN; 134 + p->backlight->props.state |= BL_CORE_FBBLANK; 135 + backlight_update_status(p->backlight); 136 + } 137 + 138 + p->enabled = false; 139 + 140 + return 0; 141 + } 142 + 143 + static int seiko_panel_unprepare(struct drm_panel *panel) 144 + { 145 + struct seiko_panel *p = to_seiko_panel(panel); 146 + 147 + if (!p->prepared) 148 + return 0; 149 + 150 + regulator_disable(p->avdd); 151 + 152 + /* Add a 100ms delay as per the panel datasheet */ 153 + msleep(100); 154 + 155 + regulator_disable(p->dvdd); 156 + 157 + p->prepared = false; 158 + 159 + return 0; 160 + } 161 + 162 + static int seiko_panel_prepare(struct drm_panel *panel) 163 + { 164 + struct seiko_panel *p = to_seiko_panel(panel); 165 + int err; 166 + 167 + if (p->prepared) 168 + return 0; 169 + 170 + err = regulator_enable(p->dvdd); 171 + if (err < 0) { 172 + dev_err(panel->dev, "failed to enable dvdd: %d\n", err); 173 + return err; 174 + } 175 + 176 + /* Add a 100ms delay as per the panel datasheet */ 177 + msleep(100); 178 + 179 + err = regulator_enable(p->avdd); 180 + if (err < 0) { 181 + dev_err(panel->dev, "failed to enable avdd: %d\n", err); 182 + goto disable_dvdd; 183 + } 184 + 185 + p->prepared = true; 186 + 187 + return 0; 188 + 189 + disable_dvdd: 190 + regulator_disable(p->dvdd); 191 + return err; 192 + } 193 + 194 + static int seiko_panel_enable(struct drm_panel *panel) 195 + { 196 + struct seiko_panel *p = to_seiko_panel(panel); 197 + 198 + if (p->enabled) 199 + return 0; 200 + 201 + if (p->backlight) { 202 + p->backlight->props.state &= ~BL_CORE_FBBLANK; 203 + p->backlight->props.power = FB_BLANK_UNBLANK; 204 + backlight_update_status(p->backlight); 205 + } 206 + 207 + p->enabled = true; 208 + 209 + return 0; 210 + } 211 + 212 + static int seiko_panel_get_modes(struct drm_panel *panel) 213 + { 214 + struct seiko_panel *p = to_seiko_panel(panel); 215 + 216 + /* add hard-coded panel modes */ 217 + return seiko_panel_get_fixed_modes(p); 218 + } 219 + 220 + static int seiko_panel_get_timings(struct drm_panel *panel, 221 + unsigned int num_timings, 222 + struct display_timing *timings) 223 + { 224 + struct seiko_panel *p = to_seiko_panel(panel); 225 + unsigned int i; 226 + 227 + if (p->desc->num_timings < num_timings) 228 + num_timings = p->desc->num_timings; 229 + 230 + if (timings) 231 + for (i = 0; i < num_timings; i++) 232 + timings[i] = p->desc->timings[i]; 233 + 234 + return p->desc->num_timings; 235 + } 236 + 237 + static const struct drm_panel_funcs seiko_panel_funcs = { 238 + .disable = seiko_panel_disable, 239 + .unprepare = seiko_panel_unprepare, 240 + .prepare = seiko_panel_prepare, 241 + .enable = seiko_panel_enable, 242 + .get_modes = seiko_panel_get_modes, 243 + .get_timings = seiko_panel_get_timings, 244 + }; 245 + 246 + static int seiko_panel_probe(struct device *dev, 247 + const struct seiko_panel_desc *desc) 248 + { 249 + struct device_node *backlight; 250 + struct seiko_panel *panel; 251 + int err; 252 + 253 + panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL); 254 + if (!panel) 255 + return -ENOMEM; 256 + 257 + panel->enabled = false; 258 + panel->prepared = false; 259 + panel->desc = desc; 260 + 261 + panel->dvdd = devm_regulator_get(dev, "dvdd"); 262 + if (IS_ERR(panel->dvdd)) 263 + return PTR_ERR(panel->dvdd); 264 + 265 + panel->avdd = devm_regulator_get(dev, "avdd"); 266 + if (IS_ERR(panel->avdd)) 267 + return PTR_ERR(panel->avdd); 268 + 269 + backlight = of_parse_phandle(dev->of_node, "backlight", 0); 270 + if (backlight) { 271 + panel->backlight = of_find_backlight_by_node(backlight); 272 + of_node_put(backlight); 273 + 274 + if (!panel->backlight) 275 + return -EPROBE_DEFER; 276 + } 277 + 278 + drm_panel_init(&panel->base); 279 + panel->base.dev = dev; 280 + panel->base.funcs = &seiko_panel_funcs; 281 + 282 + err = drm_panel_add(&panel->base); 283 + if (err < 0) 284 + return err; 285 + 286 + dev_set_drvdata(dev, panel); 287 + 288 + return 0; 289 + } 290 + 291 + static int seiko_panel_remove(struct platform_device *pdev) 292 + { 293 + struct seiko_panel *panel = dev_get_drvdata(&pdev->dev); 294 + 295 + drm_panel_detach(&panel->base); 296 + drm_panel_remove(&panel->base); 297 + 298 + seiko_panel_disable(&panel->base); 299 + 300 + if (panel->backlight) 301 + put_device(&panel->backlight->dev); 302 + 303 + return 0; 304 + } 305 + 306 + static void seiko_panel_shutdown(struct platform_device *pdev) 307 + { 308 + struct seiko_panel *panel = dev_get_drvdata(&pdev->dev); 309 + 310 + seiko_panel_disable(&panel->base); 311 + } 312 + 313 + static const struct display_timing seiko_43wvf1g_timing = { 314 + .pixelclock = { 33500000, 33500000, 33500000 }, 315 + .hactive = { 800, 800, 800 }, 316 + .hfront_porch = { 164, 164, 164 }, 317 + .hback_porch = { 89, 89, 89 }, 318 + .hsync_len = { 10, 10, 10 }, 319 + .vactive = { 480, 480, 480 }, 320 + .vfront_porch = { 10, 10, 10 }, 321 + .vback_porch = { 23, 23, 23 }, 322 + .vsync_len = { 10, 10, 10 }, 323 + .flags = DISPLAY_FLAGS_DE_LOW, 324 + }; 325 + 326 + static const struct seiko_panel_desc seiko_43wvf1g = { 327 + .timings = &seiko_43wvf1g_timing, 328 + .num_timings = 1, 329 + .bpc = 8, 330 + .size = { 331 + .width = 93, 332 + .height = 57, 333 + }, 334 + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, 335 + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_NEGEDGE, 336 + }; 337 + 338 + static const struct of_device_id platform_of_match[] = { 339 + { 340 + .compatible = "sii,43wvf1g", 341 + .data = &seiko_43wvf1g, 342 + }, { 343 + /* sentinel */ 344 + } 345 + }; 346 + MODULE_DEVICE_TABLE(of, platform_of_match); 347 + 348 + static int seiko_panel_platform_probe(struct platform_device *pdev) 349 + { 350 + const struct of_device_id *id; 351 + 352 + id = of_match_node(platform_of_match, pdev->dev.of_node); 353 + if (!id) 354 + return -ENODEV; 355 + 356 + return seiko_panel_probe(&pdev->dev, id->data); 357 + } 358 + 359 + static struct platform_driver seiko_panel_platform_driver = { 360 + .driver = { 361 + .name = "seiko_panel", 362 + .of_match_table = platform_of_match, 363 + }, 364 + .probe = seiko_panel_platform_probe, 365 + .remove = seiko_panel_remove, 366 + .shutdown = seiko_panel_shutdown, 367 + }; 368 + module_platform_driver(seiko_panel_platform_driver); 369 + 370 + MODULE_AUTHOR("Marco Franchi <marco.franchi@nxp.com"); 371 + MODULE_DESCRIPTION("Seiko 43WVF1G panel driver"); 372 + MODULE_LICENSE("GPL v2");