1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Samsung AMS427AP24 panel with S6E88A0 controller 4 * Copyright (c) 2024 Jakob Hauser <jahau@rocketmail.com> 5 */ 6 7 #include <linux/backlight.h> 8 #include <linux/delay.h> 9 #include <linux/gpio/consumer.h> 10 #include <linux/module.h> 11 #include <linux/regulator/consumer.h> 12 13 #include <video/mipi_display.h> 14 15 #include <drm/drm_mipi_dsi.h> 16 #include <drm/drm_modes.h> 17 #include <drm/drm_panel.h> 18 #include <drm/drm_probe_helper.h> 19 20 #define NUM_STEPS_CANDELA 54 21 #define NUM_STEPS_AID 39 22 #define NUM_STEPS_ELVSS 17 23 24 /* length of the payload data, thereof fixed and variable */ 25 #define FIX_LEN_AID 4 26 #define FIX_LEN_ELVSS 2 27 #define FIX_LEN_GAMMA 1 28 #define VAR_LEN_AID 2 29 #define VAR_LEN_ELVSS 1 30 #define VAR_LEN_GAMMA 33 31 #define LEN_AID (FIX_LEN_AID + VAR_LEN_AID) 32 #define LEN_ELVSS (FIX_LEN_ELVSS + VAR_LEN_ELVSS) 33 #define LEN_GAMMA (FIX_LEN_GAMMA + VAR_LEN_GAMMA) 34 35 struct s6e88a0_ams427ap24 { 36 struct drm_panel panel; 37 struct backlight_device *bl_dev; 38 struct mipi_dsi_device *dsi; 39 struct regulator_bulk_data *supplies; 40 struct gpio_desc *reset_gpio; 41 bool flip_horizontal; 42 }; 43 44 static const struct regulator_bulk_data s6e88a0_ams427ap24_supplies[] = { 45 { .supply = "vdd3" }, 46 { .supply = "vci" }, 47 }; 48 49 static inline 50 struct s6e88a0_ams427ap24 *to_s6e88a0_ams427ap24(struct drm_panel *panel) 51 { 52 return container_of(panel, struct s6e88a0_ams427ap24, panel); 53 } 54 55 enum candela { 56 CANDELA_10CD, /* 0 */ 57 CANDELA_11CD, 58 CANDELA_12CD, 59 CANDELA_13CD, 60 CANDELA_14CD, 61 CANDELA_15CD, 62 CANDELA_16CD, 63 CANDELA_17CD, 64 CANDELA_19CD, 65 CANDELA_20CD, 66 CANDELA_21CD, 67 CANDELA_22CD, 68 CANDELA_24CD, 69 CANDELA_25CD, 70 CANDELA_27CD, 71 CANDELA_29CD, 72 CANDELA_30CD, 73 CANDELA_32CD, 74 CANDELA_34CD, 75 CANDELA_37CD, 76 CANDELA_39CD, 77 CANDELA_41CD, 78 CANDELA_44CD, 79 CANDELA_47CD, 80 CANDELA_50CD, 81 CANDELA_53CD, 82 CANDELA_56CD, 83 CANDELA_60CD, 84 CANDELA_64CD, 85 CANDELA_68CD, 86 CANDELA_72CD, 87 CANDELA_77CD, 88 CANDELA_82CD, 89 CANDELA_87CD, 90 CANDELA_93CD, 91 CANDELA_98CD, 92 CANDELA_105CD, 93 CANDELA_111CD, 94 CANDELA_119CD, 95 CANDELA_126CD, 96 CANDELA_134CD, 97 CANDELA_143CD, 98 CANDELA_152CD, 99 CANDELA_162CD, 100 CANDELA_172CD, 101 CANDELA_183CD, 102 CANDELA_195CD, 103 CANDELA_207CD, 104 CANDELA_220CD, 105 CANDELA_234CD, 106 CANDELA_249CD, 107 CANDELA_265CD, 108 CANDELA_282CD, 109 CANDELA_300CD, /* 53 */ 110 }; 111 112 static const int s6e88a0_ams427ap24_br_to_cd[NUM_STEPS_CANDELA] = { 113 /* columns: brightness from, brightness till, candela */ 114 /* 0 */ 10, /* 10CD */ 115 /* 11 */ 11, /* 11CD */ 116 /* 12 */ 12, /* 12CD */ 117 /* 13 */ 13, /* 13CD */ 118 /* 14 */ 14, /* 14CD */ 119 /* 15 */ 15, /* 15CD */ 120 /* 16 */ 16, /* 16CD */ 121 /* 17 */ 17, /* 17CD */ 122 /* 18 */ 18, /* 19CD */ 123 /* 19 */ 19, /* 20CD */ 124 /* 20 */ 20, /* 21CD */ 125 /* 21 */ 21, /* 22CD */ 126 /* 22 */ 22, /* 24CD */ 127 /* 23 */ 23, /* 25CD */ 128 /* 24 */ 24, /* 27CD */ 129 /* 25 */ 25, /* 29CD */ 130 /* 26 */ 26, /* 30CD */ 131 /* 27 */ 27, /* 32CD */ 132 /* 28 */ 28, /* 34CD */ 133 /* 29 */ 29, /* 37CD */ 134 /* 30 */ 30, /* 39CD */ 135 /* 31 */ 32, /* 41CD */ 136 /* 33 */ 34, /* 44CD */ 137 /* 35 */ 36, /* 47CD */ 138 /* 37 */ 38, /* 50CD */ 139 /* 39 */ 40, /* 53CD */ 140 /* 41 */ 43, /* 56CD */ 141 /* 44 */ 46, /* 60CD */ 142 /* 47 */ 49, /* 64CD */ 143 /* 50 */ 52, /* 68CD */ 144 /* 53 */ 56, /* 72CD */ 145 /* 57 */ 59, /* 77CD */ 146 /* 60 */ 63, /* 82CD */ 147 /* 64 */ 67, /* 87CD */ 148 /* 68 */ 71, /* 93CD */ 149 /* 72 */ 76, /* 98CD */ 150 /* 77 */ 80, /* 105CD */ 151 /* 81 */ 86, /* 111CD */ 152 /* 87 */ 91, /* 119CD */ 153 /* 92 */ 97, /* 126CD */ 154 /* 98 */ 104, /* 134CD */ 155 /* 105 */ 110, /* 143CD */ 156 /* 111 */ 118, /* 152CD */ 157 /* 119 */ 125, /* 162CD */ 158 /* 126 */ 133, /* 172CD */ 159 /* 134 */ 142, /* 183CD */ 160 /* 143 */ 150, /* 195CD */ 161 /* 151 */ 160, /* 207CD */ 162 /* 161 */ 170, /* 220CD */ 163 /* 171 */ 181, /* 234CD */ 164 /* 182 */ 205, /* 249CD */ 165 /* 206 */ 234, /* 265CD */ 166 /* 235 */ 254, /* 282CD */ 167 /* 255 */ 255, /* 300CD */ 168 }; 169 170 static const u8 s6e88a0_ams427ap24_aid[NUM_STEPS_AID][VAR_LEN_AID] = { 171 { 0x03, 0x77 }, /* AOR 90.9%, 10CD */ 172 { 0x03, 0x73 }, /* AOR 90.5%, 11CD */ 173 { 0x03, 0x69 }, /* AOR 89.4%, 12CD */ 174 { 0x03, 0x65 }, /* AOR 89.0%, 13CD */ 175 { 0x03, 0x61 }, /* AOR 88.6%, 14CD */ 176 { 0x03, 0x55 }, /* AOR 87.4%, 15CD */ 177 { 0x03, 0x50 }, /* AOR 86.9%, 16CD */ 178 { 0x03, 0x45 }, /* AOR 85.8%, 17CD */ 179 { 0x03, 0x35 }, /* AOR 84.1%, 19CD */ 180 { 0x03, 0x27 }, /* AOR 82.7%, 20CD */ 181 { 0x03, 0x23 }, /* AOR 82.3%, 21CD */ 182 { 0x03, 0x17 }, /* AOR 81.0%, 22CD */ 183 { 0x03, 0x11 }, /* AOR 80.4%, 24CD */ 184 { 0x03, 0x04 }, /* AOR 79.1%, 25CD */ 185 { 0x02, 0xf4 }, /* AOR 77.5%, 27CD */ 186 { 0x02, 0xe3 }, /* AOR 75.7%, 29CD */ 187 { 0x02, 0xd7 }, /* AOR 74.5%, 30CD */ 188 { 0x02, 0xc6 }, /* AOR 72.7%, 32CD */ 189 { 0x02, 0xb7 }, /* AOR 71.2%, 34CD */ 190 { 0x02, 0xa1 }, /* AOR 69.0%, 37CD */ 191 { 0x02, 0x91 }, /* AOR 67.3%, 39CD */ 192 { 0x02, 0x78 }, /* AOR 64.8%, 41CD */ 193 { 0x02, 0x62 }, /* AOR 62.5%, 44CD */ 194 { 0x02, 0x45 }, /* AOR 59.5%, 47CD */ 195 { 0x02, 0x30 }, /* AOR 57.4%, 50CD */ 196 { 0x02, 0x13 }, /* AOR 54.4%, 53CD */ 197 { 0x01, 0xf5 }, /* AOR 51.3%, 56CD */ 198 { 0x01, 0xd3 }, /* AOR 47.8%, 60CD */ 199 { 0x01, 0xb1 }, /* AOR 44.4%, 64CD */ 200 { 0x01, 0x87 }, /* AOR 40.1%, 68CD */ 201 { 0x01, 0x63 }, /* AOR 36.6%, 72CD */ 202 { 0x01, 0x35 }, /* AOR 31.7%, 77CD */ 203 { 0x01, 0x05 }, /* AOR 26.9%, 82CD */ 204 { 0x00, 0xd5 }, /* AOR 21.8%, 87CD */ 205 { 0x00, 0xa1 }, /* AOR 16.5%, 93CD */ 206 { 0x00, 0x6f }, /* AOR 11.4%, 98CD */ 207 { 0x00, 0x31 }, /* AOR 5.0%, 105CD */ 208 { 0x01, 0x86 }, /* AOR 40.0%, 111CD ~ 172CD */ 209 { 0x00, 0x08 }, /* AOR 0.6%, 183CD ~ 300CD */ 210 }; 211 212 static const u8 s6e88a0_ams427ap24_elvss[NUM_STEPS_ELVSS][VAR_LEN_ELVSS] = { 213 { 0x14 }, /* 10CD ~ 111CD */ 214 { 0x13 }, /* 119CD */ 215 { 0x12 }, /* 126CD */ 216 { 0x12 }, /* 134CD */ 217 { 0x11 }, /* 143CD */ 218 { 0x10 }, /* 152CD */ 219 { 0x0f }, /* 162CD */ 220 { 0x0e }, /* 172CD */ 221 { 0x11 }, /* 183CD */ 222 { 0x11 }, /* 195CD */ 223 { 0x10 }, /* 207CD */ 224 { 0x0f }, /* 220CD */ 225 { 0x0f }, /* 234CD */ 226 { 0x0e }, /* 249CD */ 227 { 0x0d }, /* 265CD */ 228 { 0x0c }, /* 282CD */ 229 { 0x0b }, /* 300CD */ 230 }; 231 232 static const u8 s6e88a0_ams427ap24_gamma[NUM_STEPS_CANDELA][VAR_LEN_GAMMA] = { 233 /* 10CD */ 234 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x8a, 0x8c, 0x8b, 235 0x8c, 0x87, 0x89, 0x89, 0x88, 0x87, 0x8c, 0x80, 0x82, 0x88, 0x7b, 236 0x72, 0x8c, 0x60, 0x68, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 237 /* 11CD */ 238 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x8a, 0x8c, 0x8b, 239 0x8c, 0x87, 0x89, 0x89, 0x88, 0x87, 0x8c, 0x80, 0x82, 0x88, 0x7b, 240 0x72, 0x8c, 0x60, 0x68, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 241 /* 12CD */ 242 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x8a, 0x8b, 0x8b, 243 0x8c, 0x88, 0x89, 0x8a, 0x88, 0x87, 0x8c, 0x81, 0x82, 0x87, 0x7a, 244 0x72, 0x8b, 0x60, 0x68, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 245 /* 13CD */ 246 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x8a, 0x8b, 0x8b, 247 0x8c, 0x88, 0x89, 0x8a, 0x88, 0x87, 0x8c, 0x81, 0x82, 0x87, 0x7a, 248 0x72, 0x8b, 0x61, 0x69, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 249 /* 14CD */ 250 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8c, 0x8b, 251 0x8c, 0x88, 0x89, 0x8a, 0x87, 0x86, 0x8a, 0x82, 0x82, 0x87, 0x79, 252 0x71, 0x89, 0x63, 0x6c, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 253 /* 15CD */ 254 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x8a, 0x8c, 0x8c, 255 0x8c, 0x86, 0x87, 0x88, 0x85, 0x85, 0x8a, 0x83, 0x83, 0x88, 0x78, 256 0x72, 0x89, 0x64, 0x6c, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 257 /* 16CD */ 258 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8c, 0x8b, 259 0x8c, 0x86, 0x88, 0x88, 0x86, 0x86, 0x8a, 0x84, 0x84, 0x88, 0x78, 260 0x72, 0x89, 0x5d, 0x67, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 261 /* 17CD */ 262 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 263 0x8b, 0x87, 0x89, 0x89, 0x86, 0x86, 0x8a, 0x84, 0x83, 0x87, 0x78, 264 0x73, 0x89, 0x64, 0x6e, 0x8e, 0x38, 0x32, 0x24, 0x00, 0x00, 0x00 }, 265 /* 19CD */ 266 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 267 0x8b, 0x87, 0x89, 0x89, 0x86, 0x86, 0x89, 0x84, 0x84, 0x87, 0x77, 268 0x72, 0x88, 0x65, 0x6f, 0x8e, 0x38, 0x32, 0x24, 0x00, 0x00, 0x00 }, 269 /* 20CD */ 270 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 271 0x8b, 0x88, 0x89, 0x89, 0x85, 0x85, 0x88, 0x82, 0x83, 0x85, 0x79, 272 0x73, 0x88, 0x65, 0x6f, 0x8e, 0x38, 0x32, 0x24, 0x00, 0x00, 0x00 }, 273 /* 21CD */ 274 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 275 0x8b, 0x88, 0x89, 0x89, 0x85, 0x85, 0x88, 0x82, 0x83, 0x85, 0x79, 276 0x74, 0x88, 0x65, 0x6f, 0x8e, 0x38, 0x32, 0x24, 0x00, 0x00, 0x00 }, 277 /* 22CD */ 278 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8c, 0x8b, 279 0x8c, 0x86, 0x88, 0x87, 0x86, 0x86, 0x89, 0x82, 0x83, 0x85, 0x7c, 280 0x75, 0x87, 0x65, 0x6f, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 281 /* 24CD */ 282 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8c, 0x8b, 283 0x8c, 0x86, 0x88, 0x87, 0x86, 0x86, 0x89, 0x82, 0x83, 0x85, 0x7c, 284 0x76, 0x86, 0x66, 0x6f, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 285 /* 25CD */ 286 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 287 0x8b, 0x86, 0x89, 0x88, 0x87, 0x87, 0x89, 0x82, 0x82, 0x84, 0x7f, 288 0x7a, 0x89, 0x6b, 0x73, 0x8f, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 289 /* 27CD */ 290 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 291 0x8b, 0x86, 0x89, 0x88, 0x87, 0x87, 0x89, 0x82, 0x82, 0x84, 0x7f, 292 0x7a, 0x89, 0x6b, 0x73, 0x8f, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 293 /* 29CD */ 294 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 295 0x8b, 0x86, 0x89, 0x88, 0x85, 0x84, 0x87, 0x84, 0x85, 0x86, 0x80, 296 0x7b, 0x88, 0x6a, 0x73, 0x8f, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 297 /* 30CD */ 298 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 299 0x8b, 0x86, 0x89, 0x88, 0x85, 0x84, 0x87, 0x84, 0x85, 0x86, 0x80, 300 0x7b, 0x88, 0x6a, 0x73, 0x8f, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 301 /* 32CD */ 302 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 303 0x8b, 0x86, 0x89, 0x88, 0x85, 0x84, 0x87, 0x84, 0x85, 0x86, 0x80, 304 0x7b, 0x88, 0x6a, 0x73, 0x8f, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 305 /* 34CD */ 306 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8c, 0x8a, 0x89, 0x8b, 0x8b, 307 0x8b, 0x86, 0x89, 0x88, 0x85, 0x84, 0x87, 0x83, 0x84, 0x84, 0x7f, 308 0x79, 0x86, 0x6c, 0x76, 0x91, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 309 /* 37CD */ 310 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8b, 311 0x8b, 0x86, 0x88, 0x88, 0x87, 0x86, 0x87, 0x83, 0x84, 0x84, 0x7f, 312 0x79, 0x86, 0x6c, 0x76, 0x90, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 313 /* 39CD */ 314 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8b, 315 0x8b, 0x86, 0x88, 0x87, 0x84, 0x84, 0x86, 0x83, 0x85, 0x85, 0x80, 316 0x79, 0x85, 0x6c, 0x76, 0x90, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 317 /* 41CD */ 318 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8b, 319 0x8b, 0x86, 0x88, 0x87, 0x84, 0x84, 0x86, 0x81, 0x84, 0x83, 0x7f, 320 0x79, 0x84, 0x6e, 0x79, 0x93, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 321 /* 44CD */ 322 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8b, 323 0x8b, 0x86, 0x88, 0x87, 0x84, 0x84, 0x86, 0x81, 0x84, 0x83, 0x7f, 324 0x79, 0x84, 0x6e, 0x79, 0x92, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 325 /* 47CD */ 326 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8b, 327 0x8b, 0x86, 0x88, 0x87, 0x84, 0x85, 0x86, 0x81, 0x84, 0x83, 0x7f, 328 0x79, 0x83, 0x6f, 0x79, 0x91, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 329 /* 50CD */ 330 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8b, 331 0x8b, 0x86, 0x88, 0x87, 0x84, 0x85, 0x86, 0x82, 0x84, 0x83, 0x7f, 332 0x79, 0x83, 0x6f, 0x79, 0x90, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 333 /* 53CD */ 334 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8b, 335 0x8b, 0x86, 0x88, 0x87, 0x83, 0x83, 0x85, 0x84, 0x85, 0x85, 0x7f, 336 0x79, 0x83, 0x70, 0x79, 0x8f, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 337 /* 56CD */ 338 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8a, 339 0x8a, 0x87, 0x89, 0x87, 0x83, 0x83, 0x85, 0x84, 0x85, 0x84, 0x7f, 340 0x79, 0x82, 0x70, 0x7a, 0x8e, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 341 /* 60CD */ 342 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8a, 343 0x8a, 0x87, 0x89, 0x87, 0x83, 0x83, 0x85, 0x84, 0x85, 0x84, 0x7e, 344 0x79, 0x82, 0x71, 0x7a, 0x8d, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 345 /* 64CD */ 346 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8b, 0x89, 0x89, 0x8b, 0x8a, 347 0x8a, 0x86, 0x88, 0x86, 0x84, 0x84, 0x86, 0x82, 0x83, 0x82, 0x80, 348 0x7a, 0x84, 0x71, 0x7a, 0x8c, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 349 /* 68CD */ 350 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8a, 0x89, 0x89, 0x8c, 0x8a, 351 0x8a, 0x86, 0x88, 0x86, 0x84, 0x84, 0x86, 0x82, 0x84, 0x82, 0x81, 352 0x7b, 0x83, 0x72, 0x7b, 0x8b, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 353 /* 72CD */ 354 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8a, 0x89, 0x89, 0x8c, 0x8a, 355 0x8a, 0x86, 0x88, 0x86, 0x85, 0x85, 0x86, 0x82, 0x84, 0x82, 0x81, 356 0x7b, 0x83, 0x72, 0x7c, 0x8a, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 357 /* 77CD */ 358 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8a, 0x89, 0x89, 0x8c, 0x8a, 359 0x8a, 0x85, 0x87, 0x85, 0x85, 0x87, 0x87, 0x82, 0x84, 0x82, 0x81, 360 0x7c, 0x82, 0x72, 0x7c, 0x89, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 361 /* 82CD */ 362 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8a, 0x89, 0x89, 0x8c, 0x8a, 363 0x8a, 0x85, 0x87, 0x85, 0x85, 0x87, 0x87, 0x82, 0x84, 0x82, 0x81, 364 0x7c, 0x82, 0x73, 0x7c, 0x88, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 365 /* 87CD */ 366 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8a, 0x89, 0x89, 0x8c, 0x8a, 367 0x8a, 0x85, 0x87, 0x85, 0x84, 0x84, 0x86, 0x80, 0x84, 0x81, 0x80, 368 0x7a, 0x82, 0x76, 0x7f, 0x89, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 369 /* 93CD */ 370 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8a, 0x89, 0x89, 0x8b, 0x8a, 371 0x8a, 0x86, 0x87, 0x85, 0x84, 0x85, 0x86, 0x80, 0x84, 0x80, 0x80, 372 0x7a, 0x82, 0x76, 0x80, 0x88, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 373 /* 98CD */ 374 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x8a, 0x89, 0x89, 0x8b, 0x8a, 375 0x8a, 0x86, 0x87, 0x85, 0x85, 0x85, 0x86, 0x80, 0x84, 0x80, 0x80, 376 0x7a, 0x82, 0x76, 0x80, 0x88, 0x33, 0x2f, 0x22, 0x00, 0x00, 0x00 }, 377 /* 105CD */ 378 { 0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc5, 0x89, 0x88, 0x88, 0x8b, 0x8a, 379 0x8a, 0x84, 0x87, 0x85, 0x85, 0x85, 0x85, 0x80, 0x84, 0x80, 0x7f, 380 0x79, 0x81, 0x71, 0x7d, 0x87, 0x38, 0x32, 0x24, 0x00, 0x00, 0x00 }, 381 /* 111CD */ 382 { 0x00, 0xdf, 0x00, 0xde, 0x00, 0xde, 0x85, 0x85, 0x84, 0x87, 0x86, 383 0x87, 0x85, 0x86, 0x85, 0x83, 0x83, 0x83, 0x81, 0x82, 0x82, 0x80, 384 0x7d, 0x82, 0x75, 0x7f, 0x86, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 385 /* 119CD */ 386 { 0x00, 0xe3, 0x00, 0xe1, 0x00, 0xe2, 0x85, 0x85, 0x84, 0x86, 0x85, 387 0x85, 0x84, 0x85, 0x84, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x7e, 388 0x7b, 0x81, 0x75, 0x7f, 0x86, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 389 /* 126CD */ 390 { 0x00, 0xe6, 0x00, 0xe5, 0x00, 0xe5, 0x85, 0x84, 0x84, 0x85, 0x85, 391 0x85, 0x84, 0x84, 0x84, 0x82, 0x83, 0x83, 0x80, 0x81, 0x81, 0x80, 392 0x7f, 0x83, 0x73, 0x7c, 0x84, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 393 /* 134CD */ 394 { 0x00, 0xe9, 0x00, 0xe8, 0x00, 0xe8, 0x84, 0x84, 0x83, 0x85, 0x85, 395 0x85, 0x84, 0x84, 0x83, 0x81, 0x82, 0x82, 0x81, 0x81, 0x81, 0x7f, 396 0x7d, 0x81, 0x73, 0x7c, 0x83, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 397 /* 143CD */ 398 { 0x00, 0xed, 0x00, 0xec, 0x00, 0xec, 0x84, 0x83, 0x83, 0x84, 0x84, 399 0x84, 0x84, 0x84, 0x83, 0x82, 0x83, 0x83, 0x81, 0x80, 0x81, 0x7f, 400 0x7e, 0x81, 0x70, 0x79, 0x81, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 401 /* 152CD */ 402 { 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x83, 0x83, 0x83, 0x83, 0x83, 403 0x83, 0x84, 0x84, 0x83, 0x81, 0x81, 0x81, 0x80, 0x80, 0x81, 0x80, 404 0x80, 0x82, 0x6f, 0x78, 0x7f, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 405 /* 162CD */ 406 { 0x00, 0xf4, 0x00, 0xf3, 0x00, 0xf4, 0x83, 0x83, 0x83, 0x83, 0x83, 407 0x83, 0x82, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x81, 0x80, 408 0x7f, 0x82, 0x6f, 0x78, 0x7f, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 409 /* 172CD */ 410 { 0x00, 0xf8, 0x00, 0xf8, 0x00, 0xf8, 0x82, 0x82, 0x82, 0x82, 0x82, 411 0x82, 0x82, 0x81, 0x81, 0x80, 0x81, 0x80, 0x80, 0x80, 0x81, 0x81, 412 0x80, 0x83, 0x6d, 0x76, 0x7d, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 413 /* 183CD */ 414 { 0x00, 0xe0, 0x00, 0xdf, 0x00, 0xdf, 0x84, 0x84, 0x83, 0x86, 0x86, 415 0x86, 0x83, 0x84, 0x83, 0x82, 0x82, 0x82, 0x81, 0x83, 0x81, 0x81, 416 0x7e, 0x81, 0x80, 0x82, 0x84, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 417 /* 195CD */ 418 { 0x00, 0xe4, 0x00, 0xe3, 0x00, 0xe3, 0x84, 0x83, 0x83, 0x85, 0x85, 419 0x85, 0x83, 0x84, 0x83, 0x81, 0x82, 0x82, 0x82, 0x83, 0x81, 0x81, 420 0x80, 0x82, 0x7d, 0x7f, 0x81, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 421 /* 207CD */ 422 { 0x00, 0xe7, 0x00, 0xe6, 0x00, 0xe6, 0x83, 0x82, 0x82, 0x85, 0x85, 423 0x85, 0x82, 0x83, 0x83, 0x82, 0x82, 0x82, 0x80, 0x81, 0x80, 0x81, 424 0x80, 0x82, 0x7d, 0x7f, 0x81, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 425 /* 220CD */ 426 { 0x00, 0xeb, 0x00, 0xea, 0x00, 0xea, 0x83, 0x83, 0x82, 0x84, 0x84, 427 0x84, 0x82, 0x83, 0x82, 0x81, 0x81, 0x82, 0x81, 0x82, 0x81, 0x80, 428 0x7e, 0x80, 0x7d, 0x7f, 0x81, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 429 /* 234CD */ 430 { 0x00, 0xef, 0x00, 0xee, 0x00, 0xee, 0x83, 0x82, 0x82, 0x83, 0x83, 431 0x83, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 432 0x80, 0x81, 0x7b, 0x7c, 0x7f, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 433 /* 249CD */ 434 { 0x00, 0xf3, 0x00, 0xf2, 0x00, 0xf2, 0x82, 0x81, 0x81, 0x83, 0x83, 435 0x83, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x80, 0x81, 0x80, 0x7f, 436 0x7e, 0x7f, 0x7b, 0x7c, 0x7f, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 437 /* 265CD */ 438 { 0x00, 0xf7, 0x00, 0xf7, 0x00, 0xf7, 0x81, 0x81, 0x80, 0x82, 0x82, 439 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x80, 0x7f, 440 0x7e, 0x7f, 0x7b, 0x7c, 0x7f, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 441 /* 282CD */ 442 { 0x00, 0xfb, 0x00, 0xfb, 0x00, 0xfb, 0x80, 0x80, 0x80, 0x81, 0x81, 443 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 444 0x7f, 0x7f, 0x78, 0x79, 0x7d, 0x85, 0x85, 0x82, 0x00, 0x00, 0x00 }, 445 /* 300CD */ 446 { 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 447 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 448 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00 }, 449 }; 450 451 static int s6e88a0_ams427ap24_set_brightness(struct backlight_device *bd) 452 { 453 struct s6e88a0_ams427ap24 *ctx = bl_get_data(bd); 454 struct mipi_dsi_device *dsi = ctx->dsi; 455 struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 456 struct device *dev = &dsi->dev; 457 int brightness = bd->props.brightness; 458 int candela_enum; 459 u8 b2[LEN_AID] = { 0xb2, 0x40, 0x08, 0x20, 0x00, 0x00 }; 460 u8 b6[LEN_ELVSS] = { 0xb6, 0x28, 0x00 }; 461 u8 ca[LEN_GAMMA]; 462 463 /* get candela enum from brightness */ 464 for (candela_enum = 0; candela_enum < NUM_STEPS_CANDELA; candela_enum++) 465 if (brightness <= s6e88a0_ams427ap24_br_to_cd[candela_enum]) 466 break; 467 468 /* get aid */ 469 switch (candela_enum) { 470 case CANDELA_10CD ... CANDELA_105CD: 471 memcpy(&b2[FIX_LEN_AID], 472 s6e88a0_ams427ap24_aid[candela_enum], 473 VAR_LEN_AID); 474 break; 475 case CANDELA_111CD ... CANDELA_172CD: 476 memcpy(&b2[FIX_LEN_AID], 477 s6e88a0_ams427ap24_aid[CANDELA_111CD], 478 VAR_LEN_AID); 479 break; 480 case CANDELA_183CD ... CANDELA_300CD: 481 memcpy(&b2[FIX_LEN_AID], 482 s6e88a0_ams427ap24_aid[CANDELA_111CD + 1], 483 VAR_LEN_AID); 484 break; 485 default: 486 dev_err(dev, "Failed to get aid data\n"); 487 return -EINVAL; 488 } 489 490 /* get elvss */ 491 if (candela_enum <= CANDELA_111CD) { 492 memcpy(&b6[FIX_LEN_ELVSS], 493 s6e88a0_ams427ap24_elvss[0], 494 VAR_LEN_ELVSS); 495 } else { 496 memcpy(&b6[FIX_LEN_ELVSS], 497 s6e88a0_ams427ap24_elvss[candela_enum - CANDELA_111CD], 498 VAR_LEN_ELVSS); 499 } 500 501 /* get gamma */ 502 ca[0] = 0xca; 503 memcpy(&ca[FIX_LEN_GAMMA], 504 s6e88a0_ams427ap24_gamma[candela_enum], 505 VAR_LEN_GAMMA); 506 507 /* write data */ 508 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0x5a, 0x5a); // level 1 key on 509 mipi_dsi_dcs_write_buffer_multi(&dsi_ctx, b2, ARRAY_SIZE(b2)); // set aid 510 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x00); // acl off 511 mipi_dsi_dcs_write_buffer_multi(&dsi_ctx, b6, ARRAY_SIZE(b6)); // set elvss 512 mipi_dsi_dcs_write_buffer_multi(&dsi_ctx, ca, ARRAY_SIZE(ca)); // set gamma 513 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf7, 0x03); // gamma update 514 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xa5, 0xa5); // level 1 key off 515 516 return dsi_ctx.accum_err; 517 } 518 519 static void s6e88a0_ams427ap24_reset(struct s6e88a0_ams427ap24 *ctx) 520 { 521 gpiod_set_value_cansleep(ctx->reset_gpio, 0); 522 usleep_range(5000, 6000); 523 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 524 usleep_range(1000, 2000); 525 gpiod_set_value_cansleep(ctx->reset_gpio, 0); 526 usleep_range(18000, 19000); 527 } 528 529 static int s6e88a0_ams427ap24_on(struct s6e88a0_ams427ap24 *ctx) 530 { 531 struct mipi_dsi_device *dsi = ctx->dsi; 532 struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 533 struct device *dev = &dsi->dev; 534 int ret; 535 536 dsi->mode_flags |= MIPI_DSI_MODE_LPM; 537 538 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0x5a, 0x5a); // level 1 key on 539 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfc, 0x5a, 0x5a); // level 2 key on 540 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x11); // src latch set global 1 541 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfd, 0x11); // src latch set 1 542 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x13); // src latch set global 2 543 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfd, 0x18); // src latch set 2 544 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x02); // avdd set 1 545 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb8, 0x30); // avdd set 2 546 547 mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); 548 mipi_dsi_msleep(&dsi_ctx, 20); 549 550 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf1, 0x5a, 0x5a); // level 3 key on 551 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcc, 0x4c); // pixel clock divider pol. 552 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf2, 0x03, 0x0d); // unknown 553 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf1, 0xa5, 0xa5); // level 3 key off 554 555 if (ctx->flip_horizontal) 556 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcb, 0x0e); // flip display 557 558 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xa5, 0xa5); // level 1 key off 559 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfc, 0xa5, 0xa5); // level 2 key off 560 561 ret = s6e88a0_ams427ap24_set_brightness(ctx->bl_dev); 562 if (ret < 0) { 563 dev_err(dev, "Failed to set brightness: %d\n", ret); 564 return ret; 565 } 566 567 mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); 568 569 return dsi_ctx.accum_err; 570 } 571 572 static int s6e88a0_ams427ap24_off(struct s6e88a0_ams427ap24 *ctx) 573 { 574 struct mipi_dsi_device *dsi = ctx->dsi; 575 struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 576 577 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 578 579 mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); 580 mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); 581 mipi_dsi_msleep(&dsi_ctx, 120); 582 583 return dsi_ctx.accum_err; 584 } 585 586 static int s6e88a0_ams427ap24_prepare(struct drm_panel *panel) 587 { 588 struct s6e88a0_ams427ap24 *ctx = to_s6e88a0_ams427ap24(panel); 589 struct device *dev = &ctx->dsi->dev; 590 int ret; 591 592 ret = regulator_bulk_enable(ARRAY_SIZE(s6e88a0_ams427ap24_supplies), 593 ctx->supplies); 594 if (ret < 0) { 595 dev_err(dev, "Failed to enable regulators: %d\n", ret); 596 return ret; 597 } 598 599 s6e88a0_ams427ap24_reset(ctx); 600 601 ret = s6e88a0_ams427ap24_on(ctx); 602 if (ret < 0) { 603 dev_err(dev, "Failed to initialize panel: %d\n", ret); 604 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 605 regulator_bulk_disable(ARRAY_SIZE(s6e88a0_ams427ap24_supplies), 606 ctx->supplies); 607 return ret; 608 } 609 610 return 0; 611 } 612 613 static int s6e88a0_ams427ap24_unprepare(struct drm_panel *panel) 614 { 615 struct s6e88a0_ams427ap24 *ctx = to_s6e88a0_ams427ap24(panel); 616 struct device *dev = &ctx->dsi->dev; 617 int ret; 618 619 ret = s6e88a0_ams427ap24_off(ctx); 620 if (ret < 0) 621 dev_err(dev, "Failed to un-initialize panel: %d\n", ret); 622 623 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 624 regulator_bulk_disable(ARRAY_SIZE(s6e88a0_ams427ap24_supplies), 625 ctx->supplies); 626 627 return 0; 628 } 629 630 static const struct drm_display_mode s6e88a0_ams427ap24_mode = { 631 .clock = (540 + 94 + 4 + 18) * (960 + 12 + 1 + 3) * 60 / 1000, 632 .hdisplay = 540, 633 .hsync_start = 540 + 94, 634 .hsync_end = 540 + 94 + 4, 635 .htotal = 540 + 94 + 4 + 18, 636 .vdisplay = 960, 637 .vsync_start = 960 + 12, 638 .vsync_end = 960 + 12 + 1, 639 .vtotal = 960 + 12 + 1 + 3, 640 .width_mm = 55, 641 .height_mm = 95, 642 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, 643 }; 644 645 static int s6e88a0_ams427ap24_get_modes(struct drm_panel *panel, 646 struct drm_connector *connector) 647 { 648 return drm_connector_helper_get_modes_fixed(connector, 649 &s6e88a0_ams427ap24_mode); 650 } 651 652 static const struct drm_panel_funcs s6e88a0_ams427ap24_panel_funcs = { 653 .prepare = s6e88a0_ams427ap24_prepare, 654 .unprepare = s6e88a0_ams427ap24_unprepare, 655 .get_modes = s6e88a0_ams427ap24_get_modes, 656 }; 657 658 static const struct backlight_ops s6e88a0_ams427ap24_bl_ops = { 659 .update_status = s6e88a0_ams427ap24_set_brightness, 660 }; 661 662 static int s6e88a0_ams427ap24_register_backlight(struct s6e88a0_ams427ap24 *ctx) 663 { 664 struct backlight_properties props = { 665 .type = BACKLIGHT_RAW, 666 .brightness = 180, 667 .max_brightness = 255, 668 }; 669 struct mipi_dsi_device *dsi = ctx->dsi; 670 struct device *dev = &dsi->dev; 671 int ret = 0; 672 673 ctx->bl_dev = devm_backlight_device_register(dev, dev_name(dev), dev, ctx, 674 &s6e88a0_ams427ap24_bl_ops, 675 &props); 676 if (IS_ERR(ctx->bl_dev)) { 677 ret = PTR_ERR(ctx->bl_dev); 678 dev_err(dev, "error registering backlight device (%d)\n", ret); 679 } 680 681 return ret; 682 } 683 684 static int s6e88a0_ams427ap24_probe(struct mipi_dsi_device *dsi) 685 { 686 struct device *dev = &dsi->dev; 687 struct s6e88a0_ams427ap24 *ctx; 688 int ret; 689 690 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 691 if (!ctx) 692 return -ENOMEM; 693 694 ret = devm_regulator_bulk_get_const(dev, 695 ARRAY_SIZE(s6e88a0_ams427ap24_supplies), 696 s6e88a0_ams427ap24_supplies, 697 &ctx->supplies); 698 if (ret < 0) 699 return ret; 700 701 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 702 if (IS_ERR(ctx->reset_gpio)) 703 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 704 "Failed to get reset-gpios\n"); 705 706 ctx->dsi = dsi; 707 mipi_dsi_set_drvdata(dsi, ctx); 708 709 dsi->lanes = 2; 710 dsi->format = MIPI_DSI_FMT_RGB888; 711 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 712 MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_VIDEO_NO_HFP; 713 714 drm_panel_init(&ctx->panel, dev, &s6e88a0_ams427ap24_panel_funcs, 715 DRM_MODE_CONNECTOR_DSI); 716 ctx->panel.prepare_prev_first = true; 717 718 ctx->flip_horizontal = device_property_read_bool(dev, "flip-horizontal"); 719 720 ret = s6e88a0_ams427ap24_register_backlight(ctx); 721 if (ret < 0) 722 return ret; 723 724 drm_panel_add(&ctx->panel); 725 726 ret = mipi_dsi_attach(dsi); 727 if (ret < 0) { 728 dev_err(dev, "Failed to attach to DSI host: %d\n", ret); 729 drm_panel_remove(&ctx->panel); 730 return ret; 731 } 732 733 return 0; 734 } 735 736 static void s6e88a0_ams427ap24_remove(struct mipi_dsi_device *dsi) 737 { 738 struct s6e88a0_ams427ap24 *ctx = mipi_dsi_get_drvdata(dsi); 739 int ret; 740 741 ret = mipi_dsi_detach(dsi); 742 if (ret < 0) 743 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); 744 745 drm_panel_remove(&ctx->panel); 746 } 747 748 static const struct of_device_id s6e88a0_ams427ap24_of_match[] = { 749 { .compatible = "samsung,s6e88a0-ams427ap24" }, 750 { /* sentinel */ }, 751 }; 752 MODULE_DEVICE_TABLE(of, s6e88a0_ams427ap24_of_match); 753 754 static struct mipi_dsi_driver s6e88a0_ams427ap24_driver = { 755 .probe = s6e88a0_ams427ap24_probe, 756 .remove = s6e88a0_ams427ap24_remove, 757 .driver = { 758 .name = "panel-s6e88a0-ams427ap24", 759 .of_match_table = s6e88a0_ams427ap24_of_match, 760 }, 761 }; 762 module_mipi_dsi_driver(s6e88a0_ams427ap24_driver); 763 764 MODULE_AUTHOR("Jakob Hauser <jahau@rocketmail.com>"); 765 MODULE_DESCRIPTION("Samsung AMS427AP24 panel with S6E88A0 controller"); 766 MODULE_LICENSE("GPL v2"); 767