[PATCH v2] net: mdiobus: Prevent spike on MDIO bus reset signal

2021-02-02 Thread Mike Looijmans
The mdio_bus reset code first de-asserted the reset by allocating with
GPIOD_OUT_LOW, then asserted and de-asserted again. In other words, if
the reset signal defaulted to asserted, there'd be a short "spike"
before the reset.

Here is what happens depending on the pre-existing state of the reset
signal:
Reset (previously asserted):   ~~~|_||___
Reset (previously deasserted): _||___
  ^ ^^
  A BC

At point A, the low going transition is because the reset line is
requested using GPIOD_OUT_LOW. If the line is successfully requested,
the first thing we do is set it high _without_ any delay. This is
point B. So, a glitch occurs between A and B.

We then fsleep() and finally set the GPIO low at point C.

Requesting the line using GPIOD_OUT_HIGH eliminates the A and B
transitions. Instead we get:

Reset (previously asserted)  : ~~|__
Reset (previously deasserted): |~|__
   ^ ^
   A C

Where A and C are the points described above in the code. Point B
has been eliminated.

The issue was found when we pulled down the reset signal for the
Marvell 88E1512P PHY (because it requires at least 50ms after POR with
an active clock). Looking at the reset signal with a scope revealed a
short spike, point B in the artwork above.

Signed-off-by: Mike Looijmans 
Reviewed-by: Andrew Lunn 

---

Changes in v2:
Put more explanation into the commit text, and the artwork from Russell King

 drivers/net/phy/mdio_bus.c | 6 ++
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 2b42e46066b4..34e98ae75110 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -543,8 +543,8 @@ int __mdiobus_register(struct mii_bus *bus, struct module 
*owner)
mutex_init(>mdio_lock);
mutex_init(>shared_lock);
 
-   /* de-assert bus level PHY GPIO reset */
-   gpiod = devm_gpiod_get_optional(>dev, "reset", GPIOD_OUT_LOW);
+   /* assert bus level PHY GPIO reset */
+   gpiod = devm_gpiod_get_optional(>dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(gpiod)) {
err = dev_err_probe(>dev, PTR_ERR(gpiod),
"mii_bus %s couldn't get reset GPIO\n",
@@ -553,8 +553,6 @@ int __mdiobus_register(struct mii_bus *bus, struct module 
*owner)
return err;
} else  if (gpiod) {
bus->reset_gpiod = gpiod;
-
-   gpiod_set_value_cansleep(gpiod, 1);
fsleep(bus->reset_delay_us);
gpiod_set_value_cansleep(gpiod, 0);
if (bus->reset_post_delay_us > 0)
-- 
2.17.1



Re: [PATCH] net: mdiobus: Prevent spike on MDIO bus reset signal

2021-02-02 Thread Mike Looijmans



Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 28-01-2021 02:12, Andrew Lunn wrote:

On Thu, Jan 28, 2021 at 12:25:55AM +, Russell King - ARM Linux admin wrote:

On Thu, Jan 28, 2021 at 01:00:57AM +0100, Andrew Lunn wrote:

On Tue, Jan 26, 2021 at 01:49:38PM +, Russell King - ARM Linux admin wrote:

On Tue, Jan 26, 2021 at 02:14:40PM +0100, Andrew Lunn wrote:

On Tue, Jan 26, 2021 at 08:33:37AM +0100, Mike Looijmans wrote:

The mdio_bus reset code first de-asserted the reset by allocating with
GPIOD_OUT_LOW, then asserted and de-asserted again. In other words, if
the reset signal defaulted to asserted, there'd be a short "spike"
before the reset.

Instead, directly assert the reset signal using GPIOD_OUT_HIGH, this
removes the spike and also removes a line of code since the signal
is already high.

Hi Mike

This however appears to remove the reset pulse, if the reset line was
already low to start with. Notice you left

fsleep(bus->reset_delay_us);

without any action before it? What are we now waiting for?  Most data
sheets talk of a reset pulse. Take the reset line high, wait for some
time, take the reset low, wait for some time, and then start talking
to the PHY. I think with this patch, we have lost the guarantee of a
low to high transition.

Is this spike, followed by a pulse actually causing you problems? If
so, i would actually suggest adding another delay, to stretch the
spike. We have no control over the initial state of the reset line, it
is how the bootloader left it, we have to handle both states.

Andrew, I don't get what you're saying.

Here is what happens depending on the pre-existing state of the
reset signal:

Reset (previously asserted):   ~~~|_||___
Reset (previously deasserted): _||___
   ^ ^^
   A BC

At point A, the low going transition is because the reset line is
requested using GPIOD_OUT_LOW. If the line is successfully requested,
the first thing we do is set it high _without_ any delay. This is
point B. So, a glitch occurs between A and B.

We then fsleep() and finally set the GPIO low at point C.

Requesting the line using GPIOD_OUT_HIGH eliminates the A and B
transitions. Instead we get:

Reset (previously asserted)  : ~~|__
Reset (previously deasserted): |~|__
^ ^
A C

Where A and C are the points described above in the code. Point B
has been eliminated.

Therefore, to me the patch looks entirely reasonable and correct.

I wonder if there are any PHYs which actually need a pulse? Would it
be better to have:

  Reset (previously asserted):   ~~~|||___
  Reset (previously deasserted): ||___
^^^^
ABCD

Point D is where we actually start talking to the PHY. C-D is
reset-post-delay-us, and defaults to 0, but can be set via DT.  B-C is
reset-delay-us, and defaults to 10us, but can be set via DT.
Currently A-B is '0', so we get the glitch. But should we make A-B the
same as B-C, so we get a real pulse?

I do not see any need for A-B - what is the reason for it?

If level is all that matters, then it is not needed. If a PHY needs an
actual pulse, both a raising and a falling edge, we potentially don't
get the rising edge now.


We only caught the "spike" because the reset GPIO was controlled by a 
GPIO expander, so it took about a millisecond to toggle it. With a 
"local" GPIO controller, the pulse duration would be below the 
microsecond range and most PHYs would never see it.



But the datasheets you have looked at all seem to talk about level,
not pulse. So lets go with this.

Reviewed-by: Andrew Lunn 

 Andrew


Just wondering, now, a v2 patch isn't needed? Or should I amend the 
commit text?



--
Mike Looijmans



Re: [PATCH] net: mdiobus: Prevent spike on MDIO bus reset signal

2021-01-28 Thread Mike Looijmans

Hi Andrew,

Response below...


Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 28-01-2021 02:56, Andrew Lunn wrote:

On Tue, Jan 26, 2021 at 08:33:37AM +0100, Mike Looijmans wrote:

The mdio_bus reset code first de-asserted the reset by allocating with
GPIOD_OUT_LOW, then asserted and de-asserted again. In other words, if
the reset signal defaulted to asserted, there'd be a short "spike"
before the reset.

Instead, directly assert the reset signal using GPIOD_OUT_HIGH, this
removes the spike and also removes a line of code since the signal
is already high.


Hi Mike

Did you look at the per PHY reset? mdiobus_register_gpiod() gets the
GPIO with GPIOD_OUT_LOW. mdiobus_register_device() then immediately
sets it high.

So it looks like it suffers from the same problem.


Well, now that I have your attention...

The per PHY reset was more broken, it first probes the MDIO bus to see if the 
PHY is there, and only after that it controls the reset line. So if the reset 
defaults to "asserted", the PHY will not work because it didn't respond when 
the MDIO went looking for it. I haven't quite figured out how this was 
supposed to work, but at least for the case of one MDIO bus, one PHY 
configured through devicetree it didn't work as one would expect. I added a 
few printk statements to reveal that this was indeed the case.


This issue also makes the PHY hardware reset useless - if the PHY is in some 
non-responsive state, the MDIO won't get a response and report the PHY as 
missing before even attempting to assert/de-assert the reset line.


This was with a 5.4 kernel, but as far as I could see this hasn't changed 
since then.


My solution to that was to move to the MDIO bus reset, since that at least 
happened before interrogating the devices on the bus. This revealed the issue 
with the extra "spike" while evaluating that, which is something that I could 
easily solve and upstream.


Probably these issues were never dicovered because usually there's a pull-up 
of some kind on the (active-low) reset signal of the PHYs. That hides the 
spike and also hides the fact that the per-phy reset doesn't actually work. We 
only discovered the issue when we changed that to a pull-down and suddenly the 
phy failed to probe.


The way that the MDIO bus is being populated seemed rather complex to me, so 
chances of breaking things are quite high there...


Re: [PATCH] net: mdiobus: Prevent spike on MDIO bus reset signal

2021-01-26 Thread Mike Looijmans

See below.


Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 26-01-2021 14:49, Russell King - ARM Linux admin wrote:

On Tue, Jan 26, 2021 at 02:14:40PM +0100, Andrew Lunn wrote:

On Tue, Jan 26, 2021 at 08:33:37AM +0100, Mike Looijmans wrote:

The mdio_bus reset code first de-asserted the reset by allocating with
GPIOD_OUT_LOW, then asserted and de-asserted again. In other words, if
the reset signal defaulted to asserted, there'd be a short "spike"
before the reset.

Instead, directly assert the reset signal using GPIOD_OUT_HIGH, this
removes the spike and also removes a line of code since the signal
is already high.

Hi Mike

This however appears to remove the reset pulse, if the reset line was
already low to start with. Notice you left

fsleep(bus->reset_delay_us);

without any action before it? What are we now waiting for?  Most data
sheets talk of a reset pulse. Take the reset line high, wait for some
time, take the reset low, wait for some time, and then start talking
to the PHY. I think with this patch, we have lost the guarantee of a
low to high transition.

Is this spike, followed by a pulse actually causing you problems? If
so, i would actually suggest adding another delay, to stretch the
spike. We have no control over the initial state of the reset line, it
is how the bootloader left it, we have to handle both states.

Andrew, I don't get what you're saying.

Here is what happens depending on the pre-existing state of the
reset signal:

Reset (previously asserted):   ~~~|_||___
Reset (previously deasserted): _||___
   ^ ^^
   A BC

At point A, the low going transition is because the reset line is
requested using GPIOD_OUT_LOW. If the line is successfully requested,
the first thing we do is set it high _without_ any delay. This is
point B. So, a glitch occurs between A and B.

We then fsleep() and finally set the GPIO low at point C.

Requesting the line using GPIOD_OUT_HIGH eliminates the A and B
transitions. Instead we get:

Reset (previously asserted)  : ~~|__
Reset (previously deasserted): |~|__
^ ^
A C

Where A and C are the points described above in the code. Point B
has been eliminated.

Therefore, to me the patch looks entirely reasonable and correct.


Thanks, excellent explanation.

As a bit of background, we were using a Marvell PHY where the datasheet 
states that thou shallt not release the reset within 50 ms of power-up. 
A pull-down on the active-low reset was thus added. Looking at the reset 
signal with a scope revealed a short spike, visible only because it was 
being controlled by an I2C GPIO expander. So it's indeed point "B" that 
we wanted to eliminate.



--
Mike Looijmans



[PATCH] net: mdiobus: Prevent spike on MDIO bus reset signal

2021-01-26 Thread Mike Looijmans
The mdio_bus reset code first de-asserted the reset by allocating with
GPIOD_OUT_LOW, then asserted and de-asserted again. In other words, if
the reset signal defaulted to asserted, there'd be a short "spike"
before the reset.

Instead, directly assert the reset signal using GPIOD_OUT_HIGH, this
removes the spike and also removes a line of code since the signal
is already high.

Signed-off-by: Mike Looijmans 

---

 drivers/net/phy/mdio_bus.c | 6 ++
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 2b42e46066b4..34e98ae75110 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -543,8 +543,8 @@ int __mdiobus_register(struct mii_bus *bus, struct module 
*owner)
mutex_init(>mdio_lock);
mutex_init(>shared_lock);
 
-   /* de-assert bus level PHY GPIO reset */
-   gpiod = devm_gpiod_get_optional(>dev, "reset", GPIOD_OUT_LOW);
+   /* assert bus level PHY GPIO reset */
+   gpiod = devm_gpiod_get_optional(>dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(gpiod)) {
err = dev_err_probe(>dev, PTR_ERR(gpiod),
"mii_bus %s couldn't get reset GPIO\n",
@@ -553,8 +553,6 @@ int __mdiobus_register(struct mii_bus *bus, struct module 
*owner)
return err;
} else  if (gpiod) {
bus->reset_gpiod = gpiod;
-
-   gpiod_set_value_cansleep(gpiod, 1);
fsleep(bus->reset_delay_us);
gpiod_set_value_cansleep(gpiod, 0);
if (bus->reset_post_delay_us > 0)
-- 
2.17.1



[PATCH v8 2/2] iio: accel: Add support for the Bosch-Sensortec BMI088

2021-01-25 Thread Mike Looijmans
The BMI088 is a combined module with both accelerometer and gyroscope.
This adds the accelerometer driver support for the SPI interface.
The gyroscope part is already supported by the BMG160 driver.

Signed-off-by: Mike Looijmans 

---

Changes in v8:
include order asm/ after linux/
Suspend/resume redesigned, use runtime PM for both cases. Removed the
pm wrappers and let runtime PM handle power up/down. This also removed
the need for an internal mutex, thus reducing code further.

Changes in v7:
Change bmi088_accel to bmi088-accel
Order includes alphabetically
Suspend and disable on remove
Make bmi088_regmap_spi_{read|write} static

Changes in v6:
Hope you have good memory - v5 was almost a year ago now
Remove superfluous *val=0
Make sample_frequency selection into read_avail list

Changes in v5:
Add includes and forward defines in header
BIT(7) instead of 0x80
Reset already sets defaults, do not set them again
Remove now unused bmi088_accel_set_bw
Remove unused AXIS_MAX
Use MASK define for ODR setting
Explain buffer use and alignment
Split bmi088_accel_set_power_state into "on" and "off" parts
Cosmetic changes to improve readability

Changes in v4:
Remove unused #include directives
Remove unused #defines for event and irq
Replace (ret < 0) with (ret) for all regmap calls
Consistent checking of IO errors in probe and init
Removed #ifdef CONFIG_PM guard
Use bitops for set_frequency instead of loop with shift
s/__s16/s16/g
Remove excess blank lines
Don't return -EAGAIN in pm_runtime

Changes in v3:
Processed comments from Jonathan Cameron and Lars-Peter Clausen
implement runtime PM (tested by code tracing) and sleep
fix scale and offset factors for accel and temperature and
return raw values instead of pre-scaled ones
Use iio_device_{claim,release}_direct_mode
Remove unused code and structs
Use a cache-aligned buffer for bulk read
Configure and enable caching register values

Changes in v2:
Remove unused typedefs and variables
Fix error return when iio_device_register fails

 drivers/iio/accel/Kconfig |  18 +
 drivers/iio/accel/Makefile|   2 +
 drivers/iio/accel/bmi088-accel-core.c | 570 ++
 drivers/iio/accel/bmi088-accel-spi.c  |  83 
 drivers/iio/accel/bmi088-accel.h  |  18 +
 5 files changed, 691 insertions(+)
 create mode 100644 drivers/iio/accel/bmi088-accel-core.c
 create mode 100644 drivers/iio/accel/bmi088-accel-spi.c
 create mode 100644 drivers/iio/accel/bmi088-accel.h

diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 2e0c62c39155..cceda3cecbcf 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -157,6 +157,24 @@ config BMC150_ACCEL_SPI
tristate
select REGMAP_SPI
 
+config BMI088_ACCEL
+   tristate "Bosch BMI088 Accelerometer Driver"
+   depends on SPI
+   select IIO_BUFFER
+   select IIO_TRIGGERED_BUFFER
+   select REGMAP
+   select BMI088_ACCEL_SPI
+   help
+ Say yes here to build support for the Bosch BMI088 accelerometer.
+
+ This is a combo module with both accelerometer and gyroscope. This
+ driver only implements the accelerometer part, which has its own
+ address and register map. BMG160 provides the gyroscope driver.
+
+config BMI088_ACCEL_SPI
+   tristate
+   select REGMAP_SPI
+
 config DA280
tristate "MiraMEMS DA280 3-axis 14-bit digital accelerometer driver"
depends on I2C
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 4f6c1ebe13b0..32cd1342a31a 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -20,6 +20,8 @@ obj-$(CONFIG_BMA400_SPI) += bma400_spi.o
 obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
 obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o
 obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o
+obj-$(CONFIG_BMI088_ACCEL) += bmi088-accel-core.o
+obj-$(CONFIG_BMI088_ACCEL_SPI) += bmi088-accel-spi.o
 obj-$(CONFIG_DA280)+= da280.o
 obj-$(CONFIG_DA311)+= da311.o
 obj-$(CONFIG_DMARD06)  += dmard06.o
diff --git a/drivers/iio/accel/bmi088-accel-core.c 
b/drivers/iio/accel/bmi088-accel-core.c
new file mode 100644
index ..f86010a3cda3
--- /dev/null
+++ b/drivers/iio/accel/bmi088-accel-core.c
@@ -0,0 +1,570 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * 3-axis accelerometer driver supporting following Bosch-Sensortec chips:
+ *  - BMI088
+ *
+ * Copyright (c) 2018-2021, Topic Embedded Products
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "bmi088-accel.h"
+
+#define BMI088_ACCEL_REG_CHIP_ID   0x00
+#define BMI088_ACCEL_REG_ERROR 0x02
+
+#define BMI088_ACCEL_REG_INT_STATUS0x1D
+#define BMI088_ACCEL_INT_STATUS_BIT_DRDY   BIT(7)
+
+#define BMI088_ACCEL_REG_RESET 0x7E
+#defin

[PATCH v8 1/2] dt-bindings: iio: accel: Add bmi088 accelerometer bindings

2021-01-25 Thread Mike Looijmans
This adds the device-tree bindings for the Bosch Sensortec BMI088 IMU,
the accelerometer part.

Signed-off-by: Mike Looijmans 

---

Changes in v8:
Add spi-max-frequency: true

Changes in v7:
Add additionalProperties
Change bmi088_accel to bmi088-accel
Add interrupt-names and adjust description

Changes in v6:
I't been almost a year since the last commit, sorry...
Fixed the yaml errors
Add interrupt, vdd and vddio properties

Changes in v5:
submit together with driver code as patch series

Changes in v2:
convert to yaml format

 .../bindings/iio/accel/bosch,bmi088.yaml  | 68 +++
 1 file changed, 68 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml

diff --git a/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml 
b/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml
new file mode 100644
index ..911a1ae9c83f
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/accel/bosch,bmi088.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bosch BMI088 IMU accelerometer part
+
+maintainers:
+  - Mike Looijmans 
+
+description: |
+  Acceleration part of the IMU sensor with an SPI interface
+  Specifications about the sensor can be found at:
+
https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi088-ds001.pdf
+
+properties:
+  compatible:
+enum:
+  - bosch,bmi088-accel
+
+  reg:
+maxItems: 1
+
+  spi-max-frequency: true
+
+  vdd-supply: true
+
+  vddio-supply: true
+
+  interrupts:
+minItems: 1
+maxItems: 2
+description: |
+  Type should be either IRQ_TYPE_LEVEL_HIGH or IRQ_TYPE_LEVEL_LOW.
+  Two configurable interrupt lines exist.
+
+  interrupt-names:
+description: Specify which interrupt line is in use.
+items:
+  enum:
+- INT1
+- INT2
+minItems: 1
+maxItems: 2
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+#include 
+spi {
+  #address-cells = <1>;
+  #size-cells = <0>;
+  bmi088-accel@1 {
+compatible = "bosch,bmi088-accel";
+reg = <1>;
+spi-max-frequency = <1000>;
+interrupt-parent = <>;
+interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
+interrupt-names = "INT2";
+  };
+};
+...
-- 
2.17.1



Re: [PATCH v6 2/2] iio: accel: Add support for the Bosch-Sensortec BMI088

2021-01-25 Thread Mike Looijmans

See below


Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 24-01-2021 14:23, Jonathan Cameron wrote:

On Sun, 24 Jan 2021 00:21:13 +0100
Linus Walleij  wrote:


On Sat, Jan 23, 2021 at 4:35 PM Jonathan Cameron  wrote:

[Me]

Next, I think it is better to let suspend/resume, i.e. system PM
reuse runtime PM since you're implementing that. This is why
we invented PM runtime force resume and force suspend.

Here the driver is turning more off for full suspend than in the
runtime path.  If that results in significant extra delay then
it's not appropriate to have that in the runtime suspend path.

I see the point.

The resume path calls bmi088_accel_enable() which incurs
a 5ms delay.

The runtime resume path incurs a 1 ms delay.

The runtime autosuspend kicks in after 2 ms.


It's set to 2 seconds as I understand it. This to support reading a 
single value every second or so.





Maybe the simplification of not doing the deeper power saving
mode is worth the extra power cost or extra delay, but
I'm not yet convinced.

I would personally set the autosuspend to ~20ms and just use
one path and take a hit of 5 ms whenever we go down between
measures if it is a system that is for human interaction, but for
control systems this more complex set-up may be better for
response latencies.

The current approach may be better tuned to perfection and
we are all perfectionists :D

I'm just worrying a little about bugs and maintainability.

Fully understood.  Though for things like this I like to leave
it at the discretion of the driver author as fairly safe they
are a user of the device.

May well make sense to go with the longer times as you
suggest though!  Over to you Mike :)


I've been digging in the datasheet and it's really unclear how you're 
supposed to control the two power registers.


I think it's best to just put both control values into on/off state at 
the same time. I also prefer the simplicity of Linus' suggestion. I'll 
do some testing to see if the device behaves properly.


--
Mike Looijmans



Re: [PATCH v7 1/2] dt-bindings: iio: accel: Add bmi088 accelerometer bindings

2021-01-24 Thread Mike Looijmans

See below


Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 23-01-2021 16:38, Jonathan Cameron wrote:

On Thu, 21 Jan 2021 16:56:58 +0100
Mike Looijmans  wrote:


This adds the device-tree bindings for the Bosch Sensortec BMI088 IMU,
the accelerometer part.

Signed-off-by: Mike Looijmans 

Just the issue the build bot found.  Otherwise looks good to me.

Jonathan


---

Changes in v7:
Add additionalProperties
Change bmi088_accel to bmi088-accel
Add interrupt-names and adjust description

Changes in v6:
I't been almost a year since the last commit, sorry...
Fixed the yaml errors
Add interrupt, vdd and vddio properties

Changes in v5:
submit together with driver code as patch series

Changes in v2:
convert to yaml format

  .../bindings/iio/accel/bosch,bmi088.yaml  | 66 +++
  1 file changed, 66 insertions(+)
  create mode 100644 
Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml

diff --git a/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml 
b/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml
new file mode 100644
index ..db5dbaf80fa2
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml
@@ -0,0 +1,66 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/accel/bosch,bmi088.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bosch BMI088 IMU accelerometer part
+
+maintainers:
+  - Mike Looijmans 
+
+description: |
+  Acceleration part of the IMU sensor with an SPI interface
+  Specifications about the sensor can be found at:
+
https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi088-ds001.pdf
+
+properties:
+  compatible:
+enum:
+  - bosch,bmi088-accel
+
+  reg:
+maxItems: 1
+
+  vdd-supply: true
+
+  vddio-supply: true
+
+  interrupts:
+minItems: 1
+maxItems: 2
+description: |
+  Type should be either IRQ_TYPE_LEVEL_HIGH or IRQ_TYPE_LEVEL_LOW.
+  Two configurable interrupt lines exist.
+
+  interrupt-names:
+description: Specify which interrupt line is in use.
+items:
+  enum:
+- INT1
+- INT2
+minItems: 1
+maxItems: 2

As per Rob's build bot you need.

spi-max-frequency: true

If that's all that comes up and Rob is happy with this I can fix that up whilst
applying.  Please try to run the checks suggested in Rob's build bot message
before submitting binding patches though.


There'll be a v8 it seems, so I've already added it. Seems that I need 
to upgrade those definition files every day...



+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+#include 
+spi {
+  #address-cells = <1>;
+  #size-cells = <0>;
+  bmi088-accel@1 {
+compatible = "bosch,bmi088-accel";
+reg = <1>;
+spi-max-frequency = <1000>;
+interrupt-parent = <>;
+interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
+interrupt-names = "INT2";
+  };
+};
+...



--
Mike Looijmans



[PATCH v7 1/2] dt-bindings: iio: accel: Add bmi088 accelerometer bindings

2021-01-21 Thread Mike Looijmans
This adds the device-tree bindings for the Bosch Sensortec BMI088 IMU,
the accelerometer part.

Signed-off-by: Mike Looijmans 

---

Changes in v7:
Add additionalProperties
Change bmi088_accel to bmi088-accel
Add interrupt-names and adjust description

Changes in v6:
I't been almost a year since the last commit, sorry...
Fixed the yaml errors
Add interrupt, vdd and vddio properties

Changes in v5:
submit together with driver code as patch series

Changes in v2:
convert to yaml format

 .../bindings/iio/accel/bosch,bmi088.yaml  | 66 +++
 1 file changed, 66 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml

diff --git a/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml 
b/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml
new file mode 100644
index ..db5dbaf80fa2
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml
@@ -0,0 +1,66 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/accel/bosch,bmi088.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bosch BMI088 IMU accelerometer part
+
+maintainers:
+  - Mike Looijmans 
+
+description: |
+  Acceleration part of the IMU sensor with an SPI interface
+  Specifications about the sensor can be found at:
+
https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi088-ds001.pdf
+
+properties:
+  compatible:
+enum:
+  - bosch,bmi088-accel
+
+  reg:
+maxItems: 1
+
+  vdd-supply: true
+
+  vddio-supply: true
+
+  interrupts:
+minItems: 1
+maxItems: 2
+description: |
+  Type should be either IRQ_TYPE_LEVEL_HIGH or IRQ_TYPE_LEVEL_LOW.
+  Two configurable interrupt lines exist.
+
+  interrupt-names:
+description: Specify which interrupt line is in use.
+items:
+  enum:
+- INT1
+- INT2
+minItems: 1
+maxItems: 2
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+#include 
+spi {
+  #address-cells = <1>;
+  #size-cells = <0>;
+  bmi088-accel@1 {
+compatible = "bosch,bmi088-accel";
+reg = <1>;
+spi-max-frequency = <1000>;
+interrupt-parent = <>;
+interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
+interrupt-names = "INT2";
+  };
+};
+...
-- 
2.17.1



[PATCH v7 2/2] iio: accel: Add support for the Bosch-Sensortec BMI088

2021-01-21 Thread Mike Looijmans
The BMI088 is a combined module with both accelerometer and gyroscope.
This adds the accelerometer driver support for the SPI interface.
The gyroscope part is already supported by the BMG160 driver.

Signed-off-by: Mike Looijmans 

---

Changes in v7:
Change bmi088_accel to bmi088-accel
Order includes alphabetically
Suspend and disable on remove
Make bmi088_regmap_spi_{read|write} static

Changes in v6:
Hope you have good memory - v5 was almost a year ago now
Remove superfluous *val=0
Make sample_frequency selection into read_avail list

Changes in v5:
Add includes and forward defines in header
BIT(7) instead of 0x80
Reset already sets defaults, do not set them again
Remove now unused bmi088_accel_set_bw
Remove unused AXIS_MAX
Use MASK define for ODR setting
Explain buffer use and alignment
Split bmi088_accel_set_power_state into "on" and "off" parts
Cosmetic changes to improve readability

Changes in v4:
Remove unused #include directives
Remove unused #defines for event and irq
Replace (ret < 0) with (ret) for all regmap calls
Consistent checking of IO errors in probe and init
Removed #ifdef CONFIG_PM guard
Use bitops for set_frequency instead of loop with shift
s/__s16/s16/g
Remove excess blank lines
Don't return -EAGAIN in pm_runtime

Changes in v3:
Processed comments from Jonathan Cameron and Lars-Peter Clausen
implement runtime PM (tested by code tracing) and sleep
fix scale and offset factors for accel and temperature and
return raw values instead of pre-scaled ones
Use iio_device_{claim,release}_direct_mode
Remove unused code and structs
Use a cache-aligned buffer for bulk read
Configure and enable caching register values

Changes in v2:
Remove unused typedefs and variables
Fix error return when iio_device_register fails

 drivers/iio/accel/Kconfig |  18 +
 drivers/iio/accel/Makefile|   2 +
 drivers/iio/accel/bmi088-accel-core.c | 632 ++
 drivers/iio/accel/bmi088-accel-spi.c  |  83 
 drivers/iio/accel/bmi088-accel.h  |  18 +
 5 files changed, 753 insertions(+)
 create mode 100644 drivers/iio/accel/bmi088-accel-core.c
 create mode 100644 drivers/iio/accel/bmi088-accel-spi.c
 create mode 100644 drivers/iio/accel/bmi088-accel.h

diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 2e0c62c39155..cceda3cecbcf 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -157,6 +157,24 @@ config BMC150_ACCEL_SPI
tristate
select REGMAP_SPI
 
+config BMI088_ACCEL
+   tristate "Bosch BMI088 Accelerometer Driver"
+   depends on SPI
+   select IIO_BUFFER
+   select IIO_TRIGGERED_BUFFER
+   select REGMAP
+   select BMI088_ACCEL_SPI
+   help
+ Say yes here to build support for the Bosch BMI088 accelerometer.
+
+ This is a combo module with both accelerometer and gyroscope. This
+ driver only implements the accelerometer part, which has its own
+ address and register map. BMG160 provides the gyroscope driver.
+
+config BMI088_ACCEL_SPI
+   tristate
+   select REGMAP_SPI
+
 config DA280
tristate "MiraMEMS DA280 3-axis 14-bit digital accelerometer driver"
depends on I2C
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 4f6c1ebe13b0..32cd1342a31a 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -20,6 +20,8 @@ obj-$(CONFIG_BMA400_SPI) += bma400_spi.o
 obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
 obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o
 obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o
+obj-$(CONFIG_BMI088_ACCEL) += bmi088-accel-core.o
+obj-$(CONFIG_BMI088_ACCEL_SPI) += bmi088-accel-spi.o
 obj-$(CONFIG_DA280)+= da280.o
 obj-$(CONFIG_DA311)+= da311.o
 obj-$(CONFIG_DMARD06)  += dmard06.o
diff --git a/drivers/iio/accel/bmi088-accel-core.c 
b/drivers/iio/accel/bmi088-accel-core.c
new file mode 100644
index ..d7dc6f3e2fa6
--- /dev/null
+++ b/drivers/iio/accel/bmi088-accel-core.c
@@ -0,0 +1,632 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * 3-axis accelerometer driver supporting following Bosch-Sensortec chips:
+ *  - BMI088
+ *
+ * Copyright (c) 2018-2021, Topic Embedded Products
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "bmi088-accel.h"
+
+#define BMI088_ACCEL_REG_CHIP_ID   0x00
+#define BMI088_ACCEL_REG_ERROR 0x02
+
+#define BMI088_ACCEL_REG_INT_STATUS0x1D
+#define BMI088_ACCEL_INT_STATUS_BIT_DRDY   BIT(7)
+
+#define BMI088_ACCEL_REG_RESET 0x7E
+#define BMI088_ACCEL_RESET_VAL 0xB6
+
+#define BMI088_ACCEL_REG_PWR_CTRL  0x7D
+#define BMI088_ACCEL_REG_PWR_CONF  0x7C
+
+#define BMI088_ACCEL_REG_INT_MAP_DATA  

Re: [PATCH v6 2/2] iio: accel: Add support for the Bosch-Sensortec BMI088

2021-01-21 Thread Mike Looijmans

Comments inlined below.


Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 20-01-2021 21:22, Jonathan Cameron wrote:

On Tue, 19 Jan 2021 13:46:22 +0100
Mike Looijmans  wrote:


The BMI088 is a combined module with both accelerometer and gyroscope.
This adds the accelerometer driver support for the SPI interface.
The gyroscope part is already supported by the BMG160 driver.

Signed-off-by: Mike Looijmans 
---

Changes in v6:
Hope you have good memory - v5 was almost a year ago now

*laughs* fresh review so probably disagree with what I said back then on
something :)


A few really small comments inline seeing as you are respinning anyway.


Remove superfluous *val=0
Make sample_frequency selection into read_avail list

Changes in v5:
Add includes and forward defines in header
BIT(7) instead of 0x80
Reset already sets defaults, do not set them again
Remove now unused bmi088_accel_set_bw
Remove unused AXIS_MAX
Use MASK define for ODR setting
Explain buffer use and alignment
Split bmi088_accel_set_power_state into "on" and "off" parts
Cosmetic changes to improve readability

Changes in v4:
Remove unused #include directives
Remove unused #defines for event and irq
Replace (ret < 0) with (ret) for all regmap calls
Consistent checking of IO errors in probe and init
Removed #ifdef CONFIG_PM guard
Use bitops for set_frequency instead of loop with shift
s/__s16/s16/g
Remove excess blank lines
Don't return -EAGAIN in pm_runtime

Changes in v3:
Processed comments from Jonathan Cameron and Lars-Peter Clausen
implement runtime PM (tested by code tracing) and sleep
fix scale and offset factors for accel and temperature and
return raw values instead of pre-scaled ones
Use iio_device_{claim,release}_direct_mode
Remove unused code and structs
Use a cache-aligned buffer for bulk read
Configure and enable caching register values

Changes in v2:
Remove unused typedefs and variables
Fix error return when iio_device_register fails

  drivers/iio/accel/Kconfig |  18 +
  drivers/iio/accel/Makefile|   2 +
  drivers/iio/accel/bmi088-accel-core.c | 630 ++
  drivers/iio/accel/bmi088-accel-spi.c  |  85 
  drivers/iio/accel/bmi088-accel.h  |  18 +
  5 files changed, 753 insertions(+)
  create mode 100644 drivers/iio/accel/bmi088-accel-core.c
  create mode 100644 drivers/iio/accel/bmi088-accel-spi.c
  create mode 100644 drivers/iio/accel/bmi088-accel.h

diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 2e0c62c39155..cceda3cecbcf 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -157,6 +157,24 @@ config BMC150_ACCEL_SPI
tristate
select REGMAP_SPI
  
+config BMI088_ACCEL

+   tristate "Bosch BMI088 Accelerometer Driver"
+   depends on SPI
+   select IIO_BUFFER
+   select IIO_TRIGGERED_BUFFER
+   select REGMAP
+   select BMI088_ACCEL_SPI
+   help
+ Say yes here to build support for the Bosch BMI088 accelerometer.
+
+ This is a combo module with both accelerometer and gyroscope. This
+ driver only implements the accelerometer part, which has its own
+ address and register map. BMG160 provides the gyroscope driver.
+
+config BMI088_ACCEL_SPI
+   tristate
+   select REGMAP_SPI
+
  config DA280
tristate "MiraMEMS DA280 3-axis 14-bit digital accelerometer driver"
depends on I2C
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 4f6c1ebe13b0..32cd1342a31a 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -20,6 +20,8 @@ obj-$(CONFIG_BMA400_SPI) += bma400_spi.o
  obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
  obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o
  obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o
+obj-$(CONFIG_BMI088_ACCEL) += bmi088-accel-core.o
+obj-$(CONFIG_BMI088_ACCEL_SPI) += bmi088-accel-spi.o
  obj-$(CONFIG_DA280)   += da280.o
  obj-$(CONFIG_DA311)   += da311.o
  obj-$(CONFIG_DMARD06) += dmard06.o
diff --git a/drivers/iio/accel/bmi088-accel-core.c 
b/drivers/iio/accel/bmi088-accel-core.c
new file mode 100644
index ..788e54ed0728
--- /dev/null
+++ b/drivers/iio/accel/bmi088-accel-core.c
@@ -0,0 +1,630 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * 3-axis accelerometer driver supporting following Bosch-Sensortec chips:
+ *  - BMI088
+ *
+ * Copyright (c) 2018-2020, Topic Embedded Products
+ */
+
+#include 
+#include 
+#include 

As below. Alphabetical ordering preferred.


Will do.




+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "bmi088-accel.h"

...


+static int bmi088_accel_chip_init(struct b

Re: [PATCH v6 1/2] dt-bindings: iio: accel: Add bmi088 accelerometer bindings

2021-01-21 Thread Mike Looijmans

Comments inlined below.


Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 20-01-2021 19:50, Jonathan Cameron wrote:

On Tue, 19 Jan 2021 13:46:21 +0100
Mike Looijmans  wrote:


This adds the device-tree bindings for the Bosch Sensortec BMI088 IMU,
the accelerometer part.

Signed-off-by: Mike Looijmans 

---

Changes in v6:
I't been almost a year since the last commit, sorry...

No problem. Happens to us all sometimes!

One thing inline below.

Thanks,

Jonathan


Fixed the yaml errors
Add interrupt, vdd and vddio properties

Changes in v5:
submit together with driver code as patch series

Changes in v2:
convert to yaml format

  .../bindings/iio/accel/bosch,bmi088.yaml  | 55 +++
  1 file changed, 55 insertions(+)
  create mode 100644 
Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml

diff --git a/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml 
b/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml
new file mode 100644
index ..459b9969fd12
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/accel/bosch,bmi088.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bosch BMI088 IMU accelerometer part
+
+maintainers:
+  - Mike Looijmans 
+
+description: |
+  Acceleration part of the IMU sensor with an SPI interface
+  Specifications about the sensor can be found at:
+
https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi088-ds001.pdf
+
+properties:
+  compatible:
+enum:
+  - bosch,bmi088_accel
+
+  reg:
+maxItems: 1
+
+  vdd-supply: true
+
+  vddio-supply: true
+
+  interrupts:
+minItems: 1
+maxItems: 2
+description: |
+  Type should be either IRQ_TYPE_LEVEL_HIGH or IRQ_TYPE_LEVEL_LOW.
+  The first interrupt listed must be the one connected to the INT1 pin, the
+  second must be the one connected to the INT2 pin.


What if the board only has the INT2 pin connected?
That's looks to be a valid hardware configuration.

I'd suggest using interrupt-names to cover this.


Yeah makes sense. The pins have the same functionality, so either one will do.




+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+#include 
+spi {
+  #address-cells = <1>;
+  #size-cells = <0>;
+  bmi088_accel@1 {
+compatible = "bosch,bmi088_accel";
+reg = <1>;
+spi-max-frequency = <1000>;
+interrupt-parent = <>;
+interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
+  };
+};
+...






Re: [PATCH v6 1/2] dt-bindings: iio: accel: Add bmi088 accelerometer bindings

2021-01-19 Thread Mike Looijmans

Wow, fast response, thanks.

Updated my dtschema, fixed the match name as requested and v7 is ready 
to go. I'm awaiting feedback from the iio people so I can send a new 
patch set.


M.


Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 20-01-2021 02:31, Rob Herring wrote:

On Tue, Jan 19, 2021 at 01:46:21PM +0100, Mike Looijmans wrote:

This adds the device-tree bindings for the Bosch Sensortec BMI088 IMU,
the accelerometer part.

Signed-off-by: Mike Looijmans 

---

Changes in v6:
I't been almost a year since the last commit, sorry...
Fixed the yaml errors
Add interrupt, vdd and vddio properties

Changes in v5:
submit together with driver code as patch series

Changes in v2:
convert to yaml format

  .../bindings/iio/accel/bosch,bmi088.yaml  | 55 +++
  1 file changed, 55 insertions(+)
  create mode 100644 
Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml

diff --git a/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml 
b/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml
new file mode 100644
index ..459b9969fd12
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/accel/bosch,bmi088.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bosch BMI088 IMU accelerometer part
+
+maintainers:
+  - Mike Looijmans 
+
+description: |
+  Acceleration part of the IMU sensor with an SPI interface
+  Specifications about the sensor can be found at:
+
https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi088-ds001.pdf
+
+properties:
+  compatible:
+enum:
+  - bosch,bmi088_accel

bosch,bmi088-accel


+
+  reg:
+maxItems: 1
+
+  vdd-supply: true
+
+  vddio-supply: true
+
+  interrupts:
+minItems: 1
+maxItems: 2
+description: |
+  Type should be either IRQ_TYPE_LEVEL_HIGH or IRQ_TYPE_LEVEL_LOW.
+  The first interrupt listed must be the one connected to the INT1 pin, the
+  second must be the one connected to the INT2 pin.
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+#include 
+spi {
+  #address-cells = <1>;
+  #size-cells = <0>;
+  bmi088_accel@1 {
+compatible = "bosch,bmi088_accel";
+reg = <1>;
+spi-max-frequency = <1000>;
+interrupt-parent = <>;
+interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
+  };
+};
+...
--
2.17.1



--
Mike Looijmans



[PATCH v6 2/2] iio: accel: Add support for the Bosch-Sensortec BMI088

2021-01-19 Thread Mike Looijmans
The BMI088 is a combined module with both accelerometer and gyroscope.
This adds the accelerometer driver support for the SPI interface.
The gyroscope part is already supported by the BMG160 driver.

Signed-off-by: Mike Looijmans 
---

Changes in v6:
Hope you have good memory - v5 was almost a year ago now
Remove superfluous *val=0
Make sample_frequency selection into read_avail list

Changes in v5:
Add includes and forward defines in header
BIT(7) instead of 0x80
Reset already sets defaults, do not set them again
Remove now unused bmi088_accel_set_bw
Remove unused AXIS_MAX
Use MASK define for ODR setting
Explain buffer use and alignment
Split bmi088_accel_set_power_state into "on" and "off" parts
Cosmetic changes to improve readability

Changes in v4:
Remove unused #include directives
Remove unused #defines for event and irq
Replace (ret < 0) with (ret) for all regmap calls
Consistent checking of IO errors in probe and init
Removed #ifdef CONFIG_PM guard
Use bitops for set_frequency instead of loop with shift
s/__s16/s16/g
Remove excess blank lines
Don't return -EAGAIN in pm_runtime

Changes in v3:
Processed comments from Jonathan Cameron and Lars-Peter Clausen
implement runtime PM (tested by code tracing) and sleep
fix scale and offset factors for accel and temperature and
return raw values instead of pre-scaled ones
Use iio_device_{claim,release}_direct_mode
Remove unused code and structs
Use a cache-aligned buffer for bulk read
Configure and enable caching register values

Changes in v2:
Remove unused typedefs and variables
Fix error return when iio_device_register fails

 drivers/iio/accel/Kconfig |  18 +
 drivers/iio/accel/Makefile|   2 +
 drivers/iio/accel/bmi088-accel-core.c | 630 ++
 drivers/iio/accel/bmi088-accel-spi.c  |  85 
 drivers/iio/accel/bmi088-accel.h  |  18 +
 5 files changed, 753 insertions(+)
 create mode 100644 drivers/iio/accel/bmi088-accel-core.c
 create mode 100644 drivers/iio/accel/bmi088-accel-spi.c
 create mode 100644 drivers/iio/accel/bmi088-accel.h

diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 2e0c62c39155..cceda3cecbcf 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -157,6 +157,24 @@ config BMC150_ACCEL_SPI
tristate
select REGMAP_SPI
 
+config BMI088_ACCEL
+   tristate "Bosch BMI088 Accelerometer Driver"
+   depends on SPI
+   select IIO_BUFFER
+   select IIO_TRIGGERED_BUFFER
+   select REGMAP
+   select BMI088_ACCEL_SPI
+   help
+ Say yes here to build support for the Bosch BMI088 accelerometer.
+
+ This is a combo module with both accelerometer and gyroscope. This
+ driver only implements the accelerometer part, which has its own
+ address and register map. BMG160 provides the gyroscope driver.
+
+config BMI088_ACCEL_SPI
+   tristate
+   select REGMAP_SPI
+
 config DA280
tristate "MiraMEMS DA280 3-axis 14-bit digital accelerometer driver"
depends on I2C
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 4f6c1ebe13b0..32cd1342a31a 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -20,6 +20,8 @@ obj-$(CONFIG_BMA400_SPI) += bma400_spi.o
 obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
 obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o
 obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o
+obj-$(CONFIG_BMI088_ACCEL) += bmi088-accel-core.o
+obj-$(CONFIG_BMI088_ACCEL_SPI) += bmi088-accel-spi.o
 obj-$(CONFIG_DA280)+= da280.o
 obj-$(CONFIG_DA311)+= da311.o
 obj-$(CONFIG_DMARD06)  += dmard06.o
diff --git a/drivers/iio/accel/bmi088-accel-core.c 
b/drivers/iio/accel/bmi088-accel-core.c
new file mode 100644
index ..788e54ed0728
--- /dev/null
+++ b/drivers/iio/accel/bmi088-accel-core.c
@@ -0,0 +1,630 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * 3-axis accelerometer driver supporting following Bosch-Sensortec chips:
+ *  - BMI088
+ *
+ * Copyright (c) 2018-2020, Topic Embedded Products
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "bmi088-accel.h"
+
+#define BMI088_ACCEL_REG_CHIP_ID   0x00
+#define BMI088_ACCEL_REG_ERROR 0x02
+
+#define BMI088_ACCEL_REG_INT_STATUS0x1D
+#define BMI088_ACCEL_INT_STATUS_BIT_DRDY   BIT(7)
+
+#define BMI088_ACCEL_REG_RESET 0x7E
+#define BMI088_ACCEL_RESET_VAL 0xB6
+
+#define BMI088_ACCEL_REG_PWR_CTRL  0x7D
+#define BMI088_ACCEL_REG_PWR_CONF  0x7C
+
+#define BMI088_ACCEL_REG_INT_MAP_DATA  0x58
+#define BMI088_ACCEL_INT_MAP_DATA_BIT_INT1_DRDYBIT(2)
+#define BMI088_ACCEL_INT_MAP_DATA_BIT_INT2_FWM BIT(5)
+
+#define BMI088_

[PATCH v6 1/2] dt-bindings: iio: accel: Add bmi088 accelerometer bindings

2021-01-19 Thread Mike Looijmans
This adds the device-tree bindings for the Bosch Sensortec BMI088 IMU,
the accelerometer part.

Signed-off-by: Mike Looijmans 

---

Changes in v6:
I't been almost a year since the last commit, sorry...
Fixed the yaml errors
Add interrupt, vdd and vddio properties

Changes in v5:
submit together with driver code as patch series

Changes in v2:
convert to yaml format

 .../bindings/iio/accel/bosch,bmi088.yaml  | 55 +++
 1 file changed, 55 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml

diff --git a/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml 
b/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml
new file mode 100644
index ..459b9969fd12
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/accel/bosch,bmi088.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bosch BMI088 IMU accelerometer part
+
+maintainers:
+  - Mike Looijmans 
+
+description: |
+  Acceleration part of the IMU sensor with an SPI interface
+  Specifications about the sensor can be found at:
+
https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi088-ds001.pdf
+
+properties:
+  compatible:
+enum:
+  - bosch,bmi088_accel
+
+  reg:
+maxItems: 1
+
+  vdd-supply: true
+
+  vddio-supply: true
+
+  interrupts:
+minItems: 1
+maxItems: 2
+description: |
+  Type should be either IRQ_TYPE_LEVEL_HIGH or IRQ_TYPE_LEVEL_LOW.
+  The first interrupt listed must be the one connected to the INT1 pin, the
+  second must be the one connected to the INT2 pin.
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+#include 
+spi {
+  #address-cells = <1>;
+  #size-cells = <0>;
+  bmi088_accel@1 {
+compatible = "bosch,bmi088_accel";
+reg = <1>;
+spi-max-frequency = <1000>;
+interrupt-parent = <>;
+interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
+  };
+};
+...
-- 
2.17.1



[PATCH v5] power/supply: Add ltc4162-l-charger

2021-01-07 Thread Mike Looijmans
Add support for the LTC4162-L Li-Ion battery charger. The driver allows
reading back telemetry and to set some charging options like the input
current limit.

Signed-off-by: Mike Looijmans 
---
v2: Use microohm units instead of milliohm
Add interrupt support using smbalert
Support obtaining cell-count from devicetree
v3: Fix overflows in calculations involving resistor values
v4: Use attr_grp member to register attributes
Report input current/voltage for charger and make battery
voltage and current into sysfs attributes
v5: Remove ltc4162l_remove since core now takes care of attributes
Add ABI documentation for attributes

 .../ABI/testing/sysfs-class-power-ltc4162l|  82 ++
 drivers/power/supply/Kconfig  |   8 +
 drivers/power/supply/Makefile |   1 +
 drivers/power/supply/ltc4162-l-charger.c  | 931 ++
 4 files changed, 1022 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-class-power-ltc4162l
 create mode 100644 drivers/power/supply/ltc4162-l-charger.c

diff --git a/Documentation/ABI/testing/sysfs-class-power-ltc4162l 
b/Documentation/ABI/testing/sysfs-class-power-ltc4162l
new file mode 100644
index ..ba30db93052b
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-power-ltc4162l
@@ -0,0 +1,82 @@
+What:  /sys/class/power_supply/ltc4162-l/charge_status
+Date:  Januari 2021
+KernelVersion: 5.11
+Description:
+   Detailed charge status information as reported by the chip.
+
+   Access: Read
+
+   Valid values:
+   ilim_reg_active
+   thermal_reg_active
+   vin_uvcl_active
+   iin_limit_active
+   constant_current
+   constant_voltage
+   charger_off
+
+What:  /sys/class/power_supply/ltc4162-l/ibat
+Date:  Januari 2021
+KernelVersion: 5.11
+Description:
+   Battery input current as measured by the charger. Negative value
+   means that the battery is discharging.
+
+   Access: Read
+
+   Valid values: Signed value in microamps
+
+What:  /sys/class/power_supply/ltc4162-l/vbat
+Date:  Januari 2021
+KernelVersion: 5.11
+Description:
+   Battery voltage as measured by the charger.
+
+   Access: Read
+
+   Valid values: In microvolts
+
+What:  /sys/class/power_supply/ltc4162-l/vbat_avg
+Date:  Januari 2021
+KernelVersion: 5.11
+Description:
+   Battery voltage, averaged over time, as measured by the charger.
+
+   Access: Read
+
+   Valid values: In microvolts
+
+What:  /sys/class/power_supply/ltc4162-l/force_telemetry
+Date:  Januari 2021
+KernelVersion: 5.11
+Description:
+   To save battery current, the measurement system is disabled if
+   the battery is the only source of power. This affects all
+   voltage, current and temperature measurements.
+   Write a "1" to this to keep performing telemetry once every few
+   seconds, even when running on battery (as reported by the online
+   property, which is "1" when external power is available and "0"
+   when the system runs on battery).
+
+   Access: Read, Write
+
+   Valid values: 0 (disabled) or 1 (enabled)
+
+What:  /sys/class/power_supply/ltc4162-l/arm_ship_mode
+Date:  Januari 2021
+KernelVersion: 5.11
+Description:
+   The charger will normally drain the battery while inactive,
+   typically drawing about 54 microamps. Write a "1" to this
+   property to arm a special "ship" mode that extends shelf life
+   by reducing the leakage to about 2.8 microamps. The chip will
+   remain in this mode (and no longer respond to I2C commands)
+   until some external power-supply is attached raising the input
+   voltage above 1V. It will then automatically revert to "0".
+   Writing a "0" to the property cancels the "ship" mode request.
+   The ship mode, when armed, activates once the input voltage
+   drops below 1V.
+
+   Access: Read, Write
+
+   Valid values: 0 (disable) or 1 (enable)
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index eec646c568b7..23000976cb42 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -513,6 +513,14 @@ config CHARGER_LT3651
  Say Y to include support for the Analog Devices (Linear Technology)
  LT3651 battery charger which reports its status via GPIO lines.
 
+config CHARGER_LTC4162L
+   tristate "LTC4162-L charger"
+ 

Re: [PATCH v4] power/supply: Add ltc4162-l-charger

2021-01-07 Thread Mike Looijmans



Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 06-01-2021 16:16, Sebastian Reichel wrote:

Hi,

On Wed, Jan 06, 2021 at 08:55:57AM +0100, Mike Looijmans wrote:

Add support for the LTC4162-L Li-Ion battery charger. The driver allows
reading back telemetry and to set some charging options like the input
current limit.

Signed-off-by: Mike Looijmans 
---
v2: Use microohm units instead of milliohm
 Add interrupt support using smbalert
 Support obtaining cell-count from devicetree
v3: Fix overflows in calculations involving resistor values
v4: Use attr_grp member to register attributes
 Report input current/voltage for charger and make battery
 voltage and current into sysfs attributes

Fine with me until we have a better way to solve the problem. IIUIC
you no longer have access to the hardware anyways? But you need to
document the custom sysfs nodes: Please document them in the
following file:

Documentation/ABI/testing/sysfs-class-power-ltc4162l


v5 is on its way with a description.

I currently don't have access to the hardware, so these changes were 
only compile-tested.



[...]


+static int ltc4162l_remove(struct i2c_client *client)
+{
+   struct ltc4162l_info *info = i2c_get_clientdata(client);
+
+   sysfs_remove_group(>charger->dev.kobj, _attr_group);
+
+   return 0;
+}

power-supply core automatically removes the sysfs groups specified
in power_supply_config.attr_grp.


Ah, good catch, missed that.




-- Sebastian



--
Mike Looijmans



[PATCH v4] power/supply: Add ltc4162-l-charger

2021-01-05 Thread Mike Looijmans
Add support for the LTC4162-L Li-Ion battery charger. The driver allows
reading back telemetry and to set some charging options like the input
current limit.

Signed-off-by: Mike Looijmans 
---
v2: Use microohm units instead of milliohm
Add interrupt support using smbalert
Support obtaining cell-count from devicetree
v3: Fix overflows in calculations involving resistor values
v4: Use attr_grp member to register attributes
Report input current/voltage for charger and make battery
voltage and current into sysfs attributes

 drivers/power/supply/Kconfig |   8 +
 drivers/power/supply/Makefile|   1 +
 drivers/power/supply/ltc4162-l-charger.c | 941 +++
 3 files changed, 950 insertions(+)
 create mode 100644 drivers/power/supply/ltc4162-l-charger.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index eec646c568b7..23000976cb42 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -513,6 +513,14 @@ config CHARGER_LT3651
  Say Y to include support for the Analog Devices (Linear Technology)
  LT3651 battery charger which reports its status via GPIO lines.
 
+config CHARGER_LTC4162L
+   tristate "LTC4162-L charger"
+   depends on I2C
+   select REGMAP_I2C
+   help
+ Say Y to include support for the Analog Devices (Linear Technology)
+ LTC4162-L battery charger connected to I2C.
+
 config CHARGER_MAX14577
tristate "Maxim MAX14577/77836 battery charger driver"
depends on MFD_MAX14577
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index dd4b86318cd9..17b1cf921c44 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_CHARGER_LP8788)  += lp8788-charger.o
 obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
 obj-$(CONFIG_CHARGER_MANAGER)  += charger-manager.o
 obj-$(CONFIG_CHARGER_LT3651)   += lt3651-charger.o
+obj-$(CONFIG_CHARGER_LTC4162L) += ltc4162-l-charger.o
 obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
 obj-$(CONFIG_CHARGER_DETECTOR_MAX14656)+= max14656_charger_detector.o
 obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o
diff --git a/drivers/power/supply/ltc4162-l-charger.c 
b/drivers/power/supply/ltc4162-l-charger.c
new file mode 100644
index ..af97a9a35834
--- /dev/null
+++ b/drivers/power/supply/ltc4162-l-charger.c
@@ -0,0 +1,941 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Driver for Analog Devices (Linear Technology) LTC4162-L charger IC.
+ *  Copyright (C) 2020, Topic Embedded Products
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* Registers (names based on what datasheet uses) */
+#define LTC4162L_EN_LIMIT_ALERTS_REG   0x0D
+#define LTC4162L_EN_CHARGER_STATE_ALERTS_REG   0x0E
+#define LTC4162L_EN_CHARGE_STATUS_ALERTS_REG   0x0F
+#define LTC4162L_CONFIG_BITS_REG   0x14
+#define LTC4162L_IIN_LIMIT_TARGET  0x15
+#define LTC4162L_ARM_SHIP_MODE 0x19
+#define LTC4162L_CHARGE_CURRENT_SETTING0X1A
+#define LTC4162L_VCHARGE_SETTING   0X1B
+#define LTC4162L_C_OVER_X_THRESHOLD0x1C
+#define LTC4162L_MAX_CV_TIME   0X1D
+#define LTC4162L_MAX_CHARGE_TIME   0X1E
+#define LTC4162L_CHARGER_CONFIG_BITS   0x29
+#define LTC4162L_CHARGER_STATE 0x34
+#define LTC4162L_CHARGE_STATUS 0x35
+#define LTC4162L_LIMIT_ALERTS_REG  0x36
+#define LTC4162L_CHARGER_STATE_ALERTS_REG  0x37
+#define LTC4162L_CHARGE_STATUS_ALERTS_REG  0x38
+#define LTC4162L_SYSTEM_STATUS_REG 0x39
+#define LTC4162L_VBAT  0x3A
+#define LTC4162L_VIN   0x3B
+#define LTC4162L_VOUT  0x3C
+#define LTC4162L_IBAT  0x3D
+#define LTC4162L_IIN   0x3E
+#define LTC4162L_DIE_TEMPERATURE   0x3F
+#define LTC4162L_THERMISTOR_VOLTAGE0x40
+#define LTC4162L_BSR   0x41
+#define LTC4162L_JEITA_REGION  0x42
+#define LTC4162L_CHEM_CELLS_REG0x43
+#define LTC4162L_ICHARGE_DAC   0x44
+#define LTC4162L_VCHARGE_DAC   0x45
+#define LTC4162L_IIN_LIMIT_DAC 0x46
+#define LTC4162L_VBAT_FILT 0x47
+#define LTC4162L_INPUT_UNDERVOLTAGE_DAC0x4B
+
+/* Enumeration as in datasheet. Individual bits are mutually exclusive. */
+enum ltc4162l_state {
+   battery_detection = 2048,
+   charger_suspended = 256,
+   precharge = 128,   /* trickle on low bat voltage */
+   cc_cv_charge = 64, /* normal charge */
+   ntc_pause = 32,
+   timer_term = 16,
+   c_over_x_term = 8, /* battery is full */
+   max_charge_time_fault = 4,
+   b

[PATCH v2] clk-si5341: Support NVM programming through sysfs

2021-01-05 Thread Mike Looijmans
Export an attribute program_nvm_bank that when read reports the current
bank value. To program the chip's current state into NVM, write the
magic value 0xC7 into this attribute.

This allows the clock chip to be programmed "in system" to reduce boot
time by 300ms and allows the clock to be up and running before the
kernel boots (e.g. for bootloader usage). Some vendors initialize PLLs
only in their bootloader and thus need the clock running at boot.

Signed-off-by: Mike Looijmans 
---
v2: Add description in Documentation/ABI/
Use regmap_read_poll_timeout()
Abort on sysfs_create_group error

 .../ABI/testing/sysfs-devices-clk-si5341  | 24 +++
 drivers/clk/clk-si5341.c  | 68 +++
 2 files changed, 92 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-devices-clk-si5341

diff --git a/Documentation/ABI/testing/sysfs-devices-clk-si5341 
b/Documentation/ABI/testing/sysfs-devices-clk-si5341
new file mode 100644
index ..7243b82a3729
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-clk-si5341
@@ -0,0 +1,24 @@
+What:  /sys/bus/i2c/devices/.../clk-si534*/program_nvm_bank
+Date:  Jan 2021
+KernelVersion: 5.12
+Contact:   Mike Looijmans 
+Description:   Allows programming the NVM memory of the clock chip, so it boots
+   up in the current configuration. This saves boot time (300ms
+   clock initialization) and allows the clock to be available
+   before the kernel boots (e.g. u-boot ethernet clock).
+
+   Write the magic value 0xc7 to this attribute to program the
+   chip's current settings into its NVM storage. This magic value
+   is taken from the datasheet, it's the same value that must be
+   written to the hardware to program it. Programming can only be
+   done twice in the lifetime of the chip.
+
+   Read the value to check the state of the chip. This returns the
+   raw value as read from the hardware. Possible values:
+   0x03: Not programmed
+   0x0f: Programmed once
+   0x3f: Programmed twice, can no longer be programmed
+
+Users: User space applications for embedded boards equipped with one
+   or more Si534x programmable clock devices. Would typically be
+   used at the end of production stages.
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index e0446e66fa64..836af718eed0 100644
--- a/drivers/clk/clk-si5341.c
+++ b/drivers/clk/clk-si5341.c
@@ -92,6 +92,9 @@ struct clk_si5341_output_config {
 #define SI5341_PN_BASE 0x0002
 #define SI5341_DEVICE_REV  0x0005
 #define SI5341_STATUS  0x000C
+#define SI5341_ACTIVE_NVM_BANK 0x00E2
+#define SI5341_NVM_WRITE   0x00E3
+#define SI5341_DEVICE_READY0x00FE
 #define SI5341_SOFT_RST0x001C
 #define SI5341_IN_SEL  0x0021
 #define SI5341_XAXB_CFG0x090E
@@ -144,6 +147,9 @@ struct clk_si5341_output_config {
 #define SI5341_OUT_CFG_OE  BIT(1)
 #define SI5341_OUT_CFG_RDIV_FORCE2 BIT(2)
 
+/* Programming NVM, magic value to write to program the NVM */
+#define SI5341_SI5341_NVM_WRITE_COOKIE 0xC7
+
 /* Static configuration (to be moved to firmware) */
 struct si5341_reg_default {
u16 address;
@@ -1199,6 +1205,64 @@ static const struct regmap_config si5341_regmap_config = 
{
.volatile_table = _regmap_volatile,
 };
 
+static ssize_t program_nvm_bank_show(struct device *dev,
+   struct device_attribute *attr, char *buf)
+{
+   struct i2c_client *client = to_i2c_client(dev);
+   struct clk_si5341 *data = i2c_get_clientdata(client);
+   unsigned int regval;
+   int ret;
+
+   ret = regmap_read(data->regmap, SI5341_ACTIVE_NVM_BANK, );
+   if (ret)
+   return ret;
+
+   return sprintf(buf, "%#x\n", regval);
+}
+
+static ssize_t program_nvm_bank_store(struct device *dev,
+   struct device_attribute *attr,
+   const char *buf,
+   size_t count)
+{
+   struct clk_si5341 *data = i2c_get_clientdata(to_i2c_client(dev));
+   int ret;
+   unsigned int value;
+
+   ret = kstrtouint(buf, 0, );
+   if (ret < 0)
+   return ret;
+
+   /* Write the magic value to this attribute to program the NVM */
+   if (value != SI5341_SI5341_NVM_WRITE_COOKIE)
+   return -EINVAL;
+
+   ret = regmap_write(data->regmap, SI5341_NVM_WRITE,
+   SI5341_SI5341_NVM_WRITE_COOKIE);
+   if (ret)
+   return ret;
+
+   /* Wait for SI5341_DEVICE_READY register to become 0x0f */
+   ret = regmap_read_poll_timeout(data->regmap, SI5341_DEVICE_READY, value,
+  value == 0x0f, 0, 30);
+   if (ret)
+   return ret;
+
+   return count;
+}
+
+static

Re: [PATCH v3] power/supply: Add ltc4162-l-charger

2021-01-04 Thread Mike Looijmans

Hello,

No worries on processing time. Only drawback is that since the project 
ended, I may no longer have access to the actual hardware for testing.


Further inline comments below.


Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 29-12-2020 15:57, Sebastian Reichel wrote:

Hi,

Sorry for slow processing of this. Driver looks mostly fine, but I
do have some comments.

On Mon, Nov 02, 2020 at 10:21:31AM +0100, Mike Looijmans wrote:

Add support for the LTC4162-L Li-Ion battery charger. The driver allows
reading back telemetry and to set some charging options like the input
current limit.

Signed-off-by: Mike Looijmans 
---
v2: Use microohm units instead of milliohm
 Add interrupt support using smbalert
 Support obtaining cell-count from devicetree
v3: Fix overflows in calculations involving resistor values
resent, mail bounced

  drivers/power/supply/Kconfig |   8 +
  drivers/power/supply/Makefile|   1 +
  drivers/power/supply/ltc4162-l-charger.c | 898 +++
  3 files changed, 907 insertions(+)
  create mode 100644 drivers/power/supply/ltc4162-l-charger.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index eec646c568b7..23000976cb42 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -513,6 +513,14 @@ config CHARGER_LT3651
  Say Y to include support for the Analog Devices (Linear Technology)
  LT3651 battery charger which reports its status via GPIO lines.
  
+config CHARGER_LTC4162L

+   tristate "LTC4162-L charger"
+   depends on I2C
+   select REGMAP_I2C
+   help
+ Say Y to include support for the Analog Devices (Linear Technology)
+ LTC4162-L battery charger connected to I2C.
+
  config CHARGER_MAX14577
tristate "Maxim MAX14577/77836 battery charger driver"
depends on MFD_MAX14577
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index dd4b86318cd9..17b1cf921c44 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_CHARGER_LP8788)  += lp8788-charger.o
  obj-$(CONFIG_CHARGER_GPIO)+= gpio-charger.o
  obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
  obj-$(CONFIG_CHARGER_LT3651)  += lt3651-charger.o
+obj-$(CONFIG_CHARGER_LTC4162L) += ltc4162-l-charger.o
  obj-$(CONFIG_CHARGER_MAX14577)+= max14577_charger.o
  obj-$(CONFIG_CHARGER_DETECTOR_MAX14656)   += max14656_charger_detector.o
  obj-$(CONFIG_CHARGER_MAX77650)+= max77650-charger.o
diff --git a/drivers/power/supply/ltc4162-l-charger.c 
b/drivers/power/supply/ltc4162-l-charger.c
new file mode 100644
index ..b2f666113125
--- /dev/null
+++ b/drivers/power/supply/ltc4162-l-charger.c
@@ -0,0 +1,898 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Driver for Analog Devices (Linear Technology) LTC4162-L charger IC.
+ *  Copyright (C) 2020, Topic Embedded Products
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* Registers (names based on what datasheet uses) */
+#define LTC4162L_EN_LIMIT_ALERTS_REG   0x0D
+#define LTC4162L_EN_CHARGER_STATE_ALERTS_REG   0x0E
+#define LTC4162L_EN_CHARGE_STATUS_ALERTS_REG   0x0F
+#define LTC4162L_CONFIG_BITS_REG   0x14
+#define LTC4162L_IIN_LIMIT_TARGET  0x15
+#define LTC4162L_ARM_SHIP_MODE 0x19
+#define LTC4162L_CHARGE_CURRENT_SETTING0X1A
+#define LTC4162L_VCHARGE_SETTING   0X1B
+#define LTC4162L_C_OVER_X_THRESHOLD0x1C
+#define LTC4162L_MAX_CV_TIME   0X1D
+#define LTC4162L_MAX_CHARGE_TIME   0X1E
+#define LTC4162L_CHARGER_CONFIG_BITS   0x29
+#define LTC4162L_CHARGER_STATE 0x34
+#define LTC4162L_CHARGE_STATUS 0x35
+#define LTC4162L_LIMIT_ALERTS_REG  0x36
+#define LTC4162L_CHARGER_STATE_ALERTS_REG  0x37
+#define LTC4162L_CHARGE_STATUS_ALERTS_REG  0x38
+#define LTC4162L_SYSTEM_STATUS_REG 0x39
+#define LTC4162L_VBAT  0x3A
+#define LTC4162L_VIN   0x3B
+#define LTC4162L_VOUT  0x3C
+#define LTC4162L_IBAT  0x3D
+#define LTC4162L_IIN   0x3E
+#define LTC4162L_DIE_TEMPERATURE   0x3F
+#define LTC4162L_THERMISTOR_VOLTAGE0x40
+#define LTC4162L_BSR   0x41
+#define LTC4162L_JEITA_REGION  0x42
+#define LTC4162L_CHEM_CELLS_REG0x43
+#define LTC4162L_ICHARGE_DAC   0x44
+#define LTC4162L_VCHARGE_DAC   0x45
+#define LT

Re: [PATCH v3] power/supply: Add ltc4162-l-charger

2020-12-03 Thread Mike Looijmans

Gentle ping, haven't seen any response...


Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 02-11-2020 10:21, Mike Looijmans wrote:

Add support for the LTC4162-L Li-Ion battery charger. The driver allows
reading back telemetry and to set some charging options like the input
current limit.

Signed-off-by: Mike Looijmans 
---
v2: Use microohm units instead of milliohm
 Add interrupt support using smbalert
 Support obtaining cell-count from devicetree
v3: Fix overflows in calculations involving resistor values
resent, mail bounced

  drivers/power/supply/Kconfig |   8 +
  drivers/power/supply/Makefile|   1 +
  drivers/power/supply/ltc4162-l-charger.c | 898 +++
  3 files changed, 907 insertions(+)
  create mode 100644 drivers/power/supply/ltc4162-l-charger.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index eec646c568b7..23000976cb42 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -513,6 +513,14 @@ config CHARGER_LT3651
  Say Y to include support for the Analog Devices (Linear Technology)
  LT3651 battery charger which reports its status via GPIO lines.
  
+config CHARGER_LTC4162L

+   tristate "LTC4162-L charger"
+   depends on I2C
+   select REGMAP_I2C
+   help
+ Say Y to include support for the Analog Devices (Linear Technology)
+ LTC4162-L battery charger connected to I2C.
+
  config CHARGER_MAX14577
tristate "Maxim MAX14577/77836 battery charger driver"
depends on MFD_MAX14577
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index dd4b86318cd9..17b1cf921c44 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_CHARGER_LP8788)  += lp8788-charger.o
  obj-$(CONFIG_CHARGER_GPIO)+= gpio-charger.o
  obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
  obj-$(CONFIG_CHARGER_LT3651)  += lt3651-charger.o
+obj-$(CONFIG_CHARGER_LTC4162L) += ltc4162-l-charger.o
  obj-$(CONFIG_CHARGER_MAX14577)+= max14577_charger.o
  obj-$(CONFIG_CHARGER_DETECTOR_MAX14656)   += max14656_charger_detector.o
  obj-$(CONFIG_CHARGER_MAX77650)+= max77650-charger.o
diff --git a/drivers/power/supply/ltc4162-l-charger.c 
b/drivers/power/supply/ltc4162-l-charger.c
new file mode 100644
index ..b2f666113125
--- /dev/null
+++ b/drivers/power/supply/ltc4162-l-charger.c
@@ -0,0 +1,898 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Driver for Analog Devices (Linear Technology) LTC4162-L charger IC.
+ *  Copyright (C) 2020, Topic Embedded Products
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* Registers (names based on what datasheet uses) */
+#define LTC4162L_EN_LIMIT_ALERTS_REG   0x0D
+#define LTC4162L_EN_CHARGER_STATE_ALERTS_REG   0x0E
+#define LTC4162L_EN_CHARGE_STATUS_ALERTS_REG   0x0F
+#define LTC4162L_CONFIG_BITS_REG   0x14
+#define LTC4162L_IIN_LIMIT_TARGET  0x15
+#define LTC4162L_ARM_SHIP_MODE 0x19
+#define LTC4162L_CHARGE_CURRENT_SETTING0X1A
+#define LTC4162L_VCHARGE_SETTING   0X1B
+#define LTC4162L_C_OVER_X_THRESHOLD0x1C
+#define LTC4162L_MAX_CV_TIME   0X1D
+#define LTC4162L_MAX_CHARGE_TIME   0X1E
+#define LTC4162L_CHARGER_CONFIG_BITS   0x29
+#define LTC4162L_CHARGER_STATE 0x34
+#define LTC4162L_CHARGE_STATUS 0x35
+#define LTC4162L_LIMIT_ALERTS_REG  0x36
+#define LTC4162L_CHARGER_STATE_ALERTS_REG  0x37
+#define LTC4162L_CHARGE_STATUS_ALERTS_REG  0x38
+#define LTC4162L_SYSTEM_STATUS_REG 0x39
+#define LTC4162L_VBAT  0x3A
+#define LTC4162L_VIN   0x3B
+#define LTC4162L_VOUT  0x3C
+#define LTC4162L_IBAT  0x3D
+#define LTC4162L_IIN   0x3E
+#define LTC4162L_DIE_TEMPERATURE   0x3F
+#define LTC4162L_THERMISTOR_VOLTAGE0x40
+#define LTC4162L_BSR   0x41
+#define LTC4162L_JEITA_REGION  0x42
+#define LTC4162L_CHEM_CELLS_REG0x43
+#define LTC4162L_ICHARGE_DAC   0x44
+#define LTC4162L_VCHARGE_DAC   0x45
+#define LTC4162L_IIN_LIMIT_DAC 0x46
+#define LTC4162L_VBAT_FILT 0x47
+#define LTC4162L_INPUT_UNDERVOLTAGE_DAC0x4B
+
+/* Enumeration as in datasheet. Individual bits are mutually exclusive. */
+enum ltc4162l_state {
+   battery_detection = 2048,
+   charger_suspended = 25

Re: [PATCH v3] dt-bindings: gpio: pca953x: Add support for the NXP PCAL9554B/C

2020-11-05 Thread Mike Looijmans



Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 05-11-2020 11:25, Linus Walleij wrote:

Hi Mike!

thanks for your patch.

On Fri, Oct 9, 2020 at 8:03 AM Mike Looijmans  wrote:


- nxp,pcal9535
+  - nxp,pcal9554b
- nxp,pcal9555a


This triggers my OCD. Putting B before A? Please make it alphabetic.


Nothing wrong with a bit of OCD, it's probably in our job description :)

But there's a "4" before the "5" too.



No big deal, but...

Yours,
Linus Walleij





Re: [PATCH] clk-si5341: Support NVM programming through sysfs

2020-11-05 Thread Mike Looijmans



Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 05-11-2020 02:48, Stephen Boyd wrote:

Quoting Mike Looijmans (2020-11-03 06:17:41)

Export an attribute program_nvm_bank that when read reports the current
bank value. To program the chip's current state into NVM, write the
magic value 0xC7 into this attribute.

Signed-off-by: Mike Looijmans 
---


Any chance this can be done through the nvmem framework?


This part doesn't fit. The purpose is to store the current state of the clock 
chip into its non-volatile storage so it boots up with that configuration the 
next POR. Main use case is that some vendors initialize PLLs only in a 
bootloader and thus need the clock running at boot. Or it might just be to 
save on that 300ms initialization time.


Having said that, the clock chip does have some "scratch" areas that'd be 
useful as NVMEM storage. That'd be for a separate patch.


For this device to be NVMEM compatible, nvmem would need to have a sort of 
transaction model, where you write several values and then "commit" them all 
to NVM in one call. The nvmem framework wasn't intended for that I think.





  drivers/clk/clk-si5341.c | 73 
  1 file changed, 73 insertions(+)

diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index e0446e66fa64..4e025a5ea2b7 100644
--- a/drivers/clk/clk-si5341.c
+++ b/drivers/clk/clk-si5341.c
@@ -1199,6 +1205,69 @@ static const struct regmap_config si5341_regmap_config = 
{
 .volatile_table = _regmap_volatile,
  };
  
+static ssize_t program_nvm_bank_show(struct device *dev,

+   struct device_attribute *attr, char *buf)
+{
+   struct i2c_client *client = to_i2c_client(dev);
+   struct clk_si5341 *data = i2c_get_clientdata(client);
+   unsigned int regval;
+   int ret;
+
+   ret = regmap_read(data->regmap, SI5341_ACTIVE_NVM_BANK, );
+   if (ret)
+   return ret;
+
+   return sprintf(buf, "%#x\n", regval);
+}
+
+static ssize_t program_nvm_bank_store(struct device *dev,
+   struct device_attribute *attr,
+   const char *buf,
+   size_t count)
+{
+   struct clk_si5341 *data = i2c_get_clientdata(to_i2c_client(dev));
+   int ret;
+   unsigned int value;
+   unsigned int timeout;
+
+   ret = kstrtouint(buf, 0, );
+   if (ret < 0)
+   return ret;
+
+   /* Write the magic value to this attribute to program the NVM */
+   if (value != SI5341_SI5341_NVM_WRITE_COOKIE)
+   return -EINVAL;
+
+   ret = regmap_write(data->regmap, SI5341_NVM_WRITE,
+   SI5341_SI5341_NVM_WRITE_COOKIE);
+   if (ret)
+   return ret;
+
+   /* Wait for SI5341_DEVICE_READY register to become 0x0f */
+   for (timeout = 1; timeout; --timeout) {
+   ret = regmap_read(data->regmap, SI5341_DEVICE_READY, );


This is regmap_read_poll_timeout()?


Yes, indeed.




+   if (ret)
+   return ret;
+
+   if (value == 0x0f)
+   break;
+   }
+
+   return count;
+}
+
+static DEVICE_ATTR_RW(program_nvm_bank);
+
+static struct attribute *si5341_sysfs_entries[] = {
+   _attr_program_nvm_bank.attr,
+   NULL,
+};
+
+static struct attribute_group si5341_attr_group = {
+   .name   = NULL, /* put in device directory */
+   .attrs  = si5341_sysfs_entries,
+};


If not nvmem framework, then this needs to be documented in
Documentation/ABI/


Okay, will do.





+
  static int si5341_dt_parse_dt(struct i2c_client *client,
 struct clk_si5341_output_config *config)
  {
@@ -1544,6 +1613,10 @@ static int si5341_probe(struct i2c_client *client,
 for (i = 0; i < data->num_synth; ++i)
  devm_kfree(>dev, (void *)synth_clock_names[i]);
  
+   err = sysfs_create_group(>dev.kobj, _attr_group);

+   if (err)
+   dev_err(>dev, "failed to create sysfs entries\n");
+


Cool, I as a user would do what in this situation? The error message
seems sort of worthless.



It's not critical for the driver to be able to register this. So I could just 
silently ignore the error.


M.


[PATCH] clk-si5341: Support NVM programming through sysfs

2020-11-03 Thread Mike Looijmans
Export an attribute program_nvm_bank that when read reports the current
bank value. To program the chip's current state into NVM, write the
magic value 0xC7 into this attribute.

Signed-off-by: Mike Looijmans 
---
 drivers/clk/clk-si5341.c | 73 
 1 file changed, 73 insertions(+)

diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index e0446e66fa64..4e025a5ea2b7 100644
--- a/drivers/clk/clk-si5341.c
+++ b/drivers/clk/clk-si5341.c
@@ -92,6 +92,9 @@ struct clk_si5341_output_config {
 #define SI5341_PN_BASE 0x0002
 #define SI5341_DEVICE_REV  0x0005
 #define SI5341_STATUS  0x000C
+#define SI5341_ACTIVE_NVM_BANK 0x00E2
+#define SI5341_NVM_WRITE   0x00E3
+#define SI5341_DEVICE_READY0x00FE
 #define SI5341_SOFT_RST0x001C
 #define SI5341_IN_SEL  0x0021
 #define SI5341_XAXB_CFG0x090E
@@ -144,6 +147,9 @@ struct clk_si5341_output_config {
 #define SI5341_OUT_CFG_OE  BIT(1)
 #define SI5341_OUT_CFG_RDIV_FORCE2 BIT(2)
 
+/* Programming NVM, magic value to write to program the NVM */
+#define SI5341_SI5341_NVM_WRITE_COOKIE 0xC7
+
 /* Static configuration (to be moved to firmware) */
 struct si5341_reg_default {
u16 address;
@@ -1199,6 +1205,69 @@ static const struct regmap_config si5341_regmap_config = 
{
.volatile_table = _regmap_volatile,
 };
 
+static ssize_t program_nvm_bank_show(struct device *dev,
+   struct device_attribute *attr, char *buf)
+{
+   struct i2c_client *client = to_i2c_client(dev);
+   struct clk_si5341 *data = i2c_get_clientdata(client);
+   unsigned int regval;
+   int ret;
+
+   ret = regmap_read(data->regmap, SI5341_ACTIVE_NVM_BANK, );
+   if (ret)
+   return ret;
+
+   return sprintf(buf, "%#x\n", regval);
+}
+
+static ssize_t program_nvm_bank_store(struct device *dev,
+   struct device_attribute *attr,
+   const char *buf,
+   size_t count)
+{
+   struct clk_si5341 *data = i2c_get_clientdata(to_i2c_client(dev));
+   int ret;
+   unsigned int value;
+   unsigned int timeout;
+
+   ret = kstrtouint(buf, 0, );
+   if (ret < 0)
+   return ret;
+
+   /* Write the magic value to this attribute to program the NVM */
+   if (value != SI5341_SI5341_NVM_WRITE_COOKIE)
+   return -EINVAL;
+
+   ret = regmap_write(data->regmap, SI5341_NVM_WRITE,
+   SI5341_SI5341_NVM_WRITE_COOKIE);
+   if (ret)
+   return ret;
+
+   /* Wait for SI5341_DEVICE_READY register to become 0x0f */
+   for (timeout = 1; timeout; --timeout) {
+   ret = regmap_read(data->regmap, SI5341_DEVICE_READY, );
+   if (ret)
+   return ret;
+
+   if (value == 0x0f)
+   break;
+   }
+
+   return count;
+}
+
+static DEVICE_ATTR_RW(program_nvm_bank);
+
+static struct attribute *si5341_sysfs_entries[] = {
+   _attr_program_nvm_bank.attr,
+   NULL,
+};
+
+static struct attribute_group si5341_attr_group = {
+   .name   = NULL, /* put in device directory */
+   .attrs  = si5341_sysfs_entries,
+};
+
 static int si5341_dt_parse_dt(struct i2c_client *client,
struct clk_si5341_output_config *config)
 {
@@ -1544,6 +1613,10 @@ static int si5341_probe(struct i2c_client *client,
for (i = 0; i < data->num_synth; ++i)
 devm_kfree(>dev, (void *)synth_clock_names[i]);
 
+   err = sysfs_create_group(>dev.kobj, _attr_group);
+   if (err)
+   dev_err(>dev, "failed to create sysfs entries\n");
+
return 0;
 }
 
-- 
2.17.1



[PATCH v4] dt-bindings: power/supply: Add ltc4162-l-charger

2020-11-03 Thread Mike Looijmans
Add support for the LTC4162-L Li-Ion battery charger. The driver allows
reading back telemetry and to set some charging options like the input
current limit.

This adds the devicetree bindings.

Signed-off-by: Mike Looijmans 
---
v2: Use microohms, add lltc,cell-count
v3: Fix example dts to match description
v4: Update "required" list to include micro-ohms

 .../bindings/power/supply/ltc4162-l.yaml  | 69 +++
 1 file changed, 69 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml

diff --git a/Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml 
b/Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml
new file mode 100644
index ..1f88c9e013f4
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml
@@ -0,0 +1,69 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (C) 2020 Topic Embedded Products
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/power/supply/ltc4162-l.yaml#;
+$schema: "http://devicetree.org/meta-schemas/core.yaml#;
+
+title: Linear Technology (Analog Devices) LTC4162-L Charger
+
+maintainers:
+  - Mike Looijmans 
+
+description: |
+  The LTC ® 4162-L is an advanced monolithic synchronous step-down switching
+  battery charger and PowerPath (TM) manager that seamlessly manages power
+  distribution between input sources such as wall adapters, backplanes, solar
+  panels, etc., and a rechargeable Lithium-Ion/Polymer battery.
+
+  Specifications about the charger can be found at:
+https://www.analog.com/en/products/ltc4162-s.html
+
+properties:
+  compatible:
+enum:
+  - lltc,ltc4162-l
+
+  reg:
+maxItems: 1
+description: I2C address of the charger.
+
+  lltc,rsnsb-micro-ohms:
+$ref: /schemas/types.yaml#/definitions/uint32
+description: Battery sense resistor in microohm.
+minimum: 1000
+
+  lltc,rsnsi-micro-ohms:
+$ref: /schemas/types.yaml#/definitions/uint32
+description: Input current sense resistor in microohm.
+minimum: 1000
+
+  lltc,cell-count:
+$ref: /schemas/types.yaml#/definitions/uint32
+description: |
+  Number of battery cells. If not provided, will be obtained from the chip
+  once the external power is applied. Omit this when the number of cells
+  is somewhat dynamic. Without it, several measurements will return 0 until
+  the charger is connected to an external supply.
+
+required:
+  - compatible
+  - reg
+  - lltc,rsnsb-micro-ohms
+  - lltc,rsnsi-micro-ohms
+
+additionalProperties: false
+
+examples:
+  - |
+i2c0 {
+  #address-cells = <1>;
+  #size-cells = <0>;
+  charger: battery-charger@68 {
+  compatible = "lltc,ltc4162-l";
+  reg = <0x68>;
+  lltc,rsnsb-micro-ohms = <1>;
+  lltc,rsnsi-micro-ohms = <16000>;
+  lltc,cell-count = <2>;
+  };
+};
-- 
2.17.1



[PATCH v3] power/supply: Add ltc4162-l-charger

2020-11-02 Thread Mike Looijmans
Add support for the LTC4162-L Li-Ion battery charger. The driver allows
reading back telemetry and to set some charging options like the input
current limit.

Signed-off-by: Mike Looijmans 
---
v2: Use microohm units instead of milliohm
Add interrupt support using smbalert
Support obtaining cell-count from devicetree
v3: Fix overflows in calculations involving resistor values
resent, mail bounced

 drivers/power/supply/Kconfig |   8 +
 drivers/power/supply/Makefile|   1 +
 drivers/power/supply/ltc4162-l-charger.c | 898 +++
 3 files changed, 907 insertions(+)
 create mode 100644 drivers/power/supply/ltc4162-l-charger.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index eec646c568b7..23000976cb42 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -513,6 +513,14 @@ config CHARGER_LT3651
  Say Y to include support for the Analog Devices (Linear Technology)
  LT3651 battery charger which reports its status via GPIO lines.
 
+config CHARGER_LTC4162L
+   tristate "LTC4162-L charger"
+   depends on I2C
+   select REGMAP_I2C
+   help
+ Say Y to include support for the Analog Devices (Linear Technology)
+ LTC4162-L battery charger connected to I2C.
+
 config CHARGER_MAX14577
tristate "Maxim MAX14577/77836 battery charger driver"
depends on MFD_MAX14577
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index dd4b86318cd9..17b1cf921c44 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_CHARGER_LP8788)  += lp8788-charger.o
 obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
 obj-$(CONFIG_CHARGER_MANAGER)  += charger-manager.o
 obj-$(CONFIG_CHARGER_LT3651)   += lt3651-charger.o
+obj-$(CONFIG_CHARGER_LTC4162L) += ltc4162-l-charger.o
 obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
 obj-$(CONFIG_CHARGER_DETECTOR_MAX14656)+= max14656_charger_detector.o
 obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o
diff --git a/drivers/power/supply/ltc4162-l-charger.c 
b/drivers/power/supply/ltc4162-l-charger.c
new file mode 100644
index ..b2f666113125
--- /dev/null
+++ b/drivers/power/supply/ltc4162-l-charger.c
@@ -0,0 +1,898 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Driver for Analog Devices (Linear Technology) LTC4162-L charger IC.
+ *  Copyright (C) 2020, Topic Embedded Products
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* Registers (names based on what datasheet uses) */
+#define LTC4162L_EN_LIMIT_ALERTS_REG   0x0D
+#define LTC4162L_EN_CHARGER_STATE_ALERTS_REG   0x0E
+#define LTC4162L_EN_CHARGE_STATUS_ALERTS_REG   0x0F
+#define LTC4162L_CONFIG_BITS_REG   0x14
+#define LTC4162L_IIN_LIMIT_TARGET  0x15
+#define LTC4162L_ARM_SHIP_MODE 0x19
+#define LTC4162L_CHARGE_CURRENT_SETTING0X1A
+#define LTC4162L_VCHARGE_SETTING   0X1B
+#define LTC4162L_C_OVER_X_THRESHOLD0x1C
+#define LTC4162L_MAX_CV_TIME   0X1D
+#define LTC4162L_MAX_CHARGE_TIME   0X1E
+#define LTC4162L_CHARGER_CONFIG_BITS   0x29
+#define LTC4162L_CHARGER_STATE 0x34
+#define LTC4162L_CHARGE_STATUS 0x35
+#define LTC4162L_LIMIT_ALERTS_REG  0x36
+#define LTC4162L_CHARGER_STATE_ALERTS_REG  0x37
+#define LTC4162L_CHARGE_STATUS_ALERTS_REG  0x38
+#define LTC4162L_SYSTEM_STATUS_REG 0x39
+#define LTC4162L_VBAT  0x3A
+#define LTC4162L_VIN   0x3B
+#define LTC4162L_VOUT  0x3C
+#define LTC4162L_IBAT  0x3D
+#define LTC4162L_IIN   0x3E
+#define LTC4162L_DIE_TEMPERATURE   0x3F
+#define LTC4162L_THERMISTOR_VOLTAGE0x40
+#define LTC4162L_BSR   0x41
+#define LTC4162L_JEITA_REGION  0x42
+#define LTC4162L_CHEM_CELLS_REG0x43
+#define LTC4162L_ICHARGE_DAC   0x44
+#define LTC4162L_VCHARGE_DAC   0x45
+#define LTC4162L_IIN_LIMIT_DAC 0x46
+#define LTC4162L_VBAT_FILT 0x47
+#define LTC4162L_INPUT_UNDERVOLTAGE_DAC0x4B
+
+/* Enumeration as in datasheet. Individual bits are mutually exclusive. */
+enum ltc4162l_state {
+   battery_detection = 2048,
+   charger_suspended = 256,
+   precharge = 128,   /* trickle on low bat voltage */
+   cc_cv_charge = 64, /* normal charge */
+   ntc_pause = 32,
+   timer_term = 16,
+   c_over_x_term = 8, /* battery is full */
+   max_charge_time_fault = 4,
+   bat_missing_fault = 2,
+   bat_short_fault = 1
+};
+
+/* Individual bits are mutually exclusive. Only active in charging states.*/
+enum lt

[PATCH v3] dt-bindings: power/supply: Add ltc4162-l-charger

2020-11-02 Thread Mike Looijmans
Add support for the LTC4162-L Li-Ion battery charger. The driver allows
reading back telemetry and to set some charging options like the input
current limit.

This adds the devicetree bindings.

Signed-off-by: Mike Looijmans 
---
v2: Use microohms, add lltc,cell-count
v3: Fix example dts to match description
resent, previous patch mail bounced

 .../bindings/power/supply/ltc4162-l.yaml  | 69 +++
 1 file changed, 69 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml

diff --git a/Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml 
b/Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml
new file mode 100644
index ..c564019783ad
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml
@@ -0,0 +1,69 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (C) 2020 Topic Embedded Products
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/power/supply/ltc4162-l.yaml#;
+$schema: "http://devicetree.org/meta-schemas/core.yaml#;
+
+title: Linear Technology (Analog Devices) LTC4162-L Charger
+
+maintainers:
+  - Mike Looijmans 
+
+description: |
+  The LTC ® 4162-L is an advanced monolithic synchronous step-down switching
+  battery charger and PowerPath (TM) manager that seamlessly manages power
+  distribution between input sources such as wall adapters, backplanes, solar
+  panels, etc., and a rechargeable Lithium-Ion/Polymer battery.
+
+  Specifications about the charger can be found at:
+https://www.analog.com/en/products/ltc4162-s.html
+
+properties:
+  compatible:
+enum:
+  - lltc,ltc4162-l
+
+  reg:
+maxItems: 1
+description: I2C address of the charger.
+
+  lltc,rsnsb-micro-ohms:
+$ref: /schemas/types.yaml#/definitions/uint32
+description: Battery sense resistor in microohm.
+minimum: 1000
+
+  lltc,rsnsi-micro-ohms:
+$ref: /schemas/types.yaml#/definitions/uint32
+description: Input current sense resistor in microohm.
+minimum: 1000
+
+  lltc,cell-count:
+$ref: /schemas/types.yaml#/definitions/uint32
+description: |
+  Number of battery cells. If not provided, will be obtained from the chip
+  once the external power is applied. Omit this when the number of cells
+  is somewhat dynamic. Without it, several measurements will return 0 until
+  the charger is connected to an external supply.
+
+required:
+  - compatible
+  - reg
+  - lltc,rsnsb
+  - lltc,rsnsi
+
+additionalProperties: false
+
+examples:
+  - |
+i2c0 {
+  #address-cells = <1>;
+  #size-cells = <0>;
+  charger: battery-charger@68 {
+  compatible = "lltc,ltc4162-l";
+  reg = <0x68>;
+  lltc,rsnsb-micro-ohms = <1>;
+  lltc,rsnsi-micro-ohms = <16000>;
+  lltc,cell-count = <2>;
+  };
+};
-- 
2.17.1



[PATCH v2] power/supply: Add ltc4162-l-charger

2020-10-27 Thread Mike Looijmans
Add support for the LTC4162-L Li-Ion battery charger. The driver allows
reading back telemetry and to set some charging options like the input
current limit.

Signed-off-by: Mike Looijmans 
---
v2: Use microohm units instead of milliohm
Add interrupt support using smbalert
Support obtaining cell-count from devicetree

 drivers/power/supply/Kconfig |   8 +
 drivers/power/supply/Makefile|   1 +
 drivers/power/supply/ltc4162-l-charger.c | 887 +++
 3 files changed, 896 insertions(+)
 create mode 100644 drivers/power/supply/ltc4162-l-charger.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index eec646c568b7..23000976cb42 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -513,6 +513,14 @@ config CHARGER_LT3651
  Say Y to include support for the Analog Devices (Linear Technology)
  LT3651 battery charger which reports its status via GPIO lines.
 
+config CHARGER_LTC4162L
+   tristate "LTC4162-L charger"
+   depends on I2C
+   select REGMAP_I2C
+   help
+ Say Y to include support for the Analog Devices (Linear Technology)
+ LTC4162-L battery charger connected to I2C.
+
 config CHARGER_MAX14577
tristate "Maxim MAX14577/77836 battery charger driver"
depends on MFD_MAX14577
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index dd4b86318cd9..17b1cf921c44 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_CHARGER_LP8788)  += lp8788-charger.o
 obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
 obj-$(CONFIG_CHARGER_MANAGER)  += charger-manager.o
 obj-$(CONFIG_CHARGER_LT3651)   += lt3651-charger.o
+obj-$(CONFIG_CHARGER_LTC4162L) += ltc4162-l-charger.o
 obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
 obj-$(CONFIG_CHARGER_DETECTOR_MAX14656)+= max14656_charger_detector.o
 obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o
diff --git a/drivers/power/supply/ltc4162-l-charger.c 
b/drivers/power/supply/ltc4162-l-charger.c
new file mode 100644
index ..bea9e5130b07
--- /dev/null
+++ b/drivers/power/supply/ltc4162-l-charger.c
@@ -0,0 +1,887 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Driver for Analog Devices (Linear Technology) LTC4162-L charger IC.
+ *  Copyright (C) 2020, Topic Embedded Products
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* Registers (names based on what datasheet uses) */
+#define LTC4162L_EN_LIMIT_ALERTS_REG   0x0D
+#define LTC4162L_EN_CHARGER_STATE_ALERTS_REG   0x0E
+#define LTC4162L_EN_CHARGE_STATUS_ALERTS_REG   0x0F
+#define LTC4162L_CONFIG_BITS_REG   0x14
+#define LTC4162L_IIN_LIMIT_TARGET  0x15
+#define LTC4162L_ARM_SHIP_MODE 0x19
+#define LTC4162L_CHARGE_CURRENT_SETTING0X1A
+#define LTC4162L_VCHARGE_SETTING   0X1B
+#define LTC4162L_C_OVER_X_THRESHOLD0x1C
+#define LTC4162L_MAX_CV_TIME   0X1D
+#define LTC4162L_MAX_CHARGE_TIME   0X1E
+#define LTC4162L_CHARGER_CONFIG_BITS   0x29
+#define LTC4162L_CHARGER_STATE 0x34
+#define LTC4162L_CHARGE_STATUS 0x35
+#define LTC4162L_LIMIT_ALERTS_REG  0x36
+#define LTC4162L_CHARGER_STATE_ALERTS_REG  0x37
+#define LTC4162L_CHARGE_STATUS_ALERTS_REG  0x38
+#define LTC4162L_SYSTEM_STATUS_REG 0x39
+#define LTC4162L_VBAT  0x3A
+#define LTC4162L_VIN   0x3B
+#define LTC4162L_VOUT  0x3C
+#define LTC4162L_IBAT  0x3D
+#define LTC4162L_IIN   0x3E
+#define LTC4162L_DIE_TEMPERATURE   0x3F
+#define LTC4162L_THERMISTOR_VOLTAGE0x40
+#define LTC4162L_BSR   0x41
+#define LTC4162L_JEITA_REGION  0x42
+#define LTC4162L_CHEM_CELLS_REG0x43
+#define LTC4162L_ICHARGE_DAC   0x44
+#define LTC4162L_VCHARGE_DAC   0x45
+#define LTC4162L_IIN_LIMIT_DAC 0x46
+#define LTC4162L_VBAT_FILT 0x47
+#define LTC4162L_INPUT_UNDERVOLTAGE_DAC0x4B
+
+/* Enumeration as in datasheet. Individual bits are mutually exclusive. */
+enum ltc4162l_state {
+   battery_detection = 2048,
+   charger_suspended = 256,
+   precharge = 128,   /* trickle on low bat voltage */
+   cc_cv_charge = 64, /* normal charge */
+   ntc_pause = 32,
+   timer_term = 16,
+   c_over_x_term = 8, /* battery is full */
+   max_charge_time_fault = 4,
+   bat_missing_fault = 2,
+   bat_short_fault = 1
+};
+
+/* Individual bits are mutually exclusive. Only active in charging states.*/
+enum ltc4162l_charge_status {
+   ilim_reg_active = 32,
+   thermal_reg_active = 16,
+  

[PATCH v2] dt-bindings: power/supply: Add ltc4162-l-charger

2020-10-27 Thread Mike Looijmans
Add support for the LTC4162-L Li-Ion battery charger. The driver allows
reading back telemetry and to set some charging options like the input
current limit.

This adds the devicetree bindings.

Signed-off-by: Mike Looijmans 
---
v2: Use microohms, add lltc,cell-count

 .../bindings/power/supply/ltc4162-l.yaml  | 68 +++
 1 file changed, 68 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml

diff --git a/Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml 
b/Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml
new file mode 100644
index ..42622ac54e28
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (C) 2020 Topic Embedded Products
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/power/supply/ltc4162-l.yaml#;
+$schema: "http://devicetree.org/meta-schemas/core.yaml#;
+
+title: Linear Technology (Analog Devices) LTC4162-L Charger
+
+maintainers:
+  - Mike Looijmans 
+
+description: |
+  The LTC ® 4162-L is an advanced monolithic synchronous step-down switching
+  battery charger and PowerPath (TM) manager that seamlessly manages power
+  distribution between input sources such as wall adapters, backplanes, solar
+  panels, etc., and a rechargeable Lithium-Ion/Polymer battery.
+
+  Specifications about the charger can be found at:
+https://www.analog.com/en/products/ltc4162-s.html
+
+properties:
+  compatible:
+enum:
+  - lltc,ltc4162-l
+
+  reg:
+maxItems: 1
+description: I2C address of the charger.
+
+  lltc,rsnsb-micro-ohms:
+$ref: /schemas/types.yaml#/definitions/uint32
+description: Battery sense resistor in microohm.
+minimum: 1000
+
+  lltc,rsnsi-micro-ohms:
+$ref: /schemas/types.yaml#/definitions/uint32
+description: Input current sense resistor in microohm.
+minimum: 1000
+
+  lltc,cell-count:
+$ref: /schemas/types.yaml#/definitions/uint32
+description: |
+  Number of battery cells. If not provided, will be obtained from the chip
+  once the external power is applied. Omit this when the number of cells
+  is somewhat dynamic. Without it, several measurements will return 0 until
+  the charger is connected to an external supply.
+
+required:
+  - compatible
+  - reg
+  - lltc,rsnsb
+  - lltc,rsnsi
+
+additionalProperties: false
+
+examples:
+  - |
+i2c0 {
+  #address-cells = <1>;
+  #size-cells = <0>;
+  charger: battery-charger@68 {
+  compatible = "lltc,ltc4162-l";
+  reg =  <0x68>;
+  lltc,rsnsb = <10>;
+  lltc,rsnsi = <16>;
+  };
+};
-- 
2.17.1



[PATCH v4] dt-bindings: gpio: pca953x: Add support for the NXP PCAL9554B/C

2020-10-26 Thread Mike Looijmans
The NXP PCAL9554B is a variant of the PCA953x GPIO expander,
with 8 GPIOs, latched interrupts and some advanced configuration
options. The "C" version only differs in I2C address.

This adds the entry to the devicetree bindings.

Signed-off-by: Mike Looijmans 
Acked-by: Rob Herring 
Reviewed-by: Linus Walleij 
Reviewed-by: Bartosz Golaszewski 
---
v2: Split devicetree and code into separate patches
v3: Devicetree bindings in yaml format
v4: Rebase on v5.10-rc1

 Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml 
b/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml
index 183ec23eda39..f5ee23c2df60 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml
+++ b/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml
@@ -48,6 +48,7 @@ properties:
   - nxp,pcal6416
   - nxp,pcal6524
   - nxp,pcal9535
+  - nxp,pcal9554b
   - nxp,pcal9555a
   - onnn,cat9554
   - onnn,pca9654
-- 
2.17.1



Re: [PATCH] dt-bindings: power/supply: Add ltc4162-l-charger

2020-10-26 Thread Mike Looijmans



Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 26-10-2020 15:43, Rob Herring wrote:

On Wed, Oct 21, 2020 at 04:10:30PM +0200, Mike Looijmans wrote:

Add support for the LTC4162-L Li-Ion battery charger. The driver allows
reading back telemetry and to set some charging options like the input
current limit.

This adds the devicetree bindings.

Signed-off-by: Mike Looijmans 
---
  .../bindings/power/supply/ltc4162-l.yaml  | 60 +++
  1 file changed, 60 insertions(+)
  create mode 100644 
Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml

diff --git a/Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml 
b/Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml
new file mode 100644
index ..a23dd6f3fae0
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (C) 2020 Topic Embedded Products
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/power/supply/ltc4162-l.yaml#;
+$schema: "http://devicetree.org/meta-schemas/core.yaml#;
+
+title: Linear Technology (Analog Devices) LTC4162-L Charger
+
+maintainers:
+  - Mike Looijmans 
+
+description: |
+  The LTC ® 4162-L is an advanced monolithic synchronous step-down switching
+  battery charger and PowerPath (TM) manager that seamlessly manages power
+  distribution between input sources such as wall adapters, backplanes, solar
+  panels, etc., and a rechargeable Lithium-Ion/Polymer battery.
+
+  Specifications about the charger can be found at:
+https://www.analog.com/en/products/ltc4162-s.html
+
+properties:
+  compatible:
+enum:
+  - lltc,ltc4162-l
+
+  reg:
+maxItems: 1
+description: I2C address of the charger.
+
+  lltc,rsnsb:
+$ref: /schemas/types.yaml#/definitions/uint32
+description: Battery sense resistor in milli Ohm.
+minimum: 1
+
+  lltc,rsnsi:
+$ref: /schemas/types.yaml#/definitions/uint32
+description: Input current sense resistor in milli Ohm.
+minimum: 1

These should have a unit suffix as defined in property-units.txt.
There's not one for milli Ohms, does micro Ohms give you enough range?
If not, you can add it though that's discouraged simply so that we don't
have differring units in each binding for the same thing.


Micro Ohms is fine, might even be beneficial. Expected values are in the 
10 milliohm range. Sorry to have missed that. I'll adapt the driver to 
use this value without overflowing.




--
Mike Looijmans



[PATCH] power/supply: Add ltc4162-l-charger

2020-10-22 Thread Mike Looijmans
Add support for the LTC4162-L Li-Ion battery charger. The driver allows
reading back telemetry and to set some charging options like the input
current limit.

Signed-off-by: Mike Looijmans 
---
 drivers/power/supply/Kconfig |   8 +
 drivers/power/supply/Makefile|   1 +
 drivers/power/supply/ltc4162-l-charger.c | 847 +++
 3 files changed, 856 insertions(+)
 create mode 100644 drivers/power/supply/ltc4162-l-charger.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index faf2830aa152..ce5c35d08bb5 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -508,6 +508,14 @@ config CHARGER_LT3651
  Say Y to include support for the Analog Devices (Linear Technology)
  LT3651 battery charger which reports its status via GPIO lines.
 
+config CHARGER_LTC4162L
+   tristate "LTC4162-L charger"
+   depends on I2C
+   select REGMAP_I2C
+   help
+ Say Y to include support for the Analog Devices (Linear Technology)
+ LTC4162-L battery charger connected to I2C.
+
 config CHARGER_MAX14577
tristate "Maxim MAX14577/77836 battery charger driver"
depends on MFD_MAX14577
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index b3c694a65114..fe6881d6ef0f 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_CHARGER_LP8788)  += lp8788-charger.o
 obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
 obj-$(CONFIG_CHARGER_MANAGER)  += charger-manager.o
 obj-$(CONFIG_CHARGER_LT3651)   += lt3651-charger.o
+obj-$(CONFIG_CHARGER_LTC4162L) += ltc4162-l-charger.o
 obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
 obj-$(CONFIG_CHARGER_DETECTOR_MAX14656)+= max14656_charger_detector.o
 obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o
diff --git a/drivers/power/supply/ltc4162-l-charger.c 
b/drivers/power/supply/ltc4162-l-charger.c
new file mode 100644
index ..4560a1ac5a08
--- /dev/null
+++ b/drivers/power/supply/ltc4162-l-charger.c
@@ -0,0 +1,847 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Driver for Analog Devices (Linear Technology) LTC4162-L charger IC.
+ *  Copyright (C) 2020, Topic Embedded Products
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* Registers (names based on what datasheet uses) */
+#define LTC4162L_EN_LIMIT_ALERTS_REG   0x0D
+#define LTC4162L_EN_CHARGER_STATE_ALERTS_REG   0x0E
+#define LTC4162L_EN_CHARGE_STATUS_ALERTS_REG   0x0F
+#define LTC4162L_CONFIG_BITS_REG   0x14
+#define LTC4162L_IIN_LIMIT_TARGET  0x15
+#define LTC4162L_ARM_SHIP_MODE 0x19
+#define LTC4162L_CHARGE_CURRENT_SETTING0X1A
+#define LTC4162L_VCHARGE_SETTING   0X1B
+#define LTC4162L_C_OVER_X_THRESHOLD0x1C
+#define LTC4162L_MAX_CV_TIME   0X1D
+#define LTC4162L_MAX_CHARGE_TIME   0X1E
+#define LTC4162L_CHARGER_CONFIG_BITS   0x29
+#define LTC4162L_CHARGER_STATE 0x34
+#define LTC4162L_CHARGE_STATUS 0x35
+#define LTC4162L_LIMIT_ALERTS_REG  0x36
+#define LTC4162L_CHARGER_STATE_ALERTS_REG  0x37
+#define LTC4162L_CHARGE_STATUS_ALERTS_REG  0x38
+#define LTC4162L_SYSTEM_STATUS_REG 0x39
+#define LTC4162L_VBAT  0x3A
+#define LTC4162L_VIN   0x3B
+#define LTC4162L_VOUT  0x3C
+#define LTC4162L_IBAT  0x3D
+#define LTC4162L_IIN   0x3E
+#define LTC4162L_DIE_TEMPERATURE   0x3F
+#define LTC4162L_THERMISTOR_VOLTAGE0x40
+#define LTC4162L_BSR   0x41
+#define LTC4162L_JEITA_REGION  0x42
+#define LTC4162L_CHEM_CELLS_REG0x43
+#define LTC4162L_ICHARGE_DAC   0x44
+#define LTC4162L_VCHARGE_DAC   0x45
+#define LTC4162L_IIN_LIMIT_DAC 0x46
+#define LTC4162L_VBAT_FILT 0x47
+#define LTC4162L_INPUT_UNDERVOLTAGE_DAC0x4B
+
+/* Enumeration as in datasheet. Individual bits are mutually exclusive. */
+enum ltc4162l_state {
+   battery_detection = 2048,
+   charger_suspended = 256,
+   precharge = 128,   /* trickle on low bat voltage */
+   cc_cv_charge = 64, /* normal charge */
+   ntc_pause = 32,
+   timer_term = 16,
+   c_over_x_term = 8, /* battery is full */
+   max_charge_time_fault = 4,
+   bat_missing_fault = 2,
+   bat_short_fault = 1
+};
+
+/* Individual bits are mutually exclusive. Only active in charging states.*/
+enum ltc4162l_charge_status {
+   ilim_reg_active = 32,
+   thermal_reg_active = 16,
+   vin_uvcl_active = 8,
+   iin_limit_active = 4,
+   constant_current = 2,
+   constant_voltage = 1,

[PATCH] dt-bindings: power/supply: Add ltc4162-l-charger

2020-10-21 Thread Mike Looijmans
Add support for the LTC4162-L Li-Ion battery charger. The driver allows
reading back telemetry and to set some charging options like the input
current limit.

This adds the devicetree bindings.

Signed-off-by: Mike Looijmans 
---
 .../bindings/power/supply/ltc4162-l.yaml  | 60 +++
 1 file changed, 60 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml

diff --git a/Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml 
b/Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml
new file mode 100644
index ..a23dd6f3fae0
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (C) 2020 Topic Embedded Products
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/power/supply/ltc4162-l.yaml#;
+$schema: "http://devicetree.org/meta-schemas/core.yaml#;
+
+title: Linear Technology (Analog Devices) LTC4162-L Charger
+
+maintainers:
+  - Mike Looijmans 
+
+description: |
+  The LTC ® 4162-L is an advanced monolithic synchronous step-down switching
+  battery charger and PowerPath (TM) manager that seamlessly manages power
+  distribution between input sources such as wall adapters, backplanes, solar
+  panels, etc., and a rechargeable Lithium-Ion/Polymer battery.
+
+  Specifications about the charger can be found at:
+https://www.analog.com/en/products/ltc4162-s.html
+
+properties:
+  compatible:
+enum:
+  - lltc,ltc4162-l
+
+  reg:
+maxItems: 1
+description: I2C address of the charger.
+
+  lltc,rsnsb:
+$ref: /schemas/types.yaml#/definitions/uint32
+description: Battery sense resistor in milli Ohm.
+minimum: 1
+
+  lltc,rsnsi:
+$ref: /schemas/types.yaml#/definitions/uint32
+description: Input current sense resistor in milli Ohm.
+minimum: 1
+
+required:
+  - compatible
+  - reg
+  - lltc,rsnsb
+  - lltc,rsnsi
+
+additionalProperties: false
+
+examples:
+  - |
+i2c0 {
+  #address-cells = <1>;
+  #size-cells = <0>;
+  charger: battery-charger@68 {
+  compatible = "lltc,ltc4162-l";
+  reg =  <0x68>;
+  lltc,rsnsb = <10>;
+  lltc,rsnsi = <16>;
+  };
+};
-- 
2.17.1



[PATCH v3] dt-bindings: gpio: pca953x: Add support for the NXP PCAL9554B/C

2020-10-09 Thread Mike Looijmans
The NXP PCAL9554B is a variant of the PCA953x GPIO expander,
with 8 GPIOs, latched interrupts and some advanced configuration
options. The "C" version only differs in I2C address.

This adds the entry to the devicetree bindings.

Signed-off-by: Mike Looijmans 
---
v2: Split devicetree and code into separate patches
v3: Devicetree bindings in yaml format

 Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml 
b/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml
index 183ec23eda39..f5ee23c2df60 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml
+++ b/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml
@@ -48,6 +48,7 @@ properties:
   - nxp,pcal6416
   - nxp,pcal6524
   - nxp,pcal9535
+  - nxp,pcal9554b
   - nxp,pcal9555a
   - onnn,cat9554
   - onnn,pca9654
-- 
2.17.1



Re: [PATCH v2 1/2] dt-bindings: gpio: pca953x: Add support for the NXP PCAL9554B/C

2020-10-08 Thread Mike Looijmans



Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 07-10-2020 11:58, Linus Walleij wrote:

On Tue, Oct 6, 2020 at 9:32 PM Rob Herring  wrote:

On Wed, Sep 30, 2020 at 11:50:38AM +0200, Linus Walleij wrote:

On Wed, Sep 30, 2020 at 11:21 AM Mike Looijmans  wrote:


The NXP PCAL9554B is a variant of the PCA953x GPIO expander,
with 8 GPIOs, latched interrupts and some advanced configuration
options. The "C" version only differs in I2C address.

This adds the entry to the devicetree bindings.

Signed-off-by: Mike Looijmans 
---
v2: Split devicetree and code into separate patches


Reviewed-by: Linus Walleij 

This patch 1/2 does not apply to my tree, I suppose Rob has
to apply it?


Nope, no changes in my tree.


Weird, OK Mike apply this wherever it should be applied or rebase
on my GPIO tree and resend if you want me to apply it.



Could you provide me a git URL + branch to rebase it on, i'll send you a new 
patch then.


Re: [PATCH v2 1/2] dt-bindings: gpio: pca953x: Add support for the NXP PCAL9554B/C

2020-09-30 Thread Mike Looijmans



Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 30-09-2020 11:50, Linus Walleij wrote:

On Wed, Sep 30, 2020 at 11:21 AM Mike Looijmans  wrote:


The NXP PCAL9554B is a variant of the PCA953x GPIO expander,
with 8 GPIOs, latched interrupts and some advanced configuration
options. The "C" version only differs in I2C address.

This adds the entry to the devicetree bindings.

Signed-off-by: Mike Looijmans 
---
v2: Split devicetree and code into separate patches

Reviewed-by: Linus Walleij 

This patch 1/2 does not apply to my tree, I suppose Rob has
to apply it?

I will try to apply 2/2.

Yours,
Linus Walleij
I based the patches on the current master. Well, master a few days ago. 
A rebase on current master also had no complaints.


--
Mike Looijmans



[PATCH v2 1/2] dt-bindings: gpio: pca953x: Add support for the NXP PCAL9554B/C

2020-09-30 Thread Mike Looijmans
The NXP PCAL9554B is a variant of the PCA953x GPIO expander,
with 8 GPIOs, latched interrupts and some advanced configuration
options. The "C" version only differs in I2C address.

This adds the entry to the devicetree bindings.

Signed-off-by: Mike Looijmans 
---
v2: Split devicetree and code into separate patches

 Documentation/devicetree/bindings/gpio/gpio-pca953x.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt 
b/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
index 3126c3817e2a..99dc1936f633 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
@@ -20,6 +20,7 @@ Required properties:
nxp,pcal6416
nxp,pcal6524
nxp,pcal9535
+   nxp,pcal9554b
nxp,pcal9555a
maxim,max7310
maxim,max7312
-- 
2.17.1



[PATCH v2 2/2] gpio: pca953x: Add support for the NXP PCAL9554B/C

2020-09-30 Thread Mike Looijmans
The NXP PCAL9554B is a variant of the PCA953x GPIO expander,
with 8 GPIOs, latched interrupts and some advanced configuration
options. The "C" version only differs in I2C address.

Signed-off-by: Mike Looijmans 
---
v2: Split devicetree and code into separate patches

 drivers/gpio/gpio-pca953x.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index bd2e96c34f82..fb946b01512d 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -90,6 +90,7 @@ static const struct i2c_device_id pca953x_id[] = {
{ "pcal6416", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
{ "pcal6524", 24 | PCA953X_TYPE | PCA_LATCH_INT, },
{ "pcal9535", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
+   { "pcal9554b", 8  | PCA953X_TYPE | PCA_LATCH_INT, },
{ "pcal9555a", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
 
{ "max7310", 8  | PCA953X_TYPE, },
@@ -1237,6 +1238,7 @@ static const struct of_device_id pca953x_dt_ids[] = {
{ .compatible = "nxp,pcal6416", .data = OF_953X(16, PCA_LATCH_INT), },
{ .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_LATCH_INT), },
{ .compatible = "nxp,pcal9535", .data = OF_953X(16, PCA_LATCH_INT), },
+   { .compatible = "nxp,pcal9554b", .data = OF_953X( 8, PCA_LATCH_INT), },
{ .compatible = "nxp,pcal9555a", .data = OF_953X(16, PCA_LATCH_INT), },
 
{ .compatible = "maxim,max7310", .data = OF_953X( 8, 0), },
-- 
2.17.1



[PATCH] gpio: pca953x: Add support for the NXP PCAL9554B/C

2020-09-28 Thread Mike Looijmans
The NXP PCAL9554B is a variant of the PCA953x GPIO expander,
with 8 GPIOs, latched interrupts and some advanced configuration
options. The "C" version only differs in I2C address.

Signed-off-by: Mike Looijmans 
---
 Documentation/devicetree/bindings/gpio/gpio-pca953x.txt | 1 +
 drivers/gpio/gpio-pca953x.c | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt 
b/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
index 3126c3817e2a..99dc1936f633 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
@@ -20,6 +20,7 @@ Required properties:
nxp,pcal6416
nxp,pcal6524
nxp,pcal9535
+   nxp,pcal9554b
nxp,pcal9555a
maxim,max7310
maxim,max7312
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index bd2e96c34f82..fb946b01512d 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -90,6 +90,7 @@ static const struct i2c_device_id pca953x_id[] = {
{ "pcal6416", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
{ "pcal6524", 24 | PCA953X_TYPE | PCA_LATCH_INT, },
{ "pcal9535", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
+   { "pcal9554b", 8  | PCA953X_TYPE | PCA_LATCH_INT, },
{ "pcal9555a", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
 
{ "max7310", 8  | PCA953X_TYPE, },
@@ -1237,6 +1238,7 @@ static const struct of_device_id pca953x_dt_ids[] = {
{ .compatible = "nxp,pcal6416", .data = OF_953X(16, PCA_LATCH_INT), },
{ .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_LATCH_INT), },
{ .compatible = "nxp,pcal9535", .data = OF_953X(16, PCA_LATCH_INT), },
+   { .compatible = "nxp,pcal9554b", .data = OF_953X( 8, PCA_LATCH_INT), },
{ .compatible = "nxp,pcal9555a", .data = OF_953X(16, PCA_LATCH_INT), },
 
{ .compatible = "maxim,max7310", .data = OF_953X( 8, 0), },
-- 
2.17.1



Re: [PATCH v3] usb: dwc3: Add support for VBUS power control

2020-09-07 Thread Mike Looijmans



Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 07-09-2020 09:44, Felipe Balbi wrote:

Hi,

Mike Looijmans  writes:

Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 27-07-2020 12:23, Mark Brown wrote:

On Sun, Jul 26, 2020 at 09:10:39AM +0200, Mike Looijmans wrote:

On 23-07-2020 13:05, Mark Brown wrote:

Does the device actually support running without power so that's a thing
that can happen?  _get_optional() should only ever be used for supplies
that may be physically absent.

It's the 5V VBUS power for the USB "plug" that's being controlled here. It
must turned on when the controller is in "host" mode. Some boards arrange
this in hardware through the PHY, and some just don't have any control at
all and have it permanently on or off. On a board where the 5V is controlled
using a GPIO line or an I2C chip, this patch is required to make it work.

That sounds like the driver should not be using _get_optional() then.


Making it mandatory would break most (read: all except Topic's) existing
boards as they won't have it in their devicetree. I'm perfectly okay with
that, but others might disagree.

you're perfectly okay with break all existing users of the driver?
That's a bit harsh

It turned out that "optional" when used for regulators means the 
opposite of when used in clk context. For regulators, "optional" means 
"don't supply a dummy regulator if there's none provided". So 
get_optional will just fail when the supply isn't defined, while 
get_regulator will just return a dummy in that case.


So the v4 patch which doesn't use "_get_optional" works for both cases 
and doesn't break existing use(r)s.


--
Mike Looijmans



[PATCH v4] usb: dwc3: Add support for VBUS power control

2020-08-05 Thread Mike Looijmans
Support VBUS power control using regulator framework. Enables the regulator
while the port is in host mode.

The "vbus-supply" property can be provided using a usb-connector child node
and standard devicetree bindings.

Signed-off-by: Mike Looijmans 
---
v2: Add missing devm_regulator_get call which got lost during rebase
v3: Remove devicetree binding, use standard usb-connector
Fix probe fail when vbus-supply is not present
v4: Use devm_regulator_get (without "optional")

 drivers/usb/dwc3/core.c | 34 ++
 drivers/usb/dwc3/core.h |  4 
 drivers/usb/dwc3/drd.c  |  6 ++
 3 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index edc17155cb2b..abfd043bae21 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -25,6 +25,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -112,6 +113,23 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
dwc->current_dr_role = mode;
 }
 
+void dwc3_set_vbus(struct dwc3 *dwc, bool enable)
+{
+   int ret;
+
+   if (enable != dwc->vbus_reg_enabled) {
+   if (enable)
+   ret = regulator_enable(dwc->vbus_reg);
+   else
+   ret = regulator_disable(dwc->vbus_reg);
+   if (!ret)
+   dwc->vbus_reg_enabled = enable;
+   }
+
+   if (dwc->usb2_phy)
+   otg_set_vbus(dwc->usb2_phy->otg, enable);
+}
+
 static void __dwc3_set_mode(struct work_struct *work)
 {
struct dwc3 *dwc = work_to_dwc(work);
@@ -164,8 +182,7 @@ static void __dwc3_set_mode(struct work_struct *work)
if (ret) {
dev_err(dwc->dev, "failed to initialize host\n");
} else {
-   if (dwc->usb2_phy)
-   otg_set_vbus(dwc->usb2_phy->otg, true);
+   dwc3_set_vbus(dwc, true);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
}
@@ -173,8 +190,7 @@ static void __dwc3_set_mode(struct work_struct *work)
case DWC3_GCTL_PRTCAP_DEVICE:
dwc3_event_buffers_setup(dwc);
 
-   if (dwc->usb2_phy)
-   otg_set_vbus(dwc->usb2_phy->otg, false);
+   dwc3_set_vbus(dwc, false);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
 
@@ -1183,8 +1199,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
case USB_DR_MODE_PERIPHERAL:
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
 
-   if (dwc->usb2_phy)
-   otg_set_vbus(dwc->usb2_phy->otg, false);
+   dwc3_set_vbus(dwc, false);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
 
@@ -1198,8 +1213,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
case USB_DR_MODE_HOST:
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
 
-   if (dwc->usb2_phy)
-   otg_set_vbus(dwc->usb2_phy->otg, true);
+   dwc3_set_vbus(dwc, true);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
 
@@ -1470,6 +1484,10 @@ static int dwc3_probe(struct platform_device *pdev)
 
dwc3_get_properties(dwc);
 
+   dwc->vbus_reg = devm_regulator_get(dev, "vbus");
+   if (IS_ERR(dwc->vbus_reg))
+   return PTR_ERR(dwc->vbus_reg);
+
dwc->reset = devm_reset_control_array_get(dev, true, true);
if (IS_ERR(dwc->reset))
return PTR_ERR(dwc->reset);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 4c171a8e215f..cee2574d7bf4 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1085,6 +1085,9 @@ struct dwc3 {
 
boolphys_ready;
 
+   struct regulator*vbus_reg;
+   boolvbus_reg_enabled;
+
struct ulpi *ulpi;
boolulpi_ready;
 
@@ -1397,6 +1400,7 @@ struct dwc3_gadget_ep_cmd_params {
 
 /* prototypes */
 void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode);
+void dwc3_set_vbus(struct dwc3 *dwc, bool enable);
 void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
 u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);
 
diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c
index 7db1ffc92bbd..45fdec2d128d 100644
--- a/drivers/usb/dwc3/drd.c
+++ b/drivers/usb/dwc3/drd.c
@@ -384,8 +384,7 @@ void dwc3_otg

Re: [PATCH v3] usb: dwc3: Add support for VBUS power control

2020-07-28 Thread Mike Looijmans



Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 27-07-2020 13:53, Mark Brown wrote:

On Mon, Jul 27, 2020 at 01:50:26PM +0200, Mike Looijmans wrote:


Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


You probably want to remove your signature when replying to the list...


On 27-07-2020 12:23, Mark Brown wrote:

On Sun, Jul 26, 2020 at 09:10:39AM +0200, Mike Looijmans wrote:



It's the 5V VBUS power for the USB "plug" that's being controlled here. It
must turned on when the controller is in "host" mode. Some boards arrange
this in hardware through the PHY, and some just don't have any control at
all and have it permanently on or off. On a board where the 5V is controlled
using a GPIO line or an I2C chip, this patch is required to make it work.



That sounds like the driver should not be using _get_optional() then.



Making it mandatory would break most (read: all except Topic's) existing
boards as they won't have it in their devicetree. I'm perfectly okay with
that, but others might disagree.


No, it wouldn't break them at all - they'd get a dummy regulator
provided.



Ah, so *not* using _get_optional will yield the behaviour that I'd want. I'll 
test and make a v4 patch.


Re: [PATCH v3] usb: dwc3: Add support for VBUS power control

2020-07-27 Thread Mike Looijmans



Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 27-07-2020 12:23, Mark Brown wrote:

On Sun, Jul 26, 2020 at 09:10:39AM +0200, Mike Looijmans wrote:

On 23-07-2020 13:05, Mark Brown wrote:



Does the device actually support running without power so that's a thing
that can happen?  _get_optional() should only ever be used for supplies
that may be physically absent.



It's the 5V VBUS power for the USB "plug" that's being controlled here. It
must turned on when the controller is in "host" mode. Some boards arrange
this in hardware through the PHY, and some just don't have any control at
all and have it permanently on or off. On a board where the 5V is controlled
using a GPIO line or an I2C chip, this patch is required to make it work.


That sounds like the driver should not be using _get_optional() then.



Making it mandatory would break most (read: all except Topic's) existing 
boards as they won't have it in their devicetree. I'm perfectly okay with 
that, but others might disagree.




Re: [PATCH v3] usb: dwc3: Add support for VBUS power control

2020-07-26 Thread Mike Looijmans



Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 23-07-2020 13:05, Mark Brown wrote:

On Thu, Jul 23, 2020 at 09:56:14AM +0200, Vincent Whitchurch wrote:

On Fri, Jun 19, 2020 at 04:25:12PM +0200, Mike Looijmans wrote:

+void dwc3_set_vbus(struct dwc3 *dwc, bool enable)
+{
+   int ret;
+
+   if (enable != dwc->vbus_reg_enabled) {
+   if (enable)
+   ret = regulator_enable(dwc->vbus_reg);
+   else
+   ret = regulator_disable(dwc->vbus_reg);
  

dwc->vbus_reg is set to NULL when the regulator is not present.  These
regulator_* functions expect a non-NULL pointer so a NULL check is
required before calling them.

Does the device actually support running without power so that's a thing
that can happen?  _get_optional() should only ever be used for supplies
that may be physically absent.


It's the 5V VBUS power for the USB "plug" that's being controlled here. 
It must turned on when the controller is in "host" mode. Some boards 
arrange this in hardware through the PHY, and some just don't have any 
control at all and have it permanently on or off. On a board where the 
5V is controlled using a GPIO line or an I2C chip, this patch is 
required to make it work.



--
Mike Looijmans



[PATCH v3] usb: dwc3: Add support for VBUS power control

2020-06-19 Thread Mike Looijmans
Support VBUS power control using regulator framework. Enables the regulator
while the port is in host mode.

The "vbus-supply" property can be provided using a usb-connector child node
and standard devicetree bindings.

Signed-off-by: Mike Looijmans 
---
v2: Add missing devm_regulator_get call which got lost during rebase
v3: Remove devicetree binding, use standard usb-connector
Fix probe fail when vbus-supply is not present

 drivers/usb/dwc3/core.c | 38 ++
 drivers/usb/dwc3/core.h |  4 
 drivers/usb/dwc3/drd.c  |  6 ++
 3 files changed, 36 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index edc17155cb2b..42e804ede1b3 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -25,6 +25,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -112,6 +113,23 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
dwc->current_dr_role = mode;
 }
 
+void dwc3_set_vbus(struct dwc3 *dwc, bool enable)
+{
+   int ret;
+
+   if (enable != dwc->vbus_reg_enabled) {
+   if (enable)
+   ret = regulator_enable(dwc->vbus_reg);
+   else
+   ret = regulator_disable(dwc->vbus_reg);
+   if (!ret)
+   dwc->vbus_reg_enabled = enable;
+   }
+
+   if (dwc->usb2_phy)
+   otg_set_vbus(dwc->usb2_phy->otg, enable);
+}
+
 static void __dwc3_set_mode(struct work_struct *work)
 {
struct dwc3 *dwc = work_to_dwc(work);
@@ -164,8 +182,7 @@ static void __dwc3_set_mode(struct work_struct *work)
if (ret) {
dev_err(dwc->dev, "failed to initialize host\n");
} else {
-   if (dwc->usb2_phy)
-   otg_set_vbus(dwc->usb2_phy->otg, true);
+   dwc3_set_vbus(dwc, true);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
}
@@ -173,8 +190,7 @@ static void __dwc3_set_mode(struct work_struct *work)
case DWC3_GCTL_PRTCAP_DEVICE:
dwc3_event_buffers_setup(dwc);
 
-   if (dwc->usb2_phy)
-   otg_set_vbus(dwc->usb2_phy->otg, false);
+   dwc3_set_vbus(dwc, false);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
 
@@ -1183,8 +1199,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
case USB_DR_MODE_PERIPHERAL:
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
 
-   if (dwc->usb2_phy)
-   otg_set_vbus(dwc->usb2_phy->otg, false);
+   dwc3_set_vbus(dwc, false);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
 
@@ -1198,8 +1213,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
case USB_DR_MODE_HOST:
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
 
-   if (dwc->usb2_phy)
-   otg_set_vbus(dwc->usb2_phy->otg, true);
+   dwc3_set_vbus(dwc, true);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
 
@@ -1470,6 +1484,14 @@ static int dwc3_probe(struct platform_device *pdev)
 
dwc3_get_properties(dwc);
 
+   dwc->vbus_reg = devm_regulator_get_optional(dev, "vbus");
+   if (IS_ERR(dwc->vbus_reg)) {
+   if (PTR_ERR(dwc->vbus_reg) == -EPROBE_DEFER)
+   return -EPROBE_DEFER;
+
+   dwc->vbus_reg = NULL;
+   }
+
dwc->reset = devm_reset_control_array_get(dev, true, true);
if (IS_ERR(dwc->reset))
return PTR_ERR(dwc->reset);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 4c171a8e215f..cee2574d7bf4 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1085,6 +1085,9 @@ struct dwc3 {
 
boolphys_ready;
 
+   struct regulator*vbus_reg;
+   boolvbus_reg_enabled;
+
struct ulpi *ulpi;
boolulpi_ready;
 
@@ -1397,6 +1400,7 @@ struct dwc3_gadget_ep_cmd_params {
 
 /* prototypes */
 void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode);
+void dwc3_set_vbus(struct dwc3 *dwc, bool enable);
 void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
 u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);
 
diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c
index 7db1ffc92bbd..45fdec2d128d 100644
--- a/drivers/usb/dwc3/d

Re: [PATCH v2] usb: dwc3: Add support for VBUS power control

2020-06-19 Thread Mike Looijmans



Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 17-06-2020 19:28, Mike Looijmans wrote:

On 17-06-2020 18:13, Rob Herring wrote:
On Wed, Jun 17, 2020 at 8:38 AM Mike Looijmans 
 wrote:

On 10-06-2020 22:22, Rob Herring wrote:

On Wed, Jun 03, 2020 at 02:09:15PM +0200, Mike Looijmans wrote:
Support VBUS power control using regulator framework. Enables the 
regulator

while the port is in host mode.

Signed-off-by: Mike Looijmans 
---
v2: Add missing devm_regulator_get call which got lost during rebase

   .../devicetree/bindings/usb/dwc3.txt  |  1 +
   drivers/usb/dwc3/core.c   | 34 
++-

   drivers/usb/dwc3/core.h   |  4 +++
   drivers/usb/dwc3/drd.c    |  6 ++--
   4 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt 
b/Documentation/devicetree/bindings/usb/dwc3.txt

index 9946ff9ba735..56bc3f238e2d 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -37,6 +37,7 @@ Optional properties:
    - phys: from the *Generic PHY* bindings
    - phy-names: from the *Generic PHY* bindings; supported names 
are "usb2-phy"

  or "usb3-phy".
+ - vbus-supply: Regulator handle that provides the VBUS power.

Does the DWC3 block require Vbus to power itself? Doubtful. This
belongs in a usb-connector node. If the DWC3 driver wants to get the
Vbus supply, it can fetch it from that node.

Rob

Okay, I've been digging into that. But there's no actual driver that
binds to a "usb-b-connector" compatible, so how do we get to the
vbus-supply from there?

[devm_]regulator_get only accepts a device as argument, and will not
look into child nodes. The only way to get at the vbus of a child node
(or a node linked through a port) would be to hand-code the equivalent
of of_regulator_get(), which will not be acceptable.

Doesn't it look into child nodes calling of_get_child_regulator()?
Looking at the code in regulator/core.c, yeah, it should. I'll have to 
add some debugging lines and look into why it didn't work in my test.


Ah, I had put my "connector" child in the wrong node. If I add the 
following fragment to the dwc3 node, the vbus patch works:


    connector {
        compatible = "usb-b-connector";
        label = "micro-USB-otg";
        type = "micro";
        vbus-supply = <_usb0_vbus>;
    };

The driver indeed picks up the vbus supply from a child node.

This would mean there's no change to the devicetree bindings, it's using 
already existing bindings.



You're right that it wouldn't work if graph is used. The connector has
to be either a child of a controller for the connector or the USB
controller. I'd expect you'd have the former for Type-C, but for
"usb-b-connector" the parent is more likely just the USB controller.
For my current case, using a direct child would be fine, there's 
nothing else connected. But I expect that we'll produce a board with 
some USB-C connector some day yeah.


In any case, having a struct device shouldn't be a requirement and
most subsystems expose a get function only needing the DT node.


Or is it the intention that I write a usb-X-connector device driver
first that handles the vbus?

That's a kernel implementation detail that is independent of the
binding, but yes we'll probably need a driver or library helper
functions eventually. Note that it is possible to have a struct device
without a driver.

Rob





--
Mike Looijmans



Re: [PATCH v2] usb: dwc3: Add support for VBUS power control

2020-06-17 Thread Mike Looijmans



Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 17-06-2020 18:13, Rob Herring wrote:

On Wed, Jun 17, 2020 at 8:38 AM Mike Looijmans  wrote:


Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 10-06-2020 22:22, Rob Herring wrote:

On Wed, Jun 03, 2020 at 02:09:15PM +0200, Mike Looijmans wrote:

Support VBUS power control using regulator framework. Enables the regulator
while the port is in host mode.

Signed-off-by: Mike Looijmans 
---
v2: Add missing devm_regulator_get call which got lost during rebase

   .../devicetree/bindings/usb/dwc3.txt  |  1 +
   drivers/usb/dwc3/core.c   | 34 ++-
   drivers/usb/dwc3/core.h   |  4 +++
   drivers/usb/dwc3/drd.c|  6 ++--
   4 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt 
b/Documentation/devicetree/bindings/usb/dwc3.txt
index 9946ff9ba735..56bc3f238e2d 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -37,6 +37,7 @@ Optional properties:
- phys: from the *Generic PHY* bindings
- phy-names: from the *Generic PHY* bindings; supported names are "usb2-phy"
  or "usb3-phy".
+ - vbus-supply: Regulator handle that provides the VBUS power.

Does the DWC3 block require Vbus to power itself? Doubtful. This
belongs in a usb-connector node. If the DWC3 driver wants to get the
Vbus supply, it can fetch it from that node.

Rob

Okay, I've been digging into that. But there's no actual driver that
binds to a "usb-b-connector" compatible, so how do we get to the
vbus-supply from there?

[devm_]regulator_get only accepts a device as argument, and will not
look into child nodes. The only way to get at the vbus of a child node
(or a node linked through a port) would be to hand-code the equivalent
of of_regulator_get(), which will not be acceptable.

Doesn't it look into child nodes calling of_get_child_regulator()?
Looking at the code in regulator/core.c, yeah, it should. I'll have to 
add some debugging lines and look into why it didn't work in my test.

You're right that it wouldn't work if graph is used. The connector has
to be either a child of a controller for the connector or the USB
controller. I'd expect you'd have the former for Type-C, but for
"usb-b-connector" the parent is more likely just the USB controller.
For my current case, using a direct child would be fine, there's nothing 
else connected. But I expect that we'll produce a board with some USB-C 
connector some day yeah.


In any case, having a struct device shouldn't be a requirement and
most subsystems expose a get function only needing the DT node.


Or is it the intention that I write a usb-X-connector device driver
first that handles the vbus?

That's a kernel implementation detail that is independent of the
binding, but yes we'll probably need a driver or library helper
functions eventually. Note that it is possible to have a struct device
without a driver.

Rob



--
Mike Looijmans



Re: [PATCH v2] usb: dwc3: Add support for VBUS power control

2020-06-17 Thread Mike Looijmans



Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 10-06-2020 22:22, Rob Herring wrote:

On Wed, Jun 03, 2020 at 02:09:15PM +0200, Mike Looijmans wrote:

Support VBUS power control using regulator framework. Enables the regulator
while the port is in host mode.

Signed-off-by: Mike Looijmans 
---
v2: Add missing devm_regulator_get call which got lost during rebase

  .../devicetree/bindings/usb/dwc3.txt  |  1 +
  drivers/usb/dwc3/core.c   | 34 ++-
  drivers/usb/dwc3/core.h   |  4 +++
  drivers/usb/dwc3/drd.c|  6 ++--
  4 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt 
b/Documentation/devicetree/bindings/usb/dwc3.txt
index 9946ff9ba735..56bc3f238e2d 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -37,6 +37,7 @@ Optional properties:
   - phys: from the *Generic PHY* bindings
   - phy-names: from the *Generic PHY* bindings; supported names are "usb2-phy"
or "usb3-phy".
+ - vbus-supply: Regulator handle that provides the VBUS power.

Does the DWC3 block require Vbus to power itself? Doubtful. This
belongs in a usb-connector node. If the DWC3 driver wants to get the
Vbus supply, it can fetch it from that node.

Rob


Okay, I've been digging into that. But there's no actual driver that 
binds to a "usb-b-connector" compatible, so how do we get to the 
vbus-supply from there?


[devm_]regulator_get only accepts a device as argument, and will not 
look into child nodes. The only way to get at the vbus of a child node 
(or a node linked through a port) would be to hand-code the equivalent 
of of_regulator_get(), which will not be acceptable.


Or is it the intention that I write a usb-X-connector device driver 
first that handles the vbus?


--
Mike Looijmans



Re: [PATCH v2] usb: dwc3: Add support for VBUS power control

2020-06-11 Thread Mike Looijmans



Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 10-06-2020 22:22, Rob Herring wrote:

On Wed, Jun 03, 2020 at 02:09:15PM +0200, Mike Looijmans wrote:

Support VBUS power control using regulator framework. Enables the regulator
while the port is in host mode.

Signed-off-by: Mike Looijmans 
---
v2: Add missing devm_regulator_get call which got lost during rebase

  .../devicetree/bindings/usb/dwc3.txt  |  1 +
  drivers/usb/dwc3/core.c   | 34 ++-
  drivers/usb/dwc3/core.h   |  4 +++
  drivers/usb/dwc3/drd.c|  6 ++--
  4 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt 
b/Documentation/devicetree/bindings/usb/dwc3.txt
index 9946ff9ba735..56bc3f238e2d 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -37,6 +37,7 @@ Optional properties:
   - phys: from the *Generic PHY* bindings
   - phy-names: from the *Generic PHY* bindings; supported names are "usb2-phy"
or "usb3-phy".
+ - vbus-supply: Regulator handle that provides the VBUS power.

Does the DWC3 block require Vbus to power itself? Doubtful. This
belongs in a usb-connector node. If the DWC3 driver wants to get the
Vbus supply, it can fetch it from that node.

Rob


Ah, now I understand. There's a vbus-supply in the connector in newer 
kernel versions than the one I have to test with. It'll have to wait 
until I've been able to upgrade the kernel version for this board.



--
Mike Looijmans



[PATCH v2] usb: dwc3: Add support for VBUS power control

2020-06-03 Thread Mike Looijmans
Support VBUS power control using regulator framework. Enables the regulator
while the port is in host mode.

Signed-off-by: Mike Looijmans 
---
v2: Add missing devm_regulator_get call which got lost during rebase

 .../devicetree/bindings/usb/dwc3.txt  |  1 +
 drivers/usb/dwc3/core.c   | 34 ++-
 drivers/usb/dwc3/core.h   |  4 +++
 drivers/usb/dwc3/drd.c|  6 ++--
 4 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt 
b/Documentation/devicetree/bindings/usb/dwc3.txt
index 9946ff9ba735..56bc3f238e2d 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -37,6 +37,7 @@ Optional properties:
  - phys: from the *Generic PHY* bindings
  - phy-names: from the *Generic PHY* bindings; supported names are "usb2-phy"
or "usb3-phy".
+ - vbus-supply: Regulator handle that provides the VBUS power.
  - resets: set of phandle and reset specifier pairs
  - snps,usb2-lpm-disable: indicate if we don't want to enable USB2 HW LPM
  - snps,usb3_lpm_capable: determines if platform is USB3 LPM capable
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index edc17155cb2b..ad341a182999 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -25,6 +25,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -112,6 +113,23 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
dwc->current_dr_role = mode;
 }
 
+void dwc3_set_vbus(struct dwc3 *dwc, bool enable)
+{
+   int ret;
+
+   if (enable != dwc->vbus_reg_enabled) {
+   if (enable)
+   ret = regulator_enable(dwc->vbus_reg);
+   else
+   ret = regulator_disable(dwc->vbus_reg);
+   if (!ret)
+   dwc->vbus_reg_enabled = enable;
+   }
+
+   if (dwc->usb2_phy)
+   otg_set_vbus(dwc->usb2_phy->otg, enable);
+}
+
 static void __dwc3_set_mode(struct work_struct *work)
 {
struct dwc3 *dwc = work_to_dwc(work);
@@ -164,8 +182,7 @@ static void __dwc3_set_mode(struct work_struct *work)
if (ret) {
dev_err(dwc->dev, "failed to initialize host\n");
} else {
-   if (dwc->usb2_phy)
-   otg_set_vbus(dwc->usb2_phy->otg, true);
+   dwc3_set_vbus(dwc, true);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
}
@@ -173,8 +190,7 @@ static void __dwc3_set_mode(struct work_struct *work)
case DWC3_GCTL_PRTCAP_DEVICE:
dwc3_event_buffers_setup(dwc);
 
-   if (dwc->usb2_phy)
-   otg_set_vbus(dwc->usb2_phy->otg, false);
+   dwc3_set_vbus(dwc, false);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
 
@@ -1183,8 +1199,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
case USB_DR_MODE_PERIPHERAL:
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
 
-   if (dwc->usb2_phy)
-   otg_set_vbus(dwc->usb2_phy->otg, false);
+   dwc3_set_vbus(dwc, false);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
 
@@ -1198,8 +1213,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
case USB_DR_MODE_HOST:
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
 
-   if (dwc->usb2_phy)
-   otg_set_vbus(dwc->usb2_phy->otg, true);
+   dwc3_set_vbus(dwc, true);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
 
@@ -1470,6 +1484,10 @@ static int dwc3_probe(struct platform_device *pdev)
 
dwc3_get_properties(dwc);
 
+   dwc->vbus_reg = devm_regulator_get_optional(dev, "vbus");
+   if (IS_ERR(dwc->vbus_reg))
+   return PTR_ERR(dwc->vbus_reg);
+
dwc->reset = devm_reset_control_array_get(dev, true, true);
if (IS_ERR(dwc->reset))
return PTR_ERR(dwc->reset);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 4c171a8e215f..cee2574d7bf4 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1085,6 +1085,9 @@ struct dwc3 {
 
boolphys_ready;
 
+   struct regulator*vbus_reg;
+   boolvbus_reg_enabled;
+
struct ulpi   

Re: [PATCH] usb: dwc3: Add support for VBUS power control

2020-06-03 Thread Mike Looijmans
Oh darn, the "devm_get_regulator..." call in probe got lost in the 
rebase+merge. I'll add that in v2.




Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 03-06-2020 10:59, Mike Looijmans wrote:

Support VBUS power control using regulator framework. Enables the regulator
while the port is in host mode.

Signed-off-by: Mike Looijmans 
---
  .../devicetree/bindings/usb/dwc3.txt  |  1 +
  drivers/usb/dwc3/core.c   | 30 ++-
  drivers/usb/dwc3/core.h   |  4 +++
  drivers/usb/dwc3/drd.c|  6 ++--
  4 files changed, 29 insertions(+), 12 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt 
b/Documentation/devicetree/bindings/usb/dwc3.txt
index 9946ff9ba735..56bc3f238e2d 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -37,6 +37,7 @@ Optional properties:
   - phys: from the *Generic PHY* bindings
   - phy-names: from the *Generic PHY* bindings; supported names are "usb2-phy"
or "usb3-phy".
+ - vbus-supply: Regulator handle that provides the VBUS power.
   - resets: set of phandle and reset specifier pairs
   - snps,usb2-lpm-disable: indicate if we don't want to enable USB2 HW LPM
   - snps,usb3_lpm_capable: determines if platform is USB3 LPM capable
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index edc17155cb2b..a9e58a301446 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -25,6 +25,7 @@
  #include 
  #include 
  #include 
+#include 
  #include 
  
  #include 

@@ -112,6 +113,23 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
dwc->current_dr_role = mode;
  }
  
+void dwc3_set_vbus(struct dwc3 *dwc, bool enable)

+{
+   int ret;
+
+   if (enable != dwc->vbus_reg_enabled) {
+   if (enable)
+   ret = regulator_enable(dwc->vbus_reg);
+   else
+   ret = regulator_disable(dwc->vbus_reg);
+   if (!ret)
+   dwc->vbus_reg_enabled = enable;
+   }
+
+   if (dwc->usb2_phy)
+   otg_set_vbus(dwc->usb2_phy->otg, enable);
+}
+
  static void __dwc3_set_mode(struct work_struct *work)
  {
struct dwc3 *dwc = work_to_dwc(work);
@@ -164,8 +182,7 @@ static void __dwc3_set_mode(struct work_struct *work)
if (ret) {
dev_err(dwc->dev, "failed to initialize host\n");
} else {
-   if (dwc->usb2_phy)
-   otg_set_vbus(dwc->usb2_phy->otg, true);
+   dwc3_set_vbus(dwc, true);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
}
@@ -173,8 +190,7 @@ static void __dwc3_set_mode(struct work_struct *work)
case DWC3_GCTL_PRTCAP_DEVICE:
dwc3_event_buffers_setup(dwc);
  
-		if (dwc->usb2_phy)

-   otg_set_vbus(dwc->usb2_phy->otg, false);
+   dwc3_set_vbus(dwc, false);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
  
@@ -1183,8 +1199,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)

case USB_DR_MODE_PERIPHERAL:
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
  
-		if (dwc->usb2_phy)

-   otg_set_vbus(dwc->usb2_phy->otg, false);
+   dwc3_set_vbus(dwc, false);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
  
@@ -1198,8 +1213,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)

case USB_DR_MODE_HOST:
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
  
-		if (dwc->usb2_phy)

-   otg_set_vbus(dwc->usb2_phy->otg, true);
+   dwc3_set_vbus(dwc, true);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
  
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h

index 4c171a8e215f..cee2574d7bf4 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1085,6 +1085,9 @@ struct dwc3 {
  
  	bool			phys_ready;
  
+	struct regulator	*vbus_reg;

+   boolvbus_reg_enabled;
+
struct ulpi *ulpi;
boolulpi_ready;
  
@@ -1397,6 +1400,7 @@ struct dwc3_ga

Re: [PATCH v2] usb/phy-generic: Add support for OTG VBUS supply control

2020-06-03 Thread Mike Looijmans



Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 29-05-2020 23:08, Rob Herring wrote:

On Fri, May 29, 2020 at 08:00:45AM +0200, Mike Looijmans wrote:

This enables support for VBUS on boards where the power is supplied
by a regulator. The regulator is enabled when the USB port enters
HOST mode.

Signed-off-by: Mike Looijmans 
---
v2: Added missing "return 0;" in set_vbus method

  .../devicetree/bindings/usb/usb-nop-xceiv.txt |  3 ++
  drivers/usb/phy/phy-generic.c | 46 ++-
  drivers/usb/phy/phy-generic.h |  2 +
  3 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt 
b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
index 4dc6a8ee3071..775a19fdb613 100644
--- a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
+++ b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
@@ -16,6 +16,9 @@ Optional properties:
  
  - vcc-supply: phandle to the regulator that provides power to the PHY.
  
+- vbus-supply: phandle to the regulator that provides the VBUS power for when

+  the device is in HOST mode.
+

I'm going to say no to expanding this binding...

First, there sure are a lot of controls on a NOP tranceiver.

Second, unless Vbus is supplying the PHY, then this belongs in a
connector node for which this is already supported.


Clear, I moved the implementation to the DWC3 driver and will submit a 
new patch for that.






  - reset-gpios: Should specify the GPIO for reset.
  
  - vbus-detect-gpio: should specify the GPIO detecting a VBus insertion



--
Mike Looijmans



[PATCH] usb: dwc3: Add support for VBUS power control

2020-06-03 Thread Mike Looijmans
Support VBUS power control using regulator framework. Enables the regulator
while the port is in host mode.

Signed-off-by: Mike Looijmans 
---
 .../devicetree/bindings/usb/dwc3.txt  |  1 +
 drivers/usb/dwc3/core.c   | 30 ++-
 drivers/usb/dwc3/core.h   |  4 +++
 drivers/usb/dwc3/drd.c|  6 ++--
 4 files changed, 29 insertions(+), 12 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt 
b/Documentation/devicetree/bindings/usb/dwc3.txt
index 9946ff9ba735..56bc3f238e2d 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -37,6 +37,7 @@ Optional properties:
  - phys: from the *Generic PHY* bindings
  - phy-names: from the *Generic PHY* bindings; supported names are "usb2-phy"
or "usb3-phy".
+ - vbus-supply: Regulator handle that provides the VBUS power.
  - resets: set of phandle and reset specifier pairs
  - snps,usb2-lpm-disable: indicate if we don't want to enable USB2 HW LPM
  - snps,usb3_lpm_capable: determines if platform is USB3 LPM capable
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index edc17155cb2b..a9e58a301446 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -25,6 +25,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -112,6 +113,23 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
dwc->current_dr_role = mode;
 }
 
+void dwc3_set_vbus(struct dwc3 *dwc, bool enable)
+{
+   int ret;
+
+   if (enable != dwc->vbus_reg_enabled) {
+   if (enable)
+   ret = regulator_enable(dwc->vbus_reg);
+   else
+   ret = regulator_disable(dwc->vbus_reg);
+   if (!ret)
+   dwc->vbus_reg_enabled = enable;
+   }
+
+   if (dwc->usb2_phy)
+   otg_set_vbus(dwc->usb2_phy->otg, enable);
+}
+
 static void __dwc3_set_mode(struct work_struct *work)
 {
struct dwc3 *dwc = work_to_dwc(work);
@@ -164,8 +182,7 @@ static void __dwc3_set_mode(struct work_struct *work)
if (ret) {
dev_err(dwc->dev, "failed to initialize host\n");
} else {
-   if (dwc->usb2_phy)
-   otg_set_vbus(dwc->usb2_phy->otg, true);
+   dwc3_set_vbus(dwc, true);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
}
@@ -173,8 +190,7 @@ static void __dwc3_set_mode(struct work_struct *work)
case DWC3_GCTL_PRTCAP_DEVICE:
dwc3_event_buffers_setup(dwc);
 
-   if (dwc->usb2_phy)
-   otg_set_vbus(dwc->usb2_phy->otg, false);
+   dwc3_set_vbus(dwc, false);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
 
@@ -1183,8 +1199,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
case USB_DR_MODE_PERIPHERAL:
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
 
-   if (dwc->usb2_phy)
-   otg_set_vbus(dwc->usb2_phy->otg, false);
+   dwc3_set_vbus(dwc, false);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
 
@@ -1198,8 +1213,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
case USB_DR_MODE_HOST:
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
 
-   if (dwc->usb2_phy)
-   otg_set_vbus(dwc->usb2_phy->otg, true);
+   dwc3_set_vbus(dwc, true);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
 
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 4c171a8e215f..cee2574d7bf4 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1085,6 +1085,9 @@ struct dwc3 {
 
boolphys_ready;
 
+   struct regulator*vbus_reg;
+   boolvbus_reg_enabled;
+
struct ulpi *ulpi;
boolulpi_ready;
 
@@ -1397,6 +1400,7 @@ struct dwc3_gadget_ep_cmd_params {
 
 /* prototypes */
 void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode);
+void dwc3_set_vbus(struct dwc3 *dwc, bool enable);
 void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
 u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);
 
diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c
index 7db1ffc92bbd..45fdec2d128d 100644
--- a/drivers/usb/dwc3/drd.c
+++ b/drivers/us

[PATCH v2] usb/phy-generic: Add support for OTG VBUS supply control

2020-05-29 Thread Mike Looijmans
This enables support for VBUS on boards where the power is supplied
by a regulator. The regulator is enabled when the USB port enters
HOST mode.

Signed-off-by: Mike Looijmans 
---
v2: Added missing "return 0;" in set_vbus method

 .../devicetree/bindings/usb/usb-nop-xceiv.txt |  3 ++
 drivers/usb/phy/phy-generic.c | 46 ++-
 drivers/usb/phy/phy-generic.h |  2 +
 3 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt 
b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
index 4dc6a8ee3071..775a19fdb613 100644
--- a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
+++ b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
@@ -16,6 +16,9 @@ Optional properties:
 
 - vcc-supply: phandle to the regulator that provides power to the PHY.
 
+- vbus-supply: phandle to the regulator that provides the VBUS power for when
+  the device is in HOST mode.
+
 - reset-gpios: Should specify the GPIO for reset.
 
 - vbus-detect-gpio: should specify the GPIO detecting a VBus insertion
diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
index 661a229c105d..69bf39510e27 100644
--- a/drivers/usb/phy/phy-generic.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -203,13 +203,45 @@ static int nop_set_host(struct usb_otg *otg, struct 
usb_bus *host)
return 0;
 }
 
+static int nop_set_vbus(struct usb_otg *otg, bool enabled)
+{
+   struct usb_phy_generic *nop;
+   int ret;
+
+   if (!otg)
+   return -ENODEV;
+
+   nop = container_of(otg->usb_phy, struct usb_phy_generic, phy);
+
+   if (!nop->vbus_reg)
+   return 0;
+
+   if (enabled) {
+   if (nop->vbus_reg_enabled)
+   return 0;
+   ret = regulator_enable(nop->vbus_reg);
+   if (ret < 0)
+   return ret;
+   nop->vbus_reg_enabled = true;
+   } else {
+   if (!nop->vbus_reg_enabled)
+   return 0;
+   ret = regulator_disable(nop->vbus_reg);
+   if (ret < 0)
+   return ret;
+   nop->vbus_reg_enabled = false;
+   }
+
+   return 0;
+}
+
 int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop)
 {
enum usb_phy_type type = USB_PHY_TYPE_USB2;
int err = 0;
 
u32 clk_rate = 0;
-   bool needs_vcc = false, needs_clk = false;
+   bool needs_vcc = false, needs_clk = false, needs_vbus = false;
 
if (dev->of_node) {
struct device_node *node = dev->of_node;
@@ -219,6 +251,7 @@ int usb_phy_gen_create_phy(struct device *dev, struct 
usb_phy_generic *nop)
 
needs_vcc = of_property_read_bool(node, "vcc-supply");
needs_clk = of_property_read_bool(node, "clocks");
+   needs_vbus = of_property_read_bool(node, "vbus-supply");
}
nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
   GPIOD_ASIS);
@@ -268,6 +301,16 @@ int usb_phy_gen_create_phy(struct device *dev, struct 
usb_phy_generic *nop)
return -EPROBE_DEFER;
}
 
+   nop->vbus_reg = devm_regulator_get(dev, "vbus");
+   if (IS_ERR(nop->vbus_reg)) {
+   dev_dbg(dev, "Error getting vbus regulator: %ld\n",
+   PTR_ERR(nop->vbus_reg));
+   if (needs_vbus)
+   return -EPROBE_DEFER;
+
+   nop->vbus_reg = NULL;
+   }
+
nop->dev= dev;
nop->phy.dev= nop->dev;
nop->phy.label  = "nop-xceiv";
@@ -278,6 +321,7 @@ int usb_phy_gen_create_phy(struct device *dev, struct 
usb_phy_generic *nop)
nop->phy.otg->usb_phy   = >phy;
nop->phy.otg->set_host  = nop_set_host;
nop->phy.otg->set_peripheral= nop_set_peripheral;
+   nop->phy.otg->set_vbus  = nop_set_vbus;
 
return 0;
 }
diff --git a/drivers/usb/phy/phy-generic.h b/drivers/usb/phy/phy-generic.h
index 7ee80211a688..a3663639ea1e 100644
--- a/drivers/usb/phy/phy-generic.h
+++ b/drivers/usb/phy/phy-generic.h
@@ -14,7 +14,9 @@ struct usb_phy_generic {
struct gpio_desc *gpiod_reset;
struct gpio_desc *gpiod_vbus;
struct regulator *vbus_draw;
+   struct regulator *vbus_reg;
bool vbus_draw_enabled;
+   bool vbus_reg_enabled;
unsigned long mA;
unsigned int vbus;
 };
-- 
2.17.1



Re: [PATCH] usb/phy-generic: Add support for OTG VBUS supply control

2020-05-28 Thread Mike Looijmans



Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijm...@topicproducts.com
W: www.topicproducts.com

Please consider the environment before printing this e-mail
On 28-05-2020 13:20, Peter Chen wrote:

On 20-05-26 16:50:51, Mike Looijmans wrote:

This enables support for VBUS on boards where the power is supplied
by a regulator. The regulator is enabled when the USB port enters
HOST mode.


Why you don't do this at your host controller driver?


That was my first thought too, but it made more sense to do it here. 
It's about how things are connected on the board, and not about the 
controller. Also makes for a consistent devicetree when using different 
SOCs on the same carrier board.


I already needed this driver to properly reset the USB phy, which the 
controller driver also did not do. So it made sense to add the vbus 
power control to this driver too.


If you have a strong preference for the controller driver, I can move 
this to the DWC3 driver which happens to be the controller for the 
latest batch of SOMs.





Peter

Signed-off-by: Mike Looijmans 
---
  .../devicetree/bindings/usb/usb-nop-xceiv.txt |  3 ++
  drivers/usb/phy/phy-generic.c | 44 ++-
  drivers/usb/phy/phy-generic.h |  2 +
  3 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt 
b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
index 4dc6a8ee3071..775a19fdb613 100644
--- a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
+++ b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
@@ -16,6 +16,9 @@ Optional properties:
  
  - vcc-supply: phandle to the regulator that provides power to the PHY.
  
+- vbus-supply: phandle to the regulator that provides the VBUS power for when

+  the device is in HOST mode.
+
  - reset-gpios: Should specify the GPIO for reset.
  
  - vbus-detect-gpio: should specify the GPIO detecting a VBus insertion

diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
index 661a229c105d..ebfb90764511 100644
--- a/drivers/usb/phy/phy-generic.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -203,13 +203,43 @@ static int nop_set_host(struct usb_otg *otg, struct 
usb_bus *host)
return 0;
  }
  
+static int nop_set_vbus(struct usb_otg *otg, bool enabled)

+{
+   struct usb_phy_generic *nop;
+   int ret;
+
+   if (!otg)
+   return -ENODEV;
+
+   nop = container_of(otg->usb_phy, struct usb_phy_generic, phy);
+
+   if (!nop->vbus_reg)
+   return 0;
+
+   if (enabled) {
+   if (nop->vbus_reg_enabled)
+   return 0;
+   ret = regulator_enable(nop->vbus_reg);
+   if (ret < 0)
+   return ret;
+   nop->vbus_reg_enabled = true;
+   } else {
+   if (!nop->vbus_reg_enabled)
+   return 0;
+   ret = regulator_disable(nop->vbus_reg);
+   if (ret < 0)
+   return ret;
+   nop->vbus_reg_enabled = false;
+   }

There's a "return 0" missing here, will fix that in v2

+}
+
  int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop)
  {
enum usb_phy_type type = USB_PHY_TYPE_USB2;
int err = 0;
  
  	u32 clk_rate = 0;

-   bool needs_vcc = false, needs_clk = false;
+   bool needs_vcc = false, needs_clk = false, needs_vbus = false;
  
  	if (dev->of_node) {

struct device_node *node = dev->of_node;
@@ -219,6 +249,7 @@ int usb_phy_gen_create_phy(struct device *dev, struct 
usb_phy_generic *nop)
  
  		needs_vcc = of_property_read_bool(node, "vcc-supply");

needs_clk = of_property_read_bool(node, "clocks");
+   needs_vbus = of_property_read_bool(node, "vbus-supply");
}
nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
   GPIOD_ASIS);
@@ -268,6 +299,16 @@ int usb_phy_gen_create_phy(struct device *dev, struct 
usb_phy_generic *nop)
return -EPROBE_DEFER;
}
  
+	nop->vbus_reg = devm_regulator_get(dev, "vbus");

+   if (IS_ERR(nop->vbus_reg)) {
+   dev_dbg(dev, "Error getting vbus regulator: %ld\n",
+   PTR_ERR(nop->vbus_reg));
+   if (needs_vbus)
+   return -EPROBE_DEFER;
+
+   nop->vbus_reg = NULL;
+   }
+
nop->dev = dev;
nop->phy.dev = nop->dev;
nop->phy.label   = "nop-xceiv";
@@ -278,6 +319,7 @@ int usb_phy_gen_create_phy(struct device *dev, struct 
usb_phy

[PATCH] usb/phy-generic: Add support for OTG VBUS supply control

2020-05-26 Thread Mike Looijmans
This enables support for VBUS on boards where the power is supplied
by a regulator. The regulator is enabled when the USB port enters
HOST mode.

Signed-off-by: Mike Looijmans 
---
 .../devicetree/bindings/usb/usb-nop-xceiv.txt |  3 ++
 drivers/usb/phy/phy-generic.c | 44 ++-
 drivers/usb/phy/phy-generic.h |  2 +
 3 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt 
b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
index 4dc6a8ee3071..775a19fdb613 100644
--- a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
+++ b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
@@ -16,6 +16,9 @@ Optional properties:
 
 - vcc-supply: phandle to the regulator that provides power to the PHY.
 
+- vbus-supply: phandle to the regulator that provides the VBUS power for when
+  the device is in HOST mode.
+
 - reset-gpios: Should specify the GPIO for reset.
 
 - vbus-detect-gpio: should specify the GPIO detecting a VBus insertion
diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
index 661a229c105d..ebfb90764511 100644
--- a/drivers/usb/phy/phy-generic.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -203,13 +203,43 @@ static int nop_set_host(struct usb_otg *otg, struct 
usb_bus *host)
return 0;
 }
 
+static int nop_set_vbus(struct usb_otg *otg, bool enabled)
+{
+   struct usb_phy_generic *nop;
+   int ret;
+
+   if (!otg)
+   return -ENODEV;
+
+   nop = container_of(otg->usb_phy, struct usb_phy_generic, phy);
+
+   if (!nop->vbus_reg)
+   return 0;
+
+   if (enabled) {
+   if (nop->vbus_reg_enabled)
+   return 0;
+   ret = regulator_enable(nop->vbus_reg);
+   if (ret < 0)
+   return ret;
+   nop->vbus_reg_enabled = true;
+   } else {
+   if (!nop->vbus_reg_enabled)
+   return 0;
+   ret = regulator_disable(nop->vbus_reg);
+   if (ret < 0)
+   return ret;
+   nop->vbus_reg_enabled = false;
+   }
+}
+
 int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop)
 {
enum usb_phy_type type = USB_PHY_TYPE_USB2;
int err = 0;
 
u32 clk_rate = 0;
-   bool needs_vcc = false, needs_clk = false;
+   bool needs_vcc = false, needs_clk = false, needs_vbus = false;
 
if (dev->of_node) {
struct device_node *node = dev->of_node;
@@ -219,6 +249,7 @@ int usb_phy_gen_create_phy(struct device *dev, struct 
usb_phy_generic *nop)
 
needs_vcc = of_property_read_bool(node, "vcc-supply");
needs_clk = of_property_read_bool(node, "clocks");
+   needs_vbus = of_property_read_bool(node, "vbus-supply");
}
nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
   GPIOD_ASIS);
@@ -268,6 +299,16 @@ int usb_phy_gen_create_phy(struct device *dev, struct 
usb_phy_generic *nop)
return -EPROBE_DEFER;
}
 
+   nop->vbus_reg = devm_regulator_get(dev, "vbus");
+   if (IS_ERR(nop->vbus_reg)) {
+   dev_dbg(dev, "Error getting vbus regulator: %ld\n",
+   PTR_ERR(nop->vbus_reg));
+   if (needs_vbus)
+   return -EPROBE_DEFER;
+
+   nop->vbus_reg = NULL;
+   }
+
nop->dev= dev;
nop->phy.dev= nop->dev;
nop->phy.label  = "nop-xceiv";
@@ -278,6 +319,7 @@ int usb_phy_gen_create_phy(struct device *dev, struct 
usb_phy_generic *nop)
nop->phy.otg->usb_phy   = >phy;
nop->phy.otg->set_host  = nop_set_host;
nop->phy.otg->set_peripheral= nop_set_peripheral;
+   nop->phy.otg->set_vbus  = nop_set_vbus;
 
return 0;
 }
diff --git a/drivers/usb/phy/phy-generic.h b/drivers/usb/phy/phy-generic.h
index 7ee80211a688..a3663639ea1e 100644
--- a/drivers/usb/phy/phy-generic.h
+++ b/drivers/usb/phy/phy-generic.h
@@ -14,7 +14,9 @@ struct usb_phy_generic {
struct gpio_desc *gpiod_reset;
struct gpio_desc *gpiod_vbus;
struct regulator *vbus_draw;
+   struct regulator *vbus_reg;
bool vbus_draw_enabled;
+   bool vbus_reg_enabled;
unsigned long mA;
unsigned int vbus;
 };
-- 
2.17.1



[PATCH] clk: clk-si5341: Add support for the Si5345 series

2020-05-07 Thread Mike Looijmans
Add support for the Si5342, Si5344 and Si5345 chips. These are equivalent
to the Si5341 family, but with more clock input options (which are not
supported yet by this driver).

Signed-off-by: Mike Looijmans 
---
 .../bindings/clock/silabs,si5341.txt  | 11 ++-
 drivers/clk/clk-si5341.c  | 69 +--
 2 files changed, 74 insertions(+), 6 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/silabs,si5341.txt 
b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
index a70c333e4cd4..504cce3abe46 100644
--- a/Documentation/devicetree/bindings/clock/silabs,si5341.txt
+++ b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
@@ -1,15 +1,21 @@
-Binding for Silicon Labs Si5341 and Si5340 programmable i2c clock generator.
+Binding for Silicon Labs Si5340, Si5341 Si5342, Si5344 and Si5345 programmable
+i2c clock generator.
 
 Reference
 [1] Si5341 Data Sheet
 
https://www.silabs.com/documents/public/data-sheets/Si5341-40-D-DataSheet.pdf
 [2] Si5341 Reference Manual
 
https://www.silabs.com/documents/public/reference-manuals/Si5341-40-D-RM.pdf
+[3] Si5345 Reference Manual
+
https://www.silabs.com/documents/public/reference-manuals/Si5345-44-42-D-RM.pdf
 
 The Si5341 and Si5340 are programmable i2c clock generators with up to 10 
output
 clocks. The chip contains a PLL that sources 5 (or 4) multisynth clocks, which
 in turn can be directed to any of the 10 (or 4) outputs through a divider.
 The internal structure of the clock generators can be found in [2].
+The Si5345 is similar to the Si5341 with the addition of fractional input
+dividers and automatic input selection, as described in [3].
+The Si5342 and Si5344 are smaller versions of the Si5345, with 2 or 4 outputs.
 
 The driver can be used in "as is" mode, reading the current settings from the
 chip at boot, in case you have a (pre-)programmed device. If the PLL is not
@@ -28,6 +34,9 @@ Required properties:
 - compatible: shall be one of the following:
"silabs,si5340" - Si5340 A/B/C/D
"silabs,si5341" - Si5341 A/B/C/D
+   "silabs,si5342" - Si5342 A/B/C/D
+   "silabs,si5344" - Si5344 A/B/C/D
+   "silabs,si5345" - Si5345 A/B/C/D
 - reg: i2c device address, usually 0x74
 - #clock-cells: from common clock binding; shall be set to 2.
The first value is "0" for outputs, "1" for synthesizers.
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index 3c228b018116..3d7acab9d280 100644
--- a/drivers/clk/clk-si5341.c
+++ b/drivers/clk/clk-si5341.c
@@ -1,8 +1,14 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Driver for Silicon Labs Si5341/Si5340 Clock generator
+ * Driver for Silicon Labs Si5340, Si5341, Si5342, Si5344 and Si5345
  * Copyright (C) 2019 Topic Embedded Products
  * Author: Mike Looijmans 
+ *
+ * The Si5341 has 10 outputs and 5 synthesizers.
+ * The Si5340 is a smaller version of the Si5341 with only 4 outputs.
+ * The Si5345 is similar to the Si5341, with the addition of fractional input
+ * dividers and automatic input selection.
+ * The Si5342 and Si5344 are smaller versions of the Si5345.
  */
 
 #include 
@@ -18,11 +24,17 @@
 
 #define SI5341_NUM_INPUTS 4
 
-#define SI5341_MAX_NUM_OUTPUTS 10
 #define SI5340_MAX_NUM_OUTPUTS 4
+#define SI5341_MAX_NUM_OUTPUTS 10
+#define SI5342_MAX_NUM_OUTPUTS 2
+#define SI5344_MAX_NUM_OUTPUTS 4
+#define SI5345_MAX_NUM_OUTPUTS 10
 
-#define SI5341_NUM_SYNTH 5
 #define SI5340_NUM_SYNTH 4
+#define SI5341_NUM_SYNTH 5
+#define SI5342_NUM_SYNTH 2
+#define SI5344_NUM_SYNTH 4
+#define SI5345_NUM_SYNTH 5
 
 /* Range of the synthesizer fractional divider */
 #define SI5341_SYNTH_N_MIN 10
@@ -65,6 +77,7 @@ struct clk_si5341 {
u64 freq_vco; /* 13500–14256 MHz */
u8 num_outputs;
u8 num_synth;
+   u16 chip_id;
 };
 #define to_clk_si5341(_hw) container_of(_hw, struct clk_si5341, hw)
 
@@ -142,6 +155,7 @@ static const char * const si5341_input_clock_names[] = {
 };
 
 /* Output configuration registers 0..9 are not quite logically organized */
+/* Also for si5345 */
 static const u16 si5341_reg_output_offset[] = {
0x0108,
0x010D,
@@ -155,6 +169,7 @@ static const u16 si5341_reg_output_offset[] = {
0x013A,
 };
 
+/* for si5340, si5342 and si5344 */
 static const u16 si5340_reg_output_offset[] = {
0x0112,
0x0117,
@@ -974,12 +989,32 @@ static int si5341_probe_chip_id(struct clk_si5341 *data)
data->reg_output_offset = si5341_reg_output_offset;
data->reg_rdiv_offset = si5341_reg_rdiv_offset;
break;
+   case 0x5342:
+   data->num_outputs = SI5342_MAX_NUM_OUTPUTS;
+   data->num_synth = SI5342_NUM_SYNTH;
+   data->reg_output_offset = si5340_reg_output_offset;
+   data->reg_rdiv_offset = si5340_reg_rdiv_offset;
+   break;
+   case 0

Re: [PATCH][next] clk: Si5341/Si5340: remove redundant assignment to n_den

2019-07-23 Thread Mike Looijmans
Good catch, thanks. You have my

Acked-by: Mike Looijmans 


On 22-07-19 23:24, Stephen Boyd wrote:
> Please Cc authors of drivers so they can ack/review.
> 
> Adding Mike to take a look.
> 
> Quoting Colin King (2019-07-01 09:50:20)
>> From: Colin Ian King 
>>
>> The variable n_den is initialized however that value is never read
>> as n_den is re-assigned a little later in the two paths of a
>> following if-statement.  Remove the redundant assignment.
>>
>> Addresses-Coverity: ("Unused value")
>> Signed-off-by: Colin Ian King 
>> ---
>>   drivers/clk/clk-si5341.c | 1 -
>>   1 file changed, 1 deletion(-)
>>
>> diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
>> index 72424eb7e5f8..6e780c2a9e6b 100644
>> --- a/drivers/clk/clk-si5341.c
>> +++ b/drivers/clk/clk-si5341.c
>> @@ -547,7 +547,6 @@ static int si5341_synth_clk_set_rate(struct clk_hw *hw, 
>> unsigned long rate,
>>  bool is_integer;
>>   
>>  n_num = synth->data->freq_vco;
>> -   n_den = rate;
>>   
>>  /* see if there's an integer solution */
>>  r = do_div(n_num, rate);


-- 
Mike Looijmans


Re: [PATCH v3] clk: Add Si5341/Si5340 driver

2019-06-28 Thread Mike Looijmans
On 27-06-19 23:06, Stephen Boyd wrote:
> Quoting Mike Looijmans (2019-05-17 06:23:52)
>> Adds a driver for the Si5341 and Si5340 chips. The driver does not fully
>> support all features of these chips, but allows the chip to be used
>> without any support from the "clockbuilder pro" software.
>>
>> If the chip is preprogrammed, that is, you bought one with some defaults
>> burned in, or you programmed the NVM in some way, the driver will just
>> take over the current settings and only change them on demand. Otherwise
>> the input must be a fixed XTAL in its most basic configuration (no
>> predividers, no feedback, etc.).
>>
>> The driver supports dynamic changes of multisynth, output dividers and
>> enabling or powering down outputs and multisynths.
>>
>> Signed-off-by: Mike Looijmans 
>> ---
> 
> Applied to clk-next + some fixes. I'm not super thrilled about the kHz
> thing but we don't have a solution for it right now so might as well
> come back to it later.

Thanks for the fixes. And I'm not exactly proud of that kHz part either.

While thinking about a solution, I've also had a use case for less than 1Hz 
frequency adjustment (a video clock to "follow" another one). These clock 
generators allow for ridiculous ranges and accuracy, you can request it to 
generate a 2.0005 Hz clock.


> diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
> index 1a310835b53c..72424eb7e5f8 100644
> --- a/drivers/clk/clk-si5341.c
> +++ b/drivers/clk/clk-si5341.c
> @@ -374,7 +374,7 @@ static unsigned long si5341_clk_recalc_rate(struct clk_hw 
> *hw,
>*/
>   shift = 0;
>   res = m_num;
> - while (res & 0x) {
> + while (res & 0xULL) {
>   ++shift;
>   res >>= 1;
>   }
> @@ -921,7 +921,7 @@ static int si5341_write_multiple(struct clk_si5341 *data,
>   return 0;
>   }
>   
> -const struct si5341_reg_default si5341_preamble[] = {
> +static const struct si5341_reg_default si5341_preamble[] = {
>   { 0x0B25, 0x00 },
>   { 0x0502, 0x01 },
>   { 0x0505, 0x03 },
> @@ -994,7 +994,7 @@ static const struct regmap_range 
> si5341_regmap_volatile_range[] = {
>   regmap_reg_range(SI5341_SYNTH_N_UPD(4), SI5341_SYNTH_N_UPD(4)),
>   };
>   
> -const struct regmap_access_table si5341_regmap_volatile = {
> +static const struct regmap_access_table si5341_regmap_volatile = {
>   .yes_ranges = si5341_regmap_volatile_range,
>   .n_yes_ranges = ARRAY_SIZE(si5341_regmap_volatile_range),
>   };
> @@ -1016,7 +1016,6 @@ static const struct regmap_config si5341_regmap_config 
> = {
>   .reg_bits = 8,
>   .val_bits = 8,
>   .cache_type = REGCACHE_RBTREE,
> - .max_register = 0,
>   .ranges = si5341_regmap_ranges,
>   .num_ranges = ARRAY_SIZE(si5341_regmap_ranges),
>   .max_register = SI5341_REGISTER_MAX,
> @@ -1328,7 +1327,7 @@ MODULE_DEVICE_TABLE(i2c, si5341_id);
>   static const struct of_device_id clk_si5341_of_match[] = {
>   { .compatible = "silabs,si5340" },
>   { .compatible = "silabs,si5341" },
> - { },
> + { }
>   };
>   MODULE_DEVICE_TABLE(of, clk_si5341_of_match);
>   
> 



Re: [PATCH] dt-bindings: Add silabs,si5341

2019-06-27 Thread Mike Looijmans
On 26-06-19 23:24, Stephen Boyd wrote:
> Sorry, I'm getting through my inbox pile and saw this one.
> 
> Quoting Mike Looijmans (2019-04-30 22:46:55)
>> On 30-04-19 02:17, Stephen Boyd wrote:
>>>
>>> Why can't that driver call clk_prepare_enable()? Is there some sort of
>>> assumption that this clk will always be enabled and not have a driver
>>> that configures the rate and gates/ungates it?
>>
>> Not only clk_prepare_enable(), but the driver could also call clk_set_rate()
>> and clk_set_parent() and the likes, but it doesn't, so that's why there is
>> "assigned-clocks" right?
>>
>> There are multiple scenario's, similar to why regulators also have properties
>> like these.
>>
>> - The clock is related to hardware that the kernel is not aware of.
>> - The clock is for a driver that isn't aware of its clock requirements. It
>> might be an extra clock for an FPGA implemented controller that mimics
>> existing hardware.
> 
> Are these hypothetical scenarios or actual scenarios you need to
> support?

Actual scenario's.

Clocks are required for FPGA logic, and a some of those do not involve 
software drivers at all.

The GTR transceivers on the Xilinx ZynqMP chips use these clocks for SATA and 
PCIe, but the driver implementation from Xilinx for these is far from mature, 
for example it passes the clock frequency as a PHY parameter and isn't even 
aware of the clk framework at the moment. Xilinx hasn't even attempted 
submitting this 3 year old driver to mainline.


>> I'd also consider patching "assigned-clocks" to call "clk_prepare_enable()",
>> would that make sense, or is it intentional that assigned-clocks doesn't do 
>> that?
>>
> 
> It's intentional that assigned-clocks doesn't really do anything besides
> setup the list of clks to operate on with the rate or parent settings
> specified in other properties. We would need to add another property
> indicating which clks we want to mark as 'critical' or 'always-on'.
> 
> There have been prior discussions where we had developers want to mark
> clks with the CLK_IS_CRITICAL flag from DT, but we felt like that was
> putting SoC level details into the DT. While that was correct for SoC
> specific clk drivers, I can see board designs where it's configurable
> and we want to express that a board has some clks that must be enabled
> early on and left enabled forever because the hardware engineer has
> design the board that way. In this case, marking the clk with the
> CLK_IS_CRITICAL flag needs to be done from DT.
> 
> In fact, we pretty much already have support for this with
> of_clk_detect_critical(). Maybe we should re-use that binding with
> 'clock-critical' to let clk providers indicate that they have some clks
> that should be marked critical once they're registered. We could
> probably add another property too that indicates certain clks are
> enabled out of the bootloader, similar to the regulator-boot-on
> property, but where it takes a clock-cells wide list for the provider
> the property is inside of.
> 
> We need to be careful though and make sure that clk drivers don't start
> putting everything in DT. In your example, it sounds like you have a
> consumer driver that wants to make sure the clk is prepared or enabled
> when the consumer probes. In this case the prepare/enable calls should
> be put directly into the consumer driver so it can manage the clk state.
> For the case of rates and parents, it's essentially a oneshot
> configuration of the rate or the parents of a clk. We don't need to
> "undo" the configuration when the device driver is removed. For prepare
> and enable though, we typically want to disable clks when the hardware
> is not in use to save power. Adding a property to DT should only be done
> to indicate a clk must always be on in this board configuration, not to
> avoid calling clk_prepare_enable() in the driver probe.
> 
> To put it another way, I'm looking to describe how the board is designed
> and to indicate that certain clks are always enabled at power on or are
> enabled by the bootloader. Configuration has it's place too, just that
> configuration is a oneshot sort of thing that never needs to change at
> runtime.
> 

I can see where you going with this, and yes, we definitely should promote 
that drivers should take care of their clock (enable) requirements.

For the case of 'clock-critical', that would serve the purpose quite well 
indeed. It does add the risk of people sprinkling that all over the devicetree.

Short term, I guess the best thing to do here is to remove the "always-on" 
property from my patch.

I'll put the "clock-critical" idea on my list of generic clock patches to 
sneak in on other budgets, it'll be right behind "allow sub-1Hz or fractional 
clock rate accuracy" (yes I actually have a use case for that) and "allow 
frequencies over 4GHz" (the 14GHz clock in the Si5341 luckily isn't available 
on the outside so I can cheat)...


[PATCH v3] clk: Add Si5341/Si5340 driver

2019-05-17 Thread Mike Looijmans
Adds a driver for the Si5341 and Si5340 chips. The driver does not fully
support all features of these chips, but allows the chip to be used
without any support from the "clockbuilder pro" software.

If the chip is preprogrammed, that is, you bought one with some defaults
burned in, or you programmed the NVM in some way, the driver will just
take over the current settings and only change them on demand. Otherwise
the input must be a fixed XTAL in its most basic configuration (no
predividers, no feedback, etc.).

The driver supports dynamic changes of multisynth, output dividers and
enabling or powering down outputs and multisynths.

Signed-off-by: Mike Looijmans 
---
v2: Fix setting a Rx_DIV value of 2
v3: Rework after maintainer review
Style changes (whitespace, brackets)
Use unaligned.h
Integrate assigned-clock(-parent)s support
Remove most dev_dbg calls

 drivers/clk/Kconfig  |   11 +
 drivers/clk/Makefile |1 +
 drivers/clk/clk-si5341.c | 1347 ++
 3 files changed, 1359 insertions(+)
 create mode 100644 drivers/clk/clk-si5341.c

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index e705aab9e38b..0edd9ae3c89b 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -90,6 +90,17 @@ config COMMON_CLK_SCPI
  This driver uses SCPI Message Protocol to interact with the
  firmware providing all the clock controls.
 
+config COMMON_CLK_SI5341
+   tristate "Clock driver for SiLabs 5341 and 5340 A/B/C/D devices"
+   depends on I2C
+   select REGMAP_I2C
+   help
+ This driver supports Silicon Labs Si5341 and Si5340 programmable clock
+ generators. Not all features of these chips are currently supported
+ by the driver, in particular it only supports XTAL input. The chip can
+ be pre-programmed to support other configurations and features not yet
+ implemented in the driver.
+
 config COMMON_CLK_SI5351
tristate "Clock driver for SiLabs 5351A/B/C"
depends on I2C
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 1db133652f0c..4a7aa4a01fef 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_COMMON_CLK_HI655X)   += clk-hi655x.o
 obj-$(CONFIG_COMMON_CLK_S2MPS11)   += clk-s2mps11.o
 obj-$(CONFIG_COMMON_CLK_SCMI)   += clk-scmi.o
 obj-$(CONFIG_COMMON_CLK_SCPI)   += clk-scpi.o
+obj-$(CONFIG_COMMON_CLK_SI5341)+= clk-si5341.o
 obj-$(CONFIG_COMMON_CLK_SI5351)+= clk-si5351.o
 obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o
 obj-$(CONFIG_COMMON_CLK_SI544) += clk-si544.o
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
new file mode 100644
index ..fabbd2aec6f1
--- /dev/null
+++ b/drivers/clk/clk-si5341.c
@@ -0,0 +1,1347 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Silicon Labs Si5341/Si5340 Clock generator
+ * Copyright (C) 2019 Topic Embedded Products
+ * Author: Mike Looijmans 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define SI5341_MAX_NUM_OUTPUTS 10
+#define SI5340_MAX_NUM_OUTPUTS 4
+
+#define SI5341_NUM_SYNTH 5
+#define SI5340_NUM_SYNTH 4
+
+/* Range of the synthesizer fractional divider */
+#define SI5341_SYNTH_N_MIN 10
+#define SI5341_SYNTH_N_MAX 4095
+
+/* The chip can get its input clock from 3 input pins or an XTAL */
+
+/* There is one PLL running at 13500–14256 MHz */
+#define SI5341_PLL_VCO_MIN 135ull
+#define SI5341_PLL_VCO_MAX 1425600ull
+
+/* The 5 frequency synthesizers obtain their input from the PLL */
+struct clk_si5341_synth {
+   struct clk_hw hw;
+   struct clk_si5341 *data;
+   u8 index;
+};
+#define to_clk_si5341_synth(_hw) \
+   container_of(_hw, struct clk_si5341_synth, hw)
+
+/* The output stages can be connected to any synth (full mux) */
+struct clk_si5341_output {
+   struct clk_hw hw;
+   struct clk_si5341 *data;
+   u8 index;
+};
+#define to_clk_si5341_output(_hw) \
+   container_of(_hw, struct clk_si5341_output, hw)
+
+struct clk_si5341 {
+   struct clk_hw hw;
+   struct regmap *regmap;
+   struct i2c_client *i2c_client;
+   struct clk_si5341_synth synth[SI5341_NUM_SYNTH];
+   struct clk_si5341_output clk[SI5341_MAX_NUM_OUTPUTS];
+   struct clk *pxtal;
+   const char *pxtal_name;
+   const u16 *reg_output_offset;
+   const u16 *reg_rdiv_offset;
+   u64 freq_vco; /* 13500–14256 MHz */
+   u8 num_outputs;
+   u8 num_synth;
+};
+#define to_clk_si5341(_hw) container_of(_hw, struct clk_si5341, hw)
+
+struct clk_si5341_output_config {
+   u8 out_format_drv_bits;
+   u8 out_cm_ampl_bits;
+   bool synth_master;
+   bool always_on;
+};
+
+#define SI5341_PAGE0x0001
+#define SI5341_PN_BASE 0x0002
+#define SI5341_DEVICE_REV 

[PATCH v3] dt-bindings: clock: Add silabs,si5341

2019-05-17 Thread Mike Looijmans
Adds the devicetree bindings for the Si5341 and Si5340 chips from
Silicon Labs. These are multiple-input multiple-output clock
synthesizers.

Signed-off-by: Mike Looijmans 

---
v3: Remove synthesizers child nodes
Fix typo
v2: Add data sheet reference.
Restructured to enable use of "assigned-clock*" properties to set
up both outputs and internal synthesizers.
Nicer indentation.
Updated subject line and body of commit message.

 .../bindings/clock/silabs,si5341.txt  | 162 ++
 1 file changed, 162 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/silabs,si5341.txt

diff --git a/Documentation/devicetree/bindings/clock/silabs,si5341.txt 
b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
new file mode 100644
index ..a70c333e4cd4
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
@@ -0,0 +1,162 @@
+Binding for Silicon Labs Si5341 and Si5340 programmable i2c clock generator.
+
+Reference
+[1] Si5341 Data Sheet
+
https://www.silabs.com/documents/public/data-sheets/Si5341-40-D-DataSheet.pdf
+[2] Si5341 Reference Manual
+
https://www.silabs.com/documents/public/reference-manuals/Si5341-40-D-RM.pdf
+
+The Si5341 and Si5340 are programmable i2c clock generators with up to 10 
output
+clocks. The chip contains a PLL that sources 5 (or 4) multisynth clocks, which
+in turn can be directed to any of the 10 (or 4) outputs through a divider.
+The internal structure of the clock generators can be found in [2].
+
+The driver can be used in "as is" mode, reading the current settings from the
+chip at boot, in case you have a (pre-)programmed device. If the PLL is not
+configured when the driver probes, it assumes the driver must fully initialize
+it.
+
+The device type, speed grade and revision are determined runtime by probing.
+
+The driver currently only supports XTAL input mode, and does not support any
+fancy input configurations. They can still be programmed into the chip and
+the driver will leave them "as is".
+
+==I2C device node==
+
+Required properties:
+- compatible: shall be one of the following:
+   "silabs,si5340" - Si5340 A/B/C/D
+   "silabs,si5341" - Si5341 A/B/C/D
+- reg: i2c device address, usually 0x74
+- #clock-cells: from common clock binding; shall be set to 2.
+   The first value is "0" for outputs, "1" for synthesizers.
+   The second value is the output or synthesizer index.
+- clocks: from common clock binding; list of parent clock  handles,
+   corresponding to inputs. Use a fixed clock for the "xtal" input.
+   At least one must be present.
+- clock-names: One of: "xtal", "in0", "in1", "in2"
+- vdd-supply: Regulator node for VDD
+
+Optional properties:
+- vdda-supply: Regulator node for VDDA
+- vdds-supply: Regulator node for VDDS
+- silabs,pll-m-num, silabs,pll-m-den: Numerator and denominator for PLL
+  feedback divider. Must be such that the PLL output is in the valid range. For
+  example, to create 14GHz from a 48MHz xtal, use m-num=14000 and m-den=48. 
Only
+  the fraction matters, using 3500 and 12 will deliver the exact same result.
+  If these are not specified, and the PLL is not yet programmed when the driver
+  probes, the PLL will be set to 14GHz.
+- silabs,reprogram: When present, the driver will always assume the device must
+  be initialized, and always performs the soft-reset routine. Since this will
+  temporarily stop all output clocks, don't do this if the chip is generating
+  the CPU clock for example.
+- interrupts: Interrupt for INTRb pin.
+- #address-cells: shall be set to 1.
+- #size-cells: shall be set to 0.
+
+
+== Child nodes: Outputs ==
+
+The child nodes list the output clocks.
+
+Each of the clock outputs can be overwritten individually by using a child 
node.
+If a child node for a clock output is not set, the configuration remains
+unchanged.
+
+Required child node properties:
+- reg: number of clock output.
+
+Optional child node properties:
+- vdd-supply: Regulator node for VDD for this output. The driver selects 
default
+   values for common-mode and amplitude based on the voltage.
+- silabs,format: Output format, one of:
+   1 = differential (defaults to LVDS levels)
+   2 = low-power (defaults to HCSL levels)
+   4 = LVCMOS
+- silabs,common-mode: Manually override output common mode, see [2] for values
+- silabs,amplitude: Manually override output amplitude, see [2] for values
+- silabs,synth-master: boolean. If present, this output is allowed to change 
the
+   multisynth frequency dynamically.
+- silabs,silabs,disable-high: boolean. If set, the clock output is driven HIGH
+   when disabled, otherwise it's driven LOW.
+
+==Example==
+
+/* 48MHz reference crystal */
+ref48: ref48M {
+   compatible = "fixed-clock";
+   #clock-cells = <0>;
+ 

[PATCH v2] dt-bindings: clock: Add silabs,si5341

2019-05-07 Thread Mike Looijmans
Adds the devicetree bindings for the Si5341 and Si5340 chips from
Silicon Labs. These are multiple-input multiple-output clock
synthesizers.

Signed-off-by: Mike Looijmans 
---
v2: Add data sheet reference.
Restructured to enable use of "assigned-clock*" properties to set
up both outputs and internal synthesizers.
Nicer indentation.
Updated subject line and body of commit message.
If these bindings are (mostly) acceptable, I'll post an updated
driver patch v2 to implement these changes.

 .../bindings/clock/silabs,si5341.txt  | 187 ++
 1 file changed, 187 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/silabs,si5341.txt

diff --git a/Documentation/devicetree/bindings/clock/silabs,si5341.txt 
b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
new file mode 100644
index ..6086dfcaeecf
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
@@ -0,0 +1,187 @@
+Binding for Silicon Labs Si5341 and Si5340 programmable i2c clock generator.
+
+Reference
+[1] Si5341 Data Sheet
+
https://www.silabs.com/documents/public/data-sheets/Si5341-40-D-DataSheet.pdf
+[2] Si5341 Reference Manual
+
https://www.silabs.com/documents/public/reference-manuals/Si5341-40-D-RM.pdf
+
+The Si5341 and Si5340 are programmable i2c clock generators with up to 10 
output
+clocks. The chip contains a PLL that sources 5 (or 4) multisynth clocks, which
+in turn can be directed to any of the 10 (or 4) outputs through a divider.
+The internal structure of the clock generators can be found in [2].
+
+The driver can be used in "as is" mode, reading the current settings from the
+chip at boot, in case you have a (pre-)programmed device. If the PLL is not
+configured when the driver probes, it assumes the driver must fully initialize
+it.
+
+The device type, speed grade and revision are determined runtime by probing.
+
+The driver currently only supports XTAL input mode, and does not support any
+fancy input configurations. They can still be programmed into the chip and
+the driver will leave them "as is".
+
+==I2C device node==
+
+Required properties:
+- compatible: shall be one of the following:
+   "silabs,si5340" - Si5340 A/B/C/D
+   "silabs,si5341" - Si5341 A/B/C/D
+- reg: i2c device address, usually 0x74
+- #clock-cells: from common clock binding; shall be set to 2.
+   The first value is "0" for outputs, "1" for synthesizers.
+   The second value is the output or synthesizer index.
+- clocks: from common clock binding; list of parent clock  handles,
+   corresponding to inputs. Use a fixed clock for the "xtal" input.
+   At least one must be present.
+- clock-names: One of: "xtal", "in0", "in1", "in2"
+- vdd-supply: Regulator node for VDD
+
+Optional properties:
+- vdda-supply: Regulator node for VDDA
+- vdds-supply: Regulator node for VDDS
+- silabs,pll-m-num, silabs,pll-m-den: Numerator and denominator for PLL
+  feedback divider. Must be such that the PLL output is in the valid range. For
+  example, to create 14GHz from a 48MHz xtal, use m-num=14000 and m-den=48. 
Only
+  the fraction matters, using 3500 and 12 will deliver the exact same result.
+  If these are not specified, and the PLL is not yet programmed when the driver
+  probes, the PLL will be set to 14GHz.
+- silabs,reprogram: When present, the driver will always assume the device must
+  be initialized, and always performs the soft-reset routine. Since this will
+  temporarily stop all output clocks, don't do this if the chip is generating
+  the CPU clock for example.
+- interrupts: Interrupt for INTRb pin.
+
+== Child nodes: Synthesizers ==
+
+In order to refer to the internal synthesizers, there can be a child node named
+"synthesizers".
+
+Required synthesizers node properties:
+- #address-cells: shall be set to 1.
+- #size-cells: shall be set to 0.
+
+Each child of this node corresponds to a multisynth in the Si534X chip. This
+allows the synthesizer to be referred to with assigned-clocks.
+
+Required child node properties:
+- reg: synthesizer index in range 0..4 for Si5341 and 0..3 for Si5340.
+
+== Child nodes: Outputs ==
+
+The child node "outputs" lists the output clocks.
+
+Required outputs node properties:
+- #address-cells: shall be set to 1.
+- #size-cells: shall be set to 0.
+
+Each of the clock outputs can be overwritten individually by
+using a child node to the outputs child node. If a child node for a clock
+output is not set, the configuration remains unchanged.
+
+Required child node properties:
+- reg: number of clock output.
+
+Optional child node properties:
+- vdd-supply: Regulator node for VDD for this output. The driver selects 
default
+   values for common-mode and amplitude based on the voltage.
+- silabs,format: Output format, one of:
+   1 = differential

[PATCH] clk: clk-si544: Implement small frequency change support

2019-05-07 Thread Mike Looijmans
The Si544 supports changing frequencies "on the fly" when the change is
less than 950 ppm from the current center frequency. The driver now
uses the small adjustment routine for implementing this.

Signed-off-by: Mike Looijmans 
---
 drivers/clk/clk-si544.c | 102 
 1 file changed, 92 insertions(+), 10 deletions(-)

diff --git a/drivers/clk/clk-si544.c b/drivers/clk/clk-si544.c
index 64e607f3232a..d9ec9086184d 100644
--- a/drivers/clk/clk-si544.c
+++ b/drivers/clk/clk-si544.c
@@ -7,6 +7,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -50,6 +51,11 @@
 /* Lowest frequency synthesizeable using only the HS divider */
 #define MIN_HSDIV_FREQ (FVCO_MIN / HS_DIV_MAX)
 
+/* Range and interpretation of the adjustment value */
+#define DELTA_M_MAX8161512
+#define DELTA_M_FRAC_NUM   19
+#define DELTA_M_FRAC_DEN   2
+
 enum si544_speed_grade {
si544a,
si544b,
@@ -71,12 +77,14 @@ struct clk_si544 {
  * @hs_div:1st divider, 5..2046, must be even when >33
  * @ls_div_bits:   2nd divider, as 2^x, range 0..5
  *  If ls_div_bits is non-zero, hs_div must be even
+ * @delta_m:   Frequency shift for small -950..+950 ppm changes, 24 bit
  */
 struct clk_si544_muldiv {
u32 fb_div_frac;
u16 fb_div_int;
u16 hs_div;
u8 ls_div_bits;
+   s32 delta_m;
 };
 
 /* Enables or disables the output driver */
@@ -134,9 +142,30 @@ static int si544_get_muldiv(struct clk_si544 *data,
settings->fb_div_int = reg[4] | (reg[5] & 0x07) << 8;
settings->fb_div_frac = reg[0] | reg[1] << 8 | reg[2] << 16 |
reg[3] << 24;
+
+   err = regmap_bulk_read(data->regmap, SI544_REG_ADPLL_DELTA_M0, reg, 3);
+   if (err)
+   return err;
+
+   /* Interpret as 24-bit signed number */
+   settings->delta_m = reg[0] << 8 | reg[1] << 16 | reg[2] << 24;
+   settings->delta_m >>= 8;
+
return 0;
 }
 
+static int si544_set_delta_m(struct clk_si544 *data, s32 delta_m)
+{
+   u8 reg[3];
+
+   reg[0] = delta_m;
+   reg[1] = delta_m >> 8;
+   reg[2] = delta_m >> 16;
+
+   return regmap_bulk_write(data->regmap, SI544_REG_ADPLL_DELTA_M0,
+reg, 3);
+}
+
 static int si544_set_muldiv(struct clk_si544 *data,
struct clk_si544_muldiv *settings)
 {
@@ -238,11 +267,15 @@ static int si544_calc_muldiv(struct clk_si544_muldiv 
*settings,
do_div(vco, FXO);
settings->fb_div_frac = vco;
 
+   /* Reset the frequency adjustment */
+   settings->delta_m = 0;
+
return 0;
 }
 
 /* Calculate resulting frequency given the register settings */
-static unsigned long si544_calc_rate(struct clk_si544_muldiv *settings)
+static unsigned long si544_calc_center_rate(
+   const struct clk_si544_muldiv *settings)
 {
u32 d = settings->hs_div * BIT(settings->ls_div_bits);
u64 vco;
@@ -261,6 +294,25 @@ static unsigned long si544_calc_rate(struct 
clk_si544_muldiv *settings)
return vco;
 }
 
+static unsigned long si544_calc_rate(const struct clk_si544_muldiv *settings)
+{
+   unsigned long rate = si544_calc_center_rate(settings);
+   s64 delta = (s64)rate * (DELTA_M_FRAC_NUM * settings->delta_m);
+
+   /*
+* The clock adjustment is much smaller than 1 Hz, round to the
+* nearest multiple. Apparently div64_s64 rounds towards zero, hence
+* check the sign and adjust into the proper direction.
+*/
+   if (settings->delta_m < 0)
+   delta -= ((s64)DELTA_M_MAX * DELTA_M_FRAC_DEN) / 2;
+   else
+   delta += ((s64)DELTA_M_MAX * DELTA_M_FRAC_DEN) / 2;
+   delta = div64_s64(delta, ((s64)DELTA_M_MAX * DELTA_M_FRAC_DEN));
+
+   return rate + delta;
+}
+
 static unsigned long si544_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
 {
@@ -279,33 +331,60 @@ static long si544_round_rate(struct clk_hw *hw, unsigned 
long rate,
unsigned long *parent_rate)
 {
struct clk_si544 *data = to_clk_si544(hw);
-   struct clk_si544_muldiv settings;
-   int err;
 
if (!is_valid_frequency(data, rate))
return -EINVAL;
 
-   err = si544_calc_muldiv(, rate);
-   if (err)
-   return err;
+   /* The accuracy is less than 1 Hz, so any rate is possible */
+   return rate;
+}
 
-   return si544_calc_rate();
+/* Calculates the maximum "small" change, 950 * rate / 100 */
+static unsigned long si544_max_delta(unsigned long rate)
+{
+   u64 num = rate;
+
+   num *= DELTA_M_FRAC_NUM;
+   do_div(num, DELTA_M_FRAC_DEN);
+
+   return num;
+}
+
+static s32 si544_calc_delta(s32 delta, s32 max_delta)
+{
+   s64 n = (s64)delta * DELT

Re: [PATCH] dt-bindings: Add silabs,si5341

2019-04-30 Thread Mike Looijmans
On 30-04-19 02:17, Stephen Boyd wrote:
> Quoting Mike Looijmans (2019-04-27 02:42:56)
>> On 27-04-19 02:44, Stephen Boyd wrote:
>>> Quoting Mike Looijmans (2019-04-25 23:51:15)
>>>> On 26-04-19 01:04, Stephen Boyd wrote:
>>>>>> +
>>>>>> +Optional properties:
>>>>>> +- silabs,pll-m-num, silabs,pll-m-den: Numerator and denominator for PLL
>>>>>> +  feedback divider. Must be such that the PLL output is in the valid 
>>>>>> range. For
>>>>>> +  example, to create 14GHz from a 48MHz xtal, use m-num=14000 and 
>>>>>> m-den=48. Only
>>>>>> +  the fraction matters, using 3500 and 12 will deliver the exact same 
>>>>>> result.
>>>>>> +  If these are not specified, and the PLL is not yet programmed when 
>>>>>> the driver
>>>>>> +  probes, the PLL will be set to 14GHz.
>>>>>
>>>>> Can this be done via assigned-clock-rates? Possibly with a table in the
>>>>> clk driver to tell us how to generate those rates.
>>>>
>>>> The PLL frequency choice determines who'll get jitter and who won't. It's
>>>> ridiculously accurate too.
>>>>
>>>> For example, if you need a 26 MHz and a 100 MHz output, there's no solution
>>>> for the PLL that makes both clocks an integer divider (SI is vague about 
>>>> it,
>>>> but apparently integer dividers have less jitter on output). Only the 
>>>> enduser
>>>> can say which clock will get the better quality.
> 
> Right. So maybe we make tables of rates and put it in the driver and
> keep adding code in there? I'm worried about having these properties in
> DT and then having to work around them later on by "fixing" the DT. If
> it's only in the driver then we're able to tweak the values to get
> better jitter numbers, etc.

Programming the main PLL is easy, no tables required.

It's all user choice, that's the issue here. Drivers themselves cannot make 
this decision.

(user = the person doing board support, writing the devicetree and kernel 
config for example)

In my example, the chip has no issue synthesizing both 26 and 100 MHz. 
Depending on the main PLL setting, one may have more jitter than the other. If 
the PLL is set to 14.0 GHz, the 100 MHz clock will be of better quality, while 
if the PLL is set to 13.624 GHz (an even multiple of 26), the 26 MHz will have 
better quality.


>>>>>> +- silabs,reprogram: When present, the driver will always assume the 
>>>>>> device must
>>>>>> +  be initialized, and always performs the soft-reset routine. Since 
>>>>>> this will
>>>>>> +  temporarily stop all output clocks, don't do this if the chip is 
>>>>>> generating
>>>>>> +  the CPU clock for example.
>>>>>
>>>>> Could this be done with the reset framework? It almost sounds like if
>>>>> the clk is a CLK_IS_CRITICAL then we shouldn't do the reset, otherwise
>>>>> we probably should reset the chip when the driver probes. If we don't
>>>>> have a case where it's going to be supplying a critical clk for a long
>>>>> time then perhaps we shouldn't even consider this topic until later.
>>>>
>>>> The driver can sort of see that the chips is already configured. This tells
>>>> the driver whether that's expected or just coincidence.
>>>>
>>>> Maybe it'd be clearer if I reversed the logic and name this
>>>> "silabs,preprogrammed", which will skip the driver's initialization 
>>>> routine?
>>>>
>>>
>>> Maybe? Is there any way to look at some register to figure out for sure
>>> if it's been pre-programmed or not? Could TOOL_VERSION be used or
>>> ACTIVE_NVM_BANK or DESIGN_ID0-7?
>>
>> I've experimentally determined that TOOL_VERSION and DESIGN_IDx
>> apparently get filled with zeroes by the clockbuilder anyway.
>>
>> ACTIVE_NVM_BANK works reliably for self-programmed chips.
>>
>> The flag is about "is this chip under full kernel control, or is it
>> generating clocks the kernel doesn't know about (e.g. for realtime cores
>> or FPGA logic)".
>>
> 
> Alright.
> 
>>
>>
>>>>>> +==Child nodes==
>>>>>> +
>>>>>> +Each of the clock outputs can be overwritten individually by
>>>>>> +using a child node to the I2C device node. If a child node for a clock
>>>>

Re: [PATCH] dt-bindings: Add silabs,si5341

2019-04-27 Thread Mike Looijmans
On 27-04-19 02:44, Stephen Boyd wrote:
> Quoting Mike Looijmans (2019-04-25 23:51:15)
>> On 26-04-19 01:04, Stephen Boyd wrote:
>>> Quoting Mike Looijmans (2019-04-24 02:02:16)
>>>> Adds the devicetree bindings for the si5341 driver that supports the
>>>> Si5341 and Si5340 chips.
>>>>
>>>> Signed-off-by: Mike Looijmans 
>>>> ---
>>>>.../bindings/clock/silabs,si5341.txt  | 141 ++
>>>>1 file changed, 141 insertions(+)
>>>>create mode 100644 
>>>> Documentation/devicetree/bindings/clock/silabs,si5341.txt
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/clock/silabs,si5341.txt 
>>>> b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
>>>> new file mode 100644
>>>> index ..1a00dd83100f
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
>>>> @@ -0,0 +1,141 @@
>>>> +Binding for Silicon Labs Si5341 and Si5340 programmable i2c clock 
>>>> generator.
>>>> +
>>>> +Reference
>>>> +[1] Si5341 Data Sheet
>>>> +
>>>> https://www.silabs.com/documents/public/reference-manuals/Si5341-40-D-RM.pdf
>>>
>>> Thanks! I also had to look up the pinout in the datasheet, not the
>>> reference manual above.
>>
>> Now you mention it, this is the "reference manual", not the datasheet. I'll
>> add a reference to that as well.
>>
> 
> Cool, thanks.
> 
>>
>>>> +
>>>> +Optional properties:
>>>> +- silabs,pll-m-num, silabs,pll-m-den: Numerator and denominator for PLL
>>>> +  feedback divider. Must be such that the PLL output is in the valid 
>>>> range. For
>>>> +  example, to create 14GHz from a 48MHz xtal, use m-num=14000 and 
>>>> m-den=48. Only
>>>> +  the fraction matters, using 3500 and 12 will deliver the exact same 
>>>> result.
>>>> +  If these are not specified, and the PLL is not yet programmed when the 
>>>> driver
>>>> +  probes, the PLL will be set to 14GHz.
>>>
>>> Can this be done via assigned-clock-rates? Possibly with a table in the
>>> clk driver to tell us how to generate those rates.
>>
>> The PLL frequency choice determines who'll get jitter and who won't. It's
>> ridiculously accurate too.
>>
>> For example, if you need a 26 MHz and a 100 MHz output, there's no solution
>> for the PLL that makes both clocks an integer divider (SI is vague about it,
>> but apparently integer dividers have less jitter on output). Only the enduser
>> can say which clock will get the better quality.
>>
>>>
>>>> +- silabs,reprogram: When present, the driver will always assume the 
>>>> device must
>>>> +  be initialized, and always performs the soft-reset routine. Since this 
>>>> will
>>>> +  temporarily stop all output clocks, don't do this if the chip is 
>>>> generating
>>>> +  the CPU clock for example.
>>>
>>> Could this be done with the reset framework? It almost sounds like if
>>> the clk is a CLK_IS_CRITICAL then we shouldn't do the reset, otherwise
>>> we probably should reset the chip when the driver probes. If we don't
>>> have a case where it's going to be supplying a critical clk for a long
>>> time then perhaps we shouldn't even consider this topic until later.
>>
>> The driver can sort of see that the chips is already configured. This tells
>> the driver whether that's expected or just coincidence.
>>
>> Maybe it'd be clearer if I reversed the logic and name this
>> "silabs,preprogrammed", which will skip the driver's initialization routine?
>>
> 
> Maybe? Is there any way to look at some register to figure out for sure
> if it's been pre-programmed or not? Could TOOL_VERSION be used or
> ACTIVE_NVM_BANK or DESIGN_ID0-7?

I've experimentally determined that TOOL_VERSION and DESIGN_IDx 
apparently get filled with zeroes by the clockbuilder anyway.

ACTIVE_NVM_BANK works reliably for self-programmed chips.

The flag is about "is this chip under full kernel control, or is it 
generating clocks the kernel doesn't know about (e.g. for realtime cores 
or FPGA logic)".


>>> Looks like there is an interrupt pin? So we need an optional interrupts
>>> property?  Also, a reset pin, so maybe a 'resets' property. There's also
>>> another input pin for 'output enable' which maybe someon

Re: [PATCH] clk: Add Si5341/Si5340 driver

2019-04-26 Thread Mike Looijmans
I'll send a v2 with lots of changes someday next week (I hope). Comments 
interleaved, if I didn't comment or explicitly say "ok", just assume I agree 
and will change it.


On 26-04-19 01:36, Stephen Boyd wrote:
> Quoting Mike Looijmans (2019-04-24 02:00:38)
>> Adds a driver for the Si5341 and Si5340 chips. The driver does not fully
>> support all features of these chips, but allows the chip to be used
>> without any support from the "clockbuilder pro" software.
>>
>> If the chip is preprogrammed, that is, you bought one with some defaults
>> burned in, or you programmed the NVM in some way, the driver will just
>> take over the current settings and only change them on demand. Otherwise
>> the input must a fixed XTAL in its most basic configuration (no
> 
> must be
> 
>> predividers, no feedback, etc.).
>>
>> The driver supports dynamic changes of multisynth, output dividers and
>> enabling or powering down outputs and multisynths.
>>
>> Signed-off-by: Mike Looijmans 
>> ---
>> diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
>> new file mode 100644
>> index ..0d636658853b
>> --- /dev/null
>> +++ b/drivers/clk/clk-si5341.c
>> @@ -0,0 +1,1452 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Driver for Silicon Labs Si5341/Si5340 Clock generator
>> + * Copyright (C) 2019 Topic Embedded Products
>> + * Author: Mike Looijmans 
>> + */
>> +
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +
>> +#define SI5341_MAX_NUM_OUTPUTS 10
>> +#define SI5340_MAX_NUM_OUTPUTS 4
>> +
>> +#define SI5341_NUM_SYNTH 5
>> +#define SI5340_NUM_SYNTH 4
>> +
>> +/* Range of the synthesizer fractional divider */
>> +#define SI5341_SYNTH_N_MIN 10
>> +#define SI5341_SYNTH_N_MAX 4095
>> +
>> +/* The chip can get its input clock from 3 input pins or an XTAL */
>> +
>> +/* There is one PLL running at 13500–14256 MHz */
>> +#define SI5341_PLL_VCO_MIN 135ull
>> +#define SI5341_PLL_VCO_MAX 1425600ull
>> +
>> +/* The 5 frequency synthesizers obtain their input from the PLL */
>> +struct clk_si5341_synth {
>> +   struct clk_hw hw;
>> +   struct clk_si5341 *data;
>> +   u8 index;
>> +};
>> +#define to_clk_si5341_synth(_hw) \
>> +   container_of(_hw, struct clk_si5341_synth, hw)
>> +
>> +/* The output stages can be connected to any synth (full mux) */
>> +struct clk_si5341_output {
>> +   struct clk_hw hw;
>> +   struct clk_si5341 *data;
>> +   u8 index;
>> +};
>> +#define to_clk_si5341_output(_hw) \
>> +   container_of(_hw, struct clk_si5341_output, hw)
>> +
>> +struct clk_si5341 {
>> +   struct clk_hw hw;
>> +   struct regmap *regmap;
>> +   struct i2c_client *i2c_client;
>> +   struct clk_si5341_synth synth[SI5341_NUM_SYNTH];
>> +   struct clk_si5341_output clk[SI5341_MAX_NUM_OUTPUTS];
>> +   struct clk *pxtal;
>> +   const char *pxtal_name;
>> +   const u16 *reg_output_offset;
>> +   const u16 *reg_rdiv_offset;
>> +   u64 freq_vco; /* 13500–14256 MHz */
>> +   u8 num_outputs;
>> +   u8 num_synth;
>> +};
>> +#define to_clk_si5341(_hw) container_of(_hw, struct clk_si5341, hw)
>> +
>> +struct clk_si5341_output_config {
>> +   u8 source_index;
>> +   u8 out_format_drv_bits;
>> +   u8 out_cm_ampl_bits;
>> +   bool synth_master;
>> +   bool always_on;
>> +   u32 synth_frequency;
>> +   u32 clock_frequency;
>> +};
>> +
>> +#define SI5341_PAGE0x0001
>> +#define SI5341_PN_BASE 0x0002
>> +#define SI5341_DEVICE_REV  0x0005
>> +#define SI5341_STATUS  0x000C
>> +#define SI5341_SOFT_RST0x001C
>> +
>> +/* Input dividers (48-bit) */
>> +#define SI5341_IN_PDIV(x)  (0x0208 + ((x) * 10))
>> +#define SI5341_IN_PSET(x)  (0x020E + ((x) * 10))
>> +
>> +/* PLL configuration */
>> +#define SI5341_PLL_M_NUM   0x0235
>> +#define SI5341_PLL_M_DEN   0x023B
>> +
>> +/* Output configuration */
>> +#define SI5341_OUT_CONFIG(output)  \
>> +   ((output)->data->reg_output_offset[(output)->index])
>> +#define SI5341_OUT_FORMAT(output)  (SI5341_OUT_CONFIG(output) + 1)
>> +#define SI5341_OUT_CM(output) 

Re: [PATCH] dt-bindings: Add silabs,si5341

2019-04-26 Thread Mike Looijmans
On 26-04-19 01:04, Stephen Boyd wrote:
> Quoting Mike Looijmans (2019-04-24 02:02:16)
>> Adds the devicetree bindings for the si5341 driver that supports the
>> Si5341 and Si5340 chips.
>>
>> Signed-off-by: Mike Looijmans 
>> ---
>>   .../bindings/clock/silabs,si5341.txt  | 141 ++
>>   1 file changed, 141 insertions(+)
>>   create mode 100644 
>> Documentation/devicetree/bindings/clock/silabs,si5341.txt
>>
>> diff --git a/Documentation/devicetree/bindings/clock/silabs,si5341.txt 
>> b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
>> new file mode 100644
>> index ..1a00dd83100f
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
>> @@ -0,0 +1,141 @@
>> +Binding for Silicon Labs Si5341 and Si5340 programmable i2c clock generator.
>> +
>> +Reference
>> +[1] Si5341 Data Sheet
>> +
>> https://www.silabs.com/documents/public/reference-manuals/Si5341-40-D-RM.pdf
> 
> Thanks! I also had to look up the pinout in the datasheet, not the
> reference manual above.

Now you mention it, this is the "reference manual", not the datasheet. I'll 
add a reference to that as well.

>> +
>> +The Si5341 and Si5340 are programmable i2c clock generators with up to 10 
>> output
>> +clocks. The chip contains a PLL that sources 5 (or 4) multisynth clocks, 
>> which
>> +in turn can be directed to any of the 10 (or 4) outputs through a divider.
>> +The internal structure of the clock generators can be found in [1].
>> +
>> +The driver can be used in "as is" mode, reading the current settings from 
>> the
>> +chip at boot, in case you have a (pre-)programmed device. If the PLL is not
>> +configured when the driver probes, it assumes the driver must fully 
>> initialize
>> +it.
>> +
>> +The device type, speed grade and revision are determined runtime by probing.
>> +
>> +The driver currently only supports XTAL input mode, and does not support any
>> +fancy input configurations. They can still be programmed into the chip and
>> +the driver will leave them "as is".
>> +
>> +==I2C device node==
>> +
>> +Required properties:
>> +- compatible: shall be one of the following: "silabs,si5341", 
>> "silabs,si5340"
>> +- reg: i2c device address, usually 0x74
>> +- #clock-cells: from common clock binding; shall be set to 1.
>> +- clocks: from common clock binding; list of parent clock
>> +  handles, shall be xtal reference clock. Usually a fixed clock.
> 
> Is there only one possible clk parent? Looks like there's an optional
> xtal on the XA/XB pins and then up to three more input clks on IN0/1/2.
> So shouldn't this list all of those and then indicate that at least one
> should be specified at all times?
> 
>> +- clock-names: Shall be "xtal".
> 
> This should include the other clk inputs?

Some day maybe. That's what I meant when I wrote "does not support any fancy 
input configurations".

The input config is horrendously complex. We have never used anything but just 
the xtal input, and I think that goes for 99.9% of the use cases for this chip.

I already went way over budget with this one, my first intention was to write 
a driver that takes a firmware blob from the "clockbuilder" software, but 
while writing it I discovered that the whole damn thing could easily be 
controlled completely without it.

> 
>> +- #address-cells: shall be set to 1.
>> +- #size-cells: shall be set to 0.
> 
> I'd expect to see all the input voltage supplies here too.
> 
>   vdd-supply
>   vdda-supply
>   vdds-supply
>   vdd0-supply
>   vdd1-supply
>   vdd2-supply
>   vdd3-supply
>   vdd4-supply
>   vdd5-supply
>   vdd6-supply
>   vdd7-supply
>   vdd8-supply
>   vdd9-supply

I'll look into it. Might be useful for some register settings.

>> +
>> +Optional properties:
>> +- silabs,pll-m-num, silabs,pll-m-den: Numerator and denominator for PLL
>> +  feedback divider. Must be such that the PLL output is in the valid range. 
>> For
>> +  example, to create 14GHz from a 48MHz xtal, use m-num=14000 and m-den=48. 
>> Only
>> +  the fraction matters, using 3500 and 12 will deliver the exact same 
>> result.
>> +  If these are not specified, and the PLL is not yet programmed when the 
>> driver
>> +  probes, the PLL will be set to 14GHz.
> 
> Can this be done via assigned-clock-rates? Possibly with a table in the
> clk driver to tell us how to generate those rates

[PATCH] clk: Add Si5341/Si5340 driver

2019-04-25 Thread Mike Looijmans
Adds a driver for the Si5341 and Si5340 chips. The driver does not fully
support all features of these chips, but allows the chip to be used
without any support from the "clockbuilder pro" software.

If the chip is preprogrammed, that is, you bought one with some defaults
burned in, or you programmed the NVM in some way, the driver will just
take over the current settings and only change them on demand. Otherwise
the input must be a fixed XTAL in its most basic configuration (no
predividers, no feedback, etc.).

The driver supports dynamic changes of multisynth, output dividers and
enabling or powering down outputs and multisynths.

Signed-off-by: Mike Looijmans 
---
v2: Use correct distribution list (not the devicetree one)
Fix bug that a /2 divider setting actually disabled the divider
Update the Kconfig description (no firmware blob needed)

 drivers/clk/Kconfig  |   11 +
 drivers/clk/Makefile |1 +
 drivers/clk/clk-si5341.c | 1459 ++
 3 files changed, 1471 insertions(+)
 create mode 100644 drivers/clk/clk-si5341.c

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index e705aab9e38b..0edd9ae3c89b 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -90,6 +90,17 @@ config COMMON_CLK_SCPI
  This driver uses SCPI Message Protocol to interact with the
  firmware providing all the clock controls.
 
+config COMMON_CLK_SI5341
+   tristate "Clock driver for SiLabs 5341 and 5340 A/B/C/D devices"
+   depends on I2C
+   select REGMAP_I2C
+   help
+ This driver supports Silicon Labs Si5341 and Si5340 programmable clock
+ generators. Not all features of these chips are currently supported
+ by the driver, in particular it only supports XTAL input. The chip can
+ be pre-programmed to support other configurations and features not yet
+ implemented in the driver.
+
 config COMMON_CLK_SI5351
tristate "Clock driver for SiLabs 5351A/B/C"
depends on I2C
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 1db133652f0c..4a7aa4a01fef 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_COMMON_CLK_HI655X)   += clk-hi655x.o
 obj-$(CONFIG_COMMON_CLK_S2MPS11)   += clk-s2mps11.o
 obj-$(CONFIG_COMMON_CLK_SCMI)   += clk-scmi.o
 obj-$(CONFIG_COMMON_CLK_SCPI)   += clk-scpi.o
+obj-$(CONFIG_COMMON_CLK_SI5341)+= clk-si5341.o
 obj-$(CONFIG_COMMON_CLK_SI5351)+= clk-si5351.o
 obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o
 obj-$(CONFIG_COMMON_CLK_SI544) += clk-si544.o
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
new file mode 100644
index ..6feb3ef34a6a
--- /dev/null
+++ b/drivers/clk/clk-si5341.c
@@ -0,0 +1,1459 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Silicon Labs Si5341/Si5340 Clock generator
+ * Copyright (C) 2019 Topic Embedded Products
+ * Author: Mike Looijmans 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define SI5341_MAX_NUM_OUTPUTS 10
+#define SI5340_MAX_NUM_OUTPUTS 4
+
+#define SI5341_NUM_SYNTH 5
+#define SI5340_NUM_SYNTH 4
+
+/* Range of the synthesizer fractional divider */
+#define SI5341_SYNTH_N_MIN 10
+#define SI5341_SYNTH_N_MAX 4095
+
+/* The chip can get its input clock from 3 input pins or an XTAL */
+
+/* There is one PLL running at 13500–14256 MHz */
+#define SI5341_PLL_VCO_MIN 135ull
+#define SI5341_PLL_VCO_MAX 1425600ull
+
+/* The 5 frequency synthesizers obtain their input from the PLL */
+struct clk_si5341_synth {
+   struct clk_hw hw;
+   struct clk_si5341 *data;
+   u8 index;
+};
+#define to_clk_si5341_synth(_hw) \
+   container_of(_hw, struct clk_si5341_synth, hw)
+
+/* The output stages can be connected to any synth (full mux) */
+struct clk_si5341_output {
+   struct clk_hw hw;
+   struct clk_si5341 *data;
+   u8 index;
+};
+#define to_clk_si5341_output(_hw) \
+   container_of(_hw, struct clk_si5341_output, hw)
+
+struct clk_si5341 {
+   struct clk_hw hw;
+   struct regmap *regmap;
+   struct i2c_client *i2c_client;
+   struct clk_si5341_synth synth[SI5341_NUM_SYNTH];
+   struct clk_si5341_output clk[SI5341_MAX_NUM_OUTPUTS];
+   struct clk *pxtal;
+   const char *pxtal_name;
+   const u16 *reg_output_offset;
+   const u16 *reg_rdiv_offset;
+   u64 freq_vco; /* 13500–14256 MHz */
+   u8 num_outputs;
+   u8 num_synth;
+};
+#define to_clk_si5341(_hw) container_of(_hw, struct clk_si5341, hw)
+
+struct clk_si5341_output_config {
+   u8 source_index;
+   u8 out_format_drv_bits;
+   u8 out_cm_ampl_bits;
+   bool synth_master;
+   bool always_on;
+   u32 synth_frequency;
+   u32 clock_frequency;
+};
+
+#define SI5341_PAGE0x0001
+#define SI5341_P

[PATCH] clk: Add Si5341/Si5340 driver

2019-04-24 Thread Mike Looijmans
Adds a driver for the Si5341 and Si5340 chips. The driver does not fully
support all features of these chips, but allows the chip to be used
without any support from the "clockbuilder pro" software.

If the chip is preprogrammed, that is, you bought one with some defaults
burned in, or you programmed the NVM in some way, the driver will just
take over the current settings and only change them on demand. Otherwise
the input must a fixed XTAL in its most basic configuration (no
predividers, no feedback, etc.).

The driver supports dynamic changes of multisynth, output dividers and
enabling or powering down outputs and multisynths.

Signed-off-by: Mike Looijmans 
---
 drivers/clk/Kconfig  |   11 +
 drivers/clk/Makefile |1 +
 drivers/clk/clk-si5341.c | 1452 ++
 3 files changed, 1464 insertions(+)
 create mode 100644 drivers/clk/clk-si5341.c

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index e705aab9e38b..4824bb372b36 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -90,6 +90,17 @@ config COMMON_CLK_SCPI
  This driver uses SCPI Message Protocol to interact with the
  firmware providing all the clock controls.
 
+
+config COMMON_CLK_SI5341
+   tristate "Clock driver for SiLabs 5341 and 5340 A/B/C/D devices"
+   depends on I2C
+   select REGMAP_I2C
+   help
+ This driver supports Silicon Labs 5341 and 5340 programmable clock
+ generators. For proper operation, the device needs to be
+ pre-programmed either using NVM or a firmware "blob" with register
+ settings created by the silabs clock creator software.
+
 config COMMON_CLK_SI5351
tristate "Clock driver for SiLabs 5351A/B/C"
depends on I2C
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 1db133652f0c..4a7aa4a01fef 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_COMMON_CLK_HI655X)   += clk-hi655x.o
 obj-$(CONFIG_COMMON_CLK_S2MPS11)   += clk-s2mps11.o
 obj-$(CONFIG_COMMON_CLK_SCMI)   += clk-scmi.o
 obj-$(CONFIG_COMMON_CLK_SCPI)   += clk-scpi.o
+obj-$(CONFIG_COMMON_CLK_SI5341)+= clk-si5341.o
 obj-$(CONFIG_COMMON_CLK_SI5351)+= clk-si5351.o
 obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o
 obj-$(CONFIG_COMMON_CLK_SI544) += clk-si544.o
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
new file mode 100644
index ..0d636658853b
--- /dev/null
+++ b/drivers/clk/clk-si5341.c
@@ -0,0 +1,1452 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Silicon Labs Si5341/Si5340 Clock generator
+ * Copyright (C) 2019 Topic Embedded Products
+ * Author: Mike Looijmans 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define SI5341_MAX_NUM_OUTPUTS 10
+#define SI5340_MAX_NUM_OUTPUTS 4
+
+#define SI5341_NUM_SYNTH 5
+#define SI5340_NUM_SYNTH 4
+
+/* Range of the synthesizer fractional divider */
+#define SI5341_SYNTH_N_MIN 10
+#define SI5341_SYNTH_N_MAX 4095
+
+/* The chip can get its input clock from 3 input pins or an XTAL */
+
+/* There is one PLL running at 13500–14256 MHz */
+#define SI5341_PLL_VCO_MIN 135ull
+#define SI5341_PLL_VCO_MAX 1425600ull
+
+/* The 5 frequency synthesizers obtain their input from the PLL */
+struct clk_si5341_synth {
+   struct clk_hw hw;
+   struct clk_si5341 *data;
+   u8 index;
+};
+#define to_clk_si5341_synth(_hw) \
+   container_of(_hw, struct clk_si5341_synth, hw)
+
+/* The output stages can be connected to any synth (full mux) */
+struct clk_si5341_output {
+   struct clk_hw hw;
+   struct clk_si5341 *data;
+   u8 index;
+};
+#define to_clk_si5341_output(_hw) \
+   container_of(_hw, struct clk_si5341_output, hw)
+
+struct clk_si5341 {
+   struct clk_hw hw;
+   struct regmap *regmap;
+   struct i2c_client *i2c_client;
+   struct clk_si5341_synth synth[SI5341_NUM_SYNTH];
+   struct clk_si5341_output clk[SI5341_MAX_NUM_OUTPUTS];
+   struct clk *pxtal;
+   const char *pxtal_name;
+   const u16 *reg_output_offset;
+   const u16 *reg_rdiv_offset;
+   u64 freq_vco; /* 13500–14256 MHz */
+   u8 num_outputs;
+   u8 num_synth;
+};
+#define to_clk_si5341(_hw) container_of(_hw, struct clk_si5341, hw)
+
+struct clk_si5341_output_config {
+   u8 source_index;
+   u8 out_format_drv_bits;
+   u8 out_cm_ampl_bits;
+   bool synth_master;
+   bool always_on;
+   u32 synth_frequency;
+   u32 clock_frequency;
+};
+
+#define SI5341_PAGE0x0001
+#define SI5341_PN_BASE 0x0002
+#define SI5341_DEVICE_REV  0x0005
+#define SI5341_STATUS  0x000C
+#define SI5341_SOFT_RST0x001C
+
+/* Input dividers (48-bit) */
+#define SI5341_IN_PDIV(x)  (0x0208 + ((x) * 10))
+#define SI5341_IN_PSET

[PATCH] dt-bindings: Add silabs,si5341

2019-04-24 Thread Mike Looijmans
Adds the devicetree bindings for the si5341 driver that supports the
Si5341 and Si5340 chips.

Signed-off-by: Mike Looijmans 
---
 .../bindings/clock/silabs,si5341.txt  | 141 ++
 1 file changed, 141 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/silabs,si5341.txt

diff --git a/Documentation/devicetree/bindings/clock/silabs,si5341.txt 
b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
new file mode 100644
index ..1a00dd83100f
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
@@ -0,0 +1,141 @@
+Binding for Silicon Labs Si5341 and Si5340 programmable i2c clock generator.
+
+Reference
+[1] Si5341 Data Sheet
+
https://www.silabs.com/documents/public/reference-manuals/Si5341-40-D-RM.pdf
+
+The Si5341 and Si5340 are programmable i2c clock generators with up to 10 
output
+clocks. The chip contains a PLL that sources 5 (or 4) multisynth clocks, which
+in turn can be directed to any of the 10 (or 4) outputs through a divider.
+The internal structure of the clock generators can be found in [1].
+
+The driver can be used in "as is" mode, reading the current settings from the
+chip at boot, in case you have a (pre-)programmed device. If the PLL is not
+configured when the driver probes, it assumes the driver must fully initialize
+it.
+
+The device type, speed grade and revision are determined runtime by probing.
+
+The driver currently only supports XTAL input mode, and does not support any
+fancy input configurations. They can still be programmed into the chip and
+the driver will leave them "as is".
+
+==I2C device node==
+
+Required properties:
+- compatible: shall be one of the following: "silabs,si5341", "silabs,si5340"
+- reg: i2c device address, usually 0x74
+- #clock-cells: from common clock binding; shall be set to 1.
+- clocks: from common clock binding; list of parent clock
+  handles, shall be xtal reference clock. Usually a fixed clock.
+- clock-names: Shall be "xtal".
+- #address-cells: shall be set to 1.
+- #size-cells: shall be set to 0.
+
+Optional properties:
+- silabs,pll-m-num, silabs,pll-m-den: Numerator and denominator for PLL
+  feedback divider. Must be such that the PLL output is in the valid range. For
+  example, to create 14GHz from a 48MHz xtal, use m-num=14000 and m-den=48. 
Only
+  the fraction matters, using 3500 and 12 will deliver the exact same result.
+  If these are not specified, and the PLL is not yet programmed when the driver
+  probes, the PLL will be set to 14GHz.
+- silabs,reprogram: When present, the driver will always assume the device must
+  be initialized, and always performs the soft-reset routine. Since this will
+  temporarily stop all output clocks, don't do this if the chip is generating
+  the CPU clock for example.
+
+==Child nodes==
+
+Each of the clock outputs can be overwritten individually by
+using a child node to the I2C device node. If a child node for a clock
+output is not set, the configuration remains unchanged.
+
+Required child node properties:
+- reg: number of clock output.
+
+Optional child node properties:
+- silabs,format: Output format, see [1], 1=differential, 2=low-power, 4=LVCMOS
+- silabs,common-mode: Output common mode, depends on standard.
+- silabs,amplitude: Output amplitude, depends on standard.
+- silabs,synth-source: Select which multisynth to use for this output
+- silabs,synth-frequency: Sets the frequency for the multisynth connected to
+  this output. This will affect other outputs connected to this multisynth. The
+  setting is applied before silabs,synth-master and clock-frequency.
+- silabs,synth-master: If present, this output is allowed to change the
+  multisynth frequency dynamically.
+- clock-frequency: Sets a default frequency for this output.
+- always-on: Immediately and permanently enable this output. Particulary
+  useful when combined with assigned-clocks, since that does not prepare 
clocks.
+
+==Example==
+
+/* 48MHz reference crystal */
+ref48: ref48M {
+   compatible = "fixed-clock";
+   #clock-cells = <0>;
+   clock-frequency = <4800>;
+};
+
+i2c-master-node {
+
+   /* Programmable clock (for logic) */
+   si5341: clock-generator@74 {
+   reg = <0x74>;
+   compatible = "silabs,si5341";
+   #clock-cells = <1>;
+   #address-cells = <1>;
+   #size-cells = <0>;
+   clocks = <>;
+   clock-names = "xtal";
+
+   silabs,pll-m-num = <14000>; /* PLL at 14.0 GHz */
+   silabs,pll-m-den = <48>;
+   silabs,reprogram; /* Chips are not programmed, always reset */
+
+   /*
+* Output 0 configuration:
+*  LVDS 3v3
+*  Source from Multisynth 3
+*  Use 600MHz synt

Re: [PATCH v3 2/2] iio/chemical/bme680: Fix SPI read interface

2019-03-16 Thread Mike Looijmans
On 16-03-19 11:24, Himanshu Jha wrote:
> On Wed, Mar 06, 2019 at 08:31:48AM +0100, Mike Looijmans wrote:
>> The SPI interface implementation was completely broken.
>>
>> When using the SPI interface, there are only 7 address bits, the upper bit
>> is controlled by a page select register. The core needs access to both
>> ranges, so implement register read/write for both regions. The regmap
>> paging functionality didn't agree with a register that needs to be read
>> and modified, so I implemented a custom paging algorithm.
>>
>> This fixes that the device wouldn't even probe in SPI mode.
>>
>> The SPI interface then isn't different from I2C, merged them into the core,
>> and the I2C/SPI named registers are no longer needed.
>>
>> Implemented register value caching for the registers to reduce the I2C/SPI
>> data transfers considerably.
>>
>> The calibration set reads as all zeroes until some undefined point in time,
>> and I couldn't determine what makes it valid. The datasheet mentions these
>> registers but does not provide any hints on when they become valid, and they
>> aren't even enumerated in the memory map. So check the calibration and
>> retry reading it from the device after each measurement until it provides
>> something valid.
>>
>> Signed-off-by: Mike Looijmans 
>> ---
> 
> I have been trying to test this patch in the past week and still it
> failed everytime.
> 
> First I used ACPI to enumerate the device in QEMU setup:
> 
> Added some printks for debugging:
> 
> [   14.510198] bme680_spi spi-BME0680:00: Jumping to core driver now ...
> [   14.544528] bme680_spi spi-BME0680:00: Page setting done, on Page :0 now
> [   14.554363] bme680_spi spi-BME0680:00: bme680_regmap_spi_write: on Page :0 
> now
> [   14.556151] bme680_spi spi-BME0680:00: bme680_regmap_spi_read: on Page :0 
> now
> [   14.567815] bme680_spi spi-BME0680:00: Wrong chip ID, got ff expected 61
> 

Looks like the SPI communication isn't working. At this point I'd check 
the wires using an osciloscope or analyzer or something.


> I also tried bypassing this by removing the following snippet and force
> registration to see what happens next:
> 
>   > + ret = regmap_write(regmap, BME680_REG_SOFT_RESET,
>   > +BME680_CMD_SOFTRESET);
>   > + if (ret < 0) {
>   > + dev_err(dev, "Failed to reset chip\n");
>   > + return ret;
>   > + }
>   > +
>   > + ret = regmap_read(regmap, BME680_REG_CHIP_ID, );
>   > + if (ret < 0) {
>   > + dev_err(dev, "Error reading chip ID\n");
>   > + return ret;
>   > + }
>   > +
>   > + if (val != BME680_CHIP_ID_VAL) {
>   > + dev_err(dev, "Wrong chip ID, got %x expected %x\n",
>   > + val, BME680_CHIP_ID_VAL);
>   > + return -ENODEV;
>   > + }
>   > +
> 
> And it registered successfully, but all the bme680 attributes were
> giving wrong values like temp was constant to 0.007, resistance
> was resource busy due to insuffient target temperature error.
> Pretty eveything was messed up at this stage.

Makes perfect sense if it's unable to read the registers.

If you cannot read the chip ID, nothing will work, no point skipping that.

> Then I build and booted the kernel on BeagleBone Black Wireless with
> DT matching this time:
> 
> debian@beaglebone:~$ uname -a
> Linux beaglebone 4.19.5-ti-r5 #1xross SMP PREEMPT Sat Mar 16 12:11:50 IST 
> 2019 armv7l GNU/Linux
> debian@beaglebone:~$ dmesg | grep 'bme680'
> [   30.269207] bme680_spi spi0.0: Wrong chip ID, got ff expected 61
> [  361.867410] bme680_core: disagrees about version of symbol module_layout

Looks like a compilation problem with your kernel module?

> debian@beaglebone:~$ lsmod | grep 'bme'
> bme680_spi 16384  0
> bme680_core20480  1 bme680_spi
> debian@beaglebone:~$ cat /sys/bus/spi/devices/spi0.0/
> modaliasof_node/power/  statistics/ subsystem/  uevent
> debian@beaglebone:~$ cat /sys/bus/spi/devices/spi0.0/modalias
> spi:bme680
> debian@beaglebone:~$ cat /sys/bus/spi/devices/spi0.0/of_node/
> compatible name   regspi-max-frequency
> debian@beaglebone:~$ cat /sys/bus/spi/devices/spi0.0/of_node/compatible
> bme680
> debian@beaglebone:~$ cat /sys/bus/spi/devices/spi0.0/of_node/name
> bme680
> debian@beaglebone:~$ dtc -f -I fs /proc/device-tree | grep -A3 'bme680'
>  bme680@0 {
>  compatible = "bme680&q

[PATCH v3 1/2] iio/chemical/bme680: Report temperature in millidegrees

2019-03-05 Thread Mike Looijmans
The standard unit for temperature is millidegrees Celcius. Adapt the
driver to report in millidegrees instead of degrees.

Signed-off-by: Mike Looijmans 
---
v2: Remove unused 'addr7' variable  
 
v3: Split patch into temperature and SPI

 drivers/iio/chemical/bme680_core.c | 16 +++-
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/drivers/iio/chemical/bme680_core.c 
b/drivers/iio/chemical/bme680_core.c
index 70c1fe4..fefe32b 100644
--- a/drivers/iio/chemical/bme680_core.c
+++ b/drivers/iio/chemical/bme680_core.c
@@ -583,8 +583,7 @@ static int bme680_gas_config(struct bme680_data *data)
return ret;
 }
 
-static int bme680_read_temp(struct bme680_data *data,
-   int *val, int *val2)
+static int bme680_read_temp(struct bme680_data *data, int *val)
 {
struct device *dev = regmap_get_device(data->regmap);
int ret;
@@ -617,10 +616,9 @@ static int bme680_read_temp(struct bme680_data *data,
 * compensate_press/compensate_humid to get compensated
 * pressure/humidity readings.
 */
-   if (val && val2) {
-   *val = comp_temp;
-   *val2 = 100;
-   return IIO_VAL_FRACTIONAL;
+   if (val) {
+   *val = comp_temp * 10; /* Centidegrees to millidegrees */
+   return IIO_VAL_INT;
}
 
return ret;
@@ -635,7 +633,7 @@ static int bme680_read_press(struct bme680_data *data,
s32 adc_press;
 
/* Read and compensate temperature to get a reading of t_fine */
-   ret = bme680_read_temp(data, NULL, NULL);
+   ret = bme680_read_temp(data, NULL);
if (ret < 0)
return ret;
 
@@ -668,7 +666,7 @@ static int bme680_read_humid(struct bme680_data *data,
u32 comp_humidity;
 
/* Read and compensate temperature to get a reading of t_fine */
-   ret = bme680_read_temp(data, NULL, NULL);
+   ret = bme680_read_temp(data, NULL);
if (ret < 0)
return ret;
 
@@ -761,7 +759,7 @@ static int bme680_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_TEMP:
-   return bme680_read_temp(data, val, val2);
+   return bme680_read_temp(data, val);
case IIO_PRESSURE:
return bme680_read_press(data, val, val2);
case IIO_HUMIDITYRELATIVE:
-- 
1.9.1



[PATCH v3 2/2] iio/chemical/bme680: Fix SPI read interface

2019-03-05 Thread Mike Looijmans
The SPI interface implementation was completely broken.

When using the SPI interface, there are only 7 address bits, the upper bit
is controlled by a page select register. The core needs access to both
ranges, so implement register read/write for both regions. The regmap
paging functionality didn't agree with a register that needs to be read
and modified, so I implemented a custom paging algorithm.

This fixes that the device wouldn't even probe in SPI mode.

The SPI interface then isn't different from I2C, merged them into the core,
and the I2C/SPI named registers are no longer needed.

Implemented register value caching for the registers to reduce the I2C/SPI
data transfers considerably.

The calibration set reads as all zeroes until some undefined point in time,
and I couldn't determine what makes it valid. The datasheet mentions these
registers but does not provide any hints on when they become valid, and they
aren't even enumerated in the memory map. So check the calibration and
retry reading it from the device after each measurement until it provides
something valid.

Signed-off-by: Mike Looijmans 
---
v2: Remove unused 'addr7' variable
v3: Split patch into temperature and SPI

 drivers/iio/chemical/bme680.h  |   6 +-
 drivers/iio/chemical/bme680_core.c |  38 
 drivers/iio/chemical/bme680_i2c.c  |  21 ---
 drivers/iio/chemical/bme680_spi.c  | 115 +
 4 files changed, 118 insertions(+), 62 deletions(-)

diff --git a/drivers/iio/chemical/bme680.h b/drivers/iio/chemical/bme680.h
index 0ae89b87..4edc5d21 100644
--- a/drivers/iio/chemical/bme680.h
+++ b/drivers/iio/chemical/bme680.h
@@ -2,11 +2,9 @@
 #ifndef BME680_H_
 #define BME680_H_
 
-#define BME680_REG_CHIP_I2C_ID 0xD0
-#define BME680_REG_CHIP_SPI_ID 0x50
+#define BME680_REG_CHIP_ID 0xD0
 #define   BME680_CHIP_ID_VAL   0x61
-#define BME680_REG_SOFT_RESET_I2C  0xE0
-#define BME680_REG_SOFT_RESET_SPI  0x60
+#define BME680_REG_SOFT_RESET  0xE0
 #define   BME680_CMD_SOFTRESET 0xB6
 #define BME680_REG_STATUS  0x73
 #define   BME680_SPI_MEM_PAGE_BIT  BIT(4)
diff --git a/drivers/iio/chemical/bme680_core.c 
b/drivers/iio/chemical/bme680_core.c
index fefe32b..ccde4c6 100644
--- a/drivers/iio/chemical/bme680_core.c
+++ b/drivers/iio/chemical/bme680_core.c
@@ -63,9 +63,23 @@ struct bme680_data {
s32 t_fine;
 };
 
+static const struct regmap_range bme680_volatile_ranges[] = {
+   regmap_reg_range(BME680_REG_MEAS_STAT_0, BME680_REG_GAS_R_LSB),
+   regmap_reg_range(BME680_REG_STATUS, BME680_REG_STATUS),
+   regmap_reg_range(BME680_T2_LSB_REG, BME680_GH3_REG),
+};
+
+static const struct regmap_access_table bme680_volatile_table = {
+   .yes_ranges = bme680_volatile_ranges,
+   .n_yes_ranges   = ARRAY_SIZE(bme680_volatile_ranges),
+};
+
 const struct regmap_config bme680_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
+   .max_register = 0xef,
+   .volatile_table = _volatile_table,
+   .cache_type = REGCACHE_RBTREE,
 };
 EXPORT_SYMBOL(bme680_regmap_config);
 
@@ -316,6 +330,10 @@ static s16 bme680_compensate_temp(struct bme680_data *data,
s64 var1, var2, var3;
s16 calc_temp;
 
+   /* If the calibration is invalid, attempt to reload it */
+   if (!calib->par_t2)
+   bme680_read_calib(data, calib);
+
var1 = (adc_temp >> 3) - (calib->par_t1 << 1);
var2 = (var1 * calib->par_t2) >> 11;
var3 = ((var1 >> 1) * (var1 >> 1)) >> 12;
@@ -865,8 +883,28 @@ int bme680_core_probe(struct device *dev, struct regmap 
*regmap,
 {
struct iio_dev *indio_dev;
struct bme680_data *data;
+   unsigned int val;
int ret;
 
+   ret = regmap_write(regmap, BME680_REG_SOFT_RESET,
+  BME680_CMD_SOFTRESET);
+   if (ret < 0) {
+   dev_err(dev, "Failed to reset chip\n");
+   return ret;
+   }
+
+   ret = regmap_read(regmap, BME680_REG_CHIP_ID, );
+   if (ret < 0) {
+   dev_err(dev, "Error reading chip ID\n");
+   return ret;
+   }
+
+   if (val != BME680_CHIP_ID_VAL) {
+   dev_err(dev, "Wrong chip ID, got %x expected %x\n",
+   val, BME680_CHIP_ID_VAL);
+   return -ENODEV;
+   }
+
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
diff --git a/drivers/iio/chemical/bme680_i2c.c 
b/drivers/iio/chemical/bme680_i2c.c
index 06d4be5..cfc4449 100644
--- a/drivers/iio/chemical/bme680_i2c.c
+++ b/drivers/iio/chemical/bme680_i2c.c
@@ -23,8 +23,6 @@ static int bme680_i2c_probe(struct i2c_client *client,
 {
struct regmap *regmap;
con

Re: [PATCH v2] iio/chemical/bme680: Fix SPI read interface

2019-03-05 Thread Mike Looijmans
On 03-03-19 17:57, Jonathan Cameron wrote:
> On Thu, 21 Feb 2019 10:20:49 +0100
> Mike Looijmans  wrote:
> 
>> The SPI interface implementation was completely broken.
>>
>> When using the SPI interface, there are only 7 address bits, the upper bit
>> is controlled by a page select register. The core needs access to both
>> ranges, so implement register read/write for both regions. The regmap
>> paging functionality didn't agree with a register that needs to be read
>> and modified, so I implemented a custom paging algorithm.
>>
>> This fixes that the device wouldn't even probe in SPI mode.
>>
>> The SPI interface then isn't different from I2C, merged them into the core,
>> and the I2C/SPI named registers are no longer needed.
>>
>> Implemented register value caching for the registers to reduce the I2C/SPI
>> data transfers considerably.
>>
>> The calibration set reads as all zeroes until some undefined point in time,
>> and I couldn't determine what makes it valid. The datasheet mentions these
>> registers but does not provide any hints on when they become valid, and they
>> aren't even enumerated in the memory map. So check the calibration and
>> retry reading it from the device after each measurement until it provides
>> something valid.
>>
>> Report temperature in millidegrees Celcius instead of degrees.
> Hi Mike,
> 
> This last bit is an unrelated issue. Would you mind splitting the patch into 
> two?
> Please put the temperature one first as that is definitely a stable
> worthy patch.  The larger one is more debatable as it seems that it
> never worked and is a fairly large patch.
> 
> I'll probably mark them both for stable, but it is possible not all
> the stable branches will pick them both up.

Splitting the patch was easy enough, the're independent, I'll post a v3 with 
both patches.


> 
> Thanks,
> 
> Jonathan
> 
>>
>> Signed-off-by: Mike Looijmans 
>> ---
>> v2: Remove unused 'addr7' variable
>>
>>   drivers/iio/chemical/bme680.h  |   6 +-
>>   drivers/iio/chemical/bme680_core.c |  54 ++---
>>   drivers/iio/chemical/bme680_i2c.c  |  21 ---
>>   drivers/iio/chemical/bme680_spi.c  | 115 
>> +
>>   4 files changed, 125 insertions(+), 71 deletions(-)
>>
>> diff --git a/drivers/iio/chemical/bme680.h b/drivers/iio/chemical/bme680.h
>> index 0ae89b87..4edc5d21 100644
>> --- a/drivers/iio/chemical/bme680.h
>> +++ b/drivers/iio/chemical/bme680.h
>> @@ -2,11 +2,9 @@
>>   #ifndef BME680_H_
>>   #define BME680_H_
>>   
>> -#define BME680_REG_CHIP_I2C_ID  0xD0
>> -#define BME680_REG_CHIP_SPI_ID  0x50
>> +#define BME680_REG_CHIP_ID  0xD0
>>   #define   BME680_CHIP_ID_VAL   0x61
>> -#define BME680_REG_SOFT_RESET_I2C   0xE0
>> -#define BME680_REG_SOFT_RESET_SPI   0x60
>> +#define BME680_REG_SOFT_RESET   0xE0
>>   #define   BME680_CMD_SOFTRESET 0xB6
>>   #define BME680_REG_STATUS  0x73
>>   #define   BME680_SPI_MEM_PAGE_BIT  BIT(4)
>> diff --git a/drivers/iio/chemical/bme680_core.c 
>> b/drivers/iio/chemical/bme680_core.c
>> index 70c1fe4..ccde4c6 100644
>> --- a/drivers/iio/chemical/bme680_core.c
>> +++ b/drivers/iio/chemical/bme680_core.c
>> @@ -63,9 +63,23 @@ struct bme680_data {
>>  s32 t_fine;
>>   };
>>   
>> +static const struct regmap_range bme680_volatile_ranges[] = {
>> +regmap_reg_range(BME680_REG_MEAS_STAT_0, BME680_REG_GAS_R_LSB),
>> +regmap_reg_range(BME680_REG_STATUS, BME680_REG_STATUS),
>> +regmap_reg_range(BME680_T2_LSB_REG, BME680_GH3_REG),
>> +};
>> +
>> +static const struct regmap_access_table bme680_volatile_table = {
>> +.yes_ranges = bme680_volatile_ranges,
>> +.n_yes_ranges   = ARRAY_SIZE(bme680_volatile_ranges),
>> +};
>> +
>>   const struct regmap_config bme680_regmap_config = {
>>  .reg_bits = 8,
>>  .val_bits = 8,
>> +.max_register = 0xef,
>> +.volatile_table = _volatile_table,
>> +.cache_type = REGCACHE_RBTREE,
>>   };
>>   EXPORT_SYMBOL(bme680_regmap_config);
>>   
>> @@ -316,6 +330,10 @@ static s16 bme680_compensate_temp(struct bme680_data 
>> *data,
>>  s64 var1, var2, var3;
>>  s16 calc_temp;
>>   
>> +/* If the calibration is invalid, attempt to reload it */
>> +if (!calib->par_t2)
>> +bme680_read_ca

[PATCH v2] iio/chemical/bme680: Fix SPI read interface

2019-02-21 Thread Mike Looijmans
The SPI interface implementation was completely broken.

When using the SPI interface, there are only 7 address bits, the upper bit
is controlled by a page select register. The core needs access to both
ranges, so implement register read/write for both regions. The regmap
paging functionality didn't agree with a register that needs to be read
and modified, so I implemented a custom paging algorithm.

This fixes that the device wouldn't even probe in SPI mode.

The SPI interface then isn't different from I2C, merged them into the core,
and the I2C/SPI named registers are no longer needed.

Implemented register value caching for the registers to reduce the I2C/SPI
data transfers considerably.

The calibration set reads as all zeroes until some undefined point in time,
and I couldn't determine what makes it valid. The datasheet mentions these
registers but does not provide any hints on when they become valid, and they
aren't even enumerated in the memory map. So check the calibration and
retry reading it from the device after each measurement until it provides
something valid.

Report temperature in millidegrees Celcius instead of degrees.

Signed-off-by: Mike Looijmans 
---
v2: Remove unused 'addr7' variable

 drivers/iio/chemical/bme680.h  |   6 +-
 drivers/iio/chemical/bme680_core.c |  54 ++---
 drivers/iio/chemical/bme680_i2c.c  |  21 ---
 drivers/iio/chemical/bme680_spi.c  | 115 +
 4 files changed, 125 insertions(+), 71 deletions(-)

diff --git a/drivers/iio/chemical/bme680.h b/drivers/iio/chemical/bme680.h
index 0ae89b87..4edc5d21 100644
--- a/drivers/iio/chemical/bme680.h
+++ b/drivers/iio/chemical/bme680.h
@@ -2,11 +2,9 @@
 #ifndef BME680_H_
 #define BME680_H_
 
-#define BME680_REG_CHIP_I2C_ID 0xD0
-#define BME680_REG_CHIP_SPI_ID 0x50
+#define BME680_REG_CHIP_ID 0xD0
 #define   BME680_CHIP_ID_VAL   0x61
-#define BME680_REG_SOFT_RESET_I2C  0xE0
-#define BME680_REG_SOFT_RESET_SPI  0x60
+#define BME680_REG_SOFT_RESET  0xE0
 #define   BME680_CMD_SOFTRESET 0xB6
 #define BME680_REG_STATUS  0x73
 #define   BME680_SPI_MEM_PAGE_BIT  BIT(4)
diff --git a/drivers/iio/chemical/bme680_core.c 
b/drivers/iio/chemical/bme680_core.c
index 70c1fe4..ccde4c6 100644
--- a/drivers/iio/chemical/bme680_core.c
+++ b/drivers/iio/chemical/bme680_core.c
@@ -63,9 +63,23 @@ struct bme680_data {
s32 t_fine;
 };
 
+static const struct regmap_range bme680_volatile_ranges[] = {
+   regmap_reg_range(BME680_REG_MEAS_STAT_0, BME680_REG_GAS_R_LSB),
+   regmap_reg_range(BME680_REG_STATUS, BME680_REG_STATUS),
+   regmap_reg_range(BME680_T2_LSB_REG, BME680_GH3_REG),
+};
+
+static const struct regmap_access_table bme680_volatile_table = {
+   .yes_ranges = bme680_volatile_ranges,
+   .n_yes_ranges   = ARRAY_SIZE(bme680_volatile_ranges),
+};
+
 const struct regmap_config bme680_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
+   .max_register = 0xef,
+   .volatile_table = _volatile_table,
+   .cache_type = REGCACHE_RBTREE,
 };
 EXPORT_SYMBOL(bme680_regmap_config);
 
@@ -316,6 +330,10 @@ static s16 bme680_compensate_temp(struct bme680_data *data,
s64 var1, var2, var3;
s16 calc_temp;
 
+   /* If the calibration is invalid, attempt to reload it */
+   if (!calib->par_t2)
+   bme680_read_calib(data, calib);
+
var1 = (adc_temp >> 3) - (calib->par_t1 << 1);
var2 = (var1 * calib->par_t2) >> 11;
var3 = ((var1 >> 1) * (var1 >> 1)) >> 12;
@@ -583,8 +601,7 @@ static int bme680_gas_config(struct bme680_data *data)
return ret;
 }
 
-static int bme680_read_temp(struct bme680_data *data,
-   int *val, int *val2)
+static int bme680_read_temp(struct bme680_data *data, int *val)
 {
struct device *dev = regmap_get_device(data->regmap);
int ret;
@@ -617,10 +634,9 @@ static int bme680_read_temp(struct bme680_data *data,
 * compensate_press/compensate_humid to get compensated
 * pressure/humidity readings.
 */
-   if (val && val2) {
-   *val = comp_temp;
-   *val2 = 100;
-   return IIO_VAL_FRACTIONAL;
+   if (val) {
+   *val = comp_temp * 10; /* Centidegrees to millidegrees */
+   return IIO_VAL_INT;
}
 
return ret;
@@ -635,7 +651,7 @@ static int bme680_read_press(struct bme680_data *data,
s32 adc_press;
 
/* Read and compensate temperature to get a reading of t_fine */
-   ret = bme680_read_temp(data, NULL, NULL);
+   ret = bme680_read_temp(data, NULL);
if (ret < 0)
return ret;
 
@@ -668,7 +684,7 @@ static int bme680_read_humid(struct bme680_data *data,
u32 comp_hu

Re: [PATCH] iio/chemical/bme680: Fix SPI read interface

2019-02-17 Thread Mike Looijmans
On 16-02-19 12:27, Himanshu Jha wrote:
> Hello Mike,
> 
> On Fri, Feb 15, 2019 at 02:47:55PM +0100, Mike Looijmans wrote:
>> The SPI interface implementation was completely broken.
> 
> My apologies!
> 
> SPI interface caused me a lot of trouble in my project timeline. I tried
> many different ways to try playing with acpi dsl, printks etc. One
> of the problem was also that we don't have any facility such `i2cdetect`
> or instantiate a `new_device` from userspace.
> 
> Are there any methods that one should try to debug SPIs ?
>   -- excluding the use of Oscilloscope

Just persisting usually makes it work... Once you're able to read a single 
register, the rest is peanuts...

> With all these problems, I referred other drivers from the Bosch family,
> particularly BME280 which has exactly the same behavior and decided to
> do the same. I believed that it would also work cleanly for BME680 and
> now I see the page selection fuzz was the main problem.
> 
> I tried to test it on Beaglebone but everytime something new pops-up
> with beagle setup such as they moved from capemgr -> uboot overlays.
> Lack of latest documentation on "What new in this release?" troubled me
> + most of blogs on setup are outdated.
> 
>> When using the SPI interface, there are only 7 address bits, the upper bit
>> is controlled by a page select register.
> 
> Isn't it that upper bit is controlled R/W ?

I meant the upper 'address' bit here. Bit 7 of the first byte indeed controls 
read/write like on many register-controlled SPI devices (see regmap's standard 
SPI implementation).

> And one question that I have in mind:
> 
> Initially after poweron we are in page 0, and hence we can't access
> Page 1 which actually has the `spi_mem_page` bit. So, how can we switch
> to Page 1 eventually since Page 1 covers all the relevant data/config
> registers ?

My approach was to just assume that the register would work in either page, 
and that turned out to be correct. Most 'paging' chips work that way. Though 
they typically use register 0 or 255 for that.

> I assume if you're in Page 0, then you can't access Page 1 registers or
> simply put those registers are not visible.
> 
> Some inconsistency in datasheet:
> 
> Page 24/50:
> 
> "After power-on, spi_mem_page is in its reset state and page 0 (0x80 to 0xFF)
> will be active. Page 1 (0x00 to 0x7F) will be
> active on setting spi_mem_page to 1."
> 
> OTOH,
> 
> Page 26/50:
> 
> "5.3.1.4 SPI memory map page selection – spi_mem_page
> 
> In SPI mode complete memory page is accessed using page 0 & page 1.
> Register spi_mem_page is used for page selection.
> After power-on, spi_mem_page is in its reset state and
> page 0(0x00 to 0x7F) will be active."
> 
> 
> That's contradicting!

They fell into their own trap of calling the high range "page 0" I guess.

In this context, it's also meaningless. Upon probe, you cannot really be sure 
which page is active anyway, and the chip doesn't have a reset GPIO to enforce 
a known startup state. So "assume nothing" is the way forward.


>   page 0 (0x80 to 0xFF) Vs page 0(0x00 to 0x7F) ?
> 
>> The core needs access to both
>> ranges, so implement register read/write for both regions. The regmap
>> paging functionality didn't agree with a register that needs to be read
>> and modified, so I implemented a custom paging algorithm.
>>
>> This fixes that the device wouldn't even probe in SPI mode.
> 
> Most importantly: Does it now work for you ?

Yes, with these changes the chip works (I have it connected to SPI only).

> As I tried you patch and it is not working for me in my QEMU setup.
> 
>   /sys/bus/iio/devices # lsmod
>   Module  Size  Used byTainted: G
>   bme680_spi 16384  0
>   bme680_core24576  1 bme680_spi
>   /sys/bus/iio/devices # ls
> 
> SPI didn't probe and no logs for any errors/warnings as well.

Probably it isn't in the devicetree then. Mine looks like this:

+ {
+   status = "okay";
+   num-cs = <2>;
+
+   /* Environmental Sensor */
+   bme680_env: bme680_env@0 {
+   compatible = "bme680";
+   reg = <0>;
+   spi-max-frequency = <1000>;
+   };


> Maybe I'll give it try again later on a different board or a native
> build+boot on the current board.
> 
> Anyway, does anyone has any idea/clues for writing a dt-overlay for
> am335x-boneblack-wireless.dts to add just a compatible property to
> probe bme680_spi driver ?
> 
>> The SPI interface then isn't different from I2C, merged them into the core,
>> and the I2C/SPI named registers are

[PATCH] iio/chemical/bme680: Fix SPI read interface

2019-02-15 Thread Mike Looijmans
The SPI interface implementation was completely broken.

When using the SPI interface, there are only 7 address bits, the upper bit
is controlled by a page select register. The core needs access to both
ranges, so implement register read/write for both regions. The regmap
paging functionality didn't agree with a register that needs to be read
and modified, so I implemented a custom paging algorithm.

This fixes that the device wouldn't even probe in SPI mode.

The SPI interface then isn't different from I2C, merged them into the core,
and the I2C/SPI named registers are no longer needed.

Implemented register value caching for the registers to reduce the I2C/SPI
data transfers considerably.

The calibration set reads as all zeroes until some undefined point in time,
and I couldn't determine what makes it valid. The datasheet mentions these
registers but does not provide any hints on when they become valid, and they
aren't even enumerated in the memory map. So check the calibration and
retry reading it from the device after each measurement until it provides
something valid.

Report temperature in millidegrees Celcius instead of degrees.

Signed-off-by: Mike Looijmans 
---
 drivers/iio/chemical/bme680.h  |   6 +-
 drivers/iio/chemical/bme680_core.c |  54 ++---
 drivers/iio/chemical/bme680_i2c.c  |  21 ---
 drivers/iio/chemical/bme680_spi.c  | 116 +
 4 files changed, 126 insertions(+), 71 deletions(-)

diff --git a/drivers/iio/chemical/bme680.h b/drivers/iio/chemical/bme680.h
index 0ae89b87..4edc5d21 100644
--- a/drivers/iio/chemical/bme680.h
+++ b/drivers/iio/chemical/bme680.h
@@ -2,11 +2,9 @@
 #ifndef BME680_H_
 #define BME680_H_
 
-#define BME680_REG_CHIP_I2C_ID 0xD0
-#define BME680_REG_CHIP_SPI_ID 0x50
+#define BME680_REG_CHIP_ID 0xD0
 #define   BME680_CHIP_ID_VAL   0x61
-#define BME680_REG_SOFT_RESET_I2C  0xE0
-#define BME680_REG_SOFT_RESET_SPI  0x60
+#define BME680_REG_SOFT_RESET  0xE0
 #define   BME680_CMD_SOFTRESET 0xB6
 #define BME680_REG_STATUS  0x73
 #define   BME680_SPI_MEM_PAGE_BIT  BIT(4)
diff --git a/drivers/iio/chemical/bme680_core.c 
b/drivers/iio/chemical/bme680_core.c
index 70c1fe4..ccde4c6 100644
--- a/drivers/iio/chemical/bme680_core.c
+++ b/drivers/iio/chemical/bme680_core.c
@@ -63,9 +63,23 @@ struct bme680_data {
s32 t_fine;
 };
 
+static const struct regmap_range bme680_volatile_ranges[] = {
+   regmap_reg_range(BME680_REG_MEAS_STAT_0, BME680_REG_GAS_R_LSB),
+   regmap_reg_range(BME680_REG_STATUS, BME680_REG_STATUS),
+   regmap_reg_range(BME680_T2_LSB_REG, BME680_GH3_REG),
+};
+
+static const struct regmap_access_table bme680_volatile_table = {
+   .yes_ranges = bme680_volatile_ranges,
+   .n_yes_ranges   = ARRAY_SIZE(bme680_volatile_ranges),
+};
+
 const struct regmap_config bme680_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
+   .max_register = 0xef,
+   .volatile_table = _volatile_table,
+   .cache_type = REGCACHE_RBTREE,
 };
 EXPORT_SYMBOL(bme680_regmap_config);
 
@@ -316,6 +330,10 @@ static s16 bme680_compensate_temp(struct bme680_data *data,
s64 var1, var2, var3;
s16 calc_temp;
 
+   /* If the calibration is invalid, attempt to reload it */
+   if (!calib->par_t2)
+   bme680_read_calib(data, calib);
+
var1 = (adc_temp >> 3) - (calib->par_t1 << 1);
var2 = (var1 * calib->par_t2) >> 11;
var3 = ((var1 >> 1) * (var1 >> 1)) >> 12;
@@ -583,8 +601,7 @@ static int bme680_gas_config(struct bme680_data *data)
return ret;
 }
 
-static int bme680_read_temp(struct bme680_data *data,
-   int *val, int *val2)
+static int bme680_read_temp(struct bme680_data *data, int *val)
 {
struct device *dev = regmap_get_device(data->regmap);
int ret;
@@ -617,10 +634,9 @@ static int bme680_read_temp(struct bme680_data *data,
 * compensate_press/compensate_humid to get compensated
 * pressure/humidity readings.
 */
-   if (val && val2) {
-   *val = comp_temp;
-   *val2 = 100;
-   return IIO_VAL_FRACTIONAL;
+   if (val) {
+   *val = comp_temp * 10; /* Centidegrees to millidegrees */
+   return IIO_VAL_INT;
}
 
return ret;
@@ -635,7 +651,7 @@ static int bme680_read_press(struct bme680_data *data,
s32 adc_press;
 
/* Read and compensate temperature to get a reading of t_fine */
-   ret = bme680_read_temp(data, NULL, NULL);
+   ret = bme680_read_temp(data, NULL);
if (ret < 0)
return ret;
 
@@ -668,7 +684,7 @@ static int bme680_read_humid(struct bme680_data *data,
u32 comp_humidity;
 
/* Read and compe

[PATCH v2] iio/gyro/bmg160: Use millidegrees for temperature scale

2019-02-12 Thread Mike Looijmans
Standard unit for temperature is millidegrees Celcius, whereas this driver
was reporting in degrees. Fix the scale factor in the driver.

Signed-off-by: Mike Looijmans 
---
v2: Don't touch val2 when returning IIO_VAL_INT
Only touch val when returning a value

 drivers/iio/gyro/bmg160_core.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c
index 63ca316..92c07ab 100644
--- a/drivers/iio/gyro/bmg160_core.c
+++ b/drivers/iio/gyro/bmg160_core.c
@@ -582,11 +582,10 @@ static int bmg160_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
return bmg160_get_filter(data, val);
case IIO_CHAN_INFO_SCALE:
-   *val = 0;
switch (chan->type) {
case IIO_TEMP:
-   *val2 = 50;
-   return IIO_VAL_INT_PLUS_MICRO;
+   *val = 500;
+   return IIO_VAL_INT;
case IIO_ANGL_VEL:
{
int i;
@@ -594,6 +593,7 @@ static int bmg160_read_raw(struct iio_dev *indio_dev,
for (i = 0; i < ARRAY_SIZE(bmg160_scale_table); ++i) {
if (bmg160_scale_table[i].dps_range ==
data->dps_range) {
+   *val = 0;
*val2 = bmg160_scale_table[i].scale;
return IIO_VAL_INT_PLUS_MICRO;
}
-- 
1.9.1



Re: [PATCH] iio/gyro/bmg160: Use millidegrees for temperature scale

2019-02-12 Thread Mike Looijmans
On 12-02-19 18:00, Tomasz Duszynski wrote:
> On Tue, Feb 12, 2019 at 03:25:49PM +0100, Mike Looijmans wrote:
>> Standard unit for temperature is millidegrees Celcius, whereas this driver
>> was reporting in degrees. Fix the scale factor in the driver.
>>
>> Signed-off-by: Mike Looijmans 
>> ---
>>   drivers/iio/gyro/bmg160_core.c | 5 +++--
>>   1 file changed, 3 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c
>> index 63ca316..ad7f8cb 100644
>> --- a/drivers/iio/gyro/bmg160_core.c
>> +++ b/drivers/iio/gyro/bmg160_core.c
>> @@ -585,8 +585,9 @@ static int bmg160_read_raw(struct iio_dev *indio_dev,
>>  *val = 0;
>>  switch (chan->type) {
>>  case IIO_TEMP:
>> -*val2 = 50;
>> -return IIO_VAL_INT_PLUS_MICRO;
>> +*val = 500;
>> +*val2 = 0;
>> +return IIO_VAL_INT;
> 
> You are returning integer type to iio so there's no point in touching
> val2. iio will ignore it anyway.

Indeed, I'll post a v2 for that.

> 
>>  case IIO_ANGL_VEL:
>>  {
>>  int i;
>> --
>> 1.9.1
>>



[PATCH] iio/gyro/bmg160: Use millidegrees for temperature scale

2019-02-12 Thread Mike Looijmans
Standard unit for temperature is millidegrees Celcius, whereas this driver
was reporting in degrees. Fix the scale factor in the driver.

Signed-off-by: Mike Looijmans 
---
 drivers/iio/gyro/bmg160_core.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c
index 63ca316..ad7f8cb 100644
--- a/drivers/iio/gyro/bmg160_core.c
+++ b/drivers/iio/gyro/bmg160_core.c
@@ -585,8 +585,9 @@ static int bmg160_read_raw(struct iio_dev *indio_dev,
*val = 0;
switch (chan->type) {
case IIO_TEMP:
-   *val2 = 50;
-   return IIO_VAL_INT_PLUS_MICRO;
+   *val = 500;
+   *val2 = 0;
+   return IIO_VAL_INT;
case IIO_ANGL_VEL:
{
int i;
-- 
1.9.1



[PATCH v2] zynq-fpga: Only route PR via PCAP when required

2018-10-24 Thread Mike Looijmans
The Xilinx Zynq FPGA driver takes ownership of the PR interface, making
it impossible to use the ICAP interface for partial reconfiguration.

This patch changes the driver to only activate PR over PCAP while the
device is actively being accessed by the driver for programming.

This allows both PCAP and ICAP interfaces to be used for PR.

Signed-off-by: Mike Looijmans 
Reviewed-by: Moritz Fischer 
---
v2: Move the register setting in between the clock enable/disable

 drivers/fpga/zynq-fpga.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c
index 3110e00..ff3a427 100644
--- a/drivers/fpga/zynq-fpga.c
+++ b/drivers/fpga/zynq-fpga.c
@@ -501,6 +501,10 @@ static int zynq_fpga_ops_write_complete(struct 
fpga_manager *mgr,
if (err)
return err;
 
+   /* Release 'PR' control back to the ICAP */
+   zynq_fpga_write(priv, CTRL_OFFSET,
+   zynq_fpga_read(priv, CTRL_OFFSET) & ~CTRL_PCAP_PR_MASK);
+
err = zynq_fpga_poll_timeout(priv, INT_STS_OFFSET, intr_status,
 intr_status & IXR_PCFG_DONE_MASK,
 INIT_POLL_DELAY,
-- 
1.9.1



[PATCH v2] zynq-fpga: Only route PR via PCAP when required

2018-10-24 Thread Mike Looijmans
The Xilinx Zynq FPGA driver takes ownership of the PR interface, making
it impossible to use the ICAP interface for partial reconfiguration.

This patch changes the driver to only activate PR over PCAP while the
device is actively being accessed by the driver for programming.

This allows both PCAP and ICAP interfaces to be used for PR.

Signed-off-by: Mike Looijmans 
Reviewed-by: Moritz Fischer 
---
v2: Move the register setting in between the clock enable/disable

 drivers/fpga/zynq-fpga.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c
index 3110e00..ff3a427 100644
--- a/drivers/fpga/zynq-fpga.c
+++ b/drivers/fpga/zynq-fpga.c
@@ -501,6 +501,10 @@ static int zynq_fpga_ops_write_complete(struct 
fpga_manager *mgr,
if (err)
return err;
 
+   /* Release 'PR' control back to the ICAP */
+   zynq_fpga_write(priv, CTRL_OFFSET,
+   zynq_fpga_read(priv, CTRL_OFFSET) & ~CTRL_PCAP_PR_MASK);
+
err = zynq_fpga_poll_timeout(priv, INT_STS_OFFSET, intr_status,
 intr_status & IXR_PCFG_DONE_MASK,
 INIT_POLL_DELAY,
-- 
1.9.1



Re: [PATCH] zynq-fpga: Only route PR via PCAP when required

2018-10-23 Thread Mike Looijmans
On 23-10-18 11:01, Moritz Fischer wrote:
> Hi Mike,
> 
> seems like a good usecase (though uncommon), question below

Usecases for ICAP:
- It's considerably faster than PCAP
- Self-repairing logic (e.g. single-event upsets)
- Being programmed from a remote FPGA
- Programming through another bus (e.g. PCIe)


> 
> On Tue, Oct 23, 2018 at 08:31:19AM +0200, Mike Looijmans wrote:
>> The Xilinx Zynq FPGA driver takes ownership of the PR interface, making
>> it impossible to use the ICAP interface for partial reconfiguration.
>>
>> This patch changes the driver to only activate PR over PCAP while the
>> device is actively being accessed by the driver for programming.
>>
>> This allows both PCAP and ICAP interfaces to be used for PR.
>>
>> Signed-off-by: Mike Looijmans 
>> ---
>>   drivers/fpga/zynq-fpga.c | 4 
>>   1 file changed, 4 insertions(+)
>>
>> diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c
>> index 3110e00..f6c205a 100644
>> --- a/drivers/fpga/zynq-fpga.c
>> +++ b/drivers/fpga/zynq-fpga.c
>> @@ -497,6 +497,10 @@ static int zynq_fpga_ops_write_complete(struct 
>> fpga_manager *mgr,
>>  int err;
>>  u32 intr_status;
>>   
>> +/* Release 'PR' control back to the ICAP */
>> +zynq_fpga_write(priv, CTRL_OFFSET,
>> +zynq_fpga_read(priv, CTRL_OFFSET) & ~CTRL_PCAP_PR_MASK);
>> +
> 
> Shouldn't that be after the below stanza that enables the clock?

I'm actually not sure, and I did not encounter any problems while testing 
this, but it's easier to just move it than to find out, so I'll go for "yes, 
let's enable the clock first".
I'll await a bit more feedback and post a v2 for that.

> 
>>  err = clk_enable(priv->clk);
>>  if (err)
>>  return err;
>> -- 
>> 1.9.1
>>
> 
> Cheers,
> 
> Moritz
> 



Re: [PATCH] zynq-fpga: Only route PR via PCAP when required

2018-10-23 Thread Mike Looijmans
On 23-10-18 11:01, Moritz Fischer wrote:
> Hi Mike,
> 
> seems like a good usecase (though uncommon), question below

Usecases for ICAP:
- It's considerably faster than PCAP
- Self-repairing logic (e.g. single-event upsets)
- Being programmed from a remote FPGA
- Programming through another bus (e.g. PCIe)


> 
> On Tue, Oct 23, 2018 at 08:31:19AM +0200, Mike Looijmans wrote:
>> The Xilinx Zynq FPGA driver takes ownership of the PR interface, making
>> it impossible to use the ICAP interface for partial reconfiguration.
>>
>> This patch changes the driver to only activate PR over PCAP while the
>> device is actively being accessed by the driver for programming.
>>
>> This allows both PCAP and ICAP interfaces to be used for PR.
>>
>> Signed-off-by: Mike Looijmans 
>> ---
>>   drivers/fpga/zynq-fpga.c | 4 
>>   1 file changed, 4 insertions(+)
>>
>> diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c
>> index 3110e00..f6c205a 100644
>> --- a/drivers/fpga/zynq-fpga.c
>> +++ b/drivers/fpga/zynq-fpga.c
>> @@ -497,6 +497,10 @@ static int zynq_fpga_ops_write_complete(struct 
>> fpga_manager *mgr,
>>  int err;
>>  u32 intr_status;
>>   
>> +/* Release 'PR' control back to the ICAP */
>> +zynq_fpga_write(priv, CTRL_OFFSET,
>> +zynq_fpga_read(priv, CTRL_OFFSET) & ~CTRL_PCAP_PR_MASK);
>> +
> 
> Shouldn't that be after the below stanza that enables the clock?

I'm actually not sure, and I did not encounter any problems while testing 
this, but it's easier to just move it than to find out, so I'll go for "yes, 
let's enable the clock first".
I'll await a bit more feedback and post a v2 for that.

> 
>>  err = clk_enable(priv->clk);
>>  if (err)
>>  return err;
>> -- 
>> 1.9.1
>>
> 
> Cheers,
> 
> Moritz
> 



[PATCH] zynq-fpga: Only route PR via PCAP when required

2018-10-23 Thread Mike Looijmans
The Xilinx Zynq FPGA driver takes ownership of the PR interface, making
it impossible to use the ICAP interface for partial reconfiguration.

This patch changes the driver to only activate PR over PCAP while the
device is actively being accessed by the driver for programming.

This allows both PCAP and ICAP interfaces to be used for PR.

Signed-off-by: Mike Looijmans 
---
 drivers/fpga/zynq-fpga.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c
index 3110e00..f6c205a 100644
--- a/drivers/fpga/zynq-fpga.c
+++ b/drivers/fpga/zynq-fpga.c
@@ -497,6 +497,10 @@ static int zynq_fpga_ops_write_complete(struct 
fpga_manager *mgr,
int err;
u32 intr_status;
 
+   /* Release 'PR' control back to the ICAP */
+   zynq_fpga_write(priv, CTRL_OFFSET,
+   zynq_fpga_read(priv, CTRL_OFFSET) & ~CTRL_PCAP_PR_MASK);
+
err = clk_enable(priv->clk);
if (err)
return err;
-- 
1.9.1



[PATCH] zynq-fpga: Only route PR via PCAP when required

2018-10-23 Thread Mike Looijmans
The Xilinx Zynq FPGA driver takes ownership of the PR interface, making
it impossible to use the ICAP interface for partial reconfiguration.

This patch changes the driver to only activate PR over PCAP while the
device is actively being accessed by the driver for programming.

This allows both PCAP and ICAP interfaces to be used for PR.

Signed-off-by: Mike Looijmans 
---
 drivers/fpga/zynq-fpga.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c
index 3110e00..f6c205a 100644
--- a/drivers/fpga/zynq-fpga.c
+++ b/drivers/fpga/zynq-fpga.c
@@ -497,6 +497,10 @@ static int zynq_fpga_ops_write_complete(struct 
fpga_manager *mgr,
int err;
u32 intr_status;
 
+   /* Release 'PR' control back to the ICAP */
+   zynq_fpga_write(priv, CTRL_OFFSET,
+   zynq_fpga_read(priv, CTRL_OFFSET) & ~CTRL_PCAP_PR_MASK);
+
err = clk_enable(priv->clk);
if (err)
return err;
-- 
1.9.1



[PATCH] clk-si514, clk-si544: Implement prepare/unprepare/is_prepared operations

2018-06-03 Thread Mike Looijmans
This adds prepare/unprepare/is_prepared functionality to the drivers for
the SI544 and SI514 chips, allowing the clock output to be disabled when
the clock is not in use.

Signed-off-by: Mike Looijmans 
---
 drivers/clk/clk-si514.c | 38 +-
 drivers/clk/clk-si544.c | 39 ++-
 2 files changed, 75 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/clk-si514.c b/drivers/clk/clk-si514.c
index 09b6718..153b3a2 100644
--- a/drivers/clk/clk-si514.c
+++ b/drivers/clk/clk-si514.c
@@ -74,6 +74,33 @@ static int si514_enable_output(struct clk_si514 *data, bool 
enable)
SI514_CONTROL_OE, enable ? SI514_CONTROL_OE : 0);
 }
 
+static int si514_prepare(struct clk_hw *hw)
+{
+   struct clk_si514 *data = to_clk_si514(hw);
+
+   return si514_enable_output(data, true);
+}
+
+static void si514_unprepare(struct clk_hw *hw)
+{
+   struct clk_si514 *data = to_clk_si514(hw);
+
+   si514_enable_output(data, false);
+}
+
+static int si514_is_prepared(struct clk_hw *hw)
+{
+   struct clk_si514 *data = to_clk_si514(hw);
+   unsigned int val;
+   int err;
+
+   err = regmap_read(data->regmap, SI514_REG_CONTROL, );
+   if (err < 0)
+   return err;
+
+   return !!(val & SI514_CONTROL_OE);
+}
+
 /* Retrieve clock multiplier and dividers from hardware */
 static int si514_get_muldiv(struct clk_si514 *data,
struct clk_si514_muldiv *settings)
@@ -235,12 +262,17 @@ static int si514_set_rate(struct clk_hw *hw, unsigned 
long rate,
 {
struct clk_si514 *data = to_clk_si514(hw);
struct clk_si514_muldiv settings;
+   unsigned int old_oe_state;
int err;
 
err = si514_calc_muldiv(, rate);
if (err)
return err;
 
+   err = regmap_read(data->regmap, SI514_REG_CONTROL, _oe_state);
+   if (err)
+   return err;
+
si514_enable_output(data, false);
 
err = si514_set_muldiv(data, );
@@ -255,12 +287,16 @@ static int si514_set_rate(struct clk_hw *hw, unsigned 
long rate,
/* Applying a new frequency can take up to 10ms */
usleep_range(1, 12000);
 
-   si514_enable_output(data, true);
+   if (old_oe_state & SI514_CONTROL_OE)
+   si514_enable_output(data, true);
 
return err;
 }
 
 static const struct clk_ops si514_clk_ops = {
+   .prepare = si514_prepare,
+   .unprepare = si514_unprepare,
+   .is_prepared = si514_is_prepared,
.recalc_rate = si514_recalc_rate,
.round_rate = si514_round_rate,
.set_rate = si514_set_rate,
diff --git a/drivers/clk/clk-si544.c b/drivers/clk/clk-si544.c
index e972ffb..f8ed9d9 100644
--- a/drivers/clk/clk-si544.c
+++ b/drivers/clk/clk-si544.c
@@ -86,6 +86,34 @@ static int si544_enable_output(struct clk_si544 *data, bool 
enable)
SI544_OE_STATE_ODC_OE, enable ? SI544_OE_STATE_ODC_OE : 0);
 }
 
+static int si544_prepare(struct clk_hw *hw)
+{
+   struct clk_si544 *data = to_clk_si544(hw);
+
+   return si544_enable_output(data, true);
+}
+
+static void si544_unprepare(struct clk_hw *hw)
+{
+   struct clk_si544 *data = to_clk_si544(hw);
+
+   si544_enable_output(data, false);
+}
+
+static int si544_is_prepared(struct clk_hw *hw)
+{
+   struct clk_si544 *data = to_clk_si544(hw);
+   unsigned int val;
+   int err;
+
+   err = regmap_read(data->regmap, SI544_REG_OE_STATE, );
+   if (err < 0)
+   return err;
+
+   return !!(val & SI544_OE_STATE_ODC_OE);
+}
+
+
 /* Retrieve clock multiplier and dividers from hardware */
 static int si544_get_muldiv(struct clk_si544 *data,
struct clk_si544_muldiv *settings)
@@ -273,6 +301,7 @@ static int si544_set_rate(struct clk_hw *hw, unsigned long 
rate,
 {
struct clk_si544 *data = to_clk_si544(hw);
struct clk_si544_muldiv settings;
+   unsigned int old_oe_state;
int err;
 
if (!is_valid_frequency(data, rate))
@@ -282,6 +311,10 @@ static int si544_set_rate(struct clk_hw *hw, unsigned long 
rate,
if (err)
return err;
 
+   err = regmap_read(data->regmap, SI544_REG_OE_STATE, _oe_state);
+   if (err)
+   return err;
+
si544_enable_output(data, false);
 
/* Allow FCAL for this frequency update */
@@ -303,12 +336,16 @@ static int si544_set_rate(struct clk_hw *hw, unsigned 
long rate,
/* Applying a new frequency can take up to 10ms */
usleep_range(1, 12000);
 
-   si544_enable_output(data, true);
+   if (old_oe_state & SI544_OE_STATE_ODC_OE)
+   si544_enable_output(data, true);
 
return err;
 }
 
 static const struct clk_ops si544_clk_ops = {
+   .prepare = si544_prepare,
+   .unprepare = si544_unprepare,
+   .is_prepared = si544_is_prepared,
.recalc_rate = si544_recalc_rate,
.round_rate = si544_round_rate,

[PATCH] clk-si514, clk-si544: Implement prepare/unprepare/is_prepared operations

2018-06-03 Thread Mike Looijmans
This adds prepare/unprepare/is_prepared functionality to the drivers for
the SI544 and SI514 chips, allowing the clock output to be disabled when
the clock is not in use.

Signed-off-by: Mike Looijmans 
---
 drivers/clk/clk-si514.c | 38 +-
 drivers/clk/clk-si544.c | 39 ++-
 2 files changed, 75 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/clk-si514.c b/drivers/clk/clk-si514.c
index 09b6718..153b3a2 100644
--- a/drivers/clk/clk-si514.c
+++ b/drivers/clk/clk-si514.c
@@ -74,6 +74,33 @@ static int si514_enable_output(struct clk_si514 *data, bool 
enable)
SI514_CONTROL_OE, enable ? SI514_CONTROL_OE : 0);
 }
 
+static int si514_prepare(struct clk_hw *hw)
+{
+   struct clk_si514 *data = to_clk_si514(hw);
+
+   return si514_enable_output(data, true);
+}
+
+static void si514_unprepare(struct clk_hw *hw)
+{
+   struct clk_si514 *data = to_clk_si514(hw);
+
+   si514_enable_output(data, false);
+}
+
+static int si514_is_prepared(struct clk_hw *hw)
+{
+   struct clk_si514 *data = to_clk_si514(hw);
+   unsigned int val;
+   int err;
+
+   err = regmap_read(data->regmap, SI514_REG_CONTROL, );
+   if (err < 0)
+   return err;
+
+   return !!(val & SI514_CONTROL_OE);
+}
+
 /* Retrieve clock multiplier and dividers from hardware */
 static int si514_get_muldiv(struct clk_si514 *data,
struct clk_si514_muldiv *settings)
@@ -235,12 +262,17 @@ static int si514_set_rate(struct clk_hw *hw, unsigned 
long rate,
 {
struct clk_si514 *data = to_clk_si514(hw);
struct clk_si514_muldiv settings;
+   unsigned int old_oe_state;
int err;
 
err = si514_calc_muldiv(, rate);
if (err)
return err;
 
+   err = regmap_read(data->regmap, SI514_REG_CONTROL, _oe_state);
+   if (err)
+   return err;
+
si514_enable_output(data, false);
 
err = si514_set_muldiv(data, );
@@ -255,12 +287,16 @@ static int si514_set_rate(struct clk_hw *hw, unsigned 
long rate,
/* Applying a new frequency can take up to 10ms */
usleep_range(1, 12000);
 
-   si514_enable_output(data, true);
+   if (old_oe_state & SI514_CONTROL_OE)
+   si514_enable_output(data, true);
 
return err;
 }
 
 static const struct clk_ops si514_clk_ops = {
+   .prepare = si514_prepare,
+   .unprepare = si514_unprepare,
+   .is_prepared = si514_is_prepared,
.recalc_rate = si514_recalc_rate,
.round_rate = si514_round_rate,
.set_rate = si514_set_rate,
diff --git a/drivers/clk/clk-si544.c b/drivers/clk/clk-si544.c
index e972ffb..f8ed9d9 100644
--- a/drivers/clk/clk-si544.c
+++ b/drivers/clk/clk-si544.c
@@ -86,6 +86,34 @@ static int si544_enable_output(struct clk_si544 *data, bool 
enable)
SI544_OE_STATE_ODC_OE, enable ? SI544_OE_STATE_ODC_OE : 0);
 }
 
+static int si544_prepare(struct clk_hw *hw)
+{
+   struct clk_si544 *data = to_clk_si544(hw);
+
+   return si544_enable_output(data, true);
+}
+
+static void si544_unprepare(struct clk_hw *hw)
+{
+   struct clk_si544 *data = to_clk_si544(hw);
+
+   si544_enable_output(data, false);
+}
+
+static int si544_is_prepared(struct clk_hw *hw)
+{
+   struct clk_si544 *data = to_clk_si544(hw);
+   unsigned int val;
+   int err;
+
+   err = regmap_read(data->regmap, SI544_REG_OE_STATE, );
+   if (err < 0)
+   return err;
+
+   return !!(val & SI544_OE_STATE_ODC_OE);
+}
+
+
 /* Retrieve clock multiplier and dividers from hardware */
 static int si544_get_muldiv(struct clk_si544 *data,
struct clk_si544_muldiv *settings)
@@ -273,6 +301,7 @@ static int si544_set_rate(struct clk_hw *hw, unsigned long 
rate,
 {
struct clk_si544 *data = to_clk_si544(hw);
struct clk_si544_muldiv settings;
+   unsigned int old_oe_state;
int err;
 
if (!is_valid_frequency(data, rate))
@@ -282,6 +311,10 @@ static int si544_set_rate(struct clk_hw *hw, unsigned long 
rate,
if (err)
return err;
 
+   err = regmap_read(data->regmap, SI544_REG_OE_STATE, _oe_state);
+   if (err)
+   return err;
+
si544_enable_output(data, false);
 
/* Allow FCAL for this frequency update */
@@ -303,12 +336,16 @@ static int si544_set_rate(struct clk_hw *hw, unsigned 
long rate,
/* Applying a new frequency can take up to 10ms */
usleep_range(1, 12000);
 
-   si544_enable_output(data, true);
+   if (old_oe_state & SI544_OE_STATE_ODC_OE)
+   si544_enable_output(data, true);
 
return err;
 }
 
 static const struct clk_ops si544_clk_ops = {
+   .prepare = si544_prepare,
+   .unprepare = si544_unprepare,
+   .is_prepared = si544_is_prepared,
.recalc_rate = si544_recalc_rate,
.round_rate = si544_round_rate,

Re: [PATCH] clk-si544: Properly round requested frequency to nearest match

2018-06-01 Thread Mike Looijmans

On 31-05-18 17:34, Stephen Boyd wrote:

Quoting Mike Looijmans (2018-05-31 07:03:55)

The si544 driver had a rounding problem that using the result of clk_round_rate
may set the clock to yet another rate, for example:
clk_round_rate(19500) = 19499
clk_round_rate(19499) = 19498

Clients would expect that after clk_set_rate(clk, freq2=clk_round_rate(clk, 
freq)) the
chip will be running at exactly freq2.

The problem was in the calculation of the feedback divider, it was always 
rounded
down instead of to the nearest possible VCO value.

After this change, the following holds true for any supported frequency:
actual_freq = clk_round_rate(clk, freq);
clk_set_rate(clk, actual_freq);
clk_round_rate(clk, actual_freq) == actual_freq && clk_get_rate(clk) == 
actual_freq

Signed-off-by: Mike Looijmans 


Any fixes tag? I can slap

Fixes: 953cc3e81170 ("clk: Add driver for the si544 clock generator chip")

on to the patch here.



I think that would be good, yes. Slap it on.


Kind regards,

Mike Looijmans
System Expert

TOPIC Products
Materiaalweg 4, NL-5681 RJ Best
Postbus 440, NL-5680 AK Best
Telefoon: +31 (0) 499 33 69 79
E-mail: mike.looijm...@topicproducts.com
Website: www.topicproducts.com

Please consider the environment before printing this e-mail





Re: [PATCH] clk-si544: Properly round requested frequency to nearest match

2018-06-01 Thread Mike Looijmans

On 31-05-18 17:34, Stephen Boyd wrote:

Quoting Mike Looijmans (2018-05-31 07:03:55)

The si544 driver had a rounding problem that using the result of clk_round_rate
may set the clock to yet another rate, for example:
clk_round_rate(19500) = 19499
clk_round_rate(19499) = 19498

Clients would expect that after clk_set_rate(clk, freq2=clk_round_rate(clk, 
freq)) the
chip will be running at exactly freq2.

The problem was in the calculation of the feedback divider, it was always 
rounded
down instead of to the nearest possible VCO value.

After this change, the following holds true for any supported frequency:
actual_freq = clk_round_rate(clk, freq);
clk_set_rate(clk, actual_freq);
clk_round_rate(clk, actual_freq) == actual_freq && clk_get_rate(clk) == 
actual_freq

Signed-off-by: Mike Looijmans 


Any fixes tag? I can slap

Fixes: 953cc3e81170 ("clk: Add driver for the si544 clock generator chip")

on to the patch here.



I think that would be good, yes. Slap it on.


Kind regards,

Mike Looijmans
System Expert

TOPIC Products
Materiaalweg 4, NL-5681 RJ Best
Postbus 440, NL-5680 AK Best
Telefoon: +31 (0) 499 33 69 79
E-mail: mike.looijm...@topicproducts.com
Website: www.topicproducts.com

Please consider the environment before printing this e-mail





[PATCH] clk-si544: Properly round requested frequency to nearest match

2018-05-31 Thread Mike Looijmans
The si544 driver had a rounding problem that using the result of clk_round_rate
may set the clock to yet another rate, for example:
clk_round_rate(19500) = 19499
clk_round_rate(19499) = 19498

Clients would expect that after clk_set_rate(clk, freq2=clk_round_rate(clk, 
freq)) the
chip will be running at exactly freq2.

The problem was in the calculation of the feedback divider, it was always 
rounded
down instead of to the nearest possible VCO value.

After this change, the following holds true for any supported frequency:
actual_freq = clk_round_rate(clk, freq);
clk_set_rate(clk, actual_freq);
clk_round_rate(clk, actual_freq) == actual_freq && clk_get_rate(clk) == 
actual_freq

Signed-off-by: Mike Looijmans 
---
 drivers/clk/clk-si544.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/clk/clk-si544.c b/drivers/clk/clk-si544.c
index d437722..e972ffb 100644
--- a/drivers/clk/clk-si544.c
+++ b/drivers/clk/clk-si544.c
@@ -207,6 +207,7 @@ static int si544_calc_muldiv(struct clk_si544_muldiv 
*settings,
 
/* And the fractional bits using the remainder */
vco = (u64)tmp << 32;
+   vco += FXO / 2; /* Round to nearest multiple */
do_div(vco, FXO);
settings->fb_div_frac = vco;
 
-- 
1.9.1



[PATCH] clk-si544: Properly round requested frequency to nearest match

2018-05-31 Thread Mike Looijmans
The si544 driver had a rounding problem that using the result of clk_round_rate
may set the clock to yet another rate, for example:
clk_round_rate(19500) = 19499
clk_round_rate(19499) = 19498

Clients would expect that after clk_set_rate(clk, freq2=clk_round_rate(clk, 
freq)) the
chip will be running at exactly freq2.

The problem was in the calculation of the feedback divider, it was always 
rounded
down instead of to the nearest possible VCO value.

After this change, the following holds true for any supported frequency:
actual_freq = clk_round_rate(clk, freq);
clk_set_rate(clk, actual_freq);
clk_round_rate(clk, actual_freq) == actual_freq && clk_get_rate(clk) == 
actual_freq

Signed-off-by: Mike Looijmans 
---
 drivers/clk/clk-si544.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/clk/clk-si544.c b/drivers/clk/clk-si544.c
index d437722..e972ffb 100644
--- a/drivers/clk/clk-si544.c
+++ b/drivers/clk/clk-si544.c
@@ -207,6 +207,7 @@ static int si544_calc_muldiv(struct clk_si544_muldiv 
*settings,
 
/* And the fractional bits using the remainder */
vco = (u64)tmp << 32;
+   vco += FXO / 2; /* Round to nearest multiple */
do_div(vco, FXO);
settings->fb_div_frac = vco;
 
-- 
1.9.1



Re: [PATCH] i2c-mux-pca954x: Force reset on probe if available

2018-05-08 Thread Mike Looijmans

On 08-05-18 08:36, Peter Rosin wrote:

On 2018-05-01 13:42, Mike Looijmans wrote:

Instead of just hogging the reset GPIO into deactivated state, activate and
then de-activate the reset. This allows for better recovery if the CPU was
reset halfway through an I2C transaction for example.


I can't see any problems with this, and a reset at load time can certainly
be a benefit. Some questions below though...

Cheers,
Peter


Signed-off-by: Mike Looijmans <mike.looijm...@topic.nl>
---
  drivers/i2c/muxes/i2c-mux-pca954x.c | 12 ++--
  1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c 
b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 09bafd3..13e10d0 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -36,6 +36,7 @@
   */
  
  #include 

+#include 
  #include 
  #include 
  #include 
@@ -389,10 +390,17 @@ static int pca954x_probe(struct i2c_client *client,
i2c_set_clientdata(client, muxc);
data->client = client;
  
-	/* Get the mux out of reset if a reset GPIO is specified. */

-   gpio = devm_gpiod_get_optional(>dev, "reset", GPIOD_OUT_LOW);
+   /* Reset the mux if a reset GPIO is specified. */
+   gpio = devm_gpiod_get_optional(>dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
+   if (gpio) {
+   /* Datasheet specifies a 4 ns reset-low time */
+   udelay(1);


ndelay(4) ?



I have several reasons for making it much much longer:
- A true 4ns pulse might not make it through the GPIO controller (on some 
chips, the GPIO controller runs at 1/10th of the CPU speed or even less)
- Board designers tend to treat RESET signals as "DC", so a 250MHz pulse might 
not make it through. There may be level converters and open-drain drives in 
the signal path as well.

- I've only looked it op on a few chips, others may have different values

I think best is to just remove the comment line, it doesn't really help.


+   gpiod_set_value_cansleep(gpio, 0);
+   /* Datasheet specifies a 500 ns reset recovery time */
+   udelay(1);


ndelay(500) ?


Similar reasons as above.




+   }
  
  	match = of_match_device(of_match_ptr(pca954x_of_match), >dev);

    if (match)







Kind regards,

Mike Looijmans
System Expert

TOPIC Products
Materiaalweg 4, NL-5681 RJ Best
Postbus 440, NL-5680 AK Best
Telefoon: +31 (0) 499 33 69 79
E-mail: mike.looijm...@topicproducts.com
Website: www.topicproducts.com

Please consider the environment before printing this e-mail





Re: [PATCH] i2c-mux-pca954x: Force reset on probe if available

2018-05-08 Thread Mike Looijmans

On 08-05-18 08:36, Peter Rosin wrote:

On 2018-05-01 13:42, Mike Looijmans wrote:

Instead of just hogging the reset GPIO into deactivated state, activate and
then de-activate the reset. This allows for better recovery if the CPU was
reset halfway through an I2C transaction for example.


I can't see any problems with this, and a reset at load time can certainly
be a benefit. Some questions below though...

Cheers,
Peter


Signed-off-by: Mike Looijmans 
---
  drivers/i2c/muxes/i2c-mux-pca954x.c | 12 ++--
  1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c 
b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 09bafd3..13e10d0 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -36,6 +36,7 @@
   */
  
  #include 

+#include 
  #include 
  #include 
  #include 
@@ -389,10 +390,17 @@ static int pca954x_probe(struct i2c_client *client,
i2c_set_clientdata(client, muxc);
data->client = client;
  
-	/* Get the mux out of reset if a reset GPIO is specified. */

-   gpio = devm_gpiod_get_optional(>dev, "reset", GPIOD_OUT_LOW);
+   /* Reset the mux if a reset GPIO is specified. */
+   gpio = devm_gpiod_get_optional(>dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
+   if (gpio) {
+   /* Datasheet specifies a 4 ns reset-low time */
+   udelay(1);


ndelay(4) ?



I have several reasons for making it much much longer:
- A true 4ns pulse might not make it through the GPIO controller (on some 
chips, the GPIO controller runs at 1/10th of the CPU speed or even less)
- Board designers tend to treat RESET signals as "DC", so a 250MHz pulse might 
not make it through. There may be level converters and open-drain drives in 
the signal path as well.

- I've only looked it op on a few chips, others may have different values

I think best is to just remove the comment line, it doesn't really help.


+   gpiod_set_value_cansleep(gpio, 0);
+   /* Datasheet specifies a 500 ns reset recovery time */
+   udelay(1);


ndelay(500) ?


Similar reasons as above.




+   }
  
  	match = of_match_device(of_match_ptr(pca954x_of_match), >dev);

    if (match)







Kind regards,

Mike Looijmans
System Expert

TOPIC Products
Materiaalweg 4, NL-5681 RJ Best
Postbus 440, NL-5680 AK Best
Telefoon: +31 (0) 499 33 69 79
E-mail: mike.looijm...@topicproducts.com
Website: www.topicproducts.com

Please consider the environment before printing this e-mail





[PATCH] i2c-mux-pca954x: Force reset on probe if available

2018-05-01 Thread Mike Looijmans
Instead of just hogging the reset GPIO into deactivated state, activate and
then de-activate the reset. This allows for better recovery if the CPU was
reset halfway through an I2C transaction for example.

Signed-off-by: Mike Looijmans <mike.looijm...@topic.nl>
---
 drivers/i2c/muxes/i2c-mux-pca954x.c | 12 ++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c 
b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 09bafd3..13e10d0 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -36,6 +36,7 @@
  */
 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -389,10 +390,17 @@ static int pca954x_probe(struct i2c_client *client,
i2c_set_clientdata(client, muxc);
data->client = client;
 
-   /* Get the mux out of reset if a reset GPIO is specified. */
-   gpio = devm_gpiod_get_optional(>dev, "reset", GPIOD_OUT_LOW);
+   /* Reset the mux if a reset GPIO is specified. */
+   gpio = devm_gpiod_get_optional(>dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
+   if (gpio) {
+   /* Datasheet specifies a 4 ns reset-low time */
+   udelay(1);
+   gpiod_set_value_cansleep(gpio, 0);
+   /* Datasheet specifies a 500 ns reset recovery time */
+   udelay(1);
+   }
 
match = of_match_device(of_match_ptr(pca954x_of_match), >dev);
if (match)
-- 
1.9.1



[PATCH] i2c-mux-pca954x: Force reset on probe if available

2018-05-01 Thread Mike Looijmans
Instead of just hogging the reset GPIO into deactivated state, activate and
then de-activate the reset. This allows for better recovery if the CPU was
reset halfway through an I2C transaction for example.

Signed-off-by: Mike Looijmans 
---
 drivers/i2c/muxes/i2c-mux-pca954x.c | 12 ++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c 
b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 09bafd3..13e10d0 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -36,6 +36,7 @@
  */
 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -389,10 +390,17 @@ static int pca954x_probe(struct i2c_client *client,
i2c_set_clientdata(client, muxc);
data->client = client;
 
-   /* Get the mux out of reset if a reset GPIO is specified. */
-   gpio = devm_gpiod_get_optional(>dev, "reset", GPIOD_OUT_LOW);
+   /* Reset the mux if a reset GPIO is specified. */
+   gpio = devm_gpiod_get_optional(>dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
+   if (gpio) {
+   /* Datasheet specifies a 4 ns reset-low time */
+   udelay(1);
+   gpiod_set_value_cansleep(gpio, 0);
+   /* Datasheet specifies a 500 ns reset recovery time */
+   udelay(1);
+   }
 
match = of_match_device(of_match_ptr(pca954x_of_match), >dev);
if (match)
-- 
1.9.1



[PATCH] gpio-poweroff: Use gpiod_set_value_cansleep

2018-04-24 Thread Mike Looijmans
The power-off call is done in a context that must be able to sleep, so
use gpiod_set_value_cansleep instead of the atomic gpiod_set_value call.

This fixes a kernel warning at shutdown when the gpio is controlled
through an IO expander for example.

Signed-off-by: Mike Looijmans <mike.looijm...@topic.nl>
---
 drivers/power/reset/gpio-poweroff.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/power/reset/gpio-poweroff.c 
b/drivers/power/reset/gpio-poweroff.c
index 6273ad3..38206c3 100644
--- a/drivers/power/reset/gpio-poweroff.c
+++ b/drivers/power/reset/gpio-poweroff.c
@@ -35,11 +35,11 @@ static void gpio_poweroff_do_poweroff(void)
gpiod_direction_output(reset_gpio, 1);
mdelay(100);
/* drive inactive, also active->inactive edge */
-   gpiod_set_value(reset_gpio, 0);
+   gpiod_set_value_cansleep(reset_gpio, 0);
mdelay(100);
 
/* drive it active, also inactive->active edge */
-   gpiod_set_value(reset_gpio, 1);
+   gpiod_set_value_cansleep(reset_gpio, 1);
 
/* give it some time */
mdelay(timeout);
-- 
1.9.1



[PATCH] gpio-poweroff: Use gpiod_set_value_cansleep

2018-04-24 Thread Mike Looijmans
The power-off call is done in a context that must be able to sleep, so
use gpiod_set_value_cansleep instead of the atomic gpiod_set_value call.

This fixes a kernel warning at shutdown when the gpio is controlled
through an IO expander for example.

Signed-off-by: Mike Looijmans 
---
 drivers/power/reset/gpio-poweroff.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/power/reset/gpio-poweroff.c 
b/drivers/power/reset/gpio-poweroff.c
index 6273ad3..38206c3 100644
--- a/drivers/power/reset/gpio-poweroff.c
+++ b/drivers/power/reset/gpio-poweroff.c
@@ -35,11 +35,11 @@ static void gpio_poweroff_do_poweroff(void)
gpiod_direction_output(reset_gpio, 1);
mdelay(100);
/* drive inactive, also active->inactive edge */
-   gpiod_set_value(reset_gpio, 0);
+   gpiod_set_value_cansleep(reset_gpio, 0);
mdelay(100);
 
/* drive it active, also inactive->active edge */
-   gpiod_set_value(reset_gpio, 1);
+   gpiod_set_value_cansleep(reset_gpio, 1);
 
/* give it some time */
mdelay(timeout);
-- 
1.9.1



  1   2   3   4   5   6   >