]> Git Repo - linux.git/blob - drivers/gpu/drm/bridge/ti-dlpc3433.c
Merge tag 'linux-watchdog-6.14-rc1' of git://www.linux-watchdog.org/linux-watchdog
[linux.git] / drivers / gpu / drm / bridge / ti-dlpc3433.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2021 RenewOutReach
4  * Copyright (C) 2021 Amarula Solutions(India)
5  *
6  * Author:
7  * Jagan Teki <[email protected]>
8  * Christopher Vollo <[email protected]>
9  */
10
11 #include <drm/drm_atomic_helper.h>
12 #include <drm/drm_of.h>
13 #include <drm/drm_print.h>
14 #include <drm/drm_mipi_dsi.h>
15
16 #include <linux/delay.h>
17 #include <linux/gpio/consumer.h>
18 #include <linux/i2c.h>
19 #include <linux/media-bus-format.h>
20 #include <linux/module.h>
21 #include <linux/regmap.h>
22 #include <linux/regulator/consumer.h>
23
24 enum cmd_registers {
25         WR_INPUT_SOURCE         = 0x05, /* Write Input Source Select */
26         WR_EXT_SOURCE_FMT       = 0x07, /* Write External Video Source Format */
27         WR_IMAGE_CROP           = 0x10, /* Write Image Crop */
28         WR_DISPLAY_SIZE         = 0x12, /* Write Display Size */
29         WR_IMAGE_FREEZE         = 0x1A, /* Write Image Freeze */
30         WR_INPUT_IMAGE_SIZE     = 0x2E, /* Write External Input Image Size */
31         WR_RGB_LED_EN           = 0x52, /* Write RGB LED Enable */
32         WR_RGB_LED_CURRENT      = 0x54, /* Write RGB LED Current */
33         WR_RGB_LED_MAX_CURRENT  = 0x5C, /* Write RGB LED Max Current */
34         WR_DSI_HS_CLK           = 0xBD, /* Write DSI HS Clock */
35         RD_DEVICE_ID            = 0xD4, /* Read Controller Device ID */
36         WR_DSI_PORT_EN          = 0xD7, /* Write DSI Port Enable */
37 };
38
39 enum input_source {
40         INPUT_EXTERNAL_VIDEO    = 0,
41         INPUT_TEST_PATTERN,
42         INPUT_SPLASH_SCREEN,
43 };
44
45 #define DEV_ID_MASK             GENMASK(3, 0)
46 #define IMAGE_FREESE_EN         BIT(0)
47 #define DSI_PORT_EN             0
48 #define EXT_SOURCE_FMT_DSI      0
49 #define RED_LED_EN              BIT(0)
50 #define GREEN_LED_EN            BIT(1)
51 #define BLUE_LED_EN             BIT(2)
52 #define LED_MASK                GENMASK(2, 0)
53 #define MAX_BYTE_SIZE           8
54
55 struct dlpc {
56         struct device           *dev;
57         struct drm_bridge       bridge;
58         struct drm_bridge       *next_bridge;
59         struct device_node      *host_node;
60         struct mipi_dsi_device  *dsi;
61         struct drm_display_mode mode;
62
63         struct gpio_desc        *enable_gpio;
64         struct regulator        *vcc_intf;
65         struct regulator        *vcc_flsh;
66         struct regmap           *regmap;
67         unsigned int            dsi_lanes;
68 };
69
70 static inline struct dlpc *bridge_to_dlpc(struct drm_bridge *bridge)
71 {
72         return container_of(bridge, struct dlpc, bridge);
73 }
74
75 static bool dlpc_writeable_noinc_reg(struct device *dev, unsigned int reg)
76 {
77         switch (reg) {
78         case WR_IMAGE_CROP:
79         case WR_DISPLAY_SIZE:
80         case WR_INPUT_IMAGE_SIZE:
81         case WR_DSI_HS_CLK:
82                 return true;
83         default:
84                 return false;
85         }
86 }
87
88 static const struct regmap_range dlpc_volatile_ranges[] = {
89         { .range_min = 0x10, .range_max = 0xBF },
90 };
91
92 static const struct regmap_access_table dlpc_volatile_table = {
93         .yes_ranges = dlpc_volatile_ranges,
94         .n_yes_ranges = ARRAY_SIZE(dlpc_volatile_ranges),
95 };
96
97 static const struct regmap_config dlpc_regmap_config = {
98         .reg_bits               = 8,
99         .val_bits               = 8,
100         .max_register           = WR_DSI_PORT_EN,
101         .writeable_noinc_reg    = dlpc_writeable_noinc_reg,
102         .volatile_table         = &dlpc_volatile_table,
103         .cache_type             = REGCACHE_MAPLE,
104         .name                   = "dlpc3433",
105 };
106
107 static void dlpc_atomic_enable(struct drm_bridge *bridge,
108                                struct drm_bridge_state *old_bridge_state)
109 {
110         struct dlpc *dlpc = bridge_to_dlpc(bridge);
111         struct device *dev = dlpc->dev;
112         struct drm_display_mode *mode = &dlpc->mode;
113         struct regmap *regmap = dlpc->regmap;
114         char buf[MAX_BYTE_SIZE];
115         unsigned int devid;
116
117         regmap_read(regmap, RD_DEVICE_ID, &devid);
118         devid &= DEV_ID_MASK;
119
120         DRM_DEV_DEBUG(dev, "DLPC3433 device id: 0x%02x\n", devid);
121
122         if (devid != 0x01) {
123                 DRM_DEV_ERROR(dev, "Unsupported DLPC device id: 0x%02x\n", devid);
124                 return;
125         }
126
127         /* disable image freeze */
128         regmap_write(regmap, WR_IMAGE_FREEZE, IMAGE_FREESE_EN);
129
130         /* enable DSI port */
131         regmap_write(regmap, WR_DSI_PORT_EN, DSI_PORT_EN);
132
133         memset(buf, 0, MAX_BYTE_SIZE);
134
135         /* set image crop */
136         buf[4] = mode->hdisplay & 0xff;
137         buf[5] = (mode->hdisplay & 0xff00) >> 8;
138         buf[6] = mode->vdisplay & 0xff;
139         buf[7] = (mode->vdisplay & 0xff00) >> 8;
140         regmap_noinc_write(regmap, WR_IMAGE_CROP, buf, MAX_BYTE_SIZE);
141
142         /* set display size */
143         buf[4] = mode->hdisplay & 0xff;
144         buf[5] = (mode->hdisplay & 0xff00) >> 8;
145         buf[6] = mode->vdisplay & 0xff;
146         buf[7] = (mode->vdisplay & 0xff00) >> 8;
147         regmap_noinc_write(regmap, WR_DISPLAY_SIZE, buf, MAX_BYTE_SIZE);
148
149         /* set input image size */
150         buf[0] = mode->hdisplay & 0xff;
151         buf[1] = (mode->hdisplay & 0xff00) >> 8;
152         buf[2] = mode->vdisplay & 0xff;
153         buf[3] = (mode->vdisplay & 0xff00) >> 8;
154         regmap_noinc_write(regmap, WR_INPUT_IMAGE_SIZE, buf, 4);
155
156         /* set external video port */
157         regmap_write(regmap, WR_INPUT_SOURCE, INPUT_EXTERNAL_VIDEO);
158
159         /* set external video format select as DSI */
160         regmap_write(regmap, WR_EXT_SOURCE_FMT, EXT_SOURCE_FMT_DSI);
161
162         /* disable image freeze */
163         regmap_write(regmap, WR_IMAGE_FREEZE, 0x00);
164
165         /* enable RGB led */
166         regmap_update_bits(regmap, WR_RGB_LED_EN, LED_MASK,
167                            RED_LED_EN | GREEN_LED_EN | BLUE_LED_EN);
168
169         msleep(10);
170 }
171
172 static void dlpc_atomic_pre_enable(struct drm_bridge *bridge,
173                                    struct drm_bridge_state *old_bridge_state)
174 {
175         struct dlpc *dlpc = bridge_to_dlpc(bridge);
176         int ret;
177
178         gpiod_set_value(dlpc->enable_gpio, 1);
179
180         msleep(500);
181
182         ret = regulator_enable(dlpc->vcc_intf);
183         if (ret)
184                 DRM_DEV_ERROR(dlpc->dev,
185                               "failed to enable VCC_INTF regulator: %d\n", ret);
186
187         ret = regulator_enable(dlpc->vcc_flsh);
188         if (ret)
189                 DRM_DEV_ERROR(dlpc->dev,
190                               "failed to enable VCC_FLSH regulator: %d\n", ret);
191
192         msleep(10);
193 }
194
195 static void dlpc_atomic_post_disable(struct drm_bridge *bridge,
196                                      struct drm_bridge_state *old_bridge_state)
197 {
198         struct dlpc *dlpc = bridge_to_dlpc(bridge);
199
200         regulator_disable(dlpc->vcc_flsh);
201         regulator_disable(dlpc->vcc_intf);
202
203         msleep(10);
204
205         gpiod_set_value(dlpc->enable_gpio, 0);
206
207         msleep(500);
208 }
209
210 #define MAX_INPUT_SEL_FORMATS   1
211
212 static u32 *
213 dlpc_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
214                                struct drm_bridge_state *bridge_state,
215                                struct drm_crtc_state *crtc_state,
216                                struct drm_connector_state *conn_state,
217                                u32 output_fmt,
218                                unsigned int *num_input_fmts)
219 {
220         u32 *input_fmts;
221
222         *num_input_fmts = 0;
223
224         input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
225                              GFP_KERNEL);
226         if (!input_fmts)
227                 return NULL;
228
229         /* This is the DSI-end bus format */
230         input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
231         *num_input_fmts = 1;
232
233         return input_fmts;
234 }
235
236 static void dlpc_mode_set(struct drm_bridge *bridge,
237                           const struct drm_display_mode *mode,
238                           const struct drm_display_mode *adjusted_mode)
239 {
240         struct dlpc *dlpc = bridge_to_dlpc(bridge);
241
242         drm_mode_copy(&dlpc->mode, adjusted_mode);
243 }
244
245 static int dlpc_attach(struct drm_bridge *bridge,
246                        enum drm_bridge_attach_flags flags)
247 {
248         struct dlpc *dlpc = bridge_to_dlpc(bridge);
249
250         return drm_bridge_attach(bridge->encoder, dlpc->next_bridge, bridge, flags);
251 }
252
253 static const struct drm_bridge_funcs dlpc_bridge_funcs = {
254         .atomic_duplicate_state         = drm_atomic_helper_bridge_duplicate_state,
255         .atomic_destroy_state           = drm_atomic_helper_bridge_destroy_state,
256         .atomic_get_input_bus_fmts      = dlpc_atomic_get_input_bus_fmts,
257         .atomic_reset                   = drm_atomic_helper_bridge_reset,
258         .atomic_pre_enable              = dlpc_atomic_pre_enable,
259         .atomic_enable                  = dlpc_atomic_enable,
260         .atomic_post_disable            = dlpc_atomic_post_disable,
261         .mode_set                       = dlpc_mode_set,
262         .attach                         = dlpc_attach,
263 };
264
265 static int dlpc3433_parse_dt(struct dlpc *dlpc)
266 {
267         struct device *dev = dlpc->dev;
268         struct device_node *endpoint;
269         int ret;
270
271         dlpc->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
272         if (IS_ERR(dlpc->enable_gpio))
273                 return PTR_ERR(dlpc->enable_gpio);
274
275         dlpc->vcc_intf = devm_regulator_get(dlpc->dev, "vcc_intf");
276         if (IS_ERR(dlpc->vcc_intf))
277                 return dev_err_probe(dev, PTR_ERR(dlpc->vcc_intf),
278                                      "failed to get VCC_INTF supply\n");
279
280         dlpc->vcc_flsh = devm_regulator_get(dlpc->dev, "vcc_flsh");
281         if (IS_ERR(dlpc->vcc_flsh))
282                 return dev_err_probe(dev, PTR_ERR(dlpc->vcc_flsh),
283                                      "failed to get VCC_FLSH supply\n");
284
285         dlpc->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
286         if (IS_ERR(dlpc->next_bridge))
287                 return PTR_ERR(dlpc->next_bridge);
288
289         endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0);
290         dlpc->dsi_lanes = of_property_count_u32_elems(endpoint, "data-lanes");
291         if (dlpc->dsi_lanes < 0 || dlpc->dsi_lanes > 4) {
292                 ret = -EINVAL;
293                 goto err_put_endpoint;
294         }
295
296         dlpc->host_node = of_graph_get_remote_port_parent(endpoint);
297         if (!dlpc->host_node) {
298                 ret = -ENODEV;
299                 goto err_put_host;
300         }
301
302         of_node_put(endpoint);
303
304         return 0;
305
306 err_put_host:
307         of_node_put(dlpc->host_node);
308 err_put_endpoint:
309         of_node_put(endpoint);
310         return ret;
311 }
312
313 static int dlpc_host_attach(struct dlpc *dlpc)
314 {
315         struct device *dev = dlpc->dev;
316         struct mipi_dsi_host *host;
317         struct mipi_dsi_device_info info = {
318                 .type = "dlpc3433",
319                 .channel = 0,
320                 .node = NULL,
321         };
322         int ret;
323
324         host = of_find_mipi_dsi_host_by_node(dlpc->host_node);
325         if (!host)
326                 return dev_err_probe(dev, -EPROBE_DEFER, "failed to find dsi host\n");
327
328         dlpc->dsi = mipi_dsi_device_register_full(host, &info);
329         if (IS_ERR(dlpc->dsi)) {
330                 DRM_DEV_ERROR(dev, "failed to create dsi device\n");
331                 return PTR_ERR(dlpc->dsi);
332         }
333
334         dlpc->dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST;
335         dlpc->dsi->format = MIPI_DSI_FMT_RGB565;
336         dlpc->dsi->lanes = dlpc->dsi_lanes;
337
338         ret = devm_mipi_dsi_attach(dev, dlpc->dsi);
339         if (ret)
340                 DRM_DEV_ERROR(dev, "failed to attach dsi host\n");
341
342         return ret;
343 }
344
345 static int dlpc3433_probe(struct i2c_client *client)
346 {
347         struct device *dev = &client->dev;
348         struct dlpc *dlpc;
349         int ret;
350
351         dlpc = devm_kzalloc(dev, sizeof(*dlpc), GFP_KERNEL);
352         if (!dlpc)
353                 return -ENOMEM;
354
355         dlpc->dev = dev;
356
357         dlpc->regmap = devm_regmap_init_i2c(client, &dlpc_regmap_config);
358         if (IS_ERR(dlpc->regmap))
359                 return PTR_ERR(dlpc->regmap);
360
361         ret = dlpc3433_parse_dt(dlpc);
362         if (ret)
363                 return ret;
364
365         dev_set_drvdata(dev, dlpc);
366         i2c_set_clientdata(client, dlpc);
367
368         dlpc->bridge.funcs = &dlpc_bridge_funcs;
369         dlpc->bridge.of_node = dev->of_node;
370         drm_bridge_add(&dlpc->bridge);
371
372         ret = dlpc_host_attach(dlpc);
373         if (ret)
374                 goto err_remove_bridge;
375
376         return 0;
377
378 err_remove_bridge:
379         drm_bridge_remove(&dlpc->bridge);
380         return ret;
381 }
382
383 static void dlpc3433_remove(struct i2c_client *client)
384 {
385         struct dlpc *dlpc = i2c_get_clientdata(client);
386
387         drm_bridge_remove(&dlpc->bridge);
388         of_node_put(dlpc->host_node);
389 }
390
391 static const struct i2c_device_id dlpc3433_id[] = {
392         { "ti,dlpc3433" },
393         { /* sentinel */ }
394 };
395 MODULE_DEVICE_TABLE(i2c, dlpc3433_id);
396
397 static const struct of_device_id dlpc3433_match_table[] = {
398         { .compatible = "ti,dlpc3433" },
399         { /* sentinel */ }
400 };
401 MODULE_DEVICE_TABLE(of, dlpc3433_match_table);
402
403 static struct i2c_driver dlpc3433_driver = {
404         .probe = dlpc3433_probe,
405         .remove = dlpc3433_remove,
406         .id_table = dlpc3433_id,
407         .driver = {
408                 .name = "ti-dlpc3433",
409                 .of_match_table = dlpc3433_match_table,
410         },
411 };
412 module_i2c_driver(dlpc3433_driver);
413
414 MODULE_AUTHOR("Jagan Teki <[email protected]>");
415 MODULE_AUTHOR("Christopher Vollo <[email protected]>");
416 MODULE_DESCRIPTION("TI DLPC3433 MIPI DSI Display Controller Bridge");
417 MODULE_LICENSE("GPL");
This page took 0.056822 seconds and 4 git commands to generate.