brintos

brintos / linux-shallow public Read only

0
0
Text · 24.8 KiB · d3baccf Raw
949 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * NewVision NV3052C IPS LCD panel driver4 *5 * Copyright (C) 2020, Paul Cercueil <paul@crapouillou.net>6 * Copyright (C) 2022, Christophe Branchereau <cbranchereau@gmail.com>7 */8 9#include <linux/delay.h>10#include <linux/device.h>11#include <linux/gpio/consumer.h>12#include <linux/media-bus-format.h>13#include <linux/module.h>14#include <linux/of.h>15#include <linux/platform_device.h>16#include <linux/regulator/consumer.h>17#include <linux/spi/spi.h>18#include <video/mipi_display.h>19#include <drm/drm_mipi_dbi.h>20#include <drm/drm_modes.h>21#include <drm/drm_panel.h>22 23struct nv3052c_reg {24	u8 cmd;25	u8 val;26};27 28struct nv3052c_panel_info {29	const struct drm_display_mode *display_modes;30	unsigned int num_modes;31	u16 width_mm, height_mm;32	u32 bus_format, bus_flags;33	const struct nv3052c_reg *panel_regs;34	unsigned int panel_regs_len;35};36 37struct nv3052c {38	struct device *dev;39	struct drm_panel panel;40	struct mipi_dbi dbi;41	const struct nv3052c_panel_info *panel_info;42	struct regulator *supply;43	struct gpio_desc *reset_gpio;44};45 46static const struct nv3052c_reg ltk035c5444t_panel_regs[] = {47	// EXTC Command set enable, select page 148	{ 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x01 },49	// Mostly unknown registers50	{ 0xe3, 0x00 },51	{ 0x40, 0x00 },52	{ 0x03, 0x40 },53	{ 0x04, 0x00 },54	{ 0x05, 0x03 },55	{ 0x08, 0x00 },56	{ 0x09, 0x07 },57	{ 0x0a, 0x01 },58	{ 0x0b, 0x32 },59	{ 0x0c, 0x32 },60	{ 0x0d, 0x0b },61	{ 0x0e, 0x00 },62	{ 0x23, 0xa0 },63	{ 0x24, 0x0c },64	{ 0x25, 0x06 },65	{ 0x26, 0x14 },66	{ 0x27, 0x14 },67	{ 0x38, 0xcc }, // VCOM_ADJ168	{ 0x39, 0xd7 }, // VCOM_ADJ269	{ 0x3a, 0x4a }, // VCOM_ADJ370	{ 0x28, 0x40 },71	{ 0x29, 0x01 },72	{ 0x2a, 0xdf },73	{ 0x49, 0x3c },74	{ 0x91, 0x77 }, // EXTPW_CTRL275	{ 0x92, 0x77 }, // EXTPW_CTRL376	{ 0xa0, 0x55 },77	{ 0xa1, 0x50 },78	{ 0xa4, 0x9c },79	{ 0xa7, 0x02 },80	{ 0xa8, 0x01 },81	{ 0xa9, 0x01 },82	{ 0xaa, 0xfc },83	{ 0xab, 0x28 },84	{ 0xac, 0x06 },85	{ 0xad, 0x06 },86	{ 0xae, 0x06 },87	{ 0xaf, 0x03 },88	{ 0xb0, 0x08 },89	{ 0xb1, 0x26 },90	{ 0xb2, 0x28 },91	{ 0xb3, 0x28 },92	{ 0xb4, 0x33 },93	{ 0xb5, 0x08 },94	{ 0xb6, 0x26 },95	{ 0xb7, 0x08 },96	{ 0xb8, 0x26 },97	{ 0xf0, 0x00 },98	{ 0xf6, 0xc0 },99	// EXTC Command set enable, select page 2100	{ 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x02 },101	// Set gray scale voltage to adjust gamma102	{ 0xb0, 0x0b }, // PGAMVR0103	{ 0xb1, 0x16 }, // PGAMVR1104	{ 0xb2, 0x17 }, // PGAMVR2105	{ 0xb3, 0x2c }, // PGAMVR3106	{ 0xb4, 0x32 }, // PGAMVR4107	{ 0xb5, 0x3b }, // PGAMVR5108	{ 0xb6, 0x29 }, // PGAMPR0109	{ 0xb7, 0x40 }, // PGAMPR1110	{ 0xb8, 0x0d }, // PGAMPK0111	{ 0xb9, 0x05 }, // PGAMPK1112	{ 0xba, 0x12 }, // PGAMPK2113	{ 0xbb, 0x10 }, // PGAMPK3114	{ 0xbc, 0x12 }, // PGAMPK4115	{ 0xbd, 0x15 }, // PGAMPK5116	{ 0xbe, 0x19 }, // PGAMPK6117	{ 0xbf, 0x0e }, // PGAMPK7118	{ 0xc0, 0x16 }, // PGAMPK8119	{ 0xc1, 0x0a }, // PGAMPK9120	// Set gray scale voltage to adjust gamma121	{ 0xd0, 0x0c }, // NGAMVR0122	{ 0xd1, 0x17 }, // NGAMVR0123	{ 0xd2, 0x14 }, // NGAMVR1124	{ 0xd3, 0x2e }, // NGAMVR2125	{ 0xd4, 0x32 }, // NGAMVR3126	{ 0xd5, 0x3c }, // NGAMVR4127	{ 0xd6, 0x22 }, // NGAMPR0128	{ 0xd7, 0x3d }, // NGAMPR1129	{ 0xd8, 0x0d }, // NGAMPK0130	{ 0xd9, 0x07 }, // NGAMPK1131	{ 0xda, 0x13 }, // NGAMPK2132	{ 0xdb, 0x13 }, // NGAMPK3133	{ 0xdc, 0x11 }, // NGAMPK4134	{ 0xdd, 0x15 }, // NGAMPK5135	{ 0xde, 0x19 }, // NGAMPK6136	{ 0xdf, 0x10 }, // NGAMPK7137	{ 0xe0, 0x17 }, // NGAMPK8138	{ 0xe1, 0x0a }, // NGAMPK9139	// EXTC Command set enable, select page 3140	{ 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x03 },141	// Set various timing settings142	{ 0x00, 0x2a }, // GIP_VST_1143	{ 0x01, 0x2a }, // GIP_VST_2144	{ 0x02, 0x2a }, // GIP_VST_3145	{ 0x03, 0x2a }, // GIP_VST_4146	{ 0x04, 0x61 }, // GIP_VST_5147	{ 0x05, 0x80 }, // GIP_VST_6148	{ 0x06, 0xc7 }, // GIP_VST_7149	{ 0x07, 0x01 }, // GIP_VST_8150	{ 0x08, 0x03 }, // GIP_VST_9151	{ 0x09, 0x04 }, // GIP_VST_10152	{ 0x70, 0x22 }, // GIP_ECLK1153	{ 0x71, 0x80 }, // GIP_ECLK2154	{ 0x30, 0x2a }, // GIP_CLK_1155	{ 0x31, 0x2a }, // GIP_CLK_2156	{ 0x32, 0x2a }, // GIP_CLK_3157	{ 0x33, 0x2a }, // GIP_CLK_4158	{ 0x34, 0x61 }, // GIP_CLK_5159	{ 0x35, 0xc5 }, // GIP_CLK_6160	{ 0x36, 0x80 }, // GIP_CLK_7161	{ 0x37, 0x23 }, // GIP_CLK_8162	{ 0x40, 0x03 }, // GIP_CLKA_1163	{ 0x41, 0x04 }, // GIP_CLKA_2164	{ 0x42, 0x05 }, // GIP_CLKA_3165	{ 0x43, 0x06 }, // GIP_CLKA_4166	{ 0x44, 0x11 }, // GIP_CLKA_5167	{ 0x45, 0xe8 }, // GIP_CLKA_6168	{ 0x46, 0xe9 }, // GIP_CLKA_7169	{ 0x47, 0x11 }, // GIP_CLKA_8170	{ 0x48, 0xea }, // GIP_CLKA_9171	{ 0x49, 0xeb }, // GIP_CLKA_10172	{ 0x50, 0x07 }, // GIP_CLKB_1173	{ 0x51, 0x08 }, // GIP_CLKB_2174	{ 0x52, 0x09 }, // GIP_CLKB_3175	{ 0x53, 0x0a }, // GIP_CLKB_4176	{ 0x54, 0x11 }, // GIP_CLKB_5177	{ 0x55, 0xec }, // GIP_CLKB_6178	{ 0x56, 0xed }, // GIP_CLKB_7179	{ 0x57, 0x11 }, // GIP_CLKB_8180	{ 0x58, 0xef }, // GIP_CLKB_9181	{ 0x59, 0xf0 }, // GIP_CLKB_10182	// Map internal GOA signals to GOA output pad183	{ 0xb1, 0x01 }, // PANELD2U2184	{ 0xb4, 0x15 }, // PANELD2U5185	{ 0xb5, 0x16 }, // PANELD2U6186	{ 0xb6, 0x09 }, // PANELD2U7187	{ 0xb7, 0x0f }, // PANELD2U8188	{ 0xb8, 0x0d }, // PANELD2U9189	{ 0xb9, 0x0b }, // PANELD2U10190	{ 0xba, 0x00 }, // PANELD2U11191	{ 0xc7, 0x02 }, // PANELD2U24192	{ 0xca, 0x17 }, // PANELD2U27193	{ 0xcb, 0x18 }, // PANELD2U28194	{ 0xcc, 0x0a }, // PANELD2U29195	{ 0xcd, 0x10 }, // PANELD2U30196	{ 0xce, 0x0e }, // PANELD2U31197	{ 0xcf, 0x0c }, // PANELD2U32198	{ 0xd0, 0x00 }, // PANELD2U33199	// Map internal GOA signals to GOA output pad200	{ 0x81, 0x00 }, // PANELU2D2201	{ 0x84, 0x15 }, // PANELU2D5202	{ 0x85, 0x16 }, // PANELU2D6203	{ 0x86, 0x10 }, // PANELU2D7204	{ 0x87, 0x0a }, // PANELU2D8205	{ 0x88, 0x0c }, // PANELU2D9206	{ 0x89, 0x0e }, // PANELU2D10207	{ 0x8a, 0x02 }, // PANELU2D11208	{ 0x97, 0x00 }, // PANELU2D24209	{ 0x9a, 0x17 }, // PANELU2D27210	{ 0x9b, 0x18 }, // PANELU2D28211	{ 0x9c, 0x0f }, // PANELU2D29212	{ 0x9d, 0x09 }, // PANELU2D30213	{ 0x9e, 0x0b }, // PANELU2D31214	{ 0x9f, 0x0d }, // PANELU2D32215	{ 0xa0, 0x01 }, // PANELU2D33216	// EXTC Command set enable, select page 2217	{ 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x02 },218	// Unknown registers219	{ 0x01, 0x01 },220	{ 0x02, 0xda },221	{ 0x03, 0xba },222	{ 0x04, 0xa8 },223	{ 0x05, 0x9a },224	{ 0x06, 0x70 },225	{ 0x07, 0xff },226	{ 0x08, 0x91 },227	{ 0x09, 0x90 },228	{ 0x0a, 0xff },229	{ 0x0b, 0x8f },230	{ 0x0c, 0x60 },231	{ 0x0d, 0x58 },232	{ 0x0e, 0x48 },233	{ 0x0f, 0x38 },234	{ 0x10, 0x2b },235	// EXTC Command set enable, select page 0236	{ 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x00 },237	// Display Access Control238	{ 0x36, 0x0a }, // bgr = 1, ss = 1, gs = 0239};240 241static const struct nv3052c_reg fs035vg158_panel_regs[] = {242	// EXTC Command set enable, select page 1243	{ 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x01 },244	// Mostly unknown registers245	{ 0xe3, 0x00 },246	{ 0x40, 0x00 },247	{ 0x03, 0x40 },248	{ 0x04, 0x00 },249	{ 0x05, 0x03 },250	{ 0x08, 0x00 },251	{ 0x09, 0x07 },252	{ 0x0a, 0x01 },253	{ 0x0b, 0x32 },254	{ 0x0c, 0x32 },255	{ 0x0d, 0x0b },256	{ 0x0e, 0x00 },257	{ 0x23, 0x20 }, // RGB interface control: DE MODE PCLK-N258	{ 0x24, 0x0c },259	{ 0x25, 0x06 },260	{ 0x26, 0x14 },261	{ 0x27, 0x14 },262	{ 0x38, 0x9c }, //VCOM_ADJ1, different to ltk035c5444t263	{ 0x39, 0xa7 }, //VCOM_ADJ2, different to ltk035c5444t264	{ 0x3a, 0x50 }, //VCOM_ADJ3, different to ltk035c5444t265	{ 0x28, 0x40 },266	{ 0x29, 0x01 },267	{ 0x2a, 0xdf },268	{ 0x49, 0x3c },269	{ 0x91, 0x57 }, //EXTPW_CTRL2, different to ltk035c5444t270	{ 0x92, 0x57 }, //EXTPW_CTRL3, different to ltk035c5444t271	{ 0xa0, 0x55 },272	{ 0xa1, 0x50 },273	{ 0xa4, 0x9c },274	{ 0xa7, 0x02 },275	{ 0xa8, 0x01 },276	{ 0xa9, 0x01 },277	{ 0xaa, 0xfc },278	{ 0xab, 0x28 },279	{ 0xac, 0x06 },280	{ 0xad, 0x06 },281	{ 0xae, 0x06 },282	{ 0xaf, 0x03 },283	{ 0xb0, 0x08 },284	{ 0xb1, 0x26 },285	{ 0xb2, 0x28 },286	{ 0xb3, 0x28 },287	{ 0xb4, 0x03 }, // Unknown, different to ltk035c5444288	{ 0xb5, 0x08 },289	{ 0xb6, 0x26 },290	{ 0xb7, 0x08 },291	{ 0xb8, 0x26 },292	{ 0xf0, 0x00 },293	{ 0xf6, 0xc0 },294	// EXTC Command set enable, select page 0295	{ 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x02 },296	// Set gray scale voltage to adjust gamma297	{ 0xb0, 0x0b }, // PGAMVR0298	{ 0xb1, 0x16 }, // PGAMVR1299	{ 0xb2, 0x17 }, // PGAMVR2300	{ 0xb3, 0x2c }, // PGAMVR3301	{ 0xb4, 0x32 }, // PGAMVR4302	{ 0xb5, 0x3b }, // PGAMVR5303	{ 0xb6, 0x29 }, // PGAMPR0304	{ 0xb7, 0x40 }, // PGAMPR1305	{ 0xb8, 0x0d }, // PGAMPK0306	{ 0xb9, 0x05 }, // PGAMPK1307	{ 0xba, 0x12 }, // PGAMPK2308	{ 0xbb, 0x10 }, // PGAMPK3309	{ 0xbc, 0x12 }, // PGAMPK4310	{ 0xbd, 0x15 }, // PGAMPK5311	{ 0xbe, 0x19 }, // PGAMPK6312	{ 0xbf, 0x0e }, // PGAMPK7313	{ 0xc0, 0x16 }, // PGAMPK8314	{ 0xc1, 0x0a }, // PGAMPK9315	// Set gray scale voltage to adjust gamma316	{ 0xd0, 0x0c }, // NGAMVR0317	{ 0xd1, 0x17 }, // NGAMVR0318	{ 0xd2, 0x14 }, // NGAMVR1319	{ 0xd3, 0x2e }, // NGAMVR2320	{ 0xd4, 0x32 }, // NGAMVR3321	{ 0xd5, 0x3c }, // NGAMVR4322	{ 0xd6, 0x22 }, // NGAMPR0323	{ 0xd7, 0x3d }, // NGAMPR1324	{ 0xd8, 0x0d }, // NGAMPK0325	{ 0xd9, 0x07 }, // NGAMPK1326	{ 0xda, 0x13 }, // NGAMPK2327	{ 0xdb, 0x13 }, // NGAMPK3328	{ 0xdc, 0x11 }, // NGAMPK4329	{ 0xdd, 0x15 }, // NGAMPK5330	{ 0xde, 0x19 }, // NGAMPK6331	{ 0xdf, 0x10 }, // NGAMPK7332	{ 0xe0, 0x17 }, // NGAMPK8333	{ 0xe1, 0x0a }, // NGAMPK9334	// EXTC Command set enable, select page 3335	{ 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x03 },336	// Set various timing settings337	{ 0x00, 0x2a }, // GIP_VST_1338	{ 0x01, 0x2a }, // GIP_VST_2339	{ 0x02, 0x2a }, // GIP_VST_3340	{ 0x03, 0x2a }, // GIP_VST_4341	{ 0x04, 0x61 }, // GIP_VST_5342	{ 0x05, 0x80 }, // GIP_VST_6343	{ 0x06, 0xc7 }, // GIP_VST_7344	{ 0x07, 0x01 }, // GIP_VST_8345	{ 0x08, 0x03 }, // GIP_VST_9346	{ 0x09, 0x04 }, // GIP_VST_10347	{ 0x70, 0x22 }, // GIP_ECLK1348	{ 0x71, 0x80 }, // GIP_ECLK2349	{ 0x30, 0x2a }, // GIP_CLK_1350	{ 0x31, 0x2a }, // GIP_CLK_2351	{ 0x32, 0x2a }, // GIP_CLK_3352	{ 0x33, 0x2a }, // GIP_CLK_4353	{ 0x34, 0x61 }, // GIP_CLK_5354	{ 0x35, 0xc5 }, // GIP_CLK_6355	{ 0x36, 0x80 }, // GIP_CLK_7356	{ 0x37, 0x23 }, // GIP_CLK_8357	{ 0x40, 0x03 }, // GIP_CLKA_1358	{ 0x41, 0x04 }, // GIP_CLKA_2359	{ 0x42, 0x05 }, // GIP_CLKA_3360	{ 0x43, 0x06 }, // GIP_CLKA_4361	{ 0x44, 0x11 }, // GIP_CLKA_5362	{ 0x45, 0xe8 }, // GIP_CLKA_6363	{ 0x46, 0xe9 }, // GIP_CLKA_7364	{ 0x47, 0x11 }, // GIP_CLKA_8365	{ 0x48, 0xea }, // GIP_CLKA_9366	{ 0x49, 0xeb }, // GIP_CLKA_10367	{ 0x50, 0x07 }, // GIP_CLKB_1368	{ 0x51, 0x08 }, // GIP_CLKB_2369	{ 0x52, 0x09 }, // GIP_CLKB_3370	{ 0x53, 0x0a }, // GIP_CLKB_4371	{ 0x54, 0x11 }, // GIP_CLKB_5372	{ 0x55, 0xec }, // GIP_CLKB_6373	{ 0x56, 0xed }, // GIP_CLKB_7374	{ 0x57, 0x11 }, // GIP_CLKB_8375	{ 0x58, 0xef }, // GIP_CLKB_9376	{ 0x59, 0xf0 }, // GIP_CLKB_10377	// Map internal GOA signals to GOA output pad378	{ 0xb1, 0x01 }, // PANELD2U2379	{ 0xb4, 0x15 }, // PANELD2U5380	{ 0xb5, 0x16 }, // PANELD2U6381	{ 0xb6, 0x09 }, // PANELD2U7382	{ 0xb7, 0x0f }, // PANELD2U8383	{ 0xb8, 0x0d }, // PANELD2U9384	{ 0xb9, 0x0b }, // PANELD2U10385	{ 0xba, 0x00 }, // PANELD2U11386	{ 0xc7, 0x02 }, // PANELD2U24387	{ 0xca, 0x17 }, // PANELD2U27388	{ 0xcb, 0x18 }, // PANELD2U28389	{ 0xcc, 0x0a }, // PANELD2U29390	{ 0xcd, 0x10 }, // PANELD2U30391	{ 0xce, 0x0e }, // PANELD2U31392	{ 0xcf, 0x0c }, // PANELD2U32393	{ 0xd0, 0x00 }, // PANELD2U33394	// Map internal GOA signals to GOA output pad395	{ 0x81, 0x00 }, // PANELU2D2396	{ 0x84, 0x15 }, // PANELU2D5397	{ 0x85, 0x16 }, // PANELU2D6398	{ 0x86, 0x10 }, // PANELU2D7399	{ 0x87, 0x0a }, // PANELU2D8400	{ 0x88, 0x0c }, // PANELU2D9401	{ 0x89, 0x0e }, // PANELU2D10402	{ 0x8a, 0x02 }, // PANELU2D11403	{ 0x97, 0x00 }, // PANELU2D24404	{ 0x9a, 0x17 }, // PANELU2D27405	{ 0x9b, 0x18 }, // PANELU2D28406	{ 0x9c, 0x0f }, // PANELU2D29407	{ 0x9d, 0x09 }, // PANELU2D30408	{ 0x9e, 0x0b }, // PANELU2D31409	{ 0x9f, 0x0d }, // PANELU2D32410	{ 0xa0, 0x01 }, // PANELU2D33411	// EXTC Command set enable, select page 2412	{ 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x02 },413	// Unknown registers414	{ 0x01, 0x01 },415	{ 0x02, 0xda },416	{ 0x03, 0xba },417	{ 0x04, 0xa8 },418	{ 0x05, 0x9a },419	{ 0x06, 0x70 },420	{ 0x07, 0xff },421	{ 0x08, 0x91 },422	{ 0x09, 0x90 },423	{ 0x0a, 0xff },424	{ 0x0b, 0x8f },425	{ 0x0c, 0x60 },426	{ 0x0d, 0x58 },427	{ 0x0e, 0x48 },428	{ 0x0f, 0x38 },429	{ 0x10, 0x2b },430	// EXTC Command set enable, select page 0431	{ 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x00 },432	// Display Access Control433	{ 0x36, 0x0a }, // bgr = 1, ss = 1, gs = 0434};435 436 437static const struct nv3052c_reg wl_355608_a8_panel_regs[] = {438	// EXTC Command set enable, select page 1439	{ 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x01 },440	// Mostly unknown registers441	{ 0xe3, 0x00 },442	{ 0x40, 0x00 },443	{ 0x03, 0x40 },444	{ 0x04, 0x00 },445	{ 0x05, 0x03 },446	{ 0x08, 0x00 },447	{ 0x09, 0x07 },448	{ 0x0a, 0x01 },449	{ 0x0b, 0x32 },450	{ 0x0c, 0x32 },451	{ 0x0d, 0x0b },452	{ 0x0e, 0x00 },453	{ 0x23, 0xa0 },454	{ 0x24, 0x0c },455	{ 0x25, 0x06 },456	{ 0x26, 0x14 },457	{ 0x27, 0x14 },458	{ 0x38, 0xcc }, // VCOM_ADJ1459	{ 0x39, 0xd7 }, // VCOM_ADJ2460	{ 0x3a, 0x44 }, // VCOM_ADJ3461	{ 0x28, 0x40 },462	{ 0x29, 0x01 },463	{ 0x2a, 0xdf },464	{ 0x49, 0x3c },465	{ 0x91, 0x77 }, // EXTPW_CTRL2466	{ 0x92, 0x77 }, // EXTPW_CTRL3467	{ 0xa0, 0x55 },468	{ 0xa1, 0x50 },469	{ 0xa4, 0x9c },470	{ 0xa7, 0x02 },471	{ 0xa8, 0x01 },472	{ 0xa9, 0x01 },473	{ 0xaa, 0xfc },474	{ 0xab, 0x28 },475	{ 0xac, 0x06 },476	{ 0xad, 0x06 },477	{ 0xae, 0x06 },478	{ 0xaf, 0x03 },479	{ 0xb0, 0x08 },480	{ 0xb1, 0x26 },481	{ 0xb2, 0x28 },482	{ 0xb3, 0x28 },483	{ 0xb4, 0x33 },484	{ 0xb5, 0x08 },485	{ 0xb6, 0x26 },486	{ 0xb7, 0x08 },487	{ 0xb8, 0x26 },488	{ 0xf0, 0x00 },489	{ 0xf6, 0xc0 },490	// EXTC Command set enable, select page 2491	{ 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x02 },492	// Set gray scale voltage to adjust gamma493	{ 0xb0, 0x0b }, // PGAMVR0494	{ 0xb1, 0x16 }, // PGAMVR1495	{ 0xb2, 0x17 }, // PGAMVR2496	{ 0xb3, 0x2c }, // PGAMVR3497	{ 0xb4, 0x32 }, // PGAMVR4498	{ 0xb5, 0x3b }, // PGAMVR5499	{ 0xb6, 0x29 }, // PGAMPR0500	{ 0xb7, 0x40 }, // PGAMPR1501	{ 0xb8, 0x0d }, // PGAMPK0502	{ 0xb9, 0x05 }, // PGAMPK1503	{ 0xba, 0x12 }, // PGAMPK2504	{ 0xbb, 0x10 }, // PGAMPK3505	{ 0xbc, 0x12 }, // PGAMPK4506	{ 0xbd, 0x15 }, // PGAMPK5507	{ 0xbe, 0x19 }, // PGAMPK6508	{ 0xbf, 0x0e }, // PGAMPK7509	{ 0xc0, 0x16 }, // PGAMPK8510	{ 0xc1, 0x0a }, // PGAMPK9511	// Set gray scale voltage to adjust gamma512	{ 0xd0, 0x0c }, // NGAMVR0513	{ 0xd1, 0x17 }, // NGAMVR0514	{ 0xd2, 0x14 }, // NGAMVR1515	{ 0xd3, 0x2e }, // NGAMVR2516	{ 0xd4, 0x32 }, // NGAMVR3517	{ 0xd5, 0x3c }, // NGAMVR4518	{ 0xd6, 0x22 }, // NGAMPR0519	{ 0xd7, 0x3d }, // NGAMPR1520	{ 0xd8, 0x0d }, // NGAMPK0521	{ 0xd9, 0x07 }, // NGAMPK1522	{ 0xda, 0x13 }, // NGAMPK2523	{ 0xdb, 0x13 }, // NGAMPK3524	{ 0xdc, 0x11 }, // NGAMPK4525	{ 0xdd, 0x15 }, // NGAMPK5526	{ 0xde, 0x19 }, // NGAMPK6527	{ 0xdf, 0x10 }, // NGAMPK7528	{ 0xe0, 0x17 }, // NGAMPK8529	{ 0xe1, 0x0a }, // NGAMPK9530	// EXTC Command set enable, select page 3531	{ 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x03 },532	// Set various timing settings533	{ 0x00, 0x2a }, // GIP_VST_1534	{ 0x01, 0x2a }, // GIP_VST_2535	{ 0x02, 0x2a }, // GIP_VST_3536	{ 0x03, 0x2a }, // GIP_VST_4537	{ 0x04, 0x61 }, // GIP_VST_5538	{ 0x05, 0x80 }, // GIP_VST_6539	{ 0x06, 0xc7 }, // GIP_VST_7540	{ 0x07, 0x01 }, // GIP_VST_8541	{ 0x08, 0x03 }, // GIP_VST_9542	{ 0x09, 0x04 }, // GIP_VST_10543	{ 0x70, 0x22 }, // GIP_ECLK1544	{ 0x71, 0x80 }, // GIP_ECLK2545	{ 0x30, 0x2a }, // GIP_CLK_1546	{ 0x31, 0x2a }, // GIP_CLK_2547	{ 0x32, 0x2a }, // GIP_CLK_3548	{ 0x33, 0x2a }, // GIP_CLK_4549	{ 0x34, 0x61 }, // GIP_CLK_5550	{ 0x35, 0xc5 }, // GIP_CLK_6551	{ 0x36, 0x80 }, // GIP_CLK_7552	{ 0x37, 0x23 }, // GIP_CLK_8553	{ 0x40, 0x03 }, // GIP_CLKA_1554	{ 0x41, 0x04 }, // GIP_CLKA_2555	{ 0x42, 0x05 }, // GIP_CLKA_3556	{ 0x43, 0x06 }, // GIP_CLKA_4557	{ 0x44, 0x11 }, // GIP_CLKA_5558	{ 0x45, 0xe8 }, // GIP_CLKA_6559	{ 0x46, 0xe9 }, // GIP_CLKA_7560	{ 0x47, 0x11 }, // GIP_CLKA_8561	{ 0x48, 0xea }, // GIP_CLKA_9562	{ 0x49, 0xeb }, // GIP_CLKA_10563	{ 0x50, 0x07 }, // GIP_CLKB_1564	{ 0x51, 0x08 }, // GIP_CLKB_2565	{ 0x52, 0x09 }, // GIP_CLKB_3566	{ 0x53, 0x0a }, // GIP_CLKB_4567	{ 0x54, 0x11 }, // GIP_CLKB_5568	{ 0x55, 0xec }, // GIP_CLKB_6569	{ 0x56, 0xed }, // GIP_CLKB_7570	{ 0x57, 0x11 }, // GIP_CLKB_8571	{ 0x58, 0xef }, // GIP_CLKB_9572	{ 0x59, 0xf0 }, // GIP_CLKB_10573	// Map internal GOA signals to GOA output pad574	{ 0xb1, 0x01 }, // PANELD2U2575	{ 0xb4, 0x15 }, // PANELD2U5576	{ 0xb5, 0x16 }, // PANELD2U6577	{ 0xb6, 0x09 }, // PANELD2U7578	{ 0xb7, 0x0f }, // PANELD2U8579	{ 0xb8, 0x0d }, // PANELD2U9580	{ 0xb9, 0x0b }, // PANELD2U10581	{ 0xba, 0x00 }, // PANELD2U11582	{ 0xc7, 0x02 }, // PANELD2U24583	{ 0xca, 0x17 }, // PANELD2U27584	{ 0xcb, 0x18 }, // PANELD2U28585	{ 0xcc, 0x0a }, // PANELD2U29586	{ 0xcd, 0x10 }, // PANELD2U30587	{ 0xce, 0x0e }, // PANELD2U31588	{ 0xcf, 0x0c }, // PANELD2U32589	{ 0xd0, 0x00 }, // PANELD2U33590	// Map internal GOA signals to GOA output pad591	{ 0x81, 0x00 }, // PANELU2D2592	{ 0x84, 0x15 }, // PANELU2D5593	{ 0x85, 0x16 }, // PANELU2D6594	{ 0x86, 0x10 }, // PANELU2D7595	{ 0x87, 0x0a }, // PANELU2D8596	{ 0x88, 0x0c }, // PANELU2D9597	{ 0x89, 0x0e }, // PANELU2D10598	{ 0x8a, 0x02 }, // PANELU2D11599	{ 0x97, 0x00 }, // PANELU2D24600	{ 0x9a, 0x17 }, // PANELU2D27601	{ 0x9b, 0x18 }, // PANELU2D28602	{ 0x9c, 0x0f }, // PANELU2D29603	{ 0x9d, 0x09 }, // PANELU2D30604	{ 0x9e, 0x0b }, // PANELU2D31605	{ 0x9f, 0x0d }, // PANELU2D32606	{ 0xa0, 0x01 }, // PANELU2D33607	// EXTC Command set enable, select page 2608	{ 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x02 },609	// Unknown registers610	{ 0x01, 0x01 },611	{ 0x02, 0xda },612	{ 0x03, 0xba },613	{ 0x04, 0xa8 },614	{ 0x05, 0x9a },615	{ 0x06, 0x70 },616	{ 0x07, 0xff },617	{ 0x08, 0x91 },618	{ 0x09, 0x90 },619	{ 0x0a, 0xff },620	{ 0x0b, 0x8f },621	{ 0x0c, 0x60 },622	{ 0x0d, 0x58 },623	{ 0x0e, 0x48 },624	{ 0x0f, 0x38 },625	{ 0x10, 0x2b },626	// EXTC Command set enable, select page 0627	{ 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x00 },628	// Display Access Control629	{ 0x36, 0x0a }, // bgr = 1, ss = 1, gs = 0630};631 632static inline struct nv3052c *to_nv3052c(struct drm_panel *panel)633{634	return container_of(panel, struct nv3052c, panel);635}636 637static int nv3052c_prepare(struct drm_panel *panel)638{639	struct nv3052c *priv = to_nv3052c(panel);640	const struct nv3052c_reg *panel_regs = priv->panel_info->panel_regs;641	unsigned int panel_regs_len = priv->panel_info->panel_regs_len;642	struct mipi_dbi *dbi = &priv->dbi;643	unsigned int i;644	int err;645 646	err = regulator_enable(priv->supply);647	if (err) {648		dev_err(priv->dev, "Failed to enable power supply: %d\n", err);649		return err;650	}651 652	/* Reset the chip */653	gpiod_set_value_cansleep(priv->reset_gpio, 1);654	usleep_range(10, 1000);655	gpiod_set_value_cansleep(priv->reset_gpio, 0);656	usleep_range(5000, 20000);657 658	for (i = 0; i < panel_regs_len; i++) {659		err = mipi_dbi_command(dbi, panel_regs[i].cmd,660				       panel_regs[i].val);661 662		if (err) {663			dev_err(priv->dev, "Unable to set register: %d\n", err);664			goto err_disable_regulator;665		}666	}667 668	err = mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);669	if (err) {670		dev_err(priv->dev, "Unable to exit sleep mode: %d\n", err);671		goto err_disable_regulator;672	}673 674	return 0;675 676err_disable_regulator:677	regulator_disable(priv->supply);678	return err;679}680 681static int nv3052c_unprepare(struct drm_panel *panel)682{683	struct nv3052c *priv = to_nv3052c(panel);684	struct mipi_dbi *dbi = &priv->dbi;685	int err;686 687	err = mipi_dbi_command(dbi, MIPI_DCS_ENTER_SLEEP_MODE);688	if (err)689		dev_err(priv->dev, "Unable to enter sleep mode: %d\n", err);690 691	gpiod_set_value_cansleep(priv->reset_gpio, 1);692	regulator_disable(priv->supply);693 694	return 0;695}696 697static int nv3052c_enable(struct drm_panel *panel)698{699	struct nv3052c *priv = to_nv3052c(panel);700	struct mipi_dbi *dbi = &priv->dbi;701	int err;702 703	err = mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);704	if (err) {705		dev_err(priv->dev, "Unable to enable display: %d\n", err);706		return err;707	}708 709	if (panel->backlight) {710		/* Wait for the picture to be ready before enabling backlight */711		msleep(120);712	}713 714	return 0;715}716 717static int nv3052c_disable(struct drm_panel *panel)718{719	struct nv3052c *priv = to_nv3052c(panel);720	struct mipi_dbi *dbi = &priv->dbi;721	int err;722 723	err = mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF);724	if (err) {725		dev_err(priv->dev, "Unable to disable display: %d\n", err);726		return err;727	}728 729	return 0;730}731 732static int nv3052c_get_modes(struct drm_panel *panel,733			     struct drm_connector *connector)734{735	struct nv3052c *priv = to_nv3052c(panel);736	const struct nv3052c_panel_info *panel_info = priv->panel_info;737	struct drm_display_mode *mode;738	unsigned int i;739 740	for (i = 0; i < panel_info->num_modes; i++) {741		mode = drm_mode_duplicate(connector->dev,742					  &panel_info->display_modes[i]);743		if (!mode)744			return -ENOMEM;745 746		drm_mode_set_name(mode);747 748		mode->type = DRM_MODE_TYPE_DRIVER;749		if (panel_info->num_modes == 1)750			mode->type |= DRM_MODE_TYPE_PREFERRED;751 752		drm_mode_probed_add(connector, mode);753	}754 755	connector->display_info.bpc = 8;756	connector->display_info.width_mm = panel_info->width_mm;757	connector->display_info.height_mm = panel_info->height_mm;758 759	drm_display_info_set_bus_formats(&connector->display_info,760					 &panel_info->bus_format, 1);761	connector->display_info.bus_flags = panel_info->bus_flags;762 763	return panel_info->num_modes;764}765 766static const struct drm_panel_funcs nv3052c_funcs = {767	.prepare	= nv3052c_prepare,768	.unprepare	= nv3052c_unprepare,769	.enable		= nv3052c_enable,770	.disable	= nv3052c_disable,771	.get_modes	= nv3052c_get_modes,772};773 774static int nv3052c_probe(struct spi_device *spi)775{776	struct device *dev = &spi->dev;777	struct nv3052c *priv;778	int err;779 780	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);781	if (!priv)782		return -ENOMEM;783 784	priv->dev = dev;785 786	priv->panel_info = of_device_get_match_data(dev);787	if (!priv->panel_info)788		return -EINVAL;789 790	priv->supply = devm_regulator_get(dev, "power");791	if (IS_ERR(priv->supply))792		return dev_err_probe(dev, PTR_ERR(priv->supply), "Failed to get power supply\n");793 794	priv->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);795	if (IS_ERR(priv->reset_gpio))796		return dev_err_probe(dev, PTR_ERR(priv->reset_gpio), "Failed to get reset GPIO\n");797 798	err = mipi_dbi_spi_init(spi, &priv->dbi, NULL);799	if (err)800		return dev_err_probe(dev, err, "MIPI DBI init failed\n");801 802	priv->dbi.read_commands = NULL;803 804	spi_set_drvdata(spi, priv);805 806	drm_panel_init(&priv->panel, dev, &nv3052c_funcs,807		       DRM_MODE_CONNECTOR_DPI);808 809	err = drm_panel_of_backlight(&priv->panel);810	if (err)811		return dev_err_probe(dev, err, "Failed to attach backlight\n");812 813	drm_panel_add(&priv->panel);814 815	return 0;816}817 818static void nv3052c_remove(struct spi_device *spi)819{820	struct nv3052c *priv = spi_get_drvdata(spi);821 822	drm_panel_remove(&priv->panel);823	drm_panel_disable(&priv->panel);824	drm_panel_unprepare(&priv->panel);825}826 827static const struct drm_display_mode ltk035c5444t_modes[] = {828	{ /* 60 Hz */829		.clock = 24000,830		.hdisplay = 640,831		.hsync_start = 640 + 96,832		.hsync_end = 640 + 96 + 16,833		.htotal = 640 + 96 + 16 + 48,834		.vdisplay = 480,835		.vsync_start = 480 + 5,836		.vsync_end = 480 + 5 + 2,837		.vtotal = 480 + 5 + 2 + 13,838		.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,839	},840	{ /* 50 Hz */841		.clock = 18000,842		.hdisplay = 640,843		.hsync_start = 640 + 39,844		.hsync_end = 640 + 39 + 2,845		.htotal = 640 + 39 + 2 + 39,846		.vdisplay = 480,847		.vsync_start = 480 + 5,848		.vsync_end = 480 + 5 + 2,849		.vtotal = 480 + 5 + 2 + 13,850		.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,851	},852};853 854static const struct drm_display_mode fs035vg158_modes[] = {855	{ /* 60 Hz */856		.clock = 21000,857		.hdisplay = 640,858		.hsync_start = 640 + 34,859		.hsync_end = 640 + 34 + 4,860		.htotal = 640 + 34 + 4 + 20,861		.vdisplay = 480,862		.vsync_start = 480 + 12,863		.vsync_end = 480 + 12 + 4,864		.vtotal = 480 + 12 + 4 + 6,865		.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,866	},867};868 869static const struct drm_display_mode wl_355608_a8_mode[] = {870	{871		.clock = 24000,872		.hdisplay = 640,873		.hsync_start = 640 + 64,874		.hsync_end = 640 + 64 + 20,875		.htotal = 640 + 64 + 20 + 46,876		.vdisplay = 480,877		.vsync_start = 480 + 21,878		.vsync_end = 480 + 21 + 4,879		.vtotal = 480 + 21 + 4 + 15,880		.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,881	},882};883 884static const struct nv3052c_panel_info ltk035c5444t_panel_info = {885	.display_modes = ltk035c5444t_modes,886	.num_modes = ARRAY_SIZE(ltk035c5444t_modes),887	.width_mm = 77,888	.height_mm = 64,889	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,890	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,891	.panel_regs = ltk035c5444t_panel_regs,892	.panel_regs_len = ARRAY_SIZE(ltk035c5444t_panel_regs),893};894 895static const struct nv3052c_panel_info fs035vg158_panel_info = {896	.display_modes = fs035vg158_modes,897	.num_modes = ARRAY_SIZE(fs035vg158_modes),898	.width_mm = 70,899	.height_mm = 53,900	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,901	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,902	.panel_regs = fs035vg158_panel_regs,903	.panel_regs_len = ARRAY_SIZE(fs035vg158_panel_regs),904};905 906static const struct nv3052c_panel_info wl_355608_a8_panel_info = {907	.display_modes = wl_355608_a8_mode,908	.num_modes = ARRAY_SIZE(wl_355608_a8_mode),909	.width_mm = 150,910	.height_mm = 94,911	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,912	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,913	.panel_regs = wl_355608_a8_panel_regs,914	.panel_regs_len = ARRAY_SIZE(wl_355608_a8_panel_regs),915};916 917static const struct spi_device_id nv3052c_ids[] = {918	{ "ltk035c5444t", },919	{ "fs035vg158", },920	{ "wl-355608-a8", },921	{ /* sentinel */ }922};923MODULE_DEVICE_TABLE(spi, nv3052c_ids);924 925static const struct of_device_id nv3052c_of_match[] = {926	{ .compatible = "leadtek,ltk035c5444t", .data = &ltk035c5444t_panel_info },927	{ .compatible = "fascontek,fs035vg158", .data = &fs035vg158_panel_info },928	{ .compatible = "anbernic,rg35xx-plus-panel", .data = &wl_355608_a8_panel_info },929	{ /* sentinel */ }930};931MODULE_DEVICE_TABLE(of, nv3052c_of_match);932 933static struct spi_driver nv3052c_driver = {934	.driver = {935		.name = "nv3052c",936		.of_match_table = nv3052c_of_match,937	},938	.id_table = nv3052c_ids,939	.probe = nv3052c_probe,940	.remove = nv3052c_remove,941};942module_spi_driver(nv3052c_driver);943 944MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");945MODULE_AUTHOR("Christophe Branchereau <cbranchereau@gmail.com>");946MODULE_AUTHOR("Ryan Walklin <ryan@testtoast.com");947MODULE_DESCRIPTION("NewVision NV3052C IPS LCD panel driver");948MODULE_LICENSE("GPL v2");949