From patchwork Tue Oct 29 14:55:11 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3108421 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id B74CE9F3E2 for ; Tue, 29 Oct 2013 14:56:56 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id CF73B20136 for ; Tue, 29 Oct 2013 14:56:51 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C09162012C for ; Tue, 29 Oct 2013 14:56:46 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1VbAi8-0002yd-OL; Tue, 29 Oct 2013 14:56:01 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1VbAhw-0002mQ-DP; Tue, 29 Oct 2013 14:55:48 +0000 Received: from perceval.ideasonboard.com ([95.142.166.194]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1VbAhq-0002kM-6M for linux-arm-kernel@lists.infradead.org; Tue, 29 Oct 2013 14:55:44 +0000 Received: from avalon.ideasonboard.com (unknown [91.178.173.243]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 88A0835A6C; Tue, 29 Oct 2013 15:54:19 +0100 (CET) From: Laurent Pinchart To: linux-sh@vger.kernel.org Subject: [PATCH 3/3] clk: shmobile: Add R8A7790 clocks support Date: Tue, 29 Oct 2013 15:55:11 +0100 Message-Id: <1383058511-26046-4-git-send-email-laurent.pinchart+renesas@ideasonboard.com> X-Mailer: git-send-email 1.8.1.5 In-Reply-To: <1383058511-26046-1-git-send-email-laurent.pinchart+renesas@ideasonboard.com> References: <1383058511-26046-1-git-send-email-laurent.pinchart+renesas@ideasonboard.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20131029_105542_443442_7DD250CD X-CRM114-Status: GOOD ( 21.43 ) X-Spam-Score: -2.4 (--) Cc: devicetree@vger.kernel.org, Mike Turquette , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.7 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The R8A7790 has several clocks that are too custom to be supported in a generic driver. Those clocks can be divided in two categories: - Fixed rate clocks with multiplier and divisor set according to boot mode configuration - Custom divider clocks with SoC-specific divider values This driver supports both. Signed-off-by: Laurent Pinchart Acked-by: Kumar Gala --- .../bindings/clock/renesas,r8a7790-cpg-clocks.txt | 26 +++ drivers/clk/shmobile/Makefile | 1 + drivers/clk/shmobile/clk-r8a7790.c | 176 +++++++++++++++++++++ include/dt-bindings/clock/r8a7790-clock.h | 10 ++ include/linux/clk/shmobile.h | 19 +++ 5 files changed, 232 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/renesas,r8a7790-cpg-clocks.txt create mode 100644 drivers/clk/shmobile/clk-r8a7790.c create mode 100644 include/linux/clk/shmobile.h diff --git a/Documentation/devicetree/bindings/clock/renesas,r8a7790-cpg-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,r8a7790-cpg-clocks.txt new file mode 100644 index 0000000..d889917 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/renesas,r8a7790-cpg-clocks.txt @@ -0,0 +1,26 @@ +* Renesas R8A7790 Clock Pulse Generator (CPG) + +The CPG generates core clocks for the R8A7790. It includes three PLLs and +several fixed ratio dividers. + +Required Properties: + + - compatible: Must be "renesas,r8a7790-cpg-clocks" + - reg: Base address and length of the memory resource used by the CPG + - clocks: Reference to the parent clock + - #clock-cells: Must be 1 + - clock-output-names: The name of the clocks, must be "main", "pll1", + "pll3", "lb", "qspi", "sdh", "sd0", "sd1". + + +Example +------- + + cpg_clocks: cpg_clocks { + compatible = "renesas,r8a7790-cpg-clocks"; + reg = <0 0xe6150000 0 0x1000>; + clocks = <&extal_clk>; + #clock-cells = <1>; + clock-output-names = "main", "pll1", "pll3", "lb", + "qspi", "sdh", "sd0", "sd1"; + }; diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile index 3275c78..949f29e 100644 --- a/drivers/clk/shmobile/Makefile +++ b/drivers/clk/shmobile/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o +obj-$(CONFIG_ARCH_R8A7790) += clk-r8a7790.o obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-mstp.o diff --git a/drivers/clk/shmobile/clk-r8a7790.c b/drivers/clk/shmobile/clk-r8a7790.c new file mode 100644 index 0000000..2e76638 --- /dev/null +++ b/drivers/clk/shmobile/clk-r8a7790.c @@ -0,0 +1,176 @@ +/* + * r8a7790 Core CPG Clocks + * + * Copyright (C) 2013 Ideas On Board SPRL + * + * Contact: Laurent Pinchart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define CPG_NUM_CLOCKS (R8A7790_CLK_SD1 + 1) + +struct r8a7790_cpg { + struct clk_onecell_data data; + spinlock_t lock; + void __iomem *reg; +}; + +/* + * MD EXTAL PLL0 PLL1 PLL3 + * 14 13 19 (MHz) *1 *1 + *--------------------------------------------------- + * 0 0 0 15 x 1 x172/2 x208/2 x106 + * 0 0 1 15 x 1 x172/2 x208/2 x88 + * 0 1 0 20 x 1 x130/2 x156/2 x80 + * 0 1 1 20 x 1 x130/2 x156/2 x66 + * 1 0 0 26 / 2 x200/2 x240/2 x122 + * 1 0 1 26 / 2 x200/2 x240/2 x102 + * 1 1 0 30 / 2 x172/2 x208/2 x106 + * 1 1 1 30 / 2 x172/2 x208/2 x88 + * + * *1 : Table 7.6 indicates VCO ouput (PLLx = VCO/2) + */ +#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 12) | \ + (((md) & BIT(13)) >> 12) | \ + (((md) & BIT(19)) >> 19)) +struct cpg_pll_config { + unsigned int extal_div; + unsigned int pll1_mult; + unsigned int pll3_mult; +}; + +static const struct cpg_pll_config cpg_pll_configs[8] = { + { 1, 208, 106 }, { 1, 208, 88 }, { 1, 156, 80 }, { 1, 156, 66 }, + { 2, 240, 122 }, { 2, 240, 102 }, { 2, 208, 106 }, { 2, 208, 88 }, +}; + +/* SDHI divisors */ +static const struct clk_div_table cpg_sdh_div_table[] = { + { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, + { 4, 8 }, { 5, 12 }, { 6, 16 }, { 7, 18 }, + { 8, 24 }, { 10, 36 }, { 11, 48 }, { 0, 0 }, +}; + +static const struct clk_div_table cpg_sd01_div_table[] = { + { 5, 12 }, { 6, 16 }, { 7, 18 }, { 8, 24 }, + { 10, 36 }, { 11, 48 }, { 12, 10 }, { 0, 0 }, +}; + +static u32 cpg_mode __initdata; + +#define CPG_SDCKCR 0x00000074 + +static void __init r8a7790_cpg_clocks_init(struct device_node *np) +{ + const struct cpg_pll_config *config; + struct r8a7790_cpg *cpg; + struct clk **clks; + unsigned int i; + + cpg = kzalloc(sizeof(*cpg), GFP_KERNEL); + clks = kzalloc(CPG_NUM_CLOCKS * sizeof(*clks), GFP_KERNEL); + if (cpg == NULL || clks == NULL) { + kfree(clks); + kfree(cpg); + pr_err("%s: failed to allocate cpg\n", __func__); + return; + } + + spin_lock_init(&cpg->lock); + + cpg->data.clks = clks; + cpg->data.clk_num = CPG_NUM_CLOCKS; + + cpg->reg = of_iomap(np, 0); + if (WARN_ON(cpg->reg == NULL)) { + kfree(cpg->data.clks); + kfree(cpg); + return; + } + + config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)]; + + for (i = 0; i < CPG_NUM_CLOCKS; ++i) { + const struct clk_div_table *table = NULL; + const char *parent_name = "main"; + const char *name; + unsigned int shift; + unsigned int mult = 1; + unsigned int div = 1; + struct clk *clk; + + of_property_read_string_index(np, "clock-output-names", i, + &name); + + switch (i) { + case R8A7790_CLK_MAIN: + parent_name = of_clk_get_parent_name(np, 0); + div = config->extal_div; + break; + case R8A7790_CLK_PLL1: + mult = config->pll1_mult / 2; + break; + case R8A7790_CLK_PLL3: + mult = config->pll3_mult; + break; + case R8A7790_CLK_LB: + div = cpg_mode & BIT(18) ? 36 : 24; + break; + case R8A7790_CLK_QSPI: + div = (cpg_mode & (BIT(3) | BIT(2) | BIT(1))) == BIT(2) + ? 16 : 20; + break; + case R8A7790_CLK_SDH: + table = cpg_sdh_div_table; + shift = 8; + break; + case R8A7790_CLK_SD0: + table = cpg_sd01_div_table; + shift = 4; + break; + case R8A7790_CLK_SD1: + table = cpg_sd01_div_table; + shift = 0; + break; + } + + if (!table) + clk = clk_register_fixed_factor(NULL, name, parent_name, + 0, mult, div); + else + clk = clk_register_divider_table(NULL, name, + parent_name, 0, + cpg->reg + CPG_SDCKCR, + shift, 4, 0, table, + &cpg->lock); + + if (IS_ERR(clk)) + pr_err("%s: failed to register %s %s clock (%ld)\n", + __func__, np->name, name, PTR_ERR(clk)); + } + + of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data); +} +CLK_OF_DECLARE(r8a7790_cpg_clks, "renesas,r8a7790-cpg-clocks", + r8a7790_cpg_clocks_init); + +void __init r8a7790_clocks_init(u32 mode) +{ + cpg_mode = mode; + + of_clk_init(NULL); +} diff --git a/include/dt-bindings/clock/r8a7790-clock.h b/include/dt-bindings/clock/r8a7790-clock.h index 19f2b48..f0ed742 100644 --- a/include/dt-bindings/clock/r8a7790-clock.h +++ b/include/dt-bindings/clock/r8a7790-clock.h @@ -10,6 +10,16 @@ #ifndef __DT_BINDINGS_CLOCK_R8A7790_H__ #define __DT_BINDINGS_CLOCK_R8A7790_H__ +/* CPG */ +#define R8A7790_CLK_MAIN 0 +#define R8A7790_CLK_PLL1 1 +#define R8A7790_CLK_PLL3 2 +#define R8A7790_CLK_LB 3 +#define R8A7790_CLK_QSPI 4 +#define R8A7790_CLK_SDH 5 +#define R8A7790_CLK_SD0 6 +#define R8A7790_CLK_SD1 7 + /* MSTP1 */ #define R8A7790_CLK_CMT0 20 diff --git a/include/linux/clk/shmobile.h b/include/linux/clk/shmobile.h new file mode 100644 index 0000000..b090855 --- /dev/null +++ b/include/linux/clk/shmobile.h @@ -0,0 +1,19 @@ +/* + * Copyright 2013 Ideas On Board SPRL + * + * Contact: Laurent Pinchart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __LINUX_CLK_SHMOBILE_H_ +#define __LINUX_CLK_SHMOBILE_H_ + +#include + +void r8a7790_clocks_init(u32 mode); + +#endif