linux/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * S6E63M0 AMOLED LCD drm_panel driver.
   4 *
   5 * Copyright (C) 2019 Paweł Chmiel <pawel.mikolaj.chmiel@gmail.com>
   6 * Derived from drivers/gpu/drm/panel-samsung-ld9040.c
   7 *
   8 * Andrzej Hajda <a.hajda@samsung.com>
   9 */
  10
  11#include <drm/drm_modes.h>
  12#include <drm/drm_panel.h>
  13
  14#include <linux/backlight.h>
  15#include <linux/delay.h>
  16#include <linux/gpio/consumer.h>
  17#include <linux/module.h>
  18#include <linux/regulator/consumer.h>
  19
  20#include <video/mipi_display.h>
  21
  22#include "panel-samsung-s6e63m0.h"
  23
  24/* Manufacturer Command Set */
  25#define MCS_ELVSS_ON                0xb1
  26#define MCS_MIECTL1                0xc0
  27#define MCS_BCMODE                              0xc1
  28#define MCS_ERROR_CHECK         0xd5
  29#define MCS_READ_ID1            0xda
  30#define MCS_READ_ID2            0xdb
  31#define MCS_READ_ID3            0xdc
  32#define MCS_LEVEL_2_KEY         0xf0
  33#define MCS_MTP_KEY             0xf1
  34#define MCS_DISCTL   0xf2
  35#define MCS_SRCCTL           0xf6
  36#define MCS_IFCTL                       0xf7
  37#define MCS_PANELCTL         0xF8
  38#define MCS_PGAMMACTL                   0xfa
  39
  40#define S6E63M0_LCD_ID_VALUE_M2         0xA4
  41#define S6E63M0_LCD_ID_VALUE_SM2        0xB4
  42#define S6E63M0_LCD_ID_VALUE_SM2_1      0xB6
  43
  44#define NUM_GAMMA_LEVELS             11
  45#define GAMMA_TABLE_COUNT           23
  46
  47#define MAX_BRIGHTNESS              (NUM_GAMMA_LEVELS - 1)
  48
  49/* array of gamma tables for gamma value 2.2 */
  50static u8 const s6e63m0_gamma_22[NUM_GAMMA_LEVELS][GAMMA_TABLE_COUNT] = {
  51        { MCS_PGAMMACTL, 0x00,
  52          0x18, 0x08, 0x24, 0x78, 0xEC, 0x3D, 0xC8,
  53          0xC2, 0xB6, 0xC4, 0xC7, 0xB6, 0xD5, 0xD7,
  54          0xCC, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51 },
  55        { MCS_PGAMMACTL, 0x00,
  56          0x18, 0x08, 0x24, 0x73, 0x4A, 0x3D, 0xC0,
  57          0xC2, 0xB1, 0xBB, 0xBE, 0xAC, 0xCE, 0xCF,
  58          0xC5, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82 },
  59        { MCS_PGAMMACTL, 0x00,
  60          0x18, 0x08, 0x24, 0x70, 0x51, 0x3E, 0xBF,
  61          0xC1, 0xAF, 0xB9, 0xBC, 0xAB, 0xCC, 0xCC,
  62          0xC2, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D },
  63        { MCS_PGAMMACTL, 0x00,
  64          0x18, 0x08, 0x24, 0x6C, 0x54, 0x3A, 0xBC,
  65          0xBF, 0xAC, 0xB7, 0xBB, 0xA9, 0xC9, 0xC9,
  66          0xBE, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E },
  67        { MCS_PGAMMACTL, 0x00,
  68          0x18, 0x08, 0x24, 0x69, 0x54, 0x37, 0xBB,
  69          0xBE, 0xAC, 0xB4, 0xB7, 0xA6, 0xC7, 0xC8,
  70          0xBC, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB },
  71        { MCS_PGAMMACTL, 0x00,
  72          0x18, 0x08, 0x24, 0x66, 0x55, 0x34, 0xBA,
  73          0xBD, 0xAB, 0xB1, 0xB5, 0xA3, 0xC5, 0xC6,
  74          0xB9, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA },
  75        { MCS_PGAMMACTL, 0x00,
  76          0x18, 0x08, 0x24, 0x63, 0x53, 0x31, 0xB8,
  77          0xBC, 0xA9, 0xB0, 0xB5, 0xA2, 0xC4, 0xC4,
  78          0xB8, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2 },
  79        { MCS_PGAMMACTL, 0x00,
  80          0x18, 0x08, 0x24, 0x62, 0x54, 0x30, 0xB9,
  81          0xBB, 0xA9, 0xB0, 0xB3, 0xA1, 0xC1, 0xC3,
  82          0xB7, 0x00, 0x91, 0x00, 0x95, 0x00, 0xDA },
  83        { MCS_PGAMMACTL, 0x00,
  84          0x18, 0x08, 0x24, 0x66, 0x58, 0x34, 0xB6,
  85          0xBA, 0xA7, 0xAF, 0xB3, 0xA0, 0xC1, 0xC2,
  86          0xB7, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1 },
  87        { MCS_PGAMMACTL, 0x00,
  88          0x18, 0x08, 0x24, 0x64, 0x56, 0x33, 0xB6,
  89          0xBA, 0xA8, 0xAC, 0xB1, 0x9D, 0xC1, 0xC1,
  90          0xB7, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6 },
  91        { MCS_PGAMMACTL, 0x00,
  92          0x18, 0x08, 0x24, 0x5f, 0x50, 0x2d, 0xB6,
  93          0xB9, 0xA7, 0xAd, 0xB1, 0x9f, 0xbe, 0xC0,
  94          0xB5, 0x00, 0xa0, 0x00, 0xa4, 0x00, 0xdb },
  95};
  96
  97struct s6e63m0 {
  98        struct device *dev;
  99        int (*dcs_read)(struct device *dev, const u8 cmd, u8 *val);
 100        int (*dcs_write)(struct device *dev, const u8 *data, size_t len);
 101        struct drm_panel panel;
 102        struct backlight_device *bl_dev;
 103        u8 lcd_type;
 104
 105        struct regulator_bulk_data supplies[2];
 106        struct gpio_desc *reset_gpio;
 107
 108        bool prepared;
 109        bool enabled;
 110
 111        /*
 112         * This field is tested by functions directly accessing bus before
 113         * transfer, transfer is skipped if it is set. In case of transfer
 114         * failure or unexpected response the field is set to error value.
 115         * Such construct allows to eliminate many checks in higher level
 116         * functions.
 117         */
 118        int error;
 119};
 120
 121static const struct drm_display_mode default_mode = {
 122        .clock          = 25628,
 123        .hdisplay       = 480,
 124        .hsync_start    = 480 + 16,
 125        .hsync_end      = 480 + 16 + 2,
 126        .htotal         = 480 + 16 + 2 + 16,
 127        .vdisplay       = 800,
 128        .vsync_start    = 800 + 28,
 129        .vsync_end      = 800 + 28 + 2,
 130        .vtotal         = 800 + 28 + 2 + 1,
 131        .width_mm       = 53,
 132        .height_mm      = 89,
 133        .flags          = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
 134};
 135
 136static inline struct s6e63m0 *panel_to_s6e63m0(struct drm_panel *panel)
 137{
 138        return container_of(panel, struct s6e63m0, panel);
 139}
 140
 141static int s6e63m0_clear_error(struct s6e63m0 *ctx)
 142{
 143        int ret = ctx->error;
 144
 145        ctx->error = 0;
 146        return ret;
 147}
 148
 149static void s6e63m0_dcs_read(struct s6e63m0 *ctx, const u8 cmd, u8 *data)
 150{
 151        if (ctx->error < 0)
 152                return;
 153
 154        ctx->error = ctx->dcs_read(ctx->dev, cmd, data);
 155}
 156
 157static void s6e63m0_dcs_write(struct s6e63m0 *ctx, const u8 *data, size_t len)
 158{
 159        if (ctx->error < 0 || len == 0)
 160                return;
 161
 162        ctx->error = ctx->dcs_write(ctx->dev, data, len);
 163}
 164
 165#define s6e63m0_dcs_write_seq_static(ctx, seq ...) \
 166        ({ \
 167                static const u8 d[] = { seq }; \
 168                s6e63m0_dcs_write(ctx, d, ARRAY_SIZE(d)); \
 169        })
 170
 171static int s6e63m0_check_lcd_type(struct s6e63m0 *ctx)
 172{
 173        u8 id1, id2, id3;
 174        int ret;
 175
 176        s6e63m0_dcs_read(ctx, MCS_READ_ID1, &id1);
 177        s6e63m0_dcs_read(ctx, MCS_READ_ID2, &id2);
 178        s6e63m0_dcs_read(ctx, MCS_READ_ID3, &id3);
 179
 180        ret = s6e63m0_clear_error(ctx);
 181        if (ret) {
 182                dev_err(ctx->dev, "error checking LCD type (%d)\n", ret);
 183                ctx->lcd_type = 0x00;
 184                return ret;
 185        }
 186
 187        dev_info(ctx->dev, "MTP ID: %02x %02x %02x\n", id1, id2, id3);
 188
 189        /* We attempt to detect what panel is mounted on the controller */
 190        switch (id2) {
 191        case S6E63M0_LCD_ID_VALUE_M2:
 192                dev_info(ctx->dev, "detected LCD panel AMS397GE MIPI M2\n");
 193                break;
 194        case S6E63M0_LCD_ID_VALUE_SM2:
 195        case S6E63M0_LCD_ID_VALUE_SM2_1:
 196                dev_info(ctx->dev, "detected LCD panel AMS397GE MIPI SM2\n");
 197                break;
 198        default:
 199                dev_info(ctx->dev, "unknown LCD panel type %02x\n", id2);
 200                break;
 201        }
 202
 203        ctx->lcd_type = id2;
 204
 205        return 0;
 206}
 207
 208static void s6e63m0_init(struct s6e63m0 *ctx)
 209{
 210        s6e63m0_dcs_write_seq_static(ctx, MCS_PANELCTL,
 211                                     0x01, 0x27, 0x27, 0x07, 0x07, 0x54, 0x9f,
 212                                     0x63, 0x86, 0x1a, 0x33, 0x0d, 0x00, 0x00);
 213
 214        s6e63m0_dcs_write_seq_static(ctx, MCS_DISCTL,
 215                                     0x02, 0x03, 0x1c, 0x10, 0x10);
 216        s6e63m0_dcs_write_seq_static(ctx, MCS_IFCTL,
 217                                     0x03, 0x00, 0x00);
 218
 219        s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL,
 220                                     0x00, 0x18, 0x08, 0x24, 0x64, 0x56, 0x33,
 221                                     0xb6, 0xba, 0xa8, 0xac, 0xb1, 0x9d, 0xc1,
 222                                     0xc1, 0xb7, 0x00, 0x9c, 0x00, 0x9f, 0x00,
 223                                     0xd6);
 224        s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL,
 225                                     0x01);
 226
 227        s6e63m0_dcs_write_seq_static(ctx, MCS_SRCCTL,
 228                                     0x00, 0x8c, 0x07);
 229        s6e63m0_dcs_write_seq_static(ctx, 0xb3,
 230                                     0xc);
 231
 232        s6e63m0_dcs_write_seq_static(ctx, 0xb5,
 233                                     0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17,
 234                                     0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b,
 235                                     0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a,
 236                                     0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23,
 237                                     0x21, 0x20, 0x1e, 0x1e);
 238
 239        s6e63m0_dcs_write_seq_static(ctx, 0xb6,
 240                                     0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x44,
 241                                     0x44, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66,
 242                                     0x66, 0x66);
 243
 244        s6e63m0_dcs_write_seq_static(ctx, 0xb7,
 245                                     0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17,
 246                                     0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b,
 247                                     0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a,
 248                                     0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23,
 249                                     0x21, 0x20, 0x1e, 0x1e, 0x00, 0x00, 0x11,
 250                                     0x22, 0x33, 0x44, 0x44, 0x44, 0x55, 0x55,
 251                                     0x66, 0x66, 0x66, 0x66, 0x66, 0x66);
 252
 253        s6e63m0_dcs_write_seq_static(ctx, 0xb9,
 254                                     0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17,
 255                                     0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b,
 256                                     0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a,
 257                                     0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23,
 258                                     0x21, 0x20, 0x1e, 0x1e);
 259
 260        s6e63m0_dcs_write_seq_static(ctx, 0xba,
 261                                     0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x44,
 262                                     0x44, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66,
 263                                     0x66, 0x66);
 264
 265        s6e63m0_dcs_write_seq_static(ctx, MCS_BCMODE,
 266                                     0x4d, 0x96, 0x1d, 0x00, 0x00, 0x01, 0xdf,
 267                                     0x00, 0x00, 0x03, 0x1f, 0x00, 0x00, 0x00,
 268                                     0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06,
 269                                     0x09, 0x0d, 0x0f, 0x12, 0x15, 0x18);
 270
 271        s6e63m0_dcs_write_seq_static(ctx, 0xb2,
 272                                     0x10, 0x10, 0x0b, 0x05);
 273
 274        s6e63m0_dcs_write_seq_static(ctx, MCS_MIECTL1,
 275                                     0x01);
 276
 277        s6e63m0_dcs_write_seq_static(ctx, MCS_ELVSS_ON,
 278                                     0x0b);
 279}
 280
 281static int s6e63m0_power_on(struct s6e63m0 *ctx)
 282{
 283        int ret;
 284
 285        ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
 286        if (ret < 0)
 287                return ret;
 288
 289        msleep(25);
 290
 291        /* Be sure to send a reset pulse */
 292        gpiod_set_value(ctx->reset_gpio, 1);
 293        msleep(5);
 294        gpiod_set_value(ctx->reset_gpio, 0);
 295        msleep(120);
 296
 297        return 0;
 298}
 299
 300static int s6e63m0_power_off(struct s6e63m0 *ctx)
 301{
 302        int ret;
 303
 304        gpiod_set_value(ctx->reset_gpio, 1);
 305        msleep(120);
 306
 307        ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
 308        if (ret < 0)
 309                return ret;
 310
 311        return 0;
 312}
 313
 314static int s6e63m0_disable(struct drm_panel *panel)
 315{
 316        struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
 317
 318        if (!ctx->enabled)
 319                return 0;
 320
 321        backlight_disable(ctx->bl_dev);
 322
 323        s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF);
 324        msleep(10);
 325        s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
 326        msleep(120);
 327
 328        ctx->enabled = false;
 329
 330        return 0;
 331}
 332
 333static int s6e63m0_unprepare(struct drm_panel *panel)
 334{
 335        struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
 336        int ret;
 337
 338        if (!ctx->prepared)
 339                return 0;
 340
 341        s6e63m0_clear_error(ctx);
 342
 343        ret = s6e63m0_power_off(ctx);
 344        if (ret < 0)
 345                return ret;
 346
 347        ctx->prepared = false;
 348
 349        return 0;
 350}
 351
 352static int s6e63m0_prepare(struct drm_panel *panel)
 353{
 354        struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
 355        int ret;
 356
 357        if (ctx->prepared)
 358                return 0;
 359
 360        ret = s6e63m0_power_on(ctx);
 361        if (ret < 0)
 362                return ret;
 363
 364        /* Magic to unlock level 2 control of the display */
 365        s6e63m0_dcs_write_seq_static(ctx, MCS_LEVEL_2_KEY, 0x5a, 0x5a);
 366        /* Magic to unlock MTP reading */
 367        s6e63m0_dcs_write_seq_static(ctx, MCS_MTP_KEY, 0x5a, 0x5a);
 368
 369        ret = s6e63m0_check_lcd_type(ctx);
 370        if (ret < 0)
 371                return ret;
 372
 373        s6e63m0_init(ctx);
 374
 375        ret = s6e63m0_clear_error(ctx);
 376
 377        if (ret < 0)
 378                s6e63m0_unprepare(panel);
 379
 380        ctx->prepared = true;
 381
 382        return ret;
 383}
 384
 385static int s6e63m0_enable(struct drm_panel *panel)
 386{
 387        struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
 388
 389        if (ctx->enabled)
 390                return 0;
 391
 392        s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE);
 393        msleep(120);
 394        s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON);
 395        msleep(10);
 396
 397        s6e63m0_dcs_write_seq_static(ctx, MCS_ERROR_CHECK,
 398                                     0xE7, 0x14, 0x60, 0x17, 0x0A, 0x49, 0xC3,
 399                                     0x8F, 0x19, 0x64, 0x91, 0x84, 0x76, 0x20,
 400                                     0x0F, 0x00);
 401
 402        backlight_enable(ctx->bl_dev);
 403
 404        ctx->enabled = true;
 405
 406        return 0;
 407}
 408
 409static int s6e63m0_get_modes(struct drm_panel *panel,
 410                             struct drm_connector *connector)
 411{
 412        struct drm_display_mode *mode;
 413
 414        mode = drm_mode_duplicate(connector->dev, &default_mode);
 415        if (!mode) {
 416                dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
 417                        default_mode.hdisplay, default_mode.vdisplay,
 418                        drm_mode_vrefresh(&default_mode));
 419                return -ENOMEM;
 420        }
 421
 422        drm_mode_set_name(mode);
 423
 424        mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
 425        drm_mode_probed_add(connector, mode);
 426
 427        return 1;
 428}
 429
 430static const struct drm_panel_funcs s6e63m0_drm_funcs = {
 431        .disable        = s6e63m0_disable,
 432        .unprepare      = s6e63m0_unprepare,
 433        .prepare        = s6e63m0_prepare,
 434        .enable         = s6e63m0_enable,
 435        .get_modes      = s6e63m0_get_modes,
 436};
 437
 438static int s6e63m0_set_brightness(struct backlight_device *bd)
 439{
 440        struct s6e63m0 *ctx = bl_get_data(bd);
 441
 442        int brightness = bd->props.brightness;
 443
 444        /* disable and set new gamma */
 445        s6e63m0_dcs_write(ctx, s6e63m0_gamma_22[brightness],
 446                          ARRAY_SIZE(s6e63m0_gamma_22[brightness]));
 447
 448        /* update gamma table. */
 449        s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL, 0x01);
 450
 451        return s6e63m0_clear_error(ctx);
 452}
 453
 454static const struct backlight_ops s6e63m0_backlight_ops = {
 455        .update_status  = s6e63m0_set_brightness,
 456};
 457
 458static int s6e63m0_backlight_register(struct s6e63m0 *ctx)
 459{
 460        struct backlight_properties props = {
 461                .type           = BACKLIGHT_RAW,
 462                .brightness     = MAX_BRIGHTNESS,
 463                .max_brightness = MAX_BRIGHTNESS
 464        };
 465        struct device *dev = ctx->dev;
 466        int ret = 0;
 467
 468        ctx->bl_dev = devm_backlight_device_register(dev, "panel", dev, ctx,
 469                                                     &s6e63m0_backlight_ops,
 470                                                     &props);
 471        if (IS_ERR(ctx->bl_dev)) {
 472                ret = PTR_ERR(ctx->bl_dev);
 473                dev_err(dev, "error registering backlight device (%d)\n", ret);
 474        }
 475
 476        return ret;
 477}
 478
 479int s6e63m0_probe(struct device *dev,
 480                  int (*dcs_read)(struct device *dev, const u8 cmd, u8 *val),
 481                  int (*dcs_write)(struct device *dev, const u8 *data, size_t len),
 482                  bool dsi_mode)
 483{
 484        struct s6e63m0 *ctx;
 485        int ret;
 486
 487        ctx = devm_kzalloc(dev, sizeof(struct s6e63m0), GFP_KERNEL);
 488        if (!ctx)
 489                return -ENOMEM;
 490
 491        ctx->dcs_read = dcs_read;
 492        ctx->dcs_write = dcs_write;
 493        dev_set_drvdata(dev, ctx);
 494
 495        ctx->dev = dev;
 496        ctx->enabled = false;
 497        ctx->prepared = false;
 498
 499        ctx->supplies[0].supply = "vdd3";
 500        ctx->supplies[1].supply = "vci";
 501        ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
 502                                      ctx->supplies);
 503        if (ret < 0) {
 504                dev_err(dev, "failed to get regulators: %d\n", ret);
 505                return ret;
 506        }
 507
 508        ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
 509        if (IS_ERR(ctx->reset_gpio)) {
 510                dev_err(dev, "cannot get reset-gpios %ld\n", PTR_ERR(ctx->reset_gpio));
 511                return PTR_ERR(ctx->reset_gpio);
 512        }
 513
 514        drm_panel_init(&ctx->panel, dev, &s6e63m0_drm_funcs,
 515                       dsi_mode ? DRM_MODE_CONNECTOR_DSI :
 516                       DRM_MODE_CONNECTOR_DPI);
 517
 518        ret = s6e63m0_backlight_register(ctx);
 519        if (ret < 0)
 520                return ret;
 521
 522        drm_panel_add(&ctx->panel);
 523
 524        return 0;
 525}
 526EXPORT_SYMBOL_GPL(s6e63m0_probe);
 527
 528int s6e63m0_remove(struct device *dev)
 529{
 530        struct s6e63m0 *ctx = dev_get_drvdata(dev);
 531
 532        drm_panel_remove(&ctx->panel);
 533
 534        return 0;
 535}
 536EXPORT_SYMBOL_GPL(s6e63m0_remove);
 537
 538MODULE_AUTHOR("Paweł Chmiel <pawel.mikolaj.chmiel@gmail.com>");
 539MODULE_DESCRIPTION("s6e63m0 LCD Driver");
 540MODULE_LICENSE("GPL v2");
 541