* [PATCH v3] eeprom/at24: use device_property_*() functions instead of of_get_property()
From: Ben Gardner @ 2017-02-09 17:09 UTC (permalink / raw)
To: Wolfram Sang; +Cc: linux-i2c, linux-kernel, Andy Shevchenko, Ben Gardner
In-Reply-To: <CAE7DoPa1taAOWOO+g=A=QJ5wTy+GicjyL6GgdiTYQ94QWaX1Ug@mail.gmail.com>
Allow the at24 driver to get configuration information from both OF and
ACPI by using the more generic device_property functions.
This change was inspired by the at25.c driver.
I have a custom board with a ST M24C02 EEPROM attached to an I2C bus.
With the following ACPI construct, this patch instantiates a working
instance of the driver.
Device (EEP0) {
Name (_HID, "PRP0001")
Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () {"compatible", Package () {"st,24c02"}},
Package () {"pagesize", 16},
},
})
Name (_CRS, ResourceTemplate () {
I2cSerialBus (
0x0057, ControllerInitiated, 400000,
AddressingMode7Bit, "\\_SB.PCI0.I2C3", 0x00,
ResourceConsumer,,)
})
}
Note: Matching the driver to the I2C device requires another patch.
http://www.spinics.net/lists/linux-acpi/msg71914.html
Signed-off-by: Ben Gardner <gardner.ben@gmail.com>
---
drivers/misc/eeprom/at24.c | 45 +++++++++++++++++++--------------------------
1 file changed, 19 insertions(+), 26 deletions(-)
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 051b147..c2d9969 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -19,7 +19,7 @@
#include <linux/log2.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
-#include <linux/of.h>
+#include <linux/property.h>
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/nvmem-provider.h>
@@ -562,26 +562,26 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
return 0;
}
-#ifdef CONFIG_OF
-static void at24_get_ofdata(struct i2c_client *client,
- struct at24_platform_data *chip)
+static void at24_get_pdata(struct device *dev, struct at24_platform_data *chip)
{
- const __be32 *val;
- struct device_node *node = client->dev.of_node;
-
- if (node) {
- if (of_get_property(node, "read-only", NULL))
- chip->flags |= AT24_FLAG_READONLY;
- val = of_get_property(node, "pagesize", NULL);
- if (val)
- chip->page_size = be32_to_cpup(val);
+ int err;
+ u32 val;
+
+ if (device_property_present(dev, "read-only"))
+ chip->flags |= AT24_FLAG_READONLY;
+
+ err = device_property_read_u32(dev, "pagesize", &val);
+ if (!err) {
+ chip->page_size = val;
+ } else {
+ /*
+ * This is slow, but we can't know all eeproms, so we better
+ * play safe. Specifying custom eeprom-types via platform_data
+ * is recommended anyhow.
+ */
+ chip.page_size = 1;
}
}
-#else
-static void at24_get_ofdata(struct i2c_client *client,
- struct at24_platform_data *chip)
-{ }
-#endif /* CONFIG_OF */
static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
@@ -613,15 +613,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN));
magic >>= AT24_SIZE_BYTELEN;
chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS);
- /*
- * This is slow, but we can't know all eeproms, so we better
- * play safe. Specifying custom eeprom-types via platform_data
- * is recommended anyhow.
- */
- chip.page_size = 1;
- /* update chipdata if OF is present */
- at24_get_ofdata(client, &chip);
+ at24_get_pdata(&client->dev, &chip);
chip.setup = NULL;
chip.context = NULL;
--
2.7.4
^ permalink raw reply related
* Re: [PATCH v2] eeprom/at24: use device_property_*() functions instead of of_get_property()
From: Ben Gardner @ 2017-02-09 17:03 UTC (permalink / raw)
To: Andy Shevchenko; +Cc: Wolfram Sang, Linux I2C, linux-kernel@vger.kernel.org
In-Reply-To: <CAHp75VfM6orvq-_XOkPfzGjGZZyOERhAjhXbx5m9Fm1Rh=Biig@mail.gmail.com>
> Still couple of comments.
>
>> @@ -19,7 +19,6 @@
>> #include <linux/log2.h>
>> #include <linux/bitops.h>
>> #include <linux/jiffies.h>
>
>> -#include <linux/of.h>
>
> I suppose
> + #include <linux/property.h>
> ?
It looks like <linux/property.h> is included via <linux/acpi.h>
outside of any "#ifdef CONFIG_ACPI" check.
But Documentation/process/submit-checklist.rst indicates:
1) If you use a facility then #include the file that defines/declares
that facility. Don't depend on other header files pulling in ones
that you use.
So, I'll add it.
As an aside, a quick scan of the drivers/ folder shows that fewer than
half of the files that use functions from that header actually include
it.
>> +static void at24_get_pdata(struct device *dev,
>> + struct at24_platform_data *chip)
>
> Now it fits one line.
Sure does. Exactly 80 columns.
>> + u32 val;
>> +
>> + if (device_property_present(dev, "read-only"))
>> + chip->flags |= AT24_FLAG_READONLY;
>> +
>> + if (device_property_read_u32(dev, "pagesize", &val) == 0) {
>
> ' == 0' looks awkward.
>
> And I think
>
> ret = x();
> if (ret)
> ...
> else
> ...
>
> pattern would look slightly better.
There are 51 C files that use a temporary variable as you suggest with
"device_property_read" functions.
There are 7 C files that use the "if (!device_property_read" style.
It looks like at25.c was the only one that uses the '== 0' construct.
Guess I picked the wrong one to copy.
So, sure, I'll change that.
>> + chip->page_size = val;
>> + } else {
>> + /*
>> + * This is slow, but we can't know all eeproms, so we better
>> + * play safe. Specifying custom eeprom-types via platform_data
>> + * is recommended anyhow.
>> + */
>> + chip.page_size = 1;
>
> --
> With Best Regards,
> Andy Shevchenko
^ permalink raw reply
* Re: [PATCH] i2c: riic: correctly finish transfers
From: Wolfram Sang @ 2017-02-09 16:44 UTC (permalink / raw)
To: Chris Brandt
Cc: linux-i2c, linux-renesas-soc, Simon Horman, Geert Uytterhoeven
In-Reply-To: <20170208024122.13116-1-chris.brandt@renesas.com>
[-- Attachment #1: Type: text/plain, Size: 1266 bytes --]
On Tue, Feb 07, 2017 at 09:41:22PM -0500, Chris Brandt wrote:
> This fixes the condition where the controller has not fully completed its
> final transfer and leaves the bus and controller in a undesirable state.
>
> At the end of the last transmitted byte, the existing driver would just
> signal for a STOP condition to be transmitted then immediately signal
> completion. However, the full STOP procedure might not have fully taken
> place by the time the runtime PM shuts off the peripheral clock, leaving
> the bus in a suspended state.
>
> Alternatively, the STOP condition on the bus may have completed, but when
> the next transaction is requested by the upper layer, not all the
> necessary register cleanup was finished from the last transfer which made
> the driver return BUS BUSY when it really wasn't.
>
> This patch now makes all transmit and receive transactions wait for the
> STOP condition to fully complete before signaling a completed transaction.
> With this new method, runtime PM no longer seems to be an issue.
>
> Fixes: 310c18a41450 ("i2c: riic: add driver")
> Signed-off-by: Chris Brandt <chris.brandt@renesas.com>
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Applied to for-next, thanks!
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH -next] i2c: mux: mlxcpld: remove unused including <linux/version.h>
From: Wolfram Sang @ 2017-02-09 16:29 UTC (permalink / raw)
To: Wei Yongjun
Cc: Vadim Pasternak, Michael Shych, Peter Rosin, Wei Yongjun,
linux-i2c
In-Reply-To: <20170112142904.17582-1-weiyj.lk@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 263 bytes --]
On Thu, Jan 12, 2017 at 02:29:04PM +0000, Wei Yongjun wrote:
> From: Wei Yongjun <weiyongjun1@huawei.com>
>
> Remove including <linux/version.h> that don't need it.
>
> Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
Applied to for-next, thanks!
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH v2] i2c: i801: Add support for Intel Gemini Lake
From: Wolfram Sang @ 2017-02-09 16:40 UTC (permalink / raw)
To: Mika Westerberg; +Cc: Jean Delvare, Jarkko Nikula, linux-i2c
In-Reply-To: <20170201162059.81911-1-mika.westerberg@linux.intel.com>
[-- Attachment #1: Type: text/plain, Size: 298 bytes --]
On Wed, Feb 01, 2017 at 07:20:59PM +0300, Mika Westerberg wrote:
> Intel Gemini Lake has the same SMBus host controller than Intel Broxton.
>
> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> Signed-off-by: Jean Delvare <jdelvare@suse.de>
Applied to for-next, thanks!
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH] I2c: busses - Fix possible NULL derefrence.
From: Wolfram Sang @ 2017-02-09 16:37 UTC (permalink / raw)
To: Shailendra Verma
Cc: Laxman Dewangan, Stephen Warren, Thierry Reding,
Alexandre Courbot, linux-i2c, linux-tegra, linux-kernel,
p.shailesh, ashish.kalra, Shailendra Verma
In-Reply-To: <1485752587-30107-1-git-send-email-shailendra.v@samsung.com>
[-- Attachment #1: Type: text/plain, Size: 343 bytes --]
On Mon, Jan 30, 2017 at 10:33:07AM +0530, Shailendra Verma wrote:
> of_device_get_match_data could return NULL, and so can cause
> a NULL pointer dereference later.
>
> Signed-off-by: Shailendra Verma <shailendra.v@samsung.com>
I don't mind either way, but since Thierry is the maintainer of this
driver, I respect his preference.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [RESEND PATCH 1/2] Documentation: devicetree: Add i2c binding for mediatek MT2701 Soc Platform
From: Wolfram Sang @ 2017-02-09 16:35 UTC (permalink / raw)
To: Jun Gao
Cc: devicetree, srv_heupstream, linux-kernel, linux-mediatek,
linux-i2c, Matthias Brugger, linux-arm-kernel
In-Reply-To: <1484732461-13594-2-git-send-email-jun.gao@mediatek.com>
[-- Attachment #1.1: Type: text/plain, Size: 1863 bytes --]
On Wed, Jan 18, 2017 at 05:41:00PM +0800, Jun Gao wrote:
> From: Jun Gao <jun.gao@mediatek.com>
>
> This add i2c DT binding to i2c-mt6577.txt for MT2701.
>
> Signed-off-by: Jun Gao <jun.gao@mediatek.com>
> ---
> .../devicetree/bindings/i2c/i2c-mt6577.txt | 11 ++++++-----
> 1 file changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/i2c/i2c-mt6577.txt b/Documentation/devicetree/bindings/i2c/i2c-mt6577.txt
> index 0ce6fa3..ef22ecf 100644
> --- a/Documentation/devicetree/bindings/i2c/i2c-mt6577.txt
> +++ b/Documentation/devicetree/bindings/i2c/i2c-mt6577.txt
> @@ -4,11 +4,12 @@ The Mediatek's I2C controller is used to interface with I2C devices.
>
> Required properties:
> - compatible: value should be either of the following.
> - (a) "mediatek,mt6577-i2c", for i2c compatible with mt6577 i2c.
> - (b) "mediatek,mt6589-i2c", for i2c compatible with mt6589 i2c.
> - (c) "mediatek,mt8127-i2c", for i2c compatible with mt8127 i2c.
> - (d) "mediatek,mt8135-i2c", for i2c compatible with mt8135 i2c.
> - (e) "mediatek,mt8173-i2c", for i2c compatible with mt8173 i2c.
> + "mediatek,mt2701-i2c", for i2c compatible with mt2701 i2c.
> + "mediatek,mt6577-i2c", for i2c compatible with mt6577 i2c.
> + "mediatek,mt6589-i2c", for i2c compatible with mt6589 i2c.
> + "mediatek,mt8127-i2c", for i2c compatible with mt8127 i2c.
> + "mediatek,mt8135-i2c", for i2c compatible with mt8135 i2c.
> + "mediatek,mt8173-i2c", for i2c compatible with mt8173 i2c.
> - reg: physical base address of the controller and dma base, length of memory
> mapped region.
> - interrupts: interrupt number to the cpu.
Are there no driver changes needed? It currently lists only 3 of the
above. If so, that would be nice to be mentioned in the commit message.
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
[-- Attachment #2: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] i2c: exynos5: fix arbitration lost handling
From: Wolfram Sang @ 2017-02-09 16:27 UTC (permalink / raw)
To: Andrzej Hajda
Cc: linux-i2c, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
Krzysztof Kozlowski, Javier Martinez Canillas, linux-samsung-soc
In-Reply-To: <1483618013-10721-1-git-send-email-a.hajda@samsung.com>
[-- Attachment #1: Type: text/plain, Size: 714 bytes --]
On Thu, Jan 05, 2017 at 01:06:53PM +0100, Andrzej Hajda wrote:
> In case of arbitration lost adequate interrupt sometimes is not signaled. As
> a result transfer timeouts and is not retried, as it should. To avoid such
> cases code is added to check transaction status in case of every interrupt.
>
> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
> ---
> +
> + switch (trans_status & HSI2C_MASTER_ST_MASK) {
> + case HSI2C_MASTER_ST_LOSE:
> + i2c->state = -EAGAIN;
> + goto stop;
> + }
Why not using if() instead of switch() as in the rest of the driver?
And there is arbitration lost checking already with int_status &
HSI2C_INT_TRANS_ABORT. Any guess why it doesn't trigger?
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH v6 3/3] i2c: mux: pca954x: Add interrupt controller support
From: Peter Rosin @ 2017-02-09 16:21 UTC (permalink / raw)
To: Phil Reid, wsa-z923LK4zBo2bacvFa/9K2g,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
linux-i2c-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1485307868-5408-4-git-send-email-preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
On 2017-01-25 02:31, Phil Reid wrote:
> Various muxes can aggregate multiple interrupts from each i2c bus.
> All of the muxes with interrupt support combine the active low irq lines
> using an internal 'and' function and generate a combined active low
> output. The muxes do provide the ability to read a control register to
> determine which irq is active. By making the mux an irq controller isr
> latency can potentially be reduced by reading the status register and
> then only calling the registered isr on that bus segment.
>
> As there is no irq masking on the mux irq are disabled until irq_unmask is
> called at least once.
>
> Acked-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
> Signed-off-by: Phil Reid <preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
> ---
> drivers/i2c/muxes/i2c-mux-pca954x.c | 141 +++++++++++++++++++++++++++++++++++-
> 1 file changed, 139 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
> index bbf088e..f55da88 100644
> --- a/drivers/i2c/muxes/i2c-mux-pca954x.c
> +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
> @@ -41,14 +41,20 @@
> #include <linux/i2c.h>
> #include <linux/i2c-mux.h>
> #include <linux/i2c/pca954x.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> #include <linux/module.h>
> #include <linux/of.h>
> #include <linux/of_device.h>
> +#include <linux/of_irq.h>
> #include <linux/pm.h>
> #include <linux/slab.h>
> +#include <linux/spinlock.h>
>
> #define PCA954X_MAX_NCHANS 8
>
> +#define PCA954X_IRQ_OFFSET 4
> +
> enum pca_type {
> pca_9540,
> pca_9542,
> @@ -63,6 +69,7 @@ enum pca_type {
> struct chip_desc {
> u8 nchans;
> u8 enable; /* used for muxes only */
> + u8 has_irq;
> enum muxtype {
> pca954x_ismux = 0,
> pca954x_isswi
> @@ -75,6 +82,10 @@ struct pca954x {
> u8 last_chan; /* last register value */
> u8 deselect;
> struct i2c_client *client;
> +
> + struct irq_domain *irq;
> + unsigned int irq_mask;
> + spinlock_t lock;
> };
>
> /* Provide specs for the PCA954x types we know about */
> @@ -87,19 +98,23 @@ struct pca954x {
> [pca_9542] = {
> .nchans = 2,
> .enable = 0x4,
> + .has_irq = 1,
> .muxtype = pca954x_ismux,
> },
> [pca_9543] = {
> .nchans = 2,
> + .has_irq = 1,
> .muxtype = pca954x_isswi,
> },
> [pca_9544] = {
> .nchans = 4,
> .enable = 0x4,
> + .has_irq = 1,
> .muxtype = pca954x_ismux,
> },
> [pca_9545] = {
> .nchans = 4,
> + .has_irq = 1,
> .muxtype = pca954x_isswi,
> },
> [pca_9547] = {
> @@ -222,6 +237,114 @@ static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
> return pca954x_reg_write(muxc->parent, client, data->last_chan);
> }
>
> +static irqreturn_t pca954x_irq_handler(int irq, void *dev_id)
> +{
> + struct pca954x *data = dev_id;
> + unsigned int child_irq;
> + int ret, i, handled;
See below.
> +
> + ret = i2c_smbus_read_byte(data->client);
> + if (ret < 0)
> + return IRQ_NONE;
> +
> + for (i = 0; i < data->chip->nchans; i++) {
> + if (ret & BIT(PCA954X_IRQ_OFFSET + i)) {
> + child_irq = irq_linear_revmap(data->irq, i);
> + handle_nested_irq(child_irq);
> + handled++;
> + }
> + }
> + return handled ? IRQ_HANDLED : IRQ_NONE;
> +}
> +
> +static void pca954x_irq_mask(struct irq_data *idata)
> +{
> + struct pca954x *data = irq_data_get_irq_chip_data(idata);
> + unsigned int pos = idata->hwirq;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&data->lock, flags);
> +
> + data->irq_mask &= ~BIT(pos);
> + if (!data->irq_mask)
> + disable_irq(data->client->irq);
> +
> + spin_unlock_irqrestore(&data->lock, flags);
> +}
> +
> +static void pca954x_irq_unmask(struct irq_data *idata)
> +{
> + struct pca954x *data = irq_data_get_irq_chip_data(idata);
> + unsigned int pos = idata->hwirq;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&data->lock, flags);
> +
> + if (!data->irq_mask)
> + enable_irq(data->client->irq);
> + data->irq_mask |= BIT(pos);
> +
> + spin_unlock_irqrestore(&data->lock, flags);
> +}
> +
> +static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type)
> +{
> + if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_LOW)
> + return -EINVAL;
> + return 0;
> +}
> +
> +static struct irq_chip pca954x_irq_chip = {
> + .name = "i2c-mux-pca954x",
> + .irq_mask = pca954x_irq_mask,
> + .irq_unmask = pca954x_irq_unmask,
> + .irq_set_type = pca954x_irq_set_type,
> +};
> +
> +static int pca954x_irq_setup(struct i2c_mux_core *muxc)
> +{
> + struct pca954x *data = i2c_mux_priv(muxc);
> + struct i2c_client *client = data->client;
> + int c, err, irq;
> +
> + if (!data->chip->has_irq || client->irq <= 0)
> + return 0;
> +
> + spin_lock_init(&data->lock);
> +
> + data->irq = irq_domain_add_linear(client->dev.of_node,
> + data->chip->nchans,
> + &irq_domain_simple_ops, data);
> + if (!data->irq)
> + return -ENODEV;
> +
> + for (c = 0; c < data->chip->nchans; c++) {
> + irq = irq_create_mapping(data->irq, c);
> + irq_set_chip_data(irq, data);
> + irq_set_chip_and_handler(irq, &pca954x_irq_chip,
> + handle_simple_irq);
> + }
> +
> + err = devm_request_threaded_irq(&client->dev, data->client->irq, NULL,
> + pca954x_irq_handler,
> + IRQF_ONESHOT | IRQF_SHARED,
> + "pca954x", data);
> + if (err)
> + goto err_req_irq;
> +
> + disable_irq(data->client->irq);
> +
> + return 0;
> +err_req_irq:
> + for (c = 0; c < data->chip->nchans; c++) {
> + irq = irq_find_mapping(data->irq, c);
> + irq_dispose_mapping(irq);
> + }
> + irq_domain_remove(data->irq);
> +
> + return err;
> +}
> +
> /*
> * I2C init/probing/exit functions
> */
> @@ -286,6 +409,10 @@ static int pca954x_probe(struct i2c_client *client,
> idle_disconnect_dt = of_node &&
> of_property_read_bool(of_node, "i2c-mux-idle-disconnect");
>
> + ret = pca954x_irq_setup(muxc);
> + if (ret)
> + goto fail_del_adapters;
> +
> /* Now create an adapter for each channel */
> for (num = 0; num < data->chip->nchans; num++) {
> bool idle_disconnect_pd = false;
> @@ -311,7 +438,7 @@ static int pca954x_probe(struct i2c_client *client,
> dev_err(&client->dev,
> "failed to register multiplexed adapter"
> " %d as bus %d\n", num, force);
> - goto virt_reg_failed;
> + goto fail_del_adapters;
> }
> }
>
> @@ -322,7 +449,7 @@ static int pca954x_probe(struct i2c_client *client,
>
> return 0;
>
> -virt_reg_failed:
> +fail_del_adapters:
> i2c_mux_del_adapters(muxc);
> return ret;
> }
> @@ -330,6 +457,16 @@ static int pca954x_probe(struct i2c_client *client,
> static int pca954x_remove(struct i2c_client *client)
> {
> struct i2c_mux_core *muxc = i2c_get_clientdata(client);
> + struct pca954x *data = i2c_mux_priv(muxc);
> + int c, irq;
> +
> + if (data->irq) {
> + for (c = 0; c < data->chip->nchans; c++) {
> + irq = irq_find_mapping(data->irq, c);
> + irq_dispose_mapping(irq);
> + }
> + irq_domain_remove(data->irq);
> + }
>
> i2c_mux_del_adapters(muxc);
> return 0;
>
This patch needs this obvious fixup discovered by the kbuild bot
Cheers,
peda
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -242,7 +242,7 @@ static irqreturn_t pca954x_irq_handler(int irq, void *dev_id)
{
struct pca954x *data = dev_id;
unsigned int child_irq;
- int ret, i, handled;
+ int ret, i, handled = 0;
ret = i2c_smbus_read_byte(data->client);
if (ret < 0)
--
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 v2] eeprom/at24: use device_property_*() functions instead of of_get_property()
From: Andy Shevchenko @ 2017-02-09 16:20 UTC (permalink / raw)
To: Ben Gardner; +Cc: Wolfram Sang, linux-i2c, linux-kernel@vger.kernel.org
In-Reply-To: <1486654433-20148-1-git-send-email-gardner.ben@gmail.com>
On Thu, Feb 9, 2017 at 5:33 PM, Ben Gardner <gardner.ben@gmail.com> wrote:
> Allow the at24 driver to get configuration information from both OF and
> ACPI by using the more generic device_property functions.
> This change was inspired by the at25.c driver.
>
> I have a custom board with a ST M24C02 EEPROM attached to an I2C bus.
> With the following ACPI construct, this patch instantiates a working
> instance of the driver.
>
> Device (EEP0) {
> Name (_HID, "PRP0001")
> Name (_DSD, Package () {
> ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
> Package () {
> Package () {"compatible", Package () {"st,24c02"}},
> Package () {"size", 256},
> Package () {"pagesize", 16},
> },
> })
> Name (_CRS, ResourceTemplate () {
> I2cSerialBus (
> 0x0057, ControllerInitiated, 400000,
> AddressingMode7Bit, "\\_SB.PCI0.I2C3", 0x00,
> ResourceConsumer,,)
> })
> }
>
> Note: Matching the driver to the I2C device requires another patch.
> http://www.spinics.net/lists/linux-acpi/msg71914.html
>
Still couple of comments.
> @@ -19,7 +19,6 @@
> #include <linux/log2.h>
> #include <linux/bitops.h>
> #include <linux/jiffies.h>
> -#include <linux/of.h>
I suppose
+ #include <linux/property.h>
?
> +static void at24_get_pdata(struct device *dev,
> + struct at24_platform_data *chip)
Now it fits one line.
> + u32 val;
> +
> + if (device_property_present(dev, "read-only"))
> + chip->flags |= AT24_FLAG_READONLY;
> +
> + if (device_property_read_u32(dev, "pagesize", &val) == 0) {
' == 0' looks awkward.
And I think
ret = x();
if (ret)
...
else
...
pattern would look slightly better.
> + chip->page_size = val;
> + } else {
> + /*
> + * This is slow, but we can't know all eeproms, so we better
> + * play safe. Specifying custom eeprom-types via platform_data
> + * is recommended anyhow.
> + */
> + chip.page_size = 1;
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH] i2c: piix4: Request the SMBUS semaphore inside the mutex
From: Wolfram Sang @ 2017-02-09 16:09 UTC (permalink / raw)
To: Jean Delvare
Cc: Ricardo Ribalda Delgado, Andy Shevchenko, linux-i2c, linux-kernel
In-Reply-To: <20170203161739.7264f85b@endymion>
[-- Attachment #1: Type: text/plain, Size: 166 bytes --]
Jean,
> Thanks for the quick fix.
>
> Signed-off-by: Jean Delvare <jdelvare@suse.de>
I wonder: why do you use Signed-off instead of Reviewed-by recently?
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH] i2c: piix4: Request the SMBUS semaphore inside the mutex
From: Wolfram Sang @ 2017-02-09 16:13 UTC (permalink / raw)
To: Ricardo Ribalda Delgado
Cc: Jean Delvare, Andy Shevchenko, linux-i2c, linux-kernel
In-Reply-To: <20170202191516.4476-1-ricardo.ribalda@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 436 bytes --]
On Thu, Feb 02, 2017 at 08:15:16PM +0100, Ricardo Ribalda Delgado wrote:
> SMBSLVCNT must be protected with the piix4_mutex_sb800 in order to avoid
> multiple buses accessing to the semaphore at the same time.
>
> Reported-by: Jean Delvare <jdelvare@suse.de>
> Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
Applied to for-current and added the same fixes tag as the patch to the
resource size, thanks!
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH] i2c: piix4: Fix request_region size
From: Wolfram Sang @ 2017-02-09 16:14 UTC (permalink / raw)
To: Ricardo Ribalda Delgado
Cc: Andy Shevchenko, Jean Delvare, linux-i2c, linux-kernel
In-Reply-To: <20170127145930.13055-1-ricardo.ribalda@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 403 bytes --]
On Fri, Jan 27, 2017 at 03:59:30PM +0100, Ricardo Ribalda Delgado wrote:
> Since '701dc207bf55 ("i2c: piix4: Avoid race conditions with IMC")' we
> are using the SMBSLVCNT register at offset 0x8. We need to request it.
>
> Fixes: 701dc207bf55 ("i2c: piix4: Avoid race conditions with IMC")
> Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
Applied to for-current, thanks!
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH] i2c: busses: constify i2c_algorithm structures
From: Wolfram Sang @ 2017-02-09 16:08 UTC (permalink / raw)
To: Bhumika Goyal
Cc: jdelvare, andriy.shevchenko, kernel, patrice.chotard,
adi-buildroot-devel, linux-kernel, julia.lawall,
ludovic.desroches, jarkko.nikula, linux-i2c, sonic.zhang,
mika.westerberg, linux-arm-kernel
In-Reply-To: <1485540377-13686-1-git-send-email-bhumirks@gmail.com>
[-- Attachment #1.1: Type: text/plain, Size: 410 bytes --]
On Fri, Jan 27, 2017 at 11:36:17PM +0530, Bhumika Goyal wrote:
> Declare i2c_algorithm structures as const as they are only stored in the
> algo field of an i2c_adapter structure. This field is of type const, so
> i2c_algorithm structures having this property can be made const too.
>
> Signed-off-by: Bhumika Goyal <bhumirks@gmail.com>
Applied to for-next with a shortened commit message, thanks!
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
[-- Attachment #2: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] i2c: i2c-mux-gpio: rename i2c-gpio-mux to i2c-mux-gpio
From: Wolfram Sang @ 2017-02-09 16:02 UTC (permalink / raw)
To: Peter Rosin
Cc: linux-kernel, Peter Korsgaard, Jonathan Corbet, linux-i2c,
linux-doc
In-Reply-To: <1486503715-9224-1-git-send-email-peda@axentia.se>
[-- Attachment #1: Type: text/plain, Size: 385 bytes --]
On Tue, Feb 07, 2017 at 10:41:55PM +0100, Peter Rosin wrote:
> The rename did the wrong thing for this documentation file all those
> years ago. Fix that as well as the neglected rename of the platform
> data structure.
>
> Fixes: e7065e20d9a6 ("i2c: Rename last mux driver to standard pattern")
> Signed-off-by: Peter Rosin <peda@axentia.se>
Applied to for-next, thanks!
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* [PATCH v2] eeprom/at24: use device_property_*() functions instead of of_get_property()
From: Ben Gardner @ 2017-02-09 15:33 UTC (permalink / raw)
To: Wolfram Sang; +Cc: linux-i2c, linux-kernel, Andy Shevchenko, Ben Gardner
In-Reply-To: <1486583636-8940-1-git-send-email-gardner.ben@gmail.com>
Allow the at24 driver to get configuration information from both OF and
ACPI by using the more generic device_property functions.
This change was inspired by the at25.c driver.
I have a custom board with a ST M24C02 EEPROM attached to an I2C bus.
With the following ACPI construct, this patch instantiates a working
instance of the driver.
Device (EEP0) {
Name (_HID, "PRP0001")
Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () {"compatible", Package () {"st,24c02"}},
Package () {"size", 256},
Package () {"pagesize", 16},
},
})
Name (_CRS, ResourceTemplate () {
I2cSerialBus (
0x0057, ControllerInitiated, 400000,
AddressingMode7Bit, "\\_SB.PCI0.I2C3", 0x00,
ResourceConsumer,,)
})
}
Note: Matching the driver to the I2C device requires another patch.
http://www.spinics.net/lists/linux-acpi/msg71914.html
Signed-off-by: Ben Gardner <gardner.ben@gmail.com>
---
drivers/misc/eeprom/at24.c | 43 +++++++++++++++++--------------------------
1 file changed, 17 insertions(+), 26 deletions(-)
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 051b147..81099f3 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -19,7 +19,6 @@
#include <linux/log2.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
-#include <linux/of.h>
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/nvmem-provider.h>
@@ -562,26 +561,25 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
return 0;
}
-#ifdef CONFIG_OF
-static void at24_get_ofdata(struct i2c_client *client,
- struct at24_platform_data *chip)
+static void at24_get_pdata(struct device *dev,
+ struct at24_platform_data *chip)
{
- const __be32 *val;
- struct device_node *node = client->dev.of_node;
-
- if (node) {
- if (of_get_property(node, "read-only", NULL))
- chip->flags |= AT24_FLAG_READONLY;
- val = of_get_property(node, "pagesize", NULL);
- if (val)
- chip->page_size = be32_to_cpup(val);
+ u32 val;
+
+ if (device_property_present(dev, "read-only"))
+ chip->flags |= AT24_FLAG_READONLY;
+
+ if (device_property_read_u32(dev, "pagesize", &val) == 0) {
+ chip->page_size = val;
+ } else {
+ /*
+ * This is slow, but we can't know all eeproms, so we better
+ * play safe. Specifying custom eeprom-types via platform_data
+ * is recommended anyhow.
+ */
+ chip.page_size = 1;
}
}
-#else
-static void at24_get_ofdata(struct i2c_client *client,
- struct at24_platform_data *chip)
-{ }
-#endif /* CONFIG_OF */
static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
@@ -613,15 +611,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN));
magic >>= AT24_SIZE_BYTELEN;
chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS);
- /*
- * This is slow, but we can't know all eeproms, so we better
- * play safe. Specifying custom eeprom-types via platform_data
- * is recommended anyhow.
- */
- chip.page_size = 1;
- /* update chipdata if OF is present */
- at24_get_ofdata(client, &chip);
+ at24_get_pdata(&client->dev, &chip);
chip.setup = NULL;
chip.context = NULL;
--
2.7.4
^ permalink raw reply related
* Re: [PATCH] eeprom/at24: use device_property_*() functions instead of of_get_property()
From: Ben Gardner @ 2017-02-09 15:27 UTC (permalink / raw)
To: Andy Shevchenko; +Cc: Wolfram Sang, Linux I2C, linux-kernel@vger.kernel.org
In-Reply-To: <CAHp75Vd4iwOUaJFzS_AnDGSbmKPSg=f+9VAb6AZdkv51zpbbQA@mail.gmail.com>
Hi Andy,
Thanks for taking the time to look at this.
On Wed, Feb 8, 2017 at 6:07 PM, Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
>
> On Wed, Feb 8, 2017 at 9:53 PM, Ben Gardner <gardner.ben@gmail.com> wrote:
> > Allow the at24 driver to get configuration information from both OF and
> > ACPI by using the more generic device_property functions.
> > This change was inspired by the at25.c driver.
> >
(snip)
> Few comments, after addressing them
>
> FWIW:
> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
>
(snip)
> >
> > -#ifdef CONFIG_OF
> > -static void at24_get_ofdata(struct i2c_client *client,
> > +static void at24_fw_to_chip(struct device *dev,
> > struct at24_platform_data *chip)
>
> "fw" here is ambiguous a bit.
> Would at24_get_pdata() work for you?
That name also works for me.
> > {
> > - const __be32 *val;
> > - struct device_node *node = client->dev.of_node;
> > -
> > - if (node) {
> > - if (of_get_property(node, "read-only", NULL))
> > - chip->flags |= AT24_FLAG_READONLY;
> > - val = of_get_property(node, "pagesize", NULL);
> > - if (val)
> > - chip->page_size = be32_to_cpup(val);
> > - }
> > + u32 val;
> > +
> > + if (device_property_present(dev, "read-only"))
> > + chip->flags |= AT24_FLAG_READONLY;
> > +
>
> > + if (device_property_read_u32(dev, "pagesize", &val) == 0)
>
> I would use default from probe here.
>
> int ret;
>
> ...
>
> ret = ..._u32(..., &val);
> if (ret) {
> /* ...long comment from ->probe()... */
> chip->page_size = 1;
> } else
> chip->page_size = val;
That sounds reasonable.
> > + chip->page_size = val;
> > }
> > -#else
> > -static void at24_get_ofdata(struct i2c_client *client,
> > - struct at24_platform_data *chip)
> > -{ }
> > -#endif /* CONFIG_OF */
> >
> > static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
> > {
> > @@ -621,7 +611,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
> > chip.page_size = 1;
> >
>
> > /* update chipdata if OF is present */
>
> This is now redundant.
Yeah, that comment doesn't seem all that useful.
> > - at24_get_ofdata(client, &chip);
> > + at24_fw_to_chip(&client->dev, &chip);
> >
> > chip.setup = NULL;
> > chip.context = NULL;
> > --
> > 2.7.4
> >
>
>
>
> --
> With Best Regards,
> Andy Shevchenko
I'll send an update.
Thanks,
Ben
^ permalink raw reply
* Re: [PATCH 1/3] of: fix of_node leak caused in of_find_node_opts_by_path
From: Rob Herring @ 2017-02-09 15:11 UTC (permalink / raw)
To: Qi Hou
Cc: Peter Rosin, stable, linux-i2c@vger.kernel.org, Leif Lindholm,
Pantelis Antoniou, Grant Likely, Bruce Ashfield, Paul Gortmaker,
ZhangXiao
In-Reply-To: <1486356919-97176-1-git-send-email-qi.hou@windriver.com>
On Sun, Feb 5, 2017 at 10:55 PM, Qi Hou <qi.hou@windriver.com> wrote:
> During stepping down the tree, parent node is gotten first and its refcount is
> increased with of_node_get() in __of_get_next_child(). Since it just being used
> as tmp node, its refcount must be decreased with of_node_put() after traversing
> its child nodes.
>
> Or, its refcount will never be descreased to ZERO, then it will never be freed,
> as well as other related memory blocks.
>
> To fix this, decrease refcount of parent with of_node_put() after
> __of_find_node_by_path().
>
> Signed-off-by: Qi Hou <qi.hou@windriver.com>
> Acked-by: Peter Rosin <peda@axentia.se>
> ---
> drivers/of/base.c | 3 +++
> 1 file changed, 3 insertions(+)
It doesn't look like there is any inter-dependency with this patch and
the other 2, so I'll apply this one.
Rob
^ permalink raw reply
* Re: [PATCH v6 0/3] Init device ids from ACPI of_compatible
From: Rafael J. Wysocki @ 2017-02-09 13:53 UTC (permalink / raw)
To: Dan O'Donovan
Cc: linux-acpi-u79uwXL29TY76Z2rM5mHXA, Jarkko Nikula, Mika Westerberg,
Mark Brown, Len Brown, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
Wolfram Sang, linux-spi-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1486312214-20770-1-git-send-email-dan-M3NBUjLqch7QT0dZR+AlfA@public.gmane.org>
On Sunday, February 05, 2017 04:30:11 PM Dan O'Donovan wrote:
> When using devicetree, stuff like i2c_client.name or spi_device.modalias
> is initialized to the first DT compatible id with the vendor prefix
> stripped. Since some drivers rely on this in order to differentiate between
> hardware variants, try to replicate it when using ACPI with DT ids.
>
> This also makes it so that the i2c_device_id parameter passed to probe is
> non-NULL when matching with ACPI and DT ids.
>
> Tested using ACPI overlays but there is no actual dependency. This series
> just extends the PRP0001 feature to be more useful for I2C/SPI.
>
> The patches only touches the ACPI-specific parts of the i2c and spi core.
>
> Here is an example .dsl for an SPI accelerometer connected to minnowboard max:
>
> Device (ACCL)
> {
> Name (_ADR, Zero)
> Name (_HID, "PRP0001")
> Name (_UID, One)
>
> Method (_CRS, 0, Serialized)
> {
> Name (RBUF, ResourceTemplate ()
> {
> SPISerialBus(1, PolarityLow, FourWireMode, 16,
> ControllerInitiated, 1000000, ClockPolarityLow,
> ClockPhaseFirst, "\\_SB.SPI1",)
> GpioInt (Edge, ActiveHigh, Exclusive, PullDown, 0x0000,
> "\\_SB.GPO2", 0x00, ResourceConsumer, , )
> { // Pin list
> 1
> }
> })
> Return (RBUF)
> }
> Name (_DSD, Package ()
> {
> ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
> Package ()
> {
> Package () {"compatible", "st,lis3dh"},
> }
> })
> }
>
> Credit to Leonard Crestez for the original version of this patch set.
>
> Link to v5: http://www.spinics.net/lists/linux-acpi/msg71902.html
> Changes:
> * Change formatting of arguments passed to acpi_set_modalias (Mark Brown)
>
> Link to v4: http://www.spinics.net/lists/linux-acpi/msg71657.html
> Changes:
> * add acpi_set_modalias wrapper to handle fallback to ACPI ID (Mark Brown)
>
> Link to v3: http://www.spinics.net/lists/linux-acpi/msg71531.html
> Changes:
> * Minor cosmetic/readability improvements (Andy Shevchenko)
>
> Link to v2: https://lkml.org/lkml/2016/7/13/392
> Changes:
> * Use appropriate subject prefix for each subsystem (Mark Brown)
> * Use ACPI info as before if getting OF info fails (Mark Brown)
> * Minor cosmetic/readability improvements (Rafael J. Wysocki)
>
> Link to v1: https://www.spinics.net/lists/linux-acpi/msg66469.html
> Changes:
> * Rebase on after acpi overlays got it.
> * Change acpi_of_modalias outlen param to size_t
> * Use {} after else
>
> Dan O'Donovan (3):
> ACPI / bus: Export acpi_of_modalias equiv of of_modalias_node
> i2c: acpi: Initialize info.type from of_compatible
> spi: acpi: Initialize modalias from of_compatible
All [1-3/3] applied.
Thanks,
Rafael
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" 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 v6 3/3] i2c: zx2967: add i2c controller driver for ZTE's zx2967 family
From: Baoyou Xie @ 2017-02-09 9:32 UTC (permalink / raw)
To: shawnguo, andy.shevchenko, jun.nie, baoyou.xie, wsa, robh+dt,
mark.rutland
Cc: devicetree, xie.baoyou, linux-kernel, chen.chaokai, linux-i2c,
wang.qiang01, linux-arm-kernel
In-Reply-To: <1486632753-17363-1-git-send-email-baoyou.xie@linaro.org>
This patch adds i2c controller driver for ZTE's zx2967 family.
Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
Reviewed-by: Shawn Guo <shawnguo@kernel.org>
---
drivers/i2c/busses/Kconfig | 9 +
drivers/i2c/busses/Makefile | 1 +
drivers/i2c/busses/i2c-zx2967.c | 676 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 686 insertions(+)
create mode 100644 drivers/i2c/busses/i2c-zx2967.c
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index e4a603e..d983e36 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -1246,4 +1246,13 @@ config I2C_OPAL
This driver can also be built as a module. If so, the module will be
called as i2c-opal.
+config I2C_ZX2967
+ tristate "ZTE zx2967 I2C support"
+ depends on ARCH_ZX
+ default y
+ help
+ Selecting this option will add ZX2967 I2C driver.
+ This driver can also be built as a module. If so, the module will be
+ called i2c-zx2967.
+
endmenu
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index beb4809..16b2901 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -101,6 +101,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_ZX2967) += i2c-zx2967.o
# External I2C/SMBus adapter drivers
obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
diff --git a/drivers/i2c/busses/i2c-zx2967.c b/drivers/i2c/busses/i2c-zx2967.c
new file mode 100644
index 0000000..3a36b84
--- /dev/null
+++ b/drivers/i2c/busses/i2c-zx2967.c
@@ -0,0 +1,676 @@
+/*
+ * ZTE's zx2967 family i2c bus controller driver
+ *
+ * Copyright (C) 2017 ZTE Ltd.
+ *
+ * Author: Baoyou Xie <baoyou.xie@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define REG_CMD 0x04
+#define REG_DEVADDR_H 0x0C
+#define REG_DEVADDR_L 0x10
+#define REG_CLK_DIV_FS 0x14
+#define REG_CLK_DIV_HS 0x18
+#define REG_WRCONF 0x1C
+#define REG_RDCONF 0x20
+#define REG_DATA 0x24
+#define REG_STAT 0x28
+
+#define I2C_STOP 0
+#define I2C_MASTER BIT(0)
+#define I2C_ADDR_MODE_TEN BIT(1)
+#define I2C_IRQ_MSK_ENABLE BIT(3)
+#define I2C_RW_READ BIT(4)
+#define I2C_CMB_RW_EN BIT(5)
+#define I2C_START BIT(6)
+
+#define I2C_ADDR_LOW_MASK GENMASK(6, 0)
+#define I2C_ADDR_LOW_SHIFT 0
+#define I2C_ADDR_HI_MASK GENMASK(2, 0)
+#define I2C_ADDR_HI_SHIFT 7
+
+#define I2C_WFIFO_RESET BIT(7)
+#define I2C_RFIFO_RESET BIT(7)
+
+#define I2C_IRQ_ACK_CLEAR BIT(7)
+#define I2C_INT_MASK GENMASK(6, 0)
+
+#define I2C_TRANS_DONE BIT(0)
+#define I2C_ERROR_DEVICE BIT(1)
+#define I2C_ERROR_DATA BIT(2)
+#define I2C_ERROR_MASK GENMASK(2, 1)
+
+#define I2C_SR_BUSY BIT(6)
+
+#define I2C_SR_EDEVICE BIT(1)
+#define I2C_SR_EDATA BIT(2)
+
+#define I2C_FIFO_MAX 16
+
+#define I2C_TIMEOUT msecs_to_jiffies(1000)
+
+#define DEV(i2c) (&i2c->adap.dev)
+
+struct zx2967_i2c_info {
+ spinlock_t lock;
+ struct i2c_adapter adap;
+ struct clk *clk;
+ struct completion complete;
+ u32 clk_freq;
+ void __iomem *reg_base;
+ size_t residue;
+ int irq;
+ int msg_rd;
+ u8 *cur_trans;
+ u8 access_cnt;
+ bool is_suspended;
+};
+
+static void zx2967_i2c_writel(struct zx2967_i2c_info *zx_i2c,
+ u32 val, unsigned long reg)
+{
+ writel_relaxed(val, zx_i2c->reg_base + reg);
+}
+
+static u32 zx2967_i2c_readl(struct zx2967_i2c_info *zx_i2c, unsigned long reg)
+{
+ return readl_relaxed(zx_i2c->reg_base + reg);
+}
+
+static void zx2967_i2c_writesb(struct zx2967_i2c_info *zx_i2c,
+ void *data, unsigned long reg, int len)
+{
+ writesb(zx_i2c->reg_base + reg, data, len);
+}
+
+static void zx2967_i2c_readsb(struct zx2967_i2c_info *zx_i2c,
+ void *data, unsigned long reg, int len)
+{
+ readsb(zx_i2c->reg_base + reg, data, len);
+}
+
+static void zx2967_i2c_start_ctrl(struct zx2967_i2c_info *zx_i2c)
+{
+ u32 status;
+ u32 ctl;
+
+ status = zx2967_i2c_readl(zx_i2c, REG_STAT);
+ status |= I2C_IRQ_ACK_CLEAR;
+ zx2967_i2c_writel(zx_i2c, status, REG_STAT);
+
+ ctl = zx2967_i2c_readl(zx_i2c, REG_CMD);
+ if (zx_i2c->msg_rd)
+ ctl |= I2C_RW_READ;
+ else
+ ctl &= ~I2C_RW_READ;
+ ctl &= ~I2C_CMB_RW_EN;
+ ctl |= I2C_START;
+ zx2967_i2c_writel(zx_i2c, ctl, REG_CMD);
+}
+
+static void zx2967_i2c_flush_fifos(struct zx2967_i2c_info *zx_i2c)
+{
+ u32 offset;
+ u32 val;
+
+ if (zx_i2c->msg_rd) {
+ offset = REG_RDCONF;
+ val = I2C_RFIFO_RESET;
+ } else {
+ offset = REG_WRCONF;
+ val = I2C_WFIFO_RESET;
+ }
+
+ val |= zx2967_i2c_readl(zx_i2c, offset);
+ zx2967_i2c_writel(zx_i2c, val, offset);
+}
+
+static int zx2967_i2c_empty_rx_fifo(struct zx2967_i2c_info *zx_i2c, u32 size)
+{
+ u8 val[I2C_FIFO_MAX] = {0};
+ int i;
+
+ if (size > I2C_FIFO_MAX) {
+ dev_err(DEV(zx_i2c), "fifo size %d over the max value %d\n",
+ size, I2C_FIFO_MAX);
+ return -EINVAL;
+ }
+
+ zx2967_i2c_readsb(zx_i2c, val, REG_DATA, size);
+ for (i = 0; i < size; i++) {
+ *zx_i2c->cur_trans++ = val[i];
+ zx_i2c->residue--;
+ }
+
+ barrier();
+
+ return 0;
+}
+
+static int zx2967_i2c_fill_tx_fifo(struct zx2967_i2c_info *zx_i2c)
+{
+ size_t residue = zx_i2c->residue;
+ u8 *buf = zx_i2c->cur_trans;
+
+ if (residue == 0) {
+ dev_err(DEV(zx_i2c), "residue is %d\n", (int)residue);
+ return -EINVAL;
+ }
+
+ if (residue <= I2C_FIFO_MAX) {
+ zx2967_i2c_writesb(zx_i2c, buf, REG_DATA, residue);
+
+ /* Again update before writing to FIFO to make sure isr sees. */
+ zx_i2c->residue = 0;
+ zx_i2c->cur_trans = NULL;
+ } else {
+ zx2967_i2c_writesb(zx_i2c, buf, REG_DATA, I2C_FIFO_MAX);
+ zx_i2c->residue -= I2C_FIFO_MAX;
+ zx_i2c->cur_trans += I2C_FIFO_MAX;
+ }
+
+ barrier();
+
+ return 0;
+}
+
+static int zx2967_i2c_reset_hardware(struct zx2967_i2c_info *zx_i2c)
+{
+ u32 val;
+ u32 clk_div;
+ u32 status;
+
+ val = I2C_MASTER | I2C_IRQ_MSK_ENABLE;
+ zx2967_i2c_writel(zx_i2c, val, REG_CMD);
+
+ clk_div = clk_get_rate(zx_i2c->clk) / zx_i2c->clk_freq - 1;
+ zx2967_i2c_writel(zx_i2c, clk_div, REG_CLK_DIV_FS);
+ zx2967_i2c_writel(zx_i2c, clk_div, REG_CLK_DIV_HS);
+
+ zx2967_i2c_writel(zx_i2c, I2C_FIFO_MAX - 1, REG_WRCONF);
+ zx2967_i2c_writel(zx_i2c, I2C_FIFO_MAX - 1, REG_RDCONF);
+ zx2967_i2c_writel(zx_i2c, 1, REG_RDCONF);
+
+ zx2967_i2c_flush_fifos(zx_i2c);
+
+ status = zx2967_i2c_readl(zx_i2c, REG_STAT);
+ if (status & I2C_SR_BUSY)
+ return -EBUSY;
+ if (status & (I2C_SR_EDEVICE | I2C_SR_EDATA))
+ return -EIO;
+
+ enable_irq(zx_i2c->irq);
+
+ return 0;
+}
+
+static void zx2967_i2c_isr_clr(struct zx2967_i2c_info *zx_i2c)
+{
+ u32 status;
+
+ status = zx2967_i2c_readl(zx_i2c, REG_STAT);
+ status |= I2C_IRQ_ACK_CLEAR;
+ zx2967_i2c_writel(zx_i2c, status, REG_STAT);
+}
+
+static irqreturn_t zx2967_i2c_isr(int irq, void *dev_id)
+{
+ u32 status;
+ struct zx2967_i2c_info *zx_i2c = (struct zx2967_i2c_info *)dev_id;
+ unsigned long flags;
+
+ spin_lock_irqsave(&zx_i2c->lock, flags);
+
+ status = zx2967_i2c_readl(zx_i2c, REG_STAT) & I2C_INT_MASK;
+ zx2967_i2c_isr_clr(zx_i2c);
+
+ if (status & I2C_ERROR_MASK) {
+ spin_unlock_irqrestore(&zx_i2c->lock, flags);
+ return IRQ_HANDLED;
+ }
+
+ if (status & I2C_TRANS_DONE)
+ complete(&zx_i2c->complete);
+
+ spin_unlock_irqrestore(&zx_i2c->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static void zx2967_set_addr(struct zx2967_i2c_info *zx_i2c, u16 addr)
+{
+ u16 val;
+
+ val = (addr >> I2C_ADDR_LOW_SHIFT) & I2C_ADDR_LOW_MASK;
+ zx2967_i2c_writel(zx_i2c, val, REG_DEVADDR_L);
+
+ val = (addr >> I2C_ADDR_HI_SHIFT) & I2C_ADDR_HI_MASK;
+ zx2967_i2c_writel(zx_i2c, val, REG_DEVADDR_H);
+ if (val)
+ val = zx2967_i2c_readl(zx_i2c, REG_CMD) | I2C_ADDR_MODE_TEN;
+ else
+ val = zx2967_i2c_readl(zx_i2c, REG_CMD) & ~I2C_ADDR_MODE_TEN;
+ zx2967_i2c_writel(zx_i2c, val, REG_CMD);
+}
+
+static int
+zx2967_i2c_xfer_read_bytes(struct zx2967_i2c_info *zx_i2c, u32 bytes)
+{
+ unsigned long time_left;
+
+ reinit_completion(&zx_i2c->complete);
+ zx2967_i2c_writel(zx_i2c, bytes - 1, REG_RDCONF);
+ zx2967_i2c_start_ctrl(zx_i2c);
+
+ time_left = wait_for_completion_timeout(&zx_i2c->complete,
+ I2C_TIMEOUT);
+ if (time_left == 0) {
+ dev_err(DEV(zx_i2c), "read i2c transfer timed out\n");
+ disable_irq(zx_i2c->irq);
+ zx2967_i2c_reset_hardware(zx_i2c);
+ return -EIO;
+ }
+
+ return zx2967_i2c_empty_rx_fifo(zx_i2c, bytes);
+}
+
+static int zx2967_i2c_xfer_read(struct zx2967_i2c_info *zx_i2c)
+{
+ int ret;
+ int i;
+
+ for (i = 0; i < zx_i2c->access_cnt; i++) {
+ ret = zx2967_i2c_xfer_read_bytes(zx_i2c, I2C_FIFO_MAX);
+ if (ret)
+ return ret;
+ }
+
+ if (zx_i2c->residue > 0) {
+ ret = zx2967_i2c_xfer_read_bytes(zx_i2c, zx_i2c->residue);
+ if (ret)
+ return ret;
+ }
+
+ zx_i2c->residue = 0;
+ zx_i2c->access_cnt = 0;
+ return 0;
+}
+
+static int
+zx2967_i2c_xfer_write_bytes(struct zx2967_i2c_info *zx_i2c, u32 bytes)
+{
+ unsigned long time_left;
+ int ret;
+
+ reinit_completion(&zx_i2c->complete);
+
+ ret = zx2967_i2c_fill_tx_fifo(zx_i2c);
+ if (ret)
+ return ret;
+
+ zx2967_i2c_start_ctrl(zx_i2c);
+
+ time_left = wait_for_completion_timeout(&zx_i2c->complete,
+ I2C_TIMEOUT);
+ if (time_left == 0) {
+ dev_err(DEV(zx_i2c), "write i2c transfer timed out\n");
+ disable_irq(zx_i2c->irq);
+ zx2967_i2c_reset_hardware(zx_i2c);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int zx2967_i2c_xfer_write(struct zx2967_i2c_info *zx_i2c)
+{
+ int ret;
+ int i;
+
+ for (i = 0; i < zx_i2c->access_cnt; i++) {
+ ret = zx2967_i2c_xfer_write_bytes(zx_i2c, I2C_FIFO_MAX);
+ if (ret)
+ return ret;
+ }
+
+ if (zx_i2c->residue > 0) {
+ ret = zx2967_i2c_xfer_write_bytes(zx_i2c, zx_i2c->residue);
+ if (ret)
+ return ret;
+ }
+
+ zx_i2c->residue = 0;
+ zx_i2c->access_cnt = 0;
+ return 0;
+}
+
+static int zx2967_i2c_xfer_msg(struct zx2967_i2c_info *zx_i2c,
+ struct i2c_msg *msg)
+{
+ if (msg->len == 0)
+ return -EINVAL;
+
+ zx2967_i2c_flush_fifos(zx_i2c);
+
+ zx_i2c->cur_trans = msg->buf;
+ zx_i2c->residue = msg->len;
+ zx_i2c->access_cnt = msg->len / I2C_FIFO_MAX;
+ zx_i2c->msg_rd = msg->flags & I2C_M_RD;
+
+ if (zx_i2c->msg_rd)
+ return zx2967_i2c_xfer_read(zx_i2c);
+
+ return zx2967_i2c_xfer_write(zx_i2c);
+}
+
+static int zx2967_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct zx2967_i2c_info *zx_i2c = i2c_get_adapdata(adap);
+ int ret;
+ int i;
+
+ if (zx_i2c->is_suspended)
+ return -EBUSY;
+
+ zx2967_set_addr(zx_i2c, msgs->addr);
+
+ for (i = 0; i < num; i++) {
+ ret = zx2967_i2c_xfer_msg(zx_i2c, &msgs[i]);
+ if (ret)
+ return ret;
+ }
+
+ return num;
+}
+
+static void
+zx2967_smbus_xfer_prepare(struct zx2967_i2c_info *zx_i2c, u16 addr,
+ char read_write, u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ u32 val;
+
+ val = zx2967_i2c_readl(zx_i2c, REG_RDCONF);
+ val |= I2C_RFIFO_RESET;
+ zx2967_i2c_writel(zx_i2c, val, REG_RDCONF);
+ zx2967_set_addr(zx_i2c, addr);
+ val = zx2967_i2c_readl(zx_i2c, REG_CMD);
+ val &= ~I2C_RW_READ;
+ zx2967_i2c_writel(zx_i2c, val, REG_CMD);
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ zx2967_i2c_writel(zx_i2c, command, REG_DATA);
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ zx2967_i2c_writel(zx_i2c, command, REG_DATA);
+ if (read_write == I2C_SMBUS_WRITE)
+ zx2967_i2c_writel(zx_i2c, data->byte, REG_DATA);
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ zx2967_i2c_writel(zx_i2c, command, REG_DATA);
+ if (read_write == I2C_SMBUS_WRITE) {
+ zx2967_i2c_writel(zx_i2c, (data->word >> 8), REG_DATA);
+ zx2967_i2c_writel(zx_i2c, (data->word & 0xff),
+ REG_DATA);
+ }
+ break;
+ }
+}
+
+static int zx2967_smbus_xfer_read(struct zx2967_i2c_info *zx_i2c, int size,
+ union i2c_smbus_data *data)
+{
+ unsigned long time_left;
+ u8 buf[2];
+ u32 val;
+
+ reinit_completion(&zx_i2c->complete);
+
+ val = zx2967_i2c_readl(zx_i2c, REG_CMD);
+ val |= I2C_CMB_RW_EN;
+ zx2967_i2c_writel(zx_i2c, val, REG_CMD);
+
+ val = zx2967_i2c_readl(zx_i2c, REG_CMD);
+ val |= I2C_START;
+ zx2967_i2c_writel(zx_i2c, val, REG_CMD);
+
+ time_left = wait_for_completion_timeout(&zx_i2c->complete,
+ I2C_TIMEOUT);
+ if (time_left == 0) {
+ dev_err(DEV(zx_i2c), "i2c read transfer timed out\n");
+ disable_irq(zx_i2c->irq);
+ zx2967_i2c_reset_hardware(zx_i2c);
+ return -EIO;
+ }
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ val = zx2967_i2c_readl(zx_i2c, REG_DATA);
+ data->byte = val;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_PROC_CALL:
+ buf[0] = zx2967_i2c_readl(zx_i2c, REG_DATA);
+ buf[1] = zx2967_i2c_readl(zx_i2c, REG_DATA);
+ data->word = (buf[0] << 8) | buf[1];
+ break;
+ default:
+ dev_warn(DEV(zx_i2c), "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int zx2967_smbus_xfer_write(struct zx2967_i2c_info *zx_i2c)
+{
+ unsigned long time_left;
+ u32 val;
+
+ reinit_completion(&zx_i2c->complete);
+ val = zx2967_i2c_readl(zx_i2c, REG_CMD);
+ val |= I2C_START;
+ zx2967_i2c_writel(zx_i2c, val, REG_CMD);
+
+ time_left = wait_for_completion_timeout(&zx_i2c->complete,
+ I2C_TIMEOUT);
+ if (time_left == 0) {
+ dev_err(DEV(zx_i2c), "i2c write transfer timed out\n");
+ disable_irq(zx_i2c->irq);
+ zx2967_i2c_reset_hardware(zx_i2c);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int zx2967_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ struct zx2967_i2c_info *zx_i2c = i2c_get_adapdata(adap);
+
+ if (size == I2C_SMBUS_QUICK)
+ read_write = I2C_SMBUS_WRITE;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ case I2C_SMBUS_WORD_DATA:
+ zx2967_smbus_xfer_prepare(zx_i2c, addr, read_write,
+ command, size, data);
+ break;
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ if (read_write == I2C_SMBUS_READ)
+ return zx2967_smbus_xfer_read(zx_i2c, size, data);
+
+ return zx2967_smbus_xfer_write(zx_i2c);
+}
+
+#define ZX2967_I2C_FUNCS (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | \
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | \
+ I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL | \
+ I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK)
+
+static u32 zx2967_i2c_func(struct i2c_adapter *adap)
+{
+ return ZX2967_I2C_FUNCS;
+}
+
+static int __maybe_unused zx2967_i2c_suspend(struct device *dev)
+{
+ struct zx2967_i2c_info *zx_i2c = dev_get_drvdata(dev);
+
+ zx_i2c->is_suspended = true;
+ clk_disable_unprepare(zx_i2c->clk);
+
+ return 0;
+}
+
+static int __maybe_unused zx2967_i2c_resume(struct device *dev)
+{
+ struct zx2967_i2c_info *zx_i2c = dev_get_drvdata(dev);
+
+ zx_i2c->is_suspended = false;
+ clk_prepare_enable(zx_i2c->clk);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(zx2967_i2c_dev_pm_ops,
+ zx2967_i2c_suspend, zx2967_i2c_resume);
+
+static const struct i2c_algorithm zx2967_i2c_algo = {
+ .master_xfer = zx2967_i2c_xfer,
+ .smbus_xfer = zx2967_smbus_xfer,
+ .functionality = zx2967_i2c_func,
+};
+
+static const struct of_device_id zx2967_i2c_of_match[] = {
+ { .compatible = "zte,zx296718-i2c", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, zx2967_i2c_of_match);
+
+static int zx2967_i2c_probe(struct platform_device *pdev)
+{
+ struct zx2967_i2c_info *zx_i2c;
+ void __iomem *reg_base;
+ struct resource *res;
+ struct clk *clk;
+ int ret;
+
+ zx_i2c = devm_kzalloc(&pdev->dev, sizeof(*zx_i2c), GFP_KERNEL);
+ if (!zx_i2c)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(reg_base))
+ return PTR_ERR(reg_base);
+
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "missing controller clock");
+ return PTR_ERR(clk);
+ }
+
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable i2c_clk\n");
+ return ret;
+ }
+
+ ret = device_property_read_u32(&pdev->dev, "clock-frequency",
+ &zx_i2c->clk_freq);
+ if (ret) {
+ dev_err(&pdev->dev, "missing clock-frequency");
+ return ret;
+ }
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
+ return ret;
+
+ zx_i2c->irq = ret;
+ zx_i2c->reg_base = reg_base;
+ zx_i2c->clk = clk;
+
+ spin_lock_init(&zx_i2c->lock);
+ init_completion(&zx_i2c->complete);
+ platform_set_drvdata(pdev, zx_i2c);
+
+ ret = zx2967_i2c_reset_hardware(zx_i2c);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialize i2c controller\n");
+ goto err_clk_unprepare;
+ }
+
+ ret = devm_request_irq(&pdev->dev, zx_i2c->irq,
+ zx2967_i2c_isr, 0, dev_name(&pdev->dev), zx_i2c);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request irq %i\n", zx_i2c->irq);
+ goto err_clk_unprepare;
+ }
+
+ i2c_set_adapdata(&zx_i2c->adap, zx_i2c);
+ strlcpy(zx_i2c->adap.name, "zx2967 i2c adapter",
+ sizeof(zx_i2c->adap.name));
+ zx_i2c->adap.algo = &zx2967_i2c_algo;
+ zx_i2c->adap.nr = pdev->id;
+ zx_i2c->adap.dev.parent = &pdev->dev;
+ zx_i2c->adap.dev.of_node = pdev->dev.of_node;
+
+ ret = i2c_add_numbered_adapter(&zx_i2c->adap);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add zx2967 i2c adapter\n");
+ goto err_clk_unprepare;
+ }
+
+ return 0;
+err_clk_unprepare:
+ clk_disable_unprepare(zx_i2c->clk);
+ return ret;
+}
+
+static int zx2967_i2c_remove(struct platform_device *pdev)
+{
+ struct zx2967_i2c_info *zx_i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&zx_i2c->adap);
+ clk_disable_unprepare(zx_i2c->clk);
+
+ return 0;
+}
+
+static struct platform_driver zx2967_i2c_driver = {
+ .probe = zx2967_i2c_probe,
+ .remove = zx2967_i2c_remove,
+ .driver = {
+ .name = "zx2967_i2c",
+ .of_match_table = zx2967_i2c_of_match,
+ .pm = &zx2967_i2c_dev_pm_ops,
+ },
+};
+module_platform_driver(zx2967_i2c_driver);
+
+MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
+MODULE_DESCRIPTION("ZTE zx2967 I2C Bus Controller driver");
+MODULE_LICENSE("GPL v2");
--
2.7.4
^ permalink raw reply related
* [PATCH v6 2/3] MAINTAINERS: add zx2967 i2c controller driver to ARM ZTE architecture
From: Baoyou Xie @ 2017-02-09 9:32 UTC (permalink / raw)
To: shawnguo, andy.shevchenko, jun.nie, baoyou.xie, wsa, robh+dt,
mark.rutland
Cc: devicetree, xie.baoyou, linux-kernel, chen.chaokai, linux-i2c,
wang.qiang01, linux-arm-kernel
In-Reply-To: <1486632753-17363-1-git-send-email-baoyou.xie@linaro.org>
Add the zx2967 i2c controller driver as maintained by ARM ZTE
architecture maintainers, as they're parts of the core IP.
Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
---
MAINTAINERS | 2 ++
1 file changed, 2 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index e63063b..313fab5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1987,9 +1987,11 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: arch/arm/mach-zx/
F: drivers/clk/zte/
+F: drivers/i2c/busses/i2c-zx2967.c
F: drivers/soc/zte/
F: Documentation/devicetree/bindings/arm/zte.txt
F: Documentation/devicetree/bindings/clock/zx296702-clk.txt
+F: Documentation/devicetree/bindings/i2c/i2c-zx2967.txt
F: Documentation/devicetree/bindings/soc/zte/
F: include/dt-bindings/soc/zx*.h
--
2.7.4
^ permalink raw reply related
* [PATCH v6 1/3] dt: bindings: add documentation for zx2967 family i2c controller
From: Baoyou Xie @ 2017-02-09 9:32 UTC (permalink / raw)
To: shawnguo, andy.shevchenko, jun.nie, baoyou.xie, wsa, robh+dt,
mark.rutland
Cc: devicetree, xie.baoyou, linux-kernel, chen.chaokai, linux-i2c,
wang.qiang01, linux-arm-kernel
This patch adds dt-binding documentation for zx2967 family
i2c controller.
Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
Acked-by: Rob Herring <robh@kernel.org>
---
.../devicetree/bindings/i2c/i2c-zx2967.txt | 24 ++++++++++++++++++++++
1 file changed, 24 insertions(+)
create mode 100644 Documentation/devicetree/bindings/i2c/i2c-zx2967.txt
diff --git a/Documentation/devicetree/bindings/i2c/i2c-zx2967.txt b/Documentation/devicetree/bindings/i2c/i2c-zx2967.txt
new file mode 100644
index 0000000..a528374
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-zx2967.txt
@@ -0,0 +1,24 @@
+ZTE zx2967 I2C controller
+
+Required properties:
+ - compatible: must be "zte,zx296718-i2c"
+ - reg: physical address and length of the device registers
+ - interrupts: a single interrupt specifier
+ - clocks: clock for the device
+ - #address-cells: should be <1>
+ - #size-cells: should be <0>
+ - clock-frequency: the desired I2C bus clock frequency.
+
+Examples:
+
+ i2c@112000 {
+ compatible = "zte,zx296718-i2c";
+ reg = <0x00112000 0x1000>;
+ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&osc24m>;
+ #address-cells = <1>
+ #size-cells = <0>;
+ clock-frequency = <1600000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c_global_pin>;
+ };
--
2.7.4
^ permalink raw reply related
* Re: SMBus not found
From: Jean Delvare @ 2017-02-09 8:49 UTC (permalink / raw)
To: Hrvoje T; +Cc: linux-i2c
In-Reply-To: <CANE=DpWWeKNRGhCQciS4aqi9+FXLOmZJabZiuO8FbNq8YP65mw@mail.gmail.com>
Hi Hrvoje,
On Sat, 4 Feb 2017 02:55:02 +0100, Hrvoje T wrote:
> My hardware is HP Probook 6470b laptop, kernel 4.8.0-37-generic,
> lm-sensors version 1:3.4.0-3. I did
>
> # modprobe i2c-dev
> # i2cdetect -l
>
> and got this:
>
> i2c-3 i2c i915 gmbus dpc I2C adapter
> i2c-1 i2c i915 gmbus vga I2C adapter
> i2c-8 i2c DPDDC-D I2C adapter
> i2c-6 i2c DPDDC-B I2C adapter
> i2c-4 i2c i915 gmbus dpb I2C adapter
> i2c-2 i2c i915 gmbus panel I2C adapter
> i2c-0 i2c i915 gmbus ssc I2C adapter
> i2c-7 i2c DPDDC-C I2C adapter
> i2c-5 i2c i915 gmbus dpd I2C adapter
No SMBus here, all the I2C buses listed are from your graphics chip.
> I would like to find out CAS latency times of my RAM memory modules
> without opening the laptop. I guess those are on DIMM slots. dmidecode
> -t memory gives:
>
> Handle 0x0008, DMI type 17, 34 bytes
> Memory Device
> Array Handle: 0x0005
> Error Information Handle: Not Provided
> Total Width: 64 bits
> Data Width: 64 bits
> Size: 4096 MB
> Form Factor: SODIMM
> Set: None
> Locator: Bottom-Slot 2(under)
> Bank Locator: BANK 2
> Type: DDR3
> Type Detail: Synchronous
> Speed: 1600 MHz
> Manufacturer: Ramaxel
> Serial Number: 44BBE80E
> Asset Tag: 9876543210
> Part Number: RMT3160ED58E9W1600
> Rank: Unknown
> Configured Clock Speed: Unknown
Looks good, but DMI doesn't provide detailed timing information, only
speed.
> and lspci:
> (...)
> 00:1f.0 ISA bridge: Intel Corporation HM76 Express Chipset LPC
> Controller (rev 04)
> 00:1f.2 SATA controller: Intel Corporation 7 Series Chipset Family
> 6-port SATA Controller [AHCI mode] (rev 04)
The SMBus should show up as device 00:1f.3 here, but it is missing. It
means it has been hidden by the BIOS. We have some quirks in the kernel
to unhide the SMBus on older Intel chipsets, up to ICH6, but nothing for
recent chipsets.
> I know I could find out latency times on the manufacturer's web page,
> but I would like to know is it possible via i2c? I'm noob in Linux and
> bad at english, sorry for my mistakes and thanks for your help in
> advance.
It would be possible if the BIOS did not hide the SMBus device. But not
on your laptop, at least not until someone adds another PCI quirk to
unhide this specific device after reading its datasheet.
You may try booting memtest86 on your laptop (many Linux distributions
include it on their installation media), it may be able to display the
timing information you are looking for.
Alternatively, temporarily put the memory module in question in another
laptop where the SMBus is not hidden, and capture a dump of the SPD
data.
--
Jean Delvare
SUSE L3 Support
^ permalink raw reply
* Re: [PATCH] eeprom/at24: use device_property_*() functions instead of of_get_property()
From: Andy Shevchenko @ 2017-02-09 0:07 UTC (permalink / raw)
To: Ben Gardner; +Cc: Wolfram Sang, linux-i2c, linux-kernel@vger.kernel.org
In-Reply-To: <1486583636-8940-1-git-send-email-gardner.ben@gmail.com>
On Wed, Feb 8, 2017 at 9:53 PM, Ben Gardner <gardner.ben@gmail.com> wrote:
> Allow the at24 driver to get configuration information from both OF and
> ACPI by using the more generic device_property functions.
> This change was inspired by the at25.c driver.
>
> I have a custom board with a ST M24C02 EEPROM attached to an I2C bus.
> With the following ACPI construct, this patch instantiates a working
> instance of the driver.
>
> Device (EEP0) {
> Name (_HID, "PRP0001")
> Name (_DSD, Package () {
> ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
> Package () {
> Package () {"compatible", Package () {"st,24c02"}},
> Package () {"size", 256},
> Package () {"pagesize", 16},
> },
> })
> Name (_CRS, ResourceTemplate () {
> I2cSerialBus (
> 0x0057, ControllerInitiated, 400000,
> AddressingMode7Bit, "\\_SB.PCI0.I2C3", 0x00,
> ResourceConsumer,,)
> })
> }
>
> Note: Matching the driver to the I2C device requires another patch.
> http://www.spinics.net/lists/linux-acpi/msg71914.html
Nice!
Few comments, after addressing them
FWIW:
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
>
> Signed-off-by: Ben Gardner <gardner.ben@gmail.com>
> ---
> drivers/misc/eeprom/at24.c | 28 +++++++++-------------------
> 1 file changed, 9 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
> index 051b147..9cb8904 100644
> --- a/drivers/misc/eeprom/at24.c
> +++ b/drivers/misc/eeprom/at24.c
> @@ -19,7 +19,6 @@
> #include <linux/log2.h>
> #include <linux/bitops.h>
> #include <linux/jiffies.h>
> -#include <linux/of.h>
> #include <linux/acpi.h>
> #include <linux/i2c.h>
> #include <linux/nvmem-provider.h>
> @@ -562,26 +561,17 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
> return 0;
> }
>
> -#ifdef CONFIG_OF
> -static void at24_get_ofdata(struct i2c_client *client,
> +static void at24_fw_to_chip(struct device *dev,
> struct at24_platform_data *chip)
"fw" here is ambiguous a bit.
Would at24_get_pdata() work for you?
> {
> - const __be32 *val;
> - struct device_node *node = client->dev.of_node;
> -
> - if (node) {
> - if (of_get_property(node, "read-only", NULL))
> - chip->flags |= AT24_FLAG_READONLY;
> - val = of_get_property(node, "pagesize", NULL);
> - if (val)
> - chip->page_size = be32_to_cpup(val);
> - }
> + u32 val;
> +
> + if (device_property_present(dev, "read-only"))
> + chip->flags |= AT24_FLAG_READONLY;
> +
> + if (device_property_read_u32(dev, "pagesize", &val) == 0)
I would use default from probe here.
int ret;
...
ret = ..._u32(..., &val);
if (ret) {
/* ...long comment from ->probe()... */
chip->page_size = 1;
} else
chip->page_size = val;
> + chip->page_size = val;
> }
> -#else
> -static void at24_get_ofdata(struct i2c_client *client,
> - struct at24_platform_data *chip)
> -{ }
> -#endif /* CONFIG_OF */
>
> static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
> {
> @@ -621,7 +611,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
> chip.page_size = 1;
>
> /* update chipdata if OF is present */
This is now redundant.
> - at24_get_ofdata(client, &chip);
> + at24_fw_to_chip(&client->dev, &chip);
>
> chip.setup = NULL;
> chip.context = NULL;
> --
> 2.7.4
>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v5 3/3] i2c: zx2967: add i2c controller driver for ZTE's zx2967 family
From: Andy Shevchenko @ 2017-02-08 22:04 UTC (permalink / raw)
To: Baoyou Xie
Cc: shawnguo-DgEjT+Ai2ygdnm+yROfE0A, jun.nie-QSEj5FYQhm4dnm+yROfE0A,
Wolfram Sang, Rob Herring, Mark Rutland, linux-arm Mailing List,
linux-i2c-u79uwXL29TY76Z2rM5mHXA, devicetree,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
xie.baoyou-Th6q7B73Y6EnDS1+zs4M5A,
chen.chaokai-Th6q7B73Y6EnDS1+zs4M5A,
wang.qiang01-Th6q7B73Y6EnDS1+zs4M5A
In-Reply-To: <1486545372-5184-2-git-send-email-baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
On Wed, Feb 8, 2017 at 11:16 AM, Baoyou Xie <baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> This patch adds i2c controller driver for ZTE's zx2967 family.
>
> Signed-off-by: Baoyou Xie <baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Reviewed-by: Shawn Guo <shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> +static int zx2967_i2c_empty_rx_fifo(struct zx2967_i2c_info *zx_i2c, u32 size)
> +{
> + u8 val[I2C_FIFO_MAX] = {0};
> + int i;
> + zx2967_i2c_readsb(zx_i2c, val, REG_DATA, size);
> + for (i = 0; i < size; i++) {
> + *zx_i2c->buf++ = val[i];
Sorry, I just realized that it might be completely wrong.
Here we advance the buf pointer. If it's allocated the question is
where the beginning pointer is kept?
Or what I missed?
> + zx_i2c->residue--;
> + if (zx_i2c->residue <= 0)
How it could be < 0 ?
> +static int zx2967_i2c_xfer_msg(struct zx2967_i2c_info *zx_i2c,
> + struct i2c_msg *msg)
> +{
> + if (msg->len == 0)
> + return -EINVAL;
> +
> + zx2967_i2c_flush_fifos(zx_i2c);
> +
> + zx_i2c->buf = msg->buf;
> + zx_i2c->residue = msg->len;
> + zx_i2c->access_cnt = msg->len / I2C_FIFO_MAX;
> + zx_i2c->msg_rd = (msg->flags & I2C_M_RD);
Redundant parens.
> +
> + if (zx_i2c->msg_rd)
> + return zx2967_i2c_xfer_read(zx_i2c);
> +
> + return zx2967_i2c_xfer_write(zx_i2c);
> +}
> + zx2967_i2c_writel(zx_i2c, (msgs->addr & 0x7f), REG_DEVADDR_L);
Ditto
> + zx2967_i2c_writel(zx_i2c, (msgs->addr >> 7) & 0x7, REG_DEVADDR_H);
Though it might be written like this (depends on what style Wolfram prefers)
zx2967_i2c_writel(zx_i2c, (msgs->addr >> 0) & 0x7f, REG_DEVADDR_L);
zx2967_i2c_writel(zx_i2c, (msgs->addr >> 7) & 0x07, REG_DEVADDR_H);
> + return num;
> +}
> +static void
> +zx2967_smbus_xfer_prepare(struct zx2967_i2c_info *zx_i2c, u16 addr,
> + char read_write, u8 command, int size,
> + union i2c_smbus_data *data)
> +{
> + u32 val;
> +
> + val = zx2967_i2c_readl(zx_i2c, REG_RDCONF);
> + val |= I2C_RFIFO_RESET;
> + zx2967_i2c_writel(zx_i2c, val, REG_RDCONF);
> + zx2967_i2c_writel(zx_i2c, (addr & 0x7f), REG_DEVADDR_L);
Redundant parens.
> + case I2C_SMBUS_WORD_DATA:
> + zx2967_i2c_writel(zx_i2c, command, REG_DATA);
> + if (read_write == I2C_SMBUS_WRITE) {
> + zx2967_i2c_writel(zx_i2c, (data->word >> 8), REG_DATA);
> + zx2967_i2c_writel(zx_i2c, (data->word & 0xff),
Btw does hw support byte access?
If so, _writeb() / _readb() would help a lot in this driver.
> + REG_DATA);
> + }
> + break;
> + }
> +}
> +static int zx2967_i2c_probe(struct platform_device *pdev)
> +{
> + struct zx2967_i2c_info *zx_i2c;
> + void __iomem *reg_base;
> + ret = clk_prepare_enable(clk);
> + if (ret) {
> + dev_err(&pdev->dev, "failed to enable i2c_clk\n");
> + return ret;
> + }
If Dmitry's patch gets upstream earlier than yours I would consider to
switch to devm_clk_prepare_enable().
> +
> + ret = platform_get_irq(pdev, 0);
> + if (ret < 0)
> + return ret;
> + zx_i2c->irq = ret;
I would group this with below assignments...
> +
> + ret = device_property_read_u32(&pdev->dev, "clock-frequency",
> + &zx_i2c->clk_freq);
> + if (ret) {
> + dev_err(&pdev->dev, "missing clock-frequency");
> + return ret;
> + }
> +
> + zx_i2c->reg_base = reg_base;
> + zx_i2c->clk = clk;
...^^^
--
With Best Regards,
Andy Shevchenko
--
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
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