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>
26 #include <drm/drm_print.h>
28 struct rb070d30_panel
{
29 struct drm_panel panel
;
30 struct mipi_dsi_device
*dsi
;
31 struct regulator
*supply
;
34 struct gpio_desc
*power
;
35 struct gpio_desc
*reset
;
36 struct gpio_desc
*updn
;
37 struct gpio_desc
*shlr
;
41 static inline struct rb070d30_panel
*panel_to_rb070d30_panel(struct drm_panel
*panel
)
43 return container_of(panel
, struct rb070d30_panel
, panel
);
46 static int rb070d30_panel_prepare(struct drm_panel
*panel
)
48 struct rb070d30_panel
*ctx
= panel_to_rb070d30_panel(panel
);
51 ret
= regulator_enable(ctx
->supply
);
53 DRM_DEV_ERROR(&ctx
->dsi
->dev
, "Failed to enable supply: %d\n", ret
);
58 gpiod_set_value(ctx
->gpios
.power
, 1);
60 gpiod_set_value(ctx
->gpios
.reset
, 1);
65 static int rb070d30_panel_unprepare(struct drm_panel
*panel
)
67 struct rb070d30_panel
*ctx
= panel_to_rb070d30_panel(panel
);
69 gpiod_set_value(ctx
->gpios
.reset
, 0);
70 gpiod_set_value(ctx
->gpios
.power
, 0);
71 regulator_disable(ctx
->supply
);
76 static int rb070d30_panel_enable(struct drm_panel
*panel
)
78 struct rb070d30_panel
*ctx
= panel_to_rb070d30_panel(panel
);
81 ret
= mipi_dsi_dcs_exit_sleep_mode(ctx
->dsi
);
88 static int rb070d30_panel_disable(struct drm_panel
*panel
)
90 struct rb070d30_panel
*ctx
= panel_to_rb070d30_panel(panel
);
92 return mipi_dsi_dcs_enter_sleep_mode(ctx
->dsi
);
96 static const struct drm_display_mode default_mode
= {
99 .hsync_start
= 1024 + 160,
100 .hsync_end
= 1024 + 160 + 80,
101 .htotal
= 1024 + 160 + 80 + 80,
103 .vsync_start
= 600 + 12,
104 .vsync_end
= 600 + 12 + 10,
105 .vtotal
= 600 + 12 + 10 + 13,
112 static int rb070d30_panel_get_modes(struct drm_panel
*panel
,
113 struct drm_connector
*connector
)
115 struct rb070d30_panel
*ctx
= panel_to_rb070d30_panel(panel
);
116 struct drm_display_mode
*mode
;
117 static const u32 bus_format
= MEDIA_BUS_FMT_RGB888_1X24
;
119 mode
= drm_mode_duplicate(connector
->dev
, &default_mode
);
121 DRM_DEV_ERROR(&ctx
->dsi
->dev
,
122 "Failed to add mode " DRM_MODE_FMT
"\n",
123 DRM_MODE_ARG(&default_mode
));
127 drm_mode_set_name(mode
);
129 mode
->type
= DRM_MODE_TYPE_DRIVER
| DRM_MODE_TYPE_PREFERRED
;
130 drm_mode_probed_add(connector
, mode
);
132 connector
->display_info
.bpc
= 8;
133 connector
->display_info
.width_mm
= mode
->width_mm
;
134 connector
->display_info
.height_mm
= mode
->height_mm
;
135 drm_display_info_set_bus_formats(&connector
->display_info
,
141 static const struct drm_panel_funcs rb070d30_panel_funcs
= {
142 .get_modes
= rb070d30_panel_get_modes
,
143 .prepare
= rb070d30_panel_prepare
,
144 .enable
= rb070d30_panel_enable
,
145 .disable
= rb070d30_panel_disable
,
146 .unprepare
= rb070d30_panel_unprepare
,
149 static int rb070d30_panel_dsi_probe(struct mipi_dsi_device
*dsi
)
151 struct rb070d30_panel
*ctx
;
154 ctx
= devm_kzalloc(&dsi
->dev
, sizeof(*ctx
), GFP_KERNEL
);
158 ctx
->supply
= devm_regulator_get(&dsi
->dev
, "vcc-lcd");
159 if (IS_ERR(ctx
->supply
))
160 return PTR_ERR(ctx
->supply
);
162 mipi_dsi_set_drvdata(dsi
, ctx
);
165 drm_panel_init(&ctx
->panel
, &dsi
->dev
, &rb070d30_panel_funcs
,
166 DRM_MODE_CONNECTOR_DSI
);
168 ctx
->gpios
.reset
= devm_gpiod_get(&dsi
->dev
, "reset", GPIOD_OUT_LOW
);
169 if (IS_ERR(ctx
->gpios
.reset
)) {
170 DRM_DEV_ERROR(&dsi
->dev
, "Couldn't get our reset GPIO\n");
171 return PTR_ERR(ctx
->gpios
.reset
);
174 ctx
->gpios
.power
= devm_gpiod_get(&dsi
->dev
, "power", GPIOD_OUT_LOW
);
175 if (IS_ERR(ctx
->gpios
.power
)) {
176 DRM_DEV_ERROR(&dsi
->dev
, "Couldn't get our power GPIO\n");
177 return PTR_ERR(ctx
->gpios
.power
);
181 * We don't change the state of that GPIO later on but we need
182 * to force it into a low state.
184 ctx
->gpios
.updn
= devm_gpiod_get(&dsi
->dev
, "updn", GPIOD_OUT_LOW
);
185 if (IS_ERR(ctx
->gpios
.updn
)) {
186 DRM_DEV_ERROR(&dsi
->dev
, "Couldn't get our updn GPIO\n");
187 return PTR_ERR(ctx
->gpios
.updn
);
191 * We don't change the state of that GPIO later on but we need
192 * to force it into a low state.
194 ctx
->gpios
.shlr
= devm_gpiod_get(&dsi
->dev
, "shlr", GPIOD_OUT_LOW
);
195 if (IS_ERR(ctx
->gpios
.shlr
)) {
196 DRM_DEV_ERROR(&dsi
->dev
, "Couldn't get our shlr GPIO\n");
197 return PTR_ERR(ctx
->gpios
.shlr
);
200 ret
= drm_panel_of_backlight(&ctx
->panel
);
204 ret
= drm_panel_add(&ctx
->panel
);
208 dsi
->mode_flags
= MIPI_DSI_MODE_VIDEO
| MIPI_DSI_MODE_VIDEO_BURST
| MIPI_DSI_MODE_LPM
;
209 dsi
->format
= MIPI_DSI_FMT_RGB888
;
212 return mipi_dsi_attach(dsi
);
215 static int rb070d30_panel_dsi_remove(struct mipi_dsi_device
*dsi
)
217 struct rb070d30_panel
*ctx
= mipi_dsi_get_drvdata(dsi
);
219 mipi_dsi_detach(dsi
);
220 drm_panel_remove(&ctx
->panel
);
225 static const struct of_device_id rb070d30_panel_of_match
[] = {
226 { .compatible
= "ronbo,rb070d30" },
229 MODULE_DEVICE_TABLE(of
, rb070d30_panel_of_match
);
231 static struct mipi_dsi_driver rb070d30_panel_driver
= {
232 .probe
= rb070d30_panel_dsi_probe
,
233 .remove
= rb070d30_panel_dsi_remove
,
235 .name
= "panel-ronbo-rb070d30",
236 .of_match_table
= rb070d30_panel_of_match
,
239 module_mipi_dsi_driver(rb070d30_panel_driver
);
241 MODULE_AUTHOR("Boris Brezillon <boris.brezillon@bootlin.com>");
242 MODULE_AUTHOR("Konstantin Sudakov <k.sudakov@integrasources.com>");
243 MODULE_DESCRIPTION("Ronbo RB070D30 Panel Driver");
244 MODULE_LICENSE("GPL");