1cdace066SSascha Hauer /* 2cdace066SSascha Hauer * i2c driver for Freescale mx31 3cdace066SSascha Hauer * 4cdace066SSascha Hauer * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> 5cdace066SSascha Hauer * 6cdace066SSascha Hauer * See file CREDITS for list of people who contributed to this 7cdace066SSascha Hauer * project. 8cdace066SSascha Hauer * 9cdace066SSascha Hauer * This program is free software; you can redistribute it and/or 10cdace066SSascha Hauer * modify it under the terms of the GNU General Public License as 11cdace066SSascha Hauer * published by the Free Software Foundation; either version 2 of 12cdace066SSascha Hauer * the License, or (at your option) any later version. 13cdace066SSascha Hauer * 14cdace066SSascha Hauer * This program is distributed in the hope that it will be useful, 15cdace066SSascha Hauer * but WITHOUT ANY WARRANTY; without even the implied warranty of 16cdace066SSascha Hauer * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17cdace066SSascha Hauer * GNU General Public License for more details. 18cdace066SSascha Hauer * 19cdace066SSascha Hauer * You should have received a copy of the GNU General Public License 20cdace066SSascha Hauer * along with this program; if not, write to the Free Software 21cdace066SSascha Hauer * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 22cdace066SSascha Hauer * MA 02111-1307 USA 23cdace066SSascha Hauer */ 24cdace066SSascha Hauer 25cdace066SSascha Hauer #include <common.h> 26cdace066SSascha Hauer 27a4a549b4SMichal Simek #if defined(CONFIG_HARD_I2C) 28cdace066SSascha Hauer 29cdace066SSascha Hauer #include <asm/arch/mx31.h> 30cdace066SSascha Hauer #include <asm/arch/mx31-regs.h> 31cdace066SSascha Hauer 32cdace066SSascha Hauer #define IADR 0x00 33cdace066SSascha Hauer #define IFDR 0x04 34cdace066SSascha Hauer #define I2CR 0x08 35cdace066SSascha Hauer #define I2SR 0x0c 36cdace066SSascha Hauer #define I2DR 0x10 37cdace066SSascha Hauer 38cdace066SSascha Hauer #define I2CR_IEN (1 << 7) 39cdace066SSascha Hauer #define I2CR_IIEN (1 << 6) 40cdace066SSascha Hauer #define I2CR_MSTA (1 << 5) 41cdace066SSascha Hauer #define I2CR_MTX (1 << 4) 42cdace066SSascha Hauer #define I2CR_TX_NO_AK (1 << 3) 43cdace066SSascha Hauer #define I2CR_RSTA (1 << 2) 44cdace066SSascha Hauer 45cdace066SSascha Hauer #define I2SR_ICF (1 << 7) 46cdace066SSascha Hauer #define I2SR_IBB (1 << 5) 47cdace066SSascha Hauer #define I2SR_IIF (1 << 1) 48cdace066SSascha Hauer #define I2SR_RX_NO_AK (1 << 0) 49cdace066SSascha Hauer 50*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_I2C_MX31_PORT1 51cdace066SSascha Hauer #define I2C_BASE 0x43f80000 52*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #elif defined (CONFIG_SYS_I2C_MX31_PORT2) 53cdace066SSascha Hauer #define I2C_BASE 0x43f98000 54*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #elif defined (CONFIG_SYS_I2C_MX31_PORT3) 55cdace066SSascha Hauer #define I2C_BASE 0x43f84000 56cdace066SSascha Hauer #else 57*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #error "define CONFIG_SYS_I2C_MX31_PORTx to use the mx31 I2C driver" 58cdace066SSascha Hauer #endif 59cdace066SSascha Hauer 60cdace066SSascha Hauer #ifdef DEBUG 61cdace066SSascha Hauer #define DPRINTF(args...) printf(args) 62cdace066SSascha Hauer #else 63cdace066SSascha Hauer #define DPRINTF(args...) 64cdace066SSascha Hauer #endif 65cdace066SSascha Hauer 66cdace066SSascha Hauer static u16 div[] = { 30, 32, 36, 42, 48, 52, 60, 72, 80, 88, 104, 128, 144, 67cdace066SSascha Hauer 160, 192, 240, 288, 320, 384, 480, 576, 640, 768, 960, 68cdace066SSascha Hauer 1152, 1280, 1536, 1920, 2304, 2560, 3072, 3840}; 69cdace066SSascha Hauer 70cdace066SSascha Hauer void i2c_init(int speed, int unused) 71cdace066SSascha Hauer { 72cdace066SSascha Hauer int freq = mx31_get_ipg_clk(); 73cdace066SSascha Hauer int i; 74cdace066SSascha Hauer 75cdace066SSascha Hauer for (i = 0; i < 0x1f; i++) 76cdace066SSascha Hauer if (freq / div[i] <= speed) 77cdace066SSascha Hauer break; 78cdace066SSascha Hauer 79cdace066SSascha Hauer DPRINTF("%s: speed: %d\n",__FUNCTION__, speed); 80cdace066SSascha Hauer 81cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = 0; /* Reset module */ 82cdace066SSascha Hauer __REG16(I2C_BASE + IFDR) = i; 83cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN; 84cdace066SSascha Hauer __REG16(I2C_BASE + I2SR) = 0; 85cdace066SSascha Hauer } 86cdace066SSascha Hauer 87cdace066SSascha Hauer static int wait_busy(void) 88cdace066SSascha Hauer { 89cdace066SSascha Hauer int timeout = 10000; 90cdace066SSascha Hauer 91cdace066SSascha Hauer while (!(__REG16(I2C_BASE + I2SR) & I2SR_IIF) && --timeout) 92cdace066SSascha Hauer udelay(1); 93cdace066SSascha Hauer __REG16(I2C_BASE + I2SR) = 0; /* clear interrupt */ 94cdace066SSascha Hauer 95cdace066SSascha Hauer return timeout; 96cdace066SSascha Hauer } 97cdace066SSascha Hauer 98cdace066SSascha Hauer static int tx_byte(u8 byte) 99cdace066SSascha Hauer { 100cdace066SSascha Hauer __REG16(I2C_BASE + I2DR) = byte; 101cdace066SSascha Hauer 102cdace066SSascha Hauer if (!wait_busy() || __REG16(I2C_BASE + I2SR) & I2SR_RX_NO_AK) 103cdace066SSascha Hauer return -1; 104cdace066SSascha Hauer return 0; 105cdace066SSascha Hauer } 106cdace066SSascha Hauer 107cdace066SSascha Hauer static int rx_byte(void) 108cdace066SSascha Hauer { 109cdace066SSascha Hauer if (!wait_busy()) 110cdace066SSascha Hauer return -1; 111cdace066SSascha Hauer 112cdace066SSascha Hauer return __REG16(I2C_BASE + I2DR); 113cdace066SSascha Hauer } 114cdace066SSascha Hauer 115cdace066SSascha Hauer int i2c_probe(uchar chip) 116cdace066SSascha Hauer { 117cdace066SSascha Hauer int ret; 118cdace066SSascha Hauer 119cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = 0; /* Reset module */ 120cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN; 121cdace066SSascha Hauer 122cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | I2CR_MTX; 123cdace066SSascha Hauer ret = tx_byte(chip << 1); 124cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MTX; 125cdace066SSascha Hauer 126cdace066SSascha Hauer return ret; 127cdace066SSascha Hauer } 128cdace066SSascha Hauer 129cdace066SSascha Hauer static int i2c_addr(uchar chip, uint addr, int alen) 130cdace066SSascha Hauer { 131cdace066SSascha Hauer __REG16(I2C_BASE + I2SR) = 0; /* clear interrupt */ 132cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | I2CR_MTX; 133cdace066SSascha Hauer 134cdace066SSascha Hauer if (tx_byte(chip << 1)) 135cdace066SSascha Hauer return -1; 136cdace066SSascha Hauer 137cdace066SSascha Hauer while (alen--) 138cdace066SSascha Hauer if (tx_byte((addr >> (alen * 8)) & 0xff)) 139cdace066SSascha Hauer return -1; 140cdace066SSascha Hauer return 0; 141cdace066SSascha Hauer } 142cdace066SSascha Hauer 143cdace066SSascha Hauer int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) 144cdace066SSascha Hauer { 145cdace066SSascha Hauer int timeout = 10000; 146cdace066SSascha Hauer int ret; 147cdace066SSascha Hauer 148cdace066SSascha Hauer DPRINTF("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n",__FUNCTION__, chip, addr, alen, len); 149cdace066SSascha Hauer 150cdace066SSascha Hauer if (i2c_addr(chip, addr, alen)) { 151cdace066SSascha Hauer printf("i2c_addr failed\n"); 152cdace066SSascha Hauer return -1; 153cdace066SSascha Hauer } 154cdace066SSascha Hauer 155cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | I2CR_MTX | I2CR_RSTA; 156cdace066SSascha Hauer 157cdace066SSascha Hauer if (tx_byte(chip << 1 | 1)) 158cdace066SSascha Hauer return -1; 159cdace066SSascha Hauer 160cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | ((len == 1) ? I2CR_TX_NO_AK : 0); 161cdace066SSascha Hauer 162cdace066SSascha Hauer ret = __REG16(I2C_BASE + I2DR); 163cdace066SSascha Hauer 164cdace066SSascha Hauer while (len--) { 165cdace066SSascha Hauer if ((ret = rx_byte()) < 0) 166cdace066SSascha Hauer return -1; 167cdace066SSascha Hauer *buf++ = ret; 168cdace066SSascha Hauer if (len <= 1) 169cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | I2CR_TX_NO_AK; 170cdace066SSascha Hauer } 171cdace066SSascha Hauer 172cdace066SSascha Hauer wait_busy(); 173cdace066SSascha Hauer 174cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN; 175cdace066SSascha Hauer 176cdace066SSascha Hauer while (__REG16(I2C_BASE + I2SR) & I2SR_IBB && --timeout) 177cdace066SSascha Hauer udelay(1); 178cdace066SSascha Hauer 179cdace066SSascha Hauer return 0; 180cdace066SSascha Hauer } 181cdace066SSascha Hauer 182cdace066SSascha Hauer int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) 183cdace066SSascha Hauer { 184cdace066SSascha Hauer int timeout = 10000; 185cdace066SSascha Hauer DPRINTF("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n",__FUNCTION__, chip, addr, alen, len); 186cdace066SSascha Hauer 187cdace066SSascha Hauer if (i2c_addr(chip, addr, alen)) 188cdace066SSascha Hauer return -1; 189cdace066SSascha Hauer 190cdace066SSascha Hauer while (len--) 191cdace066SSascha Hauer if (tx_byte(*buf++)) 192cdace066SSascha Hauer return -1; 193cdace066SSascha Hauer 194cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN; 195cdace066SSascha Hauer 196cdace066SSascha Hauer while (__REG16(I2C_BASE + I2SR) & I2SR_IBB && --timeout) 197cdace066SSascha Hauer udelay(1); 198cdace066SSascha Hauer 199cdace066SSascha Hauer return 0; 200cdace066SSascha Hauer } 201cdace066SSascha Hauer 202cdace066SSascha Hauer #endif /* CONFIG_HARD_I2C */ 203