blob: ae9d11f475b6306fb3c888c5aaeaa0b23380b29f [file] [log] [blame]
Neil Armstrongc823f242020-09-29 11:53:53 +02001// 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
16struct tl070wsh30_panel_priv {
17 struct udevice *reg;
18 struct udevice *backlight;
19 struct gpio_desc reset;
20};
21
22static 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
35static int tl070wsh30_panel_enable_backlight(struct udevice *dev)
36{
37 struct mipi_dsi_panel_plat *plat = dev_get_platdata(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
65static 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
73static int tl070wsh30_panel_ofdata_to_platdata(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
105static 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_platdata(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
136static 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
141static const struct udevice_id tl070wsh30_panel_ids[] = {
142 { .compatible = "tdo,tl070wsh30" },
143 { }
144};
145
146U_BOOT_DRIVER(tl070wsh30_panel) = {
147 .name = "tl070wsh30_panel",
148 .id = UCLASS_PANEL,
149 .of_match = tl070wsh30_panel_ids,
150 .ops = &tl070wsh30_panel_ops,
151 .ofdata_to_platdata = tl070wsh30_panel_ofdata_to_platdata,
152 .probe = tl070wsh30_panel_probe,
153 .platdata_auto_alloc_size = sizeof(struct mipi_dsi_panel_plat),
154 .priv_auto_alloc_size = sizeof(struct tl070wsh30_panel_priv),
155};