0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <drm/drm_modes.h>
0012 #include <drm/drm_panel.h>
0013
0014 #include <linux/backlight.h>
0015 #include <linux/delay.h>
0016 #include <linux/gpio/consumer.h>
0017 #include <linux/module.h>
0018 #include <linux/regulator/consumer.h>
0019 #include <linux/media-bus-format.h>
0020
0021 #include <video/mipi_display.h>
0022
0023 #include "panel-samsung-s6e63m0.h"
0024
0025 #define S6E63M0_LCD_ID_VALUE_M2 0xA4
0026 #define S6E63M0_LCD_ID_VALUE_SM2 0xB4
0027 #define S6E63M0_LCD_ID_VALUE_SM2_1 0xB6
0028
0029 #define NUM_GAMMA_LEVELS 28
0030 #define GAMMA_TABLE_COUNT 23
0031
0032 #define MAX_BRIGHTNESS (NUM_GAMMA_LEVELS - 1)
0033
0034
0035 static u8 const s6e63m0_gamma_22[NUM_GAMMA_LEVELS][GAMMA_TABLE_COUNT] = {
0036
0037 { MCS_PGAMMACTL, 0x02,
0038 0x18, 0x08, 0x24, 0xA1, 0x51, 0x7B, 0xCE,
0039 0xCB, 0xC2, 0xC7, 0xCB, 0xBC, 0xDA, 0xDD,
0040 0xD3, 0x00, 0x53, 0x00, 0x52, 0x00, 0x6F, },
0041
0042 { MCS_PGAMMACTL, 0x02,
0043 0x18, 0x08, 0x24, 0x97, 0x58, 0x71, 0xCC,
0044 0xCB, 0xC0, 0xC5, 0xC9, 0xBA, 0xD9, 0xDC,
0045 0xD1, 0x00, 0x5B, 0x00, 0x5A, 0x00, 0x7A, },
0046
0047 { MCS_PGAMMACTL, 0x02,
0048 0x18, 0x08, 0x24, 0x96, 0x58, 0x72, 0xCB,
0049 0xCA, 0xBF, 0xC6, 0xC9, 0xBA, 0xD6, 0xD9,
0050 0xCD, 0x00, 0x61, 0x00, 0x61, 0x00, 0x83, },
0051
0052 { MCS_PGAMMACTL, 0x02,
0053 0x18, 0x08, 0x24, 0x91, 0x5E, 0x6E, 0xC9,
0054 0xC9, 0xBD, 0xC4, 0xC9, 0xB8, 0xD3, 0xD7,
0055 0xCA, 0x00, 0x69, 0x00, 0x67, 0x00, 0x8D, },
0056
0057 { MCS_PGAMMACTL, 0x02,
0058 0x18, 0x08, 0x24, 0x8E, 0x62, 0x6B, 0xC7,
0059 0xC9, 0xBB, 0xC3, 0xC7, 0xB7, 0xD3, 0xD7,
0060 0xCA, 0x00, 0x6E, 0x00, 0x6C, 0x00, 0x94, },
0061
0062 { MCS_PGAMMACTL, 0x02,
0063 0x18, 0x08, 0x24, 0x89, 0x68, 0x65, 0xC9,
0064 0xC9, 0xBC, 0xC1, 0xC5, 0xB6, 0xD2, 0xD5,
0065 0xC9, 0x00, 0x73, 0x00, 0x72, 0x00, 0x9A, },
0066
0067 { MCS_PGAMMACTL, 0x02,
0068 0x18, 0x08, 0x24, 0x89, 0x69, 0x64, 0xC7,
0069 0xC8, 0xBB, 0xC0, 0xC5, 0xB4, 0xD2, 0xD5,
0070 0xC9, 0x00, 0x77, 0x00, 0x76, 0x00, 0xA0, },
0071
0072 { MCS_PGAMMACTL, 0x02,
0073 0x18, 0x08, 0x24, 0x86, 0x69, 0x60, 0xC6,
0074 0xC8, 0xBA, 0xBF, 0xC4, 0xB4, 0xD0, 0xD4,
0075 0xC6, 0x00, 0x7C, 0x00, 0x7A, 0x00, 0xA7, },
0076
0077 { MCS_PGAMMACTL, 0x02,
0078 0x18, 0x08, 0x24, 0x86, 0x6A, 0x60, 0xC5,
0079 0xC7, 0xBA, 0xBD, 0xC3, 0xB2, 0xD0, 0xD4,
0080 0xC5, 0x00, 0x80, 0x00, 0x7E, 0x00, 0xAD, },
0081
0082 { MCS_PGAMMACTL, 0x02,
0083 0x18, 0x08, 0x24, 0x82, 0x6B, 0x5E, 0xC4,
0084 0xC8, 0xB9, 0xBD, 0xC2, 0xB1, 0xCE, 0xD2,
0085 0xC4, 0x00, 0x85, 0x00, 0x82, 0x00, 0xB3, },
0086
0087 { MCS_PGAMMACTL, 0x02,
0088 0x18, 0x08, 0x24, 0x8C, 0x6C, 0x60, 0xC3,
0089 0xC7, 0xB9, 0xBC, 0xC1, 0xAF, 0xCE, 0xD2,
0090 0xC3, 0x00, 0x88, 0x00, 0x86, 0x00, 0xB8, },
0091
0092 { MCS_PGAMMACTL, 0x02,
0093 0x18, 0x08, 0x24, 0x80, 0x6C, 0x5F, 0xC1,
0094 0xC6, 0xB7, 0xBC, 0xC1, 0xAE, 0xCD, 0xD0,
0095 0xC2, 0x00, 0x8C, 0x00, 0x8A, 0x00, 0xBE, },
0096
0097 { MCS_PGAMMACTL, 0x02,
0098 0x18, 0x08, 0x24, 0x80, 0x6E, 0x5F, 0xC1,
0099 0xC6, 0xB6, 0xBC, 0xC0, 0xAE, 0xCC, 0xD0,
0100 0xC2, 0x00, 0x8F, 0x00, 0x8D, 0x00, 0xC2, },
0101
0102 { MCS_PGAMMACTL, 0x02,
0103 0x18, 0x08, 0x24, 0x7F, 0x6E, 0x5F, 0xC0,
0104 0xC6, 0xB5, 0xBA, 0xBF, 0xAD, 0xCB, 0xCF,
0105 0xC0, 0x00, 0x94, 0x00, 0x91, 0x00, 0xC8, },
0106
0107 { MCS_PGAMMACTL, 0x02,
0108 0x18, 0x08, 0x24, 0x7C, 0x6D, 0x5C, 0xC0,
0109 0xC6, 0xB4, 0xBB, 0xBE, 0xAD, 0xCA, 0xCF,
0110 0xC0, 0x00, 0x96, 0x00, 0x94, 0x00, 0xCC, },
0111
0112 { MCS_PGAMMACTL, 0x02,
0113 0x18, 0x08, 0x24, 0x7B, 0x6D, 0x5B, 0xC0,
0114 0xC5, 0xB3, 0xBA, 0xBE, 0xAD, 0xCA, 0xCE,
0115 0xBF, 0x00, 0x99, 0x00, 0x97, 0x00, 0xD0, },
0116
0117 { MCS_PGAMMACTL, 0x02,
0118 0x18, 0x08, 0x24, 0x7A, 0x6D, 0x59, 0xC1,
0119 0xC5, 0xB4, 0xB8, 0xBD, 0xAC, 0xC9, 0xCE,
0120 0xBE, 0x00, 0x9D, 0x00, 0x9A, 0x00, 0xD5, },
0121
0122 { MCS_PGAMMACTL, 0x02,
0123 0x18, 0x08, 0x24, 0x79, 0x6D, 0x58, 0xC1,
0124 0xC4, 0xB4, 0xB6, 0xBD, 0xAA, 0xCA, 0xCD,
0125 0xBE, 0x00, 0x9F, 0x00, 0x9D, 0x00, 0xD9, },
0126
0127 { MCS_PGAMMACTL, 0x02,
0128 0x18, 0x08, 0x24, 0x79, 0x6D, 0x57, 0xC0,
0129 0xC4, 0xB4, 0xB7, 0xBD, 0xAA, 0xC8, 0xCC,
0130 0xBD, 0x00, 0xA2, 0x00, 0xA0, 0x00, 0xDD, },
0131
0132 { MCS_PGAMMACTL, 0x02,
0133 0x18, 0x08, 0x24, 0x78, 0x6F, 0x58, 0xBF,
0134 0xC4, 0xB3, 0xB5, 0xBB, 0xA9, 0xC8, 0xCC,
0135 0xBC, 0x00, 0xA6, 0x00, 0xA3, 0x00, 0xE2, },
0136
0137 { MCS_PGAMMACTL, 0x02,
0138 0x18, 0x08, 0x24, 0x75, 0x6F, 0x56, 0xBF,
0139 0xC3, 0xB2, 0xB6, 0xBB, 0xA8, 0xC7, 0xCB,
0140 0xBC, 0x00, 0xA8, 0x00, 0xA6, 0x00, 0xE6, },
0141
0142 { MCS_PGAMMACTL, 0x02,
0143 0x18, 0x08, 0x24, 0x76, 0x6F, 0x56, 0xC0,
0144 0xC3, 0xB2, 0xB5, 0xBA, 0xA8, 0xC6, 0xCB,
0145 0xBB, 0x00, 0xAA, 0x00, 0xA8, 0x00, 0xE9, },
0146
0147 { MCS_PGAMMACTL, 0x02,
0148 0x18, 0x08, 0x24, 0x74, 0x6D, 0x54, 0xBF,
0149 0xC3, 0xB2, 0xB4, 0xBA, 0xA7, 0xC6, 0xCA,
0150 0xBA, 0x00, 0xAD, 0x00, 0xAB, 0x00, 0xED, },
0151
0152 { MCS_PGAMMACTL, 0x02,
0153 0x18, 0x08, 0x24, 0x74, 0x6E, 0x54, 0xBD,
0154 0xC2, 0xB0, 0xB5, 0xBA, 0xA7, 0xC5, 0xC9,
0155 0xBA, 0x00, 0xB0, 0x00, 0xAE, 0x00, 0xF1, },
0156
0157 { MCS_PGAMMACTL, 0x02,
0158 0x18, 0x08, 0x24, 0x71, 0x6C, 0x50, 0xBD,
0159 0xC3, 0xB0, 0xB4, 0xB8, 0xA6, 0xC6, 0xC9,
0160 0xBB, 0x00, 0xB2, 0x00, 0xB1, 0x00, 0xF4, },
0161
0162 { MCS_PGAMMACTL, 0x02,
0163 0x18, 0x08, 0x24, 0x6E, 0x6C, 0x4D, 0xBE,
0164 0xC3, 0xB1, 0xB3, 0xB8, 0xA5, 0xC6, 0xC8,
0165 0xBB, 0x00, 0xB4, 0x00, 0xB3, 0x00, 0xF7, },
0166
0167 { MCS_PGAMMACTL, 0x02,
0168 0x18, 0x08, 0x24, 0x71, 0x70, 0x50, 0xBD,
0169 0xC1, 0xB0, 0xB2, 0xB8, 0xA4, 0xC6, 0xC7,
0170 0xBB, 0x00, 0xB6, 0x00, 0xB6, 0x00, 0xFA, },
0171
0172 { MCS_PGAMMACTL, 0x02,
0173 0x18, 0x08, 0x24, 0x70, 0x6E, 0x4E, 0xBC,
0174 0xC0, 0xAF, 0xB3, 0xB8, 0xA5, 0xC5, 0xC7,
0175 0xBB, 0x00, 0xB9, 0x00, 0xB8, 0x00, 0xFC, },
0176 };
0177
0178 #define NUM_ACL_LEVELS 7
0179 #define ACL_TABLE_COUNT 28
0180
0181 static u8 const s6e63m0_acl[NUM_ACL_LEVELS][ACL_TABLE_COUNT] = {
0182
0183 { MCS_BCMODE,
0184 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0185 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0186 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0187 0x00, 0x00, 0x00 },
0188
0189 { MCS_BCMODE,
0190 0x4D, 0x96, 0x1D, 0x00, 0x00, 0x01, 0xDF, 0x00,
0191 0x00, 0x03, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00,
0192 0x01, 0x06, 0x0C, 0x11, 0x16, 0x1C, 0x21, 0x26,
0193 0x2B, 0x31, 0x36 },
0194
0195 { MCS_BCMODE,
0196 0x4D, 0x96, 0x1D, 0x00, 0x00, 0x01, 0xDF, 0x00,
0197 0x00, 0x03, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00,
0198 0x01, 0x07, 0x0C, 0x12, 0x18, 0x1E, 0x23, 0x29,
0199 0x2F, 0x34, 0x3A },
0200
0201 { MCS_BCMODE,
0202 0x4D, 0x96, 0x1D, 0x00, 0x00, 0x01, 0xDF, 0x00,
0203 0x00, 0x03, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00,
0204 0x01, 0x07, 0x0D, 0x13, 0x19, 0x1F, 0x25, 0x2B,
0205 0x31, 0x37, 0x3D },
0206
0207 { MCS_BCMODE,
0208 0x4D, 0x96, 0x1D, 0x00, 0x00, 0x01, 0xDF, 0x00,
0209 0x00, 0x03, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00,
0210 0x01, 0x07, 0x0E, 0x14, 0x1B, 0x21, 0x27, 0x2E,
0211 0x34, 0x3B, 0x41 },
0212
0213 { MCS_BCMODE,
0214 0x4D, 0x96, 0x1D, 0x00, 0x00, 0x01, 0xDF, 0x00,
0215 0x00, 0x03, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00,
0216 0x01, 0x08, 0x0E, 0x15, 0x1B, 0x22, 0x29, 0x2F,
0217 0x36, 0x3C, 0x43 },
0218
0219 { MCS_BCMODE,
0220 0x4D, 0x96, 0x1D, 0x00, 0x00, 0x01, 0xDF, 0x00,
0221 0x00, 0x03, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00,
0222 0x01, 0x08, 0x0F, 0x16, 0x1D, 0x24, 0x2A, 0x31,
0223 0x38, 0x3F, 0x46 },
0224 };
0225
0226
0227 static u8 const s6e63m0_acl_per_gamma[NUM_GAMMA_LEVELS] = {
0228
0229 0, 0, 0, 0,
0230
0231 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0232
0233 6, 6, 6, 6, 6,
0234 };
0235
0236
0237 #define S6E63M0_ELVSS_LEVELS 5
0238
0239 static u8 const s6e63m0_elvss_offsets[S6E63M0_ELVSS_LEVELS] = {
0240 0x00,
0241 0x0D,
0242 0x09,
0243 0x07,
0244 0x00,
0245 };
0246
0247
0248 static u8 const s6e63m0_elvss_per_gamma[NUM_GAMMA_LEVELS] = {
0249
0250 1, 1, 1, 1, 1, 1, 1, 1,
0251
0252 2, 2, 2, 2, 2, 2,
0253
0254 3, 3, 3, 3,
0255
0256 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
0257 };
0258
0259 struct s6e63m0 {
0260 struct device *dev;
0261 void *transport_data;
0262 int (*dcs_read)(struct device *dev, void *trsp, const u8 cmd, u8 *val);
0263 int (*dcs_write)(struct device *dev, void *trsp, const u8 *data, size_t len);
0264 struct drm_panel panel;
0265 struct backlight_device *bl_dev;
0266 u8 lcd_type;
0267 u8 elvss_pulse;
0268 bool dsi_mode;
0269
0270 struct regulator_bulk_data supplies[2];
0271 struct gpio_desc *reset_gpio;
0272
0273 bool prepared;
0274 bool enabled;
0275
0276
0277
0278
0279
0280
0281
0282
0283 int error;
0284 };
0285
0286 static const struct drm_display_mode default_mode = {
0287 .clock = 25628,
0288 .hdisplay = 480,
0289 .hsync_start = 480 + 16,
0290 .hsync_end = 480 + 16 + 2,
0291 .htotal = 480 + 16 + 2 + 16,
0292 .vdisplay = 800,
0293 .vsync_start = 800 + 28,
0294 .vsync_end = 800 + 28 + 2,
0295 .vtotal = 800 + 28 + 2 + 1,
0296 .width_mm = 53,
0297 .height_mm = 89,
0298 .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
0299 };
0300
0301 static inline struct s6e63m0 *panel_to_s6e63m0(struct drm_panel *panel)
0302 {
0303 return container_of(panel, struct s6e63m0, panel);
0304 }
0305
0306 static int s6e63m0_clear_error(struct s6e63m0 *ctx)
0307 {
0308 int ret = ctx->error;
0309
0310 ctx->error = 0;
0311 return ret;
0312 }
0313
0314 static void s6e63m0_dcs_read(struct s6e63m0 *ctx, const u8 cmd, u8 *data)
0315 {
0316 if (ctx->error < 0)
0317 return;
0318
0319 ctx->error = ctx->dcs_read(ctx->dev, ctx->transport_data, cmd, data);
0320 }
0321
0322 static void s6e63m0_dcs_write(struct s6e63m0 *ctx, const u8 *data, size_t len)
0323 {
0324 if (ctx->error < 0 || len == 0)
0325 return;
0326
0327 ctx->error = ctx->dcs_write(ctx->dev, ctx->transport_data, data, len);
0328 }
0329
0330 #define s6e63m0_dcs_write_seq_static(ctx, seq ...) \
0331 ({ \
0332 static const u8 d[] = { seq }; \
0333 s6e63m0_dcs_write(ctx, d, ARRAY_SIZE(d)); \
0334 })
0335
0336 static int s6e63m0_check_lcd_type(struct s6e63m0 *ctx)
0337 {
0338 u8 id1, id2, id3;
0339 int ret;
0340
0341 s6e63m0_dcs_read(ctx, MCS_READ_ID1, &id1);
0342 s6e63m0_dcs_read(ctx, MCS_READ_ID2, &id2);
0343 s6e63m0_dcs_read(ctx, MCS_READ_ID3, &id3);
0344
0345 ret = s6e63m0_clear_error(ctx);
0346 if (ret) {
0347 dev_err(ctx->dev, "error checking LCD type (%d)\n", ret);
0348 ctx->lcd_type = 0x00;
0349 return ret;
0350 }
0351
0352 dev_info(ctx->dev, "MTP ID: %02x %02x %02x\n", id1, id2, id3);
0353
0354
0355
0356
0357
0358
0359 switch (id2) {
0360 case S6E63M0_LCD_ID_VALUE_M2:
0361 dev_info(ctx->dev, "detected LCD panel AMS397GE MIPI M2\n");
0362 ctx->elvss_pulse = id3;
0363 break;
0364 case S6E63M0_LCD_ID_VALUE_SM2:
0365 case S6E63M0_LCD_ID_VALUE_SM2_1:
0366 dev_info(ctx->dev, "detected LCD panel AMS397GE MIPI SM2\n");
0367 ctx->elvss_pulse = id3;
0368 break;
0369 default:
0370 dev_info(ctx->dev, "unknown LCD panel type %02x\n", id2);
0371
0372 ctx->elvss_pulse = 0x16;
0373 break;
0374 }
0375
0376 ctx->lcd_type = id2;
0377
0378 return 0;
0379 }
0380
0381 static void s6e63m0_init(struct s6e63m0 *ctx)
0382 {
0383
0384
0385
0386
0387
0388
0389
0390 if (ctx->dsi_mode)
0391 s6e63m0_dcs_write_seq_static(ctx, MCS_PANELCTL,
0392 0x01, 0x2c, 0x2c, 0x07, 0x07, 0x5f, 0xb3,
0393 0x6d, 0x97, 0x1d, 0x3a, 0x0f, 0x00, 0x00);
0394 else
0395 s6e63m0_dcs_write_seq_static(ctx, MCS_PANELCTL,
0396 0x01, 0x27, 0x27, 0x07, 0x07, 0x54, 0x9f,
0397 0x63, 0x8f, 0x1a, 0x33, 0x0d, 0x00, 0x00);
0398
0399 s6e63m0_dcs_write_seq_static(ctx, MCS_DISCTL,
0400 0x02, 0x03, 0x1c, 0x10, 0x10);
0401 s6e63m0_dcs_write_seq_static(ctx, MCS_IFCTL,
0402 0x03, 0x00, 0x00);
0403
0404 s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL,
0405 0x00, 0x18, 0x08, 0x24, 0x64, 0x56, 0x33,
0406 0xb6, 0xba, 0xa8, 0xac, 0xb1, 0x9d, 0xc1,
0407 0xc1, 0xb7, 0x00, 0x9c, 0x00, 0x9f, 0x00,
0408 0xd6);
0409 s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL,
0410 0x01);
0411
0412 s6e63m0_dcs_write_seq_static(ctx, MCS_SRCCTL,
0413 0x00, 0x8e, 0x07);
0414 s6e63m0_dcs_write_seq_static(ctx, MCS_PENTILE_1, 0x6c);
0415
0416 s6e63m0_dcs_write_seq_static(ctx, MCS_GAMMA_DELTA_Y_RED,
0417 0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17,
0418 0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b,
0419 0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a,
0420 0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23,
0421 0x21, 0x20, 0x1e, 0x1e);
0422
0423 s6e63m0_dcs_write_seq_static(ctx, MCS_GAMMA_DELTA_X_RED,
0424 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x44,
0425 0x44, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66,
0426 0x66, 0x66);
0427
0428 s6e63m0_dcs_write_seq_static(ctx, MCS_GAMMA_DELTA_Y_GREEN,
0429 0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17,
0430 0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b,
0431 0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a,
0432 0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23,
0433 0x21, 0x20, 0x1e, 0x1e);
0434
0435 s6e63m0_dcs_write_seq_static(ctx, MCS_GAMMA_DELTA_X_GREEN,
0436 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x44,
0437 0x44, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66,
0438 0x66, 0x66);
0439
0440 s6e63m0_dcs_write_seq_static(ctx, MCS_GAMMA_DELTA_Y_BLUE,
0441 0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17,
0442 0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b,
0443 0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a,
0444 0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23,
0445 0x21, 0x20, 0x1e, 0x1e);
0446
0447 s6e63m0_dcs_write_seq_static(ctx, MCS_GAMMA_DELTA_X_BLUE,
0448 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x44,
0449 0x44, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66,
0450 0x66, 0x66);
0451
0452 s6e63m0_dcs_write_seq_static(ctx, MCS_BCMODE,
0453 0x4d, 0x96, 0x1d, 0x00, 0x00, 0x01, 0xdf,
0454 0x00, 0x00, 0x03, 0x1f, 0x00, 0x00, 0x00,
0455 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06,
0456 0x09, 0x0d, 0x0f, 0x12, 0x15, 0x18);
0457
0458 s6e63m0_dcs_write_seq_static(ctx, MCS_TEMP_SWIRE,
0459 0x10, 0x10, 0x0b, 0x05);
0460
0461 s6e63m0_dcs_write_seq_static(ctx, MCS_MIECTL1,
0462 0x01);
0463
0464 s6e63m0_dcs_write_seq_static(ctx, MCS_ELVSS_ON,
0465 0x0b);
0466 }
0467
0468 static int s6e63m0_power_on(struct s6e63m0 *ctx)
0469 {
0470 int ret;
0471
0472 ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
0473 if (ret < 0)
0474 return ret;
0475
0476 msleep(25);
0477
0478
0479 gpiod_set_value(ctx->reset_gpio, 1);
0480 msleep(5);
0481 gpiod_set_value(ctx->reset_gpio, 0);
0482 msleep(120);
0483
0484 return 0;
0485 }
0486
0487 static int s6e63m0_power_off(struct s6e63m0 *ctx)
0488 {
0489 int ret;
0490
0491 gpiod_set_value(ctx->reset_gpio, 1);
0492 msleep(120);
0493
0494 ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
0495 if (ret < 0)
0496 return ret;
0497
0498 return 0;
0499 }
0500
0501 static int s6e63m0_disable(struct drm_panel *panel)
0502 {
0503 struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
0504
0505 if (!ctx->enabled)
0506 return 0;
0507
0508 backlight_disable(ctx->bl_dev);
0509
0510 s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF);
0511 msleep(10);
0512 s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
0513 msleep(120);
0514
0515 ctx->enabled = false;
0516
0517 return 0;
0518 }
0519
0520 static int s6e63m0_unprepare(struct drm_panel *panel)
0521 {
0522 struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
0523 int ret;
0524
0525 if (!ctx->prepared)
0526 return 0;
0527
0528 s6e63m0_clear_error(ctx);
0529
0530 ret = s6e63m0_power_off(ctx);
0531 if (ret < 0)
0532 return ret;
0533
0534 ctx->prepared = false;
0535
0536 return 0;
0537 }
0538
0539 static int s6e63m0_prepare(struct drm_panel *panel)
0540 {
0541 struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
0542 int ret;
0543
0544 if (ctx->prepared)
0545 return 0;
0546
0547 ret = s6e63m0_power_on(ctx);
0548 if (ret < 0)
0549 return ret;
0550
0551
0552 s6e63m0_dcs_write_seq_static(ctx, MCS_LEVEL_2_KEY, 0x5a, 0x5a);
0553
0554 s6e63m0_dcs_write_seq_static(ctx, MCS_MTP_KEY, 0x5a, 0x5a);
0555
0556 ret = s6e63m0_check_lcd_type(ctx);
0557 if (ret < 0)
0558 return ret;
0559
0560 s6e63m0_init(ctx);
0561
0562 ret = s6e63m0_clear_error(ctx);
0563
0564 if (ret < 0)
0565 s6e63m0_unprepare(panel);
0566
0567 ctx->prepared = true;
0568
0569 return ret;
0570 }
0571
0572 static int s6e63m0_enable(struct drm_panel *panel)
0573 {
0574 struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
0575
0576 if (ctx->enabled)
0577 return 0;
0578
0579 s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE);
0580 msleep(120);
0581 s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON);
0582 msleep(10);
0583
0584 s6e63m0_dcs_write_seq_static(ctx, MCS_ERROR_CHECK,
0585 0xE7, 0x14, 0x60, 0x17, 0x0A, 0x49, 0xC3,
0586 0x8F, 0x19, 0x64, 0x91, 0x84, 0x76, 0x20,
0587 0x0F, 0x00);
0588
0589 backlight_enable(ctx->bl_dev);
0590
0591 ctx->enabled = true;
0592
0593 return 0;
0594 }
0595
0596 static int s6e63m0_get_modes(struct drm_panel *panel,
0597 struct drm_connector *connector)
0598 {
0599 struct drm_display_mode *mode;
0600 static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
0601
0602 mode = drm_mode_duplicate(connector->dev, &default_mode);
0603 if (!mode) {
0604 dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
0605 default_mode.hdisplay, default_mode.vdisplay,
0606 drm_mode_vrefresh(&default_mode));
0607 return -ENOMEM;
0608 }
0609
0610 connector->display_info.width_mm = mode->width_mm;
0611 connector->display_info.height_mm = mode->height_mm;
0612 drm_display_info_set_bus_formats(&connector->display_info,
0613 &bus_format, 1);
0614 connector->display_info.bus_flags = DRM_BUS_FLAG_DE_LOW |
0615 DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
0616
0617 drm_mode_set_name(mode);
0618
0619 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
0620 drm_mode_probed_add(connector, mode);
0621
0622 return 1;
0623 }
0624
0625 static const struct drm_panel_funcs s6e63m0_drm_funcs = {
0626 .disable = s6e63m0_disable,
0627 .unprepare = s6e63m0_unprepare,
0628 .prepare = s6e63m0_prepare,
0629 .enable = s6e63m0_enable,
0630 .get_modes = s6e63m0_get_modes,
0631 };
0632
0633 static int s6e63m0_set_brightness(struct backlight_device *bd)
0634 {
0635 struct s6e63m0 *ctx = bl_get_data(bd);
0636 int brightness = bd->props.brightness;
0637 u8 elvss_val;
0638 u8 elvss_cmd_set[5];
0639 int i;
0640
0641
0642 i = s6e63m0_elvss_per_gamma[brightness];
0643 elvss_val = ctx->elvss_pulse + s6e63m0_elvss_offsets[i];
0644 if (elvss_val > 0x1f)
0645 elvss_val = 0x1f;
0646 elvss_cmd_set[0] = MCS_TEMP_SWIRE;
0647 elvss_cmd_set[1] = elvss_val;
0648 elvss_cmd_set[2] = elvss_val;
0649 elvss_cmd_set[3] = elvss_val;
0650 elvss_cmd_set[4] = elvss_val;
0651 s6e63m0_dcs_write(ctx, elvss_cmd_set, 5);
0652
0653
0654 i = s6e63m0_acl_per_gamma[brightness];
0655 s6e63m0_dcs_write(ctx, s6e63m0_acl[i],
0656 ARRAY_SIZE(s6e63m0_acl[i]));
0657
0658
0659 s6e63m0_dcs_write(ctx, s6e63m0_gamma_22[brightness],
0660 ARRAY_SIZE(s6e63m0_gamma_22[brightness]));
0661 s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL, 0x03);
0662
0663
0664 return s6e63m0_clear_error(ctx);
0665 }
0666
0667 static const struct backlight_ops s6e63m0_backlight_ops = {
0668 .update_status = s6e63m0_set_brightness,
0669 };
0670
0671 static int s6e63m0_backlight_register(struct s6e63m0 *ctx, u32 max_brightness)
0672 {
0673 struct backlight_properties props = {
0674 .type = BACKLIGHT_RAW,
0675 .brightness = max_brightness,
0676 .max_brightness = max_brightness,
0677 };
0678 struct device *dev = ctx->dev;
0679 int ret = 0;
0680
0681 ctx->bl_dev = devm_backlight_device_register(dev, "panel", dev, ctx,
0682 &s6e63m0_backlight_ops,
0683 &props);
0684 if (IS_ERR(ctx->bl_dev)) {
0685 ret = PTR_ERR(ctx->bl_dev);
0686 dev_err(dev, "error registering backlight device (%d)\n", ret);
0687 }
0688
0689 return ret;
0690 }
0691
0692 int s6e63m0_probe(struct device *dev, void *trsp,
0693 int (*dcs_read)(struct device *dev, void *trsp, const u8 cmd, u8 *val),
0694 int (*dcs_write)(struct device *dev, void *trsp, const u8 *data, size_t len),
0695 bool dsi_mode)
0696 {
0697 struct s6e63m0 *ctx;
0698 u32 max_brightness;
0699 int ret;
0700
0701 ctx = devm_kzalloc(dev, sizeof(struct s6e63m0), GFP_KERNEL);
0702 if (!ctx)
0703 return -ENOMEM;
0704
0705 ctx->transport_data = trsp;
0706 ctx->dsi_mode = dsi_mode;
0707 ctx->dcs_read = dcs_read;
0708 ctx->dcs_write = dcs_write;
0709 dev_set_drvdata(dev, ctx);
0710
0711 ctx->dev = dev;
0712 ctx->enabled = false;
0713 ctx->prepared = false;
0714
0715 ret = device_property_read_u32(dev, "max-brightness", &max_brightness);
0716 if (ret)
0717 max_brightness = MAX_BRIGHTNESS;
0718 if (max_brightness > MAX_BRIGHTNESS) {
0719 dev_err(dev, "illegal max brightness specified\n");
0720 max_brightness = MAX_BRIGHTNESS;
0721 }
0722
0723 ctx->supplies[0].supply = "vdd3";
0724 ctx->supplies[1].supply = "vci";
0725 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
0726 ctx->supplies);
0727 if (ret < 0) {
0728 dev_err(dev, "failed to get regulators: %d\n", ret);
0729 return ret;
0730 }
0731
0732 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
0733 if (IS_ERR(ctx->reset_gpio)) {
0734 dev_err(dev, "cannot get reset-gpios %ld\n", PTR_ERR(ctx->reset_gpio));
0735 return PTR_ERR(ctx->reset_gpio);
0736 }
0737
0738 drm_panel_init(&ctx->panel, dev, &s6e63m0_drm_funcs,
0739 dsi_mode ? DRM_MODE_CONNECTOR_DSI :
0740 DRM_MODE_CONNECTOR_DPI);
0741
0742 ret = s6e63m0_backlight_register(ctx, max_brightness);
0743 if (ret < 0)
0744 return ret;
0745
0746 drm_panel_add(&ctx->panel);
0747
0748 return 0;
0749 }
0750 EXPORT_SYMBOL_GPL(s6e63m0_probe);
0751
0752 void s6e63m0_remove(struct device *dev)
0753 {
0754 struct s6e63m0 *ctx = dev_get_drvdata(dev);
0755
0756 drm_panel_remove(&ctx->panel);
0757 }
0758 EXPORT_SYMBOL_GPL(s6e63m0_remove);
0759
0760 MODULE_AUTHOR("Paweł Chmiel <pawel.mikolaj.chmiel@gmail.com>");
0761 MODULE_DESCRIPTION("s6e63m0 LCD Driver");
0762 MODULE_LICENSE("GPL v2");