drm/panel: Add support for Panasonic VVX10F004B0
authorThierry Reding <treding@nvidia.com>
Fri, 22 Nov 2013 18:27:11 +0000 (19:27 +0100)
committerThierry Reding <treding@nvidia.com>
Tue, 17 Dec 2013 17:09:58 +0000 (18:09 +0100)
The Panasonic VVX10F004B0 is a 10.1" WUXGA TFT LCD panel connected using
four DSI lanes.

Signed-off-by: Thierry Reding <treding@nvidia.com>
drivers/gpu/drm/panel/panel-simple.c

index 767b7be..3e611af 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
+#include <drm/drm_mipi_dsi.h>
 #include <drm/drm_panel.h>
 
 struct panel_desc {
@@ -378,6 +379,13 @@ static struct platform_driver panel_simple_platform_driver = {
        .remove = panel_simple_platform_remove,
 };
 
+struct panel_desc_dsi {
+       struct panel_desc desc;
+
+       enum mipi_dsi_pixel_format format;
+       unsigned int lanes;
+};
+
 static const struct drm_display_mode panasonic_vvx10f004b00_mode = {
        .clock = 157200,
        .hdisplay = 1920,
@@ -391,23 +399,95 @@ static const struct drm_display_mode panasonic_vvx10f004b00_mode = {
        .vrefresh = 60,
 };
 
-static const struct panel_desc panasonic_vvx10f004b00 = {
-       .modes = &panasonic_vvx10f004b00_mode,
-       .num_modes = 1,
-       .size = {
-               .width = 217,
-               .height = 136,
+static const struct panel_desc_dsi panasonic_vvx10f004b00 = {
+       .desc = {
+               .modes = &panasonic_vvx10f004b00_mode,
+               .num_modes = 1,
+               .size = {
+                       .width = 217,
+                       .height = 136,
+               },
        },
+       .format = MIPI_DSI_FMT_RGB888,
+       .lanes = 4,
+};
+
+static const struct of_device_id dsi_of_match[] = {
+       {
+               .compatible = "panasonic,vvx10f004b00",
+               .data = &panasonic_vvx10f004b00
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(of, dsi_of_match);
+
+static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)
+{
+       const struct panel_desc_dsi *desc;
+       const struct of_device_id *id;
+       int err;
+
+       id = of_match_node(dsi_of_match, dsi->dev.of_node);
+       if (!id)
+               return -ENODEV;
+
+       desc = id->data;
+
+       err = panel_simple_probe(&dsi->dev, &desc->desc);
+       if (err < 0)
+               return err;
+
+       dsi->format = desc->format;
+       dsi->lanes = desc->lanes;
+
+       return mipi_dsi_attach(dsi);
+}
+
+static int panel_simple_dsi_remove(struct mipi_dsi_device *dsi)
+{
+       int err;
+
+       err = mipi_dsi_detach(dsi);
+       if (err < 0)
+               dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
+
+       return panel_simple_remove(&dsi->dev);
+}
+
+static struct mipi_dsi_driver panel_simple_dsi_driver = {
+       .driver = {
+               .name = "panel-simple-dsi",
+               .owner = THIS_MODULE,
+               .of_match_table = dsi_of_match,
+       },
+       .probe = panel_simple_dsi_probe,
+       .remove = panel_simple_dsi_remove,
 };
 
 static int __init panel_simple_init(void)
 {
-       return platform_driver_register(&panel_simple_platform_driver);
+       int err;
+
+       err = platform_driver_register(&panel_simple_platform_driver);
+       if (err < 0)
+               return err;
+
+       if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) {
+               err = mipi_dsi_driver_register(&panel_simple_dsi_driver);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
 }
 module_init(panel_simple_init);
 
 static void __exit panel_simple_exit(void)
 {
+       if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
+               mipi_dsi_driver_unregister(&panel_simple_dsi_driver);
+
        platform_driver_unregister(&panel_simple_platform_driver);
 }
 module_exit(panel_simple_exit);