1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <linux/array_size.h> 4 #include <linux/delay.h> 5 #include <linux/err.h> 6 #include <linux/gpio/consumer.h> 7 #include <linux/mod_devicetable.h> 8 #include <linux/module.h> 9 #include <linux/property.h> 10 #include <linux/regulator/consumer.h> 11 12 #include <video/mipi_display.h> 13 14 #include <drm/drm_mipi_dsi.h> 15 #include <drm/drm_modes.h> 16 #include <drm/drm_panel.h> 17 18 struct hv101hd1 { 19 struct drm_panel panel; 20 struct mipi_dsi_device *dsi; 21 struct regulator_bulk_data *supplies; 22 }; 23 24 static const struct regulator_bulk_data hv101hd1_supplies[] = { 25 { .supply = "vdd" }, 26 { .supply = "vio" }, 27 }; 28 29 static inline struct hv101hd1 *to_hv101hd1(struct drm_panel *panel) 30 { 31 return container_of(panel, struct hv101hd1, panel); 32 } 33 34 static int hv101hd1_prepare(struct drm_panel *panel) 35 { 36 struct hv101hd1 *hv = to_hv101hd1(panel); 37 struct mipi_dsi_multi_context ctx = { .dsi = hv->dsi }; 38 struct device *dev = &hv->dsi->dev; 39 int ret; 40 41 ret = regulator_bulk_enable(ARRAY_SIZE(hv101hd1_supplies), hv->supplies); 42 if (ret) { 43 dev_err(dev, "error enabling regulators (%d)\n", ret); 44 return ret; 45 } 46 47 mipi_dsi_dcs_exit_sleep_mode_multi(&ctx); 48 mipi_dsi_msleep(&ctx, 20); 49 50 mipi_dsi_dcs_set_display_on_multi(&ctx); 51 mipi_dsi_msleep(&ctx, 20); 52 53 return 0; 54 } 55 56 static int hv101hd1_disable(struct drm_panel *panel) 57 { 58 struct hv101hd1 *hv = to_hv101hd1(panel); 59 struct mipi_dsi_multi_context ctx = { .dsi = hv->dsi }; 60 61 mipi_dsi_dcs_set_display_off_multi(&ctx); 62 mipi_dsi_msleep(&ctx, 120); 63 mipi_dsi_dcs_enter_sleep_mode_multi(&ctx); 64 mipi_dsi_msleep(&ctx, 20); 65 66 return 0; 67 } 68 69 static int hv101hd1_unprepare(struct drm_panel *panel) 70 { 71 struct hv101hd1 *hv = to_hv101hd1(panel); 72 73 return regulator_bulk_disable(ARRAY_SIZE(hv101hd1_supplies), 74 hv->supplies); 75 } 76 77 static const struct drm_display_mode hv101hd1_mode = { 78 .clock = (1366 + 74 + 36 + 24) * (768 + 21 + 7 + 4) * 60 / 1000, 79 .hdisplay = 1366, 80 .hsync_start = 1366 + 74, 81 .hsync_end = 1366 + 74 + 36, 82 .htotal = 1366 + 74 + 36 + 24, 83 .vdisplay = 768, 84 .vsync_start = 768 + 21, 85 .vsync_end = 768 + 21 + 7, 86 .vtotal = 768 + 21 + 7 + 4, 87 .width_mm = 140, 88 .height_mm = 220, 89 }; 90 91 static int hv101hd1_get_modes(struct drm_panel *panel, struct drm_connector *connector) 92 { 93 struct drm_display_mode *mode; 94 95 mode = drm_mode_duplicate(connector->dev, &hv101hd1_mode); 96 if (!mode) 97 return -ENOMEM; 98 99 drm_mode_set_name(mode); 100 101 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 102 103 connector->display_info.width_mm = mode->width_mm; 104 connector->display_info.height_mm = mode->height_mm; 105 106 drm_mode_probed_add(connector, mode); 107 108 return 1; 109 } 110 111 static const struct drm_panel_funcs hv101hd1_panel_funcs = { 112 .prepare = hv101hd1_prepare, 113 .disable = hv101hd1_disable, 114 .unprepare = hv101hd1_unprepare, 115 .get_modes = hv101hd1_get_modes, 116 }; 117 118 static int hv101hd1_probe(struct mipi_dsi_device *dsi) 119 { 120 struct device *dev = &dsi->dev; 121 struct hv101hd1 *hv; 122 int ret; 123 124 hv = devm_drm_panel_alloc(dev, struct hv101hd1, panel, 125 &hv101hd1_panel_funcs, 126 DRM_MODE_CONNECTOR_DSI); 127 if (IS_ERR(hv)) 128 return PTR_ERR(hv); 129 130 ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(hv101hd1_supplies), 131 hv101hd1_supplies, &hv->supplies); 132 if (ret) 133 return dev_err_probe(dev, ret, "failed to get regulators\n"); 134 135 hv->dsi = dsi; 136 mipi_dsi_set_drvdata(dsi, hv); 137 138 dsi->lanes = 2; 139 dsi->format = MIPI_DSI_FMT_RGB888; 140 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM; 141 142 ret = drm_panel_of_backlight(&hv->panel); 143 if (ret) 144 return dev_err_probe(dev, ret, "Failed to get backlight\n"); 145 146 drm_panel_add(&hv->panel); 147 148 ret = mipi_dsi_attach(dsi); 149 if (ret) { 150 drm_panel_remove(&hv->panel); 151 return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); 152 } 153 154 return 0; 155 } 156 157 static void hv101hd1_remove(struct mipi_dsi_device *dsi) 158 { 159 struct hv101hd1 *hv = mipi_dsi_get_drvdata(dsi); 160 int ret; 161 162 ret = mipi_dsi_detach(dsi); 163 if (ret < 0) 164 dev_err(&dsi->dev, 165 "Failed to detach from DSI host: %d\n", ret); 166 167 drm_panel_remove(&hv->panel); 168 } 169 170 static const struct of_device_id hv101hd1_of_match[] = { 171 { .compatible = "hydis,hv101hd1" }, 172 { /* sentinel */ } 173 }; 174 MODULE_DEVICE_TABLE(of, hv101hd1_of_match); 175 176 static struct mipi_dsi_driver hv101hd1_driver = { 177 .driver = { 178 .name = "panel-hv101hd1", 179 .of_match_table = hv101hd1_of_match, 180 }, 181 .probe = hv101hd1_probe, 182 .remove = hv101hd1_remove, 183 }; 184 module_mipi_dsi_driver(hv101hd1_driver); 185 186 MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>"); 187 MODULE_DESCRIPTION("DRM driver for Hydis HV101HD1 panel"); 188 MODULE_LICENSE("GPL"); 189