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