mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
Merge tag 'i2c-7.2-part2' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux
Pull more i2c updates from Andi Shyti:
"Cleanups:
- generic cleanups in qcom, qcom-cci and pxa, plus core cleanups in
algo-bit and atr
Fixes:
- davinci: clean up cpufreq notifier on probe failure
- imx-lpi2c: suspend the adapter while hardware is powered down
- ls2x-v2: return IRQ_HANDLED after servicing error interrupts
- stm32f7: fix timing calculation accuracy
DT bindings:
- microchip: permit resets
- i2c-mux-pinctrl: update maintainer entry
- i2c-mux-reg: convert bindings to DT schema"
* tag 'i2c-7.2-part2' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux:
i2c: pxa: Use named initializers for the platform_device_id array
i2c: imx-lpi2c: mark I2C adapter when hardware is powered down
i2c: stm32f7: truncate clock period instead of rounding it
dt-bindings: i2c: microchip,corei2c: permit resets
i2c: qcom: Unify user-visible "Qualcomm" name
i2c: ls2x-v2: return IRQ_HANDLED after servicing an error
i2c: atr: annotate i2c_atr_adap_desc->aliases with __counted_by_ptr
i2c: algo: bit: use str_plural helper in bit_xfer
dt-bindings: i2c: i2c-mux-pinctrl: change maintainer
dt-bindings: i2c: convert i2c-mux-reg to DT schema
i2c: davinci: Unregister cpufreq notifier on probe failure
i2c: qcom-cci: Remove overcautious disable_irq() calls
i2c: qcom-cci: Move cci_init() under cci_reset() function
i2c: qcom-cci: Do not check return value of cci_init()
This commit is contained in:
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Pinctrl-based I2C Bus Mux
|
||||
|
||||
maintainers:
|
||||
- Wolfram Sang <wsa@kernel.org>
|
||||
- Thierry Reding <thierry.reding@kernel.org>
|
||||
|
||||
description: |
|
||||
This binding describes an I2C bus multiplexer that uses pin multiplexing to route the I2C
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
Register-based I2C Bus Mux
|
||||
|
||||
This binding describes an I2C bus multiplexer that uses a single register
|
||||
to route the I2C signals.
|
||||
|
||||
Required properties:
|
||||
- compatible: i2c-mux-reg
|
||||
- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side
|
||||
port is connected to.
|
||||
* Standard I2C mux properties. See i2c-mux.yaml in this directory.
|
||||
* I2C child bus nodes. See i2c-mux.yaml in this directory.
|
||||
|
||||
Optional properties:
|
||||
- reg: this pair of <offset size> specifies the register to control the mux.
|
||||
The <offset size> depends on its parent node. It can be any memory-mapped
|
||||
address. The size must be either 1, 2, or 4 bytes. If reg is omitted, the
|
||||
resource of this device will be used.
|
||||
- little-endian: The existence indicates the register is in little endian.
|
||||
- big-endian: The existence indicates the register is in big endian.
|
||||
If both little-endian and big-endian are omitted, the endianness of the
|
||||
CPU will be used.
|
||||
- write-only: The existence indicates the register is write-only.
|
||||
- idle-state: value to set the muxer to when idle. When no value is
|
||||
given, it defaults to the last value used.
|
||||
|
||||
Whenever an access is made to a device on a child bus, the value set
|
||||
in the relevant node's reg property will be output to the register.
|
||||
|
||||
If an idle state is defined, using the idle-state (optional) property,
|
||||
whenever an access is not being made to a device on a child bus, the
|
||||
register will be set according to the idle value.
|
||||
|
||||
If an idle state is not defined, the most recently used value will be
|
||||
left programmed into the register.
|
||||
|
||||
Example of a mux on PCIe card, the host is a powerpc SoC (big endian):
|
||||
|
||||
i2c-mux {
|
||||
/* the <offset size> depends on the address translation
|
||||
* of the parent device. If omitted, device resource
|
||||
* will be used instead. The size is to determine
|
||||
* whether iowrite32, iowrite16, or iowrite8 will be used.
|
||||
*/
|
||||
reg = <0x6028 0x4>;
|
||||
little-endian; /* little endian register on PCIe */
|
||||
compatible = "i2c-mux-reg";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
i2c-parent = <&i2c1>;
|
||||
i2c@0 {
|
||||
reg = <0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
si5338: clock-generator@70 {
|
||||
compatible = "silabs,si5338";
|
||||
reg = <0x70>;
|
||||
/* other stuff */
|
||||
};
|
||||
};
|
||||
|
||||
i2c@1 {
|
||||
/* data is written using iowrite32 */
|
||||
reg = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
si5338: clock-generator@70 {
|
||||
compatible = "silabs,si5338";
|
||||
reg = <0x70>;
|
||||
/* other stuff */
|
||||
};
|
||||
};
|
||||
};
|
||||
92
Documentation/devicetree/bindings/i2c/i2c-mux-reg.yaml
Normal file
92
Documentation/devicetree/bindings/i2c/i2c-mux-reg.yaml
Normal file
@@ -0,0 +1,92 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/i2c-mux-reg.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Register-based I2C Bus Mux
|
||||
|
||||
maintainers:
|
||||
- Peter Rosin <peda@axentia.se>
|
||||
|
||||
description: |
|
||||
This binding describes an I2C bus multiplexer that uses a single
|
||||
memory-mapped register to route the I2C signals.
|
||||
|
||||
Whenever an access is made to a device on a child bus, the value
|
||||
set in the relevant node's reg property is output to the register.
|
||||
|
||||
If an idle state is defined via the idle-state property, the
|
||||
register is set to that value whenever no access is being made.
|
||||
Otherwise the most recently used value is left programmed.
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-mux.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: i2c-mux-reg
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
description: |
|
||||
Offset and size of the register that selects the active child
|
||||
bus, relative to the parent node's address space. The size
|
||||
determines the access width and must be 1, 2, or 4 bytes. If
|
||||
omitted, the platform device's own memory resource is used
|
||||
instead.
|
||||
|
||||
i2c-parent:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle of the I2C bus that this multiplexer's master-side port
|
||||
is connected to.
|
||||
|
||||
little-endian:
|
||||
type: boolean
|
||||
description: Register is accessed in little-endian byte order.
|
||||
|
||||
big-endian:
|
||||
type: boolean
|
||||
description: Register is accessed in big-endian byte order.
|
||||
|
||||
write-only:
|
||||
type: boolean
|
||||
description:
|
||||
Register is write-only; the driver must not read back the
|
||||
current selection.
|
||||
|
||||
idle-state:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
Value to write to the register when no child bus is selected.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- i2c-parent
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c-mux@6028 {
|
||||
compatible = "i2c-mux-reg";
|
||||
reg = <0x6028 0x4>;
|
||||
little-endian;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
i2c-parent = <&i2c1>;
|
||||
|
||||
i2c@0 {
|
||||
reg = <0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
|
||||
i2c@1 {
|
||||
reg = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
};
|
||||
...
|
||||
@@ -37,6 +37,9 @@ properties:
|
||||
modes are supported, possible values are 100000 and 400000.
|
||||
enum: [100000, 400000]
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/string_choices.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
|
||||
@@ -562,7 +563,7 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
|
||||
ret = readbytes(i2c_adap, pmsg);
|
||||
if (ret >= 1)
|
||||
bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n",
|
||||
ret, ret == 1 ? "" : "s");
|
||||
ret, str_plural(ret));
|
||||
if (ret < pmsg->len) {
|
||||
if (ret >= 0)
|
||||
ret = -EIO;
|
||||
@@ -573,7 +574,7 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
|
||||
ret = sendbytes(i2c_adap, pmsg);
|
||||
if (ret >= 1)
|
||||
bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n",
|
||||
ret, ret == 1 ? "" : "s");
|
||||
ret, str_plural(ret));
|
||||
if (ret < pmsg->len) {
|
||||
if (ret >= 0)
|
||||
ret = -EIO;
|
||||
|
||||
@@ -1058,7 +1058,7 @@ config I2C_QCOM_CCI
|
||||
will be called i2c-qcom-cci.
|
||||
|
||||
config I2C_QCOM_GENI
|
||||
tristate "Qualcomm Technologies Inc.'s GENI based I2C controller"
|
||||
tristate "Qualcomm GENI based I2C controller"
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
depends on QCOM_GENI_SE
|
||||
help
|
||||
|
||||
@@ -818,12 +818,14 @@ static int davinci_i2c_probe(struct platform_device *pdev)
|
||||
adap->nr = pdev->id;
|
||||
r = i2c_add_numbered_adapter(adap);
|
||||
if (r)
|
||||
goto err_unuse_clocks;
|
||||
goto err_cpufreq;
|
||||
|
||||
pm_runtime_put_autosuspend(dev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_cpufreq:
|
||||
i2c_davinci_cpufreq_deregister(dev);
|
||||
err_unuse_clocks:
|
||||
pm_runtime_dont_use_autosuspend(dev->dev);
|
||||
pm_runtime_put_sync(dev->dev);
|
||||
|
||||
@@ -1646,7 +1646,18 @@ static int __maybe_unused lpi2c_runtime_resume(struct device *dev)
|
||||
|
||||
static int __maybe_unused lpi2c_suspend_noirq(struct device *dev)
|
||||
{
|
||||
return pm_runtime_force_suspend(dev);
|
||||
struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
i2c_mark_adapter_suspended(&lpi2c_imx->adapter);
|
||||
|
||||
ret = pm_runtime_force_suspend(dev);
|
||||
if (ret) {
|
||||
i2c_mark_adapter_resumed(&lpi2c_imx->adapter);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused lpi2c_resume_noirq(struct device *dev)
|
||||
@@ -1666,6 +1677,8 @@ static int __maybe_unused lpi2c_resume_noirq(struct device *dev)
|
||||
if (lpi2c_imx->target)
|
||||
lpi2c_imx_target_init(lpi2c_imx);
|
||||
|
||||
i2c_mark_adapter_resumed(&lpi2c_imx->adapter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -304,7 +304,7 @@ static irqreturn_t loongson2_i2c_isr_event(int irq, void *data)
|
||||
regmap_read(priv->regmap, LOONGSON2_I2C_SR1, &status);
|
||||
if (status & LOONGSON2_I2C_SR1_ITERREN_MASK) {
|
||||
loongson2_i2c_isr_error(status, data);
|
||||
return IRQ_NONE;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
regmap_read(priv->regmap, LOONGSON2_I2C_CR2, &cr2);
|
||||
|
||||
@@ -214,11 +214,11 @@ static const struct of_device_id i2c_pxa_dt_ids[] = {
|
||||
MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids);
|
||||
|
||||
static const struct platform_device_id i2c_pxa_id_table[] = {
|
||||
{ "pxa2xx-i2c", REGS_PXA2XX },
|
||||
{ "pxa3xx-pwri2c", REGS_PXA3XX },
|
||||
{ "ce4100-i2c", REGS_CE4100 },
|
||||
{ "pxa910-i2c", REGS_PXA910 },
|
||||
{ "armada-3700-i2c", REGS_A3700 },
|
||||
{ .name = "pxa2xx-i2c", .driver_data = REGS_PXA2XX },
|
||||
{ .name = "pxa3xx-pwri2c", .driver_data = REGS_PXA3XX },
|
||||
{ .name = "ce4100-i2c", .driver_data = REGS_CE4100 },
|
||||
{ .name = "pxa910-i2c", .driver_data = REGS_PXA910 },
|
||||
{ .name = "armada-3700-i2c", .driver_data = REGS_A3700 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table);
|
||||
|
||||
@@ -225,25 +225,7 @@ static int cci_halt(struct cci *cci, u8 master_num)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cci_reset(struct cci *cci)
|
||||
{
|
||||
/*
|
||||
* we reset the whole controller, here and for implicity use
|
||||
* master[0].xxx for waiting on it.
|
||||
*/
|
||||
reinit_completion(&cci->master[0].irq_complete);
|
||||
writel(CCI_RESET_CMD_MASK, cci->base + CCI_RESET_CMD);
|
||||
|
||||
if (!wait_for_completion_timeout(&cci->master[0].irq_complete,
|
||||
CCI_TIMEOUT)) {
|
||||
dev_err(cci->dev, "CCI reset timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cci_init(struct cci *cci)
|
||||
static void cci_init(struct cci *cci)
|
||||
{
|
||||
u32 val = CCI_IRQ_MASK_0_I2C_M0_RD_DONE |
|
||||
CCI_IRQ_MASK_0_I2C_M0_Q0_REPORT |
|
||||
@@ -284,6 +266,24 @@ static int cci_init(struct cci *cci)
|
||||
val = hw->scl_stretch_en << 8 | hw->trdhld << 4 | hw->tsp;
|
||||
writel(val, cci->base + CCI_I2C_Mm_MISC_CTL(i));
|
||||
}
|
||||
}
|
||||
|
||||
static int cci_reset(struct cci *cci)
|
||||
{
|
||||
/*
|
||||
* we reset the whole controller, here and for implicity use
|
||||
* master[0].xxx for waiting on it.
|
||||
*/
|
||||
reinit_completion(&cci->master[0].irq_complete);
|
||||
writel(CCI_RESET_CMD_MASK, cci->base + CCI_RESET_CMD);
|
||||
|
||||
if (!wait_for_completion_timeout(&cci->master[0].irq_complete,
|
||||
CCI_TIMEOUT)) {
|
||||
dev_err(cci->dev, "CCI reset timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
cci_init(cci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -304,7 +304,6 @@ static int cci_run_queue(struct cci *cci, u8 master, u8 queue)
|
||||
dev_err(cci->dev, "master %d queue %d timeout\n",
|
||||
master, queue);
|
||||
cci_reset(cci);
|
||||
cci_init(cci);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
@@ -609,11 +608,7 @@ static int cci_probe(struct platform_device *pdev)
|
||||
|
||||
ret = cci_reset(cci);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = cci_init(cci);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
goto disable_clocks;
|
||||
|
||||
pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
@@ -643,8 +638,6 @@ static int cci_probe(struct platform_device *pdev)
|
||||
of_node_put(cci->master[i].adap.dev.of_node);
|
||||
}
|
||||
}
|
||||
error:
|
||||
disable_irq(cci->irq);
|
||||
disable_clocks:
|
||||
cci_disable_clocks(cci);
|
||||
|
||||
@@ -664,7 +657,6 @@ static void cci_remove(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
disable_irq(cci->irq);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
}
|
||||
|
||||
@@ -464,8 +464,13 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
|
||||
{
|
||||
struct stm32f7_i2c_spec *specs;
|
||||
u32 p_prev = STM32F7_PRESC_MAX;
|
||||
u32 i2cclk = DIV_ROUND_CLOSEST(NSEC_PER_SEC,
|
||||
setup->clock_src);
|
||||
/*
|
||||
* Truncate instead of rounding to closest: if the clock period is
|
||||
* overestimated, the computed SCL timings will come out shorter on
|
||||
* the wire, which can push the bus above the target rate and below
|
||||
* the spec's tLOW/tHIGH minimums.
|
||||
*/
|
||||
u32 i2cclk = NSEC_PER_SEC / setup->clock_src;
|
||||
u32 i2cbus = DIV_ROUND_CLOSEST(NSEC_PER_SEC,
|
||||
setup->speed_freq);
|
||||
u32 clk_error_prev = i2cbus;
|
||||
|
||||
@@ -71,7 +71,7 @@ struct i2c_atr_adap_desc {
|
||||
struct device *parent;
|
||||
struct fwnode_handle *bus_handle;
|
||||
size_t num_aliases;
|
||||
u16 *aliases;
|
||||
u16 *aliases __counted_by_ptr(num_aliases);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user