Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2020 BayLibre, SAS
0004  * Author: Neil Armstrong <narmstrong@baylibre.com>
0005  */
0006 
0007 #include <linux/delay.h>
0008 #include <linux/gpio/consumer.h>
0009 #include <linux/module.h>
0010 #include <linux/of.h>
0011 #include <linux/regulator/consumer.h>
0012 
0013 #include <video/mipi_display.h>
0014 
0015 #include <drm/drm_crtc.h>
0016 #include <drm/drm_device.h>
0017 #include <drm/drm_mipi_dsi.h>
0018 #include <drm/drm_modes.h>
0019 #include <drm/drm_panel.h>
0020 
0021 struct khadas_ts050_panel {
0022     struct drm_panel base;
0023     struct mipi_dsi_device *link;
0024 
0025     struct regulator *supply;
0026     struct gpio_desc *reset_gpio;
0027     struct gpio_desc *enable_gpio;
0028 
0029     bool prepared;
0030     bool enabled;
0031 };
0032 
0033 struct khadas_ts050_panel_cmd {
0034     u8 cmd;
0035     u8 data;
0036 };
0037 
0038 /* Only the CMD1 User Command set is documented */
0039 static const struct khadas_ts050_panel_cmd init_code[] = {
0040     /* Select Unknown CMD Page (Undocumented) */
0041     {0xff, 0xee},
0042     /* Reload CMD1: Don't reload default value to register */
0043     {0xfb, 0x01},
0044     {0x1f, 0x45},
0045     {0x24, 0x4f},
0046     {0x38, 0xc8},
0047     {0x39, 0x27},
0048     {0x1e, 0x77},
0049     {0x1d, 0x0f},
0050     {0x7e, 0x71},
0051     {0x7c, 0x03},
0052     {0xff, 0x00},
0053     {0xfb, 0x01},
0054     {0x35, 0x01},
0055     /* Select CMD2 Page0 (Undocumented) */
0056     {0xff, 0x01},
0057     /* Reload CMD1: Don't reload default value to register */
0058     {0xfb, 0x01},
0059     {0x00, 0x01},
0060     {0x01, 0x55},
0061     {0x02, 0x40},
0062     {0x05, 0x40},
0063     {0x06, 0x4a},
0064     {0x07, 0x24},
0065     {0x08, 0x0c},
0066     {0x0b, 0x7d},
0067     {0x0c, 0x7d},
0068     {0x0e, 0xb0},
0069     {0x0f, 0xae},
0070     {0x11, 0x10},
0071     {0x12, 0x10},
0072     {0x13, 0x03},
0073     {0x14, 0x4a},
0074     {0x15, 0x12},
0075     {0x16, 0x12},
0076     {0x18, 0x00},
0077     {0x19, 0x77},
0078     {0x1a, 0x55},
0079     {0x1b, 0x13},
0080     {0x1c, 0x00},
0081     {0x1d, 0x00},
0082     {0x1e, 0x13},
0083     {0x1f, 0x00},
0084     {0x23, 0x00},
0085     {0x24, 0x00},
0086     {0x25, 0x00},
0087     {0x26, 0x00},
0088     {0x27, 0x00},
0089     {0x28, 0x00},
0090     {0x35, 0x00},
0091     {0x66, 0x00},
0092     {0x58, 0x82},
0093     {0x59, 0x02},
0094     {0x5a, 0x02},
0095     {0x5b, 0x02},
0096     {0x5c, 0x82},
0097     {0x5d, 0x82},
0098     {0x5e, 0x02},
0099     {0x5f, 0x02},
0100     {0x72, 0x31},
0101     /* Select CMD2 Page4 (Undocumented) */
0102     {0xff, 0x05},
0103     /* Reload CMD1: Don't reload default value to register */
0104     {0xfb, 0x01},
0105     {0x00, 0x01},
0106     {0x01, 0x0b},
0107     {0x02, 0x0c},
0108     {0x03, 0x09},
0109     {0x04, 0x0a},
0110     {0x05, 0x00},
0111     {0x06, 0x0f},
0112     {0x07, 0x10},
0113     {0x08, 0x00},
0114     {0x09, 0x00},
0115     {0x0a, 0x00},
0116     {0x0b, 0x00},
0117     {0x0c, 0x00},
0118     {0x0d, 0x13},
0119     {0x0e, 0x15},
0120     {0x0f, 0x17},
0121     {0x10, 0x01},
0122     {0x11, 0x0b},
0123     {0x12, 0x0c},
0124     {0x13, 0x09},
0125     {0x14, 0x0a},
0126     {0x15, 0x00},
0127     {0x16, 0x0f},
0128     {0x17, 0x10},
0129     {0x18, 0x00},
0130     {0x19, 0x00},
0131     {0x1a, 0x00},
0132     {0x1b, 0x00},
0133     {0x1c, 0x00},
0134     {0x1d, 0x13},
0135     {0x1e, 0x15},
0136     {0x1f, 0x17},
0137     {0x20, 0x00},
0138     {0x21, 0x03},
0139     {0x22, 0x01},
0140     {0x23, 0x40},
0141     {0x24, 0x40},
0142     {0x25, 0xed},
0143     {0x29, 0x58},
0144     {0x2a, 0x12},
0145     {0x2b, 0x01},
0146     {0x4b, 0x06},
0147     {0x4c, 0x11},
0148     {0x4d, 0x20},
0149     {0x4e, 0x02},
0150     {0x4f, 0x02},
0151     {0x50, 0x20},
0152     {0x51, 0x61},
0153     {0x52, 0x01},
0154     {0x53, 0x63},
0155     {0x54, 0x77},
0156     {0x55, 0xed},
0157     {0x5b, 0x00},
0158     {0x5c, 0x00},
0159     {0x5d, 0x00},
0160     {0x5e, 0x00},
0161     {0x5f, 0x15},
0162     {0x60, 0x75},
0163     {0x61, 0x00},
0164     {0x62, 0x00},
0165     {0x63, 0x00},
0166     {0x64, 0x00},
0167     {0x65, 0x00},
0168     {0x66, 0x00},
0169     {0x67, 0x00},
0170     {0x68, 0x04},
0171     {0x69, 0x00},
0172     {0x6a, 0x00},
0173     {0x6c, 0x40},
0174     {0x75, 0x01},
0175     {0x76, 0x01},
0176     {0x7a, 0x80},
0177     {0x7b, 0xa3},
0178     {0x7c, 0xd8},
0179     {0x7d, 0x60},
0180     {0x7f, 0x15},
0181     {0x80, 0x81},
0182     {0x83, 0x05},
0183     {0x93, 0x08},
0184     {0x94, 0x10},
0185     {0x8a, 0x00},
0186     {0x9b, 0x0f},
0187     {0xea, 0xff},
0188     {0xec, 0x00},
0189     /* Select CMD2 Page0 (Undocumented) */
0190     {0xff, 0x01},
0191     /* Reload CMD1: Don't reload default value to register */
0192     {0xfb, 0x01},
0193     {0x75, 0x00},
0194     {0x76, 0xdf},
0195     {0x77, 0x00},
0196     {0x78, 0xe4},
0197     {0x79, 0x00},
0198     {0x7a, 0xed},
0199     {0x7b, 0x00},
0200     {0x7c, 0xf6},
0201     {0x7d, 0x00},
0202     {0x7e, 0xff},
0203     {0x7f, 0x01},
0204     {0x80, 0x07},
0205     {0x81, 0x01},
0206     {0x82, 0x10},
0207     {0x83, 0x01},
0208     {0x84, 0x18},
0209     {0x85, 0x01},
0210     {0x86, 0x20},
0211     {0x87, 0x01},
0212     {0x88, 0x3d},
0213     {0x89, 0x01},
0214     {0x8a, 0x56},
0215     {0x8b, 0x01},
0216     {0x8c, 0x84},
0217     {0x8d, 0x01},
0218     {0x8e, 0xab},
0219     {0x8f, 0x01},
0220     {0x90, 0xec},
0221     {0x91, 0x02},
0222     {0x92, 0x22},
0223     {0x93, 0x02},
0224     {0x94, 0x23},
0225     {0x95, 0x02},
0226     {0x96, 0x55},
0227     {0x97, 0x02},
0228     {0x98, 0x8b},
0229     {0x99, 0x02},
0230     {0x9a, 0xaf},
0231     {0x9b, 0x02},
0232     {0x9c, 0xdf},
0233     {0x9d, 0x03},
0234     {0x9e, 0x01},
0235     {0x9f, 0x03},
0236     {0xa0, 0x2c},
0237     {0xa2, 0x03},
0238     {0xa3, 0x39},
0239     {0xa4, 0x03},
0240     {0xa5, 0x47},
0241     {0xa6, 0x03},
0242     {0xa7, 0x56},
0243     {0xa9, 0x03},
0244     {0xaa, 0x66},
0245     {0xab, 0x03},
0246     {0xac, 0x76},
0247     {0xad, 0x03},
0248     {0xae, 0x85},
0249     {0xaf, 0x03},
0250     {0xb0, 0x90},
0251     {0xb1, 0x03},
0252     {0xb2, 0xcb},
0253     {0xb3, 0x00},
0254     {0xb4, 0xdf},
0255     {0xb5, 0x00},
0256     {0xb6, 0xe4},
0257     {0xb7, 0x00},
0258     {0xb8, 0xed},
0259     {0xb9, 0x00},
0260     {0xba, 0xf6},
0261     {0xbb, 0x00},
0262     {0xbc, 0xff},
0263     {0xbd, 0x01},
0264     {0xbe, 0x07},
0265     {0xbf, 0x01},
0266     {0xc0, 0x10},
0267     {0xc1, 0x01},
0268     {0xc2, 0x18},
0269     {0xc3, 0x01},
0270     {0xc4, 0x20},
0271     {0xc5, 0x01},
0272     {0xc6, 0x3d},
0273     {0xc7, 0x01},
0274     {0xc8, 0x56},
0275     {0xc9, 0x01},
0276     {0xca, 0x84},
0277     {0xcb, 0x01},
0278     {0xcc, 0xab},
0279     {0xcd, 0x01},
0280     {0xce, 0xec},
0281     {0xcf, 0x02},
0282     {0xd0, 0x22},
0283     {0xd1, 0x02},
0284     {0xd2, 0x23},
0285     {0xd3, 0x02},
0286     {0xd4, 0x55},
0287     {0xd5, 0x02},
0288     {0xd6, 0x8b},
0289     {0xd7, 0x02},
0290     {0xd8, 0xaf},
0291     {0xd9, 0x02},
0292     {0xda, 0xdf},
0293     {0xdb, 0x03},
0294     {0xdc, 0x01},
0295     {0xdd, 0x03},
0296     {0xde, 0x2c},
0297     {0xdf, 0x03},
0298     {0xe0, 0x39},
0299     {0xe1, 0x03},
0300     {0xe2, 0x47},
0301     {0xe3, 0x03},
0302     {0xe4, 0x56},
0303     {0xe5, 0x03},
0304     {0xe6, 0x66},
0305     {0xe7, 0x03},
0306     {0xe8, 0x76},
0307     {0xe9, 0x03},
0308     {0xea, 0x85},
0309     {0xeb, 0x03},
0310     {0xec, 0x90},
0311     {0xed, 0x03},
0312     {0xee, 0xcb},
0313     {0xef, 0x00},
0314     {0xf0, 0xbb},
0315     {0xf1, 0x00},
0316     {0xf2, 0xc0},
0317     {0xf3, 0x00},
0318     {0xf4, 0xcc},
0319     {0xf5, 0x00},
0320     {0xf6, 0xd6},
0321     {0xf7, 0x00},
0322     {0xf8, 0xe1},
0323     {0xf9, 0x00},
0324     {0xfa, 0xea},
0325     /* Select CMD2 Page2 (Undocumented) */
0326     {0xff, 0x02},
0327     /* Reload CMD1: Don't reload default value to register */
0328     {0xfb, 0x01},
0329     {0x00, 0x00},
0330     {0x01, 0xf4},
0331     {0x02, 0x00},
0332     {0x03, 0xef},
0333     {0x04, 0x01},
0334     {0x05, 0x07},
0335     {0x06, 0x01},
0336     {0x07, 0x28},
0337     {0x08, 0x01},
0338     {0x09, 0x44},
0339     {0x0a, 0x01},
0340     {0x0b, 0x76},
0341     {0x0c, 0x01},
0342     {0x0d, 0xa0},
0343     {0x0e, 0x01},
0344     {0x0f, 0xe7},
0345     {0x10, 0x02},
0346     {0x11, 0x1f},
0347     {0x12, 0x02},
0348     {0x13, 0x22},
0349     {0x14, 0x02},
0350     {0x15, 0x54},
0351     {0x16, 0x02},
0352     {0x17, 0x8b},
0353     {0x18, 0x02},
0354     {0x19, 0xaf},
0355     {0x1a, 0x02},
0356     {0x1b, 0xe0},
0357     {0x1c, 0x03},
0358     {0x1d, 0x01},
0359     {0x1e, 0x03},
0360     {0x1f, 0x2d},
0361     {0x20, 0x03},
0362     {0x21, 0x39},
0363     {0x22, 0x03},
0364     {0x23, 0x47},
0365     {0x24, 0x03},
0366     {0x25, 0x57},
0367     {0x26, 0x03},
0368     {0x27, 0x65},
0369     {0x28, 0x03},
0370     {0x29, 0x77},
0371     {0x2a, 0x03},
0372     {0x2b, 0x85},
0373     {0x2d, 0x03},
0374     {0x2f, 0x8f},
0375     {0x30, 0x03},
0376     {0x31, 0xcb},
0377     {0x32, 0x00},
0378     {0x33, 0xbb},
0379     {0x34, 0x00},
0380     {0x35, 0xc0},
0381     {0x36, 0x00},
0382     {0x37, 0xcc},
0383     {0x38, 0x00},
0384     {0x39, 0xd6},
0385     {0x3a, 0x00},
0386     {0x3b, 0xe1},
0387     {0x3d, 0x00},
0388     {0x3f, 0xea},
0389     {0x40, 0x00},
0390     {0x41, 0xf4},
0391     {0x42, 0x00},
0392     {0x43, 0xfe},
0393     {0x44, 0x01},
0394     {0x45, 0x07},
0395     {0x46, 0x01},
0396     {0x47, 0x28},
0397     {0x48, 0x01},
0398     {0x49, 0x44},
0399     {0x4a, 0x01},
0400     {0x4b, 0x76},
0401     {0x4c, 0x01},
0402     {0x4d, 0xa0},
0403     {0x4e, 0x01},
0404     {0x4f, 0xe7},
0405     {0x50, 0x02},
0406     {0x51, 0x1f},
0407     {0x52, 0x02},
0408     {0x53, 0x22},
0409     {0x54, 0x02},
0410     {0x55, 0x54},
0411     {0x56, 0x02},
0412     {0x58, 0x8b},
0413     {0x59, 0x02},
0414     {0x5a, 0xaf},
0415     {0x5b, 0x02},
0416     {0x5c, 0xe0},
0417     {0x5d, 0x03},
0418     {0x5e, 0x01},
0419     {0x5f, 0x03},
0420     {0x60, 0x2d},
0421     {0x61, 0x03},
0422     {0x62, 0x39},
0423     {0x63, 0x03},
0424     {0x64, 0x47},
0425     {0x65, 0x03},
0426     {0x66, 0x57},
0427     {0x67, 0x03},
0428     {0x68, 0x65},
0429     {0x69, 0x03},
0430     {0x6a, 0x77},
0431     {0x6b, 0x03},
0432     {0x6c, 0x85},
0433     {0x6d, 0x03},
0434     {0x6e, 0x8f},
0435     {0x6f, 0x03},
0436     {0x70, 0xcb},
0437     {0x71, 0x00},
0438     {0x72, 0x00},
0439     {0x73, 0x00},
0440     {0x74, 0x21},
0441     {0x75, 0x00},
0442     {0x76, 0x4c},
0443     {0x77, 0x00},
0444     {0x78, 0x6b},
0445     {0x79, 0x00},
0446     {0x7a, 0x85},
0447     {0x7b, 0x00},
0448     {0x7c, 0x9a},
0449     {0x7d, 0x00},
0450     {0x7e, 0xad},
0451     {0x7f, 0x00},
0452     {0x80, 0xbe},
0453     {0x81, 0x00},
0454     {0x82, 0xcd},
0455     {0x83, 0x01},
0456     {0x84, 0x01},
0457     {0x85, 0x01},
0458     {0x86, 0x29},
0459     {0x87, 0x01},
0460     {0x88, 0x68},
0461     {0x89, 0x01},
0462     {0x8a, 0x98},
0463     {0x8b, 0x01},
0464     {0x8c, 0xe5},
0465     {0x8d, 0x02},
0466     {0x8e, 0x1e},
0467     {0x8f, 0x02},
0468     {0x90, 0x30},
0469     {0x91, 0x02},
0470     {0x92, 0x52},
0471     {0x93, 0x02},
0472     {0x94, 0x88},
0473     {0x95, 0x02},
0474     {0x96, 0xaa},
0475     {0x97, 0x02},
0476     {0x98, 0xd7},
0477     {0x99, 0x02},
0478     {0x9a, 0xf7},
0479     {0x9b, 0x03},
0480     {0x9c, 0x21},
0481     {0x9d, 0x03},
0482     {0x9e, 0x2e},
0483     {0x9f, 0x03},
0484     {0xa0, 0x3d},
0485     {0xa2, 0x03},
0486     {0xa3, 0x4c},
0487     {0xa4, 0x03},
0488     {0xa5, 0x5e},
0489     {0xa6, 0x03},
0490     {0xa7, 0x71},
0491     {0xa9, 0x03},
0492     {0xaa, 0x86},
0493     {0xab, 0x03},
0494     {0xac, 0x94},
0495     {0xad, 0x03},
0496     {0xae, 0xfa},
0497     {0xaf, 0x00},
0498     {0xb0, 0x00},
0499     {0xb1, 0x00},
0500     {0xb2, 0x21},
0501     {0xb3, 0x00},
0502     {0xb4, 0x4c},
0503     {0xb5, 0x00},
0504     {0xb6, 0x6b},
0505     {0xb7, 0x00},
0506     {0xb8, 0x85},
0507     {0xb9, 0x00},
0508     {0xba, 0x9a},
0509     {0xbb, 0x00},
0510     {0xbc, 0xad},
0511     {0xbd, 0x00},
0512     {0xbe, 0xbe},
0513     {0xbf, 0x00},
0514     {0xc0, 0xcd},
0515     {0xc1, 0x01},
0516     {0xc2, 0x01},
0517     {0xc3, 0x01},
0518     {0xc4, 0x29},
0519     {0xc5, 0x01},
0520     {0xc6, 0x68},
0521     {0xc7, 0x01},
0522     {0xc8, 0x98},
0523     {0xc9, 0x01},
0524     {0xca, 0xe5},
0525     {0xcb, 0x02},
0526     {0xcc, 0x1e},
0527     {0xcd, 0x02},
0528     {0xce, 0x20},
0529     {0xcf, 0x02},
0530     {0xd0, 0x52},
0531     {0xd1, 0x02},
0532     {0xd2, 0x88},
0533     {0xd3, 0x02},
0534     {0xd4, 0xaa},
0535     {0xd5, 0x02},
0536     {0xd6, 0xd7},
0537     {0xd7, 0x02},
0538     {0xd8, 0xf7},
0539     {0xd9, 0x03},
0540     {0xda, 0x21},
0541     {0xdb, 0x03},
0542     {0xdc, 0x2e},
0543     {0xdd, 0x03},
0544     {0xde, 0x3d},
0545     {0xdf, 0x03},
0546     {0xe0, 0x4c},
0547     {0xe1, 0x03},
0548     {0xe2, 0x5e},
0549     {0xe3, 0x03},
0550     {0xe4, 0x71},
0551     {0xe5, 0x03},
0552     {0xe6, 0x86},
0553     {0xe7, 0x03},
0554     {0xe8, 0x94},
0555     {0xe9, 0x03},
0556     {0xea, 0xfa},
0557     /* Select CMD2 Page0 (Undocumented) */
0558     {0xff, 0x01},
0559     /* Reload CMD1: Don't reload default value to register */
0560     {0xfb, 0x01},
0561     /* Select CMD2 Page1 (Undocumented) */
0562     {0xff, 0x02},
0563     /* Reload CMD1: Don't reload default value to register */
0564     {0xfb, 0x01},
0565     /* Select CMD2 Page3 (Undocumented) */
0566     {0xff, 0x04},
0567     /* Reload CMD1: Don't reload default value to register */
0568     {0xfb, 0x01},
0569     /* Select CMD1 */
0570     {0xff, 0x00},
0571     {0xd3, 0x05}, /* RGBMIPICTRL: VSYNC back porch = 5 */
0572     {0xd4, 0x04}, /* RGBMIPICTRL: VSYNC front porch = 4 */
0573 };
0574 
0575 static inline
0576 struct khadas_ts050_panel *to_khadas_ts050_panel(struct drm_panel *panel)
0577 {
0578     return container_of(panel, struct khadas_ts050_panel, base);
0579 }
0580 
0581 static int khadas_ts050_panel_prepare(struct drm_panel *panel)
0582 {
0583     struct khadas_ts050_panel *khadas_ts050 = to_khadas_ts050_panel(panel);
0584     unsigned int i;
0585     int err;
0586 
0587     if (khadas_ts050->prepared)
0588         return 0;
0589 
0590     gpiod_set_value_cansleep(khadas_ts050->enable_gpio, 0);
0591 
0592     err = regulator_enable(khadas_ts050->supply);
0593     if (err < 0)
0594         return err;
0595 
0596     gpiod_set_value_cansleep(khadas_ts050->enable_gpio, 1);
0597 
0598     msleep(60);
0599 
0600     gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 1);
0601 
0602     usleep_range(10000, 11000);
0603 
0604     gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 0);
0605 
0606     /* Select CMD2 page 4 (Undocumented) */
0607     mipi_dsi_dcs_write(khadas_ts050->link, 0xff, (u8[]){ 0x05 }, 1);
0608 
0609     /* Reload CMD1: Don't reload default value to register */
0610     mipi_dsi_dcs_write(khadas_ts050->link, 0xfb, (u8[]){ 0x01 }, 1);
0611 
0612     mipi_dsi_dcs_write(khadas_ts050->link, 0xc5, (u8[]){ 0x01 }, 1);
0613 
0614     msleep(100);
0615 
0616     for (i = 0; i < ARRAY_SIZE(init_code); i++) {
0617         err = mipi_dsi_dcs_write(khadas_ts050->link,
0618                      init_code[i].cmd,
0619                      &init_code[i].data, 1);
0620         if (err < 0) {
0621             dev_err(panel->dev, "failed write cmds: %d\n", err);
0622             goto poweroff;
0623         }
0624     }
0625 
0626     err = mipi_dsi_dcs_exit_sleep_mode(khadas_ts050->link);
0627     if (err < 0) {
0628         dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
0629         goto poweroff;
0630     }
0631 
0632     msleep(120);
0633 
0634     /* Select CMD1 */
0635     mipi_dsi_dcs_write(khadas_ts050->link, 0xff, (u8[]){ 0x00 }, 1);
0636 
0637     err = mipi_dsi_dcs_set_tear_on(khadas_ts050->link,
0638                        MIPI_DSI_DCS_TEAR_MODE_VBLANK);
0639     if (err < 0) {
0640         dev_err(panel->dev, "failed to set tear on: %d\n", err);
0641         goto poweroff;
0642     }
0643 
0644     err = mipi_dsi_dcs_set_display_on(khadas_ts050->link);
0645     if (err < 0) {
0646         dev_err(panel->dev, "failed to set display on: %d\n", err);
0647         goto poweroff;
0648     }
0649 
0650     usleep_range(10000, 11000);
0651 
0652     khadas_ts050->prepared = true;
0653 
0654     return 0;
0655 
0656 poweroff:
0657     gpiod_set_value_cansleep(khadas_ts050->enable_gpio, 0);
0658     gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 1);
0659 
0660     regulator_disable(khadas_ts050->supply);
0661 
0662     return err;
0663 }
0664 
0665 static int khadas_ts050_panel_unprepare(struct drm_panel *panel)
0666 {
0667     struct khadas_ts050_panel *khadas_ts050 = to_khadas_ts050_panel(panel);
0668     int err;
0669 
0670     if (!khadas_ts050->prepared)
0671         return 0;
0672 
0673     khadas_ts050->prepared = false;
0674 
0675     err = mipi_dsi_dcs_enter_sleep_mode(khadas_ts050->link);
0676     if (err < 0)
0677         dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
0678 
0679     msleep(150);
0680 
0681     gpiod_set_value_cansleep(khadas_ts050->enable_gpio, 0);
0682     gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 1);
0683 
0684     err = regulator_disable(khadas_ts050->supply);
0685     if (err < 0)
0686         return err;
0687 
0688     return 0;
0689 }
0690 
0691 static int khadas_ts050_panel_enable(struct drm_panel *panel)
0692 {
0693     struct khadas_ts050_panel *khadas_ts050 = to_khadas_ts050_panel(panel);
0694 
0695     khadas_ts050->enabled = true;
0696 
0697     return 0;
0698 }
0699 
0700 static int khadas_ts050_panel_disable(struct drm_panel *panel)
0701 {
0702     struct khadas_ts050_panel *khadas_ts050 = to_khadas_ts050_panel(panel);
0703     int err;
0704 
0705     if (!khadas_ts050->enabled)
0706         return 0;
0707 
0708     err = mipi_dsi_dcs_set_display_off(khadas_ts050->link);
0709     if (err < 0)
0710         dev_err(panel->dev, "failed to set display off: %d\n", err);
0711 
0712     usleep_range(10000, 11000);
0713 
0714     khadas_ts050->enabled = false;
0715 
0716     return 0;
0717 }
0718 
0719 static const struct drm_display_mode default_mode = {
0720     .clock = 120000,
0721     .hdisplay = 1088,
0722     .hsync_start = 1088 + 104,
0723     .hsync_end = 1088 + 104 + 4,
0724     .htotal = 1088 + 104 + 4 + 127,
0725     .vdisplay = 1920,
0726     .vsync_start = 1920 + 4,
0727     .vsync_end = 1920 + 4 + 2,
0728     .vtotal = 1920 + 4 + 2 + 3,
0729     .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
0730 };
0731 
0732 static int khadas_ts050_panel_get_modes(struct drm_panel *panel,
0733                     struct drm_connector *connector)
0734 {
0735     struct drm_display_mode *mode;
0736 
0737     mode = drm_mode_duplicate(connector->dev, &default_mode);
0738     if (!mode) {
0739         dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
0740             default_mode.hdisplay, default_mode.vdisplay,
0741             drm_mode_vrefresh(&default_mode));
0742         return -ENOMEM;
0743     }
0744 
0745     drm_mode_set_name(mode);
0746 
0747     drm_mode_probed_add(connector, mode);
0748 
0749     connector->display_info.width_mm = 64;
0750     connector->display_info.height_mm = 118;
0751     connector->display_info.bpc = 8;
0752 
0753     return 1;
0754 }
0755 
0756 static const struct drm_panel_funcs khadas_ts050_panel_funcs = {
0757     .prepare = khadas_ts050_panel_prepare,
0758     .unprepare = khadas_ts050_panel_unprepare,
0759     .enable = khadas_ts050_panel_enable,
0760     .disable = khadas_ts050_panel_disable,
0761     .get_modes = khadas_ts050_panel_get_modes,
0762 };
0763 
0764 static const struct of_device_id khadas_ts050_of_match[] = {
0765     { .compatible = "khadas,ts050", },
0766     { /* sentinel */ }
0767 };
0768 MODULE_DEVICE_TABLE(of, khadas_ts050_of_match);
0769 
0770 static int khadas_ts050_panel_add(struct khadas_ts050_panel *khadas_ts050)
0771 {
0772     struct device *dev = &khadas_ts050->link->dev;
0773     int err;
0774 
0775     khadas_ts050->supply = devm_regulator_get(dev, "power");
0776     if (IS_ERR(khadas_ts050->supply))
0777         return dev_err_probe(dev, PTR_ERR(khadas_ts050->supply),
0778                      "failed to get power supply");
0779 
0780     khadas_ts050->reset_gpio = devm_gpiod_get(dev, "reset",
0781                           GPIOD_OUT_LOW);
0782     if (IS_ERR(khadas_ts050->reset_gpio))
0783         return dev_err_probe(dev, PTR_ERR(khadas_ts050->reset_gpio),
0784                      "failed to get reset gpio");
0785 
0786     khadas_ts050->enable_gpio = devm_gpiod_get(dev, "enable",
0787                            GPIOD_OUT_HIGH);
0788     if (IS_ERR(khadas_ts050->enable_gpio))
0789         return dev_err_probe(dev, PTR_ERR(khadas_ts050->enable_gpio),
0790                      "failed to get enable gpio");
0791 
0792     drm_panel_init(&khadas_ts050->base, &khadas_ts050->link->dev,
0793                &khadas_ts050_panel_funcs, DRM_MODE_CONNECTOR_DSI);
0794 
0795     err = drm_panel_of_backlight(&khadas_ts050->base);
0796     if (err)
0797         return err;
0798 
0799     drm_panel_add(&khadas_ts050->base);
0800 
0801     return 0;
0802 }
0803 
0804 static int khadas_ts050_panel_probe(struct mipi_dsi_device *dsi)
0805 {
0806     struct khadas_ts050_panel *khadas_ts050;
0807     int err;
0808 
0809     dsi->lanes = 4;
0810     dsi->format = MIPI_DSI_FMT_RGB888;
0811     dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
0812               MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET;
0813 
0814     khadas_ts050 = devm_kzalloc(&dsi->dev, sizeof(*khadas_ts050),
0815                     GFP_KERNEL);
0816     if (!khadas_ts050)
0817         return -ENOMEM;
0818 
0819     mipi_dsi_set_drvdata(dsi, khadas_ts050);
0820     khadas_ts050->link = dsi;
0821 
0822     err = khadas_ts050_panel_add(khadas_ts050);
0823     if (err < 0)
0824         return err;
0825 
0826     err = mipi_dsi_attach(dsi);
0827     if (err)
0828         drm_panel_remove(&khadas_ts050->base);
0829 
0830     return err;
0831 }
0832 
0833 static int khadas_ts050_panel_remove(struct mipi_dsi_device *dsi)
0834 {
0835     struct khadas_ts050_panel *khadas_ts050 = mipi_dsi_get_drvdata(dsi);
0836     int err;
0837 
0838     err = mipi_dsi_detach(dsi);
0839     if (err < 0)
0840         dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
0841 
0842     drm_panel_remove(&khadas_ts050->base);
0843     drm_panel_disable(&khadas_ts050->base);
0844     drm_panel_unprepare(&khadas_ts050->base);
0845 
0846     return 0;
0847 }
0848 
0849 static void khadas_ts050_panel_shutdown(struct mipi_dsi_device *dsi)
0850 {
0851     struct khadas_ts050_panel *khadas_ts050 = mipi_dsi_get_drvdata(dsi);
0852 
0853     drm_panel_disable(&khadas_ts050->base);
0854     drm_panel_unprepare(&khadas_ts050->base);
0855 }
0856 
0857 static struct mipi_dsi_driver khadas_ts050_panel_driver = {
0858     .driver = {
0859         .name = "panel-khadas-ts050",
0860         .of_match_table = khadas_ts050_of_match,
0861     },
0862     .probe = khadas_ts050_panel_probe,
0863     .remove = khadas_ts050_panel_remove,
0864     .shutdown = khadas_ts050_panel_shutdown,
0865 };
0866 module_mipi_dsi_driver(khadas_ts050_panel_driver);
0867 
0868 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
0869 MODULE_DESCRIPTION("Khadas TS050 panel driver");
0870 MODULE_LICENSE("GPL v2");