Received: by 10.223.176.46 with SMTP id f43csp2671781wra; Mon, 22 Jan 2018 01:18:00 -0800 (PST) X-Google-Smtp-Source: AH8x226h16deWigffc4fwbm1Jcaql43UpDyFBvbk84wlApZHdXVmDqAbmsb24H4vtpqjGw5bItuc X-Received: by 10.101.66.193 with SMTP id l1mr6718741pgp.17.1516612680398; Mon, 22 Jan 2018 01:18:00 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516612680; cv=none; d=google.com; s=arc-20160816; b=BsWK5DmE4nwWQwA/DNb6QJh63/ROMka0eqK5EL0e1H2dPgelqv5XFx/MzNSCLXNnnB PTj9oEzunttesCfBV43BKT3qfYdB0wrbE17PGpcPR6dpk+GMEsEfj2+QyA9MDkM4E7h9 Pt94PSsP5iuv5cTwdMivsgmbaVIkleaUwjGAJ/9wvhIVVQw4UI4C9bA1kkW+h6FtoI7P Vx+B6lXZ6xvodp8afHDKckc6dIKQB0aaGp4Oud/HZfrnDTUMJK1af7iHgqxs3hauHP5f LagKB0ay0NghayyvkKm2Z3S5AgLiklnLFKtKTKyW6k8v67I3M5+gW3zRgaJxfJJVpWBa lphw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding :content-language:in-reply-to:mime-version:user-agent:date :message-id:from:references:cc:to:subject:arc-authentication-results; bh=FmDLEQRFMuHU/Fl8y+JxGeom13qz2ESf2yXl73bOero=; b=Rh8N/od0yxdb8QEW7LorkERKOXuuvdrd3xXxVymnNpRfsV2B+RdCvaOlw5VDdrfpkH vLhqVql+kGxB6Pih1Go5drqqXl/bID5sOdeFceVZ+cvuacs0vDReVNh68amMeSdCuWb8 wFUuOmtvnu1S/3CZu7lUb4GyfQK6y2PEZMdC0L7uMDL6ngEN0SApIIqOU9hgOmktqMW5 R5I9QTFirqY06uHj2qcHo8C+UaJDkXCGcz5jdUOIXbqoddBARzg8UgT/fvBGRhXjJeOd eQ4+du8Y8plPAx2LQTdP5ILOUJ6FYzsQsCZkFa87dJQYZWb0EndKKBk6g41uy1zEPqkG Mkog== ARC-Authentication-Results: i=1; mx.google.com; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id f29si15105085pfk.117.2018.01.22.01.17.46; Mon, 22 Jan 2018 01:18:00 -0800 (PST) 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; 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 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752307AbeAVJRV (ORCPT + 99 others); Mon, 22 Jan 2018 04:17:21 -0500 Received: from esa3.microchip.iphmx.com ([68.232.153.233]:32596 "EHLO esa3.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751111AbeAVJRQ (ORCPT ); Mon, 22 Jan 2018 04:17:16 -0500 X-IronPort-AV: E=Sophos;i="5.46,396,1511852400"; d="scan'208";a="10751554" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa3.microchip.iphmx.com with ESMTP/TLS/DHE-RSA-AES256-SHA; 22 Jan 2018 02:17:15 -0700 Received: from [10.145.6.87] (10.10.76.4) by chn-sv-exch05.mchp-main.com (10.10.76.106) with Microsoft SMTP Server id 14.3.352.0; Mon, 22 Jan 2018 02:17:14 -0700 Subject: Re: [PATCH 2/3] pwm: pwm-omap-dmtimer: Fix frequency when using prescaler To: Ladislav Michl , , CC: Keerthy , , , , , , , , , , , References: <20180117214629.GA11952@lenoch> <20180117214737.GC11952@lenoch> From: Claudiu Beznea Message-ID: <3e00e721-984c-e8db-49f7-046d7b335404@microchip.com> Date: Mon, 22 Jan 2018 11:17:08 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.5.0 MIME-Version: 1.0 In-Reply-To: <20180117214737.GC11952@lenoch> Content-Type: text/plain; charset="utf-8" Content-Language: en-US Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 17.01.2018 23:47, Ladislav Michl wrote: > Prescaler setting is currently not taken into account. > Fix that by introducing freq member variable and initialize > it at device probe time. This also avoids frequency > recomputing at each pwm configure time. > > Signed-off-by: Ladislav Michl > --- > drivers/pwm/pwm-omap-dmtimer.c | 92 +++++++++++++++++++++++---------------- > 1 file changed, 53 insertions(+), 39 deletions(-) > > diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c > index cc485d9946f3..81c79e41a167 100644 > --- a/drivers/pwm/pwm-omap-dmtimer.c > +++ b/drivers/pwm/pwm-omap-dmtimer.c > @@ -40,6 +40,7 @@ struct pwm_omap_dmtimer_chip { > pwm_omap_dmtimer *dm_timer; > struct omap_dm_timer_ops *pdata; > struct platform_device *dm_timer_pdev; > + unsigned long freq; > }; > > static inline struct pwm_omap_dmtimer_chip * > @@ -48,9 +49,10 @@ to_pwm_omap_dmtimer_chip(struct pwm_chip *chip) > return container_of(chip, struct pwm_omap_dmtimer_chip, chip); > } > > -static u32 pwm_omap_dmtimer_get_clock_cycles(unsigned long clk_rate, int ns) > +static inline u32 > +pwm_omap_dmtimer_get_clock_cycles(struct pwm_omap_dmtimer_chip *omap, int ns) > { > - return DIV_ROUND_CLOSEST_ULL((u64)clk_rate * ns, NSEC_PER_SEC); > + return DIV_ROUND_CLOSEST_ULL((u64)omap->freq * ns, NSEC_PER_SEC); > } > > static void pwm_omap_dmtimer_start(struct pwm_omap_dmtimer_chip *omap) > @@ -99,8 +101,6 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip, > struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip); > u32 period_cycles, duty_cycles; > u32 load_value, match_value; > - struct clk *fclk; > - unsigned long clk_rate; > bool timer_active; > > dev_dbg(chip->dev, "requested duty cycle: %d ns, period: %d ns\n", > @@ -114,19 +114,6 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip, > return 0; > } > > - fclk = omap->pdata->get_fclk(omap->dm_timer); > - if (!fclk) { > - dev_err(chip->dev, "invalid pmtimer fclk\n"); > - goto err_einval; > - } > - > - clk_rate = clk_get_rate(fclk); > - if (!clk_rate) { > - dev_err(chip->dev, "invalid pmtimer fclk rate\n"); > - goto err_einval; > - } > - > - dev_dbg(chip->dev, "clk rate: %luHz\n", clk_rate); > > /* > * Calculate the appropriate load and match values based on the > @@ -144,35 +131,35 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip, > * OMAP4430/60/70 TRM sections 22.2.4.10 and 22.2.4.11 > * AM335x Sitara TRM sections 20.1.3.5 and 20.1.3.6 > */ > - period_cycles = pwm_omap_dmtimer_get_clock_cycles(clk_rate, period_ns); > - duty_cycles = pwm_omap_dmtimer_get_clock_cycles(clk_rate, duty_ns); > + period_cycles = pwm_omap_dmtimer_get_clock_cycles(omap, period_ns); > + duty_cycles = pwm_omap_dmtimer_get_clock_cycles(omap, duty_ns); > > if (period_cycles < 2) { > dev_info(chip->dev, > "period %d ns too short for clock rate %lu Hz\n", > - period_ns, clk_rate); > + period_ns, omap->freq); > goto err_einval; > } > > if (duty_cycles < 1) { > dev_dbg(chip->dev, > "duty cycle %d ns is too short for clock rate %lu Hz\n", > - duty_ns, clk_rate); > + duty_ns, omap->freq); > dev_dbg(chip->dev, "using minimum of 1 clock cycle\n"); > duty_cycles = 1; > } else if (duty_cycles >= period_cycles) { > dev_dbg(chip->dev, > "duty cycle %d ns is too long for period %d ns at clock rate %lu Hz\n", > - duty_ns, period_ns, clk_rate); > + duty_ns, period_ns, omap->freq); > dev_dbg(chip->dev, "using maximum of 1 clock cycle less than period\n"); > duty_cycles = period_cycles - 1; > } > > dev_dbg(chip->dev, "effective duty cycle: %lld ns, period: %lld ns\n", > DIV_ROUND_CLOSEST_ULL((u64)NSEC_PER_SEC * duty_cycles, > - clk_rate), > + omap->freq), > DIV_ROUND_CLOSEST_ULL((u64)NSEC_PER_SEC * period_cycles, > - clk_rate)); > + omap->freq)); > > load_value = (DM_TIMER_MAX - period_cycles) + 1; > match_value = load_value + duty_cycles - 1; > @@ -248,8 +235,9 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev) > struct dmtimer_platform_data *timer_pdata; > struct omap_dm_timer_ops *pdata; > pwm_omap_dmtimer *dm_timer; > + struct clk *fclk; > u32 v; > - int status, ret; > + int ret; > > timer = of_parse_phandle(np, "ti,timers", 0); > if (!timer) > @@ -302,9 +290,8 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev) > > omap = devm_kzalloc(&pdev->dev, sizeof(*omap), GFP_KERNEL); > if (!omap) { > - pdata->free(dm_timer); > ret = -ENOMEM; > - goto put; > + goto free; > } > > omap->pdata = pdata; > @@ -315,15 +302,42 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev) > * Ensure that the timer is stopped before we allow PWM core to call > * pwm_enable. > */ > - if (pm_runtime_active(&omap->dm_timer_pdev->dev)) > - omap->pdata->stop(omap->dm_timer); > - > - if (!of_property_read_u32(pdev->dev.of_node, "ti,prescaler", &v)) > - omap->pdata->set_prescaler(omap->dm_timer, v); > + if (pm_runtime_active(&timer_pdev->dev)) > + pdata->stop(dm_timer); > > /* setup dmtimer clock source */ > - if (!of_property_read_u32(pdev->dev.of_node, "ti,clock-source", &v)) > - omap->pdata->set_source(omap->dm_timer, v); > + if (!of_property_read_u32(pdev->dev.of_node, "ti,clock-source", &v)) { > + ret = pdata->set_source(dm_timer, v); > + if (ret) { > + dev_err(&pdev->dev, "invalid clock-source\n"); > + goto free; > + } > + } > + > + fclk = pdata->get_fclk(dm_timer); > + if (!fclk) { > + dev_err(&pdev->dev, "invalid fclk\n"); > + ret = -EINVAL; > + goto free; > + } > + > + omap->freq = clk_get_rate(fclk); > + if (!omap->freq) { > + dev_err(&pdev->dev, "invalid fclk rate\n"); > + ret = -EINVAL; > + goto free; > + } > + > + if (!of_property_read_u32(pdev->dev.of_node, "ti,prescaler", &v)) { > + ret = pdata->set_prescaler(dm_timer, v); > + if (ret) { > + dev_err(&pdev->dev, "invalid prescaler\n"); > + goto free; > + } > + omap->freq >>= v + 1; > + } > + > + dev_dbg(&pdev->dev, "clk rate: %luHz\n", omap->freq); > > omap->chip.dev = &pdev->dev; > omap->chip.ops = &pwm_omap_dmtimer_ops; > @@ -334,18 +348,18 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev) > > mutex_init(&omap->mutex); > > - status = pwmchip_add(&omap->chip); > - if (status < 0) { > + ret = pwmchip_add(&omap->chip); > + if (ret < 0) { > dev_err(&pdev->dev, "failed to register PWM\n"); > - omap->pdata->free(omap->dm_timer); > - ret = status; > - goto put; > + goto free; > } > > platform_set_drvdata(pdev, omap); From documentation: "of_parse_phandle(): Returns the device_node pointer with refcount incremented. Use of_node_put() on it when done." In case of success the of_node_put() should also be called as I see. > > return 0; > > +free: > + pdata->free(dm_timer); > put: > of_node_put(timer); > >