Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Generic MIPI DPI Panel Driver
0004  *
0005  * Copyright (C) 2013 Texas Instruments
0006  * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
0007  */
0008 
0009 #include <linux/gpio.h>
0010 #include <linux/module.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/slab.h>
0013 #include <linux/of.h>
0014 #include <linux/of_gpio.h>
0015 
0016 #include <video/omapfb_dss.h>
0017 #include <video/omap-panel-data.h>
0018 #include <video/of_display_timing.h>
0019 
0020 struct panel_drv_data {
0021     struct omap_dss_device dssdev;
0022     struct omap_dss_device *in;
0023 
0024     int data_lines;
0025 
0026     struct omap_video_timings videomode;
0027 
0028     /* used for non-DT boot, to be removed */
0029     int backlight_gpio;
0030 
0031     struct gpio_desc *enable_gpio;
0032 };
0033 
0034 #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
0035 
0036 static int panel_dpi_connect(struct omap_dss_device *dssdev)
0037 {
0038     struct panel_drv_data *ddata = to_panel_data(dssdev);
0039     struct omap_dss_device *in = ddata->in;
0040 
0041     if (omapdss_device_is_connected(dssdev))
0042         return 0;
0043 
0044     return in->ops.dpi->connect(in, dssdev);
0045 }
0046 
0047 static void panel_dpi_disconnect(struct omap_dss_device *dssdev)
0048 {
0049     struct panel_drv_data *ddata = to_panel_data(dssdev);
0050     struct omap_dss_device *in = ddata->in;
0051 
0052     if (!omapdss_device_is_connected(dssdev))
0053         return;
0054 
0055     in->ops.dpi->disconnect(in, dssdev);
0056 }
0057 
0058 static int panel_dpi_enable(struct omap_dss_device *dssdev)
0059 {
0060     struct panel_drv_data *ddata = to_panel_data(dssdev);
0061     struct omap_dss_device *in = ddata->in;
0062     int r;
0063 
0064     if (!omapdss_device_is_connected(dssdev))
0065         return -ENODEV;
0066 
0067     if (omapdss_device_is_enabled(dssdev))
0068         return 0;
0069 
0070     if (ddata->data_lines)
0071         in->ops.dpi->set_data_lines(in, ddata->data_lines);
0072     in->ops.dpi->set_timings(in, &ddata->videomode);
0073 
0074     r = in->ops.dpi->enable(in);
0075     if (r)
0076         return r;
0077 
0078     gpiod_set_value_cansleep(ddata->enable_gpio, 1);
0079 
0080     if (gpio_is_valid(ddata->backlight_gpio))
0081         gpio_set_value_cansleep(ddata->backlight_gpio, 1);
0082 
0083     dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
0084 
0085     return 0;
0086 }
0087 
0088 static void panel_dpi_disable(struct omap_dss_device *dssdev)
0089 {
0090     struct panel_drv_data *ddata = to_panel_data(dssdev);
0091     struct omap_dss_device *in = ddata->in;
0092 
0093     if (!omapdss_device_is_enabled(dssdev))
0094         return;
0095 
0096     if (gpio_is_valid(ddata->backlight_gpio))
0097         gpio_set_value_cansleep(ddata->backlight_gpio, 0);
0098 
0099     gpiod_set_value_cansleep(ddata->enable_gpio, 0);
0100 
0101     in->ops.dpi->disable(in);
0102 
0103     dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
0104 }
0105 
0106 static void panel_dpi_set_timings(struct omap_dss_device *dssdev,
0107         struct omap_video_timings *timings)
0108 {
0109     struct panel_drv_data *ddata = to_panel_data(dssdev);
0110     struct omap_dss_device *in = ddata->in;
0111 
0112     ddata->videomode = *timings;
0113     dssdev->panel.timings = *timings;
0114 
0115     in->ops.dpi->set_timings(in, timings);
0116 }
0117 
0118 static void panel_dpi_get_timings(struct omap_dss_device *dssdev,
0119         struct omap_video_timings *timings)
0120 {
0121     struct panel_drv_data *ddata = to_panel_data(dssdev);
0122 
0123     *timings = ddata->videomode;
0124 }
0125 
0126 static int panel_dpi_check_timings(struct omap_dss_device *dssdev,
0127         struct omap_video_timings *timings)
0128 {
0129     struct panel_drv_data *ddata = to_panel_data(dssdev);
0130     struct omap_dss_device *in = ddata->in;
0131 
0132     return in->ops.dpi->check_timings(in, timings);
0133 }
0134 
0135 static struct omap_dss_driver panel_dpi_ops = {
0136     .connect    = panel_dpi_connect,
0137     .disconnect = panel_dpi_disconnect,
0138 
0139     .enable     = panel_dpi_enable,
0140     .disable    = panel_dpi_disable,
0141 
0142     .set_timings    = panel_dpi_set_timings,
0143     .get_timings    = panel_dpi_get_timings,
0144     .check_timings  = panel_dpi_check_timings,
0145 
0146     .get_resolution = omapdss_default_get_resolution,
0147 };
0148 
0149 static int panel_dpi_probe_pdata(struct platform_device *pdev)
0150 {
0151     const struct panel_dpi_platform_data *pdata;
0152     struct panel_drv_data *ddata = platform_get_drvdata(pdev);
0153     struct omap_dss_device *dssdev, *in;
0154     struct videomode vm;
0155     int r;
0156 
0157     pdata = dev_get_platdata(&pdev->dev);
0158 
0159     in = omap_dss_find_output(pdata->source);
0160     if (in == NULL) {
0161         dev_err(&pdev->dev, "failed to find video source '%s'\n",
0162                 pdata->source);
0163         return -EPROBE_DEFER;
0164     }
0165 
0166     ddata->in = in;
0167 
0168     ddata->data_lines = pdata->data_lines;
0169 
0170     videomode_from_timing(pdata->display_timing, &vm);
0171     videomode_to_omap_video_timings(&vm, &ddata->videomode);
0172 
0173     dssdev = &ddata->dssdev;
0174     dssdev->name = pdata->name;
0175 
0176     r = devm_gpio_request_one(&pdev->dev, pdata->enable_gpio,
0177                     GPIOF_OUT_INIT_LOW, "panel enable");
0178     if (r)
0179         goto err_gpio;
0180 
0181     ddata->enable_gpio = gpio_to_desc(pdata->enable_gpio);
0182 
0183     ddata->backlight_gpio = pdata->backlight_gpio;
0184 
0185     return 0;
0186 
0187 err_gpio:
0188     omap_dss_put_device(ddata->in);
0189     return r;
0190 }
0191 
0192 static int panel_dpi_probe_of(struct platform_device *pdev)
0193 {
0194     struct panel_drv_data *ddata = platform_get_drvdata(pdev);
0195     struct device_node *node = pdev->dev.of_node;
0196     struct omap_dss_device *in;
0197     int r;
0198     struct display_timing timing;
0199     struct videomode vm;
0200     struct gpio_desc *gpio;
0201 
0202     gpio = devm_gpiod_get_optional(&pdev->dev, "enable", GPIOD_OUT_LOW);
0203     if (IS_ERR(gpio))
0204         return PTR_ERR(gpio);
0205 
0206     ddata->enable_gpio = gpio;
0207 
0208     ddata->backlight_gpio = -ENOENT;
0209 
0210     r = of_get_display_timing(node, "panel-timing", &timing);
0211     if (r) {
0212         dev_err(&pdev->dev, "failed to get video timing\n");
0213         return r;
0214     }
0215 
0216     videomode_from_timing(&timing, &vm);
0217     videomode_to_omap_video_timings(&vm, &ddata->videomode);
0218 
0219     in = omapdss_of_find_source_for_first_ep(node);
0220     if (IS_ERR(in)) {
0221         dev_err(&pdev->dev, "failed to find video source\n");
0222         return PTR_ERR(in);
0223     }
0224 
0225     ddata->in = in;
0226 
0227     return 0;
0228 }
0229 
0230 static int panel_dpi_probe(struct platform_device *pdev)
0231 {
0232     struct panel_drv_data *ddata;
0233     struct omap_dss_device *dssdev;
0234     int r;
0235 
0236     ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
0237     if (ddata == NULL)
0238         return -ENOMEM;
0239 
0240     platform_set_drvdata(pdev, ddata);
0241 
0242     if (dev_get_platdata(&pdev->dev)) {
0243         r = panel_dpi_probe_pdata(pdev);
0244         if (r)
0245             return r;
0246     } else if (pdev->dev.of_node) {
0247         r = panel_dpi_probe_of(pdev);
0248         if (r)
0249             return r;
0250     } else {
0251         return -ENODEV;
0252     }
0253 
0254     if (gpio_is_valid(ddata->backlight_gpio)) {
0255         r = devm_gpio_request_one(&pdev->dev, ddata->backlight_gpio,
0256                 GPIOF_OUT_INIT_LOW, "panel backlight");
0257         if (r)
0258             goto err_gpio;
0259     }
0260 
0261     dssdev = &ddata->dssdev;
0262     dssdev->dev = &pdev->dev;
0263     dssdev->driver = &panel_dpi_ops;
0264     dssdev->type = OMAP_DISPLAY_TYPE_DPI;
0265     dssdev->owner = THIS_MODULE;
0266     dssdev->panel.timings = ddata->videomode;
0267     dssdev->phy.dpi.data_lines = ddata->data_lines;
0268 
0269     r = omapdss_register_display(dssdev);
0270     if (r) {
0271         dev_err(&pdev->dev, "Failed to register panel\n");
0272         goto err_reg;
0273     }
0274 
0275     return 0;
0276 
0277 err_reg:
0278 err_gpio:
0279     omap_dss_put_device(ddata->in);
0280     return r;
0281 }
0282 
0283 static int __exit panel_dpi_remove(struct platform_device *pdev)
0284 {
0285     struct panel_drv_data *ddata = platform_get_drvdata(pdev);
0286     struct omap_dss_device *dssdev = &ddata->dssdev;
0287     struct omap_dss_device *in = ddata->in;
0288 
0289     omapdss_unregister_display(dssdev);
0290 
0291     panel_dpi_disable(dssdev);
0292     panel_dpi_disconnect(dssdev);
0293 
0294     omap_dss_put_device(in);
0295 
0296     return 0;
0297 }
0298 
0299 static const struct of_device_id panel_dpi_of_match[] = {
0300     { .compatible = "omapdss,panel-dpi", },
0301     {},
0302 };
0303 
0304 MODULE_DEVICE_TABLE(of, panel_dpi_of_match);
0305 
0306 static struct platform_driver panel_dpi_driver = {
0307     .probe = panel_dpi_probe,
0308     .remove = __exit_p(panel_dpi_remove),
0309     .driver = {
0310         .name = "panel-dpi",
0311         .of_match_table = panel_dpi_of_match,
0312         .suppress_bind_attrs = true,
0313     },
0314 };
0315 
0316 module_platform_driver(panel_dpi_driver);
0317 
0318 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
0319 MODULE_DESCRIPTION("Generic MIPI DPI Panel Driver");
0320 MODULE_LICENSE("GPL");