1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2019, Huaqin Telecom Technology Co., Ltd
5 * Author: Jerry Han <jerry.han.hq@gmail.com>
9 #include <linux/delay.h>
10 #include <linux/kernel.h>
11 #include <linux/module.h>
13 #include <linux/of_device.h>
15 #include <linux/gpio/consumer.h>
16 #include <linux/regulator/consumer.h>
18 #include <drm/drm_device.h>
19 #include <drm/drm_mipi_dsi.h>
20 #include <drm/drm_modes.h>
21 #include <drm/drm_panel.h>
22 #include <drm/drm_print.h>
24 #include <video/mipi_display.h>
32 const struct drm_display_mode
*display_mode
;
34 unsigned int width_mm
;
35 unsigned int height_mm
;
37 unsigned long mode_flags
;
38 enum mipi_dsi_pixel_format format
;
40 const struct panel_cmd
*on_cmds
;
41 unsigned int on_cmds_num
;
45 struct drm_panel base
;
46 struct mipi_dsi_device
*link
;
47 const struct panel_desc
*desc
;
49 struct gpio_desc
*enable_gpio
;
50 struct gpio_desc
*pp33_gpio
;
51 struct gpio_desc
*pp18_gpio
;
57 static inline struct panel_info
*to_panel_info(struct drm_panel
*panel
)
59 return container_of(panel
, struct panel_info
, base
);
62 static void disable_gpios(struct panel_info
*pinfo
)
64 gpiod_set_value(pinfo
->enable_gpio
, 0);
65 gpiod_set_value(pinfo
->pp33_gpio
, 0);
66 gpiod_set_value(pinfo
->pp18_gpio
, 0);
69 static int send_mipi_cmds(struct drm_panel
*panel
, const struct panel_cmd
*cmds
)
71 struct panel_info
*pinfo
= to_panel_info(panel
);
75 for (i
= 0; i
< pinfo
->desc
->on_cmds_num
; i
++) {
76 err
= mipi_dsi_dcs_write_buffer(pinfo
->link
, &cmds
[i
],
77 sizeof(struct panel_cmd
));
86 static int boe_panel_disable(struct drm_panel
*panel
)
88 struct panel_info
*pinfo
= to_panel_info(panel
);
94 err
= mipi_dsi_dcs_set_display_off(pinfo
->link
);
96 DRM_DEV_ERROR(panel
->dev
, "failed to set display off: %d\n",
101 pinfo
->enabled
= false;
106 static int boe_panel_unprepare(struct drm_panel
*panel
)
108 struct panel_info
*pinfo
= to_panel_info(panel
);
111 if (!pinfo
->prepared
)
114 err
= mipi_dsi_dcs_set_display_off(pinfo
->link
);
116 DRM_DEV_ERROR(panel
->dev
, "failed to set display off: %d\n",
119 err
= mipi_dsi_dcs_enter_sleep_mode(pinfo
->link
);
121 DRM_DEV_ERROR(panel
->dev
, "failed to enter sleep mode: %d\n",
124 /* sleep_mode_delay: 1ms - 2ms */
125 usleep_range(1000, 2000);
127 disable_gpios(pinfo
);
129 pinfo
->prepared
= false;
134 static int boe_panel_prepare(struct drm_panel
*panel
)
136 struct panel_info
*pinfo
= to_panel_info(panel
);
142 gpiod_set_value(pinfo
->pp18_gpio
, 1);
144 usleep_range(5000, 6000);
145 gpiod_set_value(pinfo
->pp33_gpio
, 1);
148 /* T2: 14ms - 15ms */
149 usleep_range(14000, 15000);
150 gpiod_set_value(pinfo
->enable_gpio
, 1);
153 usleep_range(1000, 2000);
154 gpiod_set_value(pinfo
->enable_gpio
, 0);
157 usleep_range(1000, 2000);
158 gpiod_set_value(pinfo
->enable_gpio
, 1);
161 usleep_range(5000, 6000);
164 err
= send_mipi_cmds(panel
, pinfo
->desc
->on_cmds
);
166 DRM_DEV_ERROR(panel
->dev
, "failed to send DCS Init Code: %d\n",
171 err
= mipi_dsi_dcs_exit_sleep_mode(pinfo
->link
);
173 DRM_DEV_ERROR(panel
->dev
, "failed to exit sleep mode: %d\n",
178 /* T6: 120ms - 121ms */
179 usleep_range(120000, 121000);
181 err
= mipi_dsi_dcs_set_display_on(pinfo
->link
);
183 DRM_DEV_ERROR(panel
->dev
, "failed to set display on: %d\n",
188 /* T7: 20ms - 21ms */
189 usleep_range(20000, 21000);
191 pinfo
->prepared
= true;
196 disable_gpios(pinfo
);
200 static int boe_panel_enable(struct drm_panel
*panel
)
202 struct panel_info
*pinfo
= to_panel_info(panel
);
208 usleep_range(120000, 121000);
210 ret
= mipi_dsi_dcs_set_display_on(pinfo
->link
);
212 DRM_DEV_ERROR(panel
->dev
, "failed to set display on: %d\n",
217 pinfo
->enabled
= true;
222 static int boe_panel_get_modes(struct drm_panel
*panel
,
223 struct drm_connector
*connector
)
225 struct panel_info
*pinfo
= to_panel_info(panel
);
226 const struct drm_display_mode
*m
= pinfo
->desc
->display_mode
;
227 struct drm_display_mode
*mode
;
229 mode
= drm_mode_duplicate(connector
->dev
, m
);
231 DRM_DEV_ERROR(pinfo
->base
.dev
, "failed to add mode %ux%u@%u\n",
232 m
->hdisplay
, m
->vdisplay
, m
->vrefresh
);
236 drm_mode_set_name(mode
);
238 drm_mode_probed_add(connector
, mode
);
240 connector
->display_info
.width_mm
= pinfo
->desc
->width_mm
;
241 connector
->display_info
.height_mm
= pinfo
->desc
->height_mm
;
242 connector
->display_info
.bpc
= pinfo
->desc
->bpc
;
247 static const struct drm_panel_funcs panel_funcs
= {
248 .disable
= boe_panel_disable
,
249 .unprepare
= boe_panel_unprepare
,
250 .prepare
= boe_panel_prepare
,
251 .enable
= boe_panel_enable
,
252 .get_modes
= boe_panel_get_modes
,
255 static const struct drm_display_mode default_display_mode
= {
258 .hsync_start
= 1200 + 80,
259 .hsync_end
= 1200 + 80 + 60,
260 .htotal
= 1200 + 80 + 60 + 24,
262 .vsync_start
= 1920 + 10,
263 .vsync_end
= 1920 + 10 + 14,
264 .vtotal
= 1920 + 10 + 14 + 4,
269 static const struct panel_cmd boe_himax8279d8p_on_cmds
[] = {
532 static const struct panel_desc boe_himax8279d8p_panel_desc
= {
533 .display_mode
= &default_display_mode
,
537 .mode_flags
= MIPI_DSI_MODE_VIDEO
| MIPI_DSI_MODE_VIDEO_SYNC_PULSE
|
538 MIPI_DSI_CLOCK_NON_CONTINUOUS
| MIPI_DSI_MODE_LPM
,
539 .format
= MIPI_DSI_FMT_RGB888
,
541 .on_cmds
= boe_himax8279d8p_on_cmds
,
546 static const struct panel_cmd boe_himax8279d10p_on_cmds
[] = {
832 static const struct panel_desc boe_himax8279d10p_panel_desc
= {
833 .display_mode
= &default_display_mode
,
837 .mode_flags
= MIPI_DSI_MODE_VIDEO
| MIPI_DSI_MODE_VIDEO_SYNC_PULSE
|
838 MIPI_DSI_CLOCK_NON_CONTINUOUS
| MIPI_DSI_MODE_LPM
,
839 .format
= MIPI_DSI_FMT_RGB888
,
841 .on_cmds
= boe_himax8279d10p_on_cmds
,
845 static const struct of_device_id panel_of_match
[] = {
847 .compatible
= "boe,himax8279d8p",
848 .data
= &boe_himax8279d8p_panel_desc
,
851 .compatible
= "boe,himax8279d10p",
852 .data
= &boe_himax8279d10p_panel_desc
,
858 MODULE_DEVICE_TABLE(of
, panel_of_match
);
860 static int panel_add(struct panel_info
*pinfo
)
862 struct device
*dev
= &pinfo
->link
->dev
;
865 pinfo
->pp18_gpio
= devm_gpiod_get(dev
, "pp18", GPIOD_OUT_HIGH
);
866 if (IS_ERR(pinfo
->pp18_gpio
)) {
867 ret
= PTR_ERR(pinfo
->pp18_gpio
);
868 if (ret
!= -EPROBE_DEFER
)
869 DRM_DEV_ERROR(dev
, "failed to get pp18 gpio: %d\n",
874 pinfo
->pp33_gpio
= devm_gpiod_get(dev
, "pp33", GPIOD_OUT_HIGH
);
875 if (IS_ERR(pinfo
->pp33_gpio
)) {
876 ret
= PTR_ERR(pinfo
->pp33_gpio
);
877 if (ret
!= -EPROBE_DEFER
)
878 DRM_DEV_ERROR(dev
, "failed to get pp33 gpio: %d\n",
883 pinfo
->enable_gpio
= devm_gpiod_get(dev
, "enable", GPIOD_OUT_HIGH
);
884 if (IS_ERR(pinfo
->enable_gpio
)) {
885 ret
= PTR_ERR(pinfo
->enable_gpio
);
886 if (ret
!= -EPROBE_DEFER
)
887 DRM_DEV_ERROR(dev
, "failed to get enable gpio: %d\n",
892 drm_panel_init(&pinfo
->base
, dev
, &panel_funcs
,
893 DRM_MODE_CONNECTOR_DSI
);
895 ret
= drm_panel_of_backlight(&pinfo
->base
);
899 return drm_panel_add(&pinfo
->base
);
902 static int panel_probe(struct mipi_dsi_device
*dsi
)
904 struct panel_info
*pinfo
;
905 const struct panel_desc
*desc
;
908 pinfo
= devm_kzalloc(&dsi
->dev
, sizeof(*pinfo
), GFP_KERNEL
);
912 desc
= of_device_get_match_data(&dsi
->dev
);
913 dsi
->mode_flags
= desc
->mode_flags
;
914 dsi
->format
= desc
->format
;
915 dsi
->lanes
= desc
->lanes
;
919 mipi_dsi_set_drvdata(dsi
, pinfo
);
921 err
= panel_add(pinfo
);
925 err
= mipi_dsi_attach(dsi
);
927 drm_panel_remove(&pinfo
->base
);
932 static int panel_remove(struct mipi_dsi_device
*dsi
)
934 struct panel_info
*pinfo
= mipi_dsi_get_drvdata(dsi
);
937 err
= boe_panel_disable(&pinfo
->base
);
939 DRM_DEV_ERROR(&dsi
->dev
, "failed to disable panel: %d\n",
942 err
= boe_panel_unprepare(&pinfo
->base
);
944 DRM_DEV_ERROR(&dsi
->dev
, "failed to unprepare panel: %d\n",
947 err
= mipi_dsi_detach(dsi
);
949 DRM_DEV_ERROR(&dsi
->dev
, "failed to detach from DSI host: %d\n",
952 drm_panel_remove(&pinfo
->base
);
957 static void panel_shutdown(struct mipi_dsi_device
*dsi
)
959 struct panel_info
*pinfo
= mipi_dsi_get_drvdata(dsi
);
961 boe_panel_disable(&pinfo
->base
);
962 boe_panel_unprepare(&pinfo
->base
);
965 static struct mipi_dsi_driver panel_driver
= {
967 .name
= "panel-boe-himax8279d",
968 .of_match_table
= panel_of_match
,
970 .probe
= panel_probe
,
971 .remove
= panel_remove
,
972 .shutdown
= panel_shutdown
,
974 module_mipi_dsi_driver(panel_driver
);
976 MODULE_AUTHOR("Jerry Han <jerry.han.hq@gmail.com>");
977 MODULE_DESCRIPTION("Boe Himax8279d driver");
978 MODULE_LICENSE("GPL v2");