Commit 31dda85e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'i3c/for-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux

Pull i3c updates from Boris Brezillon:
 "Core changes:

   - Export i3c_device_match_id() so driver can get per-device data

   - Add addr and lvr fields to i2c_dev_desc so we can attach I2C
     devices that are not described in the DT

   - Add a missing of_node_put()

   - Fix a memory leak

   - Use dev_to_i3cmaster() instead of open-coding it

  Driver changes:

   - Use for_each_set_bit() in the Cadence driver"

* tag 'i3c/for-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux:
  i3c: master: Use dev_to_i3cmaster()
  i3c: master: fix a memory leak bug
  i3c: add addr and lvr to i2c_dev_desc structure
  i3c: master: cdns: Use for_each_set_bit()
  i3c: master: Add of_node_put() before return
  i3c: move i3c_device_match_id to device.c and export it
parents aa62325d 6030f42d
...@@ -200,6 +200,59 @@ struct i3c_device *dev_to_i3cdev(struct device *dev) ...@@ -200,6 +200,59 @@ struct i3c_device *dev_to_i3cdev(struct device *dev)
} }
EXPORT_SYMBOL_GPL(dev_to_i3cdev); EXPORT_SYMBOL_GPL(dev_to_i3cdev);
/**
* i3c_device_match_id() - Returns the i3c_device_id entry matching @i3cdev
* @i3cdev: I3C device
* @id_table: I3C device match table
*
* Return: a pointer to an i3c_device_id object or NULL if there's no match.
*/
const struct i3c_device_id *
i3c_device_match_id(struct i3c_device *i3cdev,
const struct i3c_device_id *id_table)
{
struct i3c_device_info devinfo;
const struct i3c_device_id *id;
i3c_device_get_info(i3cdev, &devinfo);
/*
* The lower 32bits of the provisional ID is just filled with a random
* value, try to match using DCR info.
*/
if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) {
u16 manuf = I3C_PID_MANUF_ID(devinfo.pid);
u16 part = I3C_PID_PART_ID(devinfo.pid);
u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid);
/* First try to match by manufacturer/part ID. */
for (id = id_table; id->match_flags != 0; id++) {
if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) !=
I3C_MATCH_MANUF_AND_PART)
continue;
if (manuf != id->manuf_id || part != id->part_id)
continue;
if ((id->match_flags & I3C_MATCH_EXTRA_INFO) &&
ext_info != id->extra_info)
continue;
return id;
}
}
/* Fallback to DCR match. */
for (id = id_table; id->match_flags != 0; id++) {
if ((id->match_flags & I3C_MATCH_DCR) &&
id->dcr == devinfo.dcr)
return id;
}
return NULL;
}
EXPORT_SYMBOL_GPL(i3c_device_match_id);
/** /**
* i3c_driver_register_with_owner() - register an I3C device driver * i3c_driver_register_with_owner() - register an I3C device driver
* *
......
...@@ -123,7 +123,7 @@ static struct i3c_dev_desc *dev_to_i3cdesc(struct device *dev) ...@@ -123,7 +123,7 @@ static struct i3c_dev_desc *dev_to_i3cdesc(struct device *dev)
if (dev->type == &i3c_device_type) if (dev->type == &i3c_device_type)
return dev_to_i3cdev(dev)->desc; return dev_to_i3cdev(dev)->desc;
master = container_of(dev, struct i3c_master_controller, dev); master = dev_to_i3cmaster(dev);
return master->this; return master->this;
} }
...@@ -276,51 +276,6 @@ static const struct device_type i3c_device_type = { ...@@ -276,51 +276,6 @@ static const struct device_type i3c_device_type = {
.uevent = i3c_device_uevent, .uevent = i3c_device_uevent,
}; };
static const struct i3c_device_id *
i3c_device_match_id(struct i3c_device *i3cdev,
const struct i3c_device_id *id_table)
{
struct i3c_device_info devinfo;
const struct i3c_device_id *id;
i3c_device_get_info(i3cdev, &devinfo);
/*
* The lower 32bits of the provisional ID is just filled with a random
* value, try to match using DCR info.
*/
if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) {
u16 manuf = I3C_PID_MANUF_ID(devinfo.pid);
u16 part = I3C_PID_PART_ID(devinfo.pid);
u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid);
/* First try to match by manufacturer/part ID. */
for (id = id_table; id->match_flags != 0; id++) {
if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) !=
I3C_MATCH_MANUF_AND_PART)
continue;
if (manuf != id->manuf_id || part != id->part_id)
continue;
if ((id->match_flags & I3C_MATCH_EXTRA_INFO) &&
ext_info != id->extra_info)
continue;
return id;
}
}
/* Fallback to DCR match. */
for (id = id_table; id->match_flags != 0; id++) {
if ((id->match_flags & I3C_MATCH_DCR) &&
id->dcr == devinfo.dcr)
return id;
}
return NULL;
}
static int i3c_device_match(struct device *dev, struct device_driver *drv) static int i3c_device_match(struct device *dev, struct device_driver *drv)
{ {
struct i3c_device *i3cdev; struct i3c_device *i3cdev;
...@@ -645,6 +600,8 @@ i3c_master_alloc_i2c_dev(struct i3c_master_controller *master, ...@@ -645,6 +600,8 @@ i3c_master_alloc_i2c_dev(struct i3c_master_controller *master,
dev->common.master = master; dev->common.master = master;
dev->boardinfo = boardinfo; dev->boardinfo = boardinfo;
dev->addr = boardinfo->base.addr;
dev->lvr = boardinfo->lvr;
return dev; return dev;
} }
...@@ -963,8 +920,8 @@ int i3c_master_defslvs_locked(struct i3c_master_controller *master) ...@@ -963,8 +920,8 @@ int i3c_master_defslvs_locked(struct i3c_master_controller *master)
desc = defslvs->slaves; desc = defslvs->slaves;
i3c_bus_for_each_i2cdev(bus, i2cdev) { i3c_bus_for_each_i2cdev(bus, i2cdev) {
desc->lvr = i2cdev->boardinfo->lvr; desc->lvr = i2cdev->lvr;
desc->static_addr = i2cdev->boardinfo->base.addr << 1; desc->static_addr = i2cdev->addr << 1;
desc++; desc++;
} }
...@@ -1084,8 +1041,10 @@ static int i3c_master_getmwl_locked(struct i3c_master_controller *master, ...@@ -1084,8 +1041,10 @@ static int i3c_master_getmwl_locked(struct i3c_master_controller *master,
if (ret) if (ret)
goto out; goto out;
if (dest.payload.len != sizeof(*mwl)) if (dest.payload.len != sizeof(*mwl)) {
return -EIO; ret = -EIO;
goto out;
}
info->max_write_len = be16_to_cpu(mwl->len); info->max_write_len = be16_to_cpu(mwl->len);
...@@ -1631,8 +1590,8 @@ static void i3c_master_detach_free_devs(struct i3c_master_controller *master) ...@@ -1631,8 +1590,8 @@ static void i3c_master_detach_free_devs(struct i3c_master_controller *master)
common.node) { common.node) {
i3c_master_detach_i2c_dev(i2cdev); i3c_master_detach_i2c_dev(i2cdev);
i3c_bus_set_addr_slot_status(&master->bus, i3c_bus_set_addr_slot_status(&master->bus,
i2cdev->boardinfo->base.addr, i2cdev->addr,
I3C_ADDR_SLOT_FREE); I3C_ADDR_SLOT_FREE);
i3c_master_free_i2c_dev(i2cdev); i3c_master_free_i2c_dev(i2cdev);
} }
} }
...@@ -2093,8 +2052,10 @@ static int of_populate_i3c_bus(struct i3c_master_controller *master) ...@@ -2093,8 +2052,10 @@ static int of_populate_i3c_bus(struct i3c_master_controller *master)
for_each_available_child_of_node(i3cbus_np, node) { for_each_available_child_of_node(i3cbus_np, node) {
ret = of_i3c_master_add_dev(master, node); ret = of_i3c_master_add_dev(master, node);
if (ret) if (ret) {
of_node_put(node);
return ret; return ret;
}
} }
/* /*
......
...@@ -1033,12 +1033,12 @@ static int dw_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev) ...@@ -1033,12 +1033,12 @@ static int dw_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev)
return -ENOMEM; return -ENOMEM;
data->index = pos; data->index = pos;
master->addrs[pos] = dev->boardinfo->base.addr; master->addrs[pos] = dev->addr;
master->free_pos &= ~BIT(pos); master->free_pos &= ~BIT(pos);
i2c_dev_set_master_data(dev, data); i2c_dev_set_master_data(dev, data);
writel(DEV_ADDR_TABLE_LEGACY_I2C_DEV | writel(DEV_ADDR_TABLE_LEGACY_I2C_DEV |
DEV_ADDR_TABLE_STATIC_ADDR(dev->boardinfo->base.addr), DEV_ADDR_TABLE_STATIC_ADDR(dev->addr),
master->regs + master->regs +
DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index));
......
...@@ -903,7 +903,8 @@ static void cdns_i3c_master_upd_i3c_addr(struct i3c_dev_desc *dev) ...@@ -903,7 +903,8 @@ static void cdns_i3c_master_upd_i3c_addr(struct i3c_dev_desc *dev)
static int cdns_i3c_master_get_rr_slot(struct cdns_i3c_master *master, static int cdns_i3c_master_get_rr_slot(struct cdns_i3c_master *master,
u8 dyn_addr) u8 dyn_addr)
{ {
u32 activedevs, rr; unsigned long activedevs;
u32 rr;
int i; int i;
if (!dyn_addr) { if (!dyn_addr) {
...@@ -913,13 +914,10 @@ static int cdns_i3c_master_get_rr_slot(struct cdns_i3c_master *master, ...@@ -913,13 +914,10 @@ static int cdns_i3c_master_get_rr_slot(struct cdns_i3c_master *master,
return ffs(master->free_rr_slots) - 1; return ffs(master->free_rr_slots) - 1;
} }
activedevs = readl(master->regs + DEVS_CTRL) & activedevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK;
DEVS_CTRL_DEVS_ACTIVE_MASK; activedevs &= ~BIT(0);
for (i = 1; i <= master->maxdevs; i++) {
if (!(BIT(i) & activedevs))
continue;
for_each_set_bit(i, &activedevs, master->maxdevs + 1) {
rr = readl(master->regs + DEV_ID_RR0(i)); rr = readl(master->regs + DEV_ID_RR0(i));
if (!(rr & DEV_ID_RR0_IS_I3C) || if (!(rr & DEV_ID_RR0_IS_I3C) ||
DEV_ID_RR0_GET_DEV_ADDR(rr) != dyn_addr) DEV_ID_RR0_GET_DEV_ADDR(rr) != dyn_addr)
...@@ -1005,9 +1003,9 @@ static int cdns_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev) ...@@ -1005,9 +1003,9 @@ static int cdns_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev)
master->free_rr_slots &= ~BIT(slot); master->free_rr_slots &= ~BIT(slot);
i2c_dev_set_master_data(dev, data); i2c_dev_set_master_data(dev, data);
writel(prepare_rr0_dev_address(dev->boardinfo->base.addr), writel(prepare_rr0_dev_address(dev->addr),
master->regs + DEV_ID_RR0(data->id)); master->regs + DEV_ID_RR0(data->id));
writel(dev->boardinfo->lvr, master->regs + DEV_ID_RR2(data->id)); writel(dev->lvr, master->regs + DEV_ID_RR2(data->id));
writel(readl(master->regs + DEVS_CTRL) | writel(readl(master->regs + DEVS_CTRL) |
DEVS_CTRL_DEV_ACTIVE(data->id), DEVS_CTRL_DEV_ACTIVE(data->id),
master->regs + DEVS_CTRL); master->regs + DEVS_CTRL);
...@@ -1126,18 +1124,16 @@ static void cdns_i3c_master_upd_i3c_scl_lim(struct cdns_i3c_master *master) ...@@ -1126,18 +1124,16 @@ static void cdns_i3c_master_upd_i3c_scl_lim(struct cdns_i3c_master *master)
static int cdns_i3c_master_do_daa(struct i3c_master_controller *m) static int cdns_i3c_master_do_daa(struct i3c_master_controller *m)
{ {
struct cdns_i3c_master *master = to_cdns_i3c_master(m); struct cdns_i3c_master *master = to_cdns_i3c_master(m);
u32 olddevs, newdevs; unsigned long olddevs, newdevs;
int ret, slot; int ret, slot;
u8 addrs[MAX_DEVS] = { }; u8 addrs[MAX_DEVS] = { };
u8 last_addr = 0; u8 last_addr = 0;
olddevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK; olddevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK;
olddevs |= BIT(0);
/* Prepare RR slots before launching DAA. */ /* Prepare RR slots before launching DAA. */
for (slot = 1; slot <= master->maxdevs; slot++) { for_each_clear_bit(slot, &olddevs, master->maxdevs + 1) {
if (olddevs & BIT(slot))
continue;
ret = i3c_master_get_free_addr(m, last_addr + 1); ret = i3c_master_get_free_addr(m, last_addr + 1);
if (ret < 0) if (ret < 0)
return -ENOSPC; return -ENOSPC;
...@@ -1161,10 +1157,8 @@ static int cdns_i3c_master_do_daa(struct i3c_master_controller *m) ...@@ -1161,10 +1157,8 @@ static int cdns_i3c_master_do_daa(struct i3c_master_controller *m)
* Clear all retaining registers filled during DAA. We already * Clear all retaining registers filled during DAA. We already
* have the addressed assigned to them in the addrs array. * have the addressed assigned to them in the addrs array.
*/ */
for (slot = 1; slot <= master->maxdevs; slot++) { for_each_set_bit(slot, &newdevs, master->maxdevs + 1)
if (newdevs & BIT(slot)) i3c_master_add_i3c_dev_locked(m, addrs[slot]);
i3c_master_add_i3c_dev_locked(m, addrs[slot]);
}
/* /*
* Clear slots that ended up not being used. Can be caused by I3C * Clear slots that ended up not being used. Can be caused by I3C
......
...@@ -188,6 +188,10 @@ static inline struct i3c_driver *drv_to_i3cdrv(struct device_driver *drv) ...@@ -188,6 +188,10 @@ static inline struct i3c_driver *drv_to_i3cdrv(struct device_driver *drv)
struct device *i3cdev_to_dev(struct i3c_device *i3cdev); struct device *i3cdev_to_dev(struct i3c_device *i3cdev);
struct i3c_device *dev_to_i3cdev(struct device *dev); struct i3c_device *dev_to_i3cdev(struct device *dev);
const struct i3c_device_id *
i3c_device_match_id(struct i3c_device *i3cdev,
const struct i3c_device_id *id_table);
static inline void i3cdev_set_drvdata(struct i3c_device *i3cdev, static inline void i3cdev_set_drvdata(struct i3c_device *i3cdev,
void *data) void *data)
{ {
......
...@@ -71,6 +71,9 @@ struct i2c_dev_boardinfo { ...@@ -71,6 +71,9 @@ struct i2c_dev_boardinfo {
* @common: common part of the I2C device descriptor * @common: common part of the I2C device descriptor
* @boardinfo: pointer to the boardinfo attached to this I2C device * @boardinfo: pointer to the boardinfo attached to this I2C device
* @dev: I2C device object registered to the I2C framework * @dev: I2C device object registered to the I2C framework
* @addr: I2C device address
* @lvr: LVR (Legacy Virtual Register) needed by the I3C core to know about
* the I2C device limitations
* *
* Each I2C device connected on the bus will have an i2c_dev_desc. * Each I2C device connected on the bus will have an i2c_dev_desc.
* This object is created by the core and later attached to the controller * This object is created by the core and later attached to the controller
...@@ -84,6 +87,8 @@ struct i2c_dev_desc { ...@@ -84,6 +87,8 @@ struct i2c_dev_desc {
struct i3c_i2c_dev_desc common; struct i3c_i2c_dev_desc common;
const struct i2c_dev_boardinfo *boardinfo; const struct i2c_dev_boardinfo *boardinfo;
struct i2c_client *dev; struct i2c_client *dev;
u16 addr;
u8 lvr;
}; };
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment