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

 - Two fixes for SMBusAlert handling in the I2C core: one to avoid an
   endless loop when scanning for handlers and one to make sure handlers
   are always called even if HW has broken behaviour

 - I2C header build fix for when ACPI is enabled but I2C isn't

 - The testunit gets a rename in the code to match the documentation

 - Two fixes for the Qualcomm GENI I2C controller are cleaning up the
   error exit patch in the runtime_resume() function. The first is
   disabling the clock, the second disables the icc on the way out

* tag 'i2c-for-6.11-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux:
  i2c: testunit: match HostNotify test name with docs
  i2c: qcom-geni: Add missing geni_icc_disable in geni_i2c_runtime_resume
  i2c: qcom-geni: Add missing clk_disable_unprepare in geni_i2c_runtime_resume
  i2c: Fix conditional for substituting empty ACPI functions
  i2c: smbus: Send alert notifications to all devices if source not found
  i2c: smbus: Improve handling of stuck alerts
parents 0409cc53 01a620d4
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -990,8 +990,11 @@ static int __maybe_unused geni_i2c_runtime_resume(struct device *dev)
		return ret;

	ret = geni_se_resources_on(&gi2c->se);
	if (ret)
	if (ret) {
		clk_disable_unprepare(gi2c->core_clk);
		geni_icc_disable(&gi2c->se);
		return ret;
	}

	enable_irq(gi2c->irq);
	gi2c->suspended = 0;
+2 −2
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@

enum testunit_cmds {
	TU_CMD_READ_BYTES = 1,	/* save 0 for ABORT, RESET or similar */
	TU_CMD_HOST_NOTIFY,
	TU_CMD_SMBUS_HOST_NOTIFY,
	TU_CMD_SMBUS_BLOCK_PROC_CALL,
	TU_NUM_CMDS
};
@@ -60,7 +60,7 @@ static void i2c_slave_testunit_work(struct work_struct *work)
		msg.len = tu->regs[TU_REG_DATAH];
		break;

	case TU_CMD_HOST_NOTIFY:
	case TU_CMD_SMBUS_HOST_NOTIFY:
		msg.addr = 0x08;
		msg.flags = 0;
		msg.len = 3;
+57 −7
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ static int smbus_do_alert(struct device *dev, void *addrp)
	struct i2c_client *client = i2c_verify_client(dev);
	struct alert_data *data = addrp;
	struct i2c_driver *driver;
	int ret;

	if (!client || client->addr != data->addr)
		return 0;
@@ -47,16 +48,47 @@ static int smbus_do_alert(struct device *dev, void *addrp)
	device_lock(dev);
	if (client->dev.driver) {
		driver = to_i2c_driver(client->dev.driver);
		if (driver->alert)
		if (driver->alert) {
			/* Stop iterating after we find the device */
			driver->alert(client, data->type, data->data);
		else
			ret = -EBUSY;
		} else {
			dev_warn(&client->dev, "no driver alert()!\n");
	} else
			ret = -EOPNOTSUPP;
		}
	} else {
		dev_dbg(&client->dev, "alert with no driver\n");
		ret = -ENODEV;
	}
	device_unlock(dev);

	/* Stop iterating after we find the device */
	return -EBUSY;
	return ret;
}

/* Same as above, but call back all drivers with alert handler */

static int smbus_do_alert_force(struct device *dev, void *addrp)
{
	struct i2c_client *client = i2c_verify_client(dev);
	struct alert_data *data = addrp;
	struct i2c_driver *driver;

	if (!client || (client->flags & I2C_CLIENT_TEN))
		return 0;

	/*
	 * Drivers should either disable alerts, or provide at least
	 * a minimal handler. Lock so the driver won't change.
	 */
	device_lock(dev);
	if (client->dev.driver) {
		driver = to_i2c_driver(client->dev.driver);
		if (driver->alert)
			driver->alert(client, data->type, data->data);
	}
	device_unlock(dev);

	return 0;
}

/*
@@ -67,6 +99,7 @@ static irqreturn_t smbus_alert(int irq, void *d)
{
	struct i2c_smbus_alert *alert = d;
	struct i2c_client *ara;
	unsigned short prev_addr = I2C_CLIENT_END; /* Not a valid address */

	ara = alert->ara;

@@ -94,8 +127,25 @@ static irqreturn_t smbus_alert(int irq, void *d)
			data.addr, data.data);

		/* Notify driver for the device which issued the alert */
		device_for_each_child(&ara->adapter->dev, &data,
		status = device_for_each_child(&ara->adapter->dev, &data,
					       smbus_do_alert);
		/*
		 * If we read the same address more than once, and the alert
		 * was not handled by a driver, it won't do any good to repeat
		 * the loop because it will never terminate. Try again, this
		 * time calling the alert handlers of all devices connected to
		 * the bus, and abort the loop afterwards. If this helps, we
		 * are all set. If it doesn't, there is nothing else we can do,
		 * so we might as well abort the loop.
		 * Note: This assumes that a driver with alert handler handles
		 * the alert properly and clears it if necessary.
		 */
		if (data.addr == prev_addr && status != -EBUSY) {
			device_for_each_child(&ara->adapter->dev, &data,
					      smbus_do_alert_force);
			break;
		}
		prev_addr = data.addr;
	}

	return IRQ_HANDLED;
+1 −1
Original line number Diff line number Diff line
@@ -1066,7 +1066,7 @@ static inline int of_i2c_get_board_info(struct device *dev,
struct acpi_resource;
struct acpi_resource_i2c_serialbus;

#if IS_ENABLED(CONFIG_ACPI)
#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_I2C)
bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares,
			       struct acpi_resource_i2c_serialbus **i2c);
int i2c_acpi_client_count(struct acpi_device *adev);