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