On 1/30/2020 10:45 PM, André Draszik wrote: > At the moment, enabling this driver without the SNVS RTC driver > being active will hang the kernel as soon as the power button > is pressed. > > The reason is that in that case the SNVS isn't enabled, and > any attempt to read the SNVS registers will simply hang forever. > > Ensure the clock is enabled (during the interrupt handler) to > make this driver work. > > Also see commit 7f8993995410 ("drivers/rtc/rtc-snvs: add clock support") > and commit edb190cb1734 > ("rtc: snvs: make sure clock is enabled for interrupt handle") > for similar updates to the snvs rtc driver. > > Signed-off-by: André Draszik <git@xxxxxxxxxx> > Cc: Anson Huang <Anson.Huang@xxxxxxx> > Cc: Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx> > Cc: "Horia Geantă" <horia.geanta@xxxxxxx> > Cc: Aymen Sghaier <aymen.sghaier@xxxxxxx> > Cc: Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx> > Cc: "David S. Miller" <davem@xxxxxxxxxxxxx> > Cc: Rob Herring <robh+dt@xxxxxxxxxx> > Cc: Mark Rutland <mark.rutland@xxxxxxx> > Cc: linux-crypto@xxxxxxxxxxxxxxx > Cc: devicetree@xxxxxxxxxxxxxxx > Cc: linux-input@xxxxxxxxxxxxxxx > --- > drivers/input/keyboard/snvs_pwrkey.c | 27 +++++++++++++++++++++++++++ > 1 file changed, 27 insertions(+) > > diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c > index 2f5e3ab5ed63..c29711d8735c 100644 > --- a/drivers/input/keyboard/snvs_pwrkey.c > +++ b/drivers/input/keyboard/snvs_pwrkey.c > @@ -16,6 +16,7 @@ > #include <linux/of_address.h> > #include <linux/platform_device.h> > #include <linux/pm_wakeirq.h> > +#include <linux/clk.h> > #include <linux/mfd/syscon.h> > #include <linux/regmap.h> > > @@ -38,6 +39,7 @@ struct pwrkey_drv_data { > int wakeup; > struct timer_list check_timer; > struct input_dev *input; > + struct clk *clk; > u8 minor_rev; > }; > > @@ -72,6 +74,9 @@ static irqreturn_t imx_snvs_pwrkey_interrupt(int irq, void *dev_id) > struct input_dev *input = pdata->input; > u32 lp_status; > > + if (pdata->clk) > + clk_enable(pdata->clk); > + clk framework handles NULL pointers internally, the check is redundant. > pm_wakeup_event(input->dev.parent, 0); > > regmap_read(pdata->snvs, SNVS_LPSR_REG, &lp_status); > @@ -96,6 +101,9 @@ static irqreturn_t imx_snvs_pwrkey_interrupt(int irq, void *dev_id) > /* clear SPO status */ > regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO); > > + if (pdata->clk) > + clk_disable(pdata->clk); > + > return IRQ_HANDLED; > } > > @@ -140,6 +148,25 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev) > if (pdata->irq < 0) > return -EINVAL; > > + pdata->clk = devm_clk_get(&pdev->dev, "snvs-pwrkey"); > + if (IS_ERR(pdata->clk)) { > + pdata->clk = NULL; Using devm_clk_get_optional() would simplify error handling. > + } else { > + error = clk_prepare_enable(pdata->clk); > + if (error) { > + dev_err(&pdev->dev, > + "Could not prepare or enable the snvs clock\n"); > + return error; > + } > + error = devm_add_action_or_reset(&pdev->dev, > + (void(*)(void *))clk_disable_unprepare, > + pdata->clk); > + if (error) { > + dev_err(&pdev->dev, "failed to add reset action on 'snvs-pwrkey'"); > + return error; > + } > + } > + > regmap_read(pdata->snvs, SNVS_HPVIDR1_REG, &vid); > pdata->minor_rev = vid & 0xff; > >