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 |