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 29*127cec18SLiu Hui-R64343 #if defined(CONFIG_MX31) 30cdace066SSascha Hauer #include <asm/arch/mx31.h> 31cdace066SSascha Hauer #include <asm/arch/mx31-regs.h> 32*127cec18SLiu Hui-R64343 #endif 33*127cec18SLiu Hui-R64343 34*127cec18SLiu Hui-R64343 #if defined(CONFIG_MX53) 35*127cec18SLiu Hui-R64343 #include <asm/arch/clock.h> 36*127cec18SLiu Hui-R64343 #endif 37cdace066SSascha Hauer 38cdace066SSascha Hauer #define IADR 0x00 39cdace066SSascha Hauer #define IFDR 0x04 40cdace066SSascha Hauer #define I2CR 0x08 41cdace066SSascha Hauer #define I2SR 0x0c 42cdace066SSascha Hauer #define I2DR 0x10 43cdace066SSascha Hauer 44cdace066SSascha Hauer #define I2CR_IEN (1 << 7) 45cdace066SSascha Hauer #define I2CR_IIEN (1 << 6) 46cdace066SSascha Hauer #define I2CR_MSTA (1 << 5) 47cdace066SSascha Hauer #define I2CR_MTX (1 << 4) 48cdace066SSascha Hauer #define I2CR_TX_NO_AK (1 << 3) 49cdace066SSascha Hauer #define I2CR_RSTA (1 << 2) 50cdace066SSascha Hauer 51cdace066SSascha Hauer #define I2SR_ICF (1 << 7) 52cdace066SSascha Hauer #define I2SR_IBB (1 << 5) 53cdace066SSascha Hauer #define I2SR_IIF (1 << 1) 54cdace066SSascha Hauer #define I2SR_RX_NO_AK (1 << 0) 55cdace066SSascha Hauer 56*127cec18SLiu Hui-R64343 #if defined(CONFIG_SYS_I2C_MX31_PORT1) 57cdace066SSascha Hauer #define I2C_BASE 0x43f80000 58e7de18afSGuennadi Liakhovetski #define I2C_CLK_OFFSET 26 596d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #elif defined (CONFIG_SYS_I2C_MX31_PORT2) 60cdace066SSascha Hauer #define I2C_BASE 0x43f98000 61e7de18afSGuennadi Liakhovetski #define I2C_CLK_OFFSET 28 626d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #elif defined (CONFIG_SYS_I2C_MX31_PORT3) 63cdace066SSascha Hauer #define I2C_BASE 0x43f84000 64e7de18afSGuennadi Liakhovetski #define I2C_CLK_OFFSET 30 65*127cec18SLiu Hui-R64343 #elif defined(CONFIG_SYS_I2C_MX53_PORT1) 66*127cec18SLiu Hui-R64343 #define I2C_BASE I2C1_BASE_ADDR 67*127cec18SLiu Hui-R64343 #elif defined(CONFIG_SYS_I2C_MX53_PORT2) 68*127cec18SLiu Hui-R64343 #define I2C_BASE I2C2_BASE_ADDR 69cdace066SSascha Hauer #else 70*127cec18SLiu Hui-R64343 #error "define CONFIG_SYS_I2C_MXxx_PORTx to use the I2C driver" 71cdace066SSascha Hauer #endif 72cdace066SSascha Hauer 73cdace066SSascha Hauer #ifdef DEBUG 74cdace066SSascha Hauer #define DPRINTF(args...) printf(args) 75cdace066SSascha Hauer #else 76cdace066SSascha Hauer #define DPRINTF(args...) 77cdace066SSascha Hauer #endif 78cdace066SSascha Hauer 79cdace066SSascha Hauer static u16 div[] = { 30, 32, 36, 42, 48, 52, 60, 72, 80, 88, 104, 128, 144, 80cdace066SSascha Hauer 160, 192, 240, 288, 320, 384, 480, 576, 640, 768, 960, 81cdace066SSascha Hauer 1152, 1280, 1536, 1920, 2304, 2560, 3072, 3840}; 82cdace066SSascha Hauer 83cdace066SSascha Hauer void i2c_init(int speed, int unused) 84cdace066SSascha Hauer { 85*127cec18SLiu Hui-R64343 int freq; 86cdace066SSascha Hauer int i; 87cdace066SSascha Hauer 88*127cec18SLiu Hui-R64343 #if defined(CONFIG_MX31) 89*127cec18SLiu Hui-R64343 freq = mx31_get_ipg_clk(); 90e7de18afSGuennadi Liakhovetski /* start the required I2C clock */ 91e7de18afSGuennadi Liakhovetski __REG(CCM_CGR0) = __REG(CCM_CGR0) | (3 << I2C_CLK_OFFSET); 92*127cec18SLiu Hui-R64343 #else 93*127cec18SLiu Hui-R64343 freq = mxc_get_clock(MXC_IPG_PERCLK); 94*127cec18SLiu Hui-R64343 #endif 95e7de18afSGuennadi Liakhovetski 96cdace066SSascha Hauer for (i = 0; i < 0x1f; i++) 97cdace066SSascha Hauer if (freq / div[i] <= speed) 98cdace066SSascha Hauer break; 99cdace066SSascha Hauer 100cdace066SSascha Hauer DPRINTF("%s: speed: %d\n",__FUNCTION__, speed); 101cdace066SSascha Hauer 102cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = 0; /* Reset module */ 103cdace066SSascha Hauer __REG16(I2C_BASE + IFDR) = i; 104cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN; 105cdace066SSascha Hauer __REG16(I2C_BASE + I2SR) = 0; 106cdace066SSascha Hauer } 107cdace066SSascha Hauer 108cdace066SSascha Hauer static int wait_busy(void) 109cdace066SSascha Hauer { 110cdace066SSascha Hauer int timeout = 10000; 111cdace066SSascha Hauer 112cdace066SSascha Hauer while (!(__REG16(I2C_BASE + I2SR) & I2SR_IIF) && --timeout) 113cdace066SSascha Hauer udelay(1); 114cdace066SSascha Hauer __REG16(I2C_BASE + I2SR) = 0; /* clear interrupt */ 115cdace066SSascha Hauer 116cdace066SSascha Hauer return timeout; 117cdace066SSascha Hauer } 118cdace066SSascha Hauer 119cdace066SSascha Hauer static int tx_byte(u8 byte) 120cdace066SSascha Hauer { 121cdace066SSascha Hauer __REG16(I2C_BASE + I2DR) = byte; 122cdace066SSascha Hauer 123cdace066SSascha Hauer if (!wait_busy() || __REG16(I2C_BASE + I2SR) & I2SR_RX_NO_AK) 124cdace066SSascha Hauer return -1; 125cdace066SSascha Hauer return 0; 126cdace066SSascha Hauer } 127cdace066SSascha Hauer 128cdace066SSascha Hauer static int rx_byte(void) 129cdace066SSascha Hauer { 130cdace066SSascha Hauer if (!wait_busy()) 131cdace066SSascha Hauer return -1; 132cdace066SSascha Hauer 133cdace066SSascha Hauer return __REG16(I2C_BASE + I2DR); 134cdace066SSascha Hauer } 135cdace066SSascha Hauer 136cdace066SSascha Hauer int i2c_probe(uchar chip) 137cdace066SSascha Hauer { 138cdace066SSascha Hauer int ret; 139cdace066SSascha Hauer 140cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = 0; /* Reset module */ 141cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN; 142cdace066SSascha Hauer 143cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | I2CR_MTX; 144cdace066SSascha Hauer ret = tx_byte(chip << 1); 145cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MTX; 146cdace066SSascha Hauer 147cdace066SSascha Hauer return ret; 148cdace066SSascha Hauer } 149cdace066SSascha Hauer 150cdace066SSascha Hauer static int i2c_addr(uchar chip, uint addr, int alen) 151cdace066SSascha Hauer { 152cdace066SSascha Hauer __REG16(I2C_BASE + I2SR) = 0; /* clear interrupt */ 153cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | I2CR_MTX; 154cdace066SSascha Hauer 155cdace066SSascha Hauer if (tx_byte(chip << 1)) 156cdace066SSascha Hauer return -1; 157cdace066SSascha Hauer 158cdace066SSascha Hauer while (alen--) 159cdace066SSascha Hauer if (tx_byte((addr >> (alen * 8)) & 0xff)) 160cdace066SSascha Hauer return -1; 161cdace066SSascha Hauer return 0; 162cdace066SSascha Hauer } 163cdace066SSascha Hauer 164cdace066SSascha Hauer int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) 165cdace066SSascha Hauer { 166cdace066SSascha Hauer int timeout = 10000; 167cdace066SSascha Hauer int ret; 168cdace066SSascha Hauer 169cdace066SSascha Hauer DPRINTF("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n",__FUNCTION__, chip, addr, alen, len); 170cdace066SSascha Hauer 171cdace066SSascha Hauer if (i2c_addr(chip, addr, alen)) { 172cdace066SSascha Hauer printf("i2c_addr failed\n"); 173cdace066SSascha Hauer return -1; 174cdace066SSascha Hauer } 175cdace066SSascha Hauer 176cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | I2CR_MTX | I2CR_RSTA; 177cdace066SSascha Hauer 178cdace066SSascha Hauer if (tx_byte(chip << 1 | 1)) 179cdace066SSascha Hauer return -1; 180cdace066SSascha Hauer 181cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | ((len == 1) ? I2CR_TX_NO_AK : 0); 182cdace066SSascha Hauer 183cdace066SSascha Hauer ret = __REG16(I2C_BASE + I2DR); 184cdace066SSascha Hauer 185cdace066SSascha Hauer while (len--) { 186cdace066SSascha Hauer if ((ret = rx_byte()) < 0) 187cdace066SSascha Hauer return -1; 188cdace066SSascha Hauer *buf++ = ret; 189cdace066SSascha Hauer if (len <= 1) 190cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | I2CR_TX_NO_AK; 191cdace066SSascha Hauer } 192cdace066SSascha Hauer 193cdace066SSascha Hauer wait_busy(); 194cdace066SSascha Hauer 195cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN; 196cdace066SSascha Hauer 197cdace066SSascha Hauer while (__REG16(I2C_BASE + I2SR) & I2SR_IBB && --timeout) 198cdace066SSascha Hauer udelay(1); 199cdace066SSascha Hauer 200cdace066SSascha Hauer return 0; 201cdace066SSascha Hauer } 202cdace066SSascha Hauer 203cdace066SSascha Hauer int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) 204cdace066SSascha Hauer { 205cdace066SSascha Hauer int timeout = 10000; 206cdace066SSascha Hauer DPRINTF("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n",__FUNCTION__, chip, addr, alen, len); 207cdace066SSascha Hauer 208cdace066SSascha Hauer if (i2c_addr(chip, addr, alen)) 209cdace066SSascha Hauer return -1; 210cdace066SSascha Hauer 211cdace066SSascha Hauer while (len--) 212cdace066SSascha Hauer if (tx_byte(*buf++)) 213cdace066SSascha Hauer return -1; 214cdace066SSascha Hauer 215cdace066SSascha Hauer __REG16(I2C_BASE + I2CR) = I2CR_IEN; 216cdace066SSascha Hauer 217cdace066SSascha Hauer while (__REG16(I2C_BASE + I2SR) & I2SR_IBB && --timeout) 218cdace066SSascha Hauer udelay(1); 219cdace066SSascha Hauer 220cdace066SSascha Hauer return 0; 221cdace066SSascha Hauer } 222cdace066SSascha Hauer 223cdace066SSascha Hauer #endif /* CONFIG_HARD_I2C */ 224