Commit 4b1acc43 authored by Wolfram Sang's avatar Wolfram Sang Committed by Wolfram Sang

i2c: core changes for slave support

Finally(!), make Linux support being an I2C slave. Most of the existing
infrastructure is reused. We mainly add i2c_slave_register/unregister()
calls which tells i2c bus drivers to activate the slave mode. Then, they
also get a callback to report slave events to.
Signed-off-by: default avatarWolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: default avatarWolfram Sang <wsa@the-dreams.de>
parent 40ed1b4c
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
(c) 2013 Wolfram Sang <wsa@the-dreams.de> (c) 2013 Wolfram Sang <wsa@the-dreams.de>
I2C ACPI code Copyright (C) 2014 Intel Corp I2C ACPI code Copyright (C) 2014 Intel Corp
Author: Lan Tianyu <tianyu.lan@intel.com> Author: Lan Tianyu <tianyu.lan@intel.com>
I2C slave support (c) 2014 by Wolfram Sang <wsa@sang-engineering.com>
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -2911,6 +2912,54 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, ...@@ -2911,6 +2912,54 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
} }
EXPORT_SYMBOL(i2c_smbus_xfer); EXPORT_SYMBOL(i2c_smbus_xfer);
int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb)
{
int ret;
if (!client || !slave_cb)
return -EINVAL;
if (!(client->flags & I2C_CLIENT_TEN)) {
/* Enforce stricter address checking */
ret = i2c_check_addr_validity(client->addr);
if (ret)
return ret;
}
if (!client->adapter->algo->reg_slave)
return -EOPNOTSUPP;
client->slave_cb = slave_cb;
i2c_lock_adapter(client->adapter);
ret = client->adapter->algo->reg_slave(client);
i2c_unlock_adapter(client->adapter);
if (ret)
client->slave_cb = NULL;
return ret;
}
EXPORT_SYMBOL_GPL(i2c_slave_register);
int i2c_slave_unregister(struct i2c_client *client)
{
int ret;
if (!client->adapter->algo->unreg_slave)
return -EOPNOTSUPP;
i2c_lock_adapter(client->adapter);
ret = client->adapter->algo->unreg_slave(client);
i2c_unlock_adapter(client->adapter);
if (ret == 0)
client->slave_cb = NULL;
return ret;
}
EXPORT_SYMBOL_GPL(i2c_slave_unregister);
MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>"); MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
MODULE_DESCRIPTION("I2C-Bus main module"); MODULE_DESCRIPTION("I2C-Bus main module");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -46,6 +46,8 @@ struct i2c_client; ...@@ -46,6 +46,8 @@ struct i2c_client;
struct i2c_driver; struct i2c_driver;
union i2c_smbus_data; union i2c_smbus_data;
struct i2c_board_info; struct i2c_board_info;
enum i2c_slave_event;
typedef int (*i2c_slave_cb_t)(struct i2c_client *, enum i2c_slave_event, u8 *);
struct module; struct module;
...@@ -209,6 +211,8 @@ struct i2c_driver { ...@@ -209,6 +211,8 @@ struct i2c_driver {
* @irq: indicates the IRQ generated by this device (if any) * @irq: indicates the IRQ generated by this device (if any)
* @detected: member of an i2c_driver.clients list or i2c-core's * @detected: member of an i2c_driver.clients list or i2c-core's
* userspace_devices list * userspace_devices list
* @slave_cb: Callback when I2C slave mode of an adapter is used. The adapter
* calls it to pass on slave events to the slave driver.
* *
* An i2c_client identifies a single device (i.e. chip) connected to an * An i2c_client identifies a single device (i.e. chip) connected to an
* i2c bus. The behaviour exposed to Linux is defined by the driver * i2c bus. The behaviour exposed to Linux is defined by the driver
...@@ -224,6 +228,7 @@ struct i2c_client { ...@@ -224,6 +228,7 @@ struct i2c_client {
struct device dev; /* the device structure */ struct device dev; /* the device structure */
int irq; /* irq issued by device */ int irq; /* irq issued by device */
struct list_head detected; struct list_head detected;
i2c_slave_cb_t slave_cb; /* callback for slave mode */
}; };
#define to_i2c_client(d) container_of(d, struct i2c_client, dev) #define to_i2c_client(d) container_of(d, struct i2c_client, dev)
...@@ -246,6 +251,25 @@ static inline void i2c_set_clientdata(struct i2c_client *dev, void *data) ...@@ -246,6 +251,25 @@ static inline void i2c_set_clientdata(struct i2c_client *dev, void *data)
dev_set_drvdata(&dev->dev, data); dev_set_drvdata(&dev->dev, data);
} }
/* I2C slave support */
enum i2c_slave_event {
I2C_SLAVE_REQ_READ_START,
I2C_SLAVE_REQ_READ_END,
I2C_SLAVE_REQ_WRITE_START,
I2C_SLAVE_REQ_WRITE_END,
I2C_SLAVE_STOP,
};
extern int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb);
extern int i2c_slave_unregister(struct i2c_client *client);
static inline int i2c_slave_event(struct i2c_client *client,
enum i2c_slave_event event, u8 *val)
{
return client->slave_cb(client, event, val);
}
/** /**
* struct i2c_board_info - template for device creation * struct i2c_board_info - template for device creation
* @type: chip type, to initialize i2c_client.name * @type: chip type, to initialize i2c_client.name
...@@ -352,6 +376,8 @@ i2c_register_board_info(int busnum, struct i2c_board_info const *info, ...@@ -352,6 +376,8 @@ i2c_register_board_info(int busnum, struct i2c_board_info const *info,
* into I2C transfers instead. * into I2C transfers instead.
* @functionality: Return the flags that this algorithm/adapter pair supports * @functionality: Return the flags that this algorithm/adapter pair supports
* from the I2C_FUNC_* flags. * from the I2C_FUNC_* flags.
* @reg_slave: Register given client to I2C slave mode of this adapter
* @unreg_slave: Unregister given client from I2C slave mode of this adapter
* *
* The following structs are for those who like to implement new bus drivers: * The following structs are for those who like to implement new bus drivers:
* i2c_algorithm is the interface to a class of hardware solutions which can * i2c_algorithm is the interface to a class of hardware solutions which can
...@@ -377,6 +403,9 @@ struct i2c_algorithm { ...@@ -377,6 +403,9 @@ struct i2c_algorithm {
/* To determine what the adapter supports */ /* To determine what the adapter supports */
u32 (*functionality) (struct i2c_adapter *); u32 (*functionality) (struct i2c_adapter *);
int (*reg_slave)(struct i2c_client *client);
int (*unreg_slave)(struct i2c_client *client);
}; };
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment