700 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Panels based on the Ilitek ILI9882T display controller.4 */5#include <linux/delay.h>6#include <linux/gpio/consumer.h>7#include <linux/module.h>8#include <linux/of.h>9#include <linux/regulator/consumer.h>10 11#include <drm/drm_connector.h>12#include <drm/drm_crtc.h>13#include <drm/drm_mipi_dsi.h>14#include <drm/drm_panel.h>15 16#include <video/mipi_display.h>17 18struct ili9882t;19 20/*21 * Use this descriptor struct to describe different panels using the22 * Ilitek ILI9882T display controller.23 */24struct panel_desc {25 const struct drm_display_mode *modes;26 unsigned int bpc;27 28 /**29 * @width_mm: width of the panel's active display area30 * @height_mm: height of the panel's active display area31 */32 struct {33 unsigned int width_mm;34 unsigned int height_mm;35 } size;36 37 unsigned long mode_flags;38 enum mipi_dsi_pixel_format format;39 int (*init)(struct ili9882t *boe);40 unsigned int lanes;41};42 43struct ili9882t {44 struct drm_panel base;45 struct mipi_dsi_device *dsi;46 47 const struct panel_desc *desc;48 49 enum drm_panel_orientation orientation;50 struct regulator *pp3300;51 struct regulator *pp1800;52 struct regulator *avee;53 struct regulator *avdd;54 struct gpio_desc *enable_gpio;55};56 57/* ILI9882-specific commands, add new commands as you decode them */58#define ILI9882T_DCS_SWITCH_PAGE 0xFF59 60#define ili9882t_switch_page(ctx, page) \61 mipi_dsi_dcs_write_seq_multi(ctx, ILI9882T_DCS_SWITCH_PAGE, \62 0x98, 0x82, (page))63 64static int starry_ili9882t_init(struct ili9882t *ili)65{66 struct mipi_dsi_multi_context ctx = { .dsi = ili->dsi };67 68 usleep_range(5000, 5100);69 70 ili9882t_switch_page(&ctx, 0x01);71 mipi_dsi_dcs_write_seq_multi(&ctx, 0x00, 0x42);72 mipi_dsi_dcs_write_seq_multi(&ctx, 0x01, 0x11);73 mipi_dsi_dcs_write_seq_multi(&ctx, 0x02, 0x00);74 mipi_dsi_dcs_write_seq_multi(&ctx, 0x03, 0x00);75 76 mipi_dsi_dcs_write_seq_multi(&ctx, 0x04, 0x01);77 mipi_dsi_dcs_write_seq_multi(&ctx, 0x05, 0x11);78 mipi_dsi_dcs_write_seq_multi(&ctx, 0x06, 0x00);79 mipi_dsi_dcs_write_seq_multi(&ctx, 0x07, 0x00);80 81 mipi_dsi_dcs_write_seq_multi(&ctx, 0x08, 0x80);82 mipi_dsi_dcs_write_seq_multi(&ctx, 0x09, 0x81);83 mipi_dsi_dcs_write_seq_multi(&ctx, 0x0a, 0x71);84 mipi_dsi_dcs_write_seq_multi(&ctx, 0x0b, 0x00);85 86 mipi_dsi_dcs_write_seq_multi(&ctx, 0x0c, 0x00);87 mipi_dsi_dcs_write_seq_multi(&ctx, 0x0e, 0x1a);88 89 mipi_dsi_dcs_write_seq_multi(&ctx, 0x24, 0x00);90 mipi_dsi_dcs_write_seq_multi(&ctx, 0x25, 0x00);91 mipi_dsi_dcs_write_seq_multi(&ctx, 0x26, 0x00);92 mipi_dsi_dcs_write_seq_multi(&ctx, 0x27, 0x00);93 94 mipi_dsi_dcs_write_seq_multi(&ctx, 0x2c, 0xd4);95 mipi_dsi_dcs_write_seq_multi(&ctx, 0xb9, 0x40);96 97 mipi_dsi_dcs_write_seq_multi(&ctx, 0xb0, 0x11);98 99 mipi_dsi_dcs_write_seq_multi(&ctx, 0xe6, 0x32);100 mipi_dsi_dcs_write_seq_multi(&ctx, 0xd1, 0x30);101 102 mipi_dsi_dcs_write_seq_multi(&ctx, 0xd6, 0x55);103 104 mipi_dsi_dcs_write_seq_multi(&ctx, 0xd0, 0x01);105 mipi_dsi_dcs_write_seq_multi(&ctx, 0xe3, 0x93);106 mipi_dsi_dcs_write_seq_multi(&ctx, 0xe4, 0x00);107 mipi_dsi_dcs_write_seq_multi(&ctx, 0xe5, 0x80);108 109 mipi_dsi_dcs_write_seq_multi(&ctx, 0x31, 0x07);110 mipi_dsi_dcs_write_seq_multi(&ctx, 0x32, 0x07);111 mipi_dsi_dcs_write_seq_multi(&ctx, 0x33, 0x07);112 mipi_dsi_dcs_write_seq_multi(&ctx, 0x34, 0x07);113 mipi_dsi_dcs_write_seq_multi(&ctx, 0x35, 0x07);114 mipi_dsi_dcs_write_seq_multi(&ctx, 0x36, 0x01);115 mipi_dsi_dcs_write_seq_multi(&ctx, 0x37, 0x00);116 mipi_dsi_dcs_write_seq_multi(&ctx, 0x38, 0x28);117 mipi_dsi_dcs_write_seq_multi(&ctx, 0x39, 0x29);118 mipi_dsi_dcs_write_seq_multi(&ctx, 0x3a, 0x11);119 mipi_dsi_dcs_write_seq_multi(&ctx, 0x3b, 0x13);120 mipi_dsi_dcs_write_seq_multi(&ctx, 0x3c, 0x15);121 mipi_dsi_dcs_write_seq_multi(&ctx, 0x3d, 0x17);122 mipi_dsi_dcs_write_seq_multi(&ctx, 0x3e, 0x09);123 mipi_dsi_dcs_write_seq_multi(&ctx, 0x3f, 0x0d);124 mipi_dsi_dcs_write_seq_multi(&ctx, 0x40, 0x02);125 mipi_dsi_dcs_write_seq_multi(&ctx, 0x41, 0x02);126 mipi_dsi_dcs_write_seq_multi(&ctx, 0x42, 0x02);127 mipi_dsi_dcs_write_seq_multi(&ctx, 0x43, 0x02);128 mipi_dsi_dcs_write_seq_multi(&ctx, 0x44, 0x02);129 mipi_dsi_dcs_write_seq_multi(&ctx, 0x45, 0x02);130 mipi_dsi_dcs_write_seq_multi(&ctx, 0x46, 0x02);131 132 mipi_dsi_dcs_write_seq_multi(&ctx, 0x47, 0x07);133 mipi_dsi_dcs_write_seq_multi(&ctx, 0x48, 0x07);134 mipi_dsi_dcs_write_seq_multi(&ctx, 0x49, 0x07);135 mipi_dsi_dcs_write_seq_multi(&ctx, 0x4a, 0x07);136 mipi_dsi_dcs_write_seq_multi(&ctx, 0x4b, 0x07);137 mipi_dsi_dcs_write_seq_multi(&ctx, 0x4c, 0x01);138 mipi_dsi_dcs_write_seq_multi(&ctx, 0x4d, 0x00);139 mipi_dsi_dcs_write_seq_multi(&ctx, 0x4e, 0x28);140 mipi_dsi_dcs_write_seq_multi(&ctx, 0x4f, 0x29);141 mipi_dsi_dcs_write_seq_multi(&ctx, 0x50, 0x10);142 mipi_dsi_dcs_write_seq_multi(&ctx, 0x51, 0x12);143 mipi_dsi_dcs_write_seq_multi(&ctx, 0x52, 0x14);144 mipi_dsi_dcs_write_seq_multi(&ctx, 0x53, 0x16);145 mipi_dsi_dcs_write_seq_multi(&ctx, 0x54, 0x08);146 mipi_dsi_dcs_write_seq_multi(&ctx, 0x55, 0x0c);147 mipi_dsi_dcs_write_seq_multi(&ctx, 0x56, 0x02);148 mipi_dsi_dcs_write_seq_multi(&ctx, 0x57, 0x02);149 mipi_dsi_dcs_write_seq_multi(&ctx, 0x58, 0x02);150 mipi_dsi_dcs_write_seq_multi(&ctx, 0x59, 0x02);151 mipi_dsi_dcs_write_seq_multi(&ctx, 0x5a, 0x02);152 mipi_dsi_dcs_write_seq_multi(&ctx, 0x5b, 0x02);153 mipi_dsi_dcs_write_seq_multi(&ctx, 0x5c, 0x02);154 155 mipi_dsi_dcs_write_seq_multi(&ctx, 0x61, 0x07);156 mipi_dsi_dcs_write_seq_multi(&ctx, 0x62, 0x07);157 mipi_dsi_dcs_write_seq_multi(&ctx, 0x63, 0x07);158 mipi_dsi_dcs_write_seq_multi(&ctx, 0x64, 0x07);159 mipi_dsi_dcs_write_seq_multi(&ctx, 0x65, 0x07);160 mipi_dsi_dcs_write_seq_multi(&ctx, 0x66, 0x01);161 mipi_dsi_dcs_write_seq_multi(&ctx, 0x67, 0x00);162 mipi_dsi_dcs_write_seq_multi(&ctx, 0x68, 0x28);163 mipi_dsi_dcs_write_seq_multi(&ctx, 0x69, 0x29);164 mipi_dsi_dcs_write_seq_multi(&ctx, 0x6a, 0x16);165 mipi_dsi_dcs_write_seq_multi(&ctx, 0x6b, 0x14);166 mipi_dsi_dcs_write_seq_multi(&ctx, 0x6c, 0x12);167 mipi_dsi_dcs_write_seq_multi(&ctx, 0x6d, 0x10);168 mipi_dsi_dcs_write_seq_multi(&ctx, 0x6e, 0x0c);169 mipi_dsi_dcs_write_seq_multi(&ctx, 0x6f, 0x08);170 mipi_dsi_dcs_write_seq_multi(&ctx, 0x70, 0x02);171 mipi_dsi_dcs_write_seq_multi(&ctx, 0x71, 0x02);172 mipi_dsi_dcs_write_seq_multi(&ctx, 0x72, 0x02);173 mipi_dsi_dcs_write_seq_multi(&ctx, 0x73, 0x02);174 mipi_dsi_dcs_write_seq_multi(&ctx, 0x74, 0x02);175 mipi_dsi_dcs_write_seq_multi(&ctx, 0x75, 0x02);176 mipi_dsi_dcs_write_seq_multi(&ctx, 0x76, 0x02);177 178 mipi_dsi_dcs_write_seq_multi(&ctx, 0x77, 0x07);179 mipi_dsi_dcs_write_seq_multi(&ctx, 0x78, 0x07);180 mipi_dsi_dcs_write_seq_multi(&ctx, 0x79, 0x07);181 mipi_dsi_dcs_write_seq_multi(&ctx, 0x7a, 0x07);182 mipi_dsi_dcs_write_seq_multi(&ctx, 0x7b, 0x07);183 mipi_dsi_dcs_write_seq_multi(&ctx, 0x7c, 0x01);184 mipi_dsi_dcs_write_seq_multi(&ctx, 0x7d, 0x00);185 mipi_dsi_dcs_write_seq_multi(&ctx, 0x7e, 0x28);186 mipi_dsi_dcs_write_seq_multi(&ctx, 0x7f, 0x29);187 mipi_dsi_dcs_write_seq_multi(&ctx, 0x80, 0x17);188 mipi_dsi_dcs_write_seq_multi(&ctx, 0x81, 0x15);189 mipi_dsi_dcs_write_seq_multi(&ctx, 0x82, 0x13);190 mipi_dsi_dcs_write_seq_multi(&ctx, 0x83, 0x11);191 mipi_dsi_dcs_write_seq_multi(&ctx, 0x84, 0x0d);192 mipi_dsi_dcs_write_seq_multi(&ctx, 0x85, 0x09);193 mipi_dsi_dcs_write_seq_multi(&ctx, 0x86, 0x02);194 mipi_dsi_dcs_write_seq_multi(&ctx, 0x87, 0x07);195 mipi_dsi_dcs_write_seq_multi(&ctx, 0x88, 0x07);196 mipi_dsi_dcs_write_seq_multi(&ctx, 0x89, 0x07);197 mipi_dsi_dcs_write_seq_multi(&ctx, 0x8a, 0x07);198 mipi_dsi_dcs_write_seq_multi(&ctx, 0x8b, 0x07);199 mipi_dsi_dcs_write_seq_multi(&ctx, 0x8c, 0x07);200 201 ili9882t_switch_page(&ctx, 0x02);202 mipi_dsi_dcs_write_seq_multi(&ctx, 0x29, 0x3a);203 mipi_dsi_dcs_write_seq_multi(&ctx, 0x2a, 0x3b);204 205 mipi_dsi_dcs_write_seq_multi(&ctx, 0x06, 0x01);206 mipi_dsi_dcs_write_seq_multi(&ctx, 0x07, 0x01);207 mipi_dsi_dcs_write_seq_multi(&ctx, 0x08, 0x0c);208 mipi_dsi_dcs_write_seq_multi(&ctx, 0x09, 0x44);209 210 mipi_dsi_dcs_write_seq_multi(&ctx, 0x3c, 0x0a);211 mipi_dsi_dcs_write_seq_multi(&ctx, 0x39, 0x11);212 mipi_dsi_dcs_write_seq_multi(&ctx, 0x3d, 0x00);213 mipi_dsi_dcs_write_seq_multi(&ctx, 0x3a, 0x0c);214 mipi_dsi_dcs_write_seq_multi(&ctx, 0x3b, 0x44);215 216 mipi_dsi_dcs_write_seq_multi(&ctx, 0x53, 0x1f);217 mipi_dsi_dcs_write_seq_multi(&ctx, 0x5e, 0x40);218 mipi_dsi_dcs_write_seq_multi(&ctx, 0x84, 0x00);219 220 ili9882t_switch_page(&ctx, 0x03);221 mipi_dsi_dcs_write_seq_multi(&ctx, 0x20, 0x01);222 mipi_dsi_dcs_write_seq_multi(&ctx, 0x21, 0x3c);223 mipi_dsi_dcs_write_seq_multi(&ctx, 0x22, 0xfa);224 225 ili9882t_switch_page(&ctx, 0x0a);226 mipi_dsi_dcs_write_seq_multi(&ctx, 0xe0, 0x01);227 mipi_dsi_dcs_write_seq_multi(&ctx, 0xe2, 0x01);228 mipi_dsi_dcs_write_seq_multi(&ctx, 0xe5, 0x91);229 mipi_dsi_dcs_write_seq_multi(&ctx, 0xe6, 0x3c);230 mipi_dsi_dcs_write_seq_multi(&ctx, 0xe7, 0x00);231 mipi_dsi_dcs_write_seq_multi(&ctx, 0xe8, 0xfa);232 233 ili9882t_switch_page(&ctx, 0x12);234 mipi_dsi_dcs_write_seq_multi(&ctx, 0x87, 0x2c);235 236 ili9882t_switch_page(&ctx, 0x05);237 mipi_dsi_dcs_write_seq_multi(&ctx, 0x73, 0xe5);238 mipi_dsi_dcs_write_seq_multi(&ctx, 0x7f, 0x6b);239 mipi_dsi_dcs_write_seq_multi(&ctx, 0x6d, 0xa4);240 mipi_dsi_dcs_write_seq_multi(&ctx, 0x79, 0x54);241 mipi_dsi_dcs_write_seq_multi(&ctx, 0x69, 0x97);242 mipi_dsi_dcs_write_seq_multi(&ctx, 0x6a, 0x97);243 mipi_dsi_dcs_write_seq_multi(&ctx, 0xa5, 0x3f);244 mipi_dsi_dcs_write_seq_multi(&ctx, 0x61, 0xda);245 mipi_dsi_dcs_write_seq_multi(&ctx, 0xa7, 0xf1);246 mipi_dsi_dcs_write_seq_multi(&ctx, 0x5f, 0x01);247 mipi_dsi_dcs_write_seq_multi(&ctx, 0x62, 0x3f);248 mipi_dsi_dcs_write_seq_multi(&ctx, 0x1d, 0x90);249 mipi_dsi_dcs_write_seq_multi(&ctx, 0x86, 0x87);250 251 ili9882t_switch_page(&ctx, 0x06);252 mipi_dsi_dcs_write_seq_multi(&ctx, 0xc0, 0x80);253 mipi_dsi_dcs_write_seq_multi(&ctx, 0xc1, 0x07);254 mipi_dsi_dcs_write_seq_multi(&ctx, 0xca, 0x58);255 mipi_dsi_dcs_write_seq_multi(&ctx, 0xcb, 0x02);256 mipi_dsi_dcs_write_seq_multi(&ctx, 0xce, 0x58);257 mipi_dsi_dcs_write_seq_multi(&ctx, 0xcf, 0x02);258 mipi_dsi_dcs_write_seq_multi(&ctx, 0x67, 0x60);259 mipi_dsi_dcs_write_seq_multi(&ctx, 0x10, 0x00);260 mipi_dsi_dcs_write_seq_multi(&ctx, 0x92, 0x22);261 mipi_dsi_dcs_write_seq_multi(&ctx, 0xd3, 0x08);262 mipi_dsi_dcs_write_seq_multi(&ctx, 0xd6, 0x55);263 mipi_dsi_dcs_write_seq_multi(&ctx, 0xdc, 0x38);264 265 ili9882t_switch_page(&ctx, 0x08);266 mipi_dsi_dcs_write_seq_multi(&ctx, 0xe0, 0x00, 0x10, 0x2a, 0x4d, 0x61, 0x56, 0x6a, 0x6e,267 0x79, 0x76, 0x8f, 0x95, 0x98, 0xae, 0xaa, 0xb2, 0xbb, 0xce,268 0xc6, 0xbd, 0xd5, 0xe2, 0xe8);269 mipi_dsi_dcs_write_seq_multi(&ctx, 0xe1, 0x00, 0x10, 0x2a, 0x4d, 0x61, 0x56, 0x6a, 0x6e,270 0x79, 0x76, 0x8f, 0x95, 0x98, 0xae, 0xaa, 0xb2, 0xbb, 0xce,271 0xc6, 0xbd, 0xd5, 0xe2, 0xe8);272 273 ili9882t_switch_page(&ctx, 0x04);274 mipi_dsi_dcs_write_seq_multi(&ctx, 0xba, 0x81);275 276 ili9882t_switch_page(&ctx, 0x0c);277 mipi_dsi_dcs_write_seq_multi(&ctx, 0x00, 0x02);278 mipi_dsi_dcs_write_seq_multi(&ctx, 0x01, 0x00);279 mipi_dsi_dcs_write_seq_multi(&ctx, 0x02, 0x03);280 mipi_dsi_dcs_write_seq_multi(&ctx, 0x03, 0x01);281 mipi_dsi_dcs_write_seq_multi(&ctx, 0x04, 0x03);282 mipi_dsi_dcs_write_seq_multi(&ctx, 0x05, 0x02);283 mipi_dsi_dcs_write_seq_multi(&ctx, 0x06, 0x04);284 mipi_dsi_dcs_write_seq_multi(&ctx, 0x07, 0x03);285 mipi_dsi_dcs_write_seq_multi(&ctx, 0x08, 0x03);286 mipi_dsi_dcs_write_seq_multi(&ctx, 0x09, 0x04);287 mipi_dsi_dcs_write_seq_multi(&ctx, 0x0a, 0x04);288 mipi_dsi_dcs_write_seq_multi(&ctx, 0x0b, 0x05);289 mipi_dsi_dcs_write_seq_multi(&ctx, 0x0c, 0x04);290 mipi_dsi_dcs_write_seq_multi(&ctx, 0x0d, 0x06);291 mipi_dsi_dcs_write_seq_multi(&ctx, 0x0e, 0x05);292 mipi_dsi_dcs_write_seq_multi(&ctx, 0x0f, 0x07);293 mipi_dsi_dcs_write_seq_multi(&ctx, 0x10, 0x04);294 mipi_dsi_dcs_write_seq_multi(&ctx, 0x11, 0x08);295 mipi_dsi_dcs_write_seq_multi(&ctx, 0x12, 0x05);296 mipi_dsi_dcs_write_seq_multi(&ctx, 0x13, 0x09);297 mipi_dsi_dcs_write_seq_multi(&ctx, 0x14, 0x05);298 mipi_dsi_dcs_write_seq_multi(&ctx, 0x15, 0x0a);299 mipi_dsi_dcs_write_seq_multi(&ctx, 0x16, 0x06);300 mipi_dsi_dcs_write_seq_multi(&ctx, 0x17, 0x0b);301 mipi_dsi_dcs_write_seq_multi(&ctx, 0x18, 0x05);302 mipi_dsi_dcs_write_seq_multi(&ctx, 0x19, 0x0c);303 mipi_dsi_dcs_write_seq_multi(&ctx, 0x1a, 0x06);304 mipi_dsi_dcs_write_seq_multi(&ctx, 0x1b, 0x0d);305 mipi_dsi_dcs_write_seq_multi(&ctx, 0x1c, 0x06);306 mipi_dsi_dcs_write_seq_multi(&ctx, 0x1d, 0x0e);307 mipi_dsi_dcs_write_seq_multi(&ctx, 0x1e, 0x07);308 mipi_dsi_dcs_write_seq_multi(&ctx, 0x1f, 0x0f);309 mipi_dsi_dcs_write_seq_multi(&ctx, 0x20, 0x06);310 mipi_dsi_dcs_write_seq_multi(&ctx, 0x21, 0x10);311 mipi_dsi_dcs_write_seq_multi(&ctx, 0x22, 0x07);312 mipi_dsi_dcs_write_seq_multi(&ctx, 0x23, 0x11);313 mipi_dsi_dcs_write_seq_multi(&ctx, 0x24, 0x07);314 mipi_dsi_dcs_write_seq_multi(&ctx, 0x25, 0x12);315 mipi_dsi_dcs_write_seq_multi(&ctx, 0x26, 0x08);316 mipi_dsi_dcs_write_seq_multi(&ctx, 0x27, 0x13);317 mipi_dsi_dcs_write_seq_multi(&ctx, 0x28, 0x07);318 mipi_dsi_dcs_write_seq_multi(&ctx, 0x29, 0x14);319 mipi_dsi_dcs_write_seq_multi(&ctx, 0x2a, 0x08);320 mipi_dsi_dcs_write_seq_multi(&ctx, 0x2b, 0x15);321 mipi_dsi_dcs_write_seq_multi(&ctx, 0x2c, 0x08);322 mipi_dsi_dcs_write_seq_multi(&ctx, 0x2d, 0x16);323 mipi_dsi_dcs_write_seq_multi(&ctx, 0x2e, 0x09);324 mipi_dsi_dcs_write_seq_multi(&ctx, 0x2f, 0x17);325 mipi_dsi_dcs_write_seq_multi(&ctx, 0x30, 0x08);326 mipi_dsi_dcs_write_seq_multi(&ctx, 0x31, 0x18);327 mipi_dsi_dcs_write_seq_multi(&ctx, 0x32, 0x09);328 mipi_dsi_dcs_write_seq_multi(&ctx, 0x33, 0x19);329 mipi_dsi_dcs_write_seq_multi(&ctx, 0x34, 0x09);330 mipi_dsi_dcs_write_seq_multi(&ctx, 0x35, 0x1a);331 mipi_dsi_dcs_write_seq_multi(&ctx, 0x36, 0x0a);332 mipi_dsi_dcs_write_seq_multi(&ctx, 0x37, 0x1b);333 mipi_dsi_dcs_write_seq_multi(&ctx, 0x38, 0x0a);334 mipi_dsi_dcs_write_seq_multi(&ctx, 0x39, 0x1c);335 mipi_dsi_dcs_write_seq_multi(&ctx, 0x3a, 0x0a);336 mipi_dsi_dcs_write_seq_multi(&ctx, 0x3b, 0x1d);337 mipi_dsi_dcs_write_seq_multi(&ctx, 0x3c, 0x0a);338 mipi_dsi_dcs_write_seq_multi(&ctx, 0x3d, 0x1e);339 mipi_dsi_dcs_write_seq_multi(&ctx, 0x3e, 0x0a);340 mipi_dsi_dcs_write_seq_multi(&ctx, 0x3f, 0x1f);341 342 ili9882t_switch_page(&ctx, 0x04);343 mipi_dsi_dcs_write_seq_multi(&ctx, 0xba, 0x01);344 345 ili9882t_switch_page(&ctx, 0x0e);346 mipi_dsi_dcs_write_seq_multi(&ctx, 0x02, 0x0c);347 mipi_dsi_dcs_write_seq_multi(&ctx, 0x20, 0x10);348 mipi_dsi_dcs_write_seq_multi(&ctx, 0x25, 0x16);349 mipi_dsi_dcs_write_seq_multi(&ctx, 0x26, 0xe0);350 mipi_dsi_dcs_write_seq_multi(&ctx, 0x27, 0x00);351 mipi_dsi_dcs_write_seq_multi(&ctx, 0x29, 0x71);352 mipi_dsi_dcs_write_seq_multi(&ctx, 0x2a, 0x46);353 mipi_dsi_dcs_write_seq_multi(&ctx, 0x2b, 0x1f);354 mipi_dsi_dcs_write_seq_multi(&ctx, 0x2d, 0xc7);355 mipi_dsi_dcs_write_seq_multi(&ctx, 0x31, 0x02);356 mipi_dsi_dcs_write_seq_multi(&ctx, 0x32, 0xdf);357 mipi_dsi_dcs_write_seq_multi(&ctx, 0x33, 0x5a);358 mipi_dsi_dcs_write_seq_multi(&ctx, 0x34, 0xc0);359 mipi_dsi_dcs_write_seq_multi(&ctx, 0x35, 0x5a);360 mipi_dsi_dcs_write_seq_multi(&ctx, 0x36, 0xc0);361 mipi_dsi_dcs_write_seq_multi(&ctx, 0x38, 0x65);362 mipi_dsi_dcs_write_seq_multi(&ctx, 0x80, 0x3e);363 mipi_dsi_dcs_write_seq_multi(&ctx, 0x81, 0xa0);364 mipi_dsi_dcs_write_seq_multi(&ctx, 0xb0, 0x01);365 mipi_dsi_dcs_write_seq_multi(&ctx, 0xb1, 0xcc);366 mipi_dsi_dcs_write_seq_multi(&ctx, 0xc0, 0x12);367 mipi_dsi_dcs_write_seq_multi(&ctx, 0xc2, 0xcc);368 mipi_dsi_dcs_write_seq_multi(&ctx, 0xc3, 0xcc);369 mipi_dsi_dcs_write_seq_multi(&ctx, 0xc4, 0xcc);370 mipi_dsi_dcs_write_seq_multi(&ctx, 0xc5, 0xcc);371 mipi_dsi_dcs_write_seq_multi(&ctx, 0xc6, 0xcc);372 mipi_dsi_dcs_write_seq_multi(&ctx, 0xc7, 0xcc);373 mipi_dsi_dcs_write_seq_multi(&ctx, 0xc8, 0xcc);374 mipi_dsi_dcs_write_seq_multi(&ctx, 0xc9, 0xcc);375 mipi_dsi_dcs_write_seq_multi(&ctx, 0x30, 0x00);376 mipi_dsi_dcs_write_seq_multi(&ctx, 0x00, 0x81);377 mipi_dsi_dcs_write_seq_multi(&ctx, 0x08, 0x02);378 mipi_dsi_dcs_write_seq_multi(&ctx, 0x09, 0x00);379 mipi_dsi_dcs_write_seq_multi(&ctx, 0x07, 0x21);380 mipi_dsi_dcs_write_seq_multi(&ctx, 0x04, 0x10);381 382 ili9882t_switch_page(&ctx, 0x1e);383 mipi_dsi_dcs_write_seq_multi(&ctx, 0x60, 0x00);384 mipi_dsi_dcs_write_seq_multi(&ctx, 0x64, 0x00);385 mipi_dsi_dcs_write_seq_multi(&ctx, 0x6d, 0x00);386 387 ili9882t_switch_page(&ctx, 0x0b);388 mipi_dsi_dcs_write_seq_multi(&ctx, 0xa6, 0x44);389 mipi_dsi_dcs_write_seq_multi(&ctx, 0xa7, 0xb6);390 mipi_dsi_dcs_write_seq_multi(&ctx, 0xa8, 0x03);391 mipi_dsi_dcs_write_seq_multi(&ctx, 0xa9, 0x03);392 mipi_dsi_dcs_write_seq_multi(&ctx, 0xaa, 0x51);393 mipi_dsi_dcs_write_seq_multi(&ctx, 0xab, 0x51);394 mipi_dsi_dcs_write_seq_multi(&ctx, 0xac, 0x04);395 mipi_dsi_dcs_write_seq_multi(&ctx, 0xbd, 0x92);396 mipi_dsi_dcs_write_seq_multi(&ctx, 0xbe, 0xa1);397 398 ili9882t_switch_page(&ctx, 0x05);399 mipi_dsi_dcs_write_seq_multi(&ctx, 0x86, 0x87);400 401 ili9882t_switch_page(&ctx, 0x06);402 mipi_dsi_dcs_write_seq_multi(&ctx, 0x92, 0x22);403 404 ili9882t_switch_page(&ctx, 0x00);405 mipi_dsi_dcs_exit_sleep_mode_multi(&ctx);406 407 mipi_dsi_msleep(&ctx, 120);408 409 mipi_dsi_dcs_set_display_on_multi(&ctx);410 411 mipi_dsi_msleep(&ctx, 20);412 413 return ctx.accum_err;414};415 416static inline struct ili9882t *to_ili9882t(struct drm_panel *panel)417{418 return container_of(panel, struct ili9882t, base);419}420 421static int ili9882t_disable(struct drm_panel *panel)422{423 struct ili9882t *ili = to_ili9882t(panel);424 struct mipi_dsi_multi_context ctx = { .dsi = ili->dsi };425 426 ili9882t_switch_page(&ctx, 0x00);427 428 ili->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;429 430 mipi_dsi_dcs_set_display_off_multi(&ctx);431 mipi_dsi_dcs_enter_sleep_mode_multi(&ctx);432 433 mipi_dsi_msleep(&ctx, 150);434 435 return ctx.accum_err;436}437 438static int ili9882t_unprepare(struct drm_panel *panel)439{440 struct ili9882t *ili = to_ili9882t(panel);441 442 gpiod_set_value(ili->enable_gpio, 0);443 usleep_range(1000, 2000);444 regulator_disable(ili->avee);445 regulator_disable(ili->avdd);446 usleep_range(5000, 7000);447 regulator_disable(ili->pp1800);448 regulator_disable(ili->pp3300);449 450 return 0;451}452 453static int ili9882t_prepare(struct drm_panel *panel)454{455 struct ili9882t *ili = to_ili9882t(panel);456 int ret;457 458 gpiod_set_value(ili->enable_gpio, 0);459 usleep_range(1000, 1500);460 461 ret = regulator_enable(ili->pp3300);462 if (ret < 0)463 return ret;464 465 ret = regulator_enable(ili->pp1800);466 if (ret < 0)467 return ret;468 469 usleep_range(3000, 5000);470 471 ret = regulator_enable(ili->avdd);472 if (ret < 0)473 goto poweroff1v8;474 ret = regulator_enable(ili->avee);475 if (ret < 0)476 goto poweroffavdd;477 478 usleep_range(10000, 11000);479 480 // MIPI needs to keep the LP11 state before the lcm_reset pin is pulled high481 ret = mipi_dsi_dcs_nop(ili->dsi);482 if (ret < 0) {483 dev_err(&ili->dsi->dev, "Failed to send NOP: %d\n", ret);484 goto poweroff;485 }486 usleep_range(1000, 2000);487 488 gpiod_set_value(ili->enable_gpio, 1);489 usleep_range(1000, 2000);490 gpiod_set_value(ili->enable_gpio, 0);491 msleep(50);492 gpiod_set_value(ili->enable_gpio, 1);493 usleep_range(6000, 10000);494 495 ret = ili->desc->init(ili);496 if (ret < 0)497 goto poweroff;498 499 return 0;500 501poweroff:502 gpiod_set_value(ili->enable_gpio, 0);503 regulator_disable(ili->avee);504poweroffavdd:505 regulator_disable(ili->avdd);506poweroff1v8:507 usleep_range(5000, 7000);508 regulator_disable(ili->pp1800);509 510 return ret;511}512 513static int ili9882t_enable(struct drm_panel *panel)514{515 msleep(130);516 return 0;517}518 519static const struct drm_display_mode starry_ili9882t_default_mode = {520 .clock = 165280,521 .hdisplay = 1200,522 .hsync_start = 1200 + 72,523 .hsync_end = 1200 + 72 + 30,524 .htotal = 1200 + 72 + 30 + 72,525 .vdisplay = 1920,526 .vsync_start = 1920 + 68,527 .vsync_end = 1920 + 68 + 2,528 .vtotal = 1920 + 68 + 2 + 10,529 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,530};531 532static const struct panel_desc starry_ili9882t_desc = {533 .modes = &starry_ili9882t_default_mode,534 .bpc = 8,535 .size = {536 .width_mm = 141,537 .height_mm = 226,538 },539 .lanes = 4,540 .format = MIPI_DSI_FMT_RGB888,541 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |542 MIPI_DSI_MODE_LPM,543 .init = starry_ili9882t_init,544};545 546static int ili9882t_get_modes(struct drm_panel *panel,547 struct drm_connector *connector)548{549 struct ili9882t *ili = to_ili9882t(panel);550 const struct drm_display_mode *m = ili->desc->modes;551 struct drm_display_mode *mode;552 553 mode = drm_mode_duplicate(connector->dev, m);554 if (!mode) {555 dev_err(panel->dev, "failed to add mode %ux%u@%u\n",556 m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));557 return -ENOMEM;558 }559 560 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;561 drm_mode_set_name(mode);562 drm_mode_probed_add(connector, mode);563 564 connector->display_info.width_mm = ili->desc->size.width_mm;565 connector->display_info.height_mm = ili->desc->size.height_mm;566 connector->display_info.bpc = ili->desc->bpc;567 568 return 1;569}570 571static enum drm_panel_orientation ili9882t_get_orientation(struct drm_panel *panel)572{573 struct ili9882t *ili = to_ili9882t(panel);574 575 return ili->orientation;576}577 578static const struct drm_panel_funcs ili9882t_funcs = {579 .disable = ili9882t_disable,580 .unprepare = ili9882t_unprepare,581 .prepare = ili9882t_prepare,582 .enable = ili9882t_enable,583 .get_modes = ili9882t_get_modes,584 .get_orientation = ili9882t_get_orientation,585};586 587static int ili9882t_add(struct ili9882t *ili)588{589 struct device *dev = &ili->dsi->dev;590 int err;591 592 ili->avdd = devm_regulator_get(dev, "avdd");593 if (IS_ERR(ili->avdd))594 return PTR_ERR(ili->avdd);595 596 ili->avee = devm_regulator_get(dev, "avee");597 if (IS_ERR(ili->avee))598 return PTR_ERR(ili->avee);599 600 ili->pp3300 = devm_regulator_get(dev, "pp3300");601 if (IS_ERR(ili->pp3300))602 return PTR_ERR(ili->pp3300);603 604 ili->pp1800 = devm_regulator_get(dev, "pp1800");605 if (IS_ERR(ili->pp1800))606 return PTR_ERR(ili->pp1800);607 608 ili->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);609 if (IS_ERR(ili->enable_gpio)) {610 dev_err(dev, "cannot get reset-gpios %ld\n",611 PTR_ERR(ili->enable_gpio));612 return PTR_ERR(ili->enable_gpio);613 }614 615 gpiod_set_value(ili->enable_gpio, 0);616 617 drm_panel_init(&ili->base, dev, &ili9882t_funcs,618 DRM_MODE_CONNECTOR_DSI);619 err = of_drm_get_panel_orientation(dev->of_node, &ili->orientation);620 if (err < 0) {621 dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);622 return err;623 }624 625 err = drm_panel_of_backlight(&ili->base);626 if (err)627 return err;628 629 ili->base.funcs = &ili9882t_funcs;630 ili->base.dev = &ili->dsi->dev;631 632 drm_panel_add(&ili->base);633 634 return 0;635}636 637static int ili9882t_probe(struct mipi_dsi_device *dsi)638{639 struct ili9882t *ili;640 int ret;641 const struct panel_desc *desc;642 643 ili = devm_kzalloc(&dsi->dev, sizeof(*ili), GFP_KERNEL);644 if (!ili)645 return -ENOMEM;646 647 desc = of_device_get_match_data(&dsi->dev);648 dsi->lanes = desc->lanes;649 dsi->format = desc->format;650 dsi->mode_flags = desc->mode_flags;651 ili->desc = desc;652 ili->dsi = dsi;653 ret = ili9882t_add(ili);654 if (ret < 0)655 return ret;656 657 mipi_dsi_set_drvdata(dsi, ili);658 659 ret = mipi_dsi_attach(dsi);660 if (ret)661 drm_panel_remove(&ili->base);662 663 return ret;664}665 666static void ili9882t_remove(struct mipi_dsi_device *dsi)667{668 struct ili9882t *ili = mipi_dsi_get_drvdata(dsi);669 int ret;670 671 ret = mipi_dsi_detach(dsi);672 if (ret < 0)673 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);674 675 if (ili->base.dev)676 drm_panel_remove(&ili->base);677}678 679static const struct of_device_id ili9882t_of_match[] = {680 { .compatible = "starry,ili9882t",681 .data = &starry_ili9882t_desc682 },683 { /* sentinel */ }684};685MODULE_DEVICE_TABLE(of, ili9882t_of_match);686 687static struct mipi_dsi_driver ili9882t_driver = {688 .driver = {689 .name = "panel-ili9882t",690 .of_match_table = ili9882t_of_match,691 },692 .probe = ili9882t_probe,693 .remove = ili9882t_remove,694};695module_mipi_dsi_driver(ili9882t_driver);696 697MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");698MODULE_DESCRIPTION("Ilitek ILI9882T-based panels driver");699MODULE_LICENSE("GPL");700