Commit 270cc3c5 authored by Wolfram Sang's avatar Wolfram Sang
Browse files

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: default avatarWolfram Sang <wsa+renesas@sang-engineering.com>
Reviewed-by: default avatarAndi Shyti <andi.shyti@kernel.org>
parent 6b238b3c
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -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
+16 −6
Original line number Diff line number Diff line
@@ -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) {
			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;
	}