1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <linux/delay.h> 4 #include <linux/device.h> 5 #include <linux/err.h> 6 #include <linux/errno.h> 7 #include <linux/kernel.h> 8 #include <linux/module.h> 9 #include <linux/of.h> 10 11 #include <linux/gpio/consumer.h> 12 #include <linux/regulator/consumer.h> 13 14 #include <drm/drm_mipi_dsi.h> 15 #include <drm/drm_modes.h> 16 #include <drm/drm_of.h> 17 #include <drm/drm_panel.h> 18 #include <drm/drm_probe_helper.h> 19 20 #include <video/mipi_display.h> 21 22 struct ili9488_desc { 23 const struct drm_display_mode *display_mode; 24 unsigned long mode_flags; 25 enum mipi_dsi_pixel_format format; 26 unsigned int lanes; 27 unsigned int bpc; 28 void (*init_sequence)(struct mipi_dsi_multi_context *ctx); 29 }; 30 31 struct ili9488 { 32 struct drm_panel panel; 33 struct mipi_dsi_device *dsi; 34 struct gpio_desc *reset; 35 struct regulator_bulk_data supplies[2]; 36 const struct ili9488_desc *desc; 37 enum drm_panel_orientation orientation; 38 }; 39 40 static const char * const regulator_names[] = { 41 "vci", 42 "iovcc", 43 }; 44 45 static void e35gh_i_mw800cb_init(struct mipi_dsi_multi_context *ctx) 46 { 47 /* Gamma control 1,2 */ 48 mipi_dsi_dcs_write_seq_multi(ctx, 0xE0, 0x00, 0x10, 0x14, 0x01, 0x0E, 0x04, 0x33, 49 0x56, 0x48, 0x03, 0x0C, 0x0B, 0x2B, 0x34, 0x0F); 50 mipi_dsi_dcs_write_seq_multi(ctx, 0xE1, 0x00, 0x12, 0x18, 0x05, 0x12, 0x06, 0x40, 51 0x34, 0x57, 0x06, 0x10, 0x0C, 0x3B, 0x3F, 0x0F); 52 /* Power control 1,2 */ 53 mipi_dsi_dcs_write_seq_multi(ctx, 0xC0, 0x0F, 0x0C); 54 mipi_dsi_dcs_write_seq_multi(ctx, 0xC1, 0x41); 55 /* VCOM Control */ 56 mipi_dsi_dcs_write_seq_multi(ctx, 0xC5, 0x00, 0x25, 0x80); 57 mipi_dsi_dcs_write_seq_multi(ctx, 0x36, 0x48); 58 /* Interface pixel format 18bpp */ 59 mipi_dsi_dcs_write_seq_multi(ctx, 0x3A, 0x66); 60 mipi_dsi_dcs_write_seq_multi(ctx, 0xB0, 0x00); 61 mipi_dsi_dcs_write_seq_multi(ctx, 0xB1, 0xA0); 62 mipi_dsi_dcs_write_seq_multi(ctx, 0xB4, 0x02); 63 mipi_dsi_dcs_write_seq_multi(ctx, 0xB6, 0x02, 0x02, 0x3B); 64 mipi_dsi_dcs_write_seq_multi(ctx, 0xE9, 0x00); 65 mipi_dsi_dcs_write_seq_multi(ctx, 0xF7, 0xA9, 0x51, 0x2C, 0x82); 66 mipi_dsi_dcs_write_seq_multi(ctx, 0x21); 67 } 68 69 static const struct drm_display_mode e35gh_i_mw800cb_display_mode = { 70 .clock = 14400, 71 72 .hdisplay = 320, 73 .hsync_start = 320 + 60, 74 .hsync_end = 320 + 60 + 20, 75 .htotal = 320 + 60 + 20 + 42, 76 77 .vdisplay = 480, 78 .vsync_start = 480 + 20, 79 .vsync_end = 480 + 20 + 10, 80 .vtotal = 480 + 20 + 10 + 33, 81 82 .width_mm = 48, 83 .height_mm = 73, 84 85 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, 86 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, 87 }; 88 89 static inline struct ili9488 *panel_to_ili9488(struct drm_panel *panel) 90 { 91 return container_of(panel, struct ili9488, panel); 92 } 93 94 static int ili9488_power_on(struct ili9488 *ili) 95 { 96 struct mipi_dsi_device *dsi = ili->dsi; 97 int ret; 98 99 ret = regulator_bulk_enable(ARRAY_SIZE(ili->supplies), ili->supplies); 100 if (ret < 0) { 101 dev_err(&dsi->dev, "regulator bulk enable failed: %d\n", ret); 102 return ret; 103 } 104 105 gpiod_set_value_cansleep(ili->reset, 0); 106 usleep_range(1000, 5000); 107 gpiod_set_value_cansleep(ili->reset, 1); 108 usleep_range(1000, 5000); 109 gpiod_set_value_cansleep(ili->reset, 0); 110 usleep_range(5000, 10000); 111 112 return 0; 113 } 114 115 static int ili9488_power_off(struct ili9488 *ili) 116 { 117 struct mipi_dsi_device *dsi = ili->dsi; 118 int ret; 119 120 gpiod_set_value_cansleep(ili->reset, 1); 121 122 ret = regulator_bulk_disable(ARRAY_SIZE(ili->supplies), ili->supplies); 123 if (ret) 124 dev_err(&dsi->dev, "regulator bulk disable failed: %d\n", ret); 125 126 return ret; 127 } 128 129 static int ili9488_activate(struct ili9488 *ili) 130 { 131 struct mipi_dsi_multi_context ctx = { .dsi = ili->dsi }; 132 133 if (ili->desc->init_sequence) 134 ili->desc->init_sequence(&ctx); 135 136 mipi_dsi_dcs_exit_sleep_mode_multi(&ctx); 137 mipi_dsi_msleep(&ctx, 120); 138 mipi_dsi_dcs_set_display_on_multi(&ctx); 139 140 return ctx.accum_err; 141 } 142 143 static int ili9488_prepare(struct drm_panel *panel) 144 { 145 struct ili9488 *ili = panel_to_ili9488(panel); 146 int ret; 147 148 ret = ili9488_power_on(ili); 149 if (ret) 150 return ret; 151 152 ret = ili9488_activate(ili); 153 if (ret) { 154 ili9488_power_off(ili); 155 return ret; 156 } 157 158 return 0; 159 } 160 161 static int ili9488_deactivate(struct ili9488 *ili) 162 { 163 struct mipi_dsi_multi_context ctx = { .dsi = ili->dsi }; 164 165 mipi_dsi_dcs_set_display_off_multi(&ctx); 166 mipi_dsi_dcs_enter_sleep_mode_multi(&ctx); 167 mipi_dsi_msleep(&ctx, 120); 168 169 return ctx.accum_err; 170 } 171 172 static int ili9488_unprepare(struct drm_panel *panel) 173 { 174 struct ili9488 *ili = panel_to_ili9488(panel); 175 struct mipi_dsi_device *dsi = ili->dsi; 176 int ret; 177 178 ili9488_deactivate(ili); 179 ret = ili9488_power_off(ili); 180 if (ret < 0) 181 dev_err(&dsi->dev, "power off failed: %d\n", ret); 182 183 return ret; 184 } 185 186 static int ili9488_get_modes(struct drm_panel *panel, struct drm_connector *connector) 187 { 188 struct ili9488 *ili = panel_to_ili9488(panel); 189 const struct drm_display_mode *mode = ili->desc->display_mode; 190 191 connector->display_info.bpc = ili->desc->bpc; 192 193 return drm_connector_helper_get_modes_fixed(connector, mode); 194 } 195 196 static enum drm_panel_orientation ili9488_get_orientation(struct drm_panel *panel) 197 { 198 struct ili9488 *ili = panel_to_ili9488(panel); 199 200 return ili->orientation; 201 } 202 203 static const struct drm_panel_funcs ili9488_funcs = { 204 .prepare = ili9488_prepare, 205 .unprepare = ili9488_unprepare, 206 .get_modes = ili9488_get_modes, 207 .get_orientation = ili9488_get_orientation, 208 }; 209 210 static int ili9488_dsi_probe(struct mipi_dsi_device *dsi) 211 { 212 struct device *dev = &dsi->dev; 213 struct ili9488 *ili; 214 int i, ret; 215 216 ili = devm_drm_panel_alloc(dev, struct ili9488, panel, &ili9488_funcs, 217 DRM_MODE_CONNECTOR_DSI); 218 if (IS_ERR(ili)) 219 return PTR_ERR(ili); 220 221 ili->desc = device_get_match_data(dev); 222 ili->dsi = dsi; 223 224 dsi->mode_flags = ili->desc->mode_flags; 225 dsi->format = ili->desc->format; 226 dsi->lanes = ili->desc->lanes; 227 228 ili->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); 229 if (IS_ERR(ili->reset)) 230 return dev_err_probe(dev, PTR_ERR(ili->reset), 231 "failed to get reset-gpios\n"); 232 233 for (i = 0; i < ARRAY_SIZE(ili->supplies); i++) 234 ili->supplies[i].supply = regulator_names[i]; 235 236 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ili->supplies), 237 ili->supplies); 238 if (ret < 0) 239 return dev_err_probe(dev, ret, "failed to get regulators\n"); 240 241 ret = drm_of_get_panel_orientation(dev->of_node, &ili->orientation); 242 if (ret) 243 return dev_err_probe(dev, ret, "failed to get orientation\n"); 244 245 ret = drm_panel_of_backlight(&ili->panel); 246 if (ret) 247 return dev_err_probe(dev, ret, "failed to get backlight\n"); 248 249 ili->panel.prepare_prev_first = true; 250 251 ret = devm_drm_panel_add(dev, &ili->panel); 252 if (ret) 253 return ret; 254 255 ret = devm_mipi_dsi_attach(dev, dsi); 256 if (ret < 0) 257 return dev_err_probe(dev, ret, "failed to attach to DSI host\n"); 258 259 return 0; 260 } 261 262 static const struct ili9488_desc e35gh_i_mw800cb_desc = { 263 .init_sequence = e35gh_i_mw800cb_init, 264 .display_mode = &e35gh_i_mw800cb_display_mode, 265 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | 266 MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS, 267 .format = MIPI_DSI_FMT_RGB666_PACKED, 268 .lanes = 1, 269 .bpc = 6, 270 }; 271 272 static const struct of_device_id ili9488_of_match[] = { 273 { .compatible = "focuslcds,e35gh-i-mw800cb", .data = &e35gh_i_mw800cb_desc }, 274 { } 275 }; 276 277 MODULE_DEVICE_TABLE(of, ili9488_of_match); 278 279 static struct mipi_dsi_driver ili9488_dsi_driver = { 280 .probe = ili9488_dsi_probe, 281 .driver = { 282 .name = "ili9488-dsi", 283 .of_match_table = ili9488_of_match, 284 }, 285 }; 286 module_mipi_dsi_driver(ili9488_dsi_driver); 287 288 MODULE_AUTHOR("Igor Reznichenko <igor@reznichenko.net>"); 289 MODULE_DESCRIPTION("Ilitek ILI9488 Controller Driver"); 290 MODULE_LICENSE("GPL"); 291