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, &regval);
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