mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	i2c: smbus: add core function handling SMBus host-notify
SMBus Host-Notify protocol, from the adapter point of view consist of receiving a message from a client, including the client address and some other data. It can be simply handled by creating a new slave device and registering a callback performing the parsing of the message received from the client. This commit introduces two new core functions * i2c_new_slave_host_notify_device * i2c_free_slave_host_notify_device that take care of registration of the new slave device and callback and will call i2c_handle_smbus_host_notify once a Host-Notify event is received. Signed-off-by: Alain Volmat <alain.volmat@st.com> Reviewed-by: Pierre-Yves MORDRET <pierre-yves.mordret@st.com> Signed-off-by: Wolfram Sang <wsa@kernel.org>
This commit is contained in:
		
							parent
							
								
									e6277308ac
								
							
						
					
					
						commit
						2a71593da3
					
				
					 2 changed files with 119 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -197,6 +197,113 @@ EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert);
 | 
			
		|||
 | 
			
		||||
module_i2c_driver(smbalert_driver);
 | 
			
		||||
 | 
			
		||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
 | 
			
		||||
#define SMBUS_HOST_NOTIFY_LEN	3
 | 
			
		||||
struct i2c_slave_host_notify_status {
 | 
			
		||||
	u8 index;
 | 
			
		||||
	u8 addr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int i2c_slave_host_notify_cb(struct i2c_client *client,
 | 
			
		||||
				    enum i2c_slave_event event, u8 *val)
 | 
			
		||||
{
 | 
			
		||||
	struct i2c_slave_host_notify_status *status = client->dev.platform_data;
 | 
			
		||||
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case I2C_SLAVE_WRITE_RECEIVED:
 | 
			
		||||
		/* We only retrieve the first byte received (addr)
 | 
			
		||||
		 * since there is currently no support to retrieve the data
 | 
			
		||||
		 * parameter from the client.
 | 
			
		||||
		 */
 | 
			
		||||
		if (status->index == 0)
 | 
			
		||||
			status->addr = *val;
 | 
			
		||||
		if (status->index < U8_MAX)
 | 
			
		||||
			status->index++;
 | 
			
		||||
		break;
 | 
			
		||||
	case I2C_SLAVE_STOP:
 | 
			
		||||
		if (status->index == SMBUS_HOST_NOTIFY_LEN)
 | 
			
		||||
			i2c_handle_smbus_host_notify(client->adapter,
 | 
			
		||||
						     status->addr);
 | 
			
		||||
		fallthrough;
 | 
			
		||||
	case I2C_SLAVE_WRITE_REQUESTED:
 | 
			
		||||
		status->index = 0;
 | 
			
		||||
		break;
 | 
			
		||||
	case I2C_SLAVE_READ_REQUESTED:
 | 
			
		||||
	case I2C_SLAVE_READ_PROCESSED:
 | 
			
		||||
		*val = 0xff;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * i2c_new_slave_host_notify_device - get a client for SMBus host-notify support
 | 
			
		||||
 * @adapter: the target adapter
 | 
			
		||||
 * Context: can sleep
 | 
			
		||||
 *
 | 
			
		||||
 * Setup handling of the SMBus host-notify protocol on a given I2C bus segment.
 | 
			
		||||
 *
 | 
			
		||||
 * Handling is done by creating a device and its callback and handling data
 | 
			
		||||
 * received via the SMBus host-notify address (0x8)
 | 
			
		||||
 *
 | 
			
		||||
 * This returns the client, which should be ultimately freed using
 | 
			
		||||
 * i2c_free_slave_host_notify_device(); or an ERRPTR to indicate an error.
 | 
			
		||||
 */
 | 
			
		||||
struct i2c_client *i2c_new_slave_host_notify_device(struct i2c_adapter *adapter)
 | 
			
		||||
{
 | 
			
		||||
	struct i2c_board_info host_notify_board_info = {
 | 
			
		||||
		I2C_BOARD_INFO("smbus_host_notify", 0x08),
 | 
			
		||||
		.flags  = I2C_CLIENT_SLAVE,
 | 
			
		||||
	};
 | 
			
		||||
	struct i2c_slave_host_notify_status *status;
 | 
			
		||||
	struct i2c_client *client;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	status = kzalloc(sizeof(struct i2c_slave_host_notify_status),
 | 
			
		||||
			 GFP_KERNEL);
 | 
			
		||||
	if (!status)
 | 
			
		||||
		return ERR_PTR(-ENOMEM);
 | 
			
		||||
 | 
			
		||||
	host_notify_board_info.platform_data = status;
 | 
			
		||||
 | 
			
		||||
	client = i2c_new_client_device(adapter, &host_notify_board_info);
 | 
			
		||||
	if (IS_ERR(client)) {
 | 
			
		||||
		kfree(status);
 | 
			
		||||
		return client;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = i2c_slave_register(client, i2c_slave_host_notify_cb);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		i2c_unregister_device(client);
 | 
			
		||||
		kfree(status);
 | 
			
		||||
		return ERR_PTR(ret);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return client;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(i2c_new_slave_host_notify_device);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * i2c_free_slave_host_notify_device - free the client for SMBus host-notify
 | 
			
		||||
 * support
 | 
			
		||||
 * @client: the client to free
 | 
			
		||||
 * Context: can sleep
 | 
			
		||||
 *
 | 
			
		||||
 * Free the i2c_client allocated via i2c_new_slave_host_notify_device
 | 
			
		||||
 */
 | 
			
		||||
void i2c_free_slave_host_notify_device(struct i2c_client *client)
 | 
			
		||||
{
 | 
			
		||||
	if (IS_ERR_OR_NULL(client))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	i2c_slave_unregister(client);
 | 
			
		||||
	kfree(client->dev.platform_data);
 | 
			
		||||
	i2c_unregister_device(client);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(i2c_free_slave_host_notify_device);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * SPD is not part of SMBus but we include it here for convenience as the
 | 
			
		||||
 * target systems are the same.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,6 +38,18 @@ static inline int of_i2c_setup_smbus_alert(struct i2c_adapter *adap)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
#if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_I2C_SLAVE)
 | 
			
		||||
struct i2c_client *i2c_new_slave_host_notify_device(struct i2c_adapter *adapter);
 | 
			
		||||
void i2c_free_slave_host_notify_device(struct i2c_client *client);
 | 
			
		||||
#else
 | 
			
		||||
static inline struct i2c_client *i2c_new_slave_host_notify_device(struct i2c_adapter *adapter)
 | 
			
		||||
{
 | 
			
		||||
	return ERR_PTR(-ENOSYS);
 | 
			
		||||
}
 | 
			
		||||
static inline void i2c_free_slave_host_notify_device(struct i2c_client *client)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_DMI)
 | 
			
		||||
void i2c_register_spd(struct i2c_adapter *adap);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue