summaryrefslogtreecommitdiffstats
path: root/drivers/video/omap2/dss/dsi.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-04-07 10:47:51 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2014-04-07 10:47:51 -0700
commit0af9fb63915cf5ebb47b5c9ff16526b47545baf5 (patch)
tree2e05c80a4b3ef074e7535c0222e37150cdec09e7 /drivers/video/omap2/dss/dsi.c
parente5744abb2fa3629aa5a94e21ca1eae32ff2fe00b (diff)
parent0f5d9d2e7d234acb26bc98dd820cc8dd178774d6 (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/omap2/dss/dsi.c')
-rw-r--r--drivers/video/omap2/dss/dsi.c147
1 files changed, 140 insertions, 7 deletions
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 0d82f731d2f..121d1049d0b 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;
+err_probe_of:
+ dsi_uninit_output(dsidev);
+ dsi_runtime_put(dsidev);
+
err_runtime_get:
pm_runtime_disable(&dsidev->dev);
return r;
}
+static int dsi_unregister_child(struct device *dev, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ platform_device_unregister(pdev);
+ return 0;
+}
+
static int __exit omap_dsihw_remove(struct platform_device *dsidev)
{
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ device_for_each_child(&dsidev->dev, NULL, dsi_unregister_child);
+
WARN_ON(dsi->scp_clk_refcount > 0);
dsi_uninit_output(dsidev);
@@ -5577,6 +5692,23 @@ static const struct dev_pm_ops dsi_pm_ops = {
.runtime_resume = dsi_runtime_resume,
};
+static const struct dsi_module_id_data dsi_of_data_omap3[] = {
+ { .address = 0x4804fc00, .id = 0, },
+ { },
+};
+
+static const struct dsi_module_id_data dsi_of_data_omap4[] = {
+ { .address = 0x58004000, .id = 0, },
+ { .address = 0x58005000, .id = 1, },
+ { },
+};
+
+static const struct of_device_id dsi_of_match[] = {
+ { .compatible = "ti,omap3-dsi", .data = dsi_of_data_omap3, },
+ { .compatible = "ti,omap4-dsi", .data = dsi_of_data_omap4, },
+ {},
+};
+
static struct platform_driver omap_dsihw_driver = {
.probe = omap_dsihw_probe,
.remove = __exit_p(omap_dsihw_remove),
@@ -5584,6 +5716,7 @@ static struct platform_driver omap_dsihw_driver = {
.name = "omapdss_dsi",
.owner = THIS_MODULE,
.pm = &dsi_pm_ops,
+ .of_match_table = dsi_of_match,
},
};