1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2020 Rockchip Electronics Co. Ltd.
4 *
5 * Author: Guochun Huang <hero.huang@rock-chips.com>
6 */
7
8 #include "rk628.h"
9 #include <linux/gpio/consumer.h>
10 #include <linux/backlight.h>
11
12 #include "panel.h"
13
14 static int
dsi_panel_parse_cmds(const u8 * data,int blen,struct panel_cmds * pcmds)15 dsi_panel_parse_cmds(const u8 *data, int blen, struct panel_cmds *pcmds)
16 {
17 unsigned int len;
18 char *buf, *bp;
19 struct cmd_ctrl_hdr *dchdr;
20 int i, cnt;
21
22 if (!pcmds)
23 return -EINVAL;
24
25 buf = kmemdup(data, blen, GFP_KERNEL);
26 if (!buf)
27 return -ENOMEM;
28
29 /* scan init commands */
30 bp = buf;
31 len = blen;
32 cnt = 0;
33 while (len > sizeof(*dchdr)) {
34 dchdr = (struct cmd_ctrl_hdr *)bp;
35
36 if (dchdr->dlen > len) {
37 pr_err("%s: error, len=%d", __func__, dchdr->dlen);
38 return -EINVAL;
39 }
40
41 bp += sizeof(*dchdr);
42 len -= sizeof(*dchdr);
43 bp += dchdr->dlen;
44 len -= dchdr->dlen;
45 cnt++;
46 }
47
48 if (len != 0) {
49 pr_err("%s: dcs_cmd=%x len=%d error!", __func__, buf[0], blen);
50 kfree(buf);
51 return -EINVAL;
52 }
53
54 pcmds->cmds = kcalloc(cnt, sizeof(struct cmd_desc), GFP_KERNEL);
55 if (!pcmds->cmds) {
56 kfree(buf);
57 return -ENOMEM;
58 }
59
60 pcmds->cmd_cnt = cnt;
61 pcmds->buf = buf;
62 pcmds->blen = blen;
63
64 bp = buf;
65 len = blen;
66 for (i = 0; i < cnt; i++) {
67 dchdr = (struct cmd_ctrl_hdr *)bp;
68 len -= sizeof(*dchdr);
69 bp += sizeof(*dchdr);
70 pcmds->cmds[i].dchdr = *dchdr;
71 pcmds->cmds[i].payload = bp;
72 bp += dchdr->dlen;
73 len -= dchdr->dlen;
74 }
75
76 return 0;
77 }
78
dsi_panel_get_cmds(struct rk628 * rk628,struct device_node * dsi_np)79 static int dsi_panel_get_cmds(struct rk628 *rk628, struct device_node *dsi_np)
80 {
81 struct device_node *np;
82 const void *data;
83 int len;
84 int ret, err;
85
86 np = of_find_node_by_name(dsi_np, "rk628-panel");
87 if (!np)
88 return -EINVAL;
89
90 data = of_get_property(np, "panel-init-sequence", &len);
91 if (data) {
92 rk628->panel->on_cmds = kcalloc(1, sizeof(struct panel_cmds), GFP_KERNEL);
93 if (!rk628->panel->on_cmds)
94 return -ENOMEM;
95
96 err = dsi_panel_parse_cmds(data, len, rk628->panel->on_cmds);
97 if (err) {
98 dev_err(rk628->dev, "failed to parse dsi panel init sequence\n");
99 ret = err;
100 goto init_err;
101 }
102 }
103
104 data = of_get_property(np, "panel-exit-sequence", &len);
105 if (data) {
106 rk628->panel->off_cmds = kcalloc(1, sizeof(struct panel_cmds), GFP_KERNEL);
107 if (!rk628->panel->off_cmds) {
108 ret = -ENOMEM;
109 goto on_err;
110 }
111
112 err = dsi_panel_parse_cmds(data, len, rk628->panel->off_cmds);
113 if (err) {
114 dev_err(rk628->dev, "failed to parse dsi panel exit sequence\n");
115 ret = err;
116 goto exit_err;
117 }
118 }
119
120 return 0;
121
122 exit_err:
123 kfree(rk628->panel->off_cmds);
124 on_err:
125 kfree(rk628->panel->on_cmds->cmds);
126 kfree(rk628->panel->on_cmds->buf);
127 init_err:
128 kfree(rk628->panel->on_cmds);
129
130 return ret;
131 }
132
rk628_panel_info_get(struct rk628 * rk628,struct device_node * np)133 int rk628_panel_info_get(struct rk628 *rk628, struct device_node *np)
134 {
135 struct panel_simple *panel;
136 struct device *dev = rk628->dev;
137 struct device_node *backlight;
138 int ret;
139
140 panel = devm_kzalloc(dev, sizeof(struct panel_simple), GFP_KERNEL);
141 if (!panel)
142 return -ENOMEM;
143
144 panel->supply = devm_regulator_get(dev, "power");
145 if (IS_ERR(panel->supply)) {
146 ret = PTR_ERR(panel->supply);
147 dev_err(dev, "failed to get power regulator: %d\n", ret);
148 return ret;
149 }
150
151 panel->enable_gpio = devm_gpiod_get_optional(dev, "panel-enable", GPIOD_OUT_LOW);
152 if (IS_ERR(panel->enable_gpio)) {
153 ret = PTR_ERR(panel->enable_gpio);
154 dev_err(dev, "failed to request panel enable GPIO: %d\n", ret);
155 return ret;
156 }
157
158 panel->reset_gpio = devm_gpiod_get_optional(dev, "panel-reset", GPIOD_OUT_LOW);
159 if (IS_ERR(panel->reset_gpio)) {
160 ret = PTR_ERR(panel->reset_gpio);
161 dev_err(dev, "failed to request panel reset GPIO: %d\n", ret);
162 return ret;
163 }
164
165 backlight = of_parse_phandle(dev->of_node, "panel-backlight", 0);
166 if (backlight) {
167 panel->backlight = of_find_backlight_by_node(backlight);
168 of_node_put(backlight);
169
170 if (!panel->backlight) {
171 dev_err(dev, "failed to find backlight\n");
172 return -EPROBE_DEFER;
173 }
174
175 }
176
177 rk628->panel = panel;
178
179 if (rk628->output_mode == OUTPUT_MODE_DSI) {
180 ret = dsi_panel_get_cmds(rk628, np);
181 if (ret) {
182 dev_err(dev, "failed to get cmds\n");
183 return ret;
184 }
185 }
186
187 return 0;
188 }
189
rk628_panel_prepare(struct rk628 * rk628)190 void rk628_panel_prepare(struct rk628 *rk628)
191 {
192 int ret;
193
194 if (rk628->panel->supply) {
195 ret = regulator_enable(rk628->panel->supply);
196 if (ret)
197 dev_info(rk628->dev, "failed to enable panel power supply\n");
198 }
199
200 if (rk628->panel->enable_gpio) {
201 gpiod_set_value(rk628->panel->enable_gpio, 0);
202 mdelay(120);
203 gpiod_set_value(rk628->panel->enable_gpio, 1);
204 mdelay(120);
205 }
206
207 if (rk628->panel->reset_gpio) {
208 gpiod_set_value(rk628->panel->reset_gpio, 0);
209 mdelay(120);
210 gpiod_set_value(rk628->panel->reset_gpio, 1);
211 mdelay(120);
212 gpiod_set_value(rk628->panel->reset_gpio, 0);
213 mdelay(120);
214 }
215 }
216
rk628_panel_enable(struct rk628 * rk628)217 void rk628_panel_enable(struct rk628 *rk628)
218 {
219 if (rk628->panel->backlight)
220 backlight_enable(rk628->panel->backlight);
221 }
222
rk628_panel_unprepare(struct rk628 * rk628)223 void rk628_panel_unprepare(struct rk628 *rk628)
224 {
225
226 if (rk628->panel->reset_gpio) {
227 gpiod_set_value(rk628->panel->reset_gpio, 1);
228 mdelay(120);
229 }
230
231 if (rk628->panel->enable_gpio) {
232 gpiod_set_value(rk628->panel->enable_gpio, 0);
233 mdelay(120);
234 }
235
236 if (rk628->panel->supply)
237 regulator_disable(rk628->panel->supply);
238 }
239
rk628_panel_disable(struct rk628 * rk628)240 void rk628_panel_disable(struct rk628 *rk628)
241 {
242 if (rk628->panel->backlight)
243 backlight_disable(rk628->panel->backlight);
244
245 }
246