Skip to content

Commit f18e345

Browse files
committed
Merge tag 'i3c/for-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux
Pull i3c updates from Alexandre Belloni: - support dynamic addition of i2c devices * tag 'i3c/for-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux: i3c: fix uninitialized variable use in i2c setup i3c: support dynamically added i2c devices i3c: remove i2c board info from i2c_dev_desc
2 parents 9512433 + 6cbf8b3 commit f18e345

File tree

2 files changed

+142
-10
lines changed

2 files changed

+142
-10
lines changed

drivers/i3c/master.c

Lines changed: 142 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ static void i3c_master_free_i2c_dev(struct i2c_dev_desc *dev)
609609

610610
static struct i2c_dev_desc *
611611
i3c_master_alloc_i2c_dev(struct i3c_master_controller *master,
612-
const struct i2c_dev_boardinfo *boardinfo)
612+
u16 addr, u8 lvr)
613613
{
614614
struct i2c_dev_desc *dev;
615615

@@ -618,9 +618,8 @@ i3c_master_alloc_i2c_dev(struct i3c_master_controller *master,
618618
return ERR_PTR(-ENOMEM);
619619

620620
dev->common.master = master;
621-
dev->boardinfo = boardinfo;
622-
dev->addr = boardinfo->base.addr;
623-
dev->lvr = boardinfo->lvr;
621+
dev->addr = addr;
622+
dev->lvr = lvr;
624623

625624
return dev;
626625
}
@@ -694,7 +693,7 @@ i3c_master_find_i2c_dev_by_addr(const struct i3c_master_controller *master,
694693
struct i2c_dev_desc *dev;
695694

696695
i3c_bus_for_each_i2cdev(&master->bus, dev) {
697-
if (dev->boardinfo->base.addr == addr)
696+
if (dev->addr == addr)
698697
return dev;
699698
}
700699

@@ -1689,7 +1688,9 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
16891688
i2cboardinfo->base.addr,
16901689
I3C_ADDR_SLOT_I2C_DEV);
16911690

1692-
i2cdev = i3c_master_alloc_i2c_dev(master, i2cboardinfo);
1691+
i2cdev = i3c_master_alloc_i2c_dev(master,
1692+
i2cboardinfo->base.addr,
1693+
i2cboardinfo->lvr);
16931694
if (IS_ERR(i2cdev)) {
16941695
ret = PTR_ERR(i2cdev);
16951696
goto err_detach_devs;
@@ -2166,15 +2167,127 @@ static u32 i3c_master_i2c_funcs(struct i2c_adapter *adapter)
21662167
return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
21672168
}
21682169

2170+
static u8 i3c_master_i2c_get_lvr(struct i2c_client *client)
2171+
{
2172+
/* Fall back to no spike filters and FM bus mode. */
2173+
u8 lvr = I3C_LVR_I2C_INDEX(2) | I3C_LVR_I2C_FM_MODE;
2174+
2175+
if (client->dev.of_node) {
2176+
u32 reg[3];
2177+
2178+
if (!of_property_read_u32_array(client->dev.of_node, "reg",
2179+
reg, ARRAY_SIZE(reg)))
2180+
lvr = reg[2];
2181+
}
2182+
2183+
return lvr;
2184+
}
2185+
2186+
static int i3c_master_i2c_attach(struct i2c_adapter *adap, struct i2c_client *client)
2187+
{
2188+
struct i3c_master_controller *master = i2c_adapter_to_i3c_master(adap);
2189+
enum i3c_addr_slot_status status;
2190+
struct i2c_dev_desc *i2cdev;
2191+
int ret;
2192+
2193+
/* Already added by board info? */
2194+
if (i3c_master_find_i2c_dev_by_addr(master, client->addr))
2195+
return 0;
2196+
2197+
status = i3c_bus_get_addr_slot_status(&master->bus, client->addr);
2198+
if (status != I3C_ADDR_SLOT_FREE)
2199+
return -EBUSY;
2200+
2201+
i3c_bus_set_addr_slot_status(&master->bus, client->addr,
2202+
I3C_ADDR_SLOT_I2C_DEV);
2203+
2204+
i2cdev = i3c_master_alloc_i2c_dev(master, client->addr,
2205+
i3c_master_i2c_get_lvr(client));
2206+
if (IS_ERR(i2cdev)) {
2207+
ret = PTR_ERR(i2cdev);
2208+
goto out_clear_status;
2209+
}
2210+
2211+
ret = i3c_master_attach_i2c_dev(master, i2cdev);
2212+
if (ret)
2213+
goto out_free_dev;
2214+
2215+
return 0;
2216+
2217+
out_free_dev:
2218+
i3c_master_free_i2c_dev(i2cdev);
2219+
out_clear_status:
2220+
i3c_bus_set_addr_slot_status(&master->bus, client->addr,
2221+
I3C_ADDR_SLOT_FREE);
2222+
2223+
return ret;
2224+
}
2225+
2226+
static int i3c_master_i2c_detach(struct i2c_adapter *adap, struct i2c_client *client)
2227+
{
2228+
struct i3c_master_controller *master = i2c_adapter_to_i3c_master(adap);
2229+
struct i2c_dev_desc *dev;
2230+
2231+
dev = i3c_master_find_i2c_dev_by_addr(master, client->addr);
2232+
if (!dev)
2233+
return -ENODEV;
2234+
2235+
i3c_master_detach_i2c_dev(dev);
2236+
i3c_bus_set_addr_slot_status(&master->bus, dev->addr,
2237+
I3C_ADDR_SLOT_FREE);
2238+
i3c_master_free_i2c_dev(dev);
2239+
2240+
return 0;
2241+
}
2242+
21692243
static const struct i2c_algorithm i3c_master_i2c_algo = {
21702244
.master_xfer = i3c_master_i2c_adapter_xfer,
21712245
.functionality = i3c_master_i2c_funcs,
21722246
};
21732247

2248+
static int i3c_i2c_notifier_call(struct notifier_block *nb, unsigned long action,
2249+
void *data)
2250+
{
2251+
struct i2c_adapter *adap;
2252+
struct i2c_client *client;
2253+
struct device *dev = data;
2254+
struct i3c_master_controller *master;
2255+
int ret;
2256+
2257+
if (dev->type != &i2c_client_type)
2258+
return 0;
2259+
2260+
client = to_i2c_client(dev);
2261+
adap = client->adapter;
2262+
2263+
if (adap->algo != &i3c_master_i2c_algo)
2264+
return 0;
2265+
2266+
master = i2c_adapter_to_i3c_master(adap);
2267+
2268+
i3c_bus_maintenance_lock(&master->bus);
2269+
switch (action) {
2270+
case BUS_NOTIFY_ADD_DEVICE:
2271+
ret = i3c_master_i2c_attach(adap, client);
2272+
break;
2273+
case BUS_NOTIFY_DEL_DEVICE:
2274+
ret = i3c_master_i2c_detach(adap, client);
2275+
break;
2276+
}
2277+
i3c_bus_maintenance_unlock(&master->bus);
2278+
2279+
return ret;
2280+
}
2281+
2282+
static struct notifier_block i2cdev_notifier = {
2283+
.notifier_call = i3c_i2c_notifier_call,
2284+
};
2285+
21742286
static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
21752287
{
21762288
struct i2c_adapter *adap = i3c_master_to_i2c_adapter(master);
21772289
struct i2c_dev_desc *i2cdev;
2290+
struct i2c_dev_boardinfo *i2cboardinfo;
21782291
int ret;
21792292

21802293
adap->dev.parent = master->dev.parent;
@@ -2194,8 +2307,13 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
21942307
* We silently ignore failures here. The bus should keep working
21952308
* correctly even if one or more i2c devices are not registered.
21962309
*/
2197-
i3c_bus_for_each_i2cdev(&master->bus, i2cdev)
2198-
i2cdev->dev = i2c_new_client_device(adap, &i2cdev->boardinfo->base);
2310+
list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) {
2311+
i2cdev = i3c_master_find_i2c_dev_by_addr(master,
2312+
i2cboardinfo->base.addr);
2313+
if (WARN_ON(!i2cdev))
2314+
continue;
2315+
i2cdev->dev = i2c_new_client_device(adap, &i2cboardinfo->base);
2316+
}
21992317

22002318
return 0;
22012319
}
@@ -2697,12 +2815,27 @@ void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev)
26972815

26982816
static int __init i3c_init(void)
26992817
{
2700-
return bus_register(&i3c_bus_type);
2818+
int res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);
2819+
2820+
if (res)
2821+
return res;
2822+
2823+
res = bus_register(&i3c_bus_type);
2824+
if (res)
2825+
goto out_unreg_notifier;
2826+
2827+
return 0;
2828+
2829+
out_unreg_notifier:
2830+
bus_unregister_notifier(&i2c_bus_type, &i2cdev_notifier);
2831+
2832+
return res;
27012833
}
27022834
subsys_initcall(i3c_init);
27032835

27042836
static void __exit i3c_exit(void)
27052837
{
2838+
bus_unregister_notifier(&i2c_bus_type, &i2cdev_notifier);
27062839
idr_destroy(&i3c_bus_idr);
27072840
bus_unregister(&i3c_bus_type);
27082841
}

include/linux/i3c/master.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ struct i2c_dev_boardinfo {
8585
*/
8686
struct i2c_dev_desc {
8787
struct i3c_i2c_dev_desc common;
88-
const struct i2c_dev_boardinfo *boardinfo;
8988
struct i2c_client *dev;
9089
u16 addr;
9190
u8 lvr;

0 commit comments

Comments
 (0)