Commit 31dda85e authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+53 −0
Original line number Diff line number Diff line
@@ -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
 *
+14 −53
Original line number Diff line number Diff line
@@ -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,7 +1590,7 @@ 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,
					     i2cdev->addr,
					     I3C_ADDR_SLOT_FREE);
		i3c_master_free_i2c_dev(i2cdev);
	}
@@ -2093,9 +2052,11 @@ 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;
		}
	}

	/*
	 * The user might want to limit I2C and I3C speed in case some devices
+2 −2
Original line number Diff line number Diff line
@@ -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));

+12 −18
Original line number Diff line number Diff line
@@ -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))
	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
+4 −0
Original line number Diff line number Diff line
@@ -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)
{
Loading