From patchwork Fri Mar 1 17:45:30 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bastian Hecht X-Patchwork-Id: 2202311 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 AF1D43FCA4 for ; Fri, 1 Mar 2013 16:45:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751256Ab3CAQpj (ORCPT ); Fri, 1 Mar 2013 11:45:39 -0500 Received: from mail-qe0-f42.google.com ([209.85.128.42]:44829 "EHLO mail-qe0-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750910Ab3CAQpi (ORCPT ); Fri, 1 Mar 2013 11:45:38 -0500 Received: by mail-qe0-f42.google.com with SMTP id f6so2491828qej.1 for ; Fri, 01 Mar 2013 08:45:38 -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=Bf3j9wSFu+KzQUdlKfZ/uLDuu+hpCXhnHqNxKnOylDI=; b=u7okLrD0dun9h+5UfHvIPeQ8A5vFRZz4HW/aQ9V3VRP0pT1JxCwHjOjv0XD6Z79C8+ c9acvEcmVIuwjrupOnMewsBmrWUUD09iqMVl57AEMChIBefhtlJ2xfeKIzZ1TQ3vKjo6 jA/S/qWHGN+UTmTubXRyMeRiRLVE6aWL+WcE2gjiLSlxc36uNRrmASZb7TbmKvmMq7cs 79NS0pUqjrBEpGq79BEBW8jSK2mZSagrJ04r2/Vxwd8n/1HhJDc7q5klLl43B4LeBaAW xo8WceDLzM7KMsd20p5+wQ/BxbR/XLm6AbycrlUO8JB5vzdK3TT3RzMTQkOqb18YJQpm 2Z8A== X-Received: by 10.49.16.135 with SMTP id g7mr19008569qed.8.1362156337979; Fri, 01 Mar 2013 08:45:37 -0800 (PST) Received: from bender.routerdd3bcc.com (rrcs-50-74-208-202.nyc.biz.rr.com. [50.74.208.202]) by mx.google.com with ESMTPS id hr3sm20805038qab.4.2013.03.01.08.45.36 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 01 Mar 2013 08:45:37 -0800 (PST) From: Bastian Hecht To: linux-sh@vger.kernel.org Cc: Magnus Damm , linux-arm-kernel@lists.infradead.org Subject: [PATCH 1/3] clocksource: sh_cmt: Add Device Tree probing Date: Fri, 1 Mar 2013 11:45:30 -0600 Message-Id: <1362159932-18533-2-git-send-email-hechtb+renesas@gmail.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1362159932-18533-1-git-send-email-hechtb+renesas@gmail.com> References: <1362159932-18533-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. We can deduce former platform data by the device IDs and channel IDs of our timer instances, so we choose this more intuitive info as our DT properties. Signed-off-by: Bastian Hecht --- .../bindings/timer/renesas,sh-cmt-timer.txt | 21 +++++ drivers/clocksource/sh_cmt.c | 94 +++++++++++++++++--- 2 files changed, 102 insertions(+), 13 deletions(-) create mode 100644 Documentation/devicetree/bindings/timer/renesas,sh-cmt-timer.txt diff --git a/Documentation/devicetree/bindings/timer/renesas,sh-cmt-timer.txt b/Documentation/devicetree/bindings/timer/renesas,sh-cmt-timer.txt new file mode 100644 index 0000000..e5ad808 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/renesas,sh-cmt-timer.txt @@ -0,0 +1,21 @@ +* Renesas SH Mobile Compare Match Timer + +Required properties: +- compatible : Should be "renesas,cmt" +- reg : Address and length of the register set for the device +- interrupts : Timer IRQ +- renesas,timer-device-id : The ID of the timer device +- renesas,timer-channel-id : The channel ID of the timer device + +Example for CMT10 of the R8A7740 SoC: + + cmt@0xe6138010 { + compatible = "renesas,cmt"; + interrupt-parent = <&intca>; + reg = <0xe6138010 0xc>; + interrupts = <0x0b00>; + renesas,timer-device-id = <1>; + renesas,timer-channel-id = <0>; + renesas,clocksource-rating = <150>; + renesas,clockevent-rating = <150>; + }; diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index b72b724..9a7a7d4 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -38,6 +38,8 @@ 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 +111,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 +127,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 +174,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 +181,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,9 +670,71 @@ 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) +#ifdef CONFIG_OF +static const struct of_device_id of_sh_cmt_match[] = { + { .compatible = "renesas,cmt" }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_sh_cmt_match); + +static const int sh_timer_offset_multiplier[] = { 0x60, 0x10, 0x40, 0x40 }; + +static struct sh_timer_config *sh_cmt_parse_dt(struct device *dev) +{ + struct sh_timer_config *cfg; + struct device_node *np = dev->of_node; + const __be32 *prop; + int timer_id, channel_id; + + 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; + } + + prop = of_get_property(np, "renesas,timer-device-id", NULL); + if (!prop) { + dev_err(dev, "device id missing\n"); + return NULL; + } + timer_id = be32_to_cpup(prop); + + prop = of_get_property(np, "renesas,timer-channel-id", NULL); + if (!prop) { + dev_err(dev, "channel id missing\n"); + return NULL; + } + channel_id = be32_to_cpup(prop); + + if (timer_id >= ARRAY_SIZE(sh_timer_offset_multiplier)) { + dev_err(dev, "unsupported timer id\n"); + return NULL; + } + + cfg->channel_offset = sh_timer_offset_multiplier[timer_id] * + (channel_id + 1); + cfg->timer_bit = channel_id; + + prop = of_get_property(np, "renesas,clocksource-rating", NULL); + if (prop) + cfg->clocksource_rating = be32_to_cpup(prop); + + prop = of_get_property(np, "renesas,clockevent-rating", NULL); + if (prop) + cfg->clockevent_rating = be32_to_cpup(prop); + + return cfg; +} +#else +static struct sh_timer_config *sh_cmt_parse_dt(struct device *dev) +{ + return NULL; +} +#endif /* CONFIG_OF */ + +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; @@ -762,6 +821,9 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) goto err2; } + p->channel_offset = cfg->channel_offset; + p->timer_bit = cfg->timer_bit; + platform_set_drvdata(pdev, p); return 0; @@ -777,7 +839,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 +847,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 +863,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 +891,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), } };