From patchwork Wed May 17 14:05:38 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 99978 Delivered-To: patch@linaro.org Received: by 10.182.142.97 with SMTP id rv1csp230032obb; Wed, 17 May 2017 07:07:14 -0700 (PDT) X-Received: by 10.98.3.133 with SMTP id 127mr3768491pfd.172.1495030033946; Wed, 17 May 2017 07:07:13 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1495030033; cv=none; d=google.com; s=arc-20160816; b=nM2+uCMZW52XzZ+o6Y9qDBBJ4I9gjrPL4nLKj7GyvaZrqehsmqzo9lA20d4KVXGcwM pYarA0+6YbZ5FKlSJHF18MXeztM8/Q+XjrRCvLJGVFvduoufNV0s9mgzUspZNW4XLPGl RVPV5wSEGaywHK9OLWqP3hb9ANxO3TufeEtjlJ6t4UR6tfI5rqIJorCFci6pGy4WxMyA maeCvWfAoc3Z57r78ZvHGeBuPmS7W1yaUpehT9bU1L1s1rVE+MQUdDHLfCsdpc/WAeuP 8K1Y7xtpL6HzTsIKJKu5xa2cwwfp3LCtNVS9om2t4iKmZ0ev9MC+2us++LCTO+FwdIzN BAeA== 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=9Dg0dZONfEa7vGmPehcXB6yB0OlEYbTFa2j+gs2U6oU=; b=k4hCWwlG5LV0BKg5nfXNaGyTAU7ax1xj5mAkWJ3qupb5CWrd96K041x1u2poq+1Zp+ 3OQGbUocSpw7He88R3VNcNHdJL9YebKtAq5gXKdwGWWJlsHCLcQW+cjUP2xgrsEs6kxm FO4M+FbApbtPWI5O4wrF0mlF2WiWhVtEwx8ncYAv2GJOjjQ2EPbwL/Y8CFngK35VJEYO R7ZyMyxaiTsVeM0VoIfXnqvf632BcRTKXrFWie4OOVDwbaxW8I66iaybSL/fhI5iPITo 1gCcLBpUwQnlqNSIALY9mga0uX0sCuSM3J6vejO9svCkLD2kR2gqvpJjy1JIA+yMUf4z LjJw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org; 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 b5si2193574pfc.53.2017.05.17.07.07.13; Wed, 17 May 2017 07:07:13 -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; 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 S932115AbdEQOG5 (ORCPT + 25 others); Wed, 17 May 2017 10:06:57 -0400 Received: from mail-wm0-f54.google.com ([74.125.82.54]:35231 "EHLO mail-wm0-f54.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753949AbdEQOGp (ORCPT ); Wed, 17 May 2017 10:06:45 -0400 Received: by mail-wm0-f54.google.com with SMTP id b84so166555957wmh.0 for ; Wed, 17 May 2017 07:06:44 -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=9Dg0dZONfEa7vGmPehcXB6yB0OlEYbTFa2j+gs2U6oU=; b=L5yVEEM5ZnBJQ7gfXxLVaqcJh8T1HW8AbLEHuR9xCN+/gg11Hks7ro4gTkD7FlSFUG PeoDQF2PHUK0rZGj7jj1LF81GjyzxmPKYSNXqJTnTbCl1tyvt2qsVMqp504Bh/SFC1/t f9ZXweDAmrdikYXl2j6N4Bj2sftUWIMcR5lwU= 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=9Dg0dZONfEa7vGmPehcXB6yB0OlEYbTFa2j+gs2U6oU=; b=ctQK8a7pe4KFXTPUCjCvIEyiKqpHXAQNt/EFMrh+Q+63QFYixcjx/RKYu6SBHvZz/1 ++1/XxdYaD5RnV/Jy07Snl0W5UrsLOUG8NjMAY/Db1DpbG+OkXI0B2d6b+NvFh66iKxS D8iR82iq8bBp3IH7VLhKRmVkhv6aeO1oydHoAkwLcebaz5F7bxLULidJy6NUmyeFavcN zUSGn7o2bP3ZVV88DmdaEAcgSlUwqwCqEuswpsybtk0Iq4JnXSxwkadcsP/yHPdHZ62L z2eXnOEpMu131yN1Mcr1UbzvrFn4adrSnP6OO/BgDKnf3aHuRBwOcAr4O1icGKGd8hGu iTpw== X-Gm-Message-State: AODbwcAlLSNQFwJn8sfouEmYD/eooWsLWEweAgHOpl7Vl7tdkvLxQ/Fs VOHeHgL+h/7UTXTK X-Received: by 10.25.25.139 with SMTP id 133mr986854lfz.33.1495030003196; Wed, 17 May 2017 07:06:43 -0700 (PDT) Received: from fabina.bredbandsbolaget.se (c-3c94db54.014-348-6c756e10.cust.bredbandsbolaget.se. [84.219.148.60]) by smtp.gmail.com with ESMTPSA id 139sm409680ljj.16.2017.05.17.07.06.41 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 17 May 2017 07:06:41 -0700 (PDT) From: Linus Walleij To: Daniel Lezcano , Thomas Gleixner , Joel Stanley , Jonas Jensen Cc: Janos Laube , Paulius Zaleckas , linux-arm-kernel@lists.infradead.org, Hans Ulli Kroll , Florian Fainelli , linux-kernel@vger.kernel.org, Linus Walleij Subject: [PATCH 4/8] clocksource/drivers/fttmr010: Use state container Date: Wed, 17 May 2017 16:05:38 +0200 Message-Id: <20170517140542.20016-5-linus.walleij@linaro.org> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20170517140542.20016-1-linus.walleij@linaro.org> References: <20170517140542.20016-1-linus.walleij@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This converts the Faraday FTTMR010 to use the state container design pattern. Take some care to handle the state container and free:ing of resources as has been done in the Moxa driver. Cc: Joel Stanley Cc: Jonas Jensen Signed-off-by: Linus Walleij --- drivers/clocksource/timer-fttmr010.c | 190 +++++++++++++++++++++-------------- 1 file changed, 116 insertions(+), 74 deletions(-) -- 2.9.3 diff --git a/drivers/clocksource/timer-fttmr010.c b/drivers/clocksource/timer-fttmr010.c index db097db346e3..9ad31489bbef 100644 --- a/drivers/clocksource/timer-fttmr010.c +++ b/drivers/clocksource/timer-fttmr010.c @@ -15,6 +15,7 @@ #include #include #include +#include /* * Register definitions for the timers @@ -62,23 +63,35 @@ #define TIMER_3_INT_OVERFLOW (1 << 8) #define TIMER_INT_ALL_MASK 0x1ff -static unsigned int tick_rate; -static void __iomem *base; +struct fttmr010 { + void __iomem *base; + unsigned int tick_rate; + struct clock_event_device clkevt; +}; + +/* A local singleton used by sched_clock, which is stateless */ +static struct fttmr010 *local_fttmr; + +static inline struct fttmr010 *to_fttmr010(struct clock_event_device *evt) +{ + return container_of(evt, struct fttmr010, clkevt); +} static u64 notrace fttmr010_read_sched_clock(void) { - return readl(base + TIMER3_COUNT); + return readl(local_fttmr->base + TIMER3_COUNT); } static int fttmr010_timer_set_next_event(unsigned long cycles, struct clock_event_device *evt) { + struct fttmr010 *fttmr010 = to_fttmr010(evt); u32 cr; /* Setup the match register */ - cr = readl(base + TIMER1_COUNT); - writel(cr + cycles, base + TIMER1_MATCH1); - if (readl(base + TIMER1_COUNT) - cr > cycles) + cr = readl(fttmr010->base + TIMER1_COUNT); + writel(cr + cycles, fttmr010->base + TIMER1_MATCH1); + if (readl(fttmr010->base + TIMER1_COUNT) - cr > cycles) return -ETIME; return 0; @@ -86,99 +99,90 @@ static int fttmr010_timer_set_next_event(unsigned long cycles, static int fttmr010_timer_shutdown(struct clock_event_device *evt) { + struct fttmr010 *fttmr010 = to_fttmr010(evt); + u32 cr; + + /* Stop timer and interrupt. */ + cr = readl(fttmr010->base + TIMER_CR); + cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); + writel(cr, fttmr010->base + TIMER_CR); + + return 0; +} + +static int fttmr010_timer_set_oneshot(struct clock_event_device *evt) +{ + struct fttmr010 *fttmr010 = to_fttmr010(evt); u32 cr; - /* - * Disable also for oneshot: the set_next() call will arm the timer - * instead. - */ /* Stop timer and interrupt. */ - cr = readl(base + TIMER_CR); + cr = readl(fttmr010->base + TIMER_CR); cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); - writel(cr, base + TIMER_CR); + writel(cr, fttmr010->base + TIMER_CR); /* Setup counter start from 0 */ - writel(0, base + TIMER1_COUNT); - writel(0, base + TIMER1_LOAD); + writel(0, fttmr010->base + TIMER1_COUNT); + writel(0, fttmr010->base + TIMER1_LOAD); - /* enable interrupt */ - cr = readl(base + TIMER_INTR_MASK); + /* Enable interrupt */ + cr = readl(fttmr010->base + TIMER_INTR_MASK); cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2); cr |= TIMER_1_INT_MATCH1; - writel(cr, base + TIMER_INTR_MASK); + writel(cr, fttmr010->base + TIMER_INTR_MASK); - /* start the timer */ - cr = readl(base + TIMER_CR); + /* Start the timer */ + cr = readl(fttmr010->base + TIMER_CR); cr |= TIMER_1_CR_ENABLE; - writel(cr, base + TIMER_CR); + writel(cr, fttmr010->base + TIMER_CR); return 0; } static int fttmr010_timer_set_periodic(struct clock_event_device *evt) { - u32 period = DIV_ROUND_CLOSEST(tick_rate, HZ); + struct fttmr010 *fttmr010 = to_fttmr010(evt); + u32 period = DIV_ROUND_CLOSEST(fttmr010->tick_rate, HZ); u32 cr; /* Stop timer and interrupt */ - cr = readl(base + TIMER_CR); + cr = readl(fttmr010->base + TIMER_CR); cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); - writel(cr, base + TIMER_CR); + writel(cr, fttmr010->base + TIMER_CR); /* Setup timer to fire at 1/HT intervals. */ cr = 0xffffffff - (period - 1); - writel(cr, base + TIMER1_COUNT); - writel(cr, base + TIMER1_LOAD); + writel(cr, fttmr010->base + TIMER1_COUNT); + writel(cr, fttmr010->base + TIMER1_LOAD); /* enable interrupt on overflow */ - cr = readl(base + TIMER_INTR_MASK); + cr = readl(fttmr010->base + TIMER_INTR_MASK); cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2); cr |= TIMER_1_INT_OVERFLOW; - writel(cr, base + TIMER_INTR_MASK); + writel(cr, fttmr010->base + TIMER_INTR_MASK); /* Start the timer */ - cr = readl(base + TIMER_CR); + cr = readl(fttmr010->base + TIMER_CR); cr |= TIMER_1_CR_ENABLE; cr |= TIMER_1_CR_INT; - writel(cr, base + TIMER_CR); + writel(cr, fttmr010->base + TIMER_CR); return 0; } -/* Use TIMER1 as clock event */ -static struct clock_event_device fttmr010_clockevent = { - .name = "TIMER1", - /* Reasonably fast and accurate clock event */ - .rating = 300, - .shift = 32, - .features = CLOCK_EVT_FEAT_PERIODIC | - CLOCK_EVT_FEAT_ONESHOT, - .set_next_event = fttmr010_timer_set_next_event, - .set_state_shutdown = fttmr010_timer_shutdown, - .set_state_periodic = fttmr010_timer_set_periodic, - .set_state_oneshot = fttmr010_timer_shutdown, - .tick_resume = fttmr010_timer_shutdown, -}; - /* * IRQ handler for the timer */ static irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id) { - struct clock_event_device *evt = &fttmr010_clockevent; + struct clock_event_device *evt = dev_id; evt->event_handler(evt); return IRQ_HANDLED; } -static struct irqaction fttmr010_timer_irq = { - .name = "Faraday FTTMR010 Timer Tick", - .flags = IRQF_TIMER, - .handler = fttmr010_timer_interrupt, -}; - static int __init fttmr010_timer_init(struct device_node *np) { + struct fttmr010 *fttmr010; int irq; struct clk *clk; int ret; @@ -198,53 +202,91 @@ static int __init fttmr010_timer_init(struct device_node *np) pr_err("failed to enable PCLK\n"); return ret; } - tick_rate = clk_get_rate(clk); - base = of_iomap(np, 0); - if (!base) { + fttmr010 = kzalloc(sizeof(*fttmr010), GFP_KERNEL); + if (!fttmr010) { + ret = -ENOMEM; + goto out_disable_clock; + } + fttmr010->tick_rate = clk_get_rate(clk); + + fttmr010->base = of_iomap(np, 0); + if (!fttmr010->base) { pr_err("Can't remap registers"); - return -ENXIO; + ret = -ENXIO; + goto out_free; } /* IRQ for timer 1 */ irq = irq_of_parse_and_map(np, 0); if (irq <= 0) { pr_err("Can't parse IRQ"); - return -EINVAL; + ret = -EINVAL; + goto out_unmap; } /* * Reset the interrupt mask and status */ - writel(TIMER_INT_ALL_MASK, base + TIMER_INTR_MASK); - writel(0, base + TIMER_INTR_STATE); - writel(TIMER_DEFAULT_FLAGS, base + TIMER_CR); + writel(TIMER_INT_ALL_MASK, fttmr010->base + TIMER_INTR_MASK); + writel(0, fttmr010->base + TIMER_INTR_STATE); + writel(TIMER_DEFAULT_FLAGS, fttmr010->base + TIMER_CR); /* * Setup free-running clocksource timer (interrupts * disabled.) */ - writel(0, base + TIMER3_COUNT); - writel(0, base + TIMER3_LOAD); - writel(0, base + TIMER3_MATCH1); - writel(0, base + TIMER3_MATCH2); - clocksource_mmio_init(base + TIMER3_COUNT, - "fttmr010_clocksource", tick_rate, + local_fttmr = fttmr010; + writel(0, fttmr010->base + TIMER3_COUNT); + writel(0, fttmr010->base + TIMER3_LOAD); + writel(0, fttmr010->base + TIMER3_MATCH1); + writel(0, fttmr010->base + TIMER3_MATCH2); + clocksource_mmio_init(fttmr010->base + TIMER3_COUNT, + "FTTMR010-TIMER3", + fttmr010->tick_rate, 300, 32, clocksource_mmio_readl_up); - sched_clock_register(fttmr010_read_sched_clock, 32, tick_rate); + sched_clock_register(fttmr010_read_sched_clock, 32, + fttmr010->tick_rate); /* - * Setup clockevent timer (interrupt-driven.) + * Setup clockevent timer (interrupt-driven) on timer 1. */ - writel(0, base + TIMER1_COUNT); - writel(0, base + TIMER1_LOAD); - writel(0, base + TIMER1_MATCH1); - writel(0, base + TIMER1_MATCH2); - setup_irq(irq, &fttmr010_timer_irq); - fttmr010_clockevent.cpumask = cpumask_of(0); - clockevents_config_and_register(&fttmr010_clockevent, tick_rate, + writel(0, fttmr010->base + TIMER1_COUNT); + writel(0, fttmr010->base + TIMER1_LOAD); + writel(0, fttmr010->base + TIMER1_MATCH1); + writel(0, fttmr010->base + TIMER1_MATCH2); + ret = request_irq(irq, fttmr010_timer_interrupt, IRQF_TIMER, + "FTTMR010-TIMER1", &fttmr010->clkevt); + if (ret) { + pr_err("FTTMR010-TIMER1 no IRQ\n"); + goto out_unmap; + } + + fttmr010->clkevt.name = "FTTMR010-TIMER1"; + /* Reasonably fast and accurate clock event */ + fttmr010->clkevt.rating = 300; + fttmr010->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT; + fttmr010->clkevt.set_next_event = fttmr010_timer_set_next_event; + fttmr010->clkevt.set_state_shutdown = fttmr010_timer_shutdown; + fttmr010->clkevt.set_state_periodic = fttmr010_timer_set_periodic; + fttmr010->clkevt.set_state_oneshot = fttmr010_timer_set_oneshot; + fttmr010->clkevt.tick_resume = fttmr010_timer_shutdown; + fttmr010->clkevt.cpumask = cpumask_of(0); + fttmr010->clkevt.irq = irq; + clockevents_config_and_register(&fttmr010->clkevt, + fttmr010->tick_rate, 1, 0xffffffff); return 0; + +out_unmap: + iounmap(fttmr010->base); +out_free: + kfree(fttmr010); +out_disable_clock: + clk_disable_unprepare(clk); + + return ret; } CLOCKSOURCE_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_init); CLOCKSOURCE_OF_DECLARE(gemini, "cortina,gemini-timer", fttmr010_timer_init);