From patchwork Tue Jun 14 07:20:41 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Eric Miao X-Patchwork-Id: 1891 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:24 -0000 Delivered-To: patches@linaro.org Received: by 10.52.183.130 with SMTP id em2cs46403vdc; Tue, 14 Jun 2011 00:21:02 -0700 (PDT) Received: by 10.52.112.164 with SMTP id ir4mr5863155vdb.291.1308036062263; Tue, 14 Jun 2011 00:21:02 -0700 (PDT) Received: from mail-vx0-f178.google.com ([209.85.220.178]) by mx.google.com with ESMTPS id c8si4317363vbv.59.2011.06.14.00.21.01 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 14 Jun 2011 00:21:01 -0700 (PDT) Received-SPF: pass (google.com: domain of eric.y.miao@gmail.com designates 209.85.220.178 as permitted sender) client-ip=209.85.220.178; Authentication-Results: mx.google.com; spf=pass (google.com: domain of eric.y.miao@gmail.com designates 209.85.220.178 as permitted sender) smtp.mail=eric.y.miao@gmail.com; dkim=pass (test mode) header.i=@gmail.com Received: by vxc11 with SMTP id 11so5143552vxc.37 for ; Tue, 14 Jun 2011 00:21:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:sender:in-reply-to:references:from :date:x-google-sender-auth:message-id:subject:to:content-type :content-transfer-encoding; bh=aBcAbHGN1au6e6H58XWJwQpwKd50qQynt1pgFbB60GE=; b=DNX2D+vLuwnmxfnv2WpahJDsNiF7AE7D2225OXnRDQpA6pyxpXg8dklDXblzDXdsv6 kVketMMizD9wMAKPKdTvhqQOojuuh+/3GDMfFJJIMAYCMGyTJz+r4chlFLhPS4V3Np89 cwJXjG1lzA7u/JYIAc2fufbzuJS0xmrocqpCA= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=bcc:mime-version:sender:in-reply-to:references:from:date :x-google-sender-auth:message-id:subject:to:content-type :content-transfer-encoding; b=aEbrXUeo/sJP/uZ+2z0DH1x0bbbDHZN0h4cG6KMqSk0khSY01F6dNHF699VvJgUzJy pazJR3ziNDXQbxwta5aCi4lb8PqHfyZpTIIyvZ2kO1gp8Vaj7Fw0ZJ9nrEVwjzVRz1ZJ VO5O2sT77Iw6zVUNypWTzdb22HOK5MW8EF514= Bcc: patches@linaro.org Received: by 10.52.68.229 with SMTP id z5mr997138vdt.99.1308036061102; Tue, 14 Jun 2011 00:21:01 -0700 (PDT) MIME-Version: 1.0 Sender: eric.y.miao@gmail.com Received: by 10.52.109.99 with HTTP; Tue, 14 Jun 2011 00:20:41 -0700 (PDT) In-Reply-To: <1308035825-22410-1-git-send-email-eric.miao@linaro.org> References: <1308035825-22410-1-git-send-email-eric.miao@linaro.org> From: Eric Miao Date: Tue, 14 Jun 2011 15:20:41 +0800 X-Google-Sender-Auth: dvf-1iNWw_HOh1AelmJENKQM4q8 Message-ID: Subject: i2c: imx: choose the better clock divider To: undisclosed-recipients:; 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(-) -- 1.7.4.1 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  }