From patchwork Fri Feb 23 10:17:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ladislav Michl X-Patchwork-Id: 10237287 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id A1B95602A0 for ; Fri, 23 Feb 2018 10:22:18 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 809F62950C for ; Fri, 23 Feb 2018 10:22:18 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 74DA32950E; Fri, 23 Feb 2018 10:22:18 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 9472A2950C for ; Fri, 23 Feb 2018 10:22:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:In-Reply-To:MIME-Version:References: Message-ID:Subject:To:From:Date:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=PLJtVqXdiRF2ZiZvrEK0AHH4+fdnfBEP+SLcls7+umU=; b=Hf/mW+XyHpa38M 3F3vSfoPDBIjrEG7kBvxGBaRqI0I9Jsoy39tD9ayaNRhsoHrKfFsO725Rbg7OReWAgeCMJ8TmQbOv 2OJX31KSKphKUuwT8gqgDPEySGuv6DeeJOrTrTv9RQxir42jYmilutENArwxBmo2PnKTkycaqm6Ph QqjWQ5C8I5DjqHroRFDxtL869HqVUSkGPG5GzdVT/6NnT3c4hRKyVw7KhltM5GQ759ZEq4FIHF5QZ nOoiU36HGeouTbVG1PbaVNsipD6PIhfEP/GWyyIL+oVUNlB0fs7jTtRvUWfo+qBMPYU67hcVkBARY 4gQnFzWb3ZDkbYfuYC8w==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.89 #1 (Red Hat Linux)) id 1epAUQ-0004w1-Gp; Fri, 23 Feb 2018 10:22:06 +0000 Received: from eddie.linux-mips.org ([148.251.95.138] helo=cvs.linux-mips.org) by bombadil.infradead.org with esmtp (Exim 4.89 #1 (Red Hat Linux)) id 1epAQT-0000Lf-QG for linux-arm-kernel@lists.infradead.org; Fri, 23 Feb 2018 10:19:54 +0000 Received: (from localhost user: 'ladis' uid#1021 fake: STDIN (ladis@eddie.linux-mips.org)) by eddie.linux-mips.org id S23990723AbeBWKRXEcUul (ORCPT ); Fri, 23 Feb 2018 11:17:23 +0100 Date: Fri, 23 Feb 2018 11:17:21 +0100 From: Ladislav Michl To: linux-omap@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-pwm@vger.kernel.org Subject: [PATCH 6/6] pwm: pwm-omap-dmtimer: Add capture functionality Message-ID: <20180223101721.GG5746@lenoch> References: <20180223101254.GA5746@lenoch> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20180223101254.GA5746@lenoch> User-Agent: Mutt/1.9.3 (2018-01-21) X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180223_021802_137581_675EF5D0 X-CRM114-Status: GOOD ( 14.21 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: t-kristo@ti.com, grygorii.strashko@ti.com, aaro.koskinen@iki.fi, tony@atomide.com, Keerthy , daniel.lezcano@linaro.org, robh+dt@kernel.org, narmstrong@baylibre.com, thierry.reding@gmail.com, Brecht Neyrinck , sebastian.reichel@collabora.co.uk, Thomas Gleixner , Claudiu.Beznea@microchip.com Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Implement event capture. Signed-off-by: Ladislav Michl --- Note: Please see cover letter drivers/pwm/pwm-omap-dmtimer.c | 127 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c index 48342285c953..5a2fc0e0a1c5 100644 --- a/drivers/pwm/pwm-omap-dmtimer.c +++ b/drivers/pwm/pwm-omap-dmtimer.c @@ -16,8 +16,10 @@ * PWM driver / controller, using the OMAP's dual-mode timers. */ +#include #include #include +#include #include #include #include @@ -30,17 +32,21 @@ #include #include #include +#include #define DM_TIMER_LOAD_MIN 0xfffffffe #define DM_TIMER_MAX 0xffffffff struct pwm_omap_dmtimer_chip { struct pwm_chip chip; + spinlock_t lock; struct mutex mutex; + wait_queue_head_t wait; pwm_omap_dmtimer *dm_timer; const struct omap_dm_timer_ops *pdata; struct platform_device *dm_timer_pdev; unsigned long freq; + unsigned int ev_cnt, overflow, width; }; static inline struct pwm_omap_dmtimer_chip * @@ -55,6 +61,22 @@ pwm_omap_dmtimer_get_clock_cycles(struct pwm_omap_dmtimer_chip *omap, int ns) return DIV_ROUND_CLOSEST_ULL((u64)omap->freq * ns, NSEC_PER_SEC); } +static inline unsigned int +pwm_omap_dmtimer_ticks_to_ns(struct pwm_omap_dmtimer_chip *omap, + unsigned int ticks) +{ + return DIV_ROUND_CLOSEST_ULL((u64)ticks * NSEC_PER_SEC, omap->freq); +} + +static unsigned int pwm_omap_dmtimer_get_width(struct pwm_omap_dmtimer_chip *omap, + unsigned int c1, unsigned int c2) +{ + if (c1 <= c2) + return c2 - c1; + + return (c2 - omap->overflow) + (DM_TIMER_MAX - c1); +} + static void pwm_omap_dmtimer_start(struct pwm_omap_dmtimer_chip *omap) { /* @@ -218,7 +240,101 @@ static int pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip, return 0; } +static int pwm_omap_dmtimer_capture(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_capture *result, + unsigned long timeout) + +{ + int res; + unsigned long flags; + struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip); + + mutex_lock(&omap->mutex); + + if (pm_runtime_active(&omap->dm_timer_pdev->dev)) + omap->pdata->stop(omap->dm_timer); + + /* Let timer overflow every 1 second */ + omap->overflow = DM_TIMER_MAX - (1 * omap->freq); + timeout = msecs_to_jiffies(timeout); + result->period = result->duty_cycle = 0; + + spin_lock_irqsave(&omap->lock, flags); + omap->pdata->set_int_enable(omap->dm_timer, OMAP_TIMER_INT_CAPTURE | + OMAP_TIMER_INT_OVERFLOW); + omap->pdata->set_capture(omap->dm_timer, 1, 1); + omap->pdata->set_load_start(omap->dm_timer, true, omap->overflow); + omap->ev_cnt = omap->width = 0; + spin_unlock_irqrestore(&omap->lock, flags); + + res = wait_event_interruptible_timeout(omap->wait, + omap->width > 0, timeout); + if (res > 0) { + spin_lock_irqsave(&omap->lock, flags); + result->period = + pwm_omap_dmtimer_ticks_to_ns(omap, omap->width); + omap->pdata->stop(omap->dm_timer); + omap->pdata->set_capture(omap->dm_timer, 1, 3); + omap->pdata->start(omap->dm_timer); + omap->ev_cnt = omap->width = 0; + spin_unlock_irqrestore(&omap->lock, flags); + + res = wait_event_interruptible_timeout(omap->wait, + omap->width > 0, + timeout); + } + + spin_lock_irqsave(&omap->lock, flags); + omap->pdata->stop(omap->dm_timer); + omap->pdata->set_int_disable(omap->dm_timer, OMAP_TIMER_INT_CAPTURE | + OMAP_TIMER_INT_OVERFLOW); + spin_unlock_irqrestore(&omap->lock, flags); + + if (res == 0) { + res = -ETIMEDOUT; + } else if (res > 0) { + result->duty_cycle = + pwm_omap_dmtimer_ticks_to_ns(omap, omap->width); + res = 0; + } + + mutex_unlock(&omap->mutex); + + return res; +} + +static irqreturn_t pwm_omap_dmtimer_irq(int irq, void *dev_id) +{ + u32 l; + unsigned int c1, c2; + unsigned long flags; + struct pwm_omap_dmtimer_chip *omap = dev_id; + + spin_lock_irqsave(&omap->lock, flags); + + l = omap->pdata->read_status(omap->dm_timer); + if (l & OMAP_TIMER_INT_CAPTURE) { + if (!omap->width && omap->ev_cnt == 1) { + omap->pdata->read_capture(omap->dm_timer, &c1, &c2); + omap->width = pwm_omap_dmtimer_get_width(omap, c1, c2); + wake_up(&omap->wait); + } + omap->ev_cnt++; + } + /* TODO: handle overflow as well + if (l & OMAP_TIMER_INT_OVERFLOW) + overflow++; + */ + omap->pdata->write_status(omap->dm_timer, l); + + spin_unlock_irqrestore(&omap->lock, flags); + + return IRQ_HANDLED; +} + static const struct pwm_ops pwm_omap_dmtimer_ops = { + .capture = pwm_omap_dmtimer_capture, .enable = pwm_omap_dmtimer_enable, .disable = pwm_omap_dmtimer_disable, .config = pwm_omap_dmtimer_config, @@ -349,7 +465,18 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev) omap->chip.of_xlate = of_pwm_xlate_with_flags; omap->chip.of_pwm_n_cells = 3; + spin_lock_init(&omap->lock); mutex_init(&omap->mutex); + init_waitqueue_head(&omap->wait); + + ret = omap->pdata->get_irq(omap->dm_timer); + if (ret < 0) + goto free_dm_timer; + + ret = devm_request_irq(&pdev->dev, ret, pwm_omap_dmtimer_irq, 0, + "event_capture", omap); + if (ret) + goto free_dm_timer; ret = pwmchip_add(&omap->chip); if (ret < 0) {