xref: /dpdk/drivers/raw/ifpga/base/opae_i2c.c (revision e41856b515cece86e2082d97f4e2a83181df5f82)
1473c88f9SBruce Richardson 
2473c88f9SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
3473c88f9SBruce Richardson  * Copyright(c) 2010-2019 Intel Corporation
4473c88f9SBruce Richardson  */
5473c88f9SBruce Richardson 
6473c88f9SBruce Richardson #include "opae_osdep.h"
7473c88f9SBruce Richardson #include "opae_i2c.h"
8473c88f9SBruce Richardson 
i2c_transfer(struct altera_i2c_dev * dev,struct i2c_msg * msg,int num)9473c88f9SBruce Richardson static int i2c_transfer(struct altera_i2c_dev *dev,
10473c88f9SBruce Richardson 		struct i2c_msg *msg, int num)
11473c88f9SBruce Richardson {
12473c88f9SBruce Richardson 	int ret, try;
13473c88f9SBruce Richardson 
14473c88f9SBruce Richardson 	for (ret = 0, try = 0; try < I2C_XFER_RETRY; try++) {
15473c88f9SBruce Richardson 		ret = dev->xfer(dev, msg, num);
16473c88f9SBruce Richardson 		if (ret != -EAGAIN)
17473c88f9SBruce Richardson 			break;
18473c88f9SBruce Richardson 	}
19473c88f9SBruce Richardson 
20473c88f9SBruce Richardson 	return ret;
21473c88f9SBruce Richardson }
22473c88f9SBruce Richardson 
23473c88f9SBruce Richardson /**
24473c88f9SBruce Richardson  * i2c read function
25473c88f9SBruce Richardson  */
i2c_read(struct altera_i2c_dev * dev,int flags,unsigned int slave_addr,u32 offset,u8 * buf,u32 count)26473c88f9SBruce Richardson int i2c_read(struct altera_i2c_dev *dev, int flags, unsigned int slave_addr,
27473c88f9SBruce Richardson 		u32 offset, u8 *buf, u32 count)
28473c88f9SBruce Richardson {
29473c88f9SBruce Richardson 	u8 msgbuf[2];
30473c88f9SBruce Richardson 	int i = 0;
314a19f891STianfei Zhang 	int ret;
324a19f891STianfei Zhang 
33*e41856b5SWei Huang 	pthread_mutex_lock(dev->mutex);
34473c88f9SBruce Richardson 
35473c88f9SBruce Richardson 	if (flags & I2C_FLAG_ADDR16)
36473c88f9SBruce Richardson 		msgbuf[i++] = offset >> 8;
37473c88f9SBruce Richardson 
38473c88f9SBruce Richardson 	msgbuf[i++] = offset;
39473c88f9SBruce Richardson 
40473c88f9SBruce Richardson 	struct i2c_msg msg[2] = {
41473c88f9SBruce Richardson 		{
42473c88f9SBruce Richardson 			.addr = slave_addr,
43473c88f9SBruce Richardson 			.flags = 0,
44473c88f9SBruce Richardson 			.len = i,
45473c88f9SBruce Richardson 			.buf = msgbuf,
46473c88f9SBruce Richardson 		},
47473c88f9SBruce Richardson 		{
48473c88f9SBruce Richardson 			.addr = slave_addr,
49473c88f9SBruce Richardson 			.flags = I2C_M_RD,
50473c88f9SBruce Richardson 			.len = count,
51473c88f9SBruce Richardson 			.buf = buf,
52473c88f9SBruce Richardson 		},
53473c88f9SBruce Richardson 	};
54473c88f9SBruce Richardson 
554a19f891STianfei Zhang 	if (!dev->xfer) {
564a19f891STianfei Zhang 		ret = -ENODEV;
574a19f891STianfei Zhang 		goto exit;
584a19f891STianfei Zhang 	}
59473c88f9SBruce Richardson 
604a19f891STianfei Zhang 	ret = i2c_transfer(dev, msg, 2);
614a19f891STianfei Zhang 
624a19f891STianfei Zhang exit:
63*e41856b5SWei Huang 	pthread_mutex_unlock(dev->mutex);
644a19f891STianfei Zhang 	return ret;
65473c88f9SBruce Richardson }
66473c88f9SBruce Richardson 
i2c_write(struct altera_i2c_dev * dev,int flags,unsigned int slave_addr,u32 offset,u8 * buffer,int len)67473c88f9SBruce Richardson int i2c_write(struct altera_i2c_dev *dev, int flags, unsigned int slave_addr,
68473c88f9SBruce Richardson 		u32 offset, u8 *buffer, int len)
69473c88f9SBruce Richardson {
70473c88f9SBruce Richardson 	struct i2c_msg msg;
71473c88f9SBruce Richardson 	u8 *buf;
72473c88f9SBruce Richardson 	int ret;
73473c88f9SBruce Richardson 	int i = 0;
74473c88f9SBruce Richardson 
75*e41856b5SWei Huang 	pthread_mutex_lock(dev->mutex);
764a19f891STianfei Zhang 
774a19f891STianfei Zhang 	if (!dev->xfer) {
784a19f891STianfei Zhang 		ret = -ENODEV;
794a19f891STianfei Zhang 		goto exit;
804a19f891STianfei Zhang 	}
81473c88f9SBruce Richardson 
82473c88f9SBruce Richardson 	buf = opae_malloc(I2C_MAX_OFFSET_LEN + len);
834a19f891STianfei Zhang 	if (!buf) {
844a19f891STianfei Zhang 		ret = -ENOMEM;
854a19f891STianfei Zhang 		goto exit;
864a19f891STianfei Zhang 	}
87473c88f9SBruce Richardson 
88473c88f9SBruce Richardson 	msg.addr = slave_addr;
89473c88f9SBruce Richardson 	msg.flags = 0;
90473c88f9SBruce Richardson 	msg.buf = buf;
91473c88f9SBruce Richardson 
92473c88f9SBruce Richardson 	if (flags & I2C_FLAG_ADDR16)
93473c88f9SBruce Richardson 		msg.buf[i++] = offset >> 8;
94473c88f9SBruce Richardson 
95473c88f9SBruce Richardson 	msg.buf[i++] = offset;
96473c88f9SBruce Richardson 	opae_memcpy(&msg.buf[i], buffer, len);
97473c88f9SBruce Richardson 	msg.len = i + len;
98473c88f9SBruce Richardson 
99473c88f9SBruce Richardson 	ret = i2c_transfer(dev, &msg, 1);
100473c88f9SBruce Richardson 
101473c88f9SBruce Richardson 	opae_free(buf);
1024a19f891STianfei Zhang exit:
103*e41856b5SWei Huang 	pthread_mutex_unlock(dev->mutex);
104473c88f9SBruce Richardson 	return ret;
105473c88f9SBruce Richardson }
106473c88f9SBruce Richardson 
i2c_read8(struct altera_i2c_dev * dev,unsigned int slave_addr,u32 offset,u8 * buf,u32 count)107473c88f9SBruce Richardson int i2c_read8(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset,
108473c88f9SBruce Richardson 		u8 *buf, u32 count)
109473c88f9SBruce Richardson {
110473c88f9SBruce Richardson 	return i2c_read(dev, 0, slave_addr, offset, buf, count);
111473c88f9SBruce Richardson }
112473c88f9SBruce Richardson 
i2c_read16(struct altera_i2c_dev * dev,unsigned int slave_addr,u32 offset,u8 * buf,u32 count)113473c88f9SBruce Richardson int i2c_read16(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset,
114473c88f9SBruce Richardson 		u8 *buf, u32 count)
115473c88f9SBruce Richardson {
116473c88f9SBruce Richardson 	return i2c_read(dev, I2C_FLAG_ADDR16, slave_addr, offset,
117473c88f9SBruce Richardson 			buf, count);
118473c88f9SBruce Richardson }
119473c88f9SBruce Richardson 
i2c_write8(struct altera_i2c_dev * dev,unsigned int slave_addr,u32 offset,u8 * buf,u32 count)120473c88f9SBruce Richardson int i2c_write8(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset,
121473c88f9SBruce Richardson 		u8 *buf, u32 count)
122473c88f9SBruce Richardson {
123473c88f9SBruce Richardson 	return i2c_write(dev, 0, slave_addr, offset, buf, count);
124473c88f9SBruce Richardson }
125473c88f9SBruce Richardson 
i2c_write16(struct altera_i2c_dev * dev,unsigned int slave_addr,u32 offset,u8 * buf,u32 count)126473c88f9SBruce Richardson int i2c_write16(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset,
127473c88f9SBruce Richardson 		u8 *buf, u32 count)
128473c88f9SBruce Richardson {
129473c88f9SBruce Richardson 	return i2c_write(dev, I2C_FLAG_ADDR16, slave_addr, offset,
130473c88f9SBruce Richardson 			buf, count);
131473c88f9SBruce Richardson }
132473c88f9SBruce Richardson 
i2c_indirect_write(struct altera_i2c_dev * dev,u32 reg,u32 value)133473c88f9SBruce Richardson static void i2c_indirect_write(struct altera_i2c_dev *dev, u32 reg,
134473c88f9SBruce Richardson 		u32 value)
135473c88f9SBruce Richardson {
136473c88f9SBruce Richardson 	u64 ctrl;
137473c88f9SBruce Richardson 
138473c88f9SBruce Richardson 	ctrl = I2C_CTRL_W | (reg >> 2);
139473c88f9SBruce Richardson 
140473c88f9SBruce Richardson 	opae_writeq(value & I2C_WRITE_DATA_MASK, dev->base + I2C_WRITE);
141473c88f9SBruce Richardson 	opae_writeq(ctrl, dev->base + I2C_CTRL);
142473c88f9SBruce Richardson }
143473c88f9SBruce Richardson 
i2c_indirect_read(struct altera_i2c_dev * dev,u32 reg)144473c88f9SBruce Richardson static u32 i2c_indirect_read(struct altera_i2c_dev *dev, u32 reg)
145473c88f9SBruce Richardson {
146473c88f9SBruce Richardson 	u64 tmp;
147473c88f9SBruce Richardson 	u64 ctrl;
148473c88f9SBruce Richardson 	u32 value;
149473c88f9SBruce Richardson 
150473c88f9SBruce Richardson 	ctrl = I2C_CTRL_R | (reg >> 2);
151473c88f9SBruce Richardson 	opae_writeq(ctrl, dev->base + I2C_CTRL);
152473c88f9SBruce Richardson 
153473c88f9SBruce Richardson 	/* FIXME: Read one more time to avoid HW timing issue. */
154473c88f9SBruce Richardson 	tmp = opae_readq(dev->base + I2C_READ);
155473c88f9SBruce Richardson 	tmp = opae_readq(dev->base + I2C_READ);
156473c88f9SBruce Richardson 
157473c88f9SBruce Richardson 	value = tmp & I2C_READ_DATA_MASK;
158473c88f9SBruce Richardson 
159473c88f9SBruce Richardson 	return value;
160473c88f9SBruce Richardson }
161473c88f9SBruce Richardson 
altera_i2c_transfer(struct altera_i2c_dev * dev,u32 data)162473c88f9SBruce Richardson static void altera_i2c_transfer(struct altera_i2c_dev *dev, u32 data)
163473c88f9SBruce Richardson {
164473c88f9SBruce Richardson 	/*send STOP on last byte*/
165473c88f9SBruce Richardson 	if (dev->msg_len == 1)
166473c88f9SBruce Richardson 		data |= ALTERA_I2C_TFR_CMD_STO;
167473c88f9SBruce Richardson 	if (dev->msg_len > 0)
168473c88f9SBruce Richardson 		i2c_indirect_write(dev, ALTERA_I2C_TFR_CMD, data);
169473c88f9SBruce Richardson }
170473c88f9SBruce Richardson 
altera_i2c_disable(struct altera_i2c_dev * dev)171473c88f9SBruce Richardson static void altera_i2c_disable(struct altera_i2c_dev *dev)
172473c88f9SBruce Richardson {
173473c88f9SBruce Richardson 	u32 val = i2c_indirect_read(dev, ALTERA_I2C_CTRL);
174473c88f9SBruce Richardson 
175473c88f9SBruce Richardson 	i2c_indirect_write(dev, ALTERA_I2C_CTRL, val&~ALTERA_I2C_CTRL_EN);
176473c88f9SBruce Richardson }
177473c88f9SBruce Richardson 
altera_i2c_enable(struct altera_i2c_dev * dev)178473c88f9SBruce Richardson static void altera_i2c_enable(struct altera_i2c_dev *dev)
179473c88f9SBruce Richardson {
180473c88f9SBruce Richardson 	u32 val = i2c_indirect_read(dev, ALTERA_I2C_CTRL);
181473c88f9SBruce Richardson 
182473c88f9SBruce Richardson 	i2c_indirect_write(dev, ALTERA_I2C_CTRL, val | ALTERA_I2C_CTRL_EN);
183473c88f9SBruce Richardson }
184473c88f9SBruce Richardson 
altera_i2c_reset(struct altera_i2c_dev * dev)185473c88f9SBruce Richardson static void altera_i2c_reset(struct altera_i2c_dev *dev)
186473c88f9SBruce Richardson {
187473c88f9SBruce Richardson 	altera_i2c_disable(dev);
188473c88f9SBruce Richardson 	altera_i2c_enable(dev);
189473c88f9SBruce Richardson }
190473c88f9SBruce Richardson 
altera_i2c_wait_core_idle(struct altera_i2c_dev * dev)191473c88f9SBruce Richardson static int altera_i2c_wait_core_idle(struct altera_i2c_dev *dev)
192473c88f9SBruce Richardson {
193473c88f9SBruce Richardson 	int retry = 0;
194473c88f9SBruce Richardson 
195473c88f9SBruce Richardson 	while (i2c_indirect_read(dev, ALTERA_I2C_STATUS)
196473c88f9SBruce Richardson 			& ALTERA_I2C_STAT_CORE) {
197473c88f9SBruce Richardson 		if (retry++ > ALTERA_I2C_TIMEOUT_US) {
198473c88f9SBruce Richardson 			dev_err(dev, "timeout: Core Status not IDLE...\n");
199473c88f9SBruce Richardson 			return -EBUSY;
200473c88f9SBruce Richardson 		}
201473c88f9SBruce Richardson 		udelay(1);
202473c88f9SBruce Richardson 	}
203473c88f9SBruce Richardson 
204473c88f9SBruce Richardson 	return 0;
205473c88f9SBruce Richardson }
206473c88f9SBruce Richardson 
altera_i2c_enable_interrupt(struct altera_i2c_dev * dev,u32 mask,bool enable)207473c88f9SBruce Richardson static void altera_i2c_enable_interrupt(struct altera_i2c_dev *dev,
208473c88f9SBruce Richardson 		u32 mask, bool enable)
209473c88f9SBruce Richardson {
210473c88f9SBruce Richardson 	u32 status;
211473c88f9SBruce Richardson 
212473c88f9SBruce Richardson 	status = i2c_indirect_read(dev, ALTERA_I2C_ISER);
213473c88f9SBruce Richardson 	if (enable)
214473c88f9SBruce Richardson 		dev->isr_mask = status | mask;
215473c88f9SBruce Richardson 	else
216473c88f9SBruce Richardson 		dev->isr_mask = status&~mask;
217473c88f9SBruce Richardson 
218473c88f9SBruce Richardson 	i2c_indirect_write(dev, ALTERA_I2C_ISER, dev->isr_mask);
219473c88f9SBruce Richardson }
220473c88f9SBruce Richardson 
altera_i2c_interrupt_clear(struct altera_i2c_dev * dev,u32 mask)221473c88f9SBruce Richardson static void altera_i2c_interrupt_clear(struct altera_i2c_dev *dev, u32 mask)
222473c88f9SBruce Richardson {
223473c88f9SBruce Richardson 	u32 int_en;
224473c88f9SBruce Richardson 
225473c88f9SBruce Richardson 	int_en = i2c_indirect_read(dev, ALTERA_I2C_ISR);
226473c88f9SBruce Richardson 
227473c88f9SBruce Richardson 	i2c_indirect_write(dev, ALTERA_I2C_ISR, int_en | mask);
228473c88f9SBruce Richardson }
229473c88f9SBruce Richardson 
altera_i2c_read_rx_fifo(struct altera_i2c_dev * dev)230473c88f9SBruce Richardson static void altera_i2c_read_rx_fifo(struct altera_i2c_dev *dev)
231473c88f9SBruce Richardson {
232473c88f9SBruce Richardson 	size_t rx_avail;
233473c88f9SBruce Richardson 	size_t bytes;
234473c88f9SBruce Richardson 
235473c88f9SBruce Richardson 	rx_avail = i2c_indirect_read(dev, ALTERA_I2C_RX_FIFO_LVL);
236473c88f9SBruce Richardson 	bytes = min(rx_avail, dev->msg_len);
237473c88f9SBruce Richardson 
238473c88f9SBruce Richardson 	while (bytes-- > 0) {
239473c88f9SBruce Richardson 		*dev->buf++ = i2c_indirect_read(dev, ALTERA_I2C_RX_DATA);
240473c88f9SBruce Richardson 		dev->msg_len--;
241473c88f9SBruce Richardson 		altera_i2c_transfer(dev, 0);
242473c88f9SBruce Richardson 	}
243473c88f9SBruce Richardson }
244473c88f9SBruce Richardson 
altera_i2c_stop(struct altera_i2c_dev * dev)245473c88f9SBruce Richardson static void altera_i2c_stop(struct altera_i2c_dev *dev)
246473c88f9SBruce Richardson {
247473c88f9SBruce Richardson 	i2c_indirect_write(dev, ALTERA_I2C_TFR_CMD, ALTERA_I2C_TFR_CMD_STO);
248473c88f9SBruce Richardson }
249473c88f9SBruce Richardson 
altera_i2c_fill_tx_fifo(struct altera_i2c_dev * dev)250473c88f9SBruce Richardson static int altera_i2c_fill_tx_fifo(struct altera_i2c_dev *dev)
251473c88f9SBruce Richardson {
252473c88f9SBruce Richardson 	size_t tx_avail;
253473c88f9SBruce Richardson 	int bytes;
254473c88f9SBruce Richardson 	int ret;
255473c88f9SBruce Richardson 
256473c88f9SBruce Richardson 	tx_avail = dev->fifo_size -
257473c88f9SBruce Richardson 		i2c_indirect_read(dev, ALTERA_I2C_TC_FIFO_LVL);
258473c88f9SBruce Richardson 	bytes = min(tx_avail, dev->msg_len);
259473c88f9SBruce Richardson 	ret = dev->msg_len - bytes;
260473c88f9SBruce Richardson 
261473c88f9SBruce Richardson 	while (bytes-- > 0) {
262473c88f9SBruce Richardson 		altera_i2c_transfer(dev, *dev->buf++);
263473c88f9SBruce Richardson 		dev->msg_len--;
264473c88f9SBruce Richardson 	}
265473c88f9SBruce Richardson 
266473c88f9SBruce Richardson 	return ret;
267473c88f9SBruce Richardson }
268473c88f9SBruce Richardson 
i2c_8bit_addr_from_msg(const struct i2c_msg * msg)269473c88f9SBruce Richardson static u8 i2c_8bit_addr_from_msg(const struct i2c_msg *msg)
270473c88f9SBruce Richardson {
271473c88f9SBruce Richardson 	return (msg->addr << 1) | (msg->flags & I2C_M_RD ? 1 : 0);
272473c88f9SBruce Richardson }
273473c88f9SBruce Richardson 
altera_i2c_wait_complete(struct altera_i2c_dev * dev,u32 * status)274473c88f9SBruce Richardson static int altera_i2c_wait_complete(struct altera_i2c_dev *dev,
275473c88f9SBruce Richardson 		u32 *status)
276473c88f9SBruce Richardson {
277473c88f9SBruce Richardson 	int retry = 0;
278473c88f9SBruce Richardson 
279473c88f9SBruce Richardson 	while (!((*status = i2c_indirect_read(dev, ALTERA_I2C_ISR))
280473c88f9SBruce Richardson 				& dev->isr_mask)) {
281473c88f9SBruce Richardson 		if (retry++ > ALTERA_I2C_TIMEOUT_US)
282473c88f9SBruce Richardson 			return -EBUSY;
283473c88f9SBruce Richardson 
284473c88f9SBruce Richardson 		udelay(1000);
285473c88f9SBruce Richardson 	}
286473c88f9SBruce Richardson 
287473c88f9SBruce Richardson 	return 0;
288473c88f9SBruce Richardson }
289473c88f9SBruce Richardson 
altera_handle_i2c_status(struct altera_i2c_dev * dev,u32 status)290473c88f9SBruce Richardson static bool altera_handle_i2c_status(struct altera_i2c_dev *dev, u32 status)
291473c88f9SBruce Richardson {
292473c88f9SBruce Richardson 	bool read, finish = false;
293473c88f9SBruce Richardson 	int ret;
294473c88f9SBruce Richardson 
295473c88f9SBruce Richardson 	read = (dev->msg->flags & I2C_M_RD) != 0;
296473c88f9SBruce Richardson 
297473c88f9SBruce Richardson 	if (status & ALTERA_I2C_ISR_ARB) {
298473c88f9SBruce Richardson 		altera_i2c_interrupt_clear(dev, ALTERA_I2C_ISR_ARB);
299473c88f9SBruce Richardson 		dev->msg_err = -EAGAIN;
300473c88f9SBruce Richardson 		finish = true;
301473c88f9SBruce Richardson 	} else if (status & ALTERA_I2C_ISR_NACK) {
302473c88f9SBruce Richardson 		dev_debug(dev, "could not get ACK\n");
303473c88f9SBruce Richardson 		dev->msg_err = -ENXIO;
304473c88f9SBruce Richardson 		altera_i2c_interrupt_clear(dev, ALTERA_I2C_ISR_NACK);
305473c88f9SBruce Richardson 		altera_i2c_stop(dev);
306473c88f9SBruce Richardson 		finish = true;
307473c88f9SBruce Richardson 	} else if (read && (status & ALTERA_I2C_ISR_RXOF)) {
308473c88f9SBruce Richardson 		/* RX FIFO Overflow */
309473c88f9SBruce Richardson 		altera_i2c_read_rx_fifo(dev);
310473c88f9SBruce Richardson 		altera_i2c_interrupt_clear(dev, ALTERA_I2C_ISER_RXOF_EN);
311473c88f9SBruce Richardson 		altera_i2c_stop(dev);
312473c88f9SBruce Richardson 		dev_err(dev, "error: RX FIFO overflow\n");
313473c88f9SBruce Richardson 		finish = true;
314473c88f9SBruce Richardson 	} else if (read && (status & ALTERA_I2C_ISR_RXRDY)) {
315473c88f9SBruce Richardson 		altera_i2c_read_rx_fifo(dev);
316473c88f9SBruce Richardson 		altera_i2c_interrupt_clear(dev, ALTERA_I2C_ISR_RXRDY);
317473c88f9SBruce Richardson 		if (!dev->msg_len)
318473c88f9SBruce Richardson 			finish = true;
319473c88f9SBruce Richardson 	} else if (!read && (status & ALTERA_I2C_ISR_TXRDY)) {
320473c88f9SBruce Richardson 		altera_i2c_interrupt_clear(dev, ALTERA_I2C_ISR_TXRDY);
321473c88f9SBruce Richardson 		if (dev->msg_len > 0)
322473c88f9SBruce Richardson 			altera_i2c_fill_tx_fifo(dev);
323473c88f9SBruce Richardson 		else
324473c88f9SBruce Richardson 			finish = true;
325473c88f9SBruce Richardson 	} else {
326473c88f9SBruce Richardson 		dev_err(dev, "unexpected status:0x%x\n", status);
327473c88f9SBruce Richardson 		altera_i2c_interrupt_clear(dev, ALTERA_I2C_ALL_IRQ);
328473c88f9SBruce Richardson 	}
329473c88f9SBruce Richardson 
330473c88f9SBruce Richardson 	if (finish) {
331473c88f9SBruce Richardson 		ret = altera_i2c_wait_core_idle(dev);
332473c88f9SBruce Richardson 		if (ret)
333473c88f9SBruce Richardson 			dev_err(dev, "message timeout\n");
334473c88f9SBruce Richardson 
335473c88f9SBruce Richardson 		altera_i2c_enable_interrupt(dev, ALTERA_I2C_ALL_IRQ, false);
336473c88f9SBruce Richardson 		altera_i2c_interrupt_clear(dev, ALTERA_I2C_ALL_IRQ);
337473c88f9SBruce Richardson 		dev_debug(dev, "message done\n");
338473c88f9SBruce Richardson 	}
339473c88f9SBruce Richardson 
340473c88f9SBruce Richardson 	return finish;
341473c88f9SBruce Richardson }
342473c88f9SBruce Richardson 
altera_i2c_poll_status(struct altera_i2c_dev * dev)343473c88f9SBruce Richardson static bool altera_i2c_poll_status(struct altera_i2c_dev *dev)
344473c88f9SBruce Richardson {
345473c88f9SBruce Richardson 	u32 status;
346473c88f9SBruce Richardson 	bool finish = false;
347473c88f9SBruce Richardson 	int i = 0;
348473c88f9SBruce Richardson 
349473c88f9SBruce Richardson 	do {
350473c88f9SBruce Richardson 		if (altera_i2c_wait_complete(dev, &status)) {
351473c88f9SBruce Richardson 			dev_err(dev, "altera i2c wait complete timeout, status=0x%x\n",
352473c88f9SBruce Richardson 					status);
353473c88f9SBruce Richardson 			return -EBUSY;
354473c88f9SBruce Richardson 		}
355473c88f9SBruce Richardson 
356473c88f9SBruce Richardson 		finish = altera_handle_i2c_status(dev, status);
357473c88f9SBruce Richardson 
358473c88f9SBruce Richardson 		if (i++ > I2C_XFER_RETRY)
359473c88f9SBruce Richardson 			break;
360473c88f9SBruce Richardson 
361473c88f9SBruce Richardson 	} while (!finish);
362473c88f9SBruce Richardson 
363473c88f9SBruce Richardson 	return finish;
364473c88f9SBruce Richardson }
365473c88f9SBruce Richardson 
altera_i2c_xfer_msg(struct altera_i2c_dev * dev,struct i2c_msg * msg)366473c88f9SBruce Richardson static int altera_i2c_xfer_msg(struct altera_i2c_dev *dev,
367473c88f9SBruce Richardson 		struct i2c_msg *msg)
368473c88f9SBruce Richardson {
369473c88f9SBruce Richardson 	u32 int_mask = ALTERA_I2C_ISR_RXOF |
370473c88f9SBruce Richardson 		ALTERA_I2C_ISR_ARB | ALTERA_I2C_ISR_NACK;
371473c88f9SBruce Richardson 	u8 addr = i2c_8bit_addr_from_msg(msg);
372473c88f9SBruce Richardson 	bool finish;
373473c88f9SBruce Richardson 
374473c88f9SBruce Richardson 	dev->msg = msg;
375473c88f9SBruce Richardson 	dev->msg_len = msg->len;
376473c88f9SBruce Richardson 	dev->buf = msg->buf;
377473c88f9SBruce Richardson 	dev->msg_err = 0;
378473c88f9SBruce Richardson 	altera_i2c_enable(dev);
379473c88f9SBruce Richardson 
380473c88f9SBruce Richardson 	/*make sure RX FIFO is emtry*/
381473c88f9SBruce Richardson 	do {
382473c88f9SBruce Richardson 		i2c_indirect_read(dev, ALTERA_I2C_RX_DATA);
383473c88f9SBruce Richardson 	} while (i2c_indirect_read(dev, ALTERA_I2C_RX_FIFO_LVL));
384473c88f9SBruce Richardson 
385473c88f9SBruce Richardson 	i2c_indirect_write(dev, ALTERA_I2C_TFR_CMD_RW_D,
386473c88f9SBruce Richardson 			ALTERA_I2C_TFR_CMD_STA | addr);
387473c88f9SBruce Richardson 
388473c88f9SBruce Richardson 	/*enable irq*/
389473c88f9SBruce Richardson 	if (msg->flags & I2C_M_RD) {
390473c88f9SBruce Richardson 		int_mask |= ALTERA_I2C_ISR_RXOF | ALTERA_I2C_ISR_RXRDY;
391473c88f9SBruce Richardson 		/* in polling mode, we should set this ISR register? */
392473c88f9SBruce Richardson 		altera_i2c_enable_interrupt(dev, int_mask, true);
393473c88f9SBruce Richardson 		altera_i2c_transfer(dev, 0);
394473c88f9SBruce Richardson 	} else {
395473c88f9SBruce Richardson 		int_mask |= ALTERA_I2C_ISR_TXRDY;
396473c88f9SBruce Richardson 		altera_i2c_enable_interrupt(dev, int_mask, true);
397473c88f9SBruce Richardson 		altera_i2c_fill_tx_fifo(dev);
398473c88f9SBruce Richardson 	}
399473c88f9SBruce Richardson 
400473c88f9SBruce Richardson 	finish = altera_i2c_poll_status(dev);
401473c88f9SBruce Richardson 	if (!finish) {
402473c88f9SBruce Richardson 		dev->msg_err = -ETIMEDOUT;
403473c88f9SBruce Richardson 		dev_err(dev, "%s: i2c transfer error\n", __func__);
404473c88f9SBruce Richardson 	}
405473c88f9SBruce Richardson 
406473c88f9SBruce Richardson 	altera_i2c_enable_interrupt(dev, int_mask, false);
407473c88f9SBruce Richardson 
408473c88f9SBruce Richardson 	if (i2c_indirect_read(dev, ALTERA_I2C_STATUS) & ALTERA_I2C_STAT_CORE)
409473c88f9SBruce Richardson 		dev_info(dev, "core not idle...\n");
410473c88f9SBruce Richardson 
411473c88f9SBruce Richardson 	altera_i2c_disable(dev);
412473c88f9SBruce Richardson 
413473c88f9SBruce Richardson 	return dev->msg_err;
414473c88f9SBruce Richardson }
415473c88f9SBruce Richardson 
altera_i2c_xfer(struct altera_i2c_dev * dev,struct i2c_msg * msg,int num)416473c88f9SBruce Richardson static int altera_i2c_xfer(struct altera_i2c_dev *dev,
417473c88f9SBruce Richardson 		struct i2c_msg *msg, int num)
418473c88f9SBruce Richardson {
419473c88f9SBruce Richardson 	int ret = 0;
420473c88f9SBruce Richardson 	int i;
421473c88f9SBruce Richardson 
422473c88f9SBruce Richardson 	for (i = 0; i < num; i++, msg++) {
423473c88f9SBruce Richardson 		ret = altera_i2c_xfer_msg(dev, msg);
424473c88f9SBruce Richardson 		if (ret)
425473c88f9SBruce Richardson 			break;
426473c88f9SBruce Richardson 	}
427473c88f9SBruce Richardson 
428473c88f9SBruce Richardson 	return ret;
429473c88f9SBruce Richardson }
430473c88f9SBruce Richardson 
altera_i2c_hardware_init(struct altera_i2c_dev * dev)431473c88f9SBruce Richardson static void altera_i2c_hardware_init(struct altera_i2c_dev *dev)
432473c88f9SBruce Richardson {
433473c88f9SBruce Richardson 	u32 divisor = dev->i2c_clk / dev->bus_clk_rate;
434473c88f9SBruce Richardson 	u32 clk_mhz = dev->i2c_clk / 1000000;
435473c88f9SBruce Richardson 	u32 tmp = (ALTERA_I2C_THRESHOLD << ALTERA_I2C_CTRL_RXT_SHFT) |
436473c88f9SBruce Richardson 		  (ALTERA_I2C_THRESHOLD << ALTERA_I2C_CTRL_TCT_SHFT);
437473c88f9SBruce Richardson 	u32 t_high, t_low;
438473c88f9SBruce Richardson 
439473c88f9SBruce Richardson 	if (dev->bus_clk_rate <= 100000) {
440473c88f9SBruce Richardson 		tmp &= ~ALTERA_I2C_CTRL_BSPEED;
441473c88f9SBruce Richardson 		/*standard mode SCL 50/50*/
442473c88f9SBruce Richardson 		t_high = divisor*1/2;
443473c88f9SBruce Richardson 		t_low = divisor*1/2;
444473c88f9SBruce Richardson 	} else {
445473c88f9SBruce Richardson 		tmp |= ALTERA_I2C_CTRL_BSPEED;
446473c88f9SBruce Richardson 		/*Fast mode SCL 33/66*/
447473c88f9SBruce Richardson 		t_high = divisor*1/3;
448473c88f9SBruce Richardson 		t_low = divisor*2/3;
449473c88f9SBruce Richardson 	}
450473c88f9SBruce Richardson 
451473c88f9SBruce Richardson 	i2c_indirect_write(dev, ALTERA_I2C_CTRL, tmp);
452473c88f9SBruce Richardson 
453473c88f9SBruce Richardson 	dev_info(dev, "%s: rate=%uHz per_clk=%uMHz -> ratio=1:%u\n",
454473c88f9SBruce Richardson 		__func__, dev->bus_clk_rate, clk_mhz, divisor);
455473c88f9SBruce Richardson 
456473c88f9SBruce Richardson 	/*reset the i2c*/
457473c88f9SBruce Richardson 	altera_i2c_reset(dev);
458473c88f9SBruce Richardson 
459473c88f9SBruce Richardson 	/*Set SCL high Time*/
460473c88f9SBruce Richardson 	i2c_indirect_write(dev, ALTERA_I2C_SCL_HIGH, t_high);
461473c88f9SBruce Richardson 	/*Set SCL low time*/
462473c88f9SBruce Richardson 	i2c_indirect_write(dev, ALTERA_I2C_SCL_LOW, t_low);
463473c88f9SBruce Richardson 	/*Set SDA Hold time, 300ms*/
464473c88f9SBruce Richardson 	i2c_indirect_write(dev, ALTERA_I2C_SDA_HOLD, (300*clk_mhz)/1000);
465473c88f9SBruce Richardson 
466473c88f9SBruce Richardson 	altera_i2c_enable_interrupt(dev, ALTERA_I2C_ALL_IRQ, false);
467473c88f9SBruce Richardson }
468473c88f9SBruce Richardson 
altera_i2c_probe(void * base)469473c88f9SBruce Richardson struct altera_i2c_dev *altera_i2c_probe(void *base)
470473c88f9SBruce Richardson {
471473c88f9SBruce Richardson 	struct altera_i2c_dev *dev;
472473c88f9SBruce Richardson 
473473c88f9SBruce Richardson 	dev = opae_malloc(sizeof(*dev));
474473c88f9SBruce Richardson 	if (!dev)
475473c88f9SBruce Richardson 		return NULL;
476473c88f9SBruce Richardson 
477473c88f9SBruce Richardson 	dev->base = (u8 *)base;
478473c88f9SBruce Richardson 	dev->i2c_param.info = opae_readq(dev->base + I2C_PARAM);
479473c88f9SBruce Richardson 
480473c88f9SBruce Richardson 	if (dev->i2c_param.devid != 0xEE011) {
481473c88f9SBruce Richardson 		dev_err(dev, "find a invalid i2c master\n");
482473c88f9SBruce Richardson 		return NULL;
483473c88f9SBruce Richardson 	}
484473c88f9SBruce Richardson 
485473c88f9SBruce Richardson 	dev->fifo_size = dev->i2c_param.fifo_depth;
486473c88f9SBruce Richardson 
487473c88f9SBruce Richardson 	if (dev->i2c_param.max_req == ALTERA_I2C_100KHZ)
488473c88f9SBruce Richardson 		dev->bus_clk_rate = 100000;
489473c88f9SBruce Richardson 	else if (dev->i2c_param.max_req == ALTERA_I2C_400KHZ)
490473c88f9SBruce Richardson 		/* i2c bus clk 400KHz*/
491473c88f9SBruce Richardson 		dev->bus_clk_rate = 400000;
492473c88f9SBruce Richardson 
493473c88f9SBruce Richardson 	/* i2c input clock for vista creek is 100MHz */
494473c88f9SBruce Richardson 	dev->i2c_clk = dev->i2c_param.ref_clk * 1000000;
495473c88f9SBruce Richardson 	dev->xfer = altera_i2c_xfer;
496473c88f9SBruce Richardson 
4974a19f891STianfei Zhang 	if (pthread_mutex_init(&dev->lock, NULL))
4984a19f891STianfei Zhang 		return NULL;
499*e41856b5SWei Huang 	dev->mutex = &dev->lock;
5004a19f891STianfei Zhang 
501473c88f9SBruce Richardson 	altera_i2c_hardware_init(dev);
502473c88f9SBruce Richardson 
503473c88f9SBruce Richardson 	return dev;
504473c88f9SBruce Richardson }
505473c88f9SBruce Richardson 
altera_i2c_remove(struct altera_i2c_dev * dev)5064a19f891STianfei Zhang void altera_i2c_remove(struct altera_i2c_dev *dev)
507473c88f9SBruce Richardson {
5084a19f891STianfei Zhang 	if (dev) {
5094a19f891STianfei Zhang 		pthread_mutex_destroy(&dev->lock);
510473c88f9SBruce Richardson 		altera_i2c_disable(dev);
5114a19f891STianfei Zhang 		opae_free(dev);
5124a19f891STianfei Zhang 	}
513473c88f9SBruce Richardson }
514