* Re: [PATCH v8 02/12] dt-bindings: document devicetree bindings for mux-controllers and mux-gpio
From: Peter Rosin @ 2017-01-27 18:57 UTC (permalink / raw)
To: Rob Herring
Cc: linux-kernel, Wolfram Sang, Mark Rutland, Jonathan Cameron,
Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
Jonathan Corbet, Andrew Morton, linux-i2c, devicetree, linux-iio,
linux-doc
In-Reply-To: <20170127174919.b7yliip6e7zofrbn@rob-hp-laptop>
On 2017-01-27 18:49, Rob Herring wrote:
> On Wed, Jan 18, 2017 at 04:57:05PM +0100, Peter Rosin wrote:
>> Allow specifying that a single multiplexer controller can be used to control
>> several parallel multiplexers, thus enabling sharing of the multiplexer
>> controller by different consumers.
>>
>> Add a binding for a first mux controller in the form of a GPIO based mux
>> controlled.
>>
>> Acked-by: Jonathan Cameron <jic23@kernel.org>
>> Signed-off-by: Peter Rosin <peda@axentia.se>
>> ---
>> .../devicetree/bindings/mux/mux-controller.txt | 127 +++++++++++++++++++++
>> Documentation/devicetree/bindings/mux/mux-gpio.txt | 68 +++++++++++
>> MAINTAINERS | 5 +
>> 3 files changed, 200 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/mux/mux-controller.txt
>> create mode 100644 Documentation/devicetree/bindings/mux/mux-gpio.txt
>
> A few nits. With those fixed:
>
> Acked-by: Rob Herring <robh@kernel.org>
>
>>
>> diff --git a/Documentation/devicetree/bindings/mux/mux-controller.txt b/Documentation/devicetree/bindings/mux/mux-controller.txt
>> new file mode 100644
>> index 000000000000..42b2177e5ae1
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mux/mux-controller.txt
>> @@ -0,0 +1,127 @@
>> +Common multiplexer controller bindings
>> +======================================
>> +
>> +A multiplexer (or mux) controller will have one, or several, consumer devices
>> +that uses the mux controller. Thus, a mux controller can possibly control
>> +several parallel multiplexers. Presumably there will be at least one
>> +multiplexer needed by each consumer, but a single mux controller can of course
>> +control several multiplexers for a single consumer.
>> +
>> +A mux controller provides a number of states to its consumers, and the state
>> +space is a simple zero-based enumeration. I.e. 0-1 for a 2-way multiplexer,
>> +0-7 for an 8-way multiplexer, etc.
>> +
>> +
>> +Consumers
>> +---------
>> +
>> +Mux controller consumers should specify a list of mux controllers that they
>> +want to use with a property containing a 'mux-ctrl-list':
>> +
>> + mux-ctrl-list ::= <single-mux-ctrl> [mux-ctrl-list]
>> + single-mux-ctrl ::= <mux-ctrl-phandle> [mux-ctrl-specifier]
>> + mux-ctrl-phandle : phandle to mux controller node
>> + mux-ctrl-specifier : array of #mux-control-cells specifying the
>> + given mux controller (controller specific)
>> +
>> +Mux controller properties should be named "mux-controls". The exact meaning of
>> +each mux controller property must be documented in the device tree binding for
>> +each consumer. An optional property "mux-control-names" may contain a list of
>> +strings to label each of the mux controllers listed in the "mux-controls"
>> +property.
>> +
>> +Drivers for devices that use more than a single mux controller can use the
>> +"mux-control-names" property to map the name of the requested mux controller
>> +to an index into the list given by the "mux-controls" property.
>> +
>> +mux-ctrl-specifier typically encodes the chip-relative mux controller number.
>> +If the mux controller chip only provides a single mux controller, the
>> +mux-ctrl-specifier can typically be left out.
>> +
>> +Example:
>> +
>> + /* One consumer of a 2-way mux controller (one GPIO-line) */
>> + mux: mux-controller {
>> + compatible = "mux-gpio";
>> + #mux-control-cells = <0>;
>> +
>> + mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>;
>> + };
>> +
>> + adc-mux {
>> + compatible = "io-channel-mux";
>> + io-channels = <&adc 0>;
>> + io-channel-names = "parent";
>> + mux-controls = <&mux>;
>> + mux-control-names = "adc";
>> +
>> + channels = "sync", "in";
>> + };
>> +
>> +Note that in the example above, specifying the "mux-control-names" is redundant
>> +because there is only one mux controller in the list.
>> +
>> + /*
>> + * Two consumers (one for an ADC line and one for an i2c bus) of
>> + * parallel 4-way multiplexers controlled by the same two GPIO-lines.
>> + */
>> + mux: mux-controller {
>> + compatible = "mux-gpio";
>> + #mux-control-cells = <0>;
>> +
>> + mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
>> + <&pioA 1 GPIO_ACTIVE_HIGH>;
>> + };
>> +
>> + adc-mux {
>> + compatible = "io-channel-mux";
>> + io-channels = <&adc 0>;
>> + io-channel-names = "parent";
>> + mux-controls = <&mux>;
>> +
>> + channels = "sync-1", "in", "out", "sync-2";
>> + };
>> +
>> + i2c-mux {
>> + compatible = "i2c-mux-simple,mux-locked";
>> + i2c-parent = <&i2c1>;
>> + mux-controls = <&mux>;
>> +
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> +
>> + i2c@0 {
>> + reg = <0>;
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> +
>> + ssd1307: oled@3c {
>> + /* ... */
>> + };
>> + };
>> +
>> + i2c@3 {
>> + reg = <3>;
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> +
>> + pca9555: pca9555@20 {
>> + /* ... */
>> + };
>> + };
>> + };
>> +
>> +
>> +Mux controller nodes
>> +--------------------
>> +
>> +Mux controller nodes must specify the number of cells used for the
>> +specifier using the '#mux-control-cells' property.
>> +
>> +An example mux controller might look like this:
>> +
>> + mux: adg792a@50 {
>
> mux-controller@50
Right, adding that to my queue.
>> + compatible = "adi,adg792a";
>> + reg = <0x50>;
>> + #mux-control-cells = <1>;
>> + };
>> diff --git a/Documentation/devicetree/bindings/mux/mux-gpio.txt b/Documentation/devicetree/bindings/mux/mux-gpio.txt
>> new file mode 100644
>> index 000000000000..8f6bda6f9d78
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mux/mux-gpio.txt
>> @@ -0,0 +1,68 @@
>> +GPIO-based multiplexer controller bindings
>> +
>> +Define what GPIO pins are used to control a multiplexer. Or several
>> +multiplexers, if the same pins control more than one multiplexer.
>> +
>> +Required properties:
>> +- compatible : "mux-gpio"
>
> Just to be consistent with other gpio compatibles: gpio-mux
Sure, I'll also rename mux-gpio.txt to gpio-mux.txt and mux-adg792a.txt
to adi,adg792a.txt so that the file names match the compatible string.
>> +- mux-gpios : list of gpios used to control the multiplexer, least
>> + significant bit first.
>> +- #mux-control-cells : <0>
>> +* Standard mux-controller bindings as decribed in mux-controller.txt
>> +
>> +Optional properties:
>> +- idle-state : if present, the state the mux will have when idle.
>
> Why is this gpio specific. Can be a common controller property?
The binding isn't appropriate for e.g. adg792a and it will not be
appropriate for any mux chip with more than one mux controller. But
sure, there could be a generic binding for all chips with a single
mux controller...
So, do you still think idle-state should be a generic binding?
Cheers,
peda
^ permalink raw reply
* [PATCH] i2c: busses: constify i2c_algorithm structures
From: Bhumika Goyal @ 2017-01-27 18:06 UTC (permalink / raw)
To: julia.lawall, ludovic.desroches, wsa, sonic.zhang, jarkko.nikula,
andriy.shevchenko, mika.westerberg, jdelvare, patrice.chotard,
linux-i2c, linux-kernel, adi-buildroot-devel, linux-arm-kernel,
kernel
Cc: Bhumika Goyal
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.
Done using Coccinelle:
@r disable optional_qualifier@
identifier i;
position p;
@@
static struct i2c_algorithm i@p={...};
@ok@
identifier r.i,x;
position p;
struct i2c_adapter adapter;
struct xlr_i2c_private priv;
@@
(
adapter.algo=&i@p;
|
priv.adap.algo=&i@p;
)
@bad@
position p!={r.p,ok.p};
identifier r.i;
@@
i@p
@depends on !bad disable optional_qualifier@
identifier r.i;
@@
+const
struct i2c_algorithm i;
File size details before and after patching.
First line of every .o file shows the file size before patching
and second line shows the size after patching.
text data bss dec hex filename
9138 1328 8 10474 28ea drivers/i2c/busses/i2c-at91.o
9178 1280 8 10466 28e2 drivers/i2c/busses/i2c-at91.o
7555 657 8 8220 201c i2c/busses/i2c-designware-core.o
7619 617 8 8244 2034 i2c/busses/i2c-designware-core.o
7240 2240 120 9600 2580 drivers/i2c/busses/i2c-eg20t.o
7304 2176 120 9600 2580 drivers/i2c/busses/i2c-eg20t.o
2399 248 8 2655 a5f drivers/i2c/busses/i2c-emev2.o
2455 192 8 2655 a5f drivers/i2c/busses/i2c-emev2.o
3766 688 8 4462 116e i2c/busses/i2c-imx-lpi2c.o
3814 632 8 4454 1166 i2c/busses/i2c-imx-lpi2c.o
11793 4280 16 16089 3ed9 drivers/i2c/busses/i2c-imx.o
11857 4216 16 16089 3ed9 drivers/i2c/busses/i2c-imx.o
4046 656 8 4710 1266 drivers/i2c/busses/i2c-nforce2.o
4110 592 8 4710 1266 drivers/i2c/busses/i2c-nforce2.o
1397 464 0 1861 745 i2c/busses/i2c-robotfuzz-osif.o
1437 408 0 1845 735 i2c/busses/i2c-robotfuzz-osif.o
9622 1216 16 10854 2a66 i2c/busses/i2c-sh_mobile.o
9662 1160 16 10838 2a56 i2c/busses/i2c-sh_mobile.o
4936 576 8 5520 1590 drivers/i2c/busses/i2c-st.o
5000 512 8 5520 1590 drivers/i2c/busses/i2c-st.o
3404 248 8 3660 e4c i2c/busses/i2c-xgene-slimpro.o
3460 192 8 3660 e4c i2c/busses/i2c-xgene-slimpro.o
2741 600 8 3349 d15 drivers/i2c/busses/i2c-xlp9xx.o
2797 544 8 3349 d15 drivers/i2c/busses/i2c-xlp9xx.o
2643 248 8 2899 b53 drivers/i2c/busses/i2c-xlr.o
2707 192 8 2907 b5b drivers/i2c/busses/i2c-xlr.o
Signed-off-by: Bhumika Goyal <bhumirks@gmail.com>
---
drivers/i2c/busses/i2c-at91.c | 2 +-
drivers/i2c/busses/i2c-bfin-twi.c | 2 +-
drivers/i2c/busses/i2c-designware-core.c | 2 +-
drivers/i2c/busses/i2c-eg20t.c | 2 +-
drivers/i2c/busses/i2c-emev2.c | 2 +-
drivers/i2c/busses/i2c-imx-lpi2c.c | 2 +-
drivers/i2c/busses/i2c-imx.c | 2 +-
drivers/i2c/busses/i2c-nforce2.c | 2 +-
drivers/i2c/busses/i2c-robotfuzz-osif.c | 2 +-
drivers/i2c/busses/i2c-sh_mobile.c | 2 +-
drivers/i2c/busses/i2c-st.c | 2 +-
drivers/i2c/busses/i2c-xgene-slimpro.c | 2 +-
drivers/i2c/busses/i2c-xlp9xx.c | 2 +-
drivers/i2c/busses/i2c-xlr.c | 2 +-
14 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index 0b86c61..e4fcb0c 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -820,7 +820,7 @@ static u32 at91_twi_func(struct i2c_adapter *adapter)
| I2C_FUNC_SMBUS_READ_BLOCK_DATA;
}
-static struct i2c_algorithm at91_twi_algorithm = {
+static const struct i2c_algorithm at91_twi_algorithm = {
.master_xfer = at91_twi_xfer,
.functionality = at91_twi_func,
};
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index 29d00c4..9fe942b 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -563,7 +563,7 @@ static u32 bfin_twi_functionality(struct i2c_adapter *adap)
I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK;
}
-static struct i2c_algorithm bfin_twi_algorithm = {
+static const struct i2c_algorithm bfin_twi_algorithm = {
.master_xfer = bfin_twi_master_xfer,
.smbus_xfer = bfin_twi_smbus_xfer,
.functionality = bfin_twi_functionality,
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index 6d81c56..a62c14c 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -822,7 +822,7 @@ static u32 i2c_dw_func(struct i2c_adapter *adap)
return dev->functionality;
}
-static struct i2c_algorithm i2c_dw_algo = {
+static const struct i2c_algorithm i2c_dw_algo = {
.master_xfer = i2c_dw_xfer,
.functionality = i2c_dw_func,
};
diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c
index 5ce71ce..bdeab01 100644
--- a/drivers/i2c/busses/i2c-eg20t.c
+++ b/drivers/i2c/busses/i2c-eg20t.c
@@ -715,7 +715,7 @@ static u32 pch_i2c_func(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
}
-static struct i2c_algorithm pch_algorithm = {
+static const struct i2c_algorithm pch_algorithm = {
.master_xfer = pch_i2c_xfer,
.functionality = pch_i2c_func
};
diff --git a/drivers/i2c/busses/i2c-emev2.c b/drivers/i2c/busses/i2c-emev2.c
index 96bb4e7..3129127 100644
--- a/drivers/i2c/busses/i2c-emev2.c
+++ b/drivers/i2c/busses/i2c-emev2.c
@@ -347,7 +347,7 @@ static int em_i2c_unreg_slave(struct i2c_client *slave)
return 0;
}
-static struct i2c_algorithm em_i2c_algo = {
+static const struct i2c_algorithm em_i2c_algo = {
.master_xfer = em_i2c_xfer,
.functionality = em_i2c_func,
.reg_slave = em_i2c_reg_slave,
diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
index c62b7cd..934f548 100644
--- a/drivers/i2c/busses/i2c-imx-lpi2c.c
+++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
@@ -537,7 +537,7 @@ static u32 lpi2c_imx_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_READ_BLOCK_DATA;
}
-static struct i2c_algorithm lpi2c_imx_algo = {
+static const struct i2c_algorithm lpi2c_imx_algo = {
.master_xfer = lpi2c_imx_xfer,
.functionality = lpi2c_imx_func,
};
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 47fc1f1..95ed171 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -1037,7 +1037,7 @@ static u32 i2c_imx_func(struct i2c_adapter *adapter)
| I2C_FUNC_SMBUS_READ_BLOCK_DATA;
}
-static struct i2c_algorithm i2c_imx_algo = {
+static const struct i2c_algorithm i2c_imx_algo = {
.master_xfer = i2c_imx_xfer,
.functionality = i2c_imx_func,
};
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index 374b35e..3241bb9 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -296,7 +296,7 @@ static u32 nforce2_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BLOCK_DATA : 0);
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = nforce2_access,
.functionality = nforce2_func,
};
diff --git a/drivers/i2c/busses/i2c-robotfuzz-osif.c b/drivers/i2c/busses/i2c-robotfuzz-osif.c
index 89d8b41..9c0f52b 100644
--- a/drivers/i2c/busses/i2c-robotfuzz-osif.c
+++ b/drivers/i2c/busses/i2c-robotfuzz-osif.c
@@ -117,7 +117,7 @@ static u32 osif_func(struct i2c_adapter *adapter)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
-static struct i2c_algorithm osif_algorithm = {
+static const struct i2c_algorithm osif_algorithm = {
.master_xfer = osif_xfer,
.functionality = osif_func,
};
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 3d9ebe6..3d75593 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -781,7 +781,7 @@ static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
}
-static struct i2c_algorithm sh_mobile_i2c_algorithm = {
+static const struct i2c_algorithm sh_mobile_i2c_algorithm = {
.functionality = sh_mobile_i2c_func,
.master_xfer = sh_mobile_i2c_xfer,
};
diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c
index 1371547..1eb9fa8 100644
--- a/drivers/i2c/busses/i2c-st.c
+++ b/drivers/i2c/busses/i2c-st.c
@@ -776,7 +776,7 @@ static u32 st_i2c_func(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
-static struct i2c_algorithm st_i2c_algo = {
+static const struct i2c_algorithm st_i2c_algo = {
.master_xfer = st_i2c_xfer,
.functionality = st_i2c_func,
};
diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c
index 0ab1e55..dbe7e44 100644
--- a/drivers/i2c/busses/i2c-xgene-slimpro.c
+++ b/drivers/i2c/busses/i2c-xgene-slimpro.c
@@ -372,7 +372,7 @@ static u32 xgene_slimpro_i2c_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_I2C_BLOCK;
}
-static struct i2c_algorithm xgene_slimpro_i2c_algorithm = {
+static const struct i2c_algorithm xgene_slimpro_i2c_algorithm = {
.smbus_xfer = xgene_slimpro_i2c_xfer,
.functionality = xgene_slimpro_i2c_func,
};
diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c
index 84a8b2e..66b464d 100644
--- a/drivers/i2c/busses/i2c-xlp9xx.c
+++ b/drivers/i2c/busses/i2c-xlp9xx.c
@@ -334,7 +334,7 @@ static u32 xlp9xx_i2c_functionality(struct i2c_adapter *adapter)
I2C_FUNC_10BIT_ADDR;
}
-static struct i2c_algorithm xlp9xx_i2c_algo = {
+static const struct i2c_algorithm xlp9xx_i2c_algo = {
.master_xfer = xlp9xx_i2c_xfer,
.functionality = xlp9xx_i2c_functionality,
};
diff --git a/drivers/i2c/busses/i2c-xlr.c b/drivers/i2c/busses/i2c-xlr.c
index ad17d88..484bfa1 100644
--- a/drivers/i2c/busses/i2c-xlr.c
+++ b/drivers/i2c/busses/i2c-xlr.c
@@ -335,7 +335,7 @@ static u32 xlr_func(struct i2c_adapter *adap)
return (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | I2C_FUNC_I2C;
}
-static struct i2c_algorithm xlr_i2c_algo = {
+static const struct i2c_algorithm xlr_i2c_algo = {
.master_xfer = xlr_i2c_xfer,
.functionality = xlr_func,
};
--
1.9.1
^ permalink raw reply related
* Re: [PATCH v8 02/12] dt-bindings: document devicetree bindings for mux-controllers and mux-gpio
From: Rob Herring @ 2017-01-27 17:49 UTC (permalink / raw)
To: Peter Rosin
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA, Wolfram Sang, Mark Rutland,
Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
Peter Meerwald-Stadler, Jonathan Corbet, Andrew Morton,
linux-i2c-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1484755035-25927-3-git-send-email-peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
On Wed, Jan 18, 2017 at 04:57:05PM +0100, Peter Rosin wrote:
> Allow specifying that a single multiplexer controller can be used to control
> several parallel multiplexers, thus enabling sharing of the multiplexer
> controller by different consumers.
>
> Add a binding for a first mux controller in the form of a GPIO based mux
> controlled.
>
> Acked-by: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
> ---
> .../devicetree/bindings/mux/mux-controller.txt | 127 +++++++++++++++++++++
> Documentation/devicetree/bindings/mux/mux-gpio.txt | 68 +++++++++++
> MAINTAINERS | 5 +
> 3 files changed, 200 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/mux/mux-controller.txt
> create mode 100644 Documentation/devicetree/bindings/mux/mux-gpio.txt
A few nits. With those fixed:
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>
> diff --git a/Documentation/devicetree/bindings/mux/mux-controller.txt b/Documentation/devicetree/bindings/mux/mux-controller.txt
> new file mode 100644
> index 000000000000..42b2177e5ae1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mux/mux-controller.txt
> @@ -0,0 +1,127 @@
> +Common multiplexer controller bindings
> +======================================
> +
> +A multiplexer (or mux) controller will have one, or several, consumer devices
> +that uses the mux controller. Thus, a mux controller can possibly control
> +several parallel multiplexers. Presumably there will be at least one
> +multiplexer needed by each consumer, but a single mux controller can of course
> +control several multiplexers for a single consumer.
> +
> +A mux controller provides a number of states to its consumers, and the state
> +space is a simple zero-based enumeration. I.e. 0-1 for a 2-way multiplexer,
> +0-7 for an 8-way multiplexer, etc.
> +
> +
> +Consumers
> +---------
> +
> +Mux controller consumers should specify a list of mux controllers that they
> +want to use with a property containing a 'mux-ctrl-list':
> +
> + mux-ctrl-list ::= <single-mux-ctrl> [mux-ctrl-list]
> + single-mux-ctrl ::= <mux-ctrl-phandle> [mux-ctrl-specifier]
> + mux-ctrl-phandle : phandle to mux controller node
> + mux-ctrl-specifier : array of #mux-control-cells specifying the
> + given mux controller (controller specific)
> +
> +Mux controller properties should be named "mux-controls". The exact meaning of
> +each mux controller property must be documented in the device tree binding for
> +each consumer. An optional property "mux-control-names" may contain a list of
> +strings to label each of the mux controllers listed in the "mux-controls"
> +property.
> +
> +Drivers for devices that use more than a single mux controller can use the
> +"mux-control-names" property to map the name of the requested mux controller
> +to an index into the list given by the "mux-controls" property.
> +
> +mux-ctrl-specifier typically encodes the chip-relative mux controller number.
> +If the mux controller chip only provides a single mux controller, the
> +mux-ctrl-specifier can typically be left out.
> +
> +Example:
> +
> + /* One consumer of a 2-way mux controller (one GPIO-line) */
> + mux: mux-controller {
> + compatible = "mux-gpio";
> + #mux-control-cells = <0>;
> +
> + mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>;
> + };
> +
> + adc-mux {
> + compatible = "io-channel-mux";
> + io-channels = <&adc 0>;
> + io-channel-names = "parent";
> + mux-controls = <&mux>;
> + mux-control-names = "adc";
> +
> + channels = "sync", "in";
> + };
> +
> +Note that in the example above, specifying the "mux-control-names" is redundant
> +because there is only one mux controller in the list.
> +
> + /*
> + * Two consumers (one for an ADC line and one for an i2c bus) of
> + * parallel 4-way multiplexers controlled by the same two GPIO-lines.
> + */
> + mux: mux-controller {
> + compatible = "mux-gpio";
> + #mux-control-cells = <0>;
> +
> + mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
> + <&pioA 1 GPIO_ACTIVE_HIGH>;
> + };
> +
> + adc-mux {
> + compatible = "io-channel-mux";
> + io-channels = <&adc 0>;
> + io-channel-names = "parent";
> + mux-controls = <&mux>;
> +
> + channels = "sync-1", "in", "out", "sync-2";
> + };
> +
> + i2c-mux {
> + compatible = "i2c-mux-simple,mux-locked";
> + i2c-parent = <&i2c1>;
> + mux-controls = <&mux>;
> +
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + i2c@0 {
> + reg = <0>;
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + ssd1307: oled@3c {
> + /* ... */
> + };
> + };
> +
> + i2c@3 {
> + reg = <3>;
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + pca9555: pca9555@20 {
> + /* ... */
> + };
> + };
> + };
> +
> +
> +Mux controller nodes
> +--------------------
> +
> +Mux controller nodes must specify the number of cells used for the
> +specifier using the '#mux-control-cells' property.
> +
> +An example mux controller might look like this:
> +
> + mux: adg792a@50 {
mux-controller@50
> + compatible = "adi,adg792a";
> + reg = <0x50>;
> + #mux-control-cells = <1>;
> + };
> diff --git a/Documentation/devicetree/bindings/mux/mux-gpio.txt b/Documentation/devicetree/bindings/mux/mux-gpio.txt
> new file mode 100644
> index 000000000000..8f6bda6f9d78
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mux/mux-gpio.txt
> @@ -0,0 +1,68 @@
> +GPIO-based multiplexer controller bindings
> +
> +Define what GPIO pins are used to control a multiplexer. Or several
> +multiplexers, if the same pins control more than one multiplexer.
> +
> +Required properties:
> +- compatible : "mux-gpio"
Just to be consistent with other gpio compatibles: gpio-mux
> +- mux-gpios : list of gpios used to control the multiplexer, least
> + significant bit first.
> +- #mux-control-cells : <0>
> +* Standard mux-controller bindings as decribed in mux-controller.txt
> +
> +Optional properties:
> +- idle-state : if present, the state the mux will have when idle.
Why is this gpio specific. Can be a common controller property?
> +
> +The multiplexer state is defined as the number represented by the
> +multiplexer GPIO pins, where the first pin is the least significant
> +bit. An active pin is a binary 1, an inactive pin is a binary 0.
> +
> +Example:
> +
> + mux: mux-controller {
> + compatible = "mux-gpio";
> + #mux-control-cells = <0>;
> +
> + mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
> + <&pioA 1 GPIO_ACTIVE_HIGH>;
> + };
> +
> + adc-mux {
> + compatible = "io-channel-mux";
> + io-channels = <&adc 0>;
> + io-channel-names = "parent";
> +
> + mux-controls = <&mux>;
> +
> + channels = "sync-1", "in", "out", "sync-2";
> + };
> +
> + i2c-mux {
> + compatible = "i2c-mux-simple,mux-locked";
> + i2c-parent = <&i2c1>;
> +
> + mux-controls = <&mux>;
> +
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + i2c@0 {
> + reg = <0>;
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + ssd1307: oled@3c {
> + /* ... */
> + };
> + };
> +
> + i2c@3 {
> + reg = <3>;
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + pca9555: pca9555@20 {
> + /* ... */
> + };
> + };
> + };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 40de344ba0e6..be57f5b8f2c2 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -8469,6 +8469,11 @@ S: Orphan
> F: drivers/mmc/host/mmc_spi.c
> F: include/linux/spi/mmc_spi.h
>
> +MULTIPLEXER SUBSYSTEM
> +M: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
> +S: Maintained
> +F: Documentation/devicetree/bindings/mux/
> +
> MULTISOUND SOUND DRIVER
> M: Andrew Veliath <andrewtv-Jdbf3xiKgS8@public.gmane.org>
> S: Maintained
> --
> 2.1.4
>
--
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 1/2] dt-bindings: Add Tegra186 BPMP I2C binding
From: Wolfram Sang @ 2017-01-27 16:09 UTC (permalink / raw)
To: Thierry Reding
Cc: Stephen Warren, Alexandre Courbot, Jon Hunter, linux-i2c,
linux-tegra
In-Reply-To: <20170127083939.20393-2-thierry.reding@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 492 bytes --]
> +- nvidia,bpmp-bus-id:
> + Single-cell integer.
> + Indicates the I2C bus number this DT node represent, as defined by the
> + BPMP firmware.
I'd like to get an ack from Rob for this one if vendor-specific bindings
are still the way to go to encode firmware data. I simply don't know.
> +
> +Example:
> +
> +bpmp {
> + ...
> +
> + i2c {
> + compatible = "nvidia,tegra186-bpmp-i2c";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + nvidia,bpmp-bus-id = <5>;
> + };
> +};
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH v8 12/12] mux: support simplified bindings for single-user gpio mux
From: Rob Herring @ 2017-01-27 15:52 UTC (permalink / raw)
To: Peter Rosin
Cc: Jonathan Cameron, linux-kernel, Wolfram Sang, Mark Rutland,
Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
Jonathan Corbet, Andrew Morton, linux-i2c, devicetree, linux-iio,
linux-doc
In-Reply-To: <d32f335f-56f2-38c1-e4d9-4629926dbe21@axentia.se>
On Mon, Jan 23, 2017 at 11:24:18AM +0100, Peter Rosin wrote:
> On 2017-01-22 14:30, Jonathan Cameron wrote:
> > On 18/01/17 15:57, Peter Rosin wrote:
> >> Allow bindings for a GPIO controlled mux to be specified in the
> >> mux consumer node.
> >>
> >> Signed-off-by: Peter Rosin <peda@axentia.se>
> > Code is good as far as I am concerned. Only question is whether this
>
> Hmmm, now that I think some more about it, the code supporting the
> simplified binding (patch 12/12) is a bit fishy in one respect.
>
> A driver that calls mux_control_get and gets a mux_control that happens
> to be backed by an implicit mux chip (i.e. using the simplified binding)
> will not be able to reverse the resource allocation with less than a
> complete destruction of itself. Now, this is likely not a problem in
> most cases, but I bet it will creep up at the most inopportune time. And
> your remark that I'm the one that has to maintain this makes me dislike
> this concept...
>
> I.e. mux_control_put *should* reverse mux_control_get, but this simply
> does not happen for the implicit mux chips, as implicit mux chips are
> not put away until the owning device is put away.
I think this is because you aren't creating a device in this case. Nodes
in DT are not the only way to create devices. Drivers can create a child
device when they find mux-gpios property.
> Every time I have tried to come up with a way to implement the simplified
> bindings I seem to hit one of these subtleties.
>
> > is worth the hassle given the normal bindings don't give that high
> > a burden in complexity!
I was going to change my mind here, but we already have "mux-gpios" as a
binding at least for i2c-gpio-mux. So really the question is do we want
to support that here?
> I am missing an ack from Rob though.
>
> > I don't really care either way:)
>
> But Rob seems to care, this series just has to find a way to get out of
> his too-much-churn-will-look-at-it-later list. I sadly don't know how to
> pull that trick...
By complaining that I'm putting it off... :) I guess I'm okay with this
series in general. I will reply on the specific patches today.
Rob
^ permalink raw reply
* [PATCH] i2c: piix4: Fix request_region size
From: Ricardo Ribalda Delgado @ 2017-01-27 14:59 UTC (permalink / raw)
To: Andy Shevchenko, Wolfram Sang, Jean Delvare, linux-i2c,
linux-kernel
Cc: Ricardo Ribalda Delgado
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>
---
Please note, not tested on hardware.
drivers/i2c/busses/i2c-piix4.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index e34d82e79b98..73cc6799cc59 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -58,7 +58,7 @@
#define SMBSLVDAT (0xC + piix4_smba)
/* count for request_region */
-#define SMBIOSIZE 8
+#define SMBIOSIZE 9
/* PCI Address Constants */
#define SMBBA 0x090
--
2.11.0
^ permalink raw reply related
* Re: [PATCH v2 12/13] drm/i915: Listen for PMIC bus access notifications
From: Ville Syrjälä @ 2017-01-27 13:52 UTC (permalink / raw)
To: Hans de Goede
Cc: Wolfram Sang, Takashi Iwai, russianneuromancer @ ya . ru,
intel-gfx, linux-i2c, Jarkko Nikula, dri-devel, H . Peter Anvin,
Daniel Vetter, Thomas Gleixner, Andy Shevchenko, Mika Westerberg,
Len Brown
In-Reply-To: <20170123210958.18410-13-hdegoede@redhat.com>
On Mon, Jan 23, 2017 at 10:09:57PM +0100, Hans de Goede wrote:
> Listen for PMIC bus access notifications and get FORCEWAKE_ALL while
> the bus is accessed to avoid needing to do any forcewakes, which need
> PMIC bus access, while the PMIC bus is busy:
>
> This fixes errors like these showing up in dmesg, usually followed
> by a gfx or system freeze:
>
> [drm:fw_domains_get [i915]] *ERROR* render: timed out waiting for forcewake ack request.
> [drm:fw_domains_get [i915]] *MEDIA* render: timed out waiting for forcewake ack request.
> i2c_designware 808622C1:06: punit semaphore timed out, resetting
> i2c_designware 808622C1:06: PUNIT SEM: 2
> i2c_designware 808622C1:06: couldn't acquire bus ownership
>
> Downside of this approach is that it causes wakeups whenever the PMIC
> bus is accessed. Unfortunately we cannot simply wait for the PMIC bus
> to go idle when we hit a race, as forcewakes may be done from interrupt
> handlers where we cannot sleep to wait for the i2c PMIC bus access to
> finish.
>
> Note that the notifications and thus the wakeups will only happen on
> baytrail / cherrytrail devices using PMICs with a shared i2c bus for
> P-Unit and host PMIC access (i2c busses with a _SEM method in their
> APCI node), e.g. an axp288 PMIC.
>
> I plan to write some patches for drivers accessing the PMIC bus to
> limit their bus accesses to a bare minimum (e.g. cache registers, do not
> update battery level more often then 4 times a minute), to limit the
> amount of wakeups.
>
> BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=155241
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> Tested-by: tagorereddy <tagore.chandan@gmail.com>
> ---
> Changes in v2:
> -Spelling: P-Unit, PMIC
> ---
> drivers/gpu/drm/i915/i915_drv.h | 1 +
> drivers/gpu/drm/i915/intel_uncore.c | 35 +++++++++++++++++++++++++++++++++++
> 2 files changed, 36 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index c717329..52f7dde 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -721,6 +721,7 @@ struct intel_uncore {
> const struct intel_forcewake_range *fw_domains_table;
> unsigned int fw_domains_table_entries;
>
> + struct notifier_block pmic_bus_access_nb;
> struct intel_uncore_funcs funcs;
>
> unsigned fifo_count;
> diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
> index 3767307..175fe02 100644
> --- a/drivers/gpu/drm/i915/intel_uncore.c
> +++ b/drivers/gpu/drm/i915/intel_uncore.c
> @@ -25,6 +25,7 @@
> #include "intel_drv.h"
> #include "i915_vgpu.h"
>
> +#include <asm/iosf_mbi.h>
> #include <linux/pm_runtime.h>
>
> #define FORCEWAKE_ACK_TIMEOUT_MS 50
> @@ -429,12 +430,16 @@ static void __intel_uncore_early_sanitize(struct drm_i915_private *dev_priv,
>
> void intel_uncore_suspend(struct drm_i915_private *dev_priv)
> {
> + iosf_mbi_unregister_pmic_bus_access_notifier(
> + &dev_priv->uncore.pmic_bus_access_nb);
> __intel_uncore_forcewake_reset(dev_priv, false);
> }
>
> void intel_uncore_resume(struct drm_i915_private *dev_priv)
> {
> __intel_uncore_early_sanitize(dev_priv, true);
> + iosf_mbi_register_pmic_bus_access_notifier(
> + &dev_priv->uncore.pmic_bus_access_nb);
> i915_check_and_clear_faults(dev_priv);
> }
The early/normal/late suspend/resume ordering starts to bother me a
little more now. I wonder if we're totally safe wrt. the suspend/resume
order of the devices now.
> @@ -1390,6 +1395,28 @@ static void intel_uncore_fw_domains_init(struct drm_i915_private *dev_priv)
> dev_priv->uncore.fw_domains_table_entries = ARRAY_SIZE((d)); \
> }
>
> +static int i915_pmic_bus_access_notifier(struct notifier_block *nb,
> + unsigned long action, void *data)
> +{
> + struct drm_i915_private *dev_priv = container_of(nb,
> + struct drm_i915_private, uncore.pmic_bus_access_nb);
> +
> + switch (action) {
> + case MBI_PMIC_BUS_ACCESS_BEGIN:
> + /*
> + * forcewake all to make sure that we don't need to forcewake
> + * any power-planes while the pmic bus is busy.
> + */
> + intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
I must say I don't really like this stuff at all. But if it helps I gues
we should go for it. I'd like to see the comment elaborate a bit more on
why we think it's is needed.
> + break;
> + case MBI_PMIC_BUS_ACCESS_END:
> + intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
> + break;
> + }
> +
> + return NOTIFY_OK;
> +}
> +
> void intel_uncore_init(struct drm_i915_private *dev_priv)
> {
> i915_check_vgpu(dev_priv);
> @@ -1399,6 +1426,8 @@ void intel_uncore_init(struct drm_i915_private *dev_priv)
> __intel_uncore_early_sanitize(dev_priv, false);
>
> dev_priv->uncore.unclaimed_mmio_check = 1;
> + dev_priv->uncore.pmic_bus_access_nb.notifier_call =
> + i915_pmic_bus_access_notifier;
>
> switch (INTEL_INFO(dev_priv)->gen) {
> default:
> @@ -1458,6 +1487,9 @@ void intel_uncore_init(struct drm_i915_private *dev_priv)
> ASSIGN_READ_MMIO_VFUNCS(vgpu);
> }
>
> + iosf_mbi_register_pmic_bus_access_notifier(
> + &dev_priv->uncore.pmic_bus_access_nb);
> +
> i915_check_and_clear_faults(dev_priv);
> }
> #undef ASSIGN_WRITE_MMIO_VFUNCS
> @@ -1465,6 +1497,9 @@ void intel_uncore_init(struct drm_i915_private *dev_priv)
>
> void intel_uncore_fini(struct drm_i915_private *dev_priv)
> {
> + iosf_mbi_unregister_pmic_bus_access_notifier(
> + &dev_priv->uncore.pmic_bus_access_nb);
> +
> /* Paranoia: make sure we have disabled everything before we exit. */
> intel_uncore_sanitize(dev_priv);
> __intel_uncore_forcewake_reset(dev_priv, false);
> --
> 2.9.3
--
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* Re: [PATCH v2 13/13] drm/i915: Acquire P-Unit access when modifying P-Unit settings
From: Ville Syrjälä @ 2017-01-27 13:51 UTC (permalink / raw)
To: Hans de Goede
Cc: Wolfram Sang, russianneuromancer @ ya . ru, intel-gfx, linux-i2c,
Jarkko Nikula, dri-devel, H . Peter Anvin, Daniel Vetter,
Thomas Gleixner, Andy Shevchenko, Mika Westerberg, Len Brown
In-Reply-To: <20170123210958.18410-14-hdegoede@redhat.com>
On Mon, Jan 23, 2017 at 10:09:58PM +0100, Hans de Goede wrote:
> Make sure the P-Unit or the PMIC i2c bus is not in use when we send a
> request to the P-Unit by calling iosf_mbi_punit_acquire() / _release()
> around P-Unit write accesses.
Can't we just stuff the calls into the actual punit write function
rather than sprinkling them all over the place?
+ a comment would be nice why it's there.
Do we need a kconfig select/depends on the iosf_mbi thing? Or some
ifdefs?
>
> BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=155241
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> Tested-by: tagorereddy <tagore.chandan@gmail.com>
> ---
> Changes in v2:
> -Spelling: P-Unit, PMIC
> -Adjust for iosf_mbi_punit_lock/_unlock to _acquire/_release rename
> ---
> drivers/gpu/drm/i915/intel_display.c | 6 ++++++
> drivers/gpu/drm/i915/intel_pm.c | 9 +++++++++
> drivers/gpu/drm/i915/intel_runtime_pm.c | 9 +++++++++
> 3 files changed, 24 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 5604701..13e5152 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -47,6 +47,7 @@
> #include <drm/drm_rect.h>
> #include <linux/dma_remapping.h>
> #include <linux/reservation.h>
> +#include <asm/iosf_mbi.h>
>
> static bool is_mmio_work(struct intel_flip_work *work)
> {
> @@ -6421,6 +6422,8 @@ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk)
> cmd = 0;
>
> mutex_lock(&dev_priv->rps.hw_lock);
> + iosf_mbi_punit_acquire();
> +
> val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
> val &= ~DSPFREQGUAR_MASK;
> val |= (cmd << DSPFREQGUAR_SHIFT);
> @@ -6430,6 +6433,7 @@ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk)
> 50)) {
> DRM_ERROR("timed out waiting for CDclk change\n");
> }
> + iosf_mbi_punit_release();
> mutex_unlock(&dev_priv->rps.hw_lock);
>
> mutex_lock(&dev_priv->sb_lock);
> @@ -6497,6 +6501,7 @@ static void cherryview_set_cdclk(struct drm_device *dev, int cdclk)
> cmd = DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, cdclk) - 1;
>
> mutex_lock(&dev_priv->rps.hw_lock);
> + iosf_mbi_punit_acquire();
> val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
> val &= ~DSPFREQGUAR_MASK_CHV;
> val |= (cmd << DSPFREQGUAR_SHIFT_CHV);
> @@ -6506,6 +6511,7 @@ static void cherryview_set_cdclk(struct drm_device *dev, int cdclk)
> 50)) {
> DRM_ERROR("timed out waiting for CDclk change\n");
> }
> + iosf_mbi_punit_release();
> mutex_unlock(&dev_priv->rps.hw_lock);
>
> intel_update_cdclk(dev_priv);
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 249623d..adff84a 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -32,6 +32,7 @@
> #include "../../../platform/x86/intel_ips.h"
> #include <linux/module.h>
> #include <drm/drm_atomic_helper.h>
> +#include <asm/iosf_mbi.h>
>
> /**
> * DOC: RC6
> @@ -276,6 +277,7 @@ static void chv_set_memory_dvfs(struct drm_i915_private *dev_priv, bool enable)
> u32 val;
>
> mutex_lock(&dev_priv->rps.hw_lock);
> + iosf_mbi_punit_acquire();
>
> val = vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2);
> if (enable)
> @@ -290,6 +292,7 @@ static void chv_set_memory_dvfs(struct drm_i915_private *dev_priv, bool enable)
> FORCE_DDR_FREQ_REQ_ACK) == 0, 3))
> DRM_ERROR("timed out waiting for Punit DDR DVFS request\n");
>
> + iosf_mbi_punit_release();
> mutex_unlock(&dev_priv->rps.hw_lock);
> }
>
> @@ -298,6 +301,7 @@ static void chv_set_memory_pm5(struct drm_i915_private *dev_priv, bool enable)
> u32 val;
>
> mutex_lock(&dev_priv->rps.hw_lock);
> + iosf_mbi_punit_acquire();
>
> val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
> if (enable)
> @@ -306,6 +310,7 @@ static void chv_set_memory_pm5(struct drm_i915_private *dev_priv, bool enable)
> val &= ~DSP_MAXFIFO_PM5_ENABLE;
> vlv_punit_write(dev_priv, PUNIT_REG_DSPFREQ, val);
>
> + iosf_mbi_punit_release();
> mutex_unlock(&dev_priv->rps.hw_lock);
> }
>
> @@ -4553,6 +4558,7 @@ void vlv_wm_get_hw_state(struct drm_device *dev)
>
> if (IS_CHERRYVIEW(dev_priv)) {
> mutex_lock(&dev_priv->rps.hw_lock);
> + iosf_mbi_punit_acquire();
>
> val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
> if (val & DSP_MAXFIFO_PM5_ENABLE)
> @@ -4582,6 +4588,7 @@ void vlv_wm_get_hw_state(struct drm_device *dev)
> wm->level = VLV_WM_LEVEL_DDR_DVFS;
> }
>
> + iosf_mbi_punit_release();
> mutex_unlock(&dev_priv->rps.hw_lock);
> }
>
> @@ -4988,7 +4995,9 @@ static void valleyview_set_rps(struct drm_i915_private *dev_priv, u8 val)
> I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val));
>
> if (val != dev_priv->rps.cur_freq) {
> + iosf_mbi_punit_acquire();
> vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
> + iosf_mbi_punit_release();
> if (!IS_CHERRYVIEW(dev_priv))
> gen6_set_rps_thresholds(dev_priv, val);
> }
> diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
> index c0b7e95..e66bcc8 100644
> --- a/drivers/gpu/drm/i915/intel_runtime_pm.c
> +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
> @@ -28,6 +28,7 @@
>
> #include <linux/pm_runtime.h>
> #include <linux/vgaarb.h>
> +#include <asm/iosf_mbi.h>
>
> #include "i915_drv.h"
> #include "intel_drv.h"
> @@ -1027,6 +1028,8 @@ static void vlv_set_power_well(struct drm_i915_private *dev_priv,
> if (COND)
> goto out;
>
> + iosf_mbi_punit_acquire();
> +
> ctrl = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL);
> ctrl &= ~mask;
> ctrl |= state;
> @@ -1037,6 +1040,8 @@ static void vlv_set_power_well(struct drm_i915_private *dev_priv,
> state,
> vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL));
>
> + iosf_mbi_punit_release();
> +
> #undef COND
>
> out:
> @@ -1643,6 +1648,8 @@ static void chv_set_pipe_power_well(struct drm_i915_private *dev_priv,
> if (COND)
> goto out;
>
> + iosf_mbi_punit_acquire();
> +
> ctrl = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
> ctrl &= ~DP_SSC_MASK(pipe);
> ctrl |= enable ? DP_SSC_PWR_ON(pipe) : DP_SSC_PWR_GATE(pipe);
> @@ -1653,6 +1660,8 @@ static void chv_set_pipe_power_well(struct drm_i915_private *dev_priv,
> state,
> vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ));
>
> + iosf_mbi_punit_release();
> +
> #undef COND
>
> out:
> --
> 2.9.3
--
Ville Syrjälä
Intel OTC
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH v2 11/13] drm/i915: Add intel_uncore_suspend / resume functions
From: Ville Syrjälä @ 2017-01-27 13:45 UTC (permalink / raw)
To: Hans de Goede
Cc: Wolfram Sang, Takashi Iwai, russianneuromancer @ ya . ru,
intel-gfx, linux-i2c, Jarkko Nikula, dri-devel, H . Peter Anvin,
Daniel Vetter, Thomas Gleixner, Andy Shevchenko, Mika Westerberg,
Len Brown
In-Reply-To: <20170123210958.18410-12-hdegoede@redhat.com>
On Mon, Jan 23, 2017 at 10:09:56PM +0100, Hans de Goede wrote:
> Rename intel_uncore_early_sanitize to intel_uncore_resume, dropping the
> (always true) restore_forcewake argument and add a new intel_uncore_resume
> function to replace the intel_uncore_forcewake_reset(dev_priv, false)
> calls done from the suspend / runtime_suspend functions and make
> intel_uncore_forcewake_reset private.
>
> This is a preparation patch for adding PMIC bus access notifier support.
>
> BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=155241
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> Tested-by: tagorereddy <tagore.chandan@gmail.com>
> ---
> Changes in v2:
> -Spelling: P-Unit, PMIC
> ---
> drivers/gpu/drm/i915/i915_drv.c | 6 +++---
> drivers/gpu/drm/i915/i915_drv.h | 6 ++----
> drivers/gpu/drm/i915/intel_uncore.c | 18 +++++++++++-------
> 3 files changed, 16 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> index aefab9a..5a62d7a 100644
> --- a/drivers/gpu/drm/i915/i915_drv.c
> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -1445,7 +1445,7 @@ static int i915_drm_suspend(struct drm_device *dev)
> opregion_target_state = suspend_to_idle(dev_priv) ? PCI_D1 : PCI_D3cold;
> intel_opregion_notify_adapter(dev_priv, opregion_target_state);
>
> - intel_uncore_forcewake_reset(dev_priv, false);
> + intel_uncore_suspend(dev_priv);
> intel_opregion_unregister(dev_priv);
>
> intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED, true);
> @@ -1690,7 +1690,7 @@ static int i915_drm_resume_early(struct drm_device *dev)
> DRM_ERROR("Resume prepare failed: %d, continuing anyway\n",
> ret);
>
> - intel_uncore_early_sanitize(dev_priv, true);
> + intel_uncore_resume(dev_priv);
>
> if (IS_GEN9_LP(dev_priv)) {
> if (!dev_priv->suspended_to_idle)
> @@ -2344,7 +2344,7 @@ static int intel_runtime_suspend(struct device *kdev)
> return ret;
> }
>
> - intel_uncore_forcewake_reset(dev_priv, false);
> + intel_uncore_suspend(dev_priv);
Doing one from early_resume and the other from the normal suspend makes
my brain hurt a little. If we do that I think we should at least name
the functions appropriately.
>
> enable_rpm_wakeref_asserts(dev_priv);
> WARN_ON_ONCE(atomic_read(&dev_priv->pm.wakeref_count));
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index e9b4ece..c717329 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -2976,14 +2976,12 @@ int intel_irq_install(struct drm_i915_private *dev_priv);
> void intel_irq_uninstall(struct drm_i915_private *dev_priv);
>
> extern void intel_uncore_sanitize(struct drm_i915_private *dev_priv);
> -extern void intel_uncore_early_sanitize(struct drm_i915_private *dev_priv,
> - bool restore_forcewake);
> extern void intel_uncore_init(struct drm_i915_private *dev_priv);
> extern bool intel_uncore_unclaimed_mmio(struct drm_i915_private *dev_priv);
> extern bool intel_uncore_arm_unclaimed_mmio_detection(struct drm_i915_private *dev_priv);
> extern void intel_uncore_fini(struct drm_i915_private *dev_priv);
> -extern void intel_uncore_forcewake_reset(struct drm_i915_private *dev_priv,
> - bool restore);
> +extern void intel_uncore_suspend(struct drm_i915_private *dev_priv);
> +extern void intel_uncore_resume(struct drm_i915_private *dev_priv);
> const char *intel_uncore_forcewake_domain_to_str(const enum forcewake_domain_id id);
> void intel_uncore_forcewake_get(struct drm_i915_private *dev_priv,
> enum forcewake_domains domains);
> diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
> index abe0888..3767307 100644
> --- a/drivers/gpu/drm/i915/intel_uncore.c
> +++ b/drivers/gpu/drm/i915/intel_uncore.c
> @@ -250,7 +250,7 @@ intel_uncore_fw_release_timer(struct hrtimer *timer)
> return HRTIMER_NORESTART;
> }
>
> -void intel_uncore_forcewake_reset(struct drm_i915_private *dev_priv,
> +static void __intel_uncore_forcewake_reset(struct drm_i915_private *dev_priv,
> bool restore)
Maybe leave out this rename to keep the diff a little easier to parse.
> {
> unsigned long irqflags;
> @@ -424,13 +424,17 @@ static void __intel_uncore_early_sanitize(struct drm_i915_private *dev_priv,
> if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_B_LAST))
> info->has_decoupled_mmio = false;
>
> - intel_uncore_forcewake_reset(dev_priv, restore_forcewake);
> + __intel_uncore_forcewake_reset(dev_priv, restore_forcewake);
> }
>
> -void intel_uncore_early_sanitize(struct drm_i915_private *dev_priv,
> - bool restore_forcewake)
> +void intel_uncore_suspend(struct drm_i915_private *dev_priv)
> {
> - __intel_uncore_early_sanitize(dev_priv, restore_forcewake);
> + __intel_uncore_forcewake_reset(dev_priv, false);
> +}
> +
> +void intel_uncore_resume(struct drm_i915_private *dev_priv)
> +{
> + __intel_uncore_early_sanitize(dev_priv, true);
> i915_check_and_clear_faults(dev_priv);
> }
>
> @@ -1463,7 +1467,7 @@ void intel_uncore_fini(struct drm_i915_private *dev_priv)
> {
> /* Paranoia: make sure we have disabled everything before we exit. */
> intel_uncore_sanitize(dev_priv);
> - intel_uncore_forcewake_reset(dev_priv, false);
> + __intel_uncore_forcewake_reset(dev_priv, false);
> }
>
> #define GEN_RANGE(l, h) GENMASK((h) - 1, (l) - 1)
> @@ -1679,7 +1683,7 @@ static int gen6_reset_engines(struct drm_i915_private *dev_priv,
>
> ret = gen6_hw_domain_reset(dev_priv, hw_mask);
>
> - intel_uncore_forcewake_reset(dev_priv, true);
> + __intel_uncore_forcewake_reset(dev_priv, true);
>
> return ret;
> }
> --
> 2.9.3
--
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* Re: [PATCH v3 3/3] spi: acpi: Initialize modalias from of_compatible
From: Andy Shevchenko @ 2017-01-27 13:43 UTC (permalink / raw)
To: Dan O'Donovan
Cc: linux-acpi@vger.kernel.org, Rafael J . Wysocki, Jarkko Nikula,
Mika Westerberg, Mark Brown, Len Brown, linux-i2c, Wolfram Sang,
linux-spi, linux-kernel@vger.kernel.org, Crestez Dan Leonard
In-Reply-To: <1114c19b-5398-799e-8302-ff87adf9d8a3@emutex.com>
On Fri, Jan 27, 2017 at 12:35 PM, Dan O'Donovan <dan@emutex.com> wrote:
> On 01/23/2017 05:11 PM, Andy Shevchenko wrote:
>> On Mon, Jan 23, 2017 at 6:08 PM, Dan O'Donovan <dan@emutex.com> wrote:
>>> + strlcpy(spi->modalias, acpi_device_hid(adev),
>>> + sizeof(spi->modalias));
>> Could this be one line?
> I couldn't see a way to reduce this to one line without exceeding 80
> chars or adding another line somewhere else, so I'll leave this one as
> it is if that's ok.
80 characters per line is not carved in stone. How many do you have
over? 3 like "s);"?
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* [PATCH v4 3/3] spi: acpi: Initialize modalias from of_compatible
From: Dan O'Donovan @ 2017-01-27 13:30 UTC (permalink / raw)
To: linux-acpi, Andy Shevchenko, Rafael J . Wysocki, Jarkko Nikula,
Mika Westerberg, Mark Brown
Cc: Len Brown, linux-i2c, Wolfram Sang, linux-spi, linux-kernel,
Dan O'Donovan, Crestez Dan Leonard
In-Reply-To: <1485523815-9629-1-git-send-email-dan@emutex.com>
From: Crestez Dan Leonard <leonard.crestez@intel.com>
When using devicetree spi_device.modalias is set to the compatible
string with the vendor prefix removed. For SPI devices described via
ACPI the spi_device.modalias string is initialized by acpi_device_hid.
When using ACPI and DT ids this string ends up something like "PRP0001".
Change acpi_register_spi_device to use the of_compatible property if
present. This makes it easier to instantiate spi drivers through ACPI
with DT ids.
Signed-off-by: Crestez Dan Leonard <leonard.crestez@intel.com>
Signed-off-by: Dan O'Donovan <dan@emutex.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Reviewed-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Tested-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
---
drivers/spi/spi.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 656dd3e..9a8c880 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1722,13 +1722,20 @@ static acpi_status acpi_register_spi_device(struct spi_master *master,
return AE_OK;
}
+ /*
+ * Populate modalias from compatible property if available,
+ * otherwise use native ACPI information
+ */
+ if (acpi_of_modalias(adev, spi->modalias, sizeof(spi->modalias)))
+ strlcpy(spi->modalias, acpi_device_hid(adev),
+ sizeof(spi->modalias));
+
if (spi->irq < 0)
spi->irq = acpi_dev_gpio_irq_get(adev, 0);
acpi_device_set_enumerated(adev);
adev->power.flags.ignore_parent = true;
- strlcpy(spi->modalias, acpi_device_hid(adev), sizeof(spi->modalias));
if (spi_add_device(spi)) {
adev->power.flags.ignore_parent = false;
dev_err(&master->dev, "failed to add SPI device %s from ACPI\n",
--
2.7.4
^ permalink raw reply related
* [PATCH v4 2/3] i2c: acpi: Initialize info.type from of_compatible
From: Dan O'Donovan @ 2017-01-27 13:30 UTC (permalink / raw)
To: linux-acpi, Andy Shevchenko, Rafael J . Wysocki, Jarkko Nikula,
Mika Westerberg, Mark Brown
Cc: Len Brown, linux-i2c, Wolfram Sang, linux-spi, linux-kernel,
Dan O'Donovan, Crestez Dan Leonard
In-Reply-To: <1485523815-9629-1-git-send-email-dan@emutex.com>
From: Crestez Dan Leonard <leonard.crestez@intel.com>
When using devicetree i2c_board_info.type is set to the compatible
string with the vendor prefix removed. For I2C devices described via
ACPI the i2c_board_info.type string is set to the ACPI device name. When
using ACPI and DT ids this string ends up something like "PRP0001:00".
If the of_compatible property is present try to use that instead. This
makes it easier to instantiate i2c drivers through ACPI with DT ids.
Signed-off-by: Crestez Dan Leonard <leonard.crestez@intel.com>
Signed-off-by: Dan O'Donovan <dan@emutex.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Reviewed-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Tested-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
---
drivers/i2c/i2c-core.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 583e950..6e99431 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -221,7 +221,12 @@ static int i2c_acpi_get_info(struct acpi_device *adev,
acpi_dev_free_resource_list(&resource_list);
- strlcpy(info->type, dev_name(&adev->dev), sizeof(info->type));
+ /*
+ * Populate modalias from compatible property if available,
+ * otherwise use native ACPI information
+ */
+ if (acpi_of_modalias(adev, info->type, sizeof(info->type)))
+ strlcpy(info->type, dev_name(&adev->dev), sizeof(info->type));
return 0;
}
--
2.7.4
^ permalink raw reply related
* [PATCH v4 1/3] ACPI / bus: Export acpi_of_modalias equiv of of_modalias_node
From: Dan O'Donovan @ 2017-01-27 13:30 UTC (permalink / raw)
To: linux-acpi, Andy Shevchenko, Rafael J . Wysocki, Jarkko Nikula,
Mika Westerberg, Mark Brown
Cc: Len Brown, linux-i2c, Wolfram Sang, linux-spi, linux-kernel,
Dan O'Donovan, Crestez Dan Leonard
In-Reply-To: <1485523815-9629-1-git-send-email-dan@emutex.com>
From: Crestez Dan Leonard <leonard.crestez@intel.com>
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 try to replicate it when using
ACPI with DT ids.
Signed-off-by: Crestez Dan Leonard <leonard.crestez@intel.com>
Signed-off-by: Dan O'Donovan <dan@emutex.com>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Reviewed-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Tested-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
---
drivers/acpi/bus.c | 35 +++++++++++++++++++++++++++++++++++
include/acpi/acpi_bus.h | 1 +
2 files changed, 36 insertions(+)
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 95855cb..8b9657f 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -677,6 +677,41 @@ static bool acpi_of_match_device(struct acpi_device *adev,
return false;
}
+/**
+ * acpi_of_modalias - Like of_modalias_node for ACPI with DT ids
+ * @adev: ACPI device object to match.
+ * @outstr: Pointer to buffer for result
+ * @outlen: Length of outstr value
+ *
+ * This is a counterpart of of_modalias_node() for struct acpi_device
+ * objects. If there is a compatible string for @adev, copy it to the
+ * @outstr location with the vendor prefix stripped.
+ *
+ * Returns 0 on success or negative errno on failure.
+ */
+int acpi_of_modalias(struct acpi_device *adev, char *outstr, size_t outlen)
+{
+ const union acpi_object *of_compatible;
+ const union acpi_object *obj;
+ const char *str, *chr;
+
+ of_compatible = adev->data.of_compatible;
+ if (!of_compatible)
+ return -ENODEV;
+
+ if (of_compatible->type == ACPI_TYPE_PACKAGE)
+ obj = of_compatible->package.elements;
+ else /* Must be ACPI_TYPE_STRING. */
+ obj = of_compatible;
+
+ str = obj->string.pointer;
+ chr = strchr(str, ',');
+ strlcpy(outstr, chr ? chr + 1 : str, outlen);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_of_modalias);
+
static bool __acpi_match_device_cls(const struct acpi_device_id *id,
struct acpi_hardware_id *hwid)
{
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 4242c31..351b4a4 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -522,6 +522,7 @@ void acpi_bus_trim(struct acpi_device *start);
acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd);
int acpi_match_device_ids(struct acpi_device *device,
const struct acpi_device_id *ids);
+int acpi_of_modalias(struct acpi_device *adev, char *outstr, size_t outlen);
int acpi_create_dir(struct acpi_device *);
void acpi_remove_dir(struct acpi_device *);
--
2.7.4
^ permalink raw reply related
* [PATCH v4 0/3] Init device ids from ACPI of_compatible
From: Dan O'Donovan @ 2017-01-27 13:30 UTC (permalink / raw)
To: linux-acpi, Andy Shevchenko, Rafael J . Wysocki, Jarkko Nikula,
Mika Westerberg, Mark Brown
Cc: Len Brown, linux-i2c, Wolfram Sang, linux-spi, linux-kernel,
Dan O'Donovan
In-Reply-To: <1485187737-22414-1-git-send-email-dan@emutex.com>
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"},
}
})
}
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
Crestez Dan Leonard (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
drivers/acpi/bus.c | 35 +++++++++++++++++++++++++++++++++++
drivers/i2c/i2c-core.c | 7 ++++++-
drivers/spi/spi.c | 9 ++++++++-
include/acpi/acpi_bus.h | 1 +
4 files changed, 50 insertions(+), 2 deletions(-)
--
2.7.4
^ permalink raw reply
* Re: [PATCH v2 10/13] i2c: designware-baytrail: Call pmic_bus_access_notifier_chain
From: Jarkko Nikula @ 2017-01-27 11:35 UTC (permalink / raw)
To: Hans de Goede, Daniel Vetter, Jani Nikula,
Ville Syrjälä, Wolfram Sang, Len Brown, Andy Shevchenko,
Thomas Gleixner, H . Peter Anvin
Cc: Takashi Iwai, russianneuromancer @ ya . ru, intel-gfx, dri-devel,
linux-i2c, Mika Westerberg
In-Reply-To: <20170123210958.18410-11-hdegoede@redhat.com>
On 01/23/2017 11:09 PM, Hans de Goede wrote:
> Call the iosf_mbi pmic_bus_access_notifier_chain on bus acquire / release.
>
> BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=155241
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> Tested-by: tagorereddy <tagore.chandan@gmail.com>
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Acked-by: Wolfram Sang <wsa@the-dreams.de>
> ---
> Changes in v2:
> -Spelling: P-Unit, PMIC
> ---
> drivers/i2c/busses/i2c-designware-baytrail.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
Acked-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* Re: [PATCH v2 09/13] i2c: designware-baytrail: Acquire P-Unit access on bus acquire
From: Jarkko Nikula @ 2017-01-27 11:29 UTC (permalink / raw)
To: Hans de Goede, Daniel Vetter, Jani Nikula,
Ville Syrjälä, Wolfram Sang, Len Brown, Andy Shevchenko,
Thomas Gleixner, H . Peter Anvin
Cc: Takashi Iwai, russianneuromancer @ ya . ru, intel-gfx, dri-devel,
linux-i2c, Mika Westerberg
In-Reply-To: <20170123210958.18410-10-hdegoede@redhat.com>
On 01/23/2017 11:09 PM, Hans de Goede wrote:
> Acquire P-Unit access to stop others from accessing the P-Unit while the
> PMIC i2c bus is in use. This is necessary because accessing the P-Unit
> from the kernel may result in the P-Unit trying to access the PMIC i2c
> bus, which results in a hang when it happens while we own the PMIC i2c
> bus semaphore.
>
> BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=155241
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> Tested-by: tagorereddy <tagore.chandan@gmail.com>
> Acked-by: Wolfram Sang <wsa@the-dreams.de>
> ---
> Changes in v2:
> -Spelling: P-Unit, PMIC
> -Adjust for iosf_mbi_punit_lock/_unlock to _acquire/_release rename
> ---
> drivers/i2c/busses/i2c-designware-baytrail.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
Acked-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* Re: [PATCH v3 3/3] spi: acpi: Initialize modalias from of_compatible
From: Dan O'Donovan @ 2017-01-27 10:35 UTC (permalink / raw)
To: Andy Shevchenko
Cc: linux-acpi@vger.kernel.org, Rafael J . Wysocki, Jarkko Nikula,
Mika Westerberg, Mark Brown, Len Brown, linux-i2c, Wolfram Sang,
linux-spi, linux-kernel@vger.kernel.org, Crestez Dan Leonard
In-Reply-To: <CAHp75Vf0NaEFnxWPt9NAa5-jWMM091Y+Tg8D=Du0uECDVoWW4Q@mail.gmail.com>
On 01/23/2017 05:11 PM, Andy Shevchenko wrote:
> On Mon, Jan 23, 2017 at 6:08 PM, Dan O'Donovan <dan@emutex.com> wrote:
>> From: Crestez Dan Leonard <leonard.crestez@intel.com>
>>
>> When using devicetree spi_device.modalias is set to the compatible
>> string with the vendor prefix removed. For SPI devices described via
>> ACPI the spi_device.modalias string is initialized by acpi_device_hid.
>> When using ACPI and DT ids this string ends up something like "PRP0001".
>>
>> Change acpi_register_spi_device to use the of_compatible property if
>> present. This makes it easier to instantiate spi drivers through ACPI
>> with DT ids.
>> + /*
>> + * Populate modalias from compatible property if available,
>> + * otherwise use native ACPI information
>> + */
>> + if ((!adev->data.of_compatible) ||
>> + acpi_of_modalias(adev, spi->modalias, sizeof(spi->modalias)))
> Same comment as in patch 2.
Thanks for the feedback, Andy. The check on of_compatible is redundant,
because its repeated in acpi_of_modalias(), so I'll remove it here (and
in patch 2) to reduce this to one line. v4 on the way.
>> + strlcpy(spi->modalias, acpi_device_hid(adev),
>> + sizeof(spi->modalias));
> Could this be one line?
I couldn't see a way to reduce this to one line without exceeding 80
chars or adding another line somewhere else, so I'll leave this one as
it is if that's ok.
^ permalink raw reply
* [PATCH v2 0/2] i2c: Add Tegra BPMP I2C proxy driver
From: Thierry Reding @ 2017-01-27 8:39 UTC (permalink / raw)
To: Wolfram Sang
Cc: Stephen Warren, Alexandre Courbot, Jon Hunter, linux-i2c,
linux-tegra
From: Thierry Reding <treding@nvidia.com>
Hi Wolfram,
I had originally sent these in for the last merge window but then got
bounces indicating that your email server was not accepting emails. At
the time it seemed like I wasn't the only one having these problems.
Looking at my mailbox that situation now seems to be resolved, so here's
hoping it'll work this time. Note that because of the above I've carried
this in the Tegra tree for a while now to get it more compile testing.
If you end up applying the set, please let me know so I can drop them
from the Tegra tree and avoid conflicts in linux-next.
On the bright side the dependencies for this were merged during the last
release cycle, so these should be good to go in without further
complications.
Thanks,
Thierry
Shardar Shariff Md (1):
i2c: Add Tegra BPMP I2C proxy driver
Stephen Warren (1):
dt-bindings: Add Tegra186 BPMP I2C binding
.../bindings/i2c/nvidia,tegra186-bpmp-i2c.txt | 42 +++
drivers/i2c/busses/Kconfig | 11 +
drivers/i2c/busses/Makefile | 1 +
drivers/i2c/busses/i2c-tegra-bpmp.c | 365 +++++++++++++++++++++
4 files changed, 419 insertions(+)
create mode 100644 Documentation/devicetree/bindings/i2c/nvidia,tegra186-bpmp-i2c.txt
create mode 100644 drivers/i2c/busses/i2c-tegra-bpmp.c
--
2.11.0
^ permalink raw reply
* [PATCH v2 2/2] i2c: Add Tegra BPMP I2C proxy driver
From: Thierry Reding @ 2017-01-27 8:39 UTC (permalink / raw)
To: Wolfram Sang
Cc: Stephen Warren, Alexandre Courbot, Jon Hunter,
linux-i2c-u79uwXL29TY76Z2rM5mHXA,
linux-tegra-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20170127083939.20393-1-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
From: Shardar Shariff Md <smohammed-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Add Tegra BPMP I2C driver. The BPMP is the boot and power management
processor embedded in Tegra SoCs. In newer SoC versions, access to one
of the I2C busses goes via the BPMP, requiring a different "proxy" I2C
driver that accesses the bus via the real I2C driver embedded in the
BPMP firmware.
Signed-off-by: Shardar Shariff Md <smohammed-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/i2c/busses/Kconfig | 11 ++
drivers/i2c/busses/Makefile | 1 +
drivers/i2c/busses/i2c-tegra-bpmp.c | 365 ++++++++++++++++++++++++++++++++++++
3 files changed, 377 insertions(+)
create mode 100644 drivers/i2c/busses/i2c-tegra-bpmp.c
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 0cdc8443deab..e4a603e5e90a 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -919,6 +919,17 @@ config I2C_TEGRA
If you say yes to this option, support will be included for the
I2C controller embedded in NVIDIA Tegra SOCs
+config I2C_TEGRA_BPMP
+ tristate "NVIDIA Tegra BPMP I2C controller"
+ depends on TEGRA_BPMP
+ help
+ If you say yes to this option, support will be included for the I2C
+ controller embedded in NVIDIA Tegra SoCs accessed via the BPMP.
+
+ This I2C driver is a 'virtual' I2C driver. The real driver is part
+ of the BPMP firmware, and this driver merely communicates with that
+ real driver.
+
config I2C_UNIPHIER
tristate "UniPhier FIFO-less I2C controller"
depends on ARCH_UNIPHIER || COMPILE_TEST
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 1c1bac87a9db..beb4809cfd47 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -88,6 +88,7 @@ obj-$(CONFIG_I2C_ST) += i2c-st.o
obj-$(CONFIG_I2C_STU300) += i2c-stu300.o
obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o
obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o
+obj-$(CONFIG_I2C_TEGRA_BPMP) += i2c-tegra-bpmp.o
obj-$(CONFIG_I2C_UNIPHIER) += i2c-uniphier.o
obj-$(CONFIG_I2C_UNIPHIER_F) += i2c-uniphier-f.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
diff --git a/drivers/i2c/busses/i2c-tegra-bpmp.c b/drivers/i2c/busses/i2c-tegra-bpmp.c
new file mode 100644
index 000000000000..480251cce238
--- /dev/null
+++ b/drivers/i2c/busses/i2c-tegra-bpmp.c
@@ -0,0 +1,365 @@
+/*
+ * drivers/i2c/busses/i2c-tegra-bpmp.c
+ *
+ * Copyright (c) 2016 NVIDIA Corporation. All rights reserved.
+ *
+ * Author: Shardar Shariff Md <smohammed-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include <soc/tegra/bpmp-abi.h>
+#include <soc/tegra/bpmp.h>
+
+/*
+ * Serialized I2C message header size is 6 bytes and includes address, flags
+ * and length
+ */
+#define SERIALI2C_HDR_SIZE 6
+
+struct tegra_bpmp_i2c {
+ struct i2c_adapter adapter;
+ struct device *dev;
+
+ struct tegra_bpmp *bpmp;
+ unsigned int bus;
+};
+
+/*
+ * Linux flags are translated to BPMP defined I2C flags that are used in BPMP
+ * firmware I2C driver to avoid any issues in future if Linux I2C flags are
+ * changed.
+ */
+static int tegra_bpmp_xlate_flags(u16 flags, u16 *out)
+{
+ if (flags & I2C_M_TEN) {
+ *out |= SERIALI2C_TEN;
+ flags &= ~I2C_M_TEN;
+ }
+
+ if (flags & I2C_M_RD) {
+ *out |= SERIALI2C_RD;
+ flags &= ~I2C_M_RD;
+ }
+
+ if (flags & I2C_M_STOP) {
+ *out |= SERIALI2C_STOP;
+ flags &= ~I2C_M_STOP;
+ }
+
+ if (flags & I2C_M_NOSTART) {
+ *out |= SERIALI2C_NOSTART;
+ flags &= ~I2C_M_NOSTART;
+ }
+
+ if (flags & I2C_M_REV_DIR_ADDR) {
+ *out |= SERIALI2C_REV_DIR_ADDR;
+ flags &= ~I2C_M_REV_DIR_ADDR;
+ }
+
+ if (flags & I2C_M_IGNORE_NAK) {
+ *out |= SERIALI2C_IGNORE_NAK;
+ flags &= ~I2C_M_IGNORE_NAK;
+ }
+
+ if (flags & I2C_M_NO_RD_ACK) {
+ *out |= SERIALI2C_NO_RD_ACK;
+ flags &= ~I2C_M_NO_RD_ACK;
+ }
+
+ if (flags & I2C_M_RECV_LEN) {
+ *out |= SERIALI2C_RECV_LEN;
+ flags &= ~I2C_M_RECV_LEN;
+ }
+
+ return (flags != 0) ? -EINVAL : 0;
+}
+
+/**
+ * The serialized I2C format is simply the following:
+ * [addr little-endian][flags little-endian][len little-endian][data if write]
+ * [addr little-endian][flags little-endian][len little-endian][data if write]
+ * ...
+ *
+ * The flags are translated from Linux kernel representation to seriali2c
+ * representation. Any undefined flag being set causes an error.
+ *
+ * The data is there only for writes. Reads have the data transferred in the
+ * other direction, and thus data is not present.
+ *
+ * See deserialize_i2c documentation for the data format in the other direction.
+ */
+static int tegra_bpmp_serialize_i2c_msg(struct tegra_bpmp_i2c *i2c,
+ struct mrq_i2c_request *request,
+ struct i2c_msg *msgs,
+ unsigned int num)
+{
+ char *buf = request->xfer.data_buf;
+ unsigned int i, j, pos = 0;
+ int err;
+
+ for (i = 0; i < num; i++) {
+ struct i2c_msg *msg = &msgs[i];
+ u16 flags = 0;
+
+ err = tegra_bpmp_xlate_flags(msg->flags, &flags);
+ if (err < 0)
+ return err;
+
+ buf[pos++] = msg->addr & 0xff;
+ buf[pos++] = (msg->addr & 0xff00) >> 8;
+ buf[pos++] = flags & 0xff;
+ buf[pos++] = (flags & 0xff00) >> 8;
+ buf[pos++] = msg->len & 0xff;
+ buf[pos++] = (msg->len & 0xff00) >> 8;
+
+ if ((flags & SERIALI2C_RD) == 0) {
+ for (j = 0; j < msg->len; j++)
+ buf[pos++] = msg->buf[j];
+ }
+ }
+
+ request->xfer.data_size = pos;
+
+ return 0;
+}
+
+/**
+ * The data in the BPMP -> CPU direction is composed of sequential blocks for
+ * those messages that have I2C_M_RD. So, for example, if you have:
+ *
+ * - !I2C_M_RD, len == 5, data == a0 01 02 03 04
+ * - !I2C_M_RD, len == 1, data == a0
+ * - I2C_M_RD, len == 2, data == [uninitialized buffer 1]
+ * - !I2C_M_RD, len == 1, data == a2
+ * - I2C_M_RD, len == 2, data == [uninitialized buffer 2]
+ *
+ * ...then the data in the BPMP -> CPU direction would be 4 bytes total, and
+ * would contain 2 bytes that will go to uninitialized buffer 1, and 2 bytes
+ * that will go to uninitialized buffer 2.
+ */
+static int tegra_bpmp_i2c_deserialize(struct tegra_bpmp_i2c *i2c, char *buf,
+ size_t size, struct i2c_msg *msgs,
+ unsigned int num)
+{
+ size_t len = 0, pos = 0;
+ unsigned int i;
+
+ for (i = 0; i < num; i++)
+ if (msgs[i].flags & I2C_M_RD)
+ len += msgs[i].len;
+
+ if (len != size)
+ return -EINVAL;
+
+ for (i = 0; i < num; i++) {
+ if (msgs[i].flags & I2C_M_RD) {
+ memcpy(msgs[i].buf, buf + pos, msgs[i].len);
+ pos += msgs[i].len;
+ }
+ }
+
+ return 0;
+}
+
+static int tegra_bpmp_i2c_msg_len_check(struct i2c_msg *msgs, unsigned int num)
+{
+ size_t tx_len = 0, rx_len = 0;
+ unsigned int i;
+
+ for (i = 0; i < num; i++)
+ if (!(msgs[i].flags & I2C_M_RD))
+ tx_len += SERIALI2C_HDR_SIZE + msgs[i].len;
+
+ if (tx_len > TEGRA_I2C_IPC_MAX_IN_BUF_SIZE)
+ return -EINVAL;
+
+ for (i = 0; i < num; i++)
+ if ((msgs[i].flags & I2C_M_RD))
+ rx_len += msgs[i].len;
+
+ if (rx_len > TEGRA_I2C_IPC_MAX_OUT_BUF_SIZE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int tegra_bpmp_i2c_msg_xfer(struct tegra_bpmp_i2c *i2c,
+ struct mrq_i2c_request *request,
+ struct mrq_i2c_response *response)
+{
+ struct tegra_bpmp_message msg;
+ int err;
+
+ request->cmd = CMD_I2C_XFER;
+ request->xfer.bus_id = i2c->bus;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.mrq = MRQ_I2C;
+ msg.tx.data = request;
+ msg.tx.size = sizeof(*request);
+ msg.rx.data = response;
+ msg.rx.size = sizeof(*response);
+
+ if (irqs_disabled())
+ err = tegra_bpmp_transfer_atomic(i2c->bpmp, &msg);
+ else
+ err = tegra_bpmp_transfer(i2c->bpmp, &msg);
+
+ return err;
+}
+
+static int tegra_bpmp_i2c_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs, int num)
+{
+ struct tegra_bpmp_i2c *i2c = i2c_get_adapdata(adapter);
+ struct mrq_i2c_response response;
+ struct mrq_i2c_request request;
+ int err;
+
+ err = tegra_bpmp_i2c_msg_len_check(msgs, num);
+ if (err < 0) {
+ dev_err(i2c->dev, "unsupported message length\n");
+ return err;
+ }
+
+ /* TODO: move this somewhere else */
+ memset(&request, 0, sizeof(request));
+ memset(&response, 0, sizeof(response));
+
+ err = tegra_bpmp_serialize_i2c_msg(i2c, &request, msgs, num);
+ if (err < 0) {
+ dev_err(i2c->dev, "failed to serialize message: %d\n", err);
+ return err;
+ }
+
+ err = tegra_bpmp_i2c_msg_xfer(i2c, &request, &response);
+ if (err < 0) {
+ dev_err(i2c->dev, "failed to transfer message: %d\n", err);
+ return err;
+ }
+
+ err = tegra_bpmp_i2c_deserialize(i2c, response.xfer.data_buf,
+ response.xfer.data_size,
+ msgs, num);
+ if (err < 0) {
+ dev_err(i2c->dev, "failed to deserialize message: %d\n", err);
+ return err;
+ }
+
+ return num;
+}
+
+static u32 tegra_bpmp_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
+ I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_NOSTART;
+}
+
+static const struct i2c_algorithm tegra_bpmp_i2c_algo = {
+ .master_xfer = tegra_bpmp_i2c_xfer,
+ .functionality = tegra_bpmp_i2c_func,
+};
+
+static int tegra_bpmp_i2c_probe(struct platform_device *pdev)
+{
+ struct tegra_bpmp_i2c *i2c;
+ u32 value;
+ int err;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ i2c->dev = &pdev->dev;
+
+ i2c->bpmp = dev_get_drvdata(pdev->dev.parent);
+ if (!i2c->bpmp)
+ return -ENODEV;
+
+ err = of_property_read_u32(pdev->dev.of_node, "nvidia,bpmp-bus-id",
+ &value);
+ if (err < 0)
+ return err;
+
+ i2c->bus = value;
+
+ i2c_set_adapdata(&i2c->adapter, i2c);
+ i2c->adapter.owner = THIS_MODULE;
+ i2c->adapter.class = I2C_CLASS_HWMON;
+ strlcpy(i2c->adapter.name, "Tegra BPMP I2C adapter",
+ sizeof(i2c->adapter.name));
+ i2c->adapter.algo = &tegra_bpmp_i2c_algo;
+ i2c->adapter.dev.parent = &pdev->dev;
+ i2c->adapter.dev.of_node = pdev->dev.of_node;
+
+ platform_set_drvdata(pdev, i2c);
+
+ err = i2c_add_adapter(&i2c->adapter);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to add I2C adapter: %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int tegra_bpmp_i2c_remove(struct platform_device *pdev)
+{
+ struct tegra_bpmp_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adapter);
+
+ return 0;
+}
+
+static const struct of_device_id tegra_bpmp_i2c_of_match[] = {
+ { .compatible = "nvidia,tegra186-bpmp-i2c", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, tegra_bpmp_i2c_of_match);
+
+static struct platform_driver tegra_bpmp_i2c_driver = {
+ .driver = {
+ .name = "tegra-bpmp-i2c",
+ .of_match_table = tegra_bpmp_i2c_of_match,
+ },
+ .probe = tegra_bpmp_i2c_probe,
+ .remove = tegra_bpmp_i2c_remove,
+};
+
+static int __init tegra_bpmp_i2c_init_driver(void)
+{
+ return platform_driver_register(&tegra_bpmp_i2c_driver);
+}
+subsys_initcall(tegra_bpmp_i2c_init_driver);
+
+static void __exit tegra_bpmp_i2c_exit_driver(void)
+{
+ platform_driver_unregister(&tegra_bpmp_i2c_driver);
+}
+module_exit(tegra_bpmp_i2c_exit_driver);
+
+MODULE_DESCRIPTION("NVIDIA Tegra BPMP I2C bus contoller driver");
+MODULE_AUTHOR("Shardar Shariff Md <smohammed-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>");
+MODULE_AUTHOR("Juha-Matti Tilli");
+MODULE_LICENSE("GPL v2");
--
2.11.0
^ permalink raw reply related
* [PATCH v2 1/2] dt-bindings: Add Tegra186 BPMP I2C binding
From: Thierry Reding @ 2017-01-27 8:39 UTC (permalink / raw)
To: Wolfram Sang
Cc: Stephen Warren, Alexandre Courbot, Jon Hunter,
linux-i2c-u79uwXL29TY76Z2rM5mHXA,
linux-tegra-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20170127083939.20393-1-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
From: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
In Tegra186, the BPMP (Boot and Power Management Processor) owns certain
HW devices, such as the I2C controller for the power management I2C bus.
Software running on other CPUs must perform IPC to the BPMP in order to
execute transactions on that I2C bus. This binding describes an I2C bus
that is accessed in such a fashion.
Signed-off-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Reviewed-by: Simon Glass <sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Signed-off-by: Tom Warren <twarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Acked-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
.../bindings/i2c/nvidia,tegra186-bpmp-i2c.txt | 42 ++++++++++++++++++++++
1 file changed, 42 insertions(+)
create mode 100644 Documentation/devicetree/bindings/i2c/nvidia,tegra186-bpmp-i2c.txt
diff --git a/Documentation/devicetree/bindings/i2c/nvidia,tegra186-bpmp-i2c.txt b/Documentation/devicetree/bindings/i2c/nvidia,tegra186-bpmp-i2c.txt
new file mode 100644
index 000000000000..ab240e10debc
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/nvidia,tegra186-bpmp-i2c.txt
@@ -0,0 +1,42 @@
+NVIDIA Tegra186 BPMP I2C controller
+
+In Tegra186, the BPMP (Boot and Power Management Processor) owns certain HW
+devices, such as the I2C controller for the power management I2C bus. Software
+running on other CPUs must perform IPC to the BPMP in order to execute
+transactions on that I2C bus. This binding describes an I2C bus that is
+accessed in such a fashion.
+
+The BPMP I2C node must be located directly inside the main BPMP node. See
+../firmware/nvidia,tegra186-bpmp.txt for details of the BPMP binding.
+
+This node represents an I2C controller. See ../i2c/i2c.txt for details of the
+core I2C binding.
+
+Required properties:
+- compatible:
+ Array of strings.
+ One of:
+ - "nvidia,tegra186-bpmp-i2c".
+- #address-cells: Address cells for I2C device address.
+ Single-cell integer.
+ Must be <1>.
+- #size-cells:
+ Single-cell integer.
+ Must be <0>.
+- nvidia,bpmp-bus-id:
+ Single-cell integer.
+ Indicates the I2C bus number this DT node represent, as defined by the
+ BPMP firmware.
+
+Example:
+
+bpmp {
+ ...
+
+ i2c {
+ compatible = "nvidia,tegra186-bpmp-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ nvidia,bpmp-bus-id = <5>;
+ };
+};
--
2.11.0
^ permalink raw reply related
* [PATCH 1/2] dt-bindings: deprecate trivial-devices.txt for i2c
From: Wolfram Sang @ 2017-01-26 22:55 UTC (permalink / raw)
To: devicetree; +Cc: linux-i2c, robh+dt, Wolfram Sang
In-Reply-To: <20170126225544.5431-1-wsa@the-dreams.de>
The idea to collect trivial devices in a seperate file is coming from
the early DT days and turned out to be a bad decision. It regularly
creates maintenance pain and the information is not where users would
expect it (i2c folder is for i2c bus drivers not clients). Also, we do
not maintain such a file for other subsystems, so we should put an end
to this as well. First step is to deprecate it and mention that it
should be refactored into proper bindings.
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
Documentation/devicetree/bindings/i2c/trivial-devices.txt | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
index cdd7b48826c38f..39570a1ca5919f 100644
--- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt
+++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
@@ -1,11 +1,15 @@
+*** This file is DEPRECATED! ***
+
This is a list of trivial i2c devices that have simple device tree
bindings, consisting only of a compatible field, an address and
possibly an interrupt line.
-If a device needs more specific bindings, such as properties to
-describe some aspect of it, there needs to be a specific binding
-document for it just like any other devices.
+The entries here need to be refactored to proper binding descriptions in
+their relevant subdirectories.
+
+New items will not be added to this file.
+*** This file is DEPRECATED! ***
Compatible Vendor / Chip
========== =============
--
2.10.2
^ permalink raw reply related
* [PATCH 0/2] dt-bindings: deprecate and move i2c/trivial-devices.txt
From: Wolfram Sang @ 2017-01-26 22:55 UTC (permalink / raw)
To: devicetree; +Cc: linux-i2c, robh+dt, Wolfram Sang
trivial-devices is cruft and a maintenance pain. I'd like to deprecate it and
suggest refactoring. More details in the patch descriptions.
Let me know what you think.
Thanks,
Wolfram
Wolfram Sang (2):
dt-bindings: deprecate trivial-devices.txt for i2c
dt-bindings: move trivial devices out of i2c subdir
.../{i2c/trivial-devices.txt => i2c-trivial-devices.txt} | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
rename Documentation/devicetree/bindings/{i2c/trivial-devices.txt => i2c-trivial-devices.txt} (98%)
--
2.10.2
^ permalink raw reply
* [PATCH 2/2] dt-bindings: move trivial devices out of i2c subdir
From: Wolfram Sang @ 2017-01-26 22:55 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
Wolfram Sang
In-Reply-To: <20170126225544.5431-1-wsa-z923LK4zBo2bacvFa/9K2g@public.gmane.org>
The i2c folder is for i2c bus drivers, not clients. Move the now
deprecated trivial devices file to the bindings base directory, so it
can be refactored from there to proper bindings in the relevant
subdirectories. This will ease maintenance for the I2C subsystem (less
irrelevant patches automatically CCed by get_maintainer.pl) and it will
make aware that we deal with the file differently now.
Signed-off-by: Wolfram Sang <wsa-z923LK4zBo2bacvFa/9K2g@public.gmane.org>
---
.../bindings/{i2c/trivial-devices.txt => i2c-trivial-devices.txt} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename Documentation/devicetree/bindings/{i2c/trivial-devices.txt => i2c-trivial-devices.txt} (100%)
diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c-trivial-devices.txt
similarity index 100%
rename from Documentation/devicetree/bindings/i2c/trivial-devices.txt
rename to Documentation/devicetree/bindings/i2c-trivial-devices.txt
--
2.10.2
--
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] i2c: core: helper function to detect slave mode
From: Luis Oliveira @ 2017-01-26 17:45 UTC (permalink / raw)
To: wsa-z923LK4zBo2bacvFa/9K2g, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, jarkko.nikula-VuQAYsv1563Yd54FQh9/CA,
andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA,
mika.westerberg-VuQAYsv1563Yd54FQh9/CA,
linux-i2c-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, vz-ChpfBGZJDbMAvxtiuMwx3w
Cc: Luis.Oliveira-HKixBCOQz3hWk0Htik3J/w,
Ramiro.Oliveira-HKixBCOQz3hWk0Htik3J/w,
Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w
This function has the purpose of mode detection by checking the
device nodes for a reg matching with the I2C_OWN_SLAVE_ADDREESS flag.
Currently only checks using OF functions (ACPI slave not supported yet).
Signed-off-by: Luis Oliveira <lolivei-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
Suggested-by: Andy Shevchenko <andy.shevchenko-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Reviewed-by: Andy Shevchenko <andy.shevchenko-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
Changes V3->V4: (@Wolfram)
- Rename of the function
- Reword of the function description
drivers/i2c/i2c-core.c | 33 +++++++++++++++++++++++++++++++++
include/linux/i2c.h | 1 +
2 files changed, 34 insertions(+)
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 583e95042a21..408de741fec5 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -3690,6 +3690,39 @@ int i2c_slave_unregister(struct i2c_client *client)
return ret;
}
EXPORT_SYMBOL_GPL(i2c_slave_unregister);
+
+/**
+ * i2c_detect_slave_mode - detect operation mode
+ * @dev: The device owning the bus
+ *
+ * This checks the device nodes for an I2C slave by checking the address
+ * used in the reg property. If the address match the I2C_OWN_SLAVE_ADDRESS
+ * flag this means the device is configured to act as a I2C slave and it will
+ * be listening at that address.
+ *
+ * Returns true if an I2C own slave address is detected, otherwise returns
+ * false.
+ */
+bool i2c_detect_slave_mode(struct device *dev)
+{
+ if (IS_BUILTIN(CONFIG_OF) && dev->of_node) {
+ struct device_node *child;
+ u32 reg;
+
+ for_each_child_of_node(dev->of_node, child) {
+ of_property_read_u32(child, "reg", ®);
+ if (reg & I2C_OWN_SLAVE_ADDRESS) {
+ of_node_put(child);
+ return true;
+ }
+ }
+ } else if (IS_BUILTIN(CONFIG_ACPI) && ACPI_HANDLE(dev)) {
+ dev_dbg(dev, "ACPI slave is not supported yet\n");
+ }
+ return false;
+}
+EXPORT_SYMBOL_GPL(i2c_detect_slave_mode);
+
#endif
MODULE_AUTHOR("Simon G. Vogl <simon-nD9nYVNVf00W+b/DJNNodF6hYfS7NtTn@public.gmane.org>");
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 4b45ec46161f..f0ba4bac7452 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -282,6 +282,7 @@ enum i2c_slave_event {
extern int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb);
extern int i2c_slave_unregister(struct i2c_client *client);
+extern bool i2c_detect_slave_mode(struct device *dev);
static inline int i2c_slave_event(struct i2c_client *client,
enum i2c_slave_event event, u8 *val)
--
2.11.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 related
* [PATCH v3 3/3] i2c: zx2967: add i2c controller driver for ZTE's zx2967 family
From: Baoyou Xie @ 2017-01-26 13:00 UTC (permalink / raw)
To: andy.shevchenko, jun.nie, wsa, robh+dt, mark.rutland
Cc: linux-arm-kernel, linux-i2c, devicetree, linux-kernel, shawnguo,
baoyou.xie, xie.baoyou, chen.chaokai, wang.qiang01
In-Reply-To: <1485435631-32642-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>
---
drivers/i2c/busses/Kconfig | 9 +
drivers/i2c/busses/Makefile | 1 +
drivers/i2c/busses/i2c-zx2967.c | 699 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 709 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..81e99d3
--- /dev/null
+++ b/drivers/i2c/busses/i2c-zx2967.c
@@ -0,0 +1,699 @@
+/*
+ * 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/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pinctrl/consumer.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_MODE_TEN BIT(1)
+
+#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)
+
+struct zx2967_i2c_info {
+ spinlock_t lock;
+ struct device *dev;
+ struct i2c_adapter adap;
+ struct clk *clk;
+ struct completion complete;
+ u32 clk_freq;
+ struct pinctrl *pin_ctrl;
+ void __iomem *reg_base;
+ size_t residue;
+ int irq;
+ int msg_rd;
+ u8 *buf;
+ 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 int zx2967_i2c_flush_fifos(struct zx2967_i2c_info *zx_i2c)
+{
+ u32 val;
+ u32 offset;
+
+ 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);
+
+ return 0;
+}
+
+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(zx_i2c->dev, "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->buf++) = val[i];
+ zx_i2c->residue--;
+ if (zx_i2c->residue <= 0)
+ break;
+ }
+
+ barrier();
+
+ return 0;
+}
+
+static int zx2967_i2c_fill_tx_fifo(struct zx2967_i2c_info *zx_i2c)
+{
+ u8 *buf = zx_i2c->buf;
+ size_t residue = zx_i2c->residue;
+
+ if (residue == 0) {
+ dev_err(zx_i2c->dev, "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->buf = NULL;
+ } else {
+ zx2967_i2c_writesb(zx_i2c, buf, REG_DATA, I2C_FIFO_MAX);
+ zx_i2c->residue -= I2C_FIFO_MAX;
+ zx_i2c->buf += 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_enable_tenbit(struct zx2967_i2c_info *zx_i2c, __u16 addr)
+{
+ u16 val = (addr >> 7) & 0x7;
+
+ if (val > 0) {
+ zx2967_i2c_writel(zx_i2c, val, REG_DEVADDR_H);
+ 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(zx_i2c->dev, "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, I2C_FIFO_MAX);
+ 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(zx_i2c->dev, "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, I2C_FIFO_MAX);
+ 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->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);
+
+ 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_i2c_writel(zx_i2c, (msgs->addr & 0x7f), REG_DEVADDR_L);
+ zx2967_i2c_writel(zx_i2c, (msgs->addr >> 7) & 0x7, REG_DEVADDR_H);
+ if (zx2967_i2c_readl(zx_i2c, REG_DEVADDR_H) > 0)
+ zx2967_enable_tenbit(zx_i2c, msgs->addr);
+
+ for (i = 0; i < num; i++) {
+ ret = zx2967_i2c_xfer_msg(zx_i2c, &msgs[i]);
+ if (ret)
+ return ret;
+ if (num > 1)
+ usleep_range(1000, 2000);
+ }
+
+ 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);
+
+ zx2967_enable_tenbit(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(zx_i2c->dev, "i2c read transfer timed out\n");
+ disable_irq(zx_i2c->irq);
+ zx2967_i2c_reset_hardware(zx_i2c);
+ return -EIO;
+ }
+
+ usleep_range(1000, 2000);
+ 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(zx_i2c->dev, "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(zx_i2c->dev, "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;
+}
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops zx2967_i2c_dev_pm_ops = {
+ .suspend = zx2967_i2c_suspend,
+ .resume = zx2967_i2c_resume,
+};
+#define ZX2967_I2C_DEV_PM_OPS (&zx2967_i2c_dev_pm_ops)
+#else
+#define ZX2967_I2C_DEV_PM_OPS NULL
+#endif
+
+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 = platform_get_irq(pdev, 0);
+ if (ret < 0)
+ return ret;
+ zx_i2c->irq = 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;
+ }
+
+ zx_i2c->reg_base = reg_base;
+ zx_i2c->clk = clk;
+ zx_i2c->dev = &pdev->dev;
+
+ zx_i2c->pin_ctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(zx_i2c->pin_ctrl)) {
+ if (PTR_ERR(zx_i2c->pin_ctrl) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ dev_info(&pdev->dev, "no pinctrl handle\n");
+ }
+
+ 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);
+ zx_i2c->adap.owner = THIS_MODULE;
+ zx_i2c->adap.class = I2C_CLASS_DEPRECATED;
+ strlcpy(zx_i2c->adap.name, "zx2967 i2c adapter",
+ sizeof(zx_i2c->adap.name));
+ zx_i2c->adap.algo = &zx2967_i2c_algo;
+ zx_i2c->adap.dev.parent = &pdev->dev;
+ zx_i2c->adap.nr = pdev->id;
+ 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
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