Linux Audio

Check our new training course

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