From patchwork Tue Aug 9 11:05:21 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Viresh KUMAR X-Patchwork-Id: 1049122 Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by demeter2.kernel.org (8.14.4/8.14.4) with ESMTP id p79B8l64006598 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 9 Aug 2011 11:09:08 GMT Received: from canuck.infradead.org ([2001:4978:20e::1]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1Qqk9m-0003Mv-Pm; Tue, 09 Aug 2011 11:07:35 +0000 Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1Qqk9m-00069F-4W; Tue, 09 Aug 2011 11:07:34 +0000 Received: from eu1sys200aog110.obsmtp.com ([207.126.144.129]) by canuck.infradead.org with smtps (Exim 4.76 #1 (Red Hat Linux)) id 1Qqk8J-0005jN-Cz for linux-arm-kernel@lists.infradead.org; Tue, 09 Aug 2011 11:06:07 +0000 Received: from beta.dmz-ap.st.com ([138.198.100.35]) (using TLSv1) by eu1sys200aob110.postini.com ([207.126.147.11]) with SMTP ID DSNKTkEUjjVDP3Nj9JvvZ7iGOZPzS8Kop4UD@postini.com; Tue, 09 Aug 2011 11:06:02 UTC Received: from zeta.dmz-ap.st.com (ns6.st.com [138.198.234.13]) by beta.dmz-ap.st.com (STMicroelectronics) with ESMTP id 35E5114E; Tue, 9 Aug 2011 11:05:40 +0000 (GMT) Received: from Webmail-ap.st.com (eapex1hubcas1.st.com [10.80.176.8]) by zeta.dmz-ap.st.com (STMicroelectronics) with ESMTP id 1162EC7D; Tue, 9 Aug 2011 11:05:40 +0000 (GMT) Received: from localhost (10.199.88.156) by Webmail-ap.st.com (10.80.176.7) with Microsoft SMTP Server (TLS) id 8.2.234.1; Tue, 9 Aug 2011 19:05:39 +0800 From: Viresh Kumar To: Subject: [PATCH 4/6] spi/spi-pl022: calculate_effective_freq() must set rate <= requested rate Date: Tue, 9 Aug 2011 16:35:21 +0530 Message-ID: X-Mailer: git-send-email 1.7.2.2 In-Reply-To: References: MIME-Version: 1.0 X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110809_070603_879069_8F468659 X-CRM114-Status: GOOD ( 20.32 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [207.126.144.129 listed in list.dnswl.org] Cc: vipin.kumar@st.com, rajeev-dlh.kumar@st.com, bhavna.yadav@st.com, bhupesh.sharma@st.com, pratyush.anand@st.com, armando.visconti@st.com, grant.likely@secretlab.ca, shiraz.hashim@st.com, amit.virdi@st.com, vipulkumar.samar@st.com, viresh.linux@gmail.com, deepak.sikri@st.com, spi-devel-general@lists.sourceforge.net, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Tue, 09 Aug 2011 11:09:08 +0000 (UTC) There were few issues with calculate_effective_freq() routine: - It was returning first rate found >= requested rate. Now, if system have spi's rate as 83 MHz, with possible prescaled rates as 83, 41.5, 20.75, 13.83 (as we can prescale with multiples of 2). If user has given rate to be programmed as 22 MHz, then driver programmes it to 41.5 MHz. This looks to be incorrect, as user might have given the upper limit of the device, and we are programming it above it. - Driver finds the first satisfying rate and programmes it, but with other values of scr & cpsdvsr, it is possible to get more closer rate. This patch fixes these two issues, with some reformatting inside the code. This also creates a macro to calculate prescaled rate based on spi's rate, cpsdvsr and scr. Signed-off-by: Viresh Kumar --- drivers/spi/spi-pl022.c | 98 ++++++++++++++++++++++------------------------ 1 files changed, 47 insertions(+), 51 deletions(-) diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 452952b..e0cfb8c 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -1791,67 +1791,63 @@ static int pl022_transfer(struct spi_device *spi, struct spi_message *msg) return 0; } -static int calculate_effective_freq(struct pl022 *pl022, - int freq, - struct ssp_clock_params *clk_freq) +#define SPI_RATE(rate, cpsdvsr, scr) (rate / (cpsdvsr * (1 + scr))) +static int calculate_effective_freq(struct pl022 *pl022, int freq, struct + ssp_clock_params * clk_freq) { /* Lets calculate the frequency parameters */ - u16 cpsdvsr = 2; - u16 scr = 0; - bool freq_found = false; - u32 rate; - u32 max_tclk; - u32 min_tclk; + u16 cpsdvsr = CPSDVR_MIN, scr = SCR_MIN; + u32 rate, max_tclk, min_tclk, best_freq = 0, best_cpsdvsr = 0, + best_scr = 0, tmp, found = 0; rate = clk_get_rate(pl022->clk); /* cpsdvscr = 2 & scr 0 */ - max_tclk = (rate / (CPSDVR_MIN * (1 + SCR_MIN))); + max_tclk = SPI_RATE(rate, CPSDVR_MIN, SCR_MIN); /* cpsdvsr = 254 & scr = 255 */ - min_tclk = (rate / (CPSDVR_MAX * (1 + SCR_MAX))); - - if ((freq <= max_tclk) && (freq >= min_tclk)) { - while (cpsdvsr <= CPSDVR_MAX && !freq_found) { - while (scr <= SCR_MAX && !freq_found) { - if ((rate / - (cpsdvsr * (1 + scr))) > freq) - scr += 1; - else { - /* - * This bool is made true when - * effective frequency >= - * target frequency is found - */ - freq_found = true; - if ((rate / - (cpsdvsr * (1 + scr))) != freq) { - if (scr == SCR_MIN) { - cpsdvsr -= 2; - scr = SCR_MAX; - } else - scr -= 1; - } - } - } - if (!freq_found) { - cpsdvsr += 2; - scr = SCR_MIN; - } - } - if (cpsdvsr != 0) { - dev_dbg(&pl022->adev->dev, - "SSP Effective Frequency is %u\n", - (rate / (cpsdvsr * (1 + scr)))); - clk_freq->cpsdvsr = (u8) (cpsdvsr & 0xFF); - clk_freq->scr = (u8) (scr & 0xFF); - dev_dbg(&pl022->adev->dev, - "SSP cpsdvsr = %d, scr = %d\n", - clk_freq->cpsdvsr, clk_freq->scr); - } - } else { + min_tclk = SPI_RATE(rate, CPSDVR_MAX, SCR_MAX); + + if (!((freq <= max_tclk) && (freq >= min_tclk))) { dev_err(&pl022->adev->dev, "controller data is incorrect: out of range frequency"); return -EINVAL; } + + /* + * best_freq will give closest possible available rate (<= requested + * freq) for all values of scr & cpsdvsr. + */ + while ((cpsdvsr <= CPSDVR_MAX) && !found) { + while (scr <= SCR_MAX) { + tmp = SPI_RATE(rate, cpsdvsr, scr); + + if (tmp > freq) + scr++; + /* + * If found exact value, update and break. + * If found more closer value, update and continue. + */ + else if ((tmp == freq) || (tmp > best_freq)) { + best_freq = tmp; + best_cpsdvsr = cpsdvsr; + best_scr = scr; + + if (tmp == freq) + break; + } + scr++; + } + cpsdvsr += 2; + scr = SCR_MIN; + } + + clk_freq->cpsdvsr = (u8) (best_cpsdvsr & 0xFF); + clk_freq->scr = (u8) (best_scr & 0xFF); + dev_dbg(&pl022->adev->dev, + "SSP Target Frequency is: %u, Effective Frequency is %u\n", + freq, best_freq); + dev_dbg(&pl022->adev->dev, "SSP cpsdvsr = %d, scr = %d\n", + clk_freq->cpsdvsr, clk_freq->scr); + return 0; }