0001
0002
0003
0004
0005
0006
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
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");