Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+49 −0
Original line number Diff line number Diff line
@@ -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>
@@ -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 −0
Original line number Diff line number Diff line
@@ -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;

@@ -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
@@ -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)

@@ -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
@@ -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
@@ -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);
};

/**