0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/delay.h>
0009 #include <linux/gpio/consumer.h>
0010 #include <linux/regulator/consumer.h>
0011 #include <linux/module.h>
0012 #include <linux/of.h>
0013
0014 #include <video/mipi_display.h>
0015
0016 #include <drm/drm_mipi_dsi.h>
0017 #include <drm/drm_modes.h>
0018 #include <drm/drm_panel.h>
0019
0020 static const char * const regulator_names[] = {
0021 "vddio",
0022 "vddpos",
0023 "vddneg",
0024 };
0025
0026 static const unsigned long regulator_enable_loads[] = {
0027 62000,
0028 100000,
0029 100000
0030 };
0031
0032 struct ebbg_ft8719 {
0033 struct drm_panel panel;
0034 struct mipi_dsi_device *dsi;
0035
0036 struct regulator_bulk_data supplies[ARRAY_SIZE(regulator_names)];
0037
0038 struct gpio_desc *reset_gpio;
0039 };
0040
0041 static inline
0042 struct ebbg_ft8719 *to_ebbg_ft8719(struct drm_panel *panel)
0043 {
0044 return container_of(panel, struct ebbg_ft8719, panel);
0045 }
0046
0047 static void ebbg_ft8719_reset(struct ebbg_ft8719 *ctx)
0048 {
0049 gpiod_set_value_cansleep(ctx->reset_gpio, 0);
0050 usleep_range(4000, 5000);
0051 gpiod_set_value_cansleep(ctx->reset_gpio, 1);
0052 usleep_range(1000, 2000);
0053 gpiod_set_value_cansleep(ctx->reset_gpio, 0);
0054 usleep_range(15000, 16000);
0055 }
0056
0057 static int ebbg_ft8719_on(struct ebbg_ft8719 *ctx)
0058 {
0059 struct mipi_dsi_device *dsi = ctx->dsi;
0060 struct device *dev = &dsi->dev;
0061 int ret;
0062
0063 dsi->mode_flags |= MIPI_DSI_MODE_LPM;
0064
0065 ret = mipi_dsi_dcs_set_display_brightness(dsi, 0x00ff);
0066 if (ret < 0) {
0067 dev_err(dev, "Failed to set display brightness: %d\n", ret);
0068 return ret;
0069 }
0070
0071 mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24);
0072 mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
0073
0074 ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
0075 if (ret < 0) {
0076 dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
0077 return ret;
0078 }
0079 msleep(90);
0080
0081 ret = mipi_dsi_dcs_set_display_on(dsi);
0082 if (ret < 0) {
0083 dev_err(dev, "Failed to set display on: %d\n", ret);
0084 return ret;
0085 }
0086
0087 return 0;
0088 }
0089
0090 static int ebbg_ft8719_off(struct ebbg_ft8719 *ctx)
0091 {
0092 struct mipi_dsi_device *dsi = ctx->dsi;
0093 struct device *dev = &dsi->dev;
0094 int ret;
0095
0096 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
0097
0098 ret = mipi_dsi_dcs_set_display_off(dsi);
0099 if (ret < 0) {
0100 dev_err(dev, "Failed to set display off: %d\n", ret);
0101 return ret;
0102 }
0103 usleep_range(10000, 11000);
0104
0105 ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
0106 if (ret < 0) {
0107 dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
0108 return ret;
0109 }
0110 msleep(90);
0111
0112 return 0;
0113 }
0114
0115 static int ebbg_ft8719_prepare(struct drm_panel *panel)
0116 {
0117 struct ebbg_ft8719 *ctx = to_ebbg_ft8719(panel);
0118 struct device *dev = &ctx->dsi->dev;
0119 int ret;
0120
0121 ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
0122 if (ret < 0)
0123 return ret;
0124
0125 ebbg_ft8719_reset(ctx);
0126
0127 ret = ebbg_ft8719_on(ctx);
0128 if (ret < 0) {
0129 dev_err(dev, "Failed to initialize panel: %d\n", ret);
0130 gpiod_set_value_cansleep(ctx->reset_gpio, 1);
0131 return ret;
0132 }
0133
0134 return 0;
0135 }
0136
0137 static int ebbg_ft8719_unprepare(struct drm_panel *panel)
0138 {
0139 struct ebbg_ft8719 *ctx = to_ebbg_ft8719(panel);
0140 struct device *dev = &ctx->dsi->dev;
0141 int ret;
0142
0143 ret = ebbg_ft8719_off(ctx);
0144 if (ret < 0)
0145 dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
0146
0147 gpiod_set_value_cansleep(ctx->reset_gpio, 1);
0148
0149 ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
0150 if (ret)
0151 dev_err(panel->dev, "Failed to disable regulators: %d\n", ret);
0152
0153 return 0;
0154 }
0155
0156 static const struct drm_display_mode ebbg_ft8719_mode = {
0157 .clock = (1080 + 28 + 4 + 16) * (2246 + 120 + 4 + 12) * 60 / 1000,
0158 .hdisplay = 1080,
0159 .hsync_start = 1080 + 28,
0160 .hsync_end = 1080 + 28 + 4,
0161 .htotal = 1080 + 28 + 4 + 16,
0162 .vdisplay = 2246,
0163 .vsync_start = 2246 + 120,
0164 .vsync_end = 2246 + 120 + 4,
0165 .vtotal = 2246 + 120 + 4 + 12,
0166 .width_mm = 68,
0167 .height_mm = 141,
0168 };
0169
0170 static int ebbg_ft8719_get_modes(struct drm_panel *panel,
0171 struct drm_connector *connector)
0172 {
0173 struct drm_display_mode *mode;
0174
0175 mode = drm_mode_duplicate(connector->dev, &ebbg_ft8719_mode);
0176 if (!mode)
0177 return -ENOMEM;
0178
0179 drm_mode_set_name(mode);
0180
0181 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
0182 connector->display_info.width_mm = mode->width_mm;
0183 connector->display_info.height_mm = mode->height_mm;
0184 drm_mode_probed_add(connector, mode);
0185
0186 return 1;
0187 }
0188
0189 static const struct drm_panel_funcs ebbg_ft8719_panel_funcs = {
0190 .prepare = ebbg_ft8719_prepare,
0191 .unprepare = ebbg_ft8719_unprepare,
0192 .get_modes = ebbg_ft8719_get_modes,
0193 };
0194
0195 static int ebbg_ft8719_probe(struct mipi_dsi_device *dsi)
0196 {
0197 struct device *dev = &dsi->dev;
0198 struct ebbg_ft8719 *ctx;
0199 int i, ret;
0200
0201 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
0202 if (!ctx)
0203 return -ENOMEM;
0204
0205 for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++)
0206 ctx->supplies[i].supply = regulator_names[i];
0207
0208 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
0209 ctx->supplies);
0210 if (ret < 0)
0211 return dev_err_probe(dev, ret, "Failed to get regulators\n");
0212
0213 for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) {
0214 ret = regulator_set_load(ctx->supplies[i].consumer,
0215 regulator_enable_loads[i]);
0216 if (ret)
0217 return dev_err_probe(dev, ret,
0218 "Failed to set regulator load\n");
0219 }
0220
0221 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
0222 if (IS_ERR(ctx->reset_gpio))
0223 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
0224 "Failed to get reset-gpios\n");
0225
0226 ctx->dsi = dsi;
0227 mipi_dsi_set_drvdata(dsi, ctx);
0228
0229 dsi->lanes = 4;
0230 dsi->format = MIPI_DSI_FMT_RGB888;
0231 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
0232 MIPI_DSI_CLOCK_NON_CONTINUOUS;
0233
0234 drm_panel_init(&ctx->panel, dev, &ebbg_ft8719_panel_funcs,
0235 DRM_MODE_CONNECTOR_DSI);
0236
0237 ret = drm_panel_of_backlight(&ctx->panel);
0238 if (ret)
0239 return dev_err_probe(dev, ret, "Failed to get backlight\n");
0240
0241 drm_panel_add(&ctx->panel);
0242
0243 ret = mipi_dsi_attach(dsi);
0244 if (ret < 0) {
0245 dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
0246 drm_panel_remove(&ctx->panel);
0247 return ret;
0248 }
0249
0250 return 0;
0251 }
0252
0253 static int ebbg_ft8719_remove(struct mipi_dsi_device *dsi)
0254 {
0255 struct ebbg_ft8719 *ctx = mipi_dsi_get_drvdata(dsi);
0256 int ret;
0257
0258 ret = mipi_dsi_detach(dsi);
0259 if (ret < 0)
0260 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
0261
0262 drm_panel_remove(&ctx->panel);
0263
0264 return 0;
0265 }
0266
0267 static const struct of_device_id ebbg_ft8719_of_match[] = {
0268 { .compatible = "ebbg,ft8719" },
0269 { }
0270 };
0271 MODULE_DEVICE_TABLE(of, ebbg_ft8719_of_match);
0272
0273 static struct mipi_dsi_driver ebbg_ft8719_driver = {
0274 .probe = ebbg_ft8719_probe,
0275 .remove = ebbg_ft8719_remove,
0276 .driver = {
0277 .name = "panel-ebbg-ft8719",
0278 .of_match_table = ebbg_ft8719_of_match,
0279 },
0280 };
0281 module_mipi_dsi_driver(ebbg_ft8719_driver);
0282
0283 MODULE_AUTHOR("Joel Selvaraj <jo@jsfamily.in>");
0284 MODULE_DESCRIPTION("DRM driver for EBBG FT8719 video dsi panel");
0285 MODULE_LICENSE("GPL v2");