cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

panel-khadas-ts050.c (16916B)


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