Hi,
NVEC driver contains code to manage tegra i2c controller in slave mode.
I2C slave support was implemented in linux kernel. The goal of this
patch serie is to implement I2C slave mode in tegra drived and rework
NVEC driver to use it.
Patches are based on i2c for-next.
Patch 1 imeplents slave mode for tegra I2C controller. This patch
was checked on tegra 2 device (Toshiba AC100) only. Please review
carefully.
Patch 2 reworks NVEC driver itself. I kept code close to original.
Patch 3 fixes device tree and documentation.
Thanks in advance
Andrey Danin (3):
i2c: tegra: implement slave mode
staging/nvec: reimplement on top of tegra i2c driver
dt: paz00: define nvec as child of i2c bus
.../devicetree/bindings/nvec/nvidia,nvec.txt | 19 +-
arch/arm/boot/dts/tegra20-paz00.dts | 22 +-
drivers/i2c/busses/i2c-tegra.c | 131 +++++++
drivers/staging/nvec/nvec.c | 379 +++++++--------------
drivers/staging/nvec/nvec.h | 17 +-
5 files changed, 264 insertions(+), 304 deletions(-)
--
1.9.1
@@ -2,20 +2,5 @@ NVIDIA compliant embedded controller Required properties: - compatible : should be "nvidia,nvec".-- reg : the iomem of the i2c slave controller-- interrupts : the interrupt line of the i2c slave controller-- clock-frequency : the frequency of the i2c bus-- gpios : the gpio used for ec request-- slave-addr: the i2c address of the slave controller-- clocks : Must contain an entry for each entry in clock-names.- See ../clocks/clock-bindings.txt for details.-- clock-names : Must include the following entries:- Tegra20/Tegra30:- - div-clk- - fast-clk- Tegra114:- - div-clk-- resets : Must contain an entry for each entry in reset-names.- See ../reset/reset.txt for details.-- reset-names : Must include the following entries:- - i2c+- request-gpios : the gpio used for ec request+- reg: the i2c address of the slave controller
@@ -2,20 +2,5 @@ NVIDIA compliant embedded controller Required properties: - compatible : should be "nvidia,nvec".
based on the earlier discussion with Wolfram, this should be "nvidia,nvec-
slave" to distunguish it from a possible nvec master driver.
quoted hunk
-- reg : the iomem of the i2c slave controller
-- interrupts : the interrupt line of the i2c slave controller
-- clock-frequency : the frequency of the i2c bus
-- gpios : the gpio used for ec request
-- slave-addr: the i2c address of the slave controller
-- clocks : Must contain an entry for each entry in clock-names.
- See ../clocks/clock-bindings.txt for details.
-- clock-names : Must include the following entries:
- Tegra20/Tegra30:
- - div-clk
- - fast-clk
- Tegra114:
- - div-clk
-- resets : Must contain an entry for each entry in reset-names.
- See ../reset/reset.txt for details.
-- reset-names : Must include the following entries:
- - i2c
+- request-gpios : the gpio used for ec request
+- reg: the i2c address of the slave controller
diff --git a/arch/arm/boot/dts/tegra20-paz00.dts
b/arch/arm/boot/dts/tegra20-paz00.dts index ed7e100..65e247b 100644
The changes to this file make more sense either as a standalone patch
1/4, or as part of the driver changes.
quoted hunk
@@ -2,20 +2,5 @@ NVIDIA compliant embedded controller Required properties: - compatible : should be "nvidia,nvec".-- reg : the iomem of the i2c slave controller-- interrupts : the interrupt line of the i2c slave controller-- clock-frequency : the frequency of the i2c bus-- gpios : the gpio used for ec request-- slave-addr: the i2c address of the slave controller-- clocks : Must contain an entry for each entry in clock-names.- See ../clocks/clock-bindings.txt for details.-- clock-names : Must include the following entries:- Tegra20/Tegra30:- - div-clk- - fast-clk- Tegra114:- - div-clk-- resets : Must contain an entry for each entry in reset-names.- See ../reset/reset.txt for details.-- reset-names : Must include the following entries:- - i2c+- request-gpios : the gpio used for ec request+- reg: the i2c address of the slave controller
This change breaks ABI.
Instead of modifying the definition of the existing compatible value, I
think you should introduce a new compatible value to describe the
external NVEC chip.
This doesn't feel correct. There's nothing here to indicate that this
child device is a slave that is implemented by the host SoC rather than
something external attached to the I2C bus.
Perhaps you can get away with this, since the driver for nvidia,nvec
only calls I2C APIs suitable for internal slaves rather than external
slaves? Even so though, I think the distinction needs to be clearly
marked in the DT so that any generic code outside the NVEC driver that
parses the DT can determine the difference.
I would recommend the I2C controller having #address-cells=<2> with cell
0 being 0==master,1==slave, cell 1 being the I2C address. The I2C driver
would need to support #address-cells=<1> for backwards-compatibility.
The changes to this file make more sense either as a standalone patch
1/4, or as part of the driver changes.
quoted
@@ -2,20 +2,5 @@ NVIDIA compliant embedded controller Required properties: - compatible : should be "nvidia,nvec".-- reg : the iomem of the i2c slave controller-- interrupts : the interrupt line of the i2c slave controller-- clock-frequency : the frequency of the i2c bus-- gpios : the gpio used for ec request-- slave-addr: the i2c address of the slave controller-- clocks : Must contain an entry for each entry in clock-names.- See ../clocks/clock-bindings.txt for details.-- clock-names : Must include the following entries:- Tegra20/Tegra30:- - div-clk- - fast-clk- Tegra114:- - div-clk-- resets : Must contain an entry for each entry in reset-names.- See ../reset/reset.txt for details.-- reset-names : Must include the following entries:- - i2c+- request-gpios : the gpio used for ec request+- reg: the i2c address of the slave controller
This change breaks ABI.
Instead of modifying the definition of the existing compatible value, I
think you should introduce a new compatible value to describe the
external NVEC chip.
This doesn't feel correct. There's nothing here to indicate that this
child device is a slave that is implemented by the host SoC rather than
something external attached to the I2C bus.
Perhaps you can get away with this, since the driver for nvidia,nvec
only calls I2C APIs suitable for internal slaves rather than external
slaves? Even so though, I think the distinction needs to be clearly
marked in the DT so that any generic code outside the NVEC driver that
parses the DT can determine the difference.
I would recommend the I2C controller having #address-cells=<2> with cell
0 being 0==master,1==slave, cell 1 being the I2C address. The I2C driver
would need to support #address-cells=<1> for backwards-compatibility.
Driver (nvec in this case) can decide what mode should it use according
to compatible value. Is it not enough ?
The changes to this file make more sense either as a standalone patch
1/4, or as part of the driver changes.
quoted
@@ -2,20 +2,5 @@ NVIDIA compliant embedded controller Required properties: - compatible : should be "nvidia,nvec".-- reg : the iomem of the i2c slave controller-- interrupts : the interrupt line of the i2c slave controller-- clock-frequency : the frequency of the i2c bus-- gpios : the gpio used for ec request-- slave-addr: the i2c address of the slave controller-- clocks : Must contain an entry for each entry in clock-names.- See ../clocks/clock-bindings.txt for details.-- clock-names : Must include the following entries:- Tegra20/Tegra30:- - div-clk- - fast-clk- Tegra114:- - div-clk-- resets : Must contain an entry for each entry in reset-names.- See ../reset/reset.txt for details.-- reset-names : Must include the following entries:- - i2c+- request-gpios : the gpio used for ec request+- reg: the i2c address of the slave controller
This change breaks ABI.
Instead of modifying the definition of the existing compatible value, I
think you should introduce a new compatible value to describe the
external NVEC chip.
This doesn't feel correct. There's nothing here to indicate that this
child device is a slave that is implemented by the host SoC rather than
something external attached to the I2C bus.
Perhaps you can get away with this, since the driver for nvidia,nvec
only calls I2C APIs suitable for internal slaves rather than external
slaves? Even so though, I think the distinction needs to be clearly
marked in the DT so that any generic code outside the NVEC driver that
parses the DT can determine the difference.
I would recommend the I2C controller having #address-cells=<2> with cell
0 being 0==master,1==slave, cell 1 being the I2C address. The I2C driver
would need to support #address-cells=<1> for backwards-compatibility.
Driver (nvec in this case) can decide what mode should it use according
to compatible value. Is it not enough ?
No, I don't think so.
The I2C binding model is that each child of an I2C controller represents
a device attached to the bus. which SW will communicate with using the
I2C controller as master and the device as a slave. If there's no
explicit representation of child-vs-slave in the DT, how does the I2C
core know whether a particular node is intended to be accessed as a
master or slave?
In other words, without an explicit "communicate with this device" or
"implement this device as a slave" flag, how could DT contain:
i2c-controller {
...
master at 1a {
compatible = "foo,device";
reg = <0x1a 1>;
};
slave at 1a {
compatible = "foo,device-slave";
reg = <0x1a 1>;
};
};
where:
- "foo,device" means: instantiate a driver to communicate with a device
of this type.
- "foo,device-slave" means: instantiate a driver to act as this I2C device.
Sure it's possible for the drivers for those two nodes to simply use the
I2C subsystem's master or slave APIs, but I suspect DT content would
confuse the I2C core into thinking that two I2C devices with the same
address had been represented in DT, and the I2C core would refuse to
instantiate one of them. The solution here is for the reg value to
encode a "master" vs. "slave" flag, so the I2C core can allow both a
master and a slave for each address.
I'm pretty sure this is the nth time I've explained this.
The changes to this file make more sense either as a standalone patch
1/4, or as part of the driver changes.
quoted
@@ -2,20 +2,5 @@ NVIDIA compliant embedded controller Required properties: - compatible : should be "nvidia,nvec".-- reg : the iomem of the i2c slave controller-- interrupts : the interrupt line of the i2c slave controller-- clock-frequency : the frequency of the i2c bus-- gpios : the gpio used for ec request-- slave-addr: the i2c address of the slave controller-- clocks : Must contain an entry for each entry in clock-names.- See ../clocks/clock-bindings.txt for details.-- clock-names : Must include the following entries:- Tegra20/Tegra30:- - div-clk- - fast-clk- Tegra114:- - div-clk-- resets : Must contain an entry for each entry in reset-names.- See ../reset/reset.txt for details.-- reset-names : Must include the following entries:- - i2c+- request-gpios : the gpio used for ec request+- reg: the i2c address of the slave controller
This change breaks ABI.
Instead of modifying the definition of the existing compatible value, I
think you should introduce a new compatible value to describe the
external NVEC chip.
This doesn't feel correct. There's nothing here to indicate that this
child device is a slave that is implemented by the host SoC rather than
something external attached to the I2C bus.
Perhaps you can get away with this, since the driver for nvidia,nvec
only calls I2C APIs suitable for internal slaves rather than external
slaves? Even so though, I think the distinction needs to be clearly
marked in the DT so that any generic code outside the NVEC driver that
parses the DT can determine the difference.
I would recommend the I2C controller having #address-cells=<2> with cell
0 being 0==master,1==slave, cell 1 being the I2C address. The I2C driver
would need to support #address-cells=<1> for backwards-compatibility.
Driver (nvec in this case) can decide what mode should it use according
to compatible value. Is it not enough ?
No, I don't think so.
The I2C binding model is that each child of an I2C controller represents
a device attached to the bus. which SW will communicate with using the
I2C controller as master and the device as a slave. If there's no
explicit representation of child-vs-slave in the DT, how does the I2C
core know whether a particular node is intended to be accessed as a
master or slave?
Device driver registers itself via slave API. Bus driver calls
appropriate callback function when needed.
If device driver decides to access hardware via master API, then it can
do it.
Am I missing something ?
In other words, without an explicit "communicate with this device" or
"implement this device as a slave" flag, how could DT contain:
i2c-controller {
...
master at 1a {
compatible = "foo,device";
reg = <0x1a 1>;
};
slave at 1a {
compatible = "foo,device-slave";
reg = <0x1a 1>;
};
};
where:
- "foo,device" means: instantiate a driver to communicate with a device
of this type.
- "foo,device-slave" means: instantiate a driver to act as this I2C device.
Sure it's possible for the drivers for those two nodes to simply use the
I2C subsystem's master or slave APIs, but I suspect DT content would
confuse the I2C core into thinking that two I2C devices with the same
address had been represented in DT, and the I2C core would refuse to
instantiate one of them. The solution here is for the reg value to
encode a "master" vs. "slave" flag, so the I2C core can allow both a
master and a slave for each address.
If there is one device, then it must be one node. If there is two
devices then it looks incorrect to me to have two devices with the same
address. Does I2C allow two devices with same address ?
I can imagine this:
- we have hardware with I2C device. This device can act as master or as
slave
- we have device driver, that can work in one, other or both modes.
If we want to force master or slave mode, we can use flags (for combined
mode we can use two nodes, but it looks weird).
If we want to let driver decide (preferred mode, arbitration, something
else), we can use current rules.
I'm pretty sure this is the nth time I've explained this.
Sorry. I don't understand why you still suggest to use flags. We can use
existing infrastructure in this case. There is already similar case in
arch/arm/boot/dts/r8a7790-lager.dts (see i2c1 and eeprom).
Do we *really* need this extra rules at this moment ?
The changes to this file make more sense either as a standalone patch
1/4, or as part of the driver changes.
quoted
@@ -2,20 +2,5 @@ NVIDIA compliant embedded controller Required properties: - compatible : should be "nvidia,nvec".-- reg : the iomem of the i2c slave controller-- interrupts : the interrupt line of the i2c slave controller-- clock-frequency : the frequency of the i2c bus-- gpios : the gpio used for ec request-- slave-addr: the i2c address of the slave controller-- clocks : Must contain an entry for each entry in clock-names.- See ../clocks/clock-bindings.txt for details.-- clock-names : Must include the following entries:- Tegra20/Tegra30:- - div-clk- - fast-clk- Tegra114:- - div-clk-- resets : Must contain an entry for each entry in reset-names.- See ../reset/reset.txt for details.-- reset-names : Must include the following entries:- - i2c+- request-gpios : the gpio used for ec request+- reg: the i2c address of the slave controller
This change breaks ABI.
Instead of modifying the definition of the existing compatible value, I
think you should introduce a new compatible value to describe the
external NVEC chip.
This doesn't feel correct. There's nothing here to indicate that this
child device is a slave that is implemented by the host SoC rather than
something external attached to the I2C bus.
Perhaps you can get away with this, since the driver for nvidia,nvec
only calls I2C APIs suitable for internal slaves rather than external
slaves? Even so though, I think the distinction needs to be clearly
marked in the DT so that any generic code outside the NVEC driver that
parses the DT can determine the difference.
I would recommend the I2C controller having #address-cells=<2> with
cell
0 being 0==master,1==slave, cell 1 being the I2C address. The I2C
driver
would need to support #address-cells=<1> for backwards-compatibility.
Driver (nvec in this case) can decide what mode should it use according
to compatible value. Is it not enough ?
No, I don't think so.
The I2C binding model is that each child of an I2C controller represents
a device attached to the bus. which SW will communicate with using the
I2C controller as master and the device as a slave. If there's no
explicit representation of child-vs-slave in the DT, how does the I2C
core know whether a particular node is intended to be accessed as a
master or slave?
Device driver registers itself via slave API. Bus driver calls
appropriate callback function when needed.
If device driver decides to access hardware via master API, then it can
do it.
Am I missing something ?
quoted
In other words, without an explicit "communicate with this device" or
"implement this device as a slave" flag, how could DT contain:
i2c-controller {
...
master at 1a {
compatible = "foo,device";
reg = <0x1a 1>;
};
slave at 1a {
compatible = "foo,device-slave";
reg = <0x1a 1>;
};
};
where:
- "foo,device" means: instantiate a driver to communicate with a device
of this type.
- "foo,device-slave" means: instantiate a driver to act as this I2C
device.
Sure it's possible for the drivers for those two nodes to simply use the
I2C subsystem's master or slave APIs, but I suspect DT content would
confuse the I2C core into thinking that two I2C devices with the same
address had been represented in DT, and the I2C core would refuse to
instantiate one of them. The solution here is for the reg value to
encode a "master" vs. "slave" flag, so the I2C core can allow both a
master and a slave for each address.
If there is one device, then it must be one node. If there is two
devices then it looks incorrect to me to have two devices with the same
address. Does I2C allow two devices with same address ?
I can imagine this:
- we have hardware with I2C device. This device can act as master or as
slave
- we have device driver, that can work in one, other or both modes.
If we want to force master or slave mode, we can use flags (for combined
mode we can use two nodes, but it looks weird).
If we want to let driver decide (preferred mode, arbitration, something
else), we can use current rules.
quoted
I'm pretty sure this is the nth time I've explained this.
Sorry. I don't understand why you still suggest to use flags. We can use
existing infrastructure in this case. There is already similar case in
arch/arm/boot/dts/r8a7790-lager.dts (see i2c1 and eeprom).
Do we *really* need this extra rules at this moment ?
The changes to this file make more sense either as a standalone patch
1/4, or as part of the driver changes.
quoted
@@ -2,20 +2,5 @@ NVIDIA compliant embedded controller Required properties: - compatible : should be "nvidia,nvec".-- reg : the iomem of the i2c slave controller-- interrupts : the interrupt line of the i2c slave controller-- clock-frequency : the frequency of the i2c bus-- gpios : the gpio used for ec request-- slave-addr: the i2c address of the slave controller-- clocks : Must contain an entry for each entry in clock-names.- See ../clocks/clock-bindings.txt for details.-- clock-names : Must include the following entries:- Tegra20/Tegra30:- - div-clk- - fast-clk- Tegra114:- - div-clk-- resets : Must contain an entry for each entry in reset-names.- See ../reset/reset.txt for details.-- reset-names : Must include the following entries:- - i2c+- request-gpios : the gpio used for ec request+- reg: the i2c address of the slave controller
This change breaks ABI.
Instead of modifying the definition of the existing compatible value, I
think you should introduce a new compatible value to describe the
external NVEC chip.
This doesn't feel correct. There's nothing here to indicate that this
child device is a slave that is implemented by the host SoC rather than
something external attached to the I2C bus.
Perhaps you can get away with this, since the driver for nvidia,nvec
only calls I2C APIs suitable for internal slaves rather than external
slaves? Even so though, I think the distinction needs to be clearly
marked in the DT so that any generic code outside the NVEC driver that
parses the DT can determine the difference.
I would recommend the I2C controller having #address-cells=<2> with
cell
0 being 0==master,1==slave, cell 1 being the I2C address. The I2C
driver
would need to support #address-cells=<1> for backwards-compatibility.
Driver (nvec in this case) can decide what mode should it use according
to compatible value. Is it not enough ?
No, I don't think so.
The I2C binding model is that each child of an I2C controller represents
a device attached to the bus. which SW will communicate with using the
I2C controller as master and the device as a slave. If there's no
explicit representation of child-vs-slave in the DT, how does the I2C
core know whether a particular node is intended to be accessed as a
master or slave?
Device driver registers itself via slave API. Bus driver calls
appropriate callback function when needed.
If device driver decides to access hardware via master API, then it can
do it.
Am I missing something ?
quoted
In other words, without an explicit "communicate with this device" or
"implement this device as a slave" flag, how could DT contain:
i2c-controller {
...
master at 1a {
compatible = "foo,device";
reg = <0x1a 1>;
};
slave at 1a {
compatible = "foo,device-slave";
reg = <0x1a 1>;
};
};
where:
- "foo,device" means: instantiate a driver to communicate with a device
of this type.
- "foo,device-slave" means: instantiate a driver to act as this I2C
device.
Sure it's possible for the drivers for those two nodes to simply use the
I2C subsystem's master or slave APIs, but I suspect DT content would
confuse the I2C core into thinking that two I2C devices with the same
address had been represented in DT, and the I2C core would refuse to
instantiate one of them. The solution here is for the reg value to
encode a "master" vs. "slave" flag, so the I2C core can allow both a
master and a slave for each address.
If there is one device, then it must be one node. If there is two
devices then it looks incorrect to me to have two devices with the same
address. Does I2C allow two devices with same address ?
One of the nodes is to indicate that the kernel should implement the
slave mode device and one is to indicate that the kernel should
implement the master mode device. Those two devices/nodes have
completely different semantics, so while they share the I2C bus address
they don't represent the same thing.
Admittedly it would be uncommon to do this, since it'd be using the I2C
bus in loopback mode. However, I don't see why we should set out to
prevent that.
I can imagine this:
- we have hardware with I2C device. This device can act as master or as
slave
- we have device driver, that can work in one, other or both modes.
If we want to force master or slave mode, we can use flags (for combined
mode we can use two nodes, but it looks weird).
If we want to let driver decide (preferred mode, arbitration, something
else), we can use current rules.
quoted
I'm pretty sure this is the nth time I've explained this.
Sorry. I don't understand why you still suggest to use flags. We can use
existing infrastructure in this case. There is already similar case in
arch/arm/boot/dts/r8a7790-lager.dts (see i2c1 and eeprom).
Do we *really* need this extra rules at this moment ?
This doesn't feel correct. There's nothing here to indicate that this
child device is a slave that is implemented by the host SoC rather than
something external attached to the I2C bus.
Perhaps you can get away with this, since the driver for nvidia,nvec
only calls I2C APIs suitable for internal slaves rather than external
slaves? Even so though, I think the distinction needs to be clearly
marked in the DT so that any generic code outside the NVEC driver that
parses the DT can determine the difference.
I would recommend the I2C controller having #address-cells=<2> with
cell
0 being 0==master,1==slave, cell 1 being the I2C address. The I2C
driver
would need to support #address-cells=<1> for backwards-compatibility.
Driver (nvec in this case) can decide what mode should it use according
to compatible value. Is it not enough ?
No, I don't think so.
The I2C binding model is that each child of an I2C controller represents
a device attached to the bus. which SW will communicate with using the
I2C controller as master and the device as a slave. If there's no
explicit representation of child-vs-slave in the DT, how does the I2C
core know whether a particular node is intended to be accessed as a
master or slave?
Device driver registers itself via slave API. Bus driver calls
appropriate callback function when needed.
If device driver decides to access hardware via master API, then it can
do it.
Am I missing something ?
quoted
In other words, without an explicit "communicate with this device" or
"implement this device as a slave" flag, how could DT contain:
i2c-controller {
...
master at 1a {
compatible = "foo,device";
reg = <0x1a 1>;
};
slave at 1a {
compatible = "foo,device-slave";
reg = <0x1a 1>;
};
};
where:
- "foo,device" means: instantiate a driver to communicate with a device
of this type.
- "foo,device-slave" means: instantiate a driver to act as this I2C
device.
Sure it's possible for the drivers for those two nodes to simply use the
I2C subsystem's master or slave APIs, but I suspect DT content would
confuse the I2C core into thinking that two I2C devices with the same
address had been represented in DT, and the I2C core would refuse to
instantiate one of them. The solution here is for the reg value to
encode a "master" vs. "slave" flag, so the I2C core can allow both a
master and a slave for each address.
If there is one device, then it must be one node. If there is two
devices then it looks incorrect to me to have two devices with the same
address. Does I2C allow two devices with same address ?
One of the nodes is to indicate that the kernel should implement the
slave mode device and one is to indicate that the kernel should
implement the master mode device. Those two devices/nodes have
completely different semantics, so while they share the I2C bus address
they don't represent the same thing.
Admittedly it would be uncommon to do this, since it'd be using the I2C
bus in loopback mode. However, I don't see why we should set out to
prevent that.
We are sitting between the chairs currently. I hope Wolfram can further
comment on this.
Having a generic loopback slave driver which just echos all messages it
received back to the master (on the same controller or a different one) would
be nice IMHO.
quoted
I can imagine this:
- we have hardware with I2C device. This device can act as master or as
slave
- we have device driver, that can work in one, other or both modes.
If we want to force master or slave mode, we can use flags (for combined
mode we can use two nodes, but it looks weird).
If we want to let driver decide (preferred mode, arbitration, something
else), we can use current rules.
quoted
I'm pretty sure this is the nth time I've explained this.
Sorry. I don't understand why you still suggest to use flags. We can use
existing infrastructure in this case. There is already similar case in
arch/arm/boot/dts/r8a7790-lager.dts (see i2c1 and eeprom).
Do we *really* need this extra rules at this moment ?
This doesn't feel correct. There's nothing here to indicate that this
child device is a slave that is implemented by the host SoC rather than
something external attached to the I2C bus.
Perhaps you can get away with this, since the driver for nvidia,nvec
only calls I2C APIs suitable for internal slaves rather than external
slaves? Even so though, I think the distinction needs to be clearly
marked in the DT so that any generic code outside the NVEC driver that
parses the DT can determine the difference.
I would recommend the I2C controller having #address-cells=<2> with
cell
0 being 0==master,1==slave, cell 1 being the I2C address. The I2C
driver
would need to support #address-cells=<1> for backwards-compatibility.
As you said in the response you linked to, the objection is invalid
since it won't break any DTs. The driver for a node is responsible for
defining the meaning of its own reg properties. It should be pretty
trivial to allow the Tegra I2C controller driver (or indeed any driver
at all) to handle either #address-cells=<1> (the current setting) or
#address-cells=<2> (a new value which enables adding a new flag cell) or
even #address-cells=<1> with some of the upper bits of the reg value
used as flags (which would default to 0 in all current DTs, so e.g.
using the MSB==1 as a slave flag), all at run-time with complete
backwards-compatibility.
Initialization code is based on NVEC driver.
There is a HW bug in AP20 that was also mentioned in kernel sources
for Toshiba AC100.
Signed-off-by: Andrey Danin <redacted>
---
drivers/i2c/busses/i2c-tegra.c | 131 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 131 insertions(+)
@@ -398,6 +409,12 @@ static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev)staticinlinevoidtegra_i2c_clock_disable(structtegra_i2c_dev*i2c_dev){+if(i2c_dev->slave){+dev_warn(i2c_dev->dev,+"i2c slave is registered, don't disable a clock\n");+return;+}+clk_disable(i2c_dev->div_clk);if(!i2c_dev->hw->has_single_clk_source)clk_disable(i2c_dev->fast_clk);
@@ -459,12 +476,84 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)returnerr;}+staticinlineintis_ready(unsignedlongstatus)+{+returnstatus&I2C_SL_ST_IRQ;+}++staticinlineintis_write(unsignedlongstatus)+{+return(status&I2C_SL_ST_RNW)==0;+}++staticinlineintis_read(unsignedlongstatus)+{+return!is_write(status);+}++staticinlineintis_trans_start(unsignedlongstatus)+{+returnstatus&I2C_SL_ST_RCVD;+}++staticinlineintis_trans_end(unsignedlongstatus)+{+returnstatus&I2C_SL_ST_END_TRANS;+}++staticbooltegra_i2c_slave_isr(intirq,structtegra_i2c_dev*i2c_dev)+{+unsignedlongstatus;+u8value;++if(!i2c_dev->slave||!i2c_dev->slave->slave_cb)+returnfalse;++status=i2c_readl(i2c_dev,I2C_SL_STATUS);+if(!is_ready(status))+returnfalse;++/* master sent stop */+if(is_trans_end(status)){+i2c_slave_event(i2c_dev->slave,I2C_SLAVE_STOP,NULL);+if(!is_trans_start(status))+returntrue;+}++/* i2c master sends data to us */+if(is_write(status)){+i2c_slave_event(i2c_dev->slave,I2C_SLAVE_REQ_WRITE_START,+NULL);+value=i2c_readl(i2c_dev,I2C_SL_RCVD);+if(is_trans_start(status))+i2c_writel(i2c_dev,0,I2C_SL_RCVD);+i2c_slave_event(i2c_dev->slave,I2C_SLAVE_REQ_WRITE_END,+&value);+}++/* i2c master reads data from us */+if(is_read(status)){+i2c_slave_event(i2c_dev->slave,I2C_SLAVE_REQ_READ_START,+&value);+if(is_trans_start(status)+&&i2c_dev->hw->slave_read_start_delay)+udelay(i2c_dev->hw->slave_read_start_delay);+i2c_writel(i2c_dev,value,I2C_SL_RCVD);+i2c_slave_event(i2c_dev->slave,I2C_SLAVE_REQ_READ_END,NULL);+}++returntrue;+}+staticirqreturn_ttegra_i2c_isr(intirq,void*dev_id){u32status;constu32status_err=I2C_INT_NO_ACK|I2C_INT_ARBITRATION_LOST;structtegra_i2c_dev*i2c_dev=dev_id;+if(tegra_i2c_slave_isr(irq,i2c_dev))+returnIRQ_HANDLED;+status=i2c_readl(i2c_dev,I2C_INT_STATUS);if(status==0){
From: Marc Dietrich <marvin24@gmx.de> Date: 2015-01-29 09:40:55
Hi Andrey,
first, thanks for accepting the challenge once more ;-)
The driver depends on I2C_SLAVE now, so you need to add this to Kconfig. The
amount of code (and additional overhead) is pretty small, so I think it's ok
to always enable it. Otherwise we would need lots of ifdefs.
Am Donnerstag, 29. Januar 2015, 10:20:20 schrieb Andrey Danin:
quoted hunk
Initialization code is based on NVEC driver.
There is a HW bug in AP20 that was also mentioned in kernel sources
for Toshiba AC100.
Signed-off-by: Andrey Danin <redacted>
---
drivers/i2c/busses/i2c-tegra.c | 131
+++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+)
long reg) @@ -398,6 +409,12 @@ static inline int
tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev)
static inline void tegra_i2c_clock_disable(struct tegra_i2c_dev *i2c_dev)
{
+ if (i2c_dev->slave) {
+ dev_warn(i2c_dev->dev,
+ "i2c slave is registered, don't disable a clock\n");
+ return;
+ }
+
is this really required? What are the callers of clock_disable? I think it
would be ok to make master or slave operation exclusive for now. We have no
way to test this anyway. Maybe some flag which blocks master operation.
quoted hunk
clk_disable(i2c_dev->div_clk);
if (!i2c_dev->hw->has_single_clk_source)
clk_disable(i2c_dev->fast_clk);
@@ -459,12 +476,84 @@ static int tegra_i2c_init(struct tegra_i2c_dev
*i2c_dev) return err;
}
+static inline int is_ready(unsigned long status)
+{
+ return status & I2C_SL_ST_IRQ;
+}
is_slave_irq?
+
+static inline int is_write(unsigned long status)
+{
+ return (status & I2C_SL_ST_RNW) == 0;
+}
+
+static inline int is_read(unsigned long status)
+{
+ return !is_write(status);
+}
+
+static inline int is_trans_start(unsigned long status)
+{
+ return status & I2C_SL_ST_RCVD;
+}
+
+static inline int is_trans_end(unsigned long status)
+{
+ return status & I2C_SL_ST_END_TRANS;
+}
Following the rest of the files coding style, I think this helpers can be
moved to the caller itself.
quoted hunk
+
+static bool tegra_i2c_slave_isr(int irq, struct tegra_i2c_dev *i2c_dev)
+{
+ unsigned long status;
+ u8 value;
+
+ if (!i2c_dev->slave || !i2c_dev->slave->slave_cb)
+ return false;
+
+ status = i2c_readl(i2c_dev, I2C_SL_STATUS);
+ if (!is_ready(status))
+ return false;
+
+ /* master sent stop */
+ if (is_trans_end(status)) {
+ i2c_slave_event(i2c_dev->slave, I2C_SLAVE_STOP, NULL);
+ if (!is_trans_start(status))
+ return true;
+ }
+
+ /* i2c master sends data to us */
+ if (is_write(status)) {
+ i2c_slave_event(i2c_dev->slave, I2C_SLAVE_REQ_WRITE_START,
+ NULL);
+ value = i2c_readl(i2c_dev, I2C_SL_RCVD);
+ if (is_trans_start(status))
+ i2c_writel(i2c_dev, 0, I2C_SL_RCVD);
+ i2c_slave_event(i2c_dev->slave, I2C_SLAVE_REQ_WRITE_END,
+ &value);
+ }
+
+ /* i2c master reads data from us */
+ if (is_read(status)) {
+ i2c_slave_event(i2c_dev->slave, I2C_SLAVE_REQ_READ_START,
+ &value);
+ if (is_trans_start(status)
+ && i2c_dev->hw->slave_read_start_delay)
+ udelay(i2c_dev->hw->slave_read_start_delay);
+ i2c_writel(i2c_dev, value, I2C_SL_RCVD);
+ i2c_slave_event(i2c_dev->slave, I2C_SLAVE_REQ_READ_END, NULL);
+ }
+
+ return true;
+}
+
static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
{
u32 status;
const u32 status_err = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
struct tegra_i2c_dev *i2c_dev = dev_id;
+ if (tegra_i2c_slave_isr(irq, i2c_dev))
+ return IRQ_HANDLED;
+
status = i2c_readl(i2c_dev, I2C_INT_STATUS);
if (status == 0) {
From: Wolfram Sang <hidden> Date: 2015-01-29 11:42:06
Hi,
Initialization code is based on NVEC driver.
There is a HW bug in AP20 that was also mentioned in kernel sources
for Toshiba AC100.
Signed-off-by: Andrey Danin <redacted>
Cool, thanks for the converison. While I usually like to only get the
patches which I need to handle, please CC me to all patches next time. I
am interested what changes were needed for the user of the slave
framework, too.
Hi,
Sorry for long delay.
And thanks for the quick review. It helped a lot!
On 29.01.2015 14:41, Wolfram Sang wrote:
Hi,
quoted
Initialization code is based on NVEC driver.
There is a HW bug in AP20 that was also mentioned in kernel sources
for Toshiba AC100.
Signed-off-by: Andrey Danin <redacted>
Cool, thanks for the converison. While I usually like to only get the
patches which I need to handle, please CC me to all patches next time. I
am interested what changes were needed for the user of the slave
framework, too.