0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <drm/drm_mipi_dsi.h>
0013 #include <drm/drm_modes.h>
0014 #include <drm/drm_panel.h>
0015
0016 #include <video/display_timing.h>
0017 #include <video/mipi_display.h>
0018
0019 #include <linux/delay.h>
0020 #include <linux/gpio/consumer.h>
0021 #include <linux/media-bus-format.h>
0022 #include <linux/module.h>
0023 #include <linux/of.h>
0024 #include <linux/regulator/consumer.h>
0025
0026
0027 #define XPP055C272_CMD_ALL_PIXEL_OFF 0x22
0028 #define XPP055C272_CMD_ALL_PIXEL_ON 0x23
0029 #define XPP055C272_CMD_SETDISP 0xb2
0030 #define XPP055C272_CMD_SETRGBIF 0xb3
0031 #define XPP055C272_CMD_SETCYC 0xb4
0032 #define XPP055C272_CMD_SETBGP 0xb5
0033 #define XPP055C272_CMD_SETVCOM 0xb6
0034 #define XPP055C272_CMD_SETOTP 0xb7
0035 #define XPP055C272_CMD_SETPOWER_EXT 0xb8
0036 #define XPP055C272_CMD_SETEXTC 0xb9
0037 #define XPP055C272_CMD_SETMIPI 0xbA
0038 #define XPP055C272_CMD_SETVDC 0xbc
0039 #define XPP055C272_CMD_SETPCR 0xbf
0040 #define XPP055C272_CMD_SETSCR 0xc0
0041 #define XPP055C272_CMD_SETPOWER 0xc1
0042 #define XPP055C272_CMD_SETECO 0xc6
0043 #define XPP055C272_CMD_SETPANEL 0xcc
0044 #define XPP055C272_CMD_SETGAMMA 0xe0
0045 #define XPP055C272_CMD_SETEQ 0xe3
0046 #define XPP055C272_CMD_SETGIP1 0xe9
0047 #define XPP055C272_CMD_SETGIP2 0xea
0048
0049 struct xpp055c272 {
0050 struct device *dev;
0051 struct drm_panel panel;
0052 struct gpio_desc *reset_gpio;
0053 struct regulator *vci;
0054 struct regulator *iovcc;
0055 bool prepared;
0056 };
0057
0058 static inline struct xpp055c272 *panel_to_xpp055c272(struct drm_panel *panel)
0059 {
0060 return container_of(panel, struct xpp055c272, panel);
0061 }
0062
0063 #define dsi_generic_write_seq(dsi, cmd, seq...) do { \
0064 static const u8 b[] = { cmd, seq }; \
0065 int ret; \
0066 ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b)); \
0067 if (ret < 0) \
0068 return ret; \
0069 } while (0)
0070
0071 static int xpp055c272_init_sequence(struct xpp055c272 *ctx)
0072 {
0073 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
0074 struct device *dev = ctx->dev;
0075
0076
0077
0078
0079
0080 dsi_generic_write_seq(dsi, XPP055C272_CMD_SETEXTC, 0xf1, 0x12, 0x83);
0081 dsi_generic_write_seq(dsi, XPP055C272_CMD_SETMIPI,
0082 0x33, 0x81, 0x05, 0xf9, 0x0e, 0x0e, 0x00, 0x00,
0083 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25,
0084 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02, 0x4f, 0x01,
0085 0x00, 0x00, 0x37);
0086 dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPOWER_EXT, 0x25);
0087 dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPCR, 0x02, 0x11, 0x00);
0088 dsi_generic_write_seq(dsi, XPP055C272_CMD_SETRGBIF,
0089 0x0c, 0x10, 0x0a, 0x50, 0x03, 0xff, 0x00, 0x00,
0090 0x00, 0x00);
0091 dsi_generic_write_seq(dsi, XPP055C272_CMD_SETSCR,
0092 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
0093 0x00);
0094 dsi_generic_write_seq(dsi, XPP055C272_CMD_SETVDC, 0x46);
0095 dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPANEL, 0x0b);
0096 dsi_generic_write_seq(dsi, XPP055C272_CMD_SETCYC, 0x80);
0097 dsi_generic_write_seq(dsi, XPP055C272_CMD_SETDISP, 0xc8, 0x12, 0x30);
0098 dsi_generic_write_seq(dsi, XPP055C272_CMD_SETEQ,
0099 0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
0100 0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
0101 dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPOWER,
0102 0x53, 0x00, 0x1e, 0x1e, 0x77, 0xe1, 0xcc, 0xdd,
0103 0x67, 0x77, 0x33, 0x33);
0104 dsi_generic_write_seq(dsi, XPP055C272_CMD_SETECO, 0x00, 0x00, 0xff,
0105 0xff, 0x01, 0xff);
0106 dsi_generic_write_seq(dsi, XPP055C272_CMD_SETBGP, 0x09, 0x09);
0107 msleep(20);
0108
0109 dsi_generic_write_seq(dsi, XPP055C272_CMD_SETVCOM, 0x87, 0x95);
0110 dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGIP1,
0111 0xc2, 0x10, 0x05, 0x05, 0x10, 0x05, 0xa0, 0x12,
0112 0x31, 0x23, 0x3f, 0x81, 0x0a, 0xa0, 0x37, 0x18,
0113 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,
0114 0x01, 0x00, 0x00, 0x00, 0x48, 0xf8, 0x86, 0x42,
0115 0x08, 0x88, 0x88, 0x80, 0x88, 0x88, 0x88, 0x58,
0116 0xf8, 0x87, 0x53, 0x18, 0x88, 0x88, 0x81, 0x88,
0117 0x88, 0x88, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
0119 dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGIP2,
0120 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
0121 0x00, 0x00, 0x00, 0x00, 0x1f, 0x88, 0x81, 0x35,
0122 0x78, 0x88, 0x88, 0x85, 0x88, 0x88, 0x88, 0x0f,
0123 0x88, 0x80, 0x24, 0x68, 0x88, 0x88, 0x84, 0x88,
0124 0x88, 0x88, 0x23, 0x10, 0x00, 0x00, 0x1c, 0x00,
0125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x05,
0127 0xa0, 0x00, 0x00, 0x00, 0x00);
0128 dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGAMMA,
0129 0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38, 0x36,
0130 0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13, 0x11,
0131 0x18, 0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38,
0132 0x36, 0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13,
0133 0x11, 0x18);
0134
0135 msleep(60);
0136
0137 dev_dbg(dev, "Panel init sequence done\n");
0138 return 0;
0139 }
0140
0141 static int xpp055c272_unprepare(struct drm_panel *panel)
0142 {
0143 struct xpp055c272 *ctx = panel_to_xpp055c272(panel);
0144 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
0145 int ret;
0146
0147 if (!ctx->prepared)
0148 return 0;
0149
0150 ret = mipi_dsi_dcs_set_display_off(dsi);
0151 if (ret < 0)
0152 dev_err(ctx->dev, "failed to set display off: %d\n", ret);
0153
0154 mipi_dsi_dcs_enter_sleep_mode(dsi);
0155 if (ret < 0) {
0156 dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret);
0157 return ret;
0158 }
0159
0160 regulator_disable(ctx->iovcc);
0161 regulator_disable(ctx->vci);
0162
0163 ctx->prepared = false;
0164
0165 return 0;
0166 }
0167
0168 static int xpp055c272_prepare(struct drm_panel *panel)
0169 {
0170 struct xpp055c272 *ctx = panel_to_xpp055c272(panel);
0171 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
0172 int ret;
0173
0174 if (ctx->prepared)
0175 return 0;
0176
0177 dev_dbg(ctx->dev, "Resetting the panel\n");
0178 ret = regulator_enable(ctx->vci);
0179 if (ret < 0) {
0180 dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret);
0181 return ret;
0182 }
0183 ret = regulator_enable(ctx->iovcc);
0184 if (ret < 0) {
0185 dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
0186 goto disable_vci;
0187 }
0188
0189 gpiod_set_value_cansleep(ctx->reset_gpio, 1);
0190
0191 usleep_range(10, 20);
0192 gpiod_set_value_cansleep(ctx->reset_gpio, 0);
0193
0194
0195 msleep(20);
0196
0197 ret = xpp055c272_init_sequence(ctx);
0198 if (ret < 0) {
0199 dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
0200 goto disable_iovcc;
0201 }
0202
0203 ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
0204 if (ret < 0) {
0205 dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
0206 goto disable_iovcc;
0207 }
0208
0209
0210 msleep(120);
0211
0212 ret = mipi_dsi_dcs_set_display_on(dsi);
0213 if (ret < 0) {
0214 dev_err(ctx->dev, "Failed to set display on: %d\n", ret);
0215 goto disable_iovcc;
0216 }
0217
0218 msleep(50);
0219
0220 ctx->prepared = true;
0221
0222 return 0;
0223
0224 disable_iovcc:
0225 regulator_disable(ctx->iovcc);
0226 disable_vci:
0227 regulator_disable(ctx->vci);
0228 return ret;
0229 }
0230
0231 static const struct drm_display_mode default_mode = {
0232 .hdisplay = 720,
0233 .hsync_start = 720 + 40,
0234 .hsync_end = 720 + 40 + 10,
0235 .htotal = 720 + 40 + 10 + 40,
0236 .vdisplay = 1280,
0237 .vsync_start = 1280 + 22,
0238 .vsync_end = 1280 + 22 + 4,
0239 .vtotal = 1280 + 22 + 4 + 11,
0240 .clock = 64000,
0241 .width_mm = 68,
0242 .height_mm = 121,
0243 };
0244
0245 static int xpp055c272_get_modes(struct drm_panel *panel,
0246 struct drm_connector *connector)
0247 {
0248 struct xpp055c272 *ctx = panel_to_xpp055c272(panel);
0249 struct drm_display_mode *mode;
0250
0251 mode = drm_mode_duplicate(connector->dev, &default_mode);
0252 if (!mode) {
0253 dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
0254 default_mode.hdisplay, default_mode.vdisplay,
0255 drm_mode_vrefresh(&default_mode));
0256 return -ENOMEM;
0257 }
0258
0259 drm_mode_set_name(mode);
0260
0261 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
0262 connector->display_info.width_mm = mode->width_mm;
0263 connector->display_info.height_mm = mode->height_mm;
0264 drm_mode_probed_add(connector, mode);
0265
0266 return 1;
0267 }
0268
0269 static const struct drm_panel_funcs xpp055c272_funcs = {
0270 .unprepare = xpp055c272_unprepare,
0271 .prepare = xpp055c272_prepare,
0272 .get_modes = xpp055c272_get_modes,
0273 };
0274
0275 static int xpp055c272_probe(struct mipi_dsi_device *dsi)
0276 {
0277 struct device *dev = &dsi->dev;
0278 struct xpp055c272 *ctx;
0279 int ret;
0280
0281 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
0282 if (!ctx)
0283 return -ENOMEM;
0284
0285 ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
0286 if (IS_ERR(ctx->reset_gpio))
0287 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
0288 "cannot get reset gpio\n");
0289
0290 ctx->vci = devm_regulator_get(dev, "vci");
0291 if (IS_ERR(ctx->vci))
0292 return dev_err_probe(dev, PTR_ERR(ctx->vci),
0293 "Failed to request vci regulator\n");
0294
0295 ctx->iovcc = devm_regulator_get(dev, "iovcc");
0296 if (IS_ERR(ctx->iovcc))
0297 return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
0298 "Failed to request iovcc regulator\n");
0299
0300 mipi_dsi_set_drvdata(dsi, ctx);
0301
0302 ctx->dev = dev;
0303
0304 dsi->lanes = 4;
0305 dsi->format = MIPI_DSI_FMT_RGB888;
0306 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
0307 MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET;
0308
0309 drm_panel_init(&ctx->panel, &dsi->dev, &xpp055c272_funcs,
0310 DRM_MODE_CONNECTOR_DSI);
0311
0312 ret = drm_panel_of_backlight(&ctx->panel);
0313 if (ret)
0314 return ret;
0315
0316 drm_panel_add(&ctx->panel);
0317
0318 ret = mipi_dsi_attach(dsi);
0319 if (ret < 0) {
0320 dev_err(dev, "mipi_dsi_attach failed: %d\n", ret);
0321 drm_panel_remove(&ctx->panel);
0322 return ret;
0323 }
0324
0325 return 0;
0326 }
0327
0328 static void xpp055c272_shutdown(struct mipi_dsi_device *dsi)
0329 {
0330 struct xpp055c272 *ctx = mipi_dsi_get_drvdata(dsi);
0331 int ret;
0332
0333 ret = drm_panel_unprepare(&ctx->panel);
0334 if (ret < 0)
0335 dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
0336
0337 ret = drm_panel_disable(&ctx->panel);
0338 if (ret < 0)
0339 dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
0340 }
0341
0342 static int xpp055c272_remove(struct mipi_dsi_device *dsi)
0343 {
0344 struct xpp055c272 *ctx = mipi_dsi_get_drvdata(dsi);
0345 int ret;
0346
0347 xpp055c272_shutdown(dsi);
0348
0349 ret = mipi_dsi_detach(dsi);
0350 if (ret < 0)
0351 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
0352
0353 drm_panel_remove(&ctx->panel);
0354
0355 return 0;
0356 }
0357
0358 static const struct of_device_id xpp055c272_of_match[] = {
0359 { .compatible = "xinpeng,xpp055c272" },
0360 { }
0361 };
0362 MODULE_DEVICE_TABLE(of, xpp055c272_of_match);
0363
0364 static struct mipi_dsi_driver xpp055c272_driver = {
0365 .driver = {
0366 .name = "panel-xinpeng-xpp055c272",
0367 .of_match_table = xpp055c272_of_match,
0368 },
0369 .probe = xpp055c272_probe,
0370 .remove = xpp055c272_remove,
0371 .shutdown = xpp055c272_shutdown,
0372 };
0373 module_mipi_dsi_driver(xpp055c272_driver);
0374
0375 MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");
0376 MODULE_DESCRIPTION("DRM driver for Xinpeng xpp055c272 MIPI DSI panel");
0377 MODULE_LICENSE("GPL v2");