|
|
@@ -39,6 +39,7 @@
|
|
|
#include <linux/of.h>
|
|
|
#include <linux/regulator/consumer.h>
|
|
|
#include <linux/suspend.h>
|
|
|
+#include <linux/component.h>
|
|
|
|
|
|
#include <video/omapdss.h>
|
|
|
|
|
|
@@ -111,6 +112,14 @@ static const char * const dss_generic_clk_source_names[] = {
|
|
|
[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DSI_PLL2_HSDIV_DSI",
|
|
|
};
|
|
|
|
|
|
+static bool dss_initialized;
|
|
|
+
|
|
|
+bool omapdss_is_initialized(void)
|
|
|
+{
|
|
|
+ return dss_initialized;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(omapdss_is_initialized);
|
|
|
+
|
|
|
static inline void dss_write_reg(const struct dss_reg idx, u32 val)
|
|
|
{
|
|
|
__raw_writel(val, dss.base + idx.idx);
|
|
|
@@ -811,7 +820,7 @@ static const enum omap_display_type dra7xx_ports[] = {
|
|
|
OMAP_DISPLAY_TYPE_DPI,
|
|
|
};
|
|
|
|
|
|
-static const struct dss_features omap24xx_dss_feats __initconst = {
|
|
|
+static const struct dss_features omap24xx_dss_feats = {
|
|
|
/*
|
|
|
* fck div max is really 16, but the divider range has gaps. The range
|
|
|
* from 1 to 6 has no gaps, so let's use that as a max.
|
|
|
@@ -824,7 +833,7 @@ static const struct dss_features omap24xx_dss_feats __initconst = {
|
|
|
.num_ports = ARRAY_SIZE(omap2plus_ports),
|
|
|
};
|
|
|
|
|
|
-static const struct dss_features omap34xx_dss_feats __initconst = {
|
|
|
+static const struct dss_features omap34xx_dss_feats = {
|
|
|
.fck_div_max = 16,
|
|
|
.dss_fck_multiplier = 2,
|
|
|
.parent_clk_name = "dpll4_ck",
|
|
|
@@ -833,7 +842,7 @@ static const struct dss_features omap34xx_dss_feats __initconst = {
|
|
|
.num_ports = ARRAY_SIZE(omap34xx_ports),
|
|
|
};
|
|
|
|
|
|
-static const struct dss_features omap3630_dss_feats __initconst = {
|
|
|
+static const struct dss_features omap3630_dss_feats = {
|
|
|
.fck_div_max = 32,
|
|
|
.dss_fck_multiplier = 1,
|
|
|
.parent_clk_name = "dpll4_ck",
|
|
|
@@ -842,7 +851,7 @@ static const struct dss_features omap3630_dss_feats __initconst = {
|
|
|
.num_ports = ARRAY_SIZE(omap2plus_ports),
|
|
|
};
|
|
|
|
|
|
-static const struct dss_features omap44xx_dss_feats __initconst = {
|
|
|
+static const struct dss_features omap44xx_dss_feats = {
|
|
|
.fck_div_max = 32,
|
|
|
.dss_fck_multiplier = 1,
|
|
|
.parent_clk_name = "dpll_per_x2_ck",
|
|
|
@@ -851,7 +860,7 @@ static const struct dss_features omap44xx_dss_feats __initconst = {
|
|
|
.num_ports = ARRAY_SIZE(omap2plus_ports),
|
|
|
};
|
|
|
|
|
|
-static const struct dss_features omap54xx_dss_feats __initconst = {
|
|
|
+static const struct dss_features omap54xx_dss_feats = {
|
|
|
.fck_div_max = 64,
|
|
|
.dss_fck_multiplier = 1,
|
|
|
.parent_clk_name = "dpll_per_x2_ck",
|
|
|
@@ -860,7 +869,7 @@ static const struct dss_features omap54xx_dss_feats __initconst = {
|
|
|
.num_ports = ARRAY_SIZE(omap2plus_ports),
|
|
|
};
|
|
|
|
|
|
-static const struct dss_features am43xx_dss_feats __initconst = {
|
|
|
+static const struct dss_features am43xx_dss_feats = {
|
|
|
.fck_div_max = 0,
|
|
|
.dss_fck_multiplier = 0,
|
|
|
.parent_clk_name = NULL,
|
|
|
@@ -869,7 +878,7 @@ static const struct dss_features am43xx_dss_feats __initconst = {
|
|
|
.num_ports = ARRAY_SIZE(omap2plus_ports),
|
|
|
};
|
|
|
|
|
|
-static const struct dss_features dra7xx_dss_feats __initconst = {
|
|
|
+static const struct dss_features dra7xx_dss_feats = {
|
|
|
.fck_div_max = 64,
|
|
|
.dss_fck_multiplier = 1,
|
|
|
.parent_clk_name = "dpll_per_x2_ck",
|
|
|
@@ -878,7 +887,7 @@ static const struct dss_features dra7xx_dss_feats __initconst = {
|
|
|
.num_ports = ARRAY_SIZE(dra7xx_ports),
|
|
|
};
|
|
|
|
|
|
-static int __init dss_init_features(struct platform_device *pdev)
|
|
|
+static int dss_init_features(struct platform_device *pdev)
|
|
|
{
|
|
|
const struct dss_features *src;
|
|
|
struct dss_features *dst;
|
|
|
@@ -932,7 +941,7 @@ static int __init dss_init_features(struct platform_device *pdev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int __init dss_init_ports(struct platform_device *pdev)
|
|
|
+static int dss_init_ports(struct platform_device *pdev)
|
|
|
{
|
|
|
struct device_node *parent = pdev->dev.of_node;
|
|
|
struct device_node *port;
|
|
|
@@ -976,7 +985,7 @@ static int __init dss_init_ports(struct platform_device *pdev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void __exit dss_uninit_ports(struct platform_device *pdev)
|
|
|
+static void dss_uninit_ports(struct platform_device *pdev)
|
|
|
{
|
|
|
struct device_node *parent = pdev->dev.of_node;
|
|
|
struct device_node *port;
|
|
|
@@ -1018,14 +1027,74 @@ static void __exit dss_uninit_ports(struct platform_device *pdev)
|
|
|
} while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
|
|
|
}
|
|
|
|
|
|
+static int dss_video_pll_probe(struct platform_device *pdev)
|
|
|
+{
|
|
|
+ struct device_node *np = pdev->dev.of_node;
|
|
|
+ struct regulator *pll_regulator;
|
|
|
+ int r;
|
|
|
+
|
|
|
+ if (!np)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (of_property_read_bool(np, "syscon-pll-ctrl")) {
|
|
|
+ dss.syscon_pll_ctrl = syscon_regmap_lookup_by_phandle(np,
|
|
|
+ "syscon-pll-ctrl");
|
|
|
+ if (IS_ERR(dss.syscon_pll_ctrl)) {
|
|
|
+ dev_err(&pdev->dev,
|
|
|
+ "failed to get syscon-pll-ctrl regmap\n");
|
|
|
+ return PTR_ERR(dss.syscon_pll_ctrl);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (of_property_read_u32_index(np, "syscon-pll-ctrl", 1,
|
|
|
+ &dss.syscon_pll_ctrl_offset)) {
|
|
|
+ dev_err(&pdev->dev,
|
|
|
+ "failed to get syscon-pll-ctrl offset\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pll_regulator = devm_regulator_get(&pdev->dev, "vdda_video");
|
|
|
+ if (IS_ERR(pll_regulator)) {
|
|
|
+ r = PTR_ERR(pll_regulator);
|
|
|
+
|
|
|
+ switch (r) {
|
|
|
+ case -ENOENT:
|
|
|
+ pll_regulator = NULL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case -EPROBE_DEFER:
|
|
|
+ return -EPROBE_DEFER;
|
|
|
+
|
|
|
+ default:
|
|
|
+ DSSERR("can't get DPLL VDDA regulator\n");
|
|
|
+ return r;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (of_property_match_string(np, "reg-names", "pll1") >= 0) {
|
|
|
+ dss.video1_pll = dss_video_pll_init(pdev, 0, pll_regulator);
|
|
|
+ if (IS_ERR(dss.video1_pll))
|
|
|
+ return PTR_ERR(dss.video1_pll);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (of_property_match_string(np, "reg-names", "pll2") >= 0) {
|
|
|
+ dss.video2_pll = dss_video_pll_init(pdev, 1, pll_regulator);
|
|
|
+ if (IS_ERR(dss.video2_pll)) {
|
|
|
+ dss_video_pll_uninit(dss.video1_pll);
|
|
|
+ return PTR_ERR(dss.video2_pll);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/* DSS HW IP initialisation */
|
|
|
-static int __init omap_dsshw_probe(struct platform_device *pdev)
|
|
|
+static int dss_bind(struct device *dev)
|
|
|
{
|
|
|
+ struct platform_device *pdev = to_platform_device(dev);
|
|
|
struct resource *dss_mem;
|
|
|
- struct device_node *np = pdev->dev.of_node;
|
|
|
u32 rev;
|
|
|
int r;
|
|
|
- struct regulator *pll_regulator;
|
|
|
|
|
|
dss.pdev = pdev;
|
|
|
|
|
|
@@ -1054,6 +1123,14 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
|
|
|
if (r)
|
|
|
goto err_setup_clocks;
|
|
|
|
|
|
+ r = dss_video_pll_probe(pdev);
|
|
|
+ if (r)
|
|
|
+ goto err_pll_init;
|
|
|
+
|
|
|
+ r = dss_init_ports(pdev);
|
|
|
+ if (r)
|
|
|
+ goto err_init_ports;
|
|
|
+
|
|
|
pm_runtime_enable(&pdev->dev);
|
|
|
|
|
|
r = dss_runtime_get();
|
|
|
@@ -1078,86 +1155,48 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
|
|
|
dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
|
|
|
dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
|
|
|
|
|
|
- dss_init_ports(pdev);
|
|
|
-
|
|
|
- if (np && of_property_read_bool(np, "syscon-pll-ctrl")) {
|
|
|
- dss.syscon_pll_ctrl = syscon_regmap_lookup_by_phandle(np,
|
|
|
- "syscon-pll-ctrl");
|
|
|
- if (IS_ERR(dss.syscon_pll_ctrl)) {
|
|
|
- dev_err(&pdev->dev,
|
|
|
- "failed to get syscon-pll-ctrl regmap\n");
|
|
|
- return PTR_ERR(dss.syscon_pll_ctrl);
|
|
|
- }
|
|
|
-
|
|
|
- if (of_property_read_u32_index(np, "syscon-pll-ctrl", 1,
|
|
|
- &dss.syscon_pll_ctrl_offset)) {
|
|
|
- dev_err(&pdev->dev,
|
|
|
- "failed to get syscon-pll-ctrl offset\n");
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- pll_regulator = devm_regulator_get(&pdev->dev, "vdda_video");
|
|
|
- if (IS_ERR(pll_regulator)) {
|
|
|
- r = PTR_ERR(pll_regulator);
|
|
|
-
|
|
|
- switch (r) {
|
|
|
- case -ENOENT:
|
|
|
- pll_regulator = NULL;
|
|
|
- break;
|
|
|
-
|
|
|
- case -EPROBE_DEFER:
|
|
|
- return -EPROBE_DEFER;
|
|
|
-
|
|
|
- default:
|
|
|
- DSSERR("can't get DPLL VDDA regulator\n");
|
|
|
- return r;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (of_property_match_string(np, "reg-names", "pll1") >= 0) {
|
|
|
- dss.video1_pll = dss_video_pll_init(pdev, 0, pll_regulator);
|
|
|
- if (IS_ERR(dss.video1_pll)) {
|
|
|
- r = PTR_ERR(dss.video1_pll);
|
|
|
- goto err_pll_init;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (of_property_match_string(np, "reg-names", "pll2") >= 0) {
|
|
|
- dss.video2_pll = dss_video_pll_init(pdev, 1, pll_regulator);
|
|
|
- if (IS_ERR(dss.video2_pll)) {
|
|
|
- r = PTR_ERR(dss.video2_pll);
|
|
|
- goto err_pll_init;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
rev = dss_read_reg(DSS_REVISION);
|
|
|
printk(KERN_INFO "OMAP DSS rev %d.%d\n",
|
|
|
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
|
|
|
|
|
|
dss_runtime_put();
|
|
|
|
|
|
+ r = component_bind_all(&pdev->dev, NULL);
|
|
|
+ if (r)
|
|
|
+ goto err_component;
|
|
|
+
|
|
|
dss_debugfs_create_file("dss", dss_dump_regs);
|
|
|
|
|
|
pm_set_vt_switch(0);
|
|
|
|
|
|
+ dss_initialized = true;
|
|
|
+
|
|
|
return 0;
|
|
|
|
|
|
-err_pll_init:
|
|
|
+err_component:
|
|
|
+err_runtime_get:
|
|
|
+ pm_runtime_disable(&pdev->dev);
|
|
|
+ dss_uninit_ports(pdev);
|
|
|
+err_init_ports:
|
|
|
if (dss.video1_pll)
|
|
|
dss_video_pll_uninit(dss.video1_pll);
|
|
|
|
|
|
if (dss.video2_pll)
|
|
|
dss_video_pll_uninit(dss.video2_pll);
|
|
|
-err_runtime_get:
|
|
|
- pm_runtime_disable(&pdev->dev);
|
|
|
+err_pll_init:
|
|
|
err_setup_clocks:
|
|
|
dss_put_clocks();
|
|
|
return r;
|
|
|
}
|
|
|
|
|
|
-static int __exit omap_dsshw_remove(struct platform_device *pdev)
|
|
|
+static void dss_unbind(struct device *dev)
|
|
|
{
|
|
|
+ struct platform_device *pdev = to_platform_device(dev);
|
|
|
+
|
|
|
+ dss_initialized = false;
|
|
|
+
|
|
|
+ component_unbind_all(&pdev->dev, NULL);
|
|
|
+
|
|
|
if (dss.video1_pll)
|
|
|
dss_video_pll_uninit(dss.video1_pll);
|
|
|
|
|
|
@@ -1169,10 +1208,49 @@ static int __exit omap_dsshw_remove(struct platform_device *pdev)
|
|
|
pm_runtime_disable(&pdev->dev);
|
|
|
|
|
|
dss_put_clocks();
|
|
|
+}
|
|
|
+
|
|
|
+static const struct component_master_ops dss_component_ops = {
|
|
|
+ .bind = dss_bind,
|
|
|
+ .unbind = dss_unbind,
|
|
|
+};
|
|
|
+
|
|
|
+static int dss_component_compare(struct device *dev, void *data)
|
|
|
+{
|
|
|
+ struct device *child = data;
|
|
|
+ return dev == child;
|
|
|
+}
|
|
|
+
|
|
|
+static int dss_add_child_component(struct device *dev, void *data)
|
|
|
+{
|
|
|
+ struct component_match **match = data;
|
|
|
+
|
|
|
+ component_match_add(dev->parent, match, dss_component_compare, dev);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int dss_probe(struct platform_device *pdev)
|
|
|
+{
|
|
|
+ struct component_match *match = NULL;
|
|
|
+ int r;
|
|
|
+
|
|
|
+ /* add all the child devices as components */
|
|
|
+ device_for_each_child(&pdev->dev, &match, dss_add_child_component);
|
|
|
+
|
|
|
+ r = component_master_add_with_match(&pdev->dev, &dss_component_ops, match);
|
|
|
+ if (r)
|
|
|
+ return r;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int dss_remove(struct platform_device *pdev)
|
|
|
+{
|
|
|
+ component_master_del(&pdev->dev, &dss_component_ops);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int dss_runtime_suspend(struct device *dev)
|
|
|
{
|
|
|
dss_save_context();
|
|
|
@@ -1215,7 +1293,8 @@ static const struct of_device_id dss_of_match[] = {
|
|
|
MODULE_DEVICE_TABLE(of, dss_of_match);
|
|
|
|
|
|
static struct platform_driver omap_dsshw_driver = {
|
|
|
- .remove = __exit_p(omap_dsshw_remove),
|
|
|
+ .probe = dss_probe,
|
|
|
+ .remove = dss_remove,
|
|
|
.driver = {
|
|
|
.name = "omapdss_dss",
|
|
|
.pm = &dss_pm_ops,
|
|
|
@@ -1226,7 +1305,7 @@ static struct platform_driver omap_dsshw_driver = {
|
|
|
|
|
|
int __init dss_init_platform_driver(void)
|
|
|
{
|
|
|
- return platform_driver_probe(&omap_dsshw_driver, omap_dsshw_probe);
|
|
|
+ return platform_driver_register(&omap_dsshw_driver);
|
|
|
}
|
|
|
|
|
|
void dss_uninit_platform_driver(void)
|