[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