All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 00/10] Add sbs-manager with smbalert support
@ 2017-06-15 13:59 Phil Reid
  2017-06-15 13:59 ` [PATCH v7 01/10] power: supply: sbs-battery: remove incorrect le16_to_cpu calls Phil Reid
                   ` (9 more replies)
  0 siblings, 10 replies; 30+ messages in thread
From: Phil Reid @ 2017-06-15 13:59 UTC (permalink / raw)
  To: wsa, robh+dt, mark.rutland, sre, jdelvare, jglauber, david.daney,
	peda, preid, linux-i2c, devicetree, linux-pm

This is another go of the sbs-manager driver using smbalert for
irq support from a while ago. 

Enables the existing smbalert driver to be loaded via the device tree.
Only need to add smbus_alert interrupt to the i2c bus segement in the
devicetree and the core will then enable the alert driver.

Reorders the rquest irq call in the pca954x driver to ensure each
muxed i2c segment can handle service smbalerts on that segment before
irq's are enabled. The pca954x can't mask individual irq's routed thru
them.

Add the sbs-manager from Karl-Heinz.
Add the alert call back and gpio interface to allow the battery detect
logic in the existing sbs-battery driver to work.

Changes from v5:
- Documentation: Add sbs-manager device tree node documentation
  - Use same style as sbs-charger for compatible property. 
- power: Adds support for Smart Battery System Manager
  - reorder kconfig / makefile
  - remove errouinous le16 to cpu conversions
  - while loops to for loops
  - formating changes to error messages
  - changed sbsm_set_proprty indentation (hopefully I got it right)
  - removed CONFIG_OF conditional around of_device_id table
  - ENODEV -> EINVAL in probe function for mismatched address
  - Use BIT() macro in probe function
  - add of_node assignment in probe function
  - remove owner assignament and set of_match_table
- power: supply: sbs-battery: Add alert callback
  - Removed patch as Sebastian has queued it.
- power: supply: sbs-manager: Add alert callback and battery change notification
  - Use device_property_present instead of of_get_property
  - Add depends on GPIOLIB

Changes from v6
- Add 2 patches to remove incorrect le16_to_cpu calls in bq24735 & sbs-battery
  this was identifed in review of v6
- i2c: i2c-smbus: Use threaded irq for smbalert
  - remove alert_edge_triggered flag, see new description
  - rework the work thread and threaded irq,commit log has more details
  - Update in tree drivers where required (untested)
- i2c: i2c-smbus: add of_i2c_setup_smbus_alert
  - Add Rob's ack for doc binding
  - rework of_i2c_setup_smbus_alert so that it doesn't need to alloc memory
    addressing concern about devres allocation.
    Probe function looks up the irq number if platform data isn't defined.
- i2c: core: call of_i2c_setup_smbus_alert in i2c_register_adapter
  - investigate if the core will release the client
    It looks like it will to me, in i2c_del_adapter it iterates thru all clients
    and calls __unregister_client.
- i2c: mux: pca954x: Call request irq after adding mux segments
  - fix logic in guard for request irq
  - fix identation
  - add check to irq_create_mapping call
- Documentation: Add sbs-manager device tree node documentation
  - Remove leading 0's
  - Add Rob's ack
- power: Adds support for Smart Battery System Manager
  - remove inc header <linux/of_device.h>
  - add macro defines for various bit and masks.
  - refactor loop around i2c_mux_add_adapter 
  - Add ifdef CONFIG_OF around OF device table to save some bytes 
- power: supply: sbs-manager: Add alert callback and battery change notification
  - Add Sebastian's ack for binding
- Added new patch
  - power: supply: sbs-battery: move gpio present detect to sbs_get_property


Karl-Heinz Schneider (2):
  Documentation: Add sbs-manager device tree node documentation
  power: Adds support for Smart Battery System Manager

Phil Reid (8):
  power: supply: sbs-battery: remove incorrect le16_to_cpu calls
  power: supply: bq24735: remove incorrect le16_to_cpu calls
  i2c: i2c-smbus: Use threaded irq for smbalert
  i2c: i2c-smbus: add of_i2c_setup_smbus_alert
  i2c: core: call of_i2c_setup_smbus_alert in i2c_register_adapter
  i2c: mux: pca954x: Call request irq after adding mux segments
  power: supply: sbs-manager: Add alert callback and battery change
    notification
  power: supply: sbs-battery: move gpio present detect to
    sbs_get_property

 Documentation/devicetree/bindings/i2c/i2c.txt      |   4 +-
 .../bindings/power/supply/sbs,sbs-manager.txt      |  66 +++
 drivers/i2c/busses/i2c-parport-light.c             |   1 -
 drivers/i2c/busses/i2c-parport.c                   |   1 -
 drivers/i2c/busses/i2c-thunderx-pcidrv.c           |   6 -
 drivers/i2c/i2c-core.c                             |   4 +
 drivers/i2c/i2c-smbus.c                            |  71 ++--
 drivers/i2c/muxes/i2c-mux-pca954x.c                |  59 +--
 drivers/power/supply/Kconfig                       |  14 +
 drivers/power/supply/Makefile                      |   1 +
 drivers/power/supply/bq24735-charger.c             |   6 +-
 drivers/power/supply/sbs-battery.c                 |  30 +-
 drivers/power/supply/sbs-manager.c                 | 444 +++++++++++++++++++++
 include/linux/i2c-smbus.h                          |  10 +-
 14 files changed, 634 insertions(+), 83 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/power/supply/sbs,sbs-manager.txt
 create mode 100644 drivers/power/supply/sbs-manager.c

-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v7 01/10] power: supply: sbs-battery: remove incorrect le16_to_cpu calls
  2017-06-15 13:59 [PATCH v7 00/10] Add sbs-manager with smbalert support Phil Reid
@ 2017-06-15 13:59 ` Phil Reid
       [not found]   ` <1497535178-12001-2-git-send-email-preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
  2017-06-15 13:59 ` [PATCH v7 02/10] power: supply: bq24735: " Phil Reid
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 30+ messages in thread
From: Phil Reid @ 2017-06-15 13:59 UTC (permalink / raw)
  To: wsa, robh+dt, mark.rutland, sre, jdelvare, jglauber, david.daney,
	peda, preid, linux-i2c, devicetree, linux-pm

i2c_smbus commands handle the correct byte order for smbus transactions
internally. This will currently result in incorrect operation on big
endian systems.

Signed-off-by: Phil Reid <preid@electromag.com.au>
---
 drivers/power/supply/sbs-battery.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
index e3a114e..cf43e38 100644
--- a/drivers/power/supply/sbs-battery.c
+++ b/drivers/power/supply/sbs-battery.c
@@ -199,7 +199,7 @@ static int sbs_read_word_data(struct i2c_client *client, u8 address)
 		return ret;
 	}
 
-	return le16_to_cpu(ret);
+	return ret;
 }
 
 static int sbs_read_string_data(struct i2c_client *client, u8 address,
@@ -265,7 +265,7 @@ static int sbs_read_string_data(struct i2c_client *client, u8 address,
 	memcpy(values, block_buffer + 1, block_length);
 	values[block_length] = '\0';
 
-	return le16_to_cpu(ret);
+	return ret;
 }
 
 static int sbs_write_word_data(struct i2c_client *client, u8 address,
@@ -278,8 +278,7 @@ static int sbs_write_word_data(struct i2c_client *client, u8 address,
 	retries = chip->i2c_retry_count;
 
 	while (retries > 0) {
-		ret = i2c_smbus_write_word_data(client, address,
-			le16_to_cpu(value));
+		ret = i2c_smbus_write_word_data(client, address, value);
 		if (ret >= 0)
 			break;
 		retries--;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v7 02/10] power: supply: bq24735: remove incorrect le16_to_cpu calls
  2017-06-15 13:59 [PATCH v7 00/10] Add sbs-manager with smbalert support Phil Reid
  2017-06-15 13:59 ` [PATCH v7 01/10] power: supply: sbs-battery: remove incorrect le16_to_cpu calls Phil Reid
@ 2017-06-15 13:59 ` Phil Reid
       [not found]   ` <1497535178-12001-3-git-send-email-preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
  2017-06-15 13:59 ` [PATCH v7 03/10] i2c: i2c-smbus: Use threaded irq for smbalert Phil Reid
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 30+ messages in thread
From: Phil Reid @ 2017-06-15 13:59 UTC (permalink / raw)
  To: wsa, robh+dt, mark.rutland, sre, jdelvare, jglauber, david.daney,
	peda, preid, linux-i2c, devicetree, linux-pm

i2c_smbus commands handle the correct byte order for smbus transactions
internally. This will currently result in incorrect operation on big
endian systems.

Signed-off-by: Phil Reid <preid@electromag.com.au>
---
 drivers/power/supply/bq24735-charger.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/power/supply/bq24735-charger.c b/drivers/power/supply/bq24735-charger.c
index eb01453..6931e1d 100644
--- a/drivers/power/supply/bq24735-charger.c
+++ b/drivers/power/supply/bq24735-charger.c
@@ -81,14 +81,12 @@ static int bq24735_charger_property_is_writeable(struct power_supply *psy,
 static inline int bq24735_write_word(struct i2c_client *client, u8 reg,
 				     u16 value)
 {
-	return i2c_smbus_write_word_data(client, reg, le16_to_cpu(value));
+	return i2c_smbus_write_word_data(client, reg, value);
 }
 
 static inline int bq24735_read_word(struct i2c_client *client, u8 reg)
 {
-	s32 ret = i2c_smbus_read_word_data(client, reg);
-
-	return ret < 0 ? ret : le16_to_cpu(ret);
+	return i2c_smbus_read_word_data(client, reg);
 }
 
 static int bq24735_update_word(struct i2c_client *client, u8 reg,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v7 03/10] i2c: i2c-smbus: Use threaded irq for smbalert
  2017-06-15 13:59 [PATCH v7 00/10] Add sbs-manager with smbalert support Phil Reid
  2017-06-15 13:59 ` [PATCH v7 01/10] power: supply: sbs-battery: remove incorrect le16_to_cpu calls Phil Reid
  2017-06-15 13:59 ` [PATCH v7 02/10] power: supply: bq24735: " Phil Reid
@ 2017-06-15 13:59 ` Phil Reid
  2017-06-19 15:27   ` Wolfram Sang
  2017-06-15 13:59 ` [PATCH v7 04/10] i2c: i2c-smbus: add of_i2c_setup_smbus_alert Phil Reid
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 30+ messages in thread
From: Phil Reid @ 2017-06-15 13:59 UTC (permalink / raw)
  To: wsa, robh+dt, mark.rutland, sre, jdelvare, jglauber, david.daney,
	peda, preid, linux-i2c, devicetree, linux-pm

Prior to this commit the smbalert_irq was handling in the hard irq
context. This change switch to using a thread irq which avoids the need
for the work thread. Using threaded irq also removes the need for the
edge_triggered flag as the enabling / disabling of the hard irq for level
triggered interrupts will be handled by the irq core.

Without this change have an irq connected to something like an i2c gpio
resulted in a null ptr deferences. Specifically handle_nested_irq calls
the threaded irq handler.

There are currently 3 in tree drivers affected by this change.

i2c-parport driver calls i2c_handle_smbus_alert in a hard irq context.
This driver use edge trigger interrupts which skip the enable / disable
calls. But it still need to handle the smbus transaction on a thread. So
the work thread is kept for this driver.

i2c-parport-light & i2c-thunderx-pcidrv provide the irq number in the
setup which will result in the thread irq being used.

i2c-parport-light is edge trigger so the enable / disable call was
skipped as well.

i2c-thunderx-pcidrv is getting the edge / level trigger setting from of
data and was setting the flag as required. However the irq core should
handle this automatically.

Signed-off-by: Phil Reid <preid@electromag.com.au>
---
 drivers/i2c/busses/i2c-parport-light.c   |  1 -
 drivers/i2c/busses/i2c-parport.c         |  1 -
 drivers/i2c/busses/i2c-thunderx-pcidrv.c |  6 -----
 drivers/i2c/i2c-smbus.c                  | 41 +++++++++++++-------------------
 include/linux/i2c-smbus.h                |  1 -
 5 files changed, 17 insertions(+), 33 deletions(-)

diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
index 1bcdd10..e6e22b8 100644
--- a/drivers/i2c/busses/i2c-parport-light.c
+++ b/drivers/i2c/busses/i2c-parport-light.c
@@ -123,7 +123,6 @@ static int parport_getsda(void *data)
 
 /* SMBus alert support */
 static struct i2c_smbus_alert_setup alert_data = {
-	.alert_edge_triggered	= 1,
 };
 static struct i2c_client *ara;
 static struct lineop parport_ctrl_irq = {
diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c
index a8e54df..319209a 100644
--- a/drivers/i2c/busses/i2c-parport.c
+++ b/drivers/i2c/busses/i2c-parport.c
@@ -237,7 +237,6 @@ static void i2c_parport_attach(struct parport *port)
 
 	/* Setup SMBus alert if supported */
 	if (adapter_parm[type].smbus_alert) {
-		adapter->alert_data.alert_edge_triggered = 1;
 		adapter->ara = i2c_setup_smbus_alert(&adapter->adapter,
 						     &adapter->alert_data);
 		if (adapter->ara)
diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c
index 1d4c2be..c27a50f 100644
--- a/drivers/i2c/busses/i2c-thunderx-pcidrv.c
+++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c
@@ -112,8 +112,6 @@ static void thunder_i2c_clock_disable(struct device *dev, struct clk *clk)
 static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c,
 				      struct device_node *node)
 {
-	u32 type;
-
 	if (!node)
 		return -EINVAL;
 
@@ -121,10 +119,6 @@ static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c,
 	if (!i2c->alert_data.irq)
 		return -EINVAL;
 
-	type = irqd_get_trigger_type(irq_get_irq_data(i2c->alert_data.irq));
-	i2c->alert_data.alert_edge_triggered =
-		(type & IRQ_TYPE_LEVEL_MASK) ? 1 : 0;
-
 	i2c->ara = i2c_setup_smbus_alert(&i2c->adap, &i2c->alert_data);
 	if (!i2c->ara)
 		return -ENODEV;
diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c
index f9271c7..d4af270 100644
--- a/drivers/i2c/i2c-smbus.c
+++ b/drivers/i2c/i2c-smbus.c
@@ -25,8 +25,6 @@
 #include <linux/workqueue.h>
 
 struct i2c_smbus_alert {
-	unsigned int		alert_edge_triggered:1;
-	int			irq;
 	struct work_struct	alert;
 	struct i2c_client	*ara;		/* Alert response address */
 };
@@ -72,13 +70,12 @@ static int smbus_do_alert(struct device *dev, void *addrp)
  * The alert IRQ handler needs to hand work off to a task which can issue
  * SMBus calls, because those sleeping calls can't be made in IRQ context.
  */
-static void smbus_alert(struct work_struct *work)
+static irqreturn_t smbus_alert(int irq, void *d)
 {
-	struct i2c_smbus_alert *alert;
+	struct i2c_smbus_alert *alert = d;
 	struct i2c_client *ara;
 	unsigned short prev_addr = 0;	/* Not a valid address */
 
-	alert = container_of(work, struct i2c_smbus_alert, alert);
 	ara = alert->ara;
 
 	for (;;) {
@@ -115,21 +112,17 @@ static void smbus_alert(struct work_struct *work)
 		prev_addr = data.addr;
 	}
 
-	/* We handled all alerts; re-enable level-triggered IRQs */
-	if (!alert->alert_edge_triggered)
-		enable_irq(alert->irq);
+	return IRQ_HANDLED;
 }
 
-static irqreturn_t smbalert_irq(int irq, void *d)
+static void smbalert_work(struct work_struct *work)
 {
-	struct i2c_smbus_alert *alert = d;
+	struct i2c_smbus_alert *alert;
+
+	alert = container_of(work, struct i2c_smbus_alert, alert);
 
-	/* Disable level-triggered IRQs until we handle them */
-	if (!alert->alert_edge_triggered)
-		disable_irq_nosync(irq);
+	smbus_alert(0, alert);
 
-	schedule_work(&alert->alert);
-	return IRQ_HANDLED;
 }
 
 /* Setup SMBALERT# infrastructure */
@@ -139,28 +132,28 @@ static int smbalert_probe(struct i2c_client *ara,
 	struct i2c_smbus_alert_setup *setup = dev_get_platdata(&ara->dev);
 	struct i2c_smbus_alert *alert;
 	struct i2c_adapter *adapter = ara->adapter;
-	int res;
+	int res, irq;
 
 	alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert),
 			     GFP_KERNEL);
 	if (!alert)
 		return -ENOMEM;
 
-	alert->alert_edge_triggered = setup->alert_edge_triggered;
-	alert->irq = setup->irq;
-	INIT_WORK(&alert->alert, smbus_alert);
+	irq = setup->irq;
+	INIT_WORK(&alert->alert, smbalert_work);
 	alert->ara = ara;
 
-	if (setup->irq > 0) {
-		res = devm_request_irq(&ara->dev, setup->irq, smbalert_irq,
-				       0, "smbus_alert", alert);
+	if (irq > 0) {
+		res = devm_request_threaded_irq(&ara->dev, irq,
+						NULL, smbus_alert,
+						IRQF_SHARED | IRQF_ONESHOT,
+						"smbus_alert", alert);
 		if (res)
 			return res;
 	}
 
 	i2c_set_clientdata(ara, alert);
-	dev_info(&adapter->dev, "supports SMBALERT#, %s trigger\n",
-		 setup->alert_edge_triggered ? "edge" : "level");
+	dev_info(&adapter->dev, "supports SMBALERT#\n");
 
 	return 0;
 }
diff --git a/include/linux/i2c-smbus.h b/include/linux/i2c-smbus.h
index a138502..19efbd1 100644
--- a/include/linux/i2c-smbus.h
+++ b/include/linux/i2c-smbus.h
@@ -42,7 +42,6 @@
  * properly set.
  */
 struct i2c_smbus_alert_setup {
-	unsigned int		alert_edge_triggered:1;
 	int			irq;
 };
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v7 04/10] i2c: i2c-smbus: add of_i2c_setup_smbus_alert
  2017-06-15 13:59 [PATCH v7 00/10] Add sbs-manager with smbalert support Phil Reid
                   ` (2 preceding siblings ...)
  2017-06-15 13:59 ` [PATCH v7 03/10] i2c: i2c-smbus: Use threaded irq for smbalert Phil Reid
@ 2017-06-15 13:59 ` Phil Reid
       [not found]   ` <1497535178-12001-5-git-send-email-preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
  2017-06-15 13:59 ` [PATCH v7 05/10] i2c: core: call of_i2c_setup_smbus_alert in i2c_register_adapter Phil Reid
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 30+ messages in thread
From: Phil Reid @ 2017-06-15 13:59 UTC (permalink / raw)
  To: wsa, robh+dt, mark.rutland, sre, jdelvare, jglauber, david.daney,
	peda, preid, linux-i2c, devicetree, linux-pm

This commit adds of_i2c_setup_smbus_alert which allows the smbalert
driver to be attached to an i2c adapter via the device tree.

Signed-off-by: Phil Reid <preid@electromag.com.au>
Acked-by: Rob Herring <robh@kernel.org>
---
 Documentation/devicetree/bindings/i2c/i2c.txt |  4 ++--
 drivers/i2c/i2c-smbus.c                       | 34 ++++++++++++++++++++++++---
 include/linux/i2c-smbus.h                     |  9 +++++++
 3 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt
index cee9d50..1126398 100644
--- a/Documentation/devicetree/bindings/i2c/i2c.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c.txt
@@ -59,8 +59,8 @@ wants to support one of the below features, it should adapt the bindings below.
 	interrupts used by the device.
 
 - interrupt-names
-	"irq" and "wakeup" names are recognized by I2C core, other names are
-	left to individual drivers.
+	"irq", "wakeup" and "smbus_alert" names are recognized by I2C core,
+	other names are	left to individual drivers.
 
 - host-notify
 	device uses SMBus host notify protocol instead of interrupt line.
diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c
index d4af270..0ad7f7f 100644
--- a/drivers/i2c/i2c-smbus.c
+++ b/drivers/i2c/i2c-smbus.c
@@ -21,6 +21,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of_irq.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 
@@ -131,7 +132,7 @@ static int smbalert_probe(struct i2c_client *ara,
 {
 	struct i2c_smbus_alert_setup *setup = dev_get_platdata(&ara->dev);
 	struct i2c_smbus_alert *alert;
-	struct i2c_adapter *adapter = ara->adapter;
+	struct i2c_adapter *adap = ara->adapter;
 	int res, irq;
 
 	alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert),
@@ -139,7 +140,14 @@ static int smbalert_probe(struct i2c_client *ara,
 	if (!alert)
 		return -ENOMEM;
 
-	irq = setup->irq;
+	if (setup) {
+		irq = setup->irq;
+	} else {
+		irq = of_irq_get_byname(adap->dev.of_node, "smbus_alert");
+		if (irq <= 0)
+			return irq;
+	}
+
 	INIT_WORK(&alert->alert, smbalert_work);
 	alert->ara = ara;
 
@@ -153,7 +161,7 @@ static int smbalert_probe(struct i2c_client *ara,
 	}
 
 	i2c_set_clientdata(ara, alert);
-	dev_info(&adapter->dev, "supports SMBALERT#\n");
+	dev_info(&adap->dev, "supports SMBALERT#\n");
 
 	return 0;
 }
@@ -214,6 +222,26 @@ struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter,
 }
 EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert);
 
+int of_i2c_setup_smbus_alert(struct i2c_adapter *adap)
+{
+	struct i2c_client *client;
+	int irq;
+
+	irq = of_property_match_string(adap->dev.of_node, "interrupt-names",
+				       "smbus_alert");
+	if (irq == -EINVAL || irq == -ENODATA)
+		return 0;
+	else if (irq < 0)
+		return irq;
+
+	client = i2c_setup_smbus_alert(adap, NULL);
+	if (!client)
+		return -ENODEV;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(of_i2c_setup_smbus_alert);
+
 /**
  * i2c_handle_smbus_alert - Handle an SMBus alert
  * @ara: the ARA client on the relevant adapter
diff --git a/include/linux/i2c-smbus.h b/include/linux/i2c-smbus.h
index 19efbd1..b5261c1 100644
--- a/include/linux/i2c-smbus.h
+++ b/include/linux/i2c-smbus.h
@@ -49,4 +49,13 @@ struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter,
 					 struct i2c_smbus_alert_setup *setup);
 int i2c_handle_smbus_alert(struct i2c_client *ara);
 
+#if IS_ENABLED(CONFIG_I2C_SMBUS)
+int of_i2c_setup_smbus_alert(struct i2c_adapter *adap);
+#else
+static inline int of_i2c_setup_smbus_alert(struct i2c_adapter *adap)
+{
+	return 0;
+}
+#endif
+
 #endif /* _LINUX_I2C_SMBUS_H */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v7 05/10] i2c: core: call of_i2c_setup_smbus_alert in i2c_register_adapter
  2017-06-15 13:59 [PATCH v7 00/10] Add sbs-manager with smbalert support Phil Reid
                   ` (3 preceding siblings ...)
  2017-06-15 13:59 ` [PATCH v7 04/10] i2c: i2c-smbus: add of_i2c_setup_smbus_alert Phil Reid
@ 2017-06-15 13:59 ` Phil Reid
  2017-06-19 15:28   ` Wolfram Sang
  2017-06-15 13:59 ` [PATCH v7 06/10] i2c: mux: pca954x: Call request irq after adding mux segments Phil Reid
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 30+ messages in thread
From: Phil Reid @ 2017-06-15 13:59 UTC (permalink / raw)
  To: wsa, robh+dt, mark.rutland, sre, jdelvare, jglauber, david.daney,
	peda, preid, linux-i2c, devicetree, linux-pm

Add a call to of_i2c_setup_smbus_alert when a i2c adapter is registered
so the the smbalert driver can be registered.

Signed-off-by: Phil Reid <preid@electromag.com.au>
---
 drivers/i2c/i2c-core.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index d2402bb..626471b 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -40,6 +40,7 @@
 #include <linux/gpio.h>
 #include <linux/hardirq.h>
 #include <linux/i2c.h>
+#include <linux/i2c-smbus.h>
 #include <linux/idr.h>
 #include <linux/init.h>
 #include <linux/irqflags.h>
@@ -2045,6 +2046,9 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
 		dev_warn(&adap->dev,
 			 "Failed to create compatibility class link\n");
 #endif
+	res = of_i2c_setup_smbus_alert(adap);
+	if (res)
+		goto out_list;
 
 	i2c_init_recovery(adap);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v7 06/10] i2c: mux: pca954x: Call request irq after adding mux segments
  2017-06-15 13:59 [PATCH v7 00/10] Add sbs-manager with smbalert support Phil Reid
                   ` (4 preceding siblings ...)
  2017-06-15 13:59 ` [PATCH v7 05/10] i2c: core: call of_i2c_setup_smbus_alert in i2c_register_adapter Phil Reid
@ 2017-06-15 13:59 ` Phil Reid
  2017-06-15 13:59 ` [PATCH v7 07/10] Documentation: Add sbs-manager device tree node documentation Phil Reid
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 30+ messages in thread
From: Phil Reid @ 2017-06-15 13:59 UTC (permalink / raw)
  To: wsa, robh+dt, mark.rutland, sre, jdelvare, jglauber, david.daney,
	peda, preid, linux-i2c, devicetree, linux-pm

The pca954x device do not have the ability to mask interrupts. For
i2c slave devices that also don't have masking ability (eg ltc1760
smbalert output) delay registering the irq until after the mux
segments have been configured. During the mux add_adaptor call the
core i2c system can register an smbalert handler which would then
be called immediately when the irq is registered. This smbalert
handler will then clear the pending irq.

Also add return check to irq_create_mapping call.

Signed-off-by: Phil Reid <preid@electromag.com.au>
---
 drivers/i2c/muxes/i2c-mux-pca954x.c | 59 +++++++++++++++++++------------------
 1 file changed, 30 insertions(+), 29 deletions(-)

diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 2f21138..b152efa 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -305,7 +305,7 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc)
 {
 	struct pca954x *data = i2c_mux_priv(muxc);
 	struct i2c_client *client = data->client;
-	int c, err, irq;
+	int c, irq;
 
 	if (!data->chip->has_irq || client->irq <= 0)
 		return 0;
@@ -320,29 +320,31 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc)
 
 	for (c = 0; c < data->chip->nchans; c++) {
 		irq = irq_create_mapping(data->irq, c);
+		if (irq <= 0) {
+			dev_err(&client->dev, "failed irq create map\n");
+			return -EINVAL;
+		}
 		irq_set_chip_data(irq, data);
 		irq_set_chip_and_handler(irq, &pca954x_irq_chip,
-			handle_simple_irq);
+					 handle_simple_irq);
 	}
 
-	err = devm_request_threaded_irq(&client->dev, data->client->irq, NULL,
-					pca954x_irq_handler,
-					IRQF_ONESHOT | IRQF_SHARED,
-					"pca954x", data);
-	if (err)
-		goto err_req_irq;
+	return 0;
+}
 
-	disable_irq(data->client->irq);
+static void pca954x_cleanup(struct i2c_mux_core *muxc)
+{
+	struct pca954x *data = i2c_mux_priv(muxc);
+	int c, irq;
 
-	return 0;
-err_req_irq:
-	for (c = 0; c < data->chip->nchans; c++) {
-		irq = irq_find_mapping(data->irq, c);
-		irq_dispose_mapping(irq);
+	if (data->irq) {
+		for (c = 0; c < data->chip->nchans; c++) {
+			irq = irq_find_mapping(data->irq, c);
+			irq_dispose_mapping(irq);
+		}
+		irq_domain_remove(data->irq);
 	}
-	irq_domain_remove(data->irq);
-
-	return err;
+	i2c_mux_del_adapters(muxc);
 }
 
 /*
@@ -435,6 +437,15 @@ static int pca954x_probe(struct i2c_client *client,
 		}
 	}
 
+	if (data->irq) {
+		ret = devm_request_threaded_irq(&client->dev, data->client->irq,
+						NULL, pca954x_irq_handler,
+						IRQF_ONESHOT | IRQF_SHARED,
+						"pca954x", data);
+		if (ret)
+			goto fail_del_adapters;
+	}
+
 	dev_info(&client->dev,
 		 "registered %d multiplexed busses for I2C %s %s\n",
 		 num, data->chip->muxtype == pca954x_ismux
@@ -443,25 +454,15 @@ static int pca954x_probe(struct i2c_client *client,
 	return 0;
 
 fail_del_adapters:
-	i2c_mux_del_adapters(muxc);
+	pca954x_cleanup(muxc);
 	return ret;
 }
 
 static int pca954x_remove(struct i2c_client *client)
 {
 	struct i2c_mux_core *muxc = i2c_get_clientdata(client);
-	struct pca954x *data = i2c_mux_priv(muxc);
-	int c, irq;
-
-	if (data->irq) {
-		for (c = 0; c < data->chip->nchans; c++) {
-			irq = irq_find_mapping(data->irq, c);
-			irq_dispose_mapping(irq);
-		}
-		irq_domain_remove(data->irq);
-	}
 
-	i2c_mux_del_adapters(muxc);
+	pca954x_cleanup(muxc);
 	return 0;
 }
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v7 07/10] Documentation: Add sbs-manager device tree node documentation
  2017-06-15 13:59 [PATCH v7 00/10] Add sbs-manager with smbalert support Phil Reid
                   ` (5 preceding siblings ...)
  2017-06-15 13:59 ` [PATCH v7 06/10] i2c: mux: pca954x: Call request irq after adding mux segments Phil Reid
@ 2017-06-15 13:59 ` Phil Reid
  2017-07-03 13:57   ` Sebastian Reichel
  2017-06-15 13:59 ` [PATCH v7 08/10] power: Adds support for Smart Battery System Manager Phil Reid
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 30+ messages in thread
From: Phil Reid @ 2017-06-15 13:59 UTC (permalink / raw)
  To: wsa, robh+dt, mark.rutland, sre, jdelvare, jglauber, david.daney,
	peda, preid, linux-i2c, devicetree, linux-pm
  Cc: Karl-Heinz Schneider

From: Karl-Heinz Schneider <karl-heinz@schneider-inet.de>

This patch adds device tree documentation for the sbs-manager

Signed-off-by: Karl-Heinz Schneider <karl-heinz@schneider-inet.de>
Signed-off-by: Phil Reid <preid@electromag.com.au>
Acked-by: Rob Herring <robh@kernel.org>
---
 .../bindings/power/supply/sbs,sbs-manager.txt      | 66 ++++++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/sbs,sbs-manager.txt

diff --git a/Documentation/devicetree/bindings/power/supply/sbs,sbs-manager.txt b/Documentation/devicetree/bindings/power/supply/sbs,sbs-manager.txt
new file mode 100644
index 0000000..4b219557
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/sbs,sbs-manager.txt
@@ -0,0 +1,66 @@
+Binding for sbs-manager
+
+Required properties:
+- compatible: "<vendor>,<part-number>", "sbs,sbs-charger" as fallback. The part
+  number compatible string might be used in order to take care of vendor
+  specific registers.
+- reg: integer, i2c address of the device. Should be <0xa>.
+Optional properties:
+- gpio-controller: Marks the port as GPIO controller.
+  See "gpio-specifier" in .../devicetree/bindings/gpio/gpio.txt.
+- #gpio-cells: Should be <2>. The first cell is the pin number, the second cell
+  is used to specify optional parameters:
+  See "gpio-specifier" in .../devicetree/bindings/gpio/gpio.txt.
+
+From OS view the device is basically an i2c-mux used to communicate with up to
+four smart battery devices at address 0xb. The driver actually implements this
+behaviour. So standard i2c-mux nodes can be used to register up to four slave
+batteries. Channels will be numerated starting from 1 to 4.
+
+Example:
+
+batman@a {
+    compatible = "lltc,ltc1760", "sbs,sbs-manager";
+    reg = <0x0a>;
+    #address-cells = <1>;
+    #size-cells = <0>;
+
+    gpio-controller;
+    #gpio-cells = <2>;
+
+    i2c@1 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        reg = <1>;
+
+        battery@b {
+            compatible = "ti,bq2060", "sbs,sbs-battery";
+            reg = <0x0b>;
+            sbs,battery-detect-gpios = <&batman 1 1>;
+        };
+    };
+
+    i2c@2 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        reg = <2>;
+
+        battery@b {
+            compatible = "ti,bq2060", "sbs,sbs-battery";
+            reg = <0x0b>;
+            sbs,battery-detect-gpios = <&batman 2 1>;
+        };
+    };
+
+    i2c@3 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        reg = <3>;
+
+        battery@b {
+            compatible = "ti,bq2060", "sbs,sbs-battery";
+            reg = <0x0b>;
+            sbs,battery-detect-gpios = <&batman 3 1>;
+        };
+    };
+};
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v7 08/10] power: Adds support for Smart Battery System Manager
  2017-06-15 13:59 [PATCH v7 00/10] Add sbs-manager with smbalert support Phil Reid
                   ` (6 preceding siblings ...)
  2017-06-15 13:59 ` [PATCH v7 07/10] Documentation: Add sbs-manager device tree node documentation Phil Reid
@ 2017-06-15 13:59 ` Phil Reid
       [not found]   ` <1497535178-12001-9-git-send-email-preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
  2017-06-15 13:59 ` [PATCH v7 09/10] power: supply: sbs-manager: Add alert callback and battery change notification Phil Reid
  2017-06-15 13:59 ` [PATCH v7 10/10] power: supply: sbs-battery: move gpio present detect to sbs_get_property Phil Reid
  9 siblings, 1 reply; 30+ messages in thread
From: Phil Reid @ 2017-06-15 13:59 UTC (permalink / raw)
  To: wsa, robh+dt, mark.rutland, sre, jdelvare, jglauber, david.daney,
	peda, preid, linux-i2c, devicetree, linux-pm
  Cc: Karl-Heinz Schneider

From: Karl-Heinz Schneider <karl-heinz@schneider-inet.de>

This patch adds support for Smart Battery System Manager.
A SBSM is a device listening at I2C/SMBus address 0x0a and is capable of
communicating up to four I2C smart battery devices. All smart battery
devices are listening at address 0x0b, so the SBSM muliplexes between
them. The driver makes use of the I2C-Mux framework to allow smart
batteries to be bound via device tree, i.e. the sbs-battery driver.

Via sysfs interface the online state and charge type are presented. If
the driver is bound as ltc1760 (an implementation of a Dual Smart Battery
System Manager) the charge type can also be changed from trickle to fast.

Tested-by: Phil Reid <preid@electromag.com.au>
Reviewed-by: Phil Reid <preid@electromag.com.au>
Signed-off-by: Karl-Heinz Schneider <karl-heinz@schneider-inet.de>
Signed-off-by: Phil Reid <preid@electromag.com.au>
---
 drivers/power/supply/Kconfig       |  13 ++
 drivers/power/supply/Makefile      |   1 +
 drivers/power/supply/sbs-manager.c | 323 +++++++++++++++++++++++++++++++++++++
 3 files changed, 337 insertions(+)
 create mode 100644 drivers/power/supply/sbs-manager.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index da54ac8..a435415 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -170,6 +170,19 @@ config CHARGER_SBS
         help
 	  Say Y to include support for SBS compilant battery chargers.
 
+config MANAGER_SBS
+	tristate "Smart Battery System Manager"
+	depends on I2C && I2C_MUX
+	help
+	  Say Y here to include support for Smart Battery System Manager
+	  ICs. The driver reports online and charging status via sysfs.
+	  It presents itself also as I2C mux which allows to bind
+	  smart battery driver to its ports.
+	  Supported is for example LTC1760.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called sbs-manager.
+
 config BATTERY_BQ27XXX
 	tristate "BQ27xxx battery driver"
 	help
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 3789a2c..350c0bb 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o
 obj-$(CONFIG_BATTERY_WM97XX)	+= wm97xx_battery.o
 obj-$(CONFIG_BATTERY_SBS)	+= sbs-battery.o
 obj-$(CONFIG_CHARGER_SBS)	+= sbs-charger.o
+obj-$(CONFIG_MANAGER_SBS)	+= sbs-manager.o
 obj-$(CONFIG_BATTERY_BQ27XXX)	+= bq27xxx_battery.o
 obj-$(CONFIG_BATTERY_BQ27XXX_I2C) += bq27xxx_battery_i2c.o
 obj-$(CONFIG_BATTERY_DA9030)	+= da9030_battery.o
diff --git a/drivers/power/supply/sbs-manager.c b/drivers/power/supply/sbs-manager.c
new file mode 100644
index 0000000..47c09a1
--- /dev/null
+++ b/drivers/power/supply/sbs-manager.c
@@ -0,0 +1,323 @@
+/*
+ * Driver for SBS compliant Smart Battery System Managers
+ *
+ * The device communicates via i2c at address 0x0a and multiplexes access to up
+ * to four smart batteries at address 0x0b.
+ *
+ * Via sysfs interface the online state and charge type are presented.
+ *
+ * Datasheet SBSM:    http://sbs-forum.org/specs/sbsm100b.pdf
+ * Datasheet LTC1760: http://cds.linear.com/docs/en/datasheet/1760fb.pdf
+ *
+ * Karl-Heinz Schneider <karl-heinz@schneider-inet.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+#include <linux/power_supply.h>
+
+#define SBSM_MAX_BATS  4
+#define SBSM_RETRY_CNT 3
+
+/* registers addresses */
+#define SBSM_CMD_BATSYSSTATE     0x01
+#define SBSM_CMD_BATSYSSTATECONT 0x02
+#define SBSM_CMD_BATSYSINFO      0x04
+#define SBSM_CMD_LTC             0x3c
+
+#define SBSM_MASK_BAT_SUPPORTED  GENMASK(3, 0)
+#define SBSM_MASK_CHARGE_BAT     GENMASK(7, 4)
+#define SBSM_BIT_AC_PRESENT      BIT(0)
+#define SBSM_BIT_TURBO           BIT(7)
+
+#define SBSM_SMB_BAT_OFFSET      11
+struct sbsm_data {
+	struct i2c_client *client;
+	struct i2c_mux_core *muxc;
+
+	struct power_supply *psy;
+
+	u8 cur_chan;          /* currently selected channel */
+	bool is_ltc1760;      /* special capabilities */
+};
+
+static enum power_supply_property sbsm_props[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+};
+
+static int sbsm_read_word(struct i2c_client *client, u8 address)
+{
+	int reg, retries;
+
+	for (retries = SBSM_RETRY_CNT; retries > 0; retries--) {
+		reg = i2c_smbus_read_word_data(client, address);
+		if (reg >= 0)
+			break;
+	}
+
+	if (reg < 0) {
+		dev_err(&client->dev, "failed to read register 0x%02x\n",
+			address);
+	}
+
+	return reg;
+}
+
+static int sbsm_write_word(struct i2c_client *client, u8 address, u16 word)
+{
+	int ret, retries;
+
+	for (retries = SBSM_RETRY_CNT; retries > 0; retries--) {
+		ret = i2c_smbus_write_word_data(client, address, word);
+		if (ret >= 0)
+			break;
+	}
+	if (ret < 0)
+		dev_err(&client->dev, "failed to write to register 0x%02x\n",
+			address);
+
+	return ret;
+}
+
+static int sbsm_get_property(struct power_supply *psy,
+			     enum power_supply_property psp,
+			     union power_supply_propval *val)
+{
+	struct sbsm_data *data = power_supply_get_drvdata(psy);
+	int regval = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		regval = sbsm_read_word(data->client, SBSM_CMD_BATSYSSTATECONT);
+		if (regval < 0)
+			return regval;
+		val->intval = !!(regval & SBSM_BIT_AC_PRESENT);
+		break;
+
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		regval = sbsm_read_word(data->client, SBSM_CMD_BATSYSSTATE);
+		if (regval < 0)
+			return regval;
+
+		if ((regval & SBSM_MASK_CHARGE_BAT) == 0) {
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
+			return 0;
+		}
+		val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+
+		if (data->is_ltc1760) {
+			/* charge mode fast if turbo is active */
+			regval = sbsm_read_word(data->client, SBSM_CMD_LTC);
+			if (regval < 0)
+				return regval;
+			else if (regval & SBSM_BIT_TURBO)
+				val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int sbsm_prop_is_writeable(struct power_supply *psy,
+				  enum power_supply_property psp)
+{
+	struct sbsm_data *data = power_supply_get_drvdata(psy);
+
+	return (psp == POWER_SUPPLY_PROP_CHARGE_TYPE) && data->is_ltc1760;
+}
+
+static int sbsm_set_property(struct power_supply *psy,
+			     enum power_supply_property psp,
+			     const union power_supply_propval *val)
+{
+	struct sbsm_data *data = power_supply_get_drvdata(psy);
+	int ret = -EINVAL;
+	u16 regval;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		/* write 1 to TURBO if type fast is given */
+		if (!data->is_ltc1760)
+			break;
+		regval = val->intval ==
+			 POWER_SUPPLY_CHARGE_TYPE_FAST ? SBSM_BIT_TURBO : 0;
+		ret = sbsm_write_word(data->client, SBSM_CMD_LTC, regval);
+		break;
+
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * Switch to battery
+ * Parameter chan is directly the content of SMB_BAT* nibble
+ */
+static int sbsm_select(struct i2c_mux_core *muxc, u32 chan)
+{
+	struct sbsm_data *data = i2c_mux_priv(muxc);
+	struct device *dev = &data->client->dev;
+	int ret = 0;
+	u16 reg;
+
+	if (data->cur_chan == chan)
+		return ret;
+
+	/* chan goes from 1 ... 4 */
+	reg = 1 << BIT(SBSM_SMB_BAT_OFFSET + chan);
+	ret = sbsm_write_word(data->client, SBSM_CMD_BATSYSSTATE, reg);
+	if (ret)
+		dev_err(dev, "Failed to select channel %i\n", chan);
+	else
+		data->cur_chan = chan;
+
+	return ret;
+}
+
+static const struct power_supply_desc sbsm_default_psy_desc = {
+	.type = POWER_SUPPLY_TYPE_MAINS,
+	.properties = sbsm_props,
+	.num_properties = ARRAY_SIZE(sbsm_props),
+	.get_property = &sbsm_get_property,
+	.set_property = &sbsm_set_property,
+	.property_is_writeable = &sbsm_prop_is_writeable,
+};
+
+static int sbsm_probe(struct i2c_client *client,
+		      const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct sbsm_data *data;
+	struct device *dev = &client->dev;
+	struct power_supply_desc *psy_desc;
+	struct power_supply_config psy_cfg = {};
+	int ret = 0, i, supported_bats;
+
+	/* Device listens only at address 0x0a */
+	if (client->addr != 0x0a)
+		return -EINVAL;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
+		return -EPFNOSUPPORT;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+
+	data->client = client;
+	data->is_ltc1760 = !!strstr(id->name, "ltc1760");
+
+	ret  = sbsm_read_word(client, SBSM_CMD_BATSYSINFO);
+	if (ret < 0)
+		return ret;
+	supported_bats = ret & SBSM_MASK_BAT_SUPPORTED;
+
+	data->muxc = i2c_mux_alloc(adapter, dev, SBSM_MAX_BATS, 0,
+				   I2C_MUX_LOCKED, &sbsm_select, NULL);
+	if (!data->muxc) {
+		dev_err(dev, "failed to alloc i2c mux\n");
+		ret = -ENOMEM;
+		goto err_mux_alloc;
+	}
+	data->muxc->priv = data;
+
+	/* register muxed i2c channels. One for each supported battery */
+	for (i = 0; i < SBSM_MAX_BATS; ++i) {
+		if (supported_bats & BIT(i)) {
+			ret = i2c_mux_add_adapter(data->muxc, 0, i + 1, 0);
+			if (ret)
+				break;
+		}
+	}
+	if (ret) {
+		dev_err(dev, "failed to register i2c mux channel %d\n", i + 1);
+		goto err_mux_register;
+	}
+
+	psy_desc = devm_kmemdup(dev, &sbsm_default_psy_desc,
+				sizeof(struct power_supply_desc),
+				GFP_KERNEL);
+	if (!psy_desc) {
+		ret = -ENOMEM;
+		goto err_psy;
+	}
+
+	psy_desc->name = devm_kasprintf(dev, GFP_KERNEL, "sbsm-%s",
+					dev_name(&client->dev));
+	if (!psy_desc->name) {
+		ret = -ENOMEM;
+		goto err_psy;
+	}
+
+	psy_cfg.drv_data = data;
+	psy_cfg.of_node = dev->of_node;
+	data->psy = devm_power_supply_register(dev, psy_desc, &psy_cfg);
+	if (IS_ERR(data->psy)) {
+		ret = PTR_ERR(data->psy);
+		dev_err(dev, "failed to register power supply %s\n",
+			psy_desc->name);
+		goto err_psy;
+	}
+
+	return 0;
+
+err_psy:
+err_mux_register:
+	i2c_mux_del_adapters(data->muxc);
+
+err_mux_alloc:
+	return ret;
+}
+
+static int sbsm_remove(struct i2c_client *client)
+{
+	struct sbsm_data *data = i2c_get_clientdata(client);
+
+	i2c_mux_del_adapters(data->muxc);
+	return 0;
+}
+
+static const struct i2c_device_id sbsm_ids[] = {
+	{ "sbs-manager", 0 },
+	{ "ltc1760",     0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, sbsm_ids);
+
+#ifdef CONFIG_OF
+static const struct of_device_id sbsm_dt_ids[] = {
+	{ .compatible = "sbs,sbs-manager" },
+	{ .compatible = "lltc,ltc1760" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, sbsm_dt_ids);
+#endif
+
+static struct i2c_driver sbsm_driver = {
+	.driver = {
+		.name = "sbsm",
+		.of_match_table = of_match_ptr(sbsm_dt_ids),
+	},
+	.probe		= sbsm_probe,
+	.remove		= sbsm_remove,
+	.id_table	= sbsm_ids
+};
+module_i2c_driver(sbsm_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Karl-Heinz Schneider <karl-heinz@schneider-inet.de>");
+MODULE_DESCRIPTION("SBSM Smart Battery System Manager");
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v7 09/10] power: supply: sbs-manager: Add alert callback and battery change notification
  2017-06-15 13:59 [PATCH v7 00/10] Add sbs-manager with smbalert support Phil Reid
                   ` (7 preceding siblings ...)
  2017-06-15 13:59 ` [PATCH v7 08/10] power: Adds support for Smart Battery System Manager Phil Reid
@ 2017-06-15 13:59 ` Phil Reid
  2017-06-15 13:59 ` [PATCH v7 10/10] power: supply: sbs-battery: move gpio present detect to sbs_get_property Phil Reid
  9 siblings, 0 replies; 30+ messages in thread
From: Phil Reid @ 2017-06-15 13:59 UTC (permalink / raw)
  To: wsa, robh+dt, mark.rutland, sre, jdelvare, jglauber, david.daney,
	peda, preid, linux-i2c, devicetree, linux-pm

This adds smb alert support via the smbus_alert driver to generate
power_supply_changed notifications when either external power is
removed / applied or a battery inserted / removed.
Use the i2c alert callback to notify the attached battery driver that a
change has occurred.

Signed-off-by: Phil Reid <preid@electromag.com.au>
Acked-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
---
 drivers/power/supply/Kconfig       |   3 +-
 drivers/power/supply/sbs-manager.c | 129 +++++++++++++++++++++++++++++++++++--
 2 files changed, 127 insertions(+), 5 deletions(-)

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index a435415..1753c6c 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -172,7 +172,8 @@ config CHARGER_SBS
 
 config MANAGER_SBS
 	tristate "Smart Battery System Manager"
-	depends on I2C && I2C_MUX
+	depends on I2C && I2C_MUX && GPIOLIB
+	select I2C_SMBUS
 	help
 	  Say Y here to include support for Smart Battery System Manager
 	  ICs. The driver reports online and charging status via sysfs.
diff --git a/drivers/power/supply/sbs-manager.c b/drivers/power/supply/sbs-manager.c
index 47c09a1..3e3ad09 100644
--- a/drivers/power/supply/sbs-manager.c
+++ b/drivers/power/supply/sbs-manager.c
@@ -16,10 +16,12 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/gpio.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/i2c-mux.h>
 #include <linux/power_supply.h>
+#include <linux/property.h>
 
 #define SBSM_MAX_BATS  4
 #define SBSM_RETRY_CNT 3
@@ -43,7 +45,12 @@ struct sbsm_data {
 	struct power_supply *psy;
 
 	u8 cur_chan;          /* currently selected channel */
+	struct gpio_chip chip;
 	bool is_ltc1760;      /* special capabilities */
+
+	unsigned int supported_bats;
+	unsigned int last_state;
+	unsigned int last_state_cont;
 };
 
 static enum power_supply_property sbsm_props[] = {
@@ -186,6 +193,117 @@ static int sbsm_select(struct i2c_mux_core *muxc, u32 chan)
 	return ret;
 }
 
+static int sbsm_gpio_get_value(struct gpio_chip *gc, unsigned off)
+{
+	struct sbsm_data *data = gpiochip_get_data(gc);
+	int ret;
+
+	ret = sbsm_read_word(data->client, SBSM_CMD_BATSYSSTATE);
+	if (ret < 0)
+		return ret;
+
+	return ret & BIT(off);
+}
+
+/*
+ * This needs to be defined or the GPIO lib fails to register the pin.
+ * But the 'gpio' is always an input.
+ */
+static int sbsm_gpio_direction_input(struct gpio_chip *gc, unsigned off)
+{
+	return 0;
+}
+
+static int sbsm_do_alert(struct device *dev, void *d)
+{
+	struct i2c_client *client = i2c_verify_client(dev);
+	struct i2c_driver *driver;
+
+	if (!client || client->addr != 0x0b)
+		return 0;
+
+	device_lock(dev);
+	if (client->dev.driver) {
+		driver = to_i2c_driver(client->dev.driver);
+		if (driver->alert)
+			driver->alert(client, I2C_PROTOCOL_SMBUS_ALERT, 0);
+		else
+			dev_warn(&client->dev, "no driver alert()!\n");
+	} else
+		dev_dbg(&client->dev, "alert with no driver\n");
+	device_unlock(dev);
+
+	return -EBUSY;
+}
+
+static void sbsm_alert(struct i2c_client *client, enum i2c_alert_protocol prot,
+		       unsigned int d)
+{
+	struct sbsm_data *sbsm = i2c_get_clientdata(client);
+
+	int ret, i, irq_bat = 0, state = 0;
+
+	ret = sbsm_read_word(sbsm->client, SBSM_CMD_BATSYSSTATE);
+	if (ret >= 0) {
+		irq_bat = ret ^ sbsm->last_state;
+		sbsm->last_state = ret;
+		state = ret;
+	}
+
+	ret = sbsm_read_word(sbsm->client, SBSM_CMD_BATSYSSTATECONT);
+	if ((ret >= 0) &&
+	    ((ret ^ sbsm->last_state_cont) & SBSM_BIT_AC_PRESENT)) {
+		irq_bat |= sbsm->supported_bats & state;
+		power_supply_changed(sbsm->psy);
+	}
+	sbsm->last_state_cont = ret;
+
+	for (i = 0; i < SBSM_MAX_BATS; i++) {
+		if (irq_bat & BIT(i)) {
+			device_for_each_child(&sbsm->muxc->adapter[i]->dev,
+					      NULL, sbsm_do_alert);
+		}
+	}
+}
+
+static int sbsm_gpio_setup(struct sbsm_data *data)
+{
+	struct gpio_chip *gc = &data->chip;
+	struct i2c_client *client = data->client;
+	struct device *dev = &client->dev;
+	int ret;
+
+	if (!device_property_present(dev, "gpio-controller"))
+		return 0;
+
+	ret  = sbsm_read_word(client, SBSM_CMD_BATSYSSTATE);
+	if (ret < 0)
+		return ret;
+	data->last_state = ret;
+
+	ret  = sbsm_read_word(client, SBSM_CMD_BATSYSSTATECONT);
+	if (ret < 0)
+		return ret;
+	data->last_state_cont = ret;
+
+	gc->get = sbsm_gpio_get_value;
+	gc->direction_input  = sbsm_gpio_direction_input;
+	gc->can_sleep = true;
+	gc->base = -1;
+	gc->ngpio = SBSM_MAX_BATS;
+	gc->label = client->name;
+	gc->parent = dev;
+	gc->owner = THIS_MODULE;
+
+	ret = devm_gpiochip_add_data(dev, gc, data);
+	if (ret) {
+		dev_err(dev, "devm_gpiochip_add_data failed: %d\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
 static const struct power_supply_desc sbsm_default_psy_desc = {
 	.type = POWER_SUPPLY_TYPE_MAINS,
 	.properties = sbsm_props,
@@ -203,7 +321,7 @@ static int sbsm_probe(struct i2c_client *client,
 	struct device *dev = &client->dev;
 	struct power_supply_desc *psy_desc;
 	struct power_supply_config psy_cfg = {};
-	int ret = 0, i, supported_bats;
+	int ret = 0, i;
 
 	/* Device listens only at address 0x0a */
 	if (client->addr != 0x0a)
@@ -224,8 +342,7 @@ static int sbsm_probe(struct i2c_client *client,
 	ret  = sbsm_read_word(client, SBSM_CMD_BATSYSINFO);
 	if (ret < 0)
 		return ret;
-	supported_bats = ret & SBSM_MASK_BAT_SUPPORTED;
-
+	data->supported_bats = ret & SBSM_MASK_BAT_SUPPORTED;
 	data->muxc = i2c_mux_alloc(adapter, dev, SBSM_MAX_BATS, 0,
 				   I2C_MUX_LOCKED, &sbsm_select, NULL);
 	if (!data->muxc) {
@@ -237,7 +354,7 @@ static int sbsm_probe(struct i2c_client *client,
 
 	/* register muxed i2c channels. One for each supported battery */
 	for (i = 0; i < SBSM_MAX_BATS; ++i) {
-		if (supported_bats & BIT(i)) {
+		if (data->supported_bats & BIT(i)) {
 			ret = i2c_mux_add_adapter(data->muxc, 0, i + 1, 0);
 			if (ret)
 				break;
@@ -262,6 +379,9 @@ static int sbsm_probe(struct i2c_client *client,
 		ret = -ENOMEM;
 		goto err_psy;
 	}
+	ret = sbsm_gpio_setup(data);
+	if (ret < 0)
+		goto err_psy;
 
 	psy_cfg.drv_data = data;
 	psy_cfg.of_node = dev->of_node;
@@ -314,6 +434,7 @@ static int sbsm_remove(struct i2c_client *client)
 	},
 	.probe		= sbsm_probe,
 	.remove		= sbsm_remove,
+	.alert		= sbsm_alert,
 	.id_table	= sbsm_ids
 };
 module_i2c_driver(sbsm_driver);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v7 10/10] power: supply: sbs-battery: move gpio present detect to sbs_get_property
  2017-06-15 13:59 [PATCH v7 00/10] Add sbs-manager with smbalert support Phil Reid
                   ` (8 preceding siblings ...)
  2017-06-15 13:59 ` [PATCH v7 09/10] power: supply: sbs-manager: Add alert callback and battery change notification Phil Reid
@ 2017-06-15 13:59 ` Phil Reid
  2017-07-03 15:21   ` Sebastian Reichel
  9 siblings, 1 reply; 30+ messages in thread
From: Phil Reid @ 2017-06-15 13:59 UTC (permalink / raw)
  To: wsa, robh+dt, mark.rutland, sre, jdelvare, jglauber, david.daney,
	peda, preid, linux-i2c, devicetree, linux-pm

Currently when a gpio is defined for battery presence it is only used in
the sbs_get_battery_presence_and_health function for 2 properties.
All other properties currently try to read data form the battery before
returning an error if not present. We should know in advance that no
data is going to returned.

As the driver tries multiple times to access a property, this prevents
a lot of smbus accesses, which had a significant effect on device boot-up.
As when the device is registered lots of property accesses are attempted
during boot.

If no gpio is used for presence detection no change in behaviour should
occur.

Signed-off-by: Phil Reid <preid@electromag.com.au>
---
 drivers/power/supply/sbs-battery.c | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
index cf43e38..1e3a8b2 100644
--- a/drivers/power/supply/sbs-battery.c
+++ b/drivers/power/supply/sbs-battery.c
@@ -324,16 +324,6 @@ static int sbs_get_battery_presence_and_health(
 	union power_supply_propval *val)
 {
 	s32 ret;
-	struct sbs_info *chip = i2c_get_clientdata(client);
-
-	if (psp == POWER_SUPPLY_PROP_PRESENT && chip->gpio_detect) {
-		ret = gpiod_get_value_cansleep(chip->gpio_detect);
-		if (ret < 0)
-			return ret;
-		val->intval = ret;
-		chip->is_present = val->intval;
-		return ret;
-	}
 
 	/*
 	 * Write to ManufacturerAccess with ManufacturerAccess command
@@ -599,6 +589,19 @@ static int sbs_get_property(struct power_supply *psy,
 	struct sbs_info *chip = power_supply_get_drvdata(psy);
 	struct i2c_client *client = chip->client;
 
+	if (chip->gpio_detect) {
+		ret = gpiod_get_value_cansleep(chip->gpio_detect);
+		if (ret < 0)
+			return ret;
+		if (psp == POWER_SUPPLY_PROP_PRESENT) {
+			val->intval = ret;
+			chip->is_present = val->intval;
+			return 0;
+		}
+		if (ret == 0)
+			return -ENODATA;
+	}
+
 	switch (psp) {
 	case POWER_SUPPLY_PROP_PRESENT:
 	case POWER_SUPPLY_PROP_HEALTH:
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [PATCH v7 01/10] power: supply: sbs-battery: remove incorrect le16_to_cpu calls
       [not found]   ` <1497535178-12001-2-git-send-email-preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
@ 2017-06-15 14:49     ` Sebastian Reichel
  0 siblings, 0 replies; 30+ messages in thread
From: Sebastian Reichel @ 2017-06-15 14:49 UTC (permalink / raw)
  To: Phil Reid
  Cc: wsa-z923LK4zBo2bacvFa/9K2g, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, jdelvare-IBi9RG/b67k,
	jglauber-YGCgFSpz5w/QT0dZR+AlfA,
	david.daney-YGCgFSpz5w/QT0dZR+AlfA, peda-koto5C5qi+TLoDKTGw+V6w,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 1631 bytes --]

Hi,

On Thu, Jun 15, 2017 at 09:59:29PM +0800, Phil Reid wrote:
> i2c_smbus commands handle the correct byte order for smbus transactions
> internally. This will currently result in incorrect operation on big
> endian systems.
> 
> Signed-off-by: Phil Reid <preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>

Thanks, queued.

-- Sebastian

>  drivers/power/supply/sbs-battery.c | 7 +++----
>  1 file changed, 3 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
> index e3a114e..cf43e38 100644
> --- a/drivers/power/supply/sbs-battery.c
> +++ b/drivers/power/supply/sbs-battery.c
> @@ -199,7 +199,7 @@ static int sbs_read_word_data(struct i2c_client *client, u8 address)
>  		return ret;
>  	}
>  
> -	return le16_to_cpu(ret);
> +	return ret;
>  }
>  
>  static int sbs_read_string_data(struct i2c_client *client, u8 address,
> @@ -265,7 +265,7 @@ static int sbs_read_string_data(struct i2c_client *client, u8 address,
>  	memcpy(values, block_buffer + 1, block_length);
>  	values[block_length] = '\0';
>  
> -	return le16_to_cpu(ret);
> +	return ret;
>  }
>  
>  static int sbs_write_word_data(struct i2c_client *client, u8 address,
> @@ -278,8 +278,7 @@ static int sbs_write_word_data(struct i2c_client *client, u8 address,
>  	retries = chip->i2c_retry_count;
>  
>  	while (retries > 0) {
> -		ret = i2c_smbus_write_word_data(client, address,
> -			le16_to_cpu(value));
> +		ret = i2c_smbus_write_word_data(client, address, value);
>  		if (ret >= 0)
>  			break;
>  		retries--;
> -- 
> 1.8.3.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v7 02/10] power: supply: bq24735: remove incorrect le16_to_cpu calls
       [not found]   ` <1497535178-12001-3-git-send-email-preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
@ 2017-06-15 14:50     ` Sebastian Reichel
  0 siblings, 0 replies; 30+ messages in thread
From: Sebastian Reichel @ 2017-06-15 14:50 UTC (permalink / raw)
  To: Phil Reid
  Cc: wsa-z923LK4zBo2bacvFa/9K2g, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, jdelvare-IBi9RG/b67k,
	jglauber-YGCgFSpz5w/QT0dZR+AlfA,
	david.daney-YGCgFSpz5w/QT0dZR+AlfA, peda-koto5C5qi+TLoDKTGw+V6w,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 1381 bytes --]

Hi,

On Thu, Jun 15, 2017 at 09:59:30PM +0800, Phil Reid wrote:
> i2c_smbus commands handle the correct byte order for smbus transactions
> internally. This will currently result in incorrect operation on big
> endian systems.
> 
> Signed-off-by: Phil Reid <preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>

Thanks, queued.

-- Sebastian

>  drivers/power/supply/bq24735-charger.c | 6 ++----
>  1 file changed, 2 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/power/supply/bq24735-charger.c b/drivers/power/supply/bq24735-charger.c
> index eb01453..6931e1d 100644
> --- a/drivers/power/supply/bq24735-charger.c
> +++ b/drivers/power/supply/bq24735-charger.c
> @@ -81,14 +81,12 @@ static int bq24735_charger_property_is_writeable(struct power_supply *psy,
>  static inline int bq24735_write_word(struct i2c_client *client, u8 reg,
>  				     u16 value)
>  {
> -	return i2c_smbus_write_word_data(client, reg, le16_to_cpu(value));
> +	return i2c_smbus_write_word_data(client, reg, value);
>  }
>  
>  static inline int bq24735_read_word(struct i2c_client *client, u8 reg)
>  {
> -	s32 ret = i2c_smbus_read_word_data(client, reg);
> -
> -	return ret < 0 ? ret : le16_to_cpu(ret);
> +	return i2c_smbus_read_word_data(client, reg);
>  }
>  
>  static int bq24735_update_word(struct i2c_client *client, u8 reg,
> -- 
> 1.8.3.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v7 03/10] i2c: i2c-smbus: Use threaded irq for smbalert
  2017-06-15 13:59 ` [PATCH v7 03/10] i2c: i2c-smbus: Use threaded irq for smbalert Phil Reid
@ 2017-06-19 15:27   ` Wolfram Sang
  2017-06-20  2:30     ` Phil Reid
  2017-06-23 12:11     ` Benjamin Tissoires
  0 siblings, 2 replies; 30+ messages in thread
From: Wolfram Sang @ 2017-06-19 15:27 UTC (permalink / raw)
  To: Phil Reid, Benjamin Tissoires
  Cc: robh+dt, mark.rutland, sre, jdelvare, jglauber, david.daney,
	peda, linux-i2c, devicetree, linux-pm

[-- Attachment #1: Type: text/plain, Size: 7331 bytes --]

On Thu, Jun 15, 2017 at 09:59:31PM +0800, Phil Reid wrote:
> Prior to this commit the smbalert_irq was handling in the hard irq
> context. This change switch to using a thread irq which avoids the need
> for the work thread. Using threaded irq also removes the need for the
> edge_triggered flag as the enabling / disabling of the hard irq for level
> triggered interrupts will be handled by the irq core.
> 
> Without this change have an irq connected to something like an i2c gpio
> resulted in a null ptr deferences. Specifically handle_nested_irq calls
> the threaded irq handler.
> 
> There are currently 3 in tree drivers affected by this change.
> 
> i2c-parport driver calls i2c_handle_smbus_alert in a hard irq context.
> This driver use edge trigger interrupts which skip the enable / disable
> calls. But it still need to handle the smbus transaction on a thread. So
> the work thread is kept for this driver.
> 
> i2c-parport-light & i2c-thunderx-pcidrv provide the irq number in the
> setup which will result in the thread irq being used.
> 
> i2c-parport-light is edge trigger so the enable / disable call was
> skipped as well.
> 
> i2c-thunderx-pcidrv is getting the edge / level trigger setting from of
> data and was setting the flag as required. However the irq core should
> handle this automatically.
> 
> Signed-off-by: Phil Reid <preid@electromag.com.au>

CCing Benjamin for smbus changes (like last time). Please CC him in the
future in case we need another revision of this series.

> ---
>  drivers/i2c/busses/i2c-parport-light.c   |  1 -
>  drivers/i2c/busses/i2c-parport.c         |  1 -
>  drivers/i2c/busses/i2c-thunderx-pcidrv.c |  6 -----
>  drivers/i2c/i2c-smbus.c                  | 41 +++++++++++++-------------------
>  include/linux/i2c-smbus.h                |  1 -
>  5 files changed, 17 insertions(+), 33 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
> index 1bcdd10..e6e22b8 100644
> --- a/drivers/i2c/busses/i2c-parport-light.c
> +++ b/drivers/i2c/busses/i2c-parport-light.c
> @@ -123,7 +123,6 @@ static int parport_getsda(void *data)
>  
>  /* SMBus alert support */
>  static struct i2c_smbus_alert_setup alert_data = {
> -	.alert_edge_triggered	= 1,
>  };
>  static struct i2c_client *ara;
>  static struct lineop parport_ctrl_irq = {
> diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c
> index a8e54df..319209a 100644
> --- a/drivers/i2c/busses/i2c-parport.c
> +++ b/drivers/i2c/busses/i2c-parport.c
> @@ -237,7 +237,6 @@ static void i2c_parport_attach(struct parport *port)
>  
>  	/* Setup SMBus alert if supported */
>  	if (adapter_parm[type].smbus_alert) {
> -		adapter->alert_data.alert_edge_triggered = 1;
>  		adapter->ara = i2c_setup_smbus_alert(&adapter->adapter,
>  						     &adapter->alert_data);
>  		if (adapter->ara)
> diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c
> index 1d4c2be..c27a50f 100644
> --- a/drivers/i2c/busses/i2c-thunderx-pcidrv.c
> +++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c
> @@ -112,8 +112,6 @@ static void thunder_i2c_clock_disable(struct device *dev, struct clk *clk)
>  static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c,
>  				      struct device_node *node)
>  {
> -	u32 type;
> -
>  	if (!node)
>  		return -EINVAL;
>  
> @@ -121,10 +119,6 @@ static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c,
>  	if (!i2c->alert_data.irq)
>  		return -EINVAL;
>  
> -	type = irqd_get_trigger_type(irq_get_irq_data(i2c->alert_data.irq));
> -	i2c->alert_data.alert_edge_triggered =
> -		(type & IRQ_TYPE_LEVEL_MASK) ? 1 : 0;
> -
>  	i2c->ara = i2c_setup_smbus_alert(&i2c->adap, &i2c->alert_data);
>  	if (!i2c->ara)
>  		return -ENODEV;
> diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c
> index f9271c7..d4af270 100644
> --- a/drivers/i2c/i2c-smbus.c
> +++ b/drivers/i2c/i2c-smbus.c
> @@ -25,8 +25,6 @@
>  #include <linux/workqueue.h>
>  
>  struct i2c_smbus_alert {
> -	unsigned int		alert_edge_triggered:1;
> -	int			irq;
>  	struct work_struct	alert;
>  	struct i2c_client	*ara;		/* Alert response address */
>  };
> @@ -72,13 +70,12 @@ static int smbus_do_alert(struct device *dev, void *addrp)
>   * The alert IRQ handler needs to hand work off to a task which can issue
>   * SMBus calls, because those sleeping calls can't be made in IRQ context.
>   */
> -static void smbus_alert(struct work_struct *work)
> +static irqreturn_t smbus_alert(int irq, void *d)
>  {
> -	struct i2c_smbus_alert *alert;
> +	struct i2c_smbus_alert *alert = d;
>  	struct i2c_client *ara;
>  	unsigned short prev_addr = 0;	/* Not a valid address */
>  
> -	alert = container_of(work, struct i2c_smbus_alert, alert);
>  	ara = alert->ara;
>  
>  	for (;;) {
> @@ -115,21 +112,17 @@ static void smbus_alert(struct work_struct *work)
>  		prev_addr = data.addr;
>  	}
>  
> -	/* We handled all alerts; re-enable level-triggered IRQs */
> -	if (!alert->alert_edge_triggered)
> -		enable_irq(alert->irq);
> +	return IRQ_HANDLED;
>  }
>  
> -static irqreturn_t smbalert_irq(int irq, void *d)
> +static void smbalert_work(struct work_struct *work)
>  {
> -	struct i2c_smbus_alert *alert = d;
> +	struct i2c_smbus_alert *alert;
> +
> +	alert = container_of(work, struct i2c_smbus_alert, alert);
>  
> -	/* Disable level-triggered IRQs until we handle them */
> -	if (!alert->alert_edge_triggered)
> -		disable_irq_nosync(irq);
> +	smbus_alert(0, alert);
>  
> -	schedule_work(&alert->alert);
> -	return IRQ_HANDLED;
>  }
>  
>  /* Setup SMBALERT# infrastructure */
> @@ -139,28 +132,28 @@ static int smbalert_probe(struct i2c_client *ara,
>  	struct i2c_smbus_alert_setup *setup = dev_get_platdata(&ara->dev);
>  	struct i2c_smbus_alert *alert;
>  	struct i2c_adapter *adapter = ara->adapter;
> -	int res;
> +	int res, irq;
>  
>  	alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert),
>  			     GFP_KERNEL);
>  	if (!alert)
>  		return -ENOMEM;
>  
> -	alert->alert_edge_triggered = setup->alert_edge_triggered;
> -	alert->irq = setup->irq;
> -	INIT_WORK(&alert->alert, smbus_alert);
> +	irq = setup->irq;
> +	INIT_WORK(&alert->alert, smbalert_work);
>  	alert->ara = ara;
>  
> -	if (setup->irq > 0) {
> -		res = devm_request_irq(&ara->dev, setup->irq, smbalert_irq,
> -				       0, "smbus_alert", alert);
> +	if (irq > 0) {
> +		res = devm_request_threaded_irq(&ara->dev, irq,
> +						NULL, smbus_alert,
> +						IRQF_SHARED | IRQF_ONESHOT,
> +						"smbus_alert", alert);
>  		if (res)
>  			return res;
>  	}
>  
>  	i2c_set_clientdata(ara, alert);
> -	dev_info(&adapter->dev, "supports SMBALERT#, %s trigger\n",
> -		 setup->alert_edge_triggered ? "edge" : "level");
> +	dev_info(&adapter->dev, "supports SMBALERT#\n");
>  
>  	return 0;
>  }
> diff --git a/include/linux/i2c-smbus.h b/include/linux/i2c-smbus.h
> index a138502..19efbd1 100644
> --- a/include/linux/i2c-smbus.h
> +++ b/include/linux/i2c-smbus.h
> @@ -42,7 +42,6 @@
>   * properly set.
>   */
>  struct i2c_smbus_alert_setup {
> -	unsigned int		alert_edge_triggered:1;
>  	int			irq;
>  };
>  
> -- 
> 1.8.3.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v7 04/10] i2c: i2c-smbus: add of_i2c_setup_smbus_alert
       [not found]   ` <1497535178-12001-5-git-send-email-preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
@ 2017-06-19 15:27     ` Wolfram Sang
  2017-06-23 12:15       ` Benjamin Tissoires
  0 siblings, 1 reply; 30+ messages in thread
From: Wolfram Sang @ 2017-06-19 15:27 UTC (permalink / raw)
  To: Phil Reid, Benjamin Tissoires
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	sre-DgEjT+Ai2ygdnm+yROfE0A, jdelvare-IBi9RG/b67k,
	jglauber-YGCgFSpz5w/QT0dZR+AlfA,
	david.daney-YGCgFSpz5w/QT0dZR+AlfA, peda-koto5C5qi+TLoDKTGw+V6w,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 4194 bytes --]

On Thu, Jun 15, 2017 at 09:59:32PM +0800, Phil Reid wrote:
> This commit adds of_i2c_setup_smbus_alert which allows the smbalert
> driver to be attached to an i2c adapter via the device tree.
> 
> Signed-off-by: Phil Reid <preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

CCing Benjamin

> ---
>  Documentation/devicetree/bindings/i2c/i2c.txt |  4 ++--
>  drivers/i2c/i2c-smbus.c                       | 34 ++++++++++++++++++++++++---
>  include/linux/i2c-smbus.h                     |  9 +++++++
>  3 files changed, 42 insertions(+), 5 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt
> index cee9d50..1126398 100644
> --- a/Documentation/devicetree/bindings/i2c/i2c.txt
> +++ b/Documentation/devicetree/bindings/i2c/i2c.txt
> @@ -59,8 +59,8 @@ wants to support one of the below features, it should adapt the bindings below.
>  	interrupts used by the device.
>  
>  - interrupt-names
> -	"irq" and "wakeup" names are recognized by I2C core, other names are
> -	left to individual drivers.
> +	"irq", "wakeup" and "smbus_alert" names are recognized by I2C core,
> +	other names are	left to individual drivers.
>  
>  - host-notify
>  	device uses SMBus host notify protocol instead of interrupt line.
> diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c
> index d4af270..0ad7f7f 100644
> --- a/drivers/i2c/i2c-smbus.c
> +++ b/drivers/i2c/i2c-smbus.c
> @@ -21,6 +21,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/kernel.h>
>  #include <linux/module.h>
> +#include <linux/of_irq.h>
>  #include <linux/slab.h>
>  #include <linux/workqueue.h>
>  
> @@ -131,7 +132,7 @@ static int smbalert_probe(struct i2c_client *ara,
>  {
>  	struct i2c_smbus_alert_setup *setup = dev_get_platdata(&ara->dev);
>  	struct i2c_smbus_alert *alert;
> -	struct i2c_adapter *adapter = ara->adapter;
> +	struct i2c_adapter *adap = ara->adapter;
>  	int res, irq;
>  
>  	alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert),
> @@ -139,7 +140,14 @@ static int smbalert_probe(struct i2c_client *ara,
>  	if (!alert)
>  		return -ENOMEM;
>  
> -	irq = setup->irq;
> +	if (setup) {
> +		irq = setup->irq;
> +	} else {
> +		irq = of_irq_get_byname(adap->dev.of_node, "smbus_alert");
> +		if (irq <= 0)
> +			return irq;
> +	}
> +
>  	INIT_WORK(&alert->alert, smbalert_work);
>  	alert->ara = ara;
>  
> @@ -153,7 +161,7 @@ static int smbalert_probe(struct i2c_client *ara,
>  	}
>  
>  	i2c_set_clientdata(ara, alert);
> -	dev_info(&adapter->dev, "supports SMBALERT#\n");
> +	dev_info(&adap->dev, "supports SMBALERT#\n");
>  
>  	return 0;
>  }
> @@ -214,6 +222,26 @@ struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter,
>  }
>  EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert);
>  
> +int of_i2c_setup_smbus_alert(struct i2c_adapter *adap)
> +{
> +	struct i2c_client *client;
> +	int irq;
> +
> +	irq = of_property_match_string(adap->dev.of_node, "interrupt-names",
> +				       "smbus_alert");
> +	if (irq == -EINVAL || irq == -ENODATA)
> +		return 0;
> +	else if (irq < 0)
> +		return irq;
> +
> +	client = i2c_setup_smbus_alert(adap, NULL);
> +	if (!client)
> +		return -ENODEV;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_i2c_setup_smbus_alert);
> +
>  /**
>   * i2c_handle_smbus_alert - Handle an SMBus alert
>   * @ara: the ARA client on the relevant adapter
> diff --git a/include/linux/i2c-smbus.h b/include/linux/i2c-smbus.h
> index 19efbd1..b5261c1 100644
> --- a/include/linux/i2c-smbus.h
> +++ b/include/linux/i2c-smbus.h
> @@ -49,4 +49,13 @@ struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter,
>  					 struct i2c_smbus_alert_setup *setup);
>  int i2c_handle_smbus_alert(struct i2c_client *ara);
>  
> +#if IS_ENABLED(CONFIG_I2C_SMBUS)
> +int of_i2c_setup_smbus_alert(struct i2c_adapter *adap);
> +#else
> +static inline int of_i2c_setup_smbus_alert(struct i2c_adapter *adap)
> +{
> +	return 0;
> +}
> +#endif
> +
>  #endif /* _LINUX_I2C_SMBUS_H */
> -- 
> 1.8.3.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v7 05/10] i2c: core: call of_i2c_setup_smbus_alert in i2c_register_adapter
  2017-06-15 13:59 ` [PATCH v7 05/10] i2c: core: call of_i2c_setup_smbus_alert in i2c_register_adapter Phil Reid
@ 2017-06-19 15:28   ` Wolfram Sang
  2017-06-23 12:19     ` Benjamin Tissoires
  0 siblings, 1 reply; 30+ messages in thread
From: Wolfram Sang @ 2017-06-19 15:28 UTC (permalink / raw)
  To: Phil Reid, Benjamin Tissoires
  Cc: robh+dt, mark.rutland, sre, jdelvare, jglauber, david.daney,
	peda, linux-i2c, devicetree, linux-pm

[-- Attachment #1: Type: text/plain, Size: 1050 bytes --]

On Thu, Jun 15, 2017 at 09:59:33PM +0800, Phil Reid wrote:
> Add a call to of_i2c_setup_smbus_alert when a i2c adapter is registered
> so the the smbalert driver can be registered.
> 
> Signed-off-by: Phil Reid <preid@electromag.com.au>

CCing Benjamin

> ---
>  drivers/i2c/i2c-core.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
> index d2402bb..626471b 100644
> --- a/drivers/i2c/i2c-core.c
> +++ b/drivers/i2c/i2c-core.c
> @@ -40,6 +40,7 @@
>  #include <linux/gpio.h>
>  #include <linux/hardirq.h>
>  #include <linux/i2c.h>
> +#include <linux/i2c-smbus.h>
>  #include <linux/idr.h>
>  #include <linux/init.h>
>  #include <linux/irqflags.h>
> @@ -2045,6 +2046,9 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
>  		dev_warn(&adap->dev,
>  			 "Failed to create compatibility class link\n");
>  #endif
> +	res = of_i2c_setup_smbus_alert(adap);
> +	if (res)
> +		goto out_list;
>  
>  	i2c_init_recovery(adap);
>  
> -- 
> 1.8.3.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v7 03/10] i2c: i2c-smbus: Use threaded irq for smbalert
  2017-06-19 15:27   ` Wolfram Sang
@ 2017-06-20  2:30     ` Phil Reid
  2017-06-23 12:11     ` Benjamin Tissoires
  1 sibling, 0 replies; 30+ messages in thread
From: Phil Reid @ 2017-06-20  2:30 UTC (permalink / raw)
  To: Wolfram Sang, Benjamin Tissoires
  Cc: robh+dt, mark.rutland, sre, jdelvare, jglauber, david.daney,
	peda, linux-i2c, devicetree, linux-pm

On 19/06/2017 23:27, Wolfram Sang wrote:
> On Thu, Jun 15, 2017 at 09:59:31PM +0800, Phil Reid wrote:
>> Prior to this commit the smbalert_irq was handling in the hard irq
>> context. This change switch to using a thread irq which avoids the need
>> for the work thread. Using threaded irq also removes the need for the
>> edge_triggered flag as the enabling / disabling of the hard irq for level
>> triggered interrupts will be handled by the irq core.
>>
>> Without this change have an irq connected to something like an i2c gpio
>> resulted in a null ptr deferences. Specifically handle_nested_irq calls
>> the threaded irq handler.
>>
>> There are currently 3 in tree drivers affected by this change.
>>
>> i2c-parport driver calls i2c_handle_smbus_alert in a hard irq context.
>> This driver use edge trigger interrupts which skip the enable / disable
>> calls. But it still need to handle the smbus transaction on a thread. So
>> the work thread is kept for this driver.
>>
>> i2c-parport-light & i2c-thunderx-pcidrv provide the irq number in the
>> setup which will result in the thread irq being used.
>>
>> i2c-parport-light is edge trigger so the enable / disable call was
>> skipped as well.
>>
>> i2c-thunderx-pcidrv is getting the edge / level trigger setting from of
>> data and was setting the flag as required. However the irq core should
>> handle this automatically.
>>
>> Signed-off-by: Phil Reid <preid@electromag.com.au>
> 
> CCing Benjamin for smbus changes (like last time). Please CC him in the
> future in case we need another revision of this series.
>

Sorry forgot he was added manually.
I just used the get maintainers script to get the list.
And he wasn't listed against the i2c / smbus paths.


-- 
Regards
Phil Reid

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v7 03/10] i2c: i2c-smbus: Use threaded irq for smbalert
  2017-06-19 15:27   ` Wolfram Sang
  2017-06-20  2:30     ` Phil Reid
@ 2017-06-23 12:11     ` Benjamin Tissoires
  1 sibling, 0 replies; 30+ messages in thread
From: Benjamin Tissoires @ 2017-06-23 12:11 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Phil Reid, robh+dt, mark.rutland, sre, jdelvare, jglauber,
	david.daney, peda, linux-i2c, devicetree, linux-pm

Hi,

On Jun 19 2017 or thereabouts, Wolfram Sang wrote:
> On Thu, Jun 15, 2017 at 09:59:31PM +0800, Phil Reid wrote:
> > Prior to this commit the smbalert_irq was handling in the hard irq
> > context. This change switch to using a thread irq which avoids the need
> > for the work thread. Using threaded irq also removes the need for the
> > edge_triggered flag as the enabling / disabling of the hard irq for level
> > triggered interrupts will be handled by the irq core.
> > 
> > Without this change have an irq connected to something like an i2c gpio
> > resulted in a null ptr deferences. Specifically handle_nested_irq calls
> > the threaded irq handler.
> > 
> > There are currently 3 in tree drivers affected by this change.
> > 
> > i2c-parport driver calls i2c_handle_smbus_alert in a hard irq context.
> > This driver use edge trigger interrupts which skip the enable / disable
> > calls. But it still need to handle the smbus transaction on a thread. So
> > the work thread is kept for this driver.
> > 
> > i2c-parport-light & i2c-thunderx-pcidrv provide the irq number in the
> > setup which will result in the thread irq being used.
> > 
> > i2c-parport-light is edge trigger so the enable / disable call was
> > skipped as well.
> > 
> > i2c-thunderx-pcidrv is getting the edge / level trigger setting from of
> > data and was setting the flag as required. However the irq core should
> > handle this automatically.
> > 
> > Signed-off-by: Phil Reid <preid@electromag.com.au>
> 
> CCing Benjamin for smbus changes (like last time). Please CC him in the
> future in case we need another revision of this series.

Thanks Wolfram.

I wonder if we can not have something similar than what we do for host notify
for removing the worker all together:

In host notify, we request a new IRQ number, and when the Host Notify
function is called, we simply call generic_handle_irq(). Switching
i2c-parport to something similar could help us remove this worker
entirely. But given this change would require to actually have a device
handled by i2c-parport, we might postpone this later.

Other than that, the patch looks good to me. The commit message is a
little bit messy IMO, and it took me a while to understand all the
subtleties (most of the issues raised in the messaged are simpler to
understand when reading the code).

Anyway, not a big deal, this one is:
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

Cheers,
Benjamin

> 
> > ---
> >  drivers/i2c/busses/i2c-parport-light.c   |  1 -
> >  drivers/i2c/busses/i2c-parport.c         |  1 -
> >  drivers/i2c/busses/i2c-thunderx-pcidrv.c |  6 -----
> >  drivers/i2c/i2c-smbus.c                  | 41 +++++++++++++-------------------
> >  include/linux/i2c-smbus.h                |  1 -
> >  5 files changed, 17 insertions(+), 33 deletions(-)
> > 
> > diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
> > index 1bcdd10..e6e22b8 100644
> > --- a/drivers/i2c/busses/i2c-parport-light.c
> > +++ b/drivers/i2c/busses/i2c-parport-light.c
> > @@ -123,7 +123,6 @@ static int parport_getsda(void *data)
> >  
> >  /* SMBus alert support */
> >  static struct i2c_smbus_alert_setup alert_data = {
> > -	.alert_edge_triggered	= 1,
> >  };
> >  static struct i2c_client *ara;
> >  static struct lineop parport_ctrl_irq = {
> > diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c
> > index a8e54df..319209a 100644
> > --- a/drivers/i2c/busses/i2c-parport.c
> > +++ b/drivers/i2c/busses/i2c-parport.c
> > @@ -237,7 +237,6 @@ static void i2c_parport_attach(struct parport *port)
> >  
> >  	/* Setup SMBus alert if supported */
> >  	if (adapter_parm[type].smbus_alert) {
> > -		adapter->alert_data.alert_edge_triggered = 1;
> >  		adapter->ara = i2c_setup_smbus_alert(&adapter->adapter,
> >  						     &adapter->alert_data);
> >  		if (adapter->ara)
> > diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c
> > index 1d4c2be..c27a50f 100644
> > --- a/drivers/i2c/busses/i2c-thunderx-pcidrv.c
> > +++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c
> > @@ -112,8 +112,6 @@ static void thunder_i2c_clock_disable(struct device *dev, struct clk *clk)
> >  static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c,
> >  				      struct device_node *node)
> >  {
> > -	u32 type;
> > -
> >  	if (!node)
> >  		return -EINVAL;
> >  
> > @@ -121,10 +119,6 @@ static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c,
> >  	if (!i2c->alert_data.irq)
> >  		return -EINVAL;
> >  
> > -	type = irqd_get_trigger_type(irq_get_irq_data(i2c->alert_data.irq));
> > -	i2c->alert_data.alert_edge_triggered =
> > -		(type & IRQ_TYPE_LEVEL_MASK) ? 1 : 0;
> > -
> >  	i2c->ara = i2c_setup_smbus_alert(&i2c->adap, &i2c->alert_data);
> >  	if (!i2c->ara)
> >  		return -ENODEV;
> > diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c
> > index f9271c7..d4af270 100644
> > --- a/drivers/i2c/i2c-smbus.c
> > +++ b/drivers/i2c/i2c-smbus.c
> > @@ -25,8 +25,6 @@
> >  #include <linux/workqueue.h>
> >  
> >  struct i2c_smbus_alert {
> > -	unsigned int		alert_edge_triggered:1;
> > -	int			irq;
> >  	struct work_struct	alert;
> >  	struct i2c_client	*ara;		/* Alert response address */
> >  };
> > @@ -72,13 +70,12 @@ static int smbus_do_alert(struct device *dev, void *addrp)
> >   * The alert IRQ handler needs to hand work off to a task which can issue
> >   * SMBus calls, because those sleeping calls can't be made in IRQ context.
> >   */
> > -static void smbus_alert(struct work_struct *work)
> > +static irqreturn_t smbus_alert(int irq, void *d)
> >  {
> > -	struct i2c_smbus_alert *alert;
> > +	struct i2c_smbus_alert *alert = d;
> >  	struct i2c_client *ara;
> >  	unsigned short prev_addr = 0;	/* Not a valid address */
> >  
> > -	alert = container_of(work, struct i2c_smbus_alert, alert);
> >  	ara = alert->ara;
> >  
> >  	for (;;) {
> > @@ -115,21 +112,17 @@ static void smbus_alert(struct work_struct *work)
> >  		prev_addr = data.addr;
> >  	}
> >  
> > -	/* We handled all alerts; re-enable level-triggered IRQs */
> > -	if (!alert->alert_edge_triggered)
> > -		enable_irq(alert->irq);
> > +	return IRQ_HANDLED;
> >  }
> >  
> > -static irqreturn_t smbalert_irq(int irq, void *d)
> > +static void smbalert_work(struct work_struct *work)
> >  {
> > -	struct i2c_smbus_alert *alert = d;
> > +	struct i2c_smbus_alert *alert;
> > +
> > +	alert = container_of(work, struct i2c_smbus_alert, alert);
> >  
> > -	/* Disable level-triggered IRQs until we handle them */
> > -	if (!alert->alert_edge_triggered)
> > -		disable_irq_nosync(irq);
> > +	smbus_alert(0, alert);
> >  
> > -	schedule_work(&alert->alert);
> > -	return IRQ_HANDLED;
> >  }
> >  
> >  /* Setup SMBALERT# infrastructure */
> > @@ -139,28 +132,28 @@ static int smbalert_probe(struct i2c_client *ara,
> >  	struct i2c_smbus_alert_setup *setup = dev_get_platdata(&ara->dev);
> >  	struct i2c_smbus_alert *alert;
> >  	struct i2c_adapter *adapter = ara->adapter;
> > -	int res;
> > +	int res, irq;
> >  
> >  	alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert),
> >  			     GFP_KERNEL);
> >  	if (!alert)
> >  		return -ENOMEM;
> >  
> > -	alert->alert_edge_triggered = setup->alert_edge_triggered;
> > -	alert->irq = setup->irq;
> > -	INIT_WORK(&alert->alert, smbus_alert);
> > +	irq = setup->irq;
> > +	INIT_WORK(&alert->alert, smbalert_work);
> >  	alert->ara = ara;
> >  
> > -	if (setup->irq > 0) {
> > -		res = devm_request_irq(&ara->dev, setup->irq, smbalert_irq,
> > -				       0, "smbus_alert", alert);
> > +	if (irq > 0) {
> > +		res = devm_request_threaded_irq(&ara->dev, irq,
> > +						NULL, smbus_alert,
> > +						IRQF_SHARED | IRQF_ONESHOT,
> > +						"smbus_alert", alert);
> >  		if (res)
> >  			return res;
> >  	}
> >  
> >  	i2c_set_clientdata(ara, alert);
> > -	dev_info(&adapter->dev, "supports SMBALERT#, %s trigger\n",
> > -		 setup->alert_edge_triggered ? "edge" : "level");
> > +	dev_info(&adapter->dev, "supports SMBALERT#\n");
> >  
> >  	return 0;
> >  }
> > diff --git a/include/linux/i2c-smbus.h b/include/linux/i2c-smbus.h
> > index a138502..19efbd1 100644
> > --- a/include/linux/i2c-smbus.h
> > +++ b/include/linux/i2c-smbus.h
> > @@ -42,7 +42,6 @@
> >   * properly set.
> >   */
> >  struct i2c_smbus_alert_setup {
> > -	unsigned int		alert_edge_triggered:1;
> >  	int			irq;
> >  };
> >  
> > -- 
> > 1.8.3.1
> > 

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v7 04/10] i2c: i2c-smbus: add of_i2c_setup_smbus_alert
  2017-06-19 15:27     ` Wolfram Sang
@ 2017-06-23 12:15       ` Benjamin Tissoires
  2017-06-28  6:48         ` Phil Reid
  0 siblings, 1 reply; 30+ messages in thread
From: Benjamin Tissoires @ 2017-06-23 12:15 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Phil Reid, robh+dt, mark.rutland, sre, jdelvare, jglauber,
	david.daney, peda, linux-i2c, devicetree, linux-pm

On Jun 19 2017 or thereabouts, Wolfram Sang wrote:
> On Thu, Jun 15, 2017 at 09:59:32PM +0800, Phil Reid wrote:
> > This commit adds of_i2c_setup_smbus_alert which allows the smbalert
> > driver to be attached to an i2c adapter via the device tree.
> > 
> > Signed-off-by: Phil Reid <preid@electromag.com.au>
> > Acked-by: Rob Herring <robh@kernel.org>
> 
> CCing Benjamin
> 
> > ---
> >  Documentation/devicetree/bindings/i2c/i2c.txt |  4 ++--
> >  drivers/i2c/i2c-smbus.c                       | 34 ++++++++++++++++++++++++---
> >  include/linux/i2c-smbus.h                     |  9 +++++++
> >  3 files changed, 42 insertions(+), 5 deletions(-)
> > 
> > diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt
> > index cee9d50..1126398 100644
> > --- a/Documentation/devicetree/bindings/i2c/i2c.txt
> > +++ b/Documentation/devicetree/bindings/i2c/i2c.txt
> > @@ -59,8 +59,8 @@ wants to support one of the below features, it should adapt the bindings below.
> >  	interrupts used by the device.
> >  
> >  - interrupt-names
> > -	"irq" and "wakeup" names are recognized by I2C core, other names are
> > -	left to individual drivers.
> > +	"irq", "wakeup" and "smbus_alert" names are recognized by I2C core,
> > +	other names are	left to individual drivers.
> >  
> >  - host-notify
> >  	device uses SMBus host notify protocol instead of interrupt line.
> > diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c
> > index d4af270..0ad7f7f 100644
> > --- a/drivers/i2c/i2c-smbus.c
> > +++ b/drivers/i2c/i2c-smbus.c
> > @@ -21,6 +21,7 @@
> >  #include <linux/interrupt.h>
> >  #include <linux/kernel.h>
> >  #include <linux/module.h>
> > +#include <linux/of_irq.h>
> >  #include <linux/slab.h>
> >  #include <linux/workqueue.h>
> >  
> > @@ -131,7 +132,7 @@ static int smbalert_probe(struct i2c_client *ara,
> >  {
> >  	struct i2c_smbus_alert_setup *setup = dev_get_platdata(&ara->dev);
> >  	struct i2c_smbus_alert *alert;
> > -	struct i2c_adapter *adapter = ara->adapter;
> > +	struct i2c_adapter *adap = ara->adapter;

I am not a big fan of this rename (even for consistency with the rest of
the file). It makes the patch bigger of 2 hunks for nothing :/

(Wolfram might have a different opinion)

> >  	int res, irq;
> >  
> >  	alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert),
> > @@ -139,7 +140,14 @@ static int smbalert_probe(struct i2c_client *ara,
> >  	if (!alert)
> >  		return -ENOMEM;
> >  
> > -	irq = setup->irq;
> > +	if (setup) {
> > +		irq = setup->irq;
> > +	} else {
> > +		irq = of_irq_get_byname(adap->dev.of_node, "smbus_alert");
> > +		if (irq <= 0)
> > +			return irq;
> > +	}
> > +
> >  	INIT_WORK(&alert->alert, smbalert_work);
> >  	alert->ara = ara;
> >  
> > @@ -153,7 +161,7 @@ static int smbalert_probe(struct i2c_client *ara,
> >  	}
> >  
> >  	i2c_set_clientdata(ara, alert);
> > -	dev_info(&adapter->dev, "supports SMBALERT#\n");
> > +	dev_info(&adap->dev, "supports SMBALERT#\n");
> >  
> >  	return 0;
> >  }
> > @@ -214,6 +222,26 @@ struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter,
> >  }
> >  EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert);
> >  
> > +int of_i2c_setup_smbus_alert(struct i2c_adapter *adap)
> > +{
> > +	struct i2c_client *client;
> > +	int irq;
> > +
> > +	irq = of_property_match_string(adap->dev.of_node, "interrupt-names",
> > +				       "smbus_alert");
> > +	if (irq == -EINVAL || irq == -ENODATA)
> > +		return 0;
> > +	else if (irq < 0)
> > +		return irq;
> > +
> > +	client = i2c_setup_smbus_alert(adap, NULL);
> > +	if (!client)
> > +		return -ENODEV;
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(of_i2c_setup_smbus_alert);
> > +
> >  /**
> >   * i2c_handle_smbus_alert - Handle an SMBus alert
> >   * @ara: the ARA client on the relevant adapter
> > diff --git a/include/linux/i2c-smbus.h b/include/linux/i2c-smbus.h
> > index 19efbd1..b5261c1 100644
> > --- a/include/linux/i2c-smbus.h
> > +++ b/include/linux/i2c-smbus.h
> > @@ -49,4 +49,13 @@ struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter,
> >  					 struct i2c_smbus_alert_setup *setup);
> >  int i2c_handle_smbus_alert(struct i2c_client *ara);
> >  
> > +#if IS_ENABLED(CONFIG_I2C_SMBUS)

Can't we have:
#if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(*whatever OF config symbol is*)

Because otherwise, even if the code works from what I understand, we
will pull in i2c-smbus from i2c-core all the time.

Besides those nitpicks, the patch is OK IMO.

Cheers,
Benjamin

> > +int of_i2c_setup_smbus_alert(struct i2c_adapter *adap);
> > +#else
> > +static inline int of_i2c_setup_smbus_alert(struct i2c_adapter *adap)
> > +{
> > +	return 0;
> > +}
> > +#endif
> > +
> >  #endif /* _LINUX_I2C_SMBUS_H */
> > -- 
> > 1.8.3.1
> > 

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v7 05/10] i2c: core: call of_i2c_setup_smbus_alert in i2c_register_adapter
  2017-06-19 15:28   ` Wolfram Sang
@ 2017-06-23 12:19     ` Benjamin Tissoires
  2017-06-28  6:44       ` Phil Reid
  0 siblings, 1 reply; 30+ messages in thread
From: Benjamin Tissoires @ 2017-06-23 12:19 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Phil Reid, robh+dt, mark.rutland, sre, jdelvare, jglauber,
	david.daney, peda, linux-i2c, devicetree, linux-pm

On Jun 19 2017 or thereabouts, Wolfram Sang wrote:
> On Thu, Jun 15, 2017 at 09:59:33PM +0800, Phil Reid wrote:
> > Add a call to of_i2c_setup_smbus_alert when a i2c adapter is registered
> > so the the smbalert driver can be registered.
> > 
> > Signed-off-by: Phil Reid <preid@electromag.com.au>
> 
> CCing Benjamin
> 
> > ---
> >  drivers/i2c/i2c-core.c | 4 ++++
> >  1 file changed, 4 insertions(+)
> > 
> > diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
> > index d2402bb..626471b 100644
> > --- a/drivers/i2c/i2c-core.c
> > +++ b/drivers/i2c/i2c-core.c
> > @@ -40,6 +40,7 @@
> >  #include <linux/gpio.h>
> >  #include <linux/hardirq.h>
> >  #include <linux/i2c.h>
> > +#include <linux/i2c-smbus.h>
> >  #include <linux/idr.h>
> >  #include <linux/init.h>
> >  #include <linux/irqflags.h>
> > @@ -2045,6 +2046,9 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
> >  		dev_warn(&adap->dev,
> >  			 "Failed to create compatibility class link\n");
> >  #endif
> > +	res = of_i2c_setup_smbus_alert(adap);
> > +	if (res)
> > +		goto out_list;

See my concerns in patch 4/10.

In addition, shouldn't this be placed before device_register() for the
least? pm_runtime_enable() would require a matching pm_runtime_disable(),
and device_register() some unregistering behavior too.

Cheers,
Benjamin

> >  
> >  	i2c_init_recovery(adap);
> >  
> > -- 
> > 1.8.3.1
> > 

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v7 05/10] i2c: core: call of_i2c_setup_smbus_alert in i2c_register_adapter
  2017-06-23 12:19     ` Benjamin Tissoires
@ 2017-06-28  6:44       ` Phil Reid
  2017-06-28 12:45         ` Benjamin Tissoires
  0 siblings, 1 reply; 30+ messages in thread
From: Phil Reid @ 2017-06-28  6:44 UTC (permalink / raw)
  To: Benjamin Tissoires, Wolfram Sang
  Cc: robh+dt, mark.rutland, sre, jdelvare, jglauber, david.daney,
	peda, linux-i2c, devicetree, linux-pm

On 23/06/2017 20:19, Benjamin Tissoires wrote:
> On Jun 19 2017 or thereabouts, Wolfram Sang wrote:
>> On Thu, Jun 15, 2017 at 09:59:33PM +0800, Phil Reid wrote:
>>> Add a call to of_i2c_setup_smbus_alert when a i2c adapter is registered
>>> so the the smbalert driver can be registered.
>>>
>>> Signed-off-by: Phil Reid <preid@electromag.com.au>
>>
>> CCing Benjamin
>>
>>> ---
>>>   drivers/i2c/i2c-core.c | 4 ++++
>>>   1 file changed, 4 insertions(+)
>>>
>>> diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
>>> index d2402bb..626471b 100644
>>> --- a/drivers/i2c/i2c-core.c
>>> +++ b/drivers/i2c/i2c-core.c
>>> @@ -40,6 +40,7 @@
>>>   #include <linux/gpio.h>
>>>   #include <linux/hardirq.h>
>>>   #include <linux/i2c.h>
>>> +#include <linux/i2c-smbus.h>
>>>   #include <linux/idr.h>
>>>   #include <linux/init.h>
>>>   #include <linux/irqflags.h>
>>> @@ -2045,6 +2046,9 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
>>>   		dev_warn(&adap->dev,
>>>   			 "Failed to create compatibility class link\n");
>>>   #endif
>>> +	res = of_i2c_setup_smbus_alert(adap);
>>> +	if (res)
>>> +		goto out_list;
> 
> See my concerns in patch 4/10.
> 
> In addition, shouldn't this be placed before device_register() for the
> least? pm_runtime_enable() would require a matching pm_runtime_disable(),
> and device_register() some unregistering behavior too.
> 

G'day Ben,

Thanks for the review.
Yes this makes sense. I tried having it before the device_register and I get an error
about a kobject not being initialised in the a call from of_i2c_setup_smbus_alert.

Having a look at what I'm doing in of_i2c_setup_smbus_alert now I'm not sure there's
a need to bail out on an error now. Originally I was registering the irq in the setup call.
Which need to handle probe defer. Now this should be handled in the alert probe call.

WDYR?



-- 
Regards
Phil Reid

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v7 04/10] i2c: i2c-smbus: add of_i2c_setup_smbus_alert
  2017-06-23 12:15       ` Benjamin Tissoires
@ 2017-06-28  6:48         ` Phil Reid
  2017-06-28 12:42           ` Benjamin Tissoires
  0 siblings, 1 reply; 30+ messages in thread
From: Phil Reid @ 2017-06-28  6:48 UTC (permalink / raw)
  To: Benjamin Tissoires, Wolfram Sang
  Cc: robh+dt, mark.rutland, sre, jdelvare, jglauber, david.daney,
	peda, linux-i2c, devicetree, linux-pm

On 23/06/2017 20:15, Benjamin Tissoires wrote:
> On Jun 19 2017 or thereabouts, Wolfram Sang wrote:
>> On Thu, Jun 15, 2017 at 09:59:32PM +0800, Phil Reid wrote:
>>> This commit adds of_i2c_setup_smbus_alert which allows the smbalert
>>> driver to be attached to an i2c adapter via the device tree.
>>>
>>> Signed-off-by: Phil Reid <preid@electromag.com.au>
>>> Acked-by: Rob Herring <robh@kernel.org>
>>
>> CCing Benjamin
>>
>>> ---
>>>   Documentation/devicetree/bindings/i2c/i2c.txt |  4 ++--
>>>   drivers/i2c/i2c-smbus.c                       | 34 ++++++++++++++++++++++++---
>>>   include/linux/i2c-smbus.h                     |  9 +++++++
>>>   3 files changed, 42 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt
>>> index cee9d50..1126398 100644
>>> --- a/Documentation/devicetree/bindings/i2c/i2c.txt
>>> +++ b/Documentation/devicetree/bindings/i2c/i2c.txt
>>> @@ -59,8 +59,8 @@ wants to support one of the below features, it should adapt the bindings below.
>>>   	interrupts used by the device.
>>>   
>>>   - interrupt-names
>>> -	"irq" and "wakeup" names are recognized by I2C core, other names are
>>> -	left to individual drivers.
>>> +	"irq", "wakeup" and "smbus_alert" names are recognized by I2C core,
>>> +	other names are	left to individual drivers.
>>>   
>>>   - host-notify
>>>   	device uses SMBus host notify protocol instead of interrupt line.
>>> diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c
>>> index d4af270..0ad7f7f 100644
>>> --- a/drivers/i2c/i2c-smbus.c
>>> +++ b/drivers/i2c/i2c-smbus.c
>>> @@ -21,6 +21,7 @@
>>>   #include <linux/interrupt.h>
>>>   #include <linux/kernel.h>
>>>   #include <linux/module.h>
>>> +#include <linux/of_irq.h>
>>>   #include <linux/slab.h>
>>>   #include <linux/workqueue.h>
>>>   
>>> @@ -131,7 +132,7 @@ static int smbalert_probe(struct i2c_client *ara,
>>>   {
>>>   	struct i2c_smbus_alert_setup *setup = dev_get_platdata(&ara->dev);
>>>   	struct i2c_smbus_alert *alert;
>>> -	struct i2c_adapter *adapter = ara->adapter;
>>> +	struct i2c_adapter *adap = ara->adapter;
> 
> I am not a big fan of this rename (even for consistency with the rest of
> the file). It makes the patch bigger of 2 hunks for nothing :/
> 
> (Wolfram might have a different opinion)

Fair enough I'll remove the rename.

> 
>>>   	int res, irq;
>>>   
>>>   	alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert),
>>> @@ -139,7 +140,14 @@ static int smbalert_probe(struct i2c_client *ara,
>>>   	if (!alert)
>>>   		return -ENOMEM;
>>>   
>>> -	irq = setup->irq;
>>> +	if (setup) {
>>> +		irq = setup->irq;
>>> +	} else {
>>> +		irq = of_irq_get_byname(adap->dev.of_node, "smbus_alert");
>>> +		if (irq <= 0)
>>> +			return irq;
>>> +	}
>>> +
>>>   	INIT_WORK(&alert->alert, smbalert_work);
>>>   	alert->ara = ara;
>>>   
>>> @@ -153,7 +161,7 @@ static int smbalert_probe(struct i2c_client *ara,
>>>   	}
>>>   
>>>   	i2c_set_clientdata(ara, alert);
>>> -	dev_info(&adapter->dev, "supports SMBALERT#\n");
>>> +	dev_info(&adap->dev, "supports SMBALERT#\n");
>>>   
>>>   	return 0;
>>>   }
>>> @@ -214,6 +222,26 @@ struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter,
>>>   }
>>>   EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert);
>>>   
>>> +int of_i2c_setup_smbus_alert(struct i2c_adapter *adap)
>>> +{
>>> +	struct i2c_client *client;
>>> +	int irq;
>>> +
>>> +	irq = of_property_match_string(adap->dev.of_node, "interrupt-names",
>>> +				       "smbus_alert");
>>> +	if (irq == -EINVAL || irq == -ENODATA)
>>> +		return 0;
>>> +	else if (irq < 0)
>>> +		return irq;
>>> +
>>> +	client = i2c_setup_smbus_alert(adap, NULL);
>>> +	if (!client)
>>> +		return -ENODEV;
>>> +
>>> +	return 0;
>>> +}
>>> +EXPORT_SYMBOL_GPL(of_i2c_setup_smbus_alert);
>>> +
>>>   /**
>>>    * i2c_handle_smbus_alert - Handle an SMBus alert
>>>    * @ara: the ARA client on the relevant adapter
>>> diff --git a/include/linux/i2c-smbus.h b/include/linux/i2c-smbus.h
>>> index 19efbd1..b5261c1 100644
>>> --- a/include/linux/i2c-smbus.h
>>> +++ b/include/linux/i2c-smbus.h
>>> @@ -49,4 +49,13 @@ struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter,
>>>   					 struct i2c_smbus_alert_setup *setup);
>>>   int i2c_handle_smbus_alert(struct i2c_client *ara);
>>>   
>>> +#if IS_ENABLED(CONFIG_I2C_SMBUS)
> 
> Can't we have:
> #if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(*whatever OF config symbol is*)
> 
> Because otherwise, even if the code works from what I understand, we
> will pull in i2c-smbus from i2c-core all the time.

Sorry I'm lost here.
CONFIG_I2C_SMBUS looks to the be symbol that enables i2c-smbus in the makefile.
I thought this would be enough to keep it out of the core.






-- 
Regards
Phil Reid

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v7 04/10] i2c: i2c-smbus: add of_i2c_setup_smbus_alert
  2017-06-28  6:48         ` Phil Reid
@ 2017-06-28 12:42           ` Benjamin Tissoires
  0 siblings, 0 replies; 30+ messages in thread
From: Benjamin Tissoires @ 2017-06-28 12:42 UTC (permalink / raw)
  To: Phil Reid
  Cc: Wolfram Sang, robh+dt, mark.rutland, sre, jdelvare, jglauber,
	david.daney, peda, linux-i2c, devicetree, linux-pm

On Jun 28 2017 or thereabouts, Phil Reid wrote:
> > > > diff --git a/include/linux/i2c-smbus.h b/include/linux/i2c-smbus.h
> > > > index 19efbd1..b5261c1 100644
> > > > --- a/include/linux/i2c-smbus.h
> > > > +++ b/include/linux/i2c-smbus.h
> > > > @@ -49,4 +49,13 @@ struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter,
> > > >   					 struct i2c_smbus_alert_setup *setup);
> > > >   int i2c_handle_smbus_alert(struct i2c_client *ara);
> > > > +#if IS_ENABLED(CONFIG_I2C_SMBUS)
> > 
> > Can't we have:
> > #if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(*whatever OF config symbol is*)
> > 
> > Because otherwise, even if the code works from what I understand, we
> > will pull in i2c-smbus from i2c-core all the time.
> 
> Sorry I'm lost here.
> CONFIG_I2C_SMBUS looks to the be symbol that enables i2c-smbus in the makefile.
> I thought this would be enough to keep it out of the core.
> 

Assuming CONFIG_I2C_SMBUS is set, my concerns are regarding the fact
that i2c-smbus.ko will now be pulled in by i2c-core.ko no matter what.
There is nothing wrong per se in the code, just that now i2c-core
depends on i2c_smbus given that you call i2c_setup_smbus_alert() in
i2c-core. So that makes the whole point of having a separate module
for i2c-smbus moot.

If of_i2c_setup_smbus_alert() is masked by IS_ENABLED(OF), then the call
for i2c_setup_smbus_alert() will only be done with OF enabled, meaning
that i2c-smbus.ko will only be pulled in by i2c-core when OF is in use.

But maybe that is too much of thinking from my part :)

Cheers,
Benjamin

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v7 05/10] i2c: core: call of_i2c_setup_smbus_alert in i2c_register_adapter
  2017-06-28  6:44       ` Phil Reid
@ 2017-06-28 12:45         ` Benjamin Tissoires
  2017-07-11  7:52           ` Phil Reid
  0 siblings, 1 reply; 30+ messages in thread
From: Benjamin Tissoires @ 2017-06-28 12:45 UTC (permalink / raw)
  To: Phil Reid
  Cc: Wolfram Sang, robh+dt, mark.rutland, sre, jdelvare, jglauber,
	david.daney, peda, linux-i2c, devicetree, linux-pm

On Jun 28 2017 or thereabouts, Phil Reid wrote:
> On 23/06/2017 20:19, Benjamin Tissoires wrote:
> > On Jun 19 2017 or thereabouts, Wolfram Sang wrote:
> > > On Thu, Jun 15, 2017 at 09:59:33PM +0800, Phil Reid wrote:
> > > > Add a call to of_i2c_setup_smbus_alert when a i2c adapter is registered
> > > > so the the smbalert driver can be registered.
> > > > 
> > > > Signed-off-by: Phil Reid <preid@electromag.com.au>
> > > 
> > > CCing Benjamin
> > > 
> > > > ---
> > > >   drivers/i2c/i2c-core.c | 4 ++++
> > > >   1 file changed, 4 insertions(+)
> > > > 
> > > > diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
> > > > index d2402bb..626471b 100644
> > > > --- a/drivers/i2c/i2c-core.c
> > > > +++ b/drivers/i2c/i2c-core.c
> > > > @@ -40,6 +40,7 @@
> > > >   #include <linux/gpio.h>
> > > >   #include <linux/hardirq.h>
> > > >   #include <linux/i2c.h>
> > > > +#include <linux/i2c-smbus.h>
> > > >   #include <linux/idr.h>
> > > >   #include <linux/init.h>
> > > >   #include <linux/irqflags.h>
> > > > @@ -2045,6 +2046,9 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
> > > >   		dev_warn(&adap->dev,
> > > >   			 "Failed to create compatibility class link\n");
> > > >   #endif
> > > > +	res = of_i2c_setup_smbus_alert(adap);
> > > > +	if (res)
> > > > +		goto out_list;
> > 
> > See my concerns in patch 4/10.
> > 
> > In addition, shouldn't this be placed before device_register() for the
> > least? pm_runtime_enable() would require a matching pm_runtime_disable(),
> > and device_register() some unregistering behavior too.
> > 
> 
> G'day Ben,
> 
> Thanks for the review.
> Yes this makes sense. I tried having it before the device_register and I get an error
> about a kobject not being initialised in the a call from of_i2c_setup_smbus_alert.
> 
> Having a look at what I'm doing in of_i2c_setup_smbus_alert now I'm not sure there's
> a need to bail out on an error now. Originally I was registering the irq in the setup call.
> Which need to handle probe defer. Now this should be handled in the alert probe call.
> 
> WDYR?

Well, of_i2c_setup_smbus_alert() returns an error code, so it has to be
accounted for. If the error is not a reason to fail, you should at least
shout some error messages and act accordingly.

However, looking at of_i2c_setup_smbus_alert() again, I wonder if we
should not split it in 2: one part that checks for the OF flag presence
and bail out early if an error is encountered (before device
registration), and one part once the device is registered that calls
i2c_setup_smbus_alert(). In case of a failure here, we need to
unregister the adapter because we don't have all the elements at hands
(assuming we consider that smbus-alert should be mandatory).

Cheers,
Benjamin

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v7 07/10] Documentation: Add sbs-manager device tree node documentation
  2017-06-15 13:59 ` [PATCH v7 07/10] Documentation: Add sbs-manager device tree node documentation Phil Reid
@ 2017-07-03 13:57   ` Sebastian Reichel
  0 siblings, 0 replies; 30+ messages in thread
From: Sebastian Reichel @ 2017-07-03 13:57 UTC (permalink / raw)
  To: Phil Reid
  Cc: wsa, robh+dt, mark.rutland, jdelvare, jglauber, david.daney,
	peda, linux-i2c, devicetree, linux-pm, Karl-Heinz Schneider

[-- Attachment #1: Type: text/plain, Size: 3168 bytes --]

Hi,

On Thu, Jun 15, 2017 at 09:59:35PM +0800, Phil Reid wrote:
> From: Karl-Heinz Schneider <karl-heinz@schneider-inet.de>
> 
> This patch adds device tree documentation for the sbs-manager
> 
> Signed-off-by: Karl-Heinz Schneider <karl-heinz@schneider-inet.de>
> Signed-off-by: Phil Reid <preid@electromag.com.au>
> Acked-by: Rob Herring <robh@kernel.org>

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

> ---
>  .../bindings/power/supply/sbs,sbs-manager.txt      | 66 ++++++++++++++++++++++
>  1 file changed, 66 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/power/supply/sbs,sbs-manager.txt
> 
> diff --git a/Documentation/devicetree/bindings/power/supply/sbs,sbs-manager.txt b/Documentation/devicetree/bindings/power/supply/sbs,sbs-manager.txt
> new file mode 100644
> index 0000000..4b219557
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/supply/sbs,sbs-manager.txt
> @@ -0,0 +1,66 @@
> +Binding for sbs-manager
> +
> +Required properties:
> +- compatible: "<vendor>,<part-number>", "sbs,sbs-charger" as fallback. The part
> +  number compatible string might be used in order to take care of vendor
> +  specific registers.
> +- reg: integer, i2c address of the device. Should be <0xa>.
> +Optional properties:
> +- gpio-controller: Marks the port as GPIO controller.
> +  See "gpio-specifier" in .../devicetree/bindings/gpio/gpio.txt.
> +- #gpio-cells: Should be <2>. The first cell is the pin number, the second cell
> +  is used to specify optional parameters:
> +  See "gpio-specifier" in .../devicetree/bindings/gpio/gpio.txt.
> +
> +From OS view the device is basically an i2c-mux used to communicate with up to
> +four smart battery devices at address 0xb. The driver actually implements this
> +behaviour. So standard i2c-mux nodes can be used to register up to four slave
> +batteries. Channels will be numerated starting from 1 to 4.
> +
> +Example:
> +
> +batman@a {
> +    compatible = "lltc,ltc1760", "sbs,sbs-manager";
> +    reg = <0x0a>;
> +    #address-cells = <1>;
> +    #size-cells = <0>;
> +
> +    gpio-controller;
> +    #gpio-cells = <2>;
> +
> +    i2c@1 {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +        reg = <1>;
> +
> +        battery@b {
> +            compatible = "ti,bq2060", "sbs,sbs-battery";
> +            reg = <0x0b>;
> +            sbs,battery-detect-gpios = <&batman 1 1>;
> +        };
> +    };
> +
> +    i2c@2 {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +        reg = <2>;
> +
> +        battery@b {
> +            compatible = "ti,bq2060", "sbs,sbs-battery";
> +            reg = <0x0b>;
> +            sbs,battery-detect-gpios = <&batman 2 1>;
> +        };
> +    };
> +
> +    i2c@3 {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +        reg = <3>;
> +
> +        battery@b {
> +            compatible = "ti,bq2060", "sbs,sbs-battery";
> +            reg = <0x0b>;
> +            sbs,battery-detect-gpios = <&batman 3 1>;
> +        };
> +    };
> +};
> -- 
> 1.8.3.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v7 08/10] power: Adds support for Smart Battery System Manager
       [not found]   ` <1497535178-12001-9-git-send-email-preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
@ 2017-07-03 15:17     ` Sebastian Reichel
  0 siblings, 0 replies; 30+ messages in thread
From: Sebastian Reichel @ 2017-07-03 15:17 UTC (permalink / raw)
  To: Phil Reid
  Cc: wsa-z923LK4zBo2bacvFa/9K2g, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, jdelvare-IBi9RG/b67k,
	jglauber-YGCgFSpz5w/QT0dZR+AlfA,
	david.daney-YGCgFSpz5w/QT0dZR+AlfA, peda-koto5C5qi+TLoDKTGw+V6w,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Karl-Heinz Schneider

[-- Attachment #1: Type: text/plain, Size: 12578 bytes --]

Hi,

On Thu, Jun 15, 2017 at 09:59:36PM +0800, Phil Reid wrote:
> From: Karl-Heinz Schneider <karl-heinz-X5L7DgJ4l23oE99TX8zNy7NAH6kLmebB@public.gmane.org>
> 
> This patch adds support for Smart Battery System Manager.
> A SBSM is a device listening at I2C/SMBus address 0x0a and is capable of
> communicating up to four I2C smart battery devices. All smart battery
> devices are listening at address 0x0b, so the SBSM muliplexes between
> them. The driver makes use of the I2C-Mux framework to allow smart
> batteries to be bound via device tree, i.e. the sbs-battery driver.
> 
> Via sysfs interface the online state and charge type are presented. If
> the driver is bound as ltc1760 (an implementation of a Dual Smart Battery
> System Manager) the charge type can also be changed from trickle to fast.
> 
> Tested-by: Phil Reid <preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
> Reviewed-by: Phil Reid <preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
> Signed-off-by: Karl-Heinz Schneider <karl-heinz-X5L7DgJ4l23oE99TX8zNy7NAH6kLmebB@public.gmane.org>
> Signed-off-by: Phil Reid <preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
> ---
>  drivers/power/supply/Kconfig       |  13 ++
>  drivers/power/supply/Makefile      |   1 +
>  drivers/power/supply/sbs-manager.c | 323 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 337 insertions(+)
>  create mode 100644 drivers/power/supply/sbs-manager.c

Reviewed-by: Sebastian Reichel <sebastian.reichel-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>

-- Sebastian

> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
> index da54ac8..a435415 100644
> --- a/drivers/power/supply/Kconfig
> +++ b/drivers/power/supply/Kconfig
> @@ -170,6 +170,19 @@ config CHARGER_SBS
>          help
>  	  Say Y to include support for SBS compilant battery chargers.
>  
> +config MANAGER_SBS
> +	tristate "Smart Battery System Manager"
> +	depends on I2C && I2C_MUX
> +	help
> +	  Say Y here to include support for Smart Battery System Manager
> +	  ICs. The driver reports online and charging status via sysfs.
> +	  It presents itself also as I2C mux which allows to bind
> +	  smart battery driver to its ports.
> +	  Supported is for example LTC1760.
> +
> +	  This driver can also be built as a module. If so, the module will be
> +	  called sbs-manager.
> +
>  config BATTERY_BQ27XXX
>  	tristate "BQ27xxx battery driver"
>  	help
> diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
> index 3789a2c..350c0bb 100644
> --- a/drivers/power/supply/Makefile
> +++ b/drivers/power/supply/Makefile
> @@ -33,6 +33,7 @@ obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o
>  obj-$(CONFIG_BATTERY_WM97XX)	+= wm97xx_battery.o
>  obj-$(CONFIG_BATTERY_SBS)	+= sbs-battery.o
>  obj-$(CONFIG_CHARGER_SBS)	+= sbs-charger.o
> +obj-$(CONFIG_MANAGER_SBS)	+= sbs-manager.o
>  obj-$(CONFIG_BATTERY_BQ27XXX)	+= bq27xxx_battery.o
>  obj-$(CONFIG_BATTERY_BQ27XXX_I2C) += bq27xxx_battery_i2c.o
>  obj-$(CONFIG_BATTERY_DA9030)	+= da9030_battery.o
> diff --git a/drivers/power/supply/sbs-manager.c b/drivers/power/supply/sbs-manager.c
> new file mode 100644
> index 0000000..47c09a1
> --- /dev/null
> +++ b/drivers/power/supply/sbs-manager.c
> @@ -0,0 +1,323 @@
> +/*
> + * Driver for SBS compliant Smart Battery System Managers
> + *
> + * The device communicates via i2c at address 0x0a and multiplexes access to up
> + * to four smart batteries at address 0x0b.
> + *
> + * Via sysfs interface the online state and charge type are presented.
> + *
> + * Datasheet SBSM:    http://sbs-forum.org/specs/sbsm100b.pdf
> + * Datasheet LTC1760: http://cds.linear.com/docs/en/datasheet/1760fb.pdf
> + *
> + * Karl-Heinz Schneider <karl-heinz-X5L7DgJ4l23oE99TX8zNy7NAH6kLmebB@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/i2c.h>
> +#include <linux/i2c-mux.h>
> +#include <linux/power_supply.h>
> +
> +#define SBSM_MAX_BATS  4
> +#define SBSM_RETRY_CNT 3
> +
> +/* registers addresses */
> +#define SBSM_CMD_BATSYSSTATE     0x01
> +#define SBSM_CMD_BATSYSSTATECONT 0x02
> +#define SBSM_CMD_BATSYSINFO      0x04
> +#define SBSM_CMD_LTC             0x3c
> +
> +#define SBSM_MASK_BAT_SUPPORTED  GENMASK(3, 0)
> +#define SBSM_MASK_CHARGE_BAT     GENMASK(7, 4)
> +#define SBSM_BIT_AC_PRESENT      BIT(0)
> +#define SBSM_BIT_TURBO           BIT(7)
> +
> +#define SBSM_SMB_BAT_OFFSET      11
> +struct sbsm_data {
> +	struct i2c_client *client;
> +	struct i2c_mux_core *muxc;
> +
> +	struct power_supply *psy;
> +
> +	u8 cur_chan;          /* currently selected channel */
> +	bool is_ltc1760;      /* special capabilities */
> +};
> +
> +static enum power_supply_property sbsm_props[] = {
> +	POWER_SUPPLY_PROP_ONLINE,
> +	POWER_SUPPLY_PROP_CHARGE_TYPE,
> +};
> +
> +static int sbsm_read_word(struct i2c_client *client, u8 address)
> +{
> +	int reg, retries;
> +
> +	for (retries = SBSM_RETRY_CNT; retries > 0; retries--) {
> +		reg = i2c_smbus_read_word_data(client, address);
> +		if (reg >= 0)
> +			break;
> +	}
> +
> +	if (reg < 0) {
> +		dev_err(&client->dev, "failed to read register 0x%02x\n",
> +			address);
> +	}
> +
> +	return reg;
> +}
> +
> +static int sbsm_write_word(struct i2c_client *client, u8 address, u16 word)
> +{
> +	int ret, retries;
> +
> +	for (retries = SBSM_RETRY_CNT; retries > 0; retries--) {
> +		ret = i2c_smbus_write_word_data(client, address, word);
> +		if (ret >= 0)
> +			break;
> +	}
> +	if (ret < 0)
> +		dev_err(&client->dev, "failed to write to register 0x%02x\n",
> +			address);
> +
> +	return ret;
> +}
> +
> +static int sbsm_get_property(struct power_supply *psy,
> +			     enum power_supply_property psp,
> +			     union power_supply_propval *val)
> +{
> +	struct sbsm_data *data = power_supply_get_drvdata(psy);
> +	int regval = 0;
> +
> +	switch (psp) {
> +	case POWER_SUPPLY_PROP_ONLINE:
> +		regval = sbsm_read_word(data->client, SBSM_CMD_BATSYSSTATECONT);
> +		if (regval < 0)
> +			return regval;
> +		val->intval = !!(regval & SBSM_BIT_AC_PRESENT);
> +		break;
> +
> +	case POWER_SUPPLY_PROP_CHARGE_TYPE:
> +		regval = sbsm_read_word(data->client, SBSM_CMD_BATSYSSTATE);
> +		if (regval < 0)
> +			return regval;
> +
> +		if ((regval & SBSM_MASK_CHARGE_BAT) == 0) {
> +			val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
> +			return 0;
> +		}
> +		val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
> +
> +		if (data->is_ltc1760) {
> +			/* charge mode fast if turbo is active */
> +			regval = sbsm_read_word(data->client, SBSM_CMD_LTC);
> +			if (regval < 0)
> +				return regval;
> +			else if (regval & SBSM_BIT_TURBO)
> +				val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
> +		}
> +		break;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int sbsm_prop_is_writeable(struct power_supply *psy,
> +				  enum power_supply_property psp)
> +{
> +	struct sbsm_data *data = power_supply_get_drvdata(psy);
> +
> +	return (psp == POWER_SUPPLY_PROP_CHARGE_TYPE) && data->is_ltc1760;
> +}
> +
> +static int sbsm_set_property(struct power_supply *psy,
> +			     enum power_supply_property psp,
> +			     const union power_supply_propval *val)
> +{
> +	struct sbsm_data *data = power_supply_get_drvdata(psy);
> +	int ret = -EINVAL;
> +	u16 regval;
> +
> +	switch (psp) {
> +	case POWER_SUPPLY_PROP_CHARGE_TYPE:
> +		/* write 1 to TURBO if type fast is given */
> +		if (!data->is_ltc1760)
> +			break;
> +		regval = val->intval ==
> +			 POWER_SUPPLY_CHARGE_TYPE_FAST ? SBSM_BIT_TURBO : 0;
> +		ret = sbsm_write_word(data->client, SBSM_CMD_LTC, regval);
> +		break;
> +
> +	default:
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +/*
> + * Switch to battery
> + * Parameter chan is directly the content of SMB_BAT* nibble
> + */
> +static int sbsm_select(struct i2c_mux_core *muxc, u32 chan)
> +{
> +	struct sbsm_data *data = i2c_mux_priv(muxc);
> +	struct device *dev = &data->client->dev;
> +	int ret = 0;
> +	u16 reg;
> +
> +	if (data->cur_chan == chan)
> +		return ret;
> +
> +	/* chan goes from 1 ... 4 */
> +	reg = 1 << BIT(SBSM_SMB_BAT_OFFSET + chan);
> +	ret = sbsm_write_word(data->client, SBSM_CMD_BATSYSSTATE, reg);
> +	if (ret)
> +		dev_err(dev, "Failed to select channel %i\n", chan);
> +	else
> +		data->cur_chan = chan;
> +
> +	return ret;
> +}
> +
> +static const struct power_supply_desc sbsm_default_psy_desc = {
> +	.type = POWER_SUPPLY_TYPE_MAINS,
> +	.properties = sbsm_props,
> +	.num_properties = ARRAY_SIZE(sbsm_props),
> +	.get_property = &sbsm_get_property,
> +	.set_property = &sbsm_set_property,
> +	.property_is_writeable = &sbsm_prop_is_writeable,
> +};
> +
> +static int sbsm_probe(struct i2c_client *client,
> +		      const struct i2c_device_id *id)
> +{
> +	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
> +	struct sbsm_data *data;
> +	struct device *dev = &client->dev;
> +	struct power_supply_desc *psy_desc;
> +	struct power_supply_config psy_cfg = {};
> +	int ret = 0, i, supported_bats;
> +
> +	/* Device listens only at address 0x0a */
> +	if (client->addr != 0x0a)
> +		return -EINVAL;
> +
> +	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
> +		return -EPFNOSUPPORT;
> +
> +	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	i2c_set_clientdata(client, data);
> +
> +	data->client = client;
> +	data->is_ltc1760 = !!strstr(id->name, "ltc1760");
> +
> +	ret  = sbsm_read_word(client, SBSM_CMD_BATSYSINFO);
> +	if (ret < 0)
> +		return ret;
> +	supported_bats = ret & SBSM_MASK_BAT_SUPPORTED;
> +
> +	data->muxc = i2c_mux_alloc(adapter, dev, SBSM_MAX_BATS, 0,
> +				   I2C_MUX_LOCKED, &sbsm_select, NULL);
> +	if (!data->muxc) {
> +		dev_err(dev, "failed to alloc i2c mux\n");
> +		ret = -ENOMEM;
> +		goto err_mux_alloc;
> +	}
> +	data->muxc->priv = data;
> +
> +	/* register muxed i2c channels. One for each supported battery */
> +	for (i = 0; i < SBSM_MAX_BATS; ++i) {
> +		if (supported_bats & BIT(i)) {
> +			ret = i2c_mux_add_adapter(data->muxc, 0, i + 1, 0);
> +			if (ret)
> +				break;
> +		}
> +	}
> +	if (ret) {
> +		dev_err(dev, "failed to register i2c mux channel %d\n", i + 1);
> +		goto err_mux_register;
> +	}
> +
> +	psy_desc = devm_kmemdup(dev, &sbsm_default_psy_desc,
> +				sizeof(struct power_supply_desc),
> +				GFP_KERNEL);
> +	if (!psy_desc) {
> +		ret = -ENOMEM;
> +		goto err_psy;
> +	}
> +
> +	psy_desc->name = devm_kasprintf(dev, GFP_KERNEL, "sbsm-%s",
> +					dev_name(&client->dev));
> +	if (!psy_desc->name) {
> +		ret = -ENOMEM;
> +		goto err_psy;
> +	}
> +
> +	psy_cfg.drv_data = data;
> +	psy_cfg.of_node = dev->of_node;
> +	data->psy = devm_power_supply_register(dev, psy_desc, &psy_cfg);
> +	if (IS_ERR(data->psy)) {
> +		ret = PTR_ERR(data->psy);
> +		dev_err(dev, "failed to register power supply %s\n",
> +			psy_desc->name);
> +		goto err_psy;
> +	}
> +
> +	return 0;
> +
> +err_psy:
> +err_mux_register:
> +	i2c_mux_del_adapters(data->muxc);
> +
> +err_mux_alloc:
> +	return ret;
> +}
> +
> +static int sbsm_remove(struct i2c_client *client)
> +{
> +	struct sbsm_data *data = i2c_get_clientdata(client);
> +
> +	i2c_mux_del_adapters(data->muxc);
> +	return 0;
> +}
> +
> +static const struct i2c_device_id sbsm_ids[] = {
> +	{ "sbs-manager", 0 },
> +	{ "ltc1760",     0 },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, sbsm_ids);
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id sbsm_dt_ids[] = {
> +	{ .compatible = "sbs,sbs-manager" },
> +	{ .compatible = "lltc,ltc1760" },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, sbsm_dt_ids);
> +#endif
> +
> +static struct i2c_driver sbsm_driver = {
> +	.driver = {
> +		.name = "sbsm",
> +		.of_match_table = of_match_ptr(sbsm_dt_ids),
> +	},
> +	.probe		= sbsm_probe,
> +	.remove		= sbsm_remove,
> +	.id_table	= sbsm_ids
> +};
> +module_i2c_driver(sbsm_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Karl-Heinz Schneider <karl-heinz-X5L7DgJ4l23oE99TX8zNy7NAH6kLmebB@public.gmane.org>");
> +MODULE_DESCRIPTION("SBSM Smart Battery System Manager");
> -- 
> 1.8.3.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v7 10/10] power: supply: sbs-battery: move gpio present detect to sbs_get_property
  2017-06-15 13:59 ` [PATCH v7 10/10] power: supply: sbs-battery: move gpio present detect to sbs_get_property Phil Reid
@ 2017-07-03 15:21   ` Sebastian Reichel
  0 siblings, 0 replies; 30+ messages in thread
From: Sebastian Reichel @ 2017-07-03 15:21 UTC (permalink / raw)
  To: Phil Reid
  Cc: wsa, robh+dt, mark.rutland, jdelvare, jglauber, david.daney,
	peda, linux-i2c, devicetree, linux-pm

[-- Attachment #1: Type: text/plain, Size: 2355 bytes --]

Hi,

On Thu, Jun 15, 2017 at 09:59:38PM +0800, Phil Reid wrote:
> Currently when a gpio is defined for battery presence it is only used in
> the sbs_get_battery_presence_and_health function for 2 properties.
> All other properties currently try to read data form the battery before
> returning an error if not present. We should know in advance that no
> data is going to returned.
> 
> As the driver tries multiple times to access a property, this prevents
> a lot of smbus accesses, which had a significant effect on device boot-up.
> As when the device is registered lots of property accesses are attempted
> during boot.
> 
> If no gpio is used for presence detection no change in behaviour should
> occur.
> 
> Signed-off-by: Phil Reid <preid@electromag.com.au>
> ---
>  drivers/power/supply/sbs-battery.c | 23 +++++++++++++----------
>  1 file changed, 13 insertions(+), 10 deletions(-)

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

> diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
> index cf43e38..1e3a8b2 100644
> --- a/drivers/power/supply/sbs-battery.c
> +++ b/drivers/power/supply/sbs-battery.c
> @@ -324,16 +324,6 @@ static int sbs_get_battery_presence_and_health(
>  	union power_supply_propval *val)
>  {
>  	s32 ret;
> -	struct sbs_info *chip = i2c_get_clientdata(client);
> -
> -	if (psp == POWER_SUPPLY_PROP_PRESENT && chip->gpio_detect) {
> -		ret = gpiod_get_value_cansleep(chip->gpio_detect);
> -		if (ret < 0)
> -			return ret;
> -		val->intval = ret;
> -		chip->is_present = val->intval;
> -		return ret;
> -	}
>  
>  	/*
>  	 * Write to ManufacturerAccess with ManufacturerAccess command
> @@ -599,6 +589,19 @@ static int sbs_get_property(struct power_supply *psy,
>  	struct sbs_info *chip = power_supply_get_drvdata(psy);
>  	struct i2c_client *client = chip->client;
>  
> +	if (chip->gpio_detect) {
> +		ret = gpiod_get_value_cansleep(chip->gpio_detect);
> +		if (ret < 0)
> +			return ret;
> +		if (psp == POWER_SUPPLY_PROP_PRESENT) {
> +			val->intval = ret;
> +			chip->is_present = val->intval;
> +			return 0;
> +		}
> +		if (ret == 0)
> +			return -ENODATA;
> +	}
> +
>  	switch (psp) {
>  	case POWER_SUPPLY_PROP_PRESENT:
>  	case POWER_SUPPLY_PROP_HEALTH:
> -- 
> 1.8.3.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v7 05/10] i2c: core: call of_i2c_setup_smbus_alert in i2c_register_adapter
  2017-06-28 12:45         ` Benjamin Tissoires
@ 2017-07-11  7:52           ` Phil Reid
  2017-07-21  9:24             ` Benjamin Tissoires
  0 siblings, 1 reply; 30+ messages in thread
From: Phil Reid @ 2017-07-11  7:52 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Wolfram Sang, robh+dt, mark.rutland, sre, jdelvare, jglauber,
	david.daney, peda, linux-i2c, devicetree, linux-pm

On 28/06/2017 20:45, Benjamin Tissoires wrote:
> On Jun 28 2017 or thereabouts, Phil Reid wrote:
>> On 23/06/2017 20:19, Benjamin Tissoires wrote:
>>> On Jun 19 2017 or thereabouts, Wolfram Sang wrote:
>>>> On Thu, Jun 15, 2017 at 09:59:33PM +0800, Phil Reid wrote:
>>>>> Add a call to of_i2c_setup_smbus_alert when a i2c adapter is registered
>>>>> so the the smbalert driver can be registered.
>>>>>
>>>>> Signed-off-by: Phil Reid <preid@electromag.com.au>
>>>>
>>>> CCing Benjamin
>>>>
>>>>> ---
>>>>>    drivers/i2c/i2c-core.c | 4 ++++
>>>>>    1 file changed, 4 insertions(+)
>>>>>
>>>>> diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
>>>>> index d2402bb..626471b 100644
>>>>> --- a/drivers/i2c/i2c-core.c
>>>>> +++ b/drivers/i2c/i2c-core.c
>>>>> @@ -40,6 +40,7 @@
>>>>>    #include <linux/gpio.h>
>>>>>    #include <linux/hardirq.h>
>>>>>    #include <linux/i2c.h>
>>>>> +#include <linux/i2c-smbus.h>
>>>>>    #include <linux/idr.h>
>>>>>    #include <linux/init.h>
>>>>>    #include <linux/irqflags.h>
>>>>> @@ -2045,6 +2046,9 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
>>>>>    		dev_warn(&adap->dev,
>>>>>    			 "Failed to create compatibility class link\n");
>>>>>    #endif
>>>>> +	res = of_i2c_setup_smbus_alert(adap);
>>>>> +	if (res)
>>>>> +		goto out_list;
>>>
>>> See my concerns in patch 4/10.
>>>
>>> In addition, shouldn't this be placed before device_register() for the
>>> least? pm_runtime_enable() would require a matching pm_runtime_disable(),
>>> and device_register() some unregistering behavior too.
>>>
>>
>> G'day Ben,
>>
>> Thanks for the review.
>> Yes this makes sense. I tried having it before the device_register and I get an error
>> about a kobject not being initialised in the a call from of_i2c_setup_smbus_alert.
>>
>> Having a look at what I'm doing in of_i2c_setup_smbus_alert now I'm not sure there's
>> a need to bail out on an error now. Originally I was registering the irq in the setup call.
>> Which need to handle probe defer. Now this should be handled in the alert probe call.
>>
>> WDYR?
> 
> Well, of_i2c_setup_smbus_alert() returns an error code, so it has to be
> accounted for. If the error is not a reason to fail, you should at least
> shout some error messages and act accordingly.
> 
> However, looking at of_i2c_setup_smbus_alert() again, I wonder if we
> should not split it in 2: one part that checks for the OF flag presence
> and bail out early if an error is encountered (before device
> registration), and one part once the device is registered that calls
> i2c_setup_smbus_alert(). In case of a failure here, we need to
> unregister the adapter because we don't have all the elements at hands
> (assuming we consider that smbus-alert should be mandatory).
> 

G'day Benjamin,

I've tried a couple of different ways of handling errors from of_i2c_setup_smbus_alert()
and not having much success.

Call of_i2c_setup_smbus_alert() before the device_register() call results in a kernel panic.

Call after device_register() and injecting an error into the of_i2c_setup_smbus_alert()
also results in a kernel panic.

On error I'm calling device_unregister()

I also tried spliting the device_unregister() call into
   device_initialize(dev);
   of_i2c_setup_smbus_alert()
   device_add(dev);

but that results in a crash in of_i2c_setup_smbus_alert()


If i2c_new_device() is not called then I get:
Unable to handle kernel NULL pointer dereference at virtual address 00000000
  PC is at __wake_up_common+0x2c/0x90

[<8015d940>] (__wake_up_common) from [<8015d9c8>] (__wake_up_locked+0x24/0x2c)
[<8015d9c8>] (__wake_up_locked) from [<8015e680>] (complete+0x48/0x58)
[<8015e680>] (complete) from [<805ba6c0>] (i2c_adapter_dev_release+0x1c/0x20)
[<805ba6c0>] (i2c_adapter_dev_release) from [<804d22f8>] (device_release+0x3c/0xa0)
[<804d22f8>] (device_release) from [<80419ab0>] (kobject_put+0xac/0x208)
[<80419ab0>] (kobject_put) from [<804d3778>] (device_unregister+0x64/0x70)
[<804d3778>] (device_unregister) from [<805bb234>] (i2c_register_adapter+0x2a4/0x480)
[<805bb234>] (i2c_register_adapter) from [<805bc5b4>] (i2c_add_adapter+0x8c/0xd0)
[<805bc5b4>] (i2c_add_adapter) from [<805c0690>] (i2c_mux_add_adapter+0x278/0x428)
[<805c0690>] (i2c_mux_add_adapter) from [<805c4b48>] (pca954x_probe+0x2b0/0x394)
[<805c4b48>] (pca954x_probe) from [<805b9c44>] (i2c_device_probe+0x200/0x2dc)
[<805b9c44>] (i2c_device_probe) from [<804d7e0c>] (driver_probe_device+0x338/0x460)
[<804d7e0c>] (driver_probe_device) from [<804d814c>] (__device_attach_driver+0xa4/0x128)
[<804d814c>] (__device_attach_driver) from [<804d5ad8>] (bus_for_each_drv+0x68/0x9c)
[<804d5ad8>] (bus_for_each_drv) from [<804d792c>] (__device_attach+0xc0/0x14c)
[<804d792c>] (__device_attach) from [<804d81ec>] (device_initial_probe+0x1c/0x20)
[<804d81ec>] (device_initial_probe) from [<804d6cf4>] (bus_probe_device+0x94/0x9c)
[<804d6cf4>] (bus_probe_device) from [<804d72dc>] (deferred_probe_work_func+0xa0/0xd4)
[<804d72dc>] (deferred_probe_work_func) from [<8013d7f0>] (process_one_work+0x14c/0x4c4)
[<8013d7f0>] (process_one_work) from [<8013dd94>] (worker_thread+0x22c/0x514)
[<8013dd94>] (worker_thread) from [<80143a20>] (kthread+0x140/0x170)
[<80143a20>] (kthread) from [<80108e38>] (ret_from_fork+0x14/0x3c)

And the system hangs.


If i2c_new_device() is called and I return an error after I get:
This one probably wouldn't happen.

WARNING: CPU: 0 PID: 70 at fs/proc/generic.c:580 remove_proc_entry+0x124/0x168
remove_proc_entry: removing non-empty directory 'irq/193', leaking at least 'smbus_alert'
Modules linked in:
CPU: 0 PID: 70 Comm: kworker/0:2 Not tainted 4.12.0-rc6+ #141
Hardware name: Altera SOCFPGA
Workqueue: events deferred_probe_work_func
[<801145a4>] (unwind_backtrace) from [<8010df44>] (show_stack+0x20/0x24)
[<8010df44>] (show_stack) from [<80418308>] (dump_stack+0x8c/0xa0)
[<80418308>] (dump_stack) from [<80123518>] (__warn+0xf8/0x110)
[<80123518>] (__warn) from [<80123578>] (warn_slowpath_fmt+0x48/0x50)
[<80123578>] (warn_slowpath_fmt) from [<802acfa0>] (remove_proc_entry+0x124/0x168)
[<802acfa0>] (remove_proc_entry) from [<80174d38>] (unregister_irq_proc+0xac/0xb4)
[<80174d38>] (unregister_irq_proc) from [<8016b404>] (free_desc+0x40/0x78)
[<8016b404>] (free_desc) from [<8016b494>] (irq_free_descs+0x58/0x90)
[<8016b494>] (irq_free_descs) from [<80174128>] (irq_dispose_mapping+0x54/0x7c)
[<80174128>] (irq_dispose_mapping) from [<805c45ac>] (pca954x_cleanup+0x4c/0x70)
[<805c45ac>] (pca954x_cleanup) from [<805c4ac0>] (pca954x_probe+0x210/0x394)
[<805c4ac0>] (pca954x_probe) from [<805b9c44>] (i2c_device_probe+0x200/0x2dc)
[<805b9c44>] (i2c_device_probe) from [<804d7e0c>] (driver_probe_device+0x338/0x460)
[<804d7e0c>] (driver_probe_device) from [<804d814c>] (__device_attach_driver+0xa4/0x128)
[<804d814c>] (__device_attach_driver) from [<804d5ad8>] (bus_for_each_drv+0x68/0x9c)
[<804d5ad8>] (bus_for_each_drv) from [<804d792c>] (__device_attach+0xc0/0x14c)
[<804d792c>] (__device_attach) from [<804d81ec>] (device_initial_probe+0x1c/0x20)
[<804d81ec>] (device_initial_probe) from [<804d6cf4>] (bus_probe_device+0x94/0x9c)
[<804d6cf4>] (bus_probe_device) from [<804d72dc>] (deferred_probe_work_func+0xa0/0xd4)
[<804d72dc>] (deferred_probe_work_func) from [<8013d7f0>] (process_one_work+0x14c/0x4c4)
[<8013d7f0>] (process_one_work) from [<8013dd94>] (worker_thread+0x22c/0x514)
[<8013dd94>] (worker_thread) from [<80143a20>] (kthread+0x140/0x170)
[<80143a20>] (kthread) from [<80108e38>] (ret_from_fork+0x14/0x3c)


I'm at a real loss on how to safely handle the error from of_i2c_setup_smbus_alert()

Any hints as to what the correct way is to unregister the device?


-- 
Regards
Phil Reid

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v7 05/10] i2c: core: call of_i2c_setup_smbus_alert in i2c_register_adapter
  2017-07-11  7:52           ` Phil Reid
@ 2017-07-21  9:24             ` Benjamin Tissoires
       [not found]               ` <20170721092431.GA11387-/m+UfqrgI5QNLKR9yMNcA1aTQe2KTcn/@public.gmane.org>
  0 siblings, 1 reply; 30+ messages in thread
From: Benjamin Tissoires @ 2017-07-21  9:24 UTC (permalink / raw)
  To: Phil Reid
  Cc: Wolfram Sang, robh+dt, mark.rutland, sre, jdelvare, jglauber,
	david.daney, peda, linux-i2c, devicetree, linux-pm

On Jul 11 2017 or thereabouts, Phil Reid wrote:
> On 28/06/2017 20:45, Benjamin Tissoires wrote:
> > On Jun 28 2017 or thereabouts, Phil Reid wrote:
> > > On 23/06/2017 20:19, Benjamin Tissoires wrote:
> > > > On Jun 19 2017 or thereabouts, Wolfram Sang wrote:
> > > > > On Thu, Jun 15, 2017 at 09:59:33PM +0800, Phil Reid wrote:
> > > > > > Add a call to of_i2c_setup_smbus_alert when a i2c adapter is registered
> > > > > > so the the smbalert driver can be registered.
> > > > > > 
> > > > > > Signed-off-by: Phil Reid <preid@electromag.com.au>
> > > > > 
> > > > > CCing Benjamin
> > > > > 
> > > > > > ---
> > > > > >    drivers/i2c/i2c-core.c | 4 ++++
> > > > > >    1 file changed, 4 insertions(+)
> > > > > > 
> > > > > > diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
> > > > > > index d2402bb..626471b 100644
> > > > > > --- a/drivers/i2c/i2c-core.c
> > > > > > +++ b/drivers/i2c/i2c-core.c
> > > > > > @@ -40,6 +40,7 @@
> > > > > >    #include <linux/gpio.h>
> > > > > >    #include <linux/hardirq.h>
> > > > > >    #include <linux/i2c.h>
> > > > > > +#include <linux/i2c-smbus.h>
> > > > > >    #include <linux/idr.h>
> > > > > >    #include <linux/init.h>
> > > > > >    #include <linux/irqflags.h>
> > > > > > @@ -2045,6 +2046,9 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
> > > > > >    		dev_warn(&adap->dev,
> > > > > >    			 "Failed to create compatibility class link\n");
> > > > > >    #endif
> > > > > > +	res = of_i2c_setup_smbus_alert(adap);
> > > > > > +	if (res)
> > > > > > +		goto out_list;
> > > > 
> > > > See my concerns in patch 4/10.
> > > > 
> > > > In addition, shouldn't this be placed before device_register() for the
> > > > least? pm_runtime_enable() would require a matching pm_runtime_disable(),
> > > > and device_register() some unregistering behavior too.
> > > > 
> > > 
> > > G'day Ben,
> > > 
> > > Thanks for the review.
> > > Yes this makes sense. I tried having it before the device_register and I get an error
> > > about a kobject not being initialised in the a call from of_i2c_setup_smbus_alert.
> > > 
> > > Having a look at what I'm doing in of_i2c_setup_smbus_alert now I'm not sure there's
> > > a need to bail out on an error now. Originally I was registering the irq in the setup call.
> > > Which need to handle probe defer. Now this should be handled in the alert probe call.
> > > 
> > > WDYR?
> > 
> > Well, of_i2c_setup_smbus_alert() returns an error code, so it has to be
> > accounted for. If the error is not a reason to fail, you should at least
> > shout some error messages and act accordingly.
> > 
> > However, looking at of_i2c_setup_smbus_alert() again, I wonder if we
> > should not split it in 2: one part that checks for the OF flag presence
> > and bail out early if an error is encountered (before device
> > registration), and one part once the device is registered that calls
> > i2c_setup_smbus_alert(). In case of a failure here, we need to
> > unregister the adapter because we don't have all the elements at hands
> > (assuming we consider that smbus-alert should be mandatory).
> > 
> 
> G'day Benjamin,

Hi Phil,

[sorry for the lag, been busy with other topics + public holidays]

> 
> I've tried a couple of different ways of handling errors from of_i2c_setup_smbus_alert()
> and not having much success.
> 
> Call of_i2c_setup_smbus_alert() before the device_register() call results in a kernel panic.

Yeah, i2c_setup_smbus_alert() basically creates an I2C device, so you
need to have the adapter registered before you can call it.

> 
> Call after device_register() and injecting an error into the of_i2c_setup_smbus_alert()
> also results in a kernel panic.

I wonder if this is just not required at all to have a failure path that
will remove the smbusalert device. Because this is an I2C device, when
we unregister the adapter, it should properly remove all of its attached
devices.

> 
> On error I'm calling device_unregister()
> 
> I also tried spliting the device_unregister() call into
>   device_initialize(dev);
>   of_i2c_setup_smbus_alert()
>   device_add(dev);
> 
> but that results in a crash in of_i2c_setup_smbus_alert()
> 
> 
> If i2c_new_device() is not called then I get:
> Unable to handle kernel NULL pointer dereference at virtual address 00000000
>  PC is at __wake_up_common+0x2c/0x90
> 
> [<8015d940>] (__wake_up_common) from [<8015d9c8>] (__wake_up_locked+0x24/0x2c)
> [<8015d9c8>] (__wake_up_locked) from [<8015e680>] (complete+0x48/0x58)
> [<8015e680>] (complete) from [<805ba6c0>] (i2c_adapter_dev_release+0x1c/0x20)
> [<805ba6c0>] (i2c_adapter_dev_release) from [<804d22f8>] (device_release+0x3c/0xa0)
> [<804d22f8>] (device_release) from [<80419ab0>] (kobject_put+0xac/0x208)
> [<80419ab0>] (kobject_put) from [<804d3778>] (device_unregister+0x64/0x70)
> [<804d3778>] (device_unregister) from [<805bb234>] (i2c_register_adapter+0x2a4/0x480)
> [<805bb234>] (i2c_register_adapter) from [<805bc5b4>] (i2c_add_adapter+0x8c/0xd0)
> [<805bc5b4>] (i2c_add_adapter) from [<805c0690>] (i2c_mux_add_adapter+0x278/0x428)
> [<805c0690>] (i2c_mux_add_adapter) from [<805c4b48>] (pca954x_probe+0x2b0/0x394)
> [<805c4b48>] (pca954x_probe) from [<805b9c44>] (i2c_device_probe+0x200/0x2dc)
> [<805b9c44>] (i2c_device_probe) from [<804d7e0c>] (driver_probe_device+0x338/0x460)
> [<804d7e0c>] (driver_probe_device) from [<804d814c>] (__device_attach_driver+0xa4/0x128)
> [<804d814c>] (__device_attach_driver) from [<804d5ad8>] (bus_for_each_drv+0x68/0x9c)
> [<804d5ad8>] (bus_for_each_drv) from [<804d792c>] (__device_attach+0xc0/0x14c)
> [<804d792c>] (__device_attach) from [<804d81ec>] (device_initial_probe+0x1c/0x20)
> [<804d81ec>] (device_initial_probe) from [<804d6cf4>] (bus_probe_device+0x94/0x9c)
> [<804d6cf4>] (bus_probe_device) from [<804d72dc>] (deferred_probe_work_func+0xa0/0xd4)
> [<804d72dc>] (deferred_probe_work_func) from [<8013d7f0>] (process_one_work+0x14c/0x4c4)
> [<8013d7f0>] (process_one_work) from [<8013dd94>] (worker_thread+0x22c/0x514)
> [<8013dd94>] (worker_thread) from [<80143a20>] (kthread+0x140/0x170)
> [<80143a20>] (kthread) from [<80108e38>] (ret_from_fork+0x14/0x3c)
> 
> And the system hangs.
> 
> 
> If i2c_new_device() is called and I return an error after I get:
> This one probably wouldn't happen.
> 
> WARNING: CPU: 0 PID: 70 at fs/proc/generic.c:580 remove_proc_entry+0x124/0x168
> remove_proc_entry: removing non-empty directory 'irq/193', leaking at least 'smbus_alert'
> Modules linked in:
> CPU: 0 PID: 70 Comm: kworker/0:2 Not tainted 4.12.0-rc6+ #141
> Hardware name: Altera SOCFPGA
> Workqueue: events deferred_probe_work_func
> [<801145a4>] (unwind_backtrace) from [<8010df44>] (show_stack+0x20/0x24)
> [<8010df44>] (show_stack) from [<80418308>] (dump_stack+0x8c/0xa0)
> [<80418308>] (dump_stack) from [<80123518>] (__warn+0xf8/0x110)
> [<80123518>] (__warn) from [<80123578>] (warn_slowpath_fmt+0x48/0x50)
> [<80123578>] (warn_slowpath_fmt) from [<802acfa0>] (remove_proc_entry+0x124/0x168)
> [<802acfa0>] (remove_proc_entry) from [<80174d38>] (unregister_irq_proc+0xac/0xb4)
> [<80174d38>] (unregister_irq_proc) from [<8016b404>] (free_desc+0x40/0x78)
> [<8016b404>] (free_desc) from [<8016b494>] (irq_free_descs+0x58/0x90)
> [<8016b494>] (irq_free_descs) from [<80174128>] (irq_dispose_mapping+0x54/0x7c)
> [<80174128>] (irq_dispose_mapping) from [<805c45ac>] (pca954x_cleanup+0x4c/0x70)
> [<805c45ac>] (pca954x_cleanup) from [<805c4ac0>] (pca954x_probe+0x210/0x394)
> [<805c4ac0>] (pca954x_probe) from [<805b9c44>] (i2c_device_probe+0x200/0x2dc)
> [<805b9c44>] (i2c_device_probe) from [<804d7e0c>] (driver_probe_device+0x338/0x460)
> [<804d7e0c>] (driver_probe_device) from [<804d814c>] (__device_attach_driver+0xa4/0x128)
> [<804d814c>] (__device_attach_driver) from [<804d5ad8>] (bus_for_each_drv+0x68/0x9c)
> [<804d5ad8>] (bus_for_each_drv) from [<804d792c>] (__device_attach+0xc0/0x14c)
> [<804d792c>] (__device_attach) from [<804d81ec>] (device_initial_probe+0x1c/0x20)
> [<804d81ec>] (device_initial_probe) from [<804d6cf4>] (bus_probe_device+0x94/0x9c)
> [<804d6cf4>] (bus_probe_device) from [<804d72dc>] (deferred_probe_work_func+0xa0/0xd4)
> [<804d72dc>] (deferred_probe_work_func) from [<8013d7f0>] (process_one_work+0x14c/0x4c4)
> [<8013d7f0>] (process_one_work) from [<8013dd94>] (worker_thread+0x22c/0x514)
> [<8013dd94>] (worker_thread) from [<80143a20>] (kthread+0x140/0x170)
> [<80143a20>] (kthread) from [<80108e38>] (ret_from_fork+0x14/0x3c)
> 
> 
> I'm at a real loss on how to safely handle the error from of_i2c_setup_smbus_alert()
> 
> Any hints as to what the correct way is to unregister the device?

I'd say try to register the smbus_alert device after the registering of
the adapter, and if it fails simply call the unregister from the
adapter. On remove, there might not need to do anything given that the
smbus_alert is an I2C client like every others.

Cheers,
Benjamin

PS: sorry if I am completely off-topic

> 
> 
> -- 
> Regards
> Phil Reid
> 

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v7 05/10] i2c: core: call of_i2c_setup_smbus_alert in i2c_register_adapter
       [not found]               ` <20170721092431.GA11387-/m+UfqrgI5QNLKR9yMNcA1aTQe2KTcn/@public.gmane.org>
@ 2017-07-24  7:38                 ` Phil Reid
  0 siblings, 0 replies; 30+ messages in thread
From: Phil Reid @ 2017-07-24  7:38 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Wolfram Sang, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, sre-DgEjT+Ai2ygdnm+yROfE0A,
	jdelvare-IBi9RG/b67k, jglauber-YGCgFSpz5w/QT0dZR+AlfA,
	david.daney-YGCgFSpz5w/QT0dZR+AlfA, peda-koto5C5qi+TLoDKTGw+V6w,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA

On 21/07/2017 17:24, Benjamin Tissoires wrote:
> On Jul 11 2017 or thereabouts, Phil Reid wrote:
>> On 28/06/2017 20:45, Benjamin Tissoires wrote:
>>> On Jun 28 2017 or thereabouts, Phil Reid wrote:
>>>> On 23/06/2017 20:19, Benjamin Tissoires wrote:
>>>>> On Jun 19 2017 or thereabouts, Wolfram Sang wrote:
>>>>>> On Thu, Jun 15, 2017 at 09:59:33PM +0800, Phil Reid wrote:
>>>>>>> Add a call to of_i2c_setup_smbus_alert when a i2c adapter is registered
>>>>>>> so the the smbalert driver can be registered.
>>>>>>>
>>>>>>> Signed-off-by: Phil Reid <preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
>>>>>>
>>>>>> CCing Benjamin
>>>>>>
>>>>>>> ---
>>>>>>>     drivers/i2c/i2c-core.c | 4 ++++
>>>>>>>     1 file changed, 4 insertions(+)
>>>>>>>
>>>>>>> diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
>>>>>>> index d2402bb..626471b 100644
>>>>>>> --- a/drivers/i2c/i2c-core.c
>>>>>>> +++ b/drivers/i2c/i2c-core.c
>>>>>>> @@ -40,6 +40,7 @@
>>>>>>>     #include <linux/gpio.h>
>>>>>>>     #include <linux/hardirq.h>
>>>>>>>     #include <linux/i2c.h>
>>>>>>> +#include <linux/i2c-smbus.h>
>>>>>>>     #include <linux/idr.h>
>>>>>>>     #include <linux/init.h>
>>>>>>>     #include <linux/irqflags.h>
>>>>>>> @@ -2045,6 +2046,9 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
>>>>>>>     		dev_warn(&adap->dev,
>>>>>>>     			 "Failed to create compatibility class link\n");
>>>>>>>     #endif
>>>>>>> +	res = of_i2c_setup_smbus_alert(adap);
>>>>>>> +	if (res)
>>>>>>> +		goto out_list;
>>>>>
>>>>> See my concerns in patch 4/10.
>>>>>
>>>>> In addition, shouldn't this be placed before device_register() for the
>>>>> least? pm_runtime_enable() would require a matching pm_runtime_disable(),
>>>>> and device_register() some unregistering behavior too.
>>>>>
>>>>
>>>> G'day Ben,
>>>>
>>>> Thanks for the review.
>>>> Yes this makes sense. I tried having it before the device_register and I get an error
>>>> about a kobject not being initialised in the a call from of_i2c_setup_smbus_alert.
>>>>
>>>> Having a look at what I'm doing in of_i2c_setup_smbus_alert now I'm not sure there's
>>>> a need to bail out on an error now. Originally I was registering the irq in the setup call.
>>>> Which need to handle probe defer. Now this should be handled in the alert probe call.
>>>>
>>>> WDYR?
>>>
>>> Well, of_i2c_setup_smbus_alert() returns an error code, so it has to be
>>> accounted for. If the error is not a reason to fail, you should at least
>>> shout some error messages and act accordingly.
>>>
>>> However, looking at of_i2c_setup_smbus_alert() again, I wonder if we
>>> should not split it in 2: one part that checks for the OF flag presence
>>> and bail out early if an error is encountered (before device
>>> registration), and one part once the device is registered that calls
>>> i2c_setup_smbus_alert(). In case of a failure here, we need to
>>> unregister the adapter because we don't have all the elements at hands
>>> (assuming we consider that smbus-alert should be mandatory).
>>>
>>
>> G'day Benjamin,
> 
> Hi Phil,
> 
> [sorry for the lag, been busy with other topics + public holidays]
> 
>>
>> I've tried a couple of different ways of handling errors from of_i2c_setup_smbus_alert()
>> and not having much success.
>>
>> Call of_i2c_setup_smbus_alert() before the device_register() call results in a kernel panic.
> 
> Yeah, i2c_setup_smbus_alert() basically creates an I2C device, so you
> need to have the adapter registered before you can call it.
> 
>>
>> Call after device_register() and injecting an error into the of_i2c_setup_smbus_alert()
>> also results in a kernel panic.
> 
> I wonder if this is just not required at all to have a failure path that
> will remove the smbusalert device. Because this is an I2C device, when
> we unregister the adapter, it should properly remove all of its attached
> devices.
> 
>>
>> On error I'm calling device_unregister()
>>
>> I also tried spliting the device_unregister() call into
>>    device_initialize(dev);
>>    of_i2c_setup_smbus_alert()
>>    device_add(dev);
>>
>> but that results in a crash in of_i2c_setup_smbus_alert()
>>
>>
>> If i2c_new_device() is not called then I get:
>> Unable to handle kernel NULL pointer dereference at virtual address 00000000
>>   PC is at __wake_up_common+0x2c/0x90
>>
>> [<8015d940>] (__wake_up_common) from [<8015d9c8>] (__wake_up_locked+0x24/0x2c)
>> [<8015d9c8>] (__wake_up_locked) from [<8015e680>] (complete+0x48/0x58)
>> [<8015e680>] (complete) from [<805ba6c0>] (i2c_adapter_dev_release+0x1c/0x20)
>> [<805ba6c0>] (i2c_adapter_dev_release) from [<804d22f8>] (device_release+0x3c/0xa0)
>> [<804d22f8>] (device_release) from [<80419ab0>] (kobject_put+0xac/0x208)
>> [<80419ab0>] (kobject_put) from [<804d3778>] (device_unregister+0x64/0x70)
>> [<804d3778>] (device_unregister) from [<805bb234>] (i2c_register_adapter+0x2a4/0x480)
>> [<805bb234>] (i2c_register_adapter) from [<805bc5b4>] (i2c_add_adapter+0x8c/0xd0)
>> [<805bc5b4>] (i2c_add_adapter) from [<805c0690>] (i2c_mux_add_adapter+0x278/0x428)
>> [<805c0690>] (i2c_mux_add_adapter) from [<805c4b48>] (pca954x_probe+0x2b0/0x394)
>> [<805c4b48>] (pca954x_probe) from [<805b9c44>] (i2c_device_probe+0x200/0x2dc)
>> [<805b9c44>] (i2c_device_probe) from [<804d7e0c>] (driver_probe_device+0x338/0x460)
>> [<804d7e0c>] (driver_probe_device) from [<804d814c>] (__device_attach_driver+0xa4/0x128)
>> [<804d814c>] (__device_attach_driver) from [<804d5ad8>] (bus_for_each_drv+0x68/0x9c)
>> [<804d5ad8>] (bus_for_each_drv) from [<804d792c>] (__device_attach+0xc0/0x14c)
>> [<804d792c>] (__device_attach) from [<804d81ec>] (device_initial_probe+0x1c/0x20)
>> [<804d81ec>] (device_initial_probe) from [<804d6cf4>] (bus_probe_device+0x94/0x9c)
>> [<804d6cf4>] (bus_probe_device) from [<804d72dc>] (deferred_probe_work_func+0xa0/0xd4)
>> [<804d72dc>] (deferred_probe_work_func) from [<8013d7f0>] (process_one_work+0x14c/0x4c4)
>> [<8013d7f0>] (process_one_work) from [<8013dd94>] (worker_thread+0x22c/0x514)
>> [<8013dd94>] (worker_thread) from [<80143a20>] (kthread+0x140/0x170)
>> [<80143a20>] (kthread) from [<80108e38>] (ret_from_fork+0x14/0x3c)
>>
>> And the system hangs.
>>
>>
>> If i2c_new_device() is called and I return an error after I get:
>> This one probably wouldn't happen.
>>
>> WARNING: CPU: 0 PID: 70 at fs/proc/generic.c:580 remove_proc_entry+0x124/0x168
>> remove_proc_entry: removing non-empty directory 'irq/193', leaking at least 'smbus_alert'
>> Modules linked in:
>> CPU: 0 PID: 70 Comm: kworker/0:2 Not tainted 4.12.0-rc6+ #141
>> Hardware name: Altera SOCFPGA
>> Workqueue: events deferred_probe_work_func
>> [<801145a4>] (unwind_backtrace) from [<8010df44>] (show_stack+0x20/0x24)
>> [<8010df44>] (show_stack) from [<80418308>] (dump_stack+0x8c/0xa0)
>> [<80418308>] (dump_stack) from [<80123518>] (__warn+0xf8/0x110)
>> [<80123518>] (__warn) from [<80123578>] (warn_slowpath_fmt+0x48/0x50)
>> [<80123578>] (warn_slowpath_fmt) from [<802acfa0>] (remove_proc_entry+0x124/0x168)
>> [<802acfa0>] (remove_proc_entry) from [<80174d38>] (unregister_irq_proc+0xac/0xb4)
>> [<80174d38>] (unregister_irq_proc) from [<8016b404>] (free_desc+0x40/0x78)
>> [<8016b404>] (free_desc) from [<8016b494>] (irq_free_descs+0x58/0x90)
>> [<8016b494>] (irq_free_descs) from [<80174128>] (irq_dispose_mapping+0x54/0x7c)
>> [<80174128>] (irq_dispose_mapping) from [<805c45ac>] (pca954x_cleanup+0x4c/0x70)
>> [<805c45ac>] (pca954x_cleanup) from [<805c4ac0>] (pca954x_probe+0x210/0x394)
>> [<805c4ac0>] (pca954x_probe) from [<805b9c44>] (i2c_device_probe+0x200/0x2dc)
>> [<805b9c44>] (i2c_device_probe) from [<804d7e0c>] (driver_probe_device+0x338/0x460)
>> [<804d7e0c>] (driver_probe_device) from [<804d814c>] (__device_attach_driver+0xa4/0x128)
>> [<804d814c>] (__device_attach_driver) from [<804d5ad8>] (bus_for_each_drv+0x68/0x9c)
>> [<804d5ad8>] (bus_for_each_drv) from [<804d792c>] (__device_attach+0xc0/0x14c)
>> [<804d792c>] (__device_attach) from [<804d81ec>] (device_initial_probe+0x1c/0x20)
>> [<804d81ec>] (device_initial_probe) from [<804d6cf4>] (bus_probe_device+0x94/0x9c)
>> [<804d6cf4>] (bus_probe_device) from [<804d72dc>] (deferred_probe_work_func+0xa0/0xd4)
>> [<804d72dc>] (deferred_probe_work_func) from [<8013d7f0>] (process_one_work+0x14c/0x4c4)
>> [<8013d7f0>] (process_one_work) from [<8013dd94>] (worker_thread+0x22c/0x514)
>> [<8013dd94>] (worker_thread) from [<80143a20>] (kthread+0x140/0x170)
>> [<80143a20>] (kthread) from [<80108e38>] (ret_from_fork+0x14/0x3c)
>>
>>
>> I'm at a real loss on how to safely handle the error from of_i2c_setup_smbus_alert()
>>
>> Any hints as to what the correct way is to unregister the device?
> 
> I'd say try to register the smbus_alert device after the registering of
> the adapter, and if it fails simply call the unregister from the
> adapter. On remove, there might not need to do anything given that the
> smbus_alert is an I2C client like every others.

I think my latest iteration of the patch solves this problem.
Testing error handling without unregistering does seem to be a problem.
I get kernel panics when I return an error from of_i2c_setup_smbus_alert().

I was missing the init_completion of dev_released.
Which I found in i2c_del_adapter().



-- 
Regards
Phil Reid

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2017-07-24  7:38 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-15 13:59 [PATCH v7 00/10] Add sbs-manager with smbalert support Phil Reid
2017-06-15 13:59 ` [PATCH v7 01/10] power: supply: sbs-battery: remove incorrect le16_to_cpu calls Phil Reid
     [not found]   ` <1497535178-12001-2-git-send-email-preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
2017-06-15 14:49     ` Sebastian Reichel
2017-06-15 13:59 ` [PATCH v7 02/10] power: supply: bq24735: " Phil Reid
     [not found]   ` <1497535178-12001-3-git-send-email-preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
2017-06-15 14:50     ` Sebastian Reichel
2017-06-15 13:59 ` [PATCH v7 03/10] i2c: i2c-smbus: Use threaded irq for smbalert Phil Reid
2017-06-19 15:27   ` Wolfram Sang
2017-06-20  2:30     ` Phil Reid
2017-06-23 12:11     ` Benjamin Tissoires
2017-06-15 13:59 ` [PATCH v7 04/10] i2c: i2c-smbus: add of_i2c_setup_smbus_alert Phil Reid
     [not found]   ` <1497535178-12001-5-git-send-email-preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
2017-06-19 15:27     ` Wolfram Sang
2017-06-23 12:15       ` Benjamin Tissoires
2017-06-28  6:48         ` Phil Reid
2017-06-28 12:42           ` Benjamin Tissoires
2017-06-15 13:59 ` [PATCH v7 05/10] i2c: core: call of_i2c_setup_smbus_alert in i2c_register_adapter Phil Reid
2017-06-19 15:28   ` Wolfram Sang
2017-06-23 12:19     ` Benjamin Tissoires
2017-06-28  6:44       ` Phil Reid
2017-06-28 12:45         ` Benjamin Tissoires
2017-07-11  7:52           ` Phil Reid
2017-07-21  9:24             ` Benjamin Tissoires
     [not found]               ` <20170721092431.GA11387-/m+UfqrgI5QNLKR9yMNcA1aTQe2KTcn/@public.gmane.org>
2017-07-24  7:38                 ` Phil Reid
2017-06-15 13:59 ` [PATCH v7 06/10] i2c: mux: pca954x: Call request irq after adding mux segments Phil Reid
2017-06-15 13:59 ` [PATCH v7 07/10] Documentation: Add sbs-manager device tree node documentation Phil Reid
2017-07-03 13:57   ` Sebastian Reichel
2017-06-15 13:59 ` [PATCH v7 08/10] power: Adds support for Smart Battery System Manager Phil Reid
     [not found]   ` <1497535178-12001-9-git-send-email-preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO@public.gmane.org>
2017-07-03 15:17     ` Sebastian Reichel
2017-06-15 13:59 ` [PATCH v7 09/10] power: supply: sbs-manager: Add alert callback and battery change notification Phil Reid
2017-06-15 13:59 ` [PATCH v7 10/10] power: supply: sbs-battery: move gpio present detect to sbs_get_property Phil Reid
2017-07-03 15:21   ` Sebastian Reichel

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.