MLK-20342 i2c: xen-i2cback/front: Add i2c_smbus interface
Add smbus_xfer interface in xen-i2cback/front driver. Reviewed-by: Peng Fan <peng.fan@nxp.com> Signed-off-by: Flynn xu <flynn.xu@nxp.com>pull/10/head
parent
7c114c457a
commit
90e818a0ab
|
@ -47,6 +47,15 @@ static bool i2cback_access_allowed(struct i2cback_info *info,
|
|||
{
|
||||
int i;
|
||||
|
||||
if (req->is_smbus) {/*check for smbus access permission*/
|
||||
for (i = 0; i < info->num_slaves; i++)
|
||||
if (req->addr == info->allowed_slaves[i])
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*check for master_xfer access permission*/
|
||||
if (req->num_msg == I2CIF_MAX_MSG) {
|
||||
if (req->msg[0].addr != req->msg[1].addr)
|
||||
return false;
|
||||
|
@ -68,6 +77,7 @@ static bool i2cback_handle_int(struct i2cback_info *info)
|
|||
RING_IDX rc, rp;
|
||||
int more_to_do, notify, num_msg = 0, ret;
|
||||
struct i2c_msg msg[I2CIF_MAX_MSG];
|
||||
union i2c_smbus_data smbus_data;
|
||||
char tmp_buf[I2CIF_BUF_LEN];
|
||||
unsigned long flags;
|
||||
bool allow_access;
|
||||
|
@ -92,7 +102,7 @@ static bool i2cback_handle_int(struct i2cback_info *info)
|
|||
|
||||
req = *RING_GET_REQUEST(i2c_ring, rc);
|
||||
allow_access = i2cback_access_allowed(info, &req);
|
||||
if (allow_access) {
|
||||
if (allow_access && !req.is_smbus) {
|
||||
/* Write/Read sequence */
|
||||
num_msg = req.num_msg;
|
||||
if (num_msg > I2CIF_MAX_MSG)
|
||||
|
@ -144,13 +154,23 @@ static bool i2cback_handle_int(struct i2cback_info *info)
|
|||
|
||||
ret = -EIO;
|
||||
}
|
||||
} else if (allow_access && req.is_smbus) {
|
||||
memcpy(&smbus_data, &req.write_buf, sizeof(smbus_data));
|
||||
|
||||
ret = i2c_smbus_xfer(info->adapter,
|
||||
req.addr,
|
||||
req.flags,
|
||||
req.read_write,
|
||||
req.command,
|
||||
req.protocol,
|
||||
&smbus_data);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&info->i2c_ring_lock, flags);
|
||||
res = RING_GET_RESPONSE(&info->i2c_ring,
|
||||
info->i2c_ring.rsp_prod_pvt);
|
||||
|
||||
if (allow_access) {
|
||||
if (allow_access && !req.is_smbus) {
|
||||
res->result = ret;
|
||||
|
||||
if ((req.num_msg == 2) &&
|
||||
|
@ -162,6 +182,10 @@ static bool i2cback_handle_int(struct i2cback_info *info)
|
|||
memcpy(res->read_buf, tmp_buf,
|
||||
I2CIF_BUF_LEN);
|
||||
}
|
||||
} else if (allow_access && req.is_smbus) {
|
||||
if (req.read_write == I2C_SMBUS_READ)
|
||||
memcpy(&res->read_buf, &smbus_data, sizeof(smbus_data));
|
||||
res->result = ret;
|
||||
} else
|
||||
res->result = -EPERM;
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ static int i2cfront_do_req(struct i2c_adapter *adapter, struct i2c_msg *msg,
|
|||
for (index = 0; index < num; index++) {
|
||||
req->msg[index].addr = msg[index].addr;
|
||||
req->msg[index].len = msg[index].len;
|
||||
req->msg[index].flags = 0;
|
||||
req->msg[index].flags = 0;
|
||||
if (msg[index].flags & I2C_M_RD)
|
||||
req->msg[index].flags |= I2CIF_M_RD;
|
||||
if (msg[index].flags & I2C_M_TEN)
|
||||
|
@ -96,6 +96,7 @@ static int i2cfront_do_req(struct i2c_adapter *adapter, struct i2c_msg *msg,
|
|||
}
|
||||
|
||||
req->num_msg = num;
|
||||
req->is_smbus = false;
|
||||
|
||||
if ((num == 2) && !(msg[0].flags & I2C_M_RD) &&
|
||||
(msg[1].flags & I2C_M_RD)) {
|
||||
|
@ -186,13 +187,87 @@ err:
|
|||
return (ret < 0) ? ret : num;
|
||||
}
|
||||
|
||||
static int i2cfront_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size, union i2c_smbus_data *data)
|
||||
{
|
||||
struct i2cfront_info *info = i2c_get_adapdata(adapter);
|
||||
struct i2cif_response *res;
|
||||
struct i2cif_request *req;
|
||||
int more_to_do = 0;
|
||||
RING_IDX i, rp;
|
||||
int notify;
|
||||
int ret;
|
||||
|
||||
if (!info || !info->i2cdev) {
|
||||
dev_err(&adapter->dev, "Not initialized\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (info->i2cdev->state != XenbusStateConnected) {
|
||||
dev_err(&adapter->dev, "Not connected\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
mutex_lock(&info->xferlock);
|
||||
req = RING_GET_REQUEST(&info->i2c_ring, info->i2c_ring.req_prod_pvt);
|
||||
|
||||
req->is_smbus = true;
|
||||
req->addr = addr;
|
||||
req->flags = flags;
|
||||
req->read_write = read_write;
|
||||
req->command = command;
|
||||
req->protocol = size;
|
||||
if (data != NULL)
|
||||
memcpy(&req->write_buf, data, sizeof(union i2c_smbus_data));
|
||||
|
||||
spin_lock(&info->lock);
|
||||
info->i2c_ring.req_prod_pvt++;
|
||||
RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->i2c_ring, notify);
|
||||
spin_unlock(&info->lock);
|
||||
if (notify)
|
||||
notify_remote_via_irq(info->irq);
|
||||
|
||||
wait_for_completion(&info->completion);
|
||||
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
rp = info->i2c_ring.sring->rsp_prod;
|
||||
rmb(); /* ensure we see queued responses up to "rp" */
|
||||
|
||||
ret = -EIO;
|
||||
for (i = info->i2c_ring.rsp_cons; i != rp; i++) {
|
||||
res = RING_GET_RESPONSE(&info->i2c_ring, i);
|
||||
|
||||
if (data != NULL && read_write == I2C_SMBUS_READ)
|
||||
memcpy(data, &res->read_buf, sizeof(union i2c_smbus_data));
|
||||
|
||||
ret = res->result;
|
||||
}
|
||||
|
||||
info->i2c_ring.rsp_cons = i;
|
||||
|
||||
if (i != info->i2c_ring.req_prod_pvt)
|
||||
RING_FINAL_CHECK_FOR_RESPONSES(&info->i2c_ring, more_to_do);
|
||||
else
|
||||
info->i2c_ring.sring->rsp_event = i + 1;
|
||||
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
|
||||
mutex_unlock(&info->xferlock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 i2cfront_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_WORD_DATA |
|
||||
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_I2C_BLOCK;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm i2cfront_algo = {
|
||||
.master_xfer = i2cfront_xfer,
|
||||
.smbus_xfer = i2cfront_smbus_xfer,
|
||||
.functionality = i2cfront_func,
|
||||
};
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include <xen/interface/io/ring.h>
|
||||
#include <xen/interface/grant_table.h>
|
||||
|
||||
#define I2CIF_BUF_LEN 32
|
||||
#define I2CIF_BUF_LEN I2C_SMBUS_BLOCK_MAX + 2
|
||||
#define I2CIF_MAX_MSG 2
|
||||
|
||||
#define I2CIF_M_RD 0x0001 /* read data, from slave to master */
|
||||
|
@ -76,6 +76,13 @@ struct i2cif_request {
|
|||
} msg[I2CIF_MAX_MSG];
|
||||
int num_msg;
|
||||
__u8 write_buf[I2CIF_BUF_LEN];
|
||||
|
||||
bool is_smbus;
|
||||
__u16 addr;
|
||||
__u16 flags;
|
||||
__u8 read_write;
|
||||
__u8 command;
|
||||
int protocol;
|
||||
};
|
||||
|
||||
struct i2cif_response {
|
||||
|
|
Loading…
Reference in New Issue