i2c-bfin-twi.c revision be2f80f0a3a333c0c00b2c8a7c2d74fcd66b75a2
1d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu/*
2bd584996b092a019a3ac32fcde7c3851935add96Mike Frysinger * Blackfin On-Chip Two Wire Interface Driver
3d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu *
4bd584996b092a019a3ac32fcde7c3851935add96Mike Frysinger * Copyright 2005-2007 Analog Devices Inc.
5d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu *
6bd584996b092a019a3ac32fcde7c3851935add96Mike Frysinger * Enter bugs at http://blackfin.uclinux.org/
7d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu *
8bd584996b092a019a3ac32fcde7c3851935add96Mike Frysinger * Licensed under the GPL-2 or later.
9d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu */
10d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
11d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu#include <linux/module.h>
12d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu#include <linux/kernel.h>
13d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu#include <linux/init.h>
14d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu#include <linux/i2c.h>
155a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
166df263cf2ee1c6dd9709488ecd3c7b3447511ecfMike Frysinger#include <linux/io.h>
17d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu#include <linux/mm.h>
18d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu#include <linux/timer.h>
19d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu#include <linux/spinlock.h>
20d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu#include <linux/completion.h>
21d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu#include <linux/interrupt.h>
22d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu#include <linux/platform_device.h>
23d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
24d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu#include <asm/blackfin.h>
2574d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu#include <asm/portmux.h>
26d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu#include <asm/irq.h>
27d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
28d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu/* SMBus mode*/
294dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang#define TWI_I2C_MODE_STANDARD		1
304dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang#define TWI_I2C_MODE_STANDARDSUB	2
314dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang#define TWI_I2C_MODE_COMBINED		3
324dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang#define TWI_I2C_MODE_REPEAT		4
33d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
34d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wustruct bfin_twi_iface {
35d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	int			irq;
36d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	spinlock_t		lock;
37d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	char			read_write;
38d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	u8			command;
39d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	u8			*transPtr;
40d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	int			readNum;
41d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	int			writeNum;
42d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	int			cur_mode;
43d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	int			manual_stop;
44d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	int			result;
45d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	struct i2c_adapter	adap;
46d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	struct completion	complete;
474dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	struct i2c_msg 		*pmsg;
484dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	int			msg_num;
494dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	int			cur_msg;
50958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich	u16			saved_clkdiv;
51958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich	u16			saved_control;
52aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	void __iomem		*regs_base;
53d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu};
54d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
55aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu
56aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu#define DEFINE_TWI_REG(reg, off) \
57aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wustatic inline u16 read_##reg(struct bfin_twi_iface *iface) \
58aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	{ return bfin_read16(iface->regs_base + (off)); } \
59aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wustatic inline void write_##reg(struct bfin_twi_iface *iface, u16 v) \
60aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	{ bfin_write16(iface->regs_base + (off), v); }
61aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu
62aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(CLKDIV, 0x00)
63aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(CONTROL, 0x04)
64aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(SLAVE_CTL, 0x08)
65aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(SLAVE_STAT, 0x0C)
66aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(SLAVE_ADDR, 0x10)
67aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(MASTER_CTL, 0x14)
68aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(MASTER_STAT, 0x18)
69aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(MASTER_ADDR, 0x1C)
70aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(INT_STAT, 0x20)
71aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(INT_MASK, 0x24)
72aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(FIFO_CTL, 0x28)
73aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(FIFO_STAT, 0x2C)
74aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(XMT_DATA8, 0x80)
75aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(XMT_DATA16, 0x84)
76aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(RCV_DATA8, 0x88)
77aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(RCV_DATA16, 0x8C)
78d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
7974d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wustatic const u16 pin_req[2][3] = {
8074d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu	{P_TWI0_SCL, P_TWI0_SDA, 0},
8174d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu	{P_TWI1_SCL, P_TWI1_SDA, 0},
8274d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu};
8374d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu
845481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhangstatic void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
855481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang					unsigned short twi_int_status)
86d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{
87aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	unsigned short mast_stat = read_MASTER_STAT(iface);
88d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
89d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	if (twi_int_status & XMTSERV) {
90d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		/* Transmit next data */
91d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		if (iface->writeNum > 0) {
925481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang			SSYNC();
93aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu			write_XMT_DATA8(iface, *(iface->transPtr++));
94d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			iface->writeNum--;
95d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		}
96d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		/* start receive immediately after complete sending in
97d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		 * combine mode.
98d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		 */
994dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang		else if (iface->cur_mode == TWI_I2C_MODE_COMBINED)
100aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu			write_MASTER_CTL(iface,
101aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu				read_MASTER_CTL(iface) | MDIR | RSTART);
1024dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang		else if (iface->manual_stop)
103aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu			write_MASTER_CTL(iface,
104aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu				read_MASTER_CTL(iface) | STOP);
1054dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang		else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
10694327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew		         iface->cur_msg + 1 < iface->msg_num) {
10794327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew			if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
10894327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew				write_MASTER_CTL(iface,
10994327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew					read_MASTER_CTL(iface) | RSTART | MDIR);
11094327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew			else
11194327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew				write_MASTER_CTL(iface,
11294327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew					(read_MASTER_CTL(iface) | RSTART) & ~MDIR);
11394327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew		}
114d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	}
115d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	if (twi_int_status & RCVSERV) {
116d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		if (iface->readNum > 0) {
117d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			/* Receive next data */
118aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu			*(iface->transPtr) = read_RCV_DATA8(iface);
119d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
120d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				/* Change combine mode into sub mode after
121d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				 * read first data.
122d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				 */
123d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
124d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				/* Get read number from first byte in block
125d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				 * combine mode.
126d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				 */
127d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				if (iface->readNum == 1 && iface->manual_stop)
128d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu					iface->readNum = *iface->transPtr + 1;
129d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			}
130d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			iface->transPtr++;
131d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			iface->readNum--;
132d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		} else if (iface->manual_stop) {
133aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu			write_MASTER_CTL(iface,
134aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu				read_MASTER_CTL(iface) | STOP);
1354dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang		} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
13694327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew		           iface->cur_msg + 1 < iface->msg_num) {
13794327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew			if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
13894327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew				write_MASTER_CTL(iface,
13994327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew					read_MASTER_CTL(iface) | RSTART | MDIR);
14094327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew			else
14194327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew				write_MASTER_CTL(iface,
14294327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew					(read_MASTER_CTL(iface) | RSTART) & ~MDIR);
143d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		}
144d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	}
145d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	if (twi_int_status & MERR) {
146aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		write_INT_MASK(iface, 0);
147aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		write_MASTER_STAT(iface, 0x3e);
148aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		write_MASTER_CTL(iface, 0);
1494dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang		iface->result = -EIO;
1505cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich
1515cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich		if (mast_stat & LOSTARB)
1525cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich			dev_dbg(&iface->adap.dev, "Lost Arbitration\n");
1535cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich		if (mast_stat & ANAK)
1545cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich			dev_dbg(&iface->adap.dev, "Address Not Acknowledged\n");
1555cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich		if (mast_stat & DNAK)
1565cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich			dev_dbg(&iface->adap.dev, "Data Not Acknowledged\n");
1575cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich		if (mast_stat & BUFRDERR)
1585cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich			dev_dbg(&iface->adap.dev, "Buffer Read Error\n");
1595cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich		if (mast_stat & BUFWRERR)
1605cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich			dev_dbg(&iface->adap.dev, "Buffer Write Error\n");
1615cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich
162d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		/* if both err and complete int stats are set, return proper
163d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		 * results.
164d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		 */
165d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		if (twi_int_status & MCOMP) {
166dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang			/* If it is a quick transfer, only address without data,
167d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			 * not an err, return 1.
168dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang			 * If address is acknowledged return 1.
169d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			 */
170dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang			if ((iface->writeNum == 0 && (mast_stat & BUFRDERR))
171dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang				|| !(mast_stat & ANAK))
172d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				iface->result = 1;
173d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		}
174d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		complete(&iface->complete);
175d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		return;
176d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	}
177d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	if (twi_int_status & MCOMP) {
178d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
179d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			if (iface->readNum == 0) {
180d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				/* set the read number to 1 and ask for manual
181d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				 * stop in block combine mode
182d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				 */
183d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				iface->readNum = 1;
184d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				iface->manual_stop = 1;
185aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu				write_MASTER_CTL(iface,
186aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu					read_MASTER_CTL(iface) | (0xff << 6));
187d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			} else {
188d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				/* set the readd number in other
189d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				 * combine mode.
190d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				 */
191aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu				write_MASTER_CTL(iface,
192aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu					(read_MASTER_CTL(iface) &
193d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu					(~(0xff << 6))) |
194aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu					(iface->readNum << 6));
195d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			}
196d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			/* remove restart bit and enable master receive */
197aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu			write_MASTER_CTL(iface,
198aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu				read_MASTER_CTL(iface) & ~RSTART);
1994dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang		} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
2004dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang				iface->cur_msg+1 < iface->msg_num) {
2014dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang			iface->cur_msg++;
2024dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang			iface->transPtr = iface->pmsg[iface->cur_msg].buf;
2034dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang			iface->writeNum = iface->readNum =
2044dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang				iface->pmsg[iface->cur_msg].len;
2054dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang			/* Set Transmit device address */
206aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu			write_MASTER_ADDR(iface,
2074dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang				iface->pmsg[iface->cur_msg].addr);
2084dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang			if (iface->pmsg[iface->cur_msg].flags & I2C_M_RD)
2094dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang				iface->read_write = I2C_SMBUS_READ;
2104dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang			else {
2114dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang				iface->read_write = I2C_SMBUS_WRITE;
2124dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang				/* Transmit first data */
2134dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang				if (iface->writeNum > 0) {
214aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu					write_XMT_DATA8(iface,
2154dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang						*(iface->transPtr++));
2164dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang					iface->writeNum--;
2174dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang				}
2184dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang			}
2194dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang
2204dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang			if (iface->pmsg[iface->cur_msg].len <= 255)
22157a8f32eafa6f36ea3a128e8b13f353c5a3ca9b2Sonic Zhang					write_MASTER_CTL(iface,
22257a8f32eafa6f36ea3a128e8b13f353c5a3ca9b2Sonic Zhang					(read_MASTER_CTL(iface) &
22357a8f32eafa6f36ea3a128e8b13f353c5a3ca9b2Sonic Zhang					(~(0xff << 6))) |
22457a8f32eafa6f36ea3a128e8b13f353c5a3ca9b2Sonic Zhang				(iface->pmsg[iface->cur_msg].len << 6));
2254dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang			else {
22657a8f32eafa6f36ea3a128e8b13f353c5a3ca9b2Sonic Zhang				write_MASTER_CTL(iface,
22757a8f32eafa6f36ea3a128e8b13f353c5a3ca9b2Sonic Zhang					(read_MASTER_CTL(iface) |
22857a8f32eafa6f36ea3a128e8b13f353c5a3ca9b2Sonic Zhang					(0xff << 6)));
2294dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang				iface->manual_stop = 1;
2304dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang			}
2314dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang			/* remove restart bit and enable master receive */
232aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu			write_MASTER_CTL(iface,
233aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu				read_MASTER_CTL(iface) & ~RSTART);
234d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		} else {
235d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			iface->result = 1;
236aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu			write_INT_MASK(iface, 0);
237aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu			write_MASTER_CTL(iface, 0);
238d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		}
239d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	}
240dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang	complete(&iface->complete);
241d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu}
242d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
243d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu/* Interrupt handler */
244d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wustatic irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id)
245d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{
246d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	struct bfin_twi_iface *iface = dev_id;
247d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	unsigned long flags;
2485481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang	unsigned short twi_int_status;
249d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
250d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	spin_lock_irqsave(&iface->lock, flags);
2515481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang	while (1) {
2525481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang		twi_int_status = read_INT_STAT(iface);
2535481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang		if (!twi_int_status)
2545481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang			break;
2555481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang		/* Clear interrupt status */
2565481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang		write_INT_STAT(iface, twi_int_status);
2575481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang		bfin_twi_handle_interrupt(iface, twi_int_status);
2585481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang		SSYNC();
2595481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang	}
260d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	spin_unlock_irqrestore(&iface->lock, flags);
261d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	return IRQ_HANDLED;
262d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu}
263d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
264d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu/*
265dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang * One i2c master transfer
266d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu */
267dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhangstatic int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
268d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				struct i2c_msg *msgs, int num)
269d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{
270d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	struct bfin_twi_iface *iface = adap->algo_data;
271d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	struct i2c_msg *pmsg;
272d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	int rc = 0;
273d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
274aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	if (!(read_CONTROL(iface) & TWI_ENA))
275d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		return -ENXIO;
276d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
277aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	while (read_MASTER_STAT(iface) & BUSBUSY)
278d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		yield();
279d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
2804dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	iface->pmsg = msgs;
2814dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	iface->msg_num = num;
2824dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	iface->cur_msg = 0;
283d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
2844dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	pmsg = &msgs[0];
2854dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	if (pmsg->flags & I2C_M_TEN) {
2864dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang		dev_err(&adap->dev, "10 bits addr not supported!\n");
2874dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang		return -EINVAL;
2884dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	}
289d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
2904dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	iface->cur_mode = TWI_I2C_MODE_REPEAT;
2914dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	iface->manual_stop = 0;
2924dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	iface->transPtr = pmsg->buf;
2934dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	iface->writeNum = iface->readNum = pmsg->len;
2944dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	iface->result = 0;
295afc13b765ea71d316ce4974d3dc5a96cc73a0e95Hans Schillstrom	init_completion(&(iface->complete));
2964dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	/* Set Transmit device address */
297aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	write_MASTER_ADDR(iface, pmsg->addr);
2984dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang
2994dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	/* FIFO Initiation. Data in FIFO should be
3004dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	 *  discarded before start a new operation.
3014dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	 */
302aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	write_FIFO_CTL(iface, 0x3);
3034dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	SSYNC();
304aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	write_FIFO_CTL(iface, 0);
3054dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	SSYNC();
3064dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang
3074dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	if (pmsg->flags & I2C_M_RD)
3084dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang		iface->read_write = I2C_SMBUS_READ;
3094dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	else {
3104dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang		iface->read_write = I2C_SMBUS_WRITE;
3114dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang		/* Transmit first data */
3124dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang		if (iface->writeNum > 0) {
313aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu			write_XMT_DATA8(iface, *(iface->transPtr++));
3144dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang			iface->writeNum--;
3154dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang			SSYNC();
316d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		}
3174dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	}
318d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
3194dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	/* clear int stat */
320aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	write_INT_STAT(iface, MERR | MCOMP | XMTSERV | RCVSERV);
321d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
3224dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	/* Interrupt mask . Enable XMT, RCV interrupt */
323aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
3244dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	SSYNC();
325d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
3264dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	if (pmsg->len <= 255)
327aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		write_MASTER_CTL(iface, pmsg->len << 6);
3284dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	else {
329aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		write_MASTER_CTL(iface, 0xff << 6);
3304dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang		iface->manual_stop = 1;
3314dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	}
332d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
3334dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	/* Master enable */
334aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
3354dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang		((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
3364dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang		((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
3374dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	SSYNC();
3384dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang
339dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang	while (!iface->result) {
340dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang		if (!wait_for_completion_timeout(&iface->complete,
341dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang			adap->timeout)) {
342dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang			iface->result = -1;
343dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang			dev_err(&adap->dev, "master transfer timeout\n");
344dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang		}
345dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang	}
346d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
347dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang	if (iface->result == 1)
348dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang		rc = iface->cur_msg + 1;
3494dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang	else
350dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang		rc = iface->result;
351dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang
352dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang	return rc;
353d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu}
354d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
355d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu/*
356dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang * Generic i2c master transfer entrypoint
357d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu */
358dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhangstatic int bfin_twi_master_xfer(struct i2c_adapter *adap,
359dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang				struct i2c_msg *msgs, int num)
360dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang{
361be2f80f0a3a333c0c00b2c8a7c2d74fcd66b75a2Sonic Zhang	return bfin_twi_do_master_xfer(adap, msgs, num);
362dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang}
363dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang
364dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang/*
365dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang * One I2C SMBus transfer
366dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang */
367dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhangint bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
368d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			unsigned short flags, char read_write,
369d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			u8 command, int size, union i2c_smbus_data *data)
370d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{
371d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	struct bfin_twi_iface *iface = adap->algo_data;
372d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	int rc = 0;
373d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
374aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	if (!(read_CONTROL(iface) & TWI_ENA))
375d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		return -ENXIO;
376d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
377aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	while (read_MASTER_STAT(iface) & BUSBUSY)
378d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		yield();
379d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
380d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	iface->writeNum = 0;
381d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	iface->readNum = 0;
382d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
383d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	/* Prepare datas & select mode */
384d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	switch (size) {
385d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	case I2C_SMBUS_QUICK:
386d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		iface->transPtr = NULL;
387d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		iface->cur_mode = TWI_I2C_MODE_STANDARD;
388d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		break;
389d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	case I2C_SMBUS_BYTE:
390d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		if (data == NULL)
391d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			iface->transPtr = NULL;
392d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		else {
393d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			if (read_write == I2C_SMBUS_READ)
394d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				iface->readNum = 1;
395d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			else
396d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				iface->writeNum = 1;
397d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			iface->transPtr = &data->byte;
398d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		}
399d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		iface->cur_mode = TWI_I2C_MODE_STANDARD;
400d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		break;
401d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	case I2C_SMBUS_BYTE_DATA:
402d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		if (read_write == I2C_SMBUS_READ) {
403d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			iface->readNum = 1;
404d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			iface->cur_mode = TWI_I2C_MODE_COMBINED;
405d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		} else {
406d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			iface->writeNum = 1;
407d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
408d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		}
409d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		iface->transPtr = &data->byte;
410d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		break;
411d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	case I2C_SMBUS_WORD_DATA:
412d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		if (read_write == I2C_SMBUS_READ) {
413d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			iface->readNum = 2;
414d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			iface->cur_mode = TWI_I2C_MODE_COMBINED;
415d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		} else {
416d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			iface->writeNum = 2;
417d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
418d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		}
419d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		iface->transPtr = (u8 *)&data->word;
420d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		break;
421d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	case I2C_SMBUS_PROC_CALL:
422d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		iface->writeNum = 2;
423d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		iface->readNum = 2;
424d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		iface->cur_mode = TWI_I2C_MODE_COMBINED;
425d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		iface->transPtr = (u8 *)&data->word;
426d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		break;
427d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	case I2C_SMBUS_BLOCK_DATA:
428d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		if (read_write == I2C_SMBUS_READ) {
429d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			iface->readNum = 0;
430d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			iface->cur_mode = TWI_I2C_MODE_COMBINED;
431d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		} else {
432d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			iface->writeNum = data->block[0] + 1;
433d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
434d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		}
435d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		iface->transPtr = data->block;
436d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		break;
437e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich	case I2C_SMBUS_I2C_BLOCK_DATA:
438e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich		if (read_write == I2C_SMBUS_READ) {
439e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich			iface->readNum = data->block[0];
440e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich			iface->cur_mode = TWI_I2C_MODE_COMBINED;
441e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich		} else {
442e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich			iface->writeNum = data->block[0];
443e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich			iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
444e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich		}
445e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich		iface->transPtr = (u8 *)&data->block[1];
446e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich		break;
447d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	default:
448d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		return -1;
449d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	}
450d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
451d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	iface->result = 0;
452d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	iface->manual_stop = 0;
453d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	iface->read_write = read_write;
454d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	iface->command = command;
455afc13b765ea71d316ce4974d3dc5a96cc73a0e95Hans Schillstrom	init_completion(&(iface->complete));
456d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
457d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	/* FIFO Initiation. Data in FIFO should be discarded before
458d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	 * start a new operation.
459d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	 */
460aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	write_FIFO_CTL(iface, 0x3);
461d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	SSYNC();
462aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	write_FIFO_CTL(iface, 0);
463d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
464d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	/* clear int stat */
465aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	write_INT_STAT(iface, MERR | MCOMP | XMTSERV | RCVSERV);
466d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
467d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	/* Set Transmit device address */
468aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	write_MASTER_ADDR(iface, addr);
469d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	SSYNC();
470d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
471d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	switch (iface->cur_mode) {
472d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	case TWI_I2C_MODE_STANDARDSUB:
473aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		write_XMT_DATA8(iface, iface->command);
474aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		write_INT_MASK(iface, MCOMP | MERR |
475d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			((iface->read_write == I2C_SMBUS_READ) ?
476d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			RCVSERV : XMTSERV));
477d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		SSYNC();
478d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
479d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		if (iface->writeNum + 1 <= 255)
480aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu			write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
481d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		else {
482aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu			write_MASTER_CTL(iface, 0xff << 6);
483d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			iface->manual_stop = 1;
484d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		}
485d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		/* Master enable */
486aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
487d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
488d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		break;
489d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	case TWI_I2C_MODE_COMBINED:
490aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		write_XMT_DATA8(iface, iface->command);
491aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
492d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		SSYNC();
493d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
494d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		if (iface->writeNum > 0)
495aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu			write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
496d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		else
497aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu			write_MASTER_CTL(iface, 0x1 << 6);
498d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		/* Master enable */
499aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
500d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
501d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		break;
502d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	default:
503aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		write_MASTER_CTL(iface, 0);
504d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		if (size != I2C_SMBUS_QUICK) {
505d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			/* Don't access xmit data register when this is a
506d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			 * read operation.
507d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			 */
508d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			if (iface->read_write != I2C_SMBUS_READ) {
509d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				if (iface->writeNum > 0) {
510aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu					write_XMT_DATA8(iface,
511aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu						*(iface->transPtr++));
512d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu					if (iface->writeNum <= 255)
513aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu						write_MASTER_CTL(iface,
514aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu							iface->writeNum << 6);
515d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu					else {
516aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu						write_MASTER_CTL(iface,
517aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu							0xff << 6);
518d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu						iface->manual_stop = 1;
519d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu					}
520d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu					iface->writeNum--;
521d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				} else {
522aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu					write_XMT_DATA8(iface, iface->command);
523aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu					write_MASTER_CTL(iface, 1 << 6);
524d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				}
525d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			} else {
526d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				if (iface->readNum > 0 && iface->readNum <= 255)
527aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu					write_MASTER_CTL(iface,
528aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu						iface->readNum << 6);
529d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu				else if (iface->readNum > 255) {
530aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu					write_MASTER_CTL(iface, 0xff << 6);
531d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu					iface->manual_stop = 1;
532dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang				} else
533d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu					break;
534d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			}
535d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		}
536aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		write_INT_MASK(iface, MCOMP | MERR |
537d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			((iface->read_write == I2C_SMBUS_READ) ?
538d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			RCVSERV : XMTSERV));
539d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		SSYNC();
540d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
541d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		/* Master enable */
542aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
543d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
544d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu			((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
545d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		break;
546d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	}
547d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	SSYNC();
548d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
549dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang	while (!iface->result) {
550dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang		if (!wait_for_completion_timeout(&iface->complete,
551dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang			adap->timeout)) {
552dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang			iface->result = -1;
553dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang			dev_err(&adap->dev, "smbus transfer timeout\n");
554dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang		}
555dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang	}
556d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
557d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	rc = (iface->result >= 0) ? 0 : -1;
558d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
559d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	return rc;
560d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu}
561d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
562d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu/*
563dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang * Generic I2C SMBus transfer entrypoint
564dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang */
565dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhangint bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
566dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang			unsigned short flags, char read_write,
567dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang			u8 command, int size, union i2c_smbus_data *data)
568dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang{
569be2f80f0a3a333c0c00b2c8a7c2d74fcd66b75a2Sonic Zhang	return bfin_twi_do_smbus_xfer(adap, addr, flags,
570dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang			read_write, command, size, data);
571dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang}
572dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang
573dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang/*
574d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu * Return what the adapter supports
575d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu */
576d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wustatic u32 bfin_twi_functionality(struct i2c_adapter *adap)
577d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{
578d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
579d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
580d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	       I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL |
581e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich	       I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK;
582d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu}
583d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
584d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wustatic struct i2c_algorithm bfin_twi_algorithm = {
585d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	.master_xfer   = bfin_twi_master_xfer,
586d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	.smbus_xfer    = bfin_twi_smbus_xfer,
587d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	.functionality = bfin_twi_functionality,
588d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu};
589d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
590958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerichstatic int i2c_bfin_twi_suspend(struct platform_device *pdev, pm_message_t state)
591d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{
592958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich	struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
593958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich
594958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich	iface->saved_clkdiv = read_CLKDIV(iface);
595958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich	iface->saved_control = read_CONTROL(iface);
596958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich
597958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich	free_irq(iface->irq, iface);
598d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
599d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	/* Disable TWI */
600958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich	write_CONTROL(iface, iface->saved_control & ~TWI_ENA);
601d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
602d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	return 0;
603d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu}
604d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
605958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerichstatic int i2c_bfin_twi_resume(struct platform_device *pdev)
606d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{
607958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich	struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
608d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
609958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich	int rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
610958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich		IRQF_DISABLED, pdev->name, iface);
611958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich	if (rc) {
612958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich		dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
613958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich		return -ENODEV;
614958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich	}
615958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich
616958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich	/* Resume TWI interface clock as specified */
617958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich	write_CLKDIV(iface, iface->saved_clkdiv);
618958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich
619958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich	/* Resume TWI */
620958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich	write_CONTROL(iface, iface->saved_control);
621d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
622d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	return 0;
623d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu}
624d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
625aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wustatic int i2c_bfin_twi_probe(struct platform_device *pdev)
626d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{
627aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	struct bfin_twi_iface *iface;
628d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	struct i2c_adapter *p_adap;
629aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	struct resource *res;
630d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	int rc;
6319528d1c7a541b481a0e80301dc8d545848104023Michael Hennerich	unsigned int clkhilow;
632d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
633aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL);
634aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	if (!iface) {
635aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		dev_err(&pdev->dev, "Cannot allocate memory\n");
636aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		rc = -ENOMEM;
637aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		goto out_error_nomem;
638aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	}
639aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu
640d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	spin_lock_init(&(iface->lock));
641aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu
642aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	/* Find and map our resources */
643aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
644aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	if (res == NULL) {
645aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
646aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		rc = -ENOENT;
647aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		goto out_error_get_res;
648aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	}
649aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu
650c6ffddea36dd576b70dfbd10eb5d2b287b786dcaLinus Walleij	iface->regs_base = ioremap(res->start, resource_size(res));
651aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	if (iface->regs_base == NULL) {
652aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		dev_err(&pdev->dev, "Cannot map IO\n");
653aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		rc = -ENXIO;
654aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		goto out_error_ioremap;
655aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	}
656aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu
657aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	iface->irq = platform_get_irq(pdev, 0);
658aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	if (iface->irq < 0) {
659aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		dev_err(&pdev->dev, "No IRQ specified\n");
660aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		rc = -ENOENT;
661aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		goto out_error_no_irq;
662aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	}
663d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
664d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	p_adap = &iface->adap;
665aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	p_adap->nr = pdev->id;
666aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name));
667d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	p_adap->algo = &bfin_twi_algorithm;
668d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	p_adap->algo_data = iface;
669e1995f65be0786ca201f466f049dad1e2e4c3421Jean Delvare	p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
670aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	p_adap->dev.parent = &pdev->dev;
671dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang	p_adap->timeout = 5 * HZ;
672dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang	p_adap->retries = 3;
673d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
67474d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu	rc = peripheral_request_list(pin_req[pdev->id], "i2c-bfin-twi");
67574d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu	if (rc) {
67674d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu		dev_err(&pdev->dev, "Can't setup pin mux!\n");
67774d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu		goto out_error_pin_mux;
67874d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu	}
67974d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu
680d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
681aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		IRQF_DISABLED, pdev->name, iface);
682d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	if (rc) {
683aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
684aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		rc = -ENODEV;
685aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		goto out_error_req_irq;
686d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	}
687d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
688d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	/* Set TWI internal clock as 10MHz */
689ac07fb4dc1908d300f50fa711982c9d750eb59f7Sonic Zhang	write_CONTROL(iface, ((get_sclk() / 1000 / 1000 + 5) / 10) & 0x7F);
690d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
6919528d1c7a541b481a0e80301dc8d545848104023Michael Hennerich	/*
6929528d1c7a541b481a0e80301dc8d545848104023Michael Hennerich	 * We will not end up with a CLKDIV=0 because no one will specify
693ac07fb4dc1908d300f50fa711982c9d750eb59f7Sonic Zhang	 * 20kHz SCL or less in Kconfig now. (5 * 1000 / 20 = 250)
6949528d1c7a541b481a0e80301dc8d545848104023Michael Hennerich	 */
695ac07fb4dc1908d300f50fa711982c9d750eb59f7Sonic Zhang	clkhilow = ((10 * 1000 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ) + 1) / 2;
6969528d1c7a541b481a0e80301dc8d545848104023Michael Hennerich
697d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	/* Set Twi interface clock as specified */
6989528d1c7a541b481a0e80301dc8d545848104023Michael Hennerich	write_CLKDIV(iface, (clkhilow << 8) | clkhilow);
699d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
700d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	/* Enable TWI */
701aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
702d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	SSYNC();
703d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
704991dee591a99d035796a8c194eb1796cc020e142Kalle Pokki	rc = i2c_add_numbered_adapter(p_adap);
705aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	if (rc < 0) {
706aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		dev_err(&pdev->dev, "Can't add i2c adapter!\n");
707aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu		goto out_error_add_adapter;
708aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	}
709aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu
710aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	platform_set_drvdata(pdev, iface);
711d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
712fa6ad222713a65980528348e7f75abc768b78297Bryan Wu	dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Contoller, "
713fa6ad222713a65980528348e7f75abc768b78297Bryan Wu		"regs_base@%p\n", iface->regs_base);
714aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu
715aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	return 0;
716aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu
717aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wuout_error_add_adapter:
718aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	free_irq(iface->irq, iface);
719aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wuout_error_req_irq:
720aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wuout_error_no_irq:
72174d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu	peripheral_free_list(pin_req[pdev->id]);
72274d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wuout_error_pin_mux:
723aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	iounmap(iface->regs_base);
724aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wuout_error_ioremap:
725aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wuout_error_get_res:
726aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	kfree(iface);
727aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wuout_error_nomem:
728d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	return rc;
729d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu}
730d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
731d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wustatic int i2c_bfin_twi_remove(struct platform_device *pdev)
732d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{
733d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
734d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
735d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	platform_set_drvdata(pdev, NULL);
736d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
737d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	i2c_del_adapter(&(iface->adap));
738d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	free_irq(iface->irq, iface);
73974d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu	peripheral_free_list(pin_req[pdev->id]);
740aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	iounmap(iface->regs_base);
741aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu	kfree(iface);
742d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
743d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	return 0;
744d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu}
745d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
746d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wustatic struct platform_driver i2c_bfin_twi_driver = {
747d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	.probe		= i2c_bfin_twi_probe,
748d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	.remove		= i2c_bfin_twi_remove,
749d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	.suspend	= i2c_bfin_twi_suspend,
750d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	.resume		= i2c_bfin_twi_resume,
751d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	.driver		= {
752d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		.name	= "i2c-bfin-twi",
753d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu		.owner	= THIS_MODULE,
754d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	},
755d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu};
756d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
757d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wustatic int __init i2c_bfin_twi_init(void)
758d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{
759d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	return platform_driver_register(&i2c_bfin_twi_driver);
760d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu}
761d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
762d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wustatic void __exit i2c_bfin_twi_exit(void)
763d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{
764d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu	platform_driver_unregister(&i2c_bfin_twi_driver);
765d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu}
766d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu
767d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wumodule_init(i2c_bfin_twi_init);
768d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wumodule_exit(i2c_bfin_twi_exit);
769fa6ad222713a65980528348e7f75abc768b78297Bryan Wu
770fa6ad222713a65980528348e7f75abc768b78297Bryan WuMODULE_AUTHOR("Bryan Wu, Sonic Zhang");
771fa6ad222713a65980528348e7f75abc768b78297Bryan WuMODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Contoller Driver");
772fa6ad222713a65980528348e7f75abc768b78297Bryan WuMODULE_LICENSE("GPL");
773add8eda7f2be781af0224241e870715cf0cfd75aKay SieversMODULE_ALIAS("platform:i2c-bfin-twi");
774