18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2003-2015 Broadcom Corporation
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public
58c2ecf20Sopenharmony_ci * License version 2. This program is licensed "as is" without any
68c2ecf20Sopenharmony_ci * warranty of any kind, whether express or implied.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/acpi.h>
108c2ecf20Sopenharmony_ci#include <linux/clk.h>
118c2ecf20Sopenharmony_ci#include <linux/completion.h>
128c2ecf20Sopenharmony_ci#include <linux/i2c.h>
138c2ecf20Sopenharmony_ci#include <linux/i2c-smbus.h>
148c2ecf20Sopenharmony_ci#include <linux/init.h>
158c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
168c2ecf20Sopenharmony_ci#include <linux/io.h>
178c2ecf20Sopenharmony_ci#include <linux/kernel.h>
188c2ecf20Sopenharmony_ci#include <linux/module.h>
198c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
208c2ecf20Sopenharmony_ci#include <linux/delay.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define XLP9XX_I2C_DIV			0x0
238c2ecf20Sopenharmony_ci#define XLP9XX_I2C_CTRL			0x1
248c2ecf20Sopenharmony_ci#define XLP9XX_I2C_CMD			0x2
258c2ecf20Sopenharmony_ci#define XLP9XX_I2C_STATUS		0x3
268c2ecf20Sopenharmony_ci#define XLP9XX_I2C_MTXFIFO		0x4
278c2ecf20Sopenharmony_ci#define XLP9XX_I2C_MRXFIFO		0x5
288c2ecf20Sopenharmony_ci#define XLP9XX_I2C_MFIFOCTRL		0x6
298c2ecf20Sopenharmony_ci#define XLP9XX_I2C_STXFIFO		0x7
308c2ecf20Sopenharmony_ci#define XLP9XX_I2C_SRXFIFO		0x8
318c2ecf20Sopenharmony_ci#define XLP9XX_I2C_SFIFOCTRL		0x9
328c2ecf20Sopenharmony_ci#define XLP9XX_I2C_SLAVEADDR		0xA
338c2ecf20Sopenharmony_ci#define XLP9XX_I2C_OWNADDR		0xB
348c2ecf20Sopenharmony_ci#define XLP9XX_I2C_FIFOWCNT		0xC
358c2ecf20Sopenharmony_ci#define XLP9XX_I2C_INTEN		0xD
368c2ecf20Sopenharmony_ci#define XLP9XX_I2C_INTST		0xE
378c2ecf20Sopenharmony_ci#define XLP9XX_I2C_WAITCNT		0xF
388c2ecf20Sopenharmony_ci#define XLP9XX_I2C_TIMEOUT		0X10
398c2ecf20Sopenharmony_ci#define XLP9XX_I2C_GENCALLADDR		0x11
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#define XLP9XX_I2C_STATUS_BUSY		BIT(0)
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define XLP9XX_I2C_CMD_START		BIT(7)
448c2ecf20Sopenharmony_ci#define XLP9XX_I2C_CMD_STOP		BIT(6)
458c2ecf20Sopenharmony_ci#define XLP9XX_I2C_CMD_READ		BIT(5)
468c2ecf20Sopenharmony_ci#define XLP9XX_I2C_CMD_WRITE		BIT(4)
478c2ecf20Sopenharmony_ci#define XLP9XX_I2C_CMD_ACK		BIT(3)
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#define XLP9XX_I2C_CTRL_MCTLEN_SHIFT	16
508c2ecf20Sopenharmony_ci#define XLP9XX_I2C_CTRL_MCTLEN_MASK	0xffff0000
518c2ecf20Sopenharmony_ci#define XLP9XX_I2C_CTRL_RST		BIT(8)
528c2ecf20Sopenharmony_ci#define XLP9XX_I2C_CTRL_EN		BIT(6)
538c2ecf20Sopenharmony_ci#define XLP9XX_I2C_CTRL_MASTER		BIT(4)
548c2ecf20Sopenharmony_ci#define XLP9XX_I2C_CTRL_FIFORD		BIT(1)
558c2ecf20Sopenharmony_ci#define XLP9XX_I2C_CTRL_ADDMODE		BIT(0)
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#define XLP9XX_I2C_INTEN_NACKADDR	BIT(25)
588c2ecf20Sopenharmony_ci#define XLP9XX_I2C_INTEN_SADDR		BIT(13)
598c2ecf20Sopenharmony_ci#define XLP9XX_I2C_INTEN_DATADONE	BIT(12)
608c2ecf20Sopenharmony_ci#define XLP9XX_I2C_INTEN_ARLOST		BIT(11)
618c2ecf20Sopenharmony_ci#define XLP9XX_I2C_INTEN_MFIFOFULL	BIT(4)
628c2ecf20Sopenharmony_ci#define XLP9XX_I2C_INTEN_MFIFOEMTY	BIT(3)
638c2ecf20Sopenharmony_ci#define XLP9XX_I2C_INTEN_MFIFOHI	BIT(2)
648c2ecf20Sopenharmony_ci#define XLP9XX_I2C_INTEN_BUSERR		BIT(0)
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#define XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT		8
678c2ecf20Sopenharmony_ci#define XLP9XX_I2C_MFIFOCTRL_LOTH_SHIFT		0
688c2ecf20Sopenharmony_ci#define XLP9XX_I2C_MFIFOCTRL_RST		BIT(16)
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci#define XLP9XX_I2C_SLAVEADDR_RW			BIT(0)
718c2ecf20Sopenharmony_ci#define XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT		1
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci#define XLP9XX_I2C_IP_CLK_FREQ		133000000UL
748c2ecf20Sopenharmony_ci#define XLP9XX_I2C_FIFO_SIZE		0x80U
758c2ecf20Sopenharmony_ci#define XLP9XX_I2C_TIMEOUT_MS		1000
768c2ecf20Sopenharmony_ci#define XLP9XX_I2C_BUSY_TIMEOUT		50
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci#define XLP9XX_I2C_FIFO_WCNT_MASK	0xff
798c2ecf20Sopenharmony_ci#define XLP9XX_I2C_STATUS_ERRMASK	(XLP9XX_I2C_INTEN_ARLOST | \
808c2ecf20Sopenharmony_ci			XLP9XX_I2C_INTEN_NACKADDR | XLP9XX_I2C_INTEN_BUSERR)
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistruct xlp9xx_i2c_dev {
838c2ecf20Sopenharmony_ci	struct device *dev;
848c2ecf20Sopenharmony_ci	struct i2c_adapter adapter;
858c2ecf20Sopenharmony_ci	struct completion msg_complete;
868c2ecf20Sopenharmony_ci	struct i2c_smbus_alert_setup alert_data;
878c2ecf20Sopenharmony_ci	struct i2c_client *ara;
888c2ecf20Sopenharmony_ci	int irq;
898c2ecf20Sopenharmony_ci	bool msg_read;
908c2ecf20Sopenharmony_ci	bool len_recv;
918c2ecf20Sopenharmony_ci	bool client_pec;
928c2ecf20Sopenharmony_ci	u32 __iomem *base;
938c2ecf20Sopenharmony_ci	u32 msg_buf_remaining;
948c2ecf20Sopenharmony_ci	u32 msg_len;
958c2ecf20Sopenharmony_ci	u32 ip_clk_hz;
968c2ecf20Sopenharmony_ci	u32 clk_hz;
978c2ecf20Sopenharmony_ci	u32 msg_err;
988c2ecf20Sopenharmony_ci	u8 *msg_buf;
998c2ecf20Sopenharmony_ci};
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic inline void xlp9xx_write_i2c_reg(struct xlp9xx_i2c_dev *priv,
1028c2ecf20Sopenharmony_ci					unsigned long reg, u32 val)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	writel(val, priv->base + reg);
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic inline u32 xlp9xx_read_i2c_reg(struct xlp9xx_i2c_dev *priv,
1088c2ecf20Sopenharmony_ci				      unsigned long reg)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	return readl(priv->base + reg);
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic void xlp9xx_i2c_mask_irq(struct xlp9xx_i2c_dev *priv, u32 mask)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	u32 inten;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) & ~mask;
1188c2ecf20Sopenharmony_ci	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten);
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic void xlp9xx_i2c_unmask_irq(struct xlp9xx_i2c_dev *priv, u32 mask)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	u32 inten;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) | mask;
1268c2ecf20Sopenharmony_ci	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten);
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic void xlp9xx_i2c_update_rx_fifo_thres(struct xlp9xx_i2c_dev *priv)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	u32 thres;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	if (priv->len_recv)
1348c2ecf20Sopenharmony_ci		/* interrupt after the first read to examine
1358c2ecf20Sopenharmony_ci		 * the length byte before proceeding further
1368c2ecf20Sopenharmony_ci		 */
1378c2ecf20Sopenharmony_ci		thres = 1;
1388c2ecf20Sopenharmony_ci	else if (priv->msg_buf_remaining > XLP9XX_I2C_FIFO_SIZE)
1398c2ecf20Sopenharmony_ci		thres = XLP9XX_I2C_FIFO_SIZE;
1408c2ecf20Sopenharmony_ci	else
1418c2ecf20Sopenharmony_ci		thres = priv->msg_buf_remaining;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL,
1448c2ecf20Sopenharmony_ci			     thres << XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT);
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic void xlp9xx_i2c_fill_tx_fifo(struct xlp9xx_i2c_dev *priv)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	u32 len, i;
1508c2ecf20Sopenharmony_ci	u8 *buf = priv->msg_buf;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	len = min(priv->msg_buf_remaining, XLP9XX_I2C_FIFO_SIZE);
1538c2ecf20Sopenharmony_ci	for (i = 0; i < len; i++)
1548c2ecf20Sopenharmony_ci		xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MTXFIFO, buf[i]);
1558c2ecf20Sopenharmony_ci	priv->msg_buf_remaining -= len;
1568c2ecf20Sopenharmony_ci	priv->msg_buf += len;
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic void xlp9xx_i2c_update_rlen(struct xlp9xx_i2c_dev *priv)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	u32 val, len;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	/*
1648c2ecf20Sopenharmony_ci	 * Update receive length. Re-read len to get the latest value,
1658c2ecf20Sopenharmony_ci	 * and then add 4 to have a minimum value that can be safely
1668c2ecf20Sopenharmony_ci	 * written. This is to account for the byte read above, the
1678c2ecf20Sopenharmony_ci	 * transfer in progress and any delays in the register I/O
1688c2ecf20Sopenharmony_ci	 */
1698c2ecf20Sopenharmony_ci	val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL);
1708c2ecf20Sopenharmony_ci	len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) &
1718c2ecf20Sopenharmony_ci				  XLP9XX_I2C_FIFO_WCNT_MASK;
1728c2ecf20Sopenharmony_ci	len = max_t(u32, priv->msg_len, len + 4);
1738c2ecf20Sopenharmony_ci	if (len >= I2C_SMBUS_BLOCK_MAX + 2)
1748c2ecf20Sopenharmony_ci		return;
1758c2ecf20Sopenharmony_ci	val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) |
1768c2ecf20Sopenharmony_ci			(len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT);
1778c2ecf20Sopenharmony_ci	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val);
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	u32 len, i;
1838c2ecf20Sopenharmony_ci	u8 rlen, *buf = priv->msg_buf;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) &
1868c2ecf20Sopenharmony_ci				  XLP9XX_I2C_FIFO_WCNT_MASK;
1878c2ecf20Sopenharmony_ci	if (!len)
1888c2ecf20Sopenharmony_ci		return;
1898c2ecf20Sopenharmony_ci	if (priv->len_recv) {
1908c2ecf20Sopenharmony_ci		/* read length byte */
1918c2ecf20Sopenharmony_ci		rlen = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci		/*
1948c2ecf20Sopenharmony_ci		 * We expect at least 2 interrupts for I2C_M_RECV_LEN
1958c2ecf20Sopenharmony_ci		 * transactions. The length is updated during the first
1968c2ecf20Sopenharmony_ci		 * interrupt, and the buffer contents are only copied
1978c2ecf20Sopenharmony_ci		 * during subsequent interrupts. If in case the interrupts
1988c2ecf20Sopenharmony_ci		 * get merged we would complete the transaction without
1998c2ecf20Sopenharmony_ci		 * copying out the bytes from RX fifo. To avoid this now we
2008c2ecf20Sopenharmony_ci		 * drain the fifo as and when data is available.
2018c2ecf20Sopenharmony_ci		 * We drained the rlen byte already, decrement total length
2028c2ecf20Sopenharmony_ci		 * by one.
2038c2ecf20Sopenharmony_ci		 */
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci		len--;
2068c2ecf20Sopenharmony_ci		if (rlen > I2C_SMBUS_BLOCK_MAX || rlen == 0) {
2078c2ecf20Sopenharmony_ci			rlen = 0;	/*abort transfer */
2088c2ecf20Sopenharmony_ci			priv->msg_buf_remaining = 0;
2098c2ecf20Sopenharmony_ci			priv->msg_len = 0;
2108c2ecf20Sopenharmony_ci			xlp9xx_i2c_update_rlen(priv);
2118c2ecf20Sopenharmony_ci			return;
2128c2ecf20Sopenharmony_ci		}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci		*buf++ = rlen;
2158c2ecf20Sopenharmony_ci		if (priv->client_pec)
2168c2ecf20Sopenharmony_ci			++rlen; /* account for error check byte */
2178c2ecf20Sopenharmony_ci		/* update remaining bytes and message length */
2188c2ecf20Sopenharmony_ci		priv->msg_buf_remaining = rlen;
2198c2ecf20Sopenharmony_ci		priv->msg_len = rlen + 1;
2208c2ecf20Sopenharmony_ci		xlp9xx_i2c_update_rlen(priv);
2218c2ecf20Sopenharmony_ci		priv->len_recv = false;
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	len = min(priv->msg_buf_remaining, len);
2258c2ecf20Sopenharmony_ci	for (i = 0; i < len; i++, buf++)
2268c2ecf20Sopenharmony_ci		*buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	priv->msg_buf_remaining -= len;
2298c2ecf20Sopenharmony_ci	priv->msg_buf = buf;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	if (priv->msg_buf_remaining)
2328c2ecf20Sopenharmony_ci		xlp9xx_i2c_update_rx_fifo_thres(priv);
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic irqreturn_t xlp9xx_i2c_isr(int irq, void *dev_id)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	struct xlp9xx_i2c_dev *priv = dev_id;
2388c2ecf20Sopenharmony_ci	u32 status;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	status = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTST);
2418c2ecf20Sopenharmony_ci	if (status == 0)
2428c2ecf20Sopenharmony_ci		return IRQ_NONE;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTST, status);
2458c2ecf20Sopenharmony_ci	if (status & XLP9XX_I2C_STATUS_ERRMASK) {
2468c2ecf20Sopenharmony_ci		priv->msg_err = status;
2478c2ecf20Sopenharmony_ci		goto xfer_done;
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	/* SADDR ACK for SMBUS_QUICK */
2518c2ecf20Sopenharmony_ci	if ((status & XLP9XX_I2C_INTEN_SADDR) && (priv->msg_len == 0))
2528c2ecf20Sopenharmony_ci		goto xfer_done;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	if (!priv->msg_read) {
2558c2ecf20Sopenharmony_ci		if (status & XLP9XX_I2C_INTEN_MFIFOEMTY) {
2568c2ecf20Sopenharmony_ci			/* TX FIFO got empty, fill it up again */
2578c2ecf20Sopenharmony_ci			if (priv->msg_buf_remaining)
2588c2ecf20Sopenharmony_ci				xlp9xx_i2c_fill_tx_fifo(priv);
2598c2ecf20Sopenharmony_ci			else
2608c2ecf20Sopenharmony_ci				xlp9xx_i2c_mask_irq(priv,
2618c2ecf20Sopenharmony_ci						    XLP9XX_I2C_INTEN_MFIFOEMTY);
2628c2ecf20Sopenharmony_ci		}
2638c2ecf20Sopenharmony_ci	} else {
2648c2ecf20Sopenharmony_ci		if (status & (XLP9XX_I2C_INTEN_DATADONE |
2658c2ecf20Sopenharmony_ci			      XLP9XX_I2C_INTEN_MFIFOHI)) {
2668c2ecf20Sopenharmony_ci			/* data is in FIFO, read it */
2678c2ecf20Sopenharmony_ci			if (priv->msg_buf_remaining)
2688c2ecf20Sopenharmony_ci				xlp9xx_i2c_drain_rx_fifo(priv);
2698c2ecf20Sopenharmony_ci		}
2708c2ecf20Sopenharmony_ci	}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	/* Transfer complete */
2738c2ecf20Sopenharmony_ci	if (status & XLP9XX_I2C_INTEN_DATADONE)
2748c2ecf20Sopenharmony_ci		goto xfer_done;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_cixfer_done:
2798c2ecf20Sopenharmony_ci	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0);
2808c2ecf20Sopenharmony_ci	complete(&priv->msg_complete);
2818c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistatic int xlp9xx_i2c_check_bus_status(struct xlp9xx_i2c_dev *priv)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	u32 status;
2878c2ecf20Sopenharmony_ci	u32 busy_timeout = XLP9XX_I2C_BUSY_TIMEOUT;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	while (busy_timeout) {
2908c2ecf20Sopenharmony_ci		status = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_STATUS);
2918c2ecf20Sopenharmony_ci		if ((status & XLP9XX_I2C_STATUS_BUSY) == 0)
2928c2ecf20Sopenharmony_ci			break;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci		busy_timeout--;
2958c2ecf20Sopenharmony_ci		usleep_range(1000, 1100);
2968c2ecf20Sopenharmony_ci	}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	if (!busy_timeout)
2998c2ecf20Sopenharmony_ci		return -EIO;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	return 0;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic int xlp9xx_i2c_init(struct xlp9xx_i2c_dev *priv)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	u32 prescale;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	/*
3098c2ecf20Sopenharmony_ci	 * The controller uses 5 * SCL clock internally.
3108c2ecf20Sopenharmony_ci	 * So prescale value should be divided by 5.
3118c2ecf20Sopenharmony_ci	 */
3128c2ecf20Sopenharmony_ci	prescale = DIV_ROUND_UP(priv->ip_clk_hz, priv->clk_hz);
3138c2ecf20Sopenharmony_ci	prescale = ((prescale - 8) / 5) - 1;
3148c2ecf20Sopenharmony_ci	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_RST);
3158c2ecf20Sopenharmony_ci	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_EN |
3168c2ecf20Sopenharmony_ci			     XLP9XX_I2C_CTRL_MASTER);
3178c2ecf20Sopenharmony_ci	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_DIV, prescale);
3188c2ecf20Sopenharmony_ci	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	return 0;
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cistatic int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg,
3248c2ecf20Sopenharmony_ci			       int last_msg)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	unsigned long timeleft;
3278c2ecf20Sopenharmony_ci	u32 intr_mask, cmd, val, len;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	priv->msg_buf = msg->buf;
3308c2ecf20Sopenharmony_ci	priv->msg_buf_remaining = priv->msg_len = msg->len;
3318c2ecf20Sopenharmony_ci	priv->msg_err = 0;
3328c2ecf20Sopenharmony_ci	priv->msg_read = (msg->flags & I2C_M_RD);
3338c2ecf20Sopenharmony_ci	reinit_completion(&priv->msg_complete);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	/* Reset FIFO */
3368c2ecf20Sopenharmony_ci	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL,
3378c2ecf20Sopenharmony_ci			     XLP9XX_I2C_MFIFOCTRL_RST);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	/* set slave addr */
3408c2ecf20Sopenharmony_ci	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_SLAVEADDR,
3418c2ecf20Sopenharmony_ci			     (msg->addr << XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT) |
3428c2ecf20Sopenharmony_ci			     (priv->msg_read ? XLP9XX_I2C_SLAVEADDR_RW : 0));
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	/* Build control word for transfer */
3458c2ecf20Sopenharmony_ci	val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL);
3468c2ecf20Sopenharmony_ci	if (!priv->msg_read)
3478c2ecf20Sopenharmony_ci		val &= ~XLP9XX_I2C_CTRL_FIFORD;
3488c2ecf20Sopenharmony_ci	else
3498c2ecf20Sopenharmony_ci		val |= XLP9XX_I2C_CTRL_FIFORD;	/* read */
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	if (msg->flags & I2C_M_TEN)
3528c2ecf20Sopenharmony_ci		val |= XLP9XX_I2C_CTRL_ADDMODE;	/* 10-bit address mode*/
3538c2ecf20Sopenharmony_ci	else
3548c2ecf20Sopenharmony_ci		val &= ~XLP9XX_I2C_CTRL_ADDMODE;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	priv->len_recv = msg->flags & I2C_M_RECV_LEN;
3578c2ecf20Sopenharmony_ci	len = priv->len_recv ? I2C_SMBUS_BLOCK_MAX + 2 : msg->len;
3588c2ecf20Sopenharmony_ci	priv->client_pec = msg->flags & I2C_CLIENT_PEC;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	/* set FIFO threshold if reading */
3618c2ecf20Sopenharmony_ci	if (priv->msg_read)
3628c2ecf20Sopenharmony_ci		xlp9xx_i2c_update_rx_fifo_thres(priv);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	/* set data length to be transferred */
3658c2ecf20Sopenharmony_ci	val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) |
3668c2ecf20Sopenharmony_ci	      (len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT);
3678c2ecf20Sopenharmony_ci	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	/* fill fifo during tx */
3708c2ecf20Sopenharmony_ci	if (!priv->msg_read)
3718c2ecf20Sopenharmony_ci		xlp9xx_i2c_fill_tx_fifo(priv);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	/* set interrupt mask */
3748c2ecf20Sopenharmony_ci	intr_mask = (XLP9XX_I2C_INTEN_ARLOST | XLP9XX_I2C_INTEN_BUSERR |
3758c2ecf20Sopenharmony_ci		     XLP9XX_I2C_INTEN_NACKADDR | XLP9XX_I2C_INTEN_DATADONE);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	if (priv->msg_read) {
3788c2ecf20Sopenharmony_ci		intr_mask |= XLP9XX_I2C_INTEN_MFIFOHI;
3798c2ecf20Sopenharmony_ci		if (msg->len == 0)
3808c2ecf20Sopenharmony_ci			intr_mask |= XLP9XX_I2C_INTEN_SADDR;
3818c2ecf20Sopenharmony_ci	} else {
3828c2ecf20Sopenharmony_ci		if (msg->len == 0)
3838c2ecf20Sopenharmony_ci			intr_mask |= XLP9XX_I2C_INTEN_SADDR;
3848c2ecf20Sopenharmony_ci		else
3858c2ecf20Sopenharmony_ci			intr_mask |= XLP9XX_I2C_INTEN_MFIFOEMTY;
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci	xlp9xx_i2c_unmask_irq(priv, intr_mask);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	/* set cmd reg */
3908c2ecf20Sopenharmony_ci	cmd = XLP9XX_I2C_CMD_START;
3918c2ecf20Sopenharmony_ci	if (msg->len)
3928c2ecf20Sopenharmony_ci		cmd |= (priv->msg_read ?
3938c2ecf20Sopenharmony_ci			XLP9XX_I2C_CMD_READ : XLP9XX_I2C_CMD_WRITE);
3948c2ecf20Sopenharmony_ci	if (last_msg)
3958c2ecf20Sopenharmony_ci		cmd |= XLP9XX_I2C_CMD_STOP;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CMD, cmd);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	timeleft = msecs_to_jiffies(XLP9XX_I2C_TIMEOUT_MS);
4008c2ecf20Sopenharmony_ci	timeleft = wait_for_completion_timeout(&priv->msg_complete, timeleft);
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	if (priv->msg_err & XLP9XX_I2C_INTEN_BUSERR) {
4038c2ecf20Sopenharmony_ci		dev_dbg(priv->dev, "transfer error %x!\n", priv->msg_err);
4048c2ecf20Sopenharmony_ci		xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CMD, XLP9XX_I2C_CMD_STOP);
4058c2ecf20Sopenharmony_ci		return -EIO;
4068c2ecf20Sopenharmony_ci	} else if (priv->msg_err & XLP9XX_I2C_INTEN_NACKADDR) {
4078c2ecf20Sopenharmony_ci		return -ENXIO;
4088c2ecf20Sopenharmony_ci	}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	if (timeleft == 0) {
4118c2ecf20Sopenharmony_ci		dev_dbg(priv->dev, "i2c transfer timed out!\n");
4128c2ecf20Sopenharmony_ci		xlp9xx_i2c_init(priv);
4138c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
4148c2ecf20Sopenharmony_ci	}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	/* update msg->len with actual received length */
4178c2ecf20Sopenharmony_ci	if (msg->flags & I2C_M_RECV_LEN) {
4188c2ecf20Sopenharmony_ci		if (!priv->msg_len)
4198c2ecf20Sopenharmony_ci			return -EPROTO;
4208c2ecf20Sopenharmony_ci		msg->len = priv->msg_len;
4218c2ecf20Sopenharmony_ci	}
4228c2ecf20Sopenharmony_ci	return 0;
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistatic int xlp9xx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
4268c2ecf20Sopenharmony_ci			   int num)
4278c2ecf20Sopenharmony_ci{
4288c2ecf20Sopenharmony_ci	int i, ret;
4298c2ecf20Sopenharmony_ci	struct xlp9xx_i2c_dev *priv = i2c_get_adapdata(adap);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	ret = xlp9xx_i2c_check_bus_status(priv);
4328c2ecf20Sopenharmony_ci	if (ret) {
4338c2ecf20Sopenharmony_ci		xlp9xx_i2c_init(priv);
4348c2ecf20Sopenharmony_ci		ret = xlp9xx_i2c_check_bus_status(priv);
4358c2ecf20Sopenharmony_ci		if (ret)
4368c2ecf20Sopenharmony_ci			return ret;
4378c2ecf20Sopenharmony_ci	}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++) {
4408c2ecf20Sopenharmony_ci		ret = xlp9xx_i2c_xfer_msg(priv, &msgs[i], i == num - 1);
4418c2ecf20Sopenharmony_ci		if (ret != 0)
4428c2ecf20Sopenharmony_ci			return ret;
4438c2ecf20Sopenharmony_ci	}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	return num;
4468c2ecf20Sopenharmony_ci}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_cistatic u32 xlp9xx_i2c_functionality(struct i2c_adapter *adapter)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_READ_BLOCK_DATA |
4518c2ecf20Sopenharmony_ci			I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR;
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_cistatic const struct i2c_algorithm xlp9xx_i2c_algo = {
4558c2ecf20Sopenharmony_ci	.master_xfer = xlp9xx_i2c_xfer,
4568c2ecf20Sopenharmony_ci	.functionality = xlp9xx_i2c_functionality,
4578c2ecf20Sopenharmony_ci};
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_cistatic int xlp9xx_i2c_get_frequency(struct platform_device *pdev,
4608c2ecf20Sopenharmony_ci				    struct xlp9xx_i2c_dev *priv)
4618c2ecf20Sopenharmony_ci{
4628c2ecf20Sopenharmony_ci	struct clk *clk;
4638c2ecf20Sopenharmony_ci	u32 freq;
4648c2ecf20Sopenharmony_ci	int err;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	clk = devm_clk_get(&pdev->dev, NULL);
4678c2ecf20Sopenharmony_ci	if (IS_ERR(clk)) {
4688c2ecf20Sopenharmony_ci		priv->ip_clk_hz = XLP9XX_I2C_IP_CLK_FREQ;
4698c2ecf20Sopenharmony_ci		dev_dbg(&pdev->dev, "using default input frequency %u\n",
4708c2ecf20Sopenharmony_ci			priv->ip_clk_hz);
4718c2ecf20Sopenharmony_ci	} else {
4728c2ecf20Sopenharmony_ci		priv->ip_clk_hz = clk_get_rate(clk);
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	err = device_property_read_u32(&pdev->dev, "clock-frequency", &freq);
4768c2ecf20Sopenharmony_ci	if (err) {
4778c2ecf20Sopenharmony_ci		freq = I2C_MAX_STANDARD_MODE_FREQ;
4788c2ecf20Sopenharmony_ci		dev_dbg(&pdev->dev, "using default frequency %u\n", freq);
4798c2ecf20Sopenharmony_ci	} else if (freq == 0 || freq > I2C_MAX_FAST_MODE_FREQ) {
4808c2ecf20Sopenharmony_ci		dev_warn(&pdev->dev, "invalid frequency %u, using default\n",
4818c2ecf20Sopenharmony_ci			 freq);
4828c2ecf20Sopenharmony_ci		freq = I2C_MAX_STANDARD_MODE_FREQ;
4838c2ecf20Sopenharmony_ci	}
4848c2ecf20Sopenharmony_ci	priv->clk_hz = freq;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	return 0;
4878c2ecf20Sopenharmony_ci}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_cistatic int xlp9xx_i2c_smbus_setup(struct xlp9xx_i2c_dev *priv,
4908c2ecf20Sopenharmony_ci				  struct platform_device *pdev)
4918c2ecf20Sopenharmony_ci{
4928c2ecf20Sopenharmony_ci	struct i2c_client *ara;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	if (!priv->alert_data.irq)
4958c2ecf20Sopenharmony_ci		return -EINVAL;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	ara = i2c_new_smbus_alert_device(&priv->adapter, &priv->alert_data);
4988c2ecf20Sopenharmony_ci	if (IS_ERR(ara))
4998c2ecf20Sopenharmony_ci		return PTR_ERR(ara);
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	priv->ara = ara;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	return 0;
5048c2ecf20Sopenharmony_ci}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_cistatic int xlp9xx_i2c_probe(struct platform_device *pdev)
5078c2ecf20Sopenharmony_ci{
5088c2ecf20Sopenharmony_ci	struct xlp9xx_i2c_dev *priv;
5098c2ecf20Sopenharmony_ci	int err = 0;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
5128c2ecf20Sopenharmony_ci	if (!priv)
5138c2ecf20Sopenharmony_ci		return -ENOMEM;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	priv->base = devm_platform_ioremap_resource(pdev, 0);
5168c2ecf20Sopenharmony_ci	if (IS_ERR(priv->base))
5178c2ecf20Sopenharmony_ci		return PTR_ERR(priv->base);
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	priv->irq = platform_get_irq(pdev, 0);
5208c2ecf20Sopenharmony_ci	if (priv->irq < 0)
5218c2ecf20Sopenharmony_ci		return priv->irq;
5228c2ecf20Sopenharmony_ci	/* SMBAlert irq */
5238c2ecf20Sopenharmony_ci	priv->alert_data.irq = platform_get_irq(pdev, 1);
5248c2ecf20Sopenharmony_ci	if (priv->alert_data.irq <= 0)
5258c2ecf20Sopenharmony_ci		priv->alert_data.irq = 0;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	xlp9xx_i2c_get_frequency(pdev, priv);
5288c2ecf20Sopenharmony_ci	xlp9xx_i2c_init(priv);
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	err = devm_request_irq(&pdev->dev, priv->irq, xlp9xx_i2c_isr, 0,
5318c2ecf20Sopenharmony_ci			       pdev->name, priv);
5328c2ecf20Sopenharmony_ci	if (err) {
5338c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "IRQ request failed!\n");
5348c2ecf20Sopenharmony_ci		return err;
5358c2ecf20Sopenharmony_ci	}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	init_completion(&priv->msg_complete);
5388c2ecf20Sopenharmony_ci	priv->adapter.dev.parent = &pdev->dev;
5398c2ecf20Sopenharmony_ci	priv->adapter.algo = &xlp9xx_i2c_algo;
5408c2ecf20Sopenharmony_ci	priv->adapter.class = I2C_CLASS_HWMON;
5418c2ecf20Sopenharmony_ci	ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&pdev->dev));
5428c2ecf20Sopenharmony_ci	priv->adapter.dev.of_node = pdev->dev.of_node;
5438c2ecf20Sopenharmony_ci	priv->dev = &pdev->dev;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	snprintf(priv->adapter.name, sizeof(priv->adapter.name), "xlp9xx-i2c");
5468c2ecf20Sopenharmony_ci	i2c_set_adapdata(&priv->adapter, priv);
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	err = i2c_add_adapter(&priv->adapter);
5498c2ecf20Sopenharmony_ci	if (err)
5508c2ecf20Sopenharmony_ci		return err;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	err = xlp9xx_i2c_smbus_setup(priv, pdev);
5538c2ecf20Sopenharmony_ci	if (err)
5548c2ecf20Sopenharmony_ci		dev_dbg(&pdev->dev, "No active SMBus alert %d\n", err);
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, priv);
5578c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "I2C bus:%d added\n", priv->adapter.nr);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	return 0;
5608c2ecf20Sopenharmony_ci}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_cistatic int xlp9xx_i2c_remove(struct platform_device *pdev)
5638c2ecf20Sopenharmony_ci{
5648c2ecf20Sopenharmony_ci	struct xlp9xx_i2c_dev *priv;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	priv = platform_get_drvdata(pdev);
5678c2ecf20Sopenharmony_ci	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0);
5688c2ecf20Sopenharmony_ci	synchronize_irq(priv->irq);
5698c2ecf20Sopenharmony_ci	i2c_del_adapter(&priv->adapter);
5708c2ecf20Sopenharmony_ci	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, 0);
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	return 0;
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_cistatic const struct of_device_id xlp9xx_i2c_of_match[] = {
5768c2ecf20Sopenharmony_ci	{ .compatible = "netlogic,xlp980-i2c", },
5778c2ecf20Sopenharmony_ci	{ /* sentinel */ },
5788c2ecf20Sopenharmony_ci};
5798c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, xlp9xx_i2c_of_match);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
5828c2ecf20Sopenharmony_cistatic const struct acpi_device_id xlp9xx_i2c_acpi_ids[] = {
5838c2ecf20Sopenharmony_ci	{"BRCM9007", 0},
5848c2ecf20Sopenharmony_ci	{"CAV9007",  0},
5858c2ecf20Sopenharmony_ci	{}
5868c2ecf20Sopenharmony_ci};
5878c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, xlp9xx_i2c_acpi_ids);
5888c2ecf20Sopenharmony_ci#endif
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_cistatic struct platform_driver xlp9xx_i2c_driver = {
5918c2ecf20Sopenharmony_ci	.probe = xlp9xx_i2c_probe,
5928c2ecf20Sopenharmony_ci	.remove = xlp9xx_i2c_remove,
5938c2ecf20Sopenharmony_ci	.driver = {
5948c2ecf20Sopenharmony_ci		.name = "xlp9xx-i2c",
5958c2ecf20Sopenharmony_ci		.of_match_table = xlp9xx_i2c_of_match,
5968c2ecf20Sopenharmony_ci		.acpi_match_table = ACPI_PTR(xlp9xx_i2c_acpi_ids),
5978c2ecf20Sopenharmony_ci	},
5988c2ecf20Sopenharmony_ci};
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_cimodule_platform_driver(xlp9xx_i2c_driver);
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ciMODULE_AUTHOR("Subhendu Sekhar Behera <sbehera@broadcom.com>");
6038c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("XLP9XX/5XX I2C Bus Controller Driver");
6048c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
605