linux/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
<<
>>
Prefs
   1/*
   2 * MIPI-DSI based s6e3ha2 AMOLED 5.7 inch panel driver.
   3 *
   4 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
   5 * Donghwa Lee <dh09.lee@samsung.com>
   6 * Hyungwon Hwang <human.hwang@samsung.com>
   7 * Hoegeun Kwon <hoegeun.kwon@samsung.com>
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2 as
  11 * published by the Free Software Foundation.
  12 */
  13
  14#include <drm/drmP.h>
  15#include <drm/drm_mipi_dsi.h>
  16#include <drm/drm_panel.h>
  17#include <linux/backlight.h>
  18#include <linux/gpio/consumer.h>
  19#include <linux/of_device.h>
  20#include <linux/regulator/consumer.h>
  21
  22#define S6E3HA2_MIN_BRIGHTNESS          0
  23#define S6E3HA2_MAX_BRIGHTNESS          100
  24#define S6E3HA2_DEFAULT_BRIGHTNESS      80
  25
  26#define S6E3HA2_NUM_GAMMA_STEPS         46
  27#define S6E3HA2_GAMMA_CMD_CNT           35
  28#define S6E3HA2_VINT_STATUS_MAX         10
  29
  30static const u8 gamma_tbl[S6E3HA2_NUM_GAMMA_STEPS][S6E3HA2_GAMMA_CMD_CNT] = {
  31        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x82, 0x83,
  32          0x85, 0x88, 0x8b, 0x8b, 0x84, 0x88, 0x82, 0x82, 0x89, 0x86, 0x8c,
  33          0x94, 0x84, 0xb1, 0xaf, 0x8e, 0xcf, 0xad, 0xc9, 0x00, 0x00, 0x00,
  34          0x00, 0x00 },
  35        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x84, 0x84,
  36          0x85, 0x87, 0x8b, 0x8a, 0x84, 0x88, 0x82, 0x82, 0x89, 0x86, 0x8a,
  37          0x93, 0x84, 0xb0, 0xae, 0x8e, 0xc9, 0xa8, 0xc5, 0x00, 0x00, 0x00,
  38          0x00, 0x00 },
  39        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
  40          0x85, 0x86, 0x8a, 0x8a, 0x84, 0x88, 0x81, 0x84, 0x8a, 0x88, 0x8a,
  41          0x91, 0x84, 0xb1, 0xae, 0x8b, 0xd5, 0xb2, 0xcc, 0x00, 0x00, 0x00,
  42          0x00, 0x00 },
  43        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
  44          0x85, 0x86, 0x8a, 0x8a, 0x84, 0x87, 0x81, 0x84, 0x8a, 0x87, 0x8a,
  45          0x91, 0x85, 0xae, 0xac, 0x8a, 0xc3, 0xa3, 0xc0, 0x00, 0x00, 0x00,
  46          0x00, 0x00 },
  47        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x85, 0x85,
  48          0x86, 0x85, 0x88, 0x89, 0x84, 0x89, 0x82, 0x84, 0x87, 0x85, 0x8b,
  49          0x91, 0x88, 0xad, 0xab, 0x8a, 0xb7, 0x9b, 0xb6, 0x00, 0x00, 0x00,
  50          0x00, 0x00 },
  51        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
  52          0x85, 0x86, 0x89, 0x8a, 0x84, 0x89, 0x83, 0x83, 0x86, 0x84, 0x8b,
  53          0x90, 0x84, 0xb0, 0xae, 0x8b, 0xce, 0xad, 0xc8, 0x00, 0x00, 0x00,
  54          0x00, 0x00 },
  55        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
  56          0x85, 0x87, 0x89, 0x8a, 0x83, 0x87, 0x82, 0x85, 0x88, 0x87, 0x89,
  57          0x8f, 0x84, 0xac, 0xaa, 0x89, 0xb1, 0x98, 0xaf, 0x00, 0x00, 0x00,
  58          0x00, 0x00 },
  59        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
  60          0x85, 0x86, 0x88, 0x89, 0x84, 0x88, 0x83, 0x82, 0x85, 0x84, 0x8c,
  61          0x91, 0x86, 0xac, 0xaa, 0x89, 0xc2, 0xa5, 0xbd, 0x00, 0x00, 0x00,
  62          0x00, 0x00 },
  63        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
  64          0x85, 0x87, 0x89, 0x8a, 0x83, 0x87, 0x82, 0x85, 0x88, 0x87, 0x88,
  65          0x8b, 0x82, 0xad, 0xaa, 0x8a, 0xc2, 0xa5, 0xbd, 0x00, 0x00, 0x00,
  66          0x00, 0x00 },
  67        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
  68          0x85, 0x86, 0x87, 0x89, 0x84, 0x88, 0x83, 0x82, 0x85, 0x84, 0x8a,
  69          0x8e, 0x84, 0xae, 0xac, 0x89, 0xda, 0xb7, 0xd0, 0x00, 0x00, 0x00,
  70          0x00, 0x00 },
  71        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
  72          0x85, 0x86, 0x87, 0x89, 0x84, 0x88, 0x83, 0x80, 0x83, 0x82, 0x8b,
  73          0x8e, 0x85, 0xac, 0xaa, 0x89, 0xc8, 0xaa, 0xc1, 0x00, 0x00, 0x00,
  74          0x00, 0x00 },
  75        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
  76          0x85, 0x86, 0x87, 0x89, 0x81, 0x85, 0x81, 0x84, 0x86, 0x84, 0x8c,
  77          0x8c, 0x84, 0xa9, 0xa8, 0x87, 0xa3, 0x92, 0xa1, 0x00, 0x00, 0x00,
  78          0x00, 0x00 },
  79        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
  80          0x85, 0x86, 0x87, 0x89, 0x84, 0x86, 0x83, 0x80, 0x83, 0x81, 0x8c,
  81          0x8d, 0x84, 0xaa, 0xaa, 0x89, 0xce, 0xaf, 0xc5, 0x00, 0x00, 0x00,
  82          0x00, 0x00 },
  83        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
  84          0x85, 0x86, 0x87, 0x89, 0x81, 0x83, 0x80, 0x83, 0x85, 0x85, 0x8c,
  85          0x8c, 0x84, 0xa8, 0xa8, 0x88, 0xb5, 0x9f, 0xb0, 0x00, 0x00, 0x00,
  86          0x00, 0x00 },
  87        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
  88          0x86, 0x86, 0x87, 0x88, 0x81, 0x83, 0x80, 0x83, 0x85, 0x85, 0x8c,
  89          0x8b, 0x84, 0xab, 0xa8, 0x86, 0xd4, 0xb4, 0xc9, 0x00, 0x00, 0x00,
  90          0x00, 0x00 },
  91        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
  92          0x86, 0x86, 0x87, 0x88, 0x81, 0x83, 0x80, 0x84, 0x84, 0x85, 0x8b,
  93          0x8a, 0x83, 0xa6, 0xa5, 0x84, 0xbb, 0xa4, 0xb3, 0x00, 0x00, 0x00,
  94          0x00, 0x00 },
  95        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
  96          0x86, 0x85, 0x86, 0x86, 0x82, 0x85, 0x81, 0x82, 0x83, 0x84, 0x8e,
  97          0x8b, 0x83, 0xa4, 0xa3, 0x8a, 0xa1, 0x93, 0x9d, 0x00, 0x00, 0x00,
  98          0x00, 0x00 },
  99        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83,
 100          0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x82, 0x82, 0x84, 0x8e,
 101          0x8b, 0x83, 0xa4, 0xa2, 0x86, 0xc1, 0xa9, 0xb7, 0x00, 0x00, 0x00,
 102          0x00, 0x00 },
 103        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83,
 104          0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x82, 0x82, 0x84, 0x8d,
 105          0x89, 0x82, 0xa2, 0xa1, 0x84, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00,
 106          0x00, 0x00 },
 107        { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83,
 108          0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x83, 0x83, 0x85, 0x8c,
 109          0x87, 0x7f, 0xa2, 0x9d, 0x88, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
 110          0x00, 0x00 },
 111        { 0x00, 0xbb, 0x00, 0xc5, 0x00, 0xb4, 0x87, 0x86, 0x86, 0x84, 0x83,
 112          0x86, 0x87, 0x87, 0x87, 0x80, 0x82, 0x7f, 0x86, 0x86, 0x88, 0x8a,
 113          0x84, 0x7e, 0x9d, 0x9c, 0x82, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
 114          0x00, 0x00 },
 115        { 0x00, 0xbd, 0x00, 0xc7, 0x00, 0xb7, 0x87, 0x85, 0x85, 0x84, 0x83,
 116          0x86, 0x86, 0x86, 0x88, 0x81, 0x83, 0x80, 0x83, 0x84, 0x85, 0x8a,
 117          0x85, 0x7e, 0x9c, 0x9b, 0x85, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
 118          0x00, 0x00 },
 119        { 0x00, 0xc0, 0x00, 0xca, 0x00, 0xbb, 0x87, 0x86, 0x85, 0x83, 0x83,
 120          0x85, 0x86, 0x86, 0x88, 0x81, 0x83, 0x80, 0x84, 0x85, 0x86, 0x89,
 121          0x83, 0x7d, 0x9c, 0x99, 0x87, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00,
 122          0x00, 0x00 },
 123        { 0x00, 0xc4, 0x00, 0xcd, 0x00, 0xbe, 0x87, 0x86, 0x85, 0x83, 0x83,
 124          0x86, 0x85, 0x85, 0x87, 0x81, 0x82, 0x80, 0x82, 0x82, 0x83, 0x8a,
 125          0x85, 0x7f, 0x9f, 0x9b, 0x86, 0xb4, 0xa1, 0xac, 0x00, 0x00, 0x00,
 126          0x00, 0x00 },
 127        { 0x00, 0xc7, 0x00, 0xd0, 0x00, 0xc2, 0x87, 0x85, 0x85, 0x83, 0x82,
 128          0x85, 0x85, 0x85, 0x86, 0x82, 0x83, 0x80, 0x82, 0x82, 0x84, 0x87,
 129          0x86, 0x80, 0x9e, 0x9a, 0x87, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00,
 130          0x00, 0x00 },
 131        { 0x00, 0xca, 0x00, 0xd2, 0x00, 0xc5, 0x87, 0x85, 0x84, 0x82, 0x82,
 132          0x84, 0x85, 0x85, 0x86, 0x81, 0x82, 0x7f, 0x82, 0x82, 0x84, 0x88,
 133          0x86, 0x81, 0x9d, 0x98, 0x86, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
 134          0x00, 0x00 },
 135        { 0x00, 0xce, 0x00, 0xd6, 0x00, 0xca, 0x86, 0x85, 0x84, 0x83, 0x83,
 136          0x85, 0x84, 0x84, 0x85, 0x81, 0x82, 0x80, 0x81, 0x81, 0x82, 0x89,
 137          0x86, 0x81, 0x9c, 0x97, 0x86, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00,
 138          0x00, 0x00 },
 139        { 0x00, 0xd1, 0x00, 0xd9, 0x00, 0xce, 0x86, 0x84, 0x83, 0x83, 0x82,
 140          0x85, 0x85, 0x85, 0x86, 0x81, 0x83, 0x81, 0x82, 0x82, 0x83, 0x86,
 141          0x83, 0x7f, 0x99, 0x95, 0x86, 0xbb, 0xa4, 0xb3, 0x00, 0x00, 0x00,
 142          0x00, 0x00 },
 143        { 0x00, 0xd4, 0x00, 0xdb, 0x00, 0xd1, 0x86, 0x85, 0x83, 0x83, 0x82,
 144          0x85, 0x84, 0x84, 0x85, 0x80, 0x83, 0x82, 0x80, 0x80, 0x81, 0x87,
 145          0x84, 0x81, 0x98, 0x93, 0x85, 0xae, 0x9c, 0xa8, 0x00, 0x00, 0x00,
 146          0x00, 0x00 },
 147        { 0x00, 0xd8, 0x00, 0xde, 0x00, 0xd6, 0x86, 0x84, 0x83, 0x81, 0x81,
 148          0x83, 0x85, 0x85, 0x85, 0x82, 0x83, 0x81, 0x81, 0x81, 0x83, 0x86,
 149          0x84, 0x80, 0x98, 0x91, 0x85, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00,
 150          0x00, 0x00 },
 151        { 0x00, 0xdc, 0x00, 0xe2, 0x00, 0xda, 0x85, 0x84, 0x83, 0x82, 0x82,
 152          0x84, 0x84, 0x84, 0x85, 0x81, 0x82, 0x82, 0x80, 0x80, 0x81, 0x83,
 153          0x82, 0x7f, 0x99, 0x93, 0x86, 0x94, 0x8b, 0x92, 0x00, 0x00, 0x00,
 154          0x00, 0x00 },
 155        { 0x00, 0xdf, 0x00, 0xe5, 0x00, 0xde, 0x85, 0x84, 0x82, 0x82, 0x82,
 156          0x84, 0x83, 0x83, 0x84, 0x81, 0x81, 0x80, 0x83, 0x82, 0x84, 0x82,
 157          0x81, 0x7f, 0x99, 0x92, 0x86, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00,
 158          0x00, 0x00 },
 159        { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
 160          0x82, 0x83, 0x83, 0x84, 0x80, 0x81, 0x80, 0x83, 0x83, 0x84, 0x80,
 161          0x81, 0x7c, 0x99, 0x92, 0x87, 0xa1, 0x93, 0x9d, 0x00, 0x00, 0x00,
 162          0x00, 0x00 },
 163        { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x85, 0x84, 0x83, 0x81, 0x81,
 164          0x82, 0x82, 0x82, 0x83, 0x80, 0x81, 0x80, 0x81, 0x80, 0x82, 0x83,
 165          0x82, 0x80, 0x91, 0x8d, 0x83, 0x9a, 0x90, 0x96, 0x00, 0x00, 0x00,
 166          0x00, 0x00 },
 167        { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
 168          0x82, 0x83, 0x83, 0x84, 0x80, 0x81, 0x80, 0x81, 0x80, 0x82, 0x83,
 169          0x81, 0x7f, 0x91, 0x8c, 0x82, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
 170          0x00, 0x00 },
 171        { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
 172          0x82, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x80, 0x82, 0x82,
 173          0x82, 0x7f, 0x94, 0x89, 0x84, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
 174          0x00, 0x00 },
 175        { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
 176          0x82, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x80, 0x82, 0x83,
 177          0x82, 0x7f, 0x91, 0x85, 0x81, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
 178          0x00, 0x00 },
 179        { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
 180          0x82, 0x83, 0x83, 0x83, 0x80, 0x80, 0x7f, 0x83, 0x82, 0x84, 0x83,
 181          0x82, 0x7f, 0x90, 0x84, 0x81, 0x9a, 0x90, 0x96, 0x00, 0x00, 0x00,
 182          0x00, 0x00 },
 183        { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x80, 0x80,
 184          0x82, 0x83, 0x83, 0x83, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x81, 0x81,
 185          0x82, 0x83, 0x7e, 0x80, 0x7c, 0xa4, 0x97, 0x9f, 0x00, 0x00, 0x00,
 186          0x00, 0x00 },
 187        { 0x00, 0xe9, 0x00, 0xec, 0x00, 0xe8, 0x84, 0x83, 0x82, 0x81, 0x81,
 188          0x82, 0x82, 0x82, 0x83, 0x7f, 0x7f, 0x7f, 0x81, 0x80, 0x82, 0x83,
 189          0x83, 0x84, 0x79, 0x7c, 0x79, 0xb1, 0xa0, 0xaa, 0x00, 0x00, 0x00,
 190          0x00, 0x00 },
 191        { 0x00, 0xed, 0x00, 0xf0, 0x00, 0xec, 0x83, 0x83, 0x82, 0x80, 0x80,
 192          0x81, 0x82, 0x82, 0x82, 0x7f, 0x7f, 0x7e, 0x81, 0x81, 0x82, 0x80,
 193          0x81, 0x81, 0x84, 0x84, 0x83, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
 194          0x00, 0x00 },
 195        { 0x00, 0xf1, 0x00, 0xf4, 0x00, 0xf1, 0x83, 0x82, 0x82, 0x80, 0x80,
 196          0x81, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x7d,
 197          0x7e, 0x7f, 0x84, 0x84, 0x83, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
 198          0x00, 0x00 },
 199        { 0x00, 0xf6, 0x00, 0xf7, 0x00, 0xf5, 0x82, 0x82, 0x81, 0x80, 0x80,
 200          0x80, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x82,
 201          0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
 202          0x00, 0x00 },
 203        { 0x00, 0xfa, 0x00, 0xfb, 0x00, 0xfa, 0x81, 0x81, 0x81, 0x80, 0x80,
 204          0x80, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
 205          0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
 206          0x00, 0x00 },
 207        { 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80,
 208          0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
 209          0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
 210          0x00, 0x00 },
 211        { 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80,
 212          0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
 213          0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
 214          0x00, 0x00 }
 215};
 216
 217unsigned char vint_table[S6E3HA2_VINT_STATUS_MAX] = {
 218        0x18, 0x19, 0x1a, 0x1b, 0x1c,
 219        0x1d, 0x1e, 0x1f, 0x20, 0x21
 220};
 221
 222enum s6e3ha2_type {
 223        HA2_TYPE,
 224        HF2_TYPE,
 225};
 226
 227struct s6e3ha2_panel_desc {
 228        const struct drm_display_mode *mode;
 229        enum s6e3ha2_type type;
 230};
 231
 232struct s6e3ha2 {
 233        struct device *dev;
 234        struct drm_panel panel;
 235        struct backlight_device *bl_dev;
 236
 237        struct regulator_bulk_data supplies[2];
 238        struct gpio_desc *reset_gpio;
 239        struct gpio_desc *enable_gpio;
 240
 241        const struct s6e3ha2_panel_desc *desc;
 242};
 243
 244static int s6e3ha2_dcs_write(struct s6e3ha2 *ctx, const void *data, size_t len)
 245{
 246        struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 247
 248        return mipi_dsi_dcs_write_buffer(dsi, data, len);
 249}
 250
 251#define s6e3ha2_dcs_write_seq_static(ctx, seq...) do {  \
 252        static const u8 d[] = { seq };                  \
 253        int ret;                                        \
 254        ret = s6e3ha2_dcs_write(ctx, d, ARRAY_SIZE(d)); \
 255        if (ret < 0)                                    \
 256                return ret;                             \
 257} while (0)
 258
 259#define s6e3ha2_call_write_func(ret, func) do { \
 260        ret = (func);                           \
 261        if (ret < 0)                            \
 262                return ret;                     \
 263} while (0)
 264
 265static int s6e3ha2_test_key_on_f0(struct s6e3ha2 *ctx)
 266{
 267        s6e3ha2_dcs_write_seq_static(ctx, 0xf0, 0x5a, 0x5a);
 268        return 0;
 269}
 270
 271static int s6e3ha2_test_key_off_f0(struct s6e3ha2 *ctx)
 272{
 273        s6e3ha2_dcs_write_seq_static(ctx, 0xf0, 0xa5, 0xa5);
 274        return 0;
 275}
 276
 277static int s6e3ha2_test_key_on_fc(struct s6e3ha2 *ctx)
 278{
 279        s6e3ha2_dcs_write_seq_static(ctx, 0xfc, 0x5a, 0x5a);
 280        return 0;
 281}
 282
 283static int s6e3ha2_test_key_off_fc(struct s6e3ha2 *ctx)
 284{
 285        s6e3ha2_dcs_write_seq_static(ctx, 0xfc, 0xa5, 0xa5);
 286        return 0;
 287}
 288
 289static int s6e3ha2_single_dsi_set(struct s6e3ha2 *ctx)
 290{
 291        s6e3ha2_dcs_write_seq_static(ctx, 0xf2, 0x67);
 292        s6e3ha2_dcs_write_seq_static(ctx, 0xf9, 0x09);
 293        return 0;
 294}
 295
 296static int s6e3ha2_freq_calibration(struct s6e3ha2 *ctx)
 297{
 298        s6e3ha2_dcs_write_seq_static(ctx, 0xfd, 0x1c);
 299        if (ctx->desc->type == HF2_TYPE)
 300                s6e3ha2_dcs_write_seq_static(ctx, 0xf2, 0x67, 0x40, 0xc5);
 301        s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x20, 0x39);
 302        s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0xa0);
 303        s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x20);
 304
 305        if (ctx->desc->type == HA2_TYPE)
 306                s6e3ha2_dcs_write_seq_static(ctx, 0xce, 0x03, 0x3b, 0x12, 0x62,
 307                                                  0x40, 0x80, 0xc0, 0x28, 0x28,
 308                                                  0x28, 0x28, 0x39, 0xc5);
 309        else
 310                s6e3ha2_dcs_write_seq_static(ctx, 0xce, 0x03, 0x3b, 0x14, 0x6d,
 311                                                  0x40, 0x80, 0xc0, 0x28, 0x28,
 312                                                  0x28, 0x28, 0x39, 0xc5);
 313
 314        return 0;
 315}
 316
 317static int s6e3ha2_aor_control(struct s6e3ha2 *ctx)
 318{
 319        s6e3ha2_dcs_write_seq_static(ctx, 0xb2, 0x03, 0x10);
 320        return 0;
 321}
 322
 323static int s6e3ha2_caps_elvss_set(struct s6e3ha2 *ctx)
 324{
 325        s6e3ha2_dcs_write_seq_static(ctx, 0xb6, 0x9c, 0x0a);
 326        return 0;
 327}
 328
 329static int s6e3ha2_acl_off(struct s6e3ha2 *ctx)
 330{
 331        s6e3ha2_dcs_write_seq_static(ctx, 0x55, 0x00);
 332        return 0;
 333}
 334
 335static int s6e3ha2_acl_off_opr(struct s6e3ha2 *ctx)
 336{
 337        s6e3ha2_dcs_write_seq_static(ctx, 0xb5, 0x40);
 338        return 0;
 339}
 340
 341static int s6e3ha2_test_global(struct s6e3ha2 *ctx)
 342{
 343        s6e3ha2_dcs_write_seq_static(ctx, 0xb0, 0x07);
 344        return 0;
 345}
 346
 347static int s6e3ha2_test(struct s6e3ha2 *ctx)
 348{
 349        s6e3ha2_dcs_write_seq_static(ctx, 0xb8, 0x19);
 350        return 0;
 351}
 352
 353static int s6e3ha2_touch_hsync_on1(struct s6e3ha2 *ctx)
 354{
 355        s6e3ha2_dcs_write_seq_static(ctx, 0xbd, 0x33, 0x11, 0x02,
 356                                        0x16, 0x02, 0x16);
 357        return 0;
 358}
 359
 360static int s6e3ha2_pentile_control(struct s6e3ha2 *ctx)
 361{
 362        s6e3ha2_dcs_write_seq_static(ctx, 0xc0, 0x00, 0x00, 0xd8, 0xd8);
 363        return 0;
 364}
 365
 366static int s6e3ha2_poc_global(struct s6e3ha2 *ctx)
 367{
 368        s6e3ha2_dcs_write_seq_static(ctx, 0xb0, 0x20);
 369        return 0;
 370}
 371
 372static int s6e3ha2_poc_setting(struct s6e3ha2 *ctx)
 373{
 374        s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x08);
 375        return 0;
 376}
 377
 378static int s6e3ha2_pcd_set_off(struct s6e3ha2 *ctx)
 379{
 380        s6e3ha2_dcs_write_seq_static(ctx, 0xcc, 0x40, 0x51);
 381        return 0;
 382}
 383
 384static int s6e3ha2_err_fg_set(struct s6e3ha2 *ctx)
 385{
 386        s6e3ha2_dcs_write_seq_static(ctx, 0xed, 0x44);
 387        return 0;
 388}
 389
 390static int s6e3ha2_hbm_off(struct s6e3ha2 *ctx)
 391{
 392        s6e3ha2_dcs_write_seq_static(ctx, 0x53, 0x00);
 393        return 0;
 394}
 395
 396static int s6e3ha2_te_start_setting(struct s6e3ha2 *ctx)
 397{
 398        s6e3ha2_dcs_write_seq_static(ctx, 0xb9, 0x10, 0x09, 0xff, 0x00, 0x09);
 399        return 0;
 400}
 401
 402static int s6e3ha2_gamma_update(struct s6e3ha2 *ctx)
 403{
 404        s6e3ha2_dcs_write_seq_static(ctx, 0xf7, 0x03);
 405        ndelay(100); /* need for 100ns delay */
 406        s6e3ha2_dcs_write_seq_static(ctx, 0xf7, 0x00);
 407        return 0;
 408}
 409
 410static int s6e3ha2_get_brightness(struct backlight_device *bl_dev)
 411{
 412        return bl_dev->props.brightness;
 413}
 414
 415static int s6e3ha2_set_vint(struct s6e3ha2 *ctx)
 416{
 417        struct backlight_device *bl_dev = ctx->bl_dev;
 418        unsigned int brightness = bl_dev->props.brightness;
 419        unsigned char data[] = { 0xf4, 0x8b,
 420                        vint_table[brightness * (S6E3HA2_VINT_STATUS_MAX - 1) /
 421                        S6E3HA2_MAX_BRIGHTNESS] };
 422
 423        return s6e3ha2_dcs_write(ctx, data, ARRAY_SIZE(data));
 424}
 425
 426static unsigned int s6e3ha2_get_brightness_index(unsigned int brightness)
 427{
 428        return (brightness * (S6E3HA2_NUM_GAMMA_STEPS - 1)) /
 429                S6E3HA2_MAX_BRIGHTNESS;
 430}
 431
 432static int s6e3ha2_update_gamma(struct s6e3ha2 *ctx, unsigned int brightness)
 433{
 434        struct backlight_device *bl_dev = ctx->bl_dev;
 435        unsigned int index = s6e3ha2_get_brightness_index(brightness);
 436        u8 data[S6E3HA2_GAMMA_CMD_CNT + 1] = { 0xca, };
 437        int ret;
 438
 439        memcpy(data + 1, gamma_tbl + index, S6E3HA2_GAMMA_CMD_CNT);
 440        s6e3ha2_call_write_func(ret,
 441                                s6e3ha2_dcs_write(ctx, data, ARRAY_SIZE(data)));
 442
 443        s6e3ha2_call_write_func(ret, s6e3ha2_gamma_update(ctx));
 444        bl_dev->props.brightness = brightness;
 445
 446        return 0;
 447}
 448
 449static int s6e3ha2_set_brightness(struct backlight_device *bl_dev)
 450{
 451        struct s6e3ha2 *ctx = bl_get_data(bl_dev);
 452        unsigned int brightness = bl_dev->props.brightness;
 453        int ret;
 454
 455        if (brightness < S6E3HA2_MIN_BRIGHTNESS ||
 456                brightness > bl_dev->props.max_brightness) {
 457                dev_err(ctx->dev, "Invalid brightness: %u\n", brightness);
 458                return -EINVAL;
 459        }
 460
 461        if (bl_dev->props.power > FB_BLANK_NORMAL)
 462                return -EPERM;
 463
 464        s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_f0(ctx));
 465        s6e3ha2_call_write_func(ret, s6e3ha2_update_gamma(ctx, brightness));
 466        s6e3ha2_call_write_func(ret, s6e3ha2_aor_control(ctx));
 467        s6e3ha2_call_write_func(ret, s6e3ha2_set_vint(ctx));
 468        s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_f0(ctx));
 469
 470        return 0;
 471}
 472
 473static const struct backlight_ops s6e3ha2_bl_ops = {
 474        .get_brightness = s6e3ha2_get_brightness,
 475        .update_status = s6e3ha2_set_brightness,
 476};
 477
 478static int s6e3ha2_panel_init(struct s6e3ha2 *ctx)
 479{
 480        struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 481        int ret;
 482
 483        s6e3ha2_call_write_func(ret, mipi_dsi_dcs_exit_sleep_mode(dsi));
 484        usleep_range(5000, 6000);
 485
 486        s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_f0(ctx));
 487        s6e3ha2_call_write_func(ret, s6e3ha2_single_dsi_set(ctx));
 488        s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_fc(ctx));
 489        s6e3ha2_call_write_func(ret, s6e3ha2_freq_calibration(ctx));
 490        s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_fc(ctx));
 491        s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_f0(ctx));
 492
 493        return 0;
 494}
 495
 496static int s6e3ha2_power_off(struct s6e3ha2 *ctx)
 497{
 498        return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
 499}
 500
 501static int s6e3ha2_disable(struct drm_panel *panel)
 502{
 503        struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
 504        struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 505        int ret;
 506
 507        s6e3ha2_call_write_func(ret, mipi_dsi_dcs_enter_sleep_mode(dsi));
 508        s6e3ha2_call_write_func(ret, mipi_dsi_dcs_set_display_off(dsi));
 509
 510        msleep(40);
 511        ctx->bl_dev->props.power = FB_BLANK_NORMAL;
 512
 513        return 0;
 514}
 515
 516static int s6e3ha2_unprepare(struct drm_panel *panel)
 517{
 518        struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
 519
 520        return s6e3ha2_power_off(ctx);
 521}
 522
 523static int s6e3ha2_power_on(struct s6e3ha2 *ctx)
 524{
 525        int ret;
 526
 527        ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
 528        if (ret < 0)
 529                return ret;
 530
 531        msleep(120);
 532
 533        gpiod_set_value(ctx->enable_gpio, 0);
 534        usleep_range(5000, 6000);
 535        gpiod_set_value(ctx->enable_gpio, 1);
 536
 537        gpiod_set_value(ctx->reset_gpio, 1);
 538        usleep_range(5000, 6000);
 539        gpiod_set_value(ctx->reset_gpio, 0);
 540        usleep_range(5000, 6000);
 541
 542        return 0;
 543}
 544static int s6e3ha2_prepare(struct drm_panel *panel)
 545{
 546        struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
 547        int ret;
 548
 549        ret = s6e3ha2_power_on(ctx);
 550        if (ret < 0)
 551                return ret;
 552
 553        ret = s6e3ha2_panel_init(ctx);
 554        if (ret < 0)
 555                goto err;
 556
 557        ctx->bl_dev->props.power = FB_BLANK_NORMAL;
 558
 559        return 0;
 560
 561err:
 562        s6e3ha2_power_off(ctx);
 563        return ret;
 564}
 565
 566static int s6e3ha2_enable(struct drm_panel *panel)
 567{
 568        struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
 569        struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 570        int ret;
 571
 572        /* common setting */
 573        s6e3ha2_call_write_func(ret,
 574                mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK));
 575
 576        s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_f0(ctx));
 577        s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_fc(ctx));
 578        s6e3ha2_call_write_func(ret, s6e3ha2_touch_hsync_on1(ctx));
 579        s6e3ha2_call_write_func(ret, s6e3ha2_pentile_control(ctx));
 580        s6e3ha2_call_write_func(ret, s6e3ha2_poc_global(ctx));
 581        s6e3ha2_call_write_func(ret, s6e3ha2_poc_setting(ctx));
 582        s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_fc(ctx));
 583
 584        /* pcd setting off for TB */
 585        s6e3ha2_call_write_func(ret, s6e3ha2_pcd_set_off(ctx));
 586        s6e3ha2_call_write_func(ret, s6e3ha2_err_fg_set(ctx));
 587        s6e3ha2_call_write_func(ret, s6e3ha2_te_start_setting(ctx));
 588
 589        /* brightness setting */
 590        s6e3ha2_call_write_func(ret, s6e3ha2_set_brightness(ctx->bl_dev));
 591        s6e3ha2_call_write_func(ret, s6e3ha2_aor_control(ctx));
 592        s6e3ha2_call_write_func(ret, s6e3ha2_caps_elvss_set(ctx));
 593        s6e3ha2_call_write_func(ret, s6e3ha2_gamma_update(ctx));
 594        s6e3ha2_call_write_func(ret, s6e3ha2_acl_off(ctx));
 595        s6e3ha2_call_write_func(ret, s6e3ha2_acl_off_opr(ctx));
 596        s6e3ha2_call_write_func(ret, s6e3ha2_hbm_off(ctx));
 597
 598        /* elvss temp compensation */
 599        s6e3ha2_call_write_func(ret, s6e3ha2_test_global(ctx));
 600        s6e3ha2_call_write_func(ret, s6e3ha2_test(ctx));
 601        s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_f0(ctx));
 602
 603        s6e3ha2_call_write_func(ret, mipi_dsi_dcs_set_display_on(dsi));
 604        ctx->bl_dev->props.power = FB_BLANK_UNBLANK;
 605
 606        return 0;
 607}
 608
 609static const struct drm_display_mode s6e3ha2_mode = {
 610        .clock = 222372,
 611        .hdisplay = 1440,
 612        .hsync_start = 1440 + 1,
 613        .hsync_end = 1440 + 1 + 1,
 614        .htotal = 1440 + 1 + 1 + 1,
 615        .vdisplay = 2560,
 616        .vsync_start = 2560 + 1,
 617        .vsync_end = 2560 + 1 + 1,
 618        .vtotal = 2560 + 1 + 1 + 15,
 619        .vrefresh = 60,
 620        .flags = 0,
 621};
 622
 623static const struct s6e3ha2_panel_desc samsung_s6e3ha2 = {
 624        .mode = &s6e3ha2_mode,
 625        .type = HA2_TYPE,
 626};
 627
 628static const struct drm_display_mode s6e3hf2_mode = {
 629        .clock = 247856,
 630        .hdisplay = 1600,
 631        .hsync_start = 1600 + 1,
 632        .hsync_end = 1600 + 1 + 1,
 633        .htotal = 1600 + 1 + 1 + 1,
 634        .vdisplay = 2560,
 635        .vsync_start = 2560 + 1,
 636        .vsync_end = 2560 + 1 + 1,
 637        .vtotal = 2560 + 1 + 1 + 15,
 638        .vrefresh = 60,
 639        .flags = 0,
 640};
 641
 642static const struct s6e3ha2_panel_desc samsung_s6e3hf2 = {
 643        .mode = &s6e3hf2_mode,
 644        .type = HF2_TYPE,
 645};
 646
 647static int s6e3ha2_get_modes(struct drm_panel *panel)
 648{
 649        struct drm_connector *connector = panel->connector;
 650        struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
 651        struct drm_display_mode *mode;
 652
 653        mode = drm_mode_duplicate(panel->drm, ctx->desc->mode);
 654        if (!mode) {
 655                DRM_ERROR("failed to add mode %ux%ux@%u\n",
 656                        ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
 657                        ctx->desc->mode->vrefresh);
 658                return -ENOMEM;
 659        }
 660
 661        drm_mode_set_name(mode);
 662
 663        mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
 664        drm_mode_probed_add(connector, mode);
 665
 666        connector->display_info.width_mm = 71;
 667        connector->display_info.height_mm = 125;
 668
 669        return 1;
 670}
 671
 672static const struct drm_panel_funcs s6e3ha2_drm_funcs = {
 673        .disable = s6e3ha2_disable,
 674        .unprepare = s6e3ha2_unprepare,
 675        .prepare = s6e3ha2_prepare,
 676        .enable = s6e3ha2_enable,
 677        .get_modes = s6e3ha2_get_modes,
 678};
 679
 680static int s6e3ha2_probe(struct mipi_dsi_device *dsi)
 681{
 682        struct device *dev = &dsi->dev;
 683        struct s6e3ha2 *ctx;
 684        int ret;
 685
 686        ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
 687        if (!ctx)
 688                return -ENOMEM;
 689
 690        mipi_dsi_set_drvdata(dsi, ctx);
 691
 692        ctx->dev = dev;
 693        ctx->desc = of_device_get_match_data(dev);
 694
 695        dsi->lanes = 4;
 696        dsi->format = MIPI_DSI_FMT_RGB888;
 697        dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS;
 698
 699        ctx->supplies[0].supply = "vdd3";
 700        ctx->supplies[1].supply = "vci";
 701
 702        ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
 703                                      ctx->supplies);
 704        if (ret < 0) {
 705                dev_err(dev, "failed to get regulators: %d\n", ret);
 706                return ret;
 707        }
 708
 709        ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
 710        if (IS_ERR(ctx->reset_gpio)) {
 711                dev_err(dev, "cannot get reset-gpios %ld\n",
 712                        PTR_ERR(ctx->reset_gpio));
 713                return PTR_ERR(ctx->reset_gpio);
 714        }
 715
 716        ctx->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
 717        if (IS_ERR(ctx->enable_gpio)) {
 718                dev_err(dev, "cannot get enable-gpios %ld\n",
 719                        PTR_ERR(ctx->enable_gpio));
 720                return PTR_ERR(ctx->enable_gpio);
 721        }
 722
 723        ctx->bl_dev = backlight_device_register("s6e3ha2", dev, ctx,
 724                                                &s6e3ha2_bl_ops, NULL);
 725        if (IS_ERR(ctx->bl_dev)) {
 726                dev_err(dev, "failed to register backlight device\n");
 727                return PTR_ERR(ctx->bl_dev);
 728        }
 729
 730        ctx->bl_dev->props.max_brightness = S6E3HA2_MAX_BRIGHTNESS;
 731        ctx->bl_dev->props.brightness = S6E3HA2_DEFAULT_BRIGHTNESS;
 732        ctx->bl_dev->props.power = FB_BLANK_POWERDOWN;
 733
 734        drm_panel_init(&ctx->panel);
 735        ctx->panel.dev = dev;
 736        ctx->panel.funcs = &s6e3ha2_drm_funcs;
 737
 738        ret = drm_panel_add(&ctx->panel);
 739        if (ret < 0)
 740                goto unregister_backlight;
 741
 742        ret = mipi_dsi_attach(dsi);
 743        if (ret < 0)
 744                goto remove_panel;
 745
 746        return ret;
 747
 748remove_panel:
 749        drm_panel_remove(&ctx->panel);
 750
 751unregister_backlight:
 752        backlight_device_unregister(ctx->bl_dev);
 753
 754        return ret;
 755}
 756
 757static int s6e3ha2_remove(struct mipi_dsi_device *dsi)
 758{
 759        struct s6e3ha2 *ctx = mipi_dsi_get_drvdata(dsi);
 760
 761        mipi_dsi_detach(dsi);
 762        drm_panel_remove(&ctx->panel);
 763        backlight_device_unregister(ctx->bl_dev);
 764
 765        return 0;
 766}
 767
 768static const struct of_device_id s6e3ha2_of_match[] = {
 769        { .compatible = "samsung,s6e3ha2", .data = &samsung_s6e3ha2 },
 770        { .compatible = "samsung,s6e3hf2", .data = &samsung_s6e3hf2 },
 771        { }
 772};
 773MODULE_DEVICE_TABLE(of, s6e3ha2_of_match);
 774
 775static struct mipi_dsi_driver s6e3ha2_driver = {
 776        .probe = s6e3ha2_probe,
 777        .remove = s6e3ha2_remove,
 778        .driver = {
 779                .name = "panel-samsung-s6e3ha2",
 780                .of_match_table = s6e3ha2_of_match,
 781        },
 782};
 783module_mipi_dsi_driver(s6e3ha2_driver);
 784
 785MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
 786MODULE_AUTHOR("Hyungwon Hwang <human.hwang@samsung.com>");
 787MODULE_AUTHOR("Hoegeun Kwon <hoegeun.kwon@samsung.com>");
 788MODULE_DESCRIPTION("MIPI-DSI based s6e3ha2 AMOLED Panel Driver");
 789MODULE_LICENSE("GPL v2");
 790