summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-11-25 17:15:12 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2024-11-25 17:15:12 -0800
commit70dbb12e95ec7585c68cb3ceae971688915021e3 (patch)
treecf14241e7fffb6679f15fda2b25514bc8a031266
parent5d38cb9bee73969125c7818a9f9e3358e0db07d6 (diff)
parent16470f60666618830cb9f0b8dfafd34a838c6dbd (diff)
Merge tag 'i2c-for-6.13-part2' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull more i2c updates from Wolfram Sang: "Andi was super busy the last weeks, so this pull requests contains one series (nomadik) and a number of smaller additions which were ready to go but nearly overlooked. New feature support: - Added support for frequencies up to 3.4 MHz on Nomadik I2C - DesignWare now accounts for bus capacitance and clock optimisation (declared as new parameters in the binding) to improve the calculation of signal rise and fall times (t_high and t_low) New Hardware support: - DWAPB I2C controller on FUJITSU-MONAKA (new ACPI HID) - Allwinner A523 (new compatible ID) - Mobileye EyeQ6H (new compatible ID)" * tag 'i2c-for-6.13-part2' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: MAINTAINERS: transfer i2c-aspeed maintainership from Brendan to Ryan i2c: designware: determine HS tHIGH and tLOW based on HW parameters dt-bindings: i2c: snps,designware-i2c: declare bus capacitance and clk freq optimized i2c: nomadik: support >=1MHz speed modes i2c: nomadik: fix BRCR computation i2c: nomadik: support Mobileye EyeQ6H I2C controller i2c: nomadik: switch from of_device_is_compatible() to of_match_device() dt-bindings: i2c: nomadik: support 400kHz < clock-frequency <= 3.4MHz dt-bindings: i2c: nomadik: add mobileye,eyeq6h-i2c bindings dt-bindings: i2c: mv64xxx: Add Allwinner A523 compatible string i2c: designware: Add ACPI HID for DWAPB I2C controller on FUJITSU-MONAKA i2c: qup: use generic device property accessors
-rw-r--r--Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml1
-rw-r--r--Documentation/devicetree/bindings/i2c/snps,designware-i2c.yaml18
-rw-r--r--Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml13
-rw-r--r--MAINTAINERS2
-rw-r--r--drivers/i2c/busses/i2c-designware-common.c5
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h6
-rw-r--r--drivers/i2c/busses/i2c-designware-master.c23
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c1
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c87
-rw-r--r--drivers/i2c/busses/i2c-qup.c4
10 files changed, 115 insertions, 45 deletions
diff --git a/Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml b/Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml
index 984fc1ed3ec6..c4efcef59133 100644
--- a/Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml
+++ b/Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml
@@ -33,6 +33,7 @@ properties:
- allwinner,sun50i-a100-i2c
- allwinner,sun50i-h616-i2c
- allwinner,sun50i-r329-i2c
+ - allwinner,sun55i-a523-i2c
- const: allwinner,sun8i-v536-i2c
- const: allwinner,sun6i-a31-i2c
- const: marvell,mv64xxx-i2c
diff --git a/Documentation/devicetree/bindings/i2c/snps,designware-i2c.yaml b/Documentation/devicetree/bindings/i2c/snps,designware-i2c.yaml
index 60035a787e5c..e5d05263c45a 100644
--- a/Documentation/devicetree/bindings/i2c/snps,designware-i2c.yaml
+++ b/Documentation/devicetree/bindings/i2c/snps,designware-i2c.yaml
@@ -97,6 +97,22 @@ properties:
- const: tx
- const: rx
+ snps,bus-capacitance-pf:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ This property indicates the bus capacitance in picofarads (pF).
+ This value is used to compute the tHIGH and tLOW periods for high speed
+ mode.
+ enum: [100, 400]
+ default: 100
+
+ snps,clk-freq-optimized:
+ description:
+ This property indicates whether the hardware reduce its clock frequency
+ by reducing the internal latency required to generate the high period and
+ low period of SCL line.
+ type: boolean
+
unevaluatedProperties: false
required:
@@ -121,6 +137,8 @@ examples:
i2c-sda-hold-time-ns = <300>;
i2c-sda-falling-time-ns = <300>;
i2c-scl-falling-time-ns = <300>;
+ snps,bus-capacitance-pf = <400>;
+ snps,clk-freq-optimized;
};
- |
i2c@2000 {
diff --git a/Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml b/Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml
index 44c54b162bb1..012402debfeb 100644
--- a/Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml
+++ b/Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml
@@ -22,6 +22,7 @@ select:
enum:
- st,nomadik-i2c
- mobileye,eyeq5-i2c
+ - mobileye,eyeq6h-i2c
required:
- compatible
@@ -29,15 +30,15 @@ properties:
compatible:
oneOf:
- items:
- - const: st,nomadik-i2c
+ - enum:
+ - st,nomadik-i2c
+ - mobileye,eyeq5-i2c
+ - mobileye,eyeq6h-i2c
- const: arm,primecell
- items:
- const: stericsson,db8500-i2c
- const: st,nomadik-i2c
- const: arm,primecell
- - items:
- - const: mobileye,eyeq5-i2c
- - const: arm,primecell
reg:
maxItems: 1
@@ -54,7 +55,7 @@ properties:
- items:
- const: mclk
- const: apb_pclk
- # Clock name in DB8500 or EyeQ5
+ # Clock name in DB8500 or EyeQ
- items:
- const: i2cclk
- const: apb_pclk
@@ -67,7 +68,7 @@ properties:
clock-frequency:
minimum: 1
- maximum: 400000
+ maximum: 3400000
mobileye,olb:
$ref: /schemas/types.yaml#/definitions/phandle-array
diff --git a/MAINTAINERS b/MAINTAINERS
index 4432351f268c..39319bed3116 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2213,7 +2213,7 @@ F: drivers/mmc/host/usdhi6rol0.c
F: drivers/pinctrl/pinctrl-artpec*
ARM/ASPEED I2C DRIVER
-M: Brendan Higgins <brendanhiggins@google.com>
+M: Ryan Chen <ryan_chen@aspeedtech.com>
R: Benjamin Herrenschmidt <benh@kernel.crashing.org>
R: Joel Stanley <joel@jms.id.au>
L: linux-i2c@vger.kernel.org
diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c
index 443f946acf36..857783d458fb 100644
--- a/drivers/i2c/busses/i2c-designware-common.c
+++ b/drivers/i2c/busses/i2c-designware-common.c
@@ -382,6 +382,11 @@ int i2c_dw_fw_parse_and_configure(struct dw_i2c_dev *dev)
i2c_parse_fw_timings(device, t, false);
+ if (device_property_read_u32(device, "snps,bus-capacitance-pf", &dev->bus_capacitance_pF))
+ dev->bus_capacitance_pF = 100;
+
+ dev->clk_freq_optimized = device_property_read_bool(device, "snps,clk-freq-optimized");
+
i2c_dw_adjust_bus_speed(dev);
if (is_of_node(fwnode))
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 520f9699e3bd..347843b4f5dd 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -242,6 +242,10 @@ struct reset_control;
* @set_sda_hold_time: callback to retrieve IP specific SDA hold timing
* @mode: operation mode - DW_IC_MASTER or DW_IC_SLAVE
* @rinfo: I²C GPIO recovery information
+ * @bus_capacitance_pF: bus capacitance in picofarads
+ * @clk_freq_optimized: if this value is true, it means the hardware reduces
+ * its internal clock frequency by reducing the internal latency required
+ * to generate the high period and low period of SCL line.
*
* HCNT and LCNT parameters can be used if the platform knows more accurate
* values than the one computed based only on the input clock frequency.
@@ -299,6 +303,8 @@ struct dw_i2c_dev {
int (*set_sda_hold_time)(struct dw_i2c_dev *dev);
int mode;
struct i2c_bus_recovery_info rinfo;
+ u32 bus_capacitance_pF;
+ bool clk_freq_optimized;
};
#define ACCESS_INTR_MASK BIT(0)
diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index 528b969253a7..eca8998d640f 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -151,19 +151,38 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
dev->hs_hcnt = 0;
dev->hs_lcnt = 0;
} else if (!dev->hs_hcnt || !dev->hs_lcnt) {
+ u32 t_high, t_low;
+
+ /*
+ * The legal values stated in the databook for bus
+ * capacitance are only 100pF and 400pF.
+ * If dev->bus_capacitance_pF is greater than or equals
+ * to 400, t_high and t_low are assumed to be
+ * appropriate values for 400pF, otherwise 100pF.
+ */
+ if (dev->bus_capacitance_pF >= 400) {
+ /* assume bus capacitance is 400pF */
+ t_high = dev->clk_freq_optimized ? 160 : 120;
+ t_low = 320;
+ } else {
+ /* assume bus capacitance is 100pF */
+ t_high = 60;
+ t_low = dev->clk_freq_optimized ? 120 : 160;
+ }
+
ic_clk = i2c_dw_clk_rate(dev);
dev->hs_hcnt =
i2c_dw_scl_hcnt(dev,
DW_IC_HS_SCL_HCNT,
ic_clk,
- 160, /* tHIGH = 160 ns */
+ t_high,
sda_falling_time,
0); /* No offset */
dev->hs_lcnt =
i2c_dw_scl_lcnt(dev,
DW_IC_HS_SCL_LCNT,
ic_clk,
- 320, /* tLOW = 320 ns */
+ t_low,
scl_falling_time,
0); /* No offset */
}
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 1643cad6489c..3e12aab6bf2d 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -349,6 +349,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "AMDI0019", ACCESS_INTR_MASK | ARBITRATION_SEMAPHORE },
{ "AMDI0510", 0 },
{ "APMC0D0F", 0 },
+ { "FUJI200B", 0 },
{ "HISI02A1", 0 },
{ "HISI02A2", 0 },
{ "HISI02A3", 0 },
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index ad0f02acdb12..efb33802804f 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -6,10 +6,10 @@
* I2C master mode controller driver, used in Nomadik 8815
* and Ux500 platforms.
*
- * The Mobileye EyeQ5 platform is also supported; it uses
+ * The Mobileye EyeQ5 and EyeQ6H platforms are also supported; they use
* the same Ux500/DB8500 IP block with two quirks:
* - The memory bus only supports 32-bit accesses.
- * - A register must be configured for the I2C speed mode;
+ * - (only EyeQ5) A register must be configured for the I2C speed mode;
* it is located in a shared register region called OLB.
*
* Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
@@ -26,6 +26,7 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
@@ -396,7 +397,7 @@ static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *priv, u16 flags)
*/
static void setup_i2c_controller(struct nmk_i2c_dev *priv)
{
- u32 brcr1, brcr2;
+ u32 brcr;
u32 i2c_clk, div;
u32 ns;
u16 slsu;
@@ -443,7 +444,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *priv)
/*
* The spec says, in case of std. mode the divider is
* 2 whereas it is 3 for fast and fastplus mode of
- * operation. TODO - high speed support.
+ * operation.
*/
div = (priv->clk_freq > I2C_MAX_STANDARD_MODE_FREQ) ? 3 : 2;
@@ -451,30 +452,23 @@ static void setup_i2c_controller(struct nmk_i2c_dev *priv)
* generate the mask for baud rate counters. The controller
* has two baud rate counters. One is used for High speed
* operation, and the other is for std, fast mode, fast mode
- * plus operation. Currently we do not supprt high speed mode
- * so set brcr1 to 0.
+ * plus operation.
+ *
+ * BRCR is a clock divider amount. Pick highest value that
+ * leads to rate strictly below target. Eg when asking for
+ * 400kHz you want a bus rate <=400kHz (and not >=400kHz).
*/
- brcr1 = FIELD_PREP(I2C_BRCR_BRCNT1, 0);
- brcr2 = FIELD_PREP(I2C_BRCR_BRCNT2, i2c_clk / (priv->clk_freq * div));
+ brcr = DIV_ROUND_UP(i2c_clk, priv->clk_freq * div);
+
+ if (priv->sm == I2C_FREQ_MODE_HIGH_SPEED)
+ brcr = FIELD_PREP(I2C_BRCR_BRCNT1, brcr);
+ else
+ brcr = FIELD_PREP(I2C_BRCR_BRCNT2, brcr);
/* set the baud rate counter register */
- writel((brcr1 | brcr2), priv->virtbase + I2C_BRCR);
+ writel(brcr, priv->virtbase + I2C_BRCR);
- /*
- * set the speed mode. Currently we support
- * only standard and fast mode of operation
- * TODO - support for fast mode plus (up to 1Mb/s)
- * and high speed (up to 3.4 Mb/s)
- */
- if (priv->sm > I2C_FREQ_MODE_FAST) {
- dev_err(&priv->adev->dev,
- "do not support this mode defaulting to std. mode\n");
- brcr2 = FIELD_PREP(I2C_BRCR_BRCNT2,
- i2c_clk / (I2C_MAX_STANDARD_MODE_FREQ * 2));
- writel((brcr1 | brcr2), priv->virtbase + I2C_BRCR);
- writel(FIELD_PREP(I2C_CR_SM, I2C_FREQ_MODE_STANDARD),
- priv->virtbase + I2C_CR);
- }
+ /* set the speed mode */
writel(FIELD_PREP(I2C_CR_SM, priv->sm), priv->virtbase + I2C_CR);
/* set the Tx and Rx FIFO threshold */
@@ -1015,11 +1009,14 @@ static void nmk_i2c_of_probe(struct device_node *np,
if (of_property_read_u32(np, "clock-frequency", &priv->clk_freq))
priv->clk_freq = I2C_MAX_STANDARD_MODE_FREQ;
- /* This driver only supports 'standard' and 'fast' modes of operation. */
if (priv->clk_freq <= I2C_MAX_STANDARD_MODE_FREQ)
priv->sm = I2C_FREQ_MODE_STANDARD;
- else
+ else if (priv->clk_freq <= I2C_MAX_FAST_MODE_FREQ)
priv->sm = I2C_FREQ_MODE_FAST;
+ else if (priv->clk_freq <= I2C_MAX_FAST_MODE_PLUS_FREQ)
+ priv->sm = I2C_FREQ_MODE_FAST_PLUS;
+ else
+ priv->sm = I2C_FREQ_MODE_HIGH_SPEED;
priv->tft = 1; /* Tx FIFO threshold */
priv->rft = 8; /* Rx FIFO threshold */
@@ -1046,8 +1043,6 @@ static int nmk_i2c_eyeq5_probe(struct nmk_i2c_dev *priv)
struct regmap *olb;
unsigned int id;
- priv->has_32b_bus = true;
-
olb = syscon_regmap_lookup_by_phandle_args(np, "mobileye,olb", 1, &id);
if (IS_ERR(olb))
return PTR_ERR(olb);
@@ -1068,15 +1063,39 @@ static int nmk_i2c_eyeq5_probe(struct nmk_i2c_dev *priv)
return 0;
}
+#define NMK_I2C_EYEQ_FLAG_32B_BUS BIT(0)
+#define NMK_I2C_EYEQ_FLAG_IS_EYEQ5 BIT(1)
+
+static const struct of_device_id nmk_i2c_eyeq_match_table[] = {
+ {
+ .compatible = "mobileye,eyeq5-i2c",
+ .data = (void *)(NMK_I2C_EYEQ_FLAG_32B_BUS | NMK_I2C_EYEQ_FLAG_IS_EYEQ5),
+ },
+ {
+ .compatible = "mobileye,eyeq6h-i2c",
+ .data = (void *)NMK_I2C_EYEQ_FLAG_32B_BUS,
+ },
+};
+
static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
{
- int ret = 0;
- struct nmk_i2c_dev *priv;
+ struct i2c_vendor_data *vendor = id->data;
+ u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1;
struct device_node *np = adev->dev.of_node;
+ const struct of_device_id *match;
struct device *dev = &adev->dev;
+ unsigned long match_flags = 0;
+ struct nmk_i2c_dev *priv;
struct i2c_adapter *adap;
- struct i2c_vendor_data *vendor = id->data;
- u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1;
+ int ret = 0;
+
+ /*
+ * We do not want to attach a .of_match_table to our amba driver.
+ * Do not convert to device_get_match_data().
+ */
+ match = of_match_device(nmk_i2c_eyeq_match_table, dev);
+ if (match)
+ match_flags = (unsigned long)match->data;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -1084,10 +1103,10 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
priv->vendor = vendor;
priv->adev = adev;
- priv->has_32b_bus = false;
+ priv->has_32b_bus = match_flags & NMK_I2C_EYEQ_FLAG_32B_BUS;
nmk_i2c_of_probe(np, priv);
- if (of_device_is_compatible(np, "mobileye,eyeq5-i2c")) {
+ if (match_flags & NMK_I2C_EYEQ_FLAG_IS_EYEQ5) {
ret = nmk_i2c_eyeq5_probe(priv);
if (ret)
return dev_err_probe(dev, ret, "failed OLB lookup\n");
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 86ec391616b0..da20b4487c9a 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -17,9 +17,9 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
#include <linux/scatterlist.h>
/* QUP Registers */
@@ -1683,7 +1683,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
}
}
- if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) {
+ if (device_is_compatible(&pdev->dev, "qcom,i2c-qup-v1.1.1")) {
qup->adap.algo = &qup_i2c_algo;
qup->adap.quirks = &qup_i2c_quirks;
is_qup_v1 = true;