mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
clk: clk-twl6040: Fix imprecise external abort for pdmclk
commit 5ae51d67ae upstream.
I noticed that modprobe clk-twl6040 can fail after a cold boot with:
abe_cm:clk:0010:0: failed to enable
...
Unhandled fault: imprecise external abort (0x1406) at 0xbe896b20
WARNING: CPU: 1 PID: 29 at drivers/clk/clk.c:828 clk_core_disable_lock+0x18/0x24
...
(clk_core_disable_lock) from [<c0123534>] (_disable_clocks+0x18/0x90)
(_disable_clocks) from [<c0124040>] (_idle+0x17c/0x244)
(_idle) from [<c0125ad4>] (omap_hwmod_idle+0x24/0x44)
(omap_hwmod_idle) from [<c053a038>] (sysc_runtime_suspend+0x48/0x108)
(sysc_runtime_suspend) from [<c06084c4>] (__rpm_callback+0x144/0x1d8)
(__rpm_callback) from [<c0608578>] (rpm_callback+0x20/0x80)
(rpm_callback) from [<c0607034>] (rpm_suspend+0x120/0x694)
(rpm_suspend) from [<c0607a78>] (__pm_runtime_idle+0x60/0x84)
(__pm_runtime_idle) from [<c053aaf0>] (sysc_probe+0x874/0xf2c)
(sysc_probe) from [<c05fecd4>] (platform_drv_probe+0x48/0x98)
After searching around for a similar issue, I came across an earlier fix
that never got merged upstream in the Android tree for glass-omap-xrr02.
There is patch "MFD: twl6040-codec: Implement PDMCLK cold temp errata"
by Misael Lopez Cruz <misael.lopez@ti.com>.
Based on my observations, this fix is also needed when cold booting
devices, and not just for deeper idle modes. Since we now have a clock
driver for pdmclk, let's fix the issue in twl6040_pdmclk_prepare().
Cc: Misael Lopez Cruz <misael.lopez@ti.com>
Cc: Peter Ujfalusi <peter.ujfalusi@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Acked-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
a712a38100
commit
d9d7760c1e
@@ -41,6 +41,43 @@ static int twl6040_pdmclk_is_prepared(struct clk_hw *hw)
|
||||
return pdmclk->enabled;
|
||||
}
|
||||
|
||||
static int twl6040_pdmclk_reset_one_clock(struct twl6040_pdmclk *pdmclk,
|
||||
unsigned int reg)
|
||||
{
|
||||
const u8 reset_mask = TWL6040_HPLLRST; /* Same for HPPLL and LPPLL */
|
||||
int ret;
|
||||
|
||||
ret = twl6040_set_bits(pdmclk->twl6040, reg, reset_mask);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = twl6040_clear_bits(pdmclk->twl6040, reg, reset_mask);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* TWL6040A2 Phoenix Audio IC erratum #6: "PDM Clock Generation Issue At
|
||||
* Cold Temperature". This affects cold boot and deeper idle states it
|
||||
* seems. The workaround consists of resetting HPPLL and LPPLL.
|
||||
*/
|
||||
static int twl6040_pdmclk_quirk_reset_clocks(struct twl6040_pdmclk *pdmclk)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = twl6040_pdmclk_reset_one_clock(pdmclk, TWL6040_REG_HPPLLCTL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = twl6040_pdmclk_reset_one_clock(pdmclk, TWL6040_REG_LPPLLCTL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int twl6040_pdmclk_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk,
|
||||
@@ -48,8 +85,20 @@ static int twl6040_pdmclk_prepare(struct clk_hw *hw)
|
||||
int ret;
|
||||
|
||||
ret = twl6040_power(pdmclk->twl6040, 1);
|
||||
if (!ret)
|
||||
pdmclk->enabled = 1;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = twl6040_pdmclk_quirk_reset_clocks(pdmclk);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
|
||||
pdmclk->enabled = 1;
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
dev_err(pdmclk->dev, "%s: error %i\n", __func__, ret);
|
||||
twl6040_power(pdmclk->twl6040, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user