From patchwork Wed Jun 14 12:39:42 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 105506 Delivered-To: patch@linaro.org Received: by 10.140.91.77 with SMTP id y71csp272099qgd; Wed, 14 Jun 2017 05:42:49 -0700 (PDT) X-Received: by 10.99.106.66 with SMTP id f63mr443174pgc.150.1497444168950; Wed, 14 Jun 2017 05:42:48 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1497444168; cv=none; d=google.com; s=arc-20160816; b=L/YgJOnzfxYbJ+b8FDh9E4BAbZphovPdyHRIqMl2/cDZ0veh/lGOhvOjf/oMJTHRTx TsCQT53UQ/6FYmQGFL7TTgSPiiWrUpNQoH5C2ziZyofgGsg/tFS3DJafStcHlOO2wOZZ 3GaDl0mhaONnqShft0uVIsOUShjtYtWbLAg8ouocajouM6udGkjsUddTIY5nt5ZRok7u 3VWOSHM+szKVrSLzIR77gPlozGwMZxr9NBYvqEIYigEjIariiL1Hkz81l3LvedGfCQcB UmUb0TSv3rFYj5mi3oC6GPqfwV6DQheqTsjEsNpakyFy5EL9D07Uy44imkg/GEOJCA/b ARng== 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:dkim-signature:arc-authentication-results; bh=kO3i/55MFiacvbcrJreAhG49SCOWb5JhLIVbkuWAjmE=; b=uw+mzFV4Z7rYbF05wvzwA1we68pbLJP8l39ituoJme4GoOLbF61QFetWtypfskXgFQ X0HuSqsEWOLAcjiP3m0zjVvpXTxYnDnl3MCmLHXZPpDN40xmLFs+Gggc9fHHIYvW2HNC bPNr4IOOnt1Qe2dBUmB0qBcicr0C7szIUBGsUSTS884tLW8b3mIhBkgJZkzFK6XK+nfT Ds4weo1Q9rrD71s4osQv/1RBpsG2mCfEUOkCHG0p4asXrMoKMeGGuMG85h8sxdaVhpQK 4YkpR78Zz6QVKLcI3M0hQhKECmKmmrABLgenfNlFSkX+AdaUa1YjohilJcVTI5yw56UG j/Zg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.b=Wnci2PeV; 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; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id e12si600533pfb.358.2017.06.14.05.42.48; Wed, 14 Jun 2017 05:42:48 -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; dkim=pass header.i=@linaro.org header.b=Wnci2PeV; 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; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752720AbdFNMmW (ORCPT + 25 others); Wed, 14 Jun 2017 08:42:22 -0400 Received: from mail-wr0-f169.google.com ([209.85.128.169]:35780 "EHLO mail-wr0-f169.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752660AbdFNMmS (ORCPT ); Wed, 14 Jun 2017 08:42:18 -0400 Received: by mail-wr0-f169.google.com with SMTP id q97so188272123wrb.2 for ; Wed, 14 Jun 2017 05:42:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=kO3i/55MFiacvbcrJreAhG49SCOWb5JhLIVbkuWAjmE=; b=Wnci2PeVfPqRGiiOw7eJRaetXW+BHZgS1qAovPfD55So4c8xJbWxzcr9at4Yd9rGX2 wJxZG2WAWbFE4cXunxEyXv2ydL/pyTIOrHK7fjTV8b9yQ3x4juKtg6vaa4z+ykzOAaYv wRe7OAUg5y3PGHGniFy6BkoXHUaFswGh1NrVQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=kO3i/55MFiacvbcrJreAhG49SCOWb5JhLIVbkuWAjmE=; b=SrGtotKoKacPu3vh1XIcMzprYEmCSR4K3CLaDDKoG0MGNcszWvpXzy3SJG5G0opF/n F1wOkzJtJORaP3BVgy0q+YnLdgwaWFXErDL7AYZMnF78iVebBefOU06w6/ViXvCJ9h12 9QcElOWhdVWly5cmauPBED4tG0i9Wln1iqD7yMyWmTNuzpQrkzHJsbdFh1pucPeT+otG OuRPyih8p+H/mwdrb0FYwnV8IctBUhUmJM3sF+MUCAq25WE58NZbvo0tq24TbDx1bHNu wG9AzMmc9TCkWJ5C+X8bc/rPevkLHibRxBTaYcLXk4Fkkci/5XwdYX9rX4/xBLTRbk7D xBmA== X-Gm-Message-State: AKS2vOwEQQbDJXqA4WmCGjItIwO5hhOwzulgHxDyIIEc0nfdAyy+AbBZ svVDAhXhnkxJnI/pQxNZ+OMS X-Received: by 10.223.162.215 with SMTP id t23mr344661wra.193.1497444136545; Wed, 14 Jun 2017 05:42:16 -0700 (PDT) Received: from localhost.localdomain ([2a01:e35:879a:6cd0:19a:b336:54d7:46e9]) by smtp.gmail.com with ESMTPSA id 80sm1457015wmg.17.2017.06.14.05.42.15 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 14 Jun 2017 05:42:15 -0700 (PDT) From: Daniel Lezcano To: tglx@linutronix.de Cc: linux-kernel@vger.kernel.org Subject: [PATCH 21/23] clocksource/drivers: Add timer-of common init routine Date: Wed, 14 Jun 2017 14:39:42 +0200 Message-Id: <1497443984-12371-21-git-send-email-daniel.lezcano@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1497443984-12371-1-git-send-email-daniel.lezcano@linaro.org> References: <20170614123800.GH2261@mai> <1497443984-12371-1-git-send-email-daniel.lezcano@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The different drivers are all using the same pattern when initializing. 1. Get the base address 2. Get the irq number 3. Get the clock 4. Prepare and enable the clock 5. Get the rate 6. Request an interrupt Instead of repeating again and again these steps in all the drivers, let's provide a common init routine to give the opportunity to factor all of them out. We can expect a significant kernel size improvement when the common routine will be used in all the drivers. Signed-off-by: Daniel Lezcano --- drivers/clocksource/Kconfig | 1 + drivers/clocksource/Makefile | 1 + drivers/clocksource/timer-of.c | 172 +++++++++++++++++++++++++++++++++++++++++ drivers/clocksource/timer-of.h | 69 +++++++++++++++++ 4 files changed, 243 insertions(+) create mode 100644 drivers/clocksource/timer-of.c create mode 100644 drivers/clocksource/timer-of.h -- 2.7.4 diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 4ba230d..4be163b 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -3,6 +3,7 @@ menu "Clock Source drivers" config TIMER_OF bool + depends on GENERIC_CLOCKEVENTS select TIMER_PROBE config TIMER_ACPI diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index ec55921..72bfd00 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -1,3 +1,4 @@ +obj-$(CONFIG_TIMER_OF) += timer-of.o obj-$(CONFIG_TIMER_PROBE) += timer-probe.o obj-$(CONFIG_ATMEL_PIT) += timer-atmel-pit.o obj-$(CONFIG_ATMEL_ST) += timer-atmel-st.o diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c new file mode 100644 index 0000000..be1dbee --- /dev/null +++ b/drivers/clocksource/timer-of.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2017, Linaro Ltd. All rights reserved. + * + * Author: Daniel Lezcano + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include +#include +#include + +#include "timer-of.h" + +static __init void timer_irq_exit(struct of_timer_irq *of_irq) +{ + struct timer_of *to = container_of(of_irq, struct timer_of, of_irq); + + struct clock_event_device *clkevt = &to->clkevt; + + of_irq->percpu ? free_percpu_irq(of_irq->irq, clkevt) : + free_irq(of_irq->irq, clkevt); +} + +static __init int timer_irq_init(struct device_node *np, + struct of_timer_irq *of_irq) +{ + int ret; + struct timer_of *to = container_of(of_irq, struct timer_of, of_irq); + struct clock_event_device *clkevt = &to->clkevt; + + of_irq->irq = of_irq->name ? of_irq_get_byname(np, of_irq->name): + irq_of_parse_and_map(np, of_irq->index); + if (!of_irq->irq) { + pr_err("Failed to map interrupt for %s\n", np->full_name); + return -EINVAL; + } + + ret = of_irq->percpu ? + request_percpu_irq(of_irq->irq, of_irq->handler, + np->full_name, clkevt) : + request_irq(of_irq->irq, of_irq->handler, + of_irq->flags ? of_irq->flags : IRQF_TIMER, + np->full_name, clkevt); + if (ret) { + pr_err("Failed to request irq %d for %s\n", of_irq->irq, + np->full_name); + return ret; + } + + clkevt->irq = of_irq->irq; + + return 0; +} + +static __init void timer_clk_exit(struct of_timer_clk *of_clk) +{ + of_clk->rate = 0; + clk_disable_unprepare(of_clk->clk); + clk_put(of_clk->clk); +} + +static __init int timer_clk_init(struct device_node *np, + struct of_timer_clk *of_clk) +{ + int ret; + + of_clk->clk = of_clk->name ? of_clk_get_by_name(np, of_clk->name) : + of_clk_get(np, of_clk->index); + if (IS_ERR(of_clk->clk)) { + pr_err("Failed to get clock for %s\n", np->full_name); + return PTR_ERR(of_clk->clk); + } + + ret = clk_prepare_enable(of_clk->clk); + if (ret) { + pr_err("Failed for enable clock for %s\n", np->full_name); + goto out_clk_put; + } + + of_clk->rate = clk_get_rate(of_clk->clk); + if (!of_clk->rate) { + ret = -EINVAL; + pr_err("Failed to get clock rate for %s\n", np->full_name); + goto out_clk_disable; + } + + of_clk->period = DIV_ROUND_UP(of_clk->rate, HZ); +out: + return ret; + +out_clk_disable: + clk_disable_unprepare(of_clk->clk); +out_clk_put: + clk_put(of_clk->clk); + + goto out; +} + +static __init void timer_base_exit(struct of_timer_base *of_base) +{ + iounmap(of_base->base); +} + +static __init int timer_base_init(struct device_node *np, + struct of_timer_base *of_base) +{ + const char *name = of_base->name ? of_base->name : np->full_name; + + of_base->base = of_io_request_and_map(np, of_base->index, name); + if (of_base->base) { + pr_err("Failed to iomap (%s)\n", name); + return -ENXIO; + } + + return 0; +} + +int __init timer_of_init(struct device_node *np, struct timer_of *to) +{ + int ret; + int flags = 0; + + if (to->flags & TIMER_OF_BASE) { + ret = timer_base_init(np, &to->of_base); + if (ret) + goto out_fail; + flags |= TIMER_OF_BASE; + } + + if (to->flags & TIMER_OF_CLOCK) { + ret = timer_clk_init(np, &to->of_clk); + if (ret) + goto out_fail; + flags |= TIMER_OF_CLOCK; + } + + if (to->flags & TIMER_OF_IRQ) { + ret = timer_irq_init(np, &to->of_irq); + if (ret) + goto out_fail; + flags |= TIMER_OF_IRQ; + } + + if (!to->clkevt.name) + to->clkevt.name = np->name; +out: + return ret; + +out_fail: + if (flags & TIMER_OF_IRQ) + timer_irq_exit(&to->of_irq); + + if (flags & TIMER_OF_CLOCK) + timer_clk_exit(&to->of_clk); + + if (flags & TIMER_OF_BASE) + timer_base_exit(&to->of_base); + goto out; +} diff --git a/drivers/clocksource/timer-of.h b/drivers/clocksource/timer-of.h new file mode 100644 index 0000000..e0d7272 --- /dev/null +++ b/drivers/clocksource/timer-of.h @@ -0,0 +1,69 @@ +#ifndef __TIMER_OF_H__ +#define __TIMER_OF_H__ + +#include + +#define TIMER_OF_BASE 0x1 +#define TIMER_OF_CLOCK 0x2 +#define TIMER_OF_IRQ 0x4 + +struct of_timer_irq { + int irq; + int index; + int percpu; + const char *name; + unsigned long flags; + irq_handler_t handler; +}; + +struct of_timer_base { + void __iomem *base; + const char *name; + int index; +}; + +struct of_timer_clk { + struct clk *clk; + const char *name; + int index; + unsigned long rate; + unsigned long period; +}; + +struct timer_of { + unsigned int flags; + struct clock_event_device clkevt; + struct of_timer_base of_base; + struct of_timer_irq of_irq; + struct of_timer_clk of_clk; + void *private_data; +}; + +static inline struct timer_of *to_timer_of(struct clock_event_device *clkevt) +{ + return container_of(clkevt, struct timer_of, clkevt); +} + +static inline void __iomem *timer_of_base(struct timer_of *to) +{ + return to->of_base.base; +} + +static inline int timer_of_irq(struct timer_of *to) +{ + return to->of_irq.irq; +} + +static inline unsigned long timer_of_rate(struct timer_of *to) +{ + return to->of_clk.rate; +} + +static inline unsigned long timer_of_period(struct timer_of *to) +{ + return to->of_clk.period; +} + +extern int __init timer_of_init(struct device_node *np, + struct timer_of *to); +#endif