xref: /linux/drivers/gpu/drm/bridge/chipone-icn6211.c (revision ce517f18944e3f8d08484cfdee425277fc2c4df6)
1*ce517f18SJagan Teki // SPDX-License-Identifier: GPL-2.0+
2*ce517f18SJagan Teki /*
3*ce517f18SJagan Teki  * Copyright (C) 2020 Amarula Solutions(India)
4*ce517f18SJagan Teki  * Author: Jagan Teki <jagan@amarulasolutions.com>
5*ce517f18SJagan Teki  */
6*ce517f18SJagan Teki 
7*ce517f18SJagan Teki #include <drm/drm_of.h>
8*ce517f18SJagan Teki #include <drm/drm_print.h>
9*ce517f18SJagan Teki #include <drm/drm_mipi_dsi.h>
10*ce517f18SJagan Teki 
11*ce517f18SJagan Teki #include <linux/delay.h>
12*ce517f18SJagan Teki #include <linux/gpio/consumer.h>
13*ce517f18SJagan Teki #include <linux/module.h>
14*ce517f18SJagan Teki #include <linux/of_device.h>
15*ce517f18SJagan Teki #include <linux/regulator/consumer.h>
16*ce517f18SJagan Teki 
17*ce517f18SJagan Teki #include <video/mipi_display.h>
18*ce517f18SJagan Teki 
19*ce517f18SJagan Teki #define HACTIVE_LI		0x20
20*ce517f18SJagan Teki #define VACTIVE_LI		0x21
21*ce517f18SJagan Teki #define VACTIVE_HACTIVE_HI	0x22
22*ce517f18SJagan Teki #define HFP_LI			0x23
23*ce517f18SJagan Teki #define HSYNC_LI		0x24
24*ce517f18SJagan Teki #define HBP_LI			0x25
25*ce517f18SJagan Teki #define HFP_HSW_HBP_HI		0x26
26*ce517f18SJagan Teki #define VFP			0x27
27*ce517f18SJagan Teki #define VSYNC			0x28
28*ce517f18SJagan Teki #define VBP			0x29
29*ce517f18SJagan Teki 
30*ce517f18SJagan Teki struct chipone {
31*ce517f18SJagan Teki 	struct device *dev;
32*ce517f18SJagan Teki 	struct drm_bridge bridge;
33*ce517f18SJagan Teki 	struct drm_bridge *panel_bridge;
34*ce517f18SJagan Teki 	struct gpio_desc *enable_gpio;
35*ce517f18SJagan Teki 	struct regulator *vdd1;
36*ce517f18SJagan Teki 	struct regulator *vdd2;
37*ce517f18SJagan Teki 	struct regulator *vdd3;
38*ce517f18SJagan Teki };
39*ce517f18SJagan Teki 
40*ce517f18SJagan Teki static inline struct chipone *bridge_to_chipone(struct drm_bridge *bridge)
41*ce517f18SJagan Teki {
42*ce517f18SJagan Teki 	return container_of(bridge, struct chipone, bridge);
43*ce517f18SJagan Teki }
44*ce517f18SJagan Teki 
45*ce517f18SJagan Teki static struct drm_display_mode *bridge_to_mode(struct drm_bridge *bridge)
46*ce517f18SJagan Teki {
47*ce517f18SJagan Teki 	return &bridge->encoder->crtc->state->adjusted_mode;
48*ce517f18SJagan Teki }
49*ce517f18SJagan Teki 
50*ce517f18SJagan Teki static inline int chipone_dsi_write(struct chipone *icn,  const void *seq,
51*ce517f18SJagan Teki 				    size_t len)
52*ce517f18SJagan Teki {
53*ce517f18SJagan Teki 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(icn->dev);
54*ce517f18SJagan Teki 
55*ce517f18SJagan Teki 	return mipi_dsi_generic_write(dsi, seq, len);
56*ce517f18SJagan Teki }
57*ce517f18SJagan Teki 
58*ce517f18SJagan Teki #define ICN6211_DSI(icn, seq...)				\
59*ce517f18SJagan Teki 	{							\
60*ce517f18SJagan Teki 		const u8 d[] = { seq };				\
61*ce517f18SJagan Teki 		chipone_dsi_write(icn, d, ARRAY_SIZE(d));	\
62*ce517f18SJagan Teki 	}
63*ce517f18SJagan Teki 
64*ce517f18SJagan Teki static void chipone_enable(struct drm_bridge *bridge)
65*ce517f18SJagan Teki {
66*ce517f18SJagan Teki 	struct chipone *icn = bridge_to_chipone(bridge);
67*ce517f18SJagan Teki 	struct drm_display_mode *mode = bridge_to_mode(bridge);
68*ce517f18SJagan Teki 
69*ce517f18SJagan Teki 	ICN6211_DSI(icn, 0x7a, 0xc1);
70*ce517f18SJagan Teki 
71*ce517f18SJagan Teki 	ICN6211_DSI(icn, HACTIVE_LI, mode->hdisplay & 0xff);
72*ce517f18SJagan Teki 
73*ce517f18SJagan Teki 	ICN6211_DSI(icn, VACTIVE_LI, mode->vdisplay & 0xff);
74*ce517f18SJagan Teki 
75*ce517f18SJagan Teki 	/**
76*ce517f18SJagan Teki 	 * lsb nibble: 2nd nibble of hdisplay
77*ce517f18SJagan Teki 	 * msb nibble: 2nd nibble of vdisplay
78*ce517f18SJagan Teki 	 */
79*ce517f18SJagan Teki 	ICN6211_DSI(icn, VACTIVE_HACTIVE_HI,
80*ce517f18SJagan Teki 		    ((mode->hdisplay >> 8) & 0xf) |
81*ce517f18SJagan Teki 		    (((mode->vdisplay >> 8) & 0xf) << 4));
82*ce517f18SJagan Teki 
83*ce517f18SJagan Teki 	ICN6211_DSI(icn, HFP_LI, mode->hsync_start - mode->hdisplay);
84*ce517f18SJagan Teki 
85*ce517f18SJagan Teki 	ICN6211_DSI(icn, HSYNC_LI, mode->hsync_end - mode->hsync_start);
86*ce517f18SJagan Teki 
87*ce517f18SJagan Teki 	ICN6211_DSI(icn, HBP_LI, mode->htotal - mode->hsync_end);
88*ce517f18SJagan Teki 
89*ce517f18SJagan Teki 	ICN6211_DSI(icn, HFP_HSW_HBP_HI, 0x00);
90*ce517f18SJagan Teki 
91*ce517f18SJagan Teki 	ICN6211_DSI(icn, VFP, mode->vsync_start - mode->vdisplay);
92*ce517f18SJagan Teki 
93*ce517f18SJagan Teki 	ICN6211_DSI(icn, VSYNC, mode->vsync_end - mode->vsync_start);
94*ce517f18SJagan Teki 
95*ce517f18SJagan Teki 	ICN6211_DSI(icn, VBP, mode->vtotal - mode->vsync_end);
96*ce517f18SJagan Teki 
97*ce517f18SJagan Teki 	/* dsi specific sequence */
98*ce517f18SJagan Teki 	ICN6211_DSI(icn, MIPI_DCS_SET_TEAR_OFF, 0x80);
99*ce517f18SJagan Teki 	ICN6211_DSI(icn, MIPI_DCS_SET_ADDRESS_MODE, 0x28);
100*ce517f18SJagan Teki 	ICN6211_DSI(icn, 0xb5, 0xa0);
101*ce517f18SJagan Teki 	ICN6211_DSI(icn, 0x5c, 0xff);
102*ce517f18SJagan Teki 	ICN6211_DSI(icn, MIPI_DCS_SET_COLUMN_ADDRESS, 0x01);
103*ce517f18SJagan Teki 	ICN6211_DSI(icn, MIPI_DCS_GET_POWER_SAVE, 0x92);
104*ce517f18SJagan Teki 	ICN6211_DSI(icn, 0x6b, 0x71);
105*ce517f18SJagan Teki 	ICN6211_DSI(icn, 0x69, 0x2b);
106*ce517f18SJagan Teki 	ICN6211_DSI(icn, MIPI_DCS_ENTER_SLEEP_MODE, 0x40);
107*ce517f18SJagan Teki 	ICN6211_DSI(icn, MIPI_DCS_EXIT_SLEEP_MODE, 0x98);
108*ce517f18SJagan Teki 
109*ce517f18SJagan Teki 	/* icn6211 specific sequence */
110*ce517f18SJagan Teki 	ICN6211_DSI(icn, 0xb6, 0x20);
111*ce517f18SJagan Teki 	ICN6211_DSI(icn, 0x51, 0x20);
112*ce517f18SJagan Teki 	ICN6211_DSI(icn, 0x09, 0x10);
113*ce517f18SJagan Teki 
114*ce517f18SJagan Teki 	usleep_range(10000, 11000);
115*ce517f18SJagan Teki }
116*ce517f18SJagan Teki 
117*ce517f18SJagan Teki static void chipone_pre_enable(struct drm_bridge *bridge)
118*ce517f18SJagan Teki {
119*ce517f18SJagan Teki 	struct chipone *icn = bridge_to_chipone(bridge);
120*ce517f18SJagan Teki 	int ret;
121*ce517f18SJagan Teki 
122*ce517f18SJagan Teki 	if (icn->vdd1) {
123*ce517f18SJagan Teki 		ret = regulator_enable(icn->vdd1);
124*ce517f18SJagan Teki 		if (ret)
125*ce517f18SJagan Teki 			DRM_DEV_ERROR(icn->dev,
126*ce517f18SJagan Teki 				      "failed to enable VDD1 regulator: %d\n", ret);
127*ce517f18SJagan Teki 	}
128*ce517f18SJagan Teki 
129*ce517f18SJagan Teki 	if (icn->vdd2) {
130*ce517f18SJagan Teki 		ret = regulator_enable(icn->vdd2);
131*ce517f18SJagan Teki 		if (ret)
132*ce517f18SJagan Teki 			DRM_DEV_ERROR(icn->dev,
133*ce517f18SJagan Teki 				      "failed to enable VDD2 regulator: %d\n", ret);
134*ce517f18SJagan Teki 	}
135*ce517f18SJagan Teki 
136*ce517f18SJagan Teki 	if (icn->vdd3) {
137*ce517f18SJagan Teki 		ret = regulator_enable(icn->vdd3);
138*ce517f18SJagan Teki 		if (ret)
139*ce517f18SJagan Teki 			DRM_DEV_ERROR(icn->dev,
140*ce517f18SJagan Teki 				      "failed to enable VDD3 regulator: %d\n", ret);
141*ce517f18SJagan Teki 	}
142*ce517f18SJagan Teki 
143*ce517f18SJagan Teki 	gpiod_set_value(icn->enable_gpio, 1);
144*ce517f18SJagan Teki 
145*ce517f18SJagan Teki 	usleep_range(10000, 11000);
146*ce517f18SJagan Teki }
147*ce517f18SJagan Teki 
148*ce517f18SJagan Teki static void chipone_post_disable(struct drm_bridge *bridge)
149*ce517f18SJagan Teki {
150*ce517f18SJagan Teki 	struct chipone *icn = bridge_to_chipone(bridge);
151*ce517f18SJagan Teki 
152*ce517f18SJagan Teki 	if (icn->vdd1)
153*ce517f18SJagan Teki 		regulator_disable(icn->vdd1);
154*ce517f18SJagan Teki 
155*ce517f18SJagan Teki 	if (icn->vdd2)
156*ce517f18SJagan Teki 		regulator_disable(icn->vdd2);
157*ce517f18SJagan Teki 
158*ce517f18SJagan Teki 	if (icn->vdd3)
159*ce517f18SJagan Teki 		regulator_disable(icn->vdd3);
160*ce517f18SJagan Teki 
161*ce517f18SJagan Teki 	gpiod_set_value(icn->enable_gpio, 0);
162*ce517f18SJagan Teki }
163*ce517f18SJagan Teki 
164*ce517f18SJagan Teki static int chipone_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags)
165*ce517f18SJagan Teki {
166*ce517f18SJagan Teki 	struct chipone *icn = bridge_to_chipone(bridge);
167*ce517f18SJagan Teki 
168*ce517f18SJagan Teki 	return drm_bridge_attach(bridge->encoder, icn->panel_bridge, bridge, flags);
169*ce517f18SJagan Teki }
170*ce517f18SJagan Teki 
171*ce517f18SJagan Teki static const struct drm_bridge_funcs chipone_bridge_funcs = {
172*ce517f18SJagan Teki 	.attach = chipone_attach,
173*ce517f18SJagan Teki 	.post_disable = chipone_post_disable,
174*ce517f18SJagan Teki 	.pre_enable = chipone_pre_enable,
175*ce517f18SJagan Teki 	.enable = chipone_enable,
176*ce517f18SJagan Teki };
177*ce517f18SJagan Teki 
178*ce517f18SJagan Teki static int chipone_parse_dt(struct chipone *icn)
179*ce517f18SJagan Teki {
180*ce517f18SJagan Teki 	struct device *dev = icn->dev;
181*ce517f18SJagan Teki 	struct drm_panel *panel;
182*ce517f18SJagan Teki 	int ret;
183*ce517f18SJagan Teki 
184*ce517f18SJagan Teki 	icn->vdd1 = devm_regulator_get_optional(dev, "vdd1");
185*ce517f18SJagan Teki 	if (IS_ERR(icn->vdd1)) {
186*ce517f18SJagan Teki 		ret = PTR_ERR(icn->vdd1);
187*ce517f18SJagan Teki 		if (ret == -EPROBE_DEFER)
188*ce517f18SJagan Teki 			return -EPROBE_DEFER;
189*ce517f18SJagan Teki 		icn->vdd1 = NULL;
190*ce517f18SJagan Teki 		DRM_DEV_DEBUG(dev, "failed to get VDD1 regulator: %d\n", ret);
191*ce517f18SJagan Teki 	}
192*ce517f18SJagan Teki 
193*ce517f18SJagan Teki 	icn->vdd2 = devm_regulator_get_optional(dev, "vdd2");
194*ce517f18SJagan Teki 	if (IS_ERR(icn->vdd2)) {
195*ce517f18SJagan Teki 		ret = PTR_ERR(icn->vdd2);
196*ce517f18SJagan Teki 		if (ret == -EPROBE_DEFER)
197*ce517f18SJagan Teki 			return -EPROBE_DEFER;
198*ce517f18SJagan Teki 		icn->vdd2 = NULL;
199*ce517f18SJagan Teki 		DRM_DEV_DEBUG(dev, "failed to get VDD2 regulator: %d\n", ret);
200*ce517f18SJagan Teki 	}
201*ce517f18SJagan Teki 
202*ce517f18SJagan Teki 	icn->vdd3 = devm_regulator_get_optional(dev, "vdd3");
203*ce517f18SJagan Teki 	if (IS_ERR(icn->vdd3)) {
204*ce517f18SJagan Teki 		ret = PTR_ERR(icn->vdd3);
205*ce517f18SJagan Teki 		if (ret == -EPROBE_DEFER)
206*ce517f18SJagan Teki 			return -EPROBE_DEFER;
207*ce517f18SJagan Teki 		icn->vdd3 = NULL;
208*ce517f18SJagan Teki 		DRM_DEV_DEBUG(dev, "failed to get VDD3 regulator: %d\n", ret);
209*ce517f18SJagan Teki 	}
210*ce517f18SJagan Teki 
211*ce517f18SJagan Teki 	icn->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
212*ce517f18SJagan Teki 	if (IS_ERR(icn->enable_gpio)) {
213*ce517f18SJagan Teki 		DRM_DEV_ERROR(dev, "failed to get enable GPIO\n");
214*ce517f18SJagan Teki 		return PTR_ERR(icn->enable_gpio);
215*ce517f18SJagan Teki 	}
216*ce517f18SJagan Teki 
217*ce517f18SJagan Teki 	ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
218*ce517f18SJagan Teki 	if (ret)
219*ce517f18SJagan Teki 		return ret;
220*ce517f18SJagan Teki 
221*ce517f18SJagan Teki 	icn->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
222*ce517f18SJagan Teki 	if (IS_ERR(icn->panel_bridge))
223*ce517f18SJagan Teki 		return PTR_ERR(icn->panel_bridge);
224*ce517f18SJagan Teki 
225*ce517f18SJagan Teki 	return 0;
226*ce517f18SJagan Teki }
227*ce517f18SJagan Teki 
228*ce517f18SJagan Teki static int chipone_probe(struct mipi_dsi_device *dsi)
229*ce517f18SJagan Teki {
230*ce517f18SJagan Teki 	struct device *dev = &dsi->dev;
231*ce517f18SJagan Teki 	struct chipone *icn;
232*ce517f18SJagan Teki 	int ret;
233*ce517f18SJagan Teki 
234*ce517f18SJagan Teki 	icn = devm_kzalloc(dev, sizeof(struct chipone), GFP_KERNEL);
235*ce517f18SJagan Teki 	if (!icn)
236*ce517f18SJagan Teki 		return -ENOMEM;
237*ce517f18SJagan Teki 
238*ce517f18SJagan Teki 	mipi_dsi_set_drvdata(dsi, icn);
239*ce517f18SJagan Teki 	icn->dev = dev;
240*ce517f18SJagan Teki 
241*ce517f18SJagan Teki 	ret = chipone_parse_dt(icn);
242*ce517f18SJagan Teki 	if (ret)
243*ce517f18SJagan Teki 		return ret;
244*ce517f18SJagan Teki 
245*ce517f18SJagan Teki 	icn->bridge.funcs = &chipone_bridge_funcs;
246*ce517f18SJagan Teki 	icn->bridge.type = DRM_MODE_CONNECTOR_DPI;
247*ce517f18SJagan Teki 	icn->bridge.of_node = dev->of_node;
248*ce517f18SJagan Teki 
249*ce517f18SJagan Teki 	drm_bridge_add(&icn->bridge);
250*ce517f18SJagan Teki 
251*ce517f18SJagan Teki 	dsi->lanes = 4;
252*ce517f18SJagan Teki 	dsi->format = MIPI_DSI_FMT_RGB888;
253*ce517f18SJagan Teki 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
254*ce517f18SJagan Teki 
255*ce517f18SJagan Teki 	ret = mipi_dsi_attach(dsi);
256*ce517f18SJagan Teki 	if (ret < 0) {
257*ce517f18SJagan Teki 		drm_bridge_remove(&icn->bridge);
258*ce517f18SJagan Teki 		dev_err(dev, "failed to attach dsi\n");
259*ce517f18SJagan Teki 	}
260*ce517f18SJagan Teki 
261*ce517f18SJagan Teki 	return ret;
262*ce517f18SJagan Teki }
263*ce517f18SJagan Teki 
264*ce517f18SJagan Teki static int chipone_remove(struct mipi_dsi_device *dsi)
265*ce517f18SJagan Teki {
266*ce517f18SJagan Teki 	struct chipone *icn = mipi_dsi_get_drvdata(dsi);
267*ce517f18SJagan Teki 
268*ce517f18SJagan Teki 	mipi_dsi_detach(dsi);
269*ce517f18SJagan Teki 	drm_bridge_remove(&icn->bridge);
270*ce517f18SJagan Teki 
271*ce517f18SJagan Teki 	return 0;
272*ce517f18SJagan Teki }
273*ce517f18SJagan Teki 
274*ce517f18SJagan Teki static const struct of_device_id chipone_of_match[] = {
275*ce517f18SJagan Teki 	{ .compatible = "chipone,icn6211", },
276*ce517f18SJagan Teki 	{ /* sentinel */ }
277*ce517f18SJagan Teki };
278*ce517f18SJagan Teki MODULE_DEVICE_TABLE(of, chipone_of_match);
279*ce517f18SJagan Teki 
280*ce517f18SJagan Teki static struct mipi_dsi_driver chipone_driver = {
281*ce517f18SJagan Teki 	.probe = chipone_probe,
282*ce517f18SJagan Teki 	.remove = chipone_remove,
283*ce517f18SJagan Teki 	.driver = {
284*ce517f18SJagan Teki 		.name = "chipone-icn6211",
285*ce517f18SJagan Teki 		.owner = THIS_MODULE,
286*ce517f18SJagan Teki 		.of_match_table = chipone_of_match,
287*ce517f18SJagan Teki 	},
288*ce517f18SJagan Teki };
289*ce517f18SJagan Teki module_mipi_dsi_driver(chipone_driver);
290*ce517f18SJagan Teki 
291*ce517f18SJagan Teki MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>");
292*ce517f18SJagan Teki MODULE_DESCRIPTION("Chipone ICN6211 MIPI-DSI to RGB Converter Bridge");
293*ce517f18SJagan Teki MODULE_LICENSE("GPL");
294