root/drivers/gpu/drm/panel/panel-lg-lg4573.c

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

DEFINITIONS

This source file includes following definitions.
  1. panel_to_lg4573
  2. lg4573_spi_write_u16
  3. lg4573_spi_write_u16_array
  4. lg4573_spi_write_dcs
  5. lg4573_display_on
  6. lg4573_display_off
  7. lg4573_display_mode_settings
  8. lg4573_power_settings
  9. lg4573_gamma_settings
  10. lg4573_init
  11. lg4573_power_on
  12. lg4573_disable
  13. lg4573_enable
  14. lg4573_get_modes
  15. lg4573_probe
  16. lg4573_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2015 Heiko Schocher <hs@denx.de>
   4  *
   5  * from:
   6  * drivers/gpu/drm/panel/panel-ld9040.c
   7  * ld9040 AMOLED LCD drm_panel driver.
   8  *
   9  * Copyright (c) 2014 Samsung Electronics Co., Ltd
  10  * Derived from drivers/video/backlight/ld9040.c
  11  *
  12  * Andrzej Hajda <a.hajda@samsung.com>
  13 */
  14 
  15 #include <linux/delay.h>
  16 #include <linux/gpio/consumer.h>
  17 #include <linux/module.h>
  18 #include <linux/regulator/consumer.h>
  19 #include <linux/spi/spi.h>
  20 
  21 #include <video/mipi_display.h>
  22 #include <video/of_videomode.h>
  23 #include <video/videomode.h>
  24 
  25 #include <drm/drm_device.h>
  26 #include <drm/drm_modes.h>
  27 #include <drm/drm_panel.h>
  28 
  29 struct lg4573 {
  30         struct drm_panel panel;
  31         struct spi_device *spi;
  32         struct videomode vm;
  33 };
  34 
  35 static inline struct lg4573 *panel_to_lg4573(struct drm_panel *panel)
  36 {
  37         return container_of(panel, struct lg4573, panel);
  38 }
  39 
  40 static int lg4573_spi_write_u16(struct lg4573 *ctx, u16 data)
  41 {
  42         struct spi_transfer xfer = {
  43                 .len = 2,
  44         };
  45         u16 temp = cpu_to_be16(data);
  46         struct spi_message msg;
  47 
  48         dev_dbg(ctx->panel.dev, "writing data: %x\n", data);
  49         xfer.tx_buf = &temp;
  50         spi_message_init(&msg);
  51         spi_message_add_tail(&xfer, &msg);
  52 
  53         return spi_sync(ctx->spi, &msg);
  54 }
  55 
  56 static int lg4573_spi_write_u16_array(struct lg4573 *ctx, const u16 *buffer,
  57                                       unsigned int count)
  58 {
  59         unsigned int i;
  60         int ret;
  61 
  62         for (i = 0; i < count; i++) {
  63                 ret = lg4573_spi_write_u16(ctx, buffer[i]);
  64                 if (ret)
  65                         return ret;
  66         }
  67 
  68         return 0;
  69 }
  70 
  71 static int lg4573_spi_write_dcs(struct lg4573 *ctx, u8 dcs)
  72 {
  73         return lg4573_spi_write_u16(ctx, (0x70 << 8 | dcs));
  74 }
  75 
  76 static int lg4573_display_on(struct lg4573 *ctx)
  77 {
  78         int ret;
  79 
  80         ret = lg4573_spi_write_dcs(ctx, MIPI_DCS_EXIT_SLEEP_MODE);
  81         if (ret)
  82                 return ret;
  83 
  84         msleep(5);
  85 
  86         return lg4573_spi_write_dcs(ctx, MIPI_DCS_SET_DISPLAY_ON);
  87 }
  88 
  89 static int lg4573_display_off(struct lg4573 *ctx)
  90 {
  91         int ret;
  92 
  93         ret = lg4573_spi_write_dcs(ctx, MIPI_DCS_SET_DISPLAY_OFF);
  94         if (ret)
  95                 return ret;
  96 
  97         msleep(120);
  98 
  99         return lg4573_spi_write_dcs(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
 100 }
 101 
 102 static int lg4573_display_mode_settings(struct lg4573 *ctx)
 103 {
 104         static const u16 display_mode_settings[] = {
 105                 0x703A, 0x7270, 0x70B1, 0x7208,
 106                 0x723B, 0x720F, 0x70B2, 0x7200,
 107                 0x72C8, 0x70B3, 0x7200, 0x70B4,
 108                 0x7200, 0x70B5, 0x7242, 0x7210,
 109                 0x7210, 0x7200, 0x7220, 0x70B6,
 110                 0x720B, 0x720F, 0x723C, 0x7213,
 111                 0x7213, 0x72E8, 0x70B7, 0x7246,
 112                 0x7206, 0x720C, 0x7200, 0x7200,
 113         };
 114 
 115         dev_dbg(ctx->panel.dev, "transfer display mode settings\n");
 116         return lg4573_spi_write_u16_array(ctx, display_mode_settings,
 117                                           ARRAY_SIZE(display_mode_settings));
 118 }
 119 
 120 static int lg4573_power_settings(struct lg4573 *ctx)
 121 {
 122         static const u16 power_settings[] = {
 123                 0x70C0, 0x7201, 0x7211, 0x70C3,
 124                 0x7207, 0x7203, 0x7204, 0x7204,
 125                 0x7204, 0x70C4, 0x7212, 0x7224,
 126                 0x7218, 0x7218, 0x7202, 0x7249,
 127                 0x70C5, 0x726F, 0x70C6, 0x7241,
 128                 0x7263,
 129         };
 130 
 131         dev_dbg(ctx->panel.dev, "transfer power settings\n");
 132         return lg4573_spi_write_u16_array(ctx, power_settings,
 133                                           ARRAY_SIZE(power_settings));
 134 }
 135 
 136 static int lg4573_gamma_settings(struct lg4573 *ctx)
 137 {
 138         static const u16 gamma_settings[] = {
 139                 0x70D0, 0x7203, 0x7207, 0x7273,
 140                 0x7235, 0x7200, 0x7201, 0x7220,
 141                 0x7200, 0x7203, 0x70D1, 0x7203,
 142                 0x7207, 0x7273, 0x7235, 0x7200,
 143                 0x7201, 0x7220, 0x7200, 0x7203,
 144                 0x70D2, 0x7203, 0x7207, 0x7273,
 145                 0x7235, 0x7200, 0x7201, 0x7220,
 146                 0x7200, 0x7203, 0x70D3, 0x7203,
 147                 0x7207, 0x7273, 0x7235, 0x7200,
 148                 0x7201, 0x7220, 0x7200, 0x7203,
 149                 0x70D4, 0x7203, 0x7207, 0x7273,
 150                 0x7235, 0x7200, 0x7201, 0x7220,
 151                 0x7200, 0x7203, 0x70D5, 0x7203,
 152                 0x7207, 0x7273, 0x7235, 0x7200,
 153                 0x7201, 0x7220, 0x7200, 0x7203,
 154         };
 155 
 156         dev_dbg(ctx->panel.dev, "transfer gamma settings\n");
 157         return lg4573_spi_write_u16_array(ctx, gamma_settings,
 158                                           ARRAY_SIZE(gamma_settings));
 159 }
 160 
 161 static int lg4573_init(struct lg4573 *ctx)
 162 {
 163         int ret;
 164 
 165         dev_dbg(ctx->panel.dev, "initializing LCD\n");
 166 
 167         ret = lg4573_display_mode_settings(ctx);
 168         if (ret)
 169                 return ret;
 170 
 171         ret = lg4573_power_settings(ctx);
 172         if (ret)
 173                 return ret;
 174 
 175         return lg4573_gamma_settings(ctx);
 176 }
 177 
 178 static int lg4573_power_on(struct lg4573 *ctx)
 179 {
 180         return lg4573_display_on(ctx);
 181 }
 182 
 183 static int lg4573_disable(struct drm_panel *panel)
 184 {
 185         struct lg4573 *ctx = panel_to_lg4573(panel);
 186 
 187         return lg4573_display_off(ctx);
 188 }
 189 
 190 static int lg4573_enable(struct drm_panel *panel)
 191 {
 192         struct lg4573 *ctx = panel_to_lg4573(panel);
 193 
 194         lg4573_init(ctx);
 195 
 196         return lg4573_power_on(ctx);
 197 }
 198 
 199 static const struct drm_display_mode default_mode = {
 200         .clock = 27000,
 201         .hdisplay = 480,
 202         .hsync_start = 480 + 10,
 203         .hsync_end = 480 + 10 + 59,
 204         .htotal = 480 + 10 + 59 + 10,
 205         .vdisplay = 800,
 206         .vsync_start = 800 + 15,
 207         .vsync_end = 800 + 15 + 15,
 208         .vtotal = 800 + 15 + 15 + 15,
 209         .vrefresh = 60,
 210 };
 211 
 212 static int lg4573_get_modes(struct drm_panel *panel)
 213 {
 214         struct drm_connector *connector = panel->connector;
 215         struct drm_display_mode *mode;
 216 
 217         mode = drm_mode_duplicate(panel->drm, &default_mode);
 218         if (!mode) {
 219                 dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
 220                         default_mode.hdisplay, default_mode.vdisplay,
 221                         default_mode.vrefresh);
 222                 return -ENOMEM;
 223         }
 224 
 225         drm_mode_set_name(mode);
 226 
 227         mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
 228         drm_mode_probed_add(connector, mode);
 229 
 230         panel->connector->display_info.width_mm = 61;
 231         panel->connector->display_info.height_mm = 103;
 232 
 233         return 1;
 234 }
 235 
 236 static const struct drm_panel_funcs lg4573_drm_funcs = {
 237         .disable = lg4573_disable,
 238         .enable = lg4573_enable,
 239         .get_modes = lg4573_get_modes,
 240 };
 241 
 242 static int lg4573_probe(struct spi_device *spi)
 243 {
 244         struct lg4573 *ctx;
 245         int ret;
 246 
 247         ctx = devm_kzalloc(&spi->dev, sizeof(*ctx), GFP_KERNEL);
 248         if (!ctx)
 249                 return -ENOMEM;
 250 
 251         ctx->spi = spi;
 252 
 253         spi_set_drvdata(spi, ctx);
 254         spi->bits_per_word = 8;
 255 
 256         ret = spi_setup(spi);
 257         if (ret < 0) {
 258                 dev_err(&spi->dev, "SPI setup failed: %d\n", ret);
 259                 return ret;
 260         }
 261 
 262         drm_panel_init(&ctx->panel);
 263         ctx->panel.dev = &spi->dev;
 264         ctx->panel.funcs = &lg4573_drm_funcs;
 265 
 266         return drm_panel_add(&ctx->panel);
 267 }
 268 
 269 static int lg4573_remove(struct spi_device *spi)
 270 {
 271         struct lg4573 *ctx = spi_get_drvdata(spi);
 272 
 273         lg4573_display_off(ctx);
 274         drm_panel_remove(&ctx->panel);
 275 
 276         return 0;
 277 }
 278 
 279 static const struct of_device_id lg4573_of_match[] = {
 280         { .compatible = "lg,lg4573" },
 281         { }
 282 };
 283 MODULE_DEVICE_TABLE(of, lg4573_of_match);
 284 
 285 static struct spi_driver lg4573_driver = {
 286         .probe = lg4573_probe,
 287         .remove = lg4573_remove,
 288         .driver = {
 289                 .name = "lg4573",
 290                 .of_match_table = lg4573_of_match,
 291         },
 292 };
 293 module_spi_driver(lg4573_driver);
 294 
 295 MODULE_AUTHOR("Heiko Schocher <hs@denx.de>");
 296 MODULE_DESCRIPTION("lg4573 LCD Driver");
 297 MODULE_LICENSE("GPL v2");

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