diff options
author | Wolfram Sang <wsa+renesas@sang-engineering.com> | 2024-09-09 14:02:56 +0300 |
---|---|---|
committer | Wolfram Sang <wsa+renesas@sang-engineering.com> | 2024-10-08 12:04:20 +0300 |
commit | 270cc3c54e229758b7c079e3aa3ef171e6d8698b (patch) | |
tree | 3af56ac18870ed22bc4a134669bf706ceb20235d | |
parent | 6b238b3c45eb67d3083d55dc17463d1f43e002a7 (diff) | |
download | linux-270cc3c54e229758b7c079e3aa3ef171e6d8698b.tar.xz |
i2c: support gpio-binding for SMBAlerts
Most I2C controllers do not have a dedicated pin for SMBus Alerts. Allow
them to define a GPIO as a side-channel.
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Reviewed-by: Andi Shyti <andi.shyti@kernel.org>
-rw-r--r-- | drivers/i2c/i2c-core-smbus.c | 9 | ||||
-rw-r--r-- | drivers/i2c/i2c-smbus.c | 22 |
2 files changed, 22 insertions, 9 deletions
diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c index e3b96fc53b5c..0a6bdc6df172 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -712,12 +712,15 @@ int i2c_setup_smbus_alert(struct i2c_adapter *adapter) if (!parent) return 0; + /* Report serious errors */ irq = device_property_match_string(parent, "interrupt-names", "smbus_alert"); - if (irq == -EINVAL || irq == -ENODATA) - return 0; - else if (irq < 0) + if (irq < 0 && irq != -EINVAL && irq != -ENODATA) return irq; + /* Skip setup when no irq was found */ + if (irq < 0 && !device_property_present(parent, "smbalert-gpios")) + return 0; + return PTR_ERR_OR_ZERO(i2c_new_smbus_alert_device(adapter, NULL)); } #endif diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index 8256f7aed0cf..7d40e7aa3799 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -8,6 +8,7 @@ #include <linux/device.h> #include <linux/dmi.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/i2c-smbus.h> #include <linux/interrupt.h> @@ -167,6 +168,8 @@ static int smbalert_probe(struct i2c_client *ara) struct i2c_smbus_alert_setup *setup = dev_get_platdata(&ara->dev); struct i2c_smbus_alert *alert; struct i2c_adapter *adapter = ara->adapter; + unsigned long irqflags = IRQF_SHARED | IRQF_ONESHOT; + struct gpio_desc *gpiod; int res, irq; alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert), @@ -179,18 +182,25 @@ static int smbalert_probe(struct i2c_client *ara) } else { irq = fwnode_irq_get_byname(dev_fwnode(adapter->dev.parent), "smbus_alert"); - if (irq <= 0) - return irq; + if (irq <= 0) { + gpiod = devm_gpiod_get(adapter->dev.parent, "smbalert", GPIOD_IN); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + + irq = gpiod_to_irq(gpiod); + if (irq <= 0) + return irq; + + irqflags |= IRQF_TRIGGER_FALLING; + } } INIT_WORK(&alert->alert, smbalert_work); alert->ara = ara; if (irq > 0) { - res = devm_request_threaded_irq(&ara->dev, irq, - NULL, smbus_alert, - IRQF_SHARED | IRQF_ONESHOT, - "smbus_alert", alert); + res = devm_request_threaded_irq(&ara->dev, irq, NULL, smbus_alert, + irqflags, "smbus_alert", alert); if (res) return res; } |