From patchwork Thu Jul 18 18:34:56 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Shiyan X-Patchwork-Id: 2829765 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 2E7E49F4D5 for ; Thu, 18 Jul 2013 18:39:07 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id CAFCF20186 for ; Thu, 18 Jul 2013 18:39:05 +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 BC64D201B6 for ; Thu, 18 Jul 2013 18:39:03 +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 1Uzt4u-0006Ci-98; Thu, 18 Jul 2013 18:37:25 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Uzt4Y-0001NM-0m; Thu, 18 Jul 2013 18:37:02 +0000 Received: from smtp49.i.mail.ru ([94.100.177.109]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Uzt4K-0001LI-LX for linux-arm-kernel@lists.infradead.org; Thu, 18 Jul 2013 18:36:50 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mail.ru; s=mail2; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From; bh=tB1uwQLyKLirMQZtxX09tzbia2JcIF8E6ft8NJwz/H0=; b=qk9kX6+YNH5+YXJ6M6r/UyeYXwReWT5mZUHx41eurNGZmDHsU5wEOI/6xR0GzsubbhOuPXBmhQrDXCPixnqk1BEHA8q1S27E8njTmAnaRKJ3lZbX41lCecMOhkSDPW51+D5+Z7M+IDKSgKZ/QxNjpibfmxkJq8vzED56SM5PxsI=; Received: from [188.134.40.128] (port=48263 helo=shc.zet) by smtp49.i.mail.ru with esmtpa (envelope-from ) id 1Uzt43-0007tN-Hn; Thu, 18 Jul 2013 22:36:32 +0400 From: Alexander Shiyan To: linux-arm-kernel@lists.infradead.org Subject: [PATCH 05/10] ARM: clps711x: Add CLPS711X clk driver Date: Thu, 18 Jul 2013 22:34:56 +0400 Message-Id: <1374172501-26796-6-git-send-email-shc_work@mail.ru> X-Mailer: git-send-email 1.8.1.5 In-Reply-To: <1374172501-26796-1-git-send-email-shc_work@mail.ru> References: <1374172501-26796-1-git-send-email-shc_work@mail.ru> X-Mras: Ok X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130718_143649_189744_B2098718 X-CRM114-Status: GOOD ( 21.04 ) X-Spam-Score: -2.0 (--) Cc: Mike Turquette , Alexander Shiyan , Arnd Bergmann , Daniel Lezcano , "Rafael J. Wysocki" , Olof Johansson , Russell King 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.4 required=5.0 tests=BAYES_00,DKIM_SIGNED, FREEMAIL_FROM,RCVD_IN_DNSWL_MED,RP_MATCHES_RCVD,T_DKIM_INVALID, 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 This adds the clock driver for Cirrus Logic CLPS711X series SoCs using common clock infrastructure. Designed primarily for migration CLPS711X subarch for multiplatform & DT, for this as the "OF" and "not-OF" calls implemented. Additionally, patch removes unnecessary symbol CLKDEV_LOOKUP for CLPS711X from main ARM Kconfig since this symbol is selected automatically by COMMON_CLK. Signed-off-by: Alexander Shiyan --- .../devicetree/bindings/clock/clps711x-clock.txt | 47 +++++++ arch/arm/Kconfig | 1 - drivers/clk/Makefile | 1 + drivers/clk/clk-clps711x.c | 150 +++++++++++++++++++++ 4 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/clock/clps711x-clock.txt create mode 100644 drivers/clk/clk-clps711x.c diff --git a/Documentation/devicetree/bindings/clock/clps711x-clock.txt b/Documentation/devicetree/bindings/clock/clps711x-clock.txt new file mode 100644 index 0000000..0fb9fff --- /dev/null +++ b/Documentation/devicetree/bindings/clock/clps711x-clock.txt @@ -0,0 +1,47 @@ +Device Tree Clock bindings for the Cirrus Logic CLPS711X CPUs + +=== Clock subsystem === +Required properties: +- compatible: Should be "cirrus,clps711x-clk" +- reg: Address of the internal register set +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. The following table is a full list of +CLPS711X clocks and IDs. + + Clock ID + ------------------ + dummy 0 + cpu 1 + pll 2 + bus 3 + timer_hf 4 + timer_lf 5 + tc1 6 + tc2 7 + spi 8 + uart 9 + +=== Clocksource subsystem === +Required properties: +- compatible: Should be "cirrus,clps711x-clocksource" +- reg: Address of the internal register set +- clocks: phandle to the source clocks TC1 and TC2 +- interrupts: The interrupt of the TC2 timer + +Example: + +clks: clks@80000000 { + compatible = "cirrus,clps711x-clk"; + reg = <0x80000000 0>; + #clock-cells = <1>; +}; + +timer { + compatible = "cirrus,clps711x-clocksource"; + reg = <0x80000000 0>; + clocks = <&clks 6>, <&clks 7>; + clock-names = "tc1", "tc2"; + interrupts = <9>; +}; diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ba412e0..dfb1e7f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -370,7 +370,6 @@ config ARCH_CLPS711X bool "Cirrus Logic CLPS711x/EP721x/EP731x-based" select ARCH_REQUIRE_GPIOLIB select AUTO_ZRELADDR - select CLKDEV_LOOKUP select CLKSRC_MMIO select COMMON_CLK select CPU_ARM720T diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 4038c2b..a7e9b73 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-composite.o # SoCs specific obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o +obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o diff --git a/drivers/clk/clk-clps711x.c b/drivers/clk/clk-clps711x.c new file mode 100644 index 0000000..662908c --- /dev/null +++ b/drivers/clk/clk-clps711x.c @@ -0,0 +1,150 @@ +/* + * CLPS711X clk driver + * + * Copyright (C) 2013 Alexander Shiyan + * + * 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. + */ + +#define pr_fmt(fmt) "clk-clps711x: " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define CLPS711X_SYSCON1 (0x0100) +#define CLPS711X_SYSCON2 (0x1100) +#define CLPS711X_PLLR (0xa5a8) + +#define CLPS711X_EXT_FREQ (13000000) +#define CLPS711X_OSC_FREQ (3686400) + +enum clps711x_clks { + dummy, cpu, pll, bus, timer_hf, timer_lf, tc1, tc2, spi, uart, clk_max +}; + +static struct { + struct clk_onecell_data clk_data; + struct clk *clks[clk_max]; +} *clps711x_clk; + +static void __init _clps711x_clk_init(phys_addr_t phys_base) +{ + const char *tc_parents[] = { "timer_lf", "timer_hf" }; + u32 tmp, f_cpu, f_pll, f_bus, f_timh, f_spi; + void __iomem *pllr, *syscon1, *syscon2; + + BUG_ON(!request_mem_region(phys_base + CLPS711X_PLLR, SZ_4, NULL)); + BUG_ON(!request_mem_region(phys_base + CLPS711X_SYSCON1, SZ_128, NULL)); + BUG_ON(!request_mem_region(phys_base + CLPS711X_SYSCON2, SZ_128, NULL)); + + clps711x_clk = kzalloc(sizeof(*clps711x_clk), GFP_KERNEL); + BUG_ON(!clps711x_clk); + + pllr = ioremap(phys_base + CLPS711X_PLLR, SZ_4); + BUG_ON(!pllr); + + syscon1 = ioremap(phys_base + CLPS711X_SYSCON1, SZ_128); + BUG_ON(!syscon1); + + syscon2 = ioremap(phys_base + CLPS711X_SYSCON2, SZ_128); + BUG_ON(!syscon2); + + tmp = readl(pllr) >> 24; + if (tmp) + f_pll = DIV_ROUND_UP(CLPS711X_OSC_FREQ * tmp, 2); + else + f_pll = 73728000; /* Old CPUs default value */ + + tmp = readl(syscon2 + SYSFLG_OFFSET); + if (tmp & SYSFLG2_CKMODE) { + f_cpu = CLPS711X_EXT_FREQ; + f_bus = CLPS711X_EXT_FREQ; + f_spi = 135400; + f_pll = 0; + } else { + f_cpu = f_pll; + if (f_cpu >= 36864000) + f_bus = DIV_ROUND_UP(f_cpu, 2); + else + f_bus = 36864000 / 2; + f_spi = DIV_ROUND_CLOSEST(f_cpu, 576); + } + + if (tmp & SYSFLG2_CKMODE) { + if (readl(syscon2 + SYSCON_OFFSET) & SYSCON2_OSTB) + f_timh = DIV_ROUND_CLOSEST(CLPS711X_EXT_FREQ, 26); + else + f_timh = DIV_ROUND_CLOSEST(CLPS711X_EXT_FREQ, 24); + } else + f_timh = DIV_ROUND_CLOSEST(f_cpu, 144); + + clps711x_clk->clks[dummy] = + clk_register_fixed_rate(NULL, "dummy", NULL, CLK_IS_ROOT, 0); + clps711x_clk->clks[cpu] = + clk_register_fixed_rate(NULL, "cpu", NULL, CLK_IS_ROOT, f_cpu); + clps711x_clk->clks[pll] = + clk_register_fixed_rate(NULL, "pll", NULL, CLK_IS_ROOT, f_pll); + clps711x_clk->clks[bus] = + clk_register_fixed_rate(NULL, "bus", NULL, CLK_IS_ROOT, f_bus); + clps711x_clk->clks[timer_hf] = + clk_register_fixed_rate(NULL, "timer_hf", NULL, CLK_IS_ROOT, + f_timh); + clps711x_clk->clks[timer_lf] = + clk_register_fixed_factor(NULL, "timer_lf", "timer_hf", + 0, 1, 256); + clps711x_clk->clks[tc1] = + clk_register_mux(NULL, "tc1", tc_parents, 2, + CLK_GET_RATE_NOCACHE, syscon1, 5, 1, 0, NULL); + clps711x_clk->clks[tc2] = + clk_register_mux(NULL, "tc2", tc_parents, 2, + CLK_GET_RATE_NOCACHE, syscon1, 7, 1, 0, NULL); + clps711x_clk->clks[spi] = + clk_register_fixed_rate(NULL, "spi", NULL, CLK_IS_ROOT, f_spi); + clps711x_clk->clks[uart] = + clk_register_fixed_factor(NULL, "uart", "bus", 0, 1, 10); + + clk_set_parent(clps711x_clk->clks[tc1], clps711x_clk->clks[timer_lf]); + clk_set_parent(clps711x_clk->clks[tc2], clps711x_clk->clks[timer_hf]); + + /* Temporary export clocks for non-DT capable drivers */ + clk_register_clkdev(clps711x_clk->clks[pll], "pll", NULL); + clk_register_clkdev(clps711x_clk->clks[spi], "spi", NULL); + clk_register_clkdev(clps711x_clk->clks[uart], "uart", NULL); + + pr_debug("CPU: %u Hz, Timer: %u Hz\n", f_cpu, f_timh); +} + +void __init clps711x_clk_init(phys_addr_t phys_base) +{ + _clps711x_clk_init(phys_base); + + clk_register_clkdev(clps711x_clk->clks[tc1], "tc1", NULL); + clk_register_clkdev(clps711x_clk->clks[tc2], "tc2", NULL); +} + +#ifdef CONFIG_OF +static void __init clps711x_clk_init_dt(struct device_node *np) +{ + struct resource res; + + BUG_ON(!of_address_to_resource(np, 0, &res)); + + _clps711x_clk_init(res.start); + + clps711x_clk->clk_data.clks = clps711x_clk->clks; + clps711x_clk->clk_data.clk_num = clk_max; + of_clk_add_provider(np, of_clk_src_onecell_get, + &clps711x_clk->clk_data); +} +CLK_OF_DECLARE(clps711x, "cirrus,clps711x-clk", clps711x_clk_init_dt); +#endif