0001
0002
0003
0004
0005
0006
0007 #include <linux/module.h>
0008 #include <linux/of.h>
0009 #include <linux/regulator/consumer.h>
0010
0011 #include <drm/drm_crtc.h>
0012 #include <drm/drm_device.h>
0013 #include <drm/drm_mipi_dsi.h>
0014 #include <drm/drm_panel.h>
0015
0016 #include <video/mipi_display.h>
0017
0018 struct osd101t2587_panel {
0019 struct drm_panel base;
0020 struct mipi_dsi_device *dsi;
0021
0022 struct regulator *supply;
0023
0024 bool prepared;
0025 bool enabled;
0026
0027 const struct drm_display_mode *default_mode;
0028 };
0029
0030 static inline struct osd101t2587_panel *ti_osd_panel(struct drm_panel *panel)
0031 {
0032 return container_of(panel, struct osd101t2587_panel, base);
0033 }
0034
0035 static int osd101t2587_panel_disable(struct drm_panel *panel)
0036 {
0037 struct osd101t2587_panel *osd101t2587 = ti_osd_panel(panel);
0038 int ret;
0039
0040 if (!osd101t2587->enabled)
0041 return 0;
0042
0043 ret = mipi_dsi_shutdown_peripheral(osd101t2587->dsi);
0044
0045 osd101t2587->enabled = false;
0046
0047 return ret;
0048 }
0049
0050 static int osd101t2587_panel_unprepare(struct drm_panel *panel)
0051 {
0052 struct osd101t2587_panel *osd101t2587 = ti_osd_panel(panel);
0053
0054 if (!osd101t2587->prepared)
0055 return 0;
0056
0057 regulator_disable(osd101t2587->supply);
0058 osd101t2587->prepared = false;
0059
0060 return 0;
0061 }
0062
0063 static int osd101t2587_panel_prepare(struct drm_panel *panel)
0064 {
0065 struct osd101t2587_panel *osd101t2587 = ti_osd_panel(panel);
0066 int ret;
0067
0068 if (osd101t2587->prepared)
0069 return 0;
0070
0071 ret = regulator_enable(osd101t2587->supply);
0072 if (!ret)
0073 osd101t2587->prepared = true;
0074
0075 return ret;
0076 }
0077
0078 static int osd101t2587_panel_enable(struct drm_panel *panel)
0079 {
0080 struct osd101t2587_panel *osd101t2587 = ti_osd_panel(panel);
0081 int ret;
0082
0083 if (osd101t2587->enabled)
0084 return 0;
0085
0086 ret = mipi_dsi_turn_on_peripheral(osd101t2587->dsi);
0087 if (ret)
0088 return ret;
0089
0090 osd101t2587->enabled = true;
0091
0092 return ret;
0093 }
0094
0095 static const struct drm_display_mode default_mode_osd101t2587 = {
0096 .clock = 164400,
0097 .hdisplay = 1920,
0098 .hsync_start = 1920 + 152,
0099 .hsync_end = 1920 + 152 + 52,
0100 .htotal = 1920 + 152 + 52 + 20,
0101 .vdisplay = 1200,
0102 .vsync_start = 1200 + 24,
0103 .vsync_end = 1200 + 24 + 6,
0104 .vtotal = 1200 + 24 + 6 + 48,
0105 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
0106 };
0107
0108 static int osd101t2587_panel_get_modes(struct drm_panel *panel,
0109 struct drm_connector *connector)
0110 {
0111 struct osd101t2587_panel *osd101t2587 = ti_osd_panel(panel);
0112 struct drm_display_mode *mode;
0113
0114 mode = drm_mode_duplicate(connector->dev, osd101t2587->default_mode);
0115 if (!mode) {
0116 dev_err(panel->dev, "failed to add mode %ux%ux@%u\n",
0117 osd101t2587->default_mode->hdisplay,
0118 osd101t2587->default_mode->vdisplay,
0119 drm_mode_vrefresh(osd101t2587->default_mode));
0120 return -ENOMEM;
0121 }
0122
0123 drm_mode_set_name(mode);
0124
0125 drm_mode_probed_add(connector, mode);
0126
0127 connector->display_info.width_mm = 217;
0128 connector->display_info.height_mm = 136;
0129
0130 return 1;
0131 }
0132
0133 static const struct drm_panel_funcs osd101t2587_panel_funcs = {
0134 .disable = osd101t2587_panel_disable,
0135 .unprepare = osd101t2587_panel_unprepare,
0136 .prepare = osd101t2587_panel_prepare,
0137 .enable = osd101t2587_panel_enable,
0138 .get_modes = osd101t2587_panel_get_modes,
0139 };
0140
0141 static const struct of_device_id osd101t2587_of_match[] = {
0142 {
0143 .compatible = "osddisplays,osd101t2587-53ts",
0144 .data = &default_mode_osd101t2587,
0145 }, {
0146
0147 }
0148 };
0149 MODULE_DEVICE_TABLE(of, osd101t2587_of_match);
0150
0151 static int osd101t2587_panel_add(struct osd101t2587_panel *osd101t2587)
0152 {
0153 struct device *dev = &osd101t2587->dsi->dev;
0154 int ret;
0155
0156 osd101t2587->supply = devm_regulator_get(dev, "power");
0157 if (IS_ERR(osd101t2587->supply))
0158 return PTR_ERR(osd101t2587->supply);
0159
0160 drm_panel_init(&osd101t2587->base, &osd101t2587->dsi->dev,
0161 &osd101t2587_panel_funcs, DRM_MODE_CONNECTOR_DSI);
0162
0163 ret = drm_panel_of_backlight(&osd101t2587->base);
0164 if (ret)
0165 return ret;
0166
0167 drm_panel_add(&osd101t2587->base);
0168
0169 return 0;
0170 }
0171
0172 static int osd101t2587_panel_probe(struct mipi_dsi_device *dsi)
0173 {
0174 struct osd101t2587_panel *osd101t2587;
0175 const struct of_device_id *id;
0176 int ret;
0177
0178 id = of_match_node(osd101t2587_of_match, dsi->dev.of_node);
0179 if (!id)
0180 return -ENODEV;
0181
0182 dsi->lanes = 4;
0183 dsi->format = MIPI_DSI_FMT_RGB888;
0184 dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
0185 MIPI_DSI_MODE_VIDEO_BURST |
0186 MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
0187 MIPI_DSI_MODE_NO_EOT_PACKET;
0188
0189 osd101t2587 = devm_kzalloc(&dsi->dev, sizeof(*osd101t2587), GFP_KERNEL);
0190 if (!osd101t2587)
0191 return -ENOMEM;
0192
0193 mipi_dsi_set_drvdata(dsi, osd101t2587);
0194
0195 osd101t2587->dsi = dsi;
0196 osd101t2587->default_mode = id->data;
0197
0198 ret = osd101t2587_panel_add(osd101t2587);
0199 if (ret < 0)
0200 return ret;
0201
0202 ret = mipi_dsi_attach(dsi);
0203 if (ret)
0204 drm_panel_remove(&osd101t2587->base);
0205
0206 return ret;
0207 }
0208
0209 static int osd101t2587_panel_remove(struct mipi_dsi_device *dsi)
0210 {
0211 struct osd101t2587_panel *osd101t2587 = mipi_dsi_get_drvdata(dsi);
0212 int ret;
0213
0214 ret = drm_panel_disable(&osd101t2587->base);
0215 if (ret < 0)
0216 dev_warn(&dsi->dev, "failed to disable panel: %d\n", ret);
0217
0218 drm_panel_unprepare(&osd101t2587->base);
0219 drm_panel_remove(&osd101t2587->base);
0220
0221 ret = mipi_dsi_detach(dsi);
0222 if (ret < 0)
0223 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
0224
0225 return ret;
0226 }
0227
0228 static void osd101t2587_panel_shutdown(struct mipi_dsi_device *dsi)
0229 {
0230 struct osd101t2587_panel *osd101t2587 = mipi_dsi_get_drvdata(dsi);
0231
0232 drm_panel_disable(&osd101t2587->base);
0233 drm_panel_unprepare(&osd101t2587->base);
0234 }
0235
0236 static struct mipi_dsi_driver osd101t2587_panel_driver = {
0237 .driver = {
0238 .name = "panel-osd-osd101t2587-53ts",
0239 .of_match_table = osd101t2587_of_match,
0240 },
0241 .probe = osd101t2587_panel_probe,
0242 .remove = osd101t2587_panel_remove,
0243 .shutdown = osd101t2587_panel_shutdown,
0244 };
0245 module_mipi_dsi_driver(osd101t2587_panel_driver);
0246
0247 MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
0248 MODULE_DESCRIPTION("OSD101T2587-53TS DSI panel");
0249 MODULE_LICENSE("GPL v2");