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