Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (c) 2018 MediaTek Inc.
  4 * Author: Jitao Shi <jitao.shi@mediatek.com>
  5 */
  6
  7#include <linux/delay.h>
  8#include <linux/gpio/consumer.h>
  9#include <linux/module.h>
 10#include <linux/of.h>
 11#include <linux/of_device.h>
 12#include <linux/regulator/consumer.h>
 13
 14#include <drm/drm_connector.h>
 15#include <drm/drm_crtc.h>
 16#include <drm/drm_mipi_dsi.h>
 17#include <drm/drm_panel.h>
 18
 19#include <video/mipi_display.h>
 20
 21struct panel_desc {
 22	const struct drm_display_mode *modes;
 23	unsigned int bpc;
 24
 25	/**
 26	 * @width_mm: width of the panel's active display area
 27	 * @height_mm: height of the panel's active display area
 28	 */
 29	struct {
 30		unsigned int width_mm;
 31		unsigned int height_mm;
 32	} size;
 33
 34	unsigned long mode_flags;
 35	enum mipi_dsi_pixel_format format;
 36	const struct panel_init_cmd *init_cmds;
 37	unsigned int lanes;
 38	bool discharge_on_disable;
 39};
 40
 41struct boe_panel {
 42	struct drm_panel base;
 43	struct mipi_dsi_device *dsi;
 44
 45	const struct panel_desc *desc;
 46
 47	enum drm_panel_orientation orientation;
 48	struct regulator *pp1800;
 49	struct regulator *avee;
 50	struct regulator *avdd;
 51	struct gpio_desc *enable_gpio;
 52
 53	bool prepared;
 54};
 55
 56enum dsi_cmd_type {
 57	INIT_DCS_CMD,
 58	DELAY_CMD,
 59};
 60
 61struct panel_init_cmd {
 62	enum dsi_cmd_type type;
 63	size_t len;
 64	const char *data;
 65};
 66
 67#define _INIT_DCS_CMD(...) { \
 68	.type = INIT_DCS_CMD, \
 69	.len = sizeof((char[]){__VA_ARGS__}), \
 70	.data = (char[]){__VA_ARGS__} }
 71
 72#define _INIT_DELAY_CMD(...) { \
 73	.type = DELAY_CMD,\
 74	.len = sizeof((char[]){__VA_ARGS__}), \
 75	.data = (char[]){__VA_ARGS__} }
 76
 77static const struct panel_init_cmd boe_init_cmd[] = {
 78	_INIT_DELAY_CMD(24),
 79	_INIT_DCS_CMD(0xB0, 0x05),
 80	_INIT_DCS_CMD(0xB1, 0xE5),
 81	_INIT_DCS_CMD(0xB3, 0x52),
 82	_INIT_DCS_CMD(0xB0, 0x00),
 83	_INIT_DCS_CMD(0xB3, 0x88),
 84	_INIT_DCS_CMD(0xB0, 0x04),
 85	_INIT_DCS_CMD(0xB8, 0x00),
 86	_INIT_DCS_CMD(0xB0, 0x00),
 87	_INIT_DCS_CMD(0xB6, 0x03),
 88	_INIT_DCS_CMD(0xBA, 0x8B),
 89	_INIT_DCS_CMD(0xBF, 0x1A),
 90	_INIT_DCS_CMD(0xC0, 0x0F),
 91	_INIT_DCS_CMD(0xC2, 0x0C),
 92	_INIT_DCS_CMD(0xC3, 0x02),
 93	_INIT_DCS_CMD(0xC4, 0x0C),
 94	_INIT_DCS_CMD(0xC5, 0x02),
 95	_INIT_DCS_CMD(0xB0, 0x01),
 96	_INIT_DCS_CMD(0xE0, 0x26),
 97	_INIT_DCS_CMD(0xE1, 0x26),
 98	_INIT_DCS_CMD(0xDC, 0x00),
 99	_INIT_DCS_CMD(0xDD, 0x00),
100	_INIT_DCS_CMD(0xCC, 0x26),
101	_INIT_DCS_CMD(0xCD, 0x26),
102	_INIT_DCS_CMD(0xC8, 0x00),
103	_INIT_DCS_CMD(0xC9, 0x00),
104	_INIT_DCS_CMD(0xD2, 0x03),
105	_INIT_DCS_CMD(0xD3, 0x03),
106	_INIT_DCS_CMD(0xE6, 0x04),
107	_INIT_DCS_CMD(0xE7, 0x04),
108	_INIT_DCS_CMD(0xC4, 0x09),
109	_INIT_DCS_CMD(0xC5, 0x09),
110	_INIT_DCS_CMD(0xD8, 0x0A),
111	_INIT_DCS_CMD(0xD9, 0x0A),
112	_INIT_DCS_CMD(0xC2, 0x0B),
113	_INIT_DCS_CMD(0xC3, 0x0B),
114	_INIT_DCS_CMD(0xD6, 0x0C),
115	_INIT_DCS_CMD(0xD7, 0x0C),
116	_INIT_DCS_CMD(0xC0, 0x05),
117	_INIT_DCS_CMD(0xC1, 0x05),
118	_INIT_DCS_CMD(0xD4, 0x06),
119	_INIT_DCS_CMD(0xD5, 0x06),
120	_INIT_DCS_CMD(0xCA, 0x07),
121	_INIT_DCS_CMD(0xCB, 0x07),
122	_INIT_DCS_CMD(0xDE, 0x08),
123	_INIT_DCS_CMD(0xDF, 0x08),
124	_INIT_DCS_CMD(0xB0, 0x02),
125	_INIT_DCS_CMD(0xC0, 0x00),
126	_INIT_DCS_CMD(0xC1, 0x0D),
127	_INIT_DCS_CMD(0xC2, 0x17),
128	_INIT_DCS_CMD(0xC3, 0x26),
129	_INIT_DCS_CMD(0xC4, 0x31),
130	_INIT_DCS_CMD(0xC5, 0x1C),
131	_INIT_DCS_CMD(0xC6, 0x2C),
132	_INIT_DCS_CMD(0xC7, 0x33),
133	_INIT_DCS_CMD(0xC8, 0x31),
134	_INIT_DCS_CMD(0xC9, 0x37),
135	_INIT_DCS_CMD(0xCA, 0x37),
136	_INIT_DCS_CMD(0xCB, 0x37),
137	_INIT_DCS_CMD(0xCC, 0x39),
138	_INIT_DCS_CMD(0xCD, 0x2E),
139	_INIT_DCS_CMD(0xCE, 0x2F),
140	_INIT_DCS_CMD(0xCF, 0x2F),
141	_INIT_DCS_CMD(0xD0, 0x07),
142	_INIT_DCS_CMD(0xD2, 0x00),
143	_INIT_DCS_CMD(0xD3, 0x0D),
144	_INIT_DCS_CMD(0xD4, 0x17),
145	_INIT_DCS_CMD(0xD5, 0x26),
146	_INIT_DCS_CMD(0xD6, 0x31),
147	_INIT_DCS_CMD(0xD7, 0x3F),
148	_INIT_DCS_CMD(0xD8, 0x3F),
149	_INIT_DCS_CMD(0xD9, 0x3F),
150	_INIT_DCS_CMD(0xDA, 0x3F),
151	_INIT_DCS_CMD(0xDB, 0x37),
152	_INIT_DCS_CMD(0xDC, 0x37),
153	_INIT_DCS_CMD(0xDD, 0x37),
154	_INIT_DCS_CMD(0xDE, 0x39),
155	_INIT_DCS_CMD(0xDF, 0x2E),
156	_INIT_DCS_CMD(0xE0, 0x2F),
157	_INIT_DCS_CMD(0xE1, 0x2F),
158	_INIT_DCS_CMD(0xE2, 0x07),
159	_INIT_DCS_CMD(0xB0, 0x03),
160	_INIT_DCS_CMD(0xC8, 0x0B),
161	_INIT_DCS_CMD(0xC9, 0x07),
162	_INIT_DCS_CMD(0xC3, 0x00),
163	_INIT_DCS_CMD(0xE7, 0x00),
164	_INIT_DCS_CMD(0xC5, 0x2A),
165	_INIT_DCS_CMD(0xDE, 0x2A),
166	_INIT_DCS_CMD(0xCA, 0x43),
167	_INIT_DCS_CMD(0xC9, 0x07),
168	_INIT_DCS_CMD(0xE4, 0xC0),
169	_INIT_DCS_CMD(0xE5, 0x0D),
170	_INIT_DCS_CMD(0xCB, 0x00),
171	_INIT_DCS_CMD(0xB0, 0x06),
172	_INIT_DCS_CMD(0xB8, 0xA5),
173	_INIT_DCS_CMD(0xC0, 0xA5),
174	_INIT_DCS_CMD(0xC7, 0x0F),
175	_INIT_DCS_CMD(0xD5, 0x32),
176	_INIT_DCS_CMD(0xB8, 0x00),
177	_INIT_DCS_CMD(0xC0, 0x00),
178	_INIT_DCS_CMD(0xBC, 0x00),
179	_INIT_DCS_CMD(0xB0, 0x07),
180	_INIT_DCS_CMD(0xB1, 0x00),
181	_INIT_DCS_CMD(0xB2, 0x02),
182	_INIT_DCS_CMD(0xB3, 0x0F),
183	_INIT_DCS_CMD(0xB4, 0x25),
184	_INIT_DCS_CMD(0xB5, 0x39),
185	_INIT_DCS_CMD(0xB6, 0x4E),
186	_INIT_DCS_CMD(0xB7, 0x72),
187	_INIT_DCS_CMD(0xB8, 0x97),
188	_INIT_DCS_CMD(0xB9, 0xDC),
189	_INIT_DCS_CMD(0xBA, 0x22),
190	_INIT_DCS_CMD(0xBB, 0xA4),
191	_INIT_DCS_CMD(0xBC, 0x2B),
192	_INIT_DCS_CMD(0xBD, 0x2F),
193	_INIT_DCS_CMD(0xBE, 0xA9),
194	_INIT_DCS_CMD(0xBF, 0x25),
195	_INIT_DCS_CMD(0xC0, 0x61),
196	_INIT_DCS_CMD(0xC1, 0x97),
197	_INIT_DCS_CMD(0xC2, 0xB2),
198	_INIT_DCS_CMD(0xC3, 0xCD),
199	_INIT_DCS_CMD(0xC4, 0xD9),
200	_INIT_DCS_CMD(0xC5, 0xE7),
201	_INIT_DCS_CMD(0xC6, 0xF4),
202	_INIT_DCS_CMD(0xC7, 0xFA),
203	_INIT_DCS_CMD(0xC8, 0xFC),
204	_INIT_DCS_CMD(0xC9, 0x00),
205	_INIT_DCS_CMD(0xCA, 0x00),
206	_INIT_DCS_CMD(0xCB, 0x16),
207	_INIT_DCS_CMD(0xCC, 0xAF),
208	_INIT_DCS_CMD(0xCD, 0xFF),
209	_INIT_DCS_CMD(0xCE, 0xFF),
210	_INIT_DCS_CMD(0xB0, 0x08),
211	_INIT_DCS_CMD(0xB1, 0x04),
212	_INIT_DCS_CMD(0xB2, 0x05),
213	_INIT_DCS_CMD(0xB3, 0x11),
214	_INIT_DCS_CMD(0xB4, 0x24),
215	_INIT_DCS_CMD(0xB5, 0x39),
216	_INIT_DCS_CMD(0xB6, 0x4F),
217	_INIT_DCS_CMD(0xB7, 0x72),
218	_INIT_DCS_CMD(0xB8, 0x98),
219	_INIT_DCS_CMD(0xB9, 0xDC),
220	_INIT_DCS_CMD(0xBA, 0x23),
221	_INIT_DCS_CMD(0xBB, 0xA6),
222	_INIT_DCS_CMD(0xBC, 0x2C),
223	_INIT_DCS_CMD(0xBD, 0x30),
224	_INIT_DCS_CMD(0xBE, 0xAA),
225	_INIT_DCS_CMD(0xBF, 0x26),
226	_INIT_DCS_CMD(0xC0, 0x62),
227	_INIT_DCS_CMD(0xC1, 0x9B),
228	_INIT_DCS_CMD(0xC2, 0xB5),
229	_INIT_DCS_CMD(0xC3, 0xCF),
230	_INIT_DCS_CMD(0xC4, 0xDB),
231	_INIT_DCS_CMD(0xC5, 0xE8),
232	_INIT_DCS_CMD(0xC6, 0xF5),
233	_INIT_DCS_CMD(0xC7, 0xFA),
234	_INIT_DCS_CMD(0xC8, 0xFC),
235	_INIT_DCS_CMD(0xC9, 0x00),
236	_INIT_DCS_CMD(0xCA, 0x00),
237	_INIT_DCS_CMD(0xCB, 0x16),
238	_INIT_DCS_CMD(0xCC, 0xAF),
239	_INIT_DCS_CMD(0xCD, 0xFF),
240	_INIT_DCS_CMD(0xCE, 0xFF),
241	_INIT_DCS_CMD(0xB0, 0x09),
242	_INIT_DCS_CMD(0xB1, 0x04),
243	_INIT_DCS_CMD(0xB2, 0x02),
244	_INIT_DCS_CMD(0xB3, 0x16),
245	_INIT_DCS_CMD(0xB4, 0x24),
246	_INIT_DCS_CMD(0xB5, 0x3B),
247	_INIT_DCS_CMD(0xB6, 0x4F),
248	_INIT_DCS_CMD(0xB7, 0x73),
249	_INIT_DCS_CMD(0xB8, 0x99),
250	_INIT_DCS_CMD(0xB9, 0xE0),
251	_INIT_DCS_CMD(0xBA, 0x26),
252	_INIT_DCS_CMD(0xBB, 0xAD),
253	_INIT_DCS_CMD(0xBC, 0x36),
254	_INIT_DCS_CMD(0xBD, 0x3A),
255	_INIT_DCS_CMD(0xBE, 0xAE),
256	_INIT_DCS_CMD(0xBF, 0x2A),
257	_INIT_DCS_CMD(0xC0, 0x66),
258	_INIT_DCS_CMD(0xC1, 0x9E),
259	_INIT_DCS_CMD(0xC2, 0xB8),
260	_INIT_DCS_CMD(0xC3, 0xD1),
261	_INIT_DCS_CMD(0xC4, 0xDD),
262	_INIT_DCS_CMD(0xC5, 0xE9),
263	_INIT_DCS_CMD(0xC6, 0xF6),
264	_INIT_DCS_CMD(0xC7, 0xFA),
265	_INIT_DCS_CMD(0xC8, 0xFC),
266	_INIT_DCS_CMD(0xC9, 0x00),
267	_INIT_DCS_CMD(0xCA, 0x00),
268	_INIT_DCS_CMD(0xCB, 0x16),
269	_INIT_DCS_CMD(0xCC, 0xAF),
270	_INIT_DCS_CMD(0xCD, 0xFF),
271	_INIT_DCS_CMD(0xCE, 0xFF),
272	_INIT_DCS_CMD(0xB0, 0x0A),
273	_INIT_DCS_CMD(0xB1, 0x00),
274	_INIT_DCS_CMD(0xB2, 0x02),
275	_INIT_DCS_CMD(0xB3, 0x0F),
276	_INIT_DCS_CMD(0xB4, 0x25),
277	_INIT_DCS_CMD(0xB5, 0x39),
278	_INIT_DCS_CMD(0xB6, 0x4E),
279	_INIT_DCS_CMD(0xB7, 0x72),
280	_INIT_DCS_CMD(0xB8, 0x97),
281	_INIT_DCS_CMD(0xB9, 0xDC),
282	_INIT_DCS_CMD(0xBA, 0x22),
283	_INIT_DCS_CMD(0xBB, 0xA4),
284	_INIT_DCS_CMD(0xBC, 0x2B),
285	_INIT_DCS_CMD(0xBD, 0x2F),
286	_INIT_DCS_CMD(0xBE, 0xA9),
287	_INIT_DCS_CMD(0xBF, 0x25),
288	_INIT_DCS_CMD(0xC0, 0x61),
289	_INIT_DCS_CMD(0xC1, 0x97),
290	_INIT_DCS_CMD(0xC2, 0xB2),
291	_INIT_DCS_CMD(0xC3, 0xCD),
292	_INIT_DCS_CMD(0xC4, 0xD9),
293	_INIT_DCS_CMD(0xC5, 0xE7),
294	_INIT_DCS_CMD(0xC6, 0xF4),
295	_INIT_DCS_CMD(0xC7, 0xFA),
296	_INIT_DCS_CMD(0xC8, 0xFC),
297	_INIT_DCS_CMD(0xC9, 0x00),
298	_INIT_DCS_CMD(0xCA, 0x00),
299	_INIT_DCS_CMD(0xCB, 0x16),
300	_INIT_DCS_CMD(0xCC, 0xAF),
301	_INIT_DCS_CMD(0xCD, 0xFF),
302	_INIT_DCS_CMD(0xCE, 0xFF),
303	_INIT_DCS_CMD(0xB0, 0x0B),
304	_INIT_DCS_CMD(0xB1, 0x04),
305	_INIT_DCS_CMD(0xB2, 0x05),
306	_INIT_DCS_CMD(0xB3, 0x11),
307	_INIT_DCS_CMD(0xB4, 0x24),
308	_INIT_DCS_CMD(0xB5, 0x39),
309	_INIT_DCS_CMD(0xB6, 0x4F),
310	_INIT_DCS_CMD(0xB7, 0x72),
311	_INIT_DCS_CMD(0xB8, 0x98),
312	_INIT_DCS_CMD(0xB9, 0xDC),
313	_INIT_DCS_CMD(0xBA, 0x23),
314	_INIT_DCS_CMD(0xBB, 0xA6),
315	_INIT_DCS_CMD(0xBC, 0x2C),
316	_INIT_DCS_CMD(0xBD, 0x30),
317	_INIT_DCS_CMD(0xBE, 0xAA),
318	_INIT_DCS_CMD(0xBF, 0x26),
319	_INIT_DCS_CMD(0xC0, 0x62),
320	_INIT_DCS_CMD(0xC1, 0x9B),
321	_INIT_DCS_CMD(0xC2, 0xB5),
322	_INIT_DCS_CMD(0xC3, 0xCF),
323	_INIT_DCS_CMD(0xC4, 0xDB),
324	_INIT_DCS_CMD(0xC5, 0xE8),
325	_INIT_DCS_CMD(0xC6, 0xF5),
326	_INIT_DCS_CMD(0xC7, 0xFA),
327	_INIT_DCS_CMD(0xC8, 0xFC),
328	_INIT_DCS_CMD(0xC9, 0x00),
329	_INIT_DCS_CMD(0xCA, 0x00),
330	_INIT_DCS_CMD(0xCB, 0x16),
331	_INIT_DCS_CMD(0xCC, 0xAF),
332	_INIT_DCS_CMD(0xCD, 0xFF),
333	_INIT_DCS_CMD(0xCE, 0xFF),
334	_INIT_DCS_CMD(0xB0, 0x0C),
335	_INIT_DCS_CMD(0xB1, 0x04),
336	_INIT_DCS_CMD(0xB2, 0x02),
337	_INIT_DCS_CMD(0xB3, 0x16),
338	_INIT_DCS_CMD(0xB4, 0x24),
339	_INIT_DCS_CMD(0xB5, 0x3B),
340	_INIT_DCS_CMD(0xB6, 0x4F),
341	_INIT_DCS_CMD(0xB7, 0x73),
342	_INIT_DCS_CMD(0xB8, 0x99),
343	_INIT_DCS_CMD(0xB9, 0xE0),
344	_INIT_DCS_CMD(0xBA, 0x26),
345	_INIT_DCS_CMD(0xBB, 0xAD),
346	_INIT_DCS_CMD(0xBC, 0x36),
347	_INIT_DCS_CMD(0xBD, 0x3A),
348	_INIT_DCS_CMD(0xBE, 0xAE),
349	_INIT_DCS_CMD(0xBF, 0x2A),
350	_INIT_DCS_CMD(0xC0, 0x66),
351	_INIT_DCS_CMD(0xC1, 0x9E),
352	_INIT_DCS_CMD(0xC2, 0xB8),
353	_INIT_DCS_CMD(0xC3, 0xD1),
354	_INIT_DCS_CMD(0xC4, 0xDD),
355	_INIT_DCS_CMD(0xC5, 0xE9),
356	_INIT_DCS_CMD(0xC6, 0xF6),
357	_INIT_DCS_CMD(0xC7, 0xFA),
358	_INIT_DCS_CMD(0xC8, 0xFC),
359	_INIT_DCS_CMD(0xC9, 0x00),
360	_INIT_DCS_CMD(0xCA, 0x00),
361	_INIT_DCS_CMD(0xCB, 0x16),
362	_INIT_DCS_CMD(0xCC, 0xAF),
363	_INIT_DCS_CMD(0xCD, 0xFF),
364	_INIT_DCS_CMD(0xCE, 0xFF),
365	_INIT_DCS_CMD(0xB0, 0x00),
366	_INIT_DCS_CMD(0xB3, 0x08),
367	_INIT_DCS_CMD(0xB0, 0x04),
368	_INIT_DCS_CMD(0xB8, 0x68),
369	_INIT_DELAY_CMD(150),
370	{},
371};
372
373static const struct panel_init_cmd auo_kd101n80_45na_init_cmd[] = {
374	_INIT_DELAY_CMD(24),
375	_INIT_DCS_CMD(0x11),
376	_INIT_DELAY_CMD(120),
377	_INIT_DCS_CMD(0x29),
378	_INIT_DELAY_CMD(120),
379	{},
380};
381
382static const struct panel_init_cmd auo_b101uan08_3_init_cmd[] = {
383	_INIT_DELAY_CMD(24),
384	_INIT_DCS_CMD(0xB0, 0x01),
385	_INIT_DCS_CMD(0xC0, 0x48),
386	_INIT_DCS_CMD(0xC1, 0x48),
387	_INIT_DCS_CMD(0xC2, 0x47),
388	_INIT_DCS_CMD(0xC3, 0x47),
389	_INIT_DCS_CMD(0xC4, 0x46),
390	_INIT_DCS_CMD(0xC5, 0x46),
391	_INIT_DCS_CMD(0xC6, 0x45),
392	_INIT_DCS_CMD(0xC7, 0x45),
393	_INIT_DCS_CMD(0xC8, 0x64),
394	_INIT_DCS_CMD(0xC9, 0x64),
395	_INIT_DCS_CMD(0xCA, 0x4F),
396	_INIT_DCS_CMD(0xCB, 0x4F),
397	_INIT_DCS_CMD(0xCC, 0x40),
398	_INIT_DCS_CMD(0xCD, 0x40),
399	_INIT_DCS_CMD(0xCE, 0x66),
400	_INIT_DCS_CMD(0xCF, 0x66),
401	_INIT_DCS_CMD(0xD0, 0x4F),
402	_INIT_DCS_CMD(0xD1, 0x4F),
403	_INIT_DCS_CMD(0xD2, 0x41),
404	_INIT_DCS_CMD(0xD3, 0x41),
405	_INIT_DCS_CMD(0xD4, 0x48),
406	_INIT_DCS_CMD(0xD5, 0x48),
407	_INIT_DCS_CMD(0xD6, 0x47),
408	_INIT_DCS_CMD(0xD7, 0x47),
409	_INIT_DCS_CMD(0xD8, 0x46),
410	_INIT_DCS_CMD(0xD9, 0x46),
411	_INIT_DCS_CMD(0xDA, 0x45),
412	_INIT_DCS_CMD(0xDB, 0x45),
413	_INIT_DCS_CMD(0xDC, 0x64),
414	_INIT_DCS_CMD(0xDD, 0x64),
415	_INIT_DCS_CMD(0xDE, 0x4F),
416	_INIT_DCS_CMD(0xDF, 0x4F),
417	_INIT_DCS_CMD(0xE0, 0x40),
418	_INIT_DCS_CMD(0xE1, 0x40),
419	_INIT_DCS_CMD(0xE2, 0x66),
420	_INIT_DCS_CMD(0xE3, 0x66),
421	_INIT_DCS_CMD(0xE4, 0x4F),
422	_INIT_DCS_CMD(0xE5, 0x4F),
423	_INIT_DCS_CMD(0xE6, 0x41),
424	_INIT_DCS_CMD(0xE7, 0x41),
425	_INIT_DELAY_CMD(150),
426	{},
427};
428
429static inline struct boe_panel *to_boe_panel(struct drm_panel *panel)
430{
431	return container_of(panel, struct boe_panel, base);
432}
433
434static int boe_panel_init_dcs_cmd(struct boe_panel *boe)
435{
436	struct mipi_dsi_device *dsi = boe->dsi;
437	struct drm_panel *panel = &boe->base;
438	int i, err = 0;
439
440	if (boe->desc->init_cmds) {
441		const struct panel_init_cmd *init_cmds = boe->desc->init_cmds;
442
443		for (i = 0; init_cmds[i].len != 0; i++) {
444			const struct panel_init_cmd *cmd = &init_cmds[i];
445
446			switch (cmd->type) {
447			case DELAY_CMD:
448				msleep(cmd->data[0]);
449				err = 0;
450				break;
451
452			case INIT_DCS_CMD:
453				err = mipi_dsi_dcs_write(dsi, cmd->data[0],
454							 cmd->len <= 1 ? NULL :
455							 &cmd->data[1],
456							 cmd->len - 1);
457				break;
458
459			default:
460				err = -EINVAL;
461			}
462
463			if (err < 0) {
464				dev_err(panel->dev,
465					"failed to write command %u\n", i);
466				return err;
467			}
468		}
469	}
470	return 0;
471}
472
473static int boe_panel_enter_sleep_mode(struct boe_panel *boe)
474{
475	struct mipi_dsi_device *dsi = boe->dsi;
476	int ret;
477
478	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
479
480	ret = mipi_dsi_dcs_set_display_off(dsi);
481	if (ret < 0)
482		return ret;
483
484	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
485	if (ret < 0)
486		return ret;
487
488	return 0;
489}
490
491static int boe_panel_unprepare(struct drm_panel *panel)
492{
493	struct boe_panel *boe = to_boe_panel(panel);
494	int ret;
495
496	if (!boe->prepared)
497		return 0;
498
499	ret = boe_panel_enter_sleep_mode(boe);
500	if (ret < 0) {
501		dev_err(panel->dev, "failed to set panel off: %d\n", ret);
502		return ret;
503	}
504
505	msleep(150);
506
507	if (boe->desc->discharge_on_disable) {
508		regulator_disable(boe->avee);
509		regulator_disable(boe->avdd);
510		usleep_range(5000, 7000);
511		gpiod_set_value(boe->enable_gpio, 0);
512		usleep_range(5000, 7000);
513		regulator_disable(boe->pp1800);
514	} else {
515		gpiod_set_value(boe->enable_gpio, 0);
516		usleep_range(500, 1000);
517		regulator_disable(boe->avee);
518		regulator_disable(boe->avdd);
519		usleep_range(5000, 7000);
520		regulator_disable(boe->pp1800);
521	}
522
523	boe->prepared = false;
524
525	return 0;
526}
527
528static int boe_panel_prepare(struct drm_panel *panel)
529{
530	struct boe_panel *boe = to_boe_panel(panel);
531	int ret;
532
533	if (boe->prepared)
534		return 0;
535
536	gpiod_set_value(boe->enable_gpio, 0);
537	usleep_range(1000, 1500);
538
539	ret = regulator_enable(boe->pp1800);
540	if (ret < 0)
541		return ret;
542
543	usleep_range(3000, 5000);
544
545	ret = regulator_enable(boe->avdd);
546	if (ret < 0)
547		goto poweroff1v8;
548	ret = regulator_enable(boe->avee);
549	if (ret < 0)
550		goto poweroffavdd;
551
552	usleep_range(5000, 10000);
553
554	gpiod_set_value(boe->enable_gpio, 1);
555	usleep_range(1000, 2000);
556	gpiod_set_value(boe->enable_gpio, 0);
557	usleep_range(1000, 2000);
558	gpiod_set_value(boe->enable_gpio, 1);
559	usleep_range(6000, 10000);
560
561	ret = boe_panel_init_dcs_cmd(boe);
562	if (ret < 0) {
563		dev_err(panel->dev, "failed to init panel: %d\n", ret);
564		goto poweroff;
565	}
566
567	boe->prepared = true;
568
569	return 0;
570
571poweroff:
572	regulator_disable(boe->avee);
573poweroffavdd:
574	regulator_disable(boe->avdd);
575poweroff1v8:
576	usleep_range(5000, 7000);
577	regulator_disable(boe->pp1800);
578	gpiod_set_value(boe->enable_gpio, 0);
579
580	return ret;
581}
582
583static int boe_panel_enable(struct drm_panel *panel)
584{
585	msleep(130);
586	return 0;
587}
588
589static const struct drm_display_mode boe_tv101wum_nl6_default_mode = {
590	.clock = 159425,
591	.hdisplay = 1200,
592	.hsync_start = 1200 + 100,
593	.hsync_end = 1200 + 100 + 40,
594	.htotal = 1200 + 100 + 40 + 24,
595	.vdisplay = 1920,
596	.vsync_start = 1920 + 10,
597	.vsync_end = 1920 + 10 + 14,
598	.vtotal = 1920 + 10 + 14 + 4,
599};
600
601static const struct panel_desc boe_tv101wum_nl6_desc = {
602	.modes = &boe_tv101wum_nl6_default_mode,
603	.bpc = 8,
604	.size = {
605		.width_mm = 135,
606		.height_mm = 216,
607	},
608	.lanes = 4,
609	.format = MIPI_DSI_FMT_RGB888,
610	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
611		      MIPI_DSI_MODE_LPM,
612	.init_cmds = boe_init_cmd,
613	.discharge_on_disable = false,
614};
615
616static const struct drm_display_mode auo_kd101n80_45na_default_mode = {
617	.clock = 157000,
618	.hdisplay = 1200,
619	.hsync_start = 1200 + 60,
620	.hsync_end = 1200 + 60 + 24,
621	.htotal = 1200 + 60 + 24 + 56,
622	.vdisplay = 1920,
623	.vsync_start = 1920 + 16,
624	.vsync_end = 1920 + 16 + 4,
625	.vtotal = 1920 + 16 + 4 + 16,
626};
627
628static const struct panel_desc auo_kd101n80_45na_desc = {
629	.modes = &auo_kd101n80_45na_default_mode,
630	.bpc = 8,
631	.size = {
632		.width_mm = 135,
633		.height_mm = 216,
634	},
635	.lanes = 4,
636	.format = MIPI_DSI_FMT_RGB888,
637	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
638		      MIPI_DSI_MODE_LPM,
639	.init_cmds = auo_kd101n80_45na_init_cmd,
640	.discharge_on_disable = true,
641};
642
643static const struct drm_display_mode boe_tv101wum_n53_default_mode = {
644	.clock = 159916,
645	.hdisplay = 1200,
646	.hsync_start = 1200 + 80,
647	.hsync_end = 1200 + 80 + 24,
648	.htotal = 1200 + 80 + 24 + 60,
649	.vdisplay = 1920,
650	.vsync_start = 1920 + 20,
651	.vsync_end = 1920 + 20 + 4,
652	.vtotal = 1920 + 20 + 4 + 10,
653	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
654};
655
656static const struct panel_desc boe_tv101wum_n53_desc = {
657	.modes = &boe_tv101wum_n53_default_mode,
658	.bpc = 8,
659	.size = {
660		.width_mm = 135,
661		.height_mm = 216,
662	},
663	.lanes = 4,
664	.format = MIPI_DSI_FMT_RGB888,
665	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
666		      MIPI_DSI_MODE_LPM,
667	.init_cmds = boe_init_cmd,
668};
669
670static const struct drm_display_mode auo_b101uan08_3_default_mode = {
671	.clock = 159667,
672	.hdisplay = 1200,
673	.hsync_start = 1200 + 60,
674	.hsync_end = 1200 + 60 + 4,
675	.htotal = 1200 + 60 + 4 + 80,
676	.vdisplay = 1920,
677	.vsync_start = 1920 + 34,
678	.vsync_end = 1920 + 34 + 2,
679	.vtotal = 1920 + 34 + 2 + 24,
680	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
681};
682
683static const struct panel_desc auo_b101uan08_3_desc = {
684	.modes = &auo_b101uan08_3_default_mode,
685	.bpc = 8,
686	.size = {
687		.width_mm = 135,
688		.height_mm = 216,
689	},
690	.lanes = 4,
691	.format = MIPI_DSI_FMT_RGB888,
692	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
693		      MIPI_DSI_MODE_LPM,
694	.init_cmds = auo_b101uan08_3_init_cmd,
695};
696
697static const struct drm_display_mode boe_tv105wum_nw0_default_mode = {
698	.clock = 159916,
699	.hdisplay = 1200,
700	.hsync_start = 1200 + 80,
701	.hsync_end = 1200 + 80 + 24,
702	.htotal = 1200 + 80 + 24 + 60,
703	.vdisplay = 1920,
704	.vsync_start = 1920 + 20,
705	.vsync_end = 1920 + 20 + 4,
706	.vtotal = 1920 + 20 + 4 + 10,
707	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
708};
709
710static const struct panel_desc boe_tv105wum_nw0_desc = {
711	.modes = &boe_tv105wum_nw0_default_mode,
712	.bpc = 8,
713	.size = {
714		.width_mm = 141,
715		.height_mm = 226,
716	},
717	.lanes = 4,
718	.format = MIPI_DSI_FMT_RGB888,
719	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
720		      MIPI_DSI_MODE_LPM,
721	.init_cmds = boe_init_cmd,
722};
723
724static int boe_panel_get_modes(struct drm_panel *panel,
725			       struct drm_connector *connector)
726{
727	struct boe_panel *boe = to_boe_panel(panel);
728	const struct drm_display_mode *m = boe->desc->modes;
729	struct drm_display_mode *mode;
730
731	mode = drm_mode_duplicate(connector->dev, m);
732	if (!mode) {
733		dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
734			m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
735		return -ENOMEM;
736	}
737
738	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
739	drm_mode_set_name(mode);
740	drm_mode_probed_add(connector, mode);
741
742	connector->display_info.width_mm = boe->desc->size.width_mm;
743	connector->display_info.height_mm = boe->desc->size.height_mm;
744	connector->display_info.bpc = boe->desc->bpc;
745	drm_connector_set_panel_orientation(connector, boe->orientation);
746
747	return 1;
748}
749
750static const struct drm_panel_funcs boe_panel_funcs = {
751	.unprepare = boe_panel_unprepare,
752	.prepare = boe_panel_prepare,
753	.enable = boe_panel_enable,
754	.get_modes = boe_panel_get_modes,
755};
756
757static int boe_panel_add(struct boe_panel *boe)
758{
759	struct device *dev = &boe->dsi->dev;
760	int err;
761
762	boe->avdd = devm_regulator_get(dev, "avdd");
763	if (IS_ERR(boe->avdd))
764		return PTR_ERR(boe->avdd);
765
766	boe->avee = devm_regulator_get(dev, "avee");
767	if (IS_ERR(boe->avee))
768		return PTR_ERR(boe->avee);
769
770	boe->pp1800 = devm_regulator_get(dev, "pp1800");
771	if (IS_ERR(boe->pp1800))
772		return PTR_ERR(boe->pp1800);
773
774	boe->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
775	if (IS_ERR(boe->enable_gpio)) {
776		dev_err(dev, "cannot get reset-gpios %ld\n",
777			PTR_ERR(boe->enable_gpio));
778		return PTR_ERR(boe->enable_gpio);
779	}
780
781	gpiod_set_value(boe->enable_gpio, 0);
782
783	drm_panel_init(&boe->base, dev, &boe_panel_funcs,
784		       DRM_MODE_CONNECTOR_DSI);
785	err = of_drm_get_panel_orientation(dev->of_node, &boe->orientation);
786	if (err < 0) {
787		dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
788		return err;
789	}
790
791	err = drm_panel_of_backlight(&boe->base);
792	if (err)
793		return err;
794
795	boe->base.funcs = &boe_panel_funcs;
796	boe->base.dev = &boe->dsi->dev;
797
798	drm_panel_add(&boe->base);
799
800	return 0;
801}
802
803static int boe_panel_probe(struct mipi_dsi_device *dsi)
804{
805	struct boe_panel *boe;
806	int ret;
807	const struct panel_desc *desc;
808
809	boe = devm_kzalloc(&dsi->dev, sizeof(*boe), GFP_KERNEL);
810	if (!boe)
811		return -ENOMEM;
812
813	desc = of_device_get_match_data(&dsi->dev);
814	dsi->lanes = desc->lanes;
815	dsi->format = desc->format;
816	dsi->mode_flags = desc->mode_flags;
817	boe->desc = desc;
818	boe->dsi = dsi;
819	ret = boe_panel_add(boe);
820	if (ret < 0)
821		return ret;
822
823	mipi_dsi_set_drvdata(dsi, boe);
824
825	ret = mipi_dsi_attach(dsi);
826	if (ret)
827		drm_panel_remove(&boe->base);
828
829	return ret;
830}
831
832static void boe_panel_shutdown(struct mipi_dsi_device *dsi)
833{
834	struct boe_panel *boe = mipi_dsi_get_drvdata(dsi);
835
836	drm_panel_disable(&boe->base);
837	drm_panel_unprepare(&boe->base);
838}
839
840static int boe_panel_remove(struct mipi_dsi_device *dsi)
841{
842	struct boe_panel *boe = mipi_dsi_get_drvdata(dsi);
843	int ret;
844
845	boe_panel_shutdown(dsi);
846
847	ret = mipi_dsi_detach(dsi);
848	if (ret < 0)
849		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
850
851	if (boe->base.dev)
852		drm_panel_remove(&boe->base);
853
854	return 0;
855}
856
857static const struct of_device_id boe_of_match[] = {
858	{ .compatible = "boe,tv101wum-nl6",
859	  .data = &boe_tv101wum_nl6_desc
860	},
861	{ .compatible = "auo,kd101n80-45na",
862	  .data = &auo_kd101n80_45na_desc
863	},
864	{ .compatible = "boe,tv101wum-n53",
865	  .data = &boe_tv101wum_n53_desc
866	},
867	{ .compatible = "auo,b101uan08.3",
868	  .data = &auo_b101uan08_3_desc
869	},
870	{ .compatible = "boe,tv105wum-nw0",
871	  .data = &boe_tv105wum_nw0_desc
872	},
873	{ /* sentinel */ }
874};
875MODULE_DEVICE_TABLE(of, boe_of_match);
876
877static struct mipi_dsi_driver boe_panel_driver = {
878	.driver = {
879		.name = "panel-boe-tv101wum-nl6",
880		.of_match_table = boe_of_match,
881	},
882	.probe = boe_panel_probe,
883	.remove = boe_panel_remove,
884	.shutdown = boe_panel_shutdown,
885};
886module_mipi_dsi_driver(boe_panel_driver);
887
888MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
889MODULE_DESCRIPTION("BOE tv101wum-nl6 1200x1920 video mode panel driver");
890MODULE_LICENSE("GPL v2");