From patchwork Mon Feb 29 11:39:21 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Sperl X-Patchwork-Id: 8452121 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 2CEF39F372 for ; Mon, 29 Feb 2016 11:44:25 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 3DA6220253 for ; Mon, 29 Feb 2016 11:44:24 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 4CC31201B4 for ; Mon, 29 Feb 2016 11:44:23 +0000 (UTC) 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 1aaMDw-0003ws-HP; Mon, 29 Feb 2016 11:42:48 +0000 Received: from 212-186-180-163.dynamic.surfer.at ([212.186.180.163] helo=cgate.sperl.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1aaMBP-00011A-J6; Mon, 29 Feb 2016 11:40:24 +0000 Received: from raspcm.intern.sperl.org (account martin@sperl.org [10.10.10.41] verified) by sperl.org (CommuniGate Pro SMTP 6.1.2) with ESMTPSA id 6394967; Mon, 29 Feb 2016 11:39:36 +0000 From: kernel@martin.sperl.org To: Michael Turquette , Stephen Boyd , Stephen Warren , Lee Jones , Eric Anholt , linux-clk@vger.kernel.org, linux-rpi-kernel@lists.infradead.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH 5/6] clk: bcm2835: correctly enable fractional clock support Date: Mon, 29 Feb 2016 11:39:21 +0000 Message-Id: <1456745963-2403-6-git-send-email-kernel@martin.sperl.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1456745963-2403-1-git-send-email-kernel@martin.sperl.org> References: <1456745963-2403-1-git-send-email-kernel@martin.sperl.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160229_034012_240302_CC98D310 X-CRM114-Status: GOOD ( 12.69 ) X-Spam-Score: -0.9 (/) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Martin Sperl MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Martin Sperl The current driver calculates the clock divider with fractional support enabled. But it does not enable fractional support in the control register itself resulting in an integer only divider, but in clk_set_rate responds back the fractionally divided clock frequency. This patch enables fractional support in the control register whenever there is a fractional bit set in the requested clock divider. Mash clock limits are are also handled for the PWM clock applying the correct divider limits (2 and max_int) applicable to basic fractional divider support (mash order of 1). It also adds locking to protect the read/modify/write cycle of the register modification. Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks") Signed-off-by: Martin Sperl Signed-off-by: Martin Sperl Reviewed-by: Eric Anholt --- drivers/clk/bcm/clk-bcm2835.c | 45 +++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) -- 1.7.10.4 diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index edb1f74..da77069 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -52,6 +52,7 @@ #define CM_GNRICCTL 0x000 #define CM_GNRICDIV 0x004 # define CM_DIV_FRAC_BITS 12 +# define CM_DIV_FRAC_MASK GENMASK(CM_DIV_FRAC_BITS - 1, 0) #define CM_VPUCTL 0x008 #define CM_VPUDIV 0x00c @@ -129,6 +130,7 @@ # define CM_GATE BIT(CM_GATE_BIT) # define CM_BUSY BIT(7) # define CM_BUSYD BIT(8) +# define CM_FRAC BIT(9) # define CM_SRC_SHIFT 0 # define CM_SRC_BITS 4 # define CM_SRC_MASK 0xf @@ -648,6 +650,7 @@ struct bcm2835_clock_data { u32 frac_bits; bool is_vpu_clock; + bool is_mash_clock; }; static const char *const bcm2835_clock_per_parents[] = { @@ -829,6 +832,7 @@ static const struct bcm2835_clock_data bcm2835_clock_pwm_data = { .div_reg = CM_PWMDIV, .int_bits = 12, .frac_bits = 12, + .is_mash_clock = true, }; struct bcm2835_pll { @@ -1184,7 +1188,7 @@ static u32 bcm2835_clock_choose_div(struct clk_hw *hw, GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1; u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS; u64 rem; - u32 div; + u32 div, mindiv, maxdiv; rem = do_div(temp, rate); div = temp; @@ -1194,11 +1198,23 @@ static u32 bcm2835_clock_choose_div(struct clk_hw *hw, div += unused_frac_mask + 1; div &= ~unused_frac_mask; - /* clamp to min divider of 1 */ - div = max_t(u32, div, 1 << CM_DIV_FRAC_BITS); - /* clamp to the highest possible fractional divider */ - div = min_t(u32, div, GENMASK(data->int_bits + CM_DIV_FRAC_BITS - 1, - CM_DIV_FRAC_BITS - data->frac_bits)); + /* different clamping limits apply for a mash clock */ + if (data->is_mash_clock) { + /* clamp to min divider of 2 */ + mindiv = 2 << CM_DIV_FRAC_BITS; + /* clamp to the highest possible integer divider */ + maxdiv = (BIT(data->int_bits) - 1) << CM_DIV_FRAC_BITS; + } else { + /* clamp to min divider of 1 */ + mindiv = 1 << CM_DIV_FRAC_BITS; + /* clamp to the highest possible fractional divider */ + maxdiv = GENMASK(data->int_bits + CM_DIV_FRAC_BITS - 1, + CM_DIV_FRAC_BITS - data->frac_bits); + } + + /* apply the clamping limits */ + div = max_t(u32, div, mindiv); + div = min_t(u32, div, maxdiv); return div; } @@ -1292,9 +1308,26 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw, struct bcm2835_cprman *cprman = clock->cprman; const struct bcm2835_clock_data *data = clock->data; u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate, false); + u32 ctl; + + spin_lock(&cprman->regs_lock); + + /* + * Setting up frac support + * + * In principle it is recommended to stop/start the clock first, + * but as we set CLK_SET_RATE_GATE during registration of the + * clock this requirement should be take care of by the + * clk-framework. + */ + ctl = cprman_read(cprman, data->ctl_reg) & ~CM_FRAC; + ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0; + cprman_write(cprman, data->ctl_reg, ctl); cprman_write(cprman, data->div_reg, div); + spin_unlock(&cprman->regs_lock); + return 0; }