Skip to content

Commit 7299cd4

Browse files
committed
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
2 parents 0409cc5 + 01a620d commit 7299cd4

File tree

4 files changed

+64
-11
lines changed

4 files changed

+64
-11
lines changed

drivers/i2c/busses/i2c-qcom-geni.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -990,8 +990,11 @@ static int __maybe_unused geni_i2c_runtime_resume(struct device *dev)
990990
return ret;
991991

992992
ret = geni_se_resources_on(&gi2c->se);
993-
if (ret)
993+
if (ret) {
994+
clk_disable_unprepare(gi2c->core_clk);
995+
geni_icc_disable(&gi2c->se);
994996
return ret;
997+
}
995998

996999
enable_irq(gi2c->irq);
9971000
gi2c->suspended = 0;

drivers/i2c/i2c-slave-testunit.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

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

63-
case TU_CMD_HOST_NOTIFY:
63+
case TU_CMD_SMBUS_HOST_NOTIFY:
6464
msg.addr = 0x08;
6565
msg.flags = 0;
6666
msg.len = 3;

drivers/i2c/i2c-smbus.c

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ static int smbus_do_alert(struct device *dev, void *addrp)
3434
struct i2c_client *client = i2c_verify_client(dev);
3535
struct alert_data *data = addrp;
3636
struct i2c_driver *driver;
37+
int ret;
3738

3839
if (!client || client->addr != data->addr)
3940
return 0;
@@ -47,16 +48,47 @@ static int smbus_do_alert(struct device *dev, void *addrp)
4748
device_lock(dev);
4849
if (client->dev.driver) {
4950
driver = to_i2c_driver(client->dev.driver);
50-
if (driver->alert)
51+
if (driver->alert) {
52+
/* Stop iterating after we find the device */
5153
driver->alert(client, data->type, data->data);
52-
else
54+
ret = -EBUSY;
55+
} else {
5356
dev_warn(&client->dev, "no driver alert()!\n");
54-
} else
57+
ret = -EOPNOTSUPP;
58+
}
59+
} else {
5560
dev_dbg(&client->dev, "alert with no driver\n");
61+
ret = -ENODEV;
62+
}
63+
device_unlock(dev);
64+
65+
return ret;
66+
}
67+
68+
/* Same as above, but call back all drivers with alert handler */
69+
70+
static int smbus_do_alert_force(struct device *dev, void *addrp)
71+
{
72+
struct i2c_client *client = i2c_verify_client(dev);
73+
struct alert_data *data = addrp;
74+
struct i2c_driver *driver;
75+
76+
if (!client || (client->flags & I2C_CLIENT_TEN))
77+
return 0;
78+
79+
/*
80+
* Drivers should either disable alerts, or provide at least
81+
* a minimal handler. Lock so the driver won't change.
82+
*/
83+
device_lock(dev);
84+
if (client->dev.driver) {
85+
driver = to_i2c_driver(client->dev.driver);
86+
if (driver->alert)
87+
driver->alert(client, data->type, data->data);
88+
}
5689
device_unlock(dev);
5790

58-
/* Stop iterating after we find the device */
59-
return -EBUSY;
91+
return 0;
6092
}
6193

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

71104
ara = alert->ara;
72105

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

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

101151
return IRQ_HANDLED;

include/linux/i2c.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1066,7 +1066,7 @@ static inline int of_i2c_get_board_info(struct device *dev,
10661066
struct acpi_resource;
10671067
struct acpi_resource_i2c_serialbus;
10681068

1069-
#if IS_ENABLED(CONFIG_ACPI)
1069+
#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_I2C)
10701070
bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares,
10711071
struct acpi_resource_i2c_serialbus **i2c);
10721072
int i2c_acpi_client_count(struct acpi_device *adev);

0 commit comments

Comments
 (0)