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>
23 #include <video/mipi_display.h>
31 const struct drm_display_mode
*display_mode
;
33 unsigned int width_mm
;
34 unsigned int height_mm
;
36 unsigned long mode_flags
;
37 enum mipi_dsi_pixel_format format
;
39 const struct panel_cmd
*on_cmds
;
40 unsigned int on_cmds_num
;
44 struct drm_panel base
;
45 struct mipi_dsi_device
*link
;
46 const struct panel_desc
*desc
;
48 struct gpio_desc
*enable_gpio
;
49 struct gpio_desc
*pp33_gpio
;
50 struct gpio_desc
*pp18_gpio
;
56 static inline struct panel_info
*to_panel_info(struct drm_panel
*panel
)
58 return container_of(panel
, struct panel_info
, base
);
61 static void disable_gpios(struct panel_info
*pinfo
)
63 gpiod_set_value(pinfo
->enable_gpio
, 0);
64 gpiod_set_value(pinfo
->pp33_gpio
, 0);
65 gpiod_set_value(pinfo
->pp18_gpio
, 0);
68 static int send_mipi_cmds(struct drm_panel
*panel
, const struct panel_cmd
*cmds
)
70 struct panel_info
*pinfo
= to_panel_info(panel
);
74 for (i
= 0; i
< pinfo
->desc
->on_cmds_num
; i
++) {
75 err
= mipi_dsi_dcs_write_buffer(pinfo
->link
, &cmds
[i
],
76 sizeof(struct panel_cmd
));
85 static int boe_panel_disable(struct drm_panel
*panel
)
87 struct panel_info
*pinfo
= to_panel_info(panel
);
93 err
= mipi_dsi_dcs_set_display_off(pinfo
->link
);
95 dev_err(panel
->dev
, "failed to set display off: %d\n", err
);
99 pinfo
->enabled
= false;
104 static int boe_panel_unprepare(struct drm_panel
*panel
)
106 struct panel_info
*pinfo
= to_panel_info(panel
);
109 if (!pinfo
->prepared
)
112 err
= mipi_dsi_dcs_set_display_off(pinfo
->link
);
114 dev_err(panel
->dev
, "failed to set display off: %d\n", err
);
116 err
= mipi_dsi_dcs_enter_sleep_mode(pinfo
->link
);
118 dev_err(panel
->dev
, "failed to enter sleep mode: %d\n", err
);
120 /* sleep_mode_delay: 1ms - 2ms */
121 usleep_range(1000, 2000);
123 disable_gpios(pinfo
);
125 pinfo
->prepared
= false;
130 static int boe_panel_prepare(struct drm_panel
*panel
)
132 struct panel_info
*pinfo
= to_panel_info(panel
);
138 gpiod_set_value(pinfo
->pp18_gpio
, 1);
140 usleep_range(5000, 6000);
141 gpiod_set_value(pinfo
->pp33_gpio
, 1);
144 /* T2: 14ms - 15ms */
145 usleep_range(14000, 15000);
146 gpiod_set_value(pinfo
->enable_gpio
, 1);
149 usleep_range(1000, 2000);
150 gpiod_set_value(pinfo
->enable_gpio
, 0);
153 usleep_range(1000, 2000);
154 gpiod_set_value(pinfo
->enable_gpio
, 1);
157 usleep_range(5000, 6000);
160 err
= send_mipi_cmds(panel
, pinfo
->desc
->on_cmds
);
162 dev_err(panel
->dev
, "failed to send DCS Init Code: %d\n", err
);
166 err
= mipi_dsi_dcs_exit_sleep_mode(pinfo
->link
);
168 dev_err(panel
->dev
, "failed to exit sleep mode: %d\n", err
);
172 /* T6: 120ms - 121ms */
173 usleep_range(120000, 121000);
175 err
= mipi_dsi_dcs_set_display_on(pinfo
->link
);
177 dev_err(panel
->dev
, "failed to set display on: %d\n", err
);
181 /* T7: 20ms - 21ms */
182 usleep_range(20000, 21000);
184 pinfo
->prepared
= true;
189 disable_gpios(pinfo
);
193 static int boe_panel_enable(struct drm_panel
*panel
)
195 struct panel_info
*pinfo
= to_panel_info(panel
);
201 usleep_range(120000, 121000);
203 ret
= mipi_dsi_dcs_set_display_on(pinfo
->link
);
205 dev_err(panel
->dev
, "failed to set display on: %d\n", ret
);
209 pinfo
->enabled
= true;
214 static int boe_panel_get_modes(struct drm_panel
*panel
,
215 struct drm_connector
*connector
)
217 struct panel_info
*pinfo
= to_panel_info(panel
);
218 const struct drm_display_mode
*m
= pinfo
->desc
->display_mode
;
219 struct drm_display_mode
*mode
;
221 mode
= drm_mode_duplicate(connector
->dev
, m
);
223 dev_err(pinfo
->base
.dev
, "failed to add mode %ux%u@%u\n",
224 m
->hdisplay
, m
->vdisplay
, drm_mode_vrefresh(m
));
228 drm_mode_set_name(mode
);
230 drm_mode_probed_add(connector
, mode
);
232 connector
->display_info
.width_mm
= pinfo
->desc
->width_mm
;
233 connector
->display_info
.height_mm
= pinfo
->desc
->height_mm
;
234 connector
->display_info
.bpc
= pinfo
->desc
->bpc
;
239 static const struct drm_panel_funcs panel_funcs
= {
240 .disable
= boe_panel_disable
,
241 .unprepare
= boe_panel_unprepare
,
242 .prepare
= boe_panel_prepare
,
243 .enable
= boe_panel_enable
,
244 .get_modes
= boe_panel_get_modes
,
247 static const struct drm_display_mode default_display_mode
= {
250 .hsync_start
= 1200 + 80,
251 .hsync_end
= 1200 + 80 + 60,
252 .htotal
= 1200 + 80 + 60 + 24,
254 .vsync_start
= 1920 + 10,
255 .vsync_end
= 1920 + 10 + 14,
256 .vtotal
= 1920 + 10 + 14 + 4,
260 static const struct panel_cmd boe_himax8279d8p_on_cmds
[] = {
523 static const struct panel_desc boe_himax8279d8p_panel_desc
= {
524 .display_mode
= &default_display_mode
,
528 .mode_flags
= MIPI_DSI_MODE_VIDEO
| MIPI_DSI_MODE_VIDEO_SYNC_PULSE
|
529 MIPI_DSI_CLOCK_NON_CONTINUOUS
| MIPI_DSI_MODE_LPM
,
530 .format
= MIPI_DSI_FMT_RGB888
,
532 .on_cmds
= boe_himax8279d8p_on_cmds
,
537 static const struct panel_cmd boe_himax8279d10p_on_cmds
[] = {
823 static const struct panel_desc boe_himax8279d10p_panel_desc
= {
824 .display_mode
= &default_display_mode
,
828 .mode_flags
= MIPI_DSI_MODE_VIDEO
| MIPI_DSI_MODE_VIDEO_SYNC_PULSE
|
829 MIPI_DSI_CLOCK_NON_CONTINUOUS
| MIPI_DSI_MODE_LPM
,
830 .format
= MIPI_DSI_FMT_RGB888
,
832 .on_cmds
= boe_himax8279d10p_on_cmds
,
836 static const struct of_device_id panel_of_match
[] = {
838 .compatible
= "boe,himax8279d8p",
839 .data
= &boe_himax8279d8p_panel_desc
,
842 .compatible
= "boe,himax8279d10p",
843 .data
= &boe_himax8279d10p_panel_desc
,
849 MODULE_DEVICE_TABLE(of
, panel_of_match
);
851 static int panel_add(struct panel_info
*pinfo
)
853 struct device
*dev
= &pinfo
->link
->dev
;
856 pinfo
->pp18_gpio
= devm_gpiod_get(dev
, "pp18", GPIOD_OUT_HIGH
);
857 if (IS_ERR(pinfo
->pp18_gpio
)) {
858 ret
= PTR_ERR(pinfo
->pp18_gpio
);
859 if (ret
!= -EPROBE_DEFER
)
860 dev_err(dev
, "failed to get pp18 gpio: %d\n", ret
);
864 pinfo
->pp33_gpio
= devm_gpiod_get(dev
, "pp33", GPIOD_OUT_HIGH
);
865 if (IS_ERR(pinfo
->pp33_gpio
)) {
866 ret
= PTR_ERR(pinfo
->pp33_gpio
);
867 if (ret
!= -EPROBE_DEFER
)
868 dev_err(dev
, "failed to get pp33 gpio: %d\n", ret
);
872 pinfo
->enable_gpio
= devm_gpiod_get(dev
, "enable", GPIOD_OUT_HIGH
);
873 if (IS_ERR(pinfo
->enable_gpio
)) {
874 ret
= PTR_ERR(pinfo
->enable_gpio
);
875 if (ret
!= -EPROBE_DEFER
)
876 dev_err(dev
, "failed to get enable gpio: %d\n", ret
);
880 drm_panel_init(&pinfo
->base
, dev
, &panel_funcs
,
881 DRM_MODE_CONNECTOR_DSI
);
883 ret
= drm_panel_of_backlight(&pinfo
->base
);
887 drm_panel_add(&pinfo
->base
);
892 static int panel_probe(struct mipi_dsi_device
*dsi
)
894 struct panel_info
*pinfo
;
895 const struct panel_desc
*desc
;
898 pinfo
= devm_kzalloc(&dsi
->dev
, sizeof(*pinfo
), GFP_KERNEL
);
902 desc
= of_device_get_match_data(&dsi
->dev
);
903 dsi
->mode_flags
= desc
->mode_flags
;
904 dsi
->format
= desc
->format
;
905 dsi
->lanes
= desc
->lanes
;
909 mipi_dsi_set_drvdata(dsi
, pinfo
);
911 err
= panel_add(pinfo
);
915 err
= mipi_dsi_attach(dsi
);
917 drm_panel_remove(&pinfo
->base
);
922 static int panel_remove(struct mipi_dsi_device
*dsi
)
924 struct panel_info
*pinfo
= mipi_dsi_get_drvdata(dsi
);
927 err
= boe_panel_disable(&pinfo
->base
);
929 dev_err(&dsi
->dev
, "failed to disable panel: %d\n", err
);
931 err
= boe_panel_unprepare(&pinfo
->base
);
933 dev_err(&dsi
->dev
, "failed to unprepare panel: %d\n", err
);
935 err
= mipi_dsi_detach(dsi
);
937 dev_err(&dsi
->dev
, "failed to detach from DSI host: %d\n", err
);
939 drm_panel_remove(&pinfo
->base
);
944 static void panel_shutdown(struct mipi_dsi_device
*dsi
)
946 struct panel_info
*pinfo
= mipi_dsi_get_drvdata(dsi
);
948 boe_panel_disable(&pinfo
->base
);
949 boe_panel_unprepare(&pinfo
->base
);
952 static struct mipi_dsi_driver panel_driver
= {
954 .name
= "panel-boe-himax8279d",
955 .of_match_table
= panel_of_match
,
957 .probe
= panel_probe
,
958 .remove
= panel_remove
,
959 .shutdown
= panel_shutdown
,
961 module_mipi_dsi_driver(panel_driver
);
963 MODULE_AUTHOR("Jerry Han <jerry.han.hq@gmail.com>");
964 MODULE_DESCRIPTION("Boe Himax8279d driver");
965 MODULE_LICENSE("GPL v2");