brintos

brintos / linux-shallow public Read only

0
0
Text · 13.5 KiB · 5bbea73 Raw
559 lines · 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 panel7 * Sony ACX424AKP - a 480x864 AMOLED DSI panel8 *9 * Copyright (C) Linaro Ltd. 2019-202110 * Author: Linus Walleij11 * Based on code and know-how from Marcus Lorentzon12 * Copyright (C) ST-Ericsson SA 201013 * Based on code and know-how from Johan Olson and Joakim Wesslen14 * Copyright (C) Sony Ericsson Mobile Communications 201015 */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		0xDA30#define NT35560_DCS_READ_ID2		0xDB31#define NT35560_DCS_READ_ID3		0xDC32#define NT35560_DCS_SET_MDDI		0xAE33 34/*35 * Sony seems to use vendor ID 0x8136 */37#define DISPLAY_SONY_ACX424AKP_ID1	0x810338#define DISPLAY_SONY_ACX424AKP_ID2	0x811a39#define DISPLAY_SONY_ACX424AKP_ID3	0x811b40/*41 * The fourth ID looks like a bug, vendor IDs begin at 0x8042 * and panel 00 ... seems like default values.43 */44#define DISPLAY_SONY_ACX424AKP_ID4	0x800045 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 in77 * 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 in119 * 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	1000147 148static int nt35560_set_brightness(struct backlight_device *bl)149{150	struct nt35560 *nt = bl_get_data(bl);151	struct mipi_dsi_device *dsi = to_mipi_dsi_device(nt->dev);152	int period_ns = 1023;153	int duty_ns = bl->props.brightness;154	u8 pwm_ratio;155	u8 pwm_div;156	u8 par;157	int ret;158 159	if (backlight_is_blank(bl)) {160		/* Disable backlight */161		par = 0x00;162		ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY,163					 &par, 1);164		if (ret) {165			dev_err(nt->dev, "failed to disable display backlight (%d)\n", ret);166			return ret;167		}168		return 0;169	}170 171	/* Calculate the PWM duty cycle in n/256's */172	pwm_ratio = max(((duty_ns * 256) / period_ns) - 1, 1);173	pwm_div = max(1,174		      ((FOSC * period_ns) / 256) /175		      SCALE_FACTOR_NS_DIV_MHZ);176 177	/* Set up PWM dutycycle ONE byte (differs from the standard) */178	dev_dbg(nt->dev, "calculated duty cycle %02x\n", pwm_ratio);179	ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,180				 &pwm_ratio, 1);181	if (ret < 0) {182		dev_err(nt->dev, "failed to set display PWM ratio (%d)\n", ret);183		return ret;184	}185 186	/*187	 * Sequence to write PWMDIV:188	 *	address		data189	 *	0xF3		0xAA   CMD2 Unlock190	 *	0x00		0x01   Enter CMD2 page 0191	 *	0X7D		0x01   No reload MTP of CMD2 P1192	 *	0x22		PWMDIV193	 *	0x7F		0xAA   CMD2 page 1 lock194	 */195	par = 0xaa;196	ret = mipi_dsi_dcs_write(dsi, 0xf3, &par, 1);197	if (ret < 0) {198		dev_err(nt->dev, "failed to unlock CMD 2 (%d)\n", ret);199		return ret;200	}201	par = 0x01;202	ret = mipi_dsi_dcs_write(dsi, 0x00, &par, 1);203	if (ret < 0) {204		dev_err(nt->dev, "failed to enter page 1 (%d)\n", ret);205		return ret;206	}207	par = 0x01;208	ret = mipi_dsi_dcs_write(dsi, 0x7d, &par, 1);209	if (ret < 0) {210		dev_err(nt->dev, "failed to disable MTP reload (%d)\n", ret);211		return ret;212	}213	ret = mipi_dsi_dcs_write(dsi, 0x22, &pwm_div, 1);214	if (ret < 0) {215		dev_err(nt->dev, "failed to set PWM divisor (%d)\n", ret);216		return ret;217	}218	par = 0xaa;219	ret = mipi_dsi_dcs_write(dsi, 0x7f, &par, 1);220	if (ret < 0) {221		dev_err(nt->dev, "failed to lock CMD 2 (%d)\n", ret);222		return ret;223	}224 225	/* Enable backlight */226	par = 0x24;227	ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY,228				 &par, 1);229	if (ret < 0) {230		dev_err(nt->dev, "failed to enable display backlight (%d)\n", ret);231		return ret;232	}233 234	return 0;235}236 237static const struct backlight_ops nt35560_bl_ops = {238	.update_status = nt35560_set_brightness,239};240 241static const struct backlight_properties nt35560_bl_props = {242	.type = BACKLIGHT_RAW,243	.brightness = 512,244	.max_brightness = 1023,245};246 247static int nt35560_read_id(struct nt35560 *nt)248{249	struct mipi_dsi_device *dsi = to_mipi_dsi_device(nt->dev);250	u8 vendor, version, panel;251	u16 val;252	int ret;253 254	ret = mipi_dsi_dcs_read(dsi, NT35560_DCS_READ_ID1, &vendor, 1);255	if (ret < 0) {256		dev_err(nt->dev, "could not vendor ID byte\n");257		return ret;258	}259	ret = mipi_dsi_dcs_read(dsi, NT35560_DCS_READ_ID2, &version, 1);260	if (ret < 0) {261		dev_err(nt->dev, "could not read device version byte\n");262		return ret;263	}264	ret = mipi_dsi_dcs_read(dsi, NT35560_DCS_READ_ID3, &panel, 1);265	if (ret < 0) {266		dev_err(nt->dev, "could not read panel ID byte\n");267		return ret;268	}269 270	if (vendor == 0x00) {271		dev_err(nt->dev, "device vendor ID is zero\n");272		return -ENODEV;273	}274 275	val = (vendor << 8) | panel;276	switch (val) {277	case DISPLAY_SONY_ACX424AKP_ID1:278	case DISPLAY_SONY_ACX424AKP_ID2:279	case DISPLAY_SONY_ACX424AKP_ID3:280	case DISPLAY_SONY_ACX424AKP_ID4:281		dev_info(nt->dev, "MTP vendor: %02x, version: %02x, panel: %02x\n",282			 vendor, version, panel);283		break;284	default:285		dev_info(nt->dev, "unknown vendor: %02x, version: %02x, panel: %02x\n",286			 vendor, version, panel);287		break;288	}289 290	return 0;291}292 293static int nt35560_power_on(struct nt35560 *nt)294{295	int ret;296 297	ret = regulator_enable(nt->supply);298	if (ret) {299		dev_err(nt->dev, "failed to enable supply (%d)\n", ret);300		return ret;301	}302 303	/* Assert RESET */304	gpiod_set_value_cansleep(nt->reset_gpio, 1);305	udelay(20);306	/* De-assert RESET */307	gpiod_set_value_cansleep(nt->reset_gpio, 0);308	usleep_range(11000, 20000);309 310	return 0;311}312 313static void nt35560_power_off(struct nt35560 *nt)314{315	/* Assert RESET */316	gpiod_set_value_cansleep(nt->reset_gpio, 1);317	usleep_range(11000, 20000);318 319	regulator_disable(nt->supply);320}321 322static int nt35560_prepare(struct drm_panel *panel)323{324	struct nt35560 *nt = panel_to_nt35560(panel);325	struct mipi_dsi_device *dsi = to_mipi_dsi_device(nt->dev);326	const u8 mddi = 3;327	int ret;328 329	ret = nt35560_power_on(nt);330	if (ret)331		return ret;332 333	ret = nt35560_read_id(nt);334	if (ret) {335		dev_err(nt->dev, "failed to read panel ID (%d)\n", ret);336		goto err_power_off;337	}338 339	/* Enabe tearing mode: send TE (tearing effect) at VBLANK */340	ret = mipi_dsi_dcs_set_tear_on(dsi,341				       MIPI_DSI_DCS_TEAR_MODE_VBLANK);342	if (ret) {343		dev_err(nt->dev, "failed to enable vblank TE (%d)\n", ret);344		goto err_power_off;345	}346 347	/*348	 * Set MDDI349	 *350	 * This presumably deactivates the Qualcomm MDDI interface and351	 * selects DSI, similar code is found in other drivers such as the352	 * Sharp LS043T1LE01 which makes us suspect that this panel may be353	 * using a Novatek NT35565 or similar display driver chip that shares354	 * this command. Due to the lack of documentation we cannot know for355	 * sure.356	 */357	ret = mipi_dsi_dcs_write(dsi, NT35560_DCS_SET_MDDI,358				 &mddi, sizeof(mddi));359	if (ret < 0) {360		dev_err(nt->dev, "failed to set MDDI (%d)\n", ret);361		goto err_power_off;362	}363 364	/* Exit sleep mode */365	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);366	if (ret) {367		dev_err(nt->dev, "failed to exit sleep mode (%d)\n", ret);368		goto err_power_off;369	}370	msleep(140);371 372	ret = mipi_dsi_dcs_set_display_on(dsi);373	if (ret) {374		dev_err(nt->dev, "failed to turn display on (%d)\n", ret);375		goto err_power_off;376	}377	if (nt->video_mode) {378		/* In video mode turn peripheral on */379		ret = mipi_dsi_turn_on_peripheral(dsi);380		if (ret) {381			dev_err(nt->dev, "failed to turn on peripheral\n");382			goto err_power_off;383		}384	}385 386	return 0;387 388err_power_off:389	nt35560_power_off(nt);390	return ret;391}392 393static int nt35560_unprepare(struct drm_panel *panel)394{395	struct nt35560 *nt = panel_to_nt35560(panel);396	struct mipi_dsi_device *dsi = to_mipi_dsi_device(nt->dev);397	int ret;398 399	ret = mipi_dsi_dcs_set_display_off(dsi);400	if (ret) {401		dev_err(nt->dev, "failed to turn display off (%d)\n", ret);402		return ret;403	}404 405	/* Enter sleep mode */406	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);407	if (ret) {408		dev_err(nt->dev, "failed to enter sleep mode (%d)\n", ret);409		return ret;410	}411	msleep(85);412 413	nt35560_power_off(nt);414 415	return 0;416}417 418 419static int nt35560_get_modes(struct drm_panel *panel,420			     struct drm_connector *connector)421{422	struct nt35560 *nt = panel_to_nt35560(panel);423	const struct nt35560_config *conf = nt->conf;424	struct drm_display_mode *mode;425 426	if (nt->video_mode)427		mode = drm_mode_duplicate(connector->dev,428					  conf->vid_mode);429	else430		mode = drm_mode_duplicate(connector->dev,431					  conf->cmd_mode);432	if (!mode) {433		dev_err(panel->dev, "bad mode or failed to add mode\n");434		return -EINVAL;435	}436	drm_mode_set_name(mode);437	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;438 439	connector->display_info.width_mm = mode->width_mm;440	connector->display_info.height_mm = mode->height_mm;441 442	drm_mode_probed_add(connector, mode);443 444	return 1; /* Number of modes */445}446 447static const struct drm_panel_funcs nt35560_drm_funcs = {448	.unprepare = nt35560_unprepare,449	.prepare = nt35560_prepare,450	.get_modes = nt35560_get_modes,451};452 453static int nt35560_probe(struct mipi_dsi_device *dsi)454{455	struct device *dev = &dsi->dev;456	struct nt35560 *nt;457	int ret;458 459	nt = devm_kzalloc(dev, sizeof(struct nt35560), GFP_KERNEL);460	if (!nt)461		return -ENOMEM;462	nt->video_mode = of_property_read_bool(dev->of_node,463						"enforce-video-mode");464 465	mipi_dsi_set_drvdata(dsi, nt);466	nt->dev = dev;467 468	nt->conf = of_device_get_match_data(dev);469	if (!nt->conf) {470		dev_err(dev, "missing device configuration\n");471		return -ENODEV;472	}473 474	dsi->lanes = 2;475	dsi->format = MIPI_DSI_FMT_RGB888;476	/*477	 * FIXME: these come from the ST-Ericsson vendor driver for the478	 * HREF520 and seems to reflect limitations in the PLLs on that479	 * platform, if you have the datasheet, please cross-check the480	 * actual max rates.481	 */482	dsi->lp_rate = 19200000;483	dsi->hs_rate = 420160000;484 485	if (nt->video_mode)486		/* Burst mode using event for sync */487		dsi->mode_flags =488			MIPI_DSI_MODE_VIDEO |489			MIPI_DSI_MODE_VIDEO_BURST;490	else491		dsi->mode_flags =492			MIPI_DSI_CLOCK_NON_CONTINUOUS;493 494	nt->supply = devm_regulator_get(dev, "vddi");495	if (IS_ERR(nt->supply))496		return PTR_ERR(nt->supply);497 498	/* This asserts RESET by default */499	nt->reset_gpio = devm_gpiod_get_optional(dev, "reset",500						 GPIOD_OUT_HIGH);501	if (IS_ERR(nt->reset_gpio))502		return dev_err_probe(dev, PTR_ERR(nt->reset_gpio),503				     "failed to request GPIO\n");504 505	drm_panel_init(&nt->panel, dev, &nt35560_drm_funcs,506		       DRM_MODE_CONNECTOR_DSI);507 508	nt->panel.backlight = devm_backlight_device_register(dev, "nt35560", dev, nt,509					&nt35560_bl_ops, &nt35560_bl_props);510	if (IS_ERR(nt->panel.backlight))511		return dev_err_probe(dev, PTR_ERR(nt->panel.backlight),512				     "failed to register backlight device\n");513 514	drm_panel_add(&nt->panel);515 516	ret = mipi_dsi_attach(dsi);517	if (ret < 0) {518		drm_panel_remove(&nt->panel);519		return ret;520	}521 522	return 0;523}524 525static void nt35560_remove(struct mipi_dsi_device *dsi)526{527	struct nt35560 *nt = mipi_dsi_get_drvdata(dsi);528 529	mipi_dsi_detach(dsi);530	drm_panel_remove(&nt->panel);531}532 533static const struct of_device_id nt35560_of_match[] = {534	{535		.compatible = "sony,acx424akp",536		.data = &sony_acx424akp_data,537	},538	{539		.compatible = "sony,acx424akm",540		.data = &sony_acx424akm_data,541	},542	{ /* sentinel */ }543};544MODULE_DEVICE_TABLE(of, nt35560_of_match);545 546static struct mipi_dsi_driver nt35560_driver = {547	.probe = nt35560_probe,548	.remove = nt35560_remove,549	.driver = {550		.name = "panel-novatek-nt35560",551		.of_match_table = nt35560_of_match,552	},553};554module_mipi_dsi_driver(nt35560_driver);555 556MODULE_AUTHOR("Linus Wallei <linus.walleij@linaro.org>");557MODULE_DESCRIPTION("MIPI-DSI Novatek NT35560 Panel Driver");558MODULE_LICENSE("GPL v2");559