global: Migrate CONFIG_STACKBASE to CFG
[platform/kernel/u-boot.git] / drivers / video / tdo-tl070wsh30.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2020 BayLibre, SAS
4  * Author: Neil Armstrong <narmstrong@baylibre.com>
5  */
6 #include <common.h>
7 #include <backlight.h>
8 #include <dm.h>
9 #include <mipi_dsi.h>
10 #include <panel.h>
11 #include <asm/gpio.h>
12 #include <dm/device_compat.h>
13 #include <linux/delay.h>
14 #include <power/regulator.h>
15
16 struct tl070wsh30_panel_priv {
17         struct udevice *reg;
18         struct udevice *backlight;
19         struct gpio_desc reset;
20 };
21
22 static const struct display_timing default_timing = {
23         .pixelclock.typ         = 47250000,
24         .hactive.typ            = 1024,
25         .hfront_porch.typ       = 46,
26         .hback_porch.typ        = 100,
27         .hsync_len.typ          = 80,
28         .vactive.typ            = 600,
29         .vfront_porch.typ       = 5,
30         .vback_porch.typ        = 20,
31         .vsync_len.typ          = 5,
32         .flags                  = DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH,
33 };
34
35 static int tl070wsh30_panel_enable_backlight(struct udevice *dev)
36 {
37         struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
38         struct mipi_dsi_device *device = plat->device;
39         struct tl070wsh30_panel_priv *priv = dev_get_priv(dev);
40         int ret;
41
42         ret = mipi_dsi_attach(device);
43         if (ret < 0)
44                 return ret;
45
46         ret = mipi_dsi_dcs_exit_sleep_mode(device);
47         if (ret)
48                 return ret;
49
50         mdelay(200);
51
52         ret = mipi_dsi_dcs_set_display_on(device);
53         if (ret)
54                 return ret;
55
56         mdelay(20);
57
58         ret = backlight_enable(priv->backlight);
59         if (ret)
60                 return ret;
61
62         return 0;
63 }
64
65 static int tl070wsh30_panel_get_display_timing(struct udevice *dev,
66                                             struct display_timing *timings)
67 {
68         memcpy(timings, &default_timing, sizeof(*timings));
69
70         return 0;
71 }
72
73 static int tl070wsh30_panel_of_to_plat(struct udevice *dev)
74 {
75         struct tl070wsh30_panel_priv *priv = dev_get_priv(dev);
76         int ret;
77
78         if (IS_ENABLED(CONFIG_DM_REGULATOR)) {
79                 ret =  device_get_supply_regulator(dev, "power-supply",
80                                                    &priv->reg);
81                 if (ret && ret != -ENOENT) {
82                         dev_err(dev, "Warning: cannot get power supply\n");
83                         return ret;
84                 }
85         }
86
87         ret = gpio_request_by_name(dev, "reset-gpios", 0, &priv->reset,
88                                    GPIOD_IS_OUT);
89         if (ret) {
90                 dev_err(dev, "Warning: cannot get reset GPIO\n");
91                 if (ret != -ENOENT)
92                         return ret;
93         }
94
95         ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
96                                            "backlight", &priv->backlight);
97         if (ret) {
98                 dev_err(dev, "Cannot get backlight: ret=%d\n", ret);
99                 return ret;
100         }
101
102         return 0;
103 }
104
105 static int tl070wsh30_panel_probe(struct udevice *dev)
106 {
107         struct tl070wsh30_panel_priv *priv = dev_get_priv(dev);
108         struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
109         int ret;
110
111         if (IS_ENABLED(CONFIG_DM_REGULATOR) && priv->reg) {
112                 ret = regulator_set_enable(priv->reg, true);
113                 if (ret)
114                         return ret;
115         }
116
117         mdelay(10);
118
119         /* reset panel */
120         dm_gpio_set_value(&priv->reset, true);
121
122         mdelay(10);
123
124         dm_gpio_set_value(&priv->reset, false);
125
126         /* fill characteristics of DSI data link */
127         plat->lanes = 4;
128         plat->format = MIPI_DSI_FMT_RGB888;
129         plat->mode_flags = MIPI_DSI_MODE_VIDEO |
130                            MIPI_DSI_MODE_VIDEO_BURST |
131                            MIPI_DSI_MODE_LPM;
132
133         return 0;
134 }
135
136 static const struct panel_ops tl070wsh30_panel_ops = {
137         .enable_backlight = tl070wsh30_panel_enable_backlight,
138         .get_display_timing = tl070wsh30_panel_get_display_timing,
139 };
140
141 static const struct udevice_id tl070wsh30_panel_ids[] = {
142         { .compatible = "tdo,tl070wsh30" },
143         { }
144 };
145
146 U_BOOT_DRIVER(tl070wsh30_panel) = {
147         .name                     = "tl070wsh30_panel",
148         .id                       = UCLASS_PANEL,
149         .of_match                 = tl070wsh30_panel_ids,
150         .ops                      = &tl070wsh30_panel_ops,
151         .of_to_plat               = tl070wsh30_panel_of_to_plat,
152         .probe                    = tl070wsh30_panel_probe,
153         .plat_auto                = sizeof(struct mipi_dsi_panel_plat),
154         .priv_auto                = sizeof(struct tl070wsh30_panel_priv),
155 };