/* Driver can be initialized by kernel platform driver or from the user * space. In the first case IRQ line number is passed through the platform * data, otherwise default IRQ line is to be used. Default IRQ is relevant * only for specific I2C slave address, allowing 3.4 MHz I2C path to the chip * (special hardware feature for I2C acceleration).
*/ #define MLXSW_I2C_DEFAULT_IRQ 17 #define MLXSW_FAST_I2C_SLAVE 0x37
/* Write out Command Interface Register GO bit to push transaction */
err = i2c_transfer(client->adapter, &push_cmd, 1); if (err < 0) return err; elseif (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;
}
/* Read mail boxes offsets. */
mlxsw_i2c_set_slave_addr(addr_buf, MLXSW_I2C_CIR2_BASE);
err = i2c_transfer(client->adapter, mbox_cmd, 2); if (err != 2) {
dev_err(&client->dev, "Could not obtain mail boxes\n"); if (!err) return -EIO; else return err;
}
/* Convert mail boxes. */
mlxsw_i2c_convert_mbox(mlxsw_i2c, &buf[MLXSW_I2C_MBOX_OUT_PARAM_OFF]);
return err;
}
/* Routine sends I2C write transaction to ASIC device. */ staticint
mlxsw_i2c_write(struct device *dev, size_t in_mbox_size, u8 *in_mbox, int num,
u8 *p_status)
{ struct i2c_client *client = to_i2c_client(dev); struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client); unsignedlong timeout = msecs_to_jiffies(MLXSW_I2C_TIMEOUT_MSECS); int off = mlxsw_i2c->cmd.mb_off_in, chunk_size, i, j; unsignedlong end;
u8 *tran_buf; struct i2c_msg write_tran =
MLXSW_I2C_WRITE_MSG(client, NULL, MLXSW_I2C_PUSH_CMD_SIZE); int err;
tran_buf = kmalloc(mlxsw_i2c->block_size + MLXSW_I2C_ADDR_BUF_SIZE,
GFP_KERNEL); if (!tran_buf) return -ENOMEM;
write_tran.buf = tran_buf; for (i = 0; i < num; i++) {
chunk_size = (in_mbox_size > mlxsw_i2c->block_size) ?
mlxsw_i2c->block_size : in_mbox_size;
write_tran.len = MLXSW_I2C_ADDR_WIDTH + chunk_size;
mlxsw_i2c_set_slave_addr(tran_buf, off);
memcpy(&tran_buf[MLXSW_I2C_ADDR_BUF_SIZE], in_mbox +
mlxsw_i2c->block_size * i, chunk_size);
j = 0;
end = jiffies + timeout; do {
err = i2c_transfer(client->adapter, &write_tran, 1); if (err == 1) break;
cond_resched();
} while ((time_before(jiffies, end)) ||
(j++ < MLXSW_I2C_RETRY));
if (err != 1) { if (!err) {
err = -EIO; goto mlxsw_i2c_write_exit;
}
}
off += chunk_size;
in_mbox_size -= chunk_size;
}
/* Prepare and write out Command Interface Register for transaction. */
err = mlxsw_i2c_write_cmd(client, mlxsw_i2c, 0); if (err) {
dev_err(&client->dev, "Could not start transaction");
err = -EIO; goto mlxsw_i2c_write_exit;
}
/* Wait until go bit is cleared. */
err = mlxsw_i2c_wait_go_bit(client, mlxsw_i2c, p_status); if (err) {
dev_err(&client->dev, "HW semaphore is not released"); goto mlxsw_i2c_write_exit;
}
/* Validate transaction completion status. */ if (*p_status) {
dev_err(&client->dev, "Bad transaction completion status %x\n",
*p_status);
err = -EIO;
}
/* 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 = DIV_ROUND_UP(reg_size, mlxsw_i2c->block_size);
if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) {
dev_err(&client->dev, "Could not acquire lock"); return -EINVAL;
}
/* Interrupt handler shares IRQ line with 'main' interrupt handler. * Return here IRQ_NONE, while main handler will return IRQ_HANDLED.
*/ return IRQ_NONE;
}
staticint mlxsw_i2c_irq_init(struct mlxsw_i2c *mlxsw_i2c, u8 addr)
{ int err;
/* Initialize interrupt handler if system hotplug driver is reachable, * otherwise interrupt line is not enabled and interrupts will not be * raised to CPU. Also request_irq() call will be not valid.
*/ if (!IS_REACHABLE(CONFIG_MLXREG_HOTPLUG)) return 0;
/* Set default interrupt line. */ if (mlxsw_i2c->pdata && mlxsw_i2c->pdata->irq)
mlxsw_i2c->irq = mlxsw_i2c->pdata->irq; elseif (addr == MLXSW_FAST_I2C_SLAVE)
mlxsw_i2c->irq = MLXSW_I2C_DEFAULT_IRQ;
/* In order to use mailboxes through the i2c, special area is reserved * on the i2c address space that can be used for input and output * mailboxes. Such mailboxes are called local mailboxes. When using a * local mailbox, software should specify 0 as the Input/Output * parameters. The location of the Local Mailbox addresses on the i2c * space can be retrieved through the QUERY_FW command. * For this purpose QUERY_FW is to be issued with opcode modifier equal * 0x01. For such command the output parameter is an immediate value. * Here QUERY_FW command is invoked for ASIC probing and for getting * local mailboxes addresses from immedate output parameters.
*/
/* Prepare and write out Command Interface Register for transaction */
err = mlxsw_i2c_write_cmd(client, mlxsw_i2c, 1); if (err) {
dev_err(&client->dev, "Could not start transaction"); goto errout;
}
/* 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"); goto errout;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.