1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020 BayLibre, SAS 4 * Author: Neil Armstrong <narmstrong@baylibre.com> 5 */ 6 7 #include <linux/delay.h> 8 #include <linux/gpio/consumer.h> 9 #include <linux/module.h> 10 #include <linux/of.h> 11 #include <linux/regulator/consumer.h> 12 13 #include <video/mipi_display.h> 14 15 #include <drm/drm_crtc.h> 16 #include <drm/drm_device.h> 17 #include <drm/drm_mipi_dsi.h> 18 #include <drm/drm_modes.h> 19 #include <drm/drm_panel.h> 20 21 struct khadas_ts050_panel { 22 struct drm_panel base; 23 struct mipi_dsi_device *link; 24 25 struct regulator *supply; 26 struct gpio_desc *reset_gpio; 27 struct gpio_desc *enable_gpio; 28 struct khadas_ts050_panel_data *panel_data; 29 }; 30 31 struct khadas_ts050_panel_cmd { 32 u8 cmd; 33 u8 data[55]; 34 u8 size; 35 }; 36 37 struct khadas_ts050_panel_data { 38 struct khadas_ts050_panel_cmd *init_code; 39 int len; 40 }; 41 42 static const struct khadas_ts050_panel_cmd ts050v2_init_code[] = { 43 {0xB9, {0xFF, 0x83, 0x99}, 0x03}, 44 {0xBA, {0x63, 0x23, 0x68, 0xCF}, 0x04}, 45 {0xD2, {0x55}, 0x01}, 46 {0xB1, {0x02, 0x04, 0x70, 0x90, 0x01, 0x32, 0x33, 47 0x11, 0x11, 0x4D, 0x57, 0x56, 0x73, 0x02, 0x02}, 0x0f}, 48 {0xB2, {0x00, 0x80, 0x80, 0xAE, 0x0A, 0x0E, 0x75, 0x11, 0x00, 0x00, 0x00}, 0x0b}, 49 {0xB4, {0x00, 0xFF, 0x04, 0xA4, 0x02, 0xA0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x02, 50 0x00, 0x24, 0x02, 0x04, 0x0A, 0x21, 0x03, 0x00, 0x00, 0x08, 0xA6, 0x88, 51 0x04, 0xA4, 0x02, 0xA0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x24, 52 0x02, 0x04, 0x0A, 0x00, 0x00, 0x08, 0xA6, 0x00, 0x08, 0x11}, 0x2e}, 53 {0xD3, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 54 0x18, 0x32, 0x10, 0x09, 0x00, 0x09, 0x32, 55 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 56 0x00, 0x00, 0x11, 0x00, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, 0x0A, 57 0x40}, 0x21}, 58 {0xD5, {0x18, 0x18, 0x18, 0x18, 0x21, 0x20, 0x18, 0x18, 0x19, 0x19, 0x19, 59 0x19, 0x18, 0x18, 0x18, 0x18, 0x03, 0x02, 0x01, 0x00, 0x2F, 0x2F, 60 0x30, 0x30, 0x31, 0x31, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, 0x20}, 61 {0xD6, {0x18, 0x18, 0x18, 0x18, 0x20, 0x21, 0x19, 0x19, 0x18, 0x18, 0x19, 62 0x19, 0x18, 0x18, 0x18, 0x18, 0x00, 0x01, 0x02, 0x03, 0x2F, 0x2F, 63 0x30, 0x30, 0x31, 0x31, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, 0x20}, 64 {0xD8, {0x0A, 0xBE, 0xFA, 0xA0, 0x0A, 0xBE, 0xFA, 0xA0}, 0x08}, 65 {0xBD, {0x01}, 0x01}, 66 {0xD8, {0x0F, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0xE0}, 0x08}, 67 {0xBD, {0x02}, 0x01}, 68 {0xD8, {0x0F, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0xE0}, 0x08}, 69 {0xBD, {0x00}, 0x01}, 70 {0xE0, {0x01, 0x35, 0x41, 0x3B, 0x79, 0x81, 0x8C, 0x85, 0x8E, 71 0x95, 0x9B, 0xA0, 0xA4, 0xAB, 0xB1, 0xB3, 0xB7, 0xC5, 0xBD, 0xC5, 72 0xB6, 0xC2, 0xC2, 0x62, 0x5D, 0x66, 0x73, 0x01, 0x35, 0x41, 0x3B, 73 0x79, 0x81, 0x8C, 0x85, 0x8E, 0x95, 0x9B, 0xA0, 0xA4, 0xAB, 0xB1, 74 0xB3, 0xB7, 0xB5, 0xBD, 0xC5, 0xB6, 0xC2, 0xC2, 0x62, 0x5D, 0x66, 75 0x73}, 0x36}, 76 {0xB6, {0x97, 0x97}, 0x02}, 77 {0xCC, {0xC8}, 0x02}, 78 {0xBF, {0x40, 0x41, 0x50, 0x19}, 0x04}, 79 {0xC6, {0xFF, 0xF9}, 0x02}, 80 {0xC0, {0x25, 0x5A}, 0x02}, 81 }; 82 83 /* Only the CMD1 User Command set is documented */ 84 static const struct khadas_ts050_panel_cmd ts050_init_code[] = { 85 /* Select Unknown CMD Page (Undocumented) */ 86 {0xff, {0xee}, 0x01}, 87 /* Reload CMD1: Don't reload default value to register */ 88 {0xfb, {0x01}, 0x01}, 89 {0x1f, {0x45}, 0x01}, 90 {0x24, {0x4f}, 0x01}, 91 {0x38, {0xc8}, 0x01}, 92 {0x39, {0x27}, 0x01}, 93 {0x1e, {0x77}, 0x01}, 94 {0x1d, {0x0f}, 0x01}, 95 {0x7e, {0x71}, 0x01}, 96 {0x7c, {0x03}, 0x01}, 97 {0xff, {0x00}, 0x01}, 98 {0xfb, {0x01}, 0x01}, 99 {0x35, {0x01}, 0x01}, 100 /* Select CMD2 Page0 (Undocumented) */ 101 {0xff, {0x01}, 0x01}, 102 /* Reload CMD1: Don't reload default value to register */ 103 {0xfb, {0x01}, 0x01}, 104 {0x00, {0x01}, 0x01}, 105 {0x01, {0x55}, 0x01}, 106 {0x02, {0x40}, 0x01}, 107 {0x05, {0x40}, 0x01}, 108 {0x06, {0x4a}, 0x01}, 109 {0x07, {0x24}, 0x01}, 110 {0x08, {0x0c}, 0x01}, 111 {0x0b, {0x7d}, 0x01}, 112 {0x0c, {0x7d}, 0x01}, 113 {0x0e, {0xb0}, 0x01}, 114 {0x0f, {0xae}, 0x01}, 115 {0x11, {0x10}, 0x01}, 116 {0x12, {0x10}, 0x01}, 117 {0x13, {0x03}, 0x01}, 118 {0x14, {0x4a}, 0x01}, 119 {0x15, {0x12}, 0x01}, 120 {0x16, {0x12}, 0x01}, 121 {0x18, {0x00}, 0x01}, 122 {0x19, {0x77}, 0x01}, 123 {0x1a, {0x55}, 0x01}, 124 {0x1b, {0x13}, 0x01}, 125 {0x1c, {0x00}, 0x01}, 126 {0x1d, {0x00}, 0x01}, 127 {0x1e, {0x13}, 0x01}, 128 {0x1f, {0x00}, 0x01}, 129 {0x23, {0x00}, 0x01}, 130 {0x24, {0x00}, 0x01}, 131 {0x25, {0x00}, 0x01}, 132 {0x26, {0x00}, 0x01}, 133 {0x27, {0x00}, 0x01}, 134 {0x28, {0x00}, 0x01}, 135 {0x35, {0x00}, 0x01}, 136 {0x66, {0x00}, 0x01}, 137 {0x58, {0x82}, 0x01}, 138 {0x59, {0x02}, 0x01}, 139 {0x5a, {0x02}, 0x01}, 140 {0x5b, {0x02}, 0x01}, 141 {0x5c, {0x82}, 0x01}, 142 {0x5d, {0x82}, 0x01}, 143 {0x5e, {0x02}, 0x01}, 144 {0x5f, {0x02}, 0x01}, 145 {0x72, {0x31}, 0x01}, 146 /* Select CMD2 Page4 (Undocumented) */ 147 {0xff, {0x05}, 0x01}, 148 /* Reload CMD1: Don't reload default value to register */ 149 {0xfb, {0x01}, 0x01}, 150 {0x00, {0x01}, 0x01}, 151 {0x01, {0x0b}, 0x01}, 152 {0x02, {0x0c}, 0x01}, 153 {0x03, {0x09}, 0x01}, 154 {0x04, {0x0a}, 0x01}, 155 {0x05, {0x00}, 0x01}, 156 {0x06, {0x0f}, 0x01}, 157 {0x07, {0x10}, 0x01}, 158 {0x08, {0x00}, 0x01}, 159 {0x09, {0x00}, 0x01}, 160 {0x0a, {0x00}, 0x01}, 161 {0x0b, {0x00}, 0x01}, 162 {0x0c, {0x00}, 0x01}, 163 {0x0d, {0x13}, 0x01}, 164 {0x0e, {0x15}, 0x01}, 165 {0x0f, {0x17}, 0x01}, 166 {0x10, {0x01}, 0x01}, 167 {0x11, {0x0b}, 0x01}, 168 {0x12, {0x0c}, 0x01}, 169 {0x13, {0x09}, 0x01}, 170 {0x14, {0x0a}, 0x01}, 171 {0x15, {0x00}, 0x01}, 172 {0x16, {0x0f}, 0x01}, 173 {0x17, {0x10}, 0x01}, 174 {0x18, {0x00}, 0x01}, 175 {0x19, {0x00}, 0x01}, 176 {0x1a, {0x00}, 0x01}, 177 {0x1b, {0x00}, 0x01}, 178 {0x1c, {0x00}, 0x01}, 179 {0x1d, {0x13}, 0x01}, 180 {0x1e, {0x15}, 0x01}, 181 {0x1f, {0x17}, 0x01}, 182 {0x20, {0x00}, 0x01}, 183 {0x21, {0x03}, 0x01}, 184 {0x22, {0x01}, 0x01}, 185 {0x23, {0x40}, 0x01}, 186 {0x24, {0x40}, 0x01}, 187 {0x25, {0xed}, 0x01}, 188 {0x29, {0x58}, 0x01}, 189 {0x2a, {0x12}, 0x01}, 190 {0x2b, {0x01}, 0x01}, 191 {0x4b, {0x06}, 0x01}, 192 {0x4c, {0x11}, 0x01}, 193 {0x4d, {0x20}, 0x01}, 194 {0x4e, {0x02}, 0x01}, 195 {0x4f, {0x02}, 0x01}, 196 {0x50, {0x20}, 0x01}, 197 {0x51, {0x61}, 0x01}, 198 {0x52, {0x01}, 0x01}, 199 {0x53, {0x63}, 0x01}, 200 {0x54, {0x77}, 0x01}, 201 {0x55, {0xed}, 0x01}, 202 {0x5b, {0x00}, 0x01}, 203 {0x5c, {0x00}, 0x01}, 204 {0x5d, {0x00}, 0x01}, 205 {0x5e, {0x00}, 0x01}, 206 {0x5f, {0x15}, 0x01}, 207 {0x60, {0x75}, 0x01}, 208 {0x61, {0x00}, 0x01}, 209 {0x62, {0x00}, 0x01}, 210 {0x63, {0x00}, 0x01}, 211 {0x64, {0x00}, 0x01}, 212 {0x65, {0x00}, 0x01}, 213 {0x66, {0x00}, 0x01}, 214 {0x67, {0x00}, 0x01}, 215 {0x68, {0x04}, 0x01}, 216 {0x69, {0x00}, 0x01}, 217 {0x6a, {0x00}, 0x01}, 218 {0x6c, {0x40}, 0x01}, 219 {0x75, {0x01}, 0x01}, 220 {0x76, {0x01}, 0x01}, 221 {0x7a, {0x80}, 0x01}, 222 {0x7b, {0xa3}, 0x01}, 223 {0x7c, {0xd8}, 0x01}, 224 {0x7d, {0x60}, 0x01}, 225 {0x7f, {0x15}, 0x01}, 226 {0x80, {0x81}, 0x01}, 227 {0x83, {0x05}, 0x01}, 228 {0x93, {0x08}, 0x01}, 229 {0x94, {0x10}, 0x01}, 230 {0x8a, {0x00}, 0x01}, 231 {0x9b, {0x0f}, 0x01}, 232 {0xea, {0xff}, 0x01}, 233 {0xec, {0x00}, 0x01}, 234 /* Select CMD2 Page0 (Undocumented) */ 235 {0xff, {0x01}, 0x01}, 236 /* Reload CMD1: Don't reload default value to register */ 237 {0xfb, {0x01}, 0x01}, 238 {0x75, {0x00}, 0x01}, 239 {0x76, {0xdf}, 0x01}, 240 {0x77, {0x00}, 0x01}, 241 {0x78, {0xe4}, 0x01}, 242 {0x79, {0x00}, 0x01}, 243 {0x7a, {0xed}, 0x01}, 244 {0x7b, {0x00}, 0x01}, 245 {0x7c, {0xf6}, 0x01}, 246 {0x7d, {0x00}, 0x01}, 247 {0x7e, {0xff}, 0x01}, 248 {0x7f, {0x01}, 0x01}, 249 {0x80, {0x07}, 0x01}, 250 {0x81, {0x01}, 0x01}, 251 {0x82, {0x10}, 0x01}, 252 {0x83, {0x01}, 0x01}, 253 {0x84, {0x18}, 0x01}, 254 {0x85, {0x01}, 0x01}, 255 {0x86, {0x20}, 0x01}, 256 {0x87, {0x01}, 0x01}, 257 {0x88, {0x3d}, 0x01}, 258 {0x89, {0x01}, 0x01}, 259 {0x8a, {0x56}, 0x01}, 260 {0x8b, {0x01}, 0x01}, 261 {0x8c, {0x84}, 0x01}, 262 {0x8d, {0x01}, 0x01}, 263 {0x8e, {0xab}, 0x01}, 264 {0x8f, {0x01}, 0x01}, 265 {0x90, {0xec}, 0x01}, 266 {0x91, {0x02}, 0x01}, 267 {0x92, {0x22}, 0x01}, 268 {0x93, {0x02}, 0x01}, 269 {0x94, {0x23}, 0x01}, 270 {0x95, {0x02}, 0x01}, 271 {0x96, {0x55}, 0x01}, 272 {0x97, {0x02}, 0x01}, 273 {0x98, {0x8b}, 0x01}, 274 {0x99, {0x02}, 0x01}, 275 {0x9a, {0xaf}, 0x01}, 276 {0x9b, {0x02}, 0x01}, 277 {0x9c, {0xdf}, 0x01}, 278 {0x9d, {0x03}, 0x01}, 279 {0x9e, {0x01}, 0x01}, 280 {0x9f, {0x03}, 0x01}, 281 {0xa0, {0x2c}, 0x01}, 282 {0xa2, {0x03}, 0x01}, 283 {0xa3, {0x39}, 0x01}, 284 {0xa4, {0x03}, 0x01}, 285 {0xa5, {0x47}, 0x01}, 286 {0xa6, {0x03}, 0x01}, 287 {0xa7, {0x56}, 0x01}, 288 {0xa9, {0x03}, 0x01}, 289 {0xaa, {0x66}, 0x01}, 290 {0xab, {0x03}, 0x01}, 291 {0xac, {0x76}, 0x01}, 292 {0xad, {0x03}, 0x01}, 293 {0xae, {0x85}, 0x01}, 294 {0xaf, {0x03}, 0x01}, 295 {0xb0, {0x90}, 0x01}, 296 {0xb1, {0x03}, 0x01}, 297 {0xb2, {0xcb}, 0x01}, 298 {0xb3, {0x00}, 0x01}, 299 {0xb4, {0xdf}, 0x01}, 300 {0xb5, {0x00}, 0x01}, 301 {0xb6, {0xe4}, 0x01}, 302 {0xb7, {0x00}, 0x01}, 303 {0xb8, {0xed}, 0x01}, 304 {0xb9, {0x00}, 0x01}, 305 {0xba, {0xf6}, 0x01}, 306 {0xbb, {0x00}, 0x01}, 307 {0xbc, {0xff}, 0x01}, 308 {0xbd, {0x01}, 0x01}, 309 {0xbe, {0x07}, 0x01}, 310 {0xbf, {0x01}, 0x01}, 311 {0xc0, {0x10}, 0x01}, 312 {0xc1, {0x01}, 0x01}, 313 {0xc2, {0x18}, 0x01}, 314 {0xc3, {0x01}, 0x01}, 315 {0xc4, {0x20}, 0x01}, 316 {0xc5, {0x01}, 0x01}, 317 {0xc6, {0x3d}, 0x01}, 318 {0xc7, {0x01}, 0x01}, 319 {0xc8, {0x56}, 0x01}, 320 {0xc9, {0x01}, 0x01}, 321 {0xca, {0x84}, 0x01}, 322 {0xcb, {0x01}, 0x01}, 323 {0xcc, {0xab}, 0x01}, 324 {0xcd, {0x01}, 0x01}, 325 {0xce, {0xec}, 0x01}, 326 {0xcf, {0x02}, 0x01}, 327 {0xd0, {0x22}, 0x01}, 328 {0xd1, {0x02}, 0x01}, 329 {0xd2, {0x23}, 0x01}, 330 {0xd3, {0x02}, 0x01}, 331 {0xd4, {0x55}, 0x01}, 332 {0xd5, {0x02}, 0x01}, 333 {0xd6, {0x8b}, 0x01}, 334 {0xd7, {0x02}, 0x01}, 335 {0xd8, {0xaf}, 0x01}, 336 {0xd9, {0x02}, 0x01}, 337 {0xda, {0xdf}, 0x01}, 338 {0xdb, {0x03}, 0x01}, 339 {0xdc, {0x01}, 0x01}, 340 {0xdd, {0x03}, 0x01}, 341 {0xde, {0x2c}, 0x01}, 342 {0xdf, {0x03}, 0x01}, 343 {0xe0, {0x39}, 0x01}, 344 {0xe1, {0x03}, 0x01}, 345 {0xe2, {0x47}, 0x01}, 346 {0xe3, {0x03}, 0x01}, 347 {0xe4, {0x56}, 0x01}, 348 {0xe5, {0x03}, 0x01}, 349 {0xe6, {0x66}, 0x01}, 350 {0xe7, {0x03}, 0x01}, 351 {0xe8, {0x76}, 0x01}, 352 {0xe9, {0x03}, 0x01}, 353 {0xea, {0x85}, 0x01}, 354 {0xeb, {0x03}, 0x01}, 355 {0xec, {0x90}, 0x01}, 356 {0xed, {0x03}, 0x01}, 357 {0xee, {0xcb}, 0x01}, 358 {0xef, {0x00}, 0x01}, 359 {0xf0, {0xbb}, 0x01}, 360 {0xf1, {0x00}, 0x01}, 361 {0xf2, {0xc0}, 0x01}, 362 {0xf3, {0x00}, 0x01}, 363 {0xf4, {0xcc}, 0x01}, 364 {0xf5, {0x00}, 0x01}, 365 {0xf6, {0xd6}, 0x01}, 366 {0xf7, {0x00}, 0x01}, 367 {0xf8, {0xe1}, 0x01}, 368 {0xf9, {0x00}, 0x01}, 369 {0xfa, {0xea}, 0x01}, 370 /* Select CMD2 Page2 (Undocumented) */ 371 {0xff, {0x02}, 0x01}, 372 /* Reload CMD1: Don't reload default value to register */ 373 {0xfb, {0x01}, 0x01}, 374 {0x00, {0x00}, 0x01}, 375 {0x01, {0xf4}, 0x01}, 376 {0x02, {0x00}, 0x01}, 377 {0x03, {0xef}, 0x01}, 378 {0x04, {0x01}, 0x01}, 379 {0x05, {0x07}, 0x01}, 380 {0x06, {0x01}, 0x01}, 381 {0x07, {0x28}, 0x01}, 382 {0x08, {0x01}, 0x01}, 383 {0x09, {0x44}, 0x01}, 384 {0x0a, {0x01}, 0x01}, 385 {0x0b, {0x76}, 0x01}, 386 {0x0c, {0x01}, 0x01}, 387 {0x0d, {0xa0}, 0x01}, 388 {0x0e, {0x01}, 0x01}, 389 {0x0f, {0xe7}, 0x01}, 390 {0x10, {0x02}, 0x01}, 391 {0x11, {0x1f}, 0x01}, 392 {0x12, {0x02}, 0x01}, 393 {0x13, {0x22}, 0x01}, 394 {0x14, {0x02}, 0x01}, 395 {0x15, {0x54}, 0x01}, 396 {0x16, {0x02}, 0x01}, 397 {0x17, {0x8b}, 0x01}, 398 {0x18, {0x02}, 0x01}, 399 {0x19, {0xaf}, 0x01}, 400 {0x1a, {0x02}, 0x01}, 401 {0x1b, {0xe0}, 0x01}, 402 {0x1c, {0x03}, 0x01}, 403 {0x1d, {0x01}, 0x01}, 404 {0x1e, {0x03}, 0x01}, 405 {0x1f, {0x2d}, 0x01}, 406 {0x20, {0x03}, 0x01}, 407 {0x21, {0x39}, 0x01}, 408 {0x22, {0x03}, 0x01}, 409 {0x23, {0x47}, 0x01}, 410 {0x24, {0x03}, 0x01}, 411 {0x25, {0x57}, 0x01}, 412 {0x26, {0x03}, 0x01}, 413 {0x27, {0x65}, 0x01}, 414 {0x28, {0x03}, 0x01}, 415 {0x29, {0x77}, 0x01}, 416 {0x2a, {0x03}, 0x01}, 417 {0x2b, {0x85}, 0x01}, 418 {0x2d, {0x03}, 0x01}, 419 {0x2f, {0x8f}, 0x01}, 420 {0x30, {0x03}, 0x01}, 421 {0x31, {0xcb}, 0x01}, 422 {0x32, {0x00}, 0x01}, 423 {0x33, {0xbb}, 0x01}, 424 {0x34, {0x00}, 0x01}, 425 {0x35, {0xc0}, 0x01}, 426 {0x36, {0x00}, 0x01}, 427 {0x37, {0xcc}, 0x01}, 428 {0x38, {0x00}, 0x01}, 429 {0x39, {0xd6}, 0x01}, 430 {0x3a, {0x00}, 0x01}, 431 {0x3b, {0xe1}, 0x01}, 432 {0x3d, {0x00}, 0x01}, 433 {0x3f, {0xea}, 0x01}, 434 {0x40, {0x00}, 0x01}, 435 {0x41, {0xf4}, 0x01}, 436 {0x42, {0x00}, 0x01}, 437 {0x43, {0xfe}, 0x01}, 438 {0x44, {0x01}, 0x01}, 439 {0x45, {0x07}, 0x01}, 440 {0x46, {0x01}, 0x01}, 441 {0x47, {0x28}, 0x01}, 442 {0x48, {0x01}, 0x01}, 443 {0x49, {0x44}, 0x01}, 444 {0x4a, {0x01}, 0x01}, 445 {0x4b, {0x76}, 0x01}, 446 {0x4c, {0x01}, 0x01}, 447 {0x4d, {0xa0}, 0x01}, 448 {0x4e, {0x01}, 0x01}, 449 {0x4f, {0xe7}, 0x01}, 450 {0x50, {0x02}, 0x01}, 451 {0x51, {0x1f}, 0x01}, 452 {0x52, {0x02}, 0x01}, 453 {0x53, {0x22}, 0x01}, 454 {0x54, {0x02}, 0x01}, 455 {0x55, {0x54}, 0x01}, 456 {0x56, {0x02}, 0x01}, 457 {0x58, {0x8b}, 0x01}, 458 {0x59, {0x02}, 0x01}, 459 {0x5a, {0xaf}, 0x01}, 460 {0x5b, {0x02}, 0x01}, 461 {0x5c, {0xe0}, 0x01}, 462 {0x5d, {0x03}, 0x01}, 463 {0x5e, {0x01}, 0x01}, 464 {0x5f, {0x03}, 0x01}, 465 {0x60, {0x2d}, 0x01}, 466 {0x61, {0x03}, 0x01}, 467 {0x62, {0x39}, 0x01}, 468 {0x63, {0x03}, 0x01}, 469 {0x64, {0x47}, 0x01}, 470 {0x65, {0x03}, 0x01}, 471 {0x66, {0x57}, 0x01}, 472 {0x67, {0x03}, 0x01}, 473 {0x68, {0x65}, 0x01}, 474 {0x69, {0x03}, 0x01}, 475 {0x6a, {0x77}, 0x01}, 476 {0x6b, {0x03}, 0x01}, 477 {0x6c, {0x85}, 0x01}, 478 {0x6d, {0x03}, 0x01}, 479 {0x6e, {0x8f}, 0x01}, 480 {0x6f, {0x03}, 0x01}, 481 {0x70, {0xcb}, 0x01}, 482 {0x71, {0x00}, 0x01}, 483 {0x72, {0x00}, 0x01}, 484 {0x73, {0x00}, 0x01}, 485 {0x74, {0x21}, 0x01}, 486 {0x75, {0x00}, 0x01}, 487 {0x76, {0x4c}, 0x01}, 488 {0x77, {0x00}, 0x01}, 489 {0x78, {0x6b}, 0x01}, 490 {0x79, {0x00}, 0x01}, 491 {0x7a, {0x85}, 0x01}, 492 {0x7b, {0x00}, 0x01}, 493 {0x7c, {0x9a}, 0x01}, 494 {0x7d, {0x00}, 0x01}, 495 {0x7e, {0xad}, 0x01}, 496 {0x7f, {0x00}, 0x01}, 497 {0x80, {0xbe}, 0x01}, 498 {0x81, {0x00}, 0x01}, 499 {0x82, {0xcd}, 0x01}, 500 {0x83, {0x01}, 0x01}, 501 {0x84, {0x01}, 0x01}, 502 {0x85, {0x01}, 0x01}, 503 {0x86, {0x29}, 0x01}, 504 {0x87, {0x01}, 0x01}, 505 {0x88, {0x68}, 0x01}, 506 {0x89, {0x01}, 0x01}, 507 {0x8a, {0x98}, 0x01}, 508 {0x8b, {0x01}, 0x01}, 509 {0x8c, {0xe5}, 0x01}, 510 {0x8d, {0x02}, 0x01}, 511 {0x8e, {0x1e}, 0x01}, 512 {0x8f, {0x02}, 0x01}, 513 {0x90, {0x30}, 0x01}, 514 {0x91, {0x02}, 0x01}, 515 {0x92, {0x52}, 0x01}, 516 {0x93, {0x02}, 0x01}, 517 {0x94, {0x88}, 0x01}, 518 {0x95, {0x02}, 0x01}, 519 {0x96, {0xaa}, 0x01}, 520 {0x97, {0x02}, 0x01}, 521 {0x98, {0xd7}, 0x01}, 522 {0x99, {0x02}, 0x01}, 523 {0x9a, {0xf7}, 0x01}, 524 {0x9b, {0x03}, 0x01}, 525 {0x9c, {0x21}, 0x01}, 526 {0x9d, {0x03}, 0x01}, 527 {0x9e, {0x2e}, 0x01}, 528 {0x9f, {0x03}, 0x01}, 529 {0xa0, {0x3d}, 0x01}, 530 {0xa2, {0x03}, 0x01}, 531 {0xa3, {0x4c}, 0x01}, 532 {0xa4, {0x03}, 0x01}, 533 {0xa5, {0x5e}, 0x01}, 534 {0xa6, {0x03}, 0x01}, 535 {0xa7, {0x71}, 0x01}, 536 {0xa9, {0x03}, 0x01}, 537 {0xaa, {0x86}, 0x01}, 538 {0xab, {0x03}, 0x01}, 539 {0xac, {0x94}, 0x01}, 540 {0xad, {0x03}, 0x01}, 541 {0xae, {0xfa}, 0x01}, 542 {0xaf, {0x00}, 0x01}, 543 {0xb0, {0x00}, 0x01}, 544 {0xb1, {0x00}, 0x01}, 545 {0xb2, {0x21}, 0x01}, 546 {0xb3, {0x00}, 0x01}, 547 {0xb4, {0x4c}, 0x01}, 548 {0xb5, {0x00}, 0x01}, 549 {0xb6, {0x6b}, 0x01}, 550 {0xb7, {0x00}, 0x01}, 551 {0xb8, {0x85}, 0x01}, 552 {0xb9, {0x00}, 0x01}, 553 {0xba, {0x9a}, 0x01}, 554 {0xbb, {0x00}, 0x01}, 555 {0xbc, {0xad}, 0x01}, 556 {0xbd, {0x00}, 0x01}, 557 {0xbe, {0xbe}, 0x01}, 558 {0xbf, {0x00}, 0x01}, 559 {0xc0, {0xcd}, 0x01}, 560 {0xc1, {0x01}, 0x01}, 561 {0xc2, {0x01}, 0x01}, 562 {0xc3, {0x01}, 0x01}, 563 {0xc4, {0x29}, 0x01}, 564 {0xc5, {0x01}, 0x01}, 565 {0xc6, {0x68}, 0x01}, 566 {0xc7, {0x01}, 0x01}, 567 {0xc8, {0x98}, 0x01}, 568 {0xc9, {0x01}, 0x01}, 569 {0xca, {0xe5}, 0x01}, 570 {0xcb, {0x02}, 0x01}, 571 {0xcc, {0x1e}, 0x01}, 572 {0xcd, {0x02}, 0x01}, 573 {0xce, {0x20}, 0x01}, 574 {0xcf, {0x02}, 0x01}, 575 {0xd0, {0x52}, 0x01}, 576 {0xd1, {0x02}, 0x01}, 577 {0xd2, {0x88}, 0x01}, 578 {0xd3, {0x02}, 0x01}, 579 {0xd4, {0xaa}, 0x01}, 580 {0xd5, {0x02}, 0x01}, 581 {0xd6, {0xd7}, 0x01}, 582 {0xd7, {0x02}, 0x01}, 583 {0xd8, {0xf7}, 0x01}, 584 {0xd9, {0x03}, 0x01}, 585 {0xda, {0x21}, 0x01}, 586 {0xdb, {0x03}, 0x01}, 587 {0xdc, {0x2e}, 0x01}, 588 {0xdd, {0x03}, 0x01}, 589 {0xde, {0x3d}, 0x01}, 590 {0xdf, {0x03}, 0x01}, 591 {0xe0, {0x4c}, 0x01}, 592 {0xe1, {0x03}, 0x01}, 593 {0xe2, {0x5e}, 0x01}, 594 {0xe3, {0x03}, 0x01}, 595 {0xe4, {0x71}, 0x01}, 596 {0xe5, {0x03}, 0x01}, 597 {0xe6, {0x86}, 0x01}, 598 {0xe7, {0x03}, 0x01}, 599 {0xe8, {0x94}, 0x01}, 600 {0xe9, {0x03}, 0x01}, 601 {0xea, {0xfa}, 0x01}, 602 /* Select CMD2 Page0 (Undocumented) */ 603 {0xff, {0x01}, 0x01}, 604 /* Reload CMD1: Don't reload default value to register */ 605 {0xfb, {0x01}, 0x01}, 606 /* Select CMD2 Page1 (Undocumented) */ 607 {0xff, {0x02}, 0x01}, 608 /* Reload CMD1: Don't reload default value to register */ 609 {0xfb, {0x01}, 0x01}, 610 /* Select CMD2 Page3 (Undocumented) */ 611 {0xff, {0x04}, 0x01}, 612 /* Reload CMD1: Don't reload default value to register */ 613 {0xfb, {0x01}, 0x01}, 614 /* Select CMD1 */ 615 {0xff, {0x00}, 0x01}, 616 {0xd3, {0x22}, 0x01}, /* RGBMIPICTRL: VSYNC back porch = 34 */ 617 {0xd4, {0x04}, 0x01}, /* RGBMIPICTRL: VSYNC front porch = 4 */ 618 }; 619 620 struct khadas_ts050_panel_data ts050_panel_data = { 621 .init_code = (struct khadas_ts050_panel_cmd *)ts050_init_code, 622 .len = ARRAY_SIZE(ts050_init_code) 623 }; 624 625 struct khadas_ts050_panel_data ts050v2_panel_data = { 626 .init_code = (struct khadas_ts050_panel_cmd *)ts050v2_init_code, 627 .len = ARRAY_SIZE(ts050v2_init_code) 628 }; 629 630 static inline 631 struct khadas_ts050_panel *to_khadas_ts050_panel(struct drm_panel *panel) 632 { 633 return container_of(panel, struct khadas_ts050_panel, base); 634 } 635 636 static int khadas_ts050_panel_prepare(struct drm_panel *panel) 637 { 638 struct khadas_ts050_panel *khadas_ts050 = to_khadas_ts050_panel(panel); 639 unsigned int i; 640 int err; 641 642 gpiod_set_value_cansleep(khadas_ts050->enable_gpio, 0); 643 644 err = regulator_enable(khadas_ts050->supply); 645 if (err < 0) 646 return err; 647 648 gpiod_set_value_cansleep(khadas_ts050->enable_gpio, 1); 649 650 msleep(60); 651 652 gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 1); 653 654 usleep_range(10000, 11000); 655 656 gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 0); 657 658 /* Select CMD2 page 4 (Undocumented) */ 659 mipi_dsi_dcs_write(khadas_ts050->link, 0xff, (u8[]){ 0x05 }, 1); 660 661 /* Reload CMD1: Don't reload default value to register */ 662 mipi_dsi_dcs_write(khadas_ts050->link, 0xfb, (u8[]){ 0x01 }, 1); 663 664 mipi_dsi_dcs_write(khadas_ts050->link, 0xc5, (u8[]){ 0x01 }, 1); 665 666 msleep(100); 667 668 for (i = 0; i < khadas_ts050->panel_data->len; i++) { 669 err = mipi_dsi_dcs_write(khadas_ts050->link, 670 khadas_ts050->panel_data->init_code[i].cmd, 671 &khadas_ts050->panel_data->init_code[i].data, 672 khadas_ts050->panel_data->init_code[i].size); 673 if (err < 0) { 674 dev_err(panel->dev, "failed write cmds: %d\n", err); 675 goto poweroff; 676 } 677 } 678 679 err = mipi_dsi_dcs_exit_sleep_mode(khadas_ts050->link); 680 if (err < 0) { 681 dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); 682 goto poweroff; 683 } 684 685 msleep(120); 686 687 /* Select CMD1 */ 688 mipi_dsi_dcs_write(khadas_ts050->link, 0xff, (u8[]){ 0x00 }, 1); 689 690 err = mipi_dsi_dcs_set_tear_on(khadas_ts050->link, 691 MIPI_DSI_DCS_TEAR_MODE_VBLANK); 692 if (err < 0) { 693 dev_err(panel->dev, "failed to set tear on: %d\n", err); 694 goto poweroff; 695 } 696 697 err = mipi_dsi_dcs_set_display_on(khadas_ts050->link); 698 if (err < 0) { 699 dev_err(panel->dev, "failed to set display on: %d\n", err); 700 goto poweroff; 701 } 702 703 usleep_range(10000, 11000); 704 705 return 0; 706 707 poweroff: 708 gpiod_set_value_cansleep(khadas_ts050->enable_gpio, 0); 709 gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 1); 710 711 regulator_disable(khadas_ts050->supply); 712 713 return err; 714 } 715 716 static int khadas_ts050_panel_unprepare(struct drm_panel *panel) 717 { 718 struct khadas_ts050_panel *khadas_ts050 = to_khadas_ts050_panel(panel); 719 int err; 720 721 err = mipi_dsi_dcs_enter_sleep_mode(khadas_ts050->link); 722 if (err < 0) 723 dev_err(panel->dev, "failed to enter sleep mode: %d\n", err); 724 725 msleep(150); 726 727 gpiod_set_value_cansleep(khadas_ts050->enable_gpio, 0); 728 gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 1); 729 730 err = regulator_disable(khadas_ts050->supply); 731 if (err < 0) 732 return err; 733 734 return 0; 735 } 736 737 static int khadas_ts050_panel_disable(struct drm_panel *panel) 738 { 739 struct khadas_ts050_panel *khadas_ts050 = to_khadas_ts050_panel(panel); 740 int err; 741 742 err = mipi_dsi_dcs_set_display_off(khadas_ts050->link); 743 if (err < 0) 744 dev_err(panel->dev, "failed to set display off: %d\n", err); 745 746 usleep_range(10000, 11000); 747 748 return 0; 749 } 750 751 static const struct drm_display_mode default_mode = { 752 .clock = 160000, 753 .hdisplay = 1080, 754 .hsync_start = 1080 + 117, 755 .hsync_end = 1080 + 117 + 5, 756 .htotal = 1080 + 117 + 5 + 160, 757 .vdisplay = 1920, 758 .vsync_start = 1920 + 4, 759 .vsync_end = 1920 + 4 + 3, 760 .vtotal = 1920 + 4 + 3 + 31, 761 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, 762 }; 763 764 static int khadas_ts050_panel_get_modes(struct drm_panel *panel, 765 struct drm_connector *connector) 766 { 767 struct drm_display_mode *mode; 768 769 mode = drm_mode_duplicate(connector->dev, &default_mode); 770 if (!mode) { 771 dev_err(panel->dev, "failed to add mode %ux%u@%u\n", 772 default_mode.hdisplay, default_mode.vdisplay, 773 drm_mode_vrefresh(&default_mode)); 774 return -ENOMEM; 775 } 776 777 drm_mode_set_name(mode); 778 779 drm_mode_probed_add(connector, mode); 780 781 connector->display_info.width_mm = 64; 782 connector->display_info.height_mm = 118; 783 connector->display_info.bpc = 8; 784 785 return 1; 786 } 787 788 static const struct drm_panel_funcs khadas_ts050_panel_funcs = { 789 .prepare = khadas_ts050_panel_prepare, 790 .unprepare = khadas_ts050_panel_unprepare, 791 .disable = khadas_ts050_panel_disable, 792 .get_modes = khadas_ts050_panel_get_modes, 793 }; 794 795 static const struct of_device_id khadas_ts050_of_match[] = { 796 { .compatible = "khadas,ts050", .data = &ts050_panel_data, }, 797 { .compatible = "khadas,ts050v2", .data = &ts050v2_panel_data, }, 798 { /* sentinel */ } 799 }; 800 MODULE_DEVICE_TABLE(of, khadas_ts050_of_match); 801 802 static int khadas_ts050_panel_add(struct khadas_ts050_panel *khadas_ts050) 803 { 804 struct device *dev = &khadas_ts050->link->dev; 805 int err; 806 807 khadas_ts050->supply = devm_regulator_get(dev, "power"); 808 if (IS_ERR(khadas_ts050->supply)) 809 return dev_err_probe(dev, PTR_ERR(khadas_ts050->supply), 810 "failed to get power supply"); 811 812 khadas_ts050->reset_gpio = devm_gpiod_get(dev, "reset", 813 GPIOD_OUT_LOW); 814 if (IS_ERR(khadas_ts050->reset_gpio)) 815 return dev_err_probe(dev, PTR_ERR(khadas_ts050->reset_gpio), 816 "failed to get reset gpio"); 817 818 khadas_ts050->enable_gpio = devm_gpiod_get(dev, "enable", 819 GPIOD_OUT_HIGH); 820 if (IS_ERR(khadas_ts050->enable_gpio)) 821 return dev_err_probe(dev, PTR_ERR(khadas_ts050->enable_gpio), 822 "failed to get enable gpio"); 823 824 drm_panel_init(&khadas_ts050->base, &khadas_ts050->link->dev, 825 &khadas_ts050_panel_funcs, DRM_MODE_CONNECTOR_DSI); 826 827 err = drm_panel_of_backlight(&khadas_ts050->base); 828 if (err) 829 return err; 830 831 drm_panel_add(&khadas_ts050->base); 832 833 return 0; 834 } 835 836 static int khadas_ts050_panel_probe(struct mipi_dsi_device *dsi) 837 { 838 struct khadas_ts050_panel *khadas_ts050; 839 int err; 840 841 const void *data = of_device_get_match_data(&dsi->dev); 842 843 if (!data) { 844 dev_err(&dsi->dev, "No matching data\n"); 845 return -ENODEV; 846 } 847 848 dsi->lanes = 4; 849 dsi->format = MIPI_DSI_FMT_RGB888; 850 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 851 MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; 852 853 khadas_ts050 = devm_kzalloc(&dsi->dev, sizeof(*khadas_ts050), 854 GFP_KERNEL); 855 if (!khadas_ts050) 856 return -ENOMEM; 857 858 khadas_ts050->panel_data = (struct khadas_ts050_panel_data *)data; 859 mipi_dsi_set_drvdata(dsi, khadas_ts050); 860 khadas_ts050->link = dsi; 861 862 err = khadas_ts050_panel_add(khadas_ts050); 863 if (err < 0) 864 return err; 865 866 err = mipi_dsi_attach(dsi); 867 if (err) 868 drm_panel_remove(&khadas_ts050->base); 869 870 return err; 871 } 872 873 static void khadas_ts050_panel_remove(struct mipi_dsi_device *dsi) 874 { 875 struct khadas_ts050_panel *khadas_ts050 = mipi_dsi_get_drvdata(dsi); 876 int err; 877 878 err = mipi_dsi_detach(dsi); 879 if (err < 0) 880 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); 881 882 drm_panel_remove(&khadas_ts050->base); 883 } 884 885 static struct mipi_dsi_driver khadas_ts050_panel_driver = { 886 .driver = { 887 .name = "panel-khadas-ts050", 888 .of_match_table = khadas_ts050_of_match, 889 }, 890 .probe = khadas_ts050_panel_probe, 891 .remove = khadas_ts050_panel_remove, 892 }; 893 module_mipi_dsi_driver(khadas_ts050_panel_driver); 894 895 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); 896 MODULE_DESCRIPTION("Khadas TS050 panel driver"); 897 MODULE_LICENSE("GPL v2"); 898