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_gpio.h>
0014
0015 #include <video/omapfb_dss.h>
0016
0017 struct panel_drv_data {
0018 struct omap_dss_device dssdev;
0019 struct omap_dss_device *in;
0020
0021 int pd_gpio;
0022 int data_lines;
0023
0024 struct omap_video_timings timings;
0025 };
0026
0027 #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
0028
0029 static int tfp410_connect(struct omap_dss_device *dssdev,
0030 struct omap_dss_device *dst)
0031 {
0032 struct panel_drv_data *ddata = to_panel_data(dssdev);
0033 struct omap_dss_device *in = ddata->in;
0034 int r;
0035
0036 if (omapdss_device_is_connected(dssdev))
0037 return -EBUSY;
0038
0039 r = in->ops.dpi->connect(in, dssdev);
0040 if (r)
0041 return r;
0042
0043 dst->src = dssdev;
0044 dssdev->dst = dst;
0045
0046 return 0;
0047 }
0048
0049 static void tfp410_disconnect(struct omap_dss_device *dssdev,
0050 struct omap_dss_device *dst)
0051 {
0052 struct panel_drv_data *ddata = to_panel_data(dssdev);
0053 struct omap_dss_device *in = ddata->in;
0054
0055 WARN_ON(!omapdss_device_is_connected(dssdev));
0056 if (!omapdss_device_is_connected(dssdev))
0057 return;
0058
0059 WARN_ON(dst != dssdev->dst);
0060 if (dst != dssdev->dst)
0061 return;
0062
0063 dst->src = NULL;
0064 dssdev->dst = NULL;
0065
0066 in->ops.dpi->disconnect(in, &ddata->dssdev);
0067 }
0068
0069 static int tfp410_enable(struct omap_dss_device *dssdev)
0070 {
0071 struct panel_drv_data *ddata = to_panel_data(dssdev);
0072 struct omap_dss_device *in = ddata->in;
0073 int r;
0074
0075 if (!omapdss_device_is_connected(dssdev))
0076 return -ENODEV;
0077
0078 if (omapdss_device_is_enabled(dssdev))
0079 return 0;
0080
0081 in->ops.dpi->set_timings(in, &ddata->timings);
0082 if (ddata->data_lines)
0083 in->ops.dpi->set_data_lines(in, ddata->data_lines);
0084
0085 r = in->ops.dpi->enable(in);
0086 if (r)
0087 return r;
0088
0089 if (gpio_is_valid(ddata->pd_gpio))
0090 gpio_set_value_cansleep(ddata->pd_gpio, 1);
0091
0092 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
0093
0094 return 0;
0095 }
0096
0097 static void tfp410_disable(struct omap_dss_device *dssdev)
0098 {
0099 struct panel_drv_data *ddata = to_panel_data(dssdev);
0100 struct omap_dss_device *in = ddata->in;
0101
0102 if (!omapdss_device_is_enabled(dssdev))
0103 return;
0104
0105 if (gpio_is_valid(ddata->pd_gpio))
0106 gpio_set_value_cansleep(ddata->pd_gpio, 0);
0107
0108 in->ops.dpi->disable(in);
0109
0110 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
0111 }
0112
0113 static void tfp410_fix_timings(struct omap_video_timings *timings)
0114 {
0115 timings->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
0116 timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
0117 timings->de_level = OMAPDSS_SIG_ACTIVE_HIGH;
0118 }
0119
0120 static void tfp410_set_timings(struct omap_dss_device *dssdev,
0121 struct omap_video_timings *timings)
0122 {
0123 struct panel_drv_data *ddata = to_panel_data(dssdev);
0124 struct omap_dss_device *in = ddata->in;
0125
0126 tfp410_fix_timings(timings);
0127
0128 ddata->timings = *timings;
0129 dssdev->panel.timings = *timings;
0130
0131 in->ops.dpi->set_timings(in, timings);
0132 }
0133
0134 static void tfp410_get_timings(struct omap_dss_device *dssdev,
0135 struct omap_video_timings *timings)
0136 {
0137 struct panel_drv_data *ddata = to_panel_data(dssdev);
0138
0139 *timings = ddata->timings;
0140 }
0141
0142 static int tfp410_check_timings(struct omap_dss_device *dssdev,
0143 struct omap_video_timings *timings)
0144 {
0145 struct panel_drv_data *ddata = to_panel_data(dssdev);
0146 struct omap_dss_device *in = ddata->in;
0147
0148 tfp410_fix_timings(timings);
0149
0150 return in->ops.dpi->check_timings(in, timings);
0151 }
0152
0153 static const struct omapdss_dvi_ops tfp410_dvi_ops = {
0154 .connect = tfp410_connect,
0155 .disconnect = tfp410_disconnect,
0156
0157 .enable = tfp410_enable,
0158 .disable = tfp410_disable,
0159
0160 .check_timings = tfp410_check_timings,
0161 .set_timings = tfp410_set_timings,
0162 .get_timings = tfp410_get_timings,
0163 };
0164
0165 static int tfp410_probe_of(struct platform_device *pdev)
0166 {
0167 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
0168 struct device_node *node = pdev->dev.of_node;
0169 struct omap_dss_device *in;
0170 int gpio;
0171
0172 gpio = of_get_named_gpio(node, "powerdown-gpios", 0);
0173
0174 if (gpio_is_valid(gpio) || gpio == -ENOENT) {
0175 ddata->pd_gpio = gpio;
0176 } else {
0177 dev_err(&pdev->dev, "failed to parse PD gpio\n");
0178 return gpio;
0179 }
0180
0181 in = omapdss_of_find_source_for_first_ep(node);
0182 if (IS_ERR(in)) {
0183 dev_err(&pdev->dev, "failed to find video source\n");
0184 return PTR_ERR(in);
0185 }
0186
0187 ddata->in = in;
0188
0189 return 0;
0190 }
0191
0192 static int tfp410_probe(struct platform_device *pdev)
0193 {
0194 struct panel_drv_data *ddata;
0195 struct omap_dss_device *dssdev;
0196 int r;
0197
0198 if (!pdev->dev.of_node)
0199 return -ENODEV;
0200
0201 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
0202 if (!ddata)
0203 return -ENOMEM;
0204
0205 platform_set_drvdata(pdev, ddata);
0206
0207 r = tfp410_probe_of(pdev);
0208 if (r)
0209 return r;
0210
0211 if (gpio_is_valid(ddata->pd_gpio)) {
0212 r = devm_gpio_request_one(&pdev->dev, ddata->pd_gpio,
0213 GPIOF_OUT_INIT_LOW, "tfp410 PD");
0214 if (r) {
0215 dev_err(&pdev->dev, "Failed to request PD GPIO %d\n",
0216 ddata->pd_gpio);
0217 goto err_gpio;
0218 }
0219 }
0220
0221 dssdev = &ddata->dssdev;
0222 dssdev->ops.dvi = &tfp410_dvi_ops;
0223 dssdev->dev = &pdev->dev;
0224 dssdev->type = OMAP_DISPLAY_TYPE_DPI;
0225 dssdev->output_type = OMAP_DISPLAY_TYPE_DVI;
0226 dssdev->owner = THIS_MODULE;
0227 dssdev->phy.dpi.data_lines = ddata->data_lines;
0228 dssdev->port_num = 1;
0229
0230 r = omapdss_register_output(dssdev);
0231 if (r) {
0232 dev_err(&pdev->dev, "Failed to register output\n");
0233 goto err_reg;
0234 }
0235
0236 return 0;
0237 err_reg:
0238 err_gpio:
0239 omap_dss_put_device(ddata->in);
0240 return r;
0241 }
0242
0243 static int __exit tfp410_remove(struct platform_device *pdev)
0244 {
0245 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
0246 struct omap_dss_device *dssdev = &ddata->dssdev;
0247 struct omap_dss_device *in = ddata->in;
0248
0249 omapdss_unregister_output(&ddata->dssdev);
0250
0251 WARN_ON(omapdss_device_is_enabled(dssdev));
0252 if (omapdss_device_is_enabled(dssdev))
0253 tfp410_disable(dssdev);
0254
0255 WARN_ON(omapdss_device_is_connected(dssdev));
0256 if (omapdss_device_is_connected(dssdev))
0257 tfp410_disconnect(dssdev, dssdev->dst);
0258
0259 omap_dss_put_device(in);
0260
0261 return 0;
0262 }
0263
0264 static const struct of_device_id tfp410_of_match[] = {
0265 { .compatible = "omapdss,ti,tfp410", },
0266 {},
0267 };
0268
0269 MODULE_DEVICE_TABLE(of, tfp410_of_match);
0270
0271 static struct platform_driver tfp410_driver = {
0272 .probe = tfp410_probe,
0273 .remove = __exit_p(tfp410_remove),
0274 .driver = {
0275 .name = "tfp410",
0276 .of_match_table = tfp410_of_match,
0277 .suppress_bind_attrs = true,
0278 },
0279 };
0280
0281 module_platform_driver(tfp410_driver);
0282
0283 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
0284 MODULE_DESCRIPTION("TFP410 DPI to DVI encoder driver");
0285 MODULE_LICENSE("GPL");