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