diff --git a/Documentation/devicetree/bindings/i2c/altr,softip-i2c-v1.0.yaml b/Documentation/devicetree/bindings/i2c/altr,softip-i2c-v1.0.yaml new file mode 100644 index 000000000000..d04570680c05 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/altr,softip-i2c-v1.0.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/i2c/altr,softip-i2c-v1.0.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Altera I2C Controller + +maintainers: + - Thor Thayer + - Chaitanya Sabnis + +description: + Altera's synthesizable logic block I2C Controller for use in Altera's FPGAs. + +allOf: + - $ref: /schemas/i2c/i2c-controller.yaml# + +properties: + compatible: + const: altr,softip-i2c-v1.0 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + fifo-size: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Size of the RX and TX FIFOs in bytes. + +required: + - compatible + - reg + - interrupts + - clocks + +unevaluatedProperties: false + +examples: + - | + i2c@80000 { + compatible = "altr,softip-i2c-v1.0"; + reg = <0x80000 0x40>; + interrupt-parent = <&intc>; + interrupts = <0 43 4>; + clocks = <&clk_0>; + clock-frequency = <100000>; + #address-cells = <1>; + #size-cells = <0>; + fifo-size = <4>; + + eeprom@51 { + compatible = "atmel,24c32"; + reg = <0x51>; + pagesize = <32>; + }; + }; diff --git a/Documentation/devicetree/bindings/i2c/cdns,i2c-r1p10.yaml b/Documentation/devicetree/bindings/i2c/cdns,i2c-r1p10.yaml index 9f1d35ce1fe8..4dc69d54f75d 100644 --- a/Documentation/devicetree/bindings/i2c/cdns,i2c-r1p10.yaml +++ b/Documentation/devicetree/bindings/i2c/cdns,i2c-r1p10.yaml @@ -14,9 +14,13 @@ allOf: properties: compatible: - enum: - - cdns,i2c-r1p10 # cadence i2c controller version 1.0 - - cdns,i2c-r1p14 # cadence i2c controller version 1.4 + oneOf: + - enum: + - cdns,i2c-r1p10 # cadence i2c controller version 1.0 + - cdns,i2c-r1p14 # cadence i2c controller version 1.4 + - items: + - const: axiado,ax3005-i2c + - const: cdns,i2c-r1p14 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/i2c/i2c-altera.txt b/Documentation/devicetree/bindings/i2c/i2c-altera.txt deleted file mode 100644 index 767664f448ec..000000000000 --- a/Documentation/devicetree/bindings/i2c/i2c-altera.txt +++ /dev/null @@ -1,39 +0,0 @@ -* Altera I2C Controller -* This is Altera's synthesizable logic block I2C Controller for use -* in Altera's FPGAs. - -Required properties : - - compatible : should be "altr,softip-i2c-v1.0" - - reg : Offset and length of the register set for the device - - interrupts : where IRQ is the interrupt number. - - clocks : phandle to input clock. - - #address-cells = <1>; - - #size-cells = <0>; - -Recommended properties : - - clock-frequency : desired I2C bus clock frequency in Hz. - -Optional properties : - - fifo-size : Size of the RX and TX FIFOs in bytes. - - Child nodes conforming to i2c bus binding - -Example : - - i2c@100080000 { - compatible = "altr,softip-i2c-v1.0"; - reg = <0x00000001 0x00080000 0x00000040>; - interrupt-parent = <&intc>; - interrupts = <0 43 4>; - clocks = <&clk_0>; - clock-frequency = <100000>; - #address-cells = <1>; - #size-cells = <0>; - fifo-size = <4>; - - eeprom@51 { - compatible = "atmel,24c32"; - reg = <0x51>; - pagesize = <32>; - }; - }; - diff --git a/Documentation/devicetree/bindings/i2c/i2c-axxia.txt b/Documentation/devicetree/bindings/i2c/i2c-axxia.txt deleted file mode 100644 index 7d53a2b79553..000000000000 --- a/Documentation/devicetree/bindings/i2c/i2c-axxia.txt +++ /dev/null @@ -1,30 +0,0 @@ -LSI Axxia I2C - -Required properties : -- compatible : Must be "lsi,api2c" -- reg : Offset and length of the register set for the device -- interrupts : the interrupt specifier -- #address-cells : Must be <1>; -- #size-cells : Must be <0>; -- clock-names : Must contain "i2c". -- clocks: Must contain an entry for each name in clock-names. See the common - clock bindings. - -Optional properties : -- clock-frequency : Desired I2C bus clock frequency in Hz. If not specified, - the default 100 kHz frequency will be used. As only Normal and Fast modes - are supported, possible values are 100000 and 400000. - -Example : - -i2c@2010084000 { - compatible = "lsi,api2c"; - device_type = "i2c"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x20 0x10084000 0x00 0x1000>; - interrupts = <0 19 4>; - clocks = <&clk_per>; - clock-names = "i2c"; - clock-frequency = <400000>; -}; diff --git a/Documentation/devicetree/bindings/i2c/lsi,api2c.yaml b/Documentation/devicetree/bindings/i2c/lsi,api2c.yaml new file mode 100644 index 000000000000..2d1c3069c3a3 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/lsi,api2c.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/i2c/lsi,api2c.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: LSI Axxia I2C Controller + +maintainers: + - Anders Berg + - Chaitanya Sabnis + +allOf: + - $ref: /schemas/i2c/i2c-controller.yaml# + +properties: + compatible: + const: lsi,api2c + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: i2c + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + i2c@10084000 { + compatible = "lsi,api2c"; + reg = <0x10084000 0x1000>; + interrupts = <0 19 4>; + clocks = <&clk_per>; + clock-names = "i2c"; + clock-frequency = <400000>; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/Documentation/devicetree/bindings/i2c/qcom,sa8255p-geni-i2c.yaml b/Documentation/devicetree/bindings/i2c/qcom,sa8255p-geni-i2c.yaml new file mode 100644 index 000000000000..04caf622b3ba --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/qcom,sa8255p-geni-i2c.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/i2c/qcom,sa8255p-geni-i2c.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SA8255p QUP GENI I2C Controller + +maintainers: + - Praveen Talari + +properties: + compatible: + oneOf: + - const: qcom,sa8255p-geni-i2c + - items: + - const: qcom,sa8797p-geni-i2c + - const: qcom,sa8255p-geni-i2c + + reg: + maxItems: 1 + + dmas: + maxItems: 2 + + dma-names: + items: + - const: tx + - const: rx + + interrupts: + maxItems: 1 + + power-domains: + maxItems: 2 + + power-domain-names: + items: + - const: power + - const: perf + +required: + - compatible + - reg + - interrupts + - power-domains + +allOf: + - $ref: /schemas/i2c/i2c-controller.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + + i2c@a90000 { + compatible = "qcom,sa8255p-geni-i2c"; + reg = <0xa90000 0x4000>; + interrupts = ; + dmas = <&gpi_dma0 0 0 QCOM_GPI_I2C>, + <&gpi_dma0 1 0 QCOM_GPI_I2C>; + dma-names = "tx", "rx"; + power-domains = <&scmi0_pd 0>, <&scmi0_dvfs 0>; + power-domain-names = "power", "perf"; + }; +... diff --git a/Documentation/devicetree/bindings/i2c/renesas,rcar-i2c.yaml b/Documentation/devicetree/bindings/i2c/renesas,rcar-i2c.yaml index 6cc60c3f61cd..f9ede03c3287 100644 --- a/Documentation/devicetree/bindings/i2c/renesas,rcar-i2c.yaml +++ b/Documentation/devicetree/bindings/i2c/renesas,rcar-i2c.yaml @@ -56,6 +56,11 @@ properties: - renesas,i2c-r8a779h0 # R-Car V4M - const: renesas,rcar-gen4-i2c # R-Car Gen4 + - items: + - enum: + - renesas,i2c-r8a78000 # R-Car X5H + - const: renesas,rcar-gen5-i2c # R-Car Gen5 + reg: maxItems: 1 @@ -140,6 +145,7 @@ allOf: - renesas,rcar-gen2-i2c - renesas,rcar-gen3-i2c - renesas,rcar-gen4-i2c + - renesas,rcar-gen5-i2c then: required: - resets diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index d1d9a6c1a1e2..7ca565cbff5b 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -639,7 +639,7 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap, struct i2c_algo_bit_data *bit_adap = adap->algo_data; int ret; - if (bit_test) { + if (bit_test && !bit_adap->skip_bit_test) { ret = test_bus(adap); if (bit_test >= 2 && ret < 0) return -ENODEV; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index d35456994280..d7b89508311f 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -793,7 +793,7 @@ config I2C_JZ4780 config I2C_K1 tristate "SpacemiT K1 I2C adapter" depends on ARCH_SPACEMIT || COMPILE_TEST - depends on OF + depends on OF && COMMON_CLK default ARCH_SPACEMIT help This option enables support for the I2C interface on the SpacemiT K1 diff --git a/drivers/i2c/busses/i2c-amd-asf-plat.c b/drivers/i2c/busses/i2c-amd-asf-plat.c index 82cbc8fb5c18..b0b40fe1d79b 100644 --- a/drivers/i2c/busses/i2c-amd-asf-plat.c +++ b/drivers/i2c/busses/i2c-amd-asf-plat.c @@ -89,6 +89,10 @@ static void amd_asf_process_target(struct work_struct *work) outb_p(reg, ASFDATABNKSEL); cmd = inb_p(ASFINDEX); len = inb_p(ASFDATARWPTR); + + if (len > ASF_BLOCK_MAX_BYTES) + return; + for (idx = 0; idx < len; idx++) data[idx] = inb_p(ASFINDEX); @@ -333,11 +337,11 @@ static int amd_asf_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) - return dev_err_probe(dev, irq, "missing IRQ resources\n"); + return irq; ret = devm_request_irq(dev, irq, amd_asf_irq_handler, IRQF_SHARED, "amd_asf", asf_dev); if (ret) - return dev_err_probe(dev, ret, "Unable to request irq: %d for use\n", irq); + return ret; asf_dev->adap.owner = THIS_MODULE; asf_dev->adap.algo = &amd_asf_smbus_algorithm; diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 86ca4c2221c4..66bb3bfdaa4c 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -1147,8 +1147,7 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev) bcm_iproc_i2c_isr, 0, pdev->name, iproc_i2c); if (ret < 0) - return dev_err_probe(iproc_i2c->device, ret, - "unable to request irq %i\n", irq); + return ret; iproc_i2c->irq = irq; } else { diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 0617f416cb0b..e15eef163a8f 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -117,8 +117,6 @@ /* timeout for pm runtime autosuspend */ #define DAVINCI_I2C_PM_TIMEOUT 1000 /* ms */ -#define DAVINCI_I2C_DEFAULT_BUS_FREQ 100000 - struct davinci_i2c_dev { struct device *dev; void __iomem *base; @@ -760,7 +758,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) r = device_property_read_u32(&pdev->dev, "clock-frequency", &prop); if (r) - prop = DAVINCI_I2C_DEFAULT_BUS_FREQ; + prop = I2C_MAX_STANDARD_MODE_FREQ; dev->bus_freq = prop / 1000; diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index f4355b17bfbf..b7521b7ece37 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -18,9 +18,21 @@ #include #include +static LIST_HEAD(i2c_gpio_scl_list); +static DEFINE_MUTEX(i2c_gpio_scl_list_lock); +static struct lock_class_key i2c_gpio_scl_lock_key; + +struct i2c_gpio_scl_data { + struct fwnode_reference_args args; + struct gpio_desc *gpio; + struct rt_mutex lock; + struct list_head list; + refcount_t ref; +}; + struct i2c_gpio_private_data { struct gpio_desc *sda; - struct gpio_desc *scl; + struct i2c_gpio_scl_data *scl; struct i2c_adapter adap; struct i2c_algo_bit_data bit_data; struct i2c_gpio_platform_data pdata; @@ -31,6 +43,11 @@ struct i2c_gpio_private_data { #endif }; +static inline struct i2c_gpio_private_data *adap_to_priv(struct i2c_adapter *adap) +{ + return container_of(adap, struct i2c_gpio_private_data, adap); +} + /* * Toggle SDA by changing the output value of the pin. This is only * valid for pins configured as open drain (i.e. setting the value @@ -53,7 +70,7 @@ static void i2c_gpio_setscl_val(void *data, int state) { struct i2c_gpio_private_data *priv = data; - gpiod_set_value_cansleep(priv->scl, state); + gpiod_set_value_cansleep(priv->scl->gpio, state); } static int i2c_gpio_getsda(void *data) @@ -67,9 +84,41 @@ static int i2c_gpio_getscl(void *data) { struct i2c_gpio_private_data *priv = data; - return gpiod_get_value_cansleep(priv->scl); + return gpiod_get_value_cansleep(priv->scl->gpio); } +static void i2c_gpio_lock_bus(struct i2c_adapter *adap, unsigned int flags) +{ + /* Take care about adapter lock. See i2c_adapter_lock_bus() and others. */ + rt_mutex_lock_nested(&adap->bus_lock, i2c_adapter_depth(adap)); + rt_mutex_lock(&adap_to_priv(adap)->scl->lock); +} + +static int i2c_gpio_trylock_bus(struct i2c_adapter *adap, unsigned int flags) +{ + if (!rt_mutex_trylock(&adap->bus_lock)) + return 0; + + if (!rt_mutex_trylock(&adap_to_priv(adap)->scl->lock)) { + rt_mutex_unlock(&adap->bus_lock); + return 0; + } + + return 1; +} + +static void i2c_gpio_unlock_bus(struct i2c_adapter *adap, unsigned int flags) +{ + rt_mutex_unlock(&adap_to_priv(adap)->scl->lock); + rt_mutex_unlock(&adap->bus_lock); +} + +static const struct i2c_lock_operations i2c_gpio_lock_ops = { + .lock_bus = i2c_gpio_lock_bus, + .trylock_bus = i2c_gpio_trylock_bus, + .unlock_bus = i2c_gpio_unlock_bus, +}; + #ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR #define setsda(bd, val) ((bd)->setsda((bd)->data, val)) @@ -165,14 +214,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_write_byte, NULL, fops_incomplete_write static int i2c_gpio_fi_act_on_scl_irq(struct i2c_gpio_private_data *priv, irqreturn_t handler(int, void*)) { - int ret, irq = gpiod_to_irq(priv->scl); + int ret, irq = gpiod_to_irq(priv->scl->gpio); if (irq < 0) return irq; i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); - ret = gpiod_direction_input(priv->scl); + ret = gpiod_direction_input(priv->scl->gpio); if (ret) goto unlock; @@ -187,7 +236,7 @@ static int i2c_gpio_fi_act_on_scl_irq(struct i2c_gpio_private_data *priv, free_irq(irq, priv); output: - ret = gpiod_direction_output(priv->scl, 1) ?: ret; + ret = gpiod_direction_output(priv->scl->gpio, 1) ?: ret; unlock: i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); @@ -308,13 +357,17 @@ static struct gpio_desc *i2c_gpio_get_desc(struct device *dev, struct gpio_desc *retdesc; int ret; - retdesc = devm_gpiod_get(dev, con_id, gflags); + /* + * Don't use resource-managed functions. SCL may be shared across adapters and has + * its own lifetime management. SDA uses the same path for consistency. + */ + retdesc = gpiod_get(dev, con_id, gflags); if (!IS_ERR(retdesc)) { dev_dbg(dev, "got GPIO from name %s\n", con_id); return retdesc; } - retdesc = devm_gpiod_get_index(dev, NULL, index, gflags); + retdesc = gpiod_get_index(dev, NULL, index, gflags); if (!IS_ERR(retdesc)) { dev_dbg(dev, "got GPIO from index %u\n", index); return retdesc; @@ -336,6 +389,134 @@ static struct gpio_desc *i2c_gpio_get_desc(struct device *dev, return retdesc; } +static struct i2c_gpio_scl_data *i2c_gpio_create_scl(struct device *dev) +{ + struct fwnode_handle *fwnode = dev_fwnode(dev); + struct fwnode_reference_args args; + struct i2c_gpio_scl_data *scl; + bool sharable = false; + int ret; + + /* + * SCL gpios can be shared if they are defined in the devicetree and have at least one + * cell in addition to the phandle. This is usually the pin. To support complex designs + * with arbitrary of_xlate() mappings handle the node cells opaque. + */ + if (fwnode) { + ret = fwnode_property_get_reference_args(fwnode, "scl-gpios", + "#gpio-cells", 0, 0, &args); + if (ret) + /* try the ancient way */ + ret = fwnode_property_get_reference_args(fwnode, "gpios", + "#gpio-cells", 0, 1, &args); + + if (!ret) { + if (args.nargs >= 1) + sharable = true; + else + fwnode_handle_put(args.fwnode); + } + } + + scl = kzalloc(sizeof(*scl), GFP_KERNEL); + if (!scl) { + if (sharable) + fwnode_handle_put(args.fwnode); + return ERR_PTR(-ENOMEM); + } + + if (sharable) { + scl->args.fwnode = args.fwnode; + scl->args.nargs = args.nargs; + memcpy(scl->args.args, args.args, sizeof(args.args[0]) * args.nargs); + } + + rt_mutex_init(&scl->lock); + lockdep_set_class(&scl->lock, &i2c_gpio_scl_lock_key); + refcount_set(&scl->ref, 1); + + return scl; +} + +static void i2c_gpio_free_scl(struct i2c_gpio_scl_data *scl) +{ + if (scl->args.fwnode) + fwnode_handle_put(scl->args.fwnode); + kfree(scl); +} + +static bool i2c_gpio_scl_matches(struct i2c_gpio_scl_data *a, struct i2c_gpio_scl_data *b) +{ + if (!a->args.fwnode || !b->args.fwnode || + a->args.fwnode != b->args.fwnode || a->args.nargs != b->args.nargs) + return false; + + return memcmp(a->args.args, b->args.args, sizeof(a->args.args[0]) * a->args.nargs) == 0; +} + +/* + * Look up an existing or create a new shared SCL structure. Optimistic setup sequence always + * creates and tries to add a new entry to the list. This uses minimum locking and afterwards + * requests the GPIO without a lock held. Concurrent probes for the same SCL pin see the entry + * and do not race into a second gpiod_get(). Until everything is setup they terminate with + * -EPROBE_DEFER. + */ +static struct i2c_gpio_scl_data *i2c_gpio_lookup_scl(struct device *dev, enum gpiod_flags gflags) +{ + struct i2c_gpio_scl_data *scl, *new_scl; + struct gpio_desc *gpio; + + new_scl = i2c_gpio_create_scl(dev); + if (IS_ERR(new_scl)) + return new_scl; + + scoped_guard(mutex, &i2c_gpio_scl_list_lock) { + list_for_each_entry(scl, &i2c_gpio_scl_list, list) { + if (!i2c_gpio_scl_matches(scl, new_scl)) + continue; + + i2c_gpio_free_scl(new_scl); + if (!scl->gpio) + return ERR_PTR(-EPROBE_DEFER); + + refcount_inc(&scl->ref); + if (scl->args.fwnode) + dev_dbg(dev, "reusing shared SCL (%pfwP)\n", scl->args.fwnode); + + return scl; + } + list_add(&new_scl->list, &i2c_gpio_scl_list); + } + + gpio = i2c_gpio_get_desc(dev, "scl", 1, gflags); + if (IS_ERR(gpio)) { + scoped_guard(mutex, &i2c_gpio_scl_list_lock) + list_del(&new_scl->list); + i2c_gpio_free_scl(new_scl); + + return ERR_CAST(gpio); + } + + scoped_guard(mutex, &i2c_gpio_scl_list_lock) + new_scl->gpio = gpio; + + if (new_scl->args.fwnode) + dev_dbg(dev, "registered shared SCL (%pfwP)\n", new_scl->args.fwnode); + + return new_scl; +} + +static void i2c_gpio_cleanup_scl(struct i2c_gpio_scl_data *scl) +{ + if (!refcount_dec_and_mutex_lock(&scl->ref, &i2c_gpio_scl_list_lock)) + return; + + list_del(&scl->list); + mutex_unlock(&i2c_gpio_scl_list_lock); + gpiod_put(scl->gpio); + i2c_gpio_free_scl(scl); +} + static int i2c_gpio_probe(struct platform_device *pdev) { struct i2c_gpio_private_data *priv; @@ -386,15 +567,18 @@ static int i2c_gpio_probe(struct platform_device *pdev) gflags = GPIOD_OUT_HIGH; else gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; - priv->scl = i2c_gpio_get_desc(dev, "scl", 1, gflags); - if (IS_ERR(priv->scl)) - return PTR_ERR(priv->scl); + priv->scl = i2c_gpio_lookup_scl(dev, gflags); + if (IS_ERR(priv->scl)) { + ret = PTR_ERR(priv->scl); + goto err_cleanup_sda; + } - if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl)) + if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl->gpio)) dev_warn(dev, "Slow GPIO pins might wreak havoc into I2C/SMBus bus timing"); else bit_data->can_do_atomic = true; + bit_data->skip_bit_test = !!priv->scl->args.fwnode; bit_data->setsda = i2c_gpio_setsda_val; bit_data->setscl = i2c_gpio_setscl_val; @@ -423,6 +607,8 @@ static int i2c_gpio_probe(struct platform_device *pdev) else snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); + /* Always use shared SCL aware locking */ + adap->lock_ops = &i2c_gpio_lock_ops; adap->algo_data = bit_data; adap->class = I2C_CLASS_HWMON; adap->dev.parent = dev; @@ -431,7 +617,7 @@ static int i2c_gpio_probe(struct platform_device *pdev) adap->nr = pdev->id; ret = i2c_bit_add_numbered_bus(adap); if (ret) - return ret; + goto err_cleanup_scl; platform_set_drvdata(pdev, priv); @@ -441,13 +627,20 @@ static int i2c_gpio_probe(struct platform_device *pdev) * from the descriptor, then provide that instead. */ dev_info(dev, "using lines %u (SDA) and %u (SCL%s)\n", - desc_to_gpio(priv->sda), desc_to_gpio(priv->scl), + desc_to_gpio(priv->sda), desc_to_gpio(priv->scl->gpio), pdata->scl_is_output_only ? ", no clock stretching" : ""); i2c_gpio_fault_injector_init(pdev); return 0; + +err_cleanup_scl: + i2c_gpio_cleanup_scl(priv->scl); +err_cleanup_sda: + gpiod_put(priv->sda); + + return ret; } static void i2c_gpio_remove(struct platform_device *pdev) @@ -459,6 +652,8 @@ static void i2c_gpio_remove(struct platform_device *pdev) adap = &priv->adap; i2c_del_adapter(adap); + i2c_gpio_cleanup_scl(priv->scl); + gpiod_put(priv->sda); } static const struct of_device_id i2c_gpio_dt_ids[] = { diff --git a/drivers/i2c/busses/i2c-gxp.c b/drivers/i2c/busses/i2c-gxp.c index f9a5465f52da..6a5cef7e4383 100644 --- a/drivers/i2c/busses/i2c-gxp.c +++ b/drivers/i2c/busses/i2c-gxp.c @@ -551,7 +551,7 @@ static int gxp_i2c_probe(struct platform_device *pdev) rc = devm_request_irq(&pdev->dev, drvdata->irq, gxp_i2c_irq_handler, IRQF_SHARED, gxp_i2c_name[drvdata->engine], drvdata); if (rc < 0) - return dev_err_probe(&pdev->dev, rc, "irq request failed\n"); + return rc; i2c_parse_fw_timings(&pdev->dev, &drvdata->t, true); diff --git a/drivers/i2c/busses/i2c-hisi.c b/drivers/i2c/busses/i2c-hisi.c index 04d7978cae04..ba5c9579ae19 100644 --- a/drivers/i2c/busses/i2c-hisi.c +++ b/drivers/i2c/busses/i2c-hisi.c @@ -481,7 +481,7 @@ static int hisi_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(dev, ctlr->irq, hisi_i2c_irq, 0, "hisi-i2c", ctlr); if (ret) - return dev_err_probe(dev, ret, "failed to request irq handler\n"); + return ret; ctlr->clk = devm_clk_get_optional_enabled(&pdev->dev, NULL); if (IS_ERR_OR_NULL(ctlr->clk)) { diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index e6c24a9d934d..e1a4338bc51e 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -1510,11 +1510,6 @@ static int lpi2c_imx_probe(struct platform_device *pdev) if (ret) lpi2c_imx->bitrate = I2C_MAX_STANDARD_MODE_FREQ; - ret = devm_request_irq(&pdev->dev, lpi2c_imx->irq, lpi2c_imx_isr, IRQF_NO_SUSPEND, - pdev->name, lpi2c_imx); - if (ret) - return dev_err_probe(&pdev->dev, ret, "can't claim irq %d\n", lpi2c_imx->irq); - i2c_set_adapdata(&lpi2c_imx->adapter, lpi2c_imx); platform_set_drvdata(pdev, lpi2c_imx); @@ -1527,14 +1522,18 @@ static int lpi2c_imx_probe(struct platform_device *pdev) * each transfer */ ret = devm_clk_rate_exclusive_get(&pdev->dev, lpi2c_imx->clks[0].clk); - if (ret) - return dev_err_probe(&pdev->dev, ret, - "can't lock I2C peripheral clock rate\n"); + if (ret) { + ret = dev_err_probe(&pdev->dev, ret, + "can't lock I2C peripheral clock rate\n"); + goto clk_disable; + } lpi2c_imx->rate_per = clk_get_rate(lpi2c_imx->clks[0].clk); - if (!lpi2c_imx->rate_per) - return dev_err_probe(&pdev->dev, -EINVAL, - "can't get I2C peripheral clock rate\n"); + if (!lpi2c_imx->rate_per) { + ret = dev_err_probe(&pdev->dev, -EINVAL, + "can't get I2C peripheral clock rate\n"); + goto clk_disable; + } if (lpi2c_imx->hwdata->need_prepare_unprepare_clk) pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_LONG_TIMEOUT_MS); @@ -1546,6 +1545,20 @@ static int lpi2c_imx_probe(struct platform_device *pdev) pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); + /* + * Reset all internal controller registers of both Master and Target + * to avoid effects of previous status. + */ + writel(MCR_RST, lpi2c_imx->base + LPI2C_MCR); + writel(SCR_RST, lpi2c_imx->base + LPI2C_SCR); + writel(0, lpi2c_imx->base + LPI2C_MCR); + writel(0, lpi2c_imx->base + LPI2C_SCR); + + ret = devm_request_irq(&pdev->dev, lpi2c_imx->irq, lpi2c_imx_isr, IRQF_NO_SUSPEND, + pdev->name, lpi2c_imx); + if (ret) + goto rpm_disable; + temp = readl(lpi2c_imx->base + LPI2C_PARAM); lpi2c_imx->txfifosize = 1 << (temp & 0x0f); lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f); @@ -1576,8 +1589,11 @@ static int lpi2c_imx_probe(struct platform_device *pdev) rpm_disable: pm_runtime_dont_use_autosuspend(&pdev->dev); - pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); +clk_disable: + clk_bulk_disable_unprepare(lpi2c_imx->num_clks, lpi2c_imx->clks); return ret; } diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 9477d814fde9..19ec056b00af 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1753,7 +1753,7 @@ static int i2c_imx_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) - return dev_err_probe(&pdev->dev, irq, "can't get IRQ\n"); + return irq; base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) diff --git a/drivers/i2c/busses/i2c-k1.c b/drivers/i2c/busses/i2c-k1.c index 3fe716cc153d..4e1d67541132 100644 --- a/drivers/i2c/busses/i2c-k1.c +++ b/drivers/i2c/busses/i2c-k1.c @@ -4,7 +4,9 @@ */ #include +#include #include +#include #include #include #include @@ -17,6 +19,8 @@ #define SPACEMIT_ISR 0x4 /* Status register */ #define SPACEMIT_IDBR 0xc /* Data buffer register */ #define SPACEMIT_IRCR 0x18 /* Reset cycle counter */ +#define SPACEMIT_ILCR 0x10 /* Load Count Register */ +#define SPACEMIT_IWCR 0x14 /* Wait Count Register */ #define SPACEMIT_IBMR 0x1c /* Bus monitor register */ /* SPACEMIT_ICR register fields */ @@ -88,12 +92,22 @@ #define SPACEMIT_BMR_SDA BIT(0) /* SDA line level */ #define SPACEMIT_BMR_SCL BIT(1) /* SCL line level */ +#define SPACEMIT_LCR_LV_STANDARD_MASK GENMASK(8, 0) +#define SPACEMIT_LCR_LV_FAST_MASK GENMASK(17, 9) + +/* SPACEMIT_IWCR register fields */ +#define SPACEMIT_WCR_COUNT GENMASK(4, 0) +#define SPACEMIT_WCR_HS_COUNT1 GENMASK(9, 5) +#define SPACEMIT_WCR_HS_COUNT2 GENMASK(14, 10) + +/* Required by I2C IP for correct SCL timing */ +#define SPACEMIT_IWCR_INIT_VALUE (FIELD_PREP(SPACEMIT_WCR_COUNT, 10) | \ + FIELD_PREP(SPACEMIT_WCR_HS_COUNT1, 1) | \ + FIELD_PREP(SPACEMIT_WCR_HS_COUNT2, 5)) + /* i2c bus recover timeout: us */ #define SPACEMIT_I2C_BUS_BUSY_TIMEOUT 100000 -#define SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ 100000 /* Hz */ -#define SPACEMIT_I2C_MAX_FAST_MODE_FREQ 400000 /* Hz */ - #define SPACEMIT_SR_ERR (SPACEMIT_SR_BED | SPACEMIT_SR_RXOV | SPACEMIT_SR_ALD) #define SPACEMIT_BUS_RESET_CLK_CNT_MAX 9 @@ -109,11 +123,20 @@ enum spacemit_i2c_state { SPACEMIT_STATE_WRITE, }; +enum spacemit_i2c_mode { + SPACEMIT_MODE_STANDARD, + SPACEMIT_MODE_FAST +}; + /* i2c-spacemit driver's main struct */ struct spacemit_i2c_dev { struct device *dev; struct i2c_adapter adapt; + struct clk_hw scl_clk_hw; + struct clk *scl_clk; + enum spacemit_i2c_mode mode; + /* hardware resources */ void __iomem *base; int irq; @@ -135,6 +158,85 @@ struct spacemit_i2c_dev { u32 status; }; +static void spacemit_i2c_scl_clk_disable_unprepare(void *data) +{ + clk_disable_unprepare(data); +} + +/* + * Calculate the ILCR divider value (lv) from the target SCL rate. + * + * Hardware timing formulas: + * - standard mode: SCL = FCLK / (2 * SLV + 8) + * - fast mode: SCL = FCLK / (2 * FLV + 10) + */ +static u32 spacemit_i2c_calc_lv(struct spacemit_i2c_dev *i2c, + unsigned long parent_rate, + unsigned long target_rate) +{ + u32 offset, denom; + + offset = (i2c->mode == SPACEMIT_MODE_STANDARD) ? 8 : 10; + denom = DIV_ROUND_CLOSEST(parent_rate, target_rate); + + return (denom <= offset) ? 0 : DIV_ROUND_CLOSEST(denom - offset, 2); +} + +static int spacemit_i2c_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct spacemit_i2c_dev *i2c = container_of(hw, struct spacemit_i2c_dev, scl_clk_hw); + u32 lv, lcr, mask; + + lv = spacemit_i2c_calc_lv(i2c, parent_rate, rate); + + mask = (i2c->mode == SPACEMIT_MODE_STANDARD) ? + SPACEMIT_LCR_LV_STANDARD_MASK : SPACEMIT_LCR_LV_FAST_MASK; + + lcr = readl(i2c->base + SPACEMIT_ILCR); + lcr &= ~mask; + lcr |= field_prep(mask, lv); + writel(lcr, i2c->base + SPACEMIT_ILCR); + + return 0; +} + +static int spacemit_i2c_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct spacemit_i2c_dev *i2c = container_of(hw, struct spacemit_i2c_dev, scl_clk_hw); + u32 lv, offset; + + lv = spacemit_i2c_calc_lv(i2c, req->best_parent_rate, req->rate); + offset = (i2c->mode == SPACEMIT_MODE_STANDARD) ? 8 : 10; + req->rate = DIV_ROUND_CLOSEST(req->best_parent_rate, lv * 2 + offset); + + return 0; +} + +static unsigned long spacemit_i2c_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct spacemit_i2c_dev *i2c = container_of(hw, struct spacemit_i2c_dev, scl_clk_hw); + u32 lcr, lv = 0; + + lcr = readl(i2c->base + SPACEMIT_ILCR); + + if (i2c->mode == SPACEMIT_MODE_STANDARD) { + lv = FIELD_GET(SPACEMIT_LCR_LV_STANDARD_MASK, lcr); + return DIV_ROUND_CLOSEST(parent_rate, lv * 2 + 8); + } + + lv = FIELD_GET(SPACEMIT_LCR_LV_FAST_MASK, lcr); + return DIV_ROUND_CLOSEST(parent_rate, lv * 2 + 10); +} + +static const struct clk_ops spacemit_i2c_clk_ops = { + .set_rate = spacemit_i2c_clk_set_rate, + .determine_rate = spacemit_i2c_clk_determine_rate, + .recalc_rate = spacemit_i2c_clk_recalc_rate, +}; + static void spacemit_i2c_enable(struct spacemit_i2c_dev *i2c) { u32 val; @@ -153,6 +255,28 @@ static void spacemit_i2c_disable(struct spacemit_i2c_dev *i2c) writel(val, i2c->base + SPACEMIT_ICR); } +static int spacemit_i2c_register_scl_clk(struct spacemit_i2c_dev *i2c) +{ + struct clk_init_data init = {}; + char name[64]; + int ret; + + ret = snprintf(name, sizeof(name), "%s_scl_clk", dev_name(i2c->dev)); + if (ret >= ARRAY_SIZE(name)) + dev_warn(i2c->dev, "scl clock name truncated"); + + init.name = name; + init.ops = &spacemit_i2c_clk_ops; + init.parent_data = (struct clk_parent_data[]) { + { .fw_name = "func" }, + }; + init.num_parents = 1; + + i2c->scl_clk_hw.init = &init; + + return devm_clk_hw_register(i2c->dev, &i2c->scl_clk_hw); +} + static void spacemit_i2c_reset(struct spacemit_i2c_dev *i2c) { writel(SPACEMIT_CR_UR, i2c->base + SPACEMIT_ICR); @@ -286,7 +410,7 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c) val |= SPACEMIT_CR_MSDIE; } - if (i2c->clock_freq == SPACEMIT_I2C_MAX_FAST_MODE_FREQ) + if (i2c->mode == SPACEMIT_MODE_FAST) val |= SPACEMIT_CR_MODE_FAST; /* disable response to general call */ @@ -309,6 +433,14 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c) writel(val, i2c->base + SPACEMIT_IRCR); spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK); + + /* + * Initialize IWCR to the value specified by the I2C IP designer. + * The SCL frequency formulas (SCL = FCLK / (2*SLV+8) for standard + * mode, SCL = FCLK / (2*FLV+10) for fast mode) are only valid when + * IWCR contains this specific value. + */ + writel(SPACEMIT_IWCR_INIT_VALUE, i2c->base + SPACEMIT_IWCR); } static void spacemit_i2c_start(struct spacemit_i2c_dev *i2c) @@ -698,19 +830,18 @@ static int spacemit_i2c_probe(struct platform_device *pdev) if (!i2c) return -ENOMEM; - ret = of_property_read_u32(of_node, "clock-frequency", &i2c->clock_freq); - if (ret && ret != -EINVAL) - dev_warn(dev, "failed to read clock-frequency property: %d\n", ret); + of_property_read_u32(of_node, "clock-frequency", &i2c->clock_freq); /* For now, this driver doesn't support high-speed. */ - if (!i2c->clock_freq || i2c->clock_freq > SPACEMIT_I2C_MAX_FAST_MODE_FREQ) { - dev_warn(dev, "unsupported clock frequency %u; using %u\n", - i2c->clock_freq, SPACEMIT_I2C_MAX_FAST_MODE_FREQ); - i2c->clock_freq = SPACEMIT_I2C_MAX_FAST_MODE_FREQ; - } else if (i2c->clock_freq < SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ) { - dev_warn(dev, "unsupported clock frequency %u; using %u\n", - i2c->clock_freq, SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ); - i2c->clock_freq = SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ; + if (i2c->clock_freq > I2C_MAX_STANDARD_MODE_FREQ && + i2c->clock_freq <= I2C_MAX_FAST_MODE_FREQ) { + i2c->mode = SPACEMIT_MODE_FAST; + } else if (i2c->clock_freq && i2c->clock_freq <= I2C_MAX_STANDARD_MODE_FREQ) { + i2c->mode = SPACEMIT_MODE_STANDARD; + } else { + dev_info(dev, "clock-frequency not set or out of range, using fast mode\n"); + i2c->mode = SPACEMIT_MODE_FAST; + i2c->clock_freq = I2C_MAX_FAST_MODE_FREQ; } i2c->dev = &pdev->dev; @@ -721,12 +852,21 @@ static int spacemit_i2c_probe(struct platform_device *pdev) i2c->irq = platform_get_irq(pdev, 0); if (i2c->irq < 0) - return dev_err_probe(dev, i2c->irq, "failed to get irq resource"); + return i2c->irq; clk = devm_clk_get_enabled(dev, "func"); if (IS_ERR(clk)) return dev_err_probe(dev, PTR_ERR(clk), "failed to enable func clock"); + ret = spacemit_i2c_register_scl_clk(i2c); + if (ret) + return dev_err_probe(dev, ret, "failed to register scl clock\n"); + + i2c->scl_clk = devm_clk_hw_get_clk(dev, &i2c->scl_clk_hw, "scl"); + if (IS_ERR(i2c->scl_clk)) + return dev_err_probe(dev, PTR_ERR(i2c->scl_clk), + "failed to get scl clock\n"); + clk = devm_clk_get_enabled(dev, "bus"); if (IS_ERR(clk)) return dev_err_probe(dev, PTR_ERR(clk), "failed to enable bus clock"); @@ -736,6 +876,19 @@ static int spacemit_i2c_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(rst), "failed to acquire deasserted reset\n"); + ret = clk_set_rate(i2c->scl_clk, i2c->clock_freq); + if (ret) + return dev_err_probe(dev, ret, "failed to set rate for SCL clock"); + + ret = clk_prepare_enable(i2c->scl_clk); + if (ret) + return dev_err_probe(dev, ret, "failed to prepare and enable clock"); + + ret = devm_add_action_or_reset(dev, spacemit_i2c_scl_clk_disable_unprepare, + i2c->scl_clk); + if (ret) + return ret; + spacemit_i2c_reset(i2c); i2c_set_adapdata(&i2c->adapt, i2c); @@ -753,7 +906,7 @@ static int spacemit_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(i2c->dev, i2c->irq, spacemit_i2c_irq_handler, IRQF_NO_SUSPEND, dev_name(i2c->dev), i2c); if (ret) - return dev_err_probe(dev, ret, "failed to request irq"); + return ret; platform_set_drvdata(pdev, i2c); diff --git a/drivers/i2c/busses/i2c-ls2x.c b/drivers/i2c/busses/i2c-ls2x.c index b475dd27b7af..af7bf61b0f4d 100644 --- a/drivers/i2c/busses/i2c-ls2x.c +++ b/drivers/i2c/busses/i2c-ls2x.c @@ -323,7 +323,7 @@ static int ls2x_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, ls2x_i2c_isr, IRQF_SHARED, "ls2x-i2c", priv); if (ret < 0) - return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq); + return ret; return devm_i2c_add_adapter(dev, adap); } diff --git a/drivers/i2c/busses/i2c-microchip-corei2c.c b/drivers/i2c/busses/i2c-microchip-corei2c.c index c8599733633e..5a429f17359f 100644 --- a/drivers/i2c/busses/i2c-microchip-corei2c.c +++ b/drivers/i2c/busses/i2c-microchip-corei2c.c @@ -565,10 +565,10 @@ static int mchp_corei2c_probe(struct platform_device *pdev) &idev->bus_clk_rate); if (ret || !idev->bus_clk_rate) { dev_info(&pdev->dev, "default to 100kHz\n"); - idev->bus_clk_rate = 100000; + idev->bus_clk_rate = I2C_MAX_STANDARD_MODE_FREQ; } - if (idev->bus_clk_rate > 400000) + if (idev->bus_clk_rate > I2C_MAX_FAST_MODE_FREQ) return dev_err_probe(&pdev->dev, -EINVAL, "clock-frequency too high: %d\n", idev->bus_clk_rate); @@ -581,8 +581,7 @@ static int mchp_corei2c_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, irq, mchp_corei2c_isr, IRQF_SHARED, pdev->name, idev); if (ret) - return dev_err_probe(&pdev->dev, ret, - "failed to claim irq %d\n", irq); + return ret; ret = clk_prepare_enable(idev->i2c_clk); if (ret) diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c index e33512b25353..24ccc4546ab8 100644 --- a/drivers/i2c/busses/i2c-mlxbf.c +++ b/drivers/i2c/busses/i2c-mlxbf.c @@ -2350,7 +2350,7 @@ static int mlxbf_i2c_probe(struct platform_device *pdev) IRQF_SHARED | IRQF_PROBE_SHARED, dev_name(dev), priv); if (ret < 0) - return dev_err_probe(dev, ret, "Cannot get irq %d\n", irq); + return ret; priv->irq = irq; diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index b63ee51c1652..c3878670da9c 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -1050,9 +1050,9 @@ static int nmk_i2c_eyeq5_probe(struct nmk_i2c_dev *priv) if (id >= ARRAY_SIZE(nmk_i2c_eyeq5_masks)) return -ENOENT; - if (priv->clk_freq <= 400000) + if (priv->clk_freq <= I2C_MAX_FAST_MODE_FREQ) speed_mode = I2C_EYEQ5_SPEED_FAST; - else if (priv->clk_freq <= 1000000) + else if (priv->clk_freq <= I2C_MAX_FAST_MODE_PLUS_FREQ) speed_mode = I2C_EYEQ5_SPEED_FAST_PLUS; else speed_mode = I2C_EYEQ5_SPEED_HIGH_SPEED; @@ -1137,8 +1137,7 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) ret = devm_request_irq(dev, priv->irq, i2c_irq_handler, 0, DRIVER_NAME, priv); if (ret) - return dev_err_probe(dev, ret, - "cannot claim the irq %d\n", priv->irq); + return ret; priv->clk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(priv->clk)) diff --git a/drivers/i2c/busses/i2c-octeon-core.h b/drivers/i2c/busses/i2c-octeon-core.h index 32a44f2d6274..aba81477d7d4 100644 --- a/drivers/i2c/busses/i2c-octeon-core.h +++ b/drivers/i2c/busses/i2c-octeon-core.h @@ -235,7 +235,7 @@ static inline void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data) octeon_i2c_writeq_flush(data, i2c->twsi_base + OCTEON_REG_TWSI_INT(i2c)); } -#define IS_LS_FREQ(twsi_freq) ((twsi_freq) <= 400000) +#define IS_LS_FREQ(twsi_freq) ((twsi_freq) <= I2C_MAX_FAST_MODE_FREQ) #define PCI_SUBSYS_DEVID_9XXX 0xB #define PCI_SUBSYS_MASK GENMASK(15, 12) /** diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 8daa0008bd05..e1cc2b2bd628 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -24,7 +24,6 @@ #include #define I2C_PNX_TIMEOUT_DEFAULT 10 /* msec */ -#define I2C_PNX_SPEED_KHZ_DEFAULT 100 #define I2C_PNX_REGION_SIZE 0x100 struct i2c_pnx_mif { @@ -606,12 +605,12 @@ static DEFINE_SIMPLE_DEV_PM_OPS(i2c_pnx_pm, static int i2c_pnx_probe(struct platform_device *pdev) { + u32 speed = I2C_MAX_STANDARD_MODE_FREQ; unsigned long tmp; int ret = 0; struct i2c_pnx_algo_data *alg_data; unsigned long freq; struct resource *res; - u32 speed = I2C_PNX_SPEED_KHZ_DEFAULT * 1000; alg_data = devm_kzalloc(&pdev->dev, sizeof(*alg_data), GFP_KERNEL); if (!alg_data) diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index d2f5055b0b10..658636c1ee0e 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +#define CREATE_TRACE_POINTS +#include + #include #include #include @@ -56,7 +59,8 @@ enum geni_i2c_err_code { GP_IRQ0, - NACK, + ADDR_NACK, + DATA_NACK, GP_IRQ2, BUS_PROTO, ARB_LOST, @@ -67,16 +71,26 @@ enum geni_i2c_err_code { GENI_TIMEOUT, }; -#define DM_I2C_CB_ERR ((BIT(NACK) | BIT(BUS_PROTO) | BIT(ARB_LOST)) \ +#define DM_I2C_CB_ERR ((BIT(ADDR_NACK) | BIT(BUS_PROTO) | BIT(ARB_LOST)) \ << 5) #define I2C_AUTO_SUSPEND_DELAY 250 #define PACKING_BYTES_PW 4 #define ABORT_TIMEOUT HZ +#define CANCEL_TIMEOUT HZ #define XFER_TIMEOUT HZ #define RST_TIMEOUT HZ +struct geni_i2c_desc { + bool no_dma_support; + unsigned int tx_fifo_depth; + int (*resources_init)(struct geni_se *se); + int (*set_rate)(struct geni_se *se, unsigned long freq); + int (*power_on)(struct geni_se *se); + int (*power_off)(struct geni_se *se); +}; + #define QCOM_I2C_MIN_NUM_OF_MSGS_MULTI_DESC 2 /** @@ -103,11 +117,14 @@ struct geni_i2c_dev { int err; struct i2c_adapter adap; struct completion done; + struct completion abort_done; + struct completion cancel_done; + struct completion tx_reset_done; + struct completion rx_reset_done; struct i2c_msg *cur; int cur_wr; int cur_rd; spinlock_t lock; - struct clk *core_clk; u32 clk_freq_out; const struct geni_i2c_clk_fld *clk_fld; void *dma_buf; @@ -117,17 +134,10 @@ struct geni_i2c_dev { struct dma_chan *rx_c; bool no_dma; bool gpi_mode; - bool abort_done; bool is_tx_multi_desc_xfer; u32 num_msgs; struct geni_i2c_gpi_multi_desc_xfer i2c_multi_desc_config; -}; - -struct geni_i2c_desc { - bool has_core_clk; - char *icc_ddr; - bool no_dma_support; - unsigned int tx_fifo_depth; + const struct geni_i2c_desc *dev_data; }; struct geni_i2c_err_log { @@ -137,7 +147,8 @@ struct geni_i2c_err_log { static const struct geni_i2c_err_log gi2c_log[] = { [GP_IRQ0] = {-EIO, "Unknown I2C err GP_IRQ0"}, - [NACK] = {-ENXIO, "NACK: slv unresponsive, check its power/reset-ln"}, + [ADDR_NACK] = {-ENXIO, "NACK: target device unresponsive, check its power/reset-ln"}, + [DATA_NACK] = {-EIO, "Data NACK: TX transfer NACK"}, [GP_IRQ2] = {-EIO, "Unknown I2C err GP IRQ2"}, [BUS_PROTO] = {-EPROTO, "Bus proto err, noisy/unexpected start/stop"}, [ARB_LOST] = {-EAGAIN, "Bus arbitration lost, clock line undriveable"}, @@ -202,8 +213,9 @@ static int geni_i2c_clk_map_idx(struct geni_i2c_dev *gi2c) return -EINVAL; } -static void qcom_geni_i2c_conf(struct geni_i2c_dev *gi2c) +static int qcom_geni_i2c_conf(struct geni_se *se, unsigned long freq) { + struct geni_i2c_dev *gi2c = dev_get_drvdata(se->dev); const struct geni_i2c_clk_fld *itr = gi2c->clk_fld; u32 val; @@ -216,6 +228,10 @@ static void qcom_geni_i2c_conf(struct geni_i2c_dev *gi2c) val |= itr->t_low_cnt << LOW_COUNTER_SHFT; val |= itr->t_cycle_cnt; writel_relaxed(val, gi2c->se.base + SE_I2C_SCL_COUNTERS); + trace_geni_i2c_bus_setup(gi2c->se.dev, gi2c->clk_freq_out, + itr->clk_div, itr->t_high_cnt, + itr->t_low_cnt, itr->t_cycle_cnt); + return 0; } static void geni_i2c_err_misc(struct geni_i2c_dev *gi2c) @@ -248,11 +264,12 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err) dev_dbg(gi2c->se.dev, "len:%d, slv-addr:0x%x, RD/WR:%d\n", gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags); + trace_geni_i2c_err(gi2c->se.dev, gi2c_log[err].err, gi2c_log[err].msg); + switch (err) { case GENI_ABORT_DONE: - gi2c->abort_done = true; - break; - case NACK: + case ADDR_NACK: + case DATA_NACK: case GENI_TIMEOUT: dev_dbg(gi2c->se.dev, "%s\n", gi2c_log[err].msg); break; @@ -263,6 +280,14 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err) } } +static void geni_i2c_check_addr_data_nack(struct geni_i2c_dev *gi2c) +{ + if (!readl_relaxed(gi2c->se.base + SE_GENI_M_GP_LENGTH)) + geni_i2c_err(gi2c, ADDR_NACK); + else if (!(gi2c->cur->flags & I2C_M_RD)) + geni_i2c_err(gi2c, DATA_NACK); +} + static irqreturn_t geni_i2c_irq(int irq, void *dev) { struct geni_i2c_dev *gi2c = dev; @@ -284,11 +309,13 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev) dma = readl_relaxed(base + SE_GENI_DMA_MODE_EN); cur = gi2c->cur; + trace_geni_i2c_irq(gi2c->se.dev, m_stat, rx_st, dm_tx_st, dm_rx_st); + if (!cur || m_stat & (M_CMD_FAILURE_EN | M_CMD_ABORT_EN) || dm_rx_st & (DM_I2C_CB_ERR)) { if (m_stat & M_GP_IRQ_1_EN) - geni_i2c_err(gi2c, NACK); + geni_i2c_check_addr_data_nack(gi2c); if (m_stat & M_GP_IRQ_3_EN) geni_i2c_err(gi2c, BUS_PROTO); if (m_stat & M_GP_IRQ_4_EN) @@ -353,10 +380,18 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev) writel_relaxed(dm_rx_st, base + SE_DMA_RX_IRQ_CLR); /* if this is err with done-bit not set, handle that through timeout. */ - if (m_stat & M_CMD_DONE_EN || m_stat & M_CMD_ABORT_EN || - dm_tx_st & TX_DMA_DONE || dm_tx_st & TX_RESET_DONE || - dm_rx_st & RX_DMA_DONE || dm_rx_st & RX_RESET_DONE) + if (m_stat & M_CMD_DONE_EN || + dm_tx_st & TX_DMA_DONE || + dm_rx_st & RX_DMA_DONE) complete(&gi2c->done); + if (m_stat & M_CMD_CANCEL_EN) + complete(&gi2c->cancel_done); + if (m_stat & M_CMD_ABORT_EN) + complete(&gi2c->abort_done); + if (dm_tx_st & TX_RESET_DONE) + complete(&gi2c->tx_reset_done); + if (dm_rx_st & RX_RESET_DONE) + complete(&gi2c->rx_reset_done); spin_unlock(&gi2c->lock); @@ -368,48 +403,59 @@ static void geni_i2c_abort_xfer(struct geni_i2c_dev *gi2c) unsigned long time_left = ABORT_TIMEOUT; unsigned long flags; + reinit_completion(&gi2c->abort_done); + spin_lock_irqsave(&gi2c->lock, flags); - geni_i2c_err(gi2c, GENI_TIMEOUT); - gi2c->cur = NULL; - gi2c->abort_done = false; geni_se_abort_m_cmd(&gi2c->se); spin_unlock_irqrestore(&gi2c->lock, flags); - do { - time_left = wait_for_completion_timeout(&gi2c->done, time_left); - } while (!gi2c->abort_done && time_left); - + time_left = wait_for_completion_timeout(&gi2c->abort_done, time_left); if (!time_left) dev_err(gi2c->se.dev, "Timeout abort_m_cmd\n"); } +static void geni_i2c_cancel_xfer(struct geni_i2c_dev *gi2c) +{ + unsigned long time_left = msecs_to_jiffies(CANCEL_TIMEOUT); + unsigned long flags; + + reinit_completion(&gi2c->cancel_done); + + spin_lock_irqsave(&gi2c->lock, flags); + if (!gi2c->err) + geni_i2c_err(gi2c, GENI_TIMEOUT); + gi2c->cur = NULL; + geni_se_cancel_m_cmd(&gi2c->se); + spin_unlock_irqrestore(&gi2c->lock, flags); + + time_left = wait_for_completion_timeout(&gi2c->cancel_done, time_left); + if (!time_left) { + dev_err(gi2c->se.dev, "Timeout cancel_m_cmd\n"); + geni_i2c_abort_xfer(gi2c); + } +} + static void geni_i2c_rx_fsm_rst(struct geni_i2c_dev *gi2c) { - u32 val; unsigned long time_left = RST_TIMEOUT; + reinit_completion(&gi2c->rx_reset_done); writel_relaxed(1, gi2c->se.base + SE_DMA_RX_FSM_RST); - do { - time_left = wait_for_completion_timeout(&gi2c->done, time_left); - val = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT); - } while (!(val & RX_RESET_DONE) && time_left); - if (!(val & RX_RESET_DONE)) + time_left = wait_for_completion_timeout(&gi2c->rx_reset_done, time_left); + if (!time_left) dev_err(gi2c->se.dev, "Timeout resetting RX_FSM\n"); } static void geni_i2c_tx_fsm_rst(struct geni_i2c_dev *gi2c) { - u32 val; unsigned long time_left = RST_TIMEOUT; + reinit_completion(&gi2c->tx_reset_done); writel_relaxed(1, gi2c->se.base + SE_DMA_TX_FSM_RST); - do { - time_left = wait_for_completion_timeout(&gi2c->done, time_left); - val = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT); - } while (!(val & TX_RESET_DONE) && time_left); - if (!(val & TX_RESET_DONE)) + time_left = wait_for_completion_timeout(&gi2c->tx_reset_done, time_left); + if (!time_left) dev_err(gi2c->se.dev, "Timeout resetting TX_FSM\n"); } @@ -418,7 +464,7 @@ static void geni_i2c_rx_msg_cleanup(struct geni_i2c_dev *gi2c, { gi2c->cur_rd = 0; if (gi2c->dma_buf) { - if (gi2c->err) + if (gi2c->err && gi2c->err != gi2c_log[ADDR_NACK].err) geni_i2c_rx_fsm_rst(gi2c); geni_se_rx_dma_unprep(&gi2c->se, gi2c->dma_addr, gi2c->xfer_len); i2c_put_dma_safe_msg_buf(gi2c->dma_buf, cur, !gi2c->err); @@ -430,7 +476,7 @@ static void geni_i2c_tx_msg_cleanup(struct geni_i2c_dev *gi2c, { gi2c->cur_wr = 0; if (gi2c->dma_buf) { - if (gi2c->err) + if (gi2c->err && gi2c->err != gi2c_log[ADDR_NACK].err) geni_i2c_tx_fsm_rst(gi2c); geni_se_tx_dma_unprep(&gi2c->se, gi2c->dma_addr, gi2c->xfer_len); i2c_put_dma_safe_msg_buf(gi2c->dma_buf, cur, !gi2c->err); @@ -468,8 +514,8 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, cur = gi2c->cur; time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); - if (!time_left) - geni_i2c_abort_xfer(gi2c); + if (!time_left || (gi2c->err && gi2c->err != gi2c_log[ADDR_NACK].err)) + geni_i2c_cancel_xfer(gi2c); geni_i2c_rx_msg_cleanup(gi2c, cur); @@ -510,8 +556,8 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, cur = gi2c->cur; time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); - if (!time_left) - geni_i2c_abort_xfer(gi2c); + if (!time_left || (gi2c->err && gi2c->err != gi2c_log[ADDR_NACK].err)) + geni_i2c_cancel_xfer(gi2c); geni_i2c_tx_msg_cleanup(gi2c, cur); @@ -784,6 +830,10 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i peripheral.set_config = 1; peripheral.multi_msg = false; + trace_geni_i2c_bus_setup(gi2c->se.dev, gi2c->clk_freq_out, + itr->clk_div, itr->t_high_cnt, + itr->t_low_cnt, itr->t_cycle_cnt); + gi2c->num_msgs = num; gi2c->is_tx_multi_desc_xfer = false; @@ -822,6 +872,7 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i for (i = 0; i < num; i++) { gi2c->cur = &msgs[i]; gi2c->err = 0; + reinit_completion(&gi2c->done); dev_dbg(gi2c->se.dev, "msg[%d].len:%d\n", i, gi2c->cur->len); peripheral.stretch = 0; @@ -891,6 +942,8 @@ static int geni_i2c_fifo_xfer(struct geni_i2c_dev *gi2c, m_param |= ((msgs[i].addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK); gi2c->cur = &msgs[i]; + gi2c->err = 0; + reinit_completion(&gi2c->done); if (msgs[i].flags & I2C_M_RD) ret = geni_i2c_rx_one_msg(gi2c, &msgs[i], m_param); else @@ -910,8 +963,6 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, struct geni_i2c_dev *gi2c = i2c_get_adapdata(adap); int ret; - gi2c->err = 0; - reinit_completion(&gi2c->done); ret = pm_runtime_get_sync(gi2c->se.dev); if (ret < 0) { dev_err(gi2c->se.dev, "error turning SE resources:%d\n", ret); @@ -921,7 +972,9 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, return ret; } - qcom_geni_i2c_conf(gi2c); + ret = gi2c->dev_data->set_rate(&gi2c->se, gi2c->clk_freq_out); + if (ret) + return ret; if (gi2c->gpi_mode) ret = geni_i2c_gpi_xfer(gi2c, msgs, num); @@ -944,15 +997,6 @@ static const struct i2c_algorithm geni_i2c_algo = { .functionality = geni_i2c_func, }; -#ifdef CONFIG_ACPI -static const struct acpi_device_id geni_i2c_acpi_match[] = { - { "QCOM0220"}, - { "QCOM0411" }, - { } -}; -MODULE_DEVICE_TABLE(acpi, geni_i2c_acpi_match); -#endif - static void release_gpi_dma(struct geni_i2c_dev *gi2c) { if (gi2c->rx_c) @@ -990,13 +1034,95 @@ err_tx: return ret; } +static int geni_i2c_init(struct geni_i2c_dev *gi2c) +{ + u32 proto, tx_depth; + bool fifo_disable; + int ret; + + ret = pm_runtime_resume_and_get(gi2c->se.dev); + if (ret < 0) { + dev_err(gi2c->se.dev, "error turning on device :%d\n", ret); + return ret; + } + + proto = geni_se_read_proto(&gi2c->se); + if (proto == GENI_SE_INVALID_PROTO) { + ret = geni_load_se_firmware(&gi2c->se, GENI_SE_I2C); + if (ret) { + dev_err_probe(gi2c->se.dev, ret, "i2c firmware load failed ret: %d\n", ret); + goto err; + } + } else if (proto != GENI_SE_I2C) { + ret = dev_err_probe(gi2c->se.dev, -ENXIO, "Invalid proto %d\n", proto); + goto err; + } + + if (gi2c->dev_data->no_dma_support) { + fifo_disable = false; + gi2c->no_dma = true; + } else { + fifo_disable = readl_relaxed(gi2c->se.base + GENI_IF_DISABLE_RO) & FIFO_IF_DISABLE; + } + + if (fifo_disable) { + /* FIFO is disabled, so we can only use GPI DMA */ + gi2c->gpi_mode = true; + ret = setup_gpi_dma(gi2c); + if (ret) + goto err; + + dev_dbg(gi2c->se.dev, "Using GPI DMA mode for I2C\n"); + } else { + gi2c->gpi_mode = false; + tx_depth = geni_se_get_tx_fifo_depth(&gi2c->se); + + /* I2C Master Hub Serial Elements doesn't have the HW_PARAM_0 register */ + if (!tx_depth && gi2c->se.core_clk) + tx_depth = gi2c->dev_data->tx_fifo_depth; + + if (!tx_depth) { + ret = dev_err_probe(gi2c->se.dev, -EINVAL, + "Invalid TX FIFO depth\n"); + goto err; + } + + gi2c->tx_wm = tx_depth - 1; + geni_se_init(&gi2c->se, gi2c->tx_wm, tx_depth); + geni_se_config_packing(&gi2c->se, BITS_PER_BYTE, + PACKING_BYTES_PW, true, true, true); + + dev_dbg(gi2c->se.dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth); + } + +err: + pm_runtime_put(gi2c->se.dev); + return ret; +} + +static int geni_i2c_resources_init(struct geni_se *se) +{ + struct geni_i2c_dev *gi2c = dev_get_drvdata(se->dev); + int ret; + + ret = geni_se_resources_init(&gi2c->se); + if (ret) + return ret; + + ret = geni_i2c_clk_map_idx(gi2c); + if (ret) + return dev_err_probe(gi2c->se.dev, ret, "Invalid clk frequency %d Hz\n", + gi2c->clk_freq_out); + + return geni_icc_set_bw_ab(&gi2c->se, GENI_DEFAULT_BW, GENI_DEFAULT_BW, + Bps_to_icc(gi2c->clk_freq_out)); +} + static int geni_i2c_probe(struct platform_device *pdev) { struct geni_i2c_dev *gi2c; - u32 proto, tx_depth, fifo_disable; int ret; struct device *dev = &pdev->dev; - const struct geni_i2c_desc *desc = NULL; gi2c = devm_kzalloc(dev, sizeof(*gi2c), GFP_KERNEL); if (!gi2c) @@ -1008,17 +1134,9 @@ static int geni_i2c_probe(struct platform_device *pdev) if (IS_ERR(gi2c->se.base)) return PTR_ERR(gi2c->se.base); - desc = device_get_match_data(&pdev->dev); - - if (desc && desc->has_core_clk) { - gi2c->core_clk = devm_clk_get(dev, "core"); - if (IS_ERR(gi2c->core_clk)) - return PTR_ERR(gi2c->core_clk); - } - - gi2c->se.clk = devm_clk_get(dev, "se"); - if (IS_ERR(gi2c->se.clk) && !has_acpi_companion(dev)) - return PTR_ERR(gi2c->se.clk); + gi2c->dev_data = device_get_match_data(&pdev->dev); + if (!gi2c->dev_data) + return -EINVAL; ret = device_property_read_u32(dev, "clock-frequency", &gi2c->clk_freq_out); @@ -1034,141 +1152,49 @@ static int geni_i2c_probe(struct platform_device *pdev) if (gi2c->irq < 0) return gi2c->irq; - ret = geni_i2c_clk_map_idx(gi2c); - if (ret) - return dev_err_probe(dev, ret, "Invalid clk frequency %d Hz\n", - gi2c->clk_freq_out); - gi2c->adap.algo = &geni_i2c_algo; init_completion(&gi2c->done); + init_completion(&gi2c->abort_done); + init_completion(&gi2c->cancel_done); + init_completion(&gi2c->tx_reset_done); + init_completion(&gi2c->rx_reset_done); spin_lock_init(&gi2c->lock); platform_set_drvdata(pdev, gi2c); + ret = gi2c->dev_data->resources_init(&gi2c->se); + if (ret) + return ret; + /* Keep interrupts disabled initially to allow for low-power modes */ ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, IRQF_NO_AUTOEN, dev_name(dev), gi2c); if (ret) - return dev_err_probe(dev, ret, - "Request_irq failed: %d\n", gi2c->irq); + return ret; i2c_set_adapdata(&gi2c->adap, gi2c); gi2c->adap.dev.parent = dev; gi2c->adap.dev.of_node = dev->of_node; strscpy(gi2c->adap.name, "Geni-I2C", sizeof(gi2c->adap.name)); - ret = geni_icc_get(&gi2c->se, desc ? desc->icc_ddr : "qup-memory"); - if (ret) - return ret; - /* - * Set the bus quota for core and cpu to a reasonable value for - * register access. - * Set quota for DDR based on bus speed. - */ - gi2c->se.icc_paths[GENI_TO_CORE].avg_bw = GENI_DEFAULT_BW; - gi2c->se.icc_paths[CPU_TO_GENI].avg_bw = GENI_DEFAULT_BW; - if (!desc || desc->icc_ddr) - gi2c->se.icc_paths[GENI_TO_DDR].avg_bw = Bps_to_icc(gi2c->clk_freq_out); + pm_runtime_set_suspended(dev); + pm_runtime_set_autosuspend_delay(dev, I2C_AUTO_SUSPEND_DELAY); + pm_runtime_use_autosuspend(dev); - ret = geni_icc_set_bw(&gi2c->se); + ret = devm_pm_runtime_enable(dev); if (ret) return ret; - ret = clk_prepare_enable(gi2c->core_clk); - if (ret) + ret = geni_i2c_init(gi2c); + if (ret < 0) return ret; - ret = geni_se_resources_on(&gi2c->se); - if (ret) { - dev_err_probe(dev, ret, "Error turning on resources\n"); - goto err_clk; - } - proto = geni_se_read_proto(&gi2c->se); - if (proto == GENI_SE_INVALID_PROTO) { - ret = geni_load_se_firmware(&gi2c->se, GENI_SE_I2C); - if (ret) { - dev_err_probe(dev, ret, "i2c firmware load failed ret: %d\n", ret); - goto err_resources; - } - } else if (proto != GENI_SE_I2C) { - ret = dev_err_probe(dev, -ENXIO, "Invalid proto %d\n", proto); - goto err_resources; - } - - if (desc && desc->no_dma_support) { - fifo_disable = false; - gi2c->no_dma = true; - } else { - fifo_disable = readl_relaxed(gi2c->se.base + GENI_IF_DISABLE_RO) & FIFO_IF_DISABLE; - } - - if (fifo_disable) { - /* FIFO is disabled, so we can only use GPI DMA */ - gi2c->gpi_mode = true; - ret = setup_gpi_dma(gi2c); - if (ret) - goto err_resources; - - dev_dbg(dev, "Using GPI DMA mode for I2C\n"); - } else { - gi2c->gpi_mode = false; - tx_depth = geni_se_get_tx_fifo_depth(&gi2c->se); - - /* I2C Master Hub Serial Elements doesn't have the HW_PARAM_0 register */ - if (!tx_depth && desc) - tx_depth = desc->tx_fifo_depth; - - if (!tx_depth) { - ret = dev_err_probe(dev, -EINVAL, - "Invalid TX FIFO depth\n"); - goto err_resources; - } - - gi2c->tx_wm = tx_depth - 1; - geni_se_init(&gi2c->se, gi2c->tx_wm, tx_depth); - geni_se_config_packing(&gi2c->se, BITS_PER_BYTE, - PACKING_BYTES_PW, true, true, true); - - dev_dbg(dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth); - } - - clk_disable_unprepare(gi2c->core_clk); - ret = geni_se_resources_off(&gi2c->se); - if (ret) { - dev_err_probe(dev, ret, "Error turning off resources\n"); - goto err_dma; - } - - ret = geni_icc_disable(&gi2c->se); - if (ret) - goto err_dma; - - pm_runtime_set_suspended(gi2c->se.dev); - pm_runtime_set_autosuspend_delay(gi2c->se.dev, I2C_AUTO_SUSPEND_DELAY); - pm_runtime_use_autosuspend(gi2c->se.dev); - pm_runtime_enable(gi2c->se.dev); - ret = i2c_add_adapter(&gi2c->adap); - if (ret) { - dev_err_probe(dev, ret, "Error adding i2c adapter\n"); - pm_runtime_disable(gi2c->se.dev); - goto err_dma; - } + if (ret) + return dev_err_probe(dev, ret, "Error adding i2c adapter\n"); dev_dbg(dev, "Geni-I2C adaptor successfully added\n"); - return ret; - -err_resources: - geni_se_resources_off(&gi2c->se); -err_clk: - clk_disable_unprepare(gi2c->core_clk); - - return ret; - -err_dma: - release_gpi_dma(gi2c); - - return ret; + return 0; } static void geni_i2c_remove(struct platform_device *pdev) @@ -1177,7 +1203,6 @@ static void geni_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&gi2c->adap); release_gpi_dma(gi2c); - pm_runtime_disable(gi2c->se.dev); } static void geni_i2c_shutdown(struct platform_device *pdev) @@ -1190,48 +1215,36 @@ static void geni_i2c_shutdown(struct platform_device *pdev) static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev) { - int ret; + int ret = 0; struct geni_i2c_dev *gi2c = dev_get_drvdata(dev); disable_irq(gi2c->irq); - ret = geni_se_resources_off(&gi2c->se); - if (ret) { - enable_irq(gi2c->irq); - return ret; + + if (gi2c->dev_data->power_off) { + ret = gi2c->dev_data->power_off(&gi2c->se); + if (ret) { + enable_irq(gi2c->irq); + return ret; + } } - clk_disable_unprepare(gi2c->core_clk); - - return geni_icc_disable(&gi2c->se); + return 0; } static int __maybe_unused geni_i2c_runtime_resume(struct device *dev) { - int ret; + int ret = 0; struct geni_i2c_dev *gi2c = dev_get_drvdata(dev); - ret = geni_icc_enable(&gi2c->se); - if (ret) - return ret; - - ret = clk_prepare_enable(gi2c->core_clk); - if (ret) - goto out_icc_disable; - - ret = geni_se_resources_on(&gi2c->se); - if (ret) - goto out_clk_disable; + if (gi2c->dev_data->power_on) { + ret = gi2c->dev_data->power_on(&gi2c->se); + if (ret) + return ret; + } enable_irq(gi2c->irq); return 0; - -out_clk_disable: - clk_disable_unprepare(gi2c->core_clk); -out_icc_disable: - geni_icc_disable(&gi2c->se); - - return ret; } static int __maybe_unused geni_i2c_suspend_noirq(struct device *dev) @@ -1267,16 +1280,40 @@ static const struct dev_pm_ops geni_i2c_pm_ops = { NULL) }; -static const struct geni_i2c_desc i2c_master_hub = { - .has_core_clk = true, - .icc_ddr = NULL, - .no_dma_support = true, - .tx_fifo_depth = 16, +static const struct geni_i2c_desc geni_i2c = { + .resources_init = geni_i2c_resources_init, + .set_rate = qcom_geni_i2c_conf, + .power_on = geni_se_resources_activate, + .power_off = geni_se_resources_deactivate, }; +static const struct geni_i2c_desc i2c_master_hub = { + .no_dma_support = true, + .tx_fifo_depth = 16, + .resources_init = geni_i2c_resources_init, + .set_rate = qcom_geni_i2c_conf, + .power_on = geni_se_resources_activate, + .power_off = geni_se_resources_deactivate, +}; + +static const struct geni_i2c_desc sa8255p_geni_i2c = { + .resources_init = geni_se_domain_attach, + .set_rate = geni_se_set_perf_opp, +}; + +#ifdef CONFIG_ACPI +static const struct acpi_device_id geni_i2c_acpi_match[] = { + { "QCOM0220", (kernel_ulong_t)&geni_i2c}, + { "QCOM0411", (kernel_ulong_t)&geni_i2c}, + { } +}; +MODULE_DEVICE_TABLE(acpi, geni_i2c_acpi_match); +#endif + static const struct of_device_id geni_i2c_dt_match[] = { - { .compatible = "qcom,geni-i2c" }, + { .compatible = "qcom,geni-i2c", .data = &geni_i2c }, { .compatible = "qcom,geni-i2c-master-hub", .data = &i2c_master_hub }, + { .compatible = "qcom,sa8255p-geni-i2c", .data = &sa8255p_geni_i2c }, {} }; MODULE_DEVICE_TABLE(of, geni_i2c_dt_match); diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index a0e076fc5f36..ee7915ee2ba2 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -1657,10 +1657,21 @@ static const struct i2c_adapter_quirks qup_i2c_quirks_v2 = { .flags = I2C_AQ_NO_ZERO_LEN, }; -static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup) +static int qup_i2c_enable_clocks(struct qup_i2c_dev *qup) { - clk_prepare_enable(qup->clk); - clk_prepare_enable(qup->pclk); + int ret; + + ret = clk_prepare_enable(qup->clk); + if (ret) + return ret; + + ret = clk_prepare_enable(qup->pclk); + if (ret) { + clk_disable_unprepare(qup->clk); + return ret; + } + + return 0; } static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup) @@ -1823,7 +1834,9 @@ nodma: ret = PTR_ERR(qup->pclk); goto fail_dma; } - qup_i2c_enable_clocks(qup); + ret = qup_i2c_enable_clocks(qup); + if (ret) + goto fail_dma; src_clk_freq = clk_get_rate(qup->clk); } qup->src_clk_freq = src_clk_freq; @@ -1975,8 +1988,7 @@ static int qup_i2c_pm_resume_runtime(struct device *device) struct qup_i2c_dev *qup = dev_get_drvdata(device); dev_dbg(device, "pm_runtime: resuming...\n"); - qup_i2c_enable_clocks(qup); - return 0; + return qup_i2c_enable_clocks(qup); } static int qup_i2c_suspend(struct device *device) @@ -1988,7 +2000,12 @@ static int qup_i2c_suspend(struct device *device) static int qup_i2c_resume(struct device *device) { - qup_i2c_pm_resume_runtime(device); + int ret; + + ret = qup_i2c_pm_resume_runtime(device); + if (ret) + return ret; + pm_request_autosuspend(device); return 0; } diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 5ce8f8e4856f..46508176712c 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -137,6 +137,7 @@ enum rcar_i2c_type { I2C_RCAR_GEN2, I2C_RCAR_GEN3, I2C_RCAR_GEN4, + I2C_RCAR_GEN5, }; struct rcar_i2c_priv { @@ -900,8 +901,12 @@ static int rcar_i2c_do_reset(struct rcar_i2c_priv *priv) if (ret) return ret; - return read_poll_timeout_atomic(reset_control_status, ret, ret == 0, 1, - 100, false, priv->rstc); + /* SCMI based resets don't need to poll for success */ + if (priv->devtype < I2C_RCAR_GEN5) + return read_poll_timeout_atomic(reset_control_status, ret, ret == 0, + 1, 100, false, priv->rstc); + + return 0; } static int rcar_i2c_master_xfer(struct i2c_adapter *adap, @@ -1111,6 +1116,7 @@ static const struct of_device_id rcar_i2c_dt_ids[] = { { .compatible = "renesas,rcar-gen2-i2c", .data = (void *)I2C_RCAR_GEN2 }, { .compatible = "renesas,rcar-gen3-i2c", .data = (void *)I2C_RCAR_GEN3 }, { .compatible = "renesas,rcar-gen4-i2c", .data = (void *)I2C_RCAR_GEN4 }, + { .compatible = "renesas,rcar-gen5-i2c", .data = (void *)I2C_RCAR_GEN5 }, {}, }; MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids); @@ -1194,9 +1200,15 @@ static int rcar_i2c_probe(struct platform_device *pdev) goto out_pm_put; } - ret = reset_control_status(priv->rstc); - if (ret < 0) - goto out_pm_put; + /* + * Gen5+ uses SCMI based reset which cannot report status. + * Firmware has to ensure proper reset + */ + if (priv->devtype < I2C_RCAR_GEN5) { + ret = reset_control_status(priv->rstc); + if (ret < 0) + goto out_pm_put; + } /* hard reset disturbs HostNotify local target, so disable it */ priv->flags &= ~ID_P_HOST_NOTIFY; diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index 6d2ebf67dd62..2fa48219b66b 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -554,8 +554,7 @@ static int riic_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, irq_desc->isr, 0, irq_desc->name, riic); if (ret) - return dev_err_probe(dev, ret, "failed to request irq %s\n", - irq_desc->name); + return ret; } diff --git a/drivers/i2c/busses/i2c-rzv2m.c b/drivers/i2c/busses/i2c-rzv2m.c index 4ba8eaa322e5..206a99e722a3 100644 --- a/drivers/i2c/busses/i2c-rzv2m.c +++ b/drivers/i2c/busses/i2c-rzv2m.c @@ -442,7 +442,7 @@ static int rzv2m_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, rzv2m_i2c_tia_irq_handler, 0, dev_name(dev), priv); if (ret < 0) - return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq); + return ret; adap = &priv->adap; adap->nr = pdev->id; diff --git a/drivers/i2c/busses/i2c-sprd.c b/drivers/i2c/busses/i2c-sprd.c index 7b321a956fca..c42925f9a330 100644 --- a/drivers/i2c/busses/i2c-sprd.c +++ b/drivers/i2c/busses/i2c-sprd.c @@ -546,10 +546,8 @@ static int sprd_i2c_probe(struct platform_device *pdev) sprd_i2c_isr, sprd_i2c_isr_thread, IRQF_NO_SUSPEND | IRQF_ONESHOT, pdev->name, i2c_dev); - if (ret) { - dev_err_probe(&pdev->dev, ret, "failed to request irq %d\n", i2c_dev->irq); + if (ret) goto err_rpm_put; - } ret = i2c_add_numbered_adapter(&i2c_dev->adap); if (ret) { diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c index 3f89c2145741..0a2b43b5577b 100644 --- a/drivers/i2c/busses/i2c-st.c +++ b/drivers/i2c/busses/i2c-st.c @@ -825,8 +825,7 @@ static int st_i2c_probe(struct platform_device *pdev) NULL, st_i2c_isr_thread, IRQF_ONESHOT, pdev->name, i2c_dev); if (ret) - return dev_err_probe(&pdev->dev, ret, - "Failed to request irq %i\n", i2c_dev->irq); + return ret; pinctrl_pm_select_default_state(i2c_dev->dev); /* In case idle state available, select it */ diff --git a/drivers/i2c/busses/i2c-stm32f4.c b/drivers/i2c/busses/i2c-stm32f4.c index 44e8b04962bb..579ab29ef554 100644 --- a/drivers/i2c/busses/i2c-stm32f4.c +++ b/drivers/i2c/busses/i2c-stm32f4.c @@ -801,14 +801,12 @@ static int stm32f4_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, irq_event, stm32f4_i2c_isr_event, 0, pdev->name, i2c_dev); if (ret) - return dev_err_probe(&pdev->dev, ret, - "Failed to request irq event %i\n", irq_event); + return ret; ret = devm_request_irq(&pdev->dev, irq_error, stm32f4_i2c_isr_error, 0, pdev->name, i2c_dev); if (ret) - return dev_err_probe(&pdev->dev, ret, - "Failed to request irq error %i\n", irq_error); + return ret; ret = stm32f4_i2c_hw_config(i2c_dev); if (ret) diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index d6d993b436cb..6bd281a9ef72 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -2204,7 +2204,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) IRQF_ONESHOT, pdev->name, i2c_dev); if (ret) - return dev_err_probe(&pdev->dev, ret, "Failed to request irq event\n"); + return ret; if (!i2c_dev->setup.single_it_line) { irq_error = platform_get_irq(pdev, 1); @@ -2217,7 +2217,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) IRQF_ONESHOT, pdev->name, i2c_dev); if (ret) - return dev_err_probe(&pdev->dev, ret, "Failed to request irq error\n"); + return ret; } ret = stm32f7_i2c_setup_timing(i2c_dev, &i2c_dev->setup); diff --git a/drivers/i2c/busses/i2c-sun6i-p2wi.c b/drivers/i2c/busses/i2c-sun6i-p2wi.c index dffbe776a195..4f70b12a9559 100644 --- a/drivers/i2c/busses/i2c-sun6i-p2wi.c +++ b/drivers/i2c/busses/i2c-sun6i-p2wi.c @@ -261,10 +261,8 @@ static int p2wi_probe(struct platform_device *pdev) i2c_set_adapdata(&p2wi->adapter, p2wi); ret = devm_request_irq(dev, irq, p2wi_interrupt, 0, pdev->name, p2wi); - if (ret) { - dev_err_probe(dev, ret, "can't register interrupt handler irq%d\n", irq); + if (ret) goto err_reset_assert; - } writel(P2WI_CTRL_SOFT_RST, p2wi->regs + P2WI_CTRL); diff --git a/drivers/i2c/busses/i2c-synquacer.c b/drivers/i2c/busses/i2c-synquacer.c index 4891d68bf0ee..0216e398f274 100644 --- a/drivers/i2c/busses/i2c-synquacer.c +++ b/drivers/i2c/busses/i2c-synquacer.c @@ -576,7 +576,7 @@ static int synquacer_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, i2c->irq, synquacer_i2c_isr, 0, dev_name(&pdev->dev), i2c); if (ret < 0) - return dev_err_probe(&pdev->dev, ret, "cannot claim IRQ %d\n", i2c->irq); + return ret; i2c->state = STATE_IDLE; i2c->dev = &pdev->dev; diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c index ca0358e8f928..7190802a493c 100644 --- a/drivers/i2c/busses/i2c-uniphier-f.c +++ b/drivers/i2c/busses/i2c-uniphier-f.c @@ -560,7 +560,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, uniphier_fi2c_interrupt, 0, pdev->name, priv); if (ret) - return dev_err_probe(dev, ret, "failed to request irq %d\n", irq); + return ret; return i2c_add_adapter(&priv->adap); } diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c index 9d49a3d5d612..ad7bbf5e2466 100644 --- a/drivers/i2c/busses/i2c-uniphier.c +++ b/drivers/i2c/busses/i2c-uniphier.c @@ -354,7 +354,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, uniphier_i2c_interrupt, 0, pdev->name, priv); if (ret) - return dev_err_probe(dev, ret, "failed to request irq %d\n", irq); + return ret; return i2c_add_adapter(&priv->adap); } diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c index 2cf3cc0165fb..d3dda7534b0a 100644 --- a/drivers/i2c/busses/i2c-viai2c-wmt.c +++ b/drivers/i2c/busses/i2c-viai2c-wmt.c @@ -114,8 +114,7 @@ static int wmt_i2c_probe(struct platform_device *pdev) err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr, 0, pdev->name, i2c); if (err) - return dev_err_probe(&pdev->dev, err, - "failed to request irq %i\n", i2c->irq); + return err; i2c->clk = of_clk_get(np, 0); if (IS_ERR(i2c->clk)) diff --git a/drivers/i2c/busses/i2c-viai2c-zhaoxin.c b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c index 95dc64902b7c..764a2dbc957a 100644 --- a/drivers/i2c/busses/i2c-viai2c-zhaoxin.c +++ b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c @@ -305,8 +305,7 @@ static int zxi2c_probe(struct platform_device *pdev) error = devm_request_irq(&pdev->dev, i2c->irq, zxi2c_isr, IRQF_SHARED, pdev->name, i2c); if (error) - return dev_err_probe(&pdev->dev, error, - "failed to request irq %i\n", i2c->irq); + return error; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index ddb1c3e8bc9d..ad0e5cd218f0 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -530,7 +530,7 @@ static int xlp9xx_i2c_probe(struct platform_device *pdev) err = devm_request_irq(&pdev->dev, priv->irq, xlp9xx_i2c_isr, 0, pdev->name, priv); if (err) - return dev_err_probe(&pdev->dev, err, "IRQ request failed!\n"); + return err; init_completion(&priv->msg_complete); priv->adapter.dev.parent = &pdev->dev; diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index e5fddacae9a4..10cdceaba475 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -168,9 +168,12 @@ static int i2c_acpi_do_lookup(struct acpi_device *adev, INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, i2c_acpi_fill_info, lookup); + if (ret < 0) + return ret; + acpi_dev_free_resource_list(&resource_list); - if (ret < 0 || !info->addr) + if (!info->addr) return -EINVAL; return 0; @@ -376,6 +379,7 @@ static const struct acpi_device_id i2c_acpi_force_100khz_device_ids[] = { { "DLL0945", 0 }, { "ELAN0678", 0 }, { "ELAN06FA", 0 }, + { "ELAN1300", 0 }, {} }; diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 3ec04787a737..fb25704219c7 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -446,7 +446,8 @@ static int i2c_init_recovery(struct i2c_adapter *adap) bri->set_scl = set_scl_gpio_value; if (bri->sda_gpiod) { bri->get_sda = get_sda_gpio_value; - if (gpiod_get_direction(bri->sda_gpiod) == GPIO_LINE_DIRECTION_OUT) + if (gpiod_get_direction(bri->sda_gpiod) == GPIO_LINE_DIRECTION_OUT || + gpiod_is_single_ended(bri->sda_gpiod)) bri->set_sda = set_sda_gpio_value; } } else if (bri->recover_bus == i2c_generic_scl_recovery) { diff --git a/include/linux/i2c-algo-bit.h b/include/linux/i2c-algo-bit.h index 7fd5575a368f..c4c43aec1e67 100644 --- a/include/linux/i2c-algo-bit.h +++ b/include/linux/i2c-algo-bit.h @@ -34,6 +34,7 @@ struct i2c_algo_bit_data { maximum 50 us for SMBus */ int timeout; /* in jiffies */ bool can_do_atomic; /* callbacks don't sleep, we can be atomic */ + bool skip_bit_test; /* override bit_test module parameter */ }; int i2c_bit_add_bus(struct i2c_adapter *); diff --git a/include/trace/events/qcom_geni_i2c.h b/include/trace/events/qcom_geni_i2c.h new file mode 100644 index 000000000000..c7e7984f3620 --- /dev/null +++ b/include/trace/events/qcom_geni_i2c.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM qcom_geni_i2c + +#if !defined(_TRACE_QCOM_GENI_I2C_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_QCOM_GENI_I2C_H + +#include + +TRACE_EVENT(geni_i2c_bus_setup, + TP_PROTO(struct device *dev, u32 clk_freq, u8 clk_div, + u8 t_high_cnt, u8 t_low_cnt, u8 t_cycle_cnt), + TP_ARGS(dev, clk_freq, clk_div, t_high_cnt, t_low_cnt, t_cycle_cnt), + + TP_STRUCT__entry(__string(name, dev_name(dev)) + __field(u32, clk_freq) + __field(u8, clk_div) + __field(u8, t_high_cnt) + __field(u8, t_low_cnt) + __field(u8, t_cycle_cnt) + ), + + TP_fast_assign(__assign_str(name); + __entry->clk_freq = clk_freq; + __entry->clk_div = clk_div; + __entry->t_high_cnt = t_high_cnt; + __entry->t_low_cnt = t_low_cnt; + __entry->t_cycle_cnt = t_cycle_cnt; + ), + + TP_printk("%s: clk_freq=%u clk_div=%u t_high=%u t_low=%u t_cycle=%u", + __get_str(name), __entry->clk_freq, __entry->clk_div, + __entry->t_high_cnt, __entry->t_low_cnt, + __entry->t_cycle_cnt) +); + +TRACE_EVENT(geni_i2c_irq, + TP_PROTO(struct device *dev, u32 m_stat, u32 rx_st, + u32 dm_tx_st, u32 dm_rx_st), + TP_ARGS(dev, m_stat, rx_st, dm_tx_st, dm_rx_st), + + TP_STRUCT__entry(__string(name, dev_name(dev)) + __field(u32, m_stat) + __field(u32, rx_st) + __field(u32, dm_tx_st) + __field(u32, dm_rx_st) + ), + + TP_fast_assign(__assign_str(name); + __entry->m_stat = m_stat; + __entry->rx_st = rx_st; + __entry->dm_tx_st = dm_tx_st; + __entry->dm_rx_st = dm_rx_st; + ), + + TP_printk("%s: m_stat=0x%08x rx_st=0x%08x dm_tx=0x%08x dm_rx=0x%08x", + __get_str(name), __entry->m_stat, __entry->rx_st, + __entry->dm_tx_st, __entry->dm_rx_st) +); + +TRACE_EVENT(geni_i2c_err, + TP_PROTO(struct device *dev, int err, const char *msg), + TP_ARGS(dev, err, msg), + + TP_STRUCT__entry(__string(name, dev_name(dev)) + __field(int, err) + __string(msg, msg) + ), + + TP_fast_assign(__assign_str(name); + __entry->err = err; + __assign_str(msg); + ), + + TP_printk("%s: err=%d msg=%s", + __get_str(name), __entry->err, __get_str(msg)) +); + +#endif /* _TRACE_QCOM_GENI_I2C_H */ + +/* This part must be outside protection */ +#include