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