From patchwork Thu Apr 11 11:23:58 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bastian Hecht X-Patchwork-Id: 2427391 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) by patchwork2.kernel.org (Postfix) with ESMTP id 7E311DF230 for ; Thu, 11 Apr 2013 11:26:25 +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 1UQFct-0007sW-9s; Thu, 11 Apr 2013 11:25:13 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UQFcE-0006FK-9r; Thu, 11 Apr 2013 11:24:30 +0000 Received: from mail-bk0-x22a.google.com ([2a00:1450:4008:c01::22a]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UQFbw-0006Bj-SF for linux-arm-kernel@lists.infradead.org; Thu, 11 Apr 2013 11:24:16 +0000 Received: by mail-bk0-f42.google.com with SMTP id jc3so765968bkc.1 for ; Thu, 11 Apr 2013 04:24:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=GPpUIRXu13+ODRpt/sUOgQDXzpVV/PXfqDtelnQ1sE8=; b=zIasexiVlGgNwHDqVyycF+4mS2RbwyE8QtiqfM7SdIvXocGNAITnCuKP3F/QHEp6aA OLp82URkp99CP4iFoGhjAj4VIvvtSC3eV42ILF/GPA67IYV3YvZKRtz5mQUJWwJQO8Sv LO8b0/fpOERj7JUxqWTBTKnLEAfGxsMi2IpVUOFTZ31mRQdjn1aTgJffU2fpJivLTp6A wIOeH4Cadg1lI8YhF8jChoEIZgmCZw0zHN/llJWsIYcKSH1pW20YXM7/cxRvCFym495q FOIEBWwPRKq6a5ixmCiVOifSvRbXVOVw5+oyiXfwtib4dZKyVbLviWTTeXjZyngmeEeJ K1Pg== X-Received: by 10.204.166.206 with SMTP id n14mr2297838bky.138.1365679450443; Thu, 11 Apr 2013 04:24:10 -0700 (PDT) Received: from localhost.localdomain (g229146212.adsl.alicedsl.de. [92.229.146.212]) by mx.google.com with ESMTPS id uo3sm1665914bkb.11.2013.04.11.04.24.08 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 11 Apr 2013 04:24:09 -0700 (PDT) From: Bastian Hecht To: linux-sh@vger.kernel.org Subject: [PATCH v4 2/7] clocksource: sh_cmt: Add OF support Date: Thu, 11 Apr 2013 13:23:58 +0200 Message-Id: <1365679443-25456-2-git-send-email-hechtb+renesas@gmail.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1365679443-25456-1-git-send-email-hechtb+renesas@gmail.com> References: <1365679443-25456-1-git-send-email-hechtb+renesas@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130411_072413_232748_38764689 X-CRM114-Status: GOOD ( 20.20 ) X-Spam-Score: -2.0 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (hechtb[at]gmail.com) -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature Cc: Mark Rutland , Sergei Shtylyov , Paul Mundt , Magnus Damm , Simon Horman , 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 We add the capabilty to probe SH CMT timer devices using Device Tree setup. Signed-off-by: Bastian Hecht --- v4: Moved the assignments of p->channel_offset and p->timer_bit so that they are ready as soon as setup_irq() is called drivers/clocksource/sh_cmt.c | 108 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 95 insertions(+), 13 deletions(-) diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 08d0c41..66a12e9 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -34,10 +34,13 @@ #include #include #include +#include struct sh_cmt_priv { void __iomem *mapbase; struct clk *clk; + long channel_offset; + int timer_bit; unsigned long width; /* 16 or 32 bit version of hardware block */ unsigned long overflow_bit; unsigned long clear_bits; @@ -109,9 +112,7 @@ static void sh_cmt_write32(void __iomem *base, unsigned long offs, static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_priv *p) { - struct sh_timer_config *cfg = p->pdev->dev.platform_data; - - return p->read_control(p->mapbase - cfg->channel_offset, 0); + return p->read_control(p->mapbase - p->channel_offset, 0); } static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_priv *p) @@ -127,9 +128,7 @@ static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_priv *p) static inline void sh_cmt_write_cmstr(struct sh_cmt_priv *p, unsigned long value) { - struct sh_timer_config *cfg = p->pdev->dev.platform_data; - - p->write_control(p->mapbase - cfg->channel_offset, 0, value); + p->write_control(p->mapbase - p->channel_offset, 0, value); } static inline void sh_cmt_write_cmcsr(struct sh_cmt_priv *p, @@ -176,7 +175,6 @@ static DEFINE_RAW_SPINLOCK(sh_cmt_lock); static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start) { - struct sh_timer_config *cfg = p->pdev->dev.platform_data; unsigned long flags, value; /* start stop register shared by multiple timer channels */ @@ -184,9 +182,9 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start) value = sh_cmt_read_cmstr(p); if (start) - value |= 1 << cfg->timer_bit; + value |= 1 << p->timer_bit; else - value &= ~(1 << cfg->timer_bit); + value &= ~(1 << p->timer_bit); sh_cmt_write_cmstr(p, value); raw_spin_unlock_irqrestore(&sh_cmt_lock, flags); @@ -673,15 +671,93 @@ static int sh_cmt_register(struct sh_cmt_priv *p, char *name, return 0; } -static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) +static const struct of_device_id of_sh_cmt_match[] = { + { .compatible = "renesas,cmt-timer" }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_sh_cmt_match); + +static const int sh_cmt_offset_multiplier[] = { 0x60, 0x10, 0x40, 0x40, 0x40 }; +#define CMT_MAX_CHANNELS 6 + +static struct sh_timer_config *sh_cmt_parse_dt(struct device *dev) +{ + struct sh_timer_config *cfg; + struct device_node *np = dev->of_node; + u32 timer_id, channel_id, rating; + + if (!IS_ENABLED(CONFIG_OF) || !np) + return NULL; + + cfg = devm_kzalloc(dev, sizeof(struct sh_timer_config), GFP_KERNEL); + if (!cfg) { + dev_err(dev, "failed to allocate DT config data\n"); + return NULL; + } + + if (of_property_read_u32(np, "renesas,device-id", &timer_id)) { + dev_err(dev, "device id missing\n"); + return NULL; + } + if (timer_id >= ARRAY_SIZE(sh_cmt_offset_multiplier)) { + dev_err(dev, "invalid device id\n"); + return NULL; + } + + if (of_property_read_u32(np, "renesas,channel-id", &channel_id)) { + dev_err(dev, "channel id missing\n"); + return NULL; + } + if (channel_id >= CMT_MAX_CHANNELS) { + dev_err(dev, "invalid channel id\n"); + return NULL; + } + + cfg->channel_offset = sh_cmt_offset_multiplier[timer_id] * + (channel_id + 1); + cfg->timer_bit = channel_id; + + /* + * We convert the {source,event}-quality DT properties to linux specific + * clock{source,event}_ratings. + */ + if (!of_property_read_u32(np, "renesas,source-quality", &rating)) { + if (rating > 10) { + dev_err(dev, "invalid source-quality\n"); + return NULL; + } + if (rating) + cfg->clocksource_rating = rating * 50 - 1; + } + + if (!of_property_read_u32(np, "renesas,event-quality", &rating)) { + if (rating > 10) { + dev_err(dev, "invalid event-quality\n"); + return NULL; + } + if (rating) + cfg->clockevent_rating = rating * 50 - 1; + } + + if (!cfg->clocksource_rating && !cfg->clockevent_rating) { + dev_err(dev, "source- and event-quality 0, timer is unused\n"); + return NULL; + } + + return cfg; +} + +static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev, + struct sh_timer_config *cfg) { - struct sh_timer_config *cfg = pdev->dev.platform_data; struct resource *res; int irq, ret; ret = -ENXIO; memset(p, 0, sizeof(*p)); p->pdev = pdev; + p->channel_offset = cfg->channel_offset; + p->timer_bit = cfg->timer_bit; if (!cfg) { dev_err(&p->pdev->dev, "missing platform data\n"); @@ -777,7 +853,7 @@ err0: static int sh_cmt_probe(struct platform_device *pdev) { struct sh_cmt_priv *p = platform_get_drvdata(pdev); - struct sh_timer_config *cfg = pdev->dev.platform_data; + struct sh_timer_config *cfg; int ret; if (!is_early_platform_device(pdev)) { @@ -785,6 +861,11 @@ static int sh_cmt_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); } + if (pdev->dev.of_node) + cfg = sh_cmt_parse_dt(&pdev->dev); + else + cfg = pdev->dev.platform_data; + if (p) { dev_info(&pdev->dev, "kept as earlytimer\n"); goto out; @@ -796,7 +877,7 @@ static int sh_cmt_probe(struct platform_device *pdev) return -ENOMEM; } - ret = sh_cmt_setup(p, pdev); + ret = sh_cmt_setup(p, pdev, cfg); if (ret) { kfree(p); pm_runtime_idle(&pdev->dev); @@ -824,6 +905,7 @@ static struct platform_driver sh_cmt_device_driver = { .remove = sh_cmt_remove, .driver = { .name = "sh_cmt", + .of_match_table = of_match_ptr(of_sh_cmt_match), } };