[Letux-kernel] [PATCH RFC] w1: omap: disable iclk autoidle
Andreas Kemnade
andreas at kemnade.info
Sun Sep 30 00:34:21 CEST 2018
On the gta04 in DM3730, omap_hdq gets stuck whenever
autosuspend is enabled for UART1/2. The system will go into
a lower power state then. According to the TRM, the module has
no way to prevent the ick from being but during a transfer if
autoidle is enabled.
So disable autoidle.
Having omap_hdq working on the gta04 is important for measuring
currents through a bq27000.
The question is what is the best place to do this.
Perhaps better in arch/arm/mach-omap2 somehow, so
no additional exported symbols are needed.
But there seems to be no simple flag to set there.
Maybe we need something like
arch/arm/mach-omap2/mcbsp.c?
And also the affected platforms need to be checked.
Probably omap_hdq_get/put should also be cleaned up and
stuff from there should be put into a runtime_suspend/resume
handler.
Signed-off-by: Andreas Kemnade <andreas at kemnade.info>
---
drivers/clk/ti/autoidle.c | 2 ++
drivers/w1/masters/omap_hdq.c | 27 ++++++++++++++++++++++++++-
2 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/ti/autoidle.c b/drivers/clk/ti/autoidle.c
index 7bb9afbe4058..b8970006efd9 100644
--- a/drivers/clk/ti/autoidle.c
+++ b/drivers/clk/ti/autoidle.c
@@ -52,6 +52,7 @@ int omap2_clk_deny_idle(struct clk *clk)
c->ops->deny_idle(c);
return 0;
}
+EXPORT_SYMBOL(omap2_clk_deny_idle);
/**
* omap2_clk_allow_idle - enable autoidle on an OMAP clock
@@ -68,6 +69,7 @@ int omap2_clk_allow_idle(struct clk *clk)
c->ops->allow_idle(c);
return 0;
}
+EXPORT_SYMBOL(omap2_clk_allow_idle);
static void _allow_autoidle(struct clk_ti_autoidle *clk)
{
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c
index 3099052e1243..e3aeba8a1155 100644
--- a/drivers/w1/masters/omap_hdq.c
+++ b/drivers/w1/masters/omap_hdq.c
@@ -18,6 +18,8 @@
#include <linux/sched.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/clk/ti.h>
#include <linux/w1.h>
@@ -59,6 +61,14 @@ MODULE_PARM_DESC(w1_id, "1-wire id for the slave detection in HDQ mode");
struct hdq_data {
struct device *dev;
+ /*
+ * needed to disable autoidle, if system power state is too low
+ * hdq transactions will not work correctly, although registers
+ * are accessible.
+ * According to AM/DM3730 TRM p.2879 the hwmod has to way to
+ * keep iclk running during a transfer if autoidle is enabled
+ */
+ struct clk *ick;
void __iomem *hdq_base;
/* lock status update */
struct mutex hdq_mutex;
@@ -414,6 +424,9 @@ static int omap_hdq_get(struct hdq_data *hdq_data)
try_module_get(THIS_MODULE);
if (1 == hdq_data->hdq_usecount) {
+ if (!IS_ERR_OR_NULL(hdq_data->ick))
+ omap2_clk_deny_idle(hdq_data->ick);
+
pm_runtime_get_sync(hdq_data->dev);
/* make sure HDQ/1W is out of reset */
@@ -460,8 +473,11 @@ static int omap_hdq_put(struct hdq_data *hdq_data)
} else {
hdq_data->hdq_usecount--;
module_put(THIS_MODULE);
- if (0 == hdq_data->hdq_usecount)
+ if (hdq_data->hdq_usecount == 0) {
pm_runtime_put_sync(hdq_data->dev);
+ if (!IS_ERR_OR_NULL(hdq_data->ick))
+ omap2_clk_allow_idle(hdq_data->ick);
+ }
}
mutex_unlock(&hdq_data->hdq_mutex);
@@ -681,8 +697,15 @@ static int omap_hdq_probe(struct platform_device *pdev)
hdq_data->hdq_usecount = 0;
hdq_data->rrw = 0;
+ hdq_data->ick = devm_clk_get(dev, "hdq_ick");
+ if (IS_ERR_OR_NULL(hdq_data->ick))
+ dev_info(dev, "no hdq_ick, lets hope autoidle behaves!");
+
mutex_init(&hdq_data->hdq_mutex);
+ if (!IS_ERR_OR_NULL(hdq_data->ick))
+ omap2_clk_deny_idle(hdq_data->ick);
+
pm_runtime_enable(&pdev->dev);
ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0) {
@@ -718,6 +741,8 @@ static int omap_hdq_probe(struct platform_device *pdev)
omap_hdq_break(hdq_data);
pm_runtime_put_sync(&pdev->dev);
+ if (!IS_ERR_OR_NULL(hdq_data->ick))
+ omap2_clk_allow_idle(hdq_data->ick);
ret = of_property_read_string(pdev->dev.of_node, "ti,mode", &mode);
if (ret < 0 || !strcmp(mode, "hdq")) {
--
2.11.0
More information about the Letux-kernel
mailing list