mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	drm: bridge: ldb: Implement simple Freescale i.MX8MP LDB bridge
The i.MX8MP contains two syscon registers which are responsible
for configuring the on-SoC DPI-to-LVDS serializer. Implement a
simple bridge driver for this serializer.
--
    - Add sentinel of_device_table
    - Add RB from Sam
    - Rename to fsl-ldb altogether
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: Lucas Stach <l.stach@pengutronix.de>
Cc: Maxime Ripard <maxime@cerno.tech>
Cc: Peng Fan <peng.fan@nxp.com>
Cc: Robby Cai <robby.cai@nxp.com>
Cc: Robert Foss <robert.foss@linaro.org>
Cc: Sam Ravnborg <sam@ravnborg.org>
Cc: Thomas Zimmermann <tzimmermann@suse.de>
To: dri-devel@lists.freedesktop.org
V2: - Rename syscon to fsl,syscon
V3: - Consistently use MX8MP
V4: - Fix MODULE_DESCRIPTION to also use MX8MP
Signed-off-by: Robert Foss <robert.foss@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20220426193645.244792-2-marex@denx.de
			
			
This commit is contained in:
		
							parent
							
								
									666518676d
								
							
						
					
					
						commit
						463db5c2ed
					
				
					 3 changed files with 351 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -75,6 +75,14 @@ config DRM_DISPLAY_CONNECTOR
 | 
			
		|||
	  on ARM-based platforms. Saying Y here when this driver is not needed
 | 
			
		||||
	  will not cause any issue.
 | 
			
		||||
 | 
			
		||||
config DRM_FSL_LDB
 | 
			
		||||
	tristate "Freescale i.MX8MP LDB bridge"
 | 
			
		||||
	depends on OF
 | 
			
		||||
	select DRM_KMS_HELPER
 | 
			
		||||
	select DRM_PANEL_BRIDGE
 | 
			
		||||
	help
 | 
			
		||||
	  Support for i.MX8MP DPI-to-LVDS on-SoC encoder.
 | 
			
		||||
 | 
			
		||||
config DRM_ITE_IT6505
 | 
			
		||||
        tristate "ITE IT6505 DisplayPort bridge"
 | 
			
		||||
        depends on OF
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_CHIPONE_ICN6211) += chipone-icn6211.o
 | 
			
		|||
obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
 | 
			
		||||
obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o
 | 
			
		||||
obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o
 | 
			
		||||
obj-$(CONFIG_DRM_FSL_LDB) += fsl-ldb.o
 | 
			
		||||
obj-$(CONFIG_DRM_ITE_IT6505) += ite-it6505.o
 | 
			
		||||
obj-$(CONFIG_DRM_LONTIUM_LT8912B) += lontium-lt8912b.o
 | 
			
		||||
obj-$(CONFIG_DRM_LONTIUM_LT9211) += lontium-lt9211.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										342
									
								
								drivers/gpu/drm/bridge/fsl-ldb.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										342
									
								
								drivers/gpu/drm/bridge/fsl-ldb.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,342 @@
 | 
			
		|||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2022 Marek Vasut <marex@denx.de>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/clk.h>
 | 
			
		||||
#include <linux/mfd/syscon.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/of.h>
 | 
			
		||||
#include <linux/of_device.h>
 | 
			
		||||
#include <linux/of_graph.h>
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/regmap.h>
 | 
			
		||||
 | 
			
		||||
#include <drm/drm_atomic_helper.h>
 | 
			
		||||
#include <drm/drm_bridge.h>
 | 
			
		||||
#include <drm/drm_of.h>
 | 
			
		||||
#include <drm/drm_panel.h>
 | 
			
		||||
 | 
			
		||||
#define LDB_CTRL				0x5c
 | 
			
		||||
#define LDB_CTRL_CH0_ENABLE			BIT(0)
 | 
			
		||||
#define LDB_CTRL_CH0_DI_SELECT			BIT(1)
 | 
			
		||||
#define LDB_CTRL_CH1_ENABLE			BIT(2)
 | 
			
		||||
#define LDB_CTRL_CH1_DI_SELECT			BIT(3)
 | 
			
		||||
#define LDB_CTRL_SPLIT_MODE			BIT(4)
 | 
			
		||||
#define LDB_CTRL_CH0_DATA_WIDTH			BIT(5)
 | 
			
		||||
#define LDB_CTRL_CH0_BIT_MAPPING		BIT(6)
 | 
			
		||||
#define LDB_CTRL_CH1_DATA_WIDTH			BIT(7)
 | 
			
		||||
#define LDB_CTRL_CH1_BIT_MAPPING		BIT(8)
 | 
			
		||||
#define LDB_CTRL_DI0_VSYNC_POLARITY		BIT(9)
 | 
			
		||||
#define LDB_CTRL_DI1_VSYNC_POLARITY		BIT(10)
 | 
			
		||||
#define LDB_CTRL_REG_CH0_FIFO_RESET		BIT(11)
 | 
			
		||||
#define LDB_CTRL_REG_CH1_FIFO_RESET		BIT(12)
 | 
			
		||||
#define LDB_CTRL_ASYNC_FIFO_ENABLE		BIT(24)
 | 
			
		||||
#define LDB_CTRL_ASYNC_FIFO_THRESHOLD_MASK	GENMASK(27, 25)
 | 
			
		||||
 | 
			
		||||
#define LVDS_CTRL				0x128
 | 
			
		||||
#define LVDS_CTRL_CH0_EN			BIT(0)
 | 
			
		||||
#define LVDS_CTRL_CH1_EN			BIT(1)
 | 
			
		||||
#define LVDS_CTRL_VBG_EN			BIT(2)
 | 
			
		||||
#define LVDS_CTRL_HS_EN				BIT(3)
 | 
			
		||||
#define LVDS_CTRL_PRE_EMPH_EN			BIT(4)
 | 
			
		||||
#define LVDS_CTRL_PRE_EMPH_ADJ(n)		(((n) & 0x7) << 5)
 | 
			
		||||
#define LVDS_CTRL_PRE_EMPH_ADJ_MASK		GENMASK(7, 5)
 | 
			
		||||
#define LVDS_CTRL_CM_ADJ(n)			(((n) & 0x7) << 8)
 | 
			
		||||
#define LVDS_CTRL_CM_ADJ_MASK			GENMASK(10, 8)
 | 
			
		||||
#define LVDS_CTRL_CC_ADJ(n)			(((n) & 0x7) << 11)
 | 
			
		||||
#define LVDS_CTRL_CC_ADJ_MASK			GENMASK(13, 11)
 | 
			
		||||
#define LVDS_CTRL_SLEW_ADJ(n)			(((n) & 0x7) << 14)
 | 
			
		||||
#define LVDS_CTRL_SLEW_ADJ_MASK			GENMASK(16, 14)
 | 
			
		||||
#define LVDS_CTRL_VBG_ADJ(n)			(((n) & 0x7) << 17)
 | 
			
		||||
#define LVDS_CTRL_VBG_ADJ_MASK			GENMASK(19, 17)
 | 
			
		||||
 | 
			
		||||
struct fsl_ldb {
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
	struct drm_bridge bridge;
 | 
			
		||||
	struct drm_bridge *panel_bridge;
 | 
			
		||||
	struct clk *clk;
 | 
			
		||||
	struct regmap *regmap;
 | 
			
		||||
	bool lvds_dual_link;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline struct fsl_ldb *to_fsl_ldb(struct drm_bridge *bridge)
 | 
			
		||||
{
 | 
			
		||||
	return container_of(bridge, struct fsl_ldb, bridge);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int fsl_ldb_attach(struct drm_bridge *bridge,
 | 
			
		||||
			  enum drm_bridge_attach_flags flags)
 | 
			
		||||
{
 | 
			
		||||
	struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
 | 
			
		||||
 | 
			
		||||
	return drm_bridge_attach(bridge->encoder, fsl_ldb->panel_bridge,
 | 
			
		||||
				 bridge, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int fsl_ldb_atomic_check(struct drm_bridge *bridge,
 | 
			
		||||
				struct drm_bridge_state *bridge_state,
 | 
			
		||||
				struct drm_crtc_state *crtc_state,
 | 
			
		||||
				struct drm_connector_state *conn_state)
 | 
			
		||||
{
 | 
			
		||||
	/* Invert DE signal polarity. */
 | 
			
		||||
	bridge_state->input_bus_cfg.flags &= ~(DRM_BUS_FLAG_DE_LOW |
 | 
			
		||||
					       DRM_BUS_FLAG_DE_HIGH);
 | 
			
		||||
	if (bridge_state->output_bus_cfg.flags & DRM_BUS_FLAG_DE_LOW)
 | 
			
		||||
		bridge_state->input_bus_cfg.flags |= DRM_BUS_FLAG_DE_HIGH;
 | 
			
		||||
	else if (bridge_state->output_bus_cfg.flags & DRM_BUS_FLAG_DE_HIGH)
 | 
			
		||||
		bridge_state->input_bus_cfg.flags |= DRM_BUS_FLAG_DE_LOW;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void fsl_ldb_atomic_enable(struct drm_bridge *bridge,
 | 
			
		||||
				  struct drm_bridge_state *old_bridge_state)
 | 
			
		||||
{
 | 
			
		||||
	struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
 | 
			
		||||
	struct drm_atomic_state *state = old_bridge_state->base.state;
 | 
			
		||||
	const struct drm_bridge_state *bridge_state;
 | 
			
		||||
	const struct drm_crtc_state *crtc_state;
 | 
			
		||||
	const struct drm_display_mode *mode;
 | 
			
		||||
	struct drm_connector *connector;
 | 
			
		||||
	struct drm_crtc *crtc;
 | 
			
		||||
	bool lvds_format_24bpp;
 | 
			
		||||
	bool lvds_format_jeida;
 | 
			
		||||
	u32 reg;
 | 
			
		||||
 | 
			
		||||
	/* Get the LVDS format from the bridge state. */
 | 
			
		||||
	bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
 | 
			
		||||
 | 
			
		||||
	switch (bridge_state->output_bus_cfg.format) {
 | 
			
		||||
	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
 | 
			
		||||
		lvds_format_24bpp = false;
 | 
			
		||||
		lvds_format_jeida = true;
 | 
			
		||||
		break;
 | 
			
		||||
	case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
 | 
			
		||||
		lvds_format_24bpp = true;
 | 
			
		||||
		lvds_format_jeida = true;
 | 
			
		||||
		break;
 | 
			
		||||
	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
 | 
			
		||||
		lvds_format_24bpp = true;
 | 
			
		||||
		lvds_format_jeida = false;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		/*
 | 
			
		||||
		 * Some bridges still don't set the correct LVDS bus pixel
 | 
			
		||||
		 * format, use SPWG24 default format until those are fixed.
 | 
			
		||||
		 */
 | 
			
		||||
		lvds_format_24bpp = true;
 | 
			
		||||
		lvds_format_jeida = false;
 | 
			
		||||
		dev_warn(fsl_ldb->dev,
 | 
			
		||||
			 "Unsupported LVDS bus format 0x%04x, please check output bridge driver. Falling back to SPWG24.\n",
 | 
			
		||||
			 bridge_state->output_bus_cfg.format);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Retrieve the CRTC adjusted mode. This requires a little dance to go
 | 
			
		||||
	 * from the bridge to the encoder, to the connector and to the CRTC.
 | 
			
		||||
	 */
 | 
			
		||||
	connector = drm_atomic_get_new_connector_for_encoder(state,
 | 
			
		||||
							     bridge->encoder);
 | 
			
		||||
	crtc = drm_atomic_get_new_connector_state(state, connector)->crtc;
 | 
			
		||||
	crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
 | 
			
		||||
	mode = &crtc_state->adjusted_mode;
 | 
			
		||||
 | 
			
		||||
	if (fsl_ldb->lvds_dual_link)
 | 
			
		||||
		clk_set_rate(fsl_ldb->clk, mode->clock * 3500);
 | 
			
		||||
	else
 | 
			
		||||
		clk_set_rate(fsl_ldb->clk, mode->clock * 7000);
 | 
			
		||||
	clk_prepare_enable(fsl_ldb->clk);
 | 
			
		||||
 | 
			
		||||
	/* Program LDB_CTRL */
 | 
			
		||||
	reg = LDB_CTRL_CH0_ENABLE;
 | 
			
		||||
 | 
			
		||||
	if (fsl_ldb->lvds_dual_link)
 | 
			
		||||
		reg |= LDB_CTRL_CH1_ENABLE;
 | 
			
		||||
 | 
			
		||||
	if (lvds_format_24bpp) {
 | 
			
		||||
		reg |= LDB_CTRL_CH0_DATA_WIDTH;
 | 
			
		||||
		if (fsl_ldb->lvds_dual_link)
 | 
			
		||||
			reg |= LDB_CTRL_CH1_DATA_WIDTH;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lvds_format_jeida) {
 | 
			
		||||
		reg |= LDB_CTRL_CH0_BIT_MAPPING;
 | 
			
		||||
		if (fsl_ldb->lvds_dual_link)
 | 
			
		||||
			reg |= LDB_CTRL_CH1_BIT_MAPPING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mode->flags & DRM_MODE_FLAG_PVSYNC) {
 | 
			
		||||
		reg |= LDB_CTRL_DI0_VSYNC_POLARITY;
 | 
			
		||||
		if (fsl_ldb->lvds_dual_link)
 | 
			
		||||
			reg |= LDB_CTRL_DI1_VSYNC_POLARITY;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	regmap_write(fsl_ldb->regmap, LDB_CTRL, reg);
 | 
			
		||||
 | 
			
		||||
	/* Program LVDS_CTRL */
 | 
			
		||||
	reg = LVDS_CTRL_CC_ADJ(2) | LVDS_CTRL_PRE_EMPH_EN |
 | 
			
		||||
	      LVDS_CTRL_PRE_EMPH_ADJ(3) | LVDS_CTRL_VBG_EN;
 | 
			
		||||
	regmap_write(fsl_ldb->regmap, LVDS_CTRL, reg);
 | 
			
		||||
 | 
			
		||||
	/* Wait for VBG to stabilize. */
 | 
			
		||||
	usleep_range(15, 20);
 | 
			
		||||
 | 
			
		||||
	reg |= LVDS_CTRL_CH0_EN;
 | 
			
		||||
	if (fsl_ldb->lvds_dual_link)
 | 
			
		||||
		reg |= LVDS_CTRL_CH1_EN;
 | 
			
		||||
 | 
			
		||||
	regmap_write(fsl_ldb->regmap, LVDS_CTRL, reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void fsl_ldb_atomic_disable(struct drm_bridge *bridge,
 | 
			
		||||
				   struct drm_bridge_state *old_bridge_state)
 | 
			
		||||
{
 | 
			
		||||
	struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
 | 
			
		||||
 | 
			
		||||
	/* Stop both channels. */
 | 
			
		||||
	regmap_write(fsl_ldb->regmap, LVDS_CTRL, 0);
 | 
			
		||||
	regmap_write(fsl_ldb->regmap, LDB_CTRL, 0);
 | 
			
		||||
 | 
			
		||||
	clk_disable_unprepare(fsl_ldb->clk);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define MAX_INPUT_SEL_FORMATS 1
 | 
			
		||||
static u32 *
 | 
			
		||||
fsl_ldb_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
 | 
			
		||||
				  struct drm_bridge_state *bridge_state,
 | 
			
		||||
				  struct drm_crtc_state *crtc_state,
 | 
			
		||||
				  struct drm_connector_state *conn_state,
 | 
			
		||||
				  u32 output_fmt,
 | 
			
		||||
				  unsigned int *num_input_fmts)
 | 
			
		||||
{
 | 
			
		||||
	u32 *input_fmts;
 | 
			
		||||
 | 
			
		||||
	*num_input_fmts = 0;
 | 
			
		||||
 | 
			
		||||
	input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
 | 
			
		||||
			     GFP_KERNEL);
 | 
			
		||||
	if (!input_fmts)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
 | 
			
		||||
	*num_input_fmts = MAX_INPUT_SEL_FORMATS;
 | 
			
		||||
 | 
			
		||||
	return input_fmts;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static enum drm_mode_status
 | 
			
		||||
fsl_ldb_mode_valid(struct drm_bridge *bridge,
 | 
			
		||||
		   const struct drm_display_info *info,
 | 
			
		||||
		   const struct drm_display_mode *mode)
 | 
			
		||||
{
 | 
			
		||||
	struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
 | 
			
		||||
 | 
			
		||||
	if (mode->clock > (fsl_ldb->lvds_dual_link ? 80000 : 160000))
 | 
			
		||||
		return MODE_CLOCK_HIGH;
 | 
			
		||||
 | 
			
		||||
	return MODE_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct drm_bridge_funcs funcs = {
 | 
			
		||||
	.attach = fsl_ldb_attach,
 | 
			
		||||
	.atomic_check = fsl_ldb_atomic_check,
 | 
			
		||||
	.atomic_enable = fsl_ldb_atomic_enable,
 | 
			
		||||
	.atomic_disable = fsl_ldb_atomic_disable,
 | 
			
		||||
	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
 | 
			
		||||
	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
 | 
			
		||||
	.atomic_get_input_bus_fmts = fsl_ldb_atomic_get_input_bus_fmts,
 | 
			
		||||
	.atomic_reset = drm_atomic_helper_bridge_reset,
 | 
			
		||||
	.mode_valid = fsl_ldb_mode_valid,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int fsl_ldb_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct device *dev = &pdev->dev;
 | 
			
		||||
	struct device_node *panel_node;
 | 
			
		||||
	struct device_node *port1, *port2;
 | 
			
		||||
	struct drm_panel *panel;
 | 
			
		||||
	struct fsl_ldb *fsl_ldb;
 | 
			
		||||
	int dual_link;
 | 
			
		||||
 | 
			
		||||
	fsl_ldb = devm_kzalloc(dev, sizeof(*fsl_ldb), GFP_KERNEL);
 | 
			
		||||
	if (!fsl_ldb)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	fsl_ldb->dev = &pdev->dev;
 | 
			
		||||
	fsl_ldb->bridge.funcs = &funcs;
 | 
			
		||||
	fsl_ldb->bridge.of_node = dev->of_node;
 | 
			
		||||
 | 
			
		||||
	fsl_ldb->clk = devm_clk_get(dev, "ldb");
 | 
			
		||||
	if (IS_ERR(fsl_ldb->clk))
 | 
			
		||||
		return PTR_ERR(fsl_ldb->clk);
 | 
			
		||||
 | 
			
		||||
	fsl_ldb->regmap = syscon_node_to_regmap(dev->of_node->parent);
 | 
			
		||||
	if (IS_ERR(fsl_ldb->regmap))
 | 
			
		||||
		return PTR_ERR(fsl_ldb->regmap);
 | 
			
		||||
 | 
			
		||||
	/* Locate the panel DT node. */
 | 
			
		||||
	panel_node = of_graph_get_remote_node(dev->of_node, 1, 0);
 | 
			
		||||
	if (!panel_node)
 | 
			
		||||
		return -ENXIO;
 | 
			
		||||
 | 
			
		||||
	panel = of_drm_find_panel(panel_node);
 | 
			
		||||
	of_node_put(panel_node);
 | 
			
		||||
	if (IS_ERR(panel))
 | 
			
		||||
		return PTR_ERR(panel);
 | 
			
		||||
 | 
			
		||||
	fsl_ldb->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
 | 
			
		||||
	if (IS_ERR(fsl_ldb->panel_bridge))
 | 
			
		||||
		return PTR_ERR(fsl_ldb->panel_bridge);
 | 
			
		||||
 | 
			
		||||
	/* Determine whether this is dual-link configuration */
 | 
			
		||||
	port1 = of_graph_get_port_by_id(dev->of_node, 1);
 | 
			
		||||
	port2 = of_graph_get_port_by_id(dev->of_node, 2);
 | 
			
		||||
	dual_link = drm_of_lvds_get_dual_link_pixel_order(port1, port2);
 | 
			
		||||
	of_node_put(port1);
 | 
			
		||||
	of_node_put(port2);
 | 
			
		||||
 | 
			
		||||
	if (dual_link == DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS) {
 | 
			
		||||
		dev_err(dev, "LVDS channel pixel swap not supported.\n");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (dual_link == DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS)
 | 
			
		||||
		fsl_ldb->lvds_dual_link = true;
 | 
			
		||||
 | 
			
		||||
	platform_set_drvdata(pdev, fsl_ldb);
 | 
			
		||||
 | 
			
		||||
	drm_bridge_add(&fsl_ldb->bridge);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int fsl_ldb_remove(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct fsl_ldb *fsl_ldb = platform_get_drvdata(pdev);
 | 
			
		||||
 | 
			
		||||
	drm_bridge_remove(&fsl_ldb->bridge);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct of_device_id fsl_ldb_match[] = {
 | 
			
		||||
	{ .compatible = "fsl,imx8mp-ldb", },
 | 
			
		||||
	{ /* sentinel */ },
 | 
			
		||||
};
 | 
			
		||||
MODULE_DEVICE_TABLE(of, fsl_ldb_match);
 | 
			
		||||
 | 
			
		||||
static struct platform_driver fsl_ldb_driver = {
 | 
			
		||||
	.probe	= fsl_ldb_probe,
 | 
			
		||||
	.remove	= fsl_ldb_remove,
 | 
			
		||||
	.driver		= {
 | 
			
		||||
		.name		= "fsl-ldb",
 | 
			
		||||
		.of_match_table	= fsl_ldb_match,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
module_platform_driver(fsl_ldb_driver);
 | 
			
		||||
 | 
			
		||||
MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
 | 
			
		||||
MODULE_DESCRIPTION("Freescale i.MX8MP LDB");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
		Loading…
	
		Reference in a new issue