diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-07 10:47:51 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-07 10:47:51 -0700 |
commit | 0af9fb63915cf5ebb47b5c9ff16526b47545baf5 (patch) | |
tree | 2e05c80a4b3ef074e7535c0222e37150cdec09e7 /drivers/video | |
parent | e5744abb2fa3629aa5a94e21ca1eae32ff2fe00b (diff) | |
parent | 0f5d9d2e7d234acb26bc98dd820cc8dd178774d6 (diff) |
Merge tag 'fbdev-omap-3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux
Pull OMAP fbdev changes from Tomi Valkeinen:
"This is based on the already pulled fbdev-main changes, and this also
merges .dts branch from Tony Lindgren (which has also been pulled), so
that I was able to add the display related .dts changes.
This contains OMAP related fbdev changes for 3.15. The bulk of the
patches are for adding Device Tree support for OMAP Display Subsystem:
- SoCs: OMAP2/3/4
- Boards: OMAP4 Panda, OMAP4 SDP, OMAP3 Beagle, OMAP3 Beagle-xM,
OMAP3 IGEP0020, OMAP3 N900
- Devices: TFP410 Encoder, tpd12s015 HDMI companion chip, Sony
acx565akm panel, MIPI DSI Command mode panel and HDMI, DVI and
Analog TV connectors"
* tag 'fbdev-omap-3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux: (45 commits)
OMAPDSS: HDMI: fix interlace output
OMAPDSS: add missing __init for dss_init_ports
ARM: OMAP2+: remove pdata quirks for displays
OMAPDSS: remove DT hacks for regulators
Doc/DT: Add DT binding documentation for tpd12s015 encoder
Doc/DT: Add DT binding documentation for TFP410 encoder
Doc/DT: Add DT binding documentation for Sony acx565akm panel
Doc/DT: Add DT binding documentation for MIPI DSI CM Panel
Doc/DT: Add DT binding documentation for HDMI Connector
Doc/DT: Add DT binding documentation for DVI Connector
Doc/DT: Add DT binding documentation for Analog TV Connector
ARM: omap3-n900.dts: add display information
ARM: omap3-igep0020.dts: add display information
ARM: omap3-beagle-xm.dts: add display information
ARM: omap3-beagle.dts: add display information
ARM: omap4-sdp.dts: add display information
Doc/DT: Add DT binding documentation for OMAP DSS
OMAPDSS: acx565akm: Add DT support
OMAPDSS: connector-analog-tv: Add DT support
OMAPDSS: hdmi-connector: Add DT support
...
Diffstat (limited to 'drivers/video')
20 files changed, 923 insertions, 42 deletions
diff --git a/drivers/video/omap2/displays-new/connector-analog-tv.c b/drivers/video/omap2/displays-new/connector-analog-tv.c index 27f33ef8fca1..5ee3b5505f7f 100644 --- a/drivers/video/omap2/displays-new/connector-analog-tv.c +++ b/drivers/video/omap2/displays-new/connector-analog-tv.c @@ -12,6 +12,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/of.h> #include <video/omapdss.h> #include <video/omap-panel-data.h> @@ -42,6 +43,12 @@ static const struct omap_video_timings tvc_pal_timings = { .interlace = true, }; +static const struct of_device_id tvc_of_match[]; + +struct tvc_of_data { + enum omap_dss_venc_type connector_type; +}; + #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) static int tvc_connect(struct omap_dss_device *dssdev) @@ -91,8 +98,12 @@ static int tvc_enable(struct omap_dss_device *dssdev) in->ops.atv->set_timings(in, &ddata->timings); - in->ops.atv->set_type(in, ddata->connector_type); - in->ops.atv->invert_vid_out_polarity(in, ddata->invert_polarity); + if (!ddata->dev->of_node) { + in->ops.atv->set_type(in, ddata->connector_type); + + in->ops.atv->invert_vid_out_polarity(in, + ddata->invert_polarity); + } r = in->ops.atv->enable(in); if (r) @@ -205,6 +216,23 @@ static int tvc_probe_pdata(struct platform_device *pdev) return 0; } +static int tvc_probe_of(struct platform_device *pdev) +{ + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + struct omap_dss_device *in; + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + return 0; +} + static int tvc_probe(struct platform_device *pdev) { struct panel_drv_data *ddata; @@ -222,6 +250,10 @@ static int tvc_probe(struct platform_device *pdev) r = tvc_probe_pdata(pdev); if (r) return r; + } else if (pdev->dev.of_node) { + r = tvc_probe_of(pdev); + if (r) + return r; } else { return -ENODEV; } @@ -263,12 +295,19 @@ static int __exit tvc_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id tvc_of_match[] = { + { .compatible = "omapdss,svideo-connector", }, + { .compatible = "omapdss,composite-video-connector", }, + {}, +}; + static struct platform_driver tvc_connector_driver = { .probe = tvc_probe, .remove = __exit_p(tvc_remove), .driver = { .name = "connector-analog-tv", .owner = THIS_MODULE, + .of_match_table = tvc_of_match, }, }; diff --git a/drivers/video/omap2/displays-new/connector-dvi.c b/drivers/video/omap2/displays-new/connector-dvi.c index d18e4b8c0731..74de2bc50c4f 100644 --- a/drivers/video/omap2/displays-new/connector-dvi.c +++ b/drivers/video/omap2/displays-new/connector-dvi.c @@ -277,6 +277,37 @@ static int dvic_probe_pdata(struct platform_device *pdev) return 0; } +static int dvic_probe_of(struct platform_device *pdev) +{ + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + struct omap_dss_device *in; + struct device_node *adapter_node; + struct i2c_adapter *adapter; + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + adapter_node = of_parse_phandle(node, "ddc-i2c-bus", 0); + if (adapter_node) { + adapter = of_find_i2c_adapter_by_node(adapter_node); + if (adapter == NULL) { + dev_err(&pdev->dev, "failed to parse ddc-i2c-bus\n"); + omap_dss_put_device(ddata->in); + return -EPROBE_DEFER; + } + + ddata->i2c_adapter = adapter; + } + + return 0; +} + static int dvic_probe(struct platform_device *pdev) { struct panel_drv_data *ddata; @@ -293,6 +324,10 @@ static int dvic_probe(struct platform_device *pdev) r = dvic_probe_pdata(pdev); if (r) return r; + } else if (pdev->dev.of_node) { + r = dvic_probe_of(pdev); + if (r) + return r; } else { return -ENODEV; } @@ -342,12 +377,20 @@ static int __exit dvic_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id dvic_of_match[] = { + { .compatible = "omapdss,dvi-connector", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, dvic_of_match); + static struct platform_driver dvi_connector_driver = { .probe = dvic_probe, .remove = __exit_p(dvic_remove), .driver = { .name = "connector-dvi", .owner = THIS_MODULE, + .of_match_table = dvic_of_match, }, }; diff --git a/drivers/video/omap2/displays-new/connector-hdmi.c b/drivers/video/omap2/displays-new/connector-hdmi.c index 9393e2d6473d..29ed21b9dce5 100644 --- a/drivers/video/omap2/displays-new/connector-hdmi.c +++ b/drivers/video/omap2/displays-new/connector-hdmi.c @@ -12,6 +12,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/of.h> #include <drm/drm_edid.h> @@ -301,6 +302,23 @@ static int hdmic_probe_pdata(struct platform_device *pdev) return 0; } +static int hdmic_probe_of(struct platform_device *pdev) +{ + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + struct omap_dss_device *in; + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + return 0; +} + static int hdmic_probe(struct platform_device *pdev) { struct panel_drv_data *ddata; @@ -318,6 +336,10 @@ static int hdmic_probe(struct platform_device *pdev) r = hdmic_probe_pdata(pdev); if (r) return r; + } else if (pdev->dev.of_node) { + r = hdmic_probe_of(pdev); + if (r) + return r; } else { return -ENODEV; } @@ -359,12 +381,20 @@ static int __exit hdmic_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id hdmic_of_match[] = { + { .compatible = "omapdss,hdmi-connector", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, hdmic_of_match); + static struct platform_driver hdmi_connector_driver = { .probe = hdmic_probe, .remove = __exit_p(hdmic_remove), .driver = { .name = "connector-hdmi", .owner = THIS_MODULE, + .of_match_table = hdmic_of_match, }, }; diff --git a/drivers/video/omap2/displays-new/encoder-tfp410.c b/drivers/video/omap2/displays-new/encoder-tfp410.c index 4a291e756be9..b4e9a42a79e6 100644 --- a/drivers/video/omap2/displays-new/encoder-tfp410.c +++ b/drivers/video/omap2/displays-new/encoder-tfp410.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/of_gpio.h> #include <video/omapdss.h> #include <video/omap-panel-data.h> @@ -82,7 +83,8 @@ static int tfp410_enable(struct omap_dss_device *dssdev) return 0; in->ops.dpi->set_timings(in, &ddata->timings); - in->ops.dpi->set_data_lines(in, ddata->data_lines); + if (ddata->data_lines) + in->ops.dpi->set_data_lines(in, ddata->data_lines); r = in->ops.dpi->enable(in); if (r) @@ -179,6 +181,33 @@ static int tfp410_probe_pdata(struct platform_device *pdev) return 0; } +static int tfp410_probe_of(struct platform_device *pdev) +{ + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + struct omap_dss_device *in; + int gpio; + + gpio = of_get_named_gpio(node, "powerdown-gpios", 0); + + if (gpio_is_valid(gpio) || gpio == -ENOENT) { + ddata->pd_gpio = gpio; + } else { + dev_err(&pdev->dev, "failed to parse PD gpio\n"); + return gpio; + } + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + return 0; +} + static int tfp410_probe(struct platform_device *pdev) { struct panel_drv_data *ddata; @@ -195,6 +224,10 @@ static int tfp410_probe(struct platform_device *pdev) r = tfp410_probe_pdata(pdev); if (r) return r; + } else if (pdev->dev.of_node) { + r = tfp410_probe_of(pdev); + if (r) + return r; } else { return -ENODEV; } @@ -251,12 +284,20 @@ static int __exit tfp410_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id tfp410_of_match[] = { + { .compatible = "omapdss,ti,tfp410", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, tfp410_of_match); + static struct platform_driver tfp410_driver = { .probe = tfp410_probe, .remove = __exit_p(tfp410_remove), .driver = { .name = "tfp410", .owner = THIS_MODULE, + .of_match_table = tfp410_of_match, }, }; diff --git a/drivers/video/omap2/displays-new/encoder-tpd12s015.c b/drivers/video/omap2/displays-new/encoder-tpd12s015.c index d5c936cb217f..7e33686171e3 100644 --- a/drivers/video/omap2/displays-new/encoder-tpd12s015.c +++ b/drivers/video/omap2/displays-new/encoder-tpd12s015.c @@ -15,6 +15,7 @@ #include <linux/slab.h> #include <linux/gpio.h> #include <linux/platform_device.h> +#include <linux/of_gpio.h> #include <video/omapdss.h> #include <video/omap-panel-data.h> @@ -289,6 +290,49 @@ static int tpd_probe_pdata(struct platform_device *pdev) return 0; } +static int tpd_probe_of(struct platform_device *pdev) +{ + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + struct omap_dss_device *in; + int gpio; + + /* CT CP HPD GPIO */ + gpio = of_get_gpio(node, 0); + if (!gpio_is_valid(gpio)) { + dev_err(&pdev->dev, "failed to parse CT CP HPD gpio\n"); + return gpio; + } + ddata->ct_cp_hpd_gpio = gpio; + + /* LS OE GPIO */ + gpio = of_get_gpio(node, 1); + if (gpio_is_valid(gpio) || gpio == -ENOENT) { + ddata->ls_oe_gpio = gpio; + } else { + dev_err(&pdev->dev, "failed to parse LS OE gpio\n"); + return gpio; + } + + /* HPD GPIO */ + gpio = of_get_gpio(node, 2); + if (!gpio_is_valid(gpio)) { + dev_err(&pdev->dev, "failed to parse HPD gpio\n"); + return gpio; + } + ddata->hpd_gpio = gpio; + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + return 0; +} + static int tpd_probe(struct platform_device *pdev) { struct omap_dss_device *in, *dssdev; @@ -307,6 +351,10 @@ static int tpd_probe(struct platform_device *pdev) r = tpd_probe_pdata(pdev); if (r) return r; + } else if (pdev->dev.of_node) { + r = tpd_probe_of(pdev); + if (r) + return r; } else { return -ENODEV; } @@ -379,12 +427,20 @@ static int __exit tpd_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id tpd_of_match[] = { + { .compatible = "omapdss,ti,tpd12s015", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, tpd_of_match); + static struct platform_driver tpd_driver = { .probe = tpd_probe, .remove = __exit_p(tpd_remove), .driver = { .name = "tpd12s015", .owner = THIS_MODULE, + .of_match_table = tpd_of_match, }, }; diff --git a/drivers/video/omap2/displays-new/panel-dsi-cm.c b/drivers/video/omap2/displays-new/panel-dsi-cm.c index f317c878a259..d6f14e8717e8 100644 --- a/drivers/video/omap2/displays-new/panel-dsi-cm.c +++ b/drivers/video/omap2/displays-new/panel-dsi-cm.c @@ -22,6 +22,8 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/workqueue.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> #include <video/omapdss.h> #include <video/omap-panel-data.h> @@ -595,10 +597,13 @@ static int dsicm_power_on(struct panel_drv_data *ddata) .lp_clk_max = 10000000, }; - r = in->ops.dsi->configure_pins(in, &ddata->pin_config); - if (r) { - dev_err(&ddata->pdev->dev, "failed to configure DSI pins\n"); - goto err0; + if (ddata->pin_config.num_pins > 0) { + r = in->ops.dsi->configure_pins(in, &ddata->pin_config); + if (r) { + dev_err(&ddata->pdev->dev, + "failed to configure DSI pins\n"); + goto err0; + } } r = in->ops.dsi->set_config(in, &dsi_config); @@ -1156,6 +1161,41 @@ static int dsicm_probe_pdata(struct platform_device *pdev) return 0; } +static int dsicm_probe_of(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct omap_dss_device *in; + int gpio; + + gpio = of_get_named_gpio(node, "reset-gpios", 0); + if (!gpio_is_valid(gpio)) { + dev_err(&pdev->dev, "failed to parse reset gpio\n"); + return gpio; + } + ddata->reset_gpio = gpio; + + gpio = of_get_named_gpio(node, "te-gpios", 0); + if (gpio_is_valid(gpio) || gpio == -ENOENT) { + ddata->ext_te_gpio = gpio; + } else { + dev_err(&pdev->dev, "failed to parse TE gpio\n"); + return gpio; + } + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + /* TODO: ulps, backlight */ + + return 0; +} + static int dsicm_probe(struct platform_device *pdev) { struct backlight_properties props; @@ -1178,6 +1218,10 @@ static int dsicm_probe(struct platform_device *pdev) r = dsicm_probe_pdata(pdev); if (r) return r; + } else if (pdev->dev.of_node) { + r = dsicm_probe_of(pdev); + if (r) + return r; } else { return -ENODEV; } @@ -1320,12 +1364,20 @@ static int __exit dsicm_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id dsicm_of_match[] = { + { .compatible = "omapdss,panel-dsi-cm", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, dsicm_of_match); + static struct platform_driver dsicm_driver = { .probe = dsicm_probe, .remove = __exit_p(dsicm_remove), .driver = { .name = "panel-dsi-cm", .owner = THIS_MODULE, + .of_match_table = dsicm_of_match, }, }; diff --git a/drivers/video/omap2/displays-new/panel-sony-acx565akm.c b/drivers/video/omap2/displays-new/panel-sony-acx565akm.c index 27f60ad6b2ab..c7ba4d8b928a 100644 --- a/drivers/video/omap2/displays-new/panel-sony-acx565akm.c +++ b/drivers/video/omap2/displays-new/panel-sony-acx565akm.c @@ -30,6 +30,8 @@ #include <linux/backlight.h> #include <linux/fb.h> #include <linux/gpio.h> +#include <linux/of.h> +#include <linux/of_gpio.h> #include <video/omapdss.h> #include <video/omap-panel-data.h> @@ -547,7 +549,9 @@ static int acx565akm_panel_power_on(struct omap_dss_device *dssdev) dev_dbg(&ddata->spi->dev, "%s\n", __func__); in->ops.sdi->set_timings(in, &ddata->videomode); - in->ops.sdi->set_datapairs(in, ddata->datapairs); + + if (ddata->datapairs > 0) + in->ops.sdi->set_datapairs(in, ddata->datapairs); r = in->ops.sdi->enable(in); if (r) { @@ -726,6 +730,22 @@ static int acx565akm_probe_pdata(struct spi_device *spi) return 0; } +static int acx565akm_probe_of(struct spi_device *spi) +{ + struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); + struct device_node *np = spi->dev.of_node; + + ddata->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); + + ddata->in = omapdss_of_find_source_for_first_ep(np); + if (IS_ERR(ddata->in)) { + dev_err(&spi->dev, "failed to find video source\n"); + return PTR_ERR(ddata->in); + } + + return 0; +} + static int acx565akm_probe(struct spi_device *spi) { struct panel_drv_data *ddata; @@ -753,7 +773,12 @@ static int acx565akm_probe(struct spi_device *spi) r = acx565akm_probe_pdata(spi); if (r) return r; + } else if (spi->dev.of_node) { + r = acx565akm_probe_of(spi); + if (r) + return r; } else { + dev_err(&spi->dev, "platform data missing!\n"); return -ENODEV; } @@ -864,10 +889,16 @@ static int acx565akm_remove(struct spi_device *spi) return 0; } +static const struct of_device_id acx565akm_of_match[] = { + { .compatible = "omapdss,sony,acx565akm", }, + {}, +}; + static struct spi_driver acx565akm_driver = { .driver = { .name = "acx565akm", .owner = THIS_MODULE, + .of_match_table = acx565akm_of_match, }, .probe = acx565akm_probe, .remove = acx565akm_remove, diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index d3aa91bdd6a8..8aec8bda27cc 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile @@ -1,7 +1,7 @@ obj-$(CONFIG_OMAP2_DSS) += omapdss.o # Core DSS files omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ - output.o + output.o dss-of.o # DSS compat layer files omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \ dispc-compat.o display-sysfs.o diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index aaecbf347748..2bbdb7ff7daf 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -3778,12 +3778,20 @@ static const struct dev_pm_ops dispc_pm_ops = { .runtime_resume = dispc_runtime_resume, }; +static const struct of_device_id dispc_of_match[] = { + { .compatible = "ti,omap2-dispc", }, + { .compatible = "ti,omap3-dispc", }, + { .compatible = "ti,omap4-dispc", }, + {}, +}; + static struct platform_driver omap_dispchw_driver = { .remove = __exit_p(omap_dispchw_remove), .driver = { .name = "omapdss_dispc", .owner = THIS_MODULE, .pm = &dispc_pm_ops, + .of_match_table = dispc_of_match, }, }; diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 9f19ae22944c..2412a0dd0c13 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/jiffies.h> #include <linux/platform_device.h> +#include <linux/of.h> #include <video/omapdss.h> #include "dss.h" @@ -133,9 +134,32 @@ static int disp_num_counter; int omapdss_register_display(struct omap_dss_device *dssdev) { struct omap_dss_driver *drv = dssdev->driver; + int id; - snprintf(dssdev->alias, sizeof(dssdev->alias), - "display%d", disp_num_counter++); + /* + * Note: this presumes all the displays are either using DT or non-DT, + * which normally should be the case. This also presumes that all + * displays either have an DT alias, or none has. + */ + + if (dssdev->dev->of_node) { + id = of_alias_get_id(dssdev->dev->of_node, "display"); + + if (id < 0) + id = disp_num_counter++; + } else { + id = disp_num_counter++; + } + + snprintf(dssdev->alias, sizeof(dssdev->alias), "display%d", id); + + /* Use 'label' property for name, if it exists */ + if (dssdev->dev->of_node) + of_property_read_string(dssdev->dev->of_node, "label", + &dssdev->name); + + if (dssdev->name == NULL) + dssdev->name = dssdev->alias; if (drv && drv->get_resolution == NULL) drv->get_resolution = omapdss_default_get_resolution; diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 6c0bb099b7bf..157921db447a 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -30,6 +30,7 @@ #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/string.h> +#include <linux/of.h> #include <video/omapdss.h> @@ -49,6 +50,8 @@ static struct { int data_lines; struct omap_dss_device output; + + bool port_initialized; } dpi; static struct platform_device *dpi_get_dsidev(enum omap_channel channel) @@ -725,3 +728,47 @@ void __exit dpi_uninit_platform_driver(void) { platform_driver_unregister(&omap_dpi_driver); } + +int __init dpi_init_port(struct platform_device *pdev, struct device_node *port) +{ + struct device_node *ep; + u32 datalines; + int r; + + ep = omapdss_of_get_next_endpoint(port, NULL); + if (!ep) + return 0; + + r = of_property_read_u32(ep, "data-lines", &datalines); + if (r) { + DSSERR("failed to parse datalines\n"); + goto err_datalines; + } + + dpi.data_lines = datalines; + + of_node_put(ep); + + dpi.pdev = pdev; + + mutex_init(&dpi.lock); + + dpi_init_output(pdev); + + dpi.port_initialized = true; + + return 0; + +err_datalines: + of_node_put(ep); + + return r; +} + +void __exit dpi_uninit_port(void) +{ + if (!dpi.port_initialized) + return; + + dpi_uninit_output(dpi.pdev); +} diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 0d82f731d2f0..121d1049d0bc 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -38,6 +38,8 @@ #include <linux/slab.h> #include <linux/debugfs.h> #include <linux/pm_runtime.h> +#include <linux/of.h> +#include <linux/of_platform.h> #include <video/omapdss.h> #include <video/mipi_display.h> @@ -386,6 +388,13 @@ struct dsi_packet_sent_handler_data { struct completion *completion; }; +struct dsi_module_id_data { + u32 address; + int id; +}; + +static const struct of_device_id dsi_of_match[]; + #ifdef DSI_PERF_MEASURE static bool dsi_perf; module_param(dsi_perf, bool, 0644); @@ -1151,15 +1160,11 @@ static int dsi_regulator_init(struct platform_device *dsidev) if (dsi->vdds_dsi_reg != NULL) return 0; - vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdds_dsi"); - - /* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */ - if (IS_ERR(vdds_dsi)) - vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "VCXIO"); + vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdd"); if (IS_ERR(vdds_dsi)) { if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER) - DSSERR("can't get VDDS_DSI regulator\n"); + DSSERR("can't get DSI VDD regulator\n"); return PTR_ERR(vdds_dsi); } @@ -5370,12 +5375,69 @@ static void dsi_uninit_output(struct platform_device *dsidev) omapdss_unregister_output(out); } +static int dsi_probe_of(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); + struct property *prop; + u32 lane_arr[10]; + int len, num_pins; + int r, i; + struct device_node *ep; + struct omap_dsi_pin_config pin_cfg; + + ep = omapdss_of_get_first_endpoint(node); + if (!ep) + return 0; + + prop = of_find_property(ep, "lanes", &len); + if (prop == NULL) { + dev_err(&pdev->dev, "failed to find lane data\n"); + r = -EINVAL; + goto err; + } + + num_pins = len / sizeof(u32); + + if (num_pins < 4 || num_pins % 2 != 0 || + num_pins > dsi->num_lanes_supported * 2) { + dev_err(&pdev->dev, "bad number of lanes\n"); + r = -EINVAL; + goto err; + } + + r = of_property_read_u32_array(ep, "lanes", lane_arr, num_pins); + if (r) { + dev_err(&pdev->dev, "failed to read lane data\n"); + goto err; + } + + pin_cfg.num_pins = num_pins; + for (i = 0; i < num_pins; ++i) + pin_cfg.pins[i] = (int)lane_arr[i]; + + r = dsi_configure_pins(&dsi->output, &pin_cfg); + if (r) { + dev_err(&pdev->dev, "failed to configure pins"); + goto err; + } + + of_node_put(ep); + + return 0; + +err: + of_node_put(ep); + return r; +} + /* DSI1 HW IP initialisation */ static int omap_dsihw_probe(struct platform_device *dsidev) { u32 rev; int r, i; struct dsi_data *dsi; + struct resource *dsi_mem; struct resource *res; struct resource temp_res; @@ -5383,7 +5445,6 @@ static int omap_dsihw_probe(struct platform_device *dsidev) if (!dsi) return -ENOMEM; - dsi->module_id = dsidev->id; dsi->pdev = dsidev; dev_set_drvdata(&dsidev->dev, dsi); @@ -5421,6 +5482,8 @@ static int omap_dsihw_probe(struct platform_device *dsidev) res = &temp_res; } + dsi_mem = res; + dsi->proto_base = devm_ioremap(&dsidev->dev, res->start, resource_size(res)); if (!dsi->proto_base) { @@ -5481,6 +5544,31 @@ static int omap_dsihw_probe(struct platform_device *dsidev) return r; } + if (dsidev->dev.of_node) { + const struct of_device_id *match; + const struct dsi_module_id_data *d; + + match = of_match_node(dsi_of_match, dsidev->dev.of_node); + if (!match) { + DSSERR("unsupported DSI module\n"); + return -ENODEV; + } + + d = match->data; + + while (d->address != 0 && d->address != dsi_mem->start) + d++; + + if (d->address == 0) { + DSSERR("unsupported DSI module\n"); + return -ENODEV; + } + + dsi->module_id = d->id; + } else { + dsi->module_id = dsidev->id; + } + /* DSI VCs initialization */ for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) { dsi->vc[i].source = DSI_VC_SOURCE_L4; @@ -5516,6 +5604,19 @@ static int omap_dsihw_probe(struct platform_device *dsidev) dsi_init_output(dsidev); + if (dsidev->dev.of_node) { + r = dsi_probe_of(dsidev); + if (r) { + DSSERR("Invalid DSI DT data\n"); + goto err_probe_of; + } + + r = of_platform_populate(dsidev->dev.of_node, NULL, NULL, + &dsidev->dev); + if (r) + DSSERR("Failed to populate DSI child devices: %d\n", r); + } + dsi_runtime_put(dsidev); if (dsi->module_id == 0) @@ -5529,17 +5630,31 @@ static int omap_dsihw_probe(struct platform_device *dsidev) else if (dsi->module_id == 1) dss_debugfs_create_file("dsi2_irqs", dsi2_dump_irqs); #endif + return 0; |