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);
|
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
|
* SPD is not part of SMBus but we include it here for convenience as the
|
||||||
* target systems are the same.
|
* target systems are the same.
|
||||||
|
|
|
@ -38,6 +38,18 @@ static inline int of_i2c_setup_smbus_alert(struct i2c_adapter *adap)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#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)
|
#if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_DMI)
|
||||||
void i2c_register_spd(struct i2c_adapter *adap);
|
void i2c_register_spd(struct i2c_adapter *adap);
|
||||||
|
|
Loading…
Add table
Reference in a new issue