Received: by 10.192.165.148 with SMTP id m20csp3704207imm; Mon, 23 Apr 2018 10:52:03 -0700 (PDT) X-Google-Smtp-Source: AIpwx4/MDgoyPyXQ/b3+YEfYt51vXN7BcyCMvy4C2h1+QfyqUaPtYWgVQC8l66cTeuWWe7DL/hh9 X-Received: by 2002:a17:902:b68e:: with SMTP id c14-v6mr21717503pls.286.1524505923527; Mon, 23 Apr 2018 10:52:03 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1524505923; cv=none; d=google.com; s=arc-20160816; b=uUX6ofH8+NKToicNiG1Hi539YxZ7wwJNOMHghgpc52QyIiSHOAfkkMGIXEu7kou0yq xlP8oUm9iSFCu78fHAh1BrMKQtULV1YCS2245xN5EQizx2w4vfoeH9sJA9IJI4u37Rh5 3uA2WfeTqZkrB7SLKt/1QgVFomssnrfaY++WuGae3uhryhICTb8KosXJoiKiQ1C1RzkY dd5sjxc8vN2y34hVoQ8YcZLSWHIMaiuhFYAU0WEY1MoC4olWqfDpJ7bcC+3AOmMF7YIi OoiAlICPY0QjAUL3ostAdi1PbjfiNwdOMudwvoKgkz6zUzVCxHCeuP74L23WtiQL9VRw BhLg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=Wncy+4c0r0ibHzc/MEO6e4aitPu9iGGJ+6NKS//nfv8=; b=SX63Jk1q+PIh/ZYSemzNzUIghFBZASj+Gd4fhWcrQLmfgwnh8fDBb6jWM2NS/G519A 34hnz4GdbjKe/MJhz07H9FsZT55VsvvEeJgo2j1hsl/t+cypK8DyptTlUxKAr0MRj9RX +iH1msnNvxNFRVdmfpgNZh0Pux56RlLtMT0oWjoW1/1o9o3FO9/iQg5r8S8vrd8IHhpo 2urDAsPSIxm8QNyED8iUeu/1lcd6j3OeRWPXvDqS2MMs5E6W40Lr/Pd6hoi0c9pc7l3c JacxfjHofGwY3Ri+HV+o0yA4BYvT5dmHzX/I0IaJ2t0MWr+ZeY9sABSNbQKaNeYSLIyu TTQA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id o1-v6si11627672plb.220.2018.04.23.10.51.49; Mon, 23 Apr 2018 10:52:03 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932508AbeDWRuK (ORCPT + 99 others); Mon, 23 Apr 2018 13:50:10 -0400 Received: from muru.com ([72.249.23.125]:38378 "EHLO muru.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932320AbeDWRq2 (ORCPT ); Mon, 23 Apr 2018 13:46:28 -0400 Received: from hillo.muru.com (localhost [127.0.0.1]) by muru.com (Postfix) with ESMTP id 885B881AE; Mon, 23 Apr 2018 17:48:10 +0000 (UTC) From: Tony Lindgren To: linux-omap@vger.kernel.org Cc: Dave Gerlach , Greg Kroah-Hartman , Nishanth Menon , Suman Anna , Tero Kristo , linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Mark Rutland , Rob Herring , devicetree@vger.kernel.org Subject: [PATCH 09/16] bus: ti-sysc: Add handling for clkctrl opt clocks Date: Mon, 23 Apr 2018 10:45:42 -0700 Message-Id: <20180423174549.57412-10-tony@atomide.com> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180423174549.57412-1-tony@atomide.com> References: <20180423174549.57412-1-tony@atomide.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org There can be up to eight optional device functional gate gate clocks for each clkctrl instance in clkctrl register bits 8 to 15. Some of them are only needed for module level reset while others may always be needed during use. Let's add support for those and update the binding doc accordingly. Note that the optional clkctrl mux and divider clocks starting at bit 20 can be directly mapped to the child devices, and ti-sysc does not need to manage those. And as GPIOs need the optional clocks for reset, we can now add it with SYSC_QUIRK_OPT_CLKS_IN_RESET. Cc: Mark Rutland Cc: Rob Herring Cc: Tero Kristo Cc: devicetree@vger.kernel.org Signed-off-by: Tony Lindgren --- .../devicetree/bindings/bus/ti-sysc.txt | 6 +- drivers/bus/ti-sysc.c | 140 ++++++++++++++---- 2 files changed, 120 insertions(+), 26 deletions(-) diff --git a/Documentation/devicetree/bindings/bus/ti-sysc.txt b/Documentation/devicetree/bindings/bus/ti-sysc.txt --- a/Documentation/devicetree/bindings/bus/ti-sysc.txt +++ b/Documentation/devicetree/bindings/bus/ti-sysc.txt @@ -79,7 +79,11 @@ Optional properties: mode as for example omap4 L4_CFG_CLKCTRL - clock-names should contain at least "fck", and optionally also "ick" - depending on the SoC and the interconnect target module + depending on the SoC and the interconnect target module, + some interconnect target modules also need additional + optional clocks that can be specified as listed in TRM + for the related CLKCTRL register bits 8 to 15 such as + "dbclk" or "clk32k" depending on their role - ti,hwmods optional TI interconnect module name to use legacy hwmod platform data diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -32,10 +32,18 @@ static const char * const reg_names[] = { "rev", "sysc", "syss", }; enum sysc_clocks { SYSC_FCK, SYSC_ICK, + SYSC_OPTFCK0, + SYSC_OPTFCK1, + SYSC_OPTFCK2, + SYSC_OPTFCK3, + SYSC_OPTFCK4, + SYSC_OPTFCK5, + SYSC_OPTFCK6, + SYSC_OPTFCK7, SYSC_MAX_CLOCKS, }; -static const char * const clock_names[] = { "fck", "ick", }; +static const char * const clock_names[SYSC_ICK + 1] = { "fck", "ick", }; #define SYSC_IDLEMODE_MASK 3 #define SYSC_CLOCKACTIVITY_MASK 3 @@ -48,6 +56,8 @@ static const char * const clock_names[] = { "fck", "ick", }; * @module_va: virtual address of the interconnect target module * @offsets: register offsets from module base * @clocks: clocks used by the interconnect target module + * @clock_roles: clock role names for the found clocks + * @nr_clocks: number of clocks used by the interconnect target module * @legacy_mode: configured for legacy mode if set * @cap: interconnect target module capabilities * @cfg: interconnect target module configuration @@ -61,7 +71,9 @@ struct sysc { u32 module_size; void __iomem *module_va; int offsets[SYSC_MAX_REGS]; - struct clk *clocks[SYSC_MAX_CLOCKS]; + struct clk **clocks; + const char **clock_roles; + int nr_clocks; const char *legacy_mode; const struct sysc_capabilities *cap; struct sysc_config cfg; @@ -88,6 +100,11 @@ static u32 sysc_read(struct sysc *ddata, int offset) return readl_relaxed(ddata->module_va + offset); } +static bool sysc_opt_clks_needed(struct sysc *ddata) +{ + return !!(ddata->cfg.quirks & SYSC_QUIRK_OPT_CLKS_NEEDED); +} + static u32 sysc_read_revision(struct sysc *ddata) { int offset = ddata->offsets[SYSC_REVISION]; @@ -98,21 +115,28 @@ static u32 sysc_read_revision(struct sysc *ddata) return sysc_read(ddata, offset); } -static int sysc_get_one_clock(struct sysc *ddata, - enum sysc_clocks index) +static int sysc_get_one_clock(struct sysc *ddata, const char *name) { - const char *name; - int error; + int error, i, index = -ENODEV; + + if (!strncmp(clock_names[SYSC_FCK], name, 3)) + index = SYSC_FCK; + else if (!strncmp(clock_names[SYSC_ICK], name, 3)) + index = SYSC_ICK; + + if (index < 0) { + for (i = SYSC_OPTFCK0; i < SYSC_MAX_CLOCKS; i++) { + if (!clock_names[i]) { + index = i; + break; + } + } + } - switch (index) { - case SYSC_FCK: - break; - case SYSC_ICK: - break; - default: - return -EINVAL; + if (index < 0) { + dev_err(ddata->dev, "clock %s not added\n", name); + return index; } - name = clock_names[index]; ddata->clocks[index] = devm_clk_get(ddata->dev, name); if (IS_ERR(ddata->clocks[index])) { @@ -138,10 +162,50 @@ static int sysc_get_one_clock(struct sysc *ddata, static int sysc_get_clocks(struct sysc *ddata) { - int i, error; + struct device_node *np = ddata->dev->of_node; + struct property *prop; + const char *name; + int nr_fck = 0, nr_ick = 0, i, error = 0; - for (i = 0; i < SYSC_MAX_CLOCKS; i++) { - error = sysc_get_one_clock(ddata, i); + ddata->clock_roles = devm_kzalloc(ddata->dev, + sizeof(*ddata->clock_roles) * + SYSC_MAX_CLOCKS, + GFP_KERNEL); + if (!ddata->clock_roles) + return -ENOMEM; + + of_property_for_each_string(np, "clock-names", prop, name) { + if (!strncmp(clock_names[SYSC_FCK], name, 3)) + nr_fck++; + if (!strncmp(clock_names[SYSC_ICK], name, 3)) + nr_ick++; + ddata->clock_roles[ddata->nr_clocks] = name; + ddata->nr_clocks++; + } + + if (ddata->nr_clocks < 1) + return 0; + + if (ddata->nr_clocks > SYSC_MAX_CLOCKS) { + dev_err(ddata->dev, "too many clocks for %pOF\n", np); + + return -EINVAL; + } + + if (nr_fck > 1 || nr_ick > 1) { + dev_err(ddata->dev, "max one fck and ick for %pOF\n", np); + + return -EINVAL; + } + + ddata->clocks = devm_kzalloc(ddata->dev, + sizeof(*ddata->clocks) * ddata->nr_clocks, + GFP_KERNEL); + if (!ddata->clocks) + return -ENOMEM; + + for (i = 0; i < ddata->nr_clocks; i++) { + error = sysc_get_one_clock(ddata, ddata->clock_roles[i]); if (error && error != -ENOENT) return error; } @@ -533,9 +597,13 @@ static int __maybe_unused sysc_runtime_suspend(struct device *dev) goto idled; } - for (i = 0; i < SYSC_MAX_CLOCKS; i++) { + for (i = 0; i < ddata->nr_clocks; i++) { if (IS_ERR_OR_NULL(ddata->clocks[i])) continue; + + if (i >= SYSC_OPTFCK0 && !sysc_opt_clks_needed(ddata)) + break; + clk_disable(ddata->clocks[i]); } @@ -572,9 +640,13 @@ static int __maybe_unused sysc_runtime_resume(struct device *dev) goto awake; } - for (i = 0; i < SYSC_MAX_CLOCKS; i++) { + for (i = 0; i < ddata->nr_clocks; i++) { if (IS_ERR_OR_NULL(ddata->clocks[i])) continue; + + if (i >= SYSC_OPTFCK0 && !sysc_opt_clks_needed(ddata)) + break; + error = clk_enable(ddata->clocks[i]); if (error) return error; @@ -651,7 +723,7 @@ struct sysc_revision_quirk { static const struct sysc_revision_quirk sysc_revision_quirks[] = { /* These drivers need to be fixed to not use pm_runtime_irq_safe() */ SYSC_QUIRK("gpio", 0, 0, 0x10, 0x114, 0x50600801, 0xffffffff, - SYSC_QUIRK_LEGACY_IDLE), + SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_OPT_CLKS_IN_RESET), SYSC_QUIRK("mmu", 0, 0, 0x10, 0x14, 0x00000020, 0xffffffff, SYSC_QUIRK_LEGACY_IDLE), SYSC_QUIRK("mmu", 0, 0, 0x10, 0x14, 0x00000030, 0xffffffff, @@ -845,6 +917,26 @@ static int sysc_child_add_named_clock(struct sysc *ddata, return error; } +static int sysc_child_add_clocks(struct sysc *ddata, + struct device *child) +{ + int i, error; + + for (i = 0; i < ddata->nr_clocks; i++) { + error = sysc_child_add_named_clock(ddata, + child, + ddata->clock_roles[i]); + if (error && error != -EEXIST) { + dev_err(ddata->dev, "could not add child clock %s: %i\n", + ddata->clock_roles[i], error); + + return error; + } + } + + return 0; +} + static struct device_type sysc_device_type = { }; @@ -992,11 +1084,9 @@ static int sysc_notifier_call(struct notifier_block *nb, switch (event) { case BUS_NOTIFY_ADD_DEVICE: - error = sysc_child_add_named_clock(ddata, dev, - clock_names[SYSC_FCK]); - if (error && error != -EEXIST) - dev_warn(ddata->dev, "could not add %s fck: %i\n", - dev_name(dev), error); + error = sysc_child_add_clocks(ddata, dev); + if (error) + return error; sysc_legacy_idle_quirk(ddata, dev); break; default: -- 2.17.0