1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2019, Huaqin Telecom Technology Co., Ltd
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);
964 MODULE_DESCRIPTION("Boe Himax8279d driver");
965 MODULE_LICENSE("GPL v2");