xref: /openbmc/linux/drivers/gpu/drm/bridge/ti-dlpc3433.c (revision 6352cd451ddbb506ce061868a9e5465d294d4857)
1*6352cd45SJagan Teki // SPDX-License-Identifier: GPL-2.0+
2*6352cd45SJagan Teki /*
3*6352cd45SJagan Teki  * Copyright (C) 2021 RenewOutReach
4*6352cd45SJagan Teki  * Copyright (C) 2021 Amarula Solutions(India)
5*6352cd45SJagan Teki  *
6*6352cd45SJagan Teki  * Author:
7*6352cd45SJagan Teki  * Jagan Teki <jagan@amarulasolutions.com>
8*6352cd45SJagan Teki  * Christopher Vollo <chris@renewoutreach.org>
9*6352cd45SJagan Teki  */
10*6352cd45SJagan Teki 
11*6352cd45SJagan Teki #include <drm/drm_atomic_helper.h>
12*6352cd45SJagan Teki #include <drm/drm_of.h>
13*6352cd45SJagan Teki #include <drm/drm_print.h>
14*6352cd45SJagan Teki #include <drm/drm_mipi_dsi.h>
15*6352cd45SJagan Teki 
16*6352cd45SJagan Teki #include <linux/delay.h>
17*6352cd45SJagan Teki #include <linux/gpio/consumer.h>
18*6352cd45SJagan Teki #include <linux/i2c.h>
19*6352cd45SJagan Teki #include <linux/module.h>
20*6352cd45SJagan Teki #include <linux/regmap.h>
21*6352cd45SJagan Teki #include <linux/regulator/consumer.h>
22*6352cd45SJagan Teki 
23*6352cd45SJagan Teki enum cmd_registers {
24*6352cd45SJagan Teki 	WR_INPUT_SOURCE		= 0x05,	/* Write Input Source Select */
25*6352cd45SJagan Teki 	WR_EXT_SOURCE_FMT	= 0x07, /* Write External Video Source Format */
26*6352cd45SJagan Teki 	WR_IMAGE_CROP		= 0x10,	/* Write Image Crop */
27*6352cd45SJagan Teki 	WR_DISPLAY_SIZE		= 0x12,	/* Write Display Size */
28*6352cd45SJagan Teki 	WR_IMAGE_FREEZE		= 0x1A,	/* Write Image Freeze */
29*6352cd45SJagan Teki 	WR_INPUT_IMAGE_SIZE	= 0x2E,	/* Write External Input Image Size */
30*6352cd45SJagan Teki 	WR_RGB_LED_EN		= 0x52,	/* Write RGB LED Enable */
31*6352cd45SJagan Teki 	WR_RGB_LED_CURRENT	= 0x54,	/* Write RGB LED Current */
32*6352cd45SJagan Teki 	WR_RGB_LED_MAX_CURRENT	= 0x5C,	/* Write RGB LED Max Current */
33*6352cd45SJagan Teki 	WR_DSI_HS_CLK		= 0xBD,	/* Write DSI HS Clock */
34*6352cd45SJagan Teki 	RD_DEVICE_ID		= 0xD4,	/* Read Controller Device ID */
35*6352cd45SJagan Teki 	WR_DSI_PORT_EN		= 0xD7,	/* Write DSI Port Enable */
36*6352cd45SJagan Teki };
37*6352cd45SJagan Teki 
38*6352cd45SJagan Teki enum input_source {
39*6352cd45SJagan Teki 	INPUT_EXTERNAL_VIDEO	= 0,
40*6352cd45SJagan Teki 	INPUT_TEST_PATTERN,
41*6352cd45SJagan Teki 	INPUT_SPLASH_SCREEN,
42*6352cd45SJagan Teki };
43*6352cd45SJagan Teki 
44*6352cd45SJagan Teki #define DEV_ID_MASK		GENMASK(3, 0)
45*6352cd45SJagan Teki #define IMAGE_FREESE_EN		BIT(0)
46*6352cd45SJagan Teki #define DSI_PORT_EN		0
47*6352cd45SJagan Teki #define EXT_SOURCE_FMT_DSI	0
48*6352cd45SJagan Teki #define RED_LED_EN		BIT(0)
49*6352cd45SJagan Teki #define GREEN_LED_EN		BIT(1)
50*6352cd45SJagan Teki #define BLUE_LED_EN		BIT(2)
51*6352cd45SJagan Teki #define LED_MASK		GENMASK(2, 0)
52*6352cd45SJagan Teki #define MAX_BYTE_SIZE		8
53*6352cd45SJagan Teki 
54*6352cd45SJagan Teki struct dlpc {
55*6352cd45SJagan Teki 	struct device		*dev;
56*6352cd45SJagan Teki 	struct drm_bridge	bridge;
57*6352cd45SJagan Teki 	struct drm_bridge	*next_bridge;
58*6352cd45SJagan Teki 	struct device_node	*host_node;
59*6352cd45SJagan Teki 	struct mipi_dsi_device	*dsi;
60*6352cd45SJagan Teki 	struct drm_display_mode	mode;
61*6352cd45SJagan Teki 
62*6352cd45SJagan Teki 	struct gpio_desc	*enable_gpio;
63*6352cd45SJagan Teki 	struct regulator	*vcc_intf;
64*6352cd45SJagan Teki 	struct regulator	*vcc_flsh;
65*6352cd45SJagan Teki 	struct regmap		*regmap;
66*6352cd45SJagan Teki 	unsigned int		dsi_lanes;
67*6352cd45SJagan Teki };
68*6352cd45SJagan Teki 
69*6352cd45SJagan Teki static inline struct dlpc *bridge_to_dlpc(struct drm_bridge *bridge)
70*6352cd45SJagan Teki {
71*6352cd45SJagan Teki 	return container_of(bridge, struct dlpc, bridge);
72*6352cd45SJagan Teki }
73*6352cd45SJagan Teki 
74*6352cd45SJagan Teki static bool dlpc_writeable_noinc_reg(struct device *dev, unsigned int reg)
75*6352cd45SJagan Teki {
76*6352cd45SJagan Teki 	switch (reg) {
77*6352cd45SJagan Teki 	case WR_IMAGE_CROP:
78*6352cd45SJagan Teki 	case WR_DISPLAY_SIZE:
79*6352cd45SJagan Teki 	case WR_INPUT_IMAGE_SIZE:
80*6352cd45SJagan Teki 	case WR_DSI_HS_CLK:
81*6352cd45SJagan Teki 		return true;
82*6352cd45SJagan Teki 	default:
83*6352cd45SJagan Teki 		return false;
84*6352cd45SJagan Teki 	}
85*6352cd45SJagan Teki }
86*6352cd45SJagan Teki 
87*6352cd45SJagan Teki static const struct regmap_range dlpc_volatile_ranges[] = {
88*6352cd45SJagan Teki 	{ .range_min = 0x10, .range_max = 0xBF },
89*6352cd45SJagan Teki };
90*6352cd45SJagan Teki 
91*6352cd45SJagan Teki static const struct regmap_access_table dlpc_volatile_table = {
92*6352cd45SJagan Teki 	.yes_ranges = dlpc_volatile_ranges,
93*6352cd45SJagan Teki 	.n_yes_ranges = ARRAY_SIZE(dlpc_volatile_ranges),
94*6352cd45SJagan Teki };
95*6352cd45SJagan Teki 
96*6352cd45SJagan Teki static struct regmap_config dlpc_regmap_config = {
97*6352cd45SJagan Teki 	.reg_bits		= 8,
98*6352cd45SJagan Teki 	.val_bits		= 8,
99*6352cd45SJagan Teki 	.max_register		= WR_DSI_PORT_EN,
100*6352cd45SJagan Teki 	.writeable_noinc_reg	= dlpc_writeable_noinc_reg,
101*6352cd45SJagan Teki 	.volatile_table		= &dlpc_volatile_table,
102*6352cd45SJagan Teki 	.cache_type		= REGCACHE_RBTREE,
103*6352cd45SJagan Teki 	.name			= "dlpc3433",
104*6352cd45SJagan Teki };
105*6352cd45SJagan Teki 
106*6352cd45SJagan Teki static void dlpc_atomic_enable(struct drm_bridge *bridge,
107*6352cd45SJagan Teki 			       struct drm_bridge_state *old_bridge_state)
108*6352cd45SJagan Teki {
109*6352cd45SJagan Teki 	struct dlpc *dlpc = bridge_to_dlpc(bridge);
110*6352cd45SJagan Teki 	struct device *dev = dlpc->dev;
111*6352cd45SJagan Teki 	struct drm_display_mode *mode = &dlpc->mode;
112*6352cd45SJagan Teki 	struct regmap *regmap = dlpc->regmap;
113*6352cd45SJagan Teki 	char buf[MAX_BYTE_SIZE];
114*6352cd45SJagan Teki 	unsigned int devid;
115*6352cd45SJagan Teki 
116*6352cd45SJagan Teki 	regmap_read(regmap, RD_DEVICE_ID, &devid);
117*6352cd45SJagan Teki 	devid &= DEV_ID_MASK;
118*6352cd45SJagan Teki 
119*6352cd45SJagan Teki 	DRM_DEV_DEBUG(dev, "DLPC3433 device id: 0x%02x\n", devid);
120*6352cd45SJagan Teki 
121*6352cd45SJagan Teki 	if (devid != 0x01) {
122*6352cd45SJagan Teki 		DRM_DEV_ERROR(dev, "Unsupported DLPC device id: 0x%02x\n", devid);
123*6352cd45SJagan Teki 		return;
124*6352cd45SJagan Teki 	}
125*6352cd45SJagan Teki 
126*6352cd45SJagan Teki 	/* disable image freeze */
127*6352cd45SJagan Teki 	regmap_write(regmap, WR_IMAGE_FREEZE, IMAGE_FREESE_EN);
128*6352cd45SJagan Teki 
129*6352cd45SJagan Teki 	/* enable DSI port */
130*6352cd45SJagan Teki 	regmap_write(regmap, WR_DSI_PORT_EN, DSI_PORT_EN);
131*6352cd45SJagan Teki 
132*6352cd45SJagan Teki 	memset(buf, 0, MAX_BYTE_SIZE);
133*6352cd45SJagan Teki 
134*6352cd45SJagan Teki 	/* set image crop */
135*6352cd45SJagan Teki 	buf[4] = mode->hdisplay & 0xff;
136*6352cd45SJagan Teki 	buf[5] = (mode->hdisplay & 0xff00) >> 8;
137*6352cd45SJagan Teki 	buf[6] = mode->vdisplay & 0xff;
138*6352cd45SJagan Teki 	buf[7] = (mode->vdisplay & 0xff00) >> 8;
139*6352cd45SJagan Teki 	regmap_noinc_write(regmap, WR_IMAGE_CROP, buf, MAX_BYTE_SIZE);
140*6352cd45SJagan Teki 
141*6352cd45SJagan Teki 	/* set display size */
142*6352cd45SJagan Teki 	buf[4] = mode->hdisplay & 0xff;
143*6352cd45SJagan Teki 	buf[5] = (mode->hdisplay & 0xff00) >> 8;
144*6352cd45SJagan Teki 	buf[6] = mode->vdisplay & 0xff;
145*6352cd45SJagan Teki 	buf[7] = (mode->vdisplay & 0xff00) >> 8;
146*6352cd45SJagan Teki 	regmap_noinc_write(regmap, WR_DISPLAY_SIZE, buf, MAX_BYTE_SIZE);
147*6352cd45SJagan Teki 
148*6352cd45SJagan Teki 	/* set input image size */
149*6352cd45SJagan Teki 	buf[0] = mode->hdisplay & 0xff;
150*6352cd45SJagan Teki 	buf[1] = (mode->hdisplay & 0xff00) >> 8;
151*6352cd45SJagan Teki 	buf[2] = mode->vdisplay & 0xff;
152*6352cd45SJagan Teki 	buf[3] = (mode->vdisplay & 0xff00) >> 8;
153*6352cd45SJagan Teki 	regmap_noinc_write(regmap, WR_INPUT_IMAGE_SIZE, buf, 4);
154*6352cd45SJagan Teki 
155*6352cd45SJagan Teki 	/* set external video port */
156*6352cd45SJagan Teki 	regmap_write(regmap, WR_INPUT_SOURCE, INPUT_EXTERNAL_VIDEO);
157*6352cd45SJagan Teki 
158*6352cd45SJagan Teki 	/* set external video format select as DSI */
159*6352cd45SJagan Teki 	regmap_write(regmap, WR_EXT_SOURCE_FMT, EXT_SOURCE_FMT_DSI);
160*6352cd45SJagan Teki 
161*6352cd45SJagan Teki 	/* disable image freeze */
162*6352cd45SJagan Teki 	regmap_write(regmap, WR_IMAGE_FREEZE, 0x00);
163*6352cd45SJagan Teki 
164*6352cd45SJagan Teki 	/* enable RGB led */
165*6352cd45SJagan Teki 	regmap_update_bits(regmap, WR_RGB_LED_EN, LED_MASK,
166*6352cd45SJagan Teki 			   RED_LED_EN | GREEN_LED_EN | BLUE_LED_EN);
167*6352cd45SJagan Teki 
168*6352cd45SJagan Teki 	msleep(10);
169*6352cd45SJagan Teki }
170*6352cd45SJagan Teki 
171*6352cd45SJagan Teki static void dlpc_atomic_pre_enable(struct drm_bridge *bridge,
172*6352cd45SJagan Teki 				   struct drm_bridge_state *old_bridge_state)
173*6352cd45SJagan Teki {
174*6352cd45SJagan Teki 	struct dlpc *dlpc = bridge_to_dlpc(bridge);
175*6352cd45SJagan Teki 	int ret;
176*6352cd45SJagan Teki 
177*6352cd45SJagan Teki 	gpiod_set_value(dlpc->enable_gpio, 1);
178*6352cd45SJagan Teki 
179*6352cd45SJagan Teki 	msleep(500);
180*6352cd45SJagan Teki 
181*6352cd45SJagan Teki 	ret = regulator_enable(dlpc->vcc_intf);
182*6352cd45SJagan Teki 	if (ret)
183*6352cd45SJagan Teki 		DRM_DEV_ERROR(dlpc->dev,
184*6352cd45SJagan Teki 			      "failed to enable VCC_INTF regulator: %d\n", ret);
185*6352cd45SJagan Teki 
186*6352cd45SJagan Teki 	ret = regulator_enable(dlpc->vcc_flsh);
187*6352cd45SJagan Teki 	if (ret)
188*6352cd45SJagan Teki 		DRM_DEV_ERROR(dlpc->dev,
189*6352cd45SJagan Teki 			      "failed to enable VCC_FLSH regulator: %d\n", ret);
190*6352cd45SJagan Teki 
191*6352cd45SJagan Teki 	msleep(10);
192*6352cd45SJagan Teki }
193*6352cd45SJagan Teki 
194*6352cd45SJagan Teki static void dlpc_atomic_post_disable(struct drm_bridge *bridge,
195*6352cd45SJagan Teki 				     struct drm_bridge_state *old_bridge_state)
196*6352cd45SJagan Teki {
197*6352cd45SJagan Teki 	struct dlpc *dlpc = bridge_to_dlpc(bridge);
198*6352cd45SJagan Teki 
199*6352cd45SJagan Teki 	regulator_disable(dlpc->vcc_flsh);
200*6352cd45SJagan Teki 	regulator_disable(dlpc->vcc_intf);
201*6352cd45SJagan Teki 
202*6352cd45SJagan Teki 	msleep(10);
203*6352cd45SJagan Teki 
204*6352cd45SJagan Teki 	gpiod_set_value(dlpc->enable_gpio, 0);
205*6352cd45SJagan Teki 
206*6352cd45SJagan Teki 	msleep(500);
207*6352cd45SJagan Teki }
208*6352cd45SJagan Teki 
209*6352cd45SJagan Teki #define MAX_INPUT_SEL_FORMATS	1
210*6352cd45SJagan Teki 
211*6352cd45SJagan Teki static u32 *
212*6352cd45SJagan Teki dlpc_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
213*6352cd45SJagan Teki 			       struct drm_bridge_state *bridge_state,
214*6352cd45SJagan Teki 			       struct drm_crtc_state *crtc_state,
215*6352cd45SJagan Teki 			       struct drm_connector_state *conn_state,
216*6352cd45SJagan Teki 			       u32 output_fmt,
217*6352cd45SJagan Teki 			       unsigned int *num_input_fmts)
218*6352cd45SJagan Teki {
219*6352cd45SJagan Teki 	u32 *input_fmts;
220*6352cd45SJagan Teki 
221*6352cd45SJagan Teki 	*num_input_fmts = 0;
222*6352cd45SJagan Teki 
223*6352cd45SJagan Teki 	input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
224*6352cd45SJagan Teki 			     GFP_KERNEL);
225*6352cd45SJagan Teki 	if (!input_fmts)
226*6352cd45SJagan Teki 		return NULL;
227*6352cd45SJagan Teki 
228*6352cd45SJagan Teki 	/* This is the DSI-end bus format */
229*6352cd45SJagan Teki 	input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
230*6352cd45SJagan Teki 	*num_input_fmts = 1;
231*6352cd45SJagan Teki 
232*6352cd45SJagan Teki 	return input_fmts;
233*6352cd45SJagan Teki }
234*6352cd45SJagan Teki 
235*6352cd45SJagan Teki static void dlpc_mode_set(struct drm_bridge *bridge,
236*6352cd45SJagan Teki 			  const struct drm_display_mode *mode,
237*6352cd45SJagan Teki 			  const struct drm_display_mode *adjusted_mode)
238*6352cd45SJagan Teki {
239*6352cd45SJagan Teki 	struct dlpc *dlpc = bridge_to_dlpc(bridge);
240*6352cd45SJagan Teki 
241*6352cd45SJagan Teki 	drm_mode_copy(&dlpc->mode, adjusted_mode);
242*6352cd45SJagan Teki }
243*6352cd45SJagan Teki 
244*6352cd45SJagan Teki static int dlpc_attach(struct drm_bridge *bridge,
245*6352cd45SJagan Teki 		       enum drm_bridge_attach_flags flags)
246*6352cd45SJagan Teki {
247*6352cd45SJagan Teki 	struct dlpc *dlpc = bridge_to_dlpc(bridge);
248*6352cd45SJagan Teki 
249*6352cd45SJagan Teki 	return drm_bridge_attach(bridge->encoder, dlpc->next_bridge, bridge, flags);
250*6352cd45SJagan Teki }
251*6352cd45SJagan Teki 
252*6352cd45SJagan Teki static const struct drm_bridge_funcs dlpc_bridge_funcs = {
253*6352cd45SJagan Teki 	.atomic_duplicate_state		= drm_atomic_helper_bridge_duplicate_state,
254*6352cd45SJagan Teki 	.atomic_destroy_state		= drm_atomic_helper_bridge_destroy_state,
255*6352cd45SJagan Teki 	.atomic_get_input_bus_fmts	= dlpc_atomic_get_input_bus_fmts,
256*6352cd45SJagan Teki 	.atomic_reset			= drm_atomic_helper_bridge_reset,
257*6352cd45SJagan Teki 	.atomic_pre_enable		= dlpc_atomic_pre_enable,
258*6352cd45SJagan Teki 	.atomic_enable			= dlpc_atomic_enable,
259*6352cd45SJagan Teki 	.atomic_post_disable		= dlpc_atomic_post_disable,
260*6352cd45SJagan Teki 	.mode_set			= dlpc_mode_set,
261*6352cd45SJagan Teki 	.attach				= dlpc_attach,
262*6352cd45SJagan Teki };
263*6352cd45SJagan Teki 
264*6352cd45SJagan Teki static int dlpc3433_parse_dt(struct dlpc *dlpc)
265*6352cd45SJagan Teki {
266*6352cd45SJagan Teki 	struct device *dev = dlpc->dev;
267*6352cd45SJagan Teki 	struct device_node *endpoint;
268*6352cd45SJagan Teki 	int ret;
269*6352cd45SJagan Teki 
270*6352cd45SJagan Teki 	dlpc->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
271*6352cd45SJagan Teki 	if (IS_ERR(dlpc->enable_gpio))
272*6352cd45SJagan Teki 		return PTR_ERR(dlpc->enable_gpio);
273*6352cd45SJagan Teki 
274*6352cd45SJagan Teki 	dlpc->vcc_intf = devm_regulator_get(dlpc->dev, "vcc_intf");
275*6352cd45SJagan Teki 	if (IS_ERR(dlpc->vcc_intf))
276*6352cd45SJagan Teki 		return dev_err_probe(dev, PTR_ERR(dlpc->vcc_intf),
277*6352cd45SJagan Teki 				     "failed to get VCC_INTF supply\n");
278*6352cd45SJagan Teki 
279*6352cd45SJagan Teki 	dlpc->vcc_flsh = devm_regulator_get(dlpc->dev, "vcc_flsh");
280*6352cd45SJagan Teki 	if (IS_ERR(dlpc->vcc_flsh))
281*6352cd45SJagan Teki 		return dev_err_probe(dev, PTR_ERR(dlpc->vcc_flsh),
282*6352cd45SJagan Teki 				     "failed to get VCC_FLSH supply\n");
283*6352cd45SJagan Teki 
284*6352cd45SJagan Teki 	dlpc->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
285*6352cd45SJagan Teki 	if (IS_ERR(dlpc->next_bridge))
286*6352cd45SJagan Teki 		return PTR_ERR(dlpc->next_bridge);
287*6352cd45SJagan Teki 
288*6352cd45SJagan Teki 	endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0);
289*6352cd45SJagan Teki 	dlpc->dsi_lanes = of_property_count_u32_elems(endpoint, "data-lanes");
290*6352cd45SJagan Teki 	if (dlpc->dsi_lanes < 0 || dlpc->dsi_lanes > 4) {
291*6352cd45SJagan Teki 		ret = -EINVAL;
292*6352cd45SJagan Teki 		goto err_put_endpoint;
293*6352cd45SJagan Teki 	}
294*6352cd45SJagan Teki 
295*6352cd45SJagan Teki 	dlpc->host_node = of_graph_get_remote_port_parent(endpoint);
296*6352cd45SJagan Teki 	if (!dlpc->host_node) {
297*6352cd45SJagan Teki 		ret = -ENODEV;
298*6352cd45SJagan Teki 		goto err_put_host;
299*6352cd45SJagan Teki 	}
300*6352cd45SJagan Teki 
301*6352cd45SJagan Teki 	of_node_put(endpoint);
302*6352cd45SJagan Teki 
303*6352cd45SJagan Teki 	return 0;
304*6352cd45SJagan Teki 
305*6352cd45SJagan Teki err_put_host:
306*6352cd45SJagan Teki 	of_node_put(dlpc->host_node);
307*6352cd45SJagan Teki err_put_endpoint:
308*6352cd45SJagan Teki 	of_node_put(endpoint);
309*6352cd45SJagan Teki 	return ret;
310*6352cd45SJagan Teki }
311*6352cd45SJagan Teki 
312*6352cd45SJagan Teki static int dlpc_host_attach(struct dlpc *dlpc)
313*6352cd45SJagan Teki {
314*6352cd45SJagan Teki 	struct device *dev = dlpc->dev;
315*6352cd45SJagan Teki 	struct mipi_dsi_host *host;
316*6352cd45SJagan Teki 	struct mipi_dsi_device_info info = {
317*6352cd45SJagan Teki 		.type = "dlpc3433",
318*6352cd45SJagan Teki 		.channel = 0,
319*6352cd45SJagan Teki 		.node = NULL,
320*6352cd45SJagan Teki 	};
321*6352cd45SJagan Teki 
322*6352cd45SJagan Teki 	host = of_find_mipi_dsi_host_by_node(dlpc->host_node);
323*6352cd45SJagan Teki 	if (!host) {
324*6352cd45SJagan Teki 		DRM_DEV_ERROR(dev, "failed to find dsi host\n");
325*6352cd45SJagan Teki 		return -EPROBE_DEFER;
326*6352cd45SJagan Teki 	}
327*6352cd45SJagan Teki 
328*6352cd45SJagan Teki 	dlpc->dsi = mipi_dsi_device_register_full(host, &info);
329*6352cd45SJagan Teki 	if (IS_ERR(dlpc->dsi)) {
330*6352cd45SJagan Teki 		DRM_DEV_ERROR(dev, "failed to create dsi device\n");
331*6352cd45SJagan Teki 		return PTR_ERR(dlpc->dsi);
332*6352cd45SJagan Teki 	}
333*6352cd45SJagan Teki 
334*6352cd45SJagan Teki 	dlpc->dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST;
335*6352cd45SJagan Teki 	dlpc->dsi->format = MIPI_DSI_FMT_RGB565;
336*6352cd45SJagan Teki 	dlpc->dsi->lanes = dlpc->dsi_lanes;
337*6352cd45SJagan Teki 
338*6352cd45SJagan Teki 	return devm_mipi_dsi_attach(dev, dlpc->dsi);
339*6352cd45SJagan Teki }
340*6352cd45SJagan Teki 
341*6352cd45SJagan Teki static int dlpc3433_probe(struct i2c_client *client)
342*6352cd45SJagan Teki {
343*6352cd45SJagan Teki 	struct device *dev = &client->dev;
344*6352cd45SJagan Teki 	struct dlpc *dlpc;
345*6352cd45SJagan Teki 	int ret;
346*6352cd45SJagan Teki 
347*6352cd45SJagan Teki 	dlpc = devm_kzalloc(dev, sizeof(*dlpc), GFP_KERNEL);
348*6352cd45SJagan Teki 	if (!dlpc)
349*6352cd45SJagan Teki 		return -ENOMEM;
350*6352cd45SJagan Teki 
351*6352cd45SJagan Teki 	dlpc->dev = dev;
352*6352cd45SJagan Teki 
353*6352cd45SJagan Teki 	dlpc->regmap = devm_regmap_init_i2c(client, &dlpc_regmap_config);
354*6352cd45SJagan Teki 	if (IS_ERR(dlpc->regmap))
355*6352cd45SJagan Teki 		return PTR_ERR(dlpc->regmap);
356*6352cd45SJagan Teki 
357*6352cd45SJagan Teki 	ret = dlpc3433_parse_dt(dlpc);
358*6352cd45SJagan Teki 	if (ret)
359*6352cd45SJagan Teki 		return ret;
360*6352cd45SJagan Teki 
361*6352cd45SJagan Teki 	dev_set_drvdata(dev, dlpc);
362*6352cd45SJagan Teki 	i2c_set_clientdata(client, dlpc);
363*6352cd45SJagan Teki 
364*6352cd45SJagan Teki 	dlpc->bridge.funcs = &dlpc_bridge_funcs;
365*6352cd45SJagan Teki 	dlpc->bridge.of_node = dev->of_node;
366*6352cd45SJagan Teki 	drm_bridge_add(&dlpc->bridge);
367*6352cd45SJagan Teki 
368*6352cd45SJagan Teki 	ret = dlpc_host_attach(dlpc);
369*6352cd45SJagan Teki 	if (ret) {
370*6352cd45SJagan Teki 		DRM_DEV_ERROR(dev, "failed to attach dsi host\n");
371*6352cd45SJagan Teki 		goto err_remove_bridge;
372*6352cd45SJagan Teki 	}
373*6352cd45SJagan Teki 
374*6352cd45SJagan Teki 	return 0;
375*6352cd45SJagan Teki 
376*6352cd45SJagan Teki err_remove_bridge:
377*6352cd45SJagan Teki 	drm_bridge_remove(&dlpc->bridge);
378*6352cd45SJagan Teki 	return ret;
379*6352cd45SJagan Teki }
380*6352cd45SJagan Teki 
381*6352cd45SJagan Teki static int dlpc3433_remove(struct i2c_client *client)
382*6352cd45SJagan Teki {
383*6352cd45SJagan Teki 	struct dlpc *dlpc = i2c_get_clientdata(client);
384*6352cd45SJagan Teki 
385*6352cd45SJagan Teki 	drm_bridge_remove(&dlpc->bridge);
386*6352cd45SJagan Teki 	of_node_put(dlpc->host_node);
387*6352cd45SJagan Teki 
388*6352cd45SJagan Teki 	return 0;
389*6352cd45SJagan Teki }
390*6352cd45SJagan Teki 
391*6352cd45SJagan Teki static const struct i2c_device_id dlpc3433_id[] = {
392*6352cd45SJagan Teki 	{ "ti,dlpc3433", 0 },
393*6352cd45SJagan Teki 	{ /* sentinel */ }
394*6352cd45SJagan Teki };
395*6352cd45SJagan Teki MODULE_DEVICE_TABLE(i2c, dlpc3433_id);
396*6352cd45SJagan Teki 
397*6352cd45SJagan Teki static const struct of_device_id dlpc3433_match_table[] = {
398*6352cd45SJagan Teki 	{ .compatible = "ti,dlpc3433" },
399*6352cd45SJagan Teki 	{ /* sentinel */ }
400*6352cd45SJagan Teki };
401*6352cd45SJagan Teki MODULE_DEVICE_TABLE(of, dlpc3433_match_table);
402*6352cd45SJagan Teki 
403*6352cd45SJagan Teki static struct i2c_driver dlpc3433_driver = {
404*6352cd45SJagan Teki 	.probe_new = dlpc3433_probe,
405*6352cd45SJagan Teki 	.remove = dlpc3433_remove,
406*6352cd45SJagan Teki 	.id_table = dlpc3433_id,
407*6352cd45SJagan Teki 	.driver = {
408*6352cd45SJagan Teki 		.name = "ti-dlpc3433",
409*6352cd45SJagan Teki 		.of_match_table = dlpc3433_match_table,
410*6352cd45SJagan Teki 	},
411*6352cd45SJagan Teki };
412*6352cd45SJagan Teki module_i2c_driver(dlpc3433_driver);
413*6352cd45SJagan Teki 
414*6352cd45SJagan Teki MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>");
415*6352cd45SJagan Teki MODULE_AUTHOR("Christopher Vollo <chris@renewoutreach.org>");
416*6352cd45SJagan Teki MODULE_DESCRIPTION("TI DLPC3433 MIPI DSI Display Controller Bridge");
417*6352cd45SJagan Teki MODULE_LICENSE("GPL");
418