From patchwork Fri Mar 8 11:29:37 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bastian Hecht X-Patchwork-Id: 2236871 Return-Path: X-Original-To: patchwork-linux-sh@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id 2A23A4006E for ; Fri, 8 Mar 2013 11:29:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752879Ab3CHL3u (ORCPT ); Fri, 8 Mar 2013 06:29:50 -0500 Received: from mail-ee0-f53.google.com ([74.125.83.53]:54127 "EHLO mail-ee0-f53.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752522Ab3CHL3u (ORCPT ); Fri, 8 Mar 2013 06:29:50 -0500 Received: by mail-ee0-f53.google.com with SMTP id e53so973964eek.40 for ; Fri, 08 Mar 2013 03:29:49 -0800 (PST) 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=xHDEx7KJ9WUigSM5GDXvaSQ6LvosQ5jIPU+gqsvI6BM=; b=WDYtT4V2s4tMFjJzOW8K1R3fnKtPZfoOH30trJexTvpfuHprccijZXv2QsgFhci3Kg 59G3r5rcgUI8PJg17W9HKxhtgjppGGC/KFpivBF0G4CLprhtKx/MCgHxmvUNCUwbDiqB prRGuGPaykm0z1KVh0znwd/zoLhIoWJHLjauzLh7nwsWUrnqiF9HEQjt1iTKbnvsA+Er B5bS5mQVwd9+NJMTWQrTHNTO6wdU6IovkRMQQhU+Sl/ECjYP16B8fxXCLayjYPwuflQZ x5ncsirWniU3eI+XHHkNjOa0Fx0DWAyK3LdES4KjBwNo2nNtG03LzAremGrCcYEo+XnG KICw== X-Received: by 10.15.21.4 with SMTP id c4mr4229706eeu.34.1362742189113; Fri, 08 Mar 2013 03:29:49 -0800 (PST) Received: from localhost.localdomain (p4FD23A77.dip.t-dialin.net. [79.210.58.119]) by mx.google.com with ESMTPS id q42sm7197626eem.14.2013.03.08.03.29.47 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 08 Mar 2013 03:29:48 -0800 (PST) From: Bastian Hecht To: linux-sh@vger.kernel.org Cc: Magnus Damm , Paul Mundt , linux-arm-kernel@lists.infradead.org, Mark Rutland , Sergei Shtylyov Subject: [PATCH v2 3/7] clocksource: sh_tmu: Add OF support Date: Fri, 8 Mar 2013 12:29:37 +0100 Message-Id: <1362742181-19111-4-git-send-email-hechtb+renesas@gmail.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1362742181-19111-1-git-send-email-hechtb+renesas@gmail.com> References: <1362742181-19111-1-git-send-email-hechtb+renesas@gmail.com> Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org We add the capabilty to probe SH CMT timer devices using Device Tree setup. Signed-off-by: Bastian Hecht --- v2: new. Done analogously to the cmt driver drivers/clocksource/sh_tmu.c | 94 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 83 insertions(+), 11 deletions(-) diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index b4502edc..7d5c999 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -34,10 +34,13 @@ #include #include #include +#include struct sh_tmu_priv { void __iomem *mapbase; struct clk *clk; + long channel_offset; + int timer_bit; struct irqaction irqaction; struct platform_device *pdev; unsigned long rate; @@ -57,12 +60,11 @@ static DEFINE_RAW_SPINLOCK(sh_tmu_lock); static inline unsigned long sh_tmu_read(struct sh_tmu_priv *p, int reg_nr) { - struct sh_timer_config *cfg = p->pdev->dev.platform_data; void __iomem *base = p->mapbase; unsigned long offs; if (reg_nr == TSTR) - return ioread8(base - cfg->channel_offset); + return ioread8(base - p->channel_offset); offs = reg_nr << 2; @@ -75,12 +77,11 @@ static inline unsigned long sh_tmu_read(struct sh_tmu_priv *p, int reg_nr) static inline void sh_tmu_write(struct sh_tmu_priv *p, int reg_nr, unsigned long value) { - struct sh_timer_config *cfg = p->pdev->dev.platform_data; void __iomem *base = p->mapbase; unsigned long offs; if (reg_nr == TSTR) { - iowrite8(value, base - cfg->channel_offset); + iowrite8(value, base - p->channel_offset); return; } @@ -94,7 +95,6 @@ static inline void sh_tmu_write(struct sh_tmu_priv *p, int reg_nr, static void sh_tmu_start_stop_ch(struct sh_tmu_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 */ @@ -102,9 +102,9 @@ static void sh_tmu_start_stop_ch(struct sh_tmu_priv *p, int start) value = sh_tmu_read(p, TSTR); if (start) - value |= 1 << cfg->timer_bit; + value |= 1 << p->timer_bit; else - value &= ~(1 << cfg->timer_bit); + value &= ~(1 << p->timer_bit); sh_tmu_write(p, TSTR, value); raw_spin_unlock_irqrestore(&sh_tmu_lock, flags); @@ -421,9 +421,75 @@ static int sh_tmu_register(struct sh_tmu_priv *p, char *name, return 0; } -static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev) +static const struct of_device_id of_sh_tmu_match[] = { + { .compatible = "renesas,tmu-timer" }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_sh_tmu_match); + +#define TMU_OFFSET_MULTIPLIER 0xc +#define TMU_MAX_CHANNELS 3 + +static struct sh_timer_config *sh_tmu_parse_dt(struct device *dev) +{ + struct sh_timer_config *cfg; + struct device_node *np = dev->of_node; + u32 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,channel-id", &channel_id)) { + dev_err(dev, "channel id missing\n"); + return NULL; + } + if (channel_id >= TMU_MAX_CHANNELS) { + dev_err(dev, "invalid channel id\n"); + return NULL; + } + + cfg->channel_offset = channel_id * TMU_OFFSET_MULTIPLIER + 4; + 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_tmu_setup(struct sh_tmu_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; @@ -487,7 +553,7 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev) static int sh_tmu_probe(struct platform_device *pdev) { struct sh_tmu_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)) { @@ -495,6 +561,11 @@ static int sh_tmu_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); } + if (pdev->dev.of_node) + cfg = sh_tmu_parse_dt(&pdev->dev); + else + cfg = pdev->dev.platform_data; + if (p) { dev_info(&pdev->dev, "kept as earlytimer\n"); goto out; @@ -506,7 +577,7 @@ static int sh_tmu_probe(struct platform_device *pdev) return -ENOMEM; } - ret = sh_tmu_setup(p, pdev); + ret = sh_tmu_setup(p, pdev, cfg); if (ret) { kfree(p); platform_set_drvdata(pdev, NULL); @@ -535,6 +606,7 @@ static struct platform_driver sh_tmu_device_driver = { .remove = sh_tmu_remove, .driver = { .name = "sh_tmu", + .of_match_table = of_sh_tmu_match, } };