]> Git Repo - linux.git/blob - drivers/gpu/drm/panel/panel-startek-kd070fhfid015.c
Revert "drm/amdgpu: add param to specify fw bo location for front-door loading"
[linux.git] / drivers / gpu / drm / panel / panel-startek-kd070fhfid015.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2016 InforceComputing
4  * Copyright (C) 2016 Linaro Ltd
5  * Copyright (C) 2023 BayLibre, SAS
6  *
7  * Authors:
8  * - Vinay Simha BN <[email protected]>
9  * - Sumit Semwal <[email protected]>
10  * - Guillaume La Roque <[email protected]>
11  *
12  */
13
14 #include <linux/backlight.h>
15 #include <linux/delay.h>
16 #include <linux/gpio/consumer.h>
17 #include <linux/module.h>
18 #include <linux/of.h>
19 #include <linux/regulator/consumer.h>
20
21 #include <video/mipi_display.h>
22
23 #include <drm/drm_mipi_dsi.h>
24 #include <drm/drm_modes.h>
25 #include <drm/drm_panel.h>
26
27 #define DSI_REG_MCAP    0xB0
28 #define DSI_REG_IS      0xB3 /* Interface Setting */
29 #define DSI_REG_IIS     0xB4 /* Interface ID Setting */
30 #define DSI_REG_CTRL    0xB6
31
32 enum {
33         IOVCC = 0,
34         POWER = 1
35 };
36
37 struct stk_panel {
38         const struct drm_display_mode *mode;
39         struct backlight_device *backlight;
40         struct drm_panel base;
41         struct gpio_desc *enable_gpio; /* Power IC supply enable */
42         struct gpio_desc *reset_gpio; /* External reset */
43         struct mipi_dsi_device *dsi;
44         struct regulator_bulk_data supplies[2];
45 };
46
47 static inline struct stk_panel *to_stk_panel(struct drm_panel *panel)
48 {
49         return container_of(panel, struct stk_panel, base);
50 }
51
52 static int stk_panel_init(struct stk_panel *stk)
53 {
54         struct mipi_dsi_device *dsi = stk->dsi;
55         struct device *dev = &stk->dsi->dev;
56         int ret;
57
58         ret = mipi_dsi_dcs_soft_reset(dsi);
59         if (ret < 0) {
60                 dev_err(dev, "failed to mipi_dsi_dcs_soft_reset: %d\n", ret);
61                 return ret;
62         }
63         mdelay(5);
64
65         ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
66         if (ret < 0) {
67                 dev_err(dev, "failed to set exit sleep mode: %d\n", ret);
68                 return ret;
69         }
70         msleep(120);
71
72         mipi_dsi_generic_write_seq(dsi, DSI_REG_MCAP, 0x04);
73
74         /* Interface setting, video mode */
75         mipi_dsi_generic_write_seq(dsi, DSI_REG_IS, 0x14, 0x08, 0x00, 0x22, 0x00);
76         mipi_dsi_generic_write_seq(dsi, DSI_REG_IIS, 0x0C, 0x00);
77         mipi_dsi_generic_write_seq(dsi, DSI_REG_CTRL, 0x3A, 0xD3);
78
79         ret = mipi_dsi_dcs_set_display_brightness(dsi, 0x77);
80         if (ret < 0) {
81                 dev_err(dev, "failed to write display brightness: %d\n", ret);
82                 return ret;
83         }
84
85         mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY,
86                                MIPI_DCS_WRITE_MEMORY_START);
87
88         ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x77);
89         if (ret < 0) {
90                 dev_err(dev, "failed to set pixel format: %d\n", ret);
91                 return ret;
92         }
93
94         ret = mipi_dsi_dcs_set_column_address(dsi, 0, stk->mode->hdisplay - 1);
95         if (ret < 0) {
96                 dev_err(dev, "failed to set column address: %d\n", ret);
97                 return ret;
98         }
99
100         ret = mipi_dsi_dcs_set_page_address(dsi, 0, stk->mode->vdisplay - 1);
101         if (ret < 0) {
102                 dev_err(dev, "failed to set page address: %d\n", ret);
103                 return ret;
104         }
105
106         return 0;
107 }
108
109 static int stk_panel_on(struct stk_panel *stk)
110 {
111         struct mipi_dsi_device *dsi = stk->dsi;
112         struct device *dev = &stk->dsi->dev;
113         int ret;
114
115         ret = mipi_dsi_dcs_set_display_on(dsi);
116         if (ret < 0)
117                 dev_err(dev, "failed to set display on: %d\n", ret);
118
119         mdelay(20);
120
121         return ret;
122 }
123
124 static void stk_panel_off(struct stk_panel *stk)
125 {
126         struct mipi_dsi_device *dsi = stk->dsi;
127         struct device *dev = &stk->dsi->dev;
128         int ret;
129
130         dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
131
132         ret = mipi_dsi_dcs_set_display_off(dsi);
133         if (ret < 0)
134                 dev_err(dev, "failed to set display off: %d\n", ret);
135
136         ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
137         if (ret < 0)
138                 dev_err(dev, "failed to enter sleep mode: %d\n", ret);
139
140         msleep(100);
141 }
142
143 static int stk_panel_unprepare(struct drm_panel *panel)
144 {
145         struct stk_panel *stk = to_stk_panel(panel);
146
147         stk_panel_off(stk);
148         regulator_bulk_disable(ARRAY_SIZE(stk->supplies), stk->supplies);
149         gpiod_set_value(stk->reset_gpio, 0);
150         gpiod_set_value(stk->enable_gpio, 1);
151
152         return 0;
153 }
154
155 static int stk_panel_prepare(struct drm_panel *panel)
156 {
157         struct stk_panel *stk = to_stk_panel(panel);
158         struct device *dev = &stk->dsi->dev;
159         int ret;
160
161         gpiod_set_value(stk->reset_gpio, 0);
162         gpiod_set_value(stk->enable_gpio, 0);
163         ret = regulator_enable(stk->supplies[IOVCC].consumer);
164         if (ret < 0)
165                 return ret;
166
167         mdelay(8);
168         ret = regulator_enable(stk->supplies[POWER].consumer);
169         if (ret < 0)
170                 goto iovccoff;
171
172         mdelay(20);
173         gpiod_set_value(stk->enable_gpio, 1);
174         mdelay(20);
175         gpiod_set_value(stk->reset_gpio, 1);
176         mdelay(10);
177         ret = stk_panel_init(stk);
178         if (ret < 0) {
179                 dev_err(dev, "failed to init panel: %d\n", ret);
180                 goto poweroff;
181         }
182
183         ret = stk_panel_on(stk);
184         if (ret < 0) {
185                 dev_err(dev, "failed to set panel on: %d\n", ret);
186                 goto poweroff;
187         }
188
189         return 0;
190
191 poweroff:
192         regulator_disable(stk->supplies[POWER].consumer);
193 iovccoff:
194         regulator_disable(stk->supplies[IOVCC].consumer);
195         gpiod_set_value(stk->reset_gpio, 0);
196         gpiod_set_value(stk->enable_gpio, 0);
197
198         return ret;
199 }
200
201 static const struct drm_display_mode default_mode = {
202                 .clock = 163204,
203                 .hdisplay = 1200,
204                 .hsync_start = 1200 + 144,
205                 .hsync_end = 1200 + 144 + 16,
206                 .htotal = 1200 + 144 + 16 + 45,
207                 .vdisplay = 1920,
208                 .vsync_start = 1920 + 8,
209                 .vsync_end = 1920 + 8 + 4,
210                 .vtotal = 1920 + 8 + 4 + 4,
211                 .width_mm = 95,
212                 .height_mm = 151,
213 };
214
215 static int stk_panel_get_modes(struct drm_panel *panel,
216                                struct drm_connector *connector)
217 {
218         struct drm_display_mode *mode;
219
220         mode = drm_mode_duplicate(connector->dev, &default_mode);
221         if (!mode) {
222                 dev_err(panel->dev, "failed to add mode %ux%ux@%u\n",
223                         default_mode.hdisplay, default_mode.vdisplay,
224                         drm_mode_vrefresh(&default_mode));
225                 return -ENOMEM;
226         }
227
228         drm_mode_set_name(mode);
229         drm_mode_probed_add(connector, mode);
230         connector->display_info.width_mm = default_mode.width_mm;
231         connector->display_info.height_mm = default_mode.height_mm;
232         return 1;
233 }
234
235 static int dsi_dcs_bl_get_brightness(struct backlight_device *bl)
236 {
237         struct mipi_dsi_device *dsi = bl_get_data(bl);
238         int ret;
239         u16 brightness;
240
241         dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
242         ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness);
243         if (ret < 0)
244                 return ret;
245
246         dsi->mode_flags |= MIPI_DSI_MODE_LPM;
247         return brightness & 0xff;
248 }
249
250 static int dsi_dcs_bl_update_status(struct backlight_device *bl)
251 {
252         struct mipi_dsi_device *dsi = bl_get_data(bl);
253         struct device *dev = &dsi->dev;
254         int ret;
255
256         dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
257         ret = mipi_dsi_dcs_set_display_brightness(dsi, bl->props.brightness);
258         if (ret < 0) {
259                 dev_err(dev, "failed to set DSI control: %d\n", ret);
260                 return ret;
261         }
262
263         dsi->mode_flags |= MIPI_DSI_MODE_LPM;
264         return 0;
265 }
266
267 static const struct backlight_ops dsi_bl_ops = {
268         .update_status = dsi_dcs_bl_update_status,
269         .get_brightness = dsi_dcs_bl_get_brightness,
270 };
271
272 static struct backlight_device *
273 drm_panel_create_dsi_backlight(struct mipi_dsi_device *dsi)
274 {
275         struct device *dev = &dsi->dev;
276         struct backlight_properties props = {
277                 .type = BACKLIGHT_RAW,
278                 .brightness = 255,
279                 .max_brightness = 255,
280         };
281
282         return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
283                                               &dsi_bl_ops, &props);
284 }
285
286 static const struct drm_panel_funcs stk_panel_funcs = {
287         .unprepare = stk_panel_unprepare,
288         .prepare = stk_panel_prepare,
289         .get_modes = stk_panel_get_modes,
290 };
291
292 static const struct of_device_id stk_of_match[] = {
293         { .compatible = "startek,kd070fhfid015", },
294         { }
295 };
296 MODULE_DEVICE_TABLE(of, stk_of_match);
297
298 static int stk_panel_add(struct stk_panel *stk)
299 {
300         struct device *dev = &stk->dsi->dev;
301         int ret;
302
303         stk->mode = &default_mode;
304
305         stk->supplies[IOVCC].supply = "iovcc";
306         stk->supplies[POWER].supply = "power";
307         ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(stk->supplies), stk->supplies);
308         if (ret) {
309                 dev_err(dev, "regulator_bulk failed\n");
310                 return ret;
311         }
312
313         stk->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
314         if (IS_ERR(stk->reset_gpio)) {
315                 ret = PTR_ERR(stk->reset_gpio);
316                 dev_err(dev, "cannot get reset-gpios %d\n", ret);
317                 return ret;
318         }
319
320         stk->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
321         if (IS_ERR(stk->enable_gpio)) {
322                 ret = PTR_ERR(stk->enable_gpio);
323                 dev_err(dev, "cannot get enable-gpio %d\n", ret);
324                 return ret;
325         }
326
327         stk->backlight = drm_panel_create_dsi_backlight(stk->dsi);
328         if (IS_ERR(stk->backlight)) {
329                 ret = PTR_ERR(stk->backlight);
330                 dev_err(dev, "failed to register backlight %d\n", ret);
331                 return ret;
332         }
333
334         drm_panel_init(&stk->base, &stk->dsi->dev, &stk_panel_funcs,
335                        DRM_MODE_CONNECTOR_DSI);
336
337         drm_panel_add(&stk->base);
338
339         return 0;
340 }
341
342 static int stk_panel_probe(struct mipi_dsi_device *dsi)
343 {
344         struct stk_panel *stk;
345         int ret;
346
347         dsi->lanes = 4;
348         dsi->format = MIPI_DSI_FMT_RGB888;
349         dsi->mode_flags = (MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM);
350
351         stk = devm_kzalloc(&dsi->dev, sizeof(*stk), GFP_KERNEL);
352         if (!stk)
353                 return -ENOMEM;
354
355         mipi_dsi_set_drvdata(dsi, stk);
356
357         stk->dsi = dsi;
358
359         ret = stk_panel_add(stk);
360         if (ret < 0)
361                 return ret;
362
363         ret = mipi_dsi_attach(dsi);
364         if (ret < 0)
365                 drm_panel_remove(&stk->base);
366
367         return 0;
368 }
369
370 static void stk_panel_remove(struct mipi_dsi_device *dsi)
371 {
372         struct stk_panel *stk = mipi_dsi_get_drvdata(dsi);
373         int err;
374
375         err = mipi_dsi_detach(dsi);
376         if (err < 0)
377                 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n",
378                         err);
379
380         drm_panel_remove(&stk->base);
381 }
382
383 static struct mipi_dsi_driver stk_panel_driver = {
384         .driver = {
385                 .name = "panel-startek-kd070fhfid015",
386                 .of_match_table = stk_of_match,
387         },
388         .probe = stk_panel_probe,
389         .remove = stk_panel_remove,
390 };
391 module_mipi_dsi_driver(stk_panel_driver);
392
393 MODULE_AUTHOR("Guillaume La Roque <[email protected]>");
394 MODULE_DESCRIPTION("STARTEK KD070FHFID015");
395 MODULE_LICENSE("GPL");
This page took 0.058209 seconds and 4 git commands to generate.