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 -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEKmCqpbOU668PNA69Ze02AX4ItwAFAl1/N00ACgkQZe02AX4I twB8wxAAvK2wd7IMXD/GldIjFmqRb94sLMHjbLavKMNv/kmTZM68BoM600pntVO0 +2lmqL7tL/2I5fnI35LJFEe2zS7XqPrh8m9rOZZHvj/uDaZnHxp18a4vwKqpw3gy QzlvUAQY5fp3dOlLqawKHbUTEwXA4WAuoFQujNimLbluKWZYiU3mBEPcVjYcNqnW 1qn+FckJ7HSNKgIwvMfD7MaF77FSkKiWmAud/Zm23vc0pISuVi4sYBT2UJ90bSBL npPiW0l9BieAsCWLn1kv0T5AaY7X1LfBkAS10Nb3vxUOXxkHR0GtlG4Xno5cwfqy bcNH8QwJ9wNi0tNcPxCe0CM1d5k0ekW95VBv4HzRT/wHP/cAcgxhk65jPPCdwuus IYMp6B0p+G50xW2b7NzQGrLbktzn6kAqfzZWCBmX3/k2V+Y0CmBLarZp1LHL/hBR 51dvqVNlgGG5DBHnAMoYCKbsas6yqXK7rxpXKkW3yhlcHHkn86wx1MI4+XqJAHKH AQOfuu+sjp35tOelb+wd49jXgWBVPVdQ2rv1h2YK6r2rgpbXE+P/t4R0BbIsIR0z 4wa9lnLaDgjyRaABUFC7YIqjSuHW7NsGJDHMajwsd8WvcUhPNDznTRnhp7o4rWXt 5ERqArQIxYCbVaROsYrgoYtxJ1E9ErnsW6cNxZX7O/6vljBxYLI= =wXtJ -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
31dda85e49
|
@ -200,6 +200,59 @@ struct i3c_device *dev_to_i3cdev(struct device *dev)
|
|||
}
|
||||
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
|
||||
*
|
||||
|
|
|
@ -123,7 +123,7 @@ static struct i3c_dev_desc *dev_to_i3cdesc(struct device *dev)
|
|||
if (dev->type == &i3c_device_type)
|
||||
return dev_to_i3cdev(dev)->desc;
|
||||
|
||||
master = container_of(dev, struct i3c_master_controller, dev);
|
||||
master = dev_to_i3cmaster(dev);
|
||||
|
||||
return master->this;
|
||||
}
|
||||
|
@ -276,51 +276,6 @@ static const struct device_type i3c_device_type = {
|
|||
.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)
|
||||
{
|
||||
struct i3c_device *i3cdev;
|
||||
|
@ -645,6 +600,8 @@ i3c_master_alloc_i2c_dev(struct i3c_master_controller *master,
|
|||
|
||||
dev->common.master = master;
|
||||
dev->boardinfo = boardinfo;
|
||||
dev->addr = boardinfo->base.addr;
|
||||
dev->lvr = boardinfo->lvr;
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
@ -963,8 +920,8 @@ int i3c_master_defslvs_locked(struct i3c_master_controller *master)
|
|||
|
||||
desc = defslvs->slaves;
|
||||
i3c_bus_for_each_i2cdev(bus, i2cdev) {
|
||||
desc->lvr = i2cdev->boardinfo->lvr;
|
||||
desc->static_addr = i2cdev->boardinfo->base.addr << 1;
|
||||
desc->lvr = i2cdev->lvr;
|
||||
desc->static_addr = i2cdev->addr << 1;
|
||||
desc++;
|
||||
}
|
||||
|
||||
|
@ -1084,8 +1041,10 @@ static int i3c_master_getmwl_locked(struct i3c_master_controller *master,
|
|||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (dest.payload.len != sizeof(*mwl))
|
||||
return -EIO;
|
||||
if (dest.payload.len != sizeof(*mwl)) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
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)
|
|||
common.node) {
|
||||
i3c_master_detach_i2c_dev(i2cdev);
|
||||
i3c_bus_set_addr_slot_status(&master->bus,
|
||||
i2cdev->boardinfo->base.addr,
|
||||
I3C_ADDR_SLOT_FREE);
|
||||
i2cdev->addr,
|
||||
I3C_ADDR_SLOT_FREE);
|
||||
i3c_master_free_i2c_dev(i2cdev);
|
||||
}
|
||||
}
|
||||
|
@ -2093,8 +2052,10 @@ static int of_populate_i3c_bus(struct i3c_master_controller *master)
|
|||
|
||||
for_each_available_child_of_node(i3cbus_np, node) {
|
||||
ret = of_i3c_master_add_dev(master, node);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
of_node_put(node);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1033,12 +1033,12 @@ static int dw_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev)
|
|||
return -ENOMEM;
|
||||
|
||||
data->index = pos;
|
||||
master->addrs[pos] = dev->boardinfo->base.addr;
|
||||
master->addrs[pos] = dev->addr;
|
||||
master->free_pos &= ~BIT(pos);
|
||||
i2c_dev_set_master_data(dev, data);
|
||||
|
||||
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 +
|
||||
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)
|
|||
static int cdns_i3c_master_get_rr_slot(struct cdns_i3c_master *master,
|
||||
u8 dyn_addr)
|
||||
{
|
||||
u32 activedevs, rr;
|
||||
unsigned long activedevs;
|
||||
u32 rr;
|
||||
int i;
|
||||
|
||||
if (!dyn_addr) {
|
||||
|
@ -913,13 +914,10 @@ static int cdns_i3c_master_get_rr_slot(struct cdns_i3c_master *master,
|
|||
return ffs(master->free_rr_slots) - 1;
|
||||
}
|
||||
|
||||
activedevs = readl(master->regs + DEVS_CTRL) &
|
||||
DEVS_CTRL_DEVS_ACTIVE_MASK;
|
||||
|
||||
for (i = 1; i <= master->maxdevs; i++) {
|
||||
if (!(BIT(i) & activedevs))
|
||||
continue;
|
||||
activedevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK;
|
||||
activedevs &= ~BIT(0);
|
||||
|
||||
for_each_set_bit(i, &activedevs, master->maxdevs + 1) {
|
||||
rr = readl(master->regs + DEV_ID_RR0(i));
|
||||
if (!(rr & DEV_ID_RR0_IS_I3C) ||
|
||||
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)
|
|||
master->free_rr_slots &= ~BIT(slot);
|
||||
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));
|
||||
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) |
|
||||
DEVS_CTRL_DEV_ACTIVE(data->id),
|
||||
master->regs + DEVS_CTRL);
|
||||
|
@ -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)
|
||||
{
|
||||
struct cdns_i3c_master *master = to_cdns_i3c_master(m);
|
||||
u32 olddevs, newdevs;
|
||||
unsigned long olddevs, newdevs;
|
||||
int ret, slot;
|
||||
u8 addrs[MAX_DEVS] = { };
|
||||
u8 last_addr = 0;
|
||||
|
||||
olddevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK;
|
||||
olddevs |= BIT(0);
|
||||
|
||||
/* Prepare RR slots before launching DAA. */
|
||||
for (slot = 1; slot <= master->maxdevs; slot++) {
|
||||
if (olddevs & BIT(slot))
|
||||
continue;
|
||||
|
||||
for_each_clear_bit(slot, &olddevs, master->maxdevs + 1) {
|
||||
ret = i3c_master_get_free_addr(m, last_addr + 1);
|
||||
if (ret < 0)
|
||||
return -ENOSPC;
|
||||
|
@ -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
|
||||
* have the addressed assigned to them in the addrs array.
|
||||
*/
|
||||
for (slot = 1; slot <= master->maxdevs; slot++) {
|
||||
if (newdevs & BIT(slot))
|
||||
i3c_master_add_i3c_dev_locked(m, addrs[slot]);
|
||||
}
|
||||
for_each_set_bit(slot, &newdevs, master->maxdevs + 1)
|
||||
i3c_master_add_i3c_dev_locked(m, addrs[slot]);
|
||||
|
||||
/*
|
||||
* 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)
|
|||
struct device *i3cdev_to_dev(struct i3c_device *i3cdev);
|
||||
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,
|
||||
void *data)
|
||||
{
|
||||
|
|
|
@ -71,6 +71,9 @@ struct i2c_dev_boardinfo {
|
|||
* @common: common part of the I2C device descriptor
|
||||
* @boardinfo: pointer to the boardinfo attached to this I2C device
|
||||
* @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.
|
||||
* This object is created by the core and later attached to the controller
|
||||
|
@ -84,6 +87,8 @@ struct i2c_dev_desc {
|
|||
struct i3c_i2c_dev_desc common;
|
||||
const struct i2c_dev_boardinfo *boardinfo;
|
||||
struct i2c_client *dev;
|
||||
u16 addr;
|
||||
u8 lvr;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue