Skip to content

Commit

Permalink
i2c: core changes for slave support
Browse files Browse the repository at this point in the history
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: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
  • Loading branch information
Wolfram Sang authored and Wolfram Sang committed Dec 11, 2014
1 parent 40ed1b4 commit 4b1acc4
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 0 deletions.
49 changes: 49 additions & 0 deletions drivers/i2c/i2c-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
(c) 2013 Wolfram Sang <wsa@the-dreams.de>
I2C ACPI code Copyright (C) 2014 Intel Corp
Author: Lan Tianyu <tianyu.lan@intel.com>
I2C slave support (c) 2014 by Wolfram Sang <wsa@sang-engineering.com>
*/

#include <linux/module.h>
Expand Down Expand Up @@ -2911,6 +2912,54 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
}
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_DESCRIPTION("I2C-Bus main module");
MODULE_LICENSE("GPL");
29 changes: 29 additions & 0 deletions include/linux/i2c.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ struct i2c_client;
struct i2c_driver;
union i2c_smbus_data;
struct i2c_board_info;
enum i2c_slave_event;
typedef int (*i2c_slave_cb_t)(struct i2c_client *, enum i2c_slave_event, u8 *);

struct module;

Expand Down Expand Up @@ -209,6 +211,8 @@ struct i2c_driver {
* @irq: indicates the IRQ generated by this device (if any)
* @detected: member of an i2c_driver.clients list or i2c-core's
* 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
* i2c bus. The behaviour exposed to Linux is defined by the driver
Expand All @@ -224,6 +228,7 @@ struct i2c_client {
struct device dev; /* the device structure */
int irq; /* irq issued by device */
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)

Expand All @@ -246,6 +251,25 @@ static inline void i2c_set_clientdata(struct i2c_client *dev, void *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
* @type: chip type, to initialize i2c_client.name
Expand Down Expand Up @@ -352,6 +376,8 @@ i2c_register_board_info(int busnum, struct i2c_board_info const *info,
* into I2C transfers instead.
* @functionality: Return the flags that this algorithm/adapter pair supports
* 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:
* i2c_algorithm is the interface to a class of hardware solutions which can
Expand All @@ -377,6 +403,9 @@ struct i2c_algorithm {

/* To determine what the adapter supports */
u32 (*functionality) (struct i2c_adapter *);

int (*reg_slave)(struct i2c_client *client);
int (*unreg_slave)(struct i2c_client *client);
};

/**
Expand Down

0 comments on commit 4b1acc4

Please sign in to comment.