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