From patchwork Tue Jul 21 12:41:06 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vaibhav Hiremath X-Patchwork-Id: 498194 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 EE546140E19 for ; Tue, 21 Jul 2015 22:46:48 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754760AbbGUMqa (ORCPT ); Tue, 21 Jul 2015 08:46:30 -0400 Received: from mail-pa0-f45.google.com ([209.85.220.45]:34895 "EHLO mail-pa0-f45.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754645AbbGUMq0 (ORCPT ); Tue, 21 Jul 2015 08:46:26 -0400 Received: by pabkd10 with SMTP id kd10so47945539pab.2 for ; Tue, 21 Jul 2015 05:46:25 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=s5GfrFVvrLRdfTtBFaaE1WdnB+iiAaKxeI9YTJ2I5c8=; b=MNMfP0xJoXrBkbZc4ZpcZPti5yHT57HoPBzSqD7z+GUHJJx+RckpZg2hxC9Le6iVHf USXnTNJXA98gUc+29ndCX2IGtoG1fIjgrO2Vundi7gjbwZmC9NBZ8jHMoQYsjn5SRh62 +Oi/PRu8COHmVNjfPrYLwXiFTBarsCIEskWkJz8zlvVtTPi7VE0MQwzTuIg/tZTxEAyB wHhvNXYI21rAmGU4SH9LUEotpNeXFL6V81lbqXf+cjuBjbJm1GUfrK4fAOJp+jkoFzf3 hN8X0oagECutqc7rHbnKtYLtWyMtWzUqIVeFAEyxOYGVVMV4lZpltQuFlM9CRExBkYgw iFvw== X-Gm-Message-State: ALoCoQkVbjq222mRuE6fYEhN8DzuK/zPhW+BH1MmRcp0EE8joBeGM2TI+2H3niDkity4VtOll633 X-Received: by 10.66.228.73 with SMTP id sg9mr73528513pac.88.1437482785562; Tue, 21 Jul 2015 05:46:25 -0700 (PDT) Received: from localhost.localdomain ([202.62.77.106]) by smtp.gmail.com with ESMTPSA id f4sm27378854pdc.95.2015.07.21.05.46.20 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 21 Jul 2015 05:46:24 -0700 (PDT) From: Vaibhav Hiremath To: linux-arm-kernel@lists.infradead.org Cc: robert.jarzmik@free.fr, linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, wsa@the-dreams.de, Vaibhav Hiremath , "Jett.Zhou" , Yi Zhang Subject: [PATCH-v5 5/5] i2c: pxa: Add ILCR (tLow & tHigh) configuration support Date: Tue, 21 Jul 2015 18:11:06 +0530 Message-Id: <1437482466-16126-6-git-send-email-vaibhav.hiremath@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1437482466-16126-1-git-send-email-vaibhav.hiremath@linaro.org> References: <1437482466-16126-1-git-send-email-vaibhav.hiremath@linaro.org> Sender: linux-i2c-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org With addition of PXA910 family of devices, the TWSI module supports SCL clock adjustment using ILCR register. This patch enables the control and configuration of ICLR through DT properties, i2c-sclk-high-time-ns: SCLK high time (tHigh), for standard/fast/high speed mode i2c-sclk-low-time-ns: SCLK low time (tLow), for standard/fast/high speed mode Note that in case of standard and fast mod, the tLow and tHigh counters are same, and software will use tLow value. Also, brought up devm_clk_get() fn above i2c_pxa_probe_dt(), as it uses clk rate for timing calculations. Signed-off-by: Vaibhav Hiremath Signed-off-by: Jett.Zhou Signed-off-by: Yi Zhang Tested-by: Robert Jarzmik --- drivers/i2c/busses/i2c-pxa.c | 69 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 8d76197..6012ae5 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -195,6 +195,9 @@ struct pxa_i2c { unsigned long rate; bool highmode_enter; bool disable_after_xfer; + + unsigned int sclk_thigh_load_cnt; + unsigned int sclk_tlow_load_cnt; }; #define _IBMR(i2c) ((i2c)->reg_ibmr) @@ -507,6 +510,36 @@ static void i2c_pxa_set_slave(struct pxa_i2c *i2c, int errcode) #define i2c_pxa_set_slave(i2c, err) do { } while (0) #endif +static void i2c_pxa_do_sclk_adj(struct pxa_i2c *i2c) +{ + unsigned int reg_ilcr; + + if (!i2c->reg_ilcr) + return; + + reg_ilcr = readl(_ILCR(i2c)); + + /* For standard/fast mode tlow and thigh counters are same */ + if (i2c->sclk_tlow_load_cnt) { + unsigned int mask, shift; + + mask = i2c->high_mode ? ILCR_HLVL_MASK : + i2c->fast_mode ? ILCR_FLV_MASK : ILCR_SLV_MASK; + shift = i2c->high_mode ? ILCR_HLVL_SHIFT : + i2c->fast_mode ? ILCR_FLV_SHIFT : ILCR_SLV_SHIFT; + + reg_ilcr &= ~mask; + reg_ilcr |= i2c->sclk_tlow_load_cnt << shift; + } + + if (i2c->high_mode && i2c->sclk_thigh_load_cnt) { + reg_ilcr &= ~ILCR_HLVH_MASK; + reg_ilcr |= i2c->sclk_thigh_load_cnt << ILCR_HLVH_SHIFT; + } + + writel(reg_ilcr, _ILCR(i2c)); +} + static void i2c_pxa_reset(struct pxa_i2c *i2c) { pr_debug("Resetting I2C Controller Unit\n"); @@ -526,6 +559,8 @@ static void i2c_pxa_reset(struct pxa_i2c *i2c) writel(I2C_ICR_INIT | (i2c->fast_mode ? ICR_FM : 0), _ICR(i2c)); writel(readl(_ICR(i2c)) | (i2c->high_mode ? ICR_HS : 0), _ICR(i2c)); + i2c_pxa_do_sclk_adj(i2c); + #ifdef CONFIG_I2C_PXA_SLAVE dev_info(&i2c->adap.dev, "Enabling slave mode\n"); writel(readl(_ICR(i2c)) | ICR_SADIE | ICR_ALDIE | ICR_SSDIE, _ICR(i2c)); @@ -1198,6 +1233,26 @@ static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c, *i2c_types = (enum pxa_i2c_types)(of_id->data); + /* optional properties */ + if (of_device_is_compatible(np, "mrvl,mmp-twsi")) { + unsigned int tlow = 0, thigh = 0; + unsigned int clk_ns; + + /* clock time in nsec */ + clk_ns = 1000000 / (i2c->rate / 1000); + + of_property_read_u32(np, "i2c-sclk-high-time-ns", &thigh); + i2c->sclk_thigh_load_cnt = thigh / clk_ns; + + of_property_read_u32(np, "i2c-sclk-low-time-ns", &tlow); + i2c->sclk_tlow_load_cnt = tlow / clk_ns; + + /* For std/fast mode tlow & thigh have same bit-fields */ + if (!i2c->high_mode && + (i2c->sclk_tlow_load_cnt != i2c->sclk_thigh_load_cnt)) + dev_warn(&i2c->adap.dev, + "mismatch of tLow & tHigh values, using tLow\n"); + } return 0; } @@ -1248,6 +1303,14 @@ static int i2c_pxa_probe(struct platform_device *dev) return irq; } + i2c->clk = devm_clk_get(&dev->dev, NULL); + if (IS_ERR(i2c->clk)) { + dev_err(&dev->dev, "failed to get the clk: %ld\n", PTR_ERR(i2c->clk)); + return PTR_ERR(i2c->clk); + } + + i2c->rate = clk_get_rate(i2c->clk); + /* Default adapter num to device id; i2c_pxa_probe_dt can override. */ i2c->adap.nr = dev->id; @@ -1265,12 +1328,6 @@ static int i2c_pxa_probe(struct platform_device *dev) strlcpy(i2c->adap.name, "pxa_i2c-i2c", sizeof(i2c->adap.name)); - i2c->clk = devm_clk_get(&dev->dev, NULL); - if (IS_ERR(i2c->clk)) { - dev_err(&dev->dev, "failed to get the clk: %ld\n", PTR_ERR(i2c->clk)); - return PTR_ERR(i2c->clk); - } - i2c->reg_ibmr = i2c->reg_base + pxa_reg_layout[i2c_type].ibmr; i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr; i2c->reg_icr = i2c->reg_base + pxa_reg_layout[i2c_type].icr;