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> 23540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich#include <linux/delay.h> 24d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 25d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu#include <asm/blackfin.h> 2674d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu#include <asm/portmux.h> 27d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu#include <asm/irq.h> 28d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 29d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu/* SMBus mode*/ 304dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang#define TWI_I2C_MODE_STANDARD 1 314dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang#define TWI_I2C_MODE_STANDARDSUB 2 324dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang#define TWI_I2C_MODE_COMBINED 3 334dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang#define TWI_I2C_MODE_REPEAT 4 34d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 35d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wustruct bfin_twi_iface { 36d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu int irq; 37d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu spinlock_t lock; 38d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu char read_write; 39d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu u8 command; 40d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu u8 *transPtr; 41d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu int readNum; 42d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu int writeNum; 43d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu int cur_mode; 44d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu int manual_stop; 45d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu int result; 46d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu struct i2c_adapter adap; 47d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu struct completion complete; 484dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang struct i2c_msg *pmsg; 494dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang int msg_num; 504dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang int cur_msg; 51958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich u16 saved_clkdiv; 52958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich u16 saved_control; 53aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu void __iomem *regs_base; 54d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu}; 55d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 56aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu 57aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu#define DEFINE_TWI_REG(reg, off) \ 58aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wustatic inline u16 read_##reg(struct bfin_twi_iface *iface) \ 59aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu { return bfin_read16(iface->regs_base + (off)); } \ 60aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wustatic inline void write_##reg(struct bfin_twi_iface *iface, u16 v) \ 61aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu { bfin_write16(iface->regs_base + (off), v); } 62aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu 63aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(CLKDIV, 0x00) 64aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(CONTROL, 0x04) 65aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(SLAVE_CTL, 0x08) 66aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(SLAVE_STAT, 0x0C) 67aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(SLAVE_ADDR, 0x10) 68aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(MASTER_CTL, 0x14) 69aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(MASTER_STAT, 0x18) 70aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(MASTER_ADDR, 0x1C) 71aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(INT_STAT, 0x20) 72aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(INT_MASK, 0x24) 73aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(FIFO_CTL, 0x28) 74aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(FIFO_STAT, 0x2C) 75aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(XMT_DATA8, 0x80) 76aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(XMT_DATA16, 0x84) 77aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(RCV_DATA8, 0x88) 78aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan WuDEFINE_TWI_REG(RCV_DATA16, 0x8C) 79d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 8074d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wustatic const u16 pin_req[2][3] = { 8174d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu {P_TWI0_SCL, P_TWI0_SDA, 0}, 8274d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu {P_TWI1_SCL, P_TWI1_SDA, 0}, 8374d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu}; 8474d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu 855481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhangstatic void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, 865481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang unsigned short twi_int_status) 87d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{ 88aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu unsigned short mast_stat = read_MASTER_STAT(iface); 89d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 90d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (twi_int_status & XMTSERV) { 91d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* Transmit next data */ 92d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (iface->writeNum > 0) { 935481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang SSYNC(); 94aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_XMT_DATA8(iface, *(iface->transPtr++)); 95d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->writeNum--; 96d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 97d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* start receive immediately after complete sending in 98d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu * combine mode. 99d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu */ 1004dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) 101aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, 102aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu read_MASTER_CTL(iface) | MDIR | RSTART); 1034dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang else if (iface->manual_stop) 104aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, 105aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu read_MASTER_CTL(iface) | STOP); 1064dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && 10794327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew iface->cur_msg + 1 < iface->msg_num) { 10894327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD) 10994327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew write_MASTER_CTL(iface, 11094327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew read_MASTER_CTL(iface) | RSTART | MDIR); 11194327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew else 11294327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew write_MASTER_CTL(iface, 11394327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew (read_MASTER_CTL(iface) | RSTART) & ~MDIR); 11494327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew } 115d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 116d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (twi_int_status & RCVSERV) { 117d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (iface->readNum > 0) { 118d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* Receive next data */ 119aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu *(iface->transPtr) = read_RCV_DATA8(iface); 120d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { 121d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* Change combine mode into sub mode after 122d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu * read first data. 123d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu */ 124d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; 125d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* Get read number from first byte in block 126d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu * combine mode. 127d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu */ 128d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (iface->readNum == 1 && iface->manual_stop) 129d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->readNum = *iface->transPtr + 1; 130d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 131d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->transPtr++; 132d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->readNum--; 133d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } else if (iface->manual_stop) { 134aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, 135aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu read_MASTER_CTL(iface) | STOP); 1364dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && 13794327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew iface->cur_msg + 1 < iface->msg_num) { 13894327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD) 13994327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew write_MASTER_CTL(iface, 14094327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew read_MASTER_CTL(iface) | RSTART | MDIR); 14194327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew else 14294327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew write_MASTER_CTL(iface, 14394327d009e3aa20214e9dfa486a1fd14445fe736Frank Shew (read_MASTER_CTL(iface) | RSTART) & ~MDIR); 144d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 145d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 146d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (twi_int_status & MERR) { 147aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_INT_MASK(iface, 0); 148aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_STAT(iface, 0x3e); 149aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, 0); 1504dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->result = -EIO; 1515cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich 1525cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich if (mast_stat & LOSTARB) 1535cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich dev_dbg(&iface->adap.dev, "Lost Arbitration\n"); 1545cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich if (mast_stat & ANAK) 1555cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich dev_dbg(&iface->adap.dev, "Address Not Acknowledged\n"); 1565cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich if (mast_stat & DNAK) 1575cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich dev_dbg(&iface->adap.dev, "Data Not Acknowledged\n"); 1585cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich if (mast_stat & BUFRDERR) 1595cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich dev_dbg(&iface->adap.dev, "Buffer Read Error\n"); 1605cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich if (mast_stat & BUFWRERR) 1615cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich dev_dbg(&iface->adap.dev, "Buffer Write Error\n"); 1625cfafc18f38aa6701f581bee875fb0b19f3b3b4bMichael Hennerich 163540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich /* Faulty slave devices, may drive SDA low after a transfer 164540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich * finishes. To release the bus this code generates up to 9 165540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich * extra clocks until SDA is released. 166540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich */ 167540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich 168540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich if (read_MASTER_STAT(iface) & SDASEN) { 169540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich int cnt = 9; 170540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich do { 171540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich write_MASTER_CTL(iface, SCLOVR); 172540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich udelay(6); 173540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich write_MASTER_CTL(iface, 0); 174540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich udelay(6); 175540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich } while ((read_MASTER_STAT(iface) & SDASEN) && cnt--); 176540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich 177540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich write_MASTER_CTL(iface, SDAOVR | SCLOVR); 178540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich udelay(6); 179540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich write_MASTER_CTL(iface, SDAOVR); 180540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich udelay(6); 181540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich write_MASTER_CTL(iface, 0); 182540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich } 183540ac5553e8169413a90a8e68b3a10f801640eb7Michael Hennerich 184f0ac131a21ed13e8baaa9df6f0420f2c4b45e807Sonic Zhang /* If it is a quick transfer, only address without data, 185f0ac131a21ed13e8baaa9df6f0420f2c4b45e807Sonic Zhang * not an err, return 1. 186d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu */ 187f0ac131a21ed13e8baaa9df6f0420f2c4b45e807Sonic Zhang if (iface->cur_mode == TWI_I2C_MODE_STANDARD && 188f0ac131a21ed13e8baaa9df6f0420f2c4b45e807Sonic Zhang iface->transPtr == NULL && 189f0ac131a21ed13e8baaa9df6f0420f2c4b45e807Sonic Zhang (twi_int_status & MCOMP) && (mast_stat & DNAK)) 190f0ac131a21ed13e8baaa9df6f0420f2c4b45e807Sonic Zhang iface->result = 1; 191f0ac131a21ed13e8baaa9df6f0420f2c4b45e807Sonic Zhang 192d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu complete(&iface->complete); 193d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu return; 194d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 195d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (twi_int_status & MCOMP) { 1964a65163e3b2190445c1d94daa21d09c5af604d97Sonic Zhang if ((read_MASTER_CTL(iface) & MEN) == 0 && 1974a65163e3b2190445c1d94daa21d09c5af604d97Sonic Zhang (iface->cur_mode == TWI_I2C_MODE_REPEAT || 1984a65163e3b2190445c1d94daa21d09c5af604d97Sonic Zhang iface->cur_mode == TWI_I2C_MODE_COMBINED)) { 1994a65163e3b2190445c1d94daa21d09c5af604d97Sonic Zhang iface->result = -1; 2004a65163e3b2190445c1d94daa21d09c5af604d97Sonic Zhang write_INT_MASK(iface, 0); 2014a65163e3b2190445c1d94daa21d09c5af604d97Sonic Zhang write_MASTER_CTL(iface, 0); 2024a65163e3b2190445c1d94daa21d09c5af604d97Sonic Zhang } else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { 203d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (iface->readNum == 0) { 204d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* set the read number to 1 and ask for manual 205d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu * stop in block combine mode 206d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu */ 207d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->readNum = 1; 208d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->manual_stop = 1; 209aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, 210aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu read_MASTER_CTL(iface) | (0xff << 6)); 211d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } else { 212d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* set the readd number in other 213d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu * combine mode. 214d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu */ 215aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, 216aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu (read_MASTER_CTL(iface) & 217d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu (~(0xff << 6))) | 218aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu (iface->readNum << 6)); 219d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 220d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* remove restart bit and enable master receive */ 221aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, 222aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu read_MASTER_CTL(iface) & ~RSTART); 2234dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && 2244dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->cur_msg+1 < iface->msg_num) { 2254dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->cur_msg++; 2264dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->transPtr = iface->pmsg[iface->cur_msg].buf; 2274dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->writeNum = iface->readNum = 2284dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->pmsg[iface->cur_msg].len; 2294dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang /* Set Transmit device address */ 230aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_ADDR(iface, 2314dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->pmsg[iface->cur_msg].addr); 2324dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang if (iface->pmsg[iface->cur_msg].flags & I2C_M_RD) 2334dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->read_write = I2C_SMBUS_READ; 2344dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang else { 2354dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->read_write = I2C_SMBUS_WRITE; 2364dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang /* Transmit first data */ 2374dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang if (iface->writeNum > 0) { 238aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_XMT_DATA8(iface, 2394dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang *(iface->transPtr++)); 2404dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->writeNum--; 2414dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang } 2424dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang } 2434dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang 2444dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang if (iface->pmsg[iface->cur_msg].len <= 255) 24557a8f32eafa6f36ea3a128e8b13f353c5a3ca9b2Sonic Zhang write_MASTER_CTL(iface, 24657a8f32eafa6f36ea3a128e8b13f353c5a3ca9b2Sonic Zhang (read_MASTER_CTL(iface) & 24757a8f32eafa6f36ea3a128e8b13f353c5a3ca9b2Sonic Zhang (~(0xff << 6))) | 24857a8f32eafa6f36ea3a128e8b13f353c5a3ca9b2Sonic Zhang (iface->pmsg[iface->cur_msg].len << 6)); 2494dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang else { 25057a8f32eafa6f36ea3a128e8b13f353c5a3ca9b2Sonic Zhang write_MASTER_CTL(iface, 25157a8f32eafa6f36ea3a128e8b13f353c5a3ca9b2Sonic Zhang (read_MASTER_CTL(iface) | 25257a8f32eafa6f36ea3a128e8b13f353c5a3ca9b2Sonic Zhang (0xff << 6))); 2534dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->manual_stop = 1; 2544dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang } 2554dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang /* remove restart bit and enable master receive */ 256aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, 257aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu read_MASTER_CTL(iface) & ~RSTART); 258d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } else { 259d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->result = 1; 260aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_INT_MASK(iface, 0); 261aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, 0); 262d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 263d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 264dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang complete(&iface->complete); 265d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu} 266d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 267d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu/* Interrupt handler */ 268d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wustatic irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id) 269d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{ 270d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu struct bfin_twi_iface *iface = dev_id; 271d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu unsigned long flags; 2725481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang unsigned short twi_int_status; 273d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 274d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu spin_lock_irqsave(&iface->lock, flags); 2755481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang while (1) { 2765481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang twi_int_status = read_INT_STAT(iface); 2775481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang if (!twi_int_status) 2785481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang break; 2795481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang /* Clear interrupt status */ 2805481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang write_INT_STAT(iface, twi_int_status); 2815481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang bfin_twi_handle_interrupt(iface, twi_int_status); 2825481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang SSYNC(); 2835481d0753e7a78bff7550a8165b7924baa74e9cfSonic Zhang } 284d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu spin_unlock_irqrestore(&iface->lock, flags); 285d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu return IRQ_HANDLED; 286d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu} 287d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 288d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu/* 289dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang * One i2c master transfer 290d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu */ 291dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhangstatic int bfin_twi_do_master_xfer(struct i2c_adapter *adap, 292d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu struct i2c_msg *msgs, int num) 293d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{ 294d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu struct bfin_twi_iface *iface = adap->algo_data; 295d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu struct i2c_msg *pmsg; 296d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu int rc = 0; 297d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 298aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu if (!(read_CONTROL(iface) & TWI_ENA)) 299d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu return -ENXIO; 300d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 301aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu while (read_MASTER_STAT(iface) & BUSBUSY) 302d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu yield(); 303d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 3044dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->pmsg = msgs; 3054dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->msg_num = num; 3064dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->cur_msg = 0; 307d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 3084dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang pmsg = &msgs[0]; 3094dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang if (pmsg->flags & I2C_M_TEN) { 3104dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang dev_err(&adap->dev, "10 bits addr not supported!\n"); 3114dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang return -EINVAL; 3124dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang } 313d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 3144dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->cur_mode = TWI_I2C_MODE_REPEAT; 3154dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->manual_stop = 0; 3164dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->transPtr = pmsg->buf; 3174dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->writeNum = iface->readNum = pmsg->len; 3184dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->result = 0; 319afc13b765ea71d316ce4974d3dc5a96cc73a0e95Hans Schillstrom init_completion(&(iface->complete)); 3204dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang /* Set Transmit device address */ 321aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_ADDR(iface, pmsg->addr); 3224dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang 3234dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang /* FIFO Initiation. Data in FIFO should be 3244dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang * discarded before start a new operation. 3254dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang */ 326aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_FIFO_CTL(iface, 0x3); 3274dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang SSYNC(); 328aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_FIFO_CTL(iface, 0); 3294dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang SSYNC(); 3304dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang 3314dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang if (pmsg->flags & I2C_M_RD) 3324dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->read_write = I2C_SMBUS_READ; 3334dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang else { 3344dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->read_write = I2C_SMBUS_WRITE; 3354dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang /* Transmit first data */ 3364dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang if (iface->writeNum > 0) { 337aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_XMT_DATA8(iface, *(iface->transPtr++)); 3384dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->writeNum--; 3394dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang SSYNC(); 340d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 3414dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang } 342d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 3434dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang /* clear int stat */ 344aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_INT_STAT(iface, MERR | MCOMP | XMTSERV | RCVSERV); 345d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 3464dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang /* Interrupt mask . Enable XMT, RCV interrupt */ 347aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV); 3484dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang SSYNC(); 349d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 3504dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang if (pmsg->len <= 255) 351aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, pmsg->len << 6); 3524dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang else { 353aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, 0xff << 6); 3544dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang iface->manual_stop = 1; 3554dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang } 356d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 3574dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang /* Master enable */ 358aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN | 3594dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) | 3604dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0)); 3614dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang SSYNC(); 3624dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang 363dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang while (!iface->result) { 364dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang if (!wait_for_completion_timeout(&iface->complete, 365dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang adap->timeout)) { 366dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang iface->result = -1; 367dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang dev_err(&adap->dev, "master transfer timeout\n"); 368dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang } 369dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang } 370d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 371dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang if (iface->result == 1) 372dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang rc = iface->cur_msg + 1; 3734dd39bb12f5b9f0d9a98f29071dc1c51e9306954Sonic Zhang else 374dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang rc = iface->result; 375dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang 376dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang return rc; 377d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu} 378d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 379d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu/* 380dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang * Generic i2c master transfer entrypoint 381d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu */ 382dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhangstatic int bfin_twi_master_xfer(struct i2c_adapter *adap, 383dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang struct i2c_msg *msgs, int num) 384dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang{ 385be2f80f0a3a333c0c00b2c8a7c2d74fcd66b75a2Sonic Zhang return bfin_twi_do_master_xfer(adap, msgs, num); 386dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang} 387dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang 388dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang/* 389dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang * One I2C SMBus transfer 390dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang */ 391dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhangint bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr, 392d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu unsigned short flags, char read_write, 393d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu u8 command, int size, union i2c_smbus_data *data) 394d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{ 395d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu struct bfin_twi_iface *iface = adap->algo_data; 396d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu int rc = 0; 397d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 398aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu if (!(read_CONTROL(iface) & TWI_ENA)) 399d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu return -ENXIO; 400d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 401aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu while (read_MASTER_STAT(iface) & BUSBUSY) 402d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu yield(); 403d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 404d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->writeNum = 0; 405d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->readNum = 0; 406d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 407d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* Prepare datas & select mode */ 408d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu switch (size) { 409d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu case I2C_SMBUS_QUICK: 410d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->transPtr = NULL; 411d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->cur_mode = TWI_I2C_MODE_STANDARD; 412d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu break; 413d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu case I2C_SMBUS_BYTE: 414d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (data == NULL) 415d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->transPtr = NULL; 416d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu else { 417d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (read_write == I2C_SMBUS_READ) 418d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->readNum = 1; 419d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu else 420d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->writeNum = 1; 421d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->transPtr = &data->byte; 422d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 423d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->cur_mode = TWI_I2C_MODE_STANDARD; 424d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu break; 425d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu case I2C_SMBUS_BYTE_DATA: 426d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (read_write == I2C_SMBUS_READ) { 427d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->readNum = 1; 428d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->cur_mode = TWI_I2C_MODE_COMBINED; 429d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } else { 430d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->writeNum = 1; 431d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; 432d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 433d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->transPtr = &data->byte; 434d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu break; 435d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu case I2C_SMBUS_WORD_DATA: 436d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (read_write == I2C_SMBUS_READ) { 437d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->readNum = 2; 438d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->cur_mode = TWI_I2C_MODE_COMBINED; 439d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } else { 440d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->writeNum = 2; 441d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; 442d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 443d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->transPtr = (u8 *)&data->word; 444d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu break; 445d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu case I2C_SMBUS_PROC_CALL: 446d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->writeNum = 2; 447d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->readNum = 2; 448d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->cur_mode = TWI_I2C_MODE_COMBINED; 449d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->transPtr = (u8 *)&data->word; 450d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu break; 451d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu case I2C_SMBUS_BLOCK_DATA: 452d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (read_write == I2C_SMBUS_READ) { 453d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->readNum = 0; 454d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->cur_mode = TWI_I2C_MODE_COMBINED; 455d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } else { 456d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->writeNum = data->block[0] + 1; 457d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; 458d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 459d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->transPtr = data->block; 460d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu break; 461e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich case I2C_SMBUS_I2C_BLOCK_DATA: 462e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich if (read_write == I2C_SMBUS_READ) { 463e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich iface->readNum = data->block[0]; 464e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich iface->cur_mode = TWI_I2C_MODE_COMBINED; 465e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich } else { 466e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich iface->writeNum = data->block[0]; 467e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; 468e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich } 469e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich iface->transPtr = (u8 *)&data->block[1]; 470e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich break; 471d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu default: 472d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu return -1; 473d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 474d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 475d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->result = 0; 476d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->manual_stop = 0; 477d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->read_write = read_write; 478d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->command = command; 479afc13b765ea71d316ce4974d3dc5a96cc73a0e95Hans Schillstrom init_completion(&(iface->complete)); 480d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 481d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* FIFO Initiation. Data in FIFO should be discarded before 482d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu * start a new operation. 483d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu */ 484aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_FIFO_CTL(iface, 0x3); 485d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu SSYNC(); 486aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_FIFO_CTL(iface, 0); 487d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 488d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* clear int stat */ 489aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_INT_STAT(iface, MERR | MCOMP | XMTSERV | RCVSERV); 490d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 491d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* Set Transmit device address */ 492aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_ADDR(iface, addr); 493d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu SSYNC(); 494d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 495d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu switch (iface->cur_mode) { 496d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu case TWI_I2C_MODE_STANDARDSUB: 497aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_XMT_DATA8(iface, iface->command); 498aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_INT_MASK(iface, MCOMP | MERR | 499d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu ((iface->read_write == I2C_SMBUS_READ) ? 500d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu RCVSERV : XMTSERV)); 501d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu SSYNC(); 502d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 503d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (iface->writeNum + 1 <= 255) 504aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, (iface->writeNum + 1) << 6); 505d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu else { 506aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, 0xff << 6); 507d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->manual_stop = 1; 508d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 509d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* Master enable */ 510aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN | 511d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0)); 512d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu break; 513d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu case TWI_I2C_MODE_COMBINED: 514aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_XMT_DATA8(iface, iface->command); 515aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV); 516d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu SSYNC(); 517d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 518d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (iface->writeNum > 0) 519aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, (iface->writeNum + 1) << 6); 520d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu else 521aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, 0x1 << 6); 522d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* Master enable */ 523aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN | 524d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0)); 525d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu break; 526d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu default: 527aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, 0); 528d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (size != I2C_SMBUS_QUICK) { 529d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* Don't access xmit data register when this is a 530d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu * read operation. 531d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu */ 532d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (iface->read_write != I2C_SMBUS_READ) { 533d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (iface->writeNum > 0) { 534aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_XMT_DATA8(iface, 535aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu *(iface->transPtr++)); 536d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (iface->writeNum <= 255) 537aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, 538aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu iface->writeNum << 6); 539d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu else { 540aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, 541aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu 0xff << 6); 542d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->manual_stop = 1; 543d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 544d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->writeNum--; 545d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } else { 546aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_XMT_DATA8(iface, iface->command); 547aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, 1 << 6); 548d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 549d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } else { 550d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (iface->readNum > 0 && iface->readNum <= 255) 551aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, 552aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu iface->readNum << 6); 553d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu else if (iface->readNum > 255) { 554aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, 0xff << 6); 555d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu iface->manual_stop = 1; 556dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang } else 557d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu break; 558d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 559d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 560aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_INT_MASK(iface, MCOMP | MERR | 561d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu ((iface->read_write == I2C_SMBUS_READ) ? 562d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu RCVSERV : XMTSERV)); 563d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu SSYNC(); 564d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 565d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* Master enable */ 566aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN | 567d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) | 568d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0)); 569d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu break; 570d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 571d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu SSYNC(); 572d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 573dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang while (!iface->result) { 574dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang if (!wait_for_completion_timeout(&iface->complete, 575dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang adap->timeout)) { 576dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang iface->result = -1; 577dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang dev_err(&adap->dev, "smbus transfer timeout\n"); 578dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang } 579dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang } 580d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 581d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu rc = (iface->result >= 0) ? 0 : -1; 582d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 583d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu return rc; 584d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu} 585d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 586d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu/* 587dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang * Generic I2C SMBus transfer entrypoint 588dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang */ 589dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhangint bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, 590dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang unsigned short flags, char read_write, 591dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang u8 command, int size, union i2c_smbus_data *data) 592dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang{ 593be2f80f0a3a333c0c00b2c8a7c2d74fcd66b75a2Sonic Zhang return bfin_twi_do_smbus_xfer(adap, addr, flags, 594dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang read_write, command, size, data); 595dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang} 596dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang 597dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang/* 598d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu * Return what the adapter supports 599d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu */ 600d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wustatic u32 bfin_twi_functionality(struct i2c_adapter *adap) 601d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{ 602d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | 603d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | 604d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL | 605e0cd2dd5dd2b7c6512e46ce0b4f119cd7b0c74a4Michael Hennerich I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK; 606d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu} 607d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 608d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wustatic struct i2c_algorithm bfin_twi_algorithm = { 609d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu .master_xfer = bfin_twi_master_xfer, 610d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu .smbus_xfer = bfin_twi_smbus_xfer, 611d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu .functionality = bfin_twi_functionality, 612d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu}; 613d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 614958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerichstatic int i2c_bfin_twi_suspend(struct platform_device *pdev, pm_message_t state) 615d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{ 616958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich struct bfin_twi_iface *iface = platform_get_drvdata(pdev); 617958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich 618958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich iface->saved_clkdiv = read_CLKDIV(iface); 619958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich iface->saved_control = read_CONTROL(iface); 620958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich 621958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich free_irq(iface->irq, iface); 622d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 623d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* Disable TWI */ 624958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich write_CONTROL(iface, iface->saved_control & ~TWI_ENA); 625d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 626d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu return 0; 627d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu} 628d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 629958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerichstatic int i2c_bfin_twi_resume(struct platform_device *pdev) 630d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{ 631958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich struct bfin_twi_iface *iface = platform_get_drvdata(pdev); 632d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 633958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich int rc = request_irq(iface->irq, bfin_twi_interrupt_entry, 6344311051c358ad0e66b68934e7a33cf10ba533466Yong Zhang 0, pdev->name, iface); 635958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich if (rc) { 636958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq); 637958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich return -ENODEV; 638958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich } 639958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich 640958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich /* Resume TWI interface clock as specified */ 641958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich write_CLKDIV(iface, iface->saved_clkdiv); 642958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich 643958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich /* Resume TWI */ 644958585f58f675a3c2855c7d91b6fdd2875552d0bMichael Hennerich write_CONTROL(iface, iface->saved_control); 645d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 646d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu return 0; 647d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu} 648d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 649aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wustatic int i2c_bfin_twi_probe(struct platform_device *pdev) 650d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{ 651aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu struct bfin_twi_iface *iface; 652d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu struct i2c_adapter *p_adap; 653aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu struct resource *res; 654d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu int rc; 6559528d1c7a541b481a0e80301dc8d545848104023Michael Hennerich unsigned int clkhilow; 656d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 657aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL); 658aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu if (!iface) { 659aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu dev_err(&pdev->dev, "Cannot allocate memory\n"); 660aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu rc = -ENOMEM; 661aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu goto out_error_nomem; 662aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu } 663aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu 664d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu spin_lock_init(&(iface->lock)); 665aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu 666aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu /* Find and map our resources */ 667aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 668aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu if (res == NULL) { 669aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); 670aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu rc = -ENOENT; 671aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu goto out_error_get_res; 672aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu } 673aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu 674c6ffddea36dd576b70dfbd10eb5d2b287b786dcaLinus Walleij iface->regs_base = ioremap(res->start, resource_size(res)); 675aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu if (iface->regs_base == NULL) { 676aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu dev_err(&pdev->dev, "Cannot map IO\n"); 677aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu rc = -ENXIO; 678aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu goto out_error_ioremap; 679aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu } 680aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu 681aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu iface->irq = platform_get_irq(pdev, 0); 682aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu if (iface->irq < 0) { 683aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu dev_err(&pdev->dev, "No IRQ specified\n"); 684aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu rc = -ENOENT; 685aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu goto out_error_no_irq; 686aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu } 687d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 688d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu p_adap = &iface->adap; 689aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu p_adap->nr = pdev->id; 690aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name)); 691d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu p_adap->algo = &bfin_twi_algorithm; 692d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu p_adap->algo_data = iface; 693e1995f65be0786ca201f466f049dad1e2e4c3421Jean Delvare p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; 694aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu p_adap->dev.parent = &pdev->dev; 695dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang p_adap->timeout = 5 * HZ; 696dd7319a5289deb4e17beb8851d343e7930b32c3bSonic Zhang p_adap->retries = 3; 697d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 69874d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu rc = peripheral_request_list(pin_req[pdev->id], "i2c-bfin-twi"); 69974d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu if (rc) { 70074d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu dev_err(&pdev->dev, "Can't setup pin mux!\n"); 70174d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu goto out_error_pin_mux; 70274d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu } 70374d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu 704d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu rc = request_irq(iface->irq, bfin_twi_interrupt_entry, 7054311051c358ad0e66b68934e7a33cf10ba533466Yong Zhang 0, pdev->name, iface); 706d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu if (rc) { 707aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq); 708aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu rc = -ENODEV; 709aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu goto out_error_req_irq; 710d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu } 711d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 712d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* Set TWI internal clock as 10MHz */ 713ac07fb4dc1908d300f50fa711982c9d750eb59f7Sonic Zhang write_CONTROL(iface, ((get_sclk() / 1000 / 1000 + 5) / 10) & 0x7F); 714d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 7159528d1c7a541b481a0e80301dc8d545848104023Michael Hennerich /* 7169528d1c7a541b481a0e80301dc8d545848104023Michael Hennerich * We will not end up with a CLKDIV=0 because no one will specify 717ac07fb4dc1908d300f50fa711982c9d750eb59f7Sonic Zhang * 20kHz SCL or less in Kconfig now. (5 * 1000 / 20 = 250) 7189528d1c7a541b481a0e80301dc8d545848104023Michael Hennerich */ 719ac07fb4dc1908d300f50fa711982c9d750eb59f7Sonic Zhang clkhilow = ((10 * 1000 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ) + 1) / 2; 7209528d1c7a541b481a0e80301dc8d545848104023Michael Hennerich 721d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* Set Twi interface clock as specified */ 7229528d1c7a541b481a0e80301dc8d545848104023Michael Hennerich write_CLKDIV(iface, (clkhilow << 8) | clkhilow); 723d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 724d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu /* Enable TWI */ 725aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA); 726d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu SSYNC(); 727d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 728991dee591a99d035796a8c194eb1796cc020e142Kalle Pokki rc = i2c_add_numbered_adapter(p_adap); 729aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu if (rc < 0) { 730aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu dev_err(&pdev->dev, "Can't add i2c adapter!\n"); 731aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu goto out_error_add_adapter; 732aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu } 733aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu 734aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu platform_set_drvdata(pdev, iface); 735d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 736fa6ad222713a65980528348e7f75abc768b78297Bryan Wu dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Contoller, " 737fa6ad222713a65980528348e7f75abc768b78297Bryan Wu "regs_base@%p\n", iface->regs_base); 738aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu 739aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu return 0; 740aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu 741aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wuout_error_add_adapter: 742aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu free_irq(iface->irq, iface); 743aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wuout_error_req_irq: 744aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wuout_error_no_irq: 74574d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu peripheral_free_list(pin_req[pdev->id]); 74674d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wuout_error_pin_mux: 747aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu iounmap(iface->regs_base); 748aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wuout_error_ioremap: 749aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wuout_error_get_res: 750aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu kfree(iface); 751aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wuout_error_nomem: 752d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu return rc; 753d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu} 754d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 755d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wustatic int i2c_bfin_twi_remove(struct platform_device *pdev) 756d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{ 757d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu struct bfin_twi_iface *iface = platform_get_drvdata(pdev); 758d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 759d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu platform_set_drvdata(pdev, NULL); 760d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 761d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu i2c_del_adapter(&(iface->adap)); 762d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu free_irq(iface->irq, iface); 76374d362e0b3afb7a324855ab9675eb6cda78fda8cBryan Wu peripheral_free_list(pin_req[pdev->id]); 764aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu iounmap(iface->regs_base); 765aa3d02091747727f7ff2e1f2455ad8363a9e6946Bryan Wu kfree(iface); 766d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 767d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu return 0; 768d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu} 769d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 770d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wustatic struct platform_driver i2c_bfin_twi_driver = { 771d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu .probe = i2c_bfin_twi_probe, 772d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu .remove = i2c_bfin_twi_remove, 773d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu .suspend = i2c_bfin_twi_suspend, 774d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu .resume = i2c_bfin_twi_resume, 775d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu .driver = { 776d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu .name = "i2c-bfin-twi", 777d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu .owner = THIS_MODULE, 778d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu }, 779d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu}; 780d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 781d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wustatic int __init i2c_bfin_twi_init(void) 782d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{ 783d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu return platform_driver_register(&i2c_bfin_twi_driver); 784d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu} 785d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 786d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wustatic void __exit i2c_bfin_twi_exit(void) 787d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu{ 788d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu platform_driver_unregister(&i2c_bfin_twi_driver); 789d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu} 790d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wu 79174f56c4ad4e4627862bddb0b8c3ab394e3c004f7Michael Hennerichsubsys_initcall(i2c_bfin_twi_init); 792d24ecfcc3953f9c3b833508cd839be614a3f3c64Bryan Wumodule_exit(i2c_bfin_twi_exit); 793fa6ad222713a65980528348e7f75abc768b78297Bryan Wu 794fa6ad222713a65980528348e7f75abc768b78297Bryan WuMODULE_AUTHOR("Bryan Wu, Sonic Zhang"); 795fa6ad222713a65980528348e7f75abc768b78297Bryan WuMODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Contoller Driver"); 796fa6ad222713a65980528348e7f75abc768b78297Bryan WuMODULE_LICENSE("GPL"); 797add8eda7f2be781af0224241e870715cf0cfd75aKay SieversMODULE_ALIAS("platform:i2c-bfin-twi"); 798