From patchwork Fri Jul 5 16:28:00 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Lothar_Wa=C3=9Fmann?= X-Patchwork-Id: 257195 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 5BB392C0091 for ; Sat, 6 Jul 2013 02:45:58 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933823Ab3GEQp5 (ORCPT ); Fri, 5 Jul 2013 12:45:57 -0400 Received: from mail.karo-electronics.de ([81.173.242.67]:53104 "EHLO mail.karo-electronics.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933776Ab3GEQp4 (ORCPT ); Fri, 5 Jul 2013 12:45:56 -0400 X-Greylist: delayed 1050 seconds by postgrey-1.27 at vger.kernel.org; Fri, 05 Jul 2013 12:45:55 EDT From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= To: Marek Vasut Cc: Shawn Guo , Fabio Estevam , linux-i2c@vger.kernel.org, =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Subject: [PATCH] i2c: mxs: fix broken timing calculation Date: Fri, 5 Jul 2013 18:28:00 +0200 Message-Id: <1373041680-26939-1-git-send-email-LW@KARO-electronics.de> X-Mailer: git-send-email 1.7.2.5 MIME-Version: 1.0 Sender: linux-i2c-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org The timing calculation is rather bogus and gives extremely wrong results for higher frequencies (on an i.MX28). E.g. instead of 400 kHz I measured 770 kHz. Implement a calculation that adheres to the I2C spec and gives exact results for I2C frequencies from 12.56 kHz to 960 kHz. Also the bus_free and leadin parameters are programmed according to the I2C spec for standard and fast mode. This was tested on a Ka-Ro TX28 module with a DS1339, TSC2007, PCA9554 and SGTL5000 client. Signed-off-by: Lothar Waßmann --- drivers/i2c/busses/i2c-mxs.c | 87 ++++++++++++++++++++++++++++++----------- 1 files changed, 63 insertions(+), 24 deletions(-) diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index df8ff5a..1333456 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -114,9 +114,10 @@ struct mxs_i2c_dev { uint32_t timing0; uint32_t timing1; + uint32_t timing2; /* DMA support components */ - struct dma_chan *dmach; + struct dma_chan *dmach; uint32_t pio_data[2]; uint32_t addr_data; struct scatterlist sg_io[2]; @@ -136,7 +137,7 @@ static void mxs_i2c_reset(struct mxs_i2c_dev *i2c) */ writel(i2c->timing0, i2c->regs + MXS_I2C_TIMING0); writel(i2c->timing1, i2c->regs + MXS_I2C_TIMING1); - writel(0x00300030, i2c->regs + MXS_I2C_TIMING2); + writel(i2c->timing2, i2c->regs + MXS_I2C_TIMING2); writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET); } @@ -577,41 +578,79 @@ static const struct i2c_algorithm mxs_i2c_algo = { .functionality = mxs_i2c_func, }; -static void mxs_i2c_derive_timing(struct mxs_i2c_dev *i2c, int speed) +static void mxs_i2c_derive_timing(struct mxs_i2c_dev *i2c, uint32_t speed) { - /* The I2C block clock run at 24MHz */ + /* The I2C block clock runs at 24MHz */ const uint32_t clk = 24000000; - uint32_t base; + uint32_t divider; uint16_t high_count, low_count, rcv_count, xmit_count; + uint32_t bus_free, leadin; struct device *dev = i2c->dev; - if (speed > 540000) { - dev_warn(dev, "Speed too high (%d Hz), using 540 kHz\n", speed); - speed = 540000; - } else if (speed < 12000) { - dev_warn(dev, "Speed too low (%d Hz), using 12 kHz\n", speed); - speed = 12000; + divider = DIV_ROUND_UP(clk, speed); + + if (divider < 25) { + /* + * limit the divider, so that min(low_count, high_count) + * is >= 1 + */ + divider = 25; + dev_warn(dev, + "Speed too high (%u.%03u kHz), using %u.%03u kHz\n", + speed / 1000, speed % 1000, + clk / divider / 1000, clk / divider % 1000); + } else if (divider > 1897) { + /* + * limit the divider, so that max(low_count, high_count) + * cannot exceed 1023 + */ + divider = 1897; + dev_warn(dev, + "Speed too low (%u.%03u kHz), using %u.%03u kHz\n", + speed / 1000, speed % 1000, + clk / divider / 1000, clk / divider % 1000); } /* - * The timing derivation algorithm. There is no documentation for this - * algorithm available, it was derived by using the scope and fiddling - * with constants until the result observed on the scope was good enough - * for 20kHz, 50kHz, 100kHz, 200kHz, 300kHz and 400kHz. It should be - * possible to assume the algorithm works for other frequencies as well. + * The I2C spec specifies the following timing data: + * standard mode fast mode Bitfield name + * tLOW (SCL LOW period) 4700 ns 1300 ns + * tHIGH (SCL HIGH period) 4000 ns 600 ns + * tSU;DAT (data setup time) 250 ns 100 ns + * tHD;STA (START hold time) 4000 ns 600 ns + * tBUF (bus free time) 4700 ns 1300 ns * - * Note it was necessary to cap the frequency on both ends as it's not - * possible to configure completely arbitrary frequency for the I2C bus - * clock. + * The hardware (of the i.MX28 at least) seems to add 2 additional + * clock cycles to the low_count and 7 cycles to the high_count. + * This is compensated for by subtracting the respective constants + * from the values written to the timing registers. */ - base = ((clk / speed) - 38) / 2; - high_count = base + 3; - low_count = base - 3; - rcv_count = (high_count * 3) / 4; - xmit_count = low_count / 4; + if (speed > 100000) { + /* fast mode */ + low_count = DIV_ROUND_CLOSEST(divider * 13, (13 + 6)); + high_count = DIV_ROUND_CLOSEST(divider * 6, (13 + 6)); + leadin = DIV_ROUND_UP(600 * (clk / 1000000), 1000); + bus_free = DIV_ROUND_UP(1300 * (clk / 1000000), 1000); + } else { + /* normal mode */ + low_count = DIV_ROUND_CLOSEST(divider * 47, (47 + 40)); + high_count = DIV_ROUND_CLOSEST(divider * 40, (47 + 40)); + leadin = DIV_ROUND_UP(4700 * (clk / 1000000), 1000); + bus_free = DIV_ROUND_UP(4700 * (clk / 1000000), 1000); + } + rcv_count = high_count * 3 / 8; + xmit_count = low_count * 3 / 8; + + dev_dbg(dev, + "speed=%u(actual %u) divider=%u low=%u high=%u xmit=%u rcv=%u leadin=%u bus_free=%u\n", + speed, clk / divider, divider, low_count, high_count, + xmit_count, rcv_count, leadin, bus_free); + low_count -= 2; + high_count -= 7; i2c->timing0 = (high_count << 16) | rcv_count; i2c->timing1 = (low_count << 16) | xmit_count; + i2c->timing2 = (bus_free << 16 | leadin); } static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)