mirror of https://gitee.com/openkylin/linux.git
mlxsw: i2c: Extend input parameters list of command API
Extend input parameters list of command API in mlxsw_i2c_cmd() in order to support initialization commands. Up until now, only access commands were supported by I2C driver. Signed-off-by: Vadim Pasternak <vadimp@mellanox.com> Acked-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
f43d9d9b4e
commit
95b75cbd1b
|
@ -20,8 +20,10 @@
|
|||
#define MLXSW_I2C_CIR2_OFF_STATUS (MLXSW_I2C_CIR2_BASE + \
|
||||
MLXSW_I2C_CIR_STATUS_OFF)
|
||||
#define MLXSW_I2C_OPMOD_SHIFT 12
|
||||
#define MLXSW_I2C_EVENT_BIT_SHIFT 22
|
||||
#define MLXSW_I2C_GO_BIT_SHIFT 23
|
||||
#define MLXSW_I2C_CIR_CTRL_STATUS_SHIFT 24
|
||||
#define MLXSW_I2C_EVENT_BIT BIT(MLXSW_I2C_EVENT_BIT_SHIFT)
|
||||
#define MLXSW_I2C_GO_BIT BIT(MLXSW_I2C_GO_BIT_SHIFT)
|
||||
#define MLXSW_I2C_GO_OPMODE BIT(MLXSW_I2C_OPMOD_SHIFT)
|
||||
#define MLXSW_I2C_SET_IMM_CMD (MLXSW_I2C_GO_OPMODE | \
|
||||
|
@ -33,6 +35,9 @@
|
|||
#define MLXSW_I2C_TLV_HDR_SIZE 0x10
|
||||
#define MLXSW_I2C_ADDR_WIDTH 4
|
||||
#define MLXSW_I2C_PUSH_CMD_SIZE (MLXSW_I2C_ADDR_WIDTH + 4)
|
||||
#define MLXSW_I2C_SET_EVENT_CMD (MLXSW_I2C_EVENT_BIT)
|
||||
#define MLXSW_I2C_PUSH_EVENT_CMD (MLXSW_I2C_GO_BIT | \
|
||||
MLXSW_I2C_SET_EVENT_CMD)
|
||||
#define MLXSW_I2C_READ_SEMA_SIZE 4
|
||||
#define MLXSW_I2C_PREP_SIZE (MLXSW_I2C_ADDR_WIDTH + 28)
|
||||
#define MLXSW_I2C_MBOX_SIZE 20
|
||||
|
@ -44,6 +49,7 @@
|
|||
#define MLXSW_I2C_BLK_MAX 32
|
||||
#define MLXSW_I2C_RETRY 5
|
||||
#define MLXSW_I2C_TIMEOUT_MSECS 5000
|
||||
#define MLXSW_I2C_MAX_DATA_SIZE 256
|
||||
|
||||
/**
|
||||
* struct mlxsw_i2c - device private data:
|
||||
|
@ -213,6 +219,66 @@ static int mlxsw_i2c_write_cmd(struct i2c_client *client,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Routine posts initialization command to ASIC through mail box. */
|
||||
static int
|
||||
mlxsw_i2c_write_init_cmd(struct i2c_client *client,
|
||||
struct mlxsw_i2c *mlxsw_i2c, u16 opcode, u32 in_mod)
|
||||
{
|
||||
__be32 push_cmd_buf[MLXSW_I2C_PUSH_CMD_SIZE / 4] = {
|
||||
0, cpu_to_be32(MLXSW_I2C_PUSH_EVENT_CMD)
|
||||
};
|
||||
__be32 prep_cmd_buf[MLXSW_I2C_PREP_SIZE / 4] = {
|
||||
0, 0, 0, 0, 0, 0,
|
||||
cpu_to_be32(client->adapter->nr & 0xffff),
|
||||
cpu_to_be32(MLXSW_I2C_SET_EVENT_CMD)
|
||||
};
|
||||
struct i2c_msg push_cmd =
|
||||
MLXSW_I2C_WRITE_MSG(client, push_cmd_buf,
|
||||
MLXSW_I2C_PUSH_CMD_SIZE);
|
||||
struct i2c_msg prep_cmd =
|
||||
MLXSW_I2C_WRITE_MSG(client, prep_cmd_buf, MLXSW_I2C_PREP_SIZE);
|
||||
u8 status;
|
||||
int err;
|
||||
|
||||
push_cmd_buf[1] = cpu_to_be32(MLXSW_I2C_PUSH_EVENT_CMD | opcode);
|
||||
prep_cmd_buf[3] = cpu_to_be32(in_mod);
|
||||
prep_cmd_buf[7] = cpu_to_be32(MLXSW_I2C_GO_BIT | opcode);
|
||||
mlxsw_i2c_set_slave_addr((u8 *)prep_cmd_buf,
|
||||
MLXSW_I2C_CIR2_BASE);
|
||||
mlxsw_i2c_set_slave_addr((u8 *)push_cmd_buf,
|
||||
MLXSW_I2C_CIR2_OFF_STATUS);
|
||||
|
||||
/* Prepare Command Interface Register for transaction */
|
||||
err = i2c_transfer(client->adapter, &prep_cmd, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
else if (err != 1)
|
||||
return -EIO;
|
||||
|
||||
/* Write out Command Interface Register GO bit to push transaction */
|
||||
err = i2c_transfer(client->adapter, &push_cmd, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
else if (err != 1)
|
||||
return -EIO;
|
||||
|
||||
/* Wait until go bit is cleared. */
|
||||
err = mlxsw_i2c_wait_go_bit(client, mlxsw_i2c, &status);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "HW semaphore is not released");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Validate transaction completion status. */
|
||||
if (status) {
|
||||
dev_err(&client->dev, "Bad transaction completion status %x\n",
|
||||
status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Routine obtains mail box offsets from ASIC register space. */
|
||||
static int mlxsw_i2c_get_mbox(struct i2c_client *client,
|
||||
struct mlxsw_i2c *mlxsw_i2c)
|
||||
|
@ -310,8 +376,8 @@ mlxsw_i2c_write(struct device *dev, size_t in_mbox_size, u8 *in_mbox, int num,
|
|||
|
||||
/* Routine executes I2C command. */
|
||||
static int
|
||||
mlxsw_i2c_cmd(struct device *dev, size_t in_mbox_size, u8 *in_mbox,
|
||||
size_t out_mbox_size, u8 *out_mbox, u8 *status)
|
||||
mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size,
|
||||
u8 *in_mbox, size_t out_mbox_size, u8 *out_mbox, u8 *status)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client);
|
||||
|
@ -326,24 +392,40 @@ mlxsw_i2c_cmd(struct device *dev, size_t in_mbox_size, u8 *in_mbox,
|
|||
|
||||
WARN_ON(in_mbox_size % sizeof(u32) || out_mbox_size % sizeof(u32));
|
||||
|
||||
reg_size = mlxsw_i2c_get_reg_size(in_mbox);
|
||||
num = reg_size / MLXSW_I2C_BLK_MAX;
|
||||
if (reg_size % MLXSW_I2C_BLK_MAX)
|
||||
num++;
|
||||
if (in_mbox) {
|
||||
reg_size = mlxsw_i2c_get_reg_size(in_mbox);
|
||||
num = reg_size / MLXSW_I2C_BLK_MAX;
|
||||
if (reg_size % MLXSW_I2C_BLK_MAX)
|
||||
num++;
|
||||
|
||||
if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) {
|
||||
dev_err(&client->dev, "Could not acquire lock");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) {
|
||||
dev_err(&client->dev, "Could not acquire lock");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = mlxsw_i2c_write(dev, reg_size, in_mbox, num, status);
|
||||
if (err)
|
||||
goto cmd_fail;
|
||||
err = mlxsw_i2c_write(dev, reg_size, in_mbox, num, status);
|
||||
if (err)
|
||||
goto cmd_fail;
|
||||
|
||||
/* No out mailbox is case of write transaction. */
|
||||
if (!out_mbox) {
|
||||
mutex_unlock(&mlxsw_i2c->cmd.lock);
|
||||
return 0;
|
||||
/* No out mailbox is case of write transaction. */
|
||||
if (!out_mbox) {
|
||||
mutex_unlock(&mlxsw_i2c->cmd.lock);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/* No input mailbox is case of initialization query command. */
|
||||
reg_size = MLXSW_I2C_MAX_DATA_SIZE;
|
||||
num = reg_size / MLXSW_I2C_BLK_MAX;
|
||||
|
||||
if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) {
|
||||
dev_err(&client->dev, "Could not acquire lock");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = mlxsw_i2c_write_init_cmd(client, mlxsw_i2c, opcode,
|
||||
in_mod);
|
||||
if (err)
|
||||
goto cmd_fail;
|
||||
}
|
||||
|
||||
/* Send read transaction to get output mailbox content. */
|
||||
|
@ -395,8 +477,8 @@ static int mlxsw_i2c_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod,
|
|||
{
|
||||
struct mlxsw_i2c *mlxsw_i2c = bus_priv;
|
||||
|
||||
return mlxsw_i2c_cmd(mlxsw_i2c->dev, in_mbox_size, in_mbox,
|
||||
out_mbox_size, out_mbox, status);
|
||||
return mlxsw_i2c_cmd(mlxsw_i2c->dev, opcode, in_mod, in_mbox_size,
|
||||
in_mbox, out_mbox_size, out_mbox, status);
|
||||
}
|
||||
|
||||
static bool mlxsw_i2c_skb_transmit_busy(void *bus_priv,
|
||||
|
|
Loading…
Reference in New Issue