diff options
Diffstat (limited to 'drivers/gpu/drm/panel')
45 files changed, 2959 insertions, 564 deletions
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index f152bc4eeb53..ae44ac2ec106 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -18,6 +18,17 @@ config DRM_PANEL_ARM_VERSATILE  	  reference designs. The panel is detected using special registers  	  in the Versatile family syscon registers. +config DRM_PANEL_BOE_HIMAX8279D +	tristate "Boe Himax8279d panel" +	depends on OF +	depends on DRM_MIPI_DSI +	depends on BACKLIGHT_CLASS_DEVICE +	help +	  Say Y here if you want to enable support for Boe Himax8279d +	  TFT-LCD modules. The panel has a 1200x1920 resolution and uses +	  24 bit RGB per pixel. It provides a MIPI DSI interface to +	  the host and has a built-in LED backlight. +  config DRM_PANEL_LVDS  	tristate "Generic LVDS panel driver"  	depends on OF @@ -98,6 +109,17 @@ config DRM_PANEL_KINGDISPLAY_KD097D04  	  24 bit RGB per pixel. It provides a MIPI DSI interface to  	  the host and has a built-in LED backlight. +config DRM_PANEL_LEADTEK_LTK500HD1829 +	tristate "Leadtek LTK500HD1829 panel" +	depends on OF +	depends on DRM_MIPI_DSI +	depends on BACKLIGHT_CLASS_DEVICE +	help +	  Say Y here if you want to enable support for Kingdisplay kd097d04 +	  TFT-LCD modules. The panel has a 1536x2048 resolution and uses +	  24 bit RGB per pixel. It provides a MIPI DSI interface to +	  the host and has a built-in LED backlight. +  config DRM_PANEL_SAMSUNG_LD9040  	tristate "Samsung LD9040 RGB/SPI panel"  	depends on OF && SPI @@ -316,6 +338,17 @@ config DRM_PANEL_SITRONIX_ST7789V  	  Say Y here if you want to enable support for the Sitronix  	  ST7789V controller for 240x320 LCD panels +config DRM_PANEL_SONY_ACX424AKP +	tristate "Sony ACX424AKP DSI command mode panel" +	depends on OF +	depends on DRM_MIPI_DSI +	depends on BACKLIGHT_CLASS_DEVICE +	select VIDEOMODE_HELPERS +	help +	  Say Y here if you want to enable the Sony ACX424 display +	  panel. This panel supports DSI in both command and video +	  mode. +  config DRM_PANEL_SONY_ACX565AKM  	tristate "Sony ACX565AKM panel"  	depends on GPIOLIB && OF && SPI @@ -355,4 +388,14 @@ config DRM_PANEL_TRULY_NT35597_WQXGA  	help  	  Say Y here if you want to enable support for Truly NT35597 WQXGA Dual DSI  	  Video Mode panel + +config DRM_PANEL_XINPENG_XPP055C272 +	tristate "Xinpeng XPP055C272 panel driver" +	depends on OF +	depends on DRM_MIPI_DSI +	depends on BACKLIGHT_CLASS_DEVICE +	help +	  Say Y here if you want to enable support for the Xinpeng +	  XPP055C272 controller for 720x1280 LCD panels with MIPI/RGB/SPI +	  system interfaces.  endmenu diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index b6cd39fe0f20..7c4d3c581fd4 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -1,5 +1,6 @@  # SPDX-License-Identifier: GPL-2.0  obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o +obj-$(CONFIG_DRM_PANEL_BOE_HIMAX8279D) += panel-boe-himax8279d.o  obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o  obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o  obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o @@ -8,6 +9,7 @@ obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o  obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o  obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o  obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o +obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o  obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o  obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o  obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o @@ -33,8 +35,10 @@ obj-$(CONFIG_DRM_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o  obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o  obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7701) += panel-sitronix-st7701.o  obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o +obj-$(CONFIG_DRM_PANEL_SONY_ACX424AKP) += panel-sony-acx424akp.o  obj-$(CONFIG_DRM_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o  obj-$(CONFIG_DRM_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o  obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o  obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o  obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o +obj-$(CONFIG_DRM_PANEL_XINPENG_XPP055C272) += panel-xinpeng-xpp055c272.o diff --git a/drivers/gpu/drm/panel/panel-arm-versatile.c b/drivers/gpu/drm/panel/panel-arm-versatile.c index a0574dc03e16..41444a73c980 100644 --- a/drivers/gpu/drm/panel/panel-arm-versatile.c +++ b/drivers/gpu/drm/panel/panel-arm-versatile.c @@ -260,9 +260,9 @@ static int versatile_panel_enable(struct drm_panel *panel)  	return 0;  } -static int versatile_panel_get_modes(struct drm_panel *panel) +static int versatile_panel_get_modes(struct drm_panel *panel, +				     struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct versatile_panel *vpanel = to_versatile_panel(panel);  	struct drm_display_mode *mode; @@ -270,7 +270,7 @@ static int versatile_panel_get_modes(struct drm_panel *panel)  	connector->display_info.height_mm = vpanel->panel_type->height_mm;  	connector->display_info.bus_flags = vpanel->panel_type->bus_flags; -	mode = drm_mode_duplicate(panel->drm, &vpanel->panel_type->mode); +	mode = drm_mode_duplicate(connector->dev, &vpanel->panel_type->mode);  	drm_mode_set_name(mode);  	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; diff --git a/drivers/gpu/drm/panel/panel-boe-himax8279d.c b/drivers/gpu/drm/panel/panel-boe-himax8279d.c new file mode 100644 index 000000000000..74d58ee7d04c --- /dev/null +++ b/drivers/gpu/drm/panel/panel-boe-himax8279d.c @@ -0,0 +1,978 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019, Huaqin Telecom Technology Co., Ltd + * + * Author: Jerry Han <[email protected]> + * + */ + +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> + +#include <linux/gpio/consumer.h> +#include <linux/regulator/consumer.h> + +#include <drm/drm_device.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> +#include <drm/drm_print.h> + +#include <video/mipi_display.h> + +struct panel_cmd { +	char cmd; +	char data; +}; + +struct panel_desc { +	const struct drm_display_mode *display_mode; +	unsigned int bpc; +	unsigned int width_mm; +	unsigned int height_mm; + +	unsigned long mode_flags; +	enum mipi_dsi_pixel_format format; +	unsigned int lanes; +	const struct panel_cmd *on_cmds; +	unsigned int on_cmds_num; +}; + +struct panel_info { +	struct drm_panel base; +	struct mipi_dsi_device *link; +	const struct panel_desc *desc; + +	struct gpio_desc *enable_gpio; +	struct gpio_desc *pp33_gpio; +	struct gpio_desc *pp18_gpio; + +	bool prepared; +	bool enabled; +}; + +static inline struct panel_info *to_panel_info(struct drm_panel *panel) +{ +	return container_of(panel, struct panel_info, base); +} + +static void disable_gpios(struct panel_info *pinfo) +{ +	gpiod_set_value(pinfo->enable_gpio, 0); +	gpiod_set_value(pinfo->pp33_gpio, 0); +	gpiod_set_value(pinfo->pp18_gpio, 0); +} + +static int send_mipi_cmds(struct drm_panel *panel, const struct panel_cmd *cmds) +{ +	struct panel_info *pinfo = to_panel_info(panel); +	unsigned int i = 0; +	int err; + +	for (i = 0; i < pinfo->desc->on_cmds_num; i++) { +		err = mipi_dsi_dcs_write_buffer(pinfo->link, &cmds[i], +						sizeof(struct panel_cmd)); + +		if (err < 0) +			return err; +	} + +	return 0; +} + +static int boe_panel_disable(struct drm_panel *panel) +{ +	struct panel_info *pinfo = to_panel_info(panel); +	int err; + +	if (!pinfo->enabled) +		return 0; + +	err = mipi_dsi_dcs_set_display_off(pinfo->link); +	if (err < 0) { +		DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", +			      err); +		return err; +	} + +	pinfo->enabled = false; + +	return 0; +} + +static int boe_panel_unprepare(struct drm_panel *panel) +{ +	struct panel_info *pinfo = to_panel_info(panel); +	int err; + +	if (!pinfo->prepared) +		return 0; + +	err = mipi_dsi_dcs_set_display_off(pinfo->link); +	if (err < 0) +		DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", +			      err); + +	err = mipi_dsi_dcs_enter_sleep_mode(pinfo->link); +	if (err < 0) +		DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", +			      err); + +	/* sleep_mode_delay: 1ms - 2ms */ +	usleep_range(1000, 2000); + +	disable_gpios(pinfo); + +	pinfo->prepared = false; + +	return 0; +} + +static int boe_panel_prepare(struct drm_panel *panel) +{ +	struct panel_info *pinfo = to_panel_info(panel); +	int err; + +	if (pinfo->prepared) +		return 0; + +	gpiod_set_value(pinfo->pp18_gpio, 1); +	/* T1: 5ms - 6ms */ +	usleep_range(5000, 6000); +	gpiod_set_value(pinfo->pp33_gpio, 1); + +	/* reset sequence */ +	/* T2: 14ms - 15ms */ +	usleep_range(14000, 15000); +	gpiod_set_value(pinfo->enable_gpio, 1); + +	/* T3: 1ms - 2ms */ +	usleep_range(1000, 2000); +	gpiod_set_value(pinfo->enable_gpio, 0); + +	/* T4: 1ms - 2ms */ +	usleep_range(1000, 2000); +	gpiod_set_value(pinfo->enable_gpio, 1); + +	/* T5: 5ms - 6ms */ +	usleep_range(5000, 6000); + +	/* send init code */ +	err = send_mipi_cmds(panel, pinfo->desc->on_cmds); +	if (err < 0) { +		DRM_DEV_ERROR(panel->dev, "failed to send DCS Init Code: %d\n", +			      err); +		goto poweroff; +	} + +	err = mipi_dsi_dcs_exit_sleep_mode(pinfo->link); +	if (err < 0) { +		DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n", +			      err); +		goto poweroff; +	} + +	/* T6: 120ms - 121ms */ +	usleep_range(120000, 121000); + +	err = mipi_dsi_dcs_set_display_on(pinfo->link); +	if (err < 0) { +		DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n", +			      err); +		goto poweroff; +	} + +	/* T7: 20ms - 21ms */ +	usleep_range(20000, 21000); + +	pinfo->prepared = true; + +	return 0; + +poweroff: +	disable_gpios(pinfo); +	return err; +} + +static int boe_panel_enable(struct drm_panel *panel) +{ +	struct panel_info *pinfo = to_panel_info(panel); +	int ret; + +	if (pinfo->enabled) +		return 0; + +	usleep_range(120000, 121000); + +	ret = mipi_dsi_dcs_set_display_on(pinfo->link); +	if (ret < 0) { +		DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n", +			      ret); +		return ret; +	} + +	pinfo->enabled = true; + +	return 0; +} + +static int boe_panel_get_modes(struct drm_panel *panel, +			       struct drm_connector *connector) +{ +	struct panel_info *pinfo = to_panel_info(panel); +	const struct drm_display_mode *m = pinfo->desc->display_mode; +	struct drm_display_mode *mode; + +	mode = drm_mode_duplicate(connector->dev, m); +	if (!mode) { +		DRM_DEV_ERROR(pinfo->base.dev, "failed to add mode %ux%u@%u\n", +			      m->hdisplay, m->vdisplay, m->vrefresh); +		return -ENOMEM; +	} + +	drm_mode_set_name(mode); + +	drm_mode_probed_add(connector, mode); + +	connector->display_info.width_mm = pinfo->desc->width_mm; +	connector->display_info.height_mm = pinfo->desc->height_mm; +	connector->display_info.bpc = pinfo->desc->bpc; + +	return 1; +} + +static const struct drm_panel_funcs panel_funcs = { +	.disable = boe_panel_disable, +	.unprepare = boe_panel_unprepare, +	.prepare = boe_panel_prepare, +	.enable = boe_panel_enable, +	.get_modes = boe_panel_get_modes, +}; + +static const struct drm_display_mode default_display_mode = { +	.clock = 159420, +	.hdisplay = 1200, +	.hsync_start = 1200 + 80, +	.hsync_end = 1200 + 80 + 60, +	.htotal = 1200 + 80 + 60 + 24, +	.vdisplay = 1920, +	.vsync_start = 1920 + 10, +	.vsync_end = 1920 + 10 + 14, +	.vtotal = 1920 + 10 + 14 + 4, +	.vrefresh = 60, +}; + +/* 8 inch */ +static const struct panel_cmd boe_himax8279d8p_on_cmds[] = { +	{ 0xB0, 0x05 }, +	{ 0xB1, 0xE5 }, +	{ 0xB3, 0x52 }, +	{ 0xC0, 0x00 }, +	{ 0xC2, 0x57 }, +	{ 0xD9, 0x85 }, +	{ 0xB0, 0x01 }, +	{ 0xC8, 0x00 }, +	{ 0xC9, 0x00 }, +	{ 0xCC, 0x26 }, +	{ 0xCD, 0x26 }, +	{ 0xDC, 0x00 }, +	{ 0xDD, 0x00 }, +	{ 0xE0, 0x26 }, +	{ 0xE1, 0x26 }, +	{ 0xB0, 0x03 }, +	{ 0xC3, 0x2A }, +	{ 0xE7, 0x2A }, +	{ 0xC5, 0x2A }, +	{ 0xDE, 0x2A }, +	{ 0xBC, 0x02 }, +	{ 0xCB, 0x02 }, +	{ 0xB0, 0x00 }, +	{ 0xB6, 0x03 }, +	{ 0xBA, 0x8B }, +	{ 0xBF, 0x15 }, +	{ 0xC0, 0x18 }, +	{ 0xC2, 0x14 }, +	{ 0xC3, 0x02 }, +	{ 0xC4, 0x14 }, +	{ 0xC5, 0x02 }, +	{ 0xCC, 0x0A }, +	{ 0xB0, 0x06 }, +	{ 0xC0, 0xA5 }, +	{ 0xD5, 0x20 }, +	{ 0xC0, 0x00 }, +	{ 0xB0, 0x02 }, +	{ 0xC0, 0x00 }, +	{ 0xC1, 0x02 }, +	{ 0xC2, 0x06 }, +	{ 0xC3, 0x16 }, +	{ 0xC4, 0x0E }, +	{ 0xC5, 0x18 }, +	{ 0xC6, 0x26 }, +	{ 0xC7, 0x32 }, +	{ 0xC8, 0x3F }, +	{ 0xC9, 0x3F }, +	{ 0xCA, 0x3F }, +	{ 0xCB, 0x3F }, +	{ 0xCC, 0x3D }, +	{ 0xCD, 0x2F }, +	{ 0xCE, 0x2F }, +	{ 0xCF, 0x2F }, +	{ 0xD0, 0x07 }, +	{ 0xD2, 0x00 }, +	{ 0xD3, 0x02 }, +	{ 0xD4, 0x06 }, +	{ 0xD5, 0x12 }, +	{ 0xD6, 0x0A }, +	{ 0xD7, 0x14 }, +	{ 0xD8, 0x22 }, +	{ 0xD9, 0x2E }, +	{ 0xDA, 0x3D }, +	{ 0xDB, 0x3F }, +	{ 0xDC, 0x3F }, +	{ 0xDD, 0x3F }, +	{ 0xDE, 0x3D }, +	{ 0xDF, 0x2F }, +	{ 0xE0, 0x2F }, +	{ 0xE1, 0x2F }, +	{ 0xE2, 0x07 }, +	{ 0xB0, 0x07 }, +	{ 0xB1, 0x18 }, +	{ 0xB2, 0x19 }, +	{ 0xB3, 0x2E }, +	{ 0xB4, 0x52 }, +	{ 0xB5, 0x72 }, +	{ 0xB6, 0x8C }, +	{ 0xB7, 0xBD }, +	{ 0xB8, 0xEB }, +	{ 0xB9, 0x47 }, +	{ 0xBA, 0x96 }, +	{ 0xBB, 0x1E }, +	{ 0xBC, 0x90 }, +	{ 0xBD, 0x93 }, +	{ 0xBE, 0xFA }, +	{ 0xBF, 0x56 }, +	{ 0xC0, 0x8C }, +	{ 0xC1, 0xB7 }, +	{ 0xC2, 0xCC }, +	{ 0xC3, 0xDF }, +	{ 0xC4, 0xE8 }, +	{ 0xC5, 0xF0 }, +	{ 0xC6, 0xF8 }, +	{ 0xC7, 0xFA }, +	{ 0xC8, 0xFC }, +	{ 0xC9, 0x00 }, +	{ 0xCA, 0x00 }, +	{ 0xCB, 0x5A }, +	{ 0xCC, 0xAF }, +	{ 0xCD, 0xFF }, +	{ 0xCE, 0xFF }, +	{ 0xB0, 0x08 }, +	{ 0xB1, 0x04 }, +	{ 0xB2, 0x15 }, +	{ 0xB3, 0x2D }, +	{ 0xB4, 0x51 }, +	{ 0xB5, 0x72 }, +	{ 0xB6, 0x8D }, +	{ 0xB7, 0xBE }, +	{ 0xB8, 0xED }, +	{ 0xB9, 0x4A }, +	{ 0xBA, 0x9A }, +	{ 0xBB, 0x23 }, +	{ 0xBC, 0x95 }, +	{ 0xBD, 0x98 }, +	{ 0xBE, 0xFF }, +	{ 0xBF, 0x59 }, +	{ 0xC0, 0x8E }, +	{ 0xC1, 0xB9 }, +	{ 0xC2, 0xCD }, +	{ 0xC3, 0xDF }, +	{ 0xC4, 0xE8 }, +	{ 0xC5, 0xF0 }, +	{ 0xC6, 0xF8 }, +	{ 0xC7, 0xFA }, +	{ 0xC8, 0xFC }, +	{ 0xC9, 0x00 }, +	{ 0xCA, 0x00 }, +	{ 0xCB, 0x5A }, +	{ 0xCC, 0xAF }, +	{ 0xCD, 0xFF }, +	{ 0xCE, 0xFF }, +	{ 0xB0, 0x09 }, +	{ 0xB1, 0x04 }, +	{ 0xB2, 0x2C }, +	{ 0xB3, 0x36 }, +	{ 0xB4, 0x53 }, +	{ 0xB5, 0x73 }, +	{ 0xB6, 0x8E }, +	{ 0xB7, 0xC0 }, +	{ 0xB8, 0xEF }, +	{ 0xB9, 0x4C }, +	{ 0xBA, 0x9D }, +	{ 0xBB, 0x25 }, +	{ 0xBC, 0x96 }, +	{ 0xBD, 0x9A }, +	{ 0xBE, 0x01 }, +	{ 0xBF, 0x59 }, +	{ 0xC0, 0x8E }, +	{ 0xC1, 0xB9 }, +	{ 0xC2, 0xCD }, +	{ 0xC3, 0xDF }, +	{ 0xC4, 0xE8 }, +	{ 0xC5, 0xF0 }, +	{ 0xC6, 0xF8 }, +	{ 0xC7, 0xFA }, +	{ 0xC8, 0xFC }, +	{ 0xC9, 0x00 }, +	{ 0xCA, 0x00 }, +	{ 0xCB, 0x5A }, +	{ 0xCC, 0xBF }, +	{ 0xCD, 0xFF }, +	{ 0xCE, 0xFF }, +	{ 0xB0, 0x0A }, +	{ 0xB1, 0x18 }, +	{ 0xB2, 0x19 }, +	{ 0xB3, 0x2E }, +	{ 0xB4, 0x52 }, +	{ 0xB5, 0x72 }, +	{ 0xB6, 0x8C }, +	{ 0xB7, 0xBD }, +	{ 0xB8, 0xEB }, +	{ 0xB9, 0x47 }, +	{ 0xBA, 0x96 }, +	{ 0xBB, 0x1E }, +	{ 0xBC, 0x90 }, +	{ 0xBD, 0x93 }, +	{ 0xBE, 0xFA }, +	{ 0xBF, 0x56 }, +	{ 0xC0, 0x8C }, +	{ 0xC1, 0xB7 }, +	{ 0xC2, 0xCC }, +	{ 0xC3, 0xDF }, +	{ 0xC4, 0xE8 }, +	{ 0xC5, 0xF0 }, +	{ 0xC6, 0xF8 }, +	{ 0xC7, 0xFA }, +	{ 0xC8, 0xFC }, +	{ 0xC9, 0x00 }, +	{ 0xCA, 0x00 }, +	{ 0xCB, 0x5A }, +	{ 0xCC, 0xAF }, +	{ 0xCD, 0xFF }, +	{ 0xCE, 0xFF }, +	{ 0xB0, 0x0B }, +	{ 0xB1, 0x04 }, +	{ 0xB2, 0x15 }, +	{ 0xB3, 0x2D }, +	{ 0xB4, 0x51 }, +	{ 0xB5, 0x72 }, +	{ 0xB6, 0x8D }, +	{ 0xB7, 0xBE }, +	{ 0xB8, 0xED }, +	{ 0xB9, 0x4A }, +	{ 0xBA, 0x9A }, +	{ 0xBB, 0x23 }, +	{ 0xBC, 0x95 }, +	{ 0xBD, 0x98 }, +	{ 0xBE, 0xFF }, +	{ 0xBF, 0x59 }, +	{ 0xC0, 0x8E }, +	{ 0xC1, 0xB9 }, +	{ 0xC2, 0xCD }, +	{ 0xC3, 0xDF }, +	{ 0xC4, 0xE8 }, +	{ 0xC5, 0xF0 }, +	{ 0xC6, 0xF8 }, +	{ 0xC7, 0xFA }, +	{ 0xC8, 0xFC }, +	{ 0xC9, 0x00 }, +	{ 0xCA, 0x00 }, +	{ 0xCB, 0x5A }, +	{ 0xCC, 0xAF }, +	{ 0xCD, 0xFF }, +	{ 0xCE, 0xFF }, +	{ 0xB0, 0x0C }, +	{ 0xB1, 0x04 }, +	{ 0xB2, 0x2C }, +	{ 0xB3, 0x36 }, +	{ 0xB4, 0x53 }, +	{ 0xB5, 0x73 }, +	{ 0xB6, 0x8E }, +	{ 0xB7, 0xC0 }, +	{ 0xB8, 0xEF }, +	{ 0xB9, 0x4C }, +	{ 0xBA, 0x9D }, +	{ 0xBB, 0x25 }, +	{ 0xBC, 0x96 }, +	{ 0xBD, 0x9A }, +	{ 0xBE, 0x01 }, +	{ 0xBF, 0x59 }, +	{ 0xC0, 0x8E }, +	{ 0xC1, 0xB9 }, +	{ 0xC2, 0xCD }, +	{ 0xC3, 0xDF }, +	{ 0xC4, 0xE8 }, +	{ 0xC5, 0xF0 }, +	{ 0xC6, 0xF8 }, +	{ 0xC7, 0xFA }, +	{ 0xC8, 0xFC }, +	{ 0xC9, 0x00 }, +	{ 0xCA, 0x00 }, +	{ 0xCB, 0x5A }, +	{ 0xCC, 0xBF }, +	{ 0xCD, 0xFF }, +	{ 0xCE, 0xFF }, +	{ 0xB0, 0x04 }, +	{ 0xB5, 0x02 }, +	{ 0xB6, 0x01 }, +}; + +static const struct panel_desc boe_himax8279d8p_panel_desc = { +	.display_mode = &default_display_mode, +	.bpc = 8, +	.width_mm = 107, +	.height_mm = 172, +	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +			MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM, +	.format = MIPI_DSI_FMT_RGB888, +	.lanes = 4, +	.on_cmds = boe_himax8279d8p_on_cmds, +	.on_cmds_num = 260, +}; + +/* 10 inch */ +static const struct panel_cmd boe_himax8279d10p_on_cmds[] = { +	{ 0xB0, 0x05 }, +	{ 0xB1, 0xE5 }, +	{ 0xB3, 0x52 }, +	{ 0xB0, 0x00 }, +	{ 0xB6, 0x03 }, +	{ 0xBA, 0x8B }, +	{ 0xBF, 0x1A }, +	{ 0xC0, 0x0F }, +	{ 0xC2, 0x0C }, +	{ 0xC3, 0x02 }, +	{ 0xC4, 0x0C }, +	{ 0xC5, 0x02 }, +	{ 0xB0, 0x01 }, +	{ 0xE0, 0x26 }, +	{ 0xE1, 0x26 }, +	{ 0xDC, 0x00 }, +	{ 0xDD, 0x00 }, +	{ 0xCC, 0x26 }, +	{ 0xCD, 0x26 }, +	{ 0xC8, 0x00 }, +	{ 0xC9, 0x00 }, +	{ 0xD2, 0x03 }, +	{ 0xD3, 0x03 }, +	{ 0xE6, 0x04 }, +	{ 0xE7, 0x04 }, +	{ 0xC4, 0x09 }, +	{ 0xC5, 0x09 }, +	{ 0xD8, 0x0A }, +	{ 0xD9, 0x0A }, +	{ 0xC2, 0x0B }, +	{ 0xC3, 0x0B }, +	{ 0xD6, 0x0C }, +	{ 0xD7, 0x0C }, +	{ 0xC0, 0x05 }, +	{ 0xC1, 0x05 }, +	{ 0xD4, 0x06 }, +	{ 0xD5, 0x06 }, +	{ 0xCA, 0x07 }, +	{ 0xCB, 0x07 }, +	{ 0xDE, 0x08 }, +	{ 0xDF, 0x08 }, +	{ 0xB0, 0x02 }, +	{ 0xC0, 0x00 }, +	{ 0xC1, 0x0D }, +	{ 0xC2, 0x17 }, +	{ 0xC3, 0x26 }, +	{ 0xC4, 0x31 }, +	{ 0xC5, 0x1C }, +	{ 0xC6, 0x2C }, +	{ 0xC7, 0x33 }, +	{ 0xC8, 0x31 }, +	{ 0xC9, 0x37 }, +	{ 0xCA, 0x37 }, +	{ 0xCB, 0x37 }, +	{ 0xCC, 0x39 }, +	{ 0xCD, 0x2E }, +	{ 0xCE, 0x2F }, +	{ 0xCF, 0x2F }, +	{ 0xD0, 0x07 }, +	{ 0xD2, 0x00 }, +	{ 0xD3, 0x0D }, +	{ 0xD4, 0x17 }, +	{ 0xD5, 0x26 }, +	{ 0xD6, 0x31 }, +	{ 0xD7, 0x3F }, +	{ 0xD8, 0x3F }, +	{ 0xD9, 0x3F }, +	{ 0xDA, 0x3F }, +	{ 0xDB, 0x37 }, +	{ 0xDC, 0x37 }, +	{ 0xDD, 0x37 }, +	{ 0xDE, 0x39 }, +	{ 0xDF, 0x2E }, +	{ 0xE0, 0x2F }, +	{ 0xE1, 0x2F }, +	{ 0xE2, 0x07 }, +	{ 0xB0, 0x03 }, +	{ 0xC8, 0x0B }, +	{ 0xC9, 0x07 }, +	{ 0xC3, 0x00 }, +	{ 0xE7, 0x00 }, +	{ 0xC5, 0x2A }, +	{ 0xDE, 0x2A }, +	{ 0xCA, 0x43 }, +	{ 0xC9, 0x07 }, +	{ 0xE4, 0xC0 }, +	{ 0xE5, 0x0D }, +	{ 0xCB, 0x01 }, +	{ 0xBC, 0x01 }, +	{ 0xB0, 0x06 }, +	{ 0xB8, 0xA5 }, +	{ 0xC0, 0xA5 }, +	{ 0xC7, 0x0F }, +	{ 0xD5, 0x32 }, +	{ 0xB8, 0x00 }, +	{ 0xC0, 0x00 }, +	{ 0xBC, 0x00 }, +	{ 0xB0, 0x07 }, +	{ 0xB1, 0x00 }, +	{ 0xB2, 0x05 }, +	{ 0xB3, 0x10 }, +	{ 0xB4, 0x22 }, +	{ 0xB5, 0x36 }, +	{ 0xB6, 0x4A }, +	{ 0xB7, 0x6C }, +	{ 0xB8, 0x9A }, +	{ 0xB9, 0xD7 }, +	{ 0xBA, 0x17 }, +	{ 0xBB, 0x92 }, +	{ 0xBC, 0x15 }, +	{ 0xBD, 0x18 }, +	{ 0xBE, 0x8C }, +	{ 0xBF, 0x00 }, +	{ 0xC0, 0x3A }, +	{ 0xC1, 0x72 }, +	{ 0xC2, 0x8C }, +	{ 0xC3, 0xA5 }, +	{ 0xC4, 0xB1 }, +	{ 0xC5, 0xBE }, +	{ 0xC6, 0xCA }, +	{ 0xC7, 0xD1 }, +	{ 0xC8, 0xD4 }, +	{ 0xC9, 0x00 }, +	{ 0xCA, 0x00 }, +	{ 0xCB, 0x16 }, +	{ 0xCC, 0xAF }, +	{ 0xCD, 0xFF }, +	{ 0xCE, 0xFF }, +	{ 0xB0, 0x08 }, +	{ 0xB1, 0x04 }, +	{ 0xB2, 0x05 }, +	{ 0xB3, 0x11 }, +	{ 0xB4, 0x24 }, +	{ 0xB5, 0x39 }, +	{ 0xB6, 0x4E }, +	{ 0xB7, 0x72 }, +	{ 0xB8, 0xA3 }, +	{ 0xB9, 0xE1 }, +	{ 0xBA, 0x25 }, +	{ 0xBB, 0xA8 }, +	{ 0xBC, 0x2E }, +	{ 0xBD, 0x32 }, +	{ 0xBE, 0xAD }, +	{ 0xBF, 0x28 }, +	{ 0xC0, 0x63 }, +	{ 0xC1, 0x9B }, +	{ 0xC2, 0xB5 }, +	{ 0xC3, 0xCF }, +	{ 0xC4, 0xDB }, +	{ 0xC5, 0xE8 }, +	{ 0xC6, 0xF5 }, +	{ 0xC7, 0xFA }, +	{ 0xC8, 0xFC }, +	{ 0xC9, 0x00 }, +	{ 0xCA, 0x00 }, +	{ 0xCB, 0x16 }, +	{ 0xCC, 0xAF }, +	{ 0xCD, 0xFF }, +	{ 0xCE, 0xFF }, +	{ 0xB0, 0x09 }, +	{ 0xB1, 0x04 }, +	{ 0xB2, 0x04 }, +	{ 0xB3, 0x0F }, +	{ 0xB4, 0x22 }, +	{ 0xB5, 0x37 }, +	{ 0xB6, 0x4D }, +	{ 0xB7, 0x71 }, +	{ 0xB8, 0xA2 }, +	{ 0xB9, 0xE1 }, +	{ 0xBA, 0x26 }, +	{ 0xBB, 0xA9 }, +	{ 0xBC, 0x2F }, +	{ 0xBD, 0x33 }, +	{ 0xBE, 0xAC }, +	{ 0xBF, 0x24 }, +	{ 0xC0, 0x5D }, +	{ 0xC1, 0x94 }, +	{ 0xC2, 0xAC }, +	{ 0xC3, 0xC5 }, +	{ 0xC4, 0xD1 }, +	{ 0xC5, 0xDC }, +	{ 0xC6, 0xE8 }, +	{ 0xC7, 0xED }, +	{ 0xC8, 0xF0 }, +	{ 0xC9, 0x00 }, +	{ 0xCA, 0x00 }, +	{ 0xCB, 0x16 }, +	{ 0xCC, 0xAF }, +	{ 0xCD, 0xFF }, +	{ 0xCE, 0xFF }, +	{ 0xB0, 0x0A }, +	{ 0xB1, 0x00 }, +	{ 0xB2, 0x05 }, +	{ 0xB3, 0x10 }, +	{ 0xB4, 0x22 }, +	{ 0xB5, 0x36 }, +	{ 0xB6, 0x4A }, +	{ 0xB7, 0x6C }, +	{ 0xB8, 0x9A }, +	{ 0xB9, 0xD7 }, +	{ 0xBA, 0x17 }, +	{ 0xBB, 0x92 }, +	{ 0xBC, 0x15 }, +	{ 0xBD, 0x18 }, +	{ 0xBE, 0x8C }, +	{ 0xBF, 0x00 }, +	{ 0xC0, 0x3A }, +	{ 0xC1, 0x72 }, +	{ 0xC2, 0x8C }, +	{ 0xC3, 0xA5 }, +	{ 0xC4, 0xB1 }, +	{ 0xC5, 0xBE }, +	{ 0xC6, 0xCA }, +	{ 0xC7, 0xD1 }, +	{ 0xC8, 0xD4 }, +	{ 0xC9, 0x00 }, +	{ 0xCA, 0x00 }, +	{ 0xCB, 0x16 }, +	{ 0xCC, 0xAF }, +	{ 0xCD, 0xFF }, +	{ 0xCE, 0xFF }, +	{ 0xB0, 0x0B }, +	{ 0xB1, 0x04 }, +	{ 0xB2, 0x05 }, +	{ 0xB3, 0x11 }, +	{ 0xB4, 0x24 }, +	{ 0xB5, 0x39 }, +	{ 0xB6, 0x4E }, +	{ 0xB7, 0x72 }, +	{ 0xB8, 0xA3 }, +	{ 0xB9, 0xE1 }, +	{ 0xBA, 0x25 }, +	{ 0xBB, 0xA8 }, +	{ 0xBC, 0x2E }, +	{ 0xBD, 0x32 }, +	{ 0xBE, 0xAD }, +	{ 0xBF, 0x28 }, +	{ 0xC0, 0x63 }, +	{ 0xC1, 0x9B }, +	{ 0xC2, 0xB5 }, +	{ 0xC3, 0xCF }, +	{ 0xC4, 0xDB }, +	{ 0xC5, 0xE8 }, +	{ 0xC6, 0xF5 }, +	{ 0xC7, 0xFA }, +	{ 0xC8, 0xFC }, +	{ 0xC9, 0x00 }, +	{ 0xCA, 0x00 }, +	{ 0xCB, 0x16 }, +	{ 0xCC, 0xAF }, +	{ 0xCD, 0xFF }, +	{ 0xCE, 0xFF }, +	{ 0xB0, 0x0C }, +	{ 0xB1, 0x04 }, +	{ 0xB2, 0x04 }, +	{ 0xB3, 0x0F }, +	{ 0xB4, 0x22 }, +	{ 0xB5, 0x37 }, +	{ 0xB6, 0x4D }, +	{ 0xB7, 0x71 }, +	{ 0xB8, 0xA2 }, +	{ 0xB9, 0xE1 }, +	{ 0xBA, 0x26 }, +	{ 0xBB, 0xA9 }, +	{ 0xBC, 0x2F }, +	{ 0xBD, 0x33 }, +	{ 0xBE, 0xAC }, +	{ 0xBF, 0x24 }, +	{ 0xC0, 0x5D }, +	{ 0xC1, 0x94 }, +	{ 0xC2, 0xAC }, +	{ 0xC3, 0xC5 }, +	{ 0xC4, 0xD1 }, +	{ 0xC5, 0xDC }, +	{ 0xC6, 0xE8 }, +	{ 0xC7, 0xED }, +	{ 0xC8, 0xF0 }, +	{ 0xC9, 0x00 }, +	{ 0xCA, 0x00 }, +	{ 0xCB, 0x16 }, +	{ 0xCC, 0xAF }, +	{ 0xCD, 0xFF }, +	{ 0xCE, 0xFF }, +}; + +static const struct panel_desc boe_himax8279d10p_panel_desc = { +	.display_mode = &default_display_mode, +	.bpc = 8, +	.width_mm = 135, +	.height_mm = 216, +	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +			MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM, +	.format = MIPI_DSI_FMT_RGB888, +	.lanes = 4, +	.on_cmds = boe_himax8279d10p_on_cmds, +	.on_cmds_num = 283, +}; + +static const struct of_device_id panel_of_match[] = { +	{ +		.compatible = "boe,himax8279d8p", +		.data = &boe_himax8279d8p_panel_desc, +	}, +	{ +		.compatible = "boe,himax8279d10p", +		.data = &boe_himax8279d10p_panel_desc, +	}, +	{ +		/* sentinel */ +	} +}; +MODULE_DEVICE_TABLE(of, panel_of_match); + +static int panel_add(struct panel_info *pinfo) +{ +	struct device *dev = &pinfo->link->dev; +	int ret; + +	pinfo->pp18_gpio = devm_gpiod_get(dev, "pp18", GPIOD_OUT_HIGH); +	if (IS_ERR(pinfo->pp18_gpio)) { +		ret = PTR_ERR(pinfo->pp18_gpio); +		if (ret != -EPROBE_DEFER) +			DRM_DEV_ERROR(dev, "failed to get pp18 gpio: %d\n", +				      ret); +		return ret; +	} + +	pinfo->pp33_gpio = devm_gpiod_get(dev, "pp33", GPIOD_OUT_HIGH); +	if (IS_ERR(pinfo->pp33_gpio)) { +		ret = PTR_ERR(pinfo->pp33_gpio); +		if (ret != -EPROBE_DEFER) +			DRM_DEV_ERROR(dev, "failed to get pp33 gpio: %d\n", +				      ret); +		return ret; +	} + +	pinfo->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); +	if (IS_ERR(pinfo->enable_gpio)) { +		ret = PTR_ERR(pinfo->enable_gpio); +		if (ret != -EPROBE_DEFER) +			DRM_DEV_ERROR(dev, "failed to get enable gpio: %d\n", +				      ret); +		return ret; +	} + +	drm_panel_init(&pinfo->base, dev, &panel_funcs, +		       DRM_MODE_CONNECTOR_DSI); + +	ret = drm_panel_of_backlight(&pinfo->base); +	if (ret) +		return ret; + +	return drm_panel_add(&pinfo->base); +} + +static int panel_probe(struct mipi_dsi_device *dsi) +{ +	struct panel_info *pinfo; +	const struct panel_desc *desc; +	int err; + +	pinfo = devm_kzalloc(&dsi->dev, sizeof(*pinfo), GFP_KERNEL); +	if (!pinfo) +		return -ENOMEM; + +	desc = of_device_get_match_data(&dsi->dev); +	dsi->mode_flags = desc->mode_flags; +	dsi->format = desc->format; +	dsi->lanes = desc->lanes; +	pinfo->desc = desc; + +	pinfo->link = dsi; +	mipi_dsi_set_drvdata(dsi, pinfo); + +	err = panel_add(pinfo); +	if (err < 0) +		return err; + +	err = mipi_dsi_attach(dsi); +	if (err < 0) +		drm_panel_remove(&pinfo->base); + +	return err; +} + +static int panel_remove(struct mipi_dsi_device *dsi) +{ +	struct panel_info *pinfo = mipi_dsi_get_drvdata(dsi); +	int err; + +	err = boe_panel_disable(&pinfo->base); +	if (err < 0) +		DRM_DEV_ERROR(&dsi->dev, "failed to disable panel: %d\n", +			      err); + +	err = boe_panel_unprepare(&pinfo->base); +	if (err < 0) +		DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n", +			      err); + +	err = mipi_dsi_detach(dsi); +	if (err < 0) +		DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n", +			      err); + +	drm_panel_remove(&pinfo->base); + +	return 0; +} + +static void panel_shutdown(struct mipi_dsi_device *dsi) +{ +	struct panel_info *pinfo = mipi_dsi_get_drvdata(dsi); + +	boe_panel_disable(&pinfo->base); +	boe_panel_unprepare(&pinfo->base); +} + +static struct mipi_dsi_driver panel_driver = { +	.driver = { +		.name = "panel-boe-himax8279d", +		.of_match_table = panel_of_match, +	}, +	.probe = panel_probe, +	.remove = panel_remove, +	.shutdown = panel_shutdown, +}; +module_mipi_dsi_driver(panel_driver); + +MODULE_AUTHOR("Jerry Han <[email protected]>"); +MODULE_DESCRIPTION("Boe Himax8279d driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c b/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c index 98f184b81187..95b789ab9d29 100644 --- a/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c +++ b/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c @@ -9,7 +9,6 @@  #include <drm/drm_panel.h>  #include <drm/drm_print.h> -#include <linux/backlight.h>  #include <linux/gpio/consumer.h>  #include <linux/delay.h>  #include <linux/module.h> @@ -22,7 +21,6 @@ struct feiyang {  	struct drm_panel	panel;  	struct mipi_dsi_device	*dsi; -	struct backlight_device	*backlight;  	struct regulator	*dvdd;  	struct regulator	*avdd;  	struct gpio_desc	*reset; @@ -102,7 +100,6 @@ static int feiyang_enable(struct drm_panel *panel)  	msleep(200);  	mipi_dsi_dcs_set_display_on(ctx->dsi); -	backlight_enable(ctx->backlight);  	return 0;  } @@ -111,7 +108,6 @@ static int feiyang_disable(struct drm_panel *panel)  {  	struct feiyang *ctx = panel_to_feiyang(panel); -	backlight_disable(ctx->backlight);  	return mipi_dsi_dcs_set_display_off(ctx->dsi);  } @@ -162,13 +158,13 @@ static const struct drm_display_mode feiyang_default_mode = {  	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,  }; -static int feiyang_get_modes(struct drm_panel *panel) +static int feiyang_get_modes(struct drm_panel *panel, +			     struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct feiyang *ctx = panel_to_feiyang(panel);  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &feiyang_default_mode); +	mode = drm_mode_duplicate(connector->dev, &feiyang_default_mode);  	if (!mode) {  		DRM_DEV_ERROR(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",  			      feiyang_default_mode.hdisplay, @@ -225,9 +221,9 @@ static int feiyang_dsi_probe(struct mipi_dsi_device *dsi)  		return PTR_ERR(ctx->reset);  	} -	ctx->backlight = devm_of_find_backlight(&dsi->dev); -	if (IS_ERR(ctx->backlight)) -		return PTR_ERR(ctx->backlight); +	ret = drm_panel_of_backlight(&ctx->panel); +	if (ret) +		return ret;  	ret = drm_panel_add(&ctx->panel);  	if (ret < 0) diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c index 24955bec1958..f394d53a7da4 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c @@ -641,10 +641,11 @@ static const struct drm_display_mode itu_r_bt_656_720_mode = {  	.flags = 0,  }; -static int ili9322_get_modes(struct drm_panel *panel) +static int ili9322_get_modes(struct drm_panel *panel, +			     struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct ili9322 *ili = panel_to_ili9322(panel); +	struct drm_device *drm = connector->dev;  	struct drm_display_mode *mode;  	struct drm_display_info *info; @@ -663,26 +664,26 @@ static int ili9322_get_modes(struct drm_panel *panel)  	switch (ili->input) {  	case ILI9322_INPUT_SRGB_DUMMY_320X240: -		mode = drm_mode_duplicate(panel->drm, &srgb_320x240_mode); +		mode = drm_mode_duplicate(drm, &srgb_320x240_mode);  		break;  	case ILI9322_INPUT_SRGB_DUMMY_360X240: -		mode = drm_mode_duplicate(panel->drm, &srgb_360x240_mode); +		mode = drm_mode_duplicate(drm, &srgb_360x240_mode);  		break;  	case ILI9322_INPUT_PRGB_THROUGH:  	case ILI9322_INPUT_PRGB_ALIGNED: -		mode = drm_mode_duplicate(panel->drm, &prgb_320x240_mode); +		mode = drm_mode_duplicate(drm, &prgb_320x240_mode);  		break;  	case ILI9322_INPUT_YUV_640X320_YCBCR: -		mode = drm_mode_duplicate(panel->drm, &yuv_640x320_mode); +		mode = drm_mode_duplicate(drm, &yuv_640x320_mode);  		break;  	case ILI9322_INPUT_YUV_720X360_YCBCR: -		mode = drm_mode_duplicate(panel->drm, &yuv_720x360_mode); +		mode = drm_mode_duplicate(drm, &yuv_720x360_mode);  		break;  	case ILI9322_INPUT_ITU_R_BT656_720X360_YCBCR: -		mode = drm_mode_duplicate(panel->drm, &itu_r_bt_656_720_mode); +		mode = drm_mode_duplicate(drm, &itu_r_bt_656_720_mode);  		break;  	case ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR: -		mode = drm_mode_duplicate(panel->drm, &itu_r_bt_656_640_mode); +		mode = drm_mode_duplicate(drm, &itu_r_bt_656_640_mode);  		break;  	default:  		mode = NULL; diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c index e8789e460a16..f54077c216a3 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -3,7 +3,6 @@   * Copyright (C) 2017-2018, Bootlin   */ -#include <linux/backlight.h>  #include <linux/delay.h>  #include <linux/device.h>  #include <linux/err.h> @@ -25,7 +24,6 @@ struct ili9881c {  	struct drm_panel	panel;  	struct mipi_dsi_device	*dsi; -	struct backlight_device *backlight;  	struct regulator	*power;  	struct gpio_desc	*reset;  }; @@ -348,7 +346,6 @@ static int ili9881c_enable(struct drm_panel *panel)  	msleep(120);  	mipi_dsi_dcs_set_display_on(ctx->dsi); -	backlight_enable(ctx->backlight);  	return 0;  } @@ -357,7 +354,6 @@ static int ili9881c_disable(struct drm_panel *panel)  {  	struct ili9881c *ctx = panel_to_ili9881c(panel); -	backlight_disable(ctx->backlight);  	return mipi_dsi_dcs_set_display_off(ctx->dsi);  } @@ -387,13 +383,13 @@ static const struct drm_display_mode bananapi_default_mode = {  	.vtotal		= 1280 + 10 + 10 + 20,  }; -static int ili9881c_get_modes(struct drm_panel *panel) +static int ili9881c_get_modes(struct drm_panel *panel, +			      struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct ili9881c *ctx = panel_to_ili9881c(panel);  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &bananapi_default_mode); +	mode = drm_mode_duplicate(connector->dev, &bananapi_default_mode);  	if (!mode) {  		dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",  			bananapi_default_mode.hdisplay, @@ -407,8 +403,8 @@ static int ili9881c_get_modes(struct drm_panel *panel)  	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;  	drm_mode_probed_add(connector, mode); -	panel->connector->display_info.width_mm = 62; -	panel->connector->display_info.height_mm = 110; +	connector->display_info.width_mm = 62; +	connector->display_info.height_mm = 110;  	return 1;  } @@ -423,7 +419,6 @@ static const struct drm_panel_funcs ili9881c_funcs = {  static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi)  { -	struct device_node *np;  	struct ili9881c *ctx;  	int ret; @@ -448,14 +443,9 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi)  		return PTR_ERR(ctx->reset);  	} -	np = of_parse_phandle(dsi->dev.of_node, "backlight", 0); -	if (np) { -		ctx->backlight = of_find_backlight_by_node(np); -		of_node_put(np); - -		if (!ctx->backlight) -			return -EPROBE_DEFER; -	} +	ret = drm_panel_of_backlight(&ctx->panel); +	if (ret) +		return ret;  	ret = drm_panel_add(&ctx->panel);  	if (ret < 0) @@ -475,9 +465,6 @@ static int ili9881c_dsi_remove(struct mipi_dsi_device *dsi)  	mipi_dsi_detach(dsi);  	drm_panel_remove(&ctx->panel); -	if (ctx->backlight) -		put_device(&ctx->backlight->dev); -  	return 0;  } diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 83df1ac4211f..7419f1f0acee 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -3,7 +3,6 @@   * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd   */ -#include <linux/backlight.h>  #include <linux/delay.h>  #include <linux/gpio/consumer.h>  #include <linux/module.h> @@ -52,7 +51,6 @@ struct innolux_panel {  	struct mipi_dsi_device *link;  	const struct panel_desc *desc; -	struct backlight_device *backlight;  	struct regulator_bulk_data *supplies;  	struct gpio_desc *enable_gpio; @@ -72,8 +70,6 @@ static int innolux_panel_disable(struct drm_panel *panel)  	if (!innolux->enabled)  		return 0; -	backlight_disable(innolux->backlight); -  	innolux->enabled = false;  	return 0; @@ -204,18 +200,10 @@ poweroff:  static int innolux_panel_enable(struct drm_panel *panel)  {  	struct innolux_panel *innolux = to_innolux_panel(panel); -	int ret;  	if (innolux->enabled)  		return 0; -	ret = backlight_enable(innolux->backlight); -	if (ret) { -		DRM_DEV_ERROR(panel->drm->dev, -			      "Failed to enable backlight %d\n", ret); -		return ret; -	} -  	innolux->enabled = true;  	return 0; @@ -403,28 +391,27 @@ static const struct panel_desc innolux_p097pfg_panel_desc = {  	.sleep_mode_delay = 100, /* T15 */  }; -static int innolux_panel_get_modes(struct drm_panel *panel) +static int innolux_panel_get_modes(struct drm_panel *panel, +				   struct drm_connector *connector)  {  	struct innolux_panel *innolux = to_innolux_panel(panel);  	const struct drm_display_mode *m = innolux->desc->mode;  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, m); +	mode = drm_mode_duplicate(connector->dev, m);  	if (!mode) { -		DRM_DEV_ERROR(panel->drm->dev, "failed to add mode %ux%ux@%u\n", +		DRM_DEV_ERROR(panel->dev, "failed to add mode %ux%ux@%u\n",  			      m->hdisplay, m->vdisplay, m->vrefresh);  		return -ENOMEM;  	}  	drm_mode_set_name(mode); -	drm_mode_probed_add(panel->connector, mode); +	drm_mode_probed_add(connector, mode); -	panel->connector->display_info.width_mm = -			innolux->desc->size.width; -	panel->connector->display_info.height_mm = -			innolux->desc->size.height; -	panel->connector->display_info.bpc = innolux->desc->bpc; +	connector->display_info.width_mm = innolux->desc->size.width; +	connector->display_info.height_mm = innolux->desc->size.height; +	connector->display_info.bpc = innolux->desc->bpc;  	return 1;  } @@ -483,13 +470,13 @@ static int innolux_panel_add(struct mipi_dsi_device *dsi,  		innolux->enable_gpio = NULL;  	} -	innolux->backlight = devm_of_find_backlight(dev); -	if (IS_ERR(innolux->backlight)) -		return PTR_ERR(innolux->backlight); -  	drm_panel_init(&innolux->base, dev, &innolux_panel_funcs,  		       DRM_MODE_CONNECTOR_DSI); +	err = drm_panel_of_backlight(&innolux->base); +	if (err) +		return err; +  	err = drm_panel_add(&innolux->base);  	if (err < 0)  		return err; @@ -527,12 +514,12 @@ static int innolux_panel_remove(struct mipi_dsi_device *dsi)  	struct innolux_panel *innolux = mipi_dsi_get_drvdata(dsi);  	int err; -	err = innolux_panel_unprepare(&innolux->base); +	err = drm_panel_unprepare(&innolux->base);  	if (err < 0)  		DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n",  			      err); -	err = innolux_panel_disable(&innolux->base); +	err = drm_panel_disable(&innolux->base);  	if (err < 0)  		DRM_DEV_ERROR(&dsi->dev, "failed to disable panel: %d\n", err); @@ -550,8 +537,8 @@ static void innolux_panel_shutdown(struct mipi_dsi_device *dsi)  {  	struct innolux_panel *innolux = mipi_dsi_get_drvdata(dsi); -	innolux_panel_unprepare(&innolux->base); -	innolux_panel_disable(&innolux->base); +	drm_panel_unprepare(&innolux->base); +	drm_panel_disable(&innolux->base);  }  static struct mipi_dsi_driver innolux_panel_driver = { diff --git a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c index 56364a93f0b8..4bfd8c877c8e 100644 --- a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c +++ b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c @@ -300,13 +300,14 @@ static const struct drm_display_mode default_mode = {  		.flags = 0,  }; -static int jdi_panel_get_modes(struct drm_panel *panel) +static int jdi_panel_get_modes(struct drm_panel *panel, +			       struct drm_connector *connector)  {  	struct drm_display_mode *mode;  	struct jdi_panel *jdi = to_jdi_panel(panel);  	struct device *dev = &jdi->dsi->dev; -	mode = drm_mode_duplicate(panel->drm, &default_mode); +	mode = drm_mode_duplicate(connector->dev, &default_mode);  	if (!mode) {  		dev_err(dev, "failed to add mode %ux%ux@%u\n",  			default_mode.hdisplay, default_mode.vdisplay, @@ -316,10 +317,10 @@ static int jdi_panel_get_modes(struct drm_panel *panel)  	drm_mode_set_name(mode); -	drm_mode_probed_add(panel->connector, mode); +	drm_mode_probed_add(connector, mode); -	panel->connector->display_info.width_mm = 95; -	panel->connector->display_info.height_mm = 151; +	connector->display_info.width_mm = 95; +	connector->display_info.height_mm = 151;  	return 1;  } diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c b/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c index 45f96556ec8c..bac1a2a06c92 100644 --- a/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c +++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c @@ -3,7 +3,6 @@   * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd   */ -#include <linux/backlight.h>  #include <linux/delay.h>  #include <linux/gpio/consumer.h>  #include <linux/module.h> @@ -23,7 +22,6 @@ struct kingdisplay_panel {  	struct drm_panel base;  	struct mipi_dsi_device *link; -	struct backlight_device *backlight;  	struct regulator *supply;  	struct gpio_desc *enable_gpio; @@ -191,8 +189,6 @@ static int kingdisplay_panel_disable(struct drm_panel *panel)  	if (!kingdisplay->enabled)  		return 0; -	backlight_disable(kingdisplay->backlight); -  	err = mipi_dsi_dcs_set_display_off(kingdisplay->link);  	if (err < 0)  		DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", @@ -303,18 +299,10 @@ poweroff:  static int kingdisplay_panel_enable(struct drm_panel *panel)  {  	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel); -	int ret;  	if (kingdisplay->enabled)  		return 0; -	ret = backlight_enable(kingdisplay->backlight); -	if (ret) { -		DRM_DEV_ERROR(panel->drm->dev, -			      "Failed to enable backlight %d\n", ret); -		return ret; -	} -  	kingdisplay->enabled = true;  	return 0; @@ -333,13 +321,14 @@ static const struct drm_display_mode default_mode = {  	.vrefresh = 60,  }; -static int kingdisplay_panel_get_modes(struct drm_panel *panel) +static int kingdisplay_panel_get_modes(struct drm_panel *panel, +				       struct drm_connector *connector)  {  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &default_mode); +	mode = drm_mode_duplicate(connector->dev, &default_mode);  	if (!mode) { -		DRM_DEV_ERROR(panel->drm->dev, "failed to add mode %ux%ux@%u\n", +		DRM_DEV_ERROR(panel->dev, "failed to add mode %ux%ux@%u\n",  			      default_mode.hdisplay, default_mode.vdisplay,  			      default_mode.vrefresh);  		return -ENOMEM; @@ -347,11 +336,11 @@ static int kingdisplay_panel_get_modes(struct drm_panel *panel)  	drm_mode_set_name(mode); -	drm_mode_probed_add(panel->connector, mode); +	drm_mode_probed_add(connector, mode); -	panel->connector->display_info.width_mm = 147; -	panel->connector->display_info.height_mm = 196; -	panel->connector->display_info.bpc = 8; +	connector->display_info.width_mm = 147; +	connector->display_info.height_mm = 196; +	connector->display_info.bpc = 8;  	return 1;  } @@ -387,13 +376,13 @@ static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay)  		kingdisplay->enable_gpio = NULL;  	} -	kingdisplay->backlight = devm_of_find_backlight(dev); -	if (IS_ERR(kingdisplay->backlight)) -		return PTR_ERR(kingdisplay->backlight); -  	drm_panel_init(&kingdisplay->base, &kingdisplay->link->dev,  		       &kingdisplay_panel_funcs, DRM_MODE_CONNECTOR_DSI); +	err = drm_panel_of_backlight(&kingdisplay->base); +	if (err) +		return err; +  	return drm_panel_add(&kingdisplay->base);  } @@ -431,12 +420,12 @@ static int kingdisplay_panel_remove(struct mipi_dsi_device *dsi)  	struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi);  	int err; -	err = kingdisplay_panel_unprepare(&kingdisplay->base); +	err = drm_panel_unprepare(&kingdisplay->base);  	if (err < 0)  		DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n",  			      err); -	err = kingdisplay_panel_disable(&kingdisplay->base); +	err = drm_panel_disable(&kingdisplay->base);  	if (err < 0)  		DRM_DEV_ERROR(&dsi->dev, "failed to disable panel: %d\n", err); @@ -454,8 +443,8 @@ static void kingdisplay_panel_shutdown(struct mipi_dsi_device *dsi)  {  	struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi); -	kingdisplay_panel_unprepare(&kingdisplay->base); -	kingdisplay_panel_disable(&kingdisplay->base); +	drm_panel_unprepare(&kingdisplay->base); +	drm_panel_disable(&kingdisplay->base);  }  static struct mipi_dsi_driver kingdisplay_panel_driver = { diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c b/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c new file mode 100644 index 000000000000..76ecf2de9c44 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c @@ -0,0 +1,531 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2019 Theobroma Systems Design und Consulting GmbH + * + * base on panel-kingdisplay-kd097d04.c + * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.h> + +#include <drm/drm_crtc.h> +#include <drm/drm_device.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> +#include <drm/drm_print.h> + +struct ltk500hd1829 { +	struct device *dev; +	struct drm_panel panel; +	struct gpio_desc *reset_gpio; +	struct regulator *vcc; +	struct regulator *iovcc; +	bool prepared; +}; + +struct ltk500hd1829_cmd { +	char cmd; +	char data; +}; + +/* + * There is no description in the Reference Manual about these commands. + * We received them from the vendor, so just use them as is. + */ +static const struct ltk500hd1829_cmd init_code[] = { +	{ 0xE0, 0x00 }, +	{ 0xE1, 0x93 }, +	{ 0xE2, 0x65 }, +	{ 0xE3, 0xF8 }, +	{ 0x80, 0x03 }, +	{ 0xE0, 0x04 }, +	{ 0x2D, 0x03 }, +	{ 0xE0, 0x01 }, +	{ 0x00, 0x00 }, +	{ 0x01, 0xB6 }, +	{ 0x03, 0x00 }, +	{ 0x04, 0xC5 }, +	{ 0x17, 0x00 }, +	{ 0x18, 0xBF }, +	{ 0x19, 0x01 }, +	{ 0x1A, 0x00 }, +	{ 0x1B, 0xBF }, +	{ 0x1C, 0x01 }, +	{ 0x1F, 0x7C }, +	{ 0x20, 0x26 }, +	{ 0x21, 0x26 }, +	{ 0x22, 0x4E }, +	{ 0x37, 0x09 }, +	{ 0x38, 0x04 }, +	{ 0x39, 0x08 }, +	{ 0x3A, 0x1F }, +	{ 0x3B, 0x1F }, +	{ 0x3C, 0x78 }, +	{ 0x3D, 0xFF }, +	{ 0x3E, 0xFF }, +	{ 0x3F, 0x00 }, +	{ 0x40, 0x04 }, +	{ 0x41, 0xA0 }, +	{ 0x43, 0x0F }, +	{ 0x44, 0x0A }, +	{ 0x45, 0x24 }, +	{ 0x55, 0x01 }, +	{ 0x56, 0x01 }, +	{ 0x57, 0xA5 }, +	{ 0x58, 0x0A }, +	{ 0x59, 0x4A }, +	{ 0x5A, 0x38 }, +	{ 0x5B, 0x10 }, +	{ 0x5C, 0x19 }, +	{ 0x5D, 0x7C }, +	{ 0x5E, 0x64 }, +	{ 0x5F, 0x54 }, +	{ 0x60, 0x48 }, +	{ 0x61, 0x44 }, +	{ 0x62, 0x35 }, +	{ 0x63, 0x3A }, +	{ 0x64, 0x24 }, +	{ 0x65, 0x3B }, +	{ 0x66, 0x39 }, +	{ 0x67, 0x37 }, +	{ 0x68, 0x56 }, +	{ 0x69, 0x41 }, +	{ 0x6A, 0x47 }, +	{ 0x6B, 0x2F }, +	{ 0x6C, 0x23 }, +	{ 0x6D, 0x13 }, +	{ 0x6E, 0x02 }, +	{ 0x6F, 0x08 }, +	{ 0x70, 0x7C }, +	{ 0x71, 0x64 }, +	{ 0x72, 0x54 }, +	{ 0x73, 0x48 }, +	{ 0x74, 0x44 }, +	{ 0x75, 0x35 }, +	{ 0x76, 0x3A }, +	{ 0x77, 0x22 }, +	{ 0x78, 0x3B }, +	{ 0x79, 0x39 }, +	{ 0x7A, 0x38 }, +	{ 0x7B, 0x52 }, +	{ 0x7C, 0x41 }, +	{ 0x7D, 0x47 }, +	{ 0x7E, 0x2F }, +	{ 0x7F, 0x23 }, +	{ 0x80, 0x13 }, +	{ 0x81, 0x02 }, +	{ 0x82, 0x08 }, +	{ 0xE0, 0x02 }, +	{ 0x00, 0x57 }, +	{ 0x01, 0x77 }, +	{ 0x02, 0x44 }, +	{ 0x03, 0x46 }, +	{ 0x04, 0x48 }, +	{ 0x05, 0x4A }, +	{ 0x06, 0x4C }, +	{ 0x07, 0x4E }, +	{ 0x08, 0x50 }, +	{ 0x09, 0x55 }, +	{ 0x0A, 0x52 }, +	{ 0x0B, 0x55 }, +	{ 0x0C, 0x55 }, +	{ 0x0D, 0x55 }, +	{ 0x0E, 0x55 }, +	{ 0x0F, 0x55 }, +	{ 0x10, 0x55 }, +	{ 0x11, 0x55 }, +	{ 0x12, 0x55 }, +	{ 0x13, 0x40 }, +	{ 0x14, 0x55 }, +	{ 0x15, 0x55 }, +	{ 0x16, 0x57 }, +	{ 0x17, 0x77 }, +	{ 0x18, 0x45 }, +	{ 0x19, 0x47 }, +	{ 0x1A, 0x49 }, +	{ 0x1B, 0x4B }, +	{ 0x1C, 0x4D }, +	{ 0x1D, 0x4F }, +	{ 0x1E, 0x51 }, +	{ 0x1F, 0x55 }, +	{ 0x20, 0x53 }, +	{ 0x21, 0x55 }, +	{ 0x22, 0x55 }, +	{ 0x23, 0x55 }, +	{ 0x24, 0x55 }, +	{ 0x25, 0x55 }, +	{ 0x26, 0x55 }, +	{ 0x27, 0x55 }, +	{ 0x28, 0x55 }, +	{ 0x29, 0x41 }, +	{ 0x2A, 0x55 }, +	{ 0x2B, 0x55 }, +	{ 0x2C, 0x57 }, +	{ 0x2D, 0x77 }, +	{ 0x2E, 0x4F }, +	{ 0x2F, 0x4D }, +	{ 0x30, 0x4B }, +	{ 0x31, 0x49 }, +	{ 0x32, 0x47 }, +	{ 0x33, 0x45 }, +	{ 0x34, 0x41 }, +	{ 0x35, 0x55 }, +	{ 0x36, 0x53 }, +	{ 0x37, 0x55 }, +	{ 0x38, 0x55 }, +	{ 0x39, 0x55 }, +	{ 0x3A, 0x55 }, +	{ 0x3B, 0x55 }, +	{ 0x3C, 0x55 }, +	{ 0x3D, 0x55 }, +	{ 0x3E, 0x55 }, +	{ 0x3F, 0x51 }, +	{ 0x40, 0x55 }, +	{ 0x41, 0x55 }, +	{ 0x42, 0x57 }, +	{ 0x43, 0x77 }, +	{ 0x44, 0x4E }, +	{ 0x45, 0x4C }, +	{ 0x46, 0x4A }, +	{ 0x47, 0x48 }, +	{ 0x48, 0x46 }, +	{ 0x49, 0x44 }, +	{ 0x4A, 0x40 }, +	{ 0x4B, 0x55 }, +	{ 0x4C, 0x52 }, +	{ 0x4D, 0x55 }, +	{ 0x4E, 0x55 }, +	{ 0x4F, 0x55 }, +	{ 0x50, 0x55 }, +	{ 0x51, 0x55 }, +	{ 0x52, 0x55 }, +	{ 0x53, 0x55 }, +	{ 0x54, 0x55 }, +	{ 0x55, 0x50 }, +	{ 0x56, 0x55 }, +	{ 0x57, 0x55 }, +	{ 0x58, 0x40 }, +	{ 0x59, 0x00 }, +	{ 0x5A, 0x00 }, +	{ 0x5B, 0x10 }, +	{ 0x5C, 0x09 }, +	{ 0x5D, 0x30 }, +	{ 0x5E, 0x01 }, +	{ 0x5F, 0x02 }, +	{ 0x60, 0x30 }, +	{ 0x61, 0x03 }, +	{ 0x62, 0x04 }, +	{ 0x63, 0x06 }, +	{ 0x64, 0x6A }, +	{ 0x65, 0x75 }, +	{ 0x66, 0x0F }, +	{ 0x67, 0xB3 }, +	{ 0x68, 0x0B }, +	{ 0x69, 0x06 }, +	{ 0x6A, 0x6A }, +	{ 0x6B, 0x10 }, +	{ 0x6C, 0x00 }, +	{ 0x6D, 0x04 }, +	{ 0x6E, 0x04 }, +	{ 0x6F, 0x88 }, +	{ 0x70, 0x00 }, +	{ 0x71, 0x00 }, +	{ 0x72, 0x06 }, +	{ 0x73, 0x7B }, +	{ 0x74, 0x00 }, +	{ 0x75, 0xBC }, +	{ 0x76, 0x00 }, +	{ 0x77, 0x05 }, +	{ 0x78, 0x2E }, +	{ 0x79, 0x00 }, +	{ 0x7A, 0x00 }, +	{ 0x7B, 0x00 }, +	{ 0x7C, 0x00 }, +	{ 0x7D, 0x03 }, +	{ 0x7E, 0x7B }, +	{ 0xE0, 0x04 }, +	{ 0x09, 0x10 }, +	{ 0x2B, 0x2B }, +	{ 0x2E, 0x44 }, +	{ 0xE0, 0x00 }, +	{ 0xE6, 0x02 }, +	{ 0xE7, 0x02 }, +	{ 0x35, 0x00 }, +}; + +static inline +struct ltk500hd1829 *panel_to_ltk500hd1829(struct drm_panel *panel) +{ +	return container_of(panel, struct ltk500hd1829, panel); +} + +static int ltk500hd1829_unprepare(struct drm_panel *panel) +{ +	struct ltk500hd1829 *ctx = panel_to_ltk500hd1829(panel); +	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); +	int ret; + +	if (!ctx->prepared) +		return 0; + +	ret = mipi_dsi_dcs_set_display_off(dsi); +	if (ret < 0) +		DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", +			      ret); + +	ret = mipi_dsi_dcs_enter_sleep_mode(dsi); +	if (ret < 0) { +		DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", +			      ret); +	} + +	/* 120ms to enter sleep mode */ +	msleep(120); + +	regulator_disable(ctx->iovcc); +	regulator_disable(ctx->vcc); + +	ctx->prepared = false; + +	return 0; +} + +static int ltk500hd1829_prepare(struct drm_panel *panel) +{ +	struct ltk500hd1829 *ctx = panel_to_ltk500hd1829(panel); +	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); +	unsigned int i; +	int ret; + +	if (ctx->prepared) +		return 0; + +	ret = regulator_enable(ctx->vcc); +	if (ret < 0) { +		DRM_DEV_ERROR(ctx->dev, +			      "Failed to enable vci supply: %d\n", ret); +		return ret; +	} +	ret = regulator_enable(ctx->iovcc); +	if (ret < 0) { +		DRM_DEV_ERROR(ctx->dev, +			      "Failed to enable iovcc supply: %d\n", ret); +		goto disable_vcc; +	} + +	gpiod_set_value_cansleep(ctx->reset_gpio, 1); +	/* tRW: 10us */ +	usleep_range(10, 20); +	gpiod_set_value_cansleep(ctx->reset_gpio, 0); + +	/* tRT: >= 5ms */ +	usleep_range(5000, 6000); + +	for (i = 0; i < ARRAY_SIZE(init_code); i++) { +		ret = mipi_dsi_generic_write(dsi, &init_code[i], +					     sizeof(struct ltk500hd1829_cmd)); +		if (ret < 0) { +			DRM_DEV_ERROR(panel->dev, +				      "failed to write init cmds: %d\n", ret); +			goto disable_iovcc; +		} +	} + +	ret = mipi_dsi_dcs_exit_sleep_mode(dsi); +	if (ret < 0) { +		DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n", +			      ret); +		goto disable_iovcc; +	} + +	/* 120ms to exit sleep mode */ +	msleep(120); + +	ret = mipi_dsi_dcs_set_display_on(dsi); +	if (ret < 0) { +		DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n", +			      ret); +		goto disable_iovcc; +	} + +	ctx->prepared = true; + +	return 0; + +disable_iovcc: +	regulator_disable(ctx->iovcc); +disable_vcc: +	regulator_disable(ctx->vcc); +	return ret; +} + +static const struct drm_display_mode default_mode = { +	.hdisplay	= 720, +	.hsync_start	= 720 + 50, +	.hsync_end	= 720 + 50 + 50, +	.htotal		= 720 + 50 + 50 + 50, +	.vdisplay	= 1280, +	.vsync_start	= 1280 + 30, +	.vsync_end	= 1280 + 30 + 4, +	.vtotal		= 1280 + 30 + 4 + 12, +	.vrefresh	= 60, +	.clock		= 41600, +	.width_mm	= 62, +	.height_mm	= 110, +}; + +static int ltk500hd1829_get_modes(struct drm_panel *panel, +				  struct drm_connector *connector) +{ +	struct ltk500hd1829 *ctx = panel_to_ltk500hd1829(panel); +	struct drm_display_mode *mode; + +	mode = drm_mode_duplicate(connector->dev, &default_mode); +	if (!mode) { +		DRM_DEV_ERROR(ctx->dev, "failed to add mode %ux%ux@%u\n", +			      default_mode.hdisplay, default_mode.vdisplay, +			      default_mode.vrefresh); +		return -ENOMEM; +	} + +	drm_mode_set_name(mode); + +	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; +	connector->display_info.width_mm = mode->width_mm; +	connector->display_info.height_mm = mode->height_mm; +	drm_mode_probed_add(connector, mode); + +	return 1; +} + +static const struct drm_panel_funcs ltk500hd1829_funcs = { +	.unprepare = ltk500hd1829_unprepare, +	.prepare = ltk500hd1829_prepare, +	.get_modes = ltk500hd1829_get_modes, +}; + +static int ltk500hd1829_probe(struct mipi_dsi_device *dsi) +{ +	struct ltk500hd1829 *ctx; +	struct device *dev = &dsi->dev; +	int ret; + +	ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL); +	if (!ctx) +		return -ENOMEM; + +	ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); +	if (IS_ERR(ctx->reset_gpio)) { +		DRM_DEV_ERROR(dev, "cannot get reset gpio\n"); +		return PTR_ERR(ctx->reset_gpio); +	} + +	ctx->vcc = devm_regulator_get(dev, "vcc"); +	if (IS_ERR(ctx->vcc)) { +		ret = PTR_ERR(ctx->vcc); +		if (ret != -EPROBE_DEFER) +			DRM_DEV_ERROR(dev, +				      "Failed to request vcc regulator: %d\n", +				      ret); +		return ret; +	} + +	ctx->iovcc = devm_regulator_get(dev, "iovcc"); +	if (IS_ERR(ctx->iovcc)) { +		ret = PTR_ERR(ctx->iovcc); +		if (ret != -EPROBE_DEFER) +			DRM_DEV_ERROR(dev, +				      "Failed to request iovcc regulator: %d\n", +				      ret); +		return ret; +	} + +	mipi_dsi_set_drvdata(dsi, ctx); + +	ctx->dev = dev; + +	dsi->lanes = 4; +	dsi->format = MIPI_DSI_FMT_RGB888; +	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | +			  MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET; + +	drm_panel_init(&ctx->panel, &dsi->dev, <k500hd1829_funcs, +		       DRM_MODE_CONNECTOR_DSI); + +	ret = drm_panel_of_backlight(&ctx->panel); +	if (ret) +		return ret; + +	drm_panel_add(&ctx->panel); + +	ret = mipi_dsi_attach(dsi); +	if (ret < 0) { +		DRM_DEV_ERROR(dev, "mipi_dsi_attach failed: %d\n", ret); +		drm_panel_remove(&ctx->panel); +		return ret; +	} + +	return 0; +} + +static void ltk500hd1829_shutdown(struct mipi_dsi_device *dsi) +{ +	struct ltk500hd1829 *ctx = mipi_dsi_get_drvdata(dsi); +	int ret; + +	ret = drm_panel_unprepare(&ctx->panel); +	if (ret < 0) +		DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", +			      ret); + +	ret = drm_panel_disable(&ctx->panel); +	if (ret < 0) +		DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", +			      ret); +} + +static int ltk500hd1829_remove(struct mipi_dsi_device *dsi) +{ +	struct ltk500hd1829 *ctx = mipi_dsi_get_drvdata(dsi); +	int ret; + +	ltk500hd1829_shutdown(dsi); + +	ret = mipi_dsi_detach(dsi); +	if (ret < 0) +		DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n", +			      ret); + +	drm_panel_remove(&ctx->panel); + +	return 0; +} + +static const struct of_device_id ltk500hd1829_of_match[] = { +	{ .compatible = "leadtek,ltk500hd1829", }, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ltk500hd1829_of_match); + +static struct mipi_dsi_driver ltk500hd1829_driver = { +	.driver = { +		.name = "panel-leadtek-ltk500hd1829", +		.of_match_table = ltk500hd1829_of_match, +	}, +	.probe = ltk500hd1829_probe, +	.remove = ltk500hd1829_remove, +	.shutdown = ltk500hd1829_shutdown, +}; +module_mipi_dsi_driver(ltk500hd1829_driver); + +MODULE_AUTHOR("Heiko Stuebner <[email protected]>"); +MODULE_DESCRIPTION("Leadtek LTK500HD1829 panel driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/panel/panel-lg-lb035q02.c b/drivers/gpu/drm/panel/panel-lg-lb035q02.c index 7a1385e834f0..e90efeaba4ad 100644 --- a/drivers/gpu/drm/panel/panel-lg-lb035q02.c +++ b/drivers/gpu/drm/panel/panel-lg-lb035q02.c @@ -141,12 +141,12 @@ static const struct drm_display_mode lb035q02_mode = {  	.height_mm = 53,  }; -static int lb035q02_get_modes(struct drm_panel *panel) +static int lb035q02_get_modes(struct drm_panel *panel, +			      struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &lb035q02_mode); +	mode = drm_mode_duplicate(connector->dev, &lb035q02_mode);  	if (!mode)  		return -ENOMEM; diff --git a/drivers/gpu/drm/panel/panel-lg-lg4573.c b/drivers/gpu/drm/panel/panel-lg-lg4573.c index db4865a4c2b9..b262b53dbd85 100644 --- a/drivers/gpu/drm/panel/panel-lg-lg4573.c +++ b/drivers/gpu/drm/panel/panel-lg-lg4573.c @@ -42,7 +42,7 @@ static int lg4573_spi_write_u16(struct lg4573 *ctx, u16 data)  	struct spi_transfer xfer = {  		.len = 2,  	}; -	u16 temp = cpu_to_be16(data); +	__be16 temp = cpu_to_be16(data);  	struct spi_message msg;  	dev_dbg(ctx->panel.dev, "writing data: %x\n", data); @@ -209,14 +209,14 @@ static const struct drm_display_mode default_mode = {  	.vrefresh = 60,  }; -static int lg4573_get_modes(struct drm_panel *panel) +static int lg4573_get_modes(struct drm_panel *panel, +			    struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &default_mode); +	mode = drm_mode_duplicate(connector->dev, &default_mode);  	if (!mode) { -		dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n", +		dev_err(panel->dev, "failed to add mode %ux%ux@%u\n",  			default_mode.hdisplay, default_mode.vdisplay,  			default_mode.vrefresh);  		return -ENOMEM; @@ -227,8 +227,8 @@ static int lg4573_get_modes(struct drm_panel *panel)  	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;  	drm_mode_probed_add(connector, mode); -	panel->connector->display_info.width_mm = 61; -	panel->connector->display_info.height_mm = 103; +	connector->display_info.width_mm = 61; +	connector->display_info.height_mm = 103;  	return 1;  } diff --git a/drivers/gpu/drm/panel/panel-lvds.c b/drivers/gpu/drm/panel/panel-lvds.c index 2405f26e5d31..5ce3f4a2b7a1 100644 --- a/drivers/gpu/drm/panel/panel-lvds.c +++ b/drivers/gpu/drm/panel/panel-lvds.c @@ -8,7 +8,6 @@   * Contact: Laurent Pinchart ([email protected])   */ -#include <linux/backlight.h>  #include <linux/gpio/consumer.h>  #include <linux/module.h>  #include <linux/of_platform.h> @@ -34,7 +33,6 @@ struct panel_lvds {  	unsigned int bus_format;  	bool data_mirror; -	struct backlight_device *backlight;  	struct regulator *supply;  	struct gpio_desc *enable_gpio; @@ -46,19 +44,6 @@ static inline struct panel_lvds *to_panel_lvds(struct drm_panel *panel)  	return container_of(panel, struct panel_lvds, panel);  } -static int panel_lvds_disable(struct drm_panel *panel) -{ -	struct panel_lvds *lvds = to_panel_lvds(panel); - -	if (lvds->backlight) { -		lvds->backlight->props.power = FB_BLANK_POWERDOWN; -		lvds->backlight->props.state |= BL_CORE_FBBLANK; -		backlight_update_status(lvds->backlight); -	} - -	return 0; -} -  static int panel_lvds_unprepare(struct drm_panel *panel)  {  	struct panel_lvds *lvds = to_panel_lvds(panel); @@ -93,26 +78,13 @@ static int panel_lvds_prepare(struct drm_panel *panel)  	return 0;  } -static int panel_lvds_enable(struct drm_panel *panel) +static int panel_lvds_get_modes(struct drm_panel *panel, +				struct drm_connector *connector)  {  	struct panel_lvds *lvds = to_panel_lvds(panel); - -	if (lvds->backlight) { -		lvds->backlight->props.state &= ~BL_CORE_FBBLANK; -		lvds->backlight->props.power = FB_BLANK_UNBLANK; -		backlight_update_status(lvds->backlight); -	} - -	return 0; -} - -static int panel_lvds_get_modes(struct drm_panel *panel) -{ -	struct panel_lvds *lvds = to_panel_lvds(panel); -	struct drm_connector *connector = lvds->panel.connector;  	struct drm_display_mode *mode; -	mode = drm_mode_create(lvds->panel.drm); +	mode = drm_mode_create(connector->dev);  	if (!mode)  		return 0; @@ -132,10 +104,8 @@ static int panel_lvds_get_modes(struct drm_panel *panel)  }  static const struct drm_panel_funcs panel_lvds_funcs = { -	.disable = panel_lvds_disable,  	.unprepare = panel_lvds_unprepare,  	.prepare = panel_lvds_prepare, -	.enable = panel_lvds_enable,  	.get_modes = panel_lvds_get_modes,  }; @@ -242,10 +212,6 @@ static int panel_lvds_probe(struct platform_device *pdev)  		return ret;  	} -	lvds->backlight = devm_of_find_backlight(lvds->dev); -	if (IS_ERR(lvds->backlight)) -		return PTR_ERR(lvds->backlight); -  	/*  	 * TODO: Handle all power supplies specified in the DT node in a generic  	 * way for panels that don't care about power supply ordering. LVDS @@ -257,6 +223,10 @@ static int panel_lvds_probe(struct platform_device *pdev)  	drm_panel_init(&lvds->panel, lvds->dev, &panel_lvds_funcs,  		       DRM_MODE_CONNECTOR_LVDS); +	ret = drm_panel_of_backlight(&lvds->panel); +	if (ret) +		return ret; +  	ret = drm_panel_add(&lvds->panel);  	if (ret < 0)  		return ret; @@ -271,7 +241,7 @@ static int panel_lvds_remove(struct platform_device *pdev)  	drm_panel_remove(&lvds->panel); -	panel_lvds_disable(&lvds->panel); +	drm_panel_disable(&lvds->panel);  	return 0;  } diff --git a/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c b/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c index fd593532ab23..c4f83f6384e1 100644 --- a/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c +++ b/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c @@ -123,12 +123,12 @@ static const struct drm_display_mode nl8048_mode = {  	.height_mm = 53,  }; -static int nl8048_get_modes(struct drm_panel *panel) +static int nl8048_get_modes(struct drm_panel *panel, +			    struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &nl8048_mode); +	mode = drm_mode_duplicate(connector->dev, &nl8048_mode);  	if (!mode)  		return -ENOMEM; diff --git a/drivers/gpu/drm/panel/panel-novatek-nt39016.c b/drivers/gpu/drm/panel/panel-novatek-nt39016.c index 60ccedce530c..a470810f7dbe 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt39016.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt39016.c @@ -206,14 +206,14 @@ static int nt39016_disable(struct drm_panel *drm_panel)  	return 0;  } -static int nt39016_get_modes(struct drm_panel *drm_panel) +static int nt39016_get_modes(struct drm_panel *drm_panel, +			     struct drm_connector *connector)  {  	struct nt39016 *panel = to_nt39016(drm_panel);  	const struct nt39016_panel_info *panel_info = panel->panel_info; -	struct drm_connector *connector = drm_panel->connector;  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(drm_panel->drm, &panel_info->display_mode); +	mode = drm_mode_duplicate(connector->dev, &panel_info->display_mode);  	if (!mode)  		return -ENOMEM; diff --git a/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c b/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c index f2a72ee6ee07..09deb99981a4 100644 --- a/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c +++ b/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c @@ -6,7 +6,6 @@   *   Author: Stefan Mavrodiev <[email protected]>   */ -#include <linux/backlight.h>  #include <linux/crc32.h>  #include <linux/gpio/consumer.h>  #include <linux/i2c.h> @@ -68,7 +67,6 @@ struct lcd_olinuxino {  	bool prepared;  	bool enabled; -	struct backlight_device *backlight;  	struct regulator *supply;  	struct gpio_desc *enable_gpio; @@ -87,8 +85,6 @@ static int lcd_olinuxino_disable(struct drm_panel *panel)  	if (!lcd->enabled)  		return 0; -	backlight_disable(lcd->backlight); -  	lcd->enabled = false;  	return 0; @@ -134,19 +130,16 @@ static int lcd_olinuxino_enable(struct drm_panel *panel)  	if (lcd->enabled)  		return 0; -	backlight_enable(lcd->backlight); -  	lcd->enabled = true;  	return 0;  } -static int lcd_olinuxino_get_modes(struct drm_panel *panel) +static int lcd_olinuxino_get_modes(struct drm_panel *panel, +				   struct drm_connector *connector)  {  	struct lcd_olinuxino *lcd = to_lcd_olinuxino(panel); -	struct drm_connector *connector = lcd->panel.connector;  	struct lcd_olinuxino_info *lcd_info = &lcd->eeprom.info; -	struct drm_device *drm = lcd->panel.drm;  	struct lcd_olinuxino_mode *lcd_mode;  	struct drm_display_mode *mode;  	u32 i, num = 0; @@ -155,13 +148,13 @@ static int lcd_olinuxino_get_modes(struct drm_panel *panel)  		lcd_mode = (struct lcd_olinuxino_mode *)  			   &lcd->eeprom.reserved[i * sizeof(*lcd_mode)]; -		mode = drm_mode_create(drm); +		mode = drm_mode_create(connector->dev);  		if (!mode) { -			dev_err(drm->dev, "failed to add mode %ux%u@%u\n", +			dev_err(panel->dev, "failed to add mode %ux%u@%u\n",  				lcd_mode->hactive,  				lcd_mode->vactive,  				lcd_mode->refresh); -				continue; +			continue;  		}  		mode->clock = lcd_mode->pixelclock; @@ -284,13 +277,13 @@ static int lcd_olinuxino_probe(struct i2c_client *client,  	if (IS_ERR(lcd->enable_gpio))  		return PTR_ERR(lcd->enable_gpio); -	lcd->backlight = devm_of_find_backlight(dev); -	if (IS_ERR(lcd->backlight)) -		return PTR_ERR(lcd->backlight); -  	drm_panel_init(&lcd->panel, dev, &lcd_olinuxino_funcs,  		       DRM_MODE_CONNECTOR_DPI); +	ret = drm_panel_of_backlight(&lcd->panel); +	if (ret) +		return ret; +  	return drm_panel_add(&lcd->panel);  } @@ -300,8 +293,8 @@ static int lcd_olinuxino_remove(struct i2c_client *client)  	drm_panel_remove(&panel->panel); -	lcd_olinuxino_disable(&panel->panel); -	lcd_olinuxino_unprepare(&panel->panel); +	drm_panel_disable(&panel->panel); +	drm_panel_unprepare(&panel->panel);  	return 0;  } diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c index bf1f928b215f..bb0c992171e8 100644 --- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c @@ -349,11 +349,12 @@ static int otm8009a_enable(struct drm_panel *panel)  	return 0;  } -static int otm8009a_get_modes(struct drm_panel *panel) +static int otm8009a_get_modes(struct drm_panel *panel, +			      struct drm_connector *connector)  {  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &default_mode); +	mode = drm_mode_duplicate(connector->dev, &default_mode);  	if (!mode) {  		DRM_ERROR("failed to add mode %ux%ux@%u\n",  			  default_mode.hdisplay, default_mode.vdisplay, @@ -364,10 +365,10 @@ static int otm8009a_get_modes(struct drm_panel *panel)  	drm_mode_set_name(mode);  	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; -	drm_mode_probed_add(panel->connector, mode); +	drm_mode_probed_add(connector, mode); -	panel->connector->display_info.width_mm = mode->width_mm; -	panel->connector->display_info.height_mm = mode->height_mm; +	connector->display_info.width_mm = mode->width_mm; +	connector->display_info.height_mm = mode->height_mm;  	return 1;  } diff --git a/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c b/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c index 2b40913899d8..3a0229d60095 100644 --- a/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c +++ b/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c @@ -4,7 +4,6 @@   *  Author: Peter Ujfalusi <[email protected]>   */ -#include <linux/backlight.h>  #include <linux/module.h>  #include <linux/of.h>  #include <linux/regulator/consumer.h> @@ -20,7 +19,6 @@ struct osd101t2587_panel {  	struct drm_panel base;  	struct mipi_dsi_device *dsi; -	struct backlight_device *backlight;  	struct regulator *supply;  	bool prepared; @@ -42,8 +40,6 @@ static int osd101t2587_panel_disable(struct drm_panel *panel)  	if (!osd101t2587->enabled)  		return 0; -	backlight_disable(osd101t2587->backlight); -  	ret = mipi_dsi_shutdown_peripheral(osd101t2587->dsi);  	osd101t2587->enabled = false; @@ -91,8 +87,6 @@ static int osd101t2587_panel_enable(struct drm_panel *panel)  	if (ret)  		return ret; -	backlight_enable(osd101t2587->backlight); -  	osd101t2587->enabled = true;  	return ret; @@ -112,14 +106,15 @@ static const struct drm_display_mode default_mode_osd101t2587 = {  	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,  }; -static int osd101t2587_panel_get_modes(struct drm_panel *panel) +static int osd101t2587_panel_get_modes(struct drm_panel *panel, +				       struct drm_connector *connector)  {  	struct osd101t2587_panel *osd101t2587 = ti_osd_panel(panel);  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, osd101t2587->default_mode); +	mode = drm_mode_duplicate(connector->dev, osd101t2587->default_mode);  	if (!mode) { -		dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n", +		dev_err(panel->dev, "failed to add mode %ux%ux@%u\n",  			osd101t2587->default_mode->hdisplay,  			osd101t2587->default_mode->vdisplay,  			osd101t2587->default_mode->vrefresh); @@ -128,10 +123,10 @@ static int osd101t2587_panel_get_modes(struct drm_panel *panel)  	drm_mode_set_name(mode); -	drm_mode_probed_add(panel->connector, mode); +	drm_mode_probed_add(connector, mode); -	panel->connector->display_info.width_mm = 217; -	panel->connector->display_info.height_mm = 136; +	connector->display_info.width_mm = 217; +	connector->display_info.height_mm = 136;  	return 1;  } @@ -157,18 +152,19 @@ MODULE_DEVICE_TABLE(of, osd101t2587_of_match);  static int osd101t2587_panel_add(struct osd101t2587_panel *osd101t2587)  {  	struct device *dev = &osd101t2587->dsi->dev; +	int ret;  	osd101t2587->supply = devm_regulator_get(dev, "power");  	if (IS_ERR(osd101t2587->supply))  		return PTR_ERR(osd101t2587->supply); -	osd101t2587->backlight = devm_of_find_backlight(dev); -	if (IS_ERR(osd101t2587->backlight)) -		return PTR_ERR(osd101t2587->backlight); -  	drm_panel_init(&osd101t2587->base, &osd101t2587->dsi->dev,  		       &osd101t2587_panel_funcs, DRM_MODE_CONNECTOR_DSI); +	ret = drm_panel_of_backlight(&osd101t2587->base); +	if (ret) +		return ret; +  	return drm_panel_add(&osd101t2587->base);  } @@ -214,12 +210,11 @@ static int osd101t2587_panel_remove(struct mipi_dsi_device *dsi)  	struct osd101t2587_panel *osd101t2587 = mipi_dsi_get_drvdata(dsi);  	int ret; -	ret = osd101t2587_panel_disable(&osd101t2587->base); +	ret = drm_panel_disable(&osd101t2587->base);  	if (ret < 0)  		dev_warn(&dsi->dev, "failed to disable panel: %d\n", ret); -	osd101t2587_panel_unprepare(&osd101t2587->base); - +	drm_panel_unprepare(&osd101t2587->base);  	drm_panel_remove(&osd101t2587->base);  	ret = mipi_dsi_detach(dsi); @@ -233,8 +228,8 @@ static void osd101t2587_panel_shutdown(struct mipi_dsi_device *dsi)  {  	struct osd101t2587_panel *osd101t2587 = mipi_dsi_get_drvdata(dsi); -	osd101t2587_panel_disable(&osd101t2587->base); -	osd101t2587_panel_unprepare(&osd101t2587->base); +	drm_panel_disable(&osd101t2587->base); +	drm_panel_unprepare(&osd101t2587->base);  }  static struct mipi_dsi_driver osd101t2587_panel_driver = { diff --git a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c index 664605071d34..69693451462e 100644 --- a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c +++ b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c @@ -7,7 +7,6 @@   * Based on AUO panel driver by Rob Clark <[email protected]>   */ -#include <linux/backlight.h>  #include <linux/delay.h>  #include <linux/module.h>  #include <linux/of.h> @@ -31,7 +30,6 @@ struct wuxga_nt_panel {  	struct drm_panel base;  	struct mipi_dsi_device *dsi; -	struct backlight_device *backlight;  	struct regulator *supply;  	bool prepared; @@ -62,12 +60,6 @@ static int wuxga_nt_panel_disable(struct drm_panel *panel)  	mipi_ret = mipi_dsi_shutdown_peripheral(wuxga_nt->dsi); -	if (wuxga_nt->backlight) { -		wuxga_nt->backlight->props.power = FB_BLANK_POWERDOWN; -		wuxga_nt->backlight->props.state |= BL_CORE_FBBLANK; -		bl_ret = backlight_update_status(wuxga_nt->backlight); -	} -  	wuxga_nt->enabled = false;  	return mipi_ret ? mipi_ret : bl_ret; @@ -142,12 +134,6 @@ static int wuxga_nt_panel_enable(struct drm_panel *panel)  	if (wuxga_nt->enabled)  		return 0; -	if (wuxga_nt->backlight) { -		wuxga_nt->backlight->props.power = FB_BLANK_UNBLANK; -		wuxga_nt->backlight->props.state &= ~BL_CORE_FBBLANK; -		backlight_update_status(wuxga_nt->backlight); -	} -  	wuxga_nt->enabled = true;  	return 0; @@ -166,24 +152,25 @@ static const struct drm_display_mode default_mode = {  	.vrefresh = 60,  }; -static int wuxga_nt_panel_get_modes(struct drm_panel *panel) +static int wuxga_nt_panel_get_modes(struct drm_panel *panel, +				    struct drm_connector *connector)  {  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &default_mode); +	mode = drm_mode_duplicate(connector->dev, &default_mode);  	if (!mode) { -		dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n", -				default_mode.hdisplay, default_mode.vdisplay, -				default_mode.vrefresh); +		dev_err(panel->dev, "failed to add mode %ux%u@%u\n", +			default_mode.hdisplay, default_mode.vdisplay, +			default_mode.vrefresh);  		return -ENOMEM;  	}  	drm_mode_set_name(mode); -	drm_mode_probed_add(panel->connector, mode); +	drm_mode_probed_add(connector, mode); -	panel->connector->display_info.width_mm = 217; -	panel->connector->display_info.height_mm = 136; +	connector->display_info.width_mm = 217; +	connector->display_info.height_mm = 136;  	return 1;  } @@ -205,7 +192,6 @@ MODULE_DEVICE_TABLE(of, wuxga_nt_of_match);  static int wuxga_nt_panel_add(struct wuxga_nt_panel *wuxga_nt)  {  	struct device *dev = &wuxga_nt->dsi->dev; -	struct device_node *np;  	int ret;  	wuxga_nt->mode = &default_mode; @@ -214,38 +200,20 @@ static int wuxga_nt_panel_add(struct wuxga_nt_panel *wuxga_nt)  	if (IS_ERR(wuxga_nt->supply))  		return PTR_ERR(wuxga_nt->supply); -	np = of_parse_phandle(dev->of_node, "backlight", 0); -	if (np) { -		wuxga_nt->backlight = of_find_backlight_by_node(np); -		of_node_put(np); - -		if (!wuxga_nt->backlight) -			return -EPROBE_DEFER; -	} -  	drm_panel_init(&wuxga_nt->base, &wuxga_nt->dsi->dev,  		       &wuxga_nt_panel_funcs, DRM_MODE_CONNECTOR_DSI); -	ret = drm_panel_add(&wuxga_nt->base); -	if (ret < 0) -		goto put_backlight; - -	return 0; - -put_backlight: -	if (wuxga_nt->backlight) -		put_device(&wuxga_nt->backlight->dev); +	ret = drm_panel_of_backlight(&wuxga_nt->base); +	if (ret) +		return ret; -	return ret; +	return drm_panel_add(&wuxga_nt->base);  }  static void wuxga_nt_panel_del(struct wuxga_nt_panel *wuxga_nt)  {  	if (wuxga_nt->base.dev)  		drm_panel_remove(&wuxga_nt->base); - -	if (wuxga_nt->backlight) -		put_device(&wuxga_nt->backlight->dev);  }  static int wuxga_nt_panel_probe(struct mipi_dsi_device *dsi) @@ -280,7 +248,7 @@ static int wuxga_nt_panel_remove(struct mipi_dsi_device *dsi)  	struct wuxga_nt_panel *wuxga_nt = mipi_dsi_get_drvdata(dsi);  	int ret; -	ret = wuxga_nt_panel_disable(&wuxga_nt->base); +	ret = drm_panel_disable(&wuxga_nt->base);  	if (ret < 0)  		dev_err(&dsi->dev, "failed to disable panel: %d\n", ret); @@ -297,7 +265,7 @@ static void wuxga_nt_panel_shutdown(struct mipi_dsi_device *dsi)  {  	struct wuxga_nt_panel *wuxga_nt = mipi_dsi_get_drvdata(dsi); -	wuxga_nt_panel_disable(&wuxga_nt->base); +	drm_panel_disable(&wuxga_nt->base);  }  static struct mipi_dsi_driver wuxga_nt_panel_driver = { diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c index 09824e92fc78..8f078b7dd89e 100644 --- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c +++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c @@ -44,8 +44,6 @@  #include <linux/delay.h>  #include <linux/err.h>  #include <linux/fb.h> -#include <linux/gpio.h> -#include <linux/gpio/consumer.h>  #include <linux/i2c.h>  #include <linux/module.h>  #include <linux/of.h> @@ -311,10 +309,9 @@ static int rpi_touchscreen_enable(struct drm_panel *panel)  	return 0;  } -static int rpi_touchscreen_get_modes(struct drm_panel *panel) +static int rpi_touchscreen_get_modes(struct drm_panel *panel, +				     struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector; -	struct drm_device *drm = panel->drm;  	unsigned int i, num = 0;  	static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; @@ -322,9 +319,9 @@ static int rpi_touchscreen_get_modes(struct drm_panel *panel)  		const struct drm_display_mode *m = &rpi_touchscreen_modes[i];  		struct drm_display_mode *mode; -		mode = drm_mode_duplicate(drm, m); +		mode = drm_mode_duplicate(connector->dev, m);  		if (!mode) { -			dev_err(drm->dev, "failed to add mode %ux%u@%u\n", +			dev_err(panel->dev, "failed to add mode %ux%u@%u\n",  				m->hdisplay, m->vdisplay, m->vrefresh);  			continue;  		} diff --git a/drivers/gpu/drm/panel/panel-raydium-rm67191.c b/drivers/gpu/drm/panel/panel-raydium-rm67191.c index fd67fc6185c4..313637d53d28 100644 --- a/drivers/gpu/drm/panel/panel-raydium-rm67191.c +++ b/drivers/gpu/drm/panel/panel-raydium-rm67191.c @@ -436,12 +436,12 @@ static int rad_panel_disable(struct drm_panel *panel)  	return 0;  } -static int rad_panel_get_modes(struct drm_panel *panel) +static int rad_panel_get_modes(struct drm_panel *panel, +			       struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &default_mode); +	mode = drm_mode_duplicate(connector->dev, &default_mode);  	if (!mode) {  		DRM_DEV_ERROR(panel->dev, "failed to add mode %ux%ux@%u\n",  			      default_mode.hdisplay, default_mode.vdisplay, @@ -451,7 +451,7 @@ static int rad_panel_get_modes(struct drm_panel *panel)  	drm_mode_set_name(mode);  	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; -	drm_mode_probed_add(panel->connector, mode); +	drm_mode_probed_add(connector, mode);  	connector->display_info.width_mm = mode->width_mm;  	connector->display_info.height_mm = mode->height_mm; diff --git a/drivers/gpu/drm/panel/panel-raydium-rm68200.c b/drivers/gpu/drm/panel/panel-raydium-rm68200.c index 994e855721f4..e8982948e0ea 100644 --- a/drivers/gpu/drm/panel/panel-raydium-rm68200.c +++ b/drivers/gpu/drm/panel/panel-raydium-rm68200.c @@ -6,9 +6,9 @@   *          Yannick Fertre <[email protected]>   */ -#include <linux/backlight.h>  #include <linux/delay.h>  #include <linux/gpio/consumer.h> +#include <linux/mod_devicetable.h>  #include <linux/module.h>  #include <linux/regulator/consumer.h> @@ -78,7 +78,6 @@ struct rm68200 {  	struct drm_panel panel;  	struct gpio_desc *reset_gpio;  	struct regulator *supply; -	struct backlight_device *backlight;  	bool prepared;  	bool enabled;  }; @@ -242,8 +241,6 @@ static int rm68200_disable(struct drm_panel *panel)  	if (!ctx->enabled)  		return 0; -	backlight_disable(ctx->backlight); -  	ctx->enabled = false;  	return 0; @@ -328,18 +325,17 @@ static int rm68200_enable(struct drm_panel *panel)  	if (ctx->enabled)  		return 0; -	backlight_enable(ctx->backlight); -  	ctx->enabled = true;  	return 0;  } -static int rm68200_get_modes(struct drm_panel *panel) +static int rm68200_get_modes(struct drm_panel *panel, +			     struct drm_connector *connector)  {  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &default_mode); +	mode = drm_mode_duplicate(connector->dev, &default_mode);  	if (!mode) {  		DRM_ERROR("failed to add mode %ux%ux@%u\n",  			  default_mode.hdisplay, default_mode.vdisplay, @@ -350,10 +346,10 @@ static int rm68200_get_modes(struct drm_panel *panel)  	drm_mode_set_name(mode);  	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; -	drm_mode_probed_add(panel->connector, mode); +	drm_mode_probed_add(connector, mode); -	panel->connector->display_info.width_mm = mode->width_mm; -	panel->connector->display_info.height_mm = mode->height_mm; +	connector->display_info.width_mm = mode->width_mm; +	connector->display_info.height_mm = mode->height_mm;  	return 1;  } @@ -391,10 +387,6 @@ static int rm68200_probe(struct mipi_dsi_device *dsi)  		return ret;  	} -	ctx->backlight = devm_of_find_backlight(dev); -	if (IS_ERR(ctx->backlight)) -		return PTR_ERR(ctx->backlight); -  	mipi_dsi_set_drvdata(dsi, ctx);  	ctx->dev = dev; @@ -407,6 +399,10 @@ static int rm68200_probe(struct mipi_dsi_device *dsi)  	drm_panel_init(&ctx->panel, dev, &rm68200_drm_funcs,  		       DRM_MODE_CONNECTOR_DSI); +	ret = drm_panel_of_backlight(&ctx->panel); +	if (ret) +		return ret; +  	drm_panel_add(&ctx->panel);  	ret = mipi_dsi_attach(dsi); diff --git a/drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c b/drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c index 31234b79d3b1..38ff742bc120 100644 --- a/drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c +++ b/drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c @@ -5,20 +5,22 @@   * Copyright (C) Purism SPC 2019   */ -#include <drm/drm_mipi_dsi.h> -#include <drm/drm_modes.h> -#include <drm/drm_panel.h> -#include <drm/drm_print.h> -#include <linux/backlight.h>  #include <linux/debugfs.h>  #include <linux/delay.h>  #include <linux/gpio/consumer.h>  #include <linux/media-bus-format.h> +#include <linux/mod_devicetable.h>  #include <linux/module.h>  #include <linux/regulator/consumer.h> +  #include <video/display_timing.h>  #include <video/mipi_display.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> +#include <drm/drm_print.h> +  #define DRV_NAME "panel-rocktech-jh057n00900"  /* Manufacturer specific Commands send via DSI */ @@ -47,7 +49,6 @@ struct jh057n {  	struct device *dev;  	struct drm_panel panel;  	struct gpio_desc *reset_gpio; -	struct backlight_device *backlight;  	struct regulator *vcc;  	struct regulator *iovcc;  	bool prepared; @@ -152,7 +153,7 @@ static int jh057n_enable(struct drm_panel *panel)  		return ret;  	} -	return backlight_enable(ctx->backlight); +	return 0;  }  static int jh057n_disable(struct drm_panel *panel) @@ -160,7 +161,6 @@ static int jh057n_disable(struct drm_panel *panel)  	struct jh057n *ctx = panel_to_jh057n(panel);  	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); -	backlight_disable(ctx->backlight);  	return mipi_dsi_dcs_set_display_off(dsi);  } @@ -230,12 +230,13 @@ static const struct drm_display_mode default_mode = {  	.height_mm   = 130,  }; -static int jh057n_get_modes(struct drm_panel *panel) +static int jh057n_get_modes(struct drm_panel *panel, +			    struct drm_connector *connector)  {  	struct jh057n *ctx = panel_to_jh057n(panel);  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &default_mode); +	mode = drm_mode_duplicate(connector->dev, &default_mode);  	if (!mode) {  		DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n",  			      default_mode.hdisplay, default_mode.vdisplay, @@ -246,9 +247,9 @@ static int jh057n_get_modes(struct drm_panel *panel)  	drm_mode_set_name(mode);  	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; -	panel->connector->display_info.width_mm = mode->width_mm; -	panel->connector->display_info.height_mm = mode->height_mm; -	drm_mode_probed_add(panel->connector, mode); +	connector->display_info.width_mm = mode->width_mm; +	connector->display_info.height_mm = mode->height_mm; +	drm_mode_probed_add(connector, mode);  	return 1;  } @@ -320,10 +321,6 @@ static int jh057n_probe(struct mipi_dsi_device *dsi)  	dsi->mode_flags = MIPI_DSI_MODE_VIDEO |  		MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; -	ctx->backlight = devm_of_find_backlight(dev); -	if (IS_ERR(ctx->backlight)) -		return PTR_ERR(ctx->backlight); -  	ctx->vcc = devm_regulator_get(dev, "vcc");  	if (IS_ERR(ctx->vcc)) {  		ret = PTR_ERR(ctx->vcc); @@ -346,6 +343,10 @@ static int jh057n_probe(struct mipi_dsi_device *dsi)  	drm_panel_init(&ctx->panel, dev, &jh057n_drm_funcs,  		       DRM_MODE_CONNECTOR_DSI); +	ret = drm_panel_of_backlight(&ctx->panel); +	if (ret) +		return ret; +  	drm_panel_add(&ctx->panel);  	ret = mipi_dsi_attach(dsi); diff --git a/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c b/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c index 170a5cda21b9..ef18559e237e 100644 --- a/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c +++ b/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c @@ -7,7 +7,6 @@   * This file based on panel-ilitek-ili9881c.c   */ -#include <linux/backlight.h>  #include <linux/delay.h>  #include <linux/device.h>  #include <linux/err.h> @@ -29,7 +28,6 @@  struct rb070d30_panel {  	struct drm_panel panel;  	struct mipi_dsi_device *dsi; -	struct backlight_device *backlight;  	struct regulator *supply;  	struct { @@ -84,22 +82,13 @@ static int rb070d30_panel_enable(struct drm_panel *panel)  	if (ret)  		return ret; -	ret = backlight_enable(ctx->backlight); -	if (ret) -		goto out; -  	return 0; - -out: -	mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); -	return ret;  }  static int rb070d30_panel_disable(struct drm_panel *panel)  {  	struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel); -	backlight_disable(ctx->backlight);  	return mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);  } @@ -120,14 +109,14 @@ static const struct drm_display_mode default_mode = {  	.height_mm	= 85,  }; -static int rb070d30_panel_get_modes(struct drm_panel *panel) +static int rb070d30_panel_get_modes(struct drm_panel *panel, +				    struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);  	struct drm_display_mode *mode;  	static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; -	mode = drm_mode_duplicate(panel->drm, &default_mode); +	mode = drm_mode_duplicate(connector->dev, &default_mode);  	if (!mode) {  		DRM_DEV_ERROR(&ctx->dsi->dev,  			      "Failed to add mode " DRM_MODE_FMT "\n", @@ -140,9 +129,9 @@ static int rb070d30_panel_get_modes(struct drm_panel *panel)  	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;  	drm_mode_probed_add(connector, mode); -	panel->connector->display_info.bpc = 8; -	panel->connector->display_info.width_mm = mode->width_mm; -	panel->connector->display_info.height_mm = mode->height_mm; +	connector->display_info.bpc = 8; +	connector->display_info.width_mm = mode->width_mm; +	connector->display_info.height_mm = mode->height_mm;  	drm_display_info_set_bus_formats(&connector->display_info,  					 &bus_format, 1); @@ -208,11 +197,9 @@ static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi)  		return PTR_ERR(ctx->gpios.shlr);  	} -	ctx->backlight = devm_of_find_backlight(&dsi->dev); -	if (IS_ERR(ctx->backlight)) { -		DRM_DEV_ERROR(&dsi->dev, "Couldn't get our backlight\n"); -		return PTR_ERR(ctx->backlight); -	} +	ret = drm_panel_of_backlight(&ctx->panel); +	if (ret) +		return ret;  	ret = drm_panel_add(&ctx->panel);  	if (ret < 0) diff --git a/drivers/gpu/drm/panel/panel-samsung-ld9040.c b/drivers/gpu/drm/panel/panel-samsung-ld9040.c index 250809ba37c7..3c52f15f7a1c 100644 --- a/drivers/gpu/drm/panel/panel-samsung-ld9040.c +++ b/drivers/gpu/drm/panel/panel-samsung-ld9040.c @@ -261,9 +261,9 @@ static int ld9040_enable(struct drm_panel *panel)  	return 0;  } -static int ld9040_get_modes(struct drm_panel *panel) +static int ld9040_get_modes(struct drm_panel *panel, +			    struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct ld9040 *ctx = panel_to_ld9040(panel);  	struct drm_display_mode *mode; diff --git a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c index e3a0397e953e..2150043dcf6b 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c @@ -143,12 +143,12 @@ static int s6d16d0_disable(struct drm_panel *panel)  	return 0;  } -static int s6d16d0_get_modes(struct drm_panel *panel) +static int s6d16d0_get_modes(struct drm_panel *panel, +			     struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &samsung_s6d16d0_mode); +	mode = drm_mode_duplicate(connector->dev, &samsung_s6d16d0_mode);  	if (!mode) {  		DRM_ERROR("bad mode or failed to add mode\n");  		return -EINVAL; diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c index 938ab72c5540..36ebd5a4ac7b 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c @@ -645,13 +645,13 @@ static const struct s6e3ha2_panel_desc samsung_s6e3hf2 = {  	.type = HF2_TYPE,  }; -static int s6e3ha2_get_modes(struct drm_panel *panel) +static int s6e3ha2_get_modes(struct drm_panel *panel, +			     struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, ctx->desc->mode); +	mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);  	if (!mode) {  		DRM_ERROR("failed to add mode %ux%ux@%u\n",  			ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c index a60635e9226d..a3570e0a90a8 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c @@ -400,12 +400,12 @@ static int s6e63j0x03_enable(struct drm_panel *panel)  	return 0;  } -static int s6e63j0x03_get_modes(struct drm_panel *panel) +static int s6e63j0x03_get_modes(struct drm_panel *panel, +				struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &default_mode); +	mode = drm_mode_duplicate(connector->dev, &default_mode);  	if (!mode) {  		DRM_ERROR("failed to add mode %ux%ux@%u\n",  			default_mode.hdisplay, default_mode.vdisplay, diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c index ba01af0b14fd..a5f76eb4fa25 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c @@ -362,12 +362,12 @@ static int s6e63m0_enable(struct drm_panel *panel)  	return 0;  } -static int s6e63m0_get_modes(struct drm_panel *panel) +static int s6e63m0_get_modes(struct drm_panel *panel, +			     struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &default_mode); +	mode = drm_mode_duplicate(connector->dev, &default_mode);  	if (!mode) {  		DRM_ERROR("failed to add mode %ux%ux@%u\n",  			  default_mode.hdisplay, default_mode.vdisplay, diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c index dbced6501204..8a028d2bd0d6 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c @@ -920,9 +920,9 @@ static int s6e8aa0_enable(struct drm_panel *panel)  	return 0;  } -static int s6e8aa0_get_modes(struct drm_panel *panel) +static int s6e8aa0_get_modes(struct drm_panel *panel, +			     struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel);  	struct drm_display_mode *mode; diff --git a/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c b/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c index b3619ba443bd..40fcbbbacb2c 100644 --- a/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c +++ b/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c @@ -6,7 +6,6 @@   * Based on Panel Simple driver by Thierry Reding <[email protected]>   */ -#include <linux/backlight.h>  #include <linux/delay.h>  #include <linux/module.h>  #include <linux/of.h> @@ -46,7 +45,6 @@ struct seiko_panel {  	bool prepared;  	bool enabled;  	const struct seiko_panel_desc *desc; -	struct backlight_device *backlight;  	struct regulator *dvdd;  	struct regulator *avdd;  }; @@ -56,10 +54,9 @@ static inline struct seiko_panel *to_seiko_panel(struct drm_panel *panel)  	return container_of(panel, struct seiko_panel, base);  } -static int seiko_panel_get_fixed_modes(struct seiko_panel *panel) +static int seiko_panel_get_fixed_modes(struct seiko_panel *panel, +				       struct drm_connector *connector)  { -	struct drm_connector *connector = panel->base.connector; -	struct drm_device *drm = panel->base.drm;  	struct drm_display_mode *mode;  	unsigned int i, num = 0; @@ -71,9 +68,9 @@ static int seiko_panel_get_fixed_modes(struct seiko_panel *panel)  		struct videomode vm;  		videomode_from_timing(dt, &vm); -		mode = drm_mode_create(drm); +		mode = drm_mode_create(connector->dev);  		if (!mode) { -			dev_err(drm->dev, "failed to add mode %ux%u\n", +			dev_err(panel->base.dev, "failed to add mode %ux%u\n",  				dt->hactive.typ, dt->vactive.typ);  			continue;  		} @@ -92,9 +89,9 @@ static int seiko_panel_get_fixed_modes(struct seiko_panel *panel)  	for (i = 0; i < panel->desc->num_modes; i++) {  		const struct drm_display_mode *m = &panel->desc->modes[i]; -		mode = drm_mode_duplicate(drm, m); +		mode = drm_mode_duplicate(connector->dev, m);  		if (!mode) { -			dev_err(drm->dev, "failed to add mode %ux%u@%u\n", +			dev_err(panel->base.dev, "failed to add mode %ux%u@%u\n",  				m->hdisplay, m->vdisplay, m->vrefresh);  			continue;  		} @@ -128,12 +125,6 @@ static int seiko_panel_disable(struct drm_panel *panel)  	if (!p->enabled)  		return 0; -	if (p->backlight) { -		p->backlight->props.power = FB_BLANK_POWERDOWN; -		p->backlight->props.state |= BL_CORE_FBBLANK; -		backlight_update_status(p->backlight); -	} -  	p->enabled = false;  	return 0; @@ -197,23 +188,18 @@ static int seiko_panel_enable(struct drm_panel *panel)  	if (p->enabled)  		return 0; -	if (p->backlight) { -		p->backlight->props.state &= ~BL_CORE_FBBLANK; -		p->backlight->props.power = FB_BLANK_UNBLANK; -		backlight_update_status(p->backlight); -	} -  	p->enabled = true;  	return 0;  } -static int seiko_panel_get_modes(struct drm_panel *panel) +static int seiko_panel_get_modes(struct drm_panel *panel, +				 struct drm_connector *connector)  {  	struct seiko_panel *p = to_seiko_panel(panel);  	/* add hard-coded panel modes */ -	return seiko_panel_get_fixed_modes(p); +	return seiko_panel_get_fixed_modes(p, connector);  }  static int seiko_panel_get_timings(struct drm_panel *panel, @@ -245,7 +231,6 @@ static const struct drm_panel_funcs seiko_panel_funcs = {  static int seiko_panel_probe(struct device *dev,  					const struct seiko_panel_desc *desc)  { -	struct device_node *backlight;  	struct seiko_panel *panel;  	int err; @@ -265,18 +250,13 @@ static int seiko_panel_probe(struct device *dev,  	if (IS_ERR(panel->avdd))  		return PTR_ERR(panel->avdd); -	backlight = of_parse_phandle(dev->of_node, "backlight", 0); -	if (backlight) { -		panel->backlight = of_find_backlight_by_node(backlight); -		of_node_put(backlight); - -		if (!panel->backlight) -			return -EPROBE_DEFER; -	} -  	drm_panel_init(&panel->base, dev, &seiko_panel_funcs,  		       DRM_MODE_CONNECTOR_DPI); +	err = drm_panel_of_backlight(&panel->base); +	if (err) +		return err; +  	err = drm_panel_add(&panel->base);  	if (err < 0)  		return err; @@ -291,11 +271,7 @@ static int seiko_panel_remove(struct platform_device *pdev)  	struct seiko_panel *panel = dev_get_drvdata(&pdev->dev);  	drm_panel_remove(&panel->base); - -	seiko_panel_disable(&panel->base); - -	if (panel->backlight) -		put_device(&panel->backlight->dev); +	drm_panel_disable(&panel->base);  	return 0;  } @@ -304,7 +280,7 @@ static void seiko_panel_shutdown(struct platform_device *pdev)  {  	struct seiko_panel *panel = dev_get_drvdata(&pdev->dev); -	seiko_panel_disable(&panel->base); +	drm_panel_disable(&panel->base);  }  static const struct display_timing seiko_43wvf1g_timing = { diff --git a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c index 5e136c3ba185..b5d1977221a7 100644 --- a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c +++ b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c @@ -3,7 +3,6 @@   * Copyright (C) 2014 NVIDIA Corporation   */ -#include <linux/backlight.h>  #include <linux/delay.h>  #include <linux/gpio/consumer.h>  #include <linux/module.h> @@ -23,7 +22,6 @@ struct sharp_panel {  	struct mipi_dsi_device *link1;  	struct mipi_dsi_device *link2; -	struct backlight_device *backlight;  	struct regulator *supply;  	bool prepared; @@ -94,8 +92,6 @@ static int sharp_panel_disable(struct drm_panel *panel)  	if (!sharp->enabled)  		return 0; -	backlight_disable(sharp->backlight); -  	sharp->enabled = false;  	return 0; @@ -258,8 +254,6 @@ static int sharp_panel_enable(struct drm_panel *panel)  	if (sharp->enabled)  		return 0; -	backlight_enable(sharp->backlight); -  	sharp->enabled = true;  	return 0; @@ -278,13 +272,14 @@ static const struct drm_display_mode default_mode = {  	.vrefresh = 60,  }; -static int sharp_panel_get_modes(struct drm_panel *panel) +static int sharp_panel_get_modes(struct drm_panel *panel, +				 struct drm_connector *connector)  {  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &default_mode); +	mode = drm_mode_duplicate(connector->dev, &default_mode);  	if (!mode) { -		dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n", +		dev_err(panel->dev, "failed to add mode %ux%ux@%u\n",  			default_mode.hdisplay, default_mode.vdisplay,  			default_mode.vrefresh);  		return -ENOMEM; @@ -292,10 +287,10 @@ static int sharp_panel_get_modes(struct drm_panel *panel)  	drm_mode_set_name(mode); -	drm_mode_probed_add(panel->connector, mode); +	drm_mode_probed_add(connector, mode); -	panel->connector->display_info.width_mm = 217; -	panel->connector->display_info.height_mm = 136; +	connector->display_info.width_mm = 217; +	connector->display_info.height_mm = 136;  	return 1;  } @@ -316,7 +311,7 @@ MODULE_DEVICE_TABLE(of, sharp_of_match);  static int sharp_panel_add(struct sharp_panel *sharp)  { -	struct device *dev = &sharp->link1->dev; +	int ret;  	sharp->mode = &default_mode; @@ -324,14 +319,13 @@ static int sharp_panel_add(struct sharp_panel *sharp)  	if (IS_ERR(sharp->supply))  		return PTR_ERR(sharp->supply); -	sharp->backlight = devm_of_find_backlight(dev); - -	if (IS_ERR(sharp->backlight)) -		return PTR_ERR(sharp->backlight); -  	drm_panel_init(&sharp->base, &sharp->link1->dev, &sharp_panel_funcs,  		       DRM_MODE_CONNECTOR_DSI); +	ret = drm_panel_of_backlight(&sharp->base); +	if (ret) +		return ret; +  	return drm_panel_add(&sharp->base);  } @@ -407,7 +401,7 @@ static int sharp_panel_remove(struct mipi_dsi_device *dsi)  		return 0;  	} -	err = sharp_panel_disable(&sharp->base); +	err = drm_panel_disable(&sharp->base);  	if (err < 0)  		dev_err(&dsi->dev, "failed to disable panel: %d\n", err); @@ -428,7 +422,7 @@ static void sharp_panel_shutdown(struct mipi_dsi_device *dsi)  	if (!sharp)  		return; -	sharp_panel_disable(&sharp->base); +	drm_panel_disable(&sharp->base);  }  static struct mipi_dsi_driver sharp_panel_driver = { diff --git a/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c b/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c index eeab7998c7de..1cf3f02435c1 100644 --- a/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c +++ b/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c @@ -100,12 +100,12 @@ static const struct drm_display_mode ls037v7dw01_mode = {  	.height_mm = 75,  }; -static int ls037v7dw01_get_modes(struct drm_panel *panel) +static int ls037v7dw01_get_modes(struct drm_panel *panel, +				 struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &ls037v7dw01_mode); +	mode = drm_mode_duplicate(connector->dev, &ls037v7dw01_mode);  	if (!mode)  		return -ENOMEM; diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c index b963ba4ab589..ce586c6d70c7 100644 --- a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c @@ -7,7 +7,6 @@   * Based on AUO panel driver by Rob Clark <[email protected]>   */ -#include <linux/backlight.h>  #include <linux/delay.h>  #include <linux/gpio/consumer.h>  #include <linux/module.h> @@ -25,7 +24,6 @@ struct sharp_nt_panel {  	struct drm_panel base;  	struct mipi_dsi_device *dsi; -	struct backlight_device *backlight;  	struct regulator *supply;  	struct gpio_desc *reset_gpio; @@ -107,8 +105,6 @@ static int sharp_nt_panel_disable(struct drm_panel *panel)  	if (!sharp_nt->enabled)  		return 0; -	backlight_disable(sharp_nt->backlight); -  	sharp_nt->enabled = false;  	return 0; @@ -190,8 +186,6 @@ static int sharp_nt_panel_enable(struct drm_panel *panel)  	if (sharp_nt->enabled)  		return 0; -	backlight_enable(sharp_nt->backlight); -  	sharp_nt->enabled = true;  	return 0; @@ -210,24 +204,25 @@ static const struct drm_display_mode default_mode = {  	.vrefresh = 60,  }; -static int sharp_nt_panel_get_modes(struct drm_panel *panel) +static int sharp_nt_panel_get_modes(struct drm_panel *panel, +				    struct drm_connector *connector)  {  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &default_mode); +	mode = drm_mode_duplicate(connector->dev, &default_mode);  	if (!mode) { -		dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n", -				default_mode.hdisplay, default_mode.vdisplay, -				default_mode.vrefresh); +		dev_err(panel->dev, "failed to add mode %ux%u@%u\n", +			default_mode.hdisplay, default_mode.vdisplay, +			default_mode.vrefresh);  		return -ENOMEM;  	}  	drm_mode_set_name(mode); -	drm_mode_probed_add(panel->connector, mode); +	drm_mode_probed_add(connector, mode); -	panel->connector->display_info.width_mm = 54; -	panel->connector->display_info.height_mm = 95; +	connector->display_info.width_mm = 54; +	connector->display_info.height_mm = 95;  	return 1;  } @@ -243,6 +238,7 @@ static const struct drm_panel_funcs sharp_nt_panel_funcs = {  static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt)  {  	struct device *dev = &sharp_nt->dsi->dev; +	int ret;  	sharp_nt->mode = &default_mode; @@ -259,14 +255,13 @@ static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt)  		gpiod_set_value(sharp_nt->reset_gpio, 0);  	} -	sharp_nt->backlight = devm_of_find_backlight(dev); - -	if (IS_ERR(sharp_nt->backlight)) -		return PTR_ERR(sharp_nt->backlight); -  	drm_panel_init(&sharp_nt->base, &sharp_nt->dsi->dev,  		       &sharp_nt_panel_funcs, DRM_MODE_CONNECTOR_DSI); +	ret = drm_panel_of_backlight(&sharp_nt->base); +	if (ret) +		return ret; +  	return drm_panel_add(&sharp_nt->base);  } @@ -308,7 +303,7 @@ static int sharp_nt_panel_remove(struct mipi_dsi_device *dsi)  	struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi);  	int ret; -	ret = sharp_nt_panel_disable(&sharp_nt->base); +	ret = drm_panel_disable(&sharp_nt->base);  	if (ret < 0)  		dev_err(&dsi->dev, "failed to disable panel: %d\n", ret); @@ -325,7 +320,7 @@ static void sharp_nt_panel_shutdown(struct mipi_dsi_device *dsi)  {  	struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi); -	sharp_nt_panel_disable(&sharp_nt->base); +	drm_panel_disable(&sharp_nt->base);  }  static const struct of_device_id sharp_nt_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 5d487686d25c..e14c14ac62b5 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -21,7 +21,6 @@   * DEALINGS IN THE SOFTWARE.   */ -#include <linux/backlight.h>  #include <linux/delay.h>  #include <linux/gpio/consumer.h>  #include <linux/module.h> @@ -105,7 +104,6 @@ struct panel_simple {  	const struct panel_desc *desc; -	struct backlight_device *backlight;  	struct regulator *supply;  	struct i2c_adapter *ddc; @@ -119,10 +117,9 @@ static inline struct panel_simple *to_panel_simple(struct drm_panel *panel)  	return container_of(panel, struct panel_simple, base);  } -static unsigned int panel_simple_get_timings_modes(struct panel_simple *panel) +static unsigned int panel_simple_get_timings_modes(struct panel_simple *panel, +						   struct drm_connector *connector)  { -	struct drm_connector *connector = panel->base.connector; -	struct drm_device *drm = panel->base.drm;  	struct drm_display_mode *mode;  	unsigned int i, num = 0; @@ -131,9 +128,9 @@ static unsigned int panel_simple_get_timings_modes(struct panel_simple *panel)  		struct videomode vm;  		videomode_from_timing(dt, &vm); -		mode = drm_mode_create(drm); +		mode = drm_mode_create(connector->dev);  		if (!mode) { -			dev_err(drm->dev, "failed to add mode %ux%u\n", +			dev_err(panel->base.dev, "failed to add mode %ux%u\n",  				dt->hactive.typ, dt->vactive.typ);  			continue;  		} @@ -152,19 +149,18 @@ static unsigned int panel_simple_get_timings_modes(struct panel_simple *panel)  	return num;  } -static unsigned int panel_simple_get_display_modes(struct panel_simple *panel) +static unsigned int panel_simple_get_display_modes(struct panel_simple *panel, +						   struct drm_connector *connector)  { -	struct drm_connector *connector = panel->base.connector; -	struct drm_device *drm = panel->base.drm;  	struct drm_display_mode *mode;  	unsigned int i, num = 0;  	for (i = 0; i < panel->desc->num_modes; i++) {  		const struct drm_display_mode *m = &panel->desc->modes[i]; -		mode = drm_mode_duplicate(drm, m); +		mode = drm_mode_duplicate(connector->dev, m);  		if (!mode) { -			dev_err(drm->dev, "failed to add mode %ux%u@%u\n", +			dev_err(panel->base.dev, "failed to add mode %ux%u@%u\n",  				m->hdisplay, m->vdisplay, m->vrefresh);  			continue;  		} @@ -183,10 +179,9 @@ static unsigned int panel_simple_get_display_modes(struct panel_simple *panel)  	return num;  } -static int panel_simple_get_non_edid_modes(struct panel_simple *panel) +static int panel_simple_get_non_edid_modes(struct panel_simple *panel, +					   struct drm_connector *connector)  { -	struct drm_connector *connector = panel->base.connector; -	struct drm_device *drm = panel->base.drm;  	struct drm_display_mode *mode;  	bool has_override = panel->override_mode.type;  	unsigned int num = 0; @@ -195,18 +190,19 @@ static int panel_simple_get_non_edid_modes(struct panel_simple *panel)  		return 0;  	if (has_override) { -		mode = drm_mode_duplicate(drm, &panel->override_mode); +		mode = drm_mode_duplicate(connector->dev, +					  &panel->override_mode);  		if (mode) {  			drm_mode_probed_add(connector, mode);  			num = 1;  		} else { -			dev_err(drm->dev, "failed to add override mode\n"); +			dev_err(panel->base.dev, "failed to add override mode\n");  		}  	}  	/* Only add timings if override was not there or failed to validate */  	if (num == 0 && panel->desc->num_timings) -		num = panel_simple_get_timings_modes(panel); +		num = panel_simple_get_timings_modes(panel, connector);  	/*  	 * Only add fixed modes if timings/override added no mode. @@ -216,7 +212,7 @@ static int panel_simple_get_non_edid_modes(struct panel_simple *panel)  	 */  	WARN_ON(panel->desc->num_timings && panel->desc->num_modes);  	if (num == 0) -		num = panel_simple_get_display_modes(panel); +		num = panel_simple_get_display_modes(panel, connector);  	connector->display_info.bpc = panel->desc->bpc;  	connector->display_info.width_mm = panel->desc->size.width; @@ -236,12 +232,6 @@ static int panel_simple_disable(struct drm_panel *panel)  	if (!p->enabled)  		return 0; -	if (p->backlight) { -		p->backlight->props.power = FB_BLANK_POWERDOWN; -		p->backlight->props.state |= BL_CORE_FBBLANK; -		backlight_update_status(p->backlight); -	} -  	if (p->desc->delay.disable)  		msleep(p->desc->delay.disable); @@ -307,34 +297,30 @@ static int panel_simple_enable(struct drm_panel *panel)  	if (p->desc->delay.enable)  		msleep(p->desc->delay.enable); -	if (p->backlight) { -		p->backlight->props.state &= ~BL_CORE_FBBLANK; -		p->backlight->props.power = FB_BLANK_UNBLANK; -		backlight_update_status(p->backlight); -	} -  	p->enabled = true;  	return 0;  } -static int panel_simple_get_modes(struct drm_panel *panel) +static int panel_simple_get_modes(struct drm_panel *panel, +				  struct drm_connector *connector)  {  	struct panel_simple *p = to_panel_simple(panel);  	int num = 0;  	/* probe EDID if a DDC bus is available */  	if (p->ddc) { -		struct edid *edid = drm_get_edid(panel->connector, p->ddc); -		drm_connector_update_edid_property(panel->connector, edid); +		struct edid *edid = drm_get_edid(connector, p->ddc); + +		drm_connector_update_edid_property(connector, edid);  		if (edid) { -			num += drm_add_edid_modes(panel->connector, edid); +			num += drm_add_edid_modes(connector, edid);  			kfree(edid);  		}  	}  	/* add hard-coded panel modes */ -	num += panel_simple_get_non_edid_modes(p); +	num += panel_simple_get_non_edid_modes(p, connector);  	return num;  } @@ -414,9 +400,9 @@ static void panel_simple_parse_panel_timing_node(struct device *dev,  static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)  { -	struct device_node *backlight, *ddc;  	struct panel_simple *panel;  	struct display_timing dt; +	struct device_node *ddc;  	int err;  	panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL); @@ -442,24 +428,13 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)  		return err;  	} -	backlight = of_parse_phandle(dev->of_node, "backlight", 0); -	if (backlight) { -		panel->backlight = of_find_backlight_by_node(backlight); -		of_node_put(backlight); - -		if (!panel->backlight) -			return -EPROBE_DEFER; -	} -  	ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0);  	if (ddc) {  		panel->ddc = of_find_i2c_adapter_by_node(ddc);  		of_node_put(ddc); -		if (!panel->ddc) { -			err = -EPROBE_DEFER; -			goto free_backlight; -		} +		if (!panel->ddc) +			return -EPROBE_DEFER;  	}  	if (!of_get_display_timing(dev->of_node, "panel-timing", &dt)) @@ -468,6 +443,10 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)  	drm_panel_init(&panel->base, dev, &panel_simple_funcs,  		       desc->connector_type); +	err = drm_panel_of_backlight(&panel->base); +	if (err) +		goto free_ddc; +  	err = drm_panel_add(&panel->base);  	if (err < 0)  		goto free_ddc; @@ -479,9 +458,6 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)  free_ddc:  	if (panel->ddc)  		put_device(&panel->ddc->dev); -free_backlight: -	if (panel->backlight) -		put_device(&panel->backlight->dev);  	return err;  } @@ -491,16 +467,12 @@ static int panel_simple_remove(struct device *dev)  	struct panel_simple *panel = dev_get_drvdata(dev);  	drm_panel_remove(&panel->base); - -	panel_simple_disable(&panel->base); -	panel_simple_unprepare(&panel->base); +	drm_panel_disable(&panel->base); +	drm_panel_unprepare(&panel->base);  	if (panel->ddc)  		put_device(&panel->ddc->dev); -	if (panel->backlight) -		put_device(&panel->backlight->dev); -  	return 0;  } @@ -508,8 +480,8 @@ static void panel_simple_shutdown(struct device *dev)  {  	struct panel_simple *panel = dev_get_drvdata(dev); -	panel_simple_disable(&panel->base); -	panel_simple_unprepare(&panel->base); +	drm_panel_disable(&panel->base); +	drm_panel_unprepare(&panel->base);  }  static const struct drm_display_mode ampire_am_480272h3tmqw_t01h_mode = { @@ -657,6 +629,35 @@ static const struct panel_desc auo_b101xtn01 = {  	},  }; +static const struct drm_display_mode auo_b116xak01_mode = { +	.clock = 69300, +	.hdisplay = 1366, +	.hsync_start = 1366 + 48, +	.hsync_end = 1366 + 48 + 32, +	.htotal = 1366 + 48 + 32 + 10, +	.vdisplay = 768, +	.vsync_start = 768 + 4, +	.vsync_end = 768 + 4 + 6, +	.vtotal = 768 + 4 + 6 + 15, +	.vrefresh = 60, +	.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, +}; + +static const struct panel_desc auo_b116xak01 = { +	.modes = &auo_b116xak01_mode, +	.num_modes = 1, +	.bpc = 6, +	.size = { +		.width = 256, +		.height = 144, +	}, +	.delay = { +		.hpd_absent_delay = 200, +	}, +	.bus_format = MEDIA_BUS_FMT_RGB666_1X18, +	.connector_type = DRM_MODE_CONNECTOR_eDP, +}; +  static const struct drm_display_mode auo_b116xw03_mode = {  	.clock = 70589,  	.hdisplay = 1366, @@ -1036,6 +1037,38 @@ static const struct panel_desc boe_nv101wxmn51 = {  	},  }; +static const struct drm_display_mode boe_nv140fhmn49_modes[] = { +	{ +		.clock = 148500, +		.hdisplay = 1920, +		.hsync_start = 1920 + 48, +		.hsync_end = 1920 + 48 + 32, +		.htotal = 2200, +		.vdisplay = 1080, +		.vsync_start = 1080 + 3, +		.vsync_end = 1080 + 3 + 5, +		.vtotal = 1125, +		.vrefresh = 60, +	}, +}; + +static const struct panel_desc boe_nv140fhmn49 = { +	.modes = boe_nv140fhmn49_modes, +	.num_modes = ARRAY_SIZE(boe_nv140fhmn49_modes), +	.bpc = 6, +	.size = { +		.width = 309, +		.height = 174, +	}, +	.delay = { +		.prepare = 210, +		.enable = 50, +		.unprepare = 160, +	}, +	.bus_format = MEDIA_BUS_FMT_RGB666_1X18, +	.connector_type = DRM_MODE_CONNECTOR_eDP, +}; +  static const struct drm_display_mode cdtech_s043wq26h_ct7_mode = {  	.clock = 9000,  	.hdisplay = 480, @@ -2061,6 +2094,40 @@ static const struct drm_display_mode mitsubishi_aa070mc01_mode = {  	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,  }; +static const struct drm_display_mode logicpd_type_28_mode = { +	.clock = 9000, +	.hdisplay = 480, +	.hsync_start = 480 + 3, +	.hsync_end = 480 + 3 + 42, +	.htotal = 480 + 3 + 42 + 2, + +	.vdisplay = 272, +	.vsync_start = 272 + 2, +	.vsync_end = 272 + 2 + 11, +	.vtotal = 272 + 2 + 11 + 3, +	.vrefresh = 60, +	.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, +}; + +static const struct panel_desc logicpd_type_28 = { +	.modes = &logicpd_type_28_mode, +	.num_modes = 1, +	.bpc = 8, +	.size = { +		.width = 105, +		.height = 67, +	}, +	.delay = { +		.prepare = 200, +		.enable = 200, +		.unprepare = 200, +		.disable = 200, +	}, +	.bus_format = MEDIA_BUS_FMT_RGB888_1X24, +	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE | +		     DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE, +}; +  static const struct panel_desc mitsubishi_aa070mc01 = {  	.modes = &mitsubishi_aa070mc01_mode,  	.num_modes = 1, @@ -2547,6 +2614,30 @@ static const struct panel_desc samsung_ltn140at29_301 = {  	},  }; +static const struct display_timing satoz_sat050at40h12r2_timing = { +	.pixelclock = {33300000, 33300000, 50000000}, +	.hactive = {800, 800, 800}, +	.hfront_porch = {16, 210, 354}, +	.hback_porch = {46, 46, 46}, +	.hsync_len = {1, 1, 40}, +	.vactive = {480, 480, 480}, +	.vfront_porch = {7, 22, 147}, +	.vback_porch = {23, 23, 23}, +	.vsync_len = {1, 1, 20}, +}; + +static const struct panel_desc satoz_sat050at40h12r2 = { +	.timings = &satoz_sat050at40h12r2_timing, +	.num_timings = 1, +	.bpc = 8, +	.size = { +		.width = 108, +		.height = 65, +	}, +	.bus_format = MEDIA_BUS_FMT_RGB888_1X24, +	.connector_type = DRM_MODE_CONNECTOR_LVDS, +}; +  static const struct drm_display_mode sharp_ld_d5116z01b_mode = {  	.clock = 168480,  	.hdisplay = 1920, @@ -3120,6 +3211,9 @@ static const struct of_device_id platform_of_match[] = {  		.compatible = "auo,b101xtn01",  		.data = &auo_b101xtn01,  	}, { +		.compatible = "auo,b116xa01", +		.data = &auo_b116xak01, +	}, {  		.compatible = "auo,b116xw03",  		.data = &auo_b116xw03,  	}, { @@ -3162,6 +3256,9 @@ static const struct of_device_id platform_of_match[] = {  		.compatible = "boe,nv101wxmn51",  		.data = &boe_nv101wxmn51,  	}, { +		.compatible = "boe,nv140fhmn49", +		.data = &boe_nv140fhmn49, +	}, {  		.compatible = "cdtech,s043wq26h-ct7",  		.data = &cdtech_s043wq26h_ct7,  	}, { @@ -3288,6 +3385,9 @@ static const struct of_device_id platform_of_match[] = {  		.compatible = "lg,lp129qe",  		.data = &lg_lp129qe,  	}, { +		.compatible = "logicpd,type28", +		.data = &logicpd_type_28, +	}, {  		.compatible = "mitsubishi,aa070mc01-ca1",  		.data = &mitsubishi_aa070mc01,  	}, { @@ -3348,6 +3448,9 @@ static const struct of_device_id platform_of_match[] = {  		.compatible = "samsung,ltn140at29-301",  		.data = &samsung_ltn140at29_301,  	}, { +		.compatible = "satoz,sat050at40h12r2", +		.data = &satoz_sat050at40h12r2, +	}, {  		.compatible = "sharp,ld-d5116z01b",  		.data = &sharp_ld_d5116z01b,  	}, { diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7701.c b/drivers/gpu/drm/panel/panel-sitronix-st7701.c index ee3f23f45755..4b4f2558e3b4 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7701.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7701.c @@ -9,7 +9,6 @@  #include <drm/drm_panel.h>  #include <drm/drm_print.h> -#include <linux/backlight.h>  #include <linux/gpio/consumer.h>  #include <linux/delay.h>  #include <linux/module.h> @@ -103,7 +102,6 @@ struct st7701 {  	struct mipi_dsi_device *dsi;  	const struct st7701_panel_desc *desc; -	struct backlight_device *backlight;  	struct regulator_bulk_data *supplies;  	struct gpio_desc *reset;  	unsigned int sleep_delay; @@ -223,7 +221,6 @@ static int st7701_enable(struct drm_panel *panel)  	struct st7701 *st7701 = panel_to_st7701(panel);  	ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_ON, 0x00); -	backlight_enable(st7701->backlight);  	return 0;  } @@ -232,7 +229,6 @@ static int st7701_disable(struct drm_panel *panel)  {  	struct st7701 *st7701 = panel_to_st7701(panel); -	backlight_disable(st7701->backlight);  	ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_OFF, 0x00);  	return 0; @@ -264,13 +260,14 @@ static int st7701_unprepare(struct drm_panel *panel)  	return 0;  } -static int st7701_get_modes(struct drm_panel *panel) +static int st7701_get_modes(struct drm_panel *panel, +			    struct drm_connector *connector)  {  	struct st7701 *st7701 = panel_to_st7701(panel);  	const struct drm_display_mode *desc_mode = st7701->desc->mode;  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, desc_mode); +	mode = drm_mode_duplicate(connector->dev, desc_mode);  	if (!mode) {  		DRM_DEV_ERROR(&st7701->dsi->dev,  			      "failed to add mode %ux%ux@%u\n", @@ -280,10 +277,10 @@ static int st7701_get_modes(struct drm_panel *panel)  	}  	drm_mode_set_name(mode); -	drm_mode_probed_add(panel->connector, mode); +	drm_mode_probed_add(connector, mode); -	panel->connector->display_info.width_mm = desc_mode->width_mm; -	panel->connector->display_info.height_mm = desc_mode->height_mm; +	connector->display_info.width_mm = desc_mode->width_mm; +	connector->display_info.height_mm = desc_mode->height_mm;  	return 1;  } @@ -365,10 +362,6 @@ static int st7701_dsi_probe(struct mipi_dsi_device *dsi)  		return PTR_ERR(st7701->reset);  	} -	st7701->backlight = devm_of_find_backlight(&dsi->dev); -	if (IS_ERR(st7701->backlight)) -		return PTR_ERR(st7701->backlight); -  	drm_panel_init(&st7701->panel, &dsi->dev, &st7701_funcs,  		       DRM_MODE_CONNECTOR_DSI); @@ -383,6 +376,10 @@ static int st7701_dsi_probe(struct mipi_dsi_device *dsi)  	 */  	st7701->sleep_delay = 120 + desc->panel_sleep_delay; +	ret = drm_panel_of_backlight(&st7701->panel); +	if (ret) +		return ret; +  	ret = drm_panel_add(&st7701->panel);  	if (ret < 0)  		return ret; diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c index 108a85bb6667..cc02c54c1b2e 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c @@ -3,7 +3,6 @@   * Copyright (C) 2017 Free Electrons   */ -#include <linux/backlight.h>  #include <linux/delay.h>  #include <linux/gpio/consumer.h>  #include <linux/module.h> @@ -116,7 +115,6 @@ struct st7789v {  	struct drm_panel panel;  	struct spi_device *spi;  	struct gpio_desc *reset; -	struct backlight_device *backlight;  	struct regulator *power;  }; @@ -170,14 +168,14 @@ static const struct drm_display_mode default_mode = {  	.vrefresh = 60,  }; -static int st7789v_get_modes(struct drm_panel *panel) +static int st7789v_get_modes(struct drm_panel *panel, +			     struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &default_mode); +	mode = drm_mode_duplicate(connector->dev, &default_mode);  	if (!mode) { -		dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n", +		dev_err(panel->dev, "failed to add mode %ux%ux@%u\n",  			default_mode.hdisplay, default_mode.vdisplay,  			default_mode.vrefresh);  		return -ENOMEM; @@ -188,8 +186,8 @@ static int st7789v_get_modes(struct drm_panel *panel)  	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;  	drm_mode_probed_add(connector, mode); -	panel->connector->display_info.width_mm = 61; -	panel->connector->display_info.height_mm = 103; +	connector->display_info.width_mm = 61; +	connector->display_info.height_mm = 103;  	return 1;  } @@ -323,12 +321,6 @@ static int st7789v_enable(struct drm_panel *panel)  {  	struct st7789v *ctx = panel_to_st7789v(panel); -	if (ctx->backlight) { -		ctx->backlight->props.state &= ~BL_CORE_FBBLANK; -		ctx->backlight->props.power = FB_BLANK_UNBLANK; -		backlight_update_status(ctx->backlight); -	} -  	return st7789v_write_command(ctx, MIPI_DCS_SET_DISPLAY_ON);  } @@ -339,12 +331,6 @@ static int st7789v_disable(struct drm_panel *panel)  	ST7789V_TEST(ret, st7789v_write_command(ctx, MIPI_DCS_SET_DISPLAY_OFF)); -	if (ctx->backlight) { -		ctx->backlight->props.power = FB_BLANK_POWERDOWN; -		ctx->backlight->props.state |= BL_CORE_FBBLANK; -		backlight_update_status(ctx->backlight); -	} -  	return 0;  } @@ -370,7 +356,6 @@ static const struct drm_panel_funcs st7789v_drm_funcs = {  static int st7789v_probe(struct spi_device *spi)  { -	struct device_node *backlight;  	struct st7789v *ctx;  	int ret; @@ -394,26 +379,15 @@ static int st7789v_probe(struct spi_device *spi)  		return PTR_ERR(ctx->reset);  	} -	backlight = of_parse_phandle(spi->dev.of_node, "backlight", 0); -	if (backlight) { -		ctx->backlight = of_find_backlight_by_node(backlight); -		of_node_put(backlight); - -		if (!ctx->backlight) -			return -EPROBE_DEFER; -	} +	ret = drm_panel_of_backlight(&ctx->panel); +	if (ret) +		return ret;  	ret = drm_panel_add(&ctx->panel);  	if (ret < 0) -		goto err_free_backlight; +		return ret;  	return 0; - -err_free_backlight: -	if (ctx->backlight) -		put_device(&ctx->backlight->dev); - -	return ret;  }  static int st7789v_remove(struct spi_device *spi) @@ -422,9 +396,6 @@ static int st7789v_remove(struct spi_device *spi)  	drm_panel_remove(&ctx->panel); -	if (ctx->backlight) -		put_device(&ctx->backlight->dev); -  	return 0;  } diff --git a/drivers/gpu/drm/panel/panel-sony-acx424akp.c b/drivers/gpu/drm/panel/panel-sony-acx424akp.c new file mode 100644 index 000000000000..de0abf76ae6f --- /dev/null +++ b/drivers/gpu/drm/panel/panel-sony-acx424akp.c @@ -0,0 +1,550 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * MIPI-DSI Sony ACX424AKP panel driver. This is a 480x864 + * AMOLED panel with a command-only DSI interface. + * + * Copyright (C) Linaro Ltd. 2019 + * Author: Linus Walleij + * Based on code and know-how from Marcus Lorentzon + * Copyright (C) ST-Ericsson SA 2010 + */ +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> +#include <drm/drm_print.h> + +#define ACX424_DCS_READ_ID1		0xDA +#define ACX424_DCS_READ_ID2		0xDB +#define ACX424_DCS_READ_ID3		0xDC +#define ACX424_DCS_SET_MDDI		0xAE + +/* + * Sony seems to use vendor ID 0x81 + */ +#define DISPLAY_SONY_ACX424AKP_ID1	0x811b +#define DISPLAY_SONY_ACX424AKP_ID2	0x811a +/* + * The third ID looks like a bug, vendor IDs begin at 0x80 + * and panel 00 ... seems like default values. + */ +#define DISPLAY_SONY_ACX424AKP_ID3	0x8000 + +struct acx424akp { +	struct drm_panel panel; +	struct device *dev; +	struct backlight_device *bl; +	struct regulator *supply; +	struct gpio_desc *reset_gpio; +	bool video_mode; +}; + +static const struct drm_display_mode sony_acx424akp_vid_mode = { +	.clock = 330000, +	.hdisplay = 480, +	.hsync_start = 480 + 15, +	.hsync_end = 480 + 15 + 0, +	.htotal = 480 + 15 + 0 + 15, +	.vdisplay = 864, +	.vsync_start = 864 + 14, +	.vsync_end = 864 + 14 + 1, +	.vtotal = 864 + 14 + 1 + 11, +	.vrefresh = 60, +	.width_mm = 48, +	.height_mm = 84, +	.flags = DRM_MODE_FLAG_PVSYNC, +}; + +/* + * The timings are not very helpful as the display is used in + * command mode using the maximum HS frequency. + */ +static const struct drm_display_mode sony_acx424akp_cmd_mode = { +	.clock = 420160, +	.hdisplay = 480, +	.hsync_start = 480 + 154, +	.hsync_end = 480 + 154 + 16, +	.htotal = 480 + 154 + 16 + 32, +	.vdisplay = 864, +	.vsync_start = 864 + 1, +	.vsync_end = 864 + 1 + 1, +	.vtotal = 864 + 1 + 1 + 1, +	/* +	 * Some desired refresh rate, experiments at the maximum "pixel" +	 * clock speed (HS clock 420 MHz) yields around 117Hz. +	 */ +	.vrefresh = 60, +	.width_mm = 48, +	.height_mm = 84, +}; + +static inline struct acx424akp *panel_to_acx424akp(struct drm_panel *panel) +{ +	return container_of(panel, struct acx424akp, panel); +} + +#define FOSC			20 /* 20Mhz */ +#define SCALE_FACTOR_NS_DIV_MHZ	1000 + +static int acx424akp_set_brightness(struct backlight_device *bl) +{ +	struct acx424akp *acx = bl_get_data(bl); +	struct mipi_dsi_device *dsi = to_mipi_dsi_device(acx->dev); +	int period_ns = 1023; +	int duty_ns = bl->props.brightness; +	u8 pwm_ratio; +	u8 pwm_div; +	u8 par; +	int ret; + +	/* Calculate the PWM duty cycle in n/256's */ +	pwm_ratio = max(((duty_ns * 256) / period_ns) - 1, 1); +	pwm_div = max(1, +		      ((FOSC * period_ns) / 256) / +		      SCALE_FACTOR_NS_DIV_MHZ); + +	/* Set up PWM dutycycle ONE byte (differs from the standard) */ +	DRM_DEV_DEBUG(acx->dev, "calculated duty cycle %02x\n", pwm_ratio); +	ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, +				 &pwm_ratio, 1); +	if (ret < 0) { +		DRM_DEV_ERROR(acx->dev, +			      "failed to set display PWM ratio (%d)\n", +			      ret); +		return ret; +	} + +	/* +	 * Sequence to write PWMDIV: +	 *	address		data +	 *	0xF3		0xAA   CMD2 Unlock +	 *	0x00		0x01   Enter CMD2 page 0 +	 *	0X7D		0x01   No reload MTP of CMD2 P1 +	 *	0x22		PWMDIV +	 *	0x7F		0xAA   CMD2 page 1 lock +	 */ +	par = 0xaa; +	ret = mipi_dsi_dcs_write(dsi, 0xf3, &par, 1); +	if (ret < 0) { +		DRM_DEV_ERROR(acx->dev, +			      "failed to unlock CMD 2 (%d)\n", +			      ret); +		return ret; +	} +	par = 0x01; +	ret = mipi_dsi_dcs_write(dsi, 0x00, &par, 1); +	if (ret < 0) { +		DRM_DEV_ERROR(acx->dev, +			      "failed to enter page 1 (%d)\n", +			      ret); +		return ret; +	} +	par = 0x01; +	ret = mipi_dsi_dcs_write(dsi, 0x7d, &par, 1); +	if (ret < 0) { +		DRM_DEV_ERROR(acx->dev, +			      "failed to disable MTP reload (%d)\n", +			      ret); +		return ret; +	} +	ret = mipi_dsi_dcs_write(dsi, 0x22, &pwm_div, 1); +	if (ret < 0) { +		DRM_DEV_ERROR(acx->dev, +			      "failed to set PWM divisor (%d)\n", +			      ret); +		return ret; +	} +	par = 0xaa; +	ret = mipi_dsi_dcs_write(dsi, 0x7f, &par, 1); +	if (ret < 0) { +		DRM_DEV_ERROR(acx->dev, +			      "failed to lock CMD 2 (%d)\n", +			      ret); +		return ret; +	} + +	/* Enable backlight */ +	par = 0x24; +	ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, +				 &par, 1); +	if (ret < 0) { +		DRM_DEV_ERROR(acx->dev, +			      "failed to enable display backlight (%d)\n", +			      ret); +		return ret; +	} + +	return 0; +} + +static const struct backlight_ops acx424akp_bl_ops = { +	.update_status = acx424akp_set_brightness, +}; + +static int acx424akp_read_id(struct acx424akp *acx) +{ +	struct mipi_dsi_device *dsi = to_mipi_dsi_device(acx->dev); +	u8 vendor, version, panel; +	u16 val; +	int ret; + +	ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID1, &vendor, 1); +	if (ret < 0) { +		DRM_DEV_ERROR(acx->dev, "could not vendor ID byte\n"); +		return ret; +	} +	ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID2, &version, 1); +	if (ret < 0) { +		DRM_DEV_ERROR(acx->dev, "could not read device version byte\n"); +		return ret; +	} +	ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID3, &panel, 1); +	if (ret < 0) { +		DRM_DEV_ERROR(acx->dev, "could not read panel ID byte\n"); +		return ret; +	} + +	if (vendor == 0x00) { +		DRM_DEV_ERROR(acx->dev, "device vendor ID is zero\n"); +		return -ENODEV; +	} + +	val = (vendor << 8) | panel; +	switch (val) { +	case DISPLAY_SONY_ACX424AKP_ID1: +	case DISPLAY_SONY_ACX424AKP_ID2: +	case DISPLAY_SONY_ACX424AKP_ID3: +		DRM_DEV_INFO(acx->dev, +			     "MTP vendor: %02x, version: %02x, panel: %02x\n", +			     vendor, version, panel); +		break; +	default: +		DRM_DEV_INFO(acx->dev, +			     "unknown vendor: %02x, version: %02x, panel: %02x\n", +			     vendor, version, panel); +		break; +	} + +	return 0; +} + +static int acx424akp_power_on(struct acx424akp *acx) +{ +	int ret; + +	ret = regulator_enable(acx->supply); +	if (ret) { +		DRM_DEV_ERROR(acx->dev, "failed to enable supply (%d)\n", ret); +		return ret; +	} + +	/* Assert RESET */ +	gpiod_set_value_cansleep(acx->reset_gpio, 1); +	udelay(20); +	/* De-assert RESET */ +	gpiod_set_value_cansleep(acx->reset_gpio, 0); +	usleep_range(11000, 20000); + +	return 0; +} + +static void acx424akp_power_off(struct acx424akp *acx) +{ +	/* Assert RESET */ +	gpiod_set_value_cansleep(acx->reset_gpio, 1); +	usleep_range(11000, 20000); + +	regulator_disable(acx->supply); +} + +static int acx424akp_prepare(struct drm_panel *panel) +{ +	struct acx424akp *acx = panel_to_acx424akp(panel); +	struct mipi_dsi_device *dsi = to_mipi_dsi_device(acx->dev); +	const u8 mddi = 3; +	int ret; + +	ret = acx424akp_power_on(acx); +	if (ret) +		return ret; + +	ret = acx424akp_read_id(acx); +	if (ret) { +		DRM_DEV_ERROR(acx->dev, "failed to read panel ID (%d)\n", ret); +		goto err_power_off; +	} + +	/* Enabe tearing mode: send TE (tearing effect) at VBLANK */ +	ret = mipi_dsi_dcs_set_tear_on(dsi, +				       MIPI_DSI_DCS_TEAR_MODE_VBLANK); +	if (ret) { +		DRM_DEV_ERROR(acx->dev, "failed to enable vblank TE (%d)\n", +			      ret); +		goto err_power_off; +	} + +	/* +	 * Set MDDI +	 * +	 * This presumably deactivates the Qualcomm MDDI interface and +	 * selects DSI, similar code is found in other drivers such as the +	 * Sharp LS043T1LE01 which makes us suspect that this panel may be +	 * using a Novatek NT35565 or similar display driver chip that shares +	 * this command. Due to the lack of documentation we cannot know for +	 * sure. +	 */ +	ret = mipi_dsi_dcs_write(dsi, ACX424_DCS_SET_MDDI, +				 &mddi, sizeof(mddi)); +	if (ret < 0) { +		DRM_DEV_ERROR(acx->dev, "failed to set MDDI (%d)\n", ret); +		goto err_power_off; +	} + +	/* Exit sleep mode */ +	ret = mipi_dsi_dcs_exit_sleep_mode(dsi); +	if (ret) { +		DRM_DEV_ERROR(acx->dev, "failed to exit sleep mode (%d)\n", +			      ret); +		goto err_power_off; +	} +	msleep(140); + +	ret = mipi_dsi_dcs_set_display_on(dsi); +	if (ret) { +		DRM_DEV_ERROR(acx->dev, "failed to turn display on (%d)\n", +			      ret); +		goto err_power_off; +	} +	if (acx->video_mode) { +		/* In video mode turn peripheral on */ +		ret = mipi_dsi_turn_on_peripheral(dsi); +		if (ret) { +			dev_err(acx->dev, "failed to turn on peripheral\n"); +			goto err_power_off; +		} +	} + +	acx->bl->props.power = FB_BLANK_NORMAL; + +	return 0; + +err_power_off: +	acx424akp_power_off(acx); +	return ret; +} + +static int acx424akp_unprepare(struct drm_panel *panel) +{ +	struct acx424akp *acx = panel_to_acx424akp(panel); +	struct mipi_dsi_device *dsi = to_mipi_dsi_device(acx->dev); +	u8 par; +	int ret; + +	/* Disable backlight */ +	par = 0x00; +	ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, +				 &par, 1); +	if (ret) { +		DRM_DEV_ERROR(acx->dev, +			      "failed to disable display backlight (%d)\n", +			      ret); +		return ret; +	} + +	ret = mipi_dsi_dcs_set_display_off(dsi); +	if (ret) { +		DRM_DEV_ERROR(acx->dev, "failed to turn display off (%d)\n", +			      ret); +		return ret; +	} + +	/* Enter sleep mode */ +	ret = mipi_dsi_dcs_enter_sleep_mode(dsi); +	if (ret) { +		DRM_DEV_ERROR(acx->dev, "failed to enter sleep mode (%d)\n", +			      ret); +		return ret; +	} +	msleep(85); + +	acx424akp_power_off(acx); +	acx->bl->props.power = FB_BLANK_POWERDOWN; + +	return 0; +} + +static int acx424akp_enable(struct drm_panel *panel) +{ +	struct acx424akp *acx = panel_to_acx424akp(panel); + +	/* +	 * The backlight is on as long as the display is on +	 * so no use to call backlight_enable() here. +	 */ +	acx->bl->props.power = FB_BLANK_UNBLANK; + +	return 0; +} + +static int acx424akp_disable(struct drm_panel *panel) +{ +	struct acx424akp *acx = panel_to_acx424akp(panel); + +	/* +	 * The backlight is on as long as the display is on +	 * so no use to call backlight_disable() here. +	 */ +	acx->bl->props.power = FB_BLANK_NORMAL; + +	return 0; +} + +static int acx424akp_get_modes(struct drm_panel *panel, +			       struct drm_connector *connector) +{ +	struct acx424akp *acx = panel_to_acx424akp(panel); +	struct drm_display_mode *mode; + +	if (acx->video_mode) +		mode = drm_mode_duplicate(connector->dev, +					  &sony_acx424akp_vid_mode); +	else +		mode = drm_mode_duplicate(connector->dev, +					  &sony_acx424akp_cmd_mode); +	if (!mode) { +		DRM_ERROR("bad mode or failed to add mode\n"); +		return -EINVAL; +	} +	drm_mode_set_name(mode); +	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + +	connector->display_info.width_mm = mode->width_mm; +	connector->display_info.height_mm = mode->height_mm; + +	drm_mode_probed_add(connector, mode); + +	return 1; /* Number of modes */ +} + +static const struct drm_panel_funcs acx424akp_drm_funcs = { +	.disable = acx424akp_disable, +	.unprepare = acx424akp_unprepare, +	.prepare = acx424akp_prepare, +	.enable = acx424akp_enable, +	.get_modes = acx424akp_get_modes, +}; + +static int acx424akp_probe(struct mipi_dsi_device *dsi) +{ +	struct device *dev = &dsi->dev; +	struct acx424akp *acx; +	int ret; + +	acx = devm_kzalloc(dev, sizeof(struct acx424akp), GFP_KERNEL); +	if (!acx) +		return -ENOMEM; +	acx->video_mode = of_property_read_bool(dev->of_node, +						"enforce-video-mode"); + +	mipi_dsi_set_drvdata(dsi, acx); +	acx->dev = dev; + +	dsi->lanes = 2; +	dsi->format = MIPI_DSI_FMT_RGB888; +	/* +	 * FIXME: these come from the ST-Ericsson vendor driver for the +	 * HREF520 and seems to reflect limitations in the PLLs on that +	 * platform, if you have the datasheet, please cross-check the +	 * actual max rates. +	 */ +	dsi->lp_rate = 19200000; +	dsi->hs_rate = 420160000; + +	if (acx->video_mode) +		/* Burst mode using event for sync */ +		dsi->mode_flags = +			MIPI_DSI_MODE_VIDEO | +			MIPI_DSI_MODE_VIDEO_BURST; +	else +		dsi->mode_flags = +			MIPI_DSI_CLOCK_NON_CONTINUOUS | +			MIPI_DSI_MODE_EOT_PACKET; + +	acx->supply = devm_regulator_get(dev, "vddi"); +	if (IS_ERR(acx->supply)) +		return PTR_ERR(acx->supply); + +	/* This asserts RESET by default */ +	acx->reset_gpio = devm_gpiod_get_optional(dev, "reset", +						  GPIOD_OUT_HIGH); +	if (IS_ERR(acx->reset_gpio)) { +		ret = PTR_ERR(acx->reset_gpio); +		if (ret != -EPROBE_DEFER) +			DRM_DEV_ERROR(dev, "failed to request GPIO (%d)\n", +				      ret); +		return ret; +	} + +	drm_panel_init(&acx->panel, dev, &acx424akp_drm_funcs, +		       DRM_MODE_CONNECTOR_DSI); + +	acx->bl = devm_backlight_device_register(dev, "acx424akp", dev, acx, +						 &acx424akp_bl_ops, NULL); +	if (IS_ERR(acx->bl)) { +		DRM_DEV_ERROR(dev, "failed to register backlight device\n"); +		return PTR_ERR(acx->bl); +	} +	acx->bl->props.max_brightness = 1023; +	acx->bl->props.brightness = 512; +	acx->bl->props.power = FB_BLANK_POWERDOWN; + +	ret = drm_panel_add(&acx->panel); +	if (ret < 0) +		return ret; + +	ret = mipi_dsi_attach(dsi); +	if (ret < 0) { +		drm_panel_remove(&acx->panel); +		return ret; +	} + +	return 0; +} + +static int acx424akp_remove(struct mipi_dsi_device *dsi) +{ +	struct acx424akp *acx = mipi_dsi_get_drvdata(dsi); + +	mipi_dsi_detach(dsi); +	drm_panel_remove(&acx->panel); + +	return 0; +} + +static const struct of_device_id acx424akp_of_match[] = { +	{ .compatible = "sony,acx424akp" }, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, acx424akp_of_match); + +static struct mipi_dsi_driver acx424akp_driver = { +	.probe = acx424akp_probe, +	.remove = acx424akp_remove, +	.driver = { +		.name = "panel-sony-acx424akp", +		.of_match_table = acx424akp_of_match, +	}, +}; +module_mipi_dsi_driver(acx424akp_driver); + +MODULE_AUTHOR("Linus Wallei <[email protected]>"); +MODULE_DESCRIPTION("MIPI-DSI Sony acx424akp Panel Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/panel/panel-sony-acx565akm.c b/drivers/gpu/drm/panel/panel-sony-acx565akm.c index d6387d8f88a3..5c4b6f6e5c2d 100644 --- a/drivers/gpu/drm/panel/panel-sony-acx565akm.c +++ b/drivers/gpu/drm/panel/panel-sony-acx565akm.c @@ -521,12 +521,12 @@ static const struct drm_display_mode acx565akm_mode = {  	.height_mm = 46,  }; -static int acx565akm_get_modes(struct drm_panel *panel) +static int acx565akm_get_modes(struct drm_panel *panel, +			       struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &acx565akm_mode); +	mode = drm_mode_duplicate(connector->dev, &acx565akm_mode);  	if (!mode)  		return -ENOMEM; diff --git a/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c b/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c index c44d6a65c0aa..cf29405a2dbe 100644 --- a/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c +++ b/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c @@ -17,7 +17,6 @@   * H. Nikolaus Schaller <[email protected]>   */ -#include <linux/backlight.h>  #include <linux/delay.h>  #include <linux/module.h>  #include <linux/spi/spi.h> @@ -83,7 +82,6 @@ struct td028ttec1_panel {  	struct drm_panel panel;  	struct spi_device *spi; -	struct backlight_device *backlight;  };  #define to_td028ttec1_device(p) container_of(p, struct td028ttec1_panel, panel) @@ -243,8 +241,6 @@ static int td028ttec1_enable(struct drm_panel *panel)  	if (ret)  		return ret; -	backlight_enable(lcd->backlight); -  	return 0;  } @@ -252,8 +248,6 @@ static int td028ttec1_disable(struct drm_panel *panel)  {  	struct td028ttec1_panel *lcd = to_td028ttec1_device(panel); -	backlight_disable(lcd->backlight); -  	jbt_ret_write_0(lcd, JBT_REG_DISPLAY_OFF, NULL);  	return 0; @@ -287,12 +281,12 @@ static const struct drm_display_mode td028ttec1_mode = {  	.height_mm = 58,  }; -static int td028ttec1_get_modes(struct drm_panel *panel) +static int td028ttec1_get_modes(struct drm_panel *panel, +				struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &td028ttec1_mode); +	mode = drm_mode_duplicate(connector->dev, &td028ttec1_mode);  	if (!mode)  		return -ENOMEM; @@ -334,10 +328,6 @@ static int td028ttec1_probe(struct spi_device *spi)  	spi_set_drvdata(spi, lcd);  	lcd->spi = spi; -	lcd->backlight = devm_of_find_backlight(&spi->dev); -	if (IS_ERR(lcd->backlight)) -		return PTR_ERR(lcd->backlight); -  	spi->mode = SPI_MODE_3;  	spi->bits_per_word = 9; @@ -350,6 +340,10 @@ static int td028ttec1_probe(struct spi_device *spi)  	drm_panel_init(&lcd->panel, &lcd->spi->dev, &td028ttec1_funcs,  		       DRM_MODE_CONNECTOR_DPI); +	ret = drm_panel_of_backlight(&lcd->panel); +	if (ret) +		return ret; +  	return drm_panel_add(&lcd->panel);  } diff --git a/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c b/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c index 621b65feec07..75f1f1f1b6de 100644 --- a/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c +++ b/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c @@ -346,12 +346,12 @@ static const struct drm_display_mode td043mtea1_mode = {  	.height_mm = 56,  }; -static int td043mtea1_get_modes(struct drm_panel *panel) +static int td043mtea1_get_modes(struct drm_panel *panel, +				struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct drm_display_mode *mode; -	mode = drm_mode_duplicate(panel->drm, &td043mtea1_mode); +	mode = drm_mode_duplicate(connector->dev, &td043mtea1_mode);  	if (!mode)  		return -ENOMEM; diff --git a/drivers/gpu/drm/panel/panel-tpo-tpg110.c b/drivers/gpu/drm/panel/panel-tpo-tpg110.c index 1a5418ae2ccf..8472d018c16f 100644 --- a/drivers/gpu/drm/panel/panel-tpo-tpg110.c +++ b/drivers/gpu/drm/panel/panel-tpo-tpg110.c @@ -14,13 +14,13 @@  #include <drm/drm_panel.h>  #include <drm/drm_print.h> -#include <linux/backlight.h>  #include <linux/bitops.h>  #include <linux/delay.h>  #include <linux/gpio/consumer.h>  #include <linux/init.h>  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/of.h>  #include <linux/platform_device.h>  #include <linux/spi/spi.h> @@ -77,10 +77,6 @@ struct tpg110 {  	 */  	struct drm_panel panel;  	/** -	 * @backlight: backlight for this panel -	 */ -	struct backlight_device *backlight; -	/**  	 * @panel_type: the panel mode as detected  	 */  	const struct tpg110_panel_mode *panel_mode; @@ -356,8 +352,6 @@ static int tpg110_disable(struct drm_panel *panel)  	val &= ~TPG110_CTRL2_PM;  	tpg110_write_reg(tpg, TPG110_CTRL2_PM, val); -	backlight_disable(tpg->backlight); -  	return 0;  } @@ -366,8 +360,6 @@ static int tpg110_enable(struct drm_panel *panel)  	struct tpg110 *tpg = to_tpg110(panel);  	u8 val; -	backlight_enable(tpg->backlight); -  	/* Take chip out of standby */  	val = tpg110_read_reg(tpg, TPG110_CTRL2_PM);  	val |= TPG110_CTRL2_PM; @@ -384,9 +376,9 @@ static int tpg110_enable(struct drm_panel *panel)   * presents the mode that is configured for the system under use,   * and which is detected by reading the registers of the display.   */ -static int tpg110_get_modes(struct drm_panel *panel) +static int tpg110_get_modes(struct drm_panel *panel, +			    struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct tpg110 *tpg = to_tpg110(panel);  	struct drm_display_mode *mode; @@ -394,7 +386,7 @@ static int tpg110_get_modes(struct drm_panel *panel)  	connector->display_info.height_mm = tpg->height;  	connector->display_info.bus_flags = tpg->panel_mode->bus_flags; -	mode = drm_mode_duplicate(panel->drm, &tpg->panel_mode->mode); +	mode = drm_mode_duplicate(connector->dev, &tpg->panel_mode->mode);  	drm_mode_set_name(mode);  	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; @@ -432,11 +424,6 @@ static int tpg110_probe(struct spi_device *spi)  	if (ret)  		DRM_DEV_ERROR(dev, "no panel height specified\n"); -	/* Look for some optional backlight */ -	tpg->backlight = devm_of_find_backlight(dev); -	if (IS_ERR(tpg->backlight)) -		return PTR_ERR(tpg->backlight); -  	/* This asserts the GRESTB signal, putting the display into reset */  	tpg->grestb = devm_gpiod_get(dev, "grestb", GPIOD_OUT_HIGH);  	if (IS_ERR(tpg->grestb)) { @@ -459,6 +446,11 @@ static int tpg110_probe(struct spi_device *spi)  	drm_panel_init(&tpg->panel, dev, &tpg110_drm_funcs,  		       DRM_MODE_CONNECTOR_DPI); + +	ret = drm_panel_of_backlight(&tpg->panel); +	if (ret) +		return ret; +  	spi_set_drvdata(spi, tpg);  	return drm_panel_add(&tpg->panel); diff --git a/drivers/gpu/drm/panel/panel-truly-nt35597.c b/drivers/gpu/drm/panel/panel-truly-nt35597.c index 0feea2456e14..012ca62bf30e 100644 --- a/drivers/gpu/drm/panel/panel-truly-nt35597.c +++ b/drivers/gpu/drm/panel/panel-truly-nt35597.c @@ -454,9 +454,9 @@ static int truly_nt35597_enable(struct drm_panel *panel)  	return 0;  } -static int truly_nt35597_get_modes(struct drm_panel *panel) +static int truly_nt35597_get_modes(struct drm_panel *panel, +				   struct drm_connector *connector)  { -	struct drm_connector *connector = panel->connector;  	struct truly_nt35597 *ctx = panel_to_ctx(panel);  	struct drm_display_mode *mode;  	const struct nt35597_config *config; diff --git a/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c b/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c new file mode 100644 index 000000000000..1645aceab597 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c @@ -0,0 +1,398 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xinpeng xpp055c272 5.5" MIPI-DSI panel driver + * Copyright (C) 2019 Theobroma Systems Design und Consulting GmbH + * + * based on + * + * Rockteck jh057n00900 5.5" MIPI-DSI panel driver + * Copyright (C) Purism SPC 2019 + */ + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> +#include <drm/drm_print.h> + +#include <video/display_timing.h> +#include <video/mipi_display.h> + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/media-bus-format.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regulator/consumer.h> + +/* Manufacturer specific Commands send via DSI */ +#define XPP055C272_CMD_ALL_PIXEL_OFF	0x22 +#define XPP055C272_CMD_ALL_PIXEL_ON	0x23 +#define XPP055C272_CMD_SETDISP		0xb2 +#define XPP055C272_CMD_SETRGBIF		0xb3 +#define XPP055C272_CMD_SETCYC		0xb4 +#define XPP055C272_CMD_SETBGP		0xb5 +#define XPP055C272_CMD_SETVCOM		0xb6 +#define XPP055C272_CMD_SETOTP		0xb7 +#define XPP055C272_CMD_SETPOWER_EXT	0xb8 +#define XPP055C272_CMD_SETEXTC		0xb9 +#define XPP055C272_CMD_SETMIPI		0xbA +#define XPP055C272_CMD_SETVDC		0xbc +#define XPP055C272_CMD_SETPCR		0xbf +#define XPP055C272_CMD_SETSCR		0xc0 +#define XPP055C272_CMD_SETPOWER		0xc1 +#define XPP055C272_CMD_SETECO		0xc6 +#define XPP055C272_CMD_SETPANEL		0xcc +#define XPP055C272_CMD_SETGAMMA		0xe0 +#define XPP055C272_CMD_SETEQ		0xe3 +#define XPP055C272_CMD_SETGIP1		0xe9 +#define XPP055C272_CMD_SETGIP2		0xea + +struct xpp055c272 { +	struct device *dev; +	struct drm_panel panel; +	struct gpio_desc *reset_gpio; +	struct regulator *vci; +	struct regulator *iovcc; +	bool prepared; +}; + +static inline struct xpp055c272 *panel_to_xpp055c272(struct drm_panel *panel) +{ +	return container_of(panel, struct xpp055c272, panel); +} + +#define dsi_generic_write_seq(dsi, cmd, seq...) do {			\ +		static const u8 d[] = { seq };				\ +		int ret;						\ +		ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d));	\ +		if (ret < 0)						\ +			return ret;					\ +	} while (0) + +static int xpp055c272_init_sequence(struct xpp055c272 *ctx) +{ +	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); +	struct device *dev = ctx->dev; + +	/* +	 * Init sequence was supplied by the panel vendor without much +	 * documentation. +	 */ +	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETEXTC, 0xf1, 0x12, 0x83); +	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETMIPI, +			      0x33, 0x81, 0x05, 0xf9, 0x0e, 0x0e, 0x00, 0x00, +			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25, +			      0x00, 0x91, 0x0a, 0x00, 0x00, 0x02, 0x4f, 0x01, +			      0x00, 0x00, 0x37); +	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPOWER_EXT, 0x25); +	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPCR, 0x02, 0x11, 0x00); +	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETRGBIF, +			      0x0c, 0x10, 0x0a, 0x50, 0x03, 0xff, 0x00, 0x00, +			      0x00, 0x00); +	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETSCR, +			      0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70, +			      0x00); +	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETVDC, 0x46); +	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPANEL, 0x0b); +	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETCYC, 0x80); +	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETDISP, 0xc8, 0x12, 0x30); +	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETEQ, +			      0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00, +			      0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10); +	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPOWER, +			      0x53, 0x00, 0x1e, 0x1e, 0x77, 0xe1, 0xcc, 0xdd, +			      0x67, 0x77, 0x33, 0x33); +	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETECO, 0x00, 0x00, 0xff, +			      0xff, 0x01, 0xff); +	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETBGP, 0x09, 0x09); +	msleep(20); + +	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETVCOM, 0x87, 0x95); +	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGIP1, +			      0xc2, 0x10, 0x05, 0x05, 0x10, 0x05, 0xa0, 0x12, +			      0x31, 0x23, 0x3f, 0x81, 0x0a, 0xa0, 0x37, 0x18, +			      0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, +			      0x01, 0x00, 0x00, 0x00, 0x48, 0xf8, 0x86, 0x42, +			      0x08, 0x88, 0x88, 0x80, 0x88, 0x88, 0x88, 0x58, +			      0xf8, 0x87, 0x53, 0x18, 0x88, 0x88, 0x81, 0x88, +			      0x88, 0x88, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, +			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); +	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGIP2, +			      0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, +			      0x00, 0x00, 0x00, 0x00, 0x1f, 0x88, 0x81, 0x35, +			      0x78, 0x88, 0x88, 0x85, 0x88, 0x88, 0x88, 0x0f, +			      0x88, 0x80, 0x24, 0x68, 0x88, 0x88, 0x84, 0x88, +			      0x88, 0x88, 0x23, 0x10, 0x00, 0x00, 0x1c, 0x00, +			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x05, +			      0xa0, 0x00, 0x00, 0x00, 0x00); +	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGAMMA, +			      0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38, 0x36, +			      0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13, 0x11, +			      0x18, 0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38, +			      0x36, 0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13, +			      0x11, 0x18); + +	msleep(60); + +	DRM_DEV_DEBUG_DRIVER(dev, "Panel init sequence done\n"); +	return 0; +} + +static int xpp055c272_unprepare(struct drm_panel *panel) +{ +	struct xpp055c272 *ctx = panel_to_xpp055c272(panel); +	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); +	int ret; + +	if (!ctx->prepared) +		return 0; + +	ret = mipi_dsi_dcs_set_display_off(dsi); +	if (ret < 0) +		DRM_DEV_ERROR(ctx->dev, "failed to set display off: %d\n", +			      ret); + +	mipi_dsi_dcs_enter_sleep_mode(dsi); +	if (ret < 0) { +		DRM_DEV_ERROR(ctx->dev, "failed to enter sleep mode: %d\n", +			      ret); +		return ret; +	} + +	regulator_disable(ctx->iovcc); +	regulator_disable(ctx->vci); + +	ctx->prepared = false; + +	return 0; +} + +static int xpp055c272_prepare(struct drm_panel *panel) +{ +	struct xpp055c272 *ctx = panel_to_xpp055c272(panel); +	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); +	int ret; + +	if (ctx->prepared) +		return 0; + +	DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n"); +	ret = regulator_enable(ctx->vci); +	if (ret < 0) { +		DRM_DEV_ERROR(ctx->dev, +			      "Failed to enable vci supply: %d\n", ret); +		return ret; +	} +	ret = regulator_enable(ctx->iovcc); +	if (ret < 0) { +		DRM_DEV_ERROR(ctx->dev, +			      "Failed to enable iovcc supply: %d\n", ret); +		goto disable_vci; +	} + +	gpiod_set_value_cansleep(ctx->reset_gpio, 1); +	/* T6: 10us */ +	usleep_range(10, 20); +	gpiod_set_value_cansleep(ctx->reset_gpio, 0); + +	/* T8: 20ms */ +	msleep(20); + +	ret = xpp055c272_init_sequence(ctx); +	if (ret < 0) { +		DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n", +			      ret); +		goto disable_iovcc; +	} + +	ret = mipi_dsi_dcs_exit_sleep_mode(dsi); +	if (ret < 0) { +		DRM_DEV_ERROR(ctx->dev, "Failed to exit sleep mode: %d\n", ret); +		goto disable_iovcc; +	} + +	/* T9: 120ms */ +	msleep(120); + +	ret = mipi_dsi_dcs_set_display_on(dsi); +	if (ret < 0) { +		DRM_DEV_ERROR(ctx->dev, "Failed to set display on: %d\n", ret); +		goto disable_iovcc; +	} + +	msleep(50); + +	ctx->prepared = true; + +	return 0; + +disable_iovcc: +	regulator_disable(ctx->iovcc); +disable_vci: +	regulator_disable(ctx->vci); +	return ret; +} + +static const struct drm_display_mode default_mode = { +	.hdisplay	= 720, +	.hsync_start	= 720 + 40, +	.hsync_end	= 720 + 40 + 10, +	.htotal		= 720 + 40 + 10 + 40, +	.vdisplay	= 1280, +	.vsync_start	= 1280 + 22, +	.vsync_end	= 1280 + 22 + 4, +	.vtotal		= 1280 + 22 + 4 + 11, +	.vrefresh	= 60, +	.clock		= 64000, +	.width_mm	= 68, +	.height_mm	= 121, +}; + +static int xpp055c272_get_modes(struct drm_panel *panel, +				struct drm_connector *connector) +{ +	struct xpp055c272 *ctx = panel_to_xpp055c272(panel); +	struct drm_display_mode *mode; + +	mode = drm_mode_duplicate(connector->dev, &default_mode); +	if (!mode) { +		DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n", +			      default_mode.hdisplay, default_mode.vdisplay, +			      default_mode.vrefresh); +		return -ENOMEM; +	} + +	drm_mode_set_name(mode); + +	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; +	connector->display_info.width_mm = mode->width_mm; +	connector->display_info.height_mm = mode->height_mm; +	drm_mode_probed_add(connector, mode); + +	return 1; +} + +static const struct drm_panel_funcs xpp055c272_funcs = { +	.unprepare	= xpp055c272_unprepare, +	.prepare	= xpp055c272_prepare, +	.get_modes	= xpp055c272_get_modes, +}; + +static int xpp055c272_probe(struct mipi_dsi_device *dsi) +{ +	struct device *dev = &dsi->dev; +	struct xpp055c272 *ctx; +	int ret; + +	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); +	if (!ctx) +		return -ENOMEM; + +	ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); +	if (IS_ERR(ctx->reset_gpio)) { +		DRM_DEV_ERROR(dev, "cannot get reset gpio\n"); +		return PTR_ERR(ctx->reset_gpio); +	} + +	ctx->vci = devm_regulator_get(dev, "vci"); +	if (IS_ERR(ctx->vci)) { +		ret = PTR_ERR(ctx->vci); +		if (ret != -EPROBE_DEFER) +			DRM_DEV_ERROR(dev, +				      "Failed to request vci regulator: %d\n", +				      ret); +		return ret; +	} + +	ctx->iovcc = devm_regulator_get(dev, "iovcc"); +	if (IS_ERR(ctx->iovcc)) { +		ret = PTR_ERR(ctx->iovcc); +		if (ret != -EPROBE_DEFER) +			DRM_DEV_ERROR(dev, +				      "Failed to request iovcc regulator: %d\n", +				      ret); +		return ret; +	} + +	mipi_dsi_set_drvdata(dsi, ctx); + +	ctx->dev = dev; + +	dsi->lanes = 4; +	dsi->format = MIPI_DSI_FMT_RGB888; +	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | +			  MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET; + +	drm_panel_init(&ctx->panel, &dsi->dev, &xpp055c272_funcs, +		       DRM_MODE_CONNECTOR_DSI); + +	ret = drm_panel_of_backlight(&ctx->panel); +	if (ret) +		return ret; + +	drm_panel_add(&ctx->panel); + +	ret = mipi_dsi_attach(dsi); +	if (ret < 0) { +		DRM_DEV_ERROR(dev, "mipi_dsi_attach failed: %d\n", ret); +		drm_panel_remove(&ctx->panel); +		return ret; +	} + +	return 0; +} + +static void xpp055c272_shutdown(struct mipi_dsi_device *dsi) +{ +	struct xpp055c272 *ctx = mipi_dsi_get_drvdata(dsi); +	int ret; + +	ret = drm_panel_unprepare(&ctx->panel); +	if (ret < 0) +		DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", +			      ret); + +	ret = drm_panel_disable(&ctx->panel); +	if (ret < 0) +		DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", +			      ret); +} + +static int xpp055c272_remove(struct mipi_dsi_device *dsi) +{ +	struct xpp055c272 *ctx = mipi_dsi_get_drvdata(dsi); +	int ret; + +	xpp055c272_shutdown(dsi); + +	ret = mipi_dsi_detach(dsi); +	if (ret < 0) +		DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n", +			      ret); + +	drm_panel_remove(&ctx->panel); + +	return 0; +} + +static const struct of_device_id xpp055c272_of_match[] = { +	{ .compatible = "xinpeng,xpp055c272" }, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, xpp055c272_of_match); + +static struct mipi_dsi_driver xpp055c272_driver = { +	.driver = { +		.name = "panel-xinpeng-xpp055c272", +		.of_match_table = xpp055c272_of_match, +	}, +	.probe	= xpp055c272_probe, +	.remove = xpp055c272_remove, +	.shutdown = xpp055c272_shutdown, +}; +module_mipi_dsi_driver(xpp055c272_driver); + +MODULE_AUTHOR("Heiko Stuebner <[email protected]>"); +MODULE_DESCRIPTION("DRM driver for Xinpeng xpp055c272 MIPI DSI panel"); +MODULE_LICENSE("GPL v2");  |