Loading...
Note: File does not exist in v3.1.
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
30struct 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
40static inline struct chipone *bridge_to_chipone(struct drm_bridge *bridge)
41{
42 return container_of(bridge, struct chipone, bridge);
43}
44
45static struct drm_display_mode *bridge_to_mode(struct drm_bridge *bridge)
46{
47 return &bridge->encoder->crtc->state->adjusted_mode;
48}
49
50static 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
64static 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
117static 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
148static 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
164static 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
171static 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
178static 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
228static 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
264static 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
274static const struct of_device_id chipone_of_match[] = {
275 { .compatible = "chipone,icn6211", },
276 { /* sentinel */ }
277};
278MODULE_DEVICE_TABLE(of, chipone_of_match);
279
280static 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};
289module_mipi_dsi_driver(chipone_driver);
290
291MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>");
292MODULE_DESCRIPTION("Chipone ICN6211 MIPI-DSI to RGB Converter Bridge");
293MODULE_LICENSE("GPL");