From patchwork Tue Apr 2 12:40:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Belloni X-Patchwork-Id: 10881557 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 57FD417EE for ; Tue, 2 Apr 2019 12:41:16 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3E09520174 for ; Tue, 2 Apr 2019 12:41:16 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 320D9288B6; Tue, 2 Apr 2019 12:41:16 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3176120174 for ; Tue, 2 Apr 2019 12:41:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730401AbfDBMk0 (ORCPT ); Tue, 2 Apr 2019 08:40:26 -0400 Received: from relay12.mail.gandi.net ([217.70.178.232]:38275 "EHLO relay12.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729060AbfDBMkY (ORCPT ); Tue, 2 Apr 2019 08:40:24 -0400 Received: from localhost (alyon-652-1-60-19.w109-213.abo.wanadoo.fr [109.213.83.19]) (Authenticated sender: alexandre.belloni@bootlin.com) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 9668520000C; Tue, 2 Apr 2019 12:40:20 +0000 (UTC) From: Alexandre Belloni To: Stephen Boyd Cc: Nicolas Ferre , Claudiu Beznea , Michael Turquette , linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 01/10] clk: at91: sckc: add support to specify registers bit offsets Date: Tue, 2 Apr 2019 14:40:07 +0200 Message-Id: <20190402124016.20558-2-alexandre.belloni@bootlin.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190402124016.20558-1-alexandre.belloni@bootlin.com> References: <20190402124016.20558-1-alexandre.belloni@bootlin.com> MIME-Version: 1.0 Sender: linux-clk-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-clk@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Claudiu Beznea Different IPs uses different offsets in registers for the same functionality, thus adapt the driver to support this. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/sckc.c | 112 +++++++++++++++++++++++++++------------- 1 file changed, 77 insertions(+), 35 deletions(-) diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index ab6ecefc49ad..b7163d3a2269 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -22,15 +22,25 @@ #define SLOWCK_SW_TIME_USEC ((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \ SLOW_CLOCK_FREQ) -#define AT91_SCKC_CR 0x00 -#define AT91_SCKC_RCEN (1 << 0) -#define AT91_SCKC_OSC32EN (1 << 1) -#define AT91_SCKC_OSC32BYP (1 << 2) -#define AT91_SCKC_OSCSEL (1 << 3) +#define AT91_SCKC_CR 0x00 +#define AT91_SCKC_RCEN(off) (1 << (off)->cr_rcen) +#define AT91_SCKC_OSC32EN(off) (1 << (off)->cr_osc32en) +#define AT91_SCKC_OSC32BYP(off) (1 << (off)->cr_osc32byp) +#define AT91_SCKC_OSCSEL(off) (1 << (off)->cr_oscsel) + +#define AT91_SCKC_OFFSET_INVALID (32) + +struct clk_slow_offsets { + u8 cr_rcen; + u8 cr_osc32en; + u8 cr_osc32byp; + u8 cr_oscsel; +}; struct clk_slow_osc { struct clk_hw hw; void __iomem *sckcr; + const struct clk_slow_offsets *offsets; unsigned long startup_usec; }; @@ -39,6 +49,7 @@ struct clk_slow_osc { struct clk_sama5d4_slow_osc { struct clk_hw hw; void __iomem *sckcr; + const struct clk_slow_offsets *offsets; unsigned long startup_usec; bool prepared; }; @@ -48,6 +59,7 @@ struct clk_sama5d4_slow_osc { struct clk_slow_rc_osc { struct clk_hw hw; void __iomem *sckcr; + const struct clk_slow_offsets *offsets; unsigned long frequency; unsigned long accuracy; unsigned long startup_usec; @@ -58,6 +70,7 @@ struct clk_slow_rc_osc { struct clk_sam9x5_slow { struct clk_hw hw; void __iomem *sckcr; + const struct clk_slow_offsets *offsets; u8 parent; }; @@ -69,10 +82,11 @@ static int clk_slow_osc_prepare(struct clk_hw *hw) void __iomem *sckcr = osc->sckcr; u32 tmp = readl(sckcr); - if (tmp & (AT91_SCKC_OSC32BYP | AT91_SCKC_OSC32EN)) + if (tmp & (AT91_SCKC_OSC32BYP(osc->offsets) | + AT91_SCKC_OSC32EN(osc->offsets))) return 0; - writel(tmp | AT91_SCKC_OSC32EN, sckcr); + writel(tmp | AT91_SCKC_OSC32EN(osc->offsets), sckcr); usleep_range(osc->startup_usec, osc->startup_usec + 1); @@ -85,10 +99,10 @@ static void clk_slow_osc_unprepare(struct clk_hw *hw) void __iomem *sckcr = osc->sckcr; u32 tmp = readl(sckcr); - if (tmp & AT91_SCKC_OSC32BYP) + if (tmp & AT91_SCKC_OSC32BYP(osc->offsets)) return; - writel(tmp & ~AT91_SCKC_OSC32EN, sckcr); + writel(tmp & ~AT91_SCKC_OSC32EN(osc->offsets), sckcr); } static int clk_slow_osc_is_prepared(struct clk_hw *hw) @@ -97,10 +111,10 @@ static int clk_slow_osc_is_prepared(struct clk_hw *hw) void __iomem *sckcr = osc->sckcr; u32 tmp = readl(sckcr); - if (tmp & AT91_SCKC_OSC32BYP) + if (tmp & AT91_SCKC_OSC32BYP(osc->offsets)) return 1; - return !!(tmp & AT91_SCKC_OSC32EN); + return !!(tmp & AT91_SCKC_OSC32EN(osc->offsets)); } static const struct clk_ops slow_osc_ops = { @@ -114,7 +128,8 @@ at91_clk_register_slow_osc(void __iomem *sckcr, const char *name, const char *parent_name, unsigned long startup, - bool bypass) + bool bypass, + const struct clk_slow_offsets *offsets) { struct clk_slow_osc *osc; struct clk_hw *hw; @@ -137,9 +152,11 @@ at91_clk_register_slow_osc(void __iomem *sckcr, osc->hw.init = &init; osc->sckcr = sckcr; osc->startup_usec = startup; + osc->offsets = offsets; if (bypass) - writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP, + writel((readl(sckcr) & ~AT91_SCKC_OSC32EN(osc->offsets)) | + AT91_SCKC_OSC32BYP(osc->offsets), sckcr); hw = &osc->hw; @@ -153,7 +170,8 @@ at91_clk_register_slow_osc(void __iomem *sckcr, } static void __init -of_at91sam9x5_clk_slow_osc_setup(struct device_node *np, void __iomem *sckcr) +of_at91sam9x5_clk_slow_osc_setup(struct device_node *np, void __iomem *sckcr, + const struct clk_slow_offsets *offsets) { struct clk_hw *hw; const char *parent_name; @@ -167,7 +185,7 @@ of_at91sam9x5_clk_slow_osc_setup(struct device_node *np, void __iomem *sckcr) bypass = of_property_read_bool(np, "atmel,osc-bypass"); hw = at91_clk_register_slow_osc(sckcr, name, parent_name, startup, - bypass); + bypass, offsets); if (IS_ERR(hw)) return; @@ -195,7 +213,7 @@ static int clk_slow_rc_osc_prepare(struct clk_hw *hw) struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); void __iomem *sckcr = osc->sckcr; - writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr); + writel(readl(sckcr) | AT91_SCKC_RCEN(osc->offsets), sckcr); usleep_range(osc->startup_usec, osc->startup_usec + 1); @@ -207,14 +225,14 @@ static void clk_slow_rc_osc_unprepare(struct clk_hw *hw) struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); void __iomem *sckcr = osc->sckcr; - writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr); + writel(readl(sckcr) & ~AT91_SCKC_RCEN(osc->offsets), sckcr); } static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw) { struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); - return !!(readl(osc->sckcr) & AT91_SCKC_RCEN); + return !!(readl(osc->sckcr) & AT91_SCKC_RCEN(osc->offsets)); } static const struct clk_ops slow_rc_osc_ops = { @@ -230,7 +248,8 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr, const char *name, unsigned long frequency, unsigned long accuracy, - unsigned long startup) + unsigned long startup, + const struct clk_slow_offsets *offsets) { struct clk_slow_rc_osc *osc; struct clk_hw *hw; @@ -252,6 +271,7 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr, osc->hw.init = &init; osc->sckcr = sckcr; + osc->offsets = offsets; osc->frequency = frequency; osc->accuracy = accuracy; osc->startup_usec = startup; @@ -267,7 +287,8 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr, } static void __init -of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np, void __iomem *sckcr) +of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np, void __iomem *sckcr, + const struct clk_slow_offsets *offsets) { struct clk_hw *hw; u32 frequency = 0; @@ -281,7 +302,7 @@ of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np, void __iomem *sckcr) of_property_read_u32(np, "atmel,startup-time-usec", &startup); hw = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy, - startup); + startup, offsets); if (IS_ERR(hw)) return; @@ -299,14 +320,14 @@ static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index) tmp = readl(sckcr); - if ((!index && !(tmp & AT91_SCKC_OSCSEL)) || - (index && (tmp & AT91_SCKC_OSCSEL))) + if ((!index && !(tmp & AT91_SCKC_OSCSEL(slowck->offsets))) || + (index && (tmp & AT91_SCKC_OSCSEL(slowck->offsets)))) return 0; if (index) - tmp |= AT91_SCKC_OSCSEL; + tmp |= AT91_SCKC_OSCSEL(slowck->offsets); else - tmp &= ~AT91_SCKC_OSCSEL; + tmp &= ~AT91_SCKC_OSCSEL(slowck->offsets); writel(tmp, sckcr); @@ -319,7 +340,7 @@ static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw) { struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw); - return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL); + return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL(slowck->offsets)); } static const struct clk_ops sam9x5_slow_ops = { @@ -331,7 +352,8 @@ static struct clk_hw * __init at91_clk_register_sam9x5_slow(void __iomem *sckcr, const char *name, const char **parent_names, - int num_parents) + int num_parents, + const struct clk_slow_offsets *offsets) { struct clk_sam9x5_slow *slowck; struct clk_hw *hw; @@ -353,7 +375,8 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr, slowck->hw.init = &init; slowck->sckcr = sckcr; - slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL); + slowck->offsets = offsets; + slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL(slowck->offsets)); hw = &slowck->hw; ret = clk_hw_register(NULL, &slowck->hw); @@ -366,7 +389,8 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr, } static void __init -of_at91sam9x5_clk_slow_setup(struct device_node *np, void __iomem *sckcr) +of_at91sam9x5_clk_slow_setup(struct device_node *np, void __iomem *sckcr, + const struct clk_slow_offsets *offsets) { struct clk_hw *hw; const char *parent_names[2]; @@ -382,7 +406,7 @@ of_at91sam9x5_clk_slow_setup(struct device_node *np, void __iomem *sckcr) of_property_read_string(np, "clock-output-names", &name); hw = at91_clk_register_sam9x5_slow(sckcr, name, parent_names, - num_parents); + num_parents, offsets); if (IS_ERR(hw)) return; @@ -406,10 +430,18 @@ static const struct of_device_id sckc_clk_ids[] __initconst = { { /*sentinel*/ } }; +static const struct clk_slow_offsets at91sam9x5_offsets = { + .cr_rcen = 0, + .cr_osc32en = 1, + .cr_osc32byp = 2, + .cr_oscsel = 3, +}; + static void __init of_at91sam9x5_sckc_setup(struct device_node *np) { struct device_node *childnp; - void (*clk_setup)(struct device_node *, void __iomem *); + void (*clk_setup)(struct device_node *np, void __iomem *io, + const struct clk_slow_offsets *offsets); const struct of_device_id *clk_id; void __iomem *regbase = of_iomap(np, 0); @@ -421,7 +453,7 @@ static void __init of_at91sam9x5_sckc_setup(struct device_node *np) if (!clk_id) continue; clk_setup = clk_id->data; - clk_setup(childnp, regbase); + clk_setup(childnp, regbase, &at91sam9x5_offsets); } } CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc", @@ -438,7 +470,7 @@ static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw) * Assume that if it has already been selected (for example by the * bootloader), enough time has aready passed. */ - if ((readl(osc->sckcr) & AT91_SCKC_OSCSEL)) { + if ((readl(osc->sckcr) & AT91_SCKC_OSCSEL(osc->offsets))) { osc->prepared = true; return 0; } @@ -461,6 +493,13 @@ static const struct clk_ops sama5d4_slow_osc_ops = { .is_prepared = clk_sama5d4_slow_osc_is_prepared, }; +static const struct clk_slow_offsets at91sama5d4_offsets = { + .cr_rcen = AT91_SCKC_OFFSET_INVALID, + .cr_osc32en = AT91_SCKC_OFFSET_INVALID, + .cr_osc32byp = AT91_SCKC_OFFSET_INVALID, + .cr_oscsel = 3, +}; + static void __init of_sama5d4_sckc_setup(struct device_node *np) { void __iomem *regbase = of_iomap(np, 0); @@ -498,9 +537,11 @@ static void __init of_sama5d4_sckc_setup(struct device_node *np) osc->hw.init = &init; osc->sckcr = regbase; osc->startup_usec = 1200000; + osc->offsets = &at91sama5d4_offsets; if (bypass) - writel((readl(regbase) | AT91_SCKC_OSC32BYP), regbase); + writel((readl(regbase) | AT91_SCKC_OSC32BYP(osc->offsets)), + regbase); hw = &osc->hw; ret = clk_hw_register(NULL, &osc->hw); @@ -509,7 +550,8 @@ static void __init of_sama5d4_sckc_setup(struct device_node *np) return; } - hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2); + hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2, + &at91sama5d4_offsets); if (IS_ERR(hw)) return; From patchwork Tue Apr 2 12:40:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Belloni X-Patchwork-Id: 10881559 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0567313B5 for ; Tue, 2 Apr 2019 12:41:17 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E4CD428898 for ; Tue, 2 Apr 2019 12:41:16 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D8239288AF; Tue, 2 Apr 2019 12:41:16 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EB77228898 for ; Tue, 2 Apr 2019 12:41:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730321AbfDBMkZ (ORCPT ); Tue, 2 Apr 2019 08:40:25 -0400 Received: from relay11.mail.gandi.net ([217.70.178.231]:35827 "EHLO relay11.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725959AbfDBMkZ (ORCPT ); Tue, 2 Apr 2019 08:40:25 -0400 Received: from localhost (alyon-652-1-60-19.w109-213.abo.wanadoo.fr [109.213.83.19]) (Authenticated sender: alexandre.belloni@bootlin.com) by relay11.mail.gandi.net (Postfix) with ESMTPSA id 3DF18100002; Tue, 2 Apr 2019 12:40:22 +0000 (UTC) From: Alexandre Belloni To: Stephen Boyd Cc: Nicolas Ferre , Claudiu Beznea , Michael Turquette , linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 02/10] clk: at91: sckc: add support for SAM9X60 Date: Tue, 2 Apr 2019 14:40:08 +0200 Message-Id: <20190402124016.20558-3-alexandre.belloni@bootlin.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190402124016.20558-1-alexandre.belloni@bootlin.com> References: <20190402124016.20558-1-alexandre.belloni@bootlin.com> MIME-Version: 1.0 Sender: linux-clk-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-clk@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Claudiu Beznea Add support for SAM9X60. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/sckc.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index b7163d3a2269..b3075c51d260 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -459,6 +459,36 @@ static void __init of_at91sam9x5_sckc_setup(struct device_node *np) CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc", of_at91sam9x5_sckc_setup); +static const struct clk_slow_offsets at91sam9x60_offsets = { + .cr_rcen = AT91_SCKC_OFFSET_INVALID, + .cr_osc32en = 1, + .cr_osc32byp = 2, + .cr_oscsel = 24, +}; + +static void __init of_at91sam9x60_sckc_setup(struct device_node *np) +{ + struct device_node *childnp; + void (*clk_setup)(struct device_node *np, void __iomem *io, + const struct clk_slow_offsets *offsets); + const struct of_device_id *clk_id; + void __iomem *regbase = of_iomap(np, 0); + + if (!regbase) + return; + + for_each_child_of_node(np, childnp) { + clk_id = of_match_node(sckc_clk_ids, childnp); + if (!clk_id) + continue; + clk_setup = clk_id->data; + clk_setup(childnp, regbase, &at91sam9x60_offsets); + } +} + +CLK_OF_DECLARE(at91sam9x60_clk_sckc, "microchip,sam9x60-sckc", + of_at91sam9x60_sckc_setup); + static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw) { struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw); From patchwork Tue Apr 2 12:40:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Belloni X-Patchwork-Id: 10881553 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3D88013B5 for ; Tue, 2 Apr 2019 12:41:11 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 27DFB28898 for ; Tue, 2 Apr 2019 12:41:11 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1BA47288AF; Tue, 2 Apr 2019 12:41:11 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C98D328898 for ; Tue, 2 Apr 2019 12:41:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730077AbfDBMlE (ORCPT ); Tue, 2 Apr 2019 08:41:04 -0400 Received: from relay11.mail.gandi.net ([217.70.178.231]:49485 "EHLO relay11.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730317AbfDBMk0 (ORCPT ); Tue, 2 Apr 2019 08:40:26 -0400 Received: from localhost (alyon-652-1-60-19.w109-213.abo.wanadoo.fr [109.213.83.19]) (Authenticated sender: alexandre.belloni@bootlin.com) by relay11.mail.gandi.net (Postfix) with ESMTPSA id 0B69D100012; Tue, 2 Apr 2019 12:40:23 +0000 (UTC) From: Alexandre Belloni To: Stephen Boyd Cc: Nicolas Ferre , Claudiu Beznea , Michael Turquette , linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 03/10] dt-bindings: clk: at91: add bindings for SAM9X60's slow clock controller Date: Tue, 2 Apr 2019 14:40:09 +0200 Message-Id: <20190402124016.20558-4-alexandre.belloni@bootlin.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190402124016.20558-1-alexandre.belloni@bootlin.com> References: <20190402124016.20558-1-alexandre.belloni@bootlin.com> MIME-Version: 1.0 Sender: linux-clk-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-clk@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Claudiu Beznea Add bindings for SAM9X60's slow clock controller. Signed-off-by: Claudiu Beznea --- Documentation/devicetree/bindings/clock/at91-clock.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/clock/at91-clock.txt b/Documentation/devicetree/bindings/clock/at91-clock.txt index e9f70fcdfe80..ce1d21102428 100644 --- a/Documentation/devicetree/bindings/clock/at91-clock.txt +++ b/Documentation/devicetree/bindings/clock/at91-clock.txt @@ -9,7 +9,8 @@ Slow Clock controller: Required properties: - compatible : shall be one of the following: "atmel,at91sam9x5-sckc" or - "atmel,sama5d4-sckc": + "atmel,sama5d4-sckc" or + "microchip,sam9x60-sckc": at91 SCKC (Slow Clock Controller) This node contains the slow clock definitions. From patchwork Tue Apr 2 12:40:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Belloni X-Patchwork-Id: 10881551 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D82DE184E for ; Tue, 2 Apr 2019 12:41:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C314E20174 for ; Tue, 2 Apr 2019 12:41:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B6A872889B; Tue, 2 Apr 2019 12:41:04 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E7F9028898 for ; Tue, 2 Apr 2019 12:41:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730851AbfDBMka (ORCPT ); Tue, 2 Apr 2019 08:40:30 -0400 Received: from relay8-d.mail.gandi.net ([217.70.183.201]:40967 "EHLO relay8-d.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729060AbfDBMk3 (ORCPT ); Tue, 2 Apr 2019 08:40:29 -0400 X-Originating-IP: 109.213.83.19 Received: from localhost (alyon-652-1-60-19.w109-213.abo.wanadoo.fr [109.213.83.19]) (Authenticated sender: alexandre.belloni@bootlin.com) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 97B3A1BF203; Tue, 2 Apr 2019 12:40:25 +0000 (UTC) From: Alexandre Belloni To: Stephen Boyd Cc: Nicolas Ferre , Claudiu Beznea , Michael Turquette , linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Alexandre Belloni Subject: [PATCH v2 04/10] clk: at91: allow configuring peripheral PCR layout Date: Tue, 2 Apr 2019 14:40:10 +0200 Message-Id: <20190402124016.20558-5-alexandre.belloni@bootlin.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190402124016.20558-1-alexandre.belloni@bootlin.com> References: <20190402124016.20558-1-alexandre.belloni@bootlin.com> MIME-Version: 1.0 Sender: linux-clk-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-clk@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The PCR register actually changed layout for each SoC. By chance, this didn't have impact on sama5d[2-4] support but since sama5d3, PID is seven bits wide and sama5d4 and sama5d2 don't have DIV. For the DT backward compatibility, keep the layout as is. Signed-off-by: Alexandre Belloni --- drivers/clk/at91/at91sam9x5.c | 9 ++++++ drivers/clk/at91/clk-peripheral.c | 46 ++++++++++++++++--------------- drivers/clk/at91/dt-compat.c | 9 ++++++ drivers/clk/at91/pmc.h | 12 ++++++++ drivers/clk/at91/sama5d2.c | 9 ++++++ drivers/clk/at91/sama5d4.c | 8 ++++++ include/linux/clk/at91_pmc.h | 3 -- 7 files changed, 71 insertions(+), 25 deletions(-) diff --git a/drivers/clk/at91/at91sam9x5.c b/drivers/clk/at91/at91sam9x5.c index 3487e03d4bc6..f5cfcbd85f10 100644 --- a/drivers/clk/at91/at91sam9x5.c +++ b/drivers/clk/at91/at91sam9x5.c @@ -49,6 +49,13 @@ static const struct { { .n = "pck1", .p = "prog1", .id = 9 }, }; +static const struct clk_pcr_layout at91sam9x5_pcr_layout = { + .offset = 0x10c, + .cmd = BIT(12), + .pid_mask = GENMASK(5, 0), + .div_mask = GENMASK(17, 16), +}; + struct pck { char *n; u8 id; @@ -242,6 +249,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np, for (i = 0; i < ARRAY_SIZE(at91sam9x5_periphck); i++) { hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &at91sam9x5_pcr_layout, at91sam9x5_periphck[i].n, "masterck", at91sam9x5_periphck[i].id, @@ -254,6 +262,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np, for (i = 0; extra_pcks[i].id; i++) { hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &at91sam9x5_pcr_layout, extra_pcks[i].n, "masterck", extra_pcks[i].id, diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c index 65c1defa78e4..6b7748b9588a 100644 --- a/drivers/clk/at91/clk-peripheral.c +++ b/drivers/clk/at91/clk-peripheral.c @@ -8,6 +8,7 @@ * */ +#include #include #include #include @@ -23,9 +24,6 @@ DEFINE_SPINLOCK(pmc_pcr_lock); #define PERIPHERAL_ID_MAX 31 #define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX)) -#define PERIPHERAL_RSHIFT_MASK 0x3 -#define PERIPHERAL_RSHIFT(val) (((val) >> 16) & PERIPHERAL_RSHIFT_MASK) - #define PERIPHERAL_MAX_SHIFT 3 struct clk_peripheral { @@ -43,6 +41,7 @@ struct clk_sam9x5_peripheral { spinlock_t *lock; u32 id; u32 div; + const struct clk_pcr_layout *layout; bool auto_div; }; @@ -169,13 +168,13 @@ static int clk_sam9x5_peripheral_enable(struct clk_hw *hw) return 0; spin_lock_irqsave(periph->lock, flags); - regmap_write(periph->regmap, AT91_PMC_PCR, - (periph->id & AT91_PMC_PCR_PID_MASK)); - regmap_update_bits(periph->regmap, AT91_PMC_PCR, - AT91_PMC_PCR_DIV_MASK | AT91_PMC_PCR_CMD | + regmap_write(periph->regmap, periph->layout->offset, + (periph->id & periph->layout->pid_mask)); + regmap_update_bits(periph->regmap, periph->layout->offset, + periph->layout->div_mask | periph->layout->cmd | AT91_PMC_PCR_EN, - AT91_PMC_PCR_DIV(periph->div) | - AT91_PMC_PCR_CMD | + field_prep(periph->layout->div_mask, periph->div) | + periph->layout->cmd | AT91_PMC_PCR_EN); spin_unlock_irqrestore(periph->lock, flags); @@ -191,11 +190,11 @@ static void clk_sam9x5_peripheral_disable(struct clk_hw *hw) return; spin_lock_irqsave(periph->lock, flags); - regmap_write(periph->regmap, AT91_PMC_PCR, - (periph->id & AT91_PMC_PCR_PID_MASK)); - regmap_update_bits(periph->regmap, AT91_PMC_PCR, - AT91_PMC_PCR_EN | AT91_PMC_PCR_CMD, - AT91_PMC_PCR_CMD); + regmap_write(periph->regmap, periph->layout->offset, + (periph->id & periph->layout->pid_mask)); + regmap_update_bits(periph->regmap, periph->layout->offset, + AT91_PMC_PCR_EN | periph->layout->cmd, + periph->layout->cmd); spin_unlock_irqrestore(periph->lock, flags); } @@ -209,9 +208,9 @@ static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw) return 1; spin_lock_irqsave(periph->lock, flags); - regmap_write(periph->regmap, AT91_PMC_PCR, - (periph->id & AT91_PMC_PCR_PID_MASK)); - regmap_read(periph->regmap, AT91_PMC_PCR, &status); + regmap_write(periph->regmap, periph->layout->offset, + (periph->id & periph->layout->pid_mask)); + regmap_read(periph->regmap, periph->layout->offset, &status); spin_unlock_irqrestore(periph->lock, flags); return status & AT91_PMC_PCR_EN ? 1 : 0; @@ -229,13 +228,13 @@ clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw, return parent_rate; spin_lock_irqsave(periph->lock, flags); - regmap_write(periph->regmap, AT91_PMC_PCR, - (periph->id & AT91_PMC_PCR_PID_MASK)); - regmap_read(periph->regmap, AT91_PMC_PCR, &status); + regmap_write(periph->regmap, periph->layout->offset, + (periph->id & periph->layout->pid_mask)); + regmap_read(periph->regmap, periph->layout->offset, &status); spin_unlock_irqrestore(periph->lock, flags); if (status & AT91_PMC_PCR_EN) { - periph->div = PERIPHERAL_RSHIFT(status); + periph->div = field_get(periph->layout->div_mask, status); periph->auto_div = false; } else { clk_sam9x5_peripheral_autodiv(periph); @@ -328,6 +327,7 @@ static const struct clk_ops sam9x5_peripheral_ops = { struct clk_hw * __init at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, + const struct clk_pcr_layout *layout, const char *name, const char *parent_name, u32 id, const struct clk_range *range) { @@ -354,7 +354,9 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, periph->div = 0; periph->regmap = regmap; periph->lock = lock; - periph->auto_div = true; + if (layout->div_mask) + periph->auto_div = true; + periph->layout = layout; periph->range = *range; hw = &periph->hw; diff --git a/drivers/clk/at91/dt-compat.c b/drivers/clk/at91/dt-compat.c index b95bb4e2a927..aa09072f36db 100644 --- a/drivers/clk/at91/dt-compat.c +++ b/drivers/clk/at91/dt-compat.c @@ -93,6 +93,14 @@ CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup, of_sama5d2_clk_audio_pll_pmc_setup); #endif /* CONFIG_HAVE_AT91_AUDIO_PLL */ +static const struct clk_pcr_layout dt_pcr_layout = { + .offset = 0x10c, + .cmd = BIT(12), + .pid_mask = GENMASK(5, 0), + .div_mask = GENMASK(17, 16), + .gckcss_mask = GENMASK(10, 8), +}; + #ifdef CONFIG_HAVE_AT91_GENERATED_CLK #define GENERATED_SOURCE_MAX 6 @@ -448,6 +456,7 @@ of_at91_clk_periph_setup(struct device_node *np, u8 type) hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &dt_pcr_layout, name, parent_name, id, &range); diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 672a79bda88c..616c04588093 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -80,6 +80,17 @@ extern const struct clk_programmable_layout at91rm9200_programmable_layout; extern const struct clk_programmable_layout at91sam9g45_programmable_layout; extern const struct clk_programmable_layout at91sam9x5_programmable_layout; +struct clk_pcr_layout { + u32 offset; + u32 cmd; + u32 div_mask; + u32 gckcss_mask; + u32 pid_mask; +}; + +#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) +#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) + #define ndck(a, s) (a[s - 1].id + 1) #define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1) struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem, @@ -143,6 +154,7 @@ at91_clk_register_peripheral(struct regmap *regmap, const char *name, const char *parent_name, u32 id); struct clk_hw * __init at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, + const struct clk_pcr_layout *layout, const char *name, const char *parent_name, u32 id, const struct clk_range *range); diff --git a/drivers/clk/at91/sama5d2.c b/drivers/clk/at91/sama5d2.c index 1f70cb164b06..9d128bd60fee 100644 --- a/drivers/clk/at91/sama5d2.c +++ b/drivers/clk/at91/sama5d2.c @@ -28,6 +28,13 @@ static const struct clk_pll_characteristics plla_characteristics = { .out = plla_out, }; +static const struct clk_pcr_layout sama5d2_pcr_layout = { + .offset = 0x10c, + .cmd = BIT(12), + .gckcss_mask = GENMASK(10, 8), + .pid_mask = GENMASK(6, 0), +}; + static const struct { char *n; char *p; @@ -266,6 +273,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np) for (i = 0; i < ARRAY_SIZE(sama5d2_periphck); i++) { hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &sama5d2_pcr_layout, sama5d2_periphck[i].n, "masterck", sama5d2_periphck[i].id, @@ -278,6 +286,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np) for (i = 0; i < ARRAY_SIZE(sama5d2_periph32ck); i++) { hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &sama5d2_pcr_layout, sama5d2_periph32ck[i].n, "h32mxck", sama5d2_periph32ck[i].id, diff --git a/drivers/clk/at91/sama5d4.c b/drivers/clk/at91/sama5d4.c index b645a9d59cdb..840edca77821 100644 --- a/drivers/clk/at91/sama5d4.c +++ b/drivers/clk/at91/sama5d4.c @@ -28,6 +28,12 @@ static const struct clk_pll_characteristics plla_characteristics = { .out = plla_out, }; +static const struct clk_pcr_layout sama5d4_pcr_layout = { + .offset = 0x10c, + .cmd = BIT(12), + .pid_mask = GENMASK(6, 0), +}; + static const struct { char *n; char *p; @@ -232,6 +238,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np) for (i = 0; i < ARRAY_SIZE(sama5d4_periphck); i++) { hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &sama5d4_pcr_layout, sama5d4_periphck[i].n, "masterck", sama5d4_periphck[i].id, @@ -244,6 +251,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np) for (i = 0; i < ARRAY_SIZE(sama5d4_periph32ck); i++) { hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &sama5d4_pcr_layout, sama5d4_periph32ck[i].n, "h32mxck", sama5d4_periph32ck[i].id, diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h index 931ab05f771d..b97b8dcbffe6 100644 --- a/include/linux/clk/at91_pmc.h +++ b/include/linux/clk/at91_pmc.h @@ -191,9 +191,6 @@ #define AT91_PMC_PCR_GCKCSS_MASK (0x7 << AT91_PMC_PCR_GCKCSS_OFFSET) #define AT91_PMC_PCR_GCKCSS(n) ((n) << AT91_PMC_PCR_GCKCSS_OFFSET) /* GCK Clock Source Selection */ #define AT91_PMC_PCR_CMD (0x1 << 12) /* Command (read=0, write=1) */ -#define AT91_PMC_PCR_DIV_OFFSET 16 -#define AT91_PMC_PCR_DIV_MASK (0x3 << AT91_PMC_PCR_DIV_OFFSET) -#define AT91_PMC_PCR_DIV(n) ((n) << AT91_PMC_PCR_DIV_OFFSET) /* Divisor Value */ #define AT91_PMC_PCR_GCKDIV_OFFSET 20 #define AT91_PMC_PCR_GCKDIV_MASK (0xff << AT91_PMC_PCR_GCKDIV_OFFSET) #define AT91_PMC_PCR_GCKDIV(n) ((n) << AT91_PMC_PCR_GCKDIV_OFFSET) /* Generated Clock Divisor Value */ From patchwork Tue Apr 2 12:40:11 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Belloni X-Patchwork-Id: 10881549 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8390917EE for ; Tue, 2 Apr 2019 12:41:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6EF9620174 for ; Tue, 2 Apr 2019 12:41:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6321E288AF; Tue, 2 Apr 2019 12:41:04 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BD12920174 for ; Tue, 2 Apr 2019 12:41:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730524AbfDBMk6 (ORCPT ); Tue, 2 Apr 2019 08:40:58 -0400 Received: from relay8-d.mail.gandi.net ([217.70.183.201]:41927 "EHLO relay8-d.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730798AbfDBMka (ORCPT ); Tue, 2 Apr 2019 08:40:30 -0400 X-Originating-IP: 109.213.83.19 Received: from localhost (alyon-652-1-60-19.w109-213.abo.wanadoo.fr [109.213.83.19]) (Authenticated sender: alexandre.belloni@bootlin.com) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 1D2711BF205; Tue, 2 Apr 2019 12:40:27 +0000 (UTC) From: Alexandre Belloni To: Stephen Boyd Cc: Nicolas Ferre , Claudiu Beznea , Michael Turquette , linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Alexandre Belloni Subject: [PATCH v2 05/10] clk: at91: allow configuring generated PCR layout Date: Tue, 2 Apr 2019 14:40:11 +0200 Message-Id: <20190402124016.20558-6-alexandre.belloni@bootlin.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190402124016.20558-1-alexandre.belloni@bootlin.com> References: <20190402124016.20558-1-alexandre.belloni@bootlin.com> MIME-Version: 1.0 Sender: linux-clk-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-clk@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The PCR register layout for GCLKCSS is changing for the future SoCs, allow configuring it. Signed-off-by: Alexandre Belloni --- drivers/clk/at91/clk-generated.c | 48 +++++++++++++++++--------------- drivers/clk/at91/dt-compat.c | 3 +- drivers/clk/at91/pmc.h | 1 + drivers/clk/at91/sama5d2.c | 1 + include/linux/clk/at91_pmc.h | 7 +---- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c index 66e7f7baf958..5f18847965c1 100644 --- a/drivers/clk/at91/clk-generated.c +++ b/drivers/clk/at91/clk-generated.c @@ -11,6 +11,7 @@ * */ +#include #include #include #include @@ -31,6 +32,7 @@ struct clk_generated { spinlock_t *lock; u32 id; u32 gckdiv; + const struct clk_pcr_layout *layout; u8 parent_id; bool audio_pll_allowed; }; @@ -47,14 +49,14 @@ static int clk_generated_enable(struct clk_hw *hw) __func__, gck->gckdiv, gck->parent_id); spin_lock_irqsave(gck->lock, flags); - regmap_write(gck->regmap, AT91_PMC_PCR, - (gck->id & AT91_PMC_PCR_PID_MASK)); - regmap_update_bits(gck->regmap, AT91_PMC_PCR, - AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK | - AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN, - AT91_PMC_PCR_GCKCSS(gck->parent_id) | - AT91_PMC_PCR_CMD | - AT91_PMC_PCR_GCKDIV(gck->gckdiv) | + regmap_write(gck->regmap, gck->layout->offset, + (gck->id & gck->layout->pid_mask)); + regmap_update_bits(gck->regmap, gck->layout->offset, + AT91_PMC_PCR_GCKDIV_MASK | gck->layout->gckcss_mask | + gck->layout->cmd | AT91_PMC_PCR_GCKEN, + field_prep(gck->layout->gckcss_mask, gck->parent_id) | + gck->layout->cmd | + FIELD_PREP(AT91_PMC_PCR_GCKDIV_MASK, gck->gckdiv) | AT91_PMC_PCR_GCKEN); spin_unlock_irqrestore(gck->lock, flags); return 0; @@ -66,11 +68,11 @@ static void clk_generated_disable(struct clk_hw *hw) unsigned long flags; spin_lock_irqsave(gck->lock, flags); - regmap_write(gck->regmap, AT91_PMC_PCR, - (gck->id & AT91_PMC_PCR_PID_MASK)); - regmap_update_bits(gck->regmap, AT91_PMC_PCR, - AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN, - AT91_PMC_PCR_CMD); + regmap_write(gck->regmap, gck->layout->offset, + (gck->id & gck->layout->pid_mask)); + regmap_update_bits(gck->regmap, gck->layout->offset, + gck->layout->cmd | AT91_PMC_PCR_GCKEN, + gck->layout->cmd); spin_unlock_irqrestore(gck->lock, flags); } @@ -81,9 +83,9 @@ static int clk_generated_is_enabled(struct clk_hw *hw) unsigned int status; spin_lock_irqsave(gck->lock, flags); - regmap_write(gck->regmap, AT91_PMC_PCR, - (gck->id & AT91_PMC_PCR_PID_MASK)); - regmap_read(gck->regmap, AT91_PMC_PCR, &status); + regmap_write(gck->regmap, gck->layout->offset, + (gck->id & gck->layout->pid_mask)); + regmap_read(gck->regmap, gck->layout->offset, &status); spin_unlock_irqrestore(gck->lock, flags); return status & AT91_PMC_PCR_GCKEN ? 1 : 0; @@ -259,19 +261,18 @@ static void clk_generated_startup(struct clk_generated *gck) unsigned long flags; spin_lock_irqsave(gck->lock, flags); - regmap_write(gck->regmap, AT91_PMC_PCR, - (gck->id & AT91_PMC_PCR_PID_MASK)); - regmap_read(gck->regmap, AT91_PMC_PCR, &tmp); + regmap_write(gck->regmap, gck->layout->offset, + (gck->id & gck->layout->pid_mask)); + regmap_read(gck->regmap, gck->layout->offset, &tmp); spin_unlock_irqrestore(gck->lock, flags); - gck->parent_id = (tmp & AT91_PMC_PCR_GCKCSS_MASK) - >> AT91_PMC_PCR_GCKCSS_OFFSET; - gck->gckdiv = (tmp & AT91_PMC_PCR_GCKDIV_MASK) - >> AT91_PMC_PCR_GCKDIV_OFFSET; + gck->parent_id = field_get(gck->layout->gckcss_mask, tmp); + gck->gckdiv = FIELD_GET(AT91_PMC_PCR_GCKDIV_MASK, tmp); } struct clk_hw * __init at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, + const struct clk_pcr_layout *layout, const char *name, const char **parent_names, u8 num_parents, u8 id, bool pll_audio, const struct clk_range *range) @@ -298,6 +299,7 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, gck->lock = lock; gck->range = *range; gck->audio_pll_allowed = pll_audio; + gck->layout = layout; clk_generated_startup(gck); hw = &gck->hw; diff --git a/drivers/clk/at91/dt-compat.c b/drivers/clk/at91/dt-compat.c index aa09072f36db..aa1754eac59f 100644 --- a/drivers/clk/at91/dt-compat.c +++ b/drivers/clk/at91/dt-compat.c @@ -154,7 +154,8 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np) id == GCK_ID_CLASSD)) pll_audio = true; - hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name, + hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, + &dt_pcr_layout, name, parent_names, num_parents, id, pll_audio, &range); if (IS_ERR(hw)) diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 616c04588093..4027306b904c 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -116,6 +116,7 @@ at91_clk_register_audio_pll_pmc(struct regmap *regmap, const char *name, struct clk_hw * __init at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, + const struct clk_pcr_layout *layout, const char *name, const char **parent_names, u8 num_parents, u8 id, bool pll_audio, const struct clk_range *range); diff --git a/drivers/clk/at91/sama5d2.c b/drivers/clk/at91/sama5d2.c index 9d128bd60fee..096156850e08 100644 --- a/drivers/clk/at91/sama5d2.c +++ b/drivers/clk/at91/sama5d2.c @@ -305,6 +305,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np) parent_names[5] = "audiopll_pmcck"; for (i = 0; i < ARRAY_SIZE(sama5d2_gck); i++) { hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, + &sama5d2_pcr_layout, sama5d2_gck[i].n, parent_names, 6, sama5d2_gck[i].id, diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h index b97b8dcbffe6..31f00ebf1315 100644 --- a/include/linux/clk/at91_pmc.h +++ b/include/linux/clk/at91_pmc.h @@ -187,13 +187,8 @@ #define AT91_PMC_PCR 0x10c /* Peripheral Control Register [some SAM9 and SAMA5] */ #define AT91_PMC_PCR_PID_MASK 0x3f -#define AT91_PMC_PCR_GCKCSS_OFFSET 8 -#define AT91_PMC_PCR_GCKCSS_MASK (0x7 << AT91_PMC_PCR_GCKCSS_OFFSET) -#define AT91_PMC_PCR_GCKCSS(n) ((n) << AT91_PMC_PCR_GCKCSS_OFFSET) /* GCK Clock Source Selection */ #define AT91_PMC_PCR_CMD (0x1 << 12) /* Command (read=0, write=1) */ -#define AT91_PMC_PCR_GCKDIV_OFFSET 20 -#define AT91_PMC_PCR_GCKDIV_MASK (0xff << AT91_PMC_PCR_GCKDIV_OFFSET) -#define AT91_PMC_PCR_GCKDIV(n) ((n) << AT91_PMC_PCR_GCKDIV_OFFSET) /* Generated Clock Divisor Value */ +#define AT91_PMC_PCR_GCKDIV_MASK GENMASK(27, 20) #define AT91_PMC_PCR_EN (0x1 << 28) /* Enable */ #define AT91_PMC_PCR_GCKEN (0x1 << 29) /* GCK Enable */ From patchwork Tue Apr 2 12:40:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Belloni X-Patchwork-Id: 10881547 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9D73C13B5 for ; Tue, 2 Apr 2019 12:40:58 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 87454286CD for ; Tue, 2 Apr 2019 12:40:58 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7B99E287FB; Tue, 2 Apr 2019 12:40:58 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2285B286CD for ; Tue, 2 Apr 2019 12:40:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730933AbfDBMke (ORCPT ); Tue, 2 Apr 2019 08:40:34 -0400 Received: from relay8-d.mail.gandi.net ([217.70.183.201]:45641 "EHLO relay8-d.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729060AbfDBMkc (ORCPT ); Tue, 2 Apr 2019 08:40:32 -0400 X-Originating-IP: 109.213.83.19 Received: from localhost (alyon-652-1-60-19.w109-213.abo.wanadoo.fr [109.213.83.19]) (Authenticated sender: alexandre.belloni@bootlin.com) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 9E33E1BF212; Tue, 2 Apr 2019 12:40:29 +0000 (UTC) From: Alexandre Belloni To: Stephen Boyd Cc: Nicolas Ferre , Claudiu Beznea , Michael Turquette , linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Alexandre Belloni Subject: [PATCH v2 06/10] clk: at91: usb: Add sam9x60 support Date: Tue, 2 Apr 2019 14:40:12 +0200 Message-Id: <20190402124016.20558-7-alexandre.belloni@bootlin.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190402124016.20558-1-alexandre.belloni@bootlin.com> References: <20190402124016.20558-1-alexandre.belloni@bootlin.com> MIME-Version: 1.0 Sender: linux-clk-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-clk@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The sam9x60 USB clock supports four different parents, ensure they can be selected. Signed-off-by: Alexandre Belloni --- drivers/clk/at91/clk-usb.c | 33 +++++++++++++++++++++++++++------ drivers/clk/at91/pmc.h | 3 +++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index 79ee1c760f2a..ebc37ee33518 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c @@ -23,9 +23,13 @@ #define RM9200_USB_DIV_SHIFT 28 #define RM9200_USB_DIV_TAB_SIZE 4 +#define SAM9X5_USBS_MASK GENMASK(0, 0) +#define SAM9X60_USBS_MASK GENMASK(1, 0) + struct at91sam9x5_clk_usb { struct clk_hw hw; struct regmap *regmap; + u32 usbs_mask; }; #define to_at91sam9x5_clk_usb(hw) \ @@ -111,8 +115,7 @@ static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index) if (index > 1) return -EINVAL; - regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS, - index ? AT91_PMC_USBS : 0); + regmap_update_bits(usb->regmap, AT91_PMC_USB, usb->usbs_mask, index); return 0; } @@ -124,7 +127,7 @@ static u8 at91sam9x5_clk_usb_get_parent(struct clk_hw *hw) regmap_read(usb->regmap, AT91_PMC_USB, &usbr); - return usbr & AT91_PMC_USBS; + return usbr & usb->usbs_mask; } static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, @@ -190,9 +193,10 @@ static const struct clk_ops at91sam9n12_usb_ops = { .set_rate = at91sam9x5_clk_usb_set_rate, }; -struct clk_hw * __init -at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, - const char **parent_names, u8 num_parents) +static struct clk_hw * __init +_at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, + const char **parent_names, u8 num_parents, + u32 usbs_mask) { struct at91sam9x5_clk_usb *usb; struct clk_hw *hw; @@ -212,6 +216,7 @@ at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, usb->hw.init = &init; usb->regmap = regmap; + usb->usbs_mask = SAM9X5_USBS_MASK; hw = &usb->hw; ret = clk_hw_register(NULL, &usb->hw); @@ -223,6 +228,22 @@ at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, return hw; } +struct clk_hw * __init +at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, + const char **parent_names, u8 num_parents) +{ + return _at91sam9x5_clk_register_usb(regmap, name, parent_names, + num_parents, SAM9X5_USBS_MASK); +} + +struct clk_hw * __init +sam9x60_clk_register_usb(struct regmap *regmap, const char *name, + const char **parent_names, u8 num_parents) +{ + return _at91sam9x5_clk_register_usb(regmap, name, parent_names, + num_parents, SAM9X60_USBS_MASK); +} + struct clk_hw * __init at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name, const char *parent_name) diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 4027306b904c..44345e4ab1c9 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -194,6 +194,9 @@ struct clk_hw * __init at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name, const char *parent_name); struct clk_hw * __init +sam9x60_clk_register_usb(struct regmap *regmap, const char *name, + const char **parent_names, u8 num_parents); +struct clk_hw * __init at91rm9200_clk_register_usb(struct regmap *regmap, const char *name, const char *parent_name, const u32 *divisors); From patchwork Tue Apr 2 12:40:13 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Belloni X-Patchwork-Id: 10881533 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8D7A813B5 for ; Tue, 2 Apr 2019 12:40:36 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 77EEE286CD for ; Tue, 2 Apr 2019 12:40:36 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6B78528717; Tue, 2 Apr 2019 12:40:36 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F3B14286CD for ; Tue, 2 Apr 2019 12:40:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731024AbfDBMkf (ORCPT ); Tue, 2 Apr 2019 08:40:35 -0400 Received: from relay7-d.mail.gandi.net ([217.70.183.200]:36753 "EHLO relay7-d.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730850AbfDBMkf (ORCPT ); Tue, 2 Apr 2019 08:40:35 -0400 X-Originating-IP: 109.213.83.19 Received: from localhost (alyon-652-1-60-19.w109-213.abo.wanadoo.fr [109.213.83.19]) (Authenticated sender: alexandre.belloni@bootlin.com) by relay7-d.mail.gandi.net (Postfix) with ESMTPSA id 28D4A20007; Tue, 2 Apr 2019 12:40:31 +0000 (UTC) From: Alexandre Belloni To: Stephen Boyd Cc: Nicolas Ferre , Claudiu Beznea , Michael Turquette , linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Alexandre Belloni Subject: [PATCH v2 07/10] clk: at91: master: Add sam9x60 support Date: Tue, 2 Apr 2019 14:40:13 +0200 Message-Id: <20190402124016.20558-8-alexandre.belloni@bootlin.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190402124016.20558-1-alexandre.belloni@bootlin.com> References: <20190402124016.20558-1-alexandre.belloni@bootlin.com> MIME-Version: 1.0 Sender: linux-clk-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-clk@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The sam9x60 cpu clock is located at a different offset but is otherwise similar to the master clock. Signed-off-by: Alexandre Belloni --- drivers/clk/at91/clk-master.c | 8 +++++--- drivers/clk/at91/pmc.h | 1 + include/linux/clk/at91_pmc.h | 2 ++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c index eb53b4a8fab6..12b5bf4cc7bb 100644 --- a/drivers/clk/at91/clk-master.c +++ b/drivers/clk/at91/clk-master.c @@ -29,6 +29,7 @@ struct clk_master { struct regmap *regmap; const struct clk_master_layout *layout; const struct clk_master_characteristics *characteristics; + u32 mckr; }; static inline bool clk_master_ready(struct regmap *regmap) @@ -69,7 +70,7 @@ static unsigned long clk_master_recalc_rate(struct clk_hw *hw, master->characteristics; unsigned int mckr; - regmap_read(master->regmap, AT91_PMC_MCKR, &mckr); + regmap_read(master->regmap, master->layout->offset, &mckr); mckr &= layout->mask; pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK; @@ -95,7 +96,7 @@ static u8 clk_master_get_parent(struct clk_hw *hw) struct clk_master *master = to_clk_master(hw); unsigned int mckr; - regmap_read(master->regmap, AT91_PMC_MCKR, &mckr); + regmap_read(master->regmap, master->layout->offset, &mckr); return mckr & AT91_PMC_CSS; } @@ -147,13 +148,14 @@ at91_clk_register_master(struct regmap *regmap, return hw; } - const struct clk_master_layout at91rm9200_master_layout = { .mask = 0x31F, .pres_shift = 2, + .offset = AT91_PMC_MCKR, }; const struct clk_master_layout at91sam9x5_master_layout = { .mask = 0x373, .pres_shift = 4, + .offset = AT91_PMC_MCKR, }; diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 44345e4ab1c9..4a30c20f17f1 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -38,6 +38,7 @@ struct clk_range { #define CLK_RANGE(MIN, MAX) {.min = MIN, .max = MAX,} struct clk_master_layout { + u32 offset; u32 mask; u8 pres_shift; }; diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h index 31f00ebf1315..0c53f26ae3d3 100644 --- a/include/linux/clk/at91_pmc.h +++ b/include/linux/clk/at91_pmc.h @@ -74,6 +74,8 @@ #define AT91_PMC_USBDIV_4 (2 << 28) #define AT91_PMC_USB96M (1 << 28) /* Divider by 2 Enable (PLLB only) */ +#define AT91_PMC_CPU_CKR 0x28 /* CPU Clock Register */ + #define AT91_PMC_MCKR 0x30 /* Master Clock Register */ #define AT91_PMC_CSS (3 << 0) /* Master Clock Selection */ #define AT91_PMC_CSS_SLOW (0 << 0) From patchwork Tue Apr 2 12:40:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Belloni X-Patchwork-Id: 10881543 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4A78317EE for ; Tue, 2 Apr 2019 12:40:53 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 33C7620174 for ; Tue, 2 Apr 2019 12:40:53 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2797F2870D; Tue, 2 Apr 2019 12:40:53 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4A72D20174 for ; Tue, 2 Apr 2019 12:40:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731038AbfDBMkj (ORCPT ); Tue, 2 Apr 2019 08:40:39 -0400 Received: from relay7-d.mail.gandi.net ([217.70.183.200]:33501 "EHLO relay7-d.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729060AbfDBMki (ORCPT ); Tue, 2 Apr 2019 08:40:38 -0400 X-Originating-IP: 109.213.83.19 Received: from localhost (alyon-652-1-60-19.w109-213.abo.wanadoo.fr [109.213.83.19]) (Authenticated sender: alexandre.belloni@bootlin.com) by relay7-d.mail.gandi.net (Postfix) with ESMTPSA id 38CB320013; Tue, 2 Apr 2019 12:40:33 +0000 (UTC) From: Alexandre Belloni To: Stephen Boyd Cc: Nicolas Ferre , Claudiu Beznea , Michael Turquette , linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Alexandre Belloni Subject: [PATCH v2 08/10] clk: at91: add sam9x60 PLL driver Date: Tue, 2 Apr 2019 14:40:14 +0200 Message-Id: <20190402124016.20558-9-alexandre.belloni@bootlin.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190402124016.20558-1-alexandre.belloni@bootlin.com> References: <20190402124016.20558-1-alexandre.belloni@bootlin.com> MIME-Version: 1.0 Sender: linux-clk-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-clk@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The PLLs on the sam9x60 (PLLA and USB PLL) use a different register set and programming model than the previous SoCs. Signed-off-by: Alexandre Belloni --- drivers/clk/at91/Makefile | 1 + drivers/clk/at91/clk-sam9x60-pll.c | 330 +++++++++++++++++++++++++++++ drivers/clk/at91/pmc.h | 6 + 3 files changed, 337 insertions(+) create mode 100644 drivers/clk/at91/clk-sam9x60-pll.c diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index c75df1cad60e..0a30fc8dfcb0 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o +obj-$(CONFIG_HAVE_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o diff --git a/drivers/clk/at91/clk-sam9x60-pll.c b/drivers/clk/at91/clk-sam9x60-pll.c new file mode 100644 index 000000000000..34b817825b22 --- /dev/null +++ b/drivers/clk/at91/clk-sam9x60-pll.c @@ -0,0 +1,330 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Microchip Technology Inc. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "pmc.h" + +#define PMC_PLL_CTRL0 0xc +#define PMC_PLL_CTRL0_DIV_MSK GENMASK(7, 0) +#define PMC_PLL_CTRL0_ENPLL BIT(28) +#define PMC_PLL_CTRL0_ENPLLCK BIT(29) +#define PMC_PLL_CTRL0_ENLOCK BIT(31) + +#define PMC_PLL_CTRL1 0x10 +#define PMC_PLL_CTRL1_FRACR_MSK GENMASK(21, 0) +#define PMC_PLL_CTRL1_MUL_MSK GENMASK(30, 24) + +#define PMC_PLL_ACR 0x18 +#define PMC_PLL_ACR_DEFAULT 0x1b040010UL +#define PMC_PLL_ACR_UTMIVR BIT(12) +#define PMC_PLL_ACR_UTMIBG BIT(13) +#define PMC_PLL_ACR_LOOP_FILTER_MSK GENMASK(31, 24) + +#define PMC_PLL_UPDT 0x1c +#define PMC_PLL_UPDT_UPDATE BIT(8) + +#define PMC_PLL_ISR0 0xec + +#define PLL_DIV_MAX (FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, UINT_MAX) + 1) +#define UPLL_DIV 2 +#define PLL_MUL_MAX (FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1) + +#define PLL_MAX_ID 1 + +struct sam9x60_pll { + struct clk_hw hw; + struct regmap *regmap; + spinlock_t *lock; + const struct clk_pll_characteristics *characteristics; + u32 frac; + u8 id; + u8 div; + u16 mul; +}; + +#define to_sam9x60_pll(hw) container_of(hw, struct sam9x60_pll, hw) + +static inline bool sam9x60_pll_ready(struct regmap *regmap, int id) +{ + unsigned int status; + + regmap_read(regmap, PMC_PLL_ISR0, &status); + + return !!(status & BIT(id)); +} + +static int sam9x60_pll_prepare(struct clk_hw *hw) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(hw); + struct regmap *regmap = pll->regmap; + unsigned long flags; + u8 div; + u16 mul; + u32 val; + + spin_lock_irqsave(pll->lock, flags); + regmap_write(regmap, PMC_PLL_UPDT, pll->id); + + regmap_read(regmap, PMC_PLL_CTRL0, &val); + div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, val); + + regmap_read(regmap, PMC_PLL_CTRL1, &val); + mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, val); + + if (sam9x60_pll_ready(regmap, pll->id) && + (div == pll->div && mul == pll->mul)) { + spin_unlock_irqrestore(pll->lock, flags); + return 0; + } + + /* Recommended value for PMC_PLL_ACR */ + val = PMC_PLL_ACR_DEFAULT; + regmap_write(regmap, PMC_PLL_ACR, val); + + regmap_write(regmap, PMC_PLL_CTRL1, + FIELD_PREP(PMC_PLL_CTRL1_MUL_MSK, pll->mul)); + + if (pll->characteristics->upll) { + /* Enable the UTMI internal bandgap */ + val |= PMC_PLL_ACR_UTMIBG; + regmap_write(regmap, PMC_PLL_ACR, val); + + udelay(10); + + /* Enable the UTMI internal regulator */ + val |= PMC_PLL_ACR_UTMIVR; + regmap_write(regmap, PMC_PLL_ACR, val); + + udelay(10); + } + + regmap_update_bits(regmap, PMC_PLL_UPDT, + PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE); + + regmap_write(regmap, PMC_PLL_CTRL0, + PMC_PLL_CTRL0_ENLOCK | PMC_PLL_CTRL0_ENPLL | + PMC_PLL_CTRL0_ENPLLCK | pll->div); + + regmap_update_bits(regmap, PMC_PLL_UPDT, + PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE); + + while (!sam9x60_pll_ready(regmap, pll->id)) + cpu_relax(); + + spin_unlock_irqrestore(pll->lock, flags); + + return 0; +} + +static int sam9x60_pll_is_prepared(struct clk_hw *hw) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(hw); + + return sam9x60_pll_ready(pll->regmap, pll->id); +} + +static void sam9x60_pll_unprepare(struct clk_hw *hw) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(hw); + unsigned long flags; + + spin_lock_irqsave(pll->lock, flags); + + regmap_write(pll->regmap, PMC_PLL_UPDT, pll->id); + + regmap_update_bits(pll->regmap, PMC_PLL_CTRL0, + PMC_PLL_CTRL0_ENPLLCK, 0); + + regmap_update_bits(pll->regmap, PMC_PLL_UPDT, + PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE); + + regmap_update_bits(pll->regmap, PMC_PLL_CTRL0, PMC_PLL_CTRL0_ENPLL, 0); + + if (pll->characteristics->upll) + regmap_update_bits(pll->regmap, PMC_PLL_ACR, + PMC_PLL_ACR_UTMIBG | PMC_PLL_ACR_UTMIVR, 0); + + regmap_update_bits(pll->regmap, PMC_PLL_UPDT, + PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE); + + spin_unlock_irqrestore(pll->lock, flags); +} + +static unsigned long sam9x60_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(hw); + + return (parent_rate * (pll->mul + 1)) / (pll->div + 1); +} + +static long sam9x60_pll_get_best_div_mul(struct sam9x60_pll *pll, + unsigned long rate, + unsigned long parent_rate, + bool update) +{ + const struct clk_pll_characteristics *characteristics = + pll->characteristics; + unsigned long bestremainder = ULONG_MAX; + unsigned long maxdiv, mindiv, tmpdiv; + long bestrate = -ERANGE; + unsigned long bestdiv = 0; + unsigned long bestmul = 0; + unsigned long bestfrac = 0; + + if (rate < characteristics->output[0].min || + rate > characteristics->output[0].max) + return -ERANGE; + + if (!pll->characteristics->upll) { + mindiv = parent_rate / rate; + if (mindiv < 2) + mindiv = 2; + + maxdiv = DIV_ROUND_UP(parent_rate * PLL_MUL_MAX, rate); + if (maxdiv > PLL_DIV_MAX) + maxdiv = PLL_DIV_MAX; + } else { + mindiv = maxdiv = UPLL_DIV; + } + + for (tmpdiv = mindiv; tmpdiv <= maxdiv; tmpdiv++) { + unsigned long remainder; + unsigned long tmprate; + unsigned long tmpmul; + unsigned long tmpfrac = 0; + + /* + * Calculate the multiplier associated with the current + * divider that provide the closest rate to the requested one. + */ + tmpmul = mult_frac(rate, tmpdiv, parent_rate); + tmprate = mult_frac(parent_rate, tmpmul, tmpdiv); + remainder = rate - tmprate; + + if (remainder) { + tmpfrac = DIV_ROUND_CLOSEST_ULL((u64)remainder * tmpdiv * (1 << 22), + parent_rate); + + tmprate += DIV_ROUND_CLOSEST_ULL((u64)tmpfrac * parent_rate, + tmpdiv * (1 << 22)); + + if (tmprate > rate) + remainder = tmprate - rate; + else + remainder = rate - tmprate; + } + + /* + * Compare the remainder with the best remainder found until + * now and elect a new best multiplier/divider pair if the + * current remainder is smaller than the best one. + */ + if (remainder < bestremainder) { + bestremainder = remainder; + bestdiv = tmpdiv; + bestmul = tmpmul; + bestrate = tmprate; + bestfrac = tmpfrac; + } + + /* We've found a perfect match! */ + if (!remainder) + break; + } + + /* Check if bestrate is a valid output rate */ + if (bestrate < characteristics->output[0].min && + bestrate > characteristics->output[0].max) + return -ERANGE; + + if (update) { + pll->div = bestdiv - 1; + pll->mul = bestmul - 1; + pll->frac = bestfrac; + } + + return bestrate; +} + +static long sam9x60_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(hw); + + return sam9x60_pll_get_best_div_mul(pll, rate, *parent_rate, false); +} + +static int sam9x60_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(hw); + + return sam9x60_pll_get_best_div_mul(pll, rate, parent_rate, true); +} + +static const struct clk_ops pll_ops = { + .prepare = sam9x60_pll_prepare, + .unprepare = sam9x60_pll_unprepare, + .is_prepared = sam9x60_pll_is_prepared, + .recalc_rate = sam9x60_pll_recalc_rate, + .round_rate = sam9x60_pll_round_rate, + .set_rate = sam9x60_pll_set_rate, +}; + +struct clk_hw * __init +sam9x60_clk_register_pll(struct regmap *regmap, spinlock_t *lock, + const char *name, const char *parent_name, u8 id, + const struct clk_pll_characteristics *characteristics) +{ + struct sam9x60_pll *pll; + struct clk_hw *hw; + struct clk_init_data init; + unsigned int pllr; + int ret; + + if (id > PLL_MAX_ID) + return ERR_PTR(-EINVAL); + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &pll_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = CLK_SET_RATE_GATE; + + pll->id = id; + pll->hw.init = &init; + pll->characteristics = characteristics; + pll->regmap = regmap; + pll->lock = lock; + + regmap_write(regmap, PMC_PLL_UPDT, id); + regmap_read(regmap, PMC_PLL_CTRL0, &pllr); + pll->div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, pllr); + regmap_read(regmap, PMC_PLL_CTRL1, &pllr); + pll->mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, pllr); + + hw = &pll->hw; + ret = clk_hw_register(NULL, hw); + if (ret) { + kfree(pll); + hw = ERR_PTR(ret); + } + + return hw; +} + diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 4a30c20f17f1..fb9e9c4cdc8d 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -69,6 +69,7 @@ struct clk_pll_characteristics { struct clk_range *output; u16 *icpll; u8 *out; + u8 upll : 1; }; struct clk_programmable_layout { @@ -169,6 +170,11 @@ struct clk_hw * __init at91_clk_register_plldiv(struct regmap *regmap, const char *name, const char *parent_name); +struct clk_hw * __init +sam9x60_clk_register_pll(struct regmap *regmap, spinlock_t *lock, + const char *name, const char *parent_name, u8 id, + const struct clk_pll_characteristics *characteristics); + struct clk_hw * __init at91_clk_register_programmable(struct regmap *regmap, const char *name, const char **parent_names, u8 num_parents, u8 id, From patchwork Tue Apr 2 12:40:15 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Belloni X-Patchwork-Id: 10881537 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7C8E217EE for ; Tue, 2 Apr 2019 12:40:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6817C286CD for ; Tue, 2 Apr 2019 12:40:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5C4F128717; Tue, 2 Apr 2019 12:40:39 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1228A286CD for ; Tue, 2 Apr 2019 12:40:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730850AbfDBMki (ORCPT ); Tue, 2 Apr 2019 08:40:38 -0400 Received: from relay7-d.mail.gandi.net ([217.70.183.200]:44755 "EHLO relay7-d.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731055AbfDBMkh (ORCPT ); Tue, 2 Apr 2019 08:40:37 -0400 X-Originating-IP: 109.213.83.19 Received: from localhost (alyon-652-1-60-19.w109-213.abo.wanadoo.fr [109.213.83.19]) (Authenticated sender: alexandre.belloni@bootlin.com) by relay7-d.mail.gandi.net (Postfix) with ESMTPSA id 0165120011; Tue, 2 Apr 2019 12:40:34 +0000 (UTC) From: Alexandre Belloni To: Stephen Boyd Cc: Nicolas Ferre , Claudiu Beznea , Michael Turquette , linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Alexandre Belloni Subject: [PATCH v2 09/10] dt-bindings: clk: at91: add bindings for SAM9X60 pmc Date: Tue, 2 Apr 2019 14:40:15 +0200 Message-Id: <20190402124016.20558-10-alexandre.belloni@bootlin.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190402124016.20558-1-alexandre.belloni@bootlin.com> References: <20190402124016.20558-1-alexandre.belloni@bootlin.com> MIME-Version: 1.0 Sender: linux-clk-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-clk@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add SAM9X60 PMC compatible string. Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/clock/at91-clock.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/clock/at91-clock.txt b/Documentation/devicetree/bindings/clock/at91-clock.txt index ce1d21102428..e0e4fa67716f 100644 --- a/Documentation/devicetree/bindings/clock/at91-clock.txt +++ b/Documentation/devicetree/bindings/clock/at91-clock.txt @@ -37,7 +37,8 @@ For example: Power Management Controller (PMC): Required properties: -- compatible : shall be "atmel,-pmc", "syscon": +- compatible : shall be "atmel,-pmc", "syscon" or + "microchip,sam9x60-pmc" can be: at91rm9200, at91sam9260, at91sam9261, at91sam9263, at91sam9g45, at91sam9n12, at91sam9rl, at91sam9g15, at91sam9g25, at91sam9g35, at91sam9x25, at91sam9x35, at91sam9x5, From patchwork Tue Apr 2 12:40:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Belloni X-Patchwork-Id: 10881541 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4391513B5 for ; Tue, 2 Apr 2019 12:40:51 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2E69C20174 for ; Tue, 2 Apr 2019 12:40:51 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 22D592870D; Tue, 2 Apr 2019 12:40:51 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 56B9220174 for ; Tue, 2 Apr 2019 12:40:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729060AbfDBMkp (ORCPT ); Tue, 2 Apr 2019 08:40:45 -0400 Received: from relay5-d.mail.gandi.net ([217.70.183.197]:36633 "EHLO relay5-d.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731124AbfDBMko (ORCPT ); Tue, 2 Apr 2019 08:40:44 -0400 X-Originating-IP: 109.213.83.19 Received: from localhost (alyon-652-1-60-19.w109-213.abo.wanadoo.fr [109.213.83.19]) (Authenticated sender: alexandre.belloni@bootlin.com) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 975171C0019; Tue, 2 Apr 2019 12:40:36 +0000 (UTC) From: Alexandre Belloni To: Stephen Boyd Cc: Nicolas Ferre , Claudiu Beznea , Michael Turquette , linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Alexandre Belloni Subject: [PATCH v2 10/10] clk: at91: add sam9x60 pmc driver Date: Tue, 2 Apr 2019 14:40:16 +0200 Message-Id: <20190402124016.20558-11-alexandre.belloni@bootlin.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190402124016.20558-1-alexandre.belloni@bootlin.com> References: <20190402124016.20558-1-alexandre.belloni@bootlin.com> MIME-Version: 1.0 Sender: linux-clk-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-clk@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add a driver for the PMC clocks of the sam9c60. Signed-off-by: Alexandre Belloni --- drivers/clk/at91/Makefile | 1 + drivers/clk/at91/sam9x60.c | 307 +++++++++++++++++++++++++++++++++++++ 2 files changed, 308 insertions(+) create mode 100644 drivers/clk/at91/sam9x60.c diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 0a30fc8dfcb0..3732241352ce 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -16,5 +16,6 @@ obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o obj-$(CONFIG_HAVE_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o +obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c new file mode 100644 index 000000000000..22bf51c55bdc --- /dev/null +++ b/drivers/clk/at91/sam9x60.c @@ -0,0 +1,307 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +#include + +#include "pmc.h" + +DEFINE_SPINLOCK(pmc_pll_lock); + +static const struct clk_master_characteristics mck_characteristics = { + .output = { .min = 140000000, .max = 200000000 }, + .divisors = { 1, 2, 4, 3 }, + .have_div3_pres = 1, +}; + +static const struct clk_master_layout sam9x60_master_layout = { + .mask = 0x373, + .pres_shift = 4, + .offset = 0x28, +}; + +static struct clk_range plla_outputs[] = { + { .min = 300000000, .max = 600000000 }, +}; + +static const struct clk_pll_characteristics plla_characteristics = { + .input = { .min = 12000000, .max = 48000000 }, + .num_output = ARRAY_SIZE(plla_outputs), + .output = plla_outputs, +}; + +static struct clk_range upll_outputs[] = { + { .min = 300000000, .max = 500000000 }, +}; + +static const struct clk_pll_characteristics upll_characteristics = { + .input = { .min = 12000000, .max = 48000000 }, + .num_output = ARRAY_SIZE(upll_outputs), + .output = upll_outputs, + .upll = true, +}; + +static const struct clk_programmable_layout sam9x60_programmable_layout = { + .pres_shift = 8, + .css_mask = 0x1f, + .have_slck_mck = 0, +}; + +static const struct clk_pcr_layout sam9x60_pcr_layout = { + .offset = 0x88, + .cmd = BIT(31), + .gckcss_mask = GENMASK(12, 8), + .pid_mask = GENMASK(6, 0), +}; + +static const struct { + char *n; + char *p; + u8 id; +} sam9x60_systemck[] = { + { .n = "ddrck", .p = "masterck", .id = 2 }, + { .n = "uhpck", .p = "usbck", .id = 6 }, + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, + { .n = "qspick", .p = "masterck", .id = 19 }, +}; + +static const struct { + char *n; + u8 id; +} sam9x60_periphck[] = { + { .n = "pioA_clk", .id = 2, }, + { .n = "pioB_clk", .id = 3, }, + { .n = "pioC_clk", .id = 4, }, + { .n = "flex0_clk", .id = 5, }, + { .n = "flex1_clk", .id = 6, }, + { .n = "flex2_clk", .id = 7, }, + { .n = "flex3_clk", .id = 8, }, + { .n = "flex6_clk", .id = 9, }, + { .n = "flex7_clk", .id = 10, }, + { .n = "flex8_clk", .id = 11, }, + { .n = "sdmmc0_clk", .id = 12, }, + { .n = "flex4_clk", .id = 13, }, + { .n = "flex5_clk", .id = 14, }, + { .n = "flex9_clk", .id = 15, }, + { .n = "flex10_clk", .id = 16, }, + { .n = "tcb0_clk", .id = 17, }, + { .n = "pwm_clk", .id = 18, }, + { .n = "adc_clk", .id = 19, }, + { .n = "dma0_clk", .id = 20, }, + { .n = "matrix_clk", .id = 21, }, + { .n = "uhphs_clk", .id = 22, }, + { .n = "udphs_clk", .id = 23, }, + { .n = "macb0_clk", .id = 24, }, + { .n = "lcd_clk", .id = 25, }, + { .n = "sdmmc1_clk", .id = 26, }, + { .n = "macb1_clk", .id = 27, }, + { .n = "ssc_clk", .id = 28, }, + { .n = "can0_clk", .id = 29, }, + { .n = "can1_clk", .id = 30, }, + { .n = "flex11_clk", .id = 32, }, + { .n = "flex12_clk", .id = 33, }, + { .n = "i2s_clk", .id = 34, }, + { .n = "qspi_clk", .id = 35, }, + { .n = "gfx2d_clk", .id = 36, }, + { .n = "pit64b_clk", .id = 37, }, + { .n = "trng_clk", .id = 38, }, + { .n = "aes_clk", .id = 39, }, + { .n = "tdes_clk", .id = 40, }, + { .n = "sha_clk", .id = 41, }, + { .n = "classd_clk", .id = 42, }, + { .n = "isi_clk", .id = 43, }, + { .n = "pioD_clk", .id = 44, }, + { .n = "tcb1_clk", .id = 45, }, + { .n = "dbgu_clk", .id = 47, }, + { .n = "mpddr_clk", .id = 49, }, +}; + +static const struct { + char *n; + u8 id; + struct clk_range r; + bool pll; +} sam9x60_gck[] = { + { .n = "flex0_gclk", .id = 5, }, + { .n = "flex1_gclk", .id = 6, }, + { .n = "flex2_gclk", .id = 7, }, + { .n = "flex3_gclk", .id = 8, }, + { .n = "flex6_gclk", .id = 9, }, + { .n = "flex7_gclk", .id = 10, }, + { .n = "flex8_gclk", .id = 11, }, + { .n = "sdmmc0_gclk", .id = 12, .r = { .min = 0, .max = 105000000 }, }, + { .n = "flex4_gclk", .id = 13, }, + { .n = "flex5_gclk", .id = 14, }, + { .n = "flex9_gclk", .id = 15, }, + { .n = "flex10_gclk", .id = 16, }, + { .n = "tcb0_gclk", .id = 17, }, + { .n = "adc_gclk", .id = 19, }, + { .n = "lcd_gclk", .id = 25, .r = { .min = 0, .max = 140000000 }, }, + { .n = "sdmmc1_gclk", .id = 26, .r = { .min = 0, .max = 105000000 }, }, + { .n = "flex11_gclk", .id = 32, }, + { .n = "flex12_gclk", .id = 33, }, + { .n = "i2s_gclk", .id = 34, .r = { .min = 0, .max = 105000000 }, + .pll = true, }, + { .n = "pit64b_gclk", .id = 37, }, + { .n = "classd_gclk", .id = 42, .r = { .min = 0, .max = 100000000 }, + .pll = true, }, + { .n = "tcb1_gclk", .id = 45, }, + { .n = "dbgu_gclk", .id = 47, }, +}; + +static void __init sam9x60_pmc_setup(struct device_node *np) +{ + struct clk_range range = CLK_RANGE(0, 0); + const char *td_slck_name, *md_slck_name, *mainxtal_name; + struct pmc_data *sam9x60_pmc; + const char *parent_names[6]; + struct regmap *regmap; + struct clk_hw *hw; + int i; + bool bypass; + + i = of_property_match_string(np, "clock-names", "td_slck"); + if (i < 0) + return; + + td_slck_name = of_clk_get_parent_name(np, i); + + i = of_property_match_string(np, "clock-names", "md_slck"); + if (i < 0) + return; + + md_slck_name = of_clk_get_parent_name(np, i); + + i = of_property_match_string(np, "clock-names", "main_xtal"); + if (i < 0) + return; + mainxtal_name = of_clk_get_parent_name(np, i); + + regmap = syscon_node_to_regmap(np); + if (IS_ERR(regmap)) + return; + + sam9x60_pmc = pmc_data_allocate(PMC_MAIN + 1, + nck(sam9x60_systemck), + nck(sam9x60_periphck), + nck(sam9x60_gck)); + if (!sam9x60_pmc) + return; + + hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 24000000, + 50000000); + if (IS_ERR(hw)) + goto err_free; + + bypass = of_property_read_bool(np, "atmel,osc-bypass"); + + hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, + bypass); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = "main_rc_osc"; + parent_names[1] = "main_osc"; + hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2); + if (IS_ERR(hw)) + goto err_free; + + sam9x60_pmc->chws[PMC_MAIN] = hw; + + hw = sam9x60_clk_register_pll(regmap, &pmc_pll_lock, "pllack", + "mainck", 0, &plla_characteristics); + if (IS_ERR(hw)) + goto err_free; + + hw = sam9x60_clk_register_pll(regmap, &pmc_pll_lock, "upllck", + "main_osc", 1, &upll_characteristics); + if (IS_ERR(hw)) + goto err_free; + + sam9x60_pmc->chws[PMC_UTMI] = hw; + + parent_names[0] = md_slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "pllack"; + hw = at91_clk_register_master(regmap, "masterck", 3, parent_names, + &sam9x60_master_layout, + &mck_characteristics); + if (IS_ERR(hw)) + goto err_free; + + sam9x60_pmc->chws[PMC_MCK] = hw; + + parent_names[0] = "pllack"; + parent_names[1] = "upllck"; + parent_names[2] = "mainck"; + parent_names[3] = "mainck"; + hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 4); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = md_slck_name; + parent_names[1] = td_slck_name; + parent_names[2] = "mainck"; + parent_names[3] = "masterck"; + parent_names[4] = "pllack"; + parent_names[5] = "upllck"; + for (i = 0; i < 8; i++) { + char name[6]; + + snprintf(name, sizeof(name), "prog%d", i); + + hw = at91_clk_register_programmable(regmap, name, + parent_names, 6, i, + &sam9x60_programmable_layout); + if (IS_ERR(hw)) + goto err_free; + } + + for (i = 0; i < ARRAY_SIZE(sam9x60_systemck); i++) { + hw = at91_clk_register_system(regmap, sam9x60_systemck[i].n, + sam9x60_systemck[i].p, + sam9x60_systemck[i].id); + if (IS_ERR(hw)) + goto err_free; + + sam9x60_pmc->shws[sam9x60_systemck[i].id] = hw; + } + + for (i = 0; i < ARRAY_SIZE(sam9x60_periphck); i++) { + hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &sam9x60_pcr_layout, + sam9x60_periphck[i].n, + "masterck", + sam9x60_periphck[i].id, + &range); + if (IS_ERR(hw)) + goto err_free; + + sam9x60_pmc->phws[sam9x60_periphck[i].id] = hw; + } + + for (i = 0; i < ARRAY_SIZE(sam9x60_gck); i++) { + hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, + &sam9x60_pcr_layout, + sam9x60_gck[i].n, + parent_names, 6, + sam9x60_gck[i].id, + sam9x60_gck[i].pll, + &sam9x60_gck[i].r); + if (IS_ERR(hw)) + goto err_free; + + sam9x60_pmc->ghws[sam9x60_gck[i].id] = hw; + } + + of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sam9x60_pmc); + + return; + +err_free: + pmc_data_free(sam9x60_pmc); +} + +CLK_OF_DECLARE_DRIVER(sam9x60_pmc, "microchip,sam9x60-pmc", sam9x60_pmc_setup);