[i2c] linux-i2c and smbalert

Mark M. Hoffman mhoffman at lightlink.com
Thu Sep 7 13:43:11 CEST 2006


Hi Hendrik:

* Hendrik Sattler <post at hendrik-sattler.de> [2006-08-28 23:05:25 +0200]:
> Index: linux-2.6.17/drivers/i2c/i2c-core.c
> ===================================================================
> --- linux-2.6.17.orig/drivers/i2c/i2c-core.c	2006-08-26 17:08:26.234925000 +0200
> +++ linux-2.6.17/drivers/i2c/i2c-core.c	2006-08-28 21:58:56.670280750 +0200
> @@ -1126,6 +1126,49 @@
>  	return res;
>  }
>  
> +void i2c_smbus_alert_notify(struct i2c_adapter *adapter, unsigned short addr)
> +{
> +	struct list_head   *item;
> +	struct i2c_client  *client = NULL;
> +
> +	mutex_lock(&adapter->clist_lock);
> +	list_for_each(item,&adapter->clients) {
> +		client = list_entry(item, struct i2c_client, list);
> +		if (client->addr == addr)
> +			break;

You'll need i2c_use_client() in there somewhere...

> +	}
> +	mutex_unlock(&adapter->clist_lock);
> +	if (item == &adapter->clients)
> +		return;
> +	if (client && client->driver->smbus_alert)
> +		client->driver->smbus_alert(client);

... and i2c_release_client() here.

> +}
> +
> +/* read from the alert-reponse-address (ARA)
> + * must NOT be called from interrupt context
> + */
> +#define I2C_ADDR_SMBUS_ARA 0x0C
> +s32 i2c_smbus_read_ara(struct i2c_adapter *adapter)
> +{
> +	struct i2c_client ara = {
> +		.addr = I2C_ADDR_SMBUS_ARA,
> +		.adapter = adapter,
> +		.flags = 0,
> +	};
> +
> +	/* TODO: does not work with 10bit addresses
> +	 * SMBus-1.0:
> +	 *   In case of 10bit addresses, two bytes are returned:
> +	 *     1111 0HH0 LLLL LLLL (H mark the high bits, L the low bits)
> +	 *   In case of 7bit addresses, one byte is returned:
> +	 *     AAAA AAAX (A is the 7bit address, X is 0 or 1).
> +	 */
> +	s32 addr = i2c_smbus_read_byte(&ara);
> +	if (addr < 0)
> +		return addr;
> +	else
> +		return (addr >> 1);
> +}
>  

Assumption: the I2C adapter/driver is going to call this function upon
receiving the SMBALERT signal?  Unfortunately, it's not going to be that
simple.  You can't do i2c_smbus_read_byte (or any other transfer) from an
interrupt context.

But I think you'll want this function to be callable from interrupt context.
So, it will need to kick off a workqueue to do the rest.  That should be
done in i2c-core rather than pushed out to each driver.

I'd like to see a patch with a bus driver implementation as well.

>  /* Next four are needed by i2c-isa */
>  EXPORT_SYMBOL_GPL(i2c_adapter_dev_release);
> @@ -1163,6 +1206,9 @@
>  EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data);
>  EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data);
>  
> +EXPORT_SYMBOL(i2c_smbus_alert_notify);
> +EXPORT_SYMBOL(i2c_smbus_read_ara);
> +
>  MODULE_AUTHOR("Simon G. Vogl <simon at tk.uni-linz.ac.at>");
>  MODULE_DESCRIPTION("I2C-Bus main module");
>  MODULE_LICENSE("GPL");
> Index: linux-2.6.17/include/linux/i2c.h
> ===================================================================
> --- linux-2.6.17.orig/include/linux/i2c.h	2006-08-26 17:43:51.963774750 +0200
> +++ linux-2.6.17/include/linux/i2c.h	2006-08-26 21:15:15.220428750 +0200
> @@ -104,6 +104,11 @@
>  					  u8 command, u8 length,
>  					  u8 *values);
>  
> +/* read the device address from the ARA */
> +unsigned short i2c_smbus_read_ara(struct i2c_adapter *adapter);
> +/* call the smbus_alert function for an I2C address */
> +void i2c_smbus_alert_notify(struct i2c_adapter *adapter, unsigned short addr);
> +
>  /*
>   * A driver is capable of handling one or more physical devices present on
>   * I2C adapters. This information is used to inform the driver of adapter
> @@ -138,6 +143,10 @@
>  	 */
>  	int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);
>  
> +        /* handle incoming SMBALERTs from the device
> +	 */
> +        void (*smbus_alert) (struct i2c_client *client);
> +
>  	struct device_driver driver;
>  	struct list_head list;
>  };

Regards,

-- 
Mark M. Hoffman
mhoffman at lightlink.com




More information about the i2c mailing list