Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * MIPI-DSI based s6e3ha2 AMOLED 5.7 inch panel driver.
0004  *
0005  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
0006  * Donghwa Lee <dh09.lee@samsung.com>
0007  * Hyungwon Hwang <human.hwang@samsung.com>
0008  * Hoegeun Kwon <hoegeun.kwon@samsung.com>
0009  */
0010 
0011 #include <linux/backlight.h>
0012 #include <linux/delay.h>
0013 #include <linux/gpio/consumer.h>
0014 #include <linux/module.h>
0015 #include <linux/of_device.h>
0016 #include <linux/regulator/consumer.h>
0017 
0018 #include <drm/drm_mipi_dsi.h>
0019 #include <drm/drm_modes.h>
0020 #include <drm/drm_panel.h>
0021 
0022 #define S6E3HA2_MIN_BRIGHTNESS      0
0023 #define S6E3HA2_MAX_BRIGHTNESS      100
0024 #define S6E3HA2_DEFAULT_BRIGHTNESS  80
0025 
0026 #define S6E3HA2_NUM_GAMMA_STEPS     46
0027 #define S6E3HA2_GAMMA_CMD_CNT       35
0028 #define S6E3HA2_VINT_STATUS_MAX     10
0029 
0030 static const u8 gamma_tbl[S6E3HA2_NUM_GAMMA_STEPS][S6E3HA2_GAMMA_CMD_CNT] = {
0031     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x82, 0x83,
0032       0x85, 0x88, 0x8b, 0x8b, 0x84, 0x88, 0x82, 0x82, 0x89, 0x86, 0x8c,
0033       0x94, 0x84, 0xb1, 0xaf, 0x8e, 0xcf, 0xad, 0xc9, 0x00, 0x00, 0x00,
0034       0x00, 0x00 },
0035     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x84, 0x84,
0036       0x85, 0x87, 0x8b, 0x8a, 0x84, 0x88, 0x82, 0x82, 0x89, 0x86, 0x8a,
0037       0x93, 0x84, 0xb0, 0xae, 0x8e, 0xc9, 0xa8, 0xc5, 0x00, 0x00, 0x00,
0038       0x00, 0x00 },
0039     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
0040       0x85, 0x86, 0x8a, 0x8a, 0x84, 0x88, 0x81, 0x84, 0x8a, 0x88, 0x8a,
0041       0x91, 0x84, 0xb1, 0xae, 0x8b, 0xd5, 0xb2, 0xcc, 0x00, 0x00, 0x00,
0042       0x00, 0x00 },
0043     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
0044       0x85, 0x86, 0x8a, 0x8a, 0x84, 0x87, 0x81, 0x84, 0x8a, 0x87, 0x8a,
0045       0x91, 0x85, 0xae, 0xac, 0x8a, 0xc3, 0xa3, 0xc0, 0x00, 0x00, 0x00,
0046       0x00, 0x00 },
0047     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x85, 0x85,
0048       0x86, 0x85, 0x88, 0x89, 0x84, 0x89, 0x82, 0x84, 0x87, 0x85, 0x8b,
0049       0x91, 0x88, 0xad, 0xab, 0x8a, 0xb7, 0x9b, 0xb6, 0x00, 0x00, 0x00,
0050       0x00, 0x00 },
0051     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
0052       0x85, 0x86, 0x89, 0x8a, 0x84, 0x89, 0x83, 0x83, 0x86, 0x84, 0x8b,
0053       0x90, 0x84, 0xb0, 0xae, 0x8b, 0xce, 0xad, 0xc8, 0x00, 0x00, 0x00,
0054       0x00, 0x00 },
0055     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
0056       0x85, 0x87, 0x89, 0x8a, 0x83, 0x87, 0x82, 0x85, 0x88, 0x87, 0x89,
0057       0x8f, 0x84, 0xac, 0xaa, 0x89, 0xb1, 0x98, 0xaf, 0x00, 0x00, 0x00,
0058       0x00, 0x00 },
0059     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
0060       0x85, 0x86, 0x88, 0x89, 0x84, 0x88, 0x83, 0x82, 0x85, 0x84, 0x8c,
0061       0x91, 0x86, 0xac, 0xaa, 0x89, 0xc2, 0xa5, 0xbd, 0x00, 0x00, 0x00,
0062       0x00, 0x00 },
0063     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
0064       0x85, 0x87, 0x89, 0x8a, 0x83, 0x87, 0x82, 0x85, 0x88, 0x87, 0x88,
0065       0x8b, 0x82, 0xad, 0xaa, 0x8a, 0xc2, 0xa5, 0xbd, 0x00, 0x00, 0x00,
0066       0x00, 0x00 },
0067     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
0068       0x85, 0x86, 0x87, 0x89, 0x84, 0x88, 0x83, 0x82, 0x85, 0x84, 0x8a,
0069       0x8e, 0x84, 0xae, 0xac, 0x89, 0xda, 0xb7, 0xd0, 0x00, 0x00, 0x00,
0070       0x00, 0x00 },
0071     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
0072       0x85, 0x86, 0x87, 0x89, 0x84, 0x88, 0x83, 0x80, 0x83, 0x82, 0x8b,
0073       0x8e, 0x85, 0xac, 0xaa, 0x89, 0xc8, 0xaa, 0xc1, 0x00, 0x00, 0x00,
0074       0x00, 0x00 },
0075     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
0076       0x85, 0x86, 0x87, 0x89, 0x81, 0x85, 0x81, 0x84, 0x86, 0x84, 0x8c,
0077       0x8c, 0x84, 0xa9, 0xa8, 0x87, 0xa3, 0x92, 0xa1, 0x00, 0x00, 0x00,
0078       0x00, 0x00 },
0079     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
0080       0x85, 0x86, 0x87, 0x89, 0x84, 0x86, 0x83, 0x80, 0x83, 0x81, 0x8c,
0081       0x8d, 0x84, 0xaa, 0xaa, 0x89, 0xce, 0xaf, 0xc5, 0x00, 0x00, 0x00,
0082       0x00, 0x00 },
0083     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
0084       0x85, 0x86, 0x87, 0x89, 0x81, 0x83, 0x80, 0x83, 0x85, 0x85, 0x8c,
0085       0x8c, 0x84, 0xa8, 0xa8, 0x88, 0xb5, 0x9f, 0xb0, 0x00, 0x00, 0x00,
0086       0x00, 0x00 },
0087     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
0088       0x86, 0x86, 0x87, 0x88, 0x81, 0x83, 0x80, 0x83, 0x85, 0x85, 0x8c,
0089       0x8b, 0x84, 0xab, 0xa8, 0x86, 0xd4, 0xb4, 0xc9, 0x00, 0x00, 0x00,
0090       0x00, 0x00 },
0091     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
0092       0x86, 0x86, 0x87, 0x88, 0x81, 0x83, 0x80, 0x84, 0x84, 0x85, 0x8b,
0093       0x8a, 0x83, 0xa6, 0xa5, 0x84, 0xbb, 0xa4, 0xb3, 0x00, 0x00, 0x00,
0094       0x00, 0x00 },
0095     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
0096       0x86, 0x85, 0x86, 0x86, 0x82, 0x85, 0x81, 0x82, 0x83, 0x84, 0x8e,
0097       0x8b, 0x83, 0xa4, 0xa3, 0x8a, 0xa1, 0x93, 0x9d, 0x00, 0x00, 0x00,
0098       0x00, 0x00 },
0099     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83,
0100       0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x82, 0x82, 0x84, 0x8e,
0101       0x8b, 0x83, 0xa4, 0xa2, 0x86, 0xc1, 0xa9, 0xb7, 0x00, 0x00, 0x00,
0102       0x00, 0x00 },
0103     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83,
0104       0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x82, 0x82, 0x84, 0x8d,
0105       0x89, 0x82, 0xa2, 0xa1, 0x84, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00,
0106       0x00, 0x00 },
0107     { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83,
0108       0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x83, 0x83, 0x85, 0x8c,
0109       0x87, 0x7f, 0xa2, 0x9d, 0x88, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
0110       0x00, 0x00 },
0111     { 0x00, 0xbb, 0x00, 0xc5, 0x00, 0xb4, 0x87, 0x86, 0x86, 0x84, 0x83,
0112       0x86, 0x87, 0x87, 0x87, 0x80, 0x82, 0x7f, 0x86, 0x86, 0x88, 0x8a,
0113       0x84, 0x7e, 0x9d, 0x9c, 0x82, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
0114       0x00, 0x00 },
0115     { 0x00, 0xbd, 0x00, 0xc7, 0x00, 0xb7, 0x87, 0x85, 0x85, 0x84, 0x83,
0116       0x86, 0x86, 0x86, 0x88, 0x81, 0x83, 0x80, 0x83, 0x84, 0x85, 0x8a,
0117       0x85, 0x7e, 0x9c, 0x9b, 0x85, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
0118       0x00, 0x00 },
0119     { 0x00, 0xc0, 0x00, 0xca, 0x00, 0xbb, 0x87, 0x86, 0x85, 0x83, 0x83,
0120       0x85, 0x86, 0x86, 0x88, 0x81, 0x83, 0x80, 0x84, 0x85, 0x86, 0x89,
0121       0x83, 0x7d, 0x9c, 0x99, 0x87, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00,
0122       0x00, 0x00 },
0123     { 0x00, 0xc4, 0x00, 0xcd, 0x00, 0xbe, 0x87, 0x86, 0x85, 0x83, 0x83,
0124       0x86, 0x85, 0x85, 0x87, 0x81, 0x82, 0x80, 0x82, 0x82, 0x83, 0x8a,
0125       0x85, 0x7f, 0x9f, 0x9b, 0x86, 0xb4, 0xa1, 0xac, 0x00, 0x00, 0x00,
0126       0x00, 0x00 },
0127     { 0x00, 0xc7, 0x00, 0xd0, 0x00, 0xc2, 0x87, 0x85, 0x85, 0x83, 0x82,
0128       0x85, 0x85, 0x85, 0x86, 0x82, 0x83, 0x80, 0x82, 0x82, 0x84, 0x87,
0129       0x86, 0x80, 0x9e, 0x9a, 0x87, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00,
0130       0x00, 0x00 },
0131     { 0x00, 0xca, 0x00, 0xd2, 0x00, 0xc5, 0x87, 0x85, 0x84, 0x82, 0x82,
0132       0x84, 0x85, 0x85, 0x86, 0x81, 0x82, 0x7f, 0x82, 0x82, 0x84, 0x88,
0133       0x86, 0x81, 0x9d, 0x98, 0x86, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
0134       0x00, 0x00 },
0135     { 0x00, 0xce, 0x00, 0xd6, 0x00, 0xca, 0x86, 0x85, 0x84, 0x83, 0x83,
0136       0x85, 0x84, 0x84, 0x85, 0x81, 0x82, 0x80, 0x81, 0x81, 0x82, 0x89,
0137       0x86, 0x81, 0x9c, 0x97, 0x86, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00,
0138       0x00, 0x00 },
0139     { 0x00, 0xd1, 0x00, 0xd9, 0x00, 0xce, 0x86, 0x84, 0x83, 0x83, 0x82,
0140       0x85, 0x85, 0x85, 0x86, 0x81, 0x83, 0x81, 0x82, 0x82, 0x83, 0x86,
0141       0x83, 0x7f, 0x99, 0x95, 0x86, 0xbb, 0xa4, 0xb3, 0x00, 0x00, 0x00,
0142       0x00, 0x00 },
0143     { 0x00, 0xd4, 0x00, 0xdb, 0x00, 0xd1, 0x86, 0x85, 0x83, 0x83, 0x82,
0144       0x85, 0x84, 0x84, 0x85, 0x80, 0x83, 0x82, 0x80, 0x80, 0x81, 0x87,
0145       0x84, 0x81, 0x98, 0x93, 0x85, 0xae, 0x9c, 0xa8, 0x00, 0x00, 0x00,
0146       0x00, 0x00 },
0147     { 0x00, 0xd8, 0x00, 0xde, 0x00, 0xd6, 0x86, 0x84, 0x83, 0x81, 0x81,
0148       0x83, 0x85, 0x85, 0x85, 0x82, 0x83, 0x81, 0x81, 0x81, 0x83, 0x86,
0149       0x84, 0x80, 0x98, 0x91, 0x85, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00,
0150       0x00, 0x00 },
0151     { 0x00, 0xdc, 0x00, 0xe2, 0x00, 0xda, 0x85, 0x84, 0x83, 0x82, 0x82,
0152       0x84, 0x84, 0x84, 0x85, 0x81, 0x82, 0x82, 0x80, 0x80, 0x81, 0x83,
0153       0x82, 0x7f, 0x99, 0x93, 0x86, 0x94, 0x8b, 0x92, 0x00, 0x00, 0x00,
0154       0x00, 0x00 },
0155     { 0x00, 0xdf, 0x00, 0xe5, 0x00, 0xde, 0x85, 0x84, 0x82, 0x82, 0x82,
0156       0x84, 0x83, 0x83, 0x84, 0x81, 0x81, 0x80, 0x83, 0x82, 0x84, 0x82,
0157       0x81, 0x7f, 0x99, 0x92, 0x86, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00,
0158       0x00, 0x00 },
0159     { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
0160       0x82, 0x83, 0x83, 0x84, 0x80, 0x81, 0x80, 0x83, 0x83, 0x84, 0x80,
0161       0x81, 0x7c, 0x99, 0x92, 0x87, 0xa1, 0x93, 0x9d, 0x00, 0x00, 0x00,
0162       0x00, 0x00 },
0163     { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x85, 0x84, 0x83, 0x81, 0x81,
0164       0x82, 0x82, 0x82, 0x83, 0x80, 0x81, 0x80, 0x81, 0x80, 0x82, 0x83,
0165       0x82, 0x80, 0x91, 0x8d, 0x83, 0x9a, 0x90, 0x96, 0x00, 0x00, 0x00,
0166       0x00, 0x00 },
0167     { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
0168       0x82, 0x83, 0x83, 0x84, 0x80, 0x81, 0x80, 0x81, 0x80, 0x82, 0x83,
0169       0x81, 0x7f, 0x91, 0x8c, 0x82, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
0170       0x00, 0x00 },
0171     { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
0172       0x82, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x80, 0x82, 0x82,
0173       0x82, 0x7f, 0x94, 0x89, 0x84, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
0174       0x00, 0x00 },
0175     { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
0176       0x82, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x80, 0x82, 0x83,
0177       0x82, 0x7f, 0x91, 0x85, 0x81, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
0178       0x00, 0x00 },
0179     { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
0180       0x82, 0x83, 0x83, 0x83, 0x80, 0x80, 0x7f, 0x83, 0x82, 0x84, 0x83,
0181       0x82, 0x7f, 0x90, 0x84, 0x81, 0x9a, 0x90, 0x96, 0x00, 0x00, 0x00,
0182       0x00, 0x00 },
0183     { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x80, 0x80,
0184       0x82, 0x83, 0x83, 0x83, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x81, 0x81,
0185       0x82, 0x83, 0x7e, 0x80, 0x7c, 0xa4, 0x97, 0x9f, 0x00, 0x00, 0x00,
0186       0x00, 0x00 },
0187     { 0x00, 0xe9, 0x00, 0xec, 0x00, 0xe8, 0x84, 0x83, 0x82, 0x81, 0x81,
0188       0x82, 0x82, 0x82, 0x83, 0x7f, 0x7f, 0x7f, 0x81, 0x80, 0x82, 0x83,
0189       0x83, 0x84, 0x79, 0x7c, 0x79, 0xb1, 0xa0, 0xaa, 0x00, 0x00, 0x00,
0190       0x00, 0x00 },
0191     { 0x00, 0xed, 0x00, 0xf0, 0x00, 0xec, 0x83, 0x83, 0x82, 0x80, 0x80,
0192       0x81, 0x82, 0x82, 0x82, 0x7f, 0x7f, 0x7e, 0x81, 0x81, 0x82, 0x80,
0193       0x81, 0x81, 0x84, 0x84, 0x83, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
0194       0x00, 0x00 },
0195     { 0x00, 0xf1, 0x00, 0xf4, 0x00, 0xf1, 0x83, 0x82, 0x82, 0x80, 0x80,
0196       0x81, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x7d,
0197       0x7e, 0x7f, 0x84, 0x84, 0x83, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
0198       0x00, 0x00 },
0199     { 0x00, 0xf6, 0x00, 0xf7, 0x00, 0xf5, 0x82, 0x82, 0x81, 0x80, 0x80,
0200       0x80, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x82,
0201       0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
0202       0x00, 0x00 },
0203     { 0x00, 0xfa, 0x00, 0xfb, 0x00, 0xfa, 0x81, 0x81, 0x81, 0x80, 0x80,
0204       0x80, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0205       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
0206       0x00, 0x00 },
0207     { 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80,
0208       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0209       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
0210       0x00, 0x00 },
0211     { 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80,
0212       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0213       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
0214       0x00, 0x00 }
0215 };
0216 
0217 static const unsigned char vint_table[S6E3HA2_VINT_STATUS_MAX] = {
0218     0x18, 0x19, 0x1a, 0x1b, 0x1c,
0219     0x1d, 0x1e, 0x1f, 0x20, 0x21
0220 };
0221 
0222 enum s6e3ha2_type {
0223     HA2_TYPE,
0224     HF2_TYPE,
0225 };
0226 
0227 struct s6e3ha2_panel_desc {
0228     const struct drm_display_mode *mode;
0229     enum s6e3ha2_type type;
0230 };
0231 
0232 struct s6e3ha2 {
0233     struct device *dev;
0234     struct drm_panel panel;
0235     struct backlight_device *bl_dev;
0236 
0237     struct regulator_bulk_data supplies[2];
0238     struct gpio_desc *reset_gpio;
0239     struct gpio_desc *enable_gpio;
0240 
0241     const struct s6e3ha2_panel_desc *desc;
0242 };
0243 
0244 static int s6e3ha2_dcs_write(struct s6e3ha2 *ctx, const void *data, size_t len)
0245 {
0246     struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
0247 
0248     return mipi_dsi_dcs_write_buffer(dsi, data, len);
0249 }
0250 
0251 #define s6e3ha2_dcs_write_seq_static(ctx, seq...) do {  \
0252     static const u8 d[] = { seq };          \
0253     int ret;                    \
0254     ret = s6e3ha2_dcs_write(ctx, d, ARRAY_SIZE(d)); \
0255     if (ret < 0)                    \
0256         return ret;             \
0257 } while (0)
0258 
0259 #define s6e3ha2_call_write_func(ret, func) do { \
0260     ret = (func);               \
0261     if (ret < 0)                \
0262         return ret;         \
0263 } while (0)
0264 
0265 static int s6e3ha2_test_key_on_f0(struct s6e3ha2 *ctx)
0266 {
0267     s6e3ha2_dcs_write_seq_static(ctx, 0xf0, 0x5a, 0x5a);
0268     return 0;
0269 }
0270 
0271 static int s6e3ha2_test_key_off_f0(struct s6e3ha2 *ctx)
0272 {
0273     s6e3ha2_dcs_write_seq_static(ctx, 0xf0, 0xa5, 0xa5);
0274     return 0;
0275 }
0276 
0277 static int s6e3ha2_test_key_on_fc(struct s6e3ha2 *ctx)
0278 {
0279     s6e3ha2_dcs_write_seq_static(ctx, 0xfc, 0x5a, 0x5a);
0280     return 0;
0281 }
0282 
0283 static int s6e3ha2_test_key_off_fc(struct s6e3ha2 *ctx)
0284 {
0285     s6e3ha2_dcs_write_seq_static(ctx, 0xfc, 0xa5, 0xa5);
0286     return 0;
0287 }
0288 
0289 static int s6e3ha2_single_dsi_set(struct s6e3ha2 *ctx)
0290 {
0291     s6e3ha2_dcs_write_seq_static(ctx, 0xf2, 0x67);
0292     s6e3ha2_dcs_write_seq_static(ctx, 0xf9, 0x09);
0293     return 0;
0294 }
0295 
0296 static int s6e3ha2_freq_calibration(struct s6e3ha2 *ctx)
0297 {
0298     s6e3ha2_dcs_write_seq_static(ctx, 0xfd, 0x1c);
0299     if (ctx->desc->type == HF2_TYPE)
0300         s6e3ha2_dcs_write_seq_static(ctx, 0xf2, 0x67, 0x40, 0xc5);
0301     s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x20, 0x39);
0302     s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0xa0);
0303     s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x20);
0304 
0305     if (ctx->desc->type == HA2_TYPE)
0306         s6e3ha2_dcs_write_seq_static(ctx, 0xce, 0x03, 0x3b, 0x12, 0x62,
0307                           0x40, 0x80, 0xc0, 0x28, 0x28,
0308                           0x28, 0x28, 0x39, 0xc5);
0309     else
0310         s6e3ha2_dcs_write_seq_static(ctx, 0xce, 0x03, 0x3b, 0x14, 0x6d,
0311                           0x40, 0x80, 0xc0, 0x28, 0x28,
0312                           0x28, 0x28, 0x39, 0xc5);
0313 
0314     return 0;
0315 }
0316 
0317 static int s6e3ha2_aor_control(struct s6e3ha2 *ctx)
0318 {
0319     s6e3ha2_dcs_write_seq_static(ctx, 0xb2, 0x03, 0x10);
0320     return 0;
0321 }
0322 
0323 static int s6e3ha2_caps_elvss_set(struct s6e3ha2 *ctx)
0324 {
0325     s6e3ha2_dcs_write_seq_static(ctx, 0xb6, 0x9c, 0x0a);
0326     return 0;
0327 }
0328 
0329 static int s6e3ha2_acl_off(struct s6e3ha2 *ctx)
0330 {
0331     s6e3ha2_dcs_write_seq_static(ctx, 0x55, 0x00);
0332     return 0;
0333 }
0334 
0335 static int s6e3ha2_acl_off_opr(struct s6e3ha2 *ctx)
0336 {
0337     s6e3ha2_dcs_write_seq_static(ctx, 0xb5, 0x40);
0338     return 0;
0339 }
0340 
0341 static int s6e3ha2_test_global(struct s6e3ha2 *ctx)
0342 {
0343     s6e3ha2_dcs_write_seq_static(ctx, 0xb0, 0x07);
0344     return 0;
0345 }
0346 
0347 static int s6e3ha2_test(struct s6e3ha2 *ctx)
0348 {
0349     s6e3ha2_dcs_write_seq_static(ctx, 0xb8, 0x19);
0350     return 0;
0351 }
0352 
0353 static int s6e3ha2_touch_hsync_on1(struct s6e3ha2 *ctx)
0354 {
0355     s6e3ha2_dcs_write_seq_static(ctx, 0xbd, 0x33, 0x11, 0x02,
0356                     0x16, 0x02, 0x16);
0357     return 0;
0358 }
0359 
0360 static int s6e3ha2_pentile_control(struct s6e3ha2 *ctx)
0361 {
0362     s6e3ha2_dcs_write_seq_static(ctx, 0xc0, 0x00, 0x00, 0xd8, 0xd8);
0363     return 0;
0364 }
0365 
0366 static int s6e3ha2_poc_global(struct s6e3ha2 *ctx)
0367 {
0368     s6e3ha2_dcs_write_seq_static(ctx, 0xb0, 0x20);
0369     return 0;
0370 }
0371 
0372 static int s6e3ha2_poc_setting(struct s6e3ha2 *ctx)
0373 {
0374     s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x08);
0375     return 0;
0376 }
0377 
0378 static int s6e3ha2_pcd_set_off(struct s6e3ha2 *ctx)
0379 {
0380     s6e3ha2_dcs_write_seq_static(ctx, 0xcc, 0x40, 0x51);
0381     return 0;
0382 }
0383 
0384 static int s6e3ha2_err_fg_set(struct s6e3ha2 *ctx)
0385 {
0386     s6e3ha2_dcs_write_seq_static(ctx, 0xed, 0x44);
0387     return 0;
0388 }
0389 
0390 static int s6e3ha2_hbm_off(struct s6e3ha2 *ctx)
0391 {
0392     s6e3ha2_dcs_write_seq_static(ctx, 0x53, 0x00);
0393     return 0;
0394 }
0395 
0396 static int s6e3ha2_te_start_setting(struct s6e3ha2 *ctx)
0397 {
0398     s6e3ha2_dcs_write_seq_static(ctx, 0xb9, 0x10, 0x09, 0xff, 0x00, 0x09);
0399     return 0;
0400 }
0401 
0402 static int s6e3ha2_gamma_update(struct s6e3ha2 *ctx)
0403 {
0404     s6e3ha2_dcs_write_seq_static(ctx, 0xf7, 0x03);
0405     ndelay(100); /* need for 100ns delay */
0406     s6e3ha2_dcs_write_seq_static(ctx, 0xf7, 0x00);
0407     return 0;
0408 }
0409 
0410 static int s6e3ha2_get_brightness(struct backlight_device *bl_dev)
0411 {
0412     return bl_dev->props.brightness;
0413 }
0414 
0415 static int s6e3ha2_set_vint(struct s6e3ha2 *ctx)
0416 {
0417     struct backlight_device *bl_dev = ctx->bl_dev;
0418     unsigned int brightness = bl_dev->props.brightness;
0419     unsigned char data[] = { 0xf4, 0x8b,
0420             vint_table[brightness * (S6E3HA2_VINT_STATUS_MAX - 1) /
0421             S6E3HA2_MAX_BRIGHTNESS] };
0422 
0423     return s6e3ha2_dcs_write(ctx, data, ARRAY_SIZE(data));
0424 }
0425 
0426 static unsigned int s6e3ha2_get_brightness_index(unsigned int brightness)
0427 {
0428     return (brightness * (S6E3HA2_NUM_GAMMA_STEPS - 1)) /
0429         S6E3HA2_MAX_BRIGHTNESS;
0430 }
0431 
0432 static int s6e3ha2_update_gamma(struct s6e3ha2 *ctx, unsigned int brightness)
0433 {
0434     struct backlight_device *bl_dev = ctx->bl_dev;
0435     unsigned int index = s6e3ha2_get_brightness_index(brightness);
0436     u8 data[S6E3HA2_GAMMA_CMD_CNT + 1] = { 0xca, };
0437     int ret;
0438 
0439     memcpy(data + 1, gamma_tbl + index, S6E3HA2_GAMMA_CMD_CNT);
0440     s6e3ha2_call_write_func(ret,
0441                 s6e3ha2_dcs_write(ctx, data, ARRAY_SIZE(data)));
0442 
0443     s6e3ha2_call_write_func(ret, s6e3ha2_gamma_update(ctx));
0444     bl_dev->props.brightness = brightness;
0445 
0446     return 0;
0447 }
0448 
0449 static int s6e3ha2_set_brightness(struct backlight_device *bl_dev)
0450 {
0451     struct s6e3ha2 *ctx = bl_get_data(bl_dev);
0452     unsigned int brightness = bl_dev->props.brightness;
0453     int ret;
0454 
0455     if (brightness < S6E3HA2_MIN_BRIGHTNESS ||
0456         brightness > bl_dev->props.max_brightness) {
0457         dev_err(ctx->dev, "Invalid brightness: %u\n", brightness);
0458         return -EINVAL;
0459     }
0460 
0461     if (bl_dev->props.power > FB_BLANK_NORMAL)
0462         return -EPERM;
0463 
0464     s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_f0(ctx));
0465     s6e3ha2_call_write_func(ret, s6e3ha2_update_gamma(ctx, brightness));
0466     s6e3ha2_call_write_func(ret, s6e3ha2_aor_control(ctx));
0467     s6e3ha2_call_write_func(ret, s6e3ha2_set_vint(ctx));
0468     s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_f0(ctx));
0469 
0470     return 0;
0471 }
0472 
0473 static const struct backlight_ops s6e3ha2_bl_ops = {
0474     .get_brightness = s6e3ha2_get_brightness,
0475     .update_status = s6e3ha2_set_brightness,
0476 };
0477 
0478 static int s6e3ha2_panel_init(struct s6e3ha2 *ctx)
0479 {
0480     struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
0481     int ret;
0482 
0483     s6e3ha2_call_write_func(ret, mipi_dsi_dcs_exit_sleep_mode(dsi));
0484     usleep_range(5000, 6000);
0485 
0486     s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_f0(ctx));
0487     s6e3ha2_call_write_func(ret, s6e3ha2_single_dsi_set(ctx));
0488     s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_fc(ctx));
0489     s6e3ha2_call_write_func(ret, s6e3ha2_freq_calibration(ctx));
0490     s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_fc(ctx));
0491     s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_f0(ctx));
0492 
0493     return 0;
0494 }
0495 
0496 static int s6e3ha2_power_off(struct s6e3ha2 *ctx)
0497 {
0498     return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
0499 }
0500 
0501 static int s6e3ha2_disable(struct drm_panel *panel)
0502 {
0503     struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
0504     struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
0505     int ret;
0506 
0507     s6e3ha2_call_write_func(ret, mipi_dsi_dcs_enter_sleep_mode(dsi));
0508     s6e3ha2_call_write_func(ret, mipi_dsi_dcs_set_display_off(dsi));
0509 
0510     msleep(40);
0511     ctx->bl_dev->props.power = FB_BLANK_NORMAL;
0512 
0513     return 0;
0514 }
0515 
0516 static int s6e3ha2_unprepare(struct drm_panel *panel)
0517 {
0518     struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
0519 
0520     return s6e3ha2_power_off(ctx);
0521 }
0522 
0523 static int s6e3ha2_power_on(struct s6e3ha2 *ctx)
0524 {
0525     int ret;
0526 
0527     ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
0528     if (ret < 0)
0529         return ret;
0530 
0531     msleep(120);
0532 
0533     gpiod_set_value(ctx->enable_gpio, 0);
0534     usleep_range(5000, 6000);
0535     gpiod_set_value(ctx->enable_gpio, 1);
0536 
0537     gpiod_set_value(ctx->reset_gpio, 1);
0538     usleep_range(5000, 6000);
0539     gpiod_set_value(ctx->reset_gpio, 0);
0540     usleep_range(5000, 6000);
0541 
0542     return 0;
0543 }
0544 static int s6e3ha2_prepare(struct drm_panel *panel)
0545 {
0546     struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
0547     int ret;
0548 
0549     ret = s6e3ha2_power_on(ctx);
0550     if (ret < 0)
0551         return ret;
0552 
0553     ret = s6e3ha2_panel_init(ctx);
0554     if (ret < 0)
0555         goto err;
0556 
0557     ctx->bl_dev->props.power = FB_BLANK_NORMAL;
0558 
0559     return 0;
0560 
0561 err:
0562     s6e3ha2_power_off(ctx);
0563     return ret;
0564 }
0565 
0566 static int s6e3ha2_enable(struct drm_panel *panel)
0567 {
0568     struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
0569     struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
0570     int ret;
0571 
0572     /* common setting */
0573     s6e3ha2_call_write_func(ret,
0574         mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK));
0575 
0576     s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_f0(ctx));
0577     s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_fc(ctx));
0578     s6e3ha2_call_write_func(ret, s6e3ha2_touch_hsync_on1(ctx));
0579     s6e3ha2_call_write_func(ret, s6e3ha2_pentile_control(ctx));
0580     s6e3ha2_call_write_func(ret, s6e3ha2_poc_global(ctx));
0581     s6e3ha2_call_write_func(ret, s6e3ha2_poc_setting(ctx));
0582     s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_fc(ctx));
0583 
0584     /* pcd setting off for TB */
0585     s6e3ha2_call_write_func(ret, s6e3ha2_pcd_set_off(ctx));
0586     s6e3ha2_call_write_func(ret, s6e3ha2_err_fg_set(ctx));
0587     s6e3ha2_call_write_func(ret, s6e3ha2_te_start_setting(ctx));
0588 
0589     /* brightness setting */
0590     s6e3ha2_call_write_func(ret, s6e3ha2_set_brightness(ctx->bl_dev));
0591     s6e3ha2_call_write_func(ret, s6e3ha2_aor_control(ctx));
0592     s6e3ha2_call_write_func(ret, s6e3ha2_caps_elvss_set(ctx));
0593     s6e3ha2_call_write_func(ret, s6e3ha2_gamma_update(ctx));
0594     s6e3ha2_call_write_func(ret, s6e3ha2_acl_off(ctx));
0595     s6e3ha2_call_write_func(ret, s6e3ha2_acl_off_opr(ctx));
0596     s6e3ha2_call_write_func(ret, s6e3ha2_hbm_off(ctx));
0597 
0598     /* elvss temp compensation */
0599     s6e3ha2_call_write_func(ret, s6e3ha2_test_global(ctx));
0600     s6e3ha2_call_write_func(ret, s6e3ha2_test(ctx));
0601     s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_f0(ctx));
0602 
0603     s6e3ha2_call_write_func(ret, mipi_dsi_dcs_set_display_on(dsi));
0604     ctx->bl_dev->props.power = FB_BLANK_UNBLANK;
0605 
0606     return 0;
0607 }
0608 
0609 static const struct drm_display_mode s6e3ha2_mode = {
0610     .clock = 222372,
0611     .hdisplay = 1440,
0612     .hsync_start = 1440 + 1,
0613     .hsync_end = 1440 + 1 + 1,
0614     .htotal = 1440 + 1 + 1 + 1,
0615     .vdisplay = 2560,
0616     .vsync_start = 2560 + 1,
0617     .vsync_end = 2560 + 1 + 1,
0618     .vtotal = 2560 + 1 + 1 + 15,
0619     .flags = 0,
0620 };
0621 
0622 static const struct s6e3ha2_panel_desc samsung_s6e3ha2 = {
0623     .mode = &s6e3ha2_mode,
0624     .type = HA2_TYPE,
0625 };
0626 
0627 static const struct drm_display_mode s6e3hf2_mode = {
0628     .clock = 247856,
0629     .hdisplay = 1600,
0630     .hsync_start = 1600 + 1,
0631     .hsync_end = 1600 + 1 + 1,
0632     .htotal = 1600 + 1 + 1 + 1,
0633     .vdisplay = 2560,
0634     .vsync_start = 2560 + 1,
0635     .vsync_end = 2560 + 1 + 1,
0636     .vtotal = 2560 + 1 + 1 + 15,
0637     .flags = 0,
0638 };
0639 
0640 static const struct s6e3ha2_panel_desc samsung_s6e3hf2 = {
0641     .mode = &s6e3hf2_mode,
0642     .type = HF2_TYPE,
0643 };
0644 
0645 static int s6e3ha2_get_modes(struct drm_panel *panel,
0646                  struct drm_connector *connector)
0647 {
0648     struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
0649     struct drm_display_mode *mode;
0650 
0651     mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
0652     if (!mode) {
0653         dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
0654             ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
0655             drm_mode_vrefresh(ctx->desc->mode));
0656         return -ENOMEM;
0657     }
0658 
0659     drm_mode_set_name(mode);
0660 
0661     mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
0662     drm_mode_probed_add(connector, mode);
0663 
0664     connector->display_info.width_mm = 71;
0665     connector->display_info.height_mm = 125;
0666 
0667     return 1;
0668 }
0669 
0670 static const struct drm_panel_funcs s6e3ha2_drm_funcs = {
0671     .disable = s6e3ha2_disable,
0672     .unprepare = s6e3ha2_unprepare,
0673     .prepare = s6e3ha2_prepare,
0674     .enable = s6e3ha2_enable,
0675     .get_modes = s6e3ha2_get_modes,
0676 };
0677 
0678 static int s6e3ha2_probe(struct mipi_dsi_device *dsi)
0679 {
0680     struct device *dev = &dsi->dev;
0681     struct s6e3ha2 *ctx;
0682     int ret;
0683 
0684     ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
0685     if (!ctx)
0686         return -ENOMEM;
0687 
0688     mipi_dsi_set_drvdata(dsi, ctx);
0689 
0690     ctx->dev = dev;
0691     ctx->desc = of_device_get_match_data(dev);
0692 
0693     dsi->lanes = 4;
0694     dsi->format = MIPI_DSI_FMT_RGB888;
0695     dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS;
0696 
0697     ctx->supplies[0].supply = "vdd3";
0698     ctx->supplies[1].supply = "vci";
0699 
0700     ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
0701                       ctx->supplies);
0702     if (ret < 0) {
0703         dev_err(dev, "failed to get regulators: %d\n", ret);
0704         return ret;
0705     }
0706 
0707     ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
0708     if (IS_ERR(ctx->reset_gpio)) {
0709         dev_err(dev, "cannot get reset-gpios %ld\n",
0710             PTR_ERR(ctx->reset_gpio));
0711         return PTR_ERR(ctx->reset_gpio);
0712     }
0713 
0714     ctx->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
0715     if (IS_ERR(ctx->enable_gpio)) {
0716         dev_err(dev, "cannot get enable-gpios %ld\n",
0717             PTR_ERR(ctx->enable_gpio));
0718         return PTR_ERR(ctx->enable_gpio);
0719     }
0720 
0721     ctx->bl_dev = backlight_device_register("s6e3ha2", dev, ctx,
0722                         &s6e3ha2_bl_ops, NULL);
0723     if (IS_ERR(ctx->bl_dev)) {
0724         dev_err(dev, "failed to register backlight device\n");
0725         return PTR_ERR(ctx->bl_dev);
0726     }
0727 
0728     ctx->bl_dev->props.max_brightness = S6E3HA2_MAX_BRIGHTNESS;
0729     ctx->bl_dev->props.brightness = S6E3HA2_DEFAULT_BRIGHTNESS;
0730     ctx->bl_dev->props.power = FB_BLANK_POWERDOWN;
0731 
0732     drm_panel_init(&ctx->panel, dev, &s6e3ha2_drm_funcs,
0733                DRM_MODE_CONNECTOR_DSI);
0734 
0735     drm_panel_add(&ctx->panel);
0736 
0737     ret = mipi_dsi_attach(dsi);
0738     if (ret < 0)
0739         goto remove_panel;
0740 
0741     return ret;
0742 
0743 remove_panel:
0744     drm_panel_remove(&ctx->panel);
0745     backlight_device_unregister(ctx->bl_dev);
0746 
0747     return ret;
0748 }
0749 
0750 static int s6e3ha2_remove(struct mipi_dsi_device *dsi)
0751 {
0752     struct s6e3ha2 *ctx = mipi_dsi_get_drvdata(dsi);
0753 
0754     mipi_dsi_detach(dsi);
0755     drm_panel_remove(&ctx->panel);
0756     backlight_device_unregister(ctx->bl_dev);
0757 
0758     return 0;
0759 }
0760 
0761 static const struct of_device_id s6e3ha2_of_match[] = {
0762     { .compatible = "samsung,s6e3ha2", .data = &samsung_s6e3ha2 },
0763     { .compatible = "samsung,s6e3hf2", .data = &samsung_s6e3hf2 },
0764     { }
0765 };
0766 MODULE_DEVICE_TABLE(of, s6e3ha2_of_match);
0767 
0768 static struct mipi_dsi_driver s6e3ha2_driver = {
0769     .probe = s6e3ha2_probe,
0770     .remove = s6e3ha2_remove,
0771     .driver = {
0772         .name = "panel-samsung-s6e3ha2",
0773         .of_match_table = s6e3ha2_of_match,
0774     },
0775 };
0776 module_mipi_dsi_driver(s6e3ha2_driver);
0777 
0778 MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
0779 MODULE_AUTHOR("Hyungwon Hwang <human.hwang@samsung.com>");
0780 MODULE_AUTHOR("Hoegeun Kwon <hoegeun.kwon@samsung.com>");
0781 MODULE_DESCRIPTION("MIPI-DSI based s6e3ha2 AMOLED Panel Driver");
0782 MODULE_LICENSE("GPL v2");