linux-i3c.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] i3c: support for dynamically added i2c devices
@ 2022-01-17 17:48 Jamie Iles
  2022-01-17 17:48 ` [PATCH 1/2] i3c: remove i2c board info from i2c_dev_desc Jamie Iles
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Jamie Iles @ 2022-01-17 17:48 UTC (permalink / raw)
  To: linux-i3c; +Cc: Jamie Iles

Devices are currently added at controller initialization time with 
boardinfo, but the i2c subsystem also supports dynamically adding 
devices through a variety of mechanisms including user-space through 
sysfs, device tree overlays and ACPI.

This small series decouples registration from the boardinfo and then 
adds a notifier to add the devices at runtime.  A future series will 
build on this to allow adding the I2C devices through ACPI.

Jamie Iles (2):
  i3c: remove i2c board info from i2c_dev_desc
  i3c: support dynamically added i2c devices

 drivers/i3c/master.c       | 145 ++++++++++++++++++++++++++++++++++---
 include/linux/i3c/master.h |   1 -
 2 files changed, 136 insertions(+), 10 deletions(-)

-- 
2.32.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* [PATCH 1/2] i3c: remove i2c board info from i2c_dev_desc
  2022-01-17 17:48 [PATCH 0/2] i3c: support for dynamically added i2c devices Jamie Iles
@ 2022-01-17 17:48 ` Jamie Iles
  2022-01-17 17:48 ` [PATCH 2/2] i3c: support dynamically added i2c devices Jamie Iles
  2022-03-04 10:35 ` [PATCH 0/2] i3c: support for " Alexandre Belloni
  2 siblings, 0 replies; 4+ messages in thread
From: Jamie Iles @ 2022-01-17 17:48 UTC (permalink / raw)
  To: linux-i3c; +Cc: Jamie Iles, Alexandre Belloni

I2C board info is only required during adapter setup so there is no
requirement to keeping a pointer to it once running.  To support dynamic
device addition we can't rely on board info - user-space creation
through sysfs won't have a boardinfo.

Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Jamie Iles <quic_jiles@quicinc.com>
---
 drivers/i3c/master.c       | 18 ++++++++++--------
 include/linux/i3c/master.h |  1 -
 2 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index dfe18dcd008d..9a09109da8cc 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -609,7 +609,7 @@ static void i3c_master_free_i2c_dev(struct i2c_dev_desc *dev)
 
 static struct i2c_dev_desc *
 i3c_master_alloc_i2c_dev(struct i3c_master_controller *master,
-			 const struct i2c_dev_boardinfo *boardinfo)
+			 u16 addr, u8 lvr)
 {
 	struct i2c_dev_desc *dev;
 
@@ -618,9 +618,8 @@ i3c_master_alloc_i2c_dev(struct i3c_master_controller *master,
 		return ERR_PTR(-ENOMEM);
 
 	dev->common.master = master;
-	dev->boardinfo = boardinfo;
-	dev->addr = boardinfo->base.addr;
-	dev->lvr = boardinfo->lvr;
+	dev->addr = addr;
+	dev->lvr = lvr;
 
 	return dev;
 }
@@ -694,7 +693,7 @@ i3c_master_find_i2c_dev_by_addr(const struct i3c_master_controller *master,
 	struct i2c_dev_desc *dev;
 
 	i3c_bus_for_each_i2cdev(&master->bus, dev) {
-		if (dev->boardinfo->base.addr == addr)
+		if (dev->addr == addr)
 			return dev;
 	}
 
@@ -1689,7 +1688,9 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
 					     i2cboardinfo->base.addr,
 					     I3C_ADDR_SLOT_I2C_DEV);
 
-		i2cdev = i3c_master_alloc_i2c_dev(master, i2cboardinfo);
+		i2cdev = i3c_master_alloc_i2c_dev(master,
+						  i2cboardinfo->base.addr,
+						  i2cboardinfo->lvr);
 		if (IS_ERR(i2cdev)) {
 			ret = PTR_ERR(i2cdev);
 			goto err_detach_devs;
@@ -2175,6 +2176,7 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
 {
 	struct i2c_adapter *adap = i3c_master_to_i2c_adapter(master);
 	struct i2c_dev_desc *i2cdev;
+	struct i2c_dev_boardinfo *i2cboardinfo;
 	int ret;
 
 	adap->dev.parent = master->dev.parent;
@@ -2194,8 +2196,8 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
 	 * We silently ignore failures here. The bus should keep working
 	 * correctly even if one or more i2c devices are not registered.
 	 */
-	i3c_bus_for_each_i2cdev(&master->bus, i2cdev)
-		i2cdev->dev = i2c_new_client_device(adap, &i2cdev->boardinfo->base);
+	list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node)
+		i2cdev->dev = i2c_new_client_device(adap, &i2cboardinfo->base);
 
 	return 0;
 }
diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
index 9cb39d901cd5..604a126b78c8 100644
--- a/include/linux/i3c/master.h
+++ b/include/linux/i3c/master.h
@@ -85,7 +85,6 @@ struct i2c_dev_boardinfo {
  */
 struct i2c_dev_desc {
 	struct i3c_i2c_dev_desc common;
-	const struct i2c_dev_boardinfo *boardinfo;
 	struct i2c_client *dev;
 	u16 addr;
 	u8 lvr;
-- 
2.32.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* [PATCH 2/2] i3c: support dynamically added i2c devices
  2022-01-17 17:48 [PATCH 0/2] i3c: support for dynamically added i2c devices Jamie Iles
  2022-01-17 17:48 ` [PATCH 1/2] i3c: remove i2c board info from i2c_dev_desc Jamie Iles
@ 2022-01-17 17:48 ` Jamie Iles
  2022-03-04 10:35 ` [PATCH 0/2] i3c: support for " Alexandre Belloni
  2 siblings, 0 replies; 4+ messages in thread
From: Jamie Iles @ 2022-01-17 17:48 UTC (permalink / raw)
  To: linux-i3c; +Cc: Jamie Iles, Alexandre Belloni

I2C devices can be added to the system dynamically through several
sources other than static board info including device tree overlays and
sysfs i2c new_device.

Add an I2C bus notifier to attach the clients at runtime if they were
not defined in the board info.  For DT devices find the LVR in the reg
property, for user-space new_device additions we synthesize a
conservative setting of no spike filters and fast mode only.

Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Jamie Iles <quic_jiles@quicinc.com>
---
 drivers/i3c/master.c | 127 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 126 insertions(+), 1 deletion(-)

diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index 9a09109da8cc..7f79b283dc45 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -2167,11 +2167,122 @@ static u32 i3c_master_i2c_funcs(struct i2c_adapter *adapter)
 	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
 }
 
+static u8 i3c_master_i2c_get_lvr(struct i2c_client *client)
+{
+	/* Fall back to no spike filters and FM bus mode. */
+	u8 lvr = I3C_LVR_I2C_INDEX(2) | I3C_LVR_I2C_FM_MODE;
+
+	if (client->dev.of_node) {
+		u32 reg[3];
+
+		if (!of_property_read_u32_array(client->dev.of_node, "reg",
+						reg, ARRAY_SIZE(reg)))
+			lvr = reg[2];
+	}
+
+	return lvr;
+}
+
+static int i3c_master_i2c_attach(struct i2c_adapter *adap, struct i2c_client *client)
+{
+	struct i3c_master_controller *master = i2c_adapter_to_i3c_master(adap);
+	enum i3c_addr_slot_status status;
+	struct i2c_dev_desc *i2cdev;
+	int ret;
+
+	/* Already added by board info? */
+	if (i3c_master_find_i2c_dev_by_addr(master, client->addr))
+		return 0;
+
+	status = i3c_bus_get_addr_slot_status(&master->bus, client->addr);
+	if (status != I3C_ADDR_SLOT_FREE)
+		return -EBUSY;
+
+	i3c_bus_set_addr_slot_status(&master->bus, client->addr,
+				     I3C_ADDR_SLOT_I2C_DEV);
+
+	i2cdev = i3c_master_alloc_i2c_dev(master, client->addr,
+					  i3c_master_i2c_get_lvr(client));
+	if (IS_ERR(i2cdev)) {
+		ret = PTR_ERR(i2cdev);
+		goto out_clear_status;
+	}
+
+	ret = i3c_master_attach_i2c_dev(master, i2cdev);
+	if (ret)
+		goto out_free_dev;
+
+	return 0;
+
+out_free_dev:
+	i3c_master_free_i2c_dev(i2cdev);
+out_clear_status:
+	i3c_bus_set_addr_slot_status(&master->bus, client->addr,
+				     I3C_ADDR_SLOT_FREE);
+
+	return ret;
+}
+
+static int i3c_master_i2c_detach(struct i2c_adapter *adap, struct i2c_client *client)
+{
+	struct i3c_master_controller *master = i2c_adapter_to_i3c_master(adap);
+	struct i2c_dev_desc *dev;
+
+	dev = i3c_master_find_i2c_dev_by_addr(master, client->addr);
+	if (!dev)
+		return -ENODEV;
+
+	i3c_master_detach_i2c_dev(dev);
+	i3c_bus_set_addr_slot_status(&master->bus, dev->addr,
+				     I3C_ADDR_SLOT_FREE);
+	i3c_master_free_i2c_dev(dev);
+
+	return 0;
+}
+
 static const struct i2c_algorithm i3c_master_i2c_algo = {
 	.master_xfer = i3c_master_i2c_adapter_xfer,
 	.functionality = i3c_master_i2c_funcs,
 };
 
+static int i3c_i2c_notifier_call(struct notifier_block *nb, unsigned long action,
+				 void *data)
+{
+	struct i2c_adapter *adap;
+	struct i2c_client *client;
+	struct device *dev = data;
+	struct i3c_master_controller *master;
+	int ret;
+
+	if (dev->type != &i2c_client_type)
+		return 0;
+
+	client = to_i2c_client(dev);
+	adap = client->adapter;
+
+	if (adap->algo != &i3c_master_i2c_algo)
+		return 0;
+
+	master = i2c_adapter_to_i3c_master(adap);
+
+	i3c_bus_maintenance_lock(&master->bus);
+	switch (action) {
+	case BUS_NOTIFY_ADD_DEVICE:
+		ret = i3c_master_i2c_attach(adap, client);
+		break;
+	case BUS_NOTIFY_DEL_DEVICE:
+		ret = i3c_master_i2c_detach(adap, client);
+		break;
+	}
+	i3c_bus_maintenance_unlock(&master->bus);
+
+	return ret;
+}
+
+static struct notifier_block i2cdev_notifier = {
+	.notifier_call = i3c_i2c_notifier_call,
+};
+
 static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
 {
 	struct i2c_adapter *adap = i3c_master_to_i2c_adapter(master);
@@ -2699,12 +2810,26 @@ void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev)
 
 static int __init i3c_init(void)
 {
-	return bus_register(&i3c_bus_type);
+	int res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);
+	if (res)
+		return res;
+
+	res = bus_register(&i3c_bus_type);
+	if (res)
+		goto out_unreg_notifier;
+
+	return 0;
+
+out_unreg_notifier:
+	bus_unregister_notifier(&i2c_bus_type,&i2cdev_notifier);
+
+	return res;
 }
 subsys_initcall(i3c_init);
 
 static void __exit i3c_exit(void)
 {
+	bus_unregister_notifier(&i2c_bus_type, &i2cdev_notifier);
 	idr_destroy(&i3c_bus_idr);
 	bus_unregister(&i3c_bus_type);
 }
-- 
2.32.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* Re: [PATCH 0/2] i3c: support for dynamically added i2c devices
  2022-01-17 17:48 [PATCH 0/2] i3c: support for dynamically added i2c devices Jamie Iles
  2022-01-17 17:48 ` [PATCH 1/2] i3c: remove i2c board info from i2c_dev_desc Jamie Iles
  2022-01-17 17:48 ` [PATCH 2/2] i3c: support dynamically added i2c devices Jamie Iles
@ 2022-03-04 10:35 ` Alexandre Belloni
  2 siblings, 0 replies; 4+ messages in thread
From: Alexandre Belloni @ 2022-03-04 10:35 UTC (permalink / raw)
  To: linux-i3c, Jamie Iles; +Cc: Alexandre Belloni

On Mon, 17 Jan 2022 17:48:14 +0000, Jamie Iles wrote:
> Devices are currently added at controller initialization time with
> boardinfo, but the i2c subsystem also supports dynamically adding
> devices through a variety of mechanisms including user-space through
> sysfs, device tree overlays and ACPI.
> 
> This small series decouples registration from the boardinfo and then
> adds a notifier to add the devices at runtime.  A future series will
> build on this to allow adding the I2C devices through ACPI.
> 
> [...]

Applied, thanks!

[1/2] i3c: remove i2c board info from i2c_dev_desc
      commit: 97a82882d8529c18ff15a0b5396d8c4bd2a36157
[2/2] i3c: support dynamically added i2c devices
      commit: cd5883f7e933764e2ddddd9cbb0f7ce18df127c4

Best regards,
-- 
Alexandre Belloni <alexandre.belloni@bootlin.com>

-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

end of thread, other threads:[~2022-03-04 10:36 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-17 17:48 [PATCH 0/2] i3c: support for dynamically added i2c devices Jamie Iles
2022-01-17 17:48 ` [PATCH 1/2] i3c: remove i2c board info from i2c_dev_desc Jamie Iles
2022-01-17 17:48 ` [PATCH 2/2] i3c: support dynamically added i2c devices Jamie Iles
2022-03-04 10:35 ` [PATCH 0/2] i3c: support for " Alexandre Belloni

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).