* Re: [PATCH v3 2/2] Documentation: tpm: add the Physical TPM device tree binding documentation
From: Jarkko Sakkinen @ 2016-11-04 7:32 UTC (permalink / raw)
To: Rob Herring
Cc: Nayna Jain, devicetree-u79uwXL29TY76Z2rM5mHXA,
tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
wsa-z923LK4zBo2bacvFa/9K2g, pawel.moll-5wv7dgnIgG8,
mark.rutland-5wv7dgnIgG8, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
galak-sgV2jX0FEOL9JmXXK+q4OQ, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
peterhuewe-Mmb7MZpHnFY, tpmdd-yWjUBOtONefk1uMJSBkQmQ,
jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
hellerda-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8,
ltcgcw-r/Jw6+rmf7HQT0dZR+AlfA,
cclaudio-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8,
honclo-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8
In-Reply-To: <20161031040245.cwnt4kelrm7liaga@rob-hp-laptop>
On Sun, Oct 30, 2016 at 11:02:45PM -0500, Rob Herring wrote:
> On Wed, Oct 26, 2016 at 05:21:45AM -0400, Nayna Jain wrote:
> > Newly added support of TPM 2.0 eventlog securityfs pseudo files in tpm
> > device driver consumes device tree bindings representing I2C based
> > Physical TPM. This patch adds the documentation for corresponding device
> > tree bindings of I2C based Physical TPM. These bindings are similar to
> > vtpm device tree bindings being used on IBM Power7+ and Power8 Systems
> > running PowerVM.
> >
> > Suggested-by: Jason Gunthorpe <jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
> > Signed-off-by: Nayna Jain <nayna-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
> > ---
> > Changelog v3:
> > - Added documentation for "label" property.
> >
> > Changelog v2:
> >
> > - Include review feedbacks.
> > - Move the doc within bindings/security/tpm.
> > - Add example for compatible property in description.
> > - Delete implicit properties like status, label from description.
> > - Redefine linux,sml-base description.
> >
> > .../devicetree/bindings/security/tpm/tpm-i2c.txt | 21 +++++++++++++++++++++
> > 1 file changed, 21 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/security/tpm/tpm-i2c.txt
>
> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Applied.
/Jarkko
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* RE: [patch v3 1/1] i2c: add master driver for mellanox systems
From: Vadim Pasternak @ 2016-11-04 7:15 UTC (permalink / raw)
To: Vladimir Zapolskiy, wsa@the-dreams.de
Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org,
jiri@resnulli.us, Michael Shych
In-Reply-To: <4708bff8-db23-e9c3-197d-ab337affa080@mleia.com>
Hi Vladimir,
Thank you very much for your reviews.
> -----Original Message-----
> From: Vladimir Zapolskiy [mailto:vz@mleia.com]
> Sent: Friday, November 04, 2016 12:34 AM
> To: Vadim Pasternak <vadimp@mellanox.com>; wsa@the-dreams.de
> Cc: linux-i2c@vger.kernel.org; linux-kernel@vger.kernel.org; jiri@resnulli.us;
> Michael Shych <michaelsh@mellanox.com>
> Subject: Re: [patch v3 1/1] i2c: add master driver for mellanox systems
>
> Hi Vadim,
>
> please find some more review comments below.
>
> On 03.11.2016 20:50, vadimp@mellanox.com wrote:
> > From: Vadim Pasternak <vadimp@mellanox.com>
> >
> > Device driver for Mellanox I2C controller logic, implemented in
> > Lattice CPLD device.
> > Device supports:
> > - Master mode
> > - One physical bus
> > - Polling mode
> >
> > The Kconfig currently controlling compilation of this code is:
> > drivers/i2c/busses/Kconfig:config I2C_MLXCPLD
> >
> > Signed-off-by: Michael Shych <michaelsh@mellanox.com>
> > Signed-off-by: Vadim Pasternak <vadimp@mellanox.com>
> > Reviewed-by: Jiri Pirko <jiri@mellanox.com>
> > ---
>
> [snip]
>
> > diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> > index d252276..be885d2 100644
> > --- a/drivers/i2c/busses/Kconfig
> > +++ b/drivers/i2c/busses/Kconfig
> > @@ -1150,6 +1150,18 @@ config I2C_ELEKTOR
> > This support is also available as a module. If so, the module
> > will be called i2c-elektor.
> >
> > +config I2C_MLXCPLD
> > + tristate "Mellanox I2C driver"
> > + depends on X86_64
> > + default y
>
> I believe the controller is not a widely used piece of hardware found on every
> second laptop.
>
> Please remove 'default y' line from the Kconfig record.
>
> > + help
> > + This exposes the Mellanox platform I2C busses to the linux I2C layer
> > + for X86 based systems.
> > + Controller is implemented as CPLD logic.
> > +
> > + This driver can also be built as a module. If so, the module will be
> > + called as i2c-mlxcpld.
> > +
> > config I2C_PCA_ISA
> > tristate "PCA9564/PCA9665 on an ISA bus"
> > depends on ISA
>
> [snip]
>
> > +
> > +struct mlxcpld_i2c_priv {
> > + struct i2c_adapter adap;
> > + u16 dev_id;
> > + u16 base_addr;
> > + struct mutex lock;
> > + struct mlxcpld_i2c_curr_transf xfer;
> > + struct device *dev;
> > +};
> > +struct platform_device *mlxcpld_i2c_plat_dev;
>
> This global variable is unused.
>
> And it emits several static check warnings:
>
> checkpatch --strict:
>
> CHECK: Please use a blank line after function/struct/union/enum declarations
> #324: FILE: drivers/i2c/busses/i2c-mlxcpld.c:110:
> +};
> +struct platform_device *mlxcpld_i2c_plat_dev;
>
> smatch:
>
> i2c-mlxcpld.c:110:24: warning: symbol 'mlxcpld_i2c_plat_dev' was not
> declared. Should it be static?
>
> Please remove it as unused.
>
> [snip]
>
> > +
> > +/* Check validity of current i2c message and all transfer.
> > + * Calculate also coomon length of all i2c messages in transfer.
> > + */
> > +static int mlxcpld_i2c_invalid_len(struct mlxcpld_i2c_priv *priv,
> > + const struct i2c_msg *msg, u8 *comm_len) {
> > + u8 max_len = msg->flags == I2C_M_RD ? MLXCPLD_I2C_DATA_REG_SZ -
> > + MLXCPLD_I2C_MAX_ADDR_LEN :
> MLXCPLD_I2C_DATA_REG_SZ;
> > +
> > + if (msg->len < 0 || msg->len > max_len)
>
> Compiler W=1 level warning:
>
> i2c-mlxcpld.c: In function 'mlxcpld_i2c_invalid_len':
> i2c-mlxcpld.c:201:15: warning: comparison is always false due to limited range
> of data type [-Wtype-limits]
> if (msg->len < 0 || msg->len > max_len)
> ^
>
> msg->len is unsigned.
>
> > + return -EINVAL;
> > +
> > + *comm_len += msg->len;
> > + if (*comm_len > MLXCPLD_I2C_DATA_REG_SZ)
> > + return -EINVAL;
> > +
> > + return 0;
> > +}
> > +
> > +/* Check validity of received i2c messages parameters.
> > + * Returns 0 if OK, other - in case of invalid parameters
> > + * or common length of data that should be passed to CPLD
>
> Sorry for nitpicking, you may consider to remove one of two spaces after
> asterisks above.
>
> [snip]
>
> > +
> > +static void mlxcpld_i2c_set_transf_data(struct mlxcpld_i2c_priv *priv,
> > + struct i2c_msg *msgs, int num,
> > + u8 comm_len)
> > +{
> > + priv->xfer.msg = msgs;
> > + priv->xfer.msg_num = num;
> > +
> > + /*
> > + * All upper layers currently are never use transfer with more than
> > + * 2 messages. Actually, it's also not so relevant in Mellanox systems
> > + * because of HW limitation. Max size of transfer is o more than 20B
> > + * in current x86 LPCI2C bridge.
> > + */
> > + priv->xfer.cmd = (msgs[num - 1].flags & I2C_M_RD);
>
> Round brackets are not needed above.
>
> > +
> > + if (priv->xfer.cmd == I2C_M_RD && comm_len != msgs[0].len) {
> > + priv->xfer.addr_width = msgs[0].len;
> > + priv->xfer.data_len = comm_len - priv->xfer.addr_width;
> > + } else {
> > + priv->xfer.addr_width = 0;
> > + priv->xfer.data_len = comm_len;
> > + }
> > +}
> > +
>
> [snip]
>
> > +/*
> > + * Wait for master transfer to complete.
> > + * It puts current process to sleep until we get interrupt or timeout expires.
> > + * Returns the number of transferred or read bytes or error (<0).
> > + */
> > +static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv) {
> > + int status, i = 1, timeout = 0;
>
> Please remove the assignment of 'i' variable, after update it is not needed
> anymore.
>
> > + u8 datalen;
> > +
> > + do {
> > + usleep_range(MLXCPLD_I2C_POLL_TIME / 2,
> MLXCPLD_I2C_POLL_TIME);
> > + if (!mlxcpld_i2c_check_status(priv, &status))
> > + break;
> > + timeout += MLXCPLD_I2C_POLL_TIME;
> > + } while (status == 0 && timeout < MLXCPLD_I2C_XFER_TO);
> > +
> > + switch (status) {
> > + case MLXCPLD_LPCI2C_NO_IND:
> > + return -ETIMEDOUT;
> > +
> > + case MLXCPLD_LPCI2C_ACK_IND:
> > + if (priv->xfer.cmd != I2C_M_RD)
> > + return (priv->xfer.addr_width + priv->xfer.data_len);
> > +
> > + if (priv->xfer.msg_num == 1)
> > + i = 0;
> > + else
> > + i = 1;
> > +
> > + if (!priv->xfer.msg[i].buf)
> > + return -EINVAL;
> > +
> > + /*
> > + * Actual read data len will be always the same as
> > + * requested len. 0xff (line pull-up) will be returned
> > + * if slave has no data to return. Thus don't read
> > + * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD.
> > + */
> > + datalen = priv->xfer.data_len;
> > +
> > + mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_DATA_REG,
> > + priv->xfer.msg[i].buf, datalen);
> > +
> > + return datalen;
> > +
> > + case MLXCPLD_LPCI2C_NACK_IND:
> > + return -EAGAIN;
> > +
> > + default:
> > + return -EINVAL;
> > + }
> > +}
> > +
>
> [snip]
>
> > +
> > +/* Generic lpc-i2c transfer.
>
> Just for my information, how do you unwrap 'lpc' acronym found in the code?
>
On Mellanox systems I2C controller logic is implemented in Lattice CPLD device.
This CPLD device is connected to CPU through LPC bus, which Intel's Low Pin Count bus:
http://www.intel.com/design/chipsets/industry/25128901.pdf
So, CPLD provides some sort of LPC to I2C bridging.
> > + * Returns the number of processed messages or error (<0).
> > + */
> > +static int mlxcpld_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
> > + int num)
> > +{
> > + struct mlxcpld_i2c_priv *priv = i2c_get_adapdata(adap);
> > + u8 comm_len = 0;
> > + int err;
> > +
> > + err = mlxcpld_i2c_check_msg_params(priv, msgs, num, &comm_len);
> > + if (err) {
> > + dev_err(priv->dev, "Incorrect message\n");
> > + return err;
> > + }
> > +
> > + /* Check bus state */
> > + if (mlxcpld_i2c_wait_for_free(priv)) {
> > + dev_err(priv->dev, "LPCI2C bridge is busy\n");
> > +
> > + /*
> > + * Usually it means something serious has happened.
> > + * We can not have unfinished previous transfer
> > + * so it doesn't make any sense to try to stop it.
> > + * Probably we were not able to recover from the
> > + * previous error.
> > + * The only reasonable thing - is soft reset.
> > + */
> > + mlxcpld_i2c_reset(priv);
> > + if (mlxcpld_i2c_check_busy(priv)) {
> > + dev_err(priv->dev, "LPCI2C bridge is busy after
> reset\n");
> > + return -EIO;
> > + }
> > + }
> > +
> > + mlxcpld_i2c_set_transf_data(priv, msgs, num, comm_len);
> > +
> > + mutex_lock(&priv->lock);
> > +
> > + /* Do real transfer. Can't fail */
> > + mlxcpld_i2c_xfer_msg(priv);
>
> Please add an empty line here to improve readability.
>
> > + /* Wait for transaction complete */
> > + err = mlxcpld_i2c_wait_for_tc(priv);
> > +
> > + mutex_unlock(&priv->lock);
> > +
> > + return err < 0 ? err : num;
> > +}
> > +
> > +static u32 mlxcpld_i2c_func(struct i2c_adapter *adap) {
> > + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
> > +I2C_FUNC_SMBUS_BLOCK_DATA; }
> > +
> > +static const struct i2c_algorithm mlxcpld_i2c_algo = {
> > + .master_xfer = mlxcpld_i2c_xfer,
> > + .functionality = mlxcpld_i2c_func
> > +};
> > +
> > +static struct i2c_adapter mlxcpld_i2c_adapter = {
> > + .owner = THIS_MODULE,
> > + .name = "i2c-mlxcpld",
> > + .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
> > + .algo = &mlxcpld_i2c_algo,
> > +};
> > +
> > +static int mlxcpld_i2c_probe(struct platform_device *pdev) {
> > + struct mlxcpld_i2c_priv *priv;
> > + int err;
> > +
> > + priv = devm_kzalloc(&pdev->dev, sizeof(struct mlxcpld_i2c_priv),
> > + GFP_KERNEL);
> > + if (!priv)
> > + return -ENOMEM;
> > +
> > + mutex_init(&priv->lock);
> > + platform_set_drvdata(pdev, priv);
> > +
> > + priv->dev = &pdev->dev;
> > +
> > + /* Register with i2c layer */
> > + priv->adap = mlxcpld_i2c_adapter;
> > + priv->adap.dev.parent = &pdev->dev;
> > + priv->adap.retries = MLXCPLD_I2C_RETR_NUM;
> > + priv->adap.nr = MLXCPLD_I2C_BUS_NUM;
>
> So since you want to allow the registration of only one such controller on a
> board (by the way in the opposite case it is also expected that "struct
> i2c_adapter" is allocated dynamically to avoid rewriting of data), you probably
> know the good reason behind it.
>
> But in that case you may consider to move .retries and .nr instantiation to the
> "static struct i2c_adapter" declaration above.
>
> > + priv->adap.timeout = usecs_to_jiffies(MLXCPLD_I2C_XFER_TO);
> > + priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR;
> > + i2c_set_adapdata(&priv->adap, priv);
> > +
> > + err = i2c_add_numbered_adapter(&priv->adap);
> > + if (err) {
> > + dev_err(&pdev->dev, "Failed to add %s adapter (%d)\n",
> > + MLXCPLD_I2C_DEVICE_NAME, err);
> > + goto fail_adapter;
> > + }
> > +
> > + return 0;
> > +
> > +fail_adapter:
> > + mutex_destroy(&priv->lock);
> > + return err;
> > +}
> > +
> > +static int mlxcpld_i2c_remove(struct platform_device *pdev) {
> > + struct mlxcpld_i2c_priv *priv = platform_get_drvdata(pdev);
> > +
> > + i2c_del_adapter(&priv->adap);
> > + mutex_destroy(&priv->lock);
> > +
> > + return 0;
> > +}
> > +
> > +static struct platform_driver mlxcpld_i2c_driver = {
> > + .probe = mlxcpld_i2c_probe,
> > + .remove = mlxcpld_i2c_remove,
> > + .driver = {
> > + .name = MLXCPLD_I2C_DEVICE_NAME,
> > + },
> > +};
> > +
> > +module_platform_driver(mlxcpld_i2c_driver);
> > +
> > +MODULE_AUTHOR("Michael Shych <michaels@mellanox.com>");
> > +MODULE_DESCRIPTION("Mellanox I2C-CPLD controller driver");
> > +MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS("platform:i2c-
> mlxcpld");
> >
>
> Generally the driver looks good and simple.
>
> --
> With best wishes,
> Vladimir
Thank you very much,
Vadim.
^ permalink raw reply
* [PATCH 2/2] i2c: uniphier-f: rename jump label to follow coding style guideline
From: Masahiro Yamada @ 2016-11-04 10:49 UTC (permalink / raw)
To: linux-i2c; +Cc: Masahiro Yamada, linux-arm-kernel, linux-kernel, Wolfram Sang
In-Reply-To: <1478256561-7709-1-git-send-email-yamada.masahiro@socionext.com>
Documentation/CodingStyle recommends to use label names which say
what the goto does or why the goto exists.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---
drivers/i2c/busses/i2c-uniphier-f.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c
index b54448e..a154cc9 100644
--- a/drivers/i2c/busses/i2c-uniphier-f.c
+++ b/drivers/i2c/busses/i2c-uniphier-f.c
@@ -528,7 +528,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
if (!clk_rate) {
dev_err(dev, "input clock rate should not be zero\n");
ret = -EINVAL;
- goto err;
+ goto disable_clk;
}
init_completion(&priv->comp);
@@ -547,11 +547,11 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
pdev->name, priv);
if (ret) {
dev_err(dev, "failed to request irq %d\n", irq);
- goto err;
+ goto disable_clk;
}
ret = i2c_add_adapter(&priv->adap);
-err:
+disable_clk:
if (ret)
clk_disable_unprepare(priv->clk);
--
1.9.1
^ permalink raw reply related
* [PATCH 1/2] i2c: uniphier: rename jump label to follow coding style guideline
From: Masahiro Yamada @ 2016-11-04 10:49 UTC (permalink / raw)
To: linux-i2c; +Cc: Masahiro Yamada, linux-arm-kernel, linux-kernel, Wolfram Sang
Documentation/CodingStyle recommends to use label names which say
what the goto does or why the goto exists.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---
drivers/i2c/busses/i2c-uniphier.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c
index cc80bb2..abc6770 100644
--- a/drivers/i2c/busses/i2c-uniphier.c
+++ b/drivers/i2c/busses/i2c-uniphier.c
@@ -373,7 +373,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev)
if (!clk_rate) {
dev_err(dev, "input clock rate should not be zero\n");
ret = -EINVAL;
- goto err;
+ goto disable_clk;
}
init_completion(&priv->comp);
@@ -392,11 +392,11 @@ static int uniphier_i2c_probe(struct platform_device *pdev)
priv);
if (ret) {
dev_err(dev, "failed to request irq %d\n", irq);
- goto err;
+ goto disable_clk;
}
ret = i2c_add_adapter(&priv->adap);
-err:
+disable_clk:
if (ret)
clk_disable_unprepare(priv->clk);
--
1.9.1
^ permalink raw reply related
* Re: [RFC 00/17] clk: Add per-controller locks to fix deadlocks
From: Marek Szyprowski @ 2016-11-04 10:53 UTC (permalink / raw)
To: Stephen Boyd, Krzysztof Kozlowski
Cc: Michael Turquette, Stephen Warren, Lee Jones, Eric Anholt,
Florian Fainelli, Ray Jui, Scott Branden,
bcm-kernel-feedback-list, Sylwester Nawrocki, Tomasz Figa,
Kukjin Kim, Russell King, Mark Brown, linux-clk, linux-rpi-kernel,
linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-i2c,
alsa-devel, Charles Keepax, Javier
In-Reply-To: <20160909002432.GE13062@codeaurora.org>
Hi Stephen,
Krzysztof has left Samsung, but we would like to continue this task, because
the ABBA dead-locks related to global prepare lock becomes more and more
problematic for us to workaround.
On 2016-09-09 02:24, Stephen Boyd wrote:
> On 08/16, Krzysztof Kozlowski wrote:
>> RFC, please, do not apply, maybe except patch #1 which is harmless.
>>
>>
>> Introduction
>> ============
>> The patchset brings new entity: clock controller representing a hardware
>> block. The clock controller comes with its own prepare lock which
>> is used then in many places. The idea is to fix the deadlock mentioned
>> in commit 10ff4c5239a1 ("i2c: exynos5: Fix possible ABBA deadlock by keeping
>> I2C clock prepared") and commit 34e81ad5f0b6 ("i2c: s3c2410: fix ABBA deadlock
>> by keeping clock prepared").
>>
>>
>> Disclaimer
>> ==========
>> Request for comments, so:
>> 1. Only exynos_defconfig builds,
>> 2. A lot of FIXME/TODO note still,
>> 3. Checkpatch not run, lines not aligned,
>> 4. Other (non-exynos) drivers not converted,
>> 5. Probably not yet bisectable,
>> 6. Locking became quite complex.
>> The previous one lock was simple. Inefficient and dead-lock prone but
>> simple. Because of clock hierarchy spanning through controllers, the
>> new locking became quite complicated. I don't like it but...
>>
>>
>> Details
>> =======
>> In Exynos-based boards case the deadlock occurs between clock's
>> prepare_lock and regmap-i2c's lock:
>>
>> CPU #0: CPU #1:
>> lock(regmap)
>> s2mps11-clk: clk_prepare_lock()
>>
>> i2c-exynos: clk_prepare_lock() - wait
>> lock(regmap) - wait
>>
>> The clk_prepare_lock() on both CPUs come from different clock drivers
>> and components:
>> 1. I2C clock is part of SoC block and is required by i2c-s3c2410/i2c-exynos5
>> driver,
>> 2. S2MPS11 clock is separate device, however driver uses I2C regmap.
>>
>> The deadlock was reported by lockdep (always) and was happening
>> in 20% of boots of Odroid XU3 with multi_v7 defconfig. Workaround for
>> deadlock was implemented by removing prepare/unprepare calls from I2C
>> transfers. However these are just workarounds... which after applying
>> this patch can be reverted.
>>
>> Additionally Marek Szyprowski's work on domains/clocks/pinctrl exposed
>> the deadlock again in different configuration.
>>
> Per-controller locks seems to be a misnomer. These patches look
> more like per-clk_register() locks. The clk registrant can decide
> how fine grained to make the prepare locking scheme. They can
> decide to have one lock per clk, one lock for the entire tree, or
> one lock per arbitrary subtree. I'd prefer to drop the controller
> concept unless it's really done that way, by attaching to the OF
> clk provider or device pointer.
This was not phrased well but the idea was to let provider/controller
have ability to define which clocks will use common lock. Probably
removing the concept of clock controller and moving the lock to
clk_provider will be much better approach.
> Given that, it seems that conceptually these patches allow clk
> registrants to carve out a set of clks that they want to be
> treated as an atomic unit with regards to the prepare lock.
> TL;DR trees of per-process recursive prepare mutex locks where
> the locks cover one or more clks.
>
> The locks are recursive per-process to simplify the problem where
> we need to acquire the same lock multiple times while traversing
> a tree that shares the same lock, right? Otherwise we would need
> to track which locks we've already grabbed and refcount and we
> wouldn't be able to re-enter the framework from within the clk
> ops of the same atomic unit.
>
> As long as we can guarantee that we always take the locks in the
> same order we'll be fine. The burden to ensure that would be
> placed on the clk registrants though, and verifying that will be
> left up to humans? That seems fragile and error prone. We can
> always say that we take the global lock and then traverse the
> children up to the roots, but we can't be sure that during the
> tree traversal we don't take locks in different order because of
> how the clk registrant has structured things.
>
> It would be great if the different clk APIs were listed, with the
> order of how locks are taken BTW. And really overall just more
> information about how the locking scheme works. I had to read
> this patch series quite a few times to come to (hopefully the
> right) conclusions.
Right, such change requires much more documentation and especially
that it took significant amount of time to figure out all(?)
possible use cases and locking schemes.
> So I'm not very fond of this design because the locking scheme is
> pretty much out of the hands of the framework and can be easily
> broken.
Well, switching from a single global lock to more granular locking
is always a good approach. Please note that the global lock sooner
or later became a serious bottleneck if one wants to make somehow
more aggressive power management and clock gating.
> I'm biased of course, because I'd prefer we go with my
> wwmutex design of per-clk locks[1]. Taking locks in any order
> works fine there, and we resolve quite a few long standing
> locking problems that we have while improving scalability. The
> problem there is that we don't get the recursive mutex design
> (maybe that's a benefit!).
Do you have any plan to continue working on your approach? per-clk
wwmutex looks like an overkill on the first glance, but that's probably
the only working solution if you want to get rid of recursive locks.
I'm still not really convinced that we really need wwmutex here,
especially if it is possible to guarantee the same order of locking
operations inside the clock core. This requires a bit of cooperation
from clock providers (with proper documentation and a list of
DO/DON'T it shouldn't be that hard).
> Once a clk_op reenters the framework
> with consumer APIs and tries to grab the same lock we deadlock.
> This is why I've been slowly splitting consumers from providers
> so we can easily identify these cases. If we had something like
> coordinated clk rate switching, we could get rid of clk_ops
> reentering the framework and avoid this problem (and we really do
> need to do that).
I'm not sure that this makes really sense split consumers and
providers. You will get recursive calls to clk core anyway with
consumers calls if you are implementing i2c clock, for which an i2c
bus driver does it's own clock gating (i2c controller uses
consumer clk api).
> The one thing I do like about this patch series though is the
> gradual movement of providers to the new locking scheme. Maybe if
> we combined that idea with per-clk wwmutex locks we could have
> the best of both worlds and fix reentrancy later when we need it?
> There's wwmutex_trylock() that we could use. Perhaps always pass
> a NULL context if some clk flag isn't set (CLK_USE_PER_CLK_LOCK).
> Plus we could assign the same wwmutex all over the place when
> that flag isn't set and allocate a unique wwmutex at clk_register
> time otherwise. I haven't thought about it deeply, so there may
> be some glaring problem that I'm missing like when we have half
> the clks in a tree with the flag set or something. This is where
> driving home from the office for 45 minutes helps.
>
> [1] http://lists.infradead.org/pipermail/linux-arm-kernel/2014-April/251039.html
Best regards
--
Marek Szyprowski, PhD
Samsung R&D Institute Poland
^ permalink raw reply
* Re: [PATCH] i2c: core: fix NULL pointer dereference under race condition
From: Wolfram Sang @ 2016-11-04 19:42 UTC (permalink / raw)
To: Vladimir Zapolskiy; +Cc: Peter Rosin, linux-i2c
In-Reply-To: <1477943184-3419-1-git-send-email-vladimir_zapolskiy@mentor.com>
[-- Attachment #1: Type: text/plain, Size: 3719 bytes --]
On Mon, Oct 31, 2016 at 09:46:24PM +0200, Vladimir Zapolskiy wrote:
> Race condition between registering an I2C device driver and
> deregistering an I2C adapter device which is assumed to manage that
> I2C device may lead to a NULL pointer dereference due to the
> uninitialized list head of driver clients.
>
> The root cause of the issue is that the I2C bus may know about the
> registered device driver and thus it is matched by bus_for_each_drv(),
> but the list of clients is not initialized and commonly it is NULL,
> because I2C device drivers define struct i2c_driver as static and
> clients field is expected to be initialized by I2C core:
>
> i2c_register_driver() i2c_del_adapter()
> driver_register() ...
> bus_add_driver() ...
> ... bus_for_each_drv(..., __process_removed_adapter)
> ... i2c_do_del_adapter()
> ... list_for_each_entry_safe(..., &driver->clients, ...)
> INIT_LIST_HEAD(&driver->clients);
>
> To solve the problem it is sufficient to do clients list head
> initialization before calling driver_register().
>
> The problem was found while using an I2C device driver with a sluggish
That one must have been really sluggish :)
> registration routine on a bus provided by a physically detachable I2C
> master controller, but practically the oops may be reproduced under
> the race between arbitraty I2C device driver registration and managing
> I2C bus device removal e.g. by unbinding the latter over sysfs:
>
> % echo 21a4000.i2c > /sys/bus/platform/drivers/imx-i2c/unbind
> Unable to handle kernel NULL pointer dereference at virtual address 00000000
> Internal error: Oops: 17 [#1] SMP ARM
> CPU: 2 PID: 533 Comm: sh Not tainted 4.9.0-rc3+ #61
> Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
> task: e5ada400 task.stack: e4936000
> PC is at i2c_do_del_adapter+0x20/0xcc
> LR is at __process_removed_adapter+0x14/0x1c
> Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none
> Control: 10c5387d Table: 35bd004a DAC: 00000051
> Process sh (pid: 533, stack limit = 0xe4936210)
> Stack: (0xe4937d28 to 0xe4938000)
> Backtrace:
> [<c0667be0>] (i2c_do_del_adapter) from [<c0667cc0>] (__process_removed_adapter+0x14/0x1c)
> [<c0667cac>] (__process_removed_adapter) from [<c0516998>] (bus_for_each_drv+0x6c/0xa0)
> [<c051692c>] (bus_for_each_drv) from [<c06685ec>] (i2c_del_adapter+0xbc/0x284)
> [<c0668530>] (i2c_del_adapter) from [<bf0110ec>] (i2c_imx_remove+0x44/0x164 [i2c_imx])
> [<bf0110a8>] (i2c_imx_remove [i2c_imx]) from [<c051a838>] (platform_drv_remove+0x2c/0x44)
> [<c051a80c>] (platform_drv_remove) from [<c05183d8>] (__device_release_driver+0x90/0x12c)
> [<c0518348>] (__device_release_driver) from [<c051849c>] (device_release_driver+0x28/0x34)
> [<c0518474>] (device_release_driver) from [<c0517150>] (unbind_store+0x80/0x104)
> [<c05170d0>] (unbind_store) from [<c0516520>] (drv_attr_store+0x28/0x34)
> [<c05164f8>] (drv_attr_store) from [<c0298acc>] (sysfs_kf_write+0x50/0x54)
> [<c0298a7c>] (sysfs_kf_write) from [<c029801c>] (kernfs_fop_write+0x100/0x214)
> [<c0297f1c>] (kernfs_fop_write) from [<c0220130>] (__vfs_write+0x34/0x120)
> [<c02200fc>] (__vfs_write) from [<c0221088>] (vfs_write+0xa8/0x170)
> [<c0220fe0>] (vfs_write) from [<c0221e74>] (SyS_write+0x4c/0xa8)
> [<c0221e28>] (SyS_write) from [<c0108a20>] (ret_fast_syscall+0x0/0x1c)
>
> Signed-off-by: Vladimir Zapolskiy <vladimir_zapolskiy@mentor.com>
Good catch! Applied to for-current, thanks!
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH] i2c: make busses/i2c-pxa-pci.c explicitly non-modular
From: Wolfram Sang @ 2016-11-04 19:47 UTC (permalink / raw)
To: Paul Gortmaker; +Cc: linux-kernel, Sebastian Andrzej Siewior, linux-i2c
In-Reply-To: <20161031175947.10531-1-paul.gortmaker@windriver.com>
[-- Attachment #1: Type: text/plain, Size: 1294 bytes --]
On Mon, Oct 31, 2016 at 01:59:47PM -0400, Paul Gortmaker wrote:
> The Kconfig currently controlling compilation of this code is:
>
> drivers/i2c/busses/Kconfig:config I2C_PXA_PCI
> drivers/i2c/busses/Kconfig: def_bool I2C_PXA && X86_32 && PCI && OF
>
> ...meaning that it currently is not being built as a module by anyone.
>
> Lets remove the modular code that is essentially orphaned, so that
> when reading the driver there is no doubt it is builtin-only.
>
> We explicitly disallow a driver unbind, since that doesn't have a
> sensible use case anyway, and it allows us to drop the ".remove"
> code for non-modular drivers.
>
> Since module_pci_driver() uses the same init level priority as
> builtin_pci_driver() the init ordering remains unchanged with
> this commit.
>
> Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code.
>
> We also delete the MODULE_LICENSE tag etc. since all that information
> was (or is now) contained at the top of the file in the comments.
>
> Cc: Wolfram Sang <wsa@the-dreams.de>
> Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> Cc: linux-i2c@vger.kernel.org
> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Looks OK to me, still I'd like an ack from Sebastian for this patch.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH] i2c: make busses/i2c-pxa-pci.c explicitly non-modular
From: Sebastian Andrzej Siewior @ 2016-11-04 20:14 UTC (permalink / raw)
To: Wolfram Sang; +Cc: Paul Gortmaker, linux-kernel, linux-i2c
In-Reply-To: <20161104194748.GB1478@katana>
On 2016-11-04 20:47:49 [+0100], Wolfram Sang wrote:
> Looks OK to me, still I'd like an ack from Sebastian for this patch.
>
Acked-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Sebastian
^ permalink raw reply
* [PATCH v4 0/2] i2c: aspeed: added driver for Aspeed I2C
From: Brendan Higgins @ 2016-11-05 1:58 UTC (permalink / raw)
To: wsa-z923LK4zBo2bacvFa/9K2g, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8
Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, joel-U3u1mxZcP9KHXe+LvDLADg,
openbmc-uLR06cmDAlY/bJ5BZ2RsiQ
Sorry, been a while since I was able to send an update for this.
As a refresher, I added a master mode and slave mode I2C driver for the Aspeed
24XX/25XX SoC as well as device binding documentation.
Changes since first update:
- I have removed the bus device tree param as requested here:
http://www.spinics.net/lists/devicetree/msg143850.html
- I2C adapter number is now generated dynamically unless an alias is provided
- I changed the Kconfig for the driver to depend only on ARCH_ASPEED
- Replaced the two module_platform_driver registrations with single
module_init
Changes have been tested on the Aspeed evaluation board.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v4 1/2] i2c: aspeed: added driver for Aspeed I2C
From: Brendan Higgins @ 2016-11-05 1:58 UTC (permalink / raw)
To: wsa, robh+dt, mark.rutland
Cc: linux-i2c, devicetree, joel, openbmc, Brendan Higgins
In-Reply-To: <1478311099-6771-1-git-send-email-brendanhiggins@google.com>
Added initial master and slave support for Aspeed I2C controller.
Supports fourteen busses present in ast24xx and ast25xx BMC SoCs by
Aspeed.
Signed-off-by: Brendan Higgins <brendanhiggins@google.com>
---
Changes for v2:
- Added single module_init (multiple was breaking some builds).
Changes for v3:
- Removed "bus" device tree param; now extracted from bus address offset
Changes for v4:
- I2C adapter number is now generated dynamically unless specified in alias.
---
drivers/i2c/busses/Kconfig | 10 +
drivers/i2c/busses/Makefile | 1 +
drivers/i2c/busses/i2c-aspeed.c | 807 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 818 insertions(+)
create mode 100644 drivers/i2c/busses/i2c-aspeed.c
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index d252276..b6caa5d 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -1009,6 +1009,16 @@ config I2C_RCAR
This driver can also be built as a module. If so, the module
will be called i2c-rcar.
+config I2C_ASPEED
+ tristate "Aspeed AST2xxx SoC I2C Controller"
+ depends on ARCH_ASPEED
+ help
+ If you say yes to this option, support will be included for the
+ Aspeed AST2xxx SoC I2C controller.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-aspeed.
+
comment "External I2C/SMBus adapter drivers"
config I2C_DIOLAN_U2C
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 29764cc..826e780 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -99,6 +99,7 @@ obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
obj-$(CONFIG_I2C_XLR) += i2c-xlr.o
obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o
obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o
+obj-$(CONFIG_I2C_ASPEED) += i2c-aspeed.o
# External I2C/SMBus adapter drivers
obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
new file mode 100644
index 0000000..88e078a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-aspeed.c
@@ -0,0 +1,807 @@
+/*
+ * I2C adapter for the ASPEED I2C bus.
+ *
+ * Copyright (C) 2012-2020 ASPEED Technology Inc.
+ * Copyright 2016 IBM Corporation
+ * Copyright 2016 Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/slab.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+/* I2C Register */
+#define ASPEED_I2C_FUN_CTRL_REG 0x00
+#define ASPEED_I2C_AC_TIMING_REG1 0x04
+#define ASPEED_I2C_AC_TIMING_REG2 0x08
+#define ASPEED_I2C_INTR_CTRL_REG 0x0c
+#define ASPEED_I2C_INTR_STS_REG 0x10
+#define ASPEED_I2C_CMD_REG 0x14
+#define ASPEED_I2C_DEV_ADDR_REG 0x18
+#define ASPEED_I2C_BYTE_BUF_REG 0x20
+#define ASPEED_I2C_OFFSET_START 0x40
+#define ASPEED_I2C_OFFSET_INCREMENT 0x40
+
+#define ASPEED_I2C_NUM_BUS 14
+
+/* Global Register Definition */
+/* 0x00 : I2C Interrupt Status Register */
+/* 0x08 : I2C Interrupt Target Assignment */
+
+/* Device Register Definition */
+/* 0x00 : I2CD Function Control Register */
+#define ASPEED_I2CD_MULTI_MASTER_DIS BIT(15)
+#define ASPEED_I2CD_SDA_DRIVE_1T_EN BIT(8)
+#define ASPEED_I2CD_M_SDA_DRIVE_1T_EN BIT(7)
+#define ASPEED_I2CD_M_HIGH_SPEED_EN BIT(6)
+#define ASPEED_I2CD_SLAVE_EN BIT(1)
+#define ASPEED_I2CD_MASTER_EN BIT(0)
+
+/* 0x08 : I2CD Clock and AC Timing Control Register #2 */
+#define ASPEED_NO_TIMEOUT_CTRL 0
+
+
+/* 0x0c : I2CD Interrupt Control Register &
+ * 0x10 : I2CD Interrupt Status Register
+ *
+ * These share bit definitions, so use the same values for the enable &
+ * status bits.
+ */
+#define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT BIT(14)
+#define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13)
+#define ASPEED_I2CD_INTR_SLAVE_MATCH BIT(7)
+#define ASPEED_I2CD_INTR_SCL_TIMEOUT BIT(6)
+#define ASPEED_I2CD_INTR_ABNORMAL BIT(5)
+#define ASPEED_I2CD_INTR_NORMAL_STOP BIT(4)
+#define ASPEED_I2CD_INTR_ARBIT_LOSS BIT(3)
+#define ASPEED_I2CD_INTR_RX_DONE BIT(2)
+#define ASPEED_I2CD_INTR_TX_NAK BIT(1)
+#define ASPEED_I2CD_INTR_TX_ACK BIT(0)
+
+/* 0x14 : I2CD Command/Status Register */
+#define ASPEED_I2CD_SCL_LINE_STS BIT(18)
+#define ASPEED_I2CD_SDA_LINE_STS BIT(17)
+#define ASPEED_I2CD_BUS_BUSY_STS BIT(16)
+#define ASPEED_I2CD_BUS_RECOVER_CMD BIT(11)
+
+/* Command Bit */
+#define ASPEED_I2CD_M_STOP_CMD BIT(5)
+#define ASPEED_I2CD_M_S_RX_CMD_LAST BIT(4)
+#define ASPEED_I2CD_M_RX_CMD BIT(3)
+#define ASPEED_I2CD_S_TX_CMD BIT(2)
+#define ASPEED_I2CD_M_TX_CMD BIT(1)
+#define ASPEED_I2CD_M_START_CMD BIT(0)
+
+/* 0x18 : I2CD Slave Device Address Register */
+#define ASPEED_I2CD_DEV_ADDR_MASK GENMASK(6, 0)
+
+enum aspeed_i2c_slave_state {
+ ASPEED_I2C_SLAVE_START,
+ ASPEED_I2C_SLAVE_READ_REQUESTED,
+ ASPEED_I2C_SLAVE_READ_PROCESSED,
+ ASPEED_I2C_SLAVE_WRITE_REQUESTED,
+ ASPEED_I2C_SLAVE_WRITE_RECEIVED,
+ ASPEED_I2C_SLAVE_STOP,
+};
+
+struct aspeed_i2c_bus {
+ struct i2c_adapter adap;
+ struct device *dev;
+ void __iomem *base;
+ spinlock_t lock;
+ struct completion cmd_complete;
+ int irq;
+ /* Transaction state. */
+ struct i2c_msg *msg;
+ int msg_pos;
+ u32 cmd_err;
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ struct i2c_client *slave;
+ enum aspeed_i2c_slave_state slave_state;
+#endif
+};
+
+struct aspeed_i2c_controller {
+ struct device *dev;
+ void __iomem *base;
+ int irq;
+ struct irq_domain *irq_domain;
+};
+
+static inline void aspeed_i2c_write(struct aspeed_i2c_bus *bus, u32 val,
+ u32 reg)
+{
+ writel(val, bus->base + reg);
+}
+
+static inline u32 aspeed_i2c_read(struct aspeed_i2c_bus *bus, u32 reg)
+{
+ return readl(bus->base + reg);
+}
+
+static u8 aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus)
+{
+ u32 command;
+ unsigned long time_left;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&bus->lock, flags);
+ command = aspeed_i2c_read(bus, ASPEED_I2C_CMD_REG);
+ /* Bus is idle: no recovery needed. */
+ if ((command & ASPEED_I2CD_SDA_LINE_STS) &&
+ (command & ASPEED_I2CD_SCL_LINE_STS))
+ goto out;
+
+ dev_dbg(bus->dev, "bus hung (state %x), attempting recovery\n",
+ command);
+
+ /* Bus held: put bus in stop state. */
+ if ((command & ASPEED_I2CD_SDA_LINE_STS) &&
+ !(command & ASPEED_I2CD_SCL_LINE_STS)) {
+ aspeed_i2c_write(bus, ASPEED_I2CD_M_STOP_CMD,
+ ASPEED_I2C_CMD_REG);
+ reinit_completion(&bus->cmd_complete);
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ time_left = wait_for_completion_interruptible_timeout(
+ &bus->cmd_complete, bus->adap.timeout * HZ);
+
+ spin_lock_irqsave(&bus->lock, flags);
+ if (time_left == 0)
+ ret = -ETIMEDOUT;
+ else if (bus->cmd_err)
+ ret = -EIO;
+ /* Bus error. */
+ } else if (!(command & ASPEED_I2CD_SDA_LINE_STS)) {
+ aspeed_i2c_write(bus, ASPEED_I2CD_BUS_RECOVER_CMD,
+ ASPEED_I2C_CMD_REG);
+ reinit_completion(&bus->cmd_complete);
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ time_left = wait_for_completion_interruptible_timeout(
+ &bus->cmd_complete, bus->adap.timeout * HZ);
+
+ spin_lock_irqsave(&bus->lock, flags);
+ if (time_left == 0)
+ ret = -ETIMEDOUT;
+ else if (bus->cmd_err)
+ ret = -EIO;
+ /* Recovery failed. */
+ else if (!(aspeed_i2c_read(bus, ASPEED_I2C_CMD_REG) &
+ ASPEED_I2CD_SDA_LINE_STS))
+ ret = -EIO;
+ }
+
+out:
+ spin_unlock_irqrestore(&bus->lock, flags);
+ return ret;
+}
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
+{
+ bool irq_handled = true;
+ u32 command;
+ u32 irq_status;
+ u32 status_ack = 0;
+ u8 value;
+ struct i2c_client *slave = bus->slave;
+
+ spin_lock(&bus->lock);
+ if (!slave) {
+ irq_handled = false;
+ goto out;
+ }
+ command = aspeed_i2c_read(bus, ASPEED_I2C_CMD_REG);
+ irq_status = aspeed_i2c_read(bus, ASPEED_I2C_INTR_STS_REG);
+
+ /* Slave was requested, restart state machine. */
+ if (irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) {
+ status_ack |= ASPEED_I2CD_INTR_SLAVE_MATCH;
+ bus->slave_state = ASPEED_I2C_SLAVE_START;
+ }
+ /* Slave is not currently active, irq was for someone else. */
+ if (bus->slave_state == ASPEED_I2C_SLAVE_STOP) {
+ irq_handled = false;
+ goto out;
+ }
+
+ dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n",
+ irq_status, command);
+
+ /* Slave was sent something. */
+ if (irq_status & ASPEED_I2CD_INTR_RX_DONE) {
+ value = aspeed_i2c_read(bus, ASPEED_I2C_BYTE_BUF_REG) >> 8;
+ /* Handle address frame. */
+ if (bus->slave_state == ASPEED_I2C_SLAVE_START) {
+ if (value & 0x1)
+ bus->slave_state =
+ ASPEED_I2C_SLAVE_READ_REQUESTED;
+ else
+ bus->slave_state =
+ ASPEED_I2C_SLAVE_WRITE_REQUESTED;
+ }
+ status_ack |= ASPEED_I2CD_INTR_RX_DONE;
+ }
+
+ /* Slave was asked to stop. */
+ if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {
+ status_ack |= ASPEED_I2CD_INTR_NORMAL_STOP;
+ bus->slave_state = ASPEED_I2C_SLAVE_STOP;
+ }
+ if (irq_status & ASPEED_I2CD_INTR_TX_NAK) {
+ status_ack |= ASPEED_I2CD_INTR_TX_NAK;
+ bus->slave_state = ASPEED_I2C_SLAVE_STOP;
+ }
+
+ if (bus->slave_state == ASPEED_I2C_SLAVE_READ_REQUESTED) {
+ if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
+ dev_err(bus->dev, "Unexpected ACK on read request.\n");
+ bus->slave_state = ASPEED_I2C_SLAVE_READ_PROCESSED;
+
+ i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
+ aspeed_i2c_write(bus, value, ASPEED_I2C_BYTE_BUF_REG);
+ aspeed_i2c_write(bus, ASPEED_I2CD_S_TX_CMD, ASPEED_I2C_CMD_REG);
+ } else if (bus->slave_state == ASPEED_I2C_SLAVE_READ_PROCESSED) {
+ status_ack |= ASPEED_I2CD_INTR_TX_ACK;
+ if (!(irq_status & ASPEED_I2CD_INTR_TX_ACK))
+ dev_err(bus->dev,
+ "Expected ACK after processed read.\n");
+ i2c_slave_event(slave, I2C_SLAVE_READ_PROCESSED, &value);
+ aspeed_i2c_write(bus, value, ASPEED_I2C_BYTE_BUF_REG);
+ aspeed_i2c_write(bus, ASPEED_I2CD_S_TX_CMD, ASPEED_I2C_CMD_REG);
+ } else if (bus->slave_state == ASPEED_I2C_SLAVE_WRITE_REQUESTED) {
+ bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED;
+ i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value);
+ } else if (bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED) {
+ i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &value);
+ } else if (bus->slave_state == ASPEED_I2C_SLAVE_STOP) {
+ i2c_slave_event(slave, I2C_SLAVE_STOP, &value);
+ }
+
+ if (status_ack != irq_status)
+ dev_err(bus->dev,
+ "irq handled != irq. expected %x, but was %x\n",
+ irq_status, status_ack);
+ aspeed_i2c_write(bus, status_ack, ASPEED_I2C_INTR_STS_REG);
+
+out:
+ spin_unlock(&bus->lock);
+ return irq_handled;
+}
+#endif
+
+static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
+{
+ const u32 errs = ASPEED_I2CD_INTR_ARBIT_LOSS |
+ ASPEED_I2CD_INTR_ABNORMAL |
+ ASPEED_I2CD_INTR_SCL_TIMEOUT |
+ ASPEED_I2CD_INTR_SDA_DL_TIMEOUT |
+ ASPEED_I2CD_INTR_TX_NAK;
+ u32 irq_status;
+
+ spin_lock(&bus->lock);
+ irq_status = aspeed_i2c_read(bus, ASPEED_I2C_INTR_STS_REG);
+ bus->cmd_err = irq_status & errs;
+
+ dev_dbg(bus->dev, "master irq status 0x%08x\n", irq_status);
+
+ /* No message to transfer. */
+ if (bus->cmd_err ||
+ (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) ||
+ (irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE)) {
+ complete(&bus->cmd_complete);
+ goto out;
+ } else if (!bus->msg || bus->msg_pos >= bus->msg->len)
+ goto out;
+
+ if ((bus->msg->flags & I2C_M_RD) &&
+ (irq_status & ASPEED_I2CD_INTR_RX_DONE)) {
+ bus->msg->buf[bus->msg_pos++] = aspeed_i2c_read(
+ bus, ASPEED_I2C_BYTE_BUF_REG) >> 8;
+ if (bus->msg_pos + 1 < bus->msg->len)
+ aspeed_i2c_write(bus, ASPEED_I2CD_M_RX_CMD,
+ ASPEED_I2C_CMD_REG);
+ else if (bus->msg_pos < bus->msg->len)
+ aspeed_i2c_write(bus, ASPEED_I2CD_M_RX_CMD |
+ ASPEED_I2CD_M_S_RX_CMD_LAST,
+ ASPEED_I2C_CMD_REG);
+ } else if (!(bus->msg->flags & I2C_M_RD) &&
+ (irq_status & ASPEED_I2CD_INTR_TX_ACK)) {
+ aspeed_i2c_write(bus, bus->msg->buf[bus->msg_pos++],
+ ASPEED_I2C_BYTE_BUF_REG);
+ aspeed_i2c_write(bus, ASPEED_I2CD_M_TX_CMD, ASPEED_I2C_CMD_REG);
+ }
+
+ /* Transmission complete: notify caller. */
+ if (bus->msg_pos >= bus->msg->len)
+ complete(&bus->cmd_complete);
+out:
+ aspeed_i2c_write(bus, irq_status, ASPEED_I2C_INTR_STS_REG);
+ spin_unlock(&bus->lock);
+ return true;
+}
+
+static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
+{
+ struct aspeed_i2c_bus *bus = dev_id;
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ if (aspeed_i2c_slave_irq(bus)) {
+ dev_dbg(bus->dev, "irq handled by slave.\n");
+ return IRQ_HANDLED;
+ }
+#endif
+ if (aspeed_i2c_master_irq(bus)) {
+ dev_dbg(bus->dev, "irq handled by master.\n");
+ return IRQ_HANDLED;
+ }
+ dev_err(bus->dev, "irq not handled properly!\n");
+ return IRQ_HANDLED;
+}
+
+static int aspeed_i2c_master_single_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msg)
+{
+ struct aspeed_i2c_bus *bus = adap->algo_data;
+ unsigned long flags;
+ u8 slave_addr;
+ u32 command = ASPEED_I2CD_M_START_CMD | ASPEED_I2CD_M_TX_CMD;
+ int ret = msg->len;
+ unsigned long time_left;
+
+ spin_lock_irqsave(&bus->lock, flags);
+ bus->msg = msg;
+ bus->msg_pos = 0;
+ slave_addr = msg->addr << 1;
+ if (msg->flags & I2C_M_RD) {
+ slave_addr |= 1;
+ command |= ASPEED_I2CD_M_RX_CMD;
+ if (msg->len == 1)
+ command |= ASPEED_I2CD_M_S_RX_CMD_LAST;
+ }
+ aspeed_i2c_write(bus, slave_addr, ASPEED_I2C_BYTE_BUF_REG);
+ aspeed_i2c_write(bus, command, ASPEED_I2C_CMD_REG);
+ reinit_completion(&bus->cmd_complete);
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ time_left = wait_for_completion_interruptible_timeout(
+ &bus->cmd_complete, bus->adap.timeout * HZ * msg->len);
+ if (time_left == 0)
+ return -ETIMEDOUT;
+
+ spin_lock_irqsave(&bus->lock, flags);
+ if (bus->cmd_err)
+ ret = -EIO;
+ bus->msg = NULL;
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ return ret;
+}
+
+static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct aspeed_i2c_bus *bus = adap->algo_data;
+ int ret;
+ int i;
+ unsigned long flags;
+ unsigned long time_left;
+
+ /* If bus is busy, attempt recovery. We assume a single master
+ * environment.
+ */
+ if (aspeed_i2c_read(bus, ASPEED_I2C_CMD_REG) &
+ ASPEED_I2CD_BUS_BUSY_STS) {
+ ret = aspeed_i2c_recover_bus(bus);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < num; i++) {
+ ret = aspeed_i2c_master_single_xfer(adap, &msgs[i]);
+ if (ret < 0)
+ break;
+ /* TODO: Support other forms of I2C protocol mangling. */
+ if (msgs[i].flags & I2C_M_STOP) {
+ spin_lock_irqsave(&bus->lock, flags);
+ aspeed_i2c_write(bus, ASPEED_I2CD_M_STOP_CMD,
+ ASPEED_I2C_CMD_REG);
+ reinit_completion(&bus->cmd_complete);
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ time_left = wait_for_completion_interruptible_timeout(
+ &bus->cmd_complete,
+ bus->adap.timeout * HZ);
+ if (time_left == 0)
+ return -ETIMEDOUT;
+ }
+ }
+
+ spin_lock_irqsave(&bus->lock, flags);
+ aspeed_i2c_write(bus, ASPEED_I2CD_M_STOP_CMD, ASPEED_I2C_CMD_REG);
+ reinit_completion(&bus->cmd_complete);
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ time_left = wait_for_completion_interruptible_timeout(
+ &bus->cmd_complete, bus->adap.timeout * HZ);
+ if (time_left == 0)
+ return -ETIMEDOUT;
+
+ /* If nothing went wrong, return number of messages transferred. */
+ if (ret < 0)
+ return ret;
+ else
+ return i;
+}
+
+static u32 aspeed_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+static int aspeed_i2c_reg_slave(struct i2c_client *client)
+{
+ struct aspeed_i2c_bus *bus;
+ unsigned long flags;
+ u32 addr_reg_val;
+ u32 func_ctrl_reg_val;
+
+ bus = client->adapter->algo_data;
+ spin_lock_irqsave(&bus->lock, flags);
+ if (bus->slave) {
+ spin_unlock_irqrestore(&bus->lock, flags);
+ return -EINVAL;
+ }
+
+ /* Set slave addr. */
+ addr_reg_val = aspeed_i2c_read(bus, ASPEED_I2C_DEV_ADDR_REG);
+ addr_reg_val &= ~ASPEED_I2CD_DEV_ADDR_MASK;
+ addr_reg_val |= client->addr & ASPEED_I2CD_DEV_ADDR_MASK;
+ aspeed_i2c_write(bus, addr_reg_val, ASPEED_I2C_DEV_ADDR_REG);
+
+ /* Switch from master mode to slave mode. */
+ func_ctrl_reg_val = aspeed_i2c_read(bus, ASPEED_I2C_FUN_CTRL_REG);
+ func_ctrl_reg_val &= ~ASPEED_I2CD_MASTER_EN;
+ func_ctrl_reg_val |= ASPEED_I2CD_SLAVE_EN;
+ aspeed_i2c_write(bus, func_ctrl_reg_val, ASPEED_I2C_FUN_CTRL_REG);
+
+ bus->slave = client;
+ bus->slave_state = ASPEED_I2C_SLAVE_STOP;
+ spin_unlock_irqrestore(&bus->lock, flags);
+ return 0;
+}
+
+static int aspeed_i2c_unreg_slave(struct i2c_client *client)
+{
+ struct aspeed_i2c_bus *bus = client->adapter->algo_data;
+ unsigned long flags;
+ u32 func_ctrl_reg_val;
+
+ spin_lock_irqsave(&bus->lock, flags);
+ if (!bus->slave) {
+ spin_unlock_irqrestore(&bus->lock, flags);
+ return -EINVAL;
+ }
+
+ /* Switch from slave mode to master mode. */
+ func_ctrl_reg_val = aspeed_i2c_read(bus, ASPEED_I2C_FUN_CTRL_REG);
+ func_ctrl_reg_val &= ~ASPEED_I2CD_SLAVE_EN;
+ func_ctrl_reg_val |= ASPEED_I2CD_MASTER_EN;
+ aspeed_i2c_write(bus, func_ctrl_reg_val, ASPEED_I2C_FUN_CTRL_REG);
+
+ bus->slave = NULL;
+ spin_unlock_irqrestore(&bus->lock, flags);
+ return 0;
+}
+#endif
+
+static const struct i2c_algorithm aspeed_i2c_algo = {
+ .master_xfer = aspeed_i2c_master_xfer,
+ .functionality = aspeed_i2c_functionality,
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ .reg_slave = aspeed_i2c_reg_slave,
+ .unreg_slave = aspeed_i2c_unreg_slave,
+#endif
+};
+
+static u32 aspeed_i2c_get_clk_reg_val(u32 divider_ratio)
+{
+ unsigned int inc = 0, div;
+ u32 scl_low, scl_high, data;
+
+ for (div = 0; divider_ratio >= 16; div++) {
+ inc |= (divider_ratio & 1);
+ divider_ratio >>= 1;
+ }
+ divider_ratio += inc;
+ scl_low = (divider_ratio >> 1) - 1;
+ scl_high = divider_ratio - scl_low - 2;
+ data = 0x77700300 | (scl_high << 16) | (scl_low << 12) | div;
+ return data;
+}
+
+static int aspeed_i2c_init_clk(struct aspeed_i2c_bus *bus,
+ struct platform_device *pdev)
+{
+ struct clk *pclk;
+ u32 clk_freq;
+ u32 divider_ratio;
+ int ret;
+
+ pclk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pclk)) {
+ dev_err(&pdev->dev, "clk_get failed\n");
+ return PTR_ERR(pclk);
+ }
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "clock-frequency", &clk_freq);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Could not read clock-frequency property\n");
+ clk_freq = 100000;
+ }
+ divider_ratio = clk_get_rate(pclk) / clk_freq;
+ /* We just need the clock rate, we don't actually use the clk object. */
+ devm_clk_put(&pdev->dev, pclk);
+
+ /* Set AC Timing */
+ if (clk_freq / 1000 > 400) {
+ aspeed_i2c_write(bus, aspeed_i2c_read(bus,
+ ASPEED_I2C_FUN_CTRL_REG) |
+ ASPEED_I2CD_M_HIGH_SPEED_EN |
+ ASPEED_I2CD_M_SDA_DRIVE_1T_EN |
+ ASPEED_I2CD_SDA_DRIVE_1T_EN,
+ ASPEED_I2C_FUN_CTRL_REG);
+
+ aspeed_i2c_write(bus, 0x3, ASPEED_I2C_AC_TIMING_REG2);
+ aspeed_i2c_write(bus, aspeed_i2c_get_clk_reg_val(divider_ratio),
+ ASPEED_I2C_AC_TIMING_REG1);
+ } else {
+ aspeed_i2c_write(bus, aspeed_i2c_get_clk_reg_val(divider_ratio),
+ ASPEED_I2C_AC_TIMING_REG1);
+ aspeed_i2c_write(bus, ASPEED_NO_TIMEOUT_CTRL,
+ ASPEED_I2C_AC_TIMING_REG2);
+ }
+
+ return 0;
+}
+
+static void noop(struct irq_data *data) { }
+
+static struct irq_chip aspeed_i2c_irqchip = {
+ .name = "ast-i2c",
+ .irq_unmask = noop,
+ .irq_mask = noop,
+};
+
+static int aspeed_i2c_probe_bus(struct platform_device *pdev)
+{
+ struct aspeed_i2c_bus *bus;
+ struct aspeed_i2c_controller *controller =
+ dev_get_drvdata(pdev->dev.parent);
+ struct resource *res;
+ int ret, irq;
+ u32 hwirq;
+
+ bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
+ if (!bus)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ bus->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(bus->base))
+ return PTR_ERR(bus->base);
+
+ bus->irq = platform_get_irq(pdev, 0);
+ if (bus->irq < 0)
+ return -ENXIO;
+ ret = of_property_read_u32(pdev->dev.of_node, "interrupts", &hwirq);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "no I2C 'interrupts' property\n");
+ return -ENXIO;
+ }
+ irq = irq_create_mapping(controller->irq_domain, hwirq);
+ irq_set_chip_data(irq, controller);
+ irq_set_chip_and_handler(irq, &aspeed_i2c_irqchip, handle_simple_irq);
+ ret = devm_request_irq(&pdev->dev, bus->irq, aspeed_i2c_bus_irq,
+ 0, dev_name(&pdev->dev), bus);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request interrupt\n");
+ return -ENXIO;
+ }
+
+ /* Initialize the I2C adapter */
+ spin_lock_init(&bus->lock);
+ init_completion(&bus->cmd_complete);
+ bus->adap.owner = THIS_MODULE;
+ bus->adap.retries = 0;
+ bus->adap.timeout = 5;
+ bus->adap.algo = &aspeed_i2c_algo;
+ bus->adap.algo_data = bus;
+ bus->adap.dev.parent = &pdev->dev;
+ bus->adap.dev.of_node = pdev->dev.of_node;
+ snprintf(bus->adap.name, sizeof(bus->adap.name), "Aspeed i2c");
+
+ bus->dev = &pdev->dev;
+
+ /* reset device: disable master & slave functions */
+ aspeed_i2c_write(bus, 0, ASPEED_I2C_FUN_CTRL_REG);
+
+ ret = aspeed_i2c_init_clk(bus, pdev);
+ if (ret < 0)
+ return ret;
+
+ /* Enable Master Mode */
+ aspeed_i2c_write(bus, aspeed_i2c_read(bus, ASPEED_I2C_FUN_CTRL_REG) |
+ ASPEED_I2CD_MASTER_EN |
+ ASPEED_I2CD_MULTI_MASTER_DIS, ASPEED_I2C_FUN_CTRL_REG);
+
+ /* Set interrupt generation of I2C controller */
+ aspeed_i2c_write(bus, ASPEED_I2CD_INTR_SDA_DL_TIMEOUT |
+ ASPEED_I2CD_INTR_BUS_RECOVER_DONE |
+ ASPEED_I2CD_INTR_SCL_TIMEOUT |
+ ASPEED_I2CD_INTR_ABNORMAL |
+ ASPEED_I2CD_INTR_NORMAL_STOP |
+ ASPEED_I2CD_INTR_ARBIT_LOSS |
+ ASPEED_I2CD_INTR_RX_DONE |
+ ASPEED_I2CD_INTR_TX_NAK |
+ ASPEED_I2CD_INTR_TX_ACK,
+ ASPEED_I2C_INTR_CTRL_REG);
+
+ ret = i2c_add_adapter(&bus->adap);
+ if (ret < 0)
+ return -ENXIO;
+
+ platform_set_drvdata(pdev, bus);
+
+ dev_info(bus->dev, "i2c bus %d registered, irq %d\n",
+ bus->adap.nr, bus->irq);
+
+ return 0;
+}
+
+static int aspeed_i2c_remove_bus(struct platform_device *pdev)
+{
+ struct aspeed_i2c_bus *bus = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&bus->adap);
+ return 0;
+}
+
+static const struct of_device_id aspeed_i2c_bus_of_table[] = {
+ { .compatible = "aspeed,ast2400-i2c-bus", },
+ { .compatible = "aspeed,ast2500-i2c-bus", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, aspeed_i2c_bus_of_table);
+
+static struct platform_driver aspeed_i2c_bus_driver = {
+ .probe = aspeed_i2c_probe_bus,
+ .remove = aspeed_i2c_remove_bus,
+ .driver = {
+ .name = "ast-i2c-bus",
+ .of_match_table = aspeed_i2c_bus_of_table,
+ },
+};
+
+static void aspeed_i2c_controller_irq(struct irq_desc *desc)
+{
+ struct aspeed_i2c_controller *c = irq_desc_get_handler_data(desc);
+ unsigned long p, status;
+ unsigned int bus_irq;
+
+ status = readl(c->base);
+ for_each_set_bit(p, &status, ASPEED_I2C_NUM_BUS) {
+ bus_irq = irq_find_mapping(c->irq_domain, p);
+ generic_handle_irq(bus_irq);
+ }
+}
+
+static int aspeed_i2c_probe_controller(struct platform_device *pdev)
+{
+ struct aspeed_i2c_controller *controller;
+ struct device_node *np;
+ struct resource *res;
+
+ controller = kzalloc(sizeof(*controller), GFP_KERNEL);
+ if (!controller)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ controller->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(controller->base))
+ return PTR_ERR(controller->base);
+
+ controller->irq = platform_get_irq(pdev, 0);
+ if (controller->irq < 0)
+ return -ENXIO;
+
+ controller->irq_domain = irq_domain_add_linear(pdev->dev.of_node,
+ ASPEED_I2C_NUM_BUS, &irq_domain_simple_ops, NULL);
+ if (!controller->irq_domain)
+ return -ENXIO;
+ controller->irq_domain->name = "ast-i2c-domain";
+
+ irq_set_chained_handler_and_data(controller->irq,
+ aspeed_i2c_controller_irq, controller);
+
+ controller->dev = &pdev->dev;
+
+ platform_set_drvdata(pdev, controller);
+
+ dev_info(controller->dev, "i2c controller registered, irq %d\n",
+ controller->irq);
+
+ for_each_child_of_node(pdev->dev.of_node, np) {
+ of_platform_device_create(np, NULL, &pdev->dev);
+ of_node_put(np);
+ }
+
+ return 0;
+}
+
+static int aspeed_i2c_remove_controller(struct platform_device *pdev)
+{
+ struct aspeed_i2c_controller *controller = platform_get_drvdata(pdev);
+
+ irq_domain_remove(controller->irq_domain);
+ return 0;
+}
+
+static const struct of_device_id aspeed_i2c_controller_of_table[] = {
+ { .compatible = "aspeed,ast2400-i2c-controller", },
+ { .compatible = "aspeed,ast2500-i2c-controller", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, aspeed_i2c_controller_of_table);
+
+static struct platform_driver aspeed_i2c_controller_driver = {
+ .probe = aspeed_i2c_probe_controller,
+ .remove = aspeed_i2c_remove_controller,
+ .driver = {
+ .name = "ast-i2c-controller",
+ .of_match_table = aspeed_i2c_controller_of_table,
+ },
+};
+
+static int __init aspeed_i2c_driver_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&aspeed_i2c_controller_driver);
+ if (ret < 0)
+ return ret;
+ return platform_driver_register(&aspeed_i2c_bus_driver);
+}
+module_init(aspeed_i2c_driver_init);
+
+static void __exit aspeed_i2c_driver_exit(void)
+{
+ platform_driver_unregister(&aspeed_i2c_bus_driver);
+ platform_driver_unregister(&aspeed_i2c_controller_driver);
+}
+module_exit(aspeed_i2c_driver_exit);
+
+MODULE_AUTHOR("Brendan Higgins <brendanhiggins@google.com>");
+MODULE_DESCRIPTION("Aspeed I2C Bus Driver");
+MODULE_LICENSE("GPL");
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [PATCH v4 2/2] i2c: aspeed: added documentation for Aspeed I2C driver
From: Brendan Higgins @ 2016-11-05 1:58 UTC (permalink / raw)
To: wsa, robh+dt, mark.rutland
Cc: linux-i2c, devicetree, joel, openbmc, Brendan Higgins
In-Reply-To: <1478311099-6771-1-git-send-email-brendanhiggins@google.com>
Added device tree binding documentation for Aspeed I2C controller and
busses.
Signed-off-by: Brendan Higgins <brendanhiggins@google.com>
---
Changes for v2:
- None
Changes for v3:
- Removed reference to "bus" device tree param
Changes for v4:
- None
---
.../devicetree/bindings/i2c/i2c-aspeed.txt | 61 ++++++++++++++++++++++
1 file changed, 61 insertions(+)
create mode 100644 Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
new file mode 100644
index 0000000..dd11a97
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
@@ -0,0 +1,61 @@
+Device tree configuration for the I2C controller and busses on the AST24XX
+and AST25XX SoCs.
+
+Controller:
+
+ Required Properties:
+ - #address-cells : should be 1
+ - #size-cells : should be 1
+ - #interrupt-cells : should be 1
+ - compatible : should be "aspeed,ast2400-i2c-controller"
+ or "aspeed,ast2500-i2c-controller"
+ - reg : address start and range of controller
+ - ranges : defines address offset and range for busses
+ - interrupts : interrupt number
+ - clocks : root clock of bus, should reference the APB
+ clock
+ - clock-ranges : specifies that child busses can inherit clocks
+ - interrupt-controller : denotes that the controller receives and fires
+ new interrupts for child busses
+
+Bus:
+
+ Required Properties:
+ - #address-cells : should be 1
+ - #size-cells : should be 0
+ - reg : address offset and range of bus
+ - compatible : should be "aspeed,ast2400-i2c-bus"
+ or "aspeed,ast2500-i2c-bus"
+ - interrupts : interrupt number
+
+ Optional Properties:
+ - clock-frequency : frequency of the bus clock in Hz
+ defaults to 100 kHz when not specified
+
+Example:
+
+i2c: i2c@1e78a000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <1>;
+
+ compatible = "aspeed,ast2400-i2c-controller";
+ reg = <0x1e78a000 0x40>;
+ ranges = <0 0x1e78a000 0x1000>;
+ interrupts = <12>;
+ clocks = <&clk_apb>;
+ clock-ranges;
+ interrupt-controller;
+
+ i2c0: i2c-bus@40 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x40 0x40>;
+ compatible = "aspeed,ast2400-i2c-bus";
+ clock-frequency = <100000>;
+ status = "disabled";
+ interrupts = <0>;
+ interrupt-parent = <&i2c>;
+ };
+};
+
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* Re: [PATCH v4 2/6] Add Advantech iManager GPIO driver
From: Linus Walleij @ 2016-11-05 8:29 UTC (permalink / raw)
To: Richard Vidal-Dorsch
Cc: Alexandre Courbot, Jean Delvare, Guenter Roeck, Wolfram Sang,
Lee Jones, Jingoo Han, Tomi Valkeinen, Wim Van Sebroeck,
linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org,
linux-hwmon, linux-i2c@vger.kernel.org,
linux-fbdev@vger.kernel.org, linux-watchdog, Krzysztof Kozlowski,
jo.sunga, weilun.huang, andrew.chou
In-Reply-To: <20161102083751.6335-3-richard.dorsch@gmail.com>
On Wed, Nov 2, 2016 at 9:37 AM, Richard Vidal-Dorsch
<richard.dorsch@gmail.com> wrote:
> Signed-off-by: Richard Vidal-Dorsch <richard.dorsch@gmail.com>
> +#include <linux/device.h>
> +#include <linux/gpio.h>
#include <linux/gpio/driver.h>
should be enough.
> +#include <linux/init.h>
> +#include <linux/mfd/imanager.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/platform_device.h>
> +
> +#define EC_GPIOF_DIR_OUT BIT(6)
> +#define EC_GPIOF_DIR_IN BIT(7)
> +
> +struct imanager_gpio_data {
> + struct imanager_device_data *imgr;
> + struct gpio_chip chip;
> +};
Maybe some kerneldoc for this. Not necessary though since its sort of
self-explanatory.
> +static int imanager_gpio_direction_in(struct gpio_chip *chip, uint offset)
> +{
> + struct imanager_gpio_data *data = gpiochip_get_data(chip);
> + struct imanager_device_data *imgr = data->imgr;
> + struct imanager_device_attribute *attr = imgr->ec.gpio.attr[offset];
> +
> + mutex_lock(&imgr->lock);
> + imanager_write8(&imgr->ec, EC_CMD_GPIO_DIR_WR, attr->did,
> + EC_GPIOF_DIR_IN);
> + mutex_unlock(&imgr->lock);
It kind of looks like it would be smarter if the imanager_write8() was
taking and releasing the lock so you don't have to do it everywhere.
> +static int imanager_gpio_get_direction(struct gpio_chip *chip, uint offset)
> +{
> + struct imanager_gpio_data *data = gpiochip_get_data(chip);
> + struct imanager_device_data *imgr = data->imgr;
> + struct imanager_device_attribute *attr = imgr->ec.gpio.attr[offset];
> + int ret;
> +
> + mutex_lock(&imgr->lock);
> + ret = imanager_read8(&imgr->ec, EC_CMD_GPIO_DIR_RD, attr->did);
> + mutex_unlock(&imgr->lock);
> +
> + return ret & EC_GPIOF_DIR_IN ? GPIOF_DIR_IN : GPIOF_DIR_OUT;
Don't use GPIOF* flags, those are for consumers. Just return 0/1.
> +static int imanager_gpio_get(struct gpio_chip *chip, uint offset)
> +{
> + struct imanager_gpio_data *data = gpiochip_get_data(chip);
> + struct imanager_device_data *imgr = data->imgr;
> + struct imanager_device_attribute *attr = imgr->ec.gpio.attr[offset];
> + int ret;
> +
> + mutex_lock(&imgr->lock);
> + ret = imanager_read8(&imgr->ec, EC_CMD_HWP_RD, attr->did);
> + mutex_unlock(&imgr->lock);
> +
> + return ret;
> +}
Can the read function return an error code? In that case it should be checked
everywhere.
Also be sure to clamp ret like this:
return !!ret;
Apart from this it looks good.
Yours,
Linus Walleij
^ permalink raw reply
* [PULL REQUEST] i2c for 4.9
From: Wolfram Sang @ 2016-11-05 22:16 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-i2c, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 755 bytes --]
Linus,
here is a bugfix for the I2C core fixing a (rare) race condition.
Please pull.
Thanks,
Wolfram
The following changes since commit a909d3e636995ba7c349e2ca5dbb528154d4ac30:
Linux 4.9-rc3 (2016-10-29 13:52:02 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git i2c/for-current
for you to fetch changes up to 147b36d5b70c083cc76770c47d60b347e8eaf231:
i2c: core: fix NULL pointer dereference under race condition (2016-11-04 20:36:58 +0100)
----------------------------------------------------------------
Vladimir Zapolskiy (1):
i2c: core: fix NULL pointer dereference under race condition
drivers/i2c/i2c-core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* [PATCH v4 01/14] ARM: dts: lager: rename and reindex i2cexio
From: Wolfram Sang @ 2016-11-06 20:20 UTC (permalink / raw)
To: linux-renesas-soc, Simon Horman; +Cc: linux-i2c, Simon Horman, Wolfram Sang
In-Reply-To: <20161106202032.5227-1-wsa+renesas@sang-engineering.com>
From: Simon Horman <horms+renesas@verge.net.au>
The rename from i2cexio to i2cexio0 is in in preparation for adding
i2cexio1 which will use the dmuxer for IIC1/I2C1.
The reindexing from i2c8 to i2c10 is to allow space for grouping of
additional GPIO buses to added by follow-up patches to support demuxing of
other i2c buses.
Also note that fallback to GPIO is not provided by the hardware for IIC0/I2C0.
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
[wsa: rebased, fixed alias and removed typo in commit message]
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---
arch/arm/boot/dts/r8a7790-lager.dts | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts
index e42748a5fe10ac..dafa49f837118e 100644
--- a/arch/arm/boot/dts/r8a7790-lager.dts
+++ b/arch/arm/boot/dts/r8a7790-lager.dts
@@ -50,7 +50,7 @@
aliases {
serial0 = &scif0;
serial1 = &scifa1;
- i2c8 = "i2cexio";
+ i2c10 = &i2cexio0;
};
chosen {
@@ -273,11 +273,13 @@
* bus with IIC3 on pins 110 (SCL) + 112 (SDA), select I2C0 at runtime, and
* instantiate the slave device at runtime according to the documentation.
* You can then communicate with the slave via IIC3.
+ *
+ * IIC0/I2C0 does not appear to support fallback to GPIO.
*/
- i2cexio: i2c-8 {
+ i2cexio0: i2c-10 {
compatible = "i2c-demux-pinctrl";
i2c-parent = <&iic0>, <&i2c0>;
- i2c-bus-name = "i2c-exio";
+ i2c-bus-name = "i2c-exio0";
#address-cells = <1>;
#size-cells = <0>;
};
@@ -597,12 +599,12 @@
&i2c0 {
pinctrl-0 = <&i2c0_pins>;
- pinctrl-names = "i2c-exio";
+ pinctrl-names = "i2c-exio0";
};
&iic0 {
pinctrl-0 = <&iic0_pins>;
- pinctrl-names = "i2c-exio";
+ pinctrl-names = "i2c-exio0";
};
&iic1 {
--
2.9.3
^ permalink raw reply related
* [PATCH v4 03/14] ARM: dts: lager: use demuxer for IIC2/I2C2
From: Wolfram Sang @ 2016-11-06 20:20 UTC (permalink / raw)
To: linux-renesas-soc, Simon Horman; +Cc: linux-i2c, Simon Horman, Wolfram Sang
In-Reply-To: <20161106202032.5227-1-wsa+renesas@sang-engineering.com>
From: Simon Horman <horms+renesas@verge.net.au>
Create a separate bus for HDMI related I2C slaves.
Based on work by Wolfram Sang.
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
[wsa: rebased, removed typo in comment and fixed aliases]
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---
arch/arm/boot/dts/r8a7790-lager.dts | 196 +++++++++++++++++++++---------------
1 file changed, 116 insertions(+), 80 deletions(-)
diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts
index bd512c86e85222..2659bf854b3bd5 100644
--- a/arch/arm/boot/dts/r8a7790-lager.dts
+++ b/arch/arm/boot/dts/r8a7790-lager.dts
@@ -51,8 +51,10 @@
serial0 = &scif0;
serial1 = &scifa1;
i2c8 = &gpioi2c1;
+ i2c9 = &gpioi2c2;
i2c10 = &i2cexio0;
i2c11 = &i2cexio1;
+ i2c12 = &i2chdmi;
};
chosen {
@@ -278,6 +280,17 @@
i2c-gpio,delay-us = <5>;
};
+ gpioi2c2: i2c-9 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "i2c-gpio";
+ status = "disabled";
+ gpios = <&gpio5 6 GPIO_ACTIVE_HIGH /* sda */
+ &gpio5 5 GPIO_ACTIVE_HIGH /* scl */
+ >;
+ i2c-gpio,delay-us = <5>;
+ };
+
/*
* IIC0/I2C0 is routed to EXIO connector A, pins 114 (SCL) + 116 (SDA) only.
* We use the I2C demuxer, so the desired IP core can be selected at runtime
@@ -309,6 +322,96 @@
#address-cells = <1>;
#size-cells = <0>;
};
+
+ /*
+ * IIC2 and I2C2 may be switched using pinmux.
+ * A fallback to GPIO is also provided.
+ */
+ i2chdmi: i2c-12 {
+ compatible = "i2c-demux-pinctrl";
+ i2c-parent = <&iic2>, <&i2c2>, <&gpioi2c2>;
+ i2c-bus-name = "i2c-hdmi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ak4643: codec@12 {
+ compatible = "asahi-kasei,ak4643";
+ #sound-dai-cells = <0>;
+ reg = <0x12>;
+ };
+
+ composite-in@20 {
+ compatible = "adi,adv7180";
+ reg = <0x20>;
+ remote = <&vin1>;
+
+ port {
+ adv7180: endpoint {
+ bus-width = <8>;
+ remote-endpoint = <&vin1ep0>;
+ };
+ };
+ };
+
+ hdmi@39 {
+ compatible = "adi,adv7511w";
+ reg = <0x39>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <15 IRQ_TYPE_LEVEL_LOW>;
+
+ adi,input-depth = <8>;
+ adi,input-colorspace = "rgb";
+ adi,input-clock = "1x";
+ adi,input-style = <1>;
+ adi,input-justification = "evenly";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ adv7511_in: endpoint {
+ remote-endpoint = <&du_out_lvds0>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ adv7511_out: endpoint {
+ remote-endpoint = <&hdmi_con_out>;
+ };
+ };
+ };
+ };
+
+ hdmi-in@4c {
+ compatible = "adi,adv7612";
+ reg = <0x4c>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <20 IRQ_TYPE_LEVEL_LOW>;
+ default-input = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ adv7612_in: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ adv7612_out: endpoint {
+ remote-endpoint = <&vin0ep2>;
+ };
+ };
+ };
+ };
+ };
};
&du {
@@ -441,6 +544,11 @@
function = "iic1";
};
+ i2c2_pins: i2c2 {
+ groups = "i2c2";
+ function = "i2c2";
+ };
+
iic2_pins: iic2 {
groups = "iic2";
function = "iic2";
@@ -648,90 +756,18 @@
pinctrl-names = "i2c-exio1";
};
-&iic2 {
- status = "okay";
- pinctrl-0 = <&iic2_pins>;
- pinctrl-names = "default";
+&i2c2 {
+ pinctrl-0 = <&i2c2_pins>;
+ pinctrl-names = "i2c-hdmi";
clock-frequency = <100000>;
+};
- ak4643: codec@12 {
- compatible = "asahi-kasei,ak4643";
- #sound-dai-cells = <0>;
- reg = <0x12>;
- };
-
- composite-in@20 {
- compatible = "adi,adv7180";
- reg = <0x20>;
- remote = <&vin1>;
-
- port {
- adv7180: endpoint {
- bus-width = <8>;
- remote-endpoint = <&vin1ep0>;
- };
- };
- };
-
- hdmi@39 {
- compatible = "adi,adv7511w";
- reg = <0x39>;
- interrupt-parent = <&gpio1>;
- interrupts = <15 IRQ_TYPE_LEVEL_LOW>;
-
- adi,input-depth = <8>;
- adi,input-colorspace = "rgb";
- adi,input-clock = "1x";
- adi,input-style = <1>;
- adi,input-justification = "evenly";
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@0 {
- reg = <0>;
- adv7511_in: endpoint {
- remote-endpoint = <&du_out_lvds0>;
- };
- };
-
- port@1 {
- reg = <1>;
- adv7511_out: endpoint {
- remote-endpoint = <&hdmi_con_out>;
- };
- };
- };
- };
-
- hdmi-in@4c {
- compatible = "adi,adv7612";
- reg = <0x4c>;
- interrupt-parent = <&gpio1>;
- interrupts = <20 IRQ_TYPE_LEVEL_LOW>;
- default-input = <0>;
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@0 {
- reg = <0>;
- adv7612_in: endpoint {
- remote-endpoint = <&hdmi_con_in>;
- };
- };
+&iic2 {
+ pinctrl-0 = <&iic2_pins>;
+ pinctrl-names = "i2c-hdmi";
- port@2 {
- reg = <2>;
- adv7612_out: endpoint {
- remote-endpoint = <&vin0ep2>;
- };
- };
- };
- };
+ clock-frequency = <100000>;
};
&iic3 {
--
2.9.3
^ permalink raw reply related
* [PATCH v4 06/14] ARM: dts: koelsch: use demuxer for I2C2
From: Wolfram Sang @ 2016-11-06 20:20 UTC (permalink / raw)
To: linux-renesas-soc, Simon Horman; +Cc: linux-i2c, Simon Horman, Wolfram Sang
In-Reply-To: <20161106202032.5227-1-wsa+renesas@sang-engineering.com>
From: Simon Horman <horms+renesas@verge.net.au>
Create a separate bus for HDMI related I2C2 and provide fallback to GPIO.
Based on work for the r8a7790/lager by Wolfram Sang.
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
[wsa: rebased and fixed aliases]
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---
arch/arm/boot/dts/r8a7791-koelsch.dts | 195 +++++++++++++++++++---------------
1 file changed, 109 insertions(+), 86 deletions(-)
diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts
index 5405d337d74486..8d653920957a4b 100644
--- a/arch/arm/boot/dts/r8a7791-koelsch.dts
+++ b/arch/arm/boot/dts/r8a7791-koelsch.dts
@@ -51,7 +51,9 @@
serial0 = &scif0;
serial1 = &scif1;
i2c9 = &gpioi2c1;
+ i2c10 = &gpioi2c2;
i2c12 = &i2cexio1;
+ i2c13 = &i2chdmi;
};
chosen {
@@ -312,6 +314,17 @@
i2c-gpio,delay-us = <5>;
};
+ gpioi2c2: i2c-10 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "i2c-gpio";
+ status = "disabled";
+ gpios = <&gpio2 7 GPIO_ACTIVE_HIGH /* sda */
+ &gpio2 6 GPIO_ACTIVE_HIGH /* scl */
+ >;
+ i2c-gpio,delay-us = <5>;
+ };
+
/*
* I2C1 is routed to EXIO connector B, pins 64 (SCL) + 66 (SDA).
* A fallback to GPIO is provided.
@@ -323,6 +336,101 @@
#address-cells = <1>;
#size-cells = <0>;
};
+
+ /*
+ * A fallback to GPIO is provided for I2C2.
+ */
+ i2chdmi: i2c-13 {
+ compatible = "i2c-demux-pinctrl";
+ i2c-parent = <&i2c2>, <&gpioi2c2>;
+ i2c-bus-name = "i2c-hdmi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ak4643: codec@12 {
+ compatible = "asahi-kasei,ak4643";
+ #sound-dai-cells = <0>;
+ reg = <0x12>;
+ };
+
+ composite-in@20 {
+ compatible = "adi,adv7180";
+ reg = <0x20>;
+ remote = <&vin1>;
+
+ port {
+ adv7180: endpoint {
+ bus-width = <8>;
+ remote-endpoint = <&vin1ep>;
+ };
+ };
+ };
+
+ hdmi@39 {
+ compatible = "adi,adv7511w";
+ reg = <0x39>;
+ interrupt-parent = <&gpio3>;
+ interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
+
+ adi,input-depth = <8>;
+ adi,input-colorspace = "rgb";
+ adi,input-clock = "1x";
+ adi,input-style = <1>;
+ adi,input-justification = "evenly";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ adv7511_in: endpoint {
+ remote-endpoint = <&du_out_rgb>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ adv7511_out: endpoint {
+ remote-endpoint = <&hdmi_con_out>;
+ };
+ };
+ };
+ };
+
+ hdmi-in@4c {
+ compatible = "adi,adv7612";
+ reg = <0x4c>;
+ interrupt-parent = <&gpio4>;
+ interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+ default-input = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ adv7612_in: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ adv7612_out: endpoint {
+ remote-endpoint = <&vin0ep2>;
+ };
+ };
+ };
+ };
+
+ eeprom@50 {
+ compatible = "renesas,24c02";
+ reg = <0x50>;
+ pagesize = <16>;
+ };
+ };
};
&du {
@@ -619,94 +727,9 @@
&i2c2 {
pinctrl-0 = <&i2c2_pins>;
- pinctrl-names = "default";
+ pinctrl-names = "i2c-hdmi";
- status = "okay";
clock-frequency = <100000>;
-
- ak4643: codec@12 {
- compatible = "asahi-kasei,ak4643";
- #sound-dai-cells = <0>;
- reg = <0x12>;
- };
-
- composite-in@20 {
- compatible = "adi,adv7180";
- reg = <0x20>;
- remote = <&vin1>;
-
- port {
- adv7180: endpoint {
- bus-width = <8>;
- remote-endpoint = <&vin1ep>;
- };
- };
- };
-
- hdmi@39 {
- compatible = "adi,adv7511w";
- reg = <0x39>;
- interrupt-parent = <&gpio3>;
- interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
-
- adi,input-depth = <8>;
- adi,input-colorspace = "rgb";
- adi,input-clock = "1x";
- adi,input-style = <1>;
- adi,input-justification = "evenly";
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@0 {
- reg = <0>;
- adv7511_in: endpoint {
- remote-endpoint = <&du_out_rgb>;
- };
- };
-
- port@1 {
- reg = <1>;
- adv7511_out: endpoint {
- remote-endpoint = <&hdmi_con_out>;
- };
- };
- };
- };
-
- hdmi-in@4c {
- compatible = "adi,adv7612";
- reg = <0x4c>;
- interrupt-parent = <&gpio4>;
- interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
- default-input = <0>;
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@0 {
- reg = <0>;
- adv7612_in: endpoint {
- remote-endpoint = <&hdmi_con_in>;
- };
- };
-
- port@2 {
- reg = <2>;
- adv7612_out: endpoint {
- remote-endpoint = <&vin0ep2>;
- };
- };
- };
- };
-
- eeprom@50 {
- compatible = "renesas,24c02";
- reg = <0x50>;
- pagesize = <16>;
- };
};
&i2c6 {
--
2.9.3
^ permalink raw reply related
* [PATCH v4 07/14] ARM: dts: koelsch: use demuxer for I2C4
From: Wolfram Sang @ 2016-11-06 20:20 UTC (permalink / raw)
To: linux-renesas-soc, Simon Horman; +Cc: linux-i2c, Simon Horman, Wolfram Sang
In-Reply-To: <20161106202032.5227-1-wsa+renesas@sang-engineering.com>
From: Simon Horman <horms+renesas@verge.net.au>
Make it possible to fallback to GPIO for I2C4 on the EXIO-E connector.
This is based on reference work for the I2C0 core of the lager/r8a7790
by Wolfram Sang.
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
[wsa: rebased and fixed aliases]
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---
arch/arm/boot/dts/r8a7791-koelsch.dts | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts
index 8d653920957a4b..442d1512a8fa9c 100644
--- a/arch/arm/boot/dts/r8a7791-koelsch.dts
+++ b/arch/arm/boot/dts/r8a7791-koelsch.dts
@@ -52,8 +52,10 @@
serial1 = &scif1;
i2c9 = &gpioi2c1;
i2c10 = &gpioi2c2;
+ i2c11 = &gpioi2c4;
i2c12 = &i2cexio1;
i2c13 = &i2chdmi;
+ i2c14 = &i2cexio4;
};
chosen {
@@ -325,6 +327,17 @@
i2c-gpio,delay-us = <5>;
};
+ gpioi2c4: i2c-11 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "i2c-gpio";
+ status = "disabled";
+ gpios = <&gpio7 14 GPIO_ACTIVE_HIGH /* sda */
+ &gpio7 13 GPIO_ACTIVE_HIGH /* scl */
+ >;
+ i2c-gpio,delay-us = <5>;
+ };
+
/*
* I2C1 is routed to EXIO connector B, pins 64 (SCL) + 66 (SDA).
* A fallback to GPIO is provided.
@@ -431,6 +444,18 @@
pagesize = <16>;
};
};
+
+ /*
+ * I2C4 is routed to EXIO connector E, pins 37 (SCL) + 39 (SDA).
+ * A fallback to GPIO is provided.
+ */
+ i2cexio4: i2c-14 {
+ compatible = "i2c-demux-pinctrl";
+ i2c-parent = <&i2c4>, <&gpioi2c4>;
+ i2c-bus-name = "i2c-exio4";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
};
&du {
@@ -476,6 +501,11 @@
function = "i2c2";
};
+ i2c4_pins: i2c4 {
+ groups = "i2c4";
+ function = "i2c4";
+ };
+
du_pins: du {
groups = "du_rgb888", "du_sync", "du_disp", "du_clk_out_0";
function = "du";
@@ -732,6 +762,11 @@
clock-frequency = <100000>;
};
+&i2c4 {
+ pinctrl-0 = <&i2c4_pins>;
+ pinctrl-names = "i2c-exio4";
+};
+
&i2c6 {
status = "okay";
clock-frequency = <100000>;
--
2.9.3
^ permalink raw reply related
* [PATCH v4 09/14] ARM: dts: gose: use demuxer for I2C2
From: Wolfram Sang @ 2016-11-06 20:20 UTC (permalink / raw)
To: linux-renesas-soc, Simon Horman; +Cc: linux-i2c, Simon Horman, Wolfram Sang
In-Reply-To: <20161106202032.5227-1-wsa+renesas@sang-engineering.com>
From: Simon Horman <horms+renesas@verge.net.au>
Create a separate bus for HDMI related I2C2 and provide fallback to GPIO.
Based on work for the r8a7790/lager by Wolfram Sang.
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
[wsa: rebased, corrected board name in subject, and fixed aliases]
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---
arch/arm/boot/dts/r8a7793-gose.dts | 170 +++++++++++++++++++++----------------
1 file changed, 97 insertions(+), 73 deletions(-)
diff --git a/arch/arm/boot/dts/r8a7793-gose.dts b/arch/arm/boot/dts/r8a7793-gose.dts
index 6329d9d2e8a3e3..df07dc252537fe 100644
--- a/arch/arm/boot/dts/r8a7793-gose.dts
+++ b/arch/arm/boot/dts/r8a7793-gose.dts
@@ -48,6 +48,8 @@
aliases {
serial0 = &scif0;
serial1 = &scif1;
+ i2c9 = &gpioi2c2;
+ i2c11 = &i2chdmi;
};
chosen {
@@ -275,6 +277,100 @@
#clock-cells = <0>;
clock-frequency = <148500000>;
};
+
+ gpioi2c2: i2c-9 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "i2c-gpio";
+ status = "disabled";
+ gpios = <&gpio2 7 GPIO_ACTIVE_HIGH /* sda */
+ &gpio2 6 GPIO_ACTIVE_HIGH /* scl */
+ >;
+ i2c-gpio,delay-us = <5>;
+ };
+
+ /*
+ * A fallback to GPIO is provided for I2C2.
+ */
+ i2chdmi: i2c-11 {
+ compatible = "i2c-demux-pinctrl";
+ i2c-parent = <&i2c2>, <&gpioi2c2>;
+ i2c-bus-name = "i2c-hdmi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ak4643: codec@12 {
+ compatible = "asahi-kasei,ak4643";
+ #sound-dai-cells = <0>;
+ reg = <0x12>;
+ };
+
+ composite-in@20 {
+ compatible = "adi,adv7180";
+ reg = <0x20>;
+ remote = <&vin1>;
+
+ port {
+ adv7180: endpoint {
+ bus-width = <8>;
+ remote-endpoint = <&vin1ep>;
+ };
+ };
+ };
+
+ hdmi@39 {
+ compatible = "adi,adv7511w";
+ reg = <0x39>;
+ interrupt-parent = <&gpio3>;
+ interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
+
+ adi,input-depth = <8>;
+ adi,input-colorspace = "rgb";
+ adi,input-clock = "1x";
+ adi,input-style = <1>;
+ adi,input-justification = "evenly";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ adv7511_in: endpoint {
+ remote-endpoint = <&du_out_rgb>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ adv7511_out: endpoint {
+ remote-endpoint = <&hdmi_con>;
+ };
+ };
+ };
+ };
+
+ hdmi-in@4c {
+ compatible = "adi,adv7612";
+ reg = <0x4c>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <20 IRQ_TYPE_LEVEL_LOW>;
+ remote = <&vin0>;
+ default-input = <0>;
+
+ port {
+ adv7612: endpoint {
+ remote-endpoint = <&vin0ep>;
+ };
+ };
+ };
+
+ eeprom@50 {
+ compatible = "renesas,r1ex24002", "atmel,24c02";
+ reg = <0x50>;
+ pagesize = <16>;
+ };
+ };
};
&du {
@@ -498,82 +594,10 @@
&i2c2 {
pinctrl-0 = <&i2c2_pins>;
- pinctrl-names = "default";
+ pinctrl-names = "i2c-hdmi";
status = "okay";
clock-frequency = <100000>;
-
- ak4643: codec@12 {
- compatible = "asahi-kasei,ak4643";
- #sound-dai-cells = <0>;
- reg = <0x12>;
- };
-
- composite-in@20 {
- compatible = "adi,adv7180";
- reg = <0x20>;
- remote = <&vin1>;
-
- port {
- adv7180: endpoint {
- bus-width = <8>;
- remote-endpoint = <&vin1ep>;
- };
- };
- };
-
- hdmi@39 {
- compatible = "adi,adv7511w";
- reg = <0x39>;
- interrupt-parent = <&gpio3>;
- interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
-
- adi,input-depth = <8>;
- adi,input-colorspace = "rgb";
- adi,input-clock = "1x";
- adi,input-style = <1>;
- adi,input-justification = "evenly";
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@0 {
- reg = <0>;
- adv7511_in: endpoint {
- remote-endpoint = <&du_out_rgb>;
- };
- };
-
- port@1 {
- reg = <1>;
- adv7511_out: endpoint {
- remote-endpoint = <&hdmi_con>;
- };
- };
- };
- };
-
- hdmi-in@4c {
- compatible = "adi,adv7612";
- reg = <0x4c>;
- interrupt-parent = <&gpio1>;
- interrupts = <20 IRQ_TYPE_LEVEL_LOW>;
- remote = <&vin0>;
- default-input = <0>;
-
- port {
- adv7612: endpoint {
- remote-endpoint = <&vin0ep>;
- };
- };
- };
-
- eeprom@50 {
- compatible = "renesas,r1ex24002", "atmel,24c02";
- reg = <0x50>;
- pagesize = <16>;
- };
};
&rcar_sound {
--
2.9.3
^ permalink raw reply related
* [PATCH v4 10/14] ARM: dts: gose: use demuxer for I2C4
From: Wolfram Sang @ 2016-11-06 20:20 UTC (permalink / raw)
To: linux-renesas-soc, Simon Horman; +Cc: linux-i2c, Simon Horman, Wolfram Sang
In-Reply-To: <20161106202032.5227-1-wsa+renesas@sang-engineering.com>
From: Simon Horman <horms+renesas@verge.net.au>
Make it possible to fallback to GPIO for I2C4 on the EXIO-E connector.
This is based on reference work for the I2C0 core of the lager/r8a7790
by Wolfram Sang.
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
[wsa: rebased, corrected board name in subject, and fixed aliases]
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---
arch/arm/boot/dts/r8a7793-gose.dts | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/arch/arm/boot/dts/r8a7793-gose.dts b/arch/arm/boot/dts/r8a7793-gose.dts
index df07dc252537fe..d22b9f969eaba8 100644
--- a/arch/arm/boot/dts/r8a7793-gose.dts
+++ b/arch/arm/boot/dts/r8a7793-gose.dts
@@ -49,7 +49,9 @@
serial0 = &scif0;
serial1 = &scif1;
i2c9 = &gpioi2c2;
+ i2c10 = &gpioi2c4;
i2c11 = &i2chdmi;
+ i2c12 = &i2cexio4;
};
chosen {
@@ -289,6 +291,17 @@
i2c-gpio,delay-us = <5>;
};
+ gpioi2c4: i2c-10 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "i2c-gpio";
+ status = "disabled";
+ gpios = <&gpio7 14 GPIO_ACTIVE_HIGH /* sda */
+ &gpio7 13 GPIO_ACTIVE_HIGH /* scl */
+ >;
+ i2c-gpio,delay-us = <5>;
+ };
+
/*
* A fallback to GPIO is provided for I2C2.
*/
@@ -371,6 +384,18 @@
pagesize = <16>;
};
};
+
+ /*
+ * I2C4 is routed to EXIO connector E, pins 37 (SCL) + 39 (SDA).
+ * A fallback to GPIO is provided.
+ */
+ i2cexio4: i2c-12 {
+ compatible = "i2c-demux-pinctrl";
+ i2c-parent = <&i2c4>, <&gpioi2c4>;
+ i2c-bus-name = "i2c-exio4";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
};
&du {
@@ -411,6 +436,11 @@
function = "i2c2";
};
+ i2c4_pins: i2c4 {
+ groups = "i2c4";
+ function = "i2c4";
+ };
+
du_pins: du {
groups = "du_rgb888", "du_sync", "du_disp", "du_clk_out_0";
function = "du";
@@ -600,6 +630,11 @@
clock-frequency = <100000>;
};
+&i2c4 {
+ pinctrl-0 = <&i2c4_pins>;
+ pinctrl-names = "i2c-exio4";
+};
+
&rcar_sound {
pinctrl-0 = <&sound_pins &sound_clk_pins>;
pinctrl-names = "default";
--
2.9.3
^ permalink raw reply related
* [PATCH v4 11/14] ARM: dts: alt: use demuxer for I2C1
From: Wolfram Sang @ 2016-11-06 20:20 UTC (permalink / raw)
To: linux-renesas-soc, Simon Horman; +Cc: linux-i2c, Simon Horman, Wolfram Sang
In-Reply-To: <20161106202032.5227-1-wsa+renesas@sang-engineering.com>
From: Simon Horman <horms+renesas@verge.net.au>
Create a separate bus for HDMI related I2C1 and provide fallback to GPIO.
Based on work for the r8a7790/lager by Wolfram Sang.
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
[wsa: rebased and fixed aliases]
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---
arch/arm/boot/dts/r8a7794-alt.dts | 53 ++++++++++++++++++++++++++++-----------
1 file changed, 38 insertions(+), 15 deletions(-)
diff --git a/arch/arm/boot/dts/r8a7794-alt.dts b/arch/arm/boot/dts/r8a7794-alt.dts
index ccb80d66076f3d..81368d11e4d3be 100644
--- a/arch/arm/boot/dts/r8a7794-alt.dts
+++ b/arch/arm/boot/dts/r8a7794-alt.dts
@@ -18,6 +18,8 @@
aliases {
serial0 = &scif2;
+ i2c9 = &gpioi2c1;
+ i2c11 = &i2chdmi;
};
chosen {
@@ -135,6 +137,41 @@
#clock-cells = <0>;
clock-frequency = <148500000>;
};
+
+ gpioi2c1: i2c-9 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "i2c-gpio";
+ status = "disabled";
+ gpios = <&gpio4 1 GPIO_ACTIVE_HIGH /* sda */
+ &gpio4 0 GPIO_ACTIVE_HIGH /* scl */
+ >;
+ i2c-gpio,delay-us = <5>;
+ };
+
+ /*
+ * A fallback to GPIO is provided for I2C1.
+ */
+ i2chdmi: i2c-11 {
+ compatible = "i2c-demux-pinctrl";
+ i2c-parent = <&i2c1>, <&gpioi2c1>;
+ i2c-bus-name = "i2c-hdmi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ composite-in@20 {
+ compatible = "adi,adv7180";
+ reg = <0x20>;
+ remote = <&vin0>;
+
+ port {
+ adv7180: endpoint {
+ bus-width = <8>;
+ remote-endpoint = <&vin0ep>;
+ };
+ };
+ };
+ };
};
&du {
@@ -296,23 +333,9 @@
&i2c1 {
pinctrl-0 = <&i2c1_pins>;
- pinctrl-names = "default";
+ pinctrl-names = "i2c-hdmi";
- status = "okay";
clock-frequency = <400000>;
-
- composite-in@20 {
- compatible = "adi,adv7180";
- reg = <0x20>;
- remote = <&vin0>;
-
- port {
- adv7180: endpoint {
- bus-width = <8>;
- remote-endpoint = <&vin0ep>;
- };
- };
- };
};
&vin0 {
--
2.9.3
^ permalink raw reply related
* [PATCH v4 12/14] ARM: dts: alt: use demuxer for I2C4
From: Wolfram Sang @ 2016-11-06 20:20 UTC (permalink / raw)
To: linux-renesas-soc, Simon Horman; +Cc: linux-i2c, Simon Horman, Wolfram Sang
In-Reply-To: <20161106202032.5227-1-wsa+renesas@sang-engineering.com>
From: Simon Horman <horms+renesas@verge.net.au>
Make it possible to fallback to GPIO for I2C4 on the EXIO-B connector.
This is based on reference work for the I2C0 core of the lager/r8a7790
by Wolfram Sang.
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
[wsa: rebased and fixed aliases]
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---
arch/arm/boot/dts/r8a7794-alt.dts | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/arch/arm/boot/dts/r8a7794-alt.dts b/arch/arm/boot/dts/r8a7794-alt.dts
index 81368d11e4d3be..bd5b2d2c568c52 100644
--- a/arch/arm/boot/dts/r8a7794-alt.dts
+++ b/arch/arm/boot/dts/r8a7794-alt.dts
@@ -19,7 +19,9 @@
aliases {
serial0 = &scif2;
i2c9 = &gpioi2c1;
+ i2c10 = &gpioi2c4;
i2c11 = &i2chdmi;
+ i2c12 = &i2cexio4;
};
chosen {
@@ -149,6 +151,17 @@
i2c-gpio,delay-us = <5>;
};
+ gpioi2c4: i2c-10 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "i2c-gpio";
+ status = "disabled";
+ gpios = <&gpio4 9 GPIO_ACTIVE_HIGH /* sda */
+ &gpio4 8 GPIO_ACTIVE_HIGH /* scl */
+ >;
+ i2c-gpio,delay-us = <5>;
+ };
+
/*
* A fallback to GPIO is provided for I2C1.
*/
@@ -172,6 +185,18 @@
};
};
};
+
+ /*
+ * I2C4 is routed to EXIO connector B, pins 73 (SCL) + 74 (SDA).
+ * A fallback to GPIO is provided.
+ */
+ i2cexio4: i2c-14 {
+ compatible = "i2c-demux-pinctrl";
+ i2c-parent = <&i2c4>, <&gpioi2c4>;
+ i2c-bus-name = "i2c-exio4";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
};
&du {
@@ -231,6 +256,11 @@
function = "i2c1";
};
+ i2c4_pins: i2c4 {
+ groups = "i2c4";
+ function = "i2c4";
+ };
+
vin0_pins: vin0 {
groups = "vin0_data8", "vin0_clk";
function = "vin0";
@@ -338,6 +368,11 @@
clock-frequency = <400000>;
};
+&i2c4 {
+ pinctrl-0 = <&i2c4_pins>;
+ pinctrl-names = "i2c-exio4";
+};
+
&vin0 {
status = "okay";
pinctrl-0 = <&vin0_pins>;
--
2.9.3
^ permalink raw reply related
* [PATCH v4 13/14] ARM: dts: silk: use demuxer for I2C1
From: Wolfram Sang @ 2016-11-06 20:20 UTC (permalink / raw)
To: linux-renesas-soc, Simon Horman; +Cc: linux-i2c, Simon Horman, Wolfram Sang
In-Reply-To: <20161106202032.5227-1-wsa+renesas@sang-engineering.com>
From: Simon Horman <horms+renesas@verge.net.au>
Create a separate bus for HDMI related I2C1 and provide fallback to GPIO.
Based on work for the r8a7790/lager by Wolfram Sang.
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
[wsa: rebased and fixed aliases]
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---
arch/arm/boot/dts/r8a7794-silk.dts | 129 ++++++++++++++++++++++---------------
1 file changed, 76 insertions(+), 53 deletions(-)
diff --git a/arch/arm/boot/dts/r8a7794-silk.dts b/arch/arm/boot/dts/r8a7794-silk.dts
index cf880ac06f4b79..9ee16953bf9989 100644
--- a/arch/arm/boot/dts/r8a7794-silk.dts
+++ b/arch/arm/boot/dts/r8a7794-silk.dts
@@ -31,6 +31,8 @@
aliases {
serial0 = &scif2;
+ i2c9 = &gpioi2c1;
+ i2c10 = &i2chdmi;
};
chosen {
@@ -153,6 +155,79 @@
clocks = <&x9_clk>;
};
};
+
+ gpioi2c1: i2c-9 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "i2c-gpio";
+ status = "disabled";
+ gpios = <&gpio4 1 GPIO_ACTIVE_HIGH /* sda */
+ &gpio4 0 GPIO_ACTIVE_HIGH /* scl */
+ >;
+ i2c-gpio,delay-us = <5>;
+ };
+
+ /*
+ * A fallback to GPIO is provided for I2C1.
+ */
+ i2chdmi: i2c-10 {
+ compatible = "i2c-demux-pinctrl";
+ i2c-parent = <&i2c1>, <&gpioi2c1>;
+ i2c-bus-name = "i2c-hdmi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ak4643: codec@12 {
+ compatible = "asahi-kasei,ak4643";
+ #sound-dai-cells = <0>;
+ reg = <0x12>;
+ };
+
+ composite-in@20 {
+ compatible = "adi,adv7180";
+ reg = <0x20>;
+ remote = <&vin0>;
+
+ port {
+ adv7180: endpoint {
+ bus-width = <8>;
+ remote-endpoint = <&vin0ep>;
+ };
+ };
+ };
+
+ hdmi@39 {
+ compatible = "adi,adv7511w";
+ reg = <0x39>;
+ interrupt-parent = <&gpio5>;
+ interrupts = <23 IRQ_TYPE_LEVEL_LOW>;
+
+ adi,input-depth = <8>;
+ adi,input-colorspace = "rgb";
+ adi,input-clock = "1x";
+ adi,input-style = <1>;
+ adi,input-justification = "evenly";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ adv7511_in: endpoint {
+ remote-endpoint = <&du_out_rgb0>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ adv7511_out: endpoint {
+ remote-endpoint = <&hdmi_con>;
+ };
+ };
+ };
+ };
+ };
};
&extal_clk {
@@ -269,61 +344,9 @@
&i2c1 {
pinctrl-0 = <&i2c1_pins>;
- pinctrl-names = "default";
+ pinctrl-names = "i2c-hdmi";
- status = "okay";
clock-frequency = <400000>;
-
- ak4643: codec@12 {
- compatible = "asahi-kasei,ak4643";
- #sound-dai-cells = <0>;
- reg = <0x12>;
- };
-
- composite-in@20 {
- compatible = "adi,adv7180";
- reg = <0x20>;
- remote = <&vin0>;
-
- port {
- adv7180: endpoint {
- bus-width = <8>;
- remote-endpoint = <&vin0ep>;
- };
- };
- };
-
- hdmi@39 {
- compatible = "adi,adv7511w";
- reg = <0x39>;
- interrupt-parent = <&gpio5>;
- interrupts = <23 IRQ_TYPE_LEVEL_LOW>;
-
- adi,input-depth = <8>;
- adi,input-colorspace = "rgb";
- adi,input-clock = "1x";
- adi,input-style = <1>;
- adi,input-justification = "evenly";
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@0 {
- reg = <0>;
- adv7511_in: endpoint {
- remote-endpoint = <&du_out_rgb0>;
- };
- };
-
- port@1 {
- reg = <1>;
- adv7511_out: endpoint {
- remote-endpoint = <&hdmi_con>;
- };
- };
- };
- };
};
&mmcif0 {
--
2.9.3
^ permalink raw reply related
* [PATCH v4 14/14] i2c: mux: demux-pinctrl: make drivers with no pinctrl work again
From: Wolfram Sang @ 2016-11-06 20:20 UTC (permalink / raw)
To: linux-renesas-soc, Simon Horman; +Cc: linux-i2c, Wolfram Sang
In-Reply-To: <20161106202032.5227-1-wsa+renesas@sang-engineering.com>
Some drivers like i2c-gpio do not have dedicated pinctrl states. They
broke when error checking for pinctrl was added. Detect them now, and in
their case, simply skip over pinctrl configuration.
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---
drivers/i2c/muxes/i2c-demux-pinctrl.c | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/drivers/i2c/muxes/i2c-demux-pinctrl.c b/drivers/i2c/muxes/i2c-demux-pinctrl.c
index b3893f6282ba5b..3e6fe1760d82fc 100644
--- a/drivers/i2c/muxes/i2c-demux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-demux-pinctrl.c
@@ -69,10 +69,28 @@ static int i2c_demux_activate_master(struct i2c_demux_pinctrl_priv *priv, u32 ne
goto err_with_revert;
}
- p = devm_pinctrl_get_select(adap->dev.parent, priv->bus_name);
+ /*
+ * Check if there are pinctrl states at all. Note: we cant' use
+ * devm_pinctrl_get_select() because we need to distinguish between
+ * the -ENODEV from devm_pinctrl_get() and pinctrl_lookup_state().
+ */
+ p = devm_pinctrl_get(adap->dev.parent);
if (IS_ERR(p)) {
ret = PTR_ERR(p);
- goto err_with_put;
+ /* continue if just no pinctrl states (e.g. i2c-gpio), otherwise exit */
+ if (ret != -ENODEV)
+ goto err_with_put;
+ } else {
+ /* there are states. check and use them */
+ struct pinctrl_state *s = pinctrl_lookup_state(p, priv->bus_name);
+
+ if (IS_ERR(s)) {
+ ret = PTR_ERR(s);
+ goto err_with_put;
+ }
+ ret = pinctrl_select_state(p, s);
+ if (ret < 0)
+ goto err_with_put;
}
priv->chan[new_chan].parent_adap = adap;
--
2.9.3
^ permalink raw reply related
* [PATCH v4 02/14] ARM: dts: lager: use demuxer for IIC1/I2C1
From: Wolfram Sang @ 2016-11-06 20:20 UTC (permalink / raw)
To: linux-renesas-soc, Simon Horman; +Cc: linux-i2c, Simon Horman, Wolfram Sang
In-Reply-To: <20161106202032.5227-1-wsa+renesas@sang-engineering.com>
From: Simon Horman <horms+renesas@verge.net.au>
Make it possible to select which I2C1 IP core you want to run on the
EXIO-A connector.
This is based on reference work for the I2C0 core of the lager board
by Wolfram Sang.
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
[wsa: rebased and fixed aliases]
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---
arch/arm/boot/dts/r8a7790-lager.dts | 39 +++++++++++++++++++++++++++++++++++--
1 file changed, 37 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts
index dafa49f837118e..bd512c86e85222 100644
--- a/arch/arm/boot/dts/r8a7790-lager.dts
+++ b/arch/arm/boot/dts/r8a7790-lager.dts
@@ -50,7 +50,9 @@
aliases {
serial0 = &scif0;
serial1 = &scifa1;
+ i2c8 = &gpioi2c1;
i2c10 = &i2cexio0;
+ i2c11 = &i2cexio1;
};
chosen {
@@ -265,6 +267,17 @@
clock-frequency = <148500000>;
};
+ gpioi2c1: i2c-8 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "i2c-gpio";
+ status = "disabled";
+ gpios = <&gpio1 17 GPIO_ACTIVE_HIGH /* sda */
+ &gpio1 16 GPIO_ACTIVE_HIGH /* scl */
+ >;
+ i2c-gpio,delay-us = <5>;
+ };
+
/*
* IIC0/I2C0 is routed to EXIO connector A, pins 114 (SCL) + 116 (SDA) only.
* We use the I2C demuxer, so the desired IP core can be selected at runtime
@@ -283,6 +296,19 @@
#address-cells = <1>;
#size-cells = <0>;
};
+
+ /*
+ * IIC1/I2C1 is routed to EXIO connector A, pins 78 (SCL) + 80 (SDA).
+ * This is similar to the arangement described for i2cexio0 (above)
+ * with a fallback to GPIO also provided.
+ */
+ i2cexio1: i2c-11 {
+ compatible = "i2c-demux-pinctrl";
+ i2c-parent = <&iic1>, <&i2c1>, <&gpioi2c1>;
+ i2c-bus-name = "i2c-exio1";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
};
&du {
@@ -405,6 +431,11 @@
function = "iic0";
};
+ i2c1_pins: i2c1 {
+ groups = "i2c1";
+ function = "i2c1";
+ };
+
iic1_pins: iic1 {
groups = "iic1";
function = "iic1";
@@ -607,10 +638,14 @@
pinctrl-names = "i2c-exio0";
};
+&i2c1 {
+ pinctrl-0 = <&i2c1_pins>;
+ pinctrl-names = "i2c-exio1";
+};
+
&iic1 {
- status = "okay";
pinctrl-0 = <&iic1_pins>;
- pinctrl-names = "default";
+ pinctrl-names = "i2c-exio1";
};
&iic2 {
--
2.9.3
^ permalink raw reply related
* [PATCH v4 00/14] ARM: dts: r8a779x: use demuxer for I2C
From: Wolfram Sang @ 2016-11-06 20:20 UTC (permalink / raw)
To: linux-renesas-soc, Simon Horman; +Cc: linux-i2c, Wolfram Sang
So, here is the newest series for using the I2C demuxer on Gen2 boards.
Initially done by Simon. The intention of this series is to extend use of the
demuxer for I2C on the lager, koelsch, porter, koelsch, alt and silk boards to
cover all I2C IP blocks that are either already used or exposed via an EXIO
connector.
I tested this on a Lager board where I could successfully switch between I2C,
IIC, and GPIO on I2C2.
Simon, can you test with your script on the other boards? If all works, I'll
pick up the i2c patch for 4.9, so the DTS changes should be fine for 4.10.
The branch is here:
git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git renesas/ip-switch-rework
Regards,
Wolfram
Changes between v4 and v3
* rebased to latest renesas-drivers (double checked that the moved i2c clients
were complete because they changed meanwhile)
* fixed the aliases to be proper phandles
* fixed some typos in comments and commit messages
* added a patch to ensure i2c-gpio works again
Changes between v2 and v3
* Group extra GPIO buses
* Add GPIO fallback for IIC1/I2C1 on Lager
* Add patches for koelsch, porter, alt and silk
Changes between v1 and v2
* Provide GPIO fallback for I2C2,
this does not seem appropriate for other I2C blocks on the lager board
Simon Horman (13):
ARM: dts: lager: rename and reindex i2cexio
ARM: dts: lager: use demuxer for IIC1/I2C1
ARM: dts: lager: use demuxer for IIC2/I2C2
ARM: dts: lager: use demuxer for IIC3/I2C3
ARM: dts: koelsch: use demuxer for I2C1
ARM: dts: koelsch: use demuxer for I2C2
ARM: dts: koelsch: use demuxer for I2C4
ARM: dts: porter: use demuxer for I2C2
ARM: dts: gose: use demuxer for I2C2
ARM: dts: gose: use demuxer for I2C4
ARM: dts: alt: use demuxer for I2C1
ARM: dts: alt: use demuxer for I2C4
ARM: dts: silk: use demuxer for I2C1
Wolfram Sang (1):
i2c: mux: demux-pinctrl: make drivers with no pinctrl work again
arch/arm/boot/dts/r8a7790-lager.dts | 329 ++++++++++++++++++++++------------
arch/arm/boot/dts/r8a7791-koelsch.dts | 263 ++++++++++++++++++---------
arch/arm/boot/dts/r8a7791-porter.dts | 129 +++++++------
arch/arm/boot/dts/r8a7793-gose.dts | 203 +++++++++++++--------
arch/arm/boot/dts/r8a7794-alt.dts | 86 +++++++--
arch/arm/boot/dts/r8a7794-silk.dts | 129 +++++++------
drivers/i2c/muxes/i2c-demux-pinctrl.c | 22 ++-
7 files changed, 765 insertions(+), 396 deletions(-)
--
2.9.3
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox