From patchwork Fri May 23 10:30:56 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 30732 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ie0-f197.google.com (mail-ie0-f197.google.com [209.85.223.197]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 6C3982066E for ; Fri, 23 May 2014 10:41:20 +0000 (UTC) Received: by mail-ie0-f197.google.com with SMTP id rd18sf22553247iec.8 for ; Fri, 23 May 2014 03:41:19 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:subject:date:message-id :in-reply-to:references:cc:precedence:list-id:list-unsubscribe :list-archive:list-post:list-help:list-subscribe:mime-version:sender :errors-to:x-original-sender:x-original-authentication-results :mailing-list:content-type:content-transfer-encoding; bh=Qg3GSuyBWFvDPr7gJpT6lr9M+AQSpw1YU4+6d4VP4Gw=; b=Na7ddMPifMqAfyWxWgwuQTaZ3VP0tF/O+kwaHabjwkWfqBkErxHL504n0bf77X98E/ iJJAaeMpSi1/5d8VKAtfK6tvoAf8nEiLW8sKqPrcb4H2IxfdWPlpOrRNXreD+pPxbYzI B9r93I9Piuw7xJ46AHZmZARtH1Fea7KqlW8TjJurpE/cU+uDQLXRwfbZw6qlrW+U3e0n MLp/c8We56kvTJW9/oXGzn7PUUrAtO29fKmV14nTC9CDyJ51ywbVcwP10r/LRUiCJ7R2 MJh4Unaye3eCaUz4G5dk7N0k7x8uJIjP5hNMIVXn72c2NAxU3ab19fEuD9G/D4nb4qIq TXrQ== X-Gm-Message-State: ALoCoQl3rW5Mnfaac9mQajeSr27VH/yCSbXQrYKi90FpCuTDzH+9Ks/kxkEOkd6KZf78tPj0/SuB X-Received: by 10.43.67.67 with SMTP id xt3mr1515798icb.23.1400841679933; Fri, 23 May 2014 03:41:19 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.82.37 with SMTP id g34ls1667676qgd.64.gmail; Fri, 23 May 2014 03:41:19 -0700 (PDT) X-Received: by 10.58.195.231 with SMTP id ih7mr3335896vec.32.1400841679811; Fri, 23 May 2014 03:41:19 -0700 (PDT) Received: from mail-ve0-f179.google.com (mail-ve0-f179.google.com [209.85.128.179]) by mx.google.com with ESMTPS id x1si1386637vep.70.2014.05.23.03.41.19 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 23 May 2014 03:41:19 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.128.179 as permitted sender) client-ip=209.85.128.179; Received: by mail-ve0-f179.google.com with SMTP id oy12so6012658veb.38 for ; Fri, 23 May 2014 03:41:19 -0700 (PDT) X-Received: by 10.52.96.8 with SMTP id do8mr1777216vdb.4.1400841679500; Fri, 23 May 2014 03:41:19 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.220.221.72 with SMTP id ib8csp20365vcb; Fri, 23 May 2014 03:41:19 -0700 (PDT) X-Received: by 10.224.37.130 with SMTP id x2mr5327245qad.36.1400841678996; Fri, 23 May 2014 03:41:18 -0700 (PDT) Received: from bombadil.infradead.org (bombadil.infradead.org. [2001:1868:205::9]) by mx.google.com with ESMTPS id p76si2963786qgd.71.2014.05.23.03.41.18 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 23 May 2014 03:41:18 -0700 (PDT) Received-SPF: none (google.com: linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org does not designate permitted sender hosts) client-ip=2001:1868:205::9; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1WnmsW-00070m-KQ; Fri, 23 May 2014 10:39:08 +0000 Received: from mail-wi0-f182.google.com ([209.85.212.182]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Wnmlq-0001El-Kg for linux-arm-kernel@lists.infradead.org; Fri, 23 May 2014 10:32:16 +0000 Received: by mail-wi0-f182.google.com with SMTP id r20so621047wiv.3 for ; Fri, 23 May 2014 03:31:56 -0700 (PDT) X-Received: by 10.180.92.103 with SMTP id cl7mr2459079wib.26.1400841115928; Fri, 23 May 2014 03:31:55 -0700 (PDT) Received: from localhost.localdomain (AToulouse-654-1-404-187.w82-125.abo.wanadoo.fr. [82.125.3.187]) by mx.google.com with ESMTPSA id s9sm2200908wix.13.2014.05.23.03.31.54 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 23 May 2014 03:31:55 -0700 (PDT) From: Daniel Lezcano To: tglx@linutronix.de, mingo@kernel.org Subject: [PATCH 16/71] clocksource: sh_cmt: Add support for multiple channels per device Date: Fri, 23 May 2014 12:30:56 +0200 Message-Id: <1400841111-6683-16-git-send-email-daniel.lezcano@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1400841111-6683-1-git-send-email-daniel.lezcano@linaro.org> References: <537F214C.8000700@linaro.org> <1400841111-6683-1-git-send-email-daniel.lezcano@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140523_033215_104936_41315735 X-CRM114-Status: GOOD ( 30.32 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.3.2 on bombadil.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.212.182 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record Cc: linux-kernel@vger.kernel.org, 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+patch=linaro.org@lists.infradead.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: daniel.lezcano@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.128.179 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 From: Laurent Pinchart CMT hardware devices can support multiple channels, with global registers and per-channel registers. The sh_cmt driver currently models the hardware with one Linux device per channel. This model makes it difficult to handle global registers in a clean way. Add support for a new model that uses one Linux device per timer with multiple channels per device. This requires changes to platform data, add new channel configuration fields. Support for the legacy model is kept and will be removed after all platforms switch to the new model. Signed-off-by: Laurent Pinchart --- drivers/clocksource/sh_cmt.c | 304 ++++++++++++++++++++++++++++++++---------- include/linux/sh_timer.h | 1 + 2 files changed, 237 insertions(+), 68 deletions(-) diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index c753efc..1efe7d6 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -53,7 +53,16 @@ struct sh_cmt_device; * channel registers block. All other versions have a shared start/stop register * located in the global space. * - * Note that CMT0 on r8a73a4, r8a7790 and r8a7791, while implementing 32-bit + * Channels are indexed from 0 to N-1 in the documentation. The channel index + * infers the start/stop bit position in the control register and the channel + * registers block address. Some CMT instances have a subset of channels + * available, in which case the index in the documentation doesn't match the + * "real" index as implemented in hardware. This is for instance the case with + * CMT0 on r8a7740, which is a 32-bit variant with a single channel numbered 0 + * in the documentation but using start/stop bit 5 and having its registers + * block at 0x60. + * + * Similarly CMT0 on r8a73a4, r8a7790 and r8a7791, while implementing 32-bit * channels only, is a 48-bit gen2 CMT with the 48-bit channels unavailable. */ @@ -85,10 +94,14 @@ struct sh_cmt_info { struct sh_cmt_channel { struct sh_cmt_device *cmt; - unsigned int index; - void __iomem *base; + unsigned int index; /* Index in the documentation */ + unsigned int hwidx; /* Real hardware index */ + + void __iomem *iostart; + void __iomem *ioctrl; + unsigned int timer_bit; unsigned long flags; unsigned long match_value; unsigned long next_match_value; @@ -105,6 +118,7 @@ struct sh_cmt_device { struct platform_device *pdev; const struct sh_cmt_info *info; + bool legacy; void __iomem *mapbase_ch; void __iomem *mapbase; @@ -112,6 +126,9 @@ struct sh_cmt_device { struct sh_cmt_channel *channels; unsigned int num_channels; + + bool has_clockevent; + bool has_clocksource; }; #define SH_CMT16_CMCSR_CMF (1 << 7) @@ -223,41 +240,47 @@ static const struct sh_cmt_info sh_cmt_info[] = { static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_channel *ch) { - return ch->cmt->info->read_control(ch->cmt->mapbase, 0); + if (ch->iostart) + return ch->cmt->info->read_control(ch->iostart, 0); + else + return ch->cmt->info->read_control(ch->cmt->mapbase, 0); } -static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_channel *ch) +static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch, + unsigned long value) { - return ch->cmt->info->read_control(ch->base, CMCSR); + if (ch->iostart) + ch->cmt->info->write_control(ch->iostart, 0, value); + else + ch->cmt->info->write_control(ch->cmt->mapbase, 0, value); } -static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_channel *ch) +static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_channel *ch) { - return ch->cmt->info->read_count(ch->base, CMCNT); + return ch->cmt->info->read_control(ch->ioctrl, CMCSR); } -static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch, +static inline void sh_cmt_write_cmcsr(struct sh_cmt_channel *ch, unsigned long value) { - ch->cmt->info->write_control(ch->cmt->mapbase, 0, value); + ch->cmt->info->write_control(ch->ioctrl, CMCSR, value); } -static inline void sh_cmt_write_cmcsr(struct sh_cmt_channel *ch, - unsigned long value) +static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_channel *ch) { - ch->cmt->info->write_control(ch->base, CMCSR, value); + return ch->cmt->info->read_count(ch->ioctrl, CMCNT); } static inline void sh_cmt_write_cmcnt(struct sh_cmt_channel *ch, unsigned long value) { - ch->cmt->info->write_count(ch->base, CMCNT, value); + ch->cmt->info->write_count(ch->ioctrl, CMCNT, value); } static inline void sh_cmt_write_cmcor(struct sh_cmt_channel *ch, unsigned long value) { - ch->cmt->info->write_count(ch->base, CMCOR, value); + ch->cmt->info->write_count(ch->ioctrl, CMCOR, value); } static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch, @@ -286,7 +309,6 @@ static DEFINE_RAW_SPINLOCK(sh_cmt_lock); static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start) { - struct sh_timer_config *cfg = ch->cmt->pdev->dev.platform_data; unsigned long flags, value; /* start stop register shared by multiple timer channels */ @@ -294,9 +316,9 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start) value = sh_cmt_read_cmstr(ch); if (start) - value |= 1 << cfg->timer_bit; + value |= 1 << ch->timer_bit; else - value &= ~(1 << cfg->timer_bit); + value &= ~(1 << ch->timer_bit); sh_cmt_write_cmstr(ch, value); raw_spin_unlock_irqrestore(&sh_cmt_lock, flags); @@ -790,27 +812,72 @@ static void sh_cmt_register_clockevent(struct sh_cmt_channel *ch, static int sh_cmt_register(struct sh_cmt_channel *ch, const char *name, bool clockevent, bool clocksource) { - if (clockevent) + if (clockevent) { + ch->cmt->has_clockevent = true; sh_cmt_register_clockevent(ch, name); + } - if (clocksource) + if (clocksource) { + ch->cmt->has_clocksource = true; sh_cmt_register_clocksource(ch, name); + } return 0; } static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index, - struct sh_cmt_device *cmt) + unsigned int hwidx, bool clockevent, + bool clocksource, struct sh_cmt_device *cmt) { - struct sh_timer_config *cfg = cmt->pdev->dev.platform_data; int irq; int ret; + /* Skip unused channels. */ + if (!clockevent && !clocksource) + return 0; + ch->cmt = cmt; - ch->base = cmt->mapbase_ch; ch->index = index; + ch->hwidx = hwidx; + + /* + * Compute the address of the channel control register block. For the + * timers with a per-channel start/stop register, compute its address + * as well. + * + * For legacy configuration the address has been mapped explicitly. + */ + if (cmt->legacy) { + ch->ioctrl = cmt->mapbase_ch; + } else { + switch (cmt->info->model) { + case SH_CMT_16BIT: + ch->ioctrl = cmt->mapbase + 2 + ch->hwidx * 6; + break; + case SH_CMT_32BIT: + case SH_CMT_48BIT: + ch->ioctrl = cmt->mapbase + 0x10 + ch->hwidx * 0x10; + break; + case SH_CMT_32BIT_FAST: + /* + * The 32-bit "fast" timer has a single channel at hwidx + * 5 but is located at offset 0x40 instead of 0x60 for + * some reason. + */ + ch->ioctrl = cmt->mapbase + 0x40; + break; + case SH_CMT_48BIT_GEN2: + ch->iostart = cmt->mapbase + ch->hwidx * 0x100; + ch->ioctrl = ch->iostart + 0x10; + break; + } + } + + if (cmt->legacy) + irq = platform_get_irq(cmt->pdev, 0); + else + irq = platform_get_irq(cmt->pdev, ch->index); - irq = platform_get_irq(cmt->pdev, 0); if (irq < 0) { dev_err(&cmt->pdev->dev, "ch%u: failed to get irq\n", ch->index); @@ -825,9 +892,15 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index, ch->match_value = ch->max_match_value; raw_spin_lock_init(&ch->lock); + if (cmt->legacy) { + ch->timer_bit = ch->hwidx; + } else { + ch->timer_bit = cmt->info->model == SH_CMT_48BIT_GEN2 + ? 0 : ch->hwidx; + } + ret = sh_cmt_register(ch, dev_name(&cmt->pdev->dev), - cfg->clockevent_rating != 0, - cfg->clocksource_rating != 0); + clockevent, clocksource); if (ret) { dev_err(&cmt->pdev->dev, "ch%u: registration failed\n", ch->index); @@ -847,97 +920,180 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index, return 0; } -static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) +static int sh_cmt_map_memory(struct sh_cmt_device *cmt) { - struct sh_timer_config *cfg = pdev->dev.platform_data; - struct resource *res, *res2; - int ret; - ret = -ENXIO; + struct resource *mem; - cmt->pdev = pdev; + mem = platform_get_resource(cmt->pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&cmt->pdev->dev, "failed to get I/O memory\n"); + return -ENXIO; + } - if (!cfg) { - dev_err(&cmt->pdev->dev, "missing platform data\n"); - goto err0; + cmt->mapbase = ioremap_nocache(mem->start, resource_size(mem)); + if (cmt->mapbase == NULL) { + dev_err(&cmt->pdev->dev, "failed to remap I/O memory\n"); + return -ENXIO; } + return 0; +} + +static int sh_cmt_map_memory_legacy(struct sh_cmt_device *cmt) +{ + struct sh_timer_config *cfg = cmt->pdev->dev.platform_data; + struct resource *res, *res2; + + /* map memory, let mapbase_ch point to our channel */ res = platform_get_resource(cmt->pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&cmt->pdev->dev, "failed to get I/O memory\n"); - goto err0; + return -ENXIO; } - /* optional resource for the shared timer start/stop register */ - res2 = platform_get_resource(cmt->pdev, IORESOURCE_MEM, 1); - - /* map memory, let mapbase_ch point to our channel */ cmt->mapbase_ch = ioremap_nocache(res->start, resource_size(res)); if (cmt->mapbase_ch == NULL) { dev_err(&cmt->pdev->dev, "failed to remap I/O memory\n"); - goto err0; + return -ENXIO; } + /* optional resource for the shared timer start/stop register */ + res2 = platform_get_resource(cmt->pdev, IORESOURCE_MEM, 1); + /* map second resource for CMSTR */ cmt->mapbase = ioremap_nocache(res2 ? res2->start : res->start - cfg->channel_offset, res2 ? resource_size(res2) : 2); if (cmt->mapbase == NULL) { dev_err(&cmt->pdev->dev, "failed to remap I/O second memory\n"); - goto err1; + iounmap(cmt->mapbase_ch); + return -ENXIO; } - /* get hold of clock */ + /* identify the model based on the resources */ + if (resource_size(res) == 6) + cmt->info = &sh_cmt_info[SH_CMT_16BIT]; + else if (res2 && (resource_size(res2) == 4)) + cmt->info = &sh_cmt_info[SH_CMT_48BIT_GEN2]; + else + cmt->info = &sh_cmt_info[SH_CMT_32BIT]; + + return 0; +} + +static void sh_cmt_unmap_memory(struct sh_cmt_device *cmt) +{ + iounmap(cmt->mapbase); + if (cmt->mapbase_ch) + iounmap(cmt->mapbase_ch); +} + +static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) +{ + struct sh_timer_config *cfg = pdev->dev.platform_data; + const struct platform_device_id *id = pdev->id_entry; + unsigned int hw_channels; + int ret; + + memset(cmt, 0, sizeof(*cmt)); + cmt->pdev = pdev; + + if (!cfg) { + dev_err(&cmt->pdev->dev, "missing platform data\n"); + return -ENXIO; + } + + cmt->info = (const struct sh_cmt_info *)id->driver_data; + cmt->legacy = cmt->info ? false : true; + + /* Get hold of clock. */ cmt->clk = clk_get(&cmt->pdev->dev, "cmt_fck"); if (IS_ERR(cmt->clk)) { dev_err(&cmt->pdev->dev, "cannot get clock\n"); - ret = PTR_ERR(cmt->clk); - goto err2; + return PTR_ERR(cmt->clk); } ret = clk_prepare(cmt->clk); if (ret < 0) - goto err3; + goto err_clk_put; - /* identify the model based on the resources */ - if (resource_size(res) == 6) - cmt->info = &sh_cmt_info[SH_CMT_16BIT]; - else if (res2 && (resource_size(res2) == 4)) - cmt->info = &sh_cmt_info[SH_CMT_48BIT_GEN2]; + /* + * Map the memory resource(s). We need to support both the legacy + * platform device configuration (with one device per channel) and the + * new version (with multiple channels per device). + */ + if (cmt->legacy) + ret = sh_cmt_map_memory_legacy(cmt); else - cmt->info = &sh_cmt_info[SH_CMT_32BIT]; + ret = sh_cmt_map_memory(cmt); - cmt->channels = kzalloc(sizeof(*cmt->channels), GFP_KERNEL); + if (ret < 0) + goto err_clk_unprepare; + + /* Allocate and setup the channels. */ + if (cmt->legacy) { + cmt->num_channels = 1; + hw_channels = 0; + } else { + cmt->num_channels = hweight8(cfg->channels_mask); + hw_channels = cfg->channels_mask; + } + + cmt->channels = kzalloc(cmt->num_channels * sizeof(*cmt->channels), + GFP_KERNEL); if (cmt->channels == NULL) { ret = -ENOMEM; - goto err4; + goto err_unmap; } - cmt->num_channels = 1; + if (cmt->legacy) { + ret = sh_cmt_setup_channel(&cmt->channels[0], + cfg->timer_bit, cfg->timer_bit, + cfg->clockevent_rating != 0, + cfg->clocksource_rating != 0, cmt); + if (ret < 0) + goto err_unmap; + } else { + unsigned int mask = hw_channels; + unsigned int i; - ret = sh_cmt_setup_channel(&cmt->channels[0], cfg->timer_bit, cmt); - if (ret < 0) - goto err4; + /* + * Use the first channel as a clock event device and the second + * channel as a clock source. If only one channel is available + * use it for both. + */ + for (i = 0; i < cmt->num_channels; ++i) { + unsigned int hwidx = ffs(mask) - 1; + bool clocksource = i == 1 || cmt->num_channels == 1; + bool clockevent = i == 0; + + ret = sh_cmt_setup_channel(&cmt->channels[i], i, hwidx, + clockevent, clocksource, + cmt); + if (ret < 0) + goto err_unmap; + + mask &= ~(1 << hwidx); + } + } platform_set_drvdata(pdev, cmt); return 0; -err4: + +err_unmap: kfree(cmt->channels); + sh_cmt_unmap_memory(cmt); +err_clk_unprepare: clk_unprepare(cmt->clk); -err3: +err_clk_put: clk_put(cmt->clk); -err2: - iounmap(cmt->mapbase); -err1: - iounmap(cmt->mapbase_ch); -err0: return ret; } static int sh_cmt_probe(struct platform_device *pdev) { struct sh_cmt_device *cmt = platform_get_drvdata(pdev); - struct sh_timer_config *cfg = pdev->dev.platform_data; int ret; if (!is_early_platform_device(pdev)) { @@ -966,7 +1122,7 @@ static int sh_cmt_probe(struct platform_device *pdev) return 0; out: - if (cfg->clockevent_rating || cfg->clocksource_rating) + if (cmt->has_clockevent || cmt->has_clocksource) pm_runtime_irq_safe(&pdev->dev); else pm_runtime_idle(&pdev->dev); @@ -979,12 +1135,24 @@ static int sh_cmt_remove(struct platform_device *pdev) return -EBUSY; /* cannot unregister clockevent and clocksource */ } +static const struct platform_device_id sh_cmt_id_table[] = { + { "sh_cmt", 0 }, + { "sh-cmt-16", (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT] }, + { "sh-cmt-32", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT] }, + { "sh-cmt-32-fast", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT_FAST] }, + { "sh-cmt-48", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT] }, + { "sh-cmt-48-gen2", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT_GEN2] }, + { } +}; +MODULE_DEVICE_TABLE(platform, sh_cmt_id_table); + static struct platform_driver sh_cmt_device_driver = { .probe = sh_cmt_probe, .remove = sh_cmt_remove, .driver = { .name = "sh_cmt", - } + }, + .id_table = sh_cmt_id_table, }; static int __init sh_cmt_init(void) diff --git a/include/linux/sh_timer.h b/include/linux/sh_timer.h index 4d9dcd1..8e1e036 100644 --- a/include/linux/sh_timer.h +++ b/include/linux/sh_timer.h @@ -7,6 +7,7 @@ struct sh_timer_config { int timer_bit; unsigned long clockevent_rating; unsigned long clocksource_rating; + unsigned int channels_mask; }; #endif /* __SH_TIMER_H__ */