18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * FSI-attached I2C master algorithm
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2018 IBM Corporation
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or
88c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License
98c2ecf20Sopenharmony_ci * as published by the Free Software Foundation; either version
108c2ecf20Sopenharmony_ci * 2 of the License, or (at your option) any later version.
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/bitfield.h>
148c2ecf20Sopenharmony_ci#include <linux/bitops.h>
158c2ecf20Sopenharmony_ci#include <linux/delay.h>
168c2ecf20Sopenharmony_ci#include <linux/device.h>
178c2ecf20Sopenharmony_ci#include <linux/errno.h>
188c2ecf20Sopenharmony_ci#include <linux/fsi.h>
198c2ecf20Sopenharmony_ci#include <linux/i2c.h>
208c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
218c2ecf20Sopenharmony_ci#include <linux/kernel.h>
228c2ecf20Sopenharmony_ci#include <linux/list.h>
238c2ecf20Sopenharmony_ci#include <linux/module.h>
248c2ecf20Sopenharmony_ci#include <linux/mutex.h>
258c2ecf20Sopenharmony_ci#include <linux/of.h>
268c2ecf20Sopenharmony_ci#include <linux/slab.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define FSI_ENGID_I2C		0x7
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define I2C_DEFAULT_CLK_DIV	6
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/* i2c registers */
338c2ecf20Sopenharmony_ci#define I2C_FSI_FIFO		0x00
348c2ecf20Sopenharmony_ci#define I2C_FSI_CMD		0x04
358c2ecf20Sopenharmony_ci#define I2C_FSI_MODE		0x08
368c2ecf20Sopenharmony_ci#define I2C_FSI_WATER_MARK	0x0C
378c2ecf20Sopenharmony_ci#define I2C_FSI_INT_MASK	0x10
388c2ecf20Sopenharmony_ci#define I2C_FSI_INT_COND	0x14
398c2ecf20Sopenharmony_ci#define I2C_FSI_OR_INT_MASK	0x14
408c2ecf20Sopenharmony_ci#define I2C_FSI_INTS		0x18
418c2ecf20Sopenharmony_ci#define I2C_FSI_AND_INT_MASK	0x18
428c2ecf20Sopenharmony_ci#define I2C_FSI_STAT		0x1C
438c2ecf20Sopenharmony_ci#define I2C_FSI_RESET_I2C	0x1C
448c2ecf20Sopenharmony_ci#define I2C_FSI_ESTAT		0x20
458c2ecf20Sopenharmony_ci#define I2C_FSI_RESET_ERR	0x20
468c2ecf20Sopenharmony_ci#define I2C_FSI_RESID_LEN	0x24
478c2ecf20Sopenharmony_ci#define I2C_FSI_SET_SCL		0x24
488c2ecf20Sopenharmony_ci#define I2C_FSI_PORT_BUSY	0x28
498c2ecf20Sopenharmony_ci#define I2C_FSI_RESET_SCL	0x2C
508c2ecf20Sopenharmony_ci#define I2C_FSI_SET_SDA		0x30
518c2ecf20Sopenharmony_ci#define I2C_FSI_RESET_SDA	0x34
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci/* cmd register */
548c2ecf20Sopenharmony_ci#define I2C_CMD_WITH_START	BIT(31)
558c2ecf20Sopenharmony_ci#define I2C_CMD_WITH_ADDR	BIT(30)
568c2ecf20Sopenharmony_ci#define I2C_CMD_RD_CONT		BIT(29)
578c2ecf20Sopenharmony_ci#define I2C_CMD_WITH_STOP	BIT(28)
588c2ecf20Sopenharmony_ci#define I2C_CMD_FORCELAUNCH	BIT(27)
598c2ecf20Sopenharmony_ci#define I2C_CMD_ADDR		GENMASK(23, 17)
608c2ecf20Sopenharmony_ci#define I2C_CMD_READ		BIT(16)
618c2ecf20Sopenharmony_ci#define I2C_CMD_LEN		GENMASK(15, 0)
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/* mode register */
648c2ecf20Sopenharmony_ci#define I2C_MODE_CLKDIV		GENMASK(31, 16)
658c2ecf20Sopenharmony_ci#define I2C_MODE_PORT		GENMASK(15, 10)
668c2ecf20Sopenharmony_ci#define I2C_MODE_ENHANCED	BIT(3)
678c2ecf20Sopenharmony_ci#define I2C_MODE_DIAG		BIT(2)
688c2ecf20Sopenharmony_ci#define I2C_MODE_PACE_ALLOW	BIT(1)
698c2ecf20Sopenharmony_ci#define I2C_MODE_WRAP		BIT(0)
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci/* watermark register */
728c2ecf20Sopenharmony_ci#define I2C_WATERMARK_HI	GENMASK(15, 12)
738c2ecf20Sopenharmony_ci#define I2C_WATERMARK_LO	GENMASK(7, 4)
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci#define I2C_FIFO_HI_LVL		4
768c2ecf20Sopenharmony_ci#define I2C_FIFO_LO_LVL		4
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/* interrupt register */
798c2ecf20Sopenharmony_ci#define I2C_INT_INV_CMD		BIT(15)
808c2ecf20Sopenharmony_ci#define I2C_INT_PARITY		BIT(14)
818c2ecf20Sopenharmony_ci#define I2C_INT_BE_OVERRUN	BIT(13)
828c2ecf20Sopenharmony_ci#define I2C_INT_BE_ACCESS	BIT(12)
838c2ecf20Sopenharmony_ci#define I2C_INT_LOST_ARB	BIT(11)
848c2ecf20Sopenharmony_ci#define I2C_INT_NACK		BIT(10)
858c2ecf20Sopenharmony_ci#define I2C_INT_DAT_REQ		BIT(9)
868c2ecf20Sopenharmony_ci#define I2C_INT_CMD_COMP	BIT(8)
878c2ecf20Sopenharmony_ci#define I2C_INT_STOP_ERR	BIT(7)
888c2ecf20Sopenharmony_ci#define I2C_INT_BUSY		BIT(6)
898c2ecf20Sopenharmony_ci#define I2C_INT_IDLE		BIT(5)
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci/* status register */
928c2ecf20Sopenharmony_ci#define I2C_STAT_INV_CMD	BIT(31)
938c2ecf20Sopenharmony_ci#define I2C_STAT_PARITY		BIT(30)
948c2ecf20Sopenharmony_ci#define I2C_STAT_BE_OVERRUN	BIT(29)
958c2ecf20Sopenharmony_ci#define I2C_STAT_BE_ACCESS	BIT(28)
968c2ecf20Sopenharmony_ci#define I2C_STAT_LOST_ARB	BIT(27)
978c2ecf20Sopenharmony_ci#define I2C_STAT_NACK		BIT(26)
988c2ecf20Sopenharmony_ci#define I2C_STAT_DAT_REQ	BIT(25)
998c2ecf20Sopenharmony_ci#define I2C_STAT_CMD_COMP	BIT(24)
1008c2ecf20Sopenharmony_ci#define I2C_STAT_STOP_ERR	BIT(23)
1018c2ecf20Sopenharmony_ci#define I2C_STAT_MAX_PORT	GENMASK(22, 16)
1028c2ecf20Sopenharmony_ci#define I2C_STAT_ANY_INT	BIT(15)
1038c2ecf20Sopenharmony_ci#define I2C_STAT_SCL_IN		BIT(11)
1048c2ecf20Sopenharmony_ci#define I2C_STAT_SDA_IN		BIT(10)
1058c2ecf20Sopenharmony_ci#define I2C_STAT_PORT_BUSY	BIT(9)
1068c2ecf20Sopenharmony_ci#define I2C_STAT_SELF_BUSY	BIT(8)
1078c2ecf20Sopenharmony_ci#define I2C_STAT_FIFO_COUNT	GENMASK(7, 0)
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci#define I2C_STAT_ERR		(I2C_STAT_INV_CMD |			\
1108c2ecf20Sopenharmony_ci				 I2C_STAT_PARITY |			\
1118c2ecf20Sopenharmony_ci				 I2C_STAT_BE_OVERRUN |			\
1128c2ecf20Sopenharmony_ci				 I2C_STAT_BE_ACCESS |			\
1138c2ecf20Sopenharmony_ci				 I2C_STAT_LOST_ARB |			\
1148c2ecf20Sopenharmony_ci				 I2C_STAT_NACK |			\
1158c2ecf20Sopenharmony_ci				 I2C_STAT_STOP_ERR)
1168c2ecf20Sopenharmony_ci#define I2C_STAT_ANY_RESP	(I2C_STAT_ERR |				\
1178c2ecf20Sopenharmony_ci				 I2C_STAT_DAT_REQ |			\
1188c2ecf20Sopenharmony_ci				 I2C_STAT_CMD_COMP)
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci/* extended status register */
1218c2ecf20Sopenharmony_ci#define I2C_ESTAT_FIFO_SZ	GENMASK(31, 24)
1228c2ecf20Sopenharmony_ci#define I2C_ESTAT_SCL_IN_SY	BIT(15)
1238c2ecf20Sopenharmony_ci#define I2C_ESTAT_SDA_IN_SY	BIT(14)
1248c2ecf20Sopenharmony_ci#define I2C_ESTAT_S_SCL		BIT(13)
1258c2ecf20Sopenharmony_ci#define I2C_ESTAT_S_SDA		BIT(12)
1268c2ecf20Sopenharmony_ci#define I2C_ESTAT_M_SCL		BIT(11)
1278c2ecf20Sopenharmony_ci#define I2C_ESTAT_M_SDA		BIT(10)
1288c2ecf20Sopenharmony_ci#define I2C_ESTAT_HI_WATER	BIT(9)
1298c2ecf20Sopenharmony_ci#define I2C_ESTAT_LO_WATER	BIT(8)
1308c2ecf20Sopenharmony_ci#define I2C_ESTAT_PORT_BUSY	BIT(7)
1318c2ecf20Sopenharmony_ci#define I2C_ESTAT_SELF_BUSY	BIT(6)
1328c2ecf20Sopenharmony_ci#define I2C_ESTAT_VERSION	GENMASK(4, 0)
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci/* port busy register */
1358c2ecf20Sopenharmony_ci#define I2C_PORT_BUSY_RESET	BIT(31)
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci/* wait for command complete or data request */
1388c2ecf20Sopenharmony_ci#define I2C_CMD_SLEEP_MAX_US	500
1398c2ecf20Sopenharmony_ci#define I2C_CMD_SLEEP_MIN_US	50
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci/* wait after reset; choose time from legacy driver */
1428c2ecf20Sopenharmony_ci#define I2C_RESET_SLEEP_MAX_US	2000
1438c2ecf20Sopenharmony_ci#define I2C_RESET_SLEEP_MIN_US	1000
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci/* choose timeout length from legacy driver; it's well tested */
1468c2ecf20Sopenharmony_ci#define I2C_ABORT_TIMEOUT	msecs_to_jiffies(100)
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistruct fsi_i2c_master {
1498c2ecf20Sopenharmony_ci	struct fsi_device	*fsi;
1508c2ecf20Sopenharmony_ci	u8			fifo_size;
1518c2ecf20Sopenharmony_ci	struct list_head	ports;
1528c2ecf20Sopenharmony_ci	struct mutex		lock;
1538c2ecf20Sopenharmony_ci};
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistruct fsi_i2c_port {
1568c2ecf20Sopenharmony_ci	struct list_head	list;
1578c2ecf20Sopenharmony_ci	struct i2c_adapter	adapter;
1588c2ecf20Sopenharmony_ci	struct fsi_i2c_master	*master;
1598c2ecf20Sopenharmony_ci	u16			port;
1608c2ecf20Sopenharmony_ci	u16			xfrd;
1618c2ecf20Sopenharmony_ci};
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic int fsi_i2c_read_reg(struct fsi_device *fsi, unsigned int reg,
1648c2ecf20Sopenharmony_ci			    u32 *data)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	int rc;
1678c2ecf20Sopenharmony_ci	__be32 data_be;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	rc = fsi_device_read(fsi, reg, &data_be, sizeof(data_be));
1708c2ecf20Sopenharmony_ci	if (rc)
1718c2ecf20Sopenharmony_ci		return rc;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	*data = be32_to_cpu(data_be);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	return 0;
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic int fsi_i2c_write_reg(struct fsi_device *fsi, unsigned int reg,
1798c2ecf20Sopenharmony_ci			     u32 *data)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	__be32 data_be = cpu_to_be32p(data);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	return fsi_device_write(fsi, reg, &data_be, sizeof(data_be));
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic int fsi_i2c_dev_init(struct fsi_i2c_master *i2c)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	int rc;
1898c2ecf20Sopenharmony_ci	u32 mode = I2C_MODE_ENHANCED, extended_status, watermark;
1908c2ecf20Sopenharmony_ci	u32 interrupt = 0;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	/* since we use polling, disable interrupts */
1938c2ecf20Sopenharmony_ci	rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_INT_MASK, &interrupt);
1948c2ecf20Sopenharmony_ci	if (rc)
1958c2ecf20Sopenharmony_ci		return rc;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	mode |= FIELD_PREP(I2C_MODE_CLKDIV, I2C_DEFAULT_CLK_DIV);
1988c2ecf20Sopenharmony_ci	rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode);
1998c2ecf20Sopenharmony_ci	if (rc)
2008c2ecf20Sopenharmony_ci		return rc;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_ESTAT, &extended_status);
2038c2ecf20Sopenharmony_ci	if (rc)
2048c2ecf20Sopenharmony_ci		return rc;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	i2c->fifo_size = FIELD_GET(I2C_ESTAT_FIFO_SZ, extended_status);
2078c2ecf20Sopenharmony_ci	watermark = FIELD_PREP(I2C_WATERMARK_HI,
2088c2ecf20Sopenharmony_ci			       i2c->fifo_size - I2C_FIFO_HI_LVL);
2098c2ecf20Sopenharmony_ci	watermark |= FIELD_PREP(I2C_WATERMARK_LO, I2C_FIFO_LO_LVL);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	return fsi_i2c_write_reg(i2c->fsi, I2C_FSI_WATER_MARK, &watermark);
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistatic int fsi_i2c_set_port(struct fsi_i2c_port *port)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	int rc;
2178c2ecf20Sopenharmony_ci	struct fsi_device *fsi = port->master->fsi;
2188c2ecf20Sopenharmony_ci	u32 mode, dummy = 0;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	rc = fsi_i2c_read_reg(fsi, I2C_FSI_MODE, &mode);
2218c2ecf20Sopenharmony_ci	if (rc)
2228c2ecf20Sopenharmony_ci		return rc;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	if (FIELD_GET(I2C_MODE_PORT, mode) == port->port)
2258c2ecf20Sopenharmony_ci		return 0;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	mode = (mode & ~I2C_MODE_PORT) | FIELD_PREP(I2C_MODE_PORT, port->port);
2288c2ecf20Sopenharmony_ci	rc = fsi_i2c_write_reg(fsi, I2C_FSI_MODE, &mode);
2298c2ecf20Sopenharmony_ci	if (rc)
2308c2ecf20Sopenharmony_ci		return rc;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	/* reset engine when port is changed */
2338c2ecf20Sopenharmony_ci	return fsi_i2c_write_reg(fsi, I2C_FSI_RESET_ERR, &dummy);
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic int fsi_i2c_start(struct fsi_i2c_port *port, struct i2c_msg *msg,
2378c2ecf20Sopenharmony_ci			 bool stop)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	struct fsi_i2c_master *i2c = port->master;
2408c2ecf20Sopenharmony_ci	u32 cmd = I2C_CMD_WITH_START | I2C_CMD_WITH_ADDR;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	port->xfrd = 0;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	if (msg->flags & I2C_M_RD)
2458c2ecf20Sopenharmony_ci		cmd |= I2C_CMD_READ;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	if (stop || msg->flags & I2C_M_STOP)
2488c2ecf20Sopenharmony_ci		cmd |= I2C_CMD_WITH_STOP;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	cmd |= FIELD_PREP(I2C_CMD_ADDR, msg->addr);
2518c2ecf20Sopenharmony_ci	cmd |= FIELD_PREP(I2C_CMD_LEN, msg->len);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	return fsi_i2c_write_reg(i2c->fsi, I2C_FSI_CMD, &cmd);
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistatic int fsi_i2c_get_op_bytes(int op_bytes)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	/* fsi is limited to max 4 byte aligned ops */
2598c2ecf20Sopenharmony_ci	if (op_bytes > 4)
2608c2ecf20Sopenharmony_ci		return 4;
2618c2ecf20Sopenharmony_ci	else if (op_bytes == 3)
2628c2ecf20Sopenharmony_ci		return 2;
2638c2ecf20Sopenharmony_ci	return op_bytes;
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic int fsi_i2c_write_fifo(struct fsi_i2c_port *port, struct i2c_msg *msg,
2678c2ecf20Sopenharmony_ci			      u8 fifo_count)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	int write;
2708c2ecf20Sopenharmony_ci	int rc;
2718c2ecf20Sopenharmony_ci	struct fsi_i2c_master *i2c = port->master;
2728c2ecf20Sopenharmony_ci	int bytes_to_write = i2c->fifo_size - fifo_count;
2738c2ecf20Sopenharmony_ci	int bytes_remaining = msg->len - port->xfrd;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	bytes_to_write = min(bytes_to_write, bytes_remaining);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	while (bytes_to_write) {
2788c2ecf20Sopenharmony_ci		write = fsi_i2c_get_op_bytes(bytes_to_write);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci		rc = fsi_device_write(i2c->fsi, I2C_FSI_FIFO,
2818c2ecf20Sopenharmony_ci				      &msg->buf[port->xfrd], write);
2828c2ecf20Sopenharmony_ci		if (rc)
2838c2ecf20Sopenharmony_ci			return rc;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci		port->xfrd += write;
2868c2ecf20Sopenharmony_ci		bytes_to_write -= write;
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	return 0;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic int fsi_i2c_read_fifo(struct fsi_i2c_port *port, struct i2c_msg *msg,
2938c2ecf20Sopenharmony_ci			     u8 fifo_count)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	int read;
2968c2ecf20Sopenharmony_ci	int rc;
2978c2ecf20Sopenharmony_ci	struct fsi_i2c_master *i2c = port->master;
2988c2ecf20Sopenharmony_ci	int bytes_to_read;
2998c2ecf20Sopenharmony_ci	int xfr_remaining = msg->len - port->xfrd;
3008c2ecf20Sopenharmony_ci	u32 dummy;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	bytes_to_read = min_t(int, fifo_count, xfr_remaining);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	while (bytes_to_read) {
3058c2ecf20Sopenharmony_ci		read = fsi_i2c_get_op_bytes(bytes_to_read);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci		if (xfr_remaining) {
3088c2ecf20Sopenharmony_ci			rc = fsi_device_read(i2c->fsi, I2C_FSI_FIFO,
3098c2ecf20Sopenharmony_ci					     &msg->buf[port->xfrd], read);
3108c2ecf20Sopenharmony_ci			if (rc)
3118c2ecf20Sopenharmony_ci				return rc;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci			port->xfrd += read;
3148c2ecf20Sopenharmony_ci			xfr_remaining -= read;
3158c2ecf20Sopenharmony_ci		} else {
3168c2ecf20Sopenharmony_ci			/* no more buffer but data in fifo, need to clear it */
3178c2ecf20Sopenharmony_ci			rc = fsi_device_read(i2c->fsi, I2C_FSI_FIFO, &dummy,
3188c2ecf20Sopenharmony_ci					     read);
3198c2ecf20Sopenharmony_ci			if (rc)
3208c2ecf20Sopenharmony_ci				return rc;
3218c2ecf20Sopenharmony_ci		}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci		bytes_to_read -= read;
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	return 0;
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic int fsi_i2c_get_scl(struct i2c_adapter *adap)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	u32 stat = 0;
3328c2ecf20Sopenharmony_ci	struct fsi_i2c_port *port = adap->algo_data;
3338c2ecf20Sopenharmony_ci	struct fsi_i2c_master *i2c = port->master;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	return !!(stat & I2C_STAT_SCL_IN);
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistatic void fsi_i2c_set_scl(struct i2c_adapter *adap, int val)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	u32 dummy = 0;
3438c2ecf20Sopenharmony_ci	struct fsi_i2c_port *port = adap->algo_data;
3448c2ecf20Sopenharmony_ci	struct fsi_i2c_master *i2c = port->master;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	if (val)
3478c2ecf20Sopenharmony_ci		fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SCL, &dummy);
3488c2ecf20Sopenharmony_ci	else
3498c2ecf20Sopenharmony_ci		fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SCL, &dummy);
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_cistatic int fsi_i2c_get_sda(struct i2c_adapter *adap)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	u32 stat = 0;
3558c2ecf20Sopenharmony_ci	struct fsi_i2c_port *port = adap->algo_data;
3568c2ecf20Sopenharmony_ci	struct fsi_i2c_master *i2c = port->master;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	return !!(stat & I2C_STAT_SDA_IN);
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_cistatic void fsi_i2c_set_sda(struct i2c_adapter *adap, int val)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	u32 dummy = 0;
3668c2ecf20Sopenharmony_ci	struct fsi_i2c_port *port = adap->algo_data;
3678c2ecf20Sopenharmony_ci	struct fsi_i2c_master *i2c = port->master;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	if (val)
3708c2ecf20Sopenharmony_ci		fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SDA, &dummy);
3718c2ecf20Sopenharmony_ci	else
3728c2ecf20Sopenharmony_ci		fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SDA, &dummy);
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_cistatic void fsi_i2c_prepare_recovery(struct i2c_adapter *adap)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	int rc;
3788c2ecf20Sopenharmony_ci	u32 mode;
3798c2ecf20Sopenharmony_ci	struct fsi_i2c_port *port = adap->algo_data;
3808c2ecf20Sopenharmony_ci	struct fsi_i2c_master *i2c = port->master;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode);
3838c2ecf20Sopenharmony_ci	if (rc)
3848c2ecf20Sopenharmony_ci		return;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	mode |= I2C_MODE_DIAG;
3878c2ecf20Sopenharmony_ci	fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode);
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_cistatic void fsi_i2c_unprepare_recovery(struct i2c_adapter *adap)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	int rc;
3938c2ecf20Sopenharmony_ci	u32 mode;
3948c2ecf20Sopenharmony_ci	struct fsi_i2c_port *port = adap->algo_data;
3958c2ecf20Sopenharmony_ci	struct fsi_i2c_master *i2c = port->master;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode);
3988c2ecf20Sopenharmony_ci	if (rc)
3998c2ecf20Sopenharmony_ci		return;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	mode &= ~I2C_MODE_DIAG;
4028c2ecf20Sopenharmony_ci	fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode);
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic int fsi_i2c_reset_bus(struct fsi_i2c_master *i2c,
4068c2ecf20Sopenharmony_ci			     struct fsi_i2c_port *port)
4078c2ecf20Sopenharmony_ci{
4088c2ecf20Sopenharmony_ci	int rc;
4098c2ecf20Sopenharmony_ci	u32 stat, dummy = 0;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	/* force bus reset, ignore errors */
4128c2ecf20Sopenharmony_ci	i2c_recover_bus(&port->adapter);
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	/* reset errors */
4158c2ecf20Sopenharmony_ci	rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_ERR, &dummy);
4168c2ecf20Sopenharmony_ci	if (rc)
4178c2ecf20Sopenharmony_ci		return rc;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	/* wait for command complete */
4208c2ecf20Sopenharmony_ci	usleep_range(I2C_RESET_SLEEP_MIN_US, I2C_RESET_SLEEP_MAX_US);
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat);
4238c2ecf20Sopenharmony_ci	if (rc)
4248c2ecf20Sopenharmony_ci		return rc;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	if (stat & I2C_STAT_CMD_COMP)
4278c2ecf20Sopenharmony_ci		return 0;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	/* failed to get command complete; reset engine again */
4308c2ecf20Sopenharmony_ci	rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_I2C, &dummy);
4318c2ecf20Sopenharmony_ci	if (rc)
4328c2ecf20Sopenharmony_ci		return rc;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	/* re-init engine again */
4358c2ecf20Sopenharmony_ci	return fsi_i2c_dev_init(i2c);
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic int fsi_i2c_reset_engine(struct fsi_i2c_master *i2c, u16 port)
4398c2ecf20Sopenharmony_ci{
4408c2ecf20Sopenharmony_ci	int rc;
4418c2ecf20Sopenharmony_ci	u32 mode, dummy = 0;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	/* reset engine */
4448c2ecf20Sopenharmony_ci	rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_I2C, &dummy);
4458c2ecf20Sopenharmony_ci	if (rc)
4468c2ecf20Sopenharmony_ci		return rc;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	/* re-init engine */
4498c2ecf20Sopenharmony_ci	rc = fsi_i2c_dev_init(i2c);
4508c2ecf20Sopenharmony_ci	if (rc)
4518c2ecf20Sopenharmony_ci		return rc;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode);
4548c2ecf20Sopenharmony_ci	if (rc)
4558c2ecf20Sopenharmony_ci		return rc;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	/* set port; default after reset is 0 */
4588c2ecf20Sopenharmony_ci	if (port) {
4598c2ecf20Sopenharmony_ci		mode &= ~I2C_MODE_PORT;
4608c2ecf20Sopenharmony_ci		mode |= FIELD_PREP(I2C_MODE_PORT, port);
4618c2ecf20Sopenharmony_ci		rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode);
4628c2ecf20Sopenharmony_ci		if (rc)
4638c2ecf20Sopenharmony_ci			return rc;
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	/* reset busy register; hw workaround */
4678c2ecf20Sopenharmony_ci	dummy = I2C_PORT_BUSY_RESET;
4688c2ecf20Sopenharmony_ci	rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_PORT_BUSY, &dummy);
4698c2ecf20Sopenharmony_ci	if (rc)
4708c2ecf20Sopenharmony_ci		return rc;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	return 0;
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cistatic int fsi_i2c_abort(struct fsi_i2c_port *port, u32 status)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	int rc;
4788c2ecf20Sopenharmony_ci	unsigned long start;
4798c2ecf20Sopenharmony_ci	u32 cmd = I2C_CMD_WITH_STOP;
4808c2ecf20Sopenharmony_ci	u32 stat;
4818c2ecf20Sopenharmony_ci	struct fsi_i2c_master *i2c = port->master;
4828c2ecf20Sopenharmony_ci	struct fsi_device *fsi = i2c->fsi;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	rc = fsi_i2c_reset_engine(i2c, port->port);
4858c2ecf20Sopenharmony_ci	if (rc)
4868c2ecf20Sopenharmony_ci		return rc;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	rc = fsi_i2c_read_reg(fsi, I2C_FSI_STAT, &stat);
4898c2ecf20Sopenharmony_ci	if (rc)
4908c2ecf20Sopenharmony_ci		return rc;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	/* if sda is low, peform full bus reset */
4938c2ecf20Sopenharmony_ci	if (!(stat & I2C_STAT_SDA_IN)) {
4948c2ecf20Sopenharmony_ci		rc = fsi_i2c_reset_bus(i2c, port);
4958c2ecf20Sopenharmony_ci		if (rc)
4968c2ecf20Sopenharmony_ci			return rc;
4978c2ecf20Sopenharmony_ci	}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	/* skip final stop command for these errors */
5008c2ecf20Sopenharmony_ci	if (status & (I2C_STAT_PARITY | I2C_STAT_LOST_ARB | I2C_STAT_STOP_ERR))
5018c2ecf20Sopenharmony_ci		return 0;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	/* write stop command */
5048c2ecf20Sopenharmony_ci	rc = fsi_i2c_write_reg(fsi, I2C_FSI_CMD, &cmd);
5058c2ecf20Sopenharmony_ci	if (rc)
5068c2ecf20Sopenharmony_ci		return rc;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	/* wait until we see command complete in the master */
5098c2ecf20Sopenharmony_ci	start = jiffies;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	do {
5128c2ecf20Sopenharmony_ci		rc = fsi_i2c_read_reg(fsi, I2C_FSI_STAT, &status);
5138c2ecf20Sopenharmony_ci		if (rc)
5148c2ecf20Sopenharmony_ci			return rc;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci		if (status & I2C_STAT_CMD_COMP)
5178c2ecf20Sopenharmony_ci			return 0;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci		usleep_range(I2C_CMD_SLEEP_MIN_US, I2C_CMD_SLEEP_MAX_US);
5208c2ecf20Sopenharmony_ci	} while (time_after(start + I2C_ABORT_TIMEOUT, jiffies));
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
5238c2ecf20Sopenharmony_ci}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_cistatic int fsi_i2c_handle_status(struct fsi_i2c_port *port,
5268c2ecf20Sopenharmony_ci				 struct i2c_msg *msg, u32 status)
5278c2ecf20Sopenharmony_ci{
5288c2ecf20Sopenharmony_ci	int rc;
5298c2ecf20Sopenharmony_ci	u8 fifo_count;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	if (status & I2C_STAT_ERR) {
5328c2ecf20Sopenharmony_ci		rc = fsi_i2c_abort(port, status);
5338c2ecf20Sopenharmony_ci		if (rc)
5348c2ecf20Sopenharmony_ci			return rc;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci		if (status & I2C_STAT_INV_CMD)
5378c2ecf20Sopenharmony_ci			return -EINVAL;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci		if (status & (I2C_STAT_PARITY | I2C_STAT_BE_OVERRUN |
5408c2ecf20Sopenharmony_ci		    I2C_STAT_BE_ACCESS))
5418c2ecf20Sopenharmony_ci			return -EPROTO;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci		if (status & I2C_STAT_NACK)
5448c2ecf20Sopenharmony_ci			return -ENXIO;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci		if (status & I2C_STAT_LOST_ARB)
5478c2ecf20Sopenharmony_ci			return -EAGAIN;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci		if (status & I2C_STAT_STOP_ERR)
5508c2ecf20Sopenharmony_ci			return -EBADMSG;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci		return -EIO;
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	if (status & I2C_STAT_DAT_REQ) {
5568c2ecf20Sopenharmony_ci		fifo_count = FIELD_GET(I2C_STAT_FIFO_COUNT, status);
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci		if (msg->flags & I2C_M_RD)
5598c2ecf20Sopenharmony_ci			return fsi_i2c_read_fifo(port, msg, fifo_count);
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci		return fsi_i2c_write_fifo(port, msg, fifo_count);
5628c2ecf20Sopenharmony_ci	}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	if (status & I2C_STAT_CMD_COMP) {
5658c2ecf20Sopenharmony_ci		if (port->xfrd < msg->len)
5668c2ecf20Sopenharmony_ci			return -ENODATA;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci		return msg->len;
5698c2ecf20Sopenharmony_ci	}
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	return 0;
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_cistatic int fsi_i2c_wait(struct fsi_i2c_port *port, struct i2c_msg *msg,
5758c2ecf20Sopenharmony_ci			unsigned long timeout)
5768c2ecf20Sopenharmony_ci{
5778c2ecf20Sopenharmony_ci	u32 status = 0;
5788c2ecf20Sopenharmony_ci	int rc;
5798c2ecf20Sopenharmony_ci	unsigned long start = jiffies;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	do {
5828c2ecf20Sopenharmony_ci		rc = fsi_i2c_read_reg(port->master->fsi, I2C_FSI_STAT,
5838c2ecf20Sopenharmony_ci				      &status);
5848c2ecf20Sopenharmony_ci		if (rc)
5858c2ecf20Sopenharmony_ci			return rc;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci		if (status & I2C_STAT_ANY_RESP) {
5888c2ecf20Sopenharmony_ci			rc = fsi_i2c_handle_status(port, msg, status);
5898c2ecf20Sopenharmony_ci			if (rc < 0)
5908c2ecf20Sopenharmony_ci				return rc;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci			/* cmd complete and all data xfrd */
5938c2ecf20Sopenharmony_ci			if (rc == msg->len)
5948c2ecf20Sopenharmony_ci				return 0;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci			/* need to xfr more data, but maybe don't need wait */
5978c2ecf20Sopenharmony_ci			continue;
5988c2ecf20Sopenharmony_ci		}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci		usleep_range(I2C_CMD_SLEEP_MIN_US, I2C_CMD_SLEEP_MAX_US);
6018c2ecf20Sopenharmony_ci	} while (time_after(start + timeout, jiffies));
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
6048c2ecf20Sopenharmony_ci}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_cistatic int fsi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
6078c2ecf20Sopenharmony_ci			int num)
6088c2ecf20Sopenharmony_ci{
6098c2ecf20Sopenharmony_ci	int i, rc;
6108c2ecf20Sopenharmony_ci	unsigned long start_time;
6118c2ecf20Sopenharmony_ci	struct fsi_i2c_port *port = adap->algo_data;
6128c2ecf20Sopenharmony_ci	struct fsi_i2c_master *master = port->master;
6138c2ecf20Sopenharmony_ci	struct i2c_msg *msg;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	mutex_lock(&master->lock);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	rc = fsi_i2c_set_port(port);
6188c2ecf20Sopenharmony_ci	if (rc)
6198c2ecf20Sopenharmony_ci		goto unlock;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++) {
6228c2ecf20Sopenharmony_ci		msg = msgs + i;
6238c2ecf20Sopenharmony_ci		start_time = jiffies;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci		rc = fsi_i2c_start(port, msg, i == num - 1);
6268c2ecf20Sopenharmony_ci		if (rc)
6278c2ecf20Sopenharmony_ci			goto unlock;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci		rc = fsi_i2c_wait(port, msg,
6308c2ecf20Sopenharmony_ci				  adap->timeout - (jiffies - start_time));
6318c2ecf20Sopenharmony_ci		if (rc)
6328c2ecf20Sopenharmony_ci			goto unlock;
6338c2ecf20Sopenharmony_ci	}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ciunlock:
6368c2ecf20Sopenharmony_ci	mutex_unlock(&master->lock);
6378c2ecf20Sopenharmony_ci	return rc ? : num;
6388c2ecf20Sopenharmony_ci}
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_cistatic u32 fsi_i2c_functionality(struct i2c_adapter *adap)
6418c2ecf20Sopenharmony_ci{
6428c2ecf20Sopenharmony_ci	return I2C_FUNC_I2C | I2C_FUNC_PROTOCOL_MANGLING |
6438c2ecf20Sopenharmony_ci		I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA;
6448c2ecf20Sopenharmony_ci}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_cistatic struct i2c_bus_recovery_info fsi_i2c_bus_recovery_info = {
6478c2ecf20Sopenharmony_ci	.recover_bus = i2c_generic_scl_recovery,
6488c2ecf20Sopenharmony_ci	.get_scl = fsi_i2c_get_scl,
6498c2ecf20Sopenharmony_ci	.set_scl = fsi_i2c_set_scl,
6508c2ecf20Sopenharmony_ci	.get_sda = fsi_i2c_get_sda,
6518c2ecf20Sopenharmony_ci	.set_sda = fsi_i2c_set_sda,
6528c2ecf20Sopenharmony_ci	.prepare_recovery = fsi_i2c_prepare_recovery,
6538c2ecf20Sopenharmony_ci	.unprepare_recovery = fsi_i2c_unprepare_recovery,
6548c2ecf20Sopenharmony_ci};
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_cistatic const struct i2c_algorithm fsi_i2c_algorithm = {
6578c2ecf20Sopenharmony_ci	.master_xfer = fsi_i2c_xfer,
6588c2ecf20Sopenharmony_ci	.functionality = fsi_i2c_functionality,
6598c2ecf20Sopenharmony_ci};
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_cistatic struct device_node *fsi_i2c_find_port_of_node(struct device_node *fsi,
6628c2ecf20Sopenharmony_ci						     int port)
6638c2ecf20Sopenharmony_ci{
6648c2ecf20Sopenharmony_ci	struct device_node *np;
6658c2ecf20Sopenharmony_ci	u32 port_no;
6668c2ecf20Sopenharmony_ci	int rc;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	for_each_child_of_node(fsi, np) {
6698c2ecf20Sopenharmony_ci		rc = of_property_read_u32(np, "reg", &port_no);
6708c2ecf20Sopenharmony_ci		if (!rc && port_no == port)
6718c2ecf20Sopenharmony_ci			return np;
6728c2ecf20Sopenharmony_ci	}
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	return NULL;
6758c2ecf20Sopenharmony_ci}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_cistatic int fsi_i2c_probe(struct device *dev)
6788c2ecf20Sopenharmony_ci{
6798c2ecf20Sopenharmony_ci	struct fsi_i2c_master *i2c;
6808c2ecf20Sopenharmony_ci	struct fsi_i2c_port *port;
6818c2ecf20Sopenharmony_ci	struct device_node *np;
6828c2ecf20Sopenharmony_ci	u32 port_no, ports, stat;
6838c2ecf20Sopenharmony_ci	int rc;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
6868c2ecf20Sopenharmony_ci	if (!i2c)
6878c2ecf20Sopenharmony_ci		return -ENOMEM;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	mutex_init(&i2c->lock);
6908c2ecf20Sopenharmony_ci	i2c->fsi = to_fsi_dev(dev);
6918c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&i2c->ports);
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	rc = fsi_i2c_dev_init(i2c);
6948c2ecf20Sopenharmony_ci	if (rc)
6958c2ecf20Sopenharmony_ci		return rc;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat);
6988c2ecf20Sopenharmony_ci	if (rc)
6998c2ecf20Sopenharmony_ci		return rc;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	ports = FIELD_GET(I2C_STAT_MAX_PORT, stat) + 1;
7028c2ecf20Sopenharmony_ci	dev_dbg(dev, "I2C master has %d ports\n", ports);
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	for (port_no = 0; port_no < ports; port_no++) {
7058c2ecf20Sopenharmony_ci		np = fsi_i2c_find_port_of_node(dev->of_node, port_no);
7068c2ecf20Sopenharmony_ci		if (!of_device_is_available(np))
7078c2ecf20Sopenharmony_ci			continue;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci		port = kzalloc(sizeof(*port), GFP_KERNEL);
7108c2ecf20Sopenharmony_ci		if (!port) {
7118c2ecf20Sopenharmony_ci			of_node_put(np);
7128c2ecf20Sopenharmony_ci			break;
7138c2ecf20Sopenharmony_ci		}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci		port->master = i2c;
7168c2ecf20Sopenharmony_ci		port->port = port_no;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci		port->adapter.owner = THIS_MODULE;
7198c2ecf20Sopenharmony_ci		port->adapter.dev.of_node = np;
7208c2ecf20Sopenharmony_ci		port->adapter.dev.parent = dev;
7218c2ecf20Sopenharmony_ci		port->adapter.algo = &fsi_i2c_algorithm;
7228c2ecf20Sopenharmony_ci		port->adapter.bus_recovery_info = &fsi_i2c_bus_recovery_info;
7238c2ecf20Sopenharmony_ci		port->adapter.algo_data = port;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci		snprintf(port->adapter.name, sizeof(port->adapter.name),
7268c2ecf20Sopenharmony_ci			 "i2c_bus-%u", port_no);
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci		rc = i2c_add_adapter(&port->adapter);
7298c2ecf20Sopenharmony_ci		if (rc < 0) {
7308c2ecf20Sopenharmony_ci			dev_err(dev, "Failed to register adapter: %d\n", rc);
7318c2ecf20Sopenharmony_ci			kfree(port);
7328c2ecf20Sopenharmony_ci			continue;
7338c2ecf20Sopenharmony_ci		}
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci		list_add(&port->list, &i2c->ports);
7368c2ecf20Sopenharmony_ci	}
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	dev_set_drvdata(dev, i2c);
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	return 0;
7418c2ecf20Sopenharmony_ci}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_cistatic int fsi_i2c_remove(struct device *dev)
7448c2ecf20Sopenharmony_ci{
7458c2ecf20Sopenharmony_ci	struct fsi_i2c_master *i2c = dev_get_drvdata(dev);
7468c2ecf20Sopenharmony_ci	struct fsi_i2c_port *port, *tmp;
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	list_for_each_entry_safe(port, tmp, &i2c->ports, list) {
7498c2ecf20Sopenharmony_ci		list_del(&port->list);
7508c2ecf20Sopenharmony_ci		i2c_del_adapter(&port->adapter);
7518c2ecf20Sopenharmony_ci		kfree(port);
7528c2ecf20Sopenharmony_ci	}
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	return 0;
7558c2ecf20Sopenharmony_ci}
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_cistatic const struct fsi_device_id fsi_i2c_ids[] = {
7588c2ecf20Sopenharmony_ci	{ FSI_ENGID_I2C, FSI_VERSION_ANY },
7598c2ecf20Sopenharmony_ci	{ }
7608c2ecf20Sopenharmony_ci};
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_cistatic struct fsi_driver fsi_i2c_driver = {
7638c2ecf20Sopenharmony_ci	.id_table = fsi_i2c_ids,
7648c2ecf20Sopenharmony_ci	.drv = {
7658c2ecf20Sopenharmony_ci		.name = "i2c-fsi",
7668c2ecf20Sopenharmony_ci		.bus = &fsi_bus_type,
7678c2ecf20Sopenharmony_ci		.probe = fsi_i2c_probe,
7688c2ecf20Sopenharmony_ci		.remove = fsi_i2c_remove,
7698c2ecf20Sopenharmony_ci	},
7708c2ecf20Sopenharmony_ci};
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_cimodule_fsi_driver(fsi_i2c_driver);
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ciMODULE_AUTHOR("Eddie James <eajames@us.ibm.com>");
7758c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("FSI attached I2C master");
7768c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
777