18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * I2C bus driver for CSR SiRFprimaII
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/slab.h>
128c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
138c2ecf20Sopenharmony_ci#include <linux/i2c.h>
148c2ecf20Sopenharmony_ci#include <linux/clk.h>
158c2ecf20Sopenharmony_ci#include <linux/err.h>
168c2ecf20Sopenharmony_ci#include <linux/io.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CLK_CTRL		0x00
198c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_STATUS		0x0C
208c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CTRL		0x10
218c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_IO_CTRL		0x14
228c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_SDA_DELAY		0x18
238c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CMD_START		0x1C
248c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CMD_BUF		0x30
258c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_DATA_BUF		0x80
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CMD_BUF_MAX		16
288c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_DATA_BUF_MAX	16
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CMD(x)		(SIRFSOC_I2C_CMD_BUF + (x)*0x04)
318c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_DATA_MASK(x)        (0xFF<<(((x)&3)*8))
328c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_DATA_SHIFT(x)       (((x)&3)*8)
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_DIV_MASK		(0xFFFF)
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/* I2C status flags */
378c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_STAT_BUSY		BIT(0)
388c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_STAT_TIP		BIT(1)
398c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_STAT_NACK		BIT(2)
408c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_STAT_TR_INT		BIT(4)
418c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_STAT_STOP		BIT(6)
428c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_STAT_CMD_DONE	BIT(8)
438c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_STAT_ERR		BIT(9)
448c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CMD_INDEX		(0x1F<<16)
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/* I2C control flags */
478c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_RESET		BIT(0)
488c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CORE_EN		BIT(1)
498c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_MASTER_MODE		BIT(2)
508c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CMD_DONE_EN		BIT(11)
518c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_ERR_INT_EN		BIT(12)
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_SDA_DELAY_MASK	(0xFF)
548c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_SCLF_FILTER		(3<<8)
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_START_CMD		BIT(0)
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_CMD_RP(x)		((x)&0x7)
598c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_NACK		BIT(3)
608c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_WRITE		BIT(4)
618c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_READ		BIT(5)
628c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_STOP		BIT(6)
638c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_START		BIT(7)
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_ERR_NOACK      1
668c2ecf20Sopenharmony_ci#define SIRFSOC_I2C_ERR_TIMEOUT    2
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistruct sirfsoc_i2c {
698c2ecf20Sopenharmony_ci	void __iomem *base;
708c2ecf20Sopenharmony_ci	struct clk *clk;
718c2ecf20Sopenharmony_ci	u32 cmd_ptr;		/* Current position in CMD buffer */
728c2ecf20Sopenharmony_ci	u8 *buf;		/* Buffer passed by user */
738c2ecf20Sopenharmony_ci	u32 msg_len;		/* Message length */
748c2ecf20Sopenharmony_ci	u32 finished_len;	/* number of bytes read/written */
758c2ecf20Sopenharmony_ci	u32 read_cmd_len;	/* number of read cmd sent */
768c2ecf20Sopenharmony_ci	int msg_read;		/* 1 indicates a read message */
778c2ecf20Sopenharmony_ci	int err_status;		/* 1 indicates an error on bus */
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	u32 sda_delay;		/* For suspend/resume */
808c2ecf20Sopenharmony_ci	u32 clk_div;
818c2ecf20Sopenharmony_ci	int last;		/* Last message in transfer, STOP cmd can be sent */
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	struct completion done;	/* indicates completion of message transfer */
848c2ecf20Sopenharmony_ci	struct i2c_adapter adapter;
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic void i2c_sirfsoc_read_data(struct sirfsoc_i2c *siic)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	u32 data = 0;
908c2ecf20Sopenharmony_ci	int i;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	for (i = 0; i < siic->read_cmd_len; i++) {
938c2ecf20Sopenharmony_ci		if (!(i & 0x3))
948c2ecf20Sopenharmony_ci			data = readl(siic->base + SIRFSOC_I2C_DATA_BUF + i);
958c2ecf20Sopenharmony_ci		siic->buf[siic->finished_len++] =
968c2ecf20Sopenharmony_ci			(u8)((data & SIRFSOC_I2C_DATA_MASK(i)) >>
978c2ecf20Sopenharmony_ci				SIRFSOC_I2C_DATA_SHIFT(i));
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic void i2c_sirfsoc_queue_cmd(struct sirfsoc_i2c *siic)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	u32 regval;
1048c2ecf20Sopenharmony_ci	int i = 0;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	if (siic->msg_read) {
1078c2ecf20Sopenharmony_ci		while (((siic->finished_len + i) < siic->msg_len)
1088c2ecf20Sopenharmony_ci				&& (siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX)) {
1098c2ecf20Sopenharmony_ci			regval = SIRFSOC_I2C_READ | SIRFSOC_I2C_CMD_RP(0);
1108c2ecf20Sopenharmony_ci			if (((siic->finished_len + i) ==
1118c2ecf20Sopenharmony_ci					(siic->msg_len - 1)) && siic->last)
1128c2ecf20Sopenharmony_ci				regval |= SIRFSOC_I2C_STOP | SIRFSOC_I2C_NACK;
1138c2ecf20Sopenharmony_ci			writel(regval,
1148c2ecf20Sopenharmony_ci				siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
1158c2ecf20Sopenharmony_ci			i++;
1168c2ecf20Sopenharmony_ci		}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci		siic->read_cmd_len = i;
1198c2ecf20Sopenharmony_ci	} else {
1208c2ecf20Sopenharmony_ci		while ((siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX - 1)
1218c2ecf20Sopenharmony_ci				&& (siic->finished_len < siic->msg_len)) {
1228c2ecf20Sopenharmony_ci			regval = SIRFSOC_I2C_WRITE | SIRFSOC_I2C_CMD_RP(0);
1238c2ecf20Sopenharmony_ci			if ((siic->finished_len == (siic->msg_len - 1))
1248c2ecf20Sopenharmony_ci				&& siic->last)
1258c2ecf20Sopenharmony_ci				regval |= SIRFSOC_I2C_STOP;
1268c2ecf20Sopenharmony_ci			writel(regval,
1278c2ecf20Sopenharmony_ci				siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
1288c2ecf20Sopenharmony_ci			writel(siic->buf[siic->finished_len++],
1298c2ecf20Sopenharmony_ci				siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
1308c2ecf20Sopenharmony_ci		}
1318c2ecf20Sopenharmony_ci	}
1328c2ecf20Sopenharmony_ci	siic->cmd_ptr = 0;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	/* Trigger the transfer */
1358c2ecf20Sopenharmony_ci	writel(SIRFSOC_I2C_START_CMD, siic->base + SIRFSOC_I2C_CMD_START);
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic irqreturn_t i2c_sirfsoc_irq(int irq, void *dev_id)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	struct sirfsoc_i2c *siic = (struct sirfsoc_i2c *)dev_id;
1418c2ecf20Sopenharmony_ci	u32 i2c_stat = readl(siic->base + SIRFSOC_I2C_STATUS);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	if (i2c_stat & SIRFSOC_I2C_STAT_ERR) {
1448c2ecf20Sopenharmony_ci		/* Error conditions */
1458c2ecf20Sopenharmony_ci		siic->err_status = SIRFSOC_I2C_ERR_NOACK;
1468c2ecf20Sopenharmony_ci		writel(SIRFSOC_I2C_STAT_ERR, siic->base + SIRFSOC_I2C_STATUS);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci		if (i2c_stat & SIRFSOC_I2C_STAT_NACK)
1498c2ecf20Sopenharmony_ci			dev_dbg(&siic->adapter.dev, "ACK not received\n");
1508c2ecf20Sopenharmony_ci		else
1518c2ecf20Sopenharmony_ci			dev_err(&siic->adapter.dev, "I2C error\n");
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci		/*
1548c2ecf20Sopenharmony_ci		 * Due to hardware ANOMALY, we need to reset I2C earlier after
1558c2ecf20Sopenharmony_ci		 * we get NOACK while accessing non-existing clients, otherwise
1568c2ecf20Sopenharmony_ci		 * we will get errors even we access existing clients later
1578c2ecf20Sopenharmony_ci		 */
1588c2ecf20Sopenharmony_ci		writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET,
1598c2ecf20Sopenharmony_ci				siic->base + SIRFSOC_I2C_CTRL);
1608c2ecf20Sopenharmony_ci		while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
1618c2ecf20Sopenharmony_ci			cpu_relax();
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci		complete(&siic->done);
1648c2ecf20Sopenharmony_ci	} else if (i2c_stat & SIRFSOC_I2C_STAT_CMD_DONE) {
1658c2ecf20Sopenharmony_ci		/* CMD buffer execution complete */
1668c2ecf20Sopenharmony_ci		if (siic->msg_read)
1678c2ecf20Sopenharmony_ci			i2c_sirfsoc_read_data(siic);
1688c2ecf20Sopenharmony_ci		if (siic->finished_len == siic->msg_len)
1698c2ecf20Sopenharmony_ci			complete(&siic->done);
1708c2ecf20Sopenharmony_ci		else /* Fill a new CMD buffer for left data */
1718c2ecf20Sopenharmony_ci			i2c_sirfsoc_queue_cmd(siic);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci		writel(SIRFSOC_I2C_STAT_CMD_DONE, siic->base + SIRFSOC_I2C_STATUS);
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic void i2c_sirfsoc_set_address(struct sirfsoc_i2c *siic,
1808c2ecf20Sopenharmony_ci	struct i2c_msg *msg)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	unsigned char addr;
1838c2ecf20Sopenharmony_ci	u32 regval = SIRFSOC_I2C_START | SIRFSOC_I2C_CMD_RP(0) | SIRFSOC_I2C_WRITE;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	/* no data and last message -> add STOP */
1868c2ecf20Sopenharmony_ci	if (siic->last && (msg->len == 0))
1878c2ecf20Sopenharmony_ci		regval |= SIRFSOC_I2C_STOP;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	writel(regval, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	addr = i2c_8bit_addr_from_msg(msg);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	/* Reverse direction bit */
1948c2ecf20Sopenharmony_ci	if (msg->flags & I2C_M_REV_DIR_ADDR)
1958c2ecf20Sopenharmony_ci		addr ^= 1;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	writel(addr, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic int i2c_sirfsoc_xfer_msg(struct sirfsoc_i2c *siic, struct i2c_msg *msg)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	u32 regval = readl(siic->base + SIRFSOC_I2C_CTRL);
2038c2ecf20Sopenharmony_ci	/* timeout waiting for the xfer to finish or fail */
2048c2ecf20Sopenharmony_ci	int timeout = msecs_to_jiffies((msg->len + 1) * 50);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	i2c_sirfsoc_set_address(siic, msg);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	writel(regval | SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN,
2098c2ecf20Sopenharmony_ci		siic->base + SIRFSOC_I2C_CTRL);
2108c2ecf20Sopenharmony_ci	i2c_sirfsoc_queue_cmd(siic);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	if (wait_for_completion_timeout(&siic->done, timeout) == 0) {
2138c2ecf20Sopenharmony_ci		siic->err_status = SIRFSOC_I2C_ERR_TIMEOUT;
2148c2ecf20Sopenharmony_ci		dev_err(&siic->adapter.dev, "Transfer timeout\n");
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	writel(regval & ~(SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN),
2188c2ecf20Sopenharmony_ci		siic->base + SIRFSOC_I2C_CTRL);
2198c2ecf20Sopenharmony_ci	writel(0, siic->base + SIRFSOC_I2C_CMD_START);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	/* i2c control doesn't response, reset it */
2228c2ecf20Sopenharmony_ci	if (siic->err_status == SIRFSOC_I2C_ERR_TIMEOUT) {
2238c2ecf20Sopenharmony_ci		writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET,
2248c2ecf20Sopenharmony_ci			siic->base + SIRFSOC_I2C_CTRL);
2258c2ecf20Sopenharmony_ci		while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
2268c2ecf20Sopenharmony_ci			cpu_relax();
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci	return siic->err_status ? -EAGAIN : 0;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic u32 i2c_sirfsoc_func(struct i2c_adapter *adap)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic int i2c_sirfsoc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
2378c2ecf20Sopenharmony_ci	int num)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	struct sirfsoc_i2c *siic = adap->algo_data;
2408c2ecf20Sopenharmony_ci	int i, ret;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	clk_enable(siic->clk);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++) {
2458c2ecf20Sopenharmony_ci		siic->buf = msgs[i].buf;
2468c2ecf20Sopenharmony_ci		siic->msg_len = msgs[i].len;
2478c2ecf20Sopenharmony_ci		siic->msg_read = !!(msgs[i].flags & I2C_M_RD);
2488c2ecf20Sopenharmony_ci		siic->err_status = 0;
2498c2ecf20Sopenharmony_ci		siic->cmd_ptr = 0;
2508c2ecf20Sopenharmony_ci		siic->finished_len = 0;
2518c2ecf20Sopenharmony_ci		siic->last = (i == (num - 1));
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci		ret = i2c_sirfsoc_xfer_msg(siic, &msgs[i]);
2548c2ecf20Sopenharmony_ci		if (ret) {
2558c2ecf20Sopenharmony_ci			clk_disable(siic->clk);
2568c2ecf20Sopenharmony_ci			return ret;
2578c2ecf20Sopenharmony_ci		}
2588c2ecf20Sopenharmony_ci	}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	clk_disable(siic->clk);
2618c2ecf20Sopenharmony_ci	return num;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci/* I2C algorithms associated with this master controller driver */
2658c2ecf20Sopenharmony_cistatic const struct i2c_algorithm i2c_sirfsoc_algo = {
2668c2ecf20Sopenharmony_ci	.master_xfer = i2c_sirfsoc_xfer,
2678c2ecf20Sopenharmony_ci	.functionality = i2c_sirfsoc_func,
2688c2ecf20Sopenharmony_ci};
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistatic int i2c_sirfsoc_probe(struct platform_device *pdev)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	struct sirfsoc_i2c *siic;
2738c2ecf20Sopenharmony_ci	struct i2c_adapter *adap;
2748c2ecf20Sopenharmony_ci	struct clk *clk;
2758c2ecf20Sopenharmony_ci	int bitrate;
2768c2ecf20Sopenharmony_ci	int ctrl_speed;
2778c2ecf20Sopenharmony_ci	int irq;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	int err;
2808c2ecf20Sopenharmony_ci	u32 regval;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	clk = clk_get(&pdev->dev, NULL);
2838c2ecf20Sopenharmony_ci	if (IS_ERR(clk)) {
2848c2ecf20Sopenharmony_ci		err = PTR_ERR(clk);
2858c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Clock get failed\n");
2868c2ecf20Sopenharmony_ci		goto err_get_clk;
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	err = clk_prepare(clk);
2908c2ecf20Sopenharmony_ci	if (err) {
2918c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Clock prepare failed\n");
2928c2ecf20Sopenharmony_ci		goto err_clk_prep;
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	err = clk_enable(clk);
2968c2ecf20Sopenharmony_ci	if (err) {
2978c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Clock enable failed\n");
2988c2ecf20Sopenharmony_ci		goto err_clk_en;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	ctrl_speed = clk_get_rate(clk);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	siic = devm_kzalloc(&pdev->dev, sizeof(*siic), GFP_KERNEL);
3048c2ecf20Sopenharmony_ci	if (!siic) {
3058c2ecf20Sopenharmony_ci		err = -ENOMEM;
3068c2ecf20Sopenharmony_ci		goto out;
3078c2ecf20Sopenharmony_ci	}
3088c2ecf20Sopenharmony_ci	adap = &siic->adapter;
3098c2ecf20Sopenharmony_ci	adap->class = I2C_CLASS_DEPRECATED;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	siic->base = devm_platform_ioremap_resource(pdev, 0);
3128c2ecf20Sopenharmony_ci	if (IS_ERR(siic->base)) {
3138c2ecf20Sopenharmony_ci		err = PTR_ERR(siic->base);
3148c2ecf20Sopenharmony_ci		goto out;
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
3188c2ecf20Sopenharmony_ci	if (irq < 0) {
3198c2ecf20Sopenharmony_ci		err = irq;
3208c2ecf20Sopenharmony_ci		goto out;
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci	err = devm_request_irq(&pdev->dev, irq, i2c_sirfsoc_irq, 0,
3238c2ecf20Sopenharmony_ci		dev_name(&pdev->dev), siic);
3248c2ecf20Sopenharmony_ci	if (err)
3258c2ecf20Sopenharmony_ci		goto out;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	adap->algo = &i2c_sirfsoc_algo;
3288c2ecf20Sopenharmony_ci	adap->algo_data = siic;
3298c2ecf20Sopenharmony_ci	adap->retries = 3;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	adap->dev.of_node = pdev->dev.of_node;
3328c2ecf20Sopenharmony_ci	adap->dev.parent = &pdev->dev;
3338c2ecf20Sopenharmony_ci	adap->nr = pdev->id;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	strlcpy(adap->name, "sirfsoc-i2c", sizeof(adap->name));
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, adap);
3388c2ecf20Sopenharmony_ci	init_completion(&siic->done);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	/* Controller initialisation */
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
3438c2ecf20Sopenharmony_ci	while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
3448c2ecf20Sopenharmony_ci		cpu_relax();
3458c2ecf20Sopenharmony_ci	writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE,
3468c2ecf20Sopenharmony_ci		siic->base + SIRFSOC_I2C_CTRL);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	siic->clk = clk;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	err = of_property_read_u32(pdev->dev.of_node,
3518c2ecf20Sopenharmony_ci		"clock-frequency", &bitrate);
3528c2ecf20Sopenharmony_ci	if (err < 0)
3538c2ecf20Sopenharmony_ci		bitrate = I2C_MAX_STANDARD_MODE_FREQ;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	/*
3568c2ecf20Sopenharmony_ci	 * Due to some hardware design issues, we need to tune the formula.
3578c2ecf20Sopenharmony_ci	 * Since i2c is open drain interface that allows the slave to
3588c2ecf20Sopenharmony_ci	 * stall the transaction by holding the SCL line at '0', the RTL
3598c2ecf20Sopenharmony_ci	 * implementation is waiting for SCL feedback from the pin after
3608c2ecf20Sopenharmony_ci	 * setting it to High-Z ('1'). This wait adds to the high-time
3618c2ecf20Sopenharmony_ci	 * interval counter few cycles of the input synchronization
3628c2ecf20Sopenharmony_ci	 * (depending on the SCL_FILTER_REG field), and also the time it
3638c2ecf20Sopenharmony_ci	 * takes for the board pull-up resistor to rise the SCL line.
3648c2ecf20Sopenharmony_ci	 * For slow SCL settings these additions are negligible,
3658c2ecf20Sopenharmony_ci	 * but they start to affect the speed when clock is set to faster
3668c2ecf20Sopenharmony_ci	 * frequencies.
3678c2ecf20Sopenharmony_ci	 * Through the actual tests, use the different user_div value(which
3688c2ecf20Sopenharmony_ci	 * in the divider formula 'Fio / (Fi2c * user_div)') to adapt
3698c2ecf20Sopenharmony_ci	 * the different ranges of i2c bus clock frequency, to make the SCL
3708c2ecf20Sopenharmony_ci	 * more accurate.
3718c2ecf20Sopenharmony_ci	 */
3728c2ecf20Sopenharmony_ci	if (bitrate <= 30000)
3738c2ecf20Sopenharmony_ci		regval = ctrl_speed / (bitrate * 5);
3748c2ecf20Sopenharmony_ci	else if (bitrate > 30000 && bitrate <= 280000)
3758c2ecf20Sopenharmony_ci		regval = (2 * ctrl_speed) / (bitrate * 11);
3768c2ecf20Sopenharmony_ci	else
3778c2ecf20Sopenharmony_ci		regval = ctrl_speed / (bitrate * 6);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	writel(regval, siic->base + SIRFSOC_I2C_CLK_CTRL);
3808c2ecf20Sopenharmony_ci	if (regval > 0xFF)
3818c2ecf20Sopenharmony_ci		writel(0xFF, siic->base + SIRFSOC_I2C_SDA_DELAY);
3828c2ecf20Sopenharmony_ci	else
3838c2ecf20Sopenharmony_ci		writel(regval, siic->base + SIRFSOC_I2C_SDA_DELAY);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	err = i2c_add_numbered_adapter(adap);
3868c2ecf20Sopenharmony_ci	if (err < 0)
3878c2ecf20Sopenharmony_ci		goto out;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	clk_disable(clk);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	dev_info(&pdev->dev, " I2C adapter ready to operate\n");
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	return 0;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ciout:
3968c2ecf20Sopenharmony_ci	clk_disable(clk);
3978c2ecf20Sopenharmony_cierr_clk_en:
3988c2ecf20Sopenharmony_ci	clk_unprepare(clk);
3998c2ecf20Sopenharmony_cierr_clk_prep:
4008c2ecf20Sopenharmony_ci	clk_put(clk);
4018c2ecf20Sopenharmony_cierr_get_clk:
4028c2ecf20Sopenharmony_ci	return err;
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic int i2c_sirfsoc_remove(struct platform_device *pdev)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter = platform_get_drvdata(pdev);
4088c2ecf20Sopenharmony_ci	struct sirfsoc_i2c *siic = adapter->algo_data;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
4118c2ecf20Sopenharmony_ci	i2c_del_adapter(adapter);
4128c2ecf20Sopenharmony_ci	clk_unprepare(siic->clk);
4138c2ecf20Sopenharmony_ci	clk_put(siic->clk);
4148c2ecf20Sopenharmony_ci	return 0;
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
4188c2ecf20Sopenharmony_cistatic int i2c_sirfsoc_suspend(struct device *dev)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter = dev_get_drvdata(dev);
4218c2ecf20Sopenharmony_ci	struct sirfsoc_i2c *siic = adapter->algo_data;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	clk_enable(siic->clk);
4248c2ecf20Sopenharmony_ci	siic->sda_delay = readl(siic->base + SIRFSOC_I2C_SDA_DELAY);
4258c2ecf20Sopenharmony_ci	siic->clk_div = readl(siic->base + SIRFSOC_I2C_CLK_CTRL);
4268c2ecf20Sopenharmony_ci	clk_disable(siic->clk);
4278c2ecf20Sopenharmony_ci	return 0;
4288c2ecf20Sopenharmony_ci}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_cistatic int i2c_sirfsoc_resume(struct device *dev)
4318c2ecf20Sopenharmony_ci{
4328c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter = dev_get_drvdata(dev);
4338c2ecf20Sopenharmony_ci	struct sirfsoc_i2c *siic = adapter->algo_data;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	clk_enable(siic->clk);
4368c2ecf20Sopenharmony_ci	writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
4378c2ecf20Sopenharmony_ci	while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
4388c2ecf20Sopenharmony_ci		cpu_relax();
4398c2ecf20Sopenharmony_ci	writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE,
4408c2ecf20Sopenharmony_ci		siic->base + SIRFSOC_I2C_CTRL);
4418c2ecf20Sopenharmony_ci	writel(siic->clk_div, siic->base + SIRFSOC_I2C_CLK_CTRL);
4428c2ecf20Sopenharmony_ci	writel(siic->sda_delay, siic->base + SIRFSOC_I2C_SDA_DELAY);
4438c2ecf20Sopenharmony_ci	clk_disable(siic->clk);
4448c2ecf20Sopenharmony_ci	return 0;
4458c2ecf20Sopenharmony_ci}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_cistatic const struct dev_pm_ops i2c_sirfsoc_pm_ops = {
4488c2ecf20Sopenharmony_ci	.suspend = i2c_sirfsoc_suspend,
4498c2ecf20Sopenharmony_ci	.resume = i2c_sirfsoc_resume,
4508c2ecf20Sopenharmony_ci};
4518c2ecf20Sopenharmony_ci#endif
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cistatic const struct of_device_id sirfsoc_i2c_of_match[] = {
4548c2ecf20Sopenharmony_ci	{ .compatible = "sirf,prima2-i2c", },
4558c2ecf20Sopenharmony_ci	{},
4568c2ecf20Sopenharmony_ci};
4578c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sirfsoc_i2c_of_match);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_cistatic struct platform_driver i2c_sirfsoc_driver = {
4608c2ecf20Sopenharmony_ci	.driver = {
4618c2ecf20Sopenharmony_ci		.name = "sirfsoc_i2c",
4628c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
4638c2ecf20Sopenharmony_ci		.pm = &i2c_sirfsoc_pm_ops,
4648c2ecf20Sopenharmony_ci#endif
4658c2ecf20Sopenharmony_ci		.of_match_table = sirfsoc_i2c_of_match,
4668c2ecf20Sopenharmony_ci	},
4678c2ecf20Sopenharmony_ci	.probe = i2c_sirfsoc_probe,
4688c2ecf20Sopenharmony_ci	.remove = i2c_sirfsoc_remove,
4698c2ecf20Sopenharmony_ci};
4708c2ecf20Sopenharmony_cimodule_platform_driver(i2c_sirfsoc_driver);
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SiRF SoC I2C master controller driver");
4738c2ecf20Sopenharmony_ciMODULE_AUTHOR("Zhiwu Song <Zhiwu.Song@csr.com>");
4748c2ecf20Sopenharmony_ciMODULE_AUTHOR("Xiangzhen Ye <Xiangzhen.Ye@csr.com>");
4758c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
476