diff options
Diffstat (limited to 'drivers/i2c/i2c-smbus.c')
-rw-r--r-- | drivers/i2c/i2c-smbus.c | 81 |
1 files changed, 25 insertions, 56 deletions
diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index f9271c713d20..5a1dd7f13bac 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -21,12 +21,11 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of_irq.h> #include <linux/slab.h> #include <linux/workqueue.h> struct i2c_smbus_alert { - unsigned int alert_edge_triggered:1; - int irq; struct work_struct alert; struct i2c_client *ara; /* Alert response address */ }; @@ -72,13 +71,12 @@ static int smbus_do_alert(struct device *dev, void *addrp) * The alert IRQ handler needs to hand work off to a task which can issue * SMBus calls, because those sleeping calls can't be made in IRQ context. */ -static void smbus_alert(struct work_struct *work) +static irqreturn_t smbus_alert(int irq, void *d) { - struct i2c_smbus_alert *alert; + struct i2c_smbus_alert *alert = d; struct i2c_client *ara; unsigned short prev_addr = 0; /* Not a valid address */ - alert = container_of(work, struct i2c_smbus_alert, alert); ara = alert->ara; for (;;) { @@ -115,21 +113,17 @@ static void smbus_alert(struct work_struct *work) prev_addr = data.addr; } - /* We handled all alerts; re-enable level-triggered IRQs */ - if (!alert->alert_edge_triggered) - enable_irq(alert->irq); + return IRQ_HANDLED; } -static irqreturn_t smbalert_irq(int irq, void *d) +static void smbalert_work(struct work_struct *work) { - struct i2c_smbus_alert *alert = d; + struct i2c_smbus_alert *alert; - /* Disable level-triggered IRQs until we handle them */ - if (!alert->alert_edge_triggered) - disable_irq_nosync(irq); + alert = container_of(work, struct i2c_smbus_alert, alert); + + smbus_alert(0, alert); - schedule_work(&alert->alert); - return IRQ_HANDLED; } /* Setup SMBALERT# infrastructure */ @@ -139,28 +133,35 @@ 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; - int res; + int res, irq; alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert), GFP_KERNEL); if (!alert) return -ENOMEM; - alert->alert_edge_triggered = setup->alert_edge_triggered; - alert->irq = setup->irq; - INIT_WORK(&alert->alert, smbus_alert); + if (setup) { + irq = setup->irq; + } else { + irq = of_irq_get_byname(adapter->dev.of_node, "smbus_alert"); + if (irq <= 0) + return irq; + } + + INIT_WORK(&alert->alert, smbalert_work); alert->ara = ara; - if (setup->irq > 0) { - res = devm_request_irq(&ara->dev, setup->irq, smbalert_irq, - 0, "smbus_alert", alert); + if (irq > 0) { + res = devm_request_threaded_irq(&ara->dev, irq, + NULL, smbus_alert, + IRQF_SHARED | IRQF_ONESHOT, + "smbus_alert", alert); if (res) return res; } i2c_set_clientdata(ara, alert); - dev_info(&adapter->dev, "supports SMBALERT#, %s trigger\n", - setup->alert_edge_triggered ? "edge" : "level"); + dev_info(&adapter->dev, "supports SMBALERT#\n"); return 0; } @@ -190,38 +191,6 @@ static struct i2c_driver smbalert_driver = { }; /** - * i2c_setup_smbus_alert - Setup SMBus alert support - * @adapter: the target adapter - * @setup: setup data for the SMBus alert handler - * Context: can sleep - * - * Setup handling of the SMBus alert protocol on a given I2C bus segment. - * - * Handling can be done either through our IRQ handler, or by the - * adapter (from its handler, periodic polling, or whatever). - * - * NOTE that if we manage the IRQ, we *MUST* know if it's level or - * edge triggered in order to hand it to the workqueue correctly. - * If triggering the alert seems to wedge the system, you probably - * should have said it's level triggered. - * - * This returns the ara client, which should be saved for later use with - * i2c_handle_smbus_alert() and ultimately i2c_unregister_device(); or NULL - * to indicate an error. - */ -struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter, - struct i2c_smbus_alert_setup *setup) -{ - struct i2c_board_info ara_board_info = { - I2C_BOARD_INFO("smbus_alert", 0x0c), - .platform_data = setup, - }; - - return i2c_new_device(adapter, &ara_board_info); -} -EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert); - -/** * i2c_handle_smbus_alert - Handle an SMBus alert * @ara: the ARA client on the relevant adapter * Context: can't sleep |