Merge tag 'i2c-for-6.11-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
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
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
@@ -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,
|
||||
smbus_do_alert);
|
||||
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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user