root/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. to_wuxga_nt_panel
  2. wuxga_nt_panel_on
  3. wuxga_nt_panel_disable
  4. wuxga_nt_panel_unprepare
  5. wuxga_nt_panel_prepare
  6. wuxga_nt_panel_enable
  7. wuxga_nt_panel_get_modes
  8. wuxga_nt_panel_add
  9. wuxga_nt_panel_del
  10. wuxga_nt_panel_probe
  11. wuxga_nt_panel_remove
  12. wuxga_nt_panel_shutdown

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2015 Red Hat
   4  * Copyright (C) 2015 Sony Mobile Communications Inc.
   5  * Author: Werner Johansson <werner.johansson@sonymobile.com>
   6  *
   7  * Based on AUO panel driver by Rob Clark <robdclark@gmail.com>
   8  */
   9 
  10 #include <linux/backlight.h>
  11 #include <linux/delay.h>
  12 #include <linux/module.h>
  13 #include <linux/of.h>
  14 #include <linux/regulator/consumer.h>
  15 
  16 #include <video/mipi_display.h>
  17 
  18 #include <drm/drm_crtc.h>
  19 #include <drm/drm_device.h>
  20 #include <drm/drm_mipi_dsi.h>
  21 #include <drm/drm_panel.h>
  22 
  23 /*
  24  * When power is turned off to this panel a minimum off time of 500ms has to be
  25  * observed before powering back on as there's no external reset pin. Keep
  26  * track of earliest wakeup time and delay subsequent prepare call accordingly
  27  */
  28 #define MIN_POFF_MS (500)
  29 
  30 struct wuxga_nt_panel {
  31         struct drm_panel base;
  32         struct mipi_dsi_device *dsi;
  33 
  34         struct backlight_device *backlight;
  35         struct regulator *supply;
  36 
  37         bool prepared;
  38         bool enabled;
  39 
  40         ktime_t earliest_wake;
  41 
  42         const struct drm_display_mode *mode;
  43 };
  44 
  45 static inline struct wuxga_nt_panel *to_wuxga_nt_panel(struct drm_panel *panel)
  46 {
  47         return container_of(panel, struct wuxga_nt_panel, base);
  48 }
  49 
  50 static int wuxga_nt_panel_on(struct wuxga_nt_panel *wuxga_nt)
  51 {
  52         return mipi_dsi_turn_on_peripheral(wuxga_nt->dsi);
  53 }
  54 
  55 static int wuxga_nt_panel_disable(struct drm_panel *panel)
  56 {
  57         struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
  58         int mipi_ret, bl_ret = 0;
  59 
  60         if (!wuxga_nt->enabled)
  61                 return 0;
  62 
  63         mipi_ret = mipi_dsi_shutdown_peripheral(wuxga_nt->dsi);
  64 
  65         if (wuxga_nt->backlight) {
  66                 wuxga_nt->backlight->props.power = FB_BLANK_POWERDOWN;
  67                 wuxga_nt->backlight->props.state |= BL_CORE_FBBLANK;
  68                 bl_ret = backlight_update_status(wuxga_nt->backlight);
  69         }
  70 
  71         wuxga_nt->enabled = false;
  72 
  73         return mipi_ret ? mipi_ret : bl_ret;
  74 }
  75 
  76 static int wuxga_nt_panel_unprepare(struct drm_panel *panel)
  77 {
  78         struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
  79 
  80         if (!wuxga_nt->prepared)
  81                 return 0;
  82 
  83         regulator_disable(wuxga_nt->supply);
  84         wuxga_nt->earliest_wake = ktime_add_ms(ktime_get_real(), MIN_POFF_MS);
  85         wuxga_nt->prepared = false;
  86 
  87         return 0;
  88 }
  89 
  90 static int wuxga_nt_panel_prepare(struct drm_panel *panel)
  91 {
  92         struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
  93         int ret;
  94         s64 enablewait;
  95 
  96         if (wuxga_nt->prepared)
  97                 return 0;
  98 
  99         /*
 100          * If the user re-enabled the panel before the required off-time then
 101          * we need to wait the remaining period before re-enabling regulator
 102          */
 103         enablewait = ktime_ms_delta(wuxga_nt->earliest_wake, ktime_get_real());
 104 
 105         /* Sanity check, this should never happen */
 106         if (enablewait > MIN_POFF_MS)
 107                 enablewait = MIN_POFF_MS;
 108 
 109         if (enablewait > 0)
 110                 msleep(enablewait);
 111 
 112         ret = regulator_enable(wuxga_nt->supply);
 113         if (ret < 0)
 114                 return ret;
 115 
 116         /*
 117          * A minimum delay of 250ms is required after power-up until commands
 118          * can be sent
 119          */
 120         msleep(250);
 121 
 122         ret = wuxga_nt_panel_on(wuxga_nt);
 123         if (ret < 0) {
 124                 dev_err(panel->dev, "failed to set panel on: %d\n", ret);
 125                 goto poweroff;
 126         }
 127 
 128         wuxga_nt->prepared = true;
 129 
 130         return 0;
 131 
 132 poweroff:
 133         regulator_disable(wuxga_nt->supply);
 134 
 135         return ret;
 136 }
 137 
 138 static int wuxga_nt_panel_enable(struct drm_panel *panel)
 139 {
 140         struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
 141 
 142         if (wuxga_nt->enabled)
 143                 return 0;
 144 
 145         if (wuxga_nt->backlight) {
 146                 wuxga_nt->backlight->props.power = FB_BLANK_UNBLANK;
 147                 wuxga_nt->backlight->props.state &= ~BL_CORE_FBBLANK;
 148                 backlight_update_status(wuxga_nt->backlight);
 149         }
 150 
 151         wuxga_nt->enabled = true;
 152 
 153         return 0;
 154 }
 155 
 156 static const struct drm_display_mode default_mode = {
 157         .clock = 164402,
 158         .hdisplay = 1920,
 159         .hsync_start = 1920 + 152,
 160         .hsync_end = 1920 + 152 + 52,
 161         .htotal = 1920 + 152 + 52 + 20,
 162         .vdisplay = 1200,
 163         .vsync_start = 1200 + 24,
 164         .vsync_end = 1200 + 24 + 6,
 165         .vtotal = 1200 + 24 + 6 + 48,
 166         .vrefresh = 60,
 167 };
 168 
 169 static int wuxga_nt_panel_get_modes(struct drm_panel *panel)
 170 {
 171         struct drm_display_mode *mode;
 172 
 173         mode = drm_mode_duplicate(panel->drm, &default_mode);
 174         if (!mode) {
 175                 dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
 176                                 default_mode.hdisplay, default_mode.vdisplay,
 177                                 default_mode.vrefresh);
 178                 return -ENOMEM;
 179         }
 180 
 181         drm_mode_set_name(mode);
 182 
 183         drm_mode_probed_add(panel->connector, mode);
 184 
 185         panel->connector->display_info.width_mm = 217;
 186         panel->connector->display_info.height_mm = 136;
 187 
 188         return 1;
 189 }
 190 
 191 static const struct drm_panel_funcs wuxga_nt_panel_funcs = {
 192         .disable = wuxga_nt_panel_disable,
 193         .unprepare = wuxga_nt_panel_unprepare,
 194         .prepare = wuxga_nt_panel_prepare,
 195         .enable = wuxga_nt_panel_enable,
 196         .get_modes = wuxga_nt_panel_get_modes,
 197 };
 198 
 199 static const struct of_device_id wuxga_nt_of_match[] = {
 200         { .compatible = "panasonic,vvx10f034n00", },
 201         { }
 202 };
 203 MODULE_DEVICE_TABLE(of, wuxga_nt_of_match);
 204 
 205 static int wuxga_nt_panel_add(struct wuxga_nt_panel *wuxga_nt)
 206 {
 207         struct device *dev = &wuxga_nt->dsi->dev;
 208         struct device_node *np;
 209         int ret;
 210 
 211         wuxga_nt->mode = &default_mode;
 212 
 213         wuxga_nt->supply = devm_regulator_get(dev, "power");
 214         if (IS_ERR(wuxga_nt->supply))
 215                 return PTR_ERR(wuxga_nt->supply);
 216 
 217         np = of_parse_phandle(dev->of_node, "backlight", 0);
 218         if (np) {
 219                 wuxga_nt->backlight = of_find_backlight_by_node(np);
 220                 of_node_put(np);
 221 
 222                 if (!wuxga_nt->backlight)
 223                         return -EPROBE_DEFER;
 224         }
 225 
 226         drm_panel_init(&wuxga_nt->base);
 227         wuxga_nt->base.funcs = &wuxga_nt_panel_funcs;
 228         wuxga_nt->base.dev = &wuxga_nt->dsi->dev;
 229 
 230         ret = drm_panel_add(&wuxga_nt->base);
 231         if (ret < 0)
 232                 goto put_backlight;
 233 
 234         return 0;
 235 
 236 put_backlight:
 237         if (wuxga_nt->backlight)
 238                 put_device(&wuxga_nt->backlight->dev);
 239 
 240         return ret;
 241 }
 242 
 243 static void wuxga_nt_panel_del(struct wuxga_nt_panel *wuxga_nt)
 244 {
 245         if (wuxga_nt->base.dev)
 246                 drm_panel_remove(&wuxga_nt->base);
 247 
 248         if (wuxga_nt->backlight)
 249                 put_device(&wuxga_nt->backlight->dev);
 250 }
 251 
 252 static int wuxga_nt_panel_probe(struct mipi_dsi_device *dsi)
 253 {
 254         struct wuxga_nt_panel *wuxga_nt;
 255         int ret;
 256 
 257         dsi->lanes = 4;
 258         dsi->format = MIPI_DSI_FMT_RGB888;
 259         dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
 260                         MIPI_DSI_MODE_VIDEO_HSE |
 261                         MIPI_DSI_CLOCK_NON_CONTINUOUS |
 262                         MIPI_DSI_MODE_LPM;
 263 
 264         wuxga_nt = devm_kzalloc(&dsi->dev, sizeof(*wuxga_nt), GFP_KERNEL);
 265         if (!wuxga_nt)
 266                 return -ENOMEM;
 267 
 268         mipi_dsi_set_drvdata(dsi, wuxga_nt);
 269 
 270         wuxga_nt->dsi = dsi;
 271 
 272         ret = wuxga_nt_panel_add(wuxga_nt);
 273         if (ret < 0)
 274                 return ret;
 275 
 276         return mipi_dsi_attach(dsi);
 277 }
 278 
 279 static int wuxga_nt_panel_remove(struct mipi_dsi_device *dsi)
 280 {
 281         struct wuxga_nt_panel *wuxga_nt = mipi_dsi_get_drvdata(dsi);
 282         int ret;
 283 
 284         ret = wuxga_nt_panel_disable(&wuxga_nt->base);
 285         if (ret < 0)
 286                 dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
 287 
 288         ret = mipi_dsi_detach(dsi);
 289         if (ret < 0)
 290                 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
 291 
 292         wuxga_nt_panel_del(wuxga_nt);
 293 
 294         return 0;
 295 }
 296 
 297 static void wuxga_nt_panel_shutdown(struct mipi_dsi_device *dsi)
 298 {
 299         struct wuxga_nt_panel *wuxga_nt = mipi_dsi_get_drvdata(dsi);
 300 
 301         wuxga_nt_panel_disable(&wuxga_nt->base);
 302 }
 303 
 304 static struct mipi_dsi_driver wuxga_nt_panel_driver = {
 305         .driver = {
 306                 .name = "panel-panasonic-vvx10f034n00",
 307                 .of_match_table = wuxga_nt_of_match,
 308         },
 309         .probe = wuxga_nt_panel_probe,
 310         .remove = wuxga_nt_panel_remove,
 311         .shutdown = wuxga_nt_panel_shutdown,
 312 };
 313 module_mipi_dsi_driver(wuxga_nt_panel_driver);
 314 
 315 MODULE_AUTHOR("Werner Johansson <werner.johansson@sonymobile.com>");
 316 MODULE_DESCRIPTION("Panasonic VVX10F034N00 Novatek NT1397-based WUXGA (1920x1200) video mode panel driver");
 317 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */