0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/delay.h>
0011 #include <linux/device.h>
0012 #include <linux/err.h>
0013 #include <linux/errno.h>
0014 #include <linux/fb.h>
0015 #include <linux/kernel.h>
0016 #include <linux/media-bus-format.h>
0017 #include <linux/module.h>
0018
0019 #include <linux/gpio/consumer.h>
0020 #include <linux/regulator/consumer.h>
0021
0022 #include <drm/drm_connector.h>
0023 #include <drm/drm_mipi_dsi.h>
0024 #include <drm/drm_modes.h>
0025 #include <drm/drm_panel.h>
0026
0027 struct rb070d30_panel {
0028 struct drm_panel panel;
0029 struct mipi_dsi_device *dsi;
0030 struct regulator *supply;
0031
0032 struct {
0033 struct gpio_desc *power;
0034 struct gpio_desc *reset;
0035 struct gpio_desc *updn;
0036 struct gpio_desc *shlr;
0037 } gpios;
0038 };
0039
0040 static inline struct rb070d30_panel *panel_to_rb070d30_panel(struct drm_panel *panel)
0041 {
0042 return container_of(panel, struct rb070d30_panel, panel);
0043 }
0044
0045 static int rb070d30_panel_prepare(struct drm_panel *panel)
0046 {
0047 struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);
0048 int ret;
0049
0050 ret = regulator_enable(ctx->supply);
0051 if (ret < 0) {
0052 dev_err(&ctx->dsi->dev, "Failed to enable supply: %d\n", ret);
0053 return ret;
0054 }
0055
0056 msleep(20);
0057 gpiod_set_value(ctx->gpios.power, 1);
0058 msleep(20);
0059 gpiod_set_value(ctx->gpios.reset, 1);
0060 msleep(20);
0061 return 0;
0062 }
0063
0064 static int rb070d30_panel_unprepare(struct drm_panel *panel)
0065 {
0066 struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);
0067
0068 gpiod_set_value(ctx->gpios.reset, 0);
0069 gpiod_set_value(ctx->gpios.power, 0);
0070 regulator_disable(ctx->supply);
0071
0072 return 0;
0073 }
0074
0075 static int rb070d30_panel_enable(struct drm_panel *panel)
0076 {
0077 struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);
0078
0079 return mipi_dsi_dcs_exit_sleep_mode(ctx->dsi);
0080 }
0081
0082 static int rb070d30_panel_disable(struct drm_panel *panel)
0083 {
0084 struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);
0085
0086 return mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
0087 }
0088
0089
0090 static const struct drm_display_mode default_mode = {
0091 .clock = 51206,
0092 .hdisplay = 1024,
0093 .hsync_start = 1024 + 160,
0094 .hsync_end = 1024 + 160 + 80,
0095 .htotal = 1024 + 160 + 80 + 80,
0096 .vdisplay = 600,
0097 .vsync_start = 600 + 12,
0098 .vsync_end = 600 + 12 + 10,
0099 .vtotal = 600 + 12 + 10 + 13,
0100
0101 .width_mm = 154,
0102 .height_mm = 85,
0103 };
0104
0105 static int rb070d30_panel_get_modes(struct drm_panel *panel,
0106 struct drm_connector *connector)
0107 {
0108 struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);
0109 struct drm_display_mode *mode;
0110 static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
0111
0112 mode = drm_mode_duplicate(connector->dev, &default_mode);
0113 if (!mode) {
0114 dev_err(&ctx->dsi->dev, "Failed to add mode " DRM_MODE_FMT "\n",
0115 DRM_MODE_ARG(&default_mode));
0116 return -EINVAL;
0117 }
0118
0119 drm_mode_set_name(mode);
0120
0121 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
0122 drm_mode_probed_add(connector, mode);
0123
0124 connector->display_info.bpc = 8;
0125 connector->display_info.width_mm = mode->width_mm;
0126 connector->display_info.height_mm = mode->height_mm;
0127 drm_display_info_set_bus_formats(&connector->display_info,
0128 &bus_format, 1);
0129
0130 return 1;
0131 }
0132
0133 static const struct drm_panel_funcs rb070d30_panel_funcs = {
0134 .get_modes = rb070d30_panel_get_modes,
0135 .prepare = rb070d30_panel_prepare,
0136 .enable = rb070d30_panel_enable,
0137 .disable = rb070d30_panel_disable,
0138 .unprepare = rb070d30_panel_unprepare,
0139 };
0140
0141 static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi)
0142 {
0143 struct rb070d30_panel *ctx;
0144 int ret;
0145
0146 ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
0147 if (!ctx)
0148 return -ENOMEM;
0149
0150 ctx->supply = devm_regulator_get(&dsi->dev, "vcc-lcd");
0151 if (IS_ERR(ctx->supply))
0152 return PTR_ERR(ctx->supply);
0153
0154 mipi_dsi_set_drvdata(dsi, ctx);
0155 ctx->dsi = dsi;
0156
0157 drm_panel_init(&ctx->panel, &dsi->dev, &rb070d30_panel_funcs,
0158 DRM_MODE_CONNECTOR_DSI);
0159
0160 ctx->gpios.reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
0161 if (IS_ERR(ctx->gpios.reset)) {
0162 dev_err(&dsi->dev, "Couldn't get our reset GPIO\n");
0163 return PTR_ERR(ctx->gpios.reset);
0164 }
0165
0166 ctx->gpios.power = devm_gpiod_get(&dsi->dev, "power", GPIOD_OUT_LOW);
0167 if (IS_ERR(ctx->gpios.power)) {
0168 dev_err(&dsi->dev, "Couldn't get our power GPIO\n");
0169 return PTR_ERR(ctx->gpios.power);
0170 }
0171
0172
0173
0174
0175
0176 ctx->gpios.updn = devm_gpiod_get(&dsi->dev, "updn", GPIOD_OUT_LOW);
0177 if (IS_ERR(ctx->gpios.updn)) {
0178 dev_err(&dsi->dev, "Couldn't get our updn GPIO\n");
0179 return PTR_ERR(ctx->gpios.updn);
0180 }
0181
0182
0183
0184
0185
0186 ctx->gpios.shlr = devm_gpiod_get(&dsi->dev, "shlr", GPIOD_OUT_LOW);
0187 if (IS_ERR(ctx->gpios.shlr)) {
0188 dev_err(&dsi->dev, "Couldn't get our shlr GPIO\n");
0189 return PTR_ERR(ctx->gpios.shlr);
0190 }
0191
0192 ret = drm_panel_of_backlight(&ctx->panel);
0193 if (ret)
0194 return ret;
0195
0196 drm_panel_add(&ctx->panel);
0197
0198 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM;
0199 dsi->format = MIPI_DSI_FMT_RGB888;
0200 dsi->lanes = 4;
0201
0202 ret = mipi_dsi_attach(dsi);
0203 if (ret < 0) {
0204 drm_panel_remove(&ctx->panel);
0205 return ret;
0206 }
0207
0208 return 0;
0209 }
0210
0211 static int rb070d30_panel_dsi_remove(struct mipi_dsi_device *dsi)
0212 {
0213 struct rb070d30_panel *ctx = mipi_dsi_get_drvdata(dsi);
0214
0215 mipi_dsi_detach(dsi);
0216 drm_panel_remove(&ctx->panel);
0217
0218 return 0;
0219 }
0220
0221 static const struct of_device_id rb070d30_panel_of_match[] = {
0222 { .compatible = "ronbo,rb070d30" },
0223 { },
0224 };
0225 MODULE_DEVICE_TABLE(of, rb070d30_panel_of_match);
0226
0227 static struct mipi_dsi_driver rb070d30_panel_driver = {
0228 .probe = rb070d30_panel_dsi_probe,
0229 .remove = rb070d30_panel_dsi_remove,
0230 .driver = {
0231 .name = "panel-ronbo-rb070d30",
0232 .of_match_table = rb070d30_panel_of_match,
0233 },
0234 };
0235 module_mipi_dsi_driver(rb070d30_panel_driver);
0236
0237 MODULE_AUTHOR("Boris Brezillon <boris.brezillon@bootlin.com>");
0238 MODULE_AUTHOR("Konstantin Sudakov <k.sudakov@integrasources.com>");
0239 MODULE_DESCRIPTION("Ronbo RB070D30 Panel Driver");
0240 MODULE_LICENSE("GPL");