summaryrefslogtreecommitdiff
path: root/drivers/video/omap2/dss/sdi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/omap2/dss/sdi.c')
-rw-r--r--drivers/video/omap2/dss/sdi.c143
1 files changed, 111 insertions, 32 deletions
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index 0bcd30272f69..856af2e89760 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -31,6 +31,8 @@
#include "dss.h"
static struct {
+ struct platform_device *pdev;
+
bool update_enabled;
struct regulator *vdds_sdi_reg;
@@ -38,7 +40,7 @@ static struct {
struct omap_video_timings timings;
int datapairs;
- struct omap_dss_output output;
+ struct omap_dss_device output;
} sdi;
struct sdi_clk_calc_ctx {
@@ -109,7 +111,7 @@ static int sdi_calc_clock_div(unsigned long pclk,
static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
{
- struct omap_overlay_manager *mgr = dssdev->output->manager;
+ struct omap_overlay_manager *mgr = sdi.output.manager;
sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
@@ -124,7 +126,7 @@ static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
{
- struct omap_dss_output *out = dssdev->output;
+ struct omap_dss_device *out = &sdi.output;
struct omap_video_timings *t = &sdi.timings;
struct dss_clock_info dss_cinfo;
struct dispc_clock_info dispc_cinfo;
@@ -136,12 +138,6 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
return -ENODEV;
}
- r = omap_dss_start_device(dssdev);
- if (r) {
- DSSERR("failed to start device\n");
- goto err_start_dev;
- }
-
r = regulator_enable(sdi.vdds_sdi_reg);
if (r)
goto err_reg_enable;
@@ -213,15 +209,13 @@ err_calc_clock_div:
err_get_dispc:
regulator_disable(sdi.vdds_sdi_reg);
err_reg_enable:
- omap_dss_stop_device(dssdev);
-err_start_dev:
return r;
}
EXPORT_SYMBOL(omapdss_sdi_display_enable);
void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
{
- struct omap_overlay_manager *mgr = dssdev->output->manager;
+ struct omap_overlay_manager *mgr = sdi.output.manager;
dss_mgr_disable(mgr);
@@ -230,8 +224,6 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
dispc_runtime_put();
regulator_disable(sdi.vdds_sdi_reg);
-
- omap_dss_stop_device(dssdev);
}
EXPORT_SYMBOL(omapdss_sdi_display_disable);
@@ -242,29 +234,51 @@ void omapdss_sdi_set_timings(struct omap_dss_device *dssdev,
}
EXPORT_SYMBOL(omapdss_sdi_set_timings);
+static void sdi_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ *timings = sdi.timings;
+}
+
+static int sdi_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct omap_overlay_manager *mgr = sdi.output.manager;
+
+ if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
+ return -EINVAL;
+
+ if (timings->pixel_clock == 0)
+ return -EINVAL;
+
+ return 0;
+}
+
void omapdss_sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs)
{
sdi.datapairs = datapairs;
}
EXPORT_SYMBOL(omapdss_sdi_set_datapairs);
-static int sdi_init_display(struct omap_dss_device *dssdev)
+static int sdi_init_regulator(void)
{
- DSSDBG("SDI init\n");
+ struct regulator *vdds_sdi;
- if (sdi.vdds_sdi_reg == NULL) {
- struct regulator *vdds_sdi;
+ if (sdi.vdds_sdi_reg)
+ return 0;
- vdds_sdi = dss_get_vdds_sdi();
+ vdds_sdi = dss_get_vdds_sdi();
+ if (IS_ERR(vdds_sdi)) {
+ vdds_sdi = devm_regulator_get(&sdi.pdev->dev, "vdds_sdi");
if (IS_ERR(vdds_sdi)) {
DSSERR("can't get VDDS_SDI regulator\n");
return PTR_ERR(vdds_sdi);
}
-
- sdi.vdds_sdi_reg = vdds_sdi;
}
+ sdi.vdds_sdi_reg = vdds_sdi;
+
return 0;
}
@@ -313,7 +327,7 @@ static int sdi_probe_pdata(struct platform_device *sdidev)
dss_copy_device_pdata(dssdev, plat_dssdev);
- r = sdi_init_display(dssdev);
+ r = sdi_init_regulator();
if (r) {
DSSERR("device %s init failed: %d\n", dssdev->name, r);
dss_put_device(dssdev);
@@ -339,39 +353,104 @@ static int sdi_probe_pdata(struct platform_device *sdidev)
return 0;
}
+static int sdi_connect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct omap_overlay_manager *mgr;
+ int r;
+
+ r = sdi_init_regulator();
+ if (r)
+ return r;
+
+ mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
+ if (!mgr)
+ return -ENODEV;
+
+ r = dss_mgr_connect(mgr, dssdev);
+ if (r)
+ return r;
+
+ r = omapdss_output_set_device(dssdev, dst);
+ if (r) {
+ DSSERR("failed to connect output to new device: %s\n",
+ dst->name);
+ dss_mgr_disconnect(mgr, dssdev);
+ return r;
+ }
+
+ return 0;
+}
+
+static void sdi_disconnect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ WARN_ON(dst != dssdev->device);
+
+ if (dst != dssdev->device)
+ return;
+
+ omapdss_output_unset_device(dssdev);
+
+ if (dssdev->manager)
+ dss_mgr_disconnect(dssdev->manager, dssdev);
+}
+
+static const struct omapdss_sdi_ops sdi_ops = {
+ .connect = sdi_connect,
+ .disconnect = sdi_disconnect,
+
+ .enable = omapdss_sdi_display_enable,
+ .disable = omapdss_sdi_display_disable,
+
+ .check_timings = sdi_check_timings,
+ .set_timings = omapdss_sdi_set_timings,
+ .get_timings = sdi_get_timings,
+
+ .set_datapairs = omapdss_sdi_set_datapairs,
+};
+
static void sdi_init_output(struct platform_device *pdev)
{
- struct omap_dss_output *out = &sdi.output;
+ struct omap_dss_device *out = &sdi.output;
- out->pdev = pdev;
+ out->dev = &pdev->dev;
out->id = OMAP_DSS_OUTPUT_SDI;
- out->type = OMAP_DISPLAY_TYPE_SDI;
+ out->output_type = OMAP_DISPLAY_TYPE_SDI;
out->name = "sdi.0";
out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
+ out->ops.sdi = &sdi_ops;
+ out->owner = THIS_MODULE;
- dss_register_output(out);
+ omapdss_register_output(out);
}
static void __exit sdi_uninit_output(struct platform_device *pdev)
{
- struct omap_dss_output *out = &sdi.output;
+ struct omap_dss_device *out = &sdi.output;
- dss_unregister_output(out);
+ omapdss_unregister_output(out);
}
static int omap_sdi_probe(struct platform_device *pdev)
{
int r;
+ sdi.pdev = pdev;
+
sdi_init_output(pdev);
- r = sdi_probe_pdata(pdev);
- if (r) {
- sdi_uninit_output(pdev);
- return r;
+ if (pdev->dev.platform_data) {
+ r = sdi_probe_pdata(pdev);
+ if (r)
+ goto err_probe;
}
return 0;
+
+err_probe:
+ sdi_uninit_output(pdev);
+ return r;
}
static int __exit omap_sdi_remove(struct platform_device *pdev)