1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2018-2019, Bridge Systems BV
4 * Copyright (C) 2018-2019, Bootlin
5 * Copyright (C) 2017, Free Electrons
7 * This file based on panel-ilitek-ili9881c.c
10 #include <linux/delay.h>
11 #include <linux/device.h>
12 #include <linux/err.h>
13 #include <linux/errno.h>
15 #include <linux/kernel.h>
16 #include <linux/media-bus-format.h>
17 #include <linux/module.h>
19 #include <linux/gpio/consumer.h>
20 #include <linux/regulator/consumer.h>
22 #include <drm/drm_connector.h>
23 #include <drm/drm_mipi_dsi.h>
24 #include <drm/drm_modes.h>
25 #include <drm/drm_panel.h>
27 struct rb070d30_panel
{
28 struct drm_panel panel
;
29 struct mipi_dsi_device
*dsi
;
30 struct regulator
*supply
;
33 struct gpio_desc
*power
;
34 struct gpio_desc
*reset
;
35 struct gpio_desc
*updn
;
36 struct gpio_desc
*shlr
;
40 static inline struct rb070d30_panel
*panel_to_rb070d30_panel(struct drm_panel
*panel
)
42 return container_of(panel
, struct rb070d30_panel
, panel
);
45 static int rb070d30_panel_prepare(struct drm_panel
*panel
)
47 struct rb070d30_panel
*ctx
= panel_to_rb070d30_panel(panel
);
50 ret
= regulator_enable(ctx
->supply
);
52 dev_err(&ctx
->dsi
->dev
, "Failed to enable supply: %d\n", ret
);
57 gpiod_set_value(ctx
->gpios
.power
, 1);
59 gpiod_set_value(ctx
->gpios
.reset
, 1);
64 static int rb070d30_panel_unprepare(struct drm_panel
*panel
)
66 struct rb070d30_panel
*ctx
= panel_to_rb070d30_panel(panel
);
68 gpiod_set_value(ctx
->gpios
.reset
, 0);
69 gpiod_set_value(ctx
->gpios
.power
, 0);
70 regulator_disable(ctx
->supply
);
75 static int rb070d30_panel_enable(struct drm_panel
*panel
)
77 struct rb070d30_panel
*ctx
= panel_to_rb070d30_panel(panel
);
79 return mipi_dsi_dcs_exit_sleep_mode(ctx
->dsi
);
82 static int rb070d30_panel_disable(struct drm_panel
*panel
)
84 struct rb070d30_panel
*ctx
= panel_to_rb070d30_panel(panel
);
86 return mipi_dsi_dcs_enter_sleep_mode(ctx
->dsi
);
90 static const struct drm_display_mode default_mode
= {
93 .hsync_start
= 1024 + 160,
94 .hsync_end
= 1024 + 160 + 80,
95 .htotal
= 1024 + 160 + 80 + 80,
97 .vsync_start
= 600 + 12,
98 .vsync_end
= 600 + 12 + 10,
99 .vtotal
= 600 + 12 + 10 + 13,
105 static int rb070d30_panel_get_modes(struct drm_panel
*panel
,
106 struct drm_connector
*connector
)
108 struct rb070d30_panel
*ctx
= panel_to_rb070d30_panel(panel
);
109 struct drm_display_mode
*mode
;
110 static const u32 bus_format
= MEDIA_BUS_FMT_RGB888_1X24
;
112 mode
= drm_mode_duplicate(connector
->dev
, &default_mode
);
114 dev_err(&ctx
->dsi
->dev
, "Failed to add mode " DRM_MODE_FMT
"\n",
115 DRM_MODE_ARG(&default_mode
));
119 drm_mode_set_name(mode
);
121 mode
->type
= DRM_MODE_TYPE_DRIVER
| DRM_MODE_TYPE_PREFERRED
;
122 drm_mode_probed_add(connector
, mode
);
124 connector
->display_info
.bpc
= 8;
125 connector
->display_info
.width_mm
= mode
->width_mm
;
126 connector
->display_info
.height_mm
= mode
->height_mm
;
127 drm_display_info_set_bus_formats(&connector
->display_info
,
133 static const struct drm_panel_funcs rb070d30_panel_funcs
= {
134 .get_modes
= rb070d30_panel_get_modes
,
135 .prepare
= rb070d30_panel_prepare
,
136 .enable
= rb070d30_panel_enable
,
137 .disable
= rb070d30_panel_disable
,
138 .unprepare
= rb070d30_panel_unprepare
,
141 static int rb070d30_panel_dsi_probe(struct mipi_dsi_device
*dsi
)
143 struct rb070d30_panel
*ctx
;
146 ctx
= devm_kzalloc(&dsi
->dev
, sizeof(*ctx
), GFP_KERNEL
);
150 ctx
->supply
= devm_regulator_get(&dsi
->dev
, "vcc-lcd");
151 if (IS_ERR(ctx
->supply
))
152 return PTR_ERR(ctx
->supply
);
154 mipi_dsi_set_drvdata(dsi
, ctx
);
157 drm_panel_init(&ctx
->panel
, &dsi
->dev
, &rb070d30_panel_funcs
,
158 DRM_MODE_CONNECTOR_DSI
);
160 ctx
->gpios
.reset
= devm_gpiod_get(&dsi
->dev
, "reset", GPIOD_OUT_LOW
);
161 if (IS_ERR(ctx
->gpios
.reset
)) {
162 dev_err(&dsi
->dev
, "Couldn't get our reset GPIO\n");
163 return PTR_ERR(ctx
->gpios
.reset
);
166 ctx
->gpios
.power
= devm_gpiod_get(&dsi
->dev
, "power", GPIOD_OUT_LOW
);
167 if (IS_ERR(ctx
->gpios
.power
)) {
168 dev_err(&dsi
->dev
, "Couldn't get our power GPIO\n");
169 return PTR_ERR(ctx
->gpios
.power
);
173 * We don't change the state of that GPIO later on but we need
174 * to force it into a low state.
176 ctx
->gpios
.updn
= devm_gpiod_get(&dsi
->dev
, "updn", GPIOD_OUT_LOW
);
177 if (IS_ERR(ctx
->gpios
.updn
)) {
178 dev_err(&dsi
->dev
, "Couldn't get our updn GPIO\n");
179 return PTR_ERR(ctx
->gpios
.updn
);
183 * We don't change the state of that GPIO later on but we need
184 * to force it into a low state.
186 ctx
->gpios
.shlr
= devm_gpiod_get(&dsi
->dev
, "shlr", GPIOD_OUT_LOW
);
187 if (IS_ERR(ctx
->gpios
.shlr
)) {
188 dev_err(&dsi
->dev
, "Couldn't get our shlr GPIO\n");
189 return PTR_ERR(ctx
->gpios
.shlr
);
192 ret
= drm_panel_of_backlight(&ctx
->panel
);
196 drm_panel_add(&ctx
->panel
);
198 dsi
->mode_flags
= MIPI_DSI_MODE_VIDEO
| MIPI_DSI_MODE_VIDEO_BURST
| MIPI_DSI_MODE_LPM
;
199 dsi
->format
= MIPI_DSI_FMT_RGB888
;
202 return mipi_dsi_attach(dsi
);
205 static int rb070d30_panel_dsi_remove(struct mipi_dsi_device
*dsi
)
207 struct rb070d30_panel
*ctx
= mipi_dsi_get_drvdata(dsi
);
209 mipi_dsi_detach(dsi
);
210 drm_panel_remove(&ctx
->panel
);
215 static const struct of_device_id rb070d30_panel_of_match
[] = {
216 { .compatible
= "ronbo,rb070d30" },
219 MODULE_DEVICE_TABLE(of
, rb070d30_panel_of_match
);
221 static struct mipi_dsi_driver rb070d30_panel_driver
= {
222 .probe
= rb070d30_panel_dsi_probe
,
223 .remove
= rb070d30_panel_dsi_remove
,
225 .name
= "panel-ronbo-rb070d30",
226 .of_match_table
= rb070d30_panel_of_match
,
229 module_mipi_dsi_driver(rb070d30_panel_driver
);
231 MODULE_AUTHOR("Boris Brezillon <boris.brezillon@bootlin.com>");
232 MODULE_AUTHOR("Konstantin Sudakov <k.sudakov@integrasources.com>");
233 MODULE_DESCRIPTION("Ronbo RB070D30 Panel Driver");
234 MODULE_LICENSE("GPL");