0001
0002
0003
0004
0005
0006
0007
0008
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);
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
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
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
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
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");