From patchwork Tue Jun 14 07:17:05 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Miao X-Patchwork-Id: 1889 Return-Path: Delivered-To: unknown Received: from imap.gmail.com (74.125.47.109) by localhost6.localdomain6 with IMAP4-SSL; 14 Jun 2011 16:46:23 -0000 Delivered-To: patches@linaro.org Received: by 10.52.183.130 with SMTP id em2cs46217vdc; Tue, 14 Jun 2011 00:17:27 -0700 (PDT) Received: by 10.236.195.102 with SMTP id o66mr8552713yhn.364.1308035846599; Tue, 14 Jun 2011 00:17:26 -0700 (PDT) Received: from mail-pv0-f178.google.com (mail-pv0-f178.google.com [74.125.83.178]) by mx.google.com with ESMTPS id y48si23350814yhl.82.2011.06.14.00.17.25 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 14 Jun 2011 00:17:26 -0700 (PDT) Received-SPF: pass (google.com: domain of eric.y.miao@gmail.com designates 74.125.83.178 as permitted sender) client-ip=74.125.83.178; Authentication-Results: mx.google.com; spf=pass (google.com: domain of eric.y.miao@gmail.com designates 74.125.83.178 as permitted sender) smtp.mail=eric.y.miao@gmail.com; dkim=pass (test mode) header.i=@gmail.com Received: by pvg7 with SMTP id 7so2823282pvg.37 for ; Tue, 14 Jun 2011 00:17:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:sender:from:to:cc:subject:date:message-id :x-mailer; bh=l1VSTC2DCD7nVK5xyRJQtkC3LPV1TPRtIQKzCcjmb8g=; b=OMnU36yEfpjtrIS5P2Ke5pAkpI+CzrlV1c8VsS/88x+HlWAwxifSll+kIc5yVBTo8S Z8pHSrCC0GZssdsc+SngQoWhRH9BBuh7jpvyza51TdyS7nrwU34Kd1GPgElhZt8DXoZS fzdw2nt35+L04ivVGw53vY93pAp7B3HrjOA+s= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=sender:from:to:cc:subject:date:message-id:x-mailer; b=Oz0V/3m3GKAGjpicrq1X8ZtrSsfP+62lrauD2rXyXWTvY7JJ+t6l8CFYLd39Vn5Ikc UooY0hd1/6VJssbxLKDopOxGLLhc5KXkpRbUBFHcZMxmQ8yKV+6JY5vT9PHHy9wKNe/F NRnZb/X8zo6L9yROVrW3AOCdMUd9NpCsb36Vo= Received: by 10.68.65.110 with SMTP id w14mr2513573pbs.382.1308035845138; Tue, 14 Jun 2011 00:17:25 -0700 (PDT) Received: from ycmiao-macbookpro.ericsmarthome.org ([112.64.51.232]) by mx.google.com with ESMTPS id b8sm5336659pbj.30.2011.06.14.00.17.21 (version=SSLv3 cipher=OTHER); Tue, 14 Jun 2011 00:17:24 -0700 (PDT) Sender: Eric Miao From: Eric Miao To: linux-i2c@vger.kernel.org, Jean Delvare Cc: linux-kernel@vger.kernel.org, Eric Miao , Richard Zhao Subject: [PATCH] i2c: imx: choose the better clock divider Date: Tue, 14 Jun 2011 15:17:05 +0800 Message-Id: <1308035825-22410-1-git-send-email-eric.miao@linaro.org> X-Mailer: git-send-email 1.7.4.1 The original algorithm doesn't perform very well in some cases, e.g. When the source clock of the I2C controller is 66MHz, and the requested rate is 100KHz, it gives a divider of 768 instead of the better 640. Choose a better clock divider so the final clock rate is closer to the requested one by comparing the rate distances calculated by two adjacent dividers. Cc: Richard Zhao Signed-off-by: Eric Miao --- drivers/i2c/busses/i2c-imx.c | 46 ++++++++++++++++++++++++++++------------- 1 files changed, 31 insertions(+), 15 deletions(-) diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 4c2a62b..cd640ff 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -112,6 +112,8 @@ static u16 __initdata i2c_clk_div[50][2] = { { 3072, 0x1E }, { 3840, 0x1F } }; +#define I2C_CLK_DIV_NUM ARRAY_SIZE(i2c_clk_div) + struct imx_i2c_struct { struct i2c_adapter adapter; struct resource *res; @@ -240,22 +242,37 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx) clk_disable(i2c_imx->clk); } -static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, - unsigned int rate) +/* find the index into i2c_clk_div[] array, compare with the two + * dividers found, return the one with smaller error + */ +static int find_div(unsigned long i2c_clk_rate, unsigned long rate) { - unsigned int i2c_clk_rate; - unsigned int div; + unsigned long div, delta_l, delta_h; int i; - /* Divider value calculation */ - i2c_clk_rate = clk_get_rate(i2c_imx->clk); div = (i2c_clk_rate + rate - 1) / rate; + if (div < i2c_clk_div[0][0]) - i = 0; - else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0]) - i = ARRAY_SIZE(i2c_clk_div) - 1; - else - for (i = 0; i2c_clk_div[i][0] < div; i++); + return 0; + + if (div > i2c_clk_div[I2C_CLK_DIV_NUM - 1][0]) + return I2C_CLK_DIV_NUM; + + for (i = 0; i < I2C_CLK_DIV_NUM; i++) + if (i2c_clk_div[i][0] > div) + break; + + delta_h = (i2c_clk_rate / i2c_clk_div[i - 1][0]) - rate; + delta_l = rate - (i2c_clk_rate / i2c_clk_div[i][0]); + + return (delta_l < delta_h) ? i : i - 1; +} + +static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, + unsigned int rate) +{ + unsigned long i2c_clk_rate = clk_get_rate(i2c_imx->clk); + int i = find_div(i2c_clk_rate, rate); /* Store divider value */ i2c_imx->ifdr = i2c_clk_div[i][1]; @@ -271,10 +288,9 @@ static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, /* dev_dbg() can't be used, because adapter is not yet registered */ #ifdef CONFIG_I2C_DEBUG_BUS - printk(KERN_DEBUG "I2C: <%s> I2C_CLK=%d, REQ DIV=%d\n", - __func__, i2c_clk_rate, div); - printk(KERN_DEBUG "I2C: <%s> IFDR[IC]=0x%x, REAL DIV=%d\n", - __func__, i2c_clk_div[i][1], i2c_clk_div[i][0]); + pr_debug("<%s> I2C_CLK=%ld, REQ RATE=%d, DIV=%d, IFDR[IC]=0x%x\n", + __func__, i2c_clk_rate, rate, + i2c_clk_div[i][0], i2c_clk_div[i][1]); #endif }