Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752488AbdIVMld (ORCPT ); Fri, 22 Sep 2017 08:41:33 -0400 Received: from esa5.microchip.iphmx.com ([216.71.150.166]:17753 "EHLO esa5.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752162AbdIVMlb (ORCPT ); Fri, 22 Sep 2017 08:41:31 -0400 X-IronPort-AV: E=Sophos;i="5.42,427,1500966000"; d="scan'208";a="4927720" Subject: Re: [PATCH v2 7/9] pwm: atmel-tcb: Support backup mode To: Romain Izard , Alexandre Belloni , Boris Brezillon , Michael Turquette , Stephen Boyd , Ludovic Desroches , Wenyou Yang , Josh Wu , David Woodhouse , Brian Norris , Marek Vasut , Cyrille Pitchen , Thierry Reding , Richard Genoud , Greg Kroah-Hartman , Alan Stern CC: , , , , , , References: <20170915140411.31716-1-romain.izard.pro@gmail.com> <20170915140411.31716-8-romain.izard.pro@gmail.com> From: Nicolas Ferre Organization: microchip Message-ID: Date: Fri, 22 Sep 2017 14:42:37 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.3.0 MIME-Version: 1.0 In-Reply-To: <20170915140411.31716-8-romain.izard.pro@gmail.com> Content-Type: text/plain; charset="utf-8" Content-Language: en-US Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3994 Lines: 126 On 15/09/2017 at 16:04, Romain Izard wrote: > Save and restore registers for the PWM on suspend and resume, which > makes hibernation and backup modes possible. > > Signed-off-by: Romain Izard Seems good to me: Acked-by: Nicolas Ferre > --- > drivers/pwm/pwm-atmel-tcb.c | 63 +++++++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 61 insertions(+), 2 deletions(-) > > diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c > index 75db585a2a94..acd3ce8ecf3f 100644 > --- a/drivers/pwm/pwm-atmel-tcb.c > +++ b/drivers/pwm/pwm-atmel-tcb.c > @@ -37,11 +37,20 @@ struct atmel_tcb_pwm_device { > unsigned period; /* PWM period expressed in clk cycles */ > }; > > +struct atmel_tcb_channel { > + u32 enabled; > + u32 cmr; > + u32 ra; > + u32 rb; > + u32 rc; > +}; > + > struct atmel_tcb_pwm_chip { > struct pwm_chip chip; > spinlock_t lock; > struct atmel_tc *tc; > struct atmel_tcb_pwm_device *pwms[NPWM]; > + struct atmel_tcb_channel bkup[NPWM / 2]; > }; > > static inline struct atmel_tcb_pwm_chip *to_tcb_chip(struct pwm_chip *chip) > @@ -175,12 +184,15 @@ static void atmel_tcb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) > * Use software trigger to apply the new setting. > * If both PWM devices in this group are disabled we stop the clock. > */ > - if (!(cmr & (ATMEL_TC_ACPC | ATMEL_TC_BCPC))) > + if (!(cmr & (ATMEL_TC_ACPC | ATMEL_TC_BCPC))) { > __raw_writel(ATMEL_TC_SWTRG | ATMEL_TC_CLKDIS, > regs + ATMEL_TC_REG(group, CCR)); > - else > + tcbpwmc->bkup[group].enabled = 1; > + } else { > __raw_writel(ATMEL_TC_SWTRG, regs + > ATMEL_TC_REG(group, CCR)); > + tcbpwmc->bkup[group].enabled = 0; > + } > > spin_unlock(&tcbpwmc->lock); > } > @@ -263,6 +275,7 @@ static int atmel_tcb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) > /* Use software trigger to apply the new setting */ > __raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, > regs + ATMEL_TC_REG(group, CCR)); > + tcbpwmc->bkup[group].enabled = 1; > spin_unlock(&tcbpwmc->lock); > return 0; > } > @@ -445,10 +458,56 @@ static const struct of_device_id atmel_tcb_pwm_dt_ids[] = { > }; > MODULE_DEVICE_TABLE(of, atmel_tcb_pwm_dt_ids); > > +#ifdef CONFIG_PM_SLEEP > +static int atmel_tcb_pwm_suspend(struct device *dev) > +{ > + struct platform_device *pdev = to_platform_device(dev); > + struct atmel_tcb_pwm_chip *tcbpwm = platform_get_drvdata(pdev); > + void __iomem *base = tcbpwm->tc->regs; > + int i; > + > + for (i = 0; i < (NPWM / 2); i++) { > + struct atmel_tcb_channel *chan = &tcbpwm->bkup[i]; > + > + chan->cmr = readl(base + ATMEL_TC_REG(i, CMR)); > + chan->ra = readl(base + ATMEL_TC_REG(i, RA)); > + chan->rb = readl(base + ATMEL_TC_REG(i, RB)); > + chan->rc = readl(base + ATMEL_TC_REG(i, RC)); > + } > + return 0; > +} > + > +static int atmel_tcb_pwm_resume(struct device *dev) > +{ > + struct platform_device *pdev = to_platform_device(dev); > + struct atmel_tcb_pwm_chip *tcbpwm = platform_get_drvdata(pdev); > + void __iomem *base = tcbpwm->tc->regs; > + int i; > + > + for (i = 0; i < (NPWM / 2); i++) { > + struct atmel_tcb_channel *chan = &tcbpwm->bkup[i]; > + > + writel(chan->cmr, base + ATMEL_TC_REG(i, CMR)); > + writel(chan->ra, base + ATMEL_TC_REG(i, RA)); > + writel(chan->rb, base + ATMEL_TC_REG(i, RB)); > + writel(chan->rc, base + ATMEL_TC_REG(i, RC)); > + if (chan->enabled) { > + writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, > + base + ATMEL_TC_REG(i, CCR)); > + } > + } > + return 0; > +} > +#endif > + > +static SIMPLE_DEV_PM_OPS(atmel_tcb_pwm_pm_ops, atmel_tcb_pwm_suspend, > + atmel_tcb_pwm_resume); > + > static struct platform_driver atmel_tcb_pwm_driver = { > .driver = { > .name = "atmel-tcb-pwm", > .of_match_table = atmel_tcb_pwm_dt_ids, > + .pm = &atmel_tcb_pwm_pm_ops, > }, > .probe = atmel_tcb_pwm_probe, > .remove = atmel_tcb_pwm_remove, > -- Nicolas Ferre