File Index
Files and directories
Sign in
FILE

panel-novatek-nt35560.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/panel/panel-novatek-nt35560.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * MIPI-DSI Novatek NT35560-based panel controller.
  4 *
  5 * Supported panels include:
  6 * Sony ACX424AKM - a 480x854 AMOLED DSI panel
  7 * Sony ACX424AKP - a 480x864 AMOLED DSI panel
  8 *
  9 * Copyright (C) Linaro Ltd. 2019-2021
 10 * Author: Linus Walleij
 11 * Based on code and know-how from Marcus Lorentzon
 12 * Copyright (C) ST-Ericsson SA 2010
 13 * Based on code and know-how from Johan Olson and Joakim Wesslen
 14 * Copyright (C) Sony Ericsson Mobile Communications 2010
 15 */
 16#include <linux/backlight.h>
 17#include <linux/delay.h>
 18#include <linux/gpio/consumer.h>
 19#include <linux/module.h>
 20#include <linux/of.h>
 21#include <linux/regulator/consumer.h>
 22
 23#include <video/mipi_display.h>
 24
 25#include <drm/drm_mipi_dsi.h>
 26#include <drm/drm_modes.h>
 27#include <drm/drm_panel.h>
 28
 29#define NT35560_DCS_READ_ID1		0xDA
 30#define NT35560_DCS_READ_ID2		0xDB
 31#define NT35560_DCS_READ_ID3		0xDC
 32#define NT35560_DCS_SET_MDDI		0xAE
 33
 34/*
 35 * Sony seems to use vendor ID 0x81
 36 */
 37#define DISPLAY_SONY_ACX424AKP_ID1	0x8103
 38#define DISPLAY_SONY_ACX424AKP_ID2	0x811a
 39#define DISPLAY_SONY_ACX424AKP_ID3	0x811b
 40/*
 41 * The fourth ID looks like a bug, vendor IDs begin at 0x80
 42 * and panel 00 ... seems like default values.
 43 */
 44#define DISPLAY_SONY_ACX424AKP_ID4	0x8000
 45
 46struct nt35560_config {
 47	const struct drm_display_mode *vid_mode;
 48	const struct drm_display_mode *cmd_mode;
 49};
 50
 51struct nt35560 {
 52	const struct nt35560_config *conf;
 53	struct drm_panel panel;
 54	struct device *dev;
 55	struct regulator *supply;
 56	struct gpio_desc *reset_gpio;
 57	bool video_mode;
 58};
 59
 60static const struct drm_display_mode sony_acx424akp_vid_mode = {
 61	.clock = 27234,
 62	.hdisplay = 480,
 63	.hsync_start = 480 + 15,
 64	.hsync_end = 480 + 15 + 0,
 65	.htotal = 480 + 15 + 0 + 15,
 66	.vdisplay = 864,
 67	.vsync_start = 864 + 14,
 68	.vsync_end = 864 + 14 + 1,
 69	.vtotal = 864 + 14 + 1 + 11,
 70	.width_mm = 48,
 71	.height_mm = 84,
 72	.flags = DRM_MODE_FLAG_PVSYNC,
 73};
 74
 75/*
 76 * The timings are not very helpful as the display is used in
 77 * command mode using the maximum HS frequency.
 78 */
 79static const struct drm_display_mode sony_acx424akp_cmd_mode = {
 80	.clock = 35478,
 81	.hdisplay = 480,
 82	.hsync_start = 480 + 154,
 83	.hsync_end = 480 + 154 + 16,
 84	.htotal = 480 + 154 + 16 + 32,
 85	.vdisplay = 864,
 86	.vsync_start = 864 + 1,
 87	.vsync_end = 864 + 1 + 1,
 88	.vtotal = 864 + 1 + 1 + 1,
 89	/*
 90	 * Some desired refresh rate, experiments at the maximum "pixel"
 91	 * clock speed (HS clock 420 MHz) yields around 117Hz.
 92	 */
 93	.width_mm = 48,
 94	.height_mm = 84,
 95};
 96
 97static const struct nt35560_config sony_acx424akp_data = {
 98	.vid_mode = &sony_acx424akp_vid_mode,
 99	.cmd_mode = &sony_acx424akp_cmd_mode,
100};
101
102static const struct drm_display_mode sony_acx424akm_vid_mode = {
103	.clock = 27234,
104	.hdisplay = 480,
105	.hsync_start = 480 + 15,
106	.hsync_end = 480 + 15 + 0,
107	.htotal = 480 + 15 + 0 + 15,
108	.vdisplay = 854,
109	.vsync_start = 854 + 14,
110	.vsync_end = 854 + 14 + 1,
111	.vtotal = 854 + 14 + 1 + 11,
112	.width_mm = 46,
113	.height_mm = 82,
114	.flags = DRM_MODE_FLAG_PVSYNC,
115};
116
117/*
118 * The timings are not very helpful as the display is used in
119 * command mode using the maximum HS frequency.
120 */
121static const struct drm_display_mode sony_acx424akm_cmd_mode = {
122	.clock = 35478,
123	.hdisplay = 480,
124	.hsync_start = 480 + 154,
125	.hsync_end = 480 + 154 + 16,
126	.htotal = 480 + 154 + 16 + 32,
127	.vdisplay = 854,
128	.vsync_start = 854 + 1,
129	.vsync_end = 854 + 1 + 1,
130	.vtotal = 854 + 1 + 1 + 1,
131	.width_mm = 46,
132	.height_mm = 82,
133};
134
135static const struct nt35560_config sony_acx424akm_data = {
136	.vid_mode = &sony_acx424akm_vid_mode,
137	.cmd_mode = &sony_acx424akm_cmd_mode,
138};
139
140static inline struct nt35560 *panel_to_nt35560(struct drm_panel *panel)
141{
142	return container_of(panel, struct nt35560, panel);
143}
144
145#define FOSC			20 /* 20Mhz */
146#define SCALE_FACTOR_NS_DIV_MHZ	1000
147
148static int nt35560_set_brightness(struct backlight_device *bl)
149{
150	struct nt35560 *nt = bl_get_data(bl);
151	struct mipi_dsi_multi_context dsi_ctx = {
152		.dsi = to_mipi_dsi_device(nt->dev)
153	};
154	int duty_ns = bl->props.brightness;
155	int period_ns = 1023;
156	u8 pwm_ratio;
157	u8 pwm_div;
158
159	if (backlight_is_blank(bl)) {
160		/* Disable backlight */
161		mipi_dsi_dcs_write_seq_multi(&dsi_ctx,
162					     MIPI_DCS_WRITE_CONTROL_DISPLAY,
163					     0x00);
164		return dsi_ctx.accum_err;
165	}
166
167	/* Calculate the PWM duty cycle in n/256's */
168	pwm_ratio = max(((duty_ns * 256) / period_ns) - 1, 1);
169	pwm_div = max(1,
170		      ((FOSC * period_ns) / 256) /
171		      SCALE_FACTOR_NS_DIV_MHZ);
172
173	/* Set up PWM dutycycle ONE byte (differs from the standard) */
174	dev_dbg(nt->dev, "calculated duty cycle %02x\n", pwm_ratio);
175
176	/*
177	 * Sequence to write PWMDIV:
178	 *	address		data
179	 *	0xF3		0xAA   CMD2 Unlock
180	 *	0x00		0x01   Enter CMD2 page 0
181	 *	0X7D		0x01   No reload MTP of CMD2 P1
182	 *	0x22		PWMDIV
183	 *	0x7F		0xAA   CMD2 page 1 lock
184	 */
185	mipi_dsi_dcs_write_var_seq_multi(&dsi_ctx,
186					 MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
187					 pwm_ratio);
188
189	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, 0xaa);
190	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x01);
191	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7d, 0x01);
192
193	mipi_dsi_dcs_write_var_seq_multi(&dsi_ctx, 0x22, pwm_div);
194
195	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7f, 0xaa);
196
197	/* Enable backlight */
198	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY,
199				     0x24);
200
201	return dsi_ctx.accum_err;
202}
203
204static const struct backlight_ops nt35560_bl_ops = {
205	.update_status = nt35560_set_brightness,
206};
207
208static const struct backlight_properties nt35560_bl_props = {
209	.type = BACKLIGHT_RAW,
210	.brightness = 512,
211	.max_brightness = 1023,
212};
213
214static void nt35560_read_id(struct mipi_dsi_multi_context *dsi_ctx)
215{
216	struct device *dev = &dsi_ctx->dsi->dev;
217	u8 vendor, version, panel;
218	u16 val;
219
220	mipi_dsi_dcs_read_multi(dsi_ctx, NT35560_DCS_READ_ID1, &vendor, 1);
221	mipi_dsi_dcs_read_multi(dsi_ctx, NT35560_DCS_READ_ID2, &version, 1);
222	mipi_dsi_dcs_read_multi(dsi_ctx, NT35560_DCS_READ_ID3, &panel, 1);
223
224	if (dsi_ctx->accum_err < 0)
225		return;
226
227	if (vendor == 0x00) {
228		dev_err(dev, "device vendor ID is zero\n");
229		dsi_ctx->accum_err = -ENODEV;
230		return;
231	}
232
233	val = (vendor << 8) | panel;
234	switch (val) {
235	case DISPLAY_SONY_ACX424AKP_ID1:
236	case DISPLAY_SONY_ACX424AKP_ID2:
237	case DISPLAY_SONY_ACX424AKP_ID3:
238	case DISPLAY_SONY_ACX424AKP_ID4:
239		dev_info(dev,
240			 "MTP vendor: %02x, version: %02x, panel: %02x\n",
241			 vendor, version, panel);
242		break;
243	default:
244		dev_info(dev,
245			 "unknown vendor: %02x, version: %02x, panel: %02x\n",
246			 vendor, version, panel);
247		break;
248	}
249}
250
251static int nt35560_power_on(struct nt35560 *nt)
252{
253	int ret;
254
255	ret = regulator_enable(nt->supply);
256	if (ret) {
257		dev_err(nt->dev, "failed to enable supply (%d)\n", ret);
258		return ret;
259	}
260
261	/* Assert RESET */
262	gpiod_set_value_cansleep(nt->reset_gpio, 1);
263	udelay(20);
264	/* De-assert RESET */
265	gpiod_set_value_cansleep(nt->reset_gpio, 0);
266	usleep_range(11000, 20000);
267
268	return 0;
269}
270
271static void nt35560_power_off(struct nt35560 *nt)
272{
273	/* Assert RESET */
274	gpiod_set_value_cansleep(nt->reset_gpio, 1);
275	usleep_range(11000, 20000);
276
277	regulator_disable(nt->supply);
278}
279
280static int nt35560_prepare(struct drm_panel *panel)
281{
282	struct nt35560 *nt = panel_to_nt35560(panel);
283	struct mipi_dsi_multi_context dsi_ctx = {
284		.dsi = to_mipi_dsi_device(nt->dev)
285	};
286	int ret;
287
288	ret = nt35560_power_on(nt);
289	if (ret)
290		return ret;
291
292	nt35560_read_id(&dsi_ctx);
293
294	/* Enable tearing mode: send TE (tearing effect) at VBLANK */
295	mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx,
296				       MIPI_DSI_DCS_TEAR_MODE_VBLANK);
297
298	/*
299	 * Set MDDI
300	 *
301	 * This presumably deactivates the Qualcomm MDDI interface and
302	 * selects DSI, similar code is found in other drivers such as the
303	 * Sharp LS043T1LE01.
304	 */
305	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, NT35560_DCS_SET_MDDI, 3);
306
307	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
308	mipi_dsi_msleep(&dsi_ctx, 140);
309
310	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
311	if (nt->video_mode) {
312		mipi_dsi_turn_on_peripheral_multi(&dsi_ctx);
313	}
314
315	if (dsi_ctx.accum_err < 0)
316		nt35560_power_off(nt);
317	return dsi_ctx.accum_err;
318}
319
320static int nt35560_unprepare(struct drm_panel *panel)
321{
322	struct nt35560 *nt = panel_to_nt35560(panel);
323	struct mipi_dsi_multi_context dsi_ctx = {
324		.dsi = to_mipi_dsi_device(nt->dev)
325	};
326
327	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
328	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
329
330	if (dsi_ctx.accum_err < 0)
331		return dsi_ctx.accum_err;
332
333	msleep(85);
334
335	nt35560_power_off(nt);
336
337	return 0;
338}
339
340
341static int nt35560_get_modes(struct drm_panel *panel,
342			     struct drm_connector *connector)
343{
344	struct nt35560 *nt = panel_to_nt35560(panel);
345	const struct nt35560_config *conf = nt->conf;
346	struct drm_display_mode *mode;
347
348	if (nt->video_mode)
349		mode = drm_mode_duplicate(connector->dev,
350					  conf->vid_mode);
351	else
352		mode = drm_mode_duplicate(connector->dev,
353					  conf->cmd_mode);
354	if (!mode) {
355		dev_err(panel->dev, "bad mode or failed to add mode\n");
356		return -EINVAL;
357	}
358	drm_mode_set_name(mode);
359	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
360
361	connector->display_info.width_mm = mode->width_mm;
362	connector->display_info.height_mm = mode->height_mm;
363
364	drm_mode_probed_add(connector, mode);
365
366	return 1; /* Number of modes */
367}
368
369static const struct drm_panel_funcs nt35560_drm_funcs = {
370	.unprepare = nt35560_unprepare,
371	.prepare = nt35560_prepare,
372	.get_modes = nt35560_get_modes,
373};
374
375static int nt35560_probe(struct mipi_dsi_device *dsi)
376{
377	struct device *dev = &dsi->dev;
378	struct nt35560 *nt;
379	int ret;
380
381	nt = devm_drm_panel_alloc(dev, struct nt35560, panel,
382				  &nt35560_drm_funcs,
383				  DRM_MODE_CONNECTOR_DSI);
384	if (IS_ERR(nt))
385		return PTR_ERR(nt);
386
387	nt->video_mode = of_property_read_bool(dev->of_node,
388						"enforce-video-mode");
389
390	mipi_dsi_set_drvdata(dsi, nt);
391	nt->dev = dev;
392
393	nt->conf = of_device_get_match_data(dev);
394	if (!nt->conf) {
395		dev_err(dev, "missing device configuration\n");
396		return -ENODEV;
397	}
398
399	dsi->lanes = 2;
400	dsi->format = MIPI_DSI_FMT_RGB888;
401	/*
402	 * FIXME: these come from the ST-Ericsson vendor driver for the
403	 * HREF520 and seems to reflect limitations in the PLLs on that
404	 * platform, if you have the datasheet, please cross-check the
405	 * actual max rates.
406	 */
407	dsi->lp_rate = 19200000;
408	dsi->hs_rate = 420160000;
409
410	if (nt->video_mode)
411		/* Burst mode using event for sync */
412		dsi->mode_flags =
413			MIPI_DSI_MODE_VIDEO |
414			MIPI_DSI_MODE_VIDEO_BURST;
415	else
416		dsi->mode_flags =
417			MIPI_DSI_CLOCK_NON_CONTINUOUS;
418
419	nt->supply = devm_regulator_get(dev, "vddi");
420	if (IS_ERR(nt->supply))
421		return PTR_ERR(nt->supply);
422
423	/* This asserts RESET by default */
424	nt->reset_gpio = devm_gpiod_get_optional(dev, "reset",
425						 GPIOD_OUT_HIGH);
426	if (IS_ERR(nt->reset_gpio))
427		return dev_err_probe(dev, PTR_ERR(nt->reset_gpio),
428				     "failed to request GPIO\n");
429
430	nt->panel.backlight = devm_backlight_device_register(dev, "nt35560", dev, nt,
431					&nt35560_bl_ops, &nt35560_bl_props);
432	if (IS_ERR(nt->panel.backlight))
433		return dev_err_probe(dev, PTR_ERR(nt->panel.backlight),
434				     "failed to register backlight device\n");
435
436	drm_panel_add(&nt->panel);
437
438	ret = mipi_dsi_attach(dsi);
439	if (ret < 0) {
440		drm_panel_remove(&nt->panel);
441		return ret;
442	}
443
444	return 0;
445}
446
447static void nt35560_remove(struct mipi_dsi_device *dsi)
448{
449	struct nt35560 *nt = mipi_dsi_get_drvdata(dsi);
450
451	mipi_dsi_detach(dsi);
452	drm_panel_remove(&nt->panel);
453}
454
455static const struct of_device_id nt35560_of_match[] = {
456	{
457		.compatible = "sony,acx424akp",
458		.data = &sony_acx424akp_data,
459	},
460	{
461		.compatible = "sony,acx424akm",
462		.data = &sony_acx424akm_data,
463	},
464	{ /* sentinel */ }
465};
466MODULE_DEVICE_TABLE(of, nt35560_of_match);
467
468static struct mipi_dsi_driver nt35560_driver = {
469	.probe = nt35560_probe,
470	.remove = nt35560_remove,
471	.driver = {
472		.name = "panel-novatek-nt35560",
473		.of_match_table = nt35560_of_match,
474	},
475};
476module_mipi_dsi_driver(nt35560_driver);
477
478MODULE_AUTHOR("Linus Wallei <linus.walleij@linaro.org>");
479MODULE_DESCRIPTION("MIPI-DSI Novatek NT35560 Panel Driver");
480MODULE_LICENSE("GPL v2");
~/ Read-only file preview.