162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Mellanox i2c driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2016-2020 Mellanox Technologies 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/delay.h> 962306a36Sopenharmony_ci#include <linux/i2c.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/io.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/platform_data/mlxreg.h> 1562306a36Sopenharmony_ci#include <linux/platform_device.h> 1662306a36Sopenharmony_ci#include <linux/regmap.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* General defines */ 1962306a36Sopenharmony_ci#define MLXPLAT_CPLD_LPC_I2C_BASE_ADDR 0x2000 2062306a36Sopenharmony_ci#define MLXCPLD_I2C_DEVICE_NAME "i2c_mlxcpld" 2162306a36Sopenharmony_ci#define MLXCPLD_I2C_VALID_FLAG (I2C_M_RECV_LEN | I2C_M_RD) 2262306a36Sopenharmony_ci#define MLXCPLD_I2C_BUS_NUM 1 2362306a36Sopenharmony_ci#define MLXCPLD_I2C_DATA_REG_SZ 36 2462306a36Sopenharmony_ci#define MLXCPLD_I2C_DATA_SZ_BIT BIT(5) 2562306a36Sopenharmony_ci#define MLXCPLD_I2C_DATA_EXT2_SZ_BIT BIT(6) 2662306a36Sopenharmony_ci#define MLXCPLD_I2C_DATA_SZ_MASK GENMASK(6, 5) 2762306a36Sopenharmony_ci#define MLXCPLD_I2C_SMBUS_BLK_BIT BIT(7) 2862306a36Sopenharmony_ci#define MLXCPLD_I2C_MAX_ADDR_LEN 4 2962306a36Sopenharmony_ci#define MLXCPLD_I2C_RETR_NUM 2 3062306a36Sopenharmony_ci#define MLXCPLD_I2C_XFER_TO 500000 /* usec */ 3162306a36Sopenharmony_ci#define MLXCPLD_I2C_POLL_TIME 200 /* usec */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* LPC I2C registers */ 3462306a36Sopenharmony_ci#define MLXCPLD_LPCI2C_CPBLTY_REG 0x0 3562306a36Sopenharmony_ci#define MLXCPLD_LPCI2C_CTRL_REG 0x1 3662306a36Sopenharmony_ci#define MLXCPLD_LPCI2C_HALF_CYC_REG 0x4 3762306a36Sopenharmony_ci#define MLXCPLD_LPCI2C_I2C_HOLD_REG 0x5 3862306a36Sopenharmony_ci#define MLXCPLD_LPCI2C_CMD_REG 0x6 3962306a36Sopenharmony_ci#define MLXCPLD_LPCI2C_NUM_DAT_REG 0x7 4062306a36Sopenharmony_ci#define MLXCPLD_LPCI2C_NUM_ADDR_REG 0x8 4162306a36Sopenharmony_ci#define MLXCPLD_LPCI2C_STATUS_REG 0x9 4262306a36Sopenharmony_ci#define MLXCPLD_LPCI2C_DATA_REG 0xa 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* LPC I2C masks and parameters */ 4562306a36Sopenharmony_ci#define MLXCPLD_LPCI2C_RST_SEL_MASK 0x1 4662306a36Sopenharmony_ci#define MLXCPLD_LPCI2C_TRANS_END 0x1 4762306a36Sopenharmony_ci#define MLXCPLD_LPCI2C_STATUS_NACK 0x10 4862306a36Sopenharmony_ci#define MLXCPLD_LPCI2C_NO_IND 0 4962306a36Sopenharmony_ci#define MLXCPLD_LPCI2C_ACK_IND 1 5062306a36Sopenharmony_ci#define MLXCPLD_LPCI2C_NACK_IND 2 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define MLXCPLD_I2C_FREQ_1000KHZ_SET 0x04 5362306a36Sopenharmony_ci#define MLXCPLD_I2C_FREQ_400KHZ_SET 0x0e 5462306a36Sopenharmony_ci#define MLXCPLD_I2C_FREQ_100KHZ_SET 0x42 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cienum mlxcpld_i2c_frequency { 5762306a36Sopenharmony_ci MLXCPLD_I2C_FREQ_1000KHZ = 1, 5862306a36Sopenharmony_ci MLXCPLD_I2C_FREQ_400KHZ = 2, 5962306a36Sopenharmony_ci MLXCPLD_I2C_FREQ_100KHZ = 3, 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistruct mlxcpld_i2c_curr_xfer { 6362306a36Sopenharmony_ci u8 cmd; 6462306a36Sopenharmony_ci u8 addr_width; 6562306a36Sopenharmony_ci u8 data_len; 6662306a36Sopenharmony_ci u8 msg_num; 6762306a36Sopenharmony_ci struct i2c_msg *msg; 6862306a36Sopenharmony_ci}; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistruct mlxcpld_i2c_priv { 7162306a36Sopenharmony_ci struct i2c_adapter adap; 7262306a36Sopenharmony_ci u32 base_addr; 7362306a36Sopenharmony_ci struct mutex lock; 7462306a36Sopenharmony_ci struct mlxcpld_i2c_curr_xfer xfer; 7562306a36Sopenharmony_ci struct device *dev; 7662306a36Sopenharmony_ci bool smbus_block; 7762306a36Sopenharmony_ci int polling_time; 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic void mlxcpld_i2c_lpc_write_buf(u8 *data, u8 len, u32 addr) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci int i; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci for (i = 0; i < len - len % 4; i += 4) 8562306a36Sopenharmony_ci outl(*(u32 *)(data + i), addr + i); 8662306a36Sopenharmony_ci for (; i < len; ++i) 8762306a36Sopenharmony_ci outb(*(data + i), addr + i); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic void mlxcpld_i2c_lpc_read_buf(u8 *data, u8 len, u32 addr) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci int i; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci for (i = 0; i < len - len % 4; i += 4) 9562306a36Sopenharmony_ci *(u32 *)(data + i) = inl(addr + i); 9662306a36Sopenharmony_ci for (; i < len; ++i) 9762306a36Sopenharmony_ci *(data + i) = inb(addr + i); 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic void mlxcpld_i2c_read_comm(struct mlxcpld_i2c_priv *priv, u8 offs, 10162306a36Sopenharmony_ci u8 *data, u8 datalen) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci u32 addr = priv->base_addr + offs; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci switch (datalen) { 10662306a36Sopenharmony_ci case 1: 10762306a36Sopenharmony_ci *(data) = inb(addr); 10862306a36Sopenharmony_ci break; 10962306a36Sopenharmony_ci case 2: 11062306a36Sopenharmony_ci *((u16 *)data) = inw(addr); 11162306a36Sopenharmony_ci break; 11262306a36Sopenharmony_ci case 3: 11362306a36Sopenharmony_ci *((u16 *)data) = inw(addr); 11462306a36Sopenharmony_ci *(data + 2) = inb(addr + 2); 11562306a36Sopenharmony_ci break; 11662306a36Sopenharmony_ci case 4: 11762306a36Sopenharmony_ci *((u32 *)data) = inl(addr); 11862306a36Sopenharmony_ci break; 11962306a36Sopenharmony_ci default: 12062306a36Sopenharmony_ci mlxcpld_i2c_lpc_read_buf(data, datalen, addr); 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic void mlxcpld_i2c_write_comm(struct mlxcpld_i2c_priv *priv, u8 offs, 12662306a36Sopenharmony_ci u8 *data, u8 datalen) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci u32 addr = priv->base_addr + offs; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci switch (datalen) { 13162306a36Sopenharmony_ci case 1: 13262306a36Sopenharmony_ci outb(*(data), addr); 13362306a36Sopenharmony_ci break; 13462306a36Sopenharmony_ci case 2: 13562306a36Sopenharmony_ci outw(*((u16 *)data), addr); 13662306a36Sopenharmony_ci break; 13762306a36Sopenharmony_ci case 3: 13862306a36Sopenharmony_ci outw(*((u16 *)data), addr); 13962306a36Sopenharmony_ci outb(*(data + 2), addr + 2); 14062306a36Sopenharmony_ci break; 14162306a36Sopenharmony_ci case 4: 14262306a36Sopenharmony_ci outl(*((u32 *)data), addr); 14362306a36Sopenharmony_ci break; 14462306a36Sopenharmony_ci default: 14562306a36Sopenharmony_ci mlxcpld_i2c_lpc_write_buf(data, datalen, addr); 14662306a36Sopenharmony_ci break; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/* 15162306a36Sopenharmony_ci * Check validity of received i2c messages parameters. 15262306a36Sopenharmony_ci * Returns 0 if OK, other - in case of invalid parameters. 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_cistatic int mlxcpld_i2c_check_msg_params(struct mlxcpld_i2c_priv *priv, 15562306a36Sopenharmony_ci struct i2c_msg *msgs, int num) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci int i; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (!num) { 16062306a36Sopenharmony_ci dev_err(priv->dev, "Incorrect 0 num of messages\n"); 16162306a36Sopenharmony_ci return -EINVAL; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (unlikely(msgs[0].addr > 0x7f)) { 16562306a36Sopenharmony_ci dev_err(priv->dev, "Invalid address 0x%03x\n", 16662306a36Sopenharmony_ci msgs[0].addr); 16762306a36Sopenharmony_ci return -EINVAL; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci for (i = 0; i < num; ++i) { 17162306a36Sopenharmony_ci if (unlikely(!msgs[i].buf)) { 17262306a36Sopenharmony_ci dev_err(priv->dev, "Invalid buf in msg[%d]\n", 17362306a36Sopenharmony_ci i); 17462306a36Sopenharmony_ci return -EINVAL; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci if (unlikely(msgs[0].addr != msgs[i].addr)) { 17762306a36Sopenharmony_ci dev_err(priv->dev, "Invalid addr in msg[%d]\n", 17862306a36Sopenharmony_ci i); 17962306a36Sopenharmony_ci return -EINVAL; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci return 0; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/* 18762306a36Sopenharmony_ci * Check if transfer is completed and status of operation. 18862306a36Sopenharmony_ci * Returns 0 - transfer completed (both ACK or NACK), 18962306a36Sopenharmony_ci * negative - transfer isn't finished. 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_cistatic int mlxcpld_i2c_check_status(struct mlxcpld_i2c_priv *priv, int *status) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci u8 val; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_STATUS_REG, &val, 1); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (val & MLXCPLD_LPCI2C_TRANS_END) { 19862306a36Sopenharmony_ci if (val & MLXCPLD_LPCI2C_STATUS_NACK) 19962306a36Sopenharmony_ci /* 20062306a36Sopenharmony_ci * The slave is unable to accept the data. No such 20162306a36Sopenharmony_ci * slave, command not understood, or unable to accept 20262306a36Sopenharmony_ci * any more data. 20362306a36Sopenharmony_ci */ 20462306a36Sopenharmony_ci *status = MLXCPLD_LPCI2C_NACK_IND; 20562306a36Sopenharmony_ci else 20662306a36Sopenharmony_ci *status = MLXCPLD_LPCI2C_ACK_IND; 20762306a36Sopenharmony_ci return 0; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci *status = MLXCPLD_LPCI2C_NO_IND; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci return -EIO; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic void mlxcpld_i2c_set_transf_data(struct mlxcpld_i2c_priv *priv, 21562306a36Sopenharmony_ci struct i2c_msg *msgs, int num, 21662306a36Sopenharmony_ci u8 comm_len) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci priv->xfer.msg = msgs; 21962306a36Sopenharmony_ci priv->xfer.msg_num = num; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* 22262306a36Sopenharmony_ci * All upper layers currently are never use transfer with more than 22362306a36Sopenharmony_ci * 2 messages. Actually, it's also not so relevant in Mellanox systems 22462306a36Sopenharmony_ci * because of HW limitation. Max size of transfer is not more than 32 22562306a36Sopenharmony_ci * or 68 bytes in the current x86 LPCI2C bridge. 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_ci priv->xfer.cmd = msgs[num - 1].flags & I2C_M_RD; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (priv->xfer.cmd == I2C_M_RD && comm_len != msgs[0].len) { 23062306a36Sopenharmony_ci priv->xfer.addr_width = msgs[0].len; 23162306a36Sopenharmony_ci priv->xfer.data_len = comm_len - priv->xfer.addr_width; 23262306a36Sopenharmony_ci } else { 23362306a36Sopenharmony_ci priv->xfer.addr_width = 0; 23462306a36Sopenharmony_ci priv->xfer.data_len = comm_len; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci/* Reset CPLD LPCI2C block */ 23962306a36Sopenharmony_cistatic void mlxcpld_i2c_reset(struct mlxcpld_i2c_priv *priv) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci u8 val; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci mutex_lock(&priv->lock); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_CTRL_REG, &val, 1); 24662306a36Sopenharmony_ci val &= ~MLXCPLD_LPCI2C_RST_SEL_MASK; 24762306a36Sopenharmony_ci mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_CTRL_REG, &val, 1); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci mutex_unlock(&priv->lock); 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci/* Make sure the CPLD is ready to start transmitting. */ 25362306a36Sopenharmony_cistatic int mlxcpld_i2c_check_busy(struct mlxcpld_i2c_priv *priv) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci u8 val; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_STATUS_REG, &val, 1); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (val & MLXCPLD_LPCI2C_TRANS_END) 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return -EIO; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic int mlxcpld_i2c_wait_for_free(struct mlxcpld_i2c_priv *priv) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci int timeout = 0; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci do { 27062306a36Sopenharmony_ci if (!mlxcpld_i2c_check_busy(priv)) 27162306a36Sopenharmony_ci break; 27262306a36Sopenharmony_ci usleep_range(priv->polling_time / 2, priv->polling_time); 27362306a36Sopenharmony_ci timeout += priv->polling_time; 27462306a36Sopenharmony_ci } while (timeout <= MLXCPLD_I2C_XFER_TO); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (timeout > MLXCPLD_I2C_XFER_TO) 27762306a36Sopenharmony_ci return -ETIMEDOUT; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci return 0; 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci/* 28362306a36Sopenharmony_ci * Wait for master transfer to complete. 28462306a36Sopenharmony_ci * It puts current process to sleep until we get interrupt or timeout expires. 28562306a36Sopenharmony_ci * Returns the number of transferred or read bytes or error (<0). 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_cistatic int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci int status, i, timeout = 0; 29062306a36Sopenharmony_ci u8 datalen, val; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci do { 29362306a36Sopenharmony_ci usleep_range(priv->polling_time / 2, priv->polling_time); 29462306a36Sopenharmony_ci if (!mlxcpld_i2c_check_status(priv, &status)) 29562306a36Sopenharmony_ci break; 29662306a36Sopenharmony_ci timeout += priv->polling_time; 29762306a36Sopenharmony_ci } while (status == 0 && timeout < MLXCPLD_I2C_XFER_TO); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci switch (status) { 30062306a36Sopenharmony_ci case MLXCPLD_LPCI2C_NO_IND: 30162306a36Sopenharmony_ci return -ETIMEDOUT; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci case MLXCPLD_LPCI2C_ACK_IND: 30462306a36Sopenharmony_ci if (priv->xfer.cmd != I2C_M_RD) 30562306a36Sopenharmony_ci return (priv->xfer.addr_width + priv->xfer.data_len); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (priv->xfer.msg_num == 1) 30862306a36Sopenharmony_ci i = 0; 30962306a36Sopenharmony_ci else 31062306a36Sopenharmony_ci i = 1; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (!priv->xfer.msg[i].buf) 31362306a36Sopenharmony_ci return -EINVAL; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* 31662306a36Sopenharmony_ci * Actual read data len will be always the same as 31762306a36Sopenharmony_ci * requested len. 0xff (line pull-up) will be returned 31862306a36Sopenharmony_ci * if slave has no data to return. Thus don't read 31962306a36Sopenharmony_ci * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD. Only in case of 32062306a36Sopenharmony_ci * SMBus block read transaction data len can be different, 32162306a36Sopenharmony_ci * check this case. 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_ci mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, &val, 32462306a36Sopenharmony_ci 1); 32562306a36Sopenharmony_ci if (priv->smbus_block && (val & MLXCPLD_I2C_SMBUS_BLK_BIT)) { 32662306a36Sopenharmony_ci mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG, 32762306a36Sopenharmony_ci &datalen, 1); 32862306a36Sopenharmony_ci if (unlikely(datalen > I2C_SMBUS_BLOCK_MAX)) { 32962306a36Sopenharmony_ci dev_err(priv->dev, "Incorrect smbus block read message len\n"); 33062306a36Sopenharmony_ci return -EPROTO; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci } else { 33362306a36Sopenharmony_ci datalen = priv->xfer.data_len; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_DATA_REG, 33762306a36Sopenharmony_ci priv->xfer.msg[i].buf, datalen); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci return datalen; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci case MLXCPLD_LPCI2C_NACK_IND: 34262306a36Sopenharmony_ci return -ENXIO; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci default: 34562306a36Sopenharmony_ci return -EINVAL; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic void mlxcpld_i2c_xfer_msg(struct mlxcpld_i2c_priv *priv) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci int i, len = 0; 35262306a36Sopenharmony_ci u8 cmd, val; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG, 35562306a36Sopenharmony_ci &priv->xfer.data_len, 1); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci val = priv->xfer.addr_width; 35862306a36Sopenharmony_ci /* Notify HW about SMBus block read transaction */ 35962306a36Sopenharmony_ci if (priv->smbus_block && priv->xfer.msg_num >= 2 && 36062306a36Sopenharmony_ci priv->xfer.msg[1].len == 1 && 36162306a36Sopenharmony_ci (priv->xfer.msg[1].flags & I2C_M_RECV_LEN) && 36262306a36Sopenharmony_ci (priv->xfer.msg[1].flags & I2C_M_RD)) 36362306a36Sopenharmony_ci val |= MLXCPLD_I2C_SMBUS_BLK_BIT; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, &val, 1); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci for (i = 0; i < priv->xfer.msg_num; i++) { 36862306a36Sopenharmony_ci if ((priv->xfer.msg[i].flags & I2C_M_RD) != I2C_M_RD) { 36962306a36Sopenharmony_ci /* Don't write to CPLD buffer in read transaction */ 37062306a36Sopenharmony_ci mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_DATA_REG + 37162306a36Sopenharmony_ci len, priv->xfer.msg[i].buf, 37262306a36Sopenharmony_ci priv->xfer.msg[i].len); 37362306a36Sopenharmony_ci len += priv->xfer.msg[i].len; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci /* 37862306a36Sopenharmony_ci * Set target slave address with command for master transfer. 37962306a36Sopenharmony_ci * It should be latest executed function before CPLD transaction. 38062306a36Sopenharmony_ci */ 38162306a36Sopenharmony_ci cmd = (priv->xfer.msg[0].addr << 1) | priv->xfer.cmd; 38262306a36Sopenharmony_ci mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_CMD_REG, &cmd, 1); 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci/* 38662306a36Sopenharmony_ci * Generic lpc-i2c transfer. 38762306a36Sopenharmony_ci * Returns the number of processed messages or error (<0). 38862306a36Sopenharmony_ci */ 38962306a36Sopenharmony_cistatic int mlxcpld_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, 39062306a36Sopenharmony_ci int num) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct mlxcpld_i2c_priv *priv = i2c_get_adapdata(adap); 39362306a36Sopenharmony_ci u8 comm_len = 0; 39462306a36Sopenharmony_ci int i, err; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci err = mlxcpld_i2c_check_msg_params(priv, msgs, num); 39762306a36Sopenharmony_ci if (err) { 39862306a36Sopenharmony_ci dev_err(priv->dev, "Incorrect message\n"); 39962306a36Sopenharmony_ci return err; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci for (i = 0; i < num; ++i) 40362306a36Sopenharmony_ci comm_len += msgs[i].len; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* Check bus state */ 40662306a36Sopenharmony_ci if (mlxcpld_i2c_wait_for_free(priv)) { 40762306a36Sopenharmony_ci dev_err(priv->dev, "LPCI2C bridge is busy\n"); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* 41062306a36Sopenharmony_ci * Usually it means something serious has happened. 41162306a36Sopenharmony_ci * We can not have unfinished previous transfer 41262306a36Sopenharmony_ci * so it doesn't make any sense to try to stop it. 41362306a36Sopenharmony_ci * Probably we were not able to recover from the 41462306a36Sopenharmony_ci * previous error. 41562306a36Sopenharmony_ci * The only reasonable thing - is soft reset. 41662306a36Sopenharmony_ci */ 41762306a36Sopenharmony_ci mlxcpld_i2c_reset(priv); 41862306a36Sopenharmony_ci if (mlxcpld_i2c_check_busy(priv)) { 41962306a36Sopenharmony_ci dev_err(priv->dev, "LPCI2C bridge is busy after reset\n"); 42062306a36Sopenharmony_ci return -EIO; 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci mlxcpld_i2c_set_transf_data(priv, msgs, num, comm_len); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci mutex_lock(&priv->lock); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci /* Do real transfer. Can't fail */ 42962306a36Sopenharmony_ci mlxcpld_i2c_xfer_msg(priv); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci /* Wait for transaction complete */ 43262306a36Sopenharmony_ci err = mlxcpld_i2c_wait_for_tc(priv); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci mutex_unlock(&priv->lock); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return err < 0 ? err : num; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic u32 mlxcpld_i2c_func(struct i2c_adapter *adap) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci struct mlxcpld_i2c_priv *priv = i2c_get_adapdata(adap); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (priv->smbus_block) 44462306a36Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | 44562306a36Sopenharmony_ci I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_BLOCK_DATA; 44662306a36Sopenharmony_ci else 44762306a36Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | 44862306a36Sopenharmony_ci I2C_FUNC_SMBUS_I2C_BLOCK; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic const struct i2c_algorithm mlxcpld_i2c_algo = { 45262306a36Sopenharmony_ci .master_xfer = mlxcpld_i2c_xfer, 45362306a36Sopenharmony_ci .functionality = mlxcpld_i2c_func 45462306a36Sopenharmony_ci}; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic const struct i2c_adapter_quirks mlxcpld_i2c_quirks = { 45762306a36Sopenharmony_ci .flags = I2C_AQ_COMB_WRITE_THEN_READ, 45862306a36Sopenharmony_ci .max_read_len = MLXCPLD_I2C_DATA_REG_SZ - MLXCPLD_I2C_MAX_ADDR_LEN, 45962306a36Sopenharmony_ci .max_write_len = MLXCPLD_I2C_DATA_REG_SZ, 46062306a36Sopenharmony_ci .max_comb_1st_msg_len = 4, 46162306a36Sopenharmony_ci}; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic const struct i2c_adapter_quirks mlxcpld_i2c_quirks_ext = { 46462306a36Sopenharmony_ci .flags = I2C_AQ_COMB_WRITE_THEN_READ, 46562306a36Sopenharmony_ci .max_read_len = MLXCPLD_I2C_DATA_REG_SZ * 2 - MLXCPLD_I2C_MAX_ADDR_LEN, 46662306a36Sopenharmony_ci .max_write_len = MLXCPLD_I2C_DATA_REG_SZ * 2, 46762306a36Sopenharmony_ci .max_comb_1st_msg_len = 4, 46862306a36Sopenharmony_ci}; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic const struct i2c_adapter_quirks mlxcpld_i2c_quirks_ext2 = { 47162306a36Sopenharmony_ci .flags = I2C_AQ_COMB_WRITE_THEN_READ, 47262306a36Sopenharmony_ci .max_read_len = (MLXCPLD_I2C_DATA_REG_SZ - 4) * 4, 47362306a36Sopenharmony_ci .max_write_len = (MLXCPLD_I2C_DATA_REG_SZ - 4) * 4 + MLXCPLD_I2C_MAX_ADDR_LEN, 47462306a36Sopenharmony_ci .max_comb_1st_msg_len = 4, 47562306a36Sopenharmony_ci}; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic struct i2c_adapter mlxcpld_i2c_adapter = { 47862306a36Sopenharmony_ci .owner = THIS_MODULE, 47962306a36Sopenharmony_ci .name = "i2c-mlxcpld", 48062306a36Sopenharmony_ci .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, 48162306a36Sopenharmony_ci .algo = &mlxcpld_i2c_algo, 48262306a36Sopenharmony_ci .quirks = &mlxcpld_i2c_quirks, 48362306a36Sopenharmony_ci .retries = MLXCPLD_I2C_RETR_NUM, 48462306a36Sopenharmony_ci .nr = MLXCPLD_I2C_BUS_NUM, 48562306a36Sopenharmony_ci}; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic int 48862306a36Sopenharmony_cimlxcpld_i2c_set_frequency(struct mlxcpld_i2c_priv *priv, 48962306a36Sopenharmony_ci struct mlxreg_core_hotplug_platform_data *pdata) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci struct mlxreg_core_item *item = pdata->items; 49262306a36Sopenharmony_ci struct mlxreg_core_data *data; 49362306a36Sopenharmony_ci u32 regval; 49462306a36Sopenharmony_ci u8 freq; 49562306a36Sopenharmony_ci int err; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (!item) 49862306a36Sopenharmony_ci return 0; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* Read frequency setting. */ 50162306a36Sopenharmony_ci data = item->data; 50262306a36Sopenharmony_ci err = regmap_read(pdata->regmap, data->reg, ®val); 50362306a36Sopenharmony_ci if (err) 50462306a36Sopenharmony_ci return err; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* Set frequency only if it is not 100KHz, which is default. */ 50762306a36Sopenharmony_ci switch ((regval & data->mask) >> data->bit) { 50862306a36Sopenharmony_ci case MLXCPLD_I2C_FREQ_1000KHZ: 50962306a36Sopenharmony_ci freq = MLXCPLD_I2C_FREQ_1000KHZ_SET; 51062306a36Sopenharmony_ci priv->polling_time /= 4; 51162306a36Sopenharmony_ci break; 51262306a36Sopenharmony_ci case MLXCPLD_I2C_FREQ_400KHZ: 51362306a36Sopenharmony_ci freq = MLXCPLD_I2C_FREQ_400KHZ_SET; 51462306a36Sopenharmony_ci priv->polling_time /= 4; 51562306a36Sopenharmony_ci break; 51662306a36Sopenharmony_ci default: 51762306a36Sopenharmony_ci return 0; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_HALF_CYC_REG, &freq, 1); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci return 0; 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic int mlxcpld_i2c_probe(struct platform_device *pdev) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci struct mlxreg_core_hotplug_platform_data *pdata; 52862306a36Sopenharmony_ci struct mlxcpld_i2c_priv *priv; 52962306a36Sopenharmony_ci int err; 53062306a36Sopenharmony_ci u8 val; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 53362306a36Sopenharmony_ci if (!priv) 53462306a36Sopenharmony_ci return -ENOMEM; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci mutex_init(&priv->lock); 53762306a36Sopenharmony_ci platform_set_drvdata(pdev, priv); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci priv->dev = &pdev->dev; 54062306a36Sopenharmony_ci priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR; 54162306a36Sopenharmony_ci priv->polling_time = MLXCPLD_I2C_POLL_TIME; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* Set I2C bus frequency if platform data provides this info. */ 54462306a36Sopenharmony_ci pdata = dev_get_platdata(&pdev->dev); 54562306a36Sopenharmony_ci if (pdata) { 54662306a36Sopenharmony_ci err = mlxcpld_i2c_set_frequency(priv, pdata); 54762306a36Sopenharmony_ci if (err) 54862306a36Sopenharmony_ci goto mlxcpld_i2_probe_failed; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* Register with i2c layer */ 55262306a36Sopenharmony_ci mlxcpld_i2c_adapter.timeout = usecs_to_jiffies(MLXCPLD_I2C_XFER_TO); 55362306a36Sopenharmony_ci /* Read capability register */ 55462306a36Sopenharmony_ci mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_CPBLTY_REG, &val, 1); 55562306a36Sopenharmony_ci /* Check support for extended transaction length */ 55662306a36Sopenharmony_ci if ((val & MLXCPLD_I2C_DATA_SZ_MASK) == MLXCPLD_I2C_DATA_SZ_BIT) 55762306a36Sopenharmony_ci mlxcpld_i2c_adapter.quirks = &mlxcpld_i2c_quirks_ext; 55862306a36Sopenharmony_ci else if ((val & MLXCPLD_I2C_DATA_SZ_MASK) == MLXCPLD_I2C_DATA_EXT2_SZ_BIT) 55962306a36Sopenharmony_ci mlxcpld_i2c_adapter.quirks = &mlxcpld_i2c_quirks_ext2; 56062306a36Sopenharmony_ci /* Check support for smbus block transaction */ 56162306a36Sopenharmony_ci if (val & MLXCPLD_I2C_SMBUS_BLK_BIT) 56262306a36Sopenharmony_ci priv->smbus_block = true; 56362306a36Sopenharmony_ci if (pdev->id >= -1) 56462306a36Sopenharmony_ci mlxcpld_i2c_adapter.nr = pdev->id; 56562306a36Sopenharmony_ci priv->adap = mlxcpld_i2c_adapter; 56662306a36Sopenharmony_ci priv->adap.dev.parent = &pdev->dev; 56762306a36Sopenharmony_ci i2c_set_adapdata(&priv->adap, priv); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci err = i2c_add_numbered_adapter(&priv->adap); 57062306a36Sopenharmony_ci if (err) 57162306a36Sopenharmony_ci goto mlxcpld_i2_probe_failed; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* Notify caller when adapter is added. */ 57462306a36Sopenharmony_ci if (pdata && pdata->completion_notify) 57562306a36Sopenharmony_ci pdata->completion_notify(pdata->handle, mlxcpld_i2c_adapter.nr); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci return 0; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_cimlxcpld_i2_probe_failed: 58062306a36Sopenharmony_ci mutex_destroy(&priv->lock); 58162306a36Sopenharmony_ci return err; 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic void mlxcpld_i2c_remove(struct platform_device *pdev) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci struct mlxcpld_i2c_priv *priv = platform_get_drvdata(pdev); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci i2c_del_adapter(&priv->adap); 58962306a36Sopenharmony_ci mutex_destroy(&priv->lock); 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cistatic struct platform_driver mlxcpld_i2c_driver = { 59362306a36Sopenharmony_ci .probe = mlxcpld_i2c_probe, 59462306a36Sopenharmony_ci .remove_new = mlxcpld_i2c_remove, 59562306a36Sopenharmony_ci .driver = { 59662306a36Sopenharmony_ci .name = MLXCPLD_I2C_DEVICE_NAME, 59762306a36Sopenharmony_ci }, 59862306a36Sopenharmony_ci}; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cimodule_platform_driver(mlxcpld_i2c_driver); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ciMODULE_AUTHOR("Michael Shych <michaels@mellanox.com>"); 60362306a36Sopenharmony_ciMODULE_DESCRIPTION("Mellanox I2C-CPLD controller driver"); 60462306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 60562306a36Sopenharmony_ciMODULE_ALIAS("platform:i2c-mlxcpld"); 606