From patchwork Thu Jul 18 18:34:57 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Shiyan X-Patchwork-Id: 2829769 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 C20589F4D5 for ; Thu, 18 Jul 2013 18:49:11 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id AD0A6201BD for ; Thu, 18 Jul 2013 18:49:10 +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 5F78C20121 for ; Thu, 18 Jul 2013 18:49:09 +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 1Uzt8c-0008Uu-6A; Thu, 18 Jul 2013 18:41:15 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Uzt8D-0001VI-FX; Thu, 18 Jul 2013 18:40:49 +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 1Uzt8A-0001TS-3n for linux-arm-kernel@lists.infradead.org; Thu, 18 Jul 2013 18:40:47 +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=eeKz3+6IFfUb82x4QSuq2gWaRBy/pENP4/xrJZa9Bxg=; b=kUR0RpxHJL8XTphBqQTHAKrxrXp2To4eSE1ABWRhjqk4U6oVSYn0wTTV5OZVY3ovcnUfn0xeJ/8MsQlIQJ5VDMDDuGhTD5hFTNPrwDY2Mn+r2q5lUoc3g2qNY7ugZUBdPnwtidG/4rP1pBRbRoUrWHdyoqxNBi5JK2g3qLGt3Ec=; Received: from [188.134.40.128] (port=48263 helo=shc.zet) by smtp49.i.mail.ru with esmtpa (envelope-from ) id 1Uzt4D-0007tN-HK; Thu, 18 Jul 2013 22:36:49 +0400 From: Alexander Shiyan To: linux-arm-kernel@lists.infradead.org Subject: [PATCH 06/10] ARM: clps711x: Add CLPS711X clocksource driver Date: Thu, 18 Jul 2013 22:34:57 +0400 Message-Id: <1374172501-26796-7-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_144046_614529_FA30B552 X-CRM114-Status: GOOD ( 19.17 ) 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 clocksource driver for Cirrus Logic CLPS711X series SoCs. Designed primarily for migration CLPS711X subarch for multiplatform & DT, for this as the "OF" and "not-OF" calls implemented. Signed-off-by: Alexander Shiyan --- arch/arm/Kconfig | 2 - drivers/clocksource/Kconfig | 6 ++ drivers/clocksource/Makefile | 1 + drivers/clocksource/clps711x-clksrc.c | 151 ++++++++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 drivers/clocksource/clps711x-clksrc.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index dfb1e7f..5c60cb7 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -370,10 +370,8 @@ config ARCH_CLPS711X bool "Cirrus Logic CLPS711x/EP721x/EP731x-based" select ARCH_REQUIRE_GPIOLIB select AUTO_ZRELADDR - select CLKSRC_MMIO select COMMON_CLK select CPU_ARM720T - select GENERIC_CLOCKEVENTS select MFD_SYSCON select MULTI_IRQ_HANDLER select SPARSE_IRQ diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index b7b9b04..bd6dc82 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -41,6 +41,12 @@ config VT8500_TIMER config CADENCE_TTC_TIMER bool +config CLKSRC_CLPS711X + def_bool y if ARCH_CLPS711X + select CLKSRC_MMIO + select CLKSRC_OF if OF + select GENERIC_CLOCKEVENTS + config CLKSRC_NOMADIK_MTU bool depends on (ARCH_NOMADIK || ARCH_U8500) diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 8b00c5c..da6c102 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_CLKBLD_I8253) += i8253.o obj-$(CONFIG_CLKSRC_MMIO) += mmio.o obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o +obj-$(CONFIG_CLKSRC_CLPS711X) += clps711x-clksrc.o obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o diff --git a/drivers/clocksource/clps711x-clksrc.c b/drivers/clocksource/clps711x-clksrc.c new file mode 100644 index 0000000..1749b0b --- /dev/null +++ b/drivers/clocksource/clps711x-clksrc.c @@ -0,0 +1,151 @@ +/* + * CLPS711X clocksource 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define CLPS711X_SYSCON1 (0x0100) +#define CLPS711X_TC1D (0x0300) +#define CLPS711X_TC2D (0x0340) + +static struct { + void __iomem *tc1d; + int irq; +} *clps711x_clksrc; + +static u32 notrace clps711x_sched_clock_read(void) +{ + return ~readw(clps711x_clksrc->tc1d); +} + +static void clps711x_clockevent_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + disable_irq(clps711x_clksrc->irq); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + enable_irq(clps711x_clksrc->irq); + break; + case CLOCK_EVT_MODE_ONESHOT: + /* Not supported */ + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_RESUME: + /* Left event sources disabled, no more interrupts appear */ + break; + } +} + +static struct clock_event_device clps711x_clockevent = { + .name = "clps711x-clockevent", + .rating = 300, + .features = CLOCK_EVT_FEAT_PERIODIC, + .set_mode = clps711x_clockevent_set_mode, +}; + +static irqreturn_t clps711x_timer_interrupt(int irq, void *dev_id) +{ + clps711x_clockevent.event_handler(&clps711x_clockevent); + + return IRQ_HANDLED; +} + +static struct irqaction clps711x_timer_irq = { + .name = "clps711x-timer", + .flags = IRQF_TIMER | IRQF_IRQPOLL, + .handler = clps711x_timer_interrupt, +}; + +static void __init _clps711x_clksrc_init(phys_addr_t phys_base, int irq, + struct clk *tc1, struct clk *tc2) +{ + unsigned long tc1_rate, tc2_rate; + void __iomem *tc2d, *syscon1; + u32 tmp; + + BUG_ON(IS_ERR(tc1) || IS_ERR(tc2)); + + BUG_ON(!request_mem_region(phys_base + CLPS711X_TC1D, SZ_2, NULL)); + BUG_ON(!request_mem_region(phys_base + CLPS711X_TC2D, SZ_2, NULL)); + + clps711x_clksrc = kzalloc(sizeof(*clps711x_clksrc), GFP_KERNEL); + BUG_ON(!clps711x_clksrc); + + clps711x_clksrc->tc1d = ioremap(phys_base + CLPS711X_TC1D, SZ_2); + BUG_ON(!clps711x_clksrc->tc1d); + + tc2d = ioremap(phys_base + CLPS711X_TC2D, SZ_2); + BUG_ON(!tc2d); + + syscon1 = ioremap(phys_base + CLPS711X_SYSCON1, SZ_4); + BUG_ON(!syscon1); + + clps711x_clksrc->irq = irq; + + tmp = readl(syscon1); + /* TC1 in free running mode */ + tmp &= ~SYSCON1_TC1M; + /* TC2 in prescale mode */ + tmp |= SYSCON1_TC2M; + writel(tmp, syscon1); + + tc1_rate = clk_get_rate(tc1); + tc2_rate = clk_get_rate(tc2); + + clocksource_mmio_init(clps711x_clksrc->tc1d, "clps711x-clocksource", + tc1_rate, 300, 16, clocksource_mmio_readw_down); + + setup_sched_clock(clps711x_sched_clock_read, 16, tc1_rate); + + /* Set Timer prescaler */ + writew(DIV_ROUND_CLOSEST(tc2_rate, HZ), tc2d); + + clockevents_config_and_register(&clps711x_clockevent, tc2_rate, 0, 0); + + BUG_ON(setup_irq(clps711x_clksrc->irq, &clps711x_timer_irq)); +} + +void __init clps711x_clksrc_init(phys_addr_t phys_base, int irq) +{ + struct clk *tc1 = clk_get(NULL, "tc1"); + struct clk *tc2 = clk_get(NULL, "tc2"); + + _clps711x_clksrc_init(phys_base, irq, tc1, tc2); +} + +#ifdef CONFIG_CLKSRC_OF +static void __init clps711x_clksrc_init_dt(struct device_node *np) +{ + struct clk *tc1 = of_clk_get_by_name(np, "tc1"); + struct clk *tc2 = of_clk_get_by_name(np, "tc2"); + struct resource res_io, res_irq; + + BUG_ON(!of_address_to_resource(np, 0, &res_io)); + + BUG_ON(!of_irq_to_resource(np, 0, &res_irq)); + + _clps711x_clksrc_init(res_io.start, res_irq.start, tc1, tc2); +} +CLOCKSOURCE_OF_DECLARE(clps711x, "cirrus,clps711x-clocksource", + clps711x_clksrc_init_dt); +#endif