1979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song/*
2979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song * I2C bus driver for CSR SiRFprimaII
3979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song *
4979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song *
6979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song * Licensed under GPLv2 or later.
7979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song */
8979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
9979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#include <linux/interrupt.h>
10979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#include <linux/kernel.h>
11979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#include <linux/module.h>
12979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#include <linux/slab.h>
13979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#include <linux/platform_device.h>
14979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#include <linux/i2c.h>
15979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#include <linux/clk.h>
16979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#include <linux/err.h>
17979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#include <linux/io.h>
18979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
19979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_CLK_CTRL		0x00
20979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_STATUS		0x0C
21979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_CTRL		0x10
22979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_IO_CTRL		0x14
23979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_SDA_DELAY		0x18
24979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_CMD_START		0x1C
25979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_CMD_BUF		0x30
26979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_DATA_BUF		0x80
27979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
28979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_CMD_BUF_MAX		16
29979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_DATA_BUF_MAX	16
30979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
31979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_CMD(x)		(SIRFSOC_I2C_CMD_BUF + (x)*0x04)
32979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_DATA_MASK(x)        (0xFF<<(((x)&3)*8))
33979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_DATA_SHIFT(x)       (((x)&3)*8)
34979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
35979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_DIV_MASK		(0xFFFF)
36979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
37979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song/* I2C status flags */
38979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_STAT_BUSY		BIT(0)
39979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_STAT_TIP		BIT(1)
40979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_STAT_NACK		BIT(2)
41979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_STAT_TR_INT		BIT(4)
42979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_STAT_STOP		BIT(6)
43979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_STAT_CMD_DONE	BIT(8)
44979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_STAT_ERR		BIT(9)
45979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_CMD_INDEX		(0x1F<<16)
46979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
47979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song/* I2C control flags */
48979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_RESET		BIT(0)
49979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_CORE_EN		BIT(1)
50979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_MASTER_MODE		BIT(2)
51979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_CMD_DONE_EN		BIT(11)
52979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_ERR_INT_EN		BIT(12)
53979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
54979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_SDA_DELAY_MASK	(0xFF)
55979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_SCLF_FILTER		(3<<8)
56979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
57979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_START_CMD		BIT(0)
58979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
59979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_CMD_RP(x)		((x)&0x7)
60979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_NACK		BIT(3)
61979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_WRITE		BIT(4)
62979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_READ		BIT(5)
63979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_STOP		BIT(6)
64979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_START		BIT(7)
65979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
66979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#define SIRFSOC_I2C_DEFAULT_SPEED 100000
67979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
68979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songstruct sirfsoc_i2c {
69979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	void __iomem *base;
70979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	struct clk *clk;
71979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	u32 cmd_ptr;		/* Current position in CMD buffer */
72979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	u8 *buf;		/* Buffer passed by user */
73979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	u32 msg_len;		/* Message length */
74979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	u32 finished_len;	/* number of bytes read/written */
75979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	u32 read_cmd_len;	/* number of read cmd sent */
76979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	int msg_read;		/* 1 indicates a read message */
77979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	int err_status;		/* 1 indicates an error on bus */
78979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
79979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	u32 sda_delay;		/* For suspend/resume */
80979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	u32 clk_div;
81979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	int last;		/* Last message in transfer, STOP cmd can be sent */
82979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
83979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	struct completion done;	/* indicates completion of message transfer */
84979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	struct i2c_adapter adapter;
85979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song};
86979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
87979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songstatic void i2c_sirfsoc_read_data(struct sirfsoc_i2c *siic)
88979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song{
89979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	u32 data = 0;
90979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	int i;
91979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
92979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	for (i = 0; i < siic->read_cmd_len; i++) {
93979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		if (!(i & 0x3))
94979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			data = readl(siic->base + SIRFSOC_I2C_DATA_BUF + i);
95979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		siic->buf[siic->finished_len++] =
96979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			(u8)((data & SIRFSOC_I2C_DATA_MASK(i)) >>
97979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song				SIRFSOC_I2C_DATA_SHIFT(i));
98979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	}
99979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song}
100979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
101979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songstatic void i2c_sirfsoc_queue_cmd(struct sirfsoc_i2c *siic)
102979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song{
103979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	u32 regval;
104979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	int i = 0;
105979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
106979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	if (siic->msg_read) {
107979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		while (((siic->finished_len + i) < siic->msg_len)
108979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song				&& (siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX)) {
109979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			regval = SIRFSOC_I2C_READ | SIRFSOC_I2C_CMD_RP(0);
110979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			if (((siic->finished_len + i) ==
111979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song					(siic->msg_len - 1)) && siic->last)
112979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song				regval |= SIRFSOC_I2C_STOP | SIRFSOC_I2C_NACK;
113979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			writel(regval,
114979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song				siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
115979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			i++;
116979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		}
117979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
118979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		siic->read_cmd_len = i;
119979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	} else {
120979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		while ((siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX - 1)
121979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song				&& (siic->finished_len < siic->msg_len)) {
122979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			regval = SIRFSOC_I2C_WRITE | SIRFSOC_I2C_CMD_RP(0);
123979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			if ((siic->finished_len == (siic->msg_len - 1))
124979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song				&& siic->last)
125979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song				regval |= SIRFSOC_I2C_STOP;
126979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			writel(regval,
127979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song				siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
128979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			writel(siic->buf[siic->finished_len++],
129979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song				siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
130979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		}
131979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	}
132979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	siic->cmd_ptr = 0;
133979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
134979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	/* Trigger the transfer */
135979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	writel(SIRFSOC_I2C_START_CMD, siic->base + SIRFSOC_I2C_CMD_START);
136979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song}
137979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
138979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songstatic irqreturn_t i2c_sirfsoc_irq(int irq, void *dev_id)
139979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song{
140979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	struct sirfsoc_i2c *siic = (struct sirfsoc_i2c *)dev_id;
141979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	u32 i2c_stat = readl(siic->base + SIRFSOC_I2C_STATUS);
142979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
143979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	if (i2c_stat & SIRFSOC_I2C_STAT_ERR) {
144979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		/* Error conditions */
145979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		siic->err_status = 1;
146979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		writel(SIRFSOC_I2C_STAT_ERR, siic->base + SIRFSOC_I2C_STATUS);
147979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
148979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		if (i2c_stat & SIRFSOC_I2C_STAT_NACK)
149979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			dev_err(&siic->adapter.dev, "ACK not received\n");
150979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		else
151979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			dev_err(&siic->adapter.dev, "I2C error\n");
152979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
153979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		complete(&siic->done);
154979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	} else if (i2c_stat & SIRFSOC_I2C_STAT_CMD_DONE) {
155979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		/* CMD buffer execution complete */
156979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		if (siic->msg_read)
157979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			i2c_sirfsoc_read_data(siic);
158979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		if (siic->finished_len == siic->msg_len)
159979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			complete(&siic->done);
160979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		else /* Fill a new CMD buffer for left data */
161979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			i2c_sirfsoc_queue_cmd(siic);
162979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
163979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		writel(SIRFSOC_I2C_STAT_CMD_DONE, siic->base + SIRFSOC_I2C_STATUS);
164979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	}
165979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
166979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	return IRQ_HANDLED;
167979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song}
168979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
169979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songstatic void i2c_sirfsoc_set_address(struct sirfsoc_i2c *siic,
170979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	struct i2c_msg *msg)
171979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song{
172979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	unsigned char addr;
173979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	u32 regval = SIRFSOC_I2C_START | SIRFSOC_I2C_CMD_RP(0) | SIRFSOC_I2C_WRITE;
174979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
175979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	/* no data and last message -> add STOP */
176979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	if (siic->last && (msg->len == 0))
177979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		regval |= SIRFSOC_I2C_STOP;
178979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
179979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	writel(regval, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
180979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
181979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	addr = msg->addr << 1;	/* Generate address */
182979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	if (msg->flags & I2C_M_RD)
183979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		addr |= 1;
184979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
185979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	writel(addr, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
186979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song}
187979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
188979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songstatic int i2c_sirfsoc_xfer_msg(struct sirfsoc_i2c *siic, struct i2c_msg *msg)
189979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song{
190979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	u32 regval = readl(siic->base + SIRFSOC_I2C_CTRL);
191979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	/* timeout waiting for the xfer to finish or fail */
192979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	int timeout = msecs_to_jiffies((msg->len + 1) * 50);
193979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	int ret = 0;
194979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
195979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	i2c_sirfsoc_set_address(siic, msg);
196979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
197979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	writel(regval | SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN,
198979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		siic->base + SIRFSOC_I2C_CTRL);
199979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	i2c_sirfsoc_queue_cmd(siic);
200979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
201979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	if (wait_for_completion_timeout(&siic->done, timeout) == 0) {
202979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		siic->err_status = 1;
203979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		dev_err(&siic->adapter.dev, "Transfer timeout\n");
204979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	}
205979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
206979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	writel(regval & ~(SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN),
207979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		siic->base + SIRFSOC_I2C_CTRL);
208979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	writel(0, siic->base + SIRFSOC_I2C_CMD_START);
209979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
210979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	if (siic->err_status) {
211979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET,
212979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			siic->base + SIRFSOC_I2C_CTRL);
213979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
214979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			cpu_relax();
215979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
216979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		ret = -EIO;
217979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	}
218979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
219979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	return ret;
220979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song}
221979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
222979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songstatic u32 i2c_sirfsoc_func(struct i2c_adapter *adap)
223979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song{
224979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
225979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song}
226979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
227979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songstatic int i2c_sirfsoc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
228979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	int num)
229979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song{
230979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	struct sirfsoc_i2c *siic = adap->algo_data;
231979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	int i, ret;
232979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
233979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	clk_enable(siic->clk);
234979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
235979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	for (i = 0; i < num; i++) {
236979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		siic->buf = msgs[i].buf;
237979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		siic->msg_len = msgs[i].len;
238979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		siic->msg_read = !!(msgs[i].flags & I2C_M_RD);
239979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		siic->err_status = 0;
240979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		siic->cmd_ptr = 0;
241979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		siic->finished_len = 0;
242979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		siic->last = (i == (num - 1));
243979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
244979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		ret = i2c_sirfsoc_xfer_msg(siic, &msgs[i]);
245979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		if (ret) {
246979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			clk_disable(siic->clk);
247979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			return ret;
248979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		}
249979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	}
250979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
251979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	clk_disable(siic->clk);
252979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	return num;
253979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song}
254979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
255979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song/* I2C algorithms associated with this master controller driver */
256979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songstatic const struct i2c_algorithm i2c_sirfsoc_algo = {
257979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	.master_xfer = i2c_sirfsoc_xfer,
258979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	.functionality = i2c_sirfsoc_func,
259979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song};
260979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
261979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songstatic int __devinit i2c_sirfsoc_probe(struct platform_device *pdev)
262979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song{
263979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	struct sirfsoc_i2c *siic;
264979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	struct i2c_adapter *adap;
265979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	struct resource *mem_res;
266979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	struct clk *clk;
267979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	int bitrate;
268979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	int ctrl_speed;
269979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	int irq;
270979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
271979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	int err;
272979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	u32 regval;
273979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
274979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	clk = clk_get(&pdev->dev, NULL);
275979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	if (IS_ERR(clk)) {
276979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		err = PTR_ERR(clk);
277979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		dev_err(&pdev->dev, "Clock get failed\n");
278979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		goto err_get_clk;
279979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	}
280979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
281979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	err = clk_prepare(clk);
282979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	if (err) {
283979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		dev_err(&pdev->dev, "Clock prepare failed\n");
284979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		goto err_clk_prep;
285979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	}
286979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
287979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	err = clk_enable(clk);
288979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	if (err) {
289979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		dev_err(&pdev->dev, "Clock enable failed\n");
290979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		goto err_clk_en;
291979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	}
292979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
293979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	ctrl_speed = clk_get_rate(clk);
294979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
295979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	siic = devm_kzalloc(&pdev->dev, sizeof(*siic), GFP_KERNEL);
296979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	if (!siic) {
297979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		dev_err(&pdev->dev, "Can't allocate driver data\n");
298979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		err = -ENOMEM;
299979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		goto out;
300979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	}
301979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	adap = &siic->adapter;
302979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	adap->class = I2C_CLASS_HWMON;
303979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
304979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
305979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	if (mem_res == NULL) {
306979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		dev_err(&pdev->dev, "Unable to get MEM resource\n");
307979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		err = -EINVAL;
308979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		goto out;
309979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	}
310979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
311979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	siic->base = devm_request_and_ioremap(&pdev->dev, mem_res);
312979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	if (siic->base == NULL) {
313979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		dev_err(&pdev->dev, "IO remap failed!\n");
314979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		err = -ENOMEM;
315979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		goto out;
316979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	}
317979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
318979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	irq = platform_get_irq(pdev, 0);
319979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	if (irq < 0) {
320979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		err = irq;
321979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		goto out;
322979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	}
323979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	err = devm_request_irq(&pdev->dev, irq, i2c_sirfsoc_irq, 0,
324979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		dev_name(&pdev->dev), siic);
325979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	if (err)
326979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		goto out;
327979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
328979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	adap->algo = &i2c_sirfsoc_algo;
329979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	adap->algo_data = siic;
330979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
331979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	adap->dev.parent = &pdev->dev;
332979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	adap->nr = pdev->id;
333979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
334979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	strlcpy(adap->name, "sirfsoc-i2c", sizeof(adap->name));
335979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
336979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	platform_set_drvdata(pdev, adap);
337979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	init_completion(&siic->done);
338979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
339979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	/* Controller Initalisation */
340979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
341979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
342979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
343979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		cpu_relax();
344979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE,
345979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		siic->base + SIRFSOC_I2C_CTRL);
346979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
347979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	siic->clk = clk;
348979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
349979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	err = of_property_read_u32(pdev->dev.of_node,
350979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		"clock-frequency", &bitrate);
351979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	if (err < 0)
352979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		bitrate = SIRFSOC_I2C_DEFAULT_SPEED;
353979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
354979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	if (bitrate < 100000)
355979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		regval =
356979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song			(2 * ctrl_speed) / (2 * bitrate * 11);
357979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	else
358979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		regval = ctrl_speed / (bitrate * 5);
359979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
360979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	writel(regval, siic->base + SIRFSOC_I2C_CLK_CTRL);
361979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	if (regval > 0xFF)
362979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		writel(0xFF, siic->base + SIRFSOC_I2C_SDA_DELAY);
363979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	else
364979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		writel(regval, siic->base + SIRFSOC_I2C_SDA_DELAY);
365979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
366979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	err = i2c_add_numbered_adapter(adap);
367979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	if (err < 0) {
368979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		dev_err(&pdev->dev, "Can't add new i2c adapter\n");
369979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		goto out;
370979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	}
371979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
372979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	clk_disable(clk);
373979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
374979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	dev_info(&pdev->dev, " I2C adapter ready to operate\n");
375979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
376979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	return 0;
377979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
378979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songout:
379979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	clk_disable(clk);
380979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songerr_clk_en:
381979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	clk_unprepare(clk);
382979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songerr_clk_prep:
383979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	clk_put(clk);
384979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songerr_get_clk:
385979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	return err;
386979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song}
387979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
388979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songstatic int __devexit i2c_sirfsoc_remove(struct platform_device *pdev)
389979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song{
390979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	struct i2c_adapter *adapter = platform_get_drvdata(pdev);
391979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	struct sirfsoc_i2c *siic = adapter->algo_data;
392979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
393979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
394979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	i2c_del_adapter(adapter);
395979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	clk_unprepare(siic->clk);
396979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	clk_put(siic->clk);
397979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	return 0;
398979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song}
399979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
400979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#ifdef CONFIG_PM
401979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songstatic int i2c_sirfsoc_suspend(struct device *dev)
402979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song{
403979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	struct platform_device *pdev = to_platform_device(dev);
404979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	struct i2c_adapter *adapter = platform_get_drvdata(pdev);
405979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	struct sirfsoc_i2c *siic = adapter->algo_data;
406979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
407979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	clk_enable(siic->clk);
408979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	siic->sda_delay = readl(siic->base + SIRFSOC_I2C_SDA_DELAY);
409979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	siic->clk_div = readl(siic->base + SIRFSOC_I2C_CLK_CTRL);
410979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	clk_disable(siic->clk);
411979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	return 0;
412979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song}
413979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
414979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songstatic int i2c_sirfsoc_resume(struct device *dev)
415979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song{
416979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	struct platform_device *pdev = to_platform_device(dev);
417979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	struct i2c_adapter *adapter = platform_get_drvdata(pdev);
418979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	struct sirfsoc_i2c *siic = adapter->algo_data;
419979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
420979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	clk_enable(siic->clk);
421979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
422979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE,
423979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		siic->base + SIRFSOC_I2C_CTRL);
424979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	writel(siic->clk_div, siic->base + SIRFSOC_I2C_CLK_CTRL);
425979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	writel(siic->sda_delay, siic->base + SIRFSOC_I2C_SDA_DELAY);
426979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	clk_disable(siic->clk);
427979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	return 0;
428979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song}
429979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
430979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songstatic const struct dev_pm_ops i2c_sirfsoc_pm_ops = {
431979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	.suspend = i2c_sirfsoc_suspend,
432979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	.resume = i2c_sirfsoc_resume,
433979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song};
434979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#endif
435979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
436979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songstatic const struct of_device_id sirfsoc_i2c_of_match[] __devinitconst = {
437979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	{ .compatible = "sirf,prima2-i2c", },
438979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	{},
439979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song};
440979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu SongMODULE_DEVICE_TABLE(of, sirfsoc_i2c_of_match);
441979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
442979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songstatic struct platform_driver i2c_sirfsoc_driver = {
443979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	.driver = {
444979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		.name = "sirfsoc_i2c",
445979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		.owner = THIS_MODULE,
446979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#ifdef CONFIG_PM
447979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		.pm = &i2c_sirfsoc_pm_ops,
448979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song#endif
449979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song		.of_match_table = sirfsoc_i2c_of_match,
450979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	},
451979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	.probe = i2c_sirfsoc_probe,
452979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	.remove = __devexit_p(i2c_sirfsoc_remove),
453979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song};
454979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Songmodule_platform_driver(i2c_sirfsoc_driver);
455979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song
456979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu SongMODULE_DESCRIPTION("SiRF SoC I2C master controller driver");
457979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu SongMODULE_AUTHOR("Zhiwu Song <Zhiwu.Song@csr.com>, "
458979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu Song	"Xiangzhen Ye <Xiangzhen.Ye@csr.com>");
459979b907fa55be8cdbbf455b9204b7e4602f303e6Zhiwu SongMODULE_LICENSE("GPL v2");
460