Commit 5e74b9bf authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull i2c fixes from Wolfram Sang:

 - fix ref leak in the I2C core

 - fix remove notification in the address translator

 - missing error check in the pinctrl demuxer (plus a typo fix)

 - fix NAK handling when Linux is testunit target

 - fix NAK handling for the Renesas R-Car controller when it is a target

* tag 'i2c-for-6.13-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux:
  i2c: testunit: on errors, repeat NACK until STOP
  i2c: rcar: fix NACK handling when being a target
  i2c: mux: demux-pinctrl: correct comment
  i2c: mux: demux-pinctrl: check initial mux selection, too
  i2c: atr: Fix client detach
  i2c: core: fix reference leak in i2c_register_adapter()
parents 4b040f0a 6ad30f78
Loading
Loading
Loading
Loading
+15 −5
Original line number Diff line number Diff line
@@ -130,6 +130,8 @@
#define ID_P_PM_BLOCKED		BIT(31)
#define ID_P_MASK		GENMASK(31, 27)

#define ID_SLAVE_NACK		BIT(0)

enum rcar_i2c_type {
	I2C_RCAR_GEN1,
	I2C_RCAR_GEN2,
@@ -166,6 +168,7 @@ struct rcar_i2c_priv {
	int irq;

	struct i2c_client *host_notify_client;
	u8 slave_flags;
};

#define rcar_i2c_priv_to_dev(p)		((p)->adap.dev.parent)
@@ -655,6 +658,7 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
{
	u32 ssr_raw, ssr_filtered;
	u8 value;
	int ret;

	ssr_raw = rcar_i2c_read(priv, ICSSR) & 0xff;
	ssr_filtered = ssr_raw & rcar_i2c_read(priv, ICSIER);
@@ -670,7 +674,10 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
			rcar_i2c_write(priv, ICRXTX, value);
			rcar_i2c_write(priv, ICSIER, SDE | SSR | SAR);
		} else {
			i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED, &value);
			ret = i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED, &value);
			if (ret)
				priv->slave_flags |= ID_SLAVE_NACK;

			rcar_i2c_read(priv, ICRXTX);	/* dummy read */
			rcar_i2c_write(priv, ICSIER, SDR | SSR | SAR);
		}
@@ -683,18 +690,21 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
	if (ssr_filtered & SSR) {
		i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value);
		rcar_i2c_write(priv, ICSCR, SIE | SDBS); /* clear our NACK */
		priv->slave_flags &= ~ID_SLAVE_NACK;
		rcar_i2c_write(priv, ICSIER, SAR);
		rcar_i2c_write(priv, ICSSR, ~SSR & 0xff);
	}

	/* master wants to write to us */
	if (ssr_filtered & SDR) {
		int ret;

		value = rcar_i2c_read(priv, ICRXTX);
		ret = i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_RECEIVED, &value);
		/* Send NACK in case of error */
		rcar_i2c_write(priv, ICSCR, SIE | SDBS | (ret < 0 ? FNA : 0));
		if (ret)
			priv->slave_flags |= ID_SLAVE_NACK;

		/* Send NACK in case of error, but it will come 1 byte late :( */
		rcar_i2c_write(priv, ICSCR, SIE | SDBS |
			       (priv->slave_flags & ID_SLAVE_NACK ? FNA : 0));
		rcar_i2c_write(priv, ICSSR, ~SDR & 0xff);
	}

+1 −1
Original line number Diff line number Diff line
@@ -412,7 +412,7 @@ static int i2c_atr_bus_notifier_call(struct notifier_block *nb,
				dev_name(dev), ret);
		break;

	case BUS_NOTIFY_DEL_DEVICE:
	case BUS_NOTIFY_REMOVED_DEVICE:
		i2c_atr_detach_client(client->adapter, client);
		break;

+1 −0
Original line number Diff line number Diff line
@@ -1562,6 +1562,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
	res = device_add(&adap->dev);
	if (res) {
		pr_err("adapter '%s': can't register device (%d)\n", adap->name, res);
		put_device(&adap->dev);
		goto out_list;
	}

+15 −4
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ enum testunit_regs {

enum testunit_flags {
	TU_FLAG_IN_PROCESS,
	TU_FLAG_NACK,
};

struct testunit_data {
@@ -90,8 +91,10 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client,

	switch (event) {
	case I2C_SLAVE_WRITE_REQUESTED:
		if (test_bit(TU_FLAG_IN_PROCESS, &tu->flags))
			return -EBUSY;
		if (test_bit(TU_FLAG_IN_PROCESS | TU_FLAG_NACK, &tu->flags)) {
			ret = -EBUSY;
			break;
		}

		memset(tu->regs, 0, TU_NUM_REGS);
		tu->reg_idx = 0;
@@ -99,8 +102,10 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
		break;

	case I2C_SLAVE_WRITE_RECEIVED:
		if (test_bit(TU_FLAG_IN_PROCESS, &tu->flags))
			return -EBUSY;
		if (test_bit(TU_FLAG_IN_PROCESS | TU_FLAG_NACK, &tu->flags)) {
			ret = -EBUSY;
			break;
		}

		if (tu->reg_idx < TU_NUM_REGS)
			tu->regs[tu->reg_idx] = *val;
@@ -129,6 +134,8 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
		 * here because we still need them in the workqueue!
		 */
		tu->reg_idx = 0;

		clear_bit(TU_FLAG_NACK, &tu->flags);
		break;

	case I2C_SLAVE_READ_PROCESSED:
@@ -151,6 +158,10 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
		break;
	}

	/* If an error occurred somewhen, we NACK everything until next STOP */
	if (ret)
		set_bit(TU_FLAG_NACK, &tu->flags);

	return ret;
}

+4 −2
Original line number Diff line number Diff line
@@ -68,7 +68,7 @@ static int i2c_demux_activate_master(struct i2c_demux_pinctrl_priv *priv, u32 ne
	}

	/*
	 * Check if there are pinctrl states at all. Note: we cant' use
	 * Check if there are pinctrl states at all. Note: we can't use
	 * devm_pinctrl_get_select() because we need to distinguish between
	 * the -ENODEV from devm_pinctrl_get() and pinctrl_lookup_state().
	 */
@@ -261,7 +261,9 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev)
	pm_runtime_no_callbacks(&pdev->dev);

	/* switch to first parent as active master */
	i2c_demux_activate_master(priv, 0);
	err = i2c_demux_activate_master(priv, 0);
	if (err)
		goto err_rollback;

	err = device_create_file(&pdev->dev, &dev_attr_available_masters);
	if (err)