1
0
Fork 0

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
Flynn xu 2018-11-13 17:46:50 +08:00
parent 7c114c457a
commit 90e818a0ab
3 changed files with 111 additions and 5 deletions

View File

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

View File

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

View File

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