1d3b63577SJean-Christophe PLAGNIOL-VILLARD /* 2d3b63577SJean-Christophe PLAGNIOL-VILLARD * (C) Copyright 2002 3d3b63577SJean-Christophe PLAGNIOL-VILLARD * David Mueller, ELSOFT AG, d.mueller@elsoft.ch 4d3b63577SJean-Christophe PLAGNIOL-VILLARD * 5d3b63577SJean-Christophe PLAGNIOL-VILLARD * See file CREDITS for list of people who contributed to this 6d3b63577SJean-Christophe PLAGNIOL-VILLARD * project. 7d3b63577SJean-Christophe PLAGNIOL-VILLARD * 8d3b63577SJean-Christophe PLAGNIOL-VILLARD * This program is free software; you can redistribute it and/or 9d3b63577SJean-Christophe PLAGNIOL-VILLARD * modify it under the terms of the GNU General Public License as 10d3b63577SJean-Christophe PLAGNIOL-VILLARD * published by the Free Software Foundation; either version 2 of 11d3b63577SJean-Christophe PLAGNIOL-VILLARD * the License, or (at your option) any later version. 12d3b63577SJean-Christophe PLAGNIOL-VILLARD * 13d3b63577SJean-Christophe PLAGNIOL-VILLARD * This program is distributed in the hope that it will be useful, 14d3b63577SJean-Christophe PLAGNIOL-VILLARD * but WITHOUT ANY WARRANTY; without even the implied warranty of 15d3b63577SJean-Christophe PLAGNIOL-VILLARD * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16d3b63577SJean-Christophe PLAGNIOL-VILLARD * GNU General Public License for more details. 17d3b63577SJean-Christophe PLAGNIOL-VILLARD * 18d3b63577SJean-Christophe PLAGNIOL-VILLARD * You should have received a copy of the GNU General Public License 19d3b63577SJean-Christophe PLAGNIOL-VILLARD * along with this program; if not, write to the Free Software 20d3b63577SJean-Christophe PLAGNIOL-VILLARD * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21d3b63577SJean-Christophe PLAGNIOL-VILLARD * MA 02111-1307 USA 22d3b63577SJean-Christophe PLAGNIOL-VILLARD */ 23d3b63577SJean-Christophe PLAGNIOL-VILLARD 24d3b63577SJean-Christophe PLAGNIOL-VILLARD /* This code should work for both the S3C2400 and the S3C2410 25d3b63577SJean-Christophe PLAGNIOL-VILLARD * as they seem to have the same I2C controller inside. 26d3b63577SJean-Christophe PLAGNIOL-VILLARD * The different address mapping is handled by the s3c24xx.h files below. 27d3b63577SJean-Christophe PLAGNIOL-VILLARD */ 28d3b63577SJean-Christophe PLAGNIOL-VILLARD 29d3b63577SJean-Christophe PLAGNIOL-VILLARD #include <common.h> 30*c86d9ed3SPiotr Wilczek #if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) 31ab7e52bbSRajeshwari Shinde #include <asm/arch/clk.h> 32ab7e52bbSRajeshwari Shinde #include <asm/arch/cpu.h> 33ab7e52bbSRajeshwari Shinde #else 34ac67804fSkevin.morfitt@fearnside-systems.co.uk #include <asm/arch/s3c24x0_cpu.h> 35ab7e52bbSRajeshwari Shinde #endif 36eb0ae7f5Skevin.morfitt@fearnside-systems.co.uk #include <asm/io.h> 37d3b63577SJean-Christophe PLAGNIOL-VILLARD #include <i2c.h> 38ab7e52bbSRajeshwari Shinde #include "s3c24x0_i2c.h" 39d3b63577SJean-Christophe PLAGNIOL-VILLARD 40d3b63577SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_HARD_I2C 41d3b63577SJean-Christophe PLAGNIOL-VILLARD 42d3b63577SJean-Christophe PLAGNIOL-VILLARD #define I2C_WRITE 0 43d3b63577SJean-Christophe PLAGNIOL-VILLARD #define I2C_READ 1 44d3b63577SJean-Christophe PLAGNIOL-VILLARD 45d3b63577SJean-Christophe PLAGNIOL-VILLARD #define I2C_OK 0 46d3b63577SJean-Christophe PLAGNIOL-VILLARD #define I2C_NOK 1 47d3b63577SJean-Christophe PLAGNIOL-VILLARD #define I2C_NACK 2 48d3b63577SJean-Christophe PLAGNIOL-VILLARD #define I2C_NOK_LA 3 /* Lost arbitration */ 49d3b63577SJean-Christophe PLAGNIOL-VILLARD #define I2C_NOK_TOUT 4 /* time out */ 50d3b63577SJean-Christophe PLAGNIOL-VILLARD 51d3b63577SJean-Christophe PLAGNIOL-VILLARD #define I2CSTAT_BSY 0x20 /* Busy bit */ 52d3b63577SJean-Christophe PLAGNIOL-VILLARD #define I2CSTAT_NACK 0x01 /* Nack bit */ 53ab7e52bbSRajeshwari Shinde #define I2CCON_ACKGEN 0x80 /* Acknowledge generation */ 54d3b63577SJean-Christophe PLAGNIOL-VILLARD #define I2CCON_IRPND 0x10 /* Interrupt pending bit */ 55d3b63577SJean-Christophe PLAGNIOL-VILLARD #define I2C_MODE_MT 0xC0 /* Master Transmit Mode */ 56d3b63577SJean-Christophe PLAGNIOL-VILLARD #define I2C_MODE_MR 0x80 /* Master Receive Mode */ 57d3b63577SJean-Christophe PLAGNIOL-VILLARD #define I2C_START_STOP 0x20 /* START / STOP */ 58d3b63577SJean-Christophe PLAGNIOL-VILLARD #define I2C_TXRX_ENA 0x10 /* I2C Tx/Rx enable */ 59d3b63577SJean-Christophe PLAGNIOL-VILLARD 60d3b63577SJean-Christophe PLAGNIOL-VILLARD #define I2C_TIMEOUT 1 /* 1 second */ 61d3b63577SJean-Christophe PLAGNIOL-VILLARD 62ab7e52bbSRajeshwari Shinde 63ab7e52bbSRajeshwari Shinde static unsigned int g_current_bus; /* Stores Current I2C Bus */ 64ab7e52bbSRajeshwari Shinde 65*c86d9ed3SPiotr Wilczek #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) 66d3b63577SJean-Christophe PLAGNIOL-VILLARD static int GetI2CSDA(void) 67d3b63577SJean-Christophe PLAGNIOL-VILLARD { 68eb0ae7f5Skevin.morfitt@fearnside-systems.co.uk struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); 69d3b63577SJean-Christophe PLAGNIOL-VILLARD 70d3b63577SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_S3C2410 71d9abba82SC Nauman return (readl(&gpio->gpedat) & 0x8000) >> 15; 72d3b63577SJean-Christophe PLAGNIOL-VILLARD #endif 73d3b63577SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_S3C2400 74d9abba82SC Nauman return (readl(&gpio->pgdat) & 0x0020) >> 5; 75d3b63577SJean-Christophe PLAGNIOL-VILLARD #endif 76d3b63577SJean-Christophe PLAGNIOL-VILLARD } 77d3b63577SJean-Christophe PLAGNIOL-VILLARD 78d3b63577SJean-Christophe PLAGNIOL-VILLARD #if 0 79d3b63577SJean-Christophe PLAGNIOL-VILLARD static void SetI2CSDA(int x) 80d3b63577SJean-Christophe PLAGNIOL-VILLARD { 81d3b63577SJean-Christophe PLAGNIOL-VILLARD rGPEDAT = (rGPEDAT & ~0x8000) | (x & 1) << 15; 82d3b63577SJean-Christophe PLAGNIOL-VILLARD } 83d3b63577SJean-Christophe PLAGNIOL-VILLARD #endif 84d3b63577SJean-Christophe PLAGNIOL-VILLARD 85d3b63577SJean-Christophe PLAGNIOL-VILLARD static void SetI2CSCL(int x) 86d3b63577SJean-Christophe PLAGNIOL-VILLARD { 87eb0ae7f5Skevin.morfitt@fearnside-systems.co.uk struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); 88d3b63577SJean-Christophe PLAGNIOL-VILLARD 89d3b63577SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_S3C2410 90ab7e52bbSRajeshwari Shinde writel((readl(&gpio->gpedat) & ~0x4000) | 91ab7e52bbSRajeshwari Shinde (x & 1) << 14, &gpio->gpedat); 92d3b63577SJean-Christophe PLAGNIOL-VILLARD #endif 93d3b63577SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_S3C2400 94d9abba82SC Nauman writel((readl(&gpio->pgdat) & ~0x0040) | (x & 1) << 6, &gpio->pgdat); 95d3b63577SJean-Christophe PLAGNIOL-VILLARD #endif 96d3b63577SJean-Christophe PLAGNIOL-VILLARD } 97ab7e52bbSRajeshwari Shinde #endif 98d3b63577SJean-Christophe PLAGNIOL-VILLARD 99ab7e52bbSRajeshwari Shinde static int WaitForXfer(struct s3c24x0_i2c *i2c) 100d3b63577SJean-Christophe PLAGNIOL-VILLARD { 101eb0ae7f5Skevin.morfitt@fearnside-systems.co.uk int i; 102d3b63577SJean-Christophe PLAGNIOL-VILLARD 103d3b63577SJean-Christophe PLAGNIOL-VILLARD i = I2C_TIMEOUT * 10000; 104d9abba82SC Nauman while (!(readl(&i2c->iiccon) & I2CCON_IRPND) && (i > 0)) { 105d3b63577SJean-Christophe PLAGNIOL-VILLARD udelay(100); 106d3b63577SJean-Christophe PLAGNIOL-VILLARD i--; 107d3b63577SJean-Christophe PLAGNIOL-VILLARD } 108d3b63577SJean-Christophe PLAGNIOL-VILLARD 109d9abba82SC Nauman return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT; 110d3b63577SJean-Christophe PLAGNIOL-VILLARD } 111d3b63577SJean-Christophe PLAGNIOL-VILLARD 112ab7e52bbSRajeshwari Shinde static int IsACK(struct s3c24x0_i2c *i2c) 113d3b63577SJean-Christophe PLAGNIOL-VILLARD { 114d9abba82SC Nauman return !(readl(&i2c->iicstat) & I2CSTAT_NACK); 115d3b63577SJean-Christophe PLAGNIOL-VILLARD } 116d3b63577SJean-Christophe PLAGNIOL-VILLARD 117ab7e52bbSRajeshwari Shinde static void ReadWriteByte(struct s3c24x0_i2c *i2c) 118d3b63577SJean-Christophe PLAGNIOL-VILLARD { 119d9abba82SC Nauman writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon); 120d3b63577SJean-Christophe PLAGNIOL-VILLARD } 121d3b63577SJean-Christophe PLAGNIOL-VILLARD 122ab7e52bbSRajeshwari Shinde static struct s3c24x0_i2c *get_base_i2c(void) 123ab7e52bbSRajeshwari Shinde { 124*c86d9ed3SPiotr Wilczek #ifdef CONFIG_EXYNOS4 125*c86d9ed3SPiotr Wilczek struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)(samsung_get_base_i2c() 126*c86d9ed3SPiotr Wilczek + (EXYNOS4_I2C_SPACING 127*c86d9ed3SPiotr Wilczek * g_current_bus)); 128*c86d9ed3SPiotr Wilczek return i2c; 129*c86d9ed3SPiotr Wilczek #elif defined CONFIG_EXYNOS5 130ab7e52bbSRajeshwari Shinde struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)(samsung_get_base_i2c() 131ab7e52bbSRajeshwari Shinde + (EXYNOS5_I2C_SPACING 132ab7e52bbSRajeshwari Shinde * g_current_bus)); 133ab7e52bbSRajeshwari Shinde return i2c; 134ab7e52bbSRajeshwari Shinde #else 135ab7e52bbSRajeshwari Shinde return s3c24x0_get_base_i2c(); 136ab7e52bbSRajeshwari Shinde #endif 137ab7e52bbSRajeshwari Shinde } 138ab7e52bbSRajeshwari Shinde 139ab7e52bbSRajeshwari Shinde static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) 140ab7e52bbSRajeshwari Shinde { 141ab7e52bbSRajeshwari Shinde ulong freq, pres = 16, div; 142*c86d9ed3SPiotr Wilczek #if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) 143ab7e52bbSRajeshwari Shinde freq = get_i2c_clk(); 144ab7e52bbSRajeshwari Shinde #else 145ab7e52bbSRajeshwari Shinde freq = get_PCLK(); 146ab7e52bbSRajeshwari Shinde #endif 147ab7e52bbSRajeshwari Shinde /* calculate prescaler and divisor values */ 148ab7e52bbSRajeshwari Shinde if ((freq / pres / (16 + 1)) > speed) 149ab7e52bbSRajeshwari Shinde /* set prescaler to 512 */ 150ab7e52bbSRajeshwari Shinde pres = 512; 151ab7e52bbSRajeshwari Shinde 152ab7e52bbSRajeshwari Shinde div = 0; 153ab7e52bbSRajeshwari Shinde while ((freq / pres / (div + 1)) > speed) 154ab7e52bbSRajeshwari Shinde div++; 155ab7e52bbSRajeshwari Shinde 156ab7e52bbSRajeshwari Shinde /* set prescaler, divisor according to freq, also set ACKGEN, IRQ */ 157ab7e52bbSRajeshwari Shinde writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon); 158ab7e52bbSRajeshwari Shinde 159ab7e52bbSRajeshwari Shinde /* init to SLAVE REVEIVE and set slaveaddr */ 160ab7e52bbSRajeshwari Shinde writel(0, &i2c->iicstat); 161ab7e52bbSRajeshwari Shinde writel(slaveadd, &i2c->iicadd); 162ab7e52bbSRajeshwari Shinde /* program Master Transmit (and implicit STOP) */ 163ab7e52bbSRajeshwari Shinde writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); 164ab7e52bbSRajeshwari Shinde } 165ab7e52bbSRajeshwari Shinde 166178239deSRajeshwari Shinde /* 167178239deSRajeshwari Shinde * MULTI BUS I2C support 168178239deSRajeshwari Shinde */ 169178239deSRajeshwari Shinde 170178239deSRajeshwari Shinde #ifdef CONFIG_I2C_MULTI_BUS 171178239deSRajeshwari Shinde int i2c_set_bus_num(unsigned int bus) 172178239deSRajeshwari Shinde { 173178239deSRajeshwari Shinde struct s3c24x0_i2c *i2c; 174178239deSRajeshwari Shinde 175178239deSRajeshwari Shinde if ((bus < 0) || (bus >= CONFIG_MAX_I2C_NUM)) { 176178239deSRajeshwari Shinde debug("Bad bus: %d\n", bus); 177178239deSRajeshwari Shinde return -1; 178178239deSRajeshwari Shinde } 179178239deSRajeshwari Shinde 180178239deSRajeshwari Shinde g_current_bus = bus; 181178239deSRajeshwari Shinde i2c = get_base_i2c(); 182178239deSRajeshwari Shinde i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); 183178239deSRajeshwari Shinde 184178239deSRajeshwari Shinde return 0; 185178239deSRajeshwari Shinde } 186178239deSRajeshwari Shinde 187178239deSRajeshwari Shinde unsigned int i2c_get_bus_num(void) 188178239deSRajeshwari Shinde { 189178239deSRajeshwari Shinde return g_current_bus; 190178239deSRajeshwari Shinde } 191178239deSRajeshwari Shinde #endif 192178239deSRajeshwari Shinde 193d3b63577SJean-Christophe PLAGNIOL-VILLARD void i2c_init(int speed, int slaveadd) 194d3b63577SJean-Christophe PLAGNIOL-VILLARD { 195ab7e52bbSRajeshwari Shinde struct s3c24x0_i2c *i2c; 196*c86d9ed3SPiotr Wilczek #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) 197eb0ae7f5Skevin.morfitt@fearnside-systems.co.uk struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); 198ab7e52bbSRajeshwari Shinde #endif 199eb0ae7f5Skevin.morfitt@fearnside-systems.co.uk int i; 200d3b63577SJean-Christophe PLAGNIOL-VILLARD 201ab7e52bbSRajeshwari Shinde /* By default i2c channel 0 is the current bus */ 202ab7e52bbSRajeshwari Shinde g_current_bus = 0; 203ab7e52bbSRajeshwari Shinde i2c = get_base_i2c(); 204d3b63577SJean-Christophe PLAGNIOL-VILLARD 205ab7e52bbSRajeshwari Shinde /* wait for some time to give previous transfer a chance to finish */ 206d3b63577SJean-Christophe PLAGNIOL-VILLARD i = I2C_TIMEOUT * 1000; 207ab7e52bbSRajeshwari Shinde while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) { 208d3b63577SJean-Christophe PLAGNIOL-VILLARD udelay(1000); 209d3b63577SJean-Christophe PLAGNIOL-VILLARD i--; 210d3b63577SJean-Christophe PLAGNIOL-VILLARD } 211d3b63577SJean-Christophe PLAGNIOL-VILLARD 212*c86d9ed3SPiotr Wilczek #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) 213d9abba82SC Nauman if ((readl(&i2c->iicstat) & I2CSTAT_BSY) || GetI2CSDA() == 0) { 214d3b63577SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_S3C2410 215d9abba82SC Nauman ulong old_gpecon = readl(&gpio->gpecon); 216d3b63577SJean-Christophe PLAGNIOL-VILLARD #endif 217d3b63577SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_S3C2400 218d9abba82SC Nauman ulong old_gpecon = readl(&gpio->pgcon); 219d3b63577SJean-Christophe PLAGNIOL-VILLARD #endif 220eb0ae7f5Skevin.morfitt@fearnside-systems.co.uk /* bus still busy probably by (most) previously interrupted 221eb0ae7f5Skevin.morfitt@fearnside-systems.co.uk transfer */ 222d3b63577SJean-Christophe PLAGNIOL-VILLARD 223d3b63577SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_S3C2410 224d3b63577SJean-Christophe PLAGNIOL-VILLARD /* set I2CSDA and I2CSCL (GPE15, GPE14) to GPIO */ 225d9abba82SC Nauman writel((readl(&gpio->gpecon) & ~0xF0000000) | 0x10000000, 226d9abba82SC Nauman &gpio->gpecon); 227d3b63577SJean-Christophe PLAGNIOL-VILLARD #endif 228d3b63577SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_S3C2400 229d3b63577SJean-Christophe PLAGNIOL-VILLARD /* set I2CSDA and I2CSCL (PG5, PG6) to GPIO */ 230d9abba82SC Nauman writel((readl(&gpio->pgcon) & ~0x00003c00) | 0x00001000, 231d9abba82SC Nauman &gpio->pgcon); 232d3b63577SJean-Christophe PLAGNIOL-VILLARD #endif 233d3b63577SJean-Christophe PLAGNIOL-VILLARD 234d3b63577SJean-Christophe PLAGNIOL-VILLARD /* toggle I2CSCL until bus idle */ 235d3b63577SJean-Christophe PLAGNIOL-VILLARD SetI2CSCL(0); 236d3b63577SJean-Christophe PLAGNIOL-VILLARD udelay(1000); 237d3b63577SJean-Christophe PLAGNIOL-VILLARD i = 10; 238d3b63577SJean-Christophe PLAGNIOL-VILLARD while ((i > 0) && (GetI2CSDA() != 1)) { 239d3b63577SJean-Christophe PLAGNIOL-VILLARD SetI2CSCL(1); 240d3b63577SJean-Christophe PLAGNIOL-VILLARD udelay(1000); 241d3b63577SJean-Christophe PLAGNIOL-VILLARD SetI2CSCL(0); 242d3b63577SJean-Christophe PLAGNIOL-VILLARD udelay(1000); 243d3b63577SJean-Christophe PLAGNIOL-VILLARD i--; 244d3b63577SJean-Christophe PLAGNIOL-VILLARD } 245d3b63577SJean-Christophe PLAGNIOL-VILLARD SetI2CSCL(1); 246d3b63577SJean-Christophe PLAGNIOL-VILLARD udelay(1000); 247d3b63577SJean-Christophe PLAGNIOL-VILLARD 248d3b63577SJean-Christophe PLAGNIOL-VILLARD /* restore pin functions */ 249d3b63577SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_S3C2410 250d9abba82SC Nauman writel(old_gpecon, &gpio->gpecon); 251d3b63577SJean-Christophe PLAGNIOL-VILLARD #endif 252d3b63577SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_S3C2400 253d9abba82SC Nauman writel(old_gpecon, &gpio->pgcon); 254d3b63577SJean-Christophe PLAGNIOL-VILLARD #endif 255d3b63577SJean-Christophe PLAGNIOL-VILLARD } 256*c86d9ed3SPiotr Wilczek #endif /* #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) */ 257ab7e52bbSRajeshwari Shinde i2c_ch_init(i2c, speed, slaveadd); 258d3b63577SJean-Christophe PLAGNIOL-VILLARD } 259d3b63577SJean-Christophe PLAGNIOL-VILLARD 260d3b63577SJean-Christophe PLAGNIOL-VILLARD /* 261d3b63577SJean-Christophe PLAGNIOL-VILLARD * cmd_type is 0 for write, 1 for read. 262d3b63577SJean-Christophe PLAGNIOL-VILLARD * 263d3b63577SJean-Christophe PLAGNIOL-VILLARD * addr_len can take any value from 0-255, it is only limited 264d3b63577SJean-Christophe PLAGNIOL-VILLARD * by the char, we could make it larger if needed. If it is 265d3b63577SJean-Christophe PLAGNIOL-VILLARD * 0 we skip the address write cycle. 266d3b63577SJean-Christophe PLAGNIOL-VILLARD */ 267ab7e52bbSRajeshwari Shinde static int i2c_transfer(struct s3c24x0_i2c *i2c, 268ab7e52bbSRajeshwari Shinde unsigned char cmd_type, 269d3b63577SJean-Christophe PLAGNIOL-VILLARD unsigned char chip, 270d3b63577SJean-Christophe PLAGNIOL-VILLARD unsigned char addr[], 271d3b63577SJean-Christophe PLAGNIOL-VILLARD unsigned char addr_len, 272ab7e52bbSRajeshwari Shinde unsigned char data[], 273ab7e52bbSRajeshwari Shinde unsigned short data_len) 274d3b63577SJean-Christophe PLAGNIOL-VILLARD { 275eb0ae7f5Skevin.morfitt@fearnside-systems.co.uk int i, result; 276d3b63577SJean-Christophe PLAGNIOL-VILLARD 277d3b63577SJean-Christophe PLAGNIOL-VILLARD if (data == 0 || data_len == 0) { 278d3b63577SJean-Christophe PLAGNIOL-VILLARD /*Don't support data transfer of no length or to address 0 */ 279ab7e52bbSRajeshwari Shinde debug("i2c_transfer: bad call\n"); 280d3b63577SJean-Christophe PLAGNIOL-VILLARD return I2C_NOK; 281d3b63577SJean-Christophe PLAGNIOL-VILLARD } 282d3b63577SJean-Christophe PLAGNIOL-VILLARD 283d3b63577SJean-Christophe PLAGNIOL-VILLARD /* Check I2C bus idle */ 284d3b63577SJean-Christophe PLAGNIOL-VILLARD i = I2C_TIMEOUT * 1000; 285d9abba82SC Nauman while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) { 286d3b63577SJean-Christophe PLAGNIOL-VILLARD udelay(1000); 287d3b63577SJean-Christophe PLAGNIOL-VILLARD i--; 288d3b63577SJean-Christophe PLAGNIOL-VILLARD } 289d3b63577SJean-Christophe PLAGNIOL-VILLARD 290d9abba82SC Nauman if (readl(&i2c->iicstat) & I2CSTAT_BSY) 291d3b63577SJean-Christophe PLAGNIOL-VILLARD return I2C_NOK_TOUT; 292d3b63577SJean-Christophe PLAGNIOL-VILLARD 293ab7e52bbSRajeshwari Shinde writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon); 294d3b63577SJean-Christophe PLAGNIOL-VILLARD result = I2C_OK; 295d3b63577SJean-Christophe PLAGNIOL-VILLARD 296d3b63577SJean-Christophe PLAGNIOL-VILLARD switch (cmd_type) { 297d3b63577SJean-Christophe PLAGNIOL-VILLARD case I2C_WRITE: 298d3b63577SJean-Christophe PLAGNIOL-VILLARD if (addr && addr_len) { 299d9abba82SC Nauman writel(chip, &i2c->iicds); 300d3b63577SJean-Christophe PLAGNIOL-VILLARD /* send START */ 301eb0ae7f5Skevin.morfitt@fearnside-systems.co.uk writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, 302d9abba82SC Nauman &i2c->iicstat); 303d3b63577SJean-Christophe PLAGNIOL-VILLARD i = 0; 304d3b63577SJean-Christophe PLAGNIOL-VILLARD while ((i < addr_len) && (result == I2C_OK)) { 305ab7e52bbSRajeshwari Shinde result = WaitForXfer(i2c); 306d9abba82SC Nauman writel(addr[i], &i2c->iicds); 307ab7e52bbSRajeshwari Shinde ReadWriteByte(i2c); 308d3b63577SJean-Christophe PLAGNIOL-VILLARD i++; 309d3b63577SJean-Christophe PLAGNIOL-VILLARD } 310d3b63577SJean-Christophe PLAGNIOL-VILLARD i = 0; 311d3b63577SJean-Christophe PLAGNIOL-VILLARD while ((i < data_len) && (result == I2C_OK)) { 312ab7e52bbSRajeshwari Shinde result = WaitForXfer(i2c); 313d9abba82SC Nauman writel(data[i], &i2c->iicds); 314ab7e52bbSRajeshwari Shinde ReadWriteByte(i2c); 315d3b63577SJean-Christophe PLAGNIOL-VILLARD i++; 316d3b63577SJean-Christophe PLAGNIOL-VILLARD } 317d3b63577SJean-Christophe PLAGNIOL-VILLARD } else { 318d9abba82SC Nauman writel(chip, &i2c->iicds); 319d3b63577SJean-Christophe PLAGNIOL-VILLARD /* send START */ 320eb0ae7f5Skevin.morfitt@fearnside-systems.co.uk writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, 321d9abba82SC Nauman &i2c->iicstat); 322d3b63577SJean-Christophe PLAGNIOL-VILLARD i = 0; 323d3b63577SJean-Christophe PLAGNIOL-VILLARD while ((i < data_len) && (result = I2C_OK)) { 324ab7e52bbSRajeshwari Shinde result = WaitForXfer(i2c); 325d9abba82SC Nauman writel(data[i], &i2c->iicds); 326ab7e52bbSRajeshwari Shinde ReadWriteByte(i2c); 327d3b63577SJean-Christophe PLAGNIOL-VILLARD i++; 328d3b63577SJean-Christophe PLAGNIOL-VILLARD } 329d3b63577SJean-Christophe PLAGNIOL-VILLARD } 330d3b63577SJean-Christophe PLAGNIOL-VILLARD 331d3b63577SJean-Christophe PLAGNIOL-VILLARD if (result == I2C_OK) 332ab7e52bbSRajeshwari Shinde result = WaitForXfer(i2c); 333d3b63577SJean-Christophe PLAGNIOL-VILLARD 334d3b63577SJean-Christophe PLAGNIOL-VILLARD /* send STOP */ 335d9abba82SC Nauman writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat); 336ab7e52bbSRajeshwari Shinde ReadWriteByte(i2c); 337d3b63577SJean-Christophe PLAGNIOL-VILLARD break; 338d3b63577SJean-Christophe PLAGNIOL-VILLARD 339d3b63577SJean-Christophe PLAGNIOL-VILLARD case I2C_READ: 340d3b63577SJean-Christophe PLAGNIOL-VILLARD if (addr && addr_len) { 341d9abba82SC Nauman writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); 342d9abba82SC Nauman writel(chip, &i2c->iicds); 343d3b63577SJean-Christophe PLAGNIOL-VILLARD /* send START */ 344d9abba82SC Nauman writel(readl(&i2c->iicstat) | I2C_START_STOP, 345d9abba82SC Nauman &i2c->iicstat); 346ab7e52bbSRajeshwari Shinde result = WaitForXfer(i2c); 347ab7e52bbSRajeshwari Shinde if (IsACK(i2c)) { 348d3b63577SJean-Christophe PLAGNIOL-VILLARD i = 0; 349d3b63577SJean-Christophe PLAGNIOL-VILLARD while ((i < addr_len) && (result == I2C_OK)) { 350d9abba82SC Nauman writel(addr[i], &i2c->iicds); 351ab7e52bbSRajeshwari Shinde ReadWriteByte(i2c); 352ab7e52bbSRajeshwari Shinde result = WaitForXfer(i2c); 353d3b63577SJean-Christophe PLAGNIOL-VILLARD i++; 354d3b63577SJean-Christophe PLAGNIOL-VILLARD } 355d3b63577SJean-Christophe PLAGNIOL-VILLARD 356d9abba82SC Nauman writel(chip, &i2c->iicds); 357d3b63577SJean-Christophe PLAGNIOL-VILLARD /* resend START */ 358eb0ae7f5Skevin.morfitt@fearnside-systems.co.uk writel(I2C_MODE_MR | I2C_TXRX_ENA | 359d9abba82SC Nauman I2C_START_STOP, &i2c->iicstat); 360ab7e52bbSRajeshwari Shinde ReadWriteByte(i2c); 361ab7e52bbSRajeshwari Shinde result = WaitForXfer(i2c); 362d3b63577SJean-Christophe PLAGNIOL-VILLARD i = 0; 363d3b63577SJean-Christophe PLAGNIOL-VILLARD while ((i < data_len) && (result == I2C_OK)) { 364d3b63577SJean-Christophe PLAGNIOL-VILLARD /* disable ACK for final READ */ 365d3b63577SJean-Christophe PLAGNIOL-VILLARD if (i == data_len - 1) 366d9abba82SC Nauman writel(readl(&i2c->iiccon) 367ab7e52bbSRajeshwari Shinde & ~I2CCON_ACKGEN, 368ab7e52bbSRajeshwari Shinde &i2c->iiccon); 369ab7e52bbSRajeshwari Shinde ReadWriteByte(i2c); 370ab7e52bbSRajeshwari Shinde result = WaitForXfer(i2c); 371d9abba82SC Nauman data[i] = readl(&i2c->iicds); 372d3b63577SJean-Christophe PLAGNIOL-VILLARD i++; 373d3b63577SJean-Christophe PLAGNIOL-VILLARD } 374d3b63577SJean-Christophe PLAGNIOL-VILLARD } else { 375d3b63577SJean-Christophe PLAGNIOL-VILLARD result = I2C_NACK; 376d3b63577SJean-Christophe PLAGNIOL-VILLARD } 377d3b63577SJean-Christophe PLAGNIOL-VILLARD 378d3b63577SJean-Christophe PLAGNIOL-VILLARD } else { 379d9abba82SC Nauman writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat); 380d9abba82SC Nauman writel(chip, &i2c->iicds); 381d3b63577SJean-Christophe PLAGNIOL-VILLARD /* send START */ 382d9abba82SC Nauman writel(readl(&i2c->iicstat) | I2C_START_STOP, 383d9abba82SC Nauman &i2c->iicstat); 384ab7e52bbSRajeshwari Shinde result = WaitForXfer(i2c); 385d3b63577SJean-Christophe PLAGNIOL-VILLARD 386ab7e52bbSRajeshwari Shinde if (IsACK(i2c)) { 387d3b63577SJean-Christophe PLAGNIOL-VILLARD i = 0; 388d3b63577SJean-Christophe PLAGNIOL-VILLARD while ((i < data_len) && (result == I2C_OK)) { 389d3b63577SJean-Christophe PLAGNIOL-VILLARD /* disable ACK for final READ */ 390d3b63577SJean-Christophe PLAGNIOL-VILLARD if (i == data_len - 1) 391d9abba82SC Nauman writel(readl(&i2c->iiccon) & 392ab7e52bbSRajeshwari Shinde ~I2CCON_ACKGEN, 393ab7e52bbSRajeshwari Shinde &i2c->iiccon); 394ab7e52bbSRajeshwari Shinde ReadWriteByte(i2c); 395ab7e52bbSRajeshwari Shinde result = WaitForXfer(i2c); 396d9abba82SC Nauman data[i] = readl(&i2c->iicds); 397d3b63577SJean-Christophe PLAGNIOL-VILLARD i++; 398d3b63577SJean-Christophe PLAGNIOL-VILLARD } 399d3b63577SJean-Christophe PLAGNIOL-VILLARD } else { 400d3b63577SJean-Christophe PLAGNIOL-VILLARD result = I2C_NACK; 401d3b63577SJean-Christophe PLAGNIOL-VILLARD } 402d3b63577SJean-Christophe PLAGNIOL-VILLARD } 403d3b63577SJean-Christophe PLAGNIOL-VILLARD 404d3b63577SJean-Christophe PLAGNIOL-VILLARD /* send STOP */ 405d9abba82SC Nauman writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat); 406ab7e52bbSRajeshwari Shinde ReadWriteByte(i2c); 407d3b63577SJean-Christophe PLAGNIOL-VILLARD break; 408d3b63577SJean-Christophe PLAGNIOL-VILLARD 409d3b63577SJean-Christophe PLAGNIOL-VILLARD default: 410ab7e52bbSRajeshwari Shinde debug("i2c_transfer: bad call\n"); 411d3b63577SJean-Christophe PLAGNIOL-VILLARD result = I2C_NOK; 412d3b63577SJean-Christophe PLAGNIOL-VILLARD break; 413d3b63577SJean-Christophe PLAGNIOL-VILLARD } 414d3b63577SJean-Christophe PLAGNIOL-VILLARD 415ab7e52bbSRajeshwari Shinde return result; 416d3b63577SJean-Christophe PLAGNIOL-VILLARD } 417d3b63577SJean-Christophe PLAGNIOL-VILLARD 418d3b63577SJean-Christophe PLAGNIOL-VILLARD int i2c_probe(uchar chip) 419d3b63577SJean-Christophe PLAGNIOL-VILLARD { 420ab7e52bbSRajeshwari Shinde struct s3c24x0_i2c *i2c; 421d3b63577SJean-Christophe PLAGNIOL-VILLARD uchar buf[1]; 422d3b63577SJean-Christophe PLAGNIOL-VILLARD 423ab7e52bbSRajeshwari Shinde i2c = get_base_i2c(); 424d3b63577SJean-Christophe PLAGNIOL-VILLARD buf[0] = 0; 425d3b63577SJean-Christophe PLAGNIOL-VILLARD 426d3b63577SJean-Christophe PLAGNIOL-VILLARD /* 427d3b63577SJean-Christophe PLAGNIOL-VILLARD * What is needed is to send the chip address and verify that the 428d3b63577SJean-Christophe PLAGNIOL-VILLARD * address was <ACK>ed (i.e. there was a chip at that address which 429d3b63577SJean-Christophe PLAGNIOL-VILLARD * drove the data line low). 430d3b63577SJean-Christophe PLAGNIOL-VILLARD */ 431ab7e52bbSRajeshwari Shinde return i2c_transfer(i2c, I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK; 432d3b63577SJean-Christophe PLAGNIOL-VILLARD } 433d3b63577SJean-Christophe PLAGNIOL-VILLARD 434d3b63577SJean-Christophe PLAGNIOL-VILLARD int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) 435d3b63577SJean-Christophe PLAGNIOL-VILLARD { 436ab7e52bbSRajeshwari Shinde struct s3c24x0_i2c *i2c; 437d3b63577SJean-Christophe PLAGNIOL-VILLARD uchar xaddr[4]; 438d3b63577SJean-Christophe PLAGNIOL-VILLARD int ret; 439d3b63577SJean-Christophe PLAGNIOL-VILLARD 440d3b63577SJean-Christophe PLAGNIOL-VILLARD if (alen > 4) { 441ab7e52bbSRajeshwari Shinde debug("I2C read: addr len %d not supported\n", alen); 442d3b63577SJean-Christophe PLAGNIOL-VILLARD return 1; 443d3b63577SJean-Christophe PLAGNIOL-VILLARD } 444d3b63577SJean-Christophe PLAGNIOL-VILLARD 445d3b63577SJean-Christophe PLAGNIOL-VILLARD if (alen > 0) { 446d3b63577SJean-Christophe PLAGNIOL-VILLARD xaddr[0] = (addr >> 24) & 0xFF; 447d3b63577SJean-Christophe PLAGNIOL-VILLARD xaddr[1] = (addr >> 16) & 0xFF; 448d3b63577SJean-Christophe PLAGNIOL-VILLARD xaddr[2] = (addr >> 8) & 0xFF; 449d3b63577SJean-Christophe PLAGNIOL-VILLARD xaddr[3] = addr & 0xFF; 450d3b63577SJean-Christophe PLAGNIOL-VILLARD } 451d3b63577SJean-Christophe PLAGNIOL-VILLARD 452d3b63577SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW 453d3b63577SJean-Christophe PLAGNIOL-VILLARD /* 454d3b63577SJean-Christophe PLAGNIOL-VILLARD * EEPROM chips that implement "address overflow" are ones 455d3b63577SJean-Christophe PLAGNIOL-VILLARD * like Catalyst 24WC04/08/16 which has 9/10/11 bits of 456d3b63577SJean-Christophe PLAGNIOL-VILLARD * address and the extra bits end up in the "chip address" 457d3b63577SJean-Christophe PLAGNIOL-VILLARD * bit slots. This makes a 24WC08 (1Kbyte) chip look like 458d3b63577SJean-Christophe PLAGNIOL-VILLARD * four 256 byte chips. 459d3b63577SJean-Christophe PLAGNIOL-VILLARD * 460d3b63577SJean-Christophe PLAGNIOL-VILLARD * Note that we consider the length of the address field to 461d3b63577SJean-Christophe PLAGNIOL-VILLARD * still be one byte because the extra address bits are 462d3b63577SJean-Christophe PLAGNIOL-VILLARD * hidden in the chip address. 463d3b63577SJean-Christophe PLAGNIOL-VILLARD */ 464d3b63577SJean-Christophe PLAGNIOL-VILLARD if (alen > 0) 465eb0ae7f5Skevin.morfitt@fearnside-systems.co.uk chip |= ((addr >> (alen * 8)) & 466eb0ae7f5Skevin.morfitt@fearnside-systems.co.uk CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); 467d3b63577SJean-Christophe PLAGNIOL-VILLARD #endif 468ab7e52bbSRajeshwari Shinde i2c = get_base_i2c(); 469ab7e52bbSRajeshwari Shinde ret = i2c_transfer(i2c, I2C_READ, chip << 1, &xaddr[4 - alen], alen, 470ab7e52bbSRajeshwari Shinde buffer, len); 471ab7e52bbSRajeshwari Shinde if (ret != 0) { 472ab7e52bbSRajeshwari Shinde debug("I2c read: failed %d\n", ret); 473d3b63577SJean-Christophe PLAGNIOL-VILLARD return 1; 474d3b63577SJean-Christophe PLAGNIOL-VILLARD } 475d3b63577SJean-Christophe PLAGNIOL-VILLARD return 0; 476d3b63577SJean-Christophe PLAGNIOL-VILLARD } 477d3b63577SJean-Christophe PLAGNIOL-VILLARD 478d3b63577SJean-Christophe PLAGNIOL-VILLARD int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) 479d3b63577SJean-Christophe PLAGNIOL-VILLARD { 480ab7e52bbSRajeshwari Shinde struct s3c24x0_i2c *i2c; 481d3b63577SJean-Christophe PLAGNIOL-VILLARD uchar xaddr[4]; 482d3b63577SJean-Christophe PLAGNIOL-VILLARD 483d3b63577SJean-Christophe PLAGNIOL-VILLARD if (alen > 4) { 484ab7e52bbSRajeshwari Shinde debug("I2C write: addr len %d not supported\n", alen); 485d3b63577SJean-Christophe PLAGNIOL-VILLARD return 1; 486d3b63577SJean-Christophe PLAGNIOL-VILLARD } 487d3b63577SJean-Christophe PLAGNIOL-VILLARD 488d3b63577SJean-Christophe PLAGNIOL-VILLARD if (alen > 0) { 489d3b63577SJean-Christophe PLAGNIOL-VILLARD xaddr[0] = (addr >> 24) & 0xFF; 490d3b63577SJean-Christophe PLAGNIOL-VILLARD xaddr[1] = (addr >> 16) & 0xFF; 491d3b63577SJean-Christophe PLAGNIOL-VILLARD xaddr[2] = (addr >> 8) & 0xFF; 492d3b63577SJean-Christophe PLAGNIOL-VILLARD xaddr[3] = addr & 0xFF; 493d3b63577SJean-Christophe PLAGNIOL-VILLARD } 494d3b63577SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW 495d3b63577SJean-Christophe PLAGNIOL-VILLARD /* 496d3b63577SJean-Christophe PLAGNIOL-VILLARD * EEPROM chips that implement "address overflow" are ones 497d3b63577SJean-Christophe PLAGNIOL-VILLARD * like Catalyst 24WC04/08/16 which has 9/10/11 bits of 498d3b63577SJean-Christophe PLAGNIOL-VILLARD * address and the extra bits end up in the "chip address" 499d3b63577SJean-Christophe PLAGNIOL-VILLARD * bit slots. This makes a 24WC08 (1Kbyte) chip look like 500d3b63577SJean-Christophe PLAGNIOL-VILLARD * four 256 byte chips. 501d3b63577SJean-Christophe PLAGNIOL-VILLARD * 502d3b63577SJean-Christophe PLAGNIOL-VILLARD * Note that we consider the length of the address field to 503d3b63577SJean-Christophe PLAGNIOL-VILLARD * still be one byte because the extra address bits are 504d3b63577SJean-Christophe PLAGNIOL-VILLARD * hidden in the chip address. 505d3b63577SJean-Christophe PLAGNIOL-VILLARD */ 506d3b63577SJean-Christophe PLAGNIOL-VILLARD if (alen > 0) 507eb0ae7f5Skevin.morfitt@fearnside-systems.co.uk chip |= ((addr >> (alen * 8)) & 508eb0ae7f5Skevin.morfitt@fearnside-systems.co.uk CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); 509d3b63577SJean-Christophe PLAGNIOL-VILLARD #endif 510ab7e52bbSRajeshwari Shinde i2c = get_base_i2c(); 511d3b63577SJean-Christophe PLAGNIOL-VILLARD return (i2c_transfer 512ab7e52bbSRajeshwari Shinde (i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer, 513d3b63577SJean-Christophe PLAGNIOL-VILLARD len) != 0); 514d3b63577SJean-Christophe PLAGNIOL-VILLARD } 515d3b63577SJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_HARD_I2C */ 516