Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+22 -9
+6 -3
drivers/i2c/i2c-core-smbus.c
··· 712 712 if (!parent) 713 713 return 0; 714 714 715 + /* Report serious errors */ 715 716 irq = device_property_match_string(parent, "interrupt-names", "smbus_alert"); 716 - if (irq == -EINVAL || irq == -ENODATA) 717 - return 0; 718 - else if (irq < 0) 717 + if (irq < 0 && irq != -EINVAL && irq != -ENODATA) 719 718 return irq; 719 + 720 + /* Skip setup when no irq was found */ 721 + if (irq < 0 && !device_property_present(parent, "smbalert-gpios")) 722 + return 0; 720 723 721 724 return PTR_ERR_OR_ZERO(i2c_new_smbus_alert_device(adapter, NULL)); 722 725 }
+16 -6
drivers/i2c/i2c-smbus.c
··· 8 8 9 9 #include <linux/device.h> 10 10 #include <linux/dmi.h> 11 + #include <linux/gpio/consumer.h> 11 12 #include <linux/i2c.h> 12 13 #include <linux/i2c-smbus.h> 13 14 #include <linux/interrupt.h> ··· 168 167 struct i2c_smbus_alert_setup *setup = dev_get_platdata(&ara->dev); 169 168 struct i2c_smbus_alert *alert; 170 169 struct i2c_adapter *adapter = ara->adapter; 170 + unsigned long irqflags = IRQF_SHARED | IRQF_ONESHOT; 171 + struct gpio_desc *gpiod; 171 172 int res, irq; 172 173 173 174 alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert), ··· 182 179 } else { 183 180 irq = fwnode_irq_get_byname(dev_fwnode(adapter->dev.parent), 184 181 "smbus_alert"); 185 - if (irq <= 0) 186 - return irq; 182 + if (irq <= 0) { 183 + gpiod = devm_gpiod_get(adapter->dev.parent, "smbalert", GPIOD_IN); 184 + if (IS_ERR(gpiod)) 185 + return PTR_ERR(gpiod); 186 + 187 + irq = gpiod_to_irq(gpiod); 188 + if (irq <= 0) 189 + return irq; 190 + 191 + irqflags |= IRQF_TRIGGER_FALLING; 192 + } 187 193 } 188 194 189 195 INIT_WORK(&alert->alert, smbalert_work); 190 196 alert->ara = ara; 191 197 192 198 if (irq > 0) { 193 - res = devm_request_threaded_irq(&ara->dev, irq, 194 - NULL, smbus_alert, 195 - IRQF_SHARED | IRQF_ONESHOT, 196 - "smbus_alert", alert); 199 + res = devm_request_threaded_irq(&ara->dev, irq, NULL, smbus_alert, 200 + irqflags, "smbus_alert", alert); 197 201 if (res) 198 202 return res; 199 203 }