1 /* 2 * (C) Copyright 2009 3 * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. 4 * 5 * See file CREDITS for list of people who contributed to this 6 * project. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 * MA 02111-1307 USA 22 */ 23 24 #include <common.h> 25 #include <asm/io.h> 26 #include <asm/arch/hardware.h> 27 #include "designware_i2c.h" 28 29 static struct i2c_regs *const i2c_regs_p = 30 (struct i2c_regs *)CONFIG_SYS_I2C_BASE; 31 32 /* 33 * set_speed - Set the i2c speed mode (standard, high, fast) 34 * @i2c_spd: required i2c speed mode 35 * 36 * Set the i2c speed mode (standard, high, fast) 37 */ 38 static void set_speed(int i2c_spd) 39 { 40 unsigned int cntl; 41 unsigned int hcnt, lcnt; 42 unsigned int high, low; 43 unsigned int enbl; 44 45 /* to set speed cltr must be disabled */ 46 enbl = readl(&i2c_regs_p->ic_enable); 47 enbl &= ~IC_ENABLE_0B; 48 writel(enbl, &i2c_regs_p->ic_enable); 49 50 51 cntl = (readl(&i2c_regs_p->ic_con) & (~IC_CON_SPD_MSK)); 52 53 switch (i2c_spd) { 54 case IC_SPEED_MODE_MAX: 55 cntl |= IC_CON_SPD_HS; 56 high = MIN_HS_SCL_HIGHTIME; 57 low = MIN_HS_SCL_LOWTIME; 58 break; 59 60 case IC_SPEED_MODE_STANDARD: 61 cntl |= IC_CON_SPD_SS; 62 high = MIN_SS_SCL_HIGHTIME; 63 low = MIN_SS_SCL_LOWTIME; 64 break; 65 66 case IC_SPEED_MODE_FAST: 67 default: 68 cntl |= IC_CON_SPD_FS; 69 high = MIN_FS_SCL_HIGHTIME; 70 low = MIN_FS_SCL_LOWTIME; 71 break; 72 } 73 74 writel(cntl, &i2c_regs_p->ic_con); 75 76 hcnt = (IC_CLK * high) / NANO_TO_MICRO; 77 writel(hcnt, &i2c_regs_p->ic_fs_scl_hcnt); 78 79 lcnt = (IC_CLK * low) / NANO_TO_MICRO; 80 writel(lcnt, &i2c_regs_p->ic_fs_scl_lcnt); 81 82 /* re-enable i2c ctrl back now that speed is set */ 83 enbl |= IC_ENABLE_0B; 84 writel(enbl, &i2c_regs_p->ic_enable); 85 } 86 87 /* 88 * i2c_set_bus_speed - Set the i2c speed 89 * @speed: required i2c speed 90 * 91 * Set the i2c speed. 92 */ 93 void i2c_set_bus_speed(int speed) 94 { 95 if (speed >= I2C_MAX_SPEED) 96 set_speed(IC_SPEED_MODE_MAX); 97 else if (speed >= I2C_FAST_SPEED) 98 set_speed(IC_SPEED_MODE_FAST); 99 else 100 set_speed(IC_SPEED_MODE_STANDARD); 101 } 102 103 /* 104 * i2c_get_bus_speed - Gets the i2c speed 105 * 106 * Gets the i2c speed. 107 */ 108 int i2c_get_bus_speed(void) 109 { 110 u32 cntl; 111 112 cntl = (readl(&i2c_regs_p->ic_con) & IC_CON_SPD_MSK); 113 114 if (cntl == IC_CON_SPD_HS) 115 return I2C_MAX_SPEED; 116 else if (cntl == IC_CON_SPD_FS) 117 return I2C_FAST_SPEED; 118 else if (cntl == IC_CON_SPD_SS) 119 return I2C_STANDARD_SPEED; 120 121 return 0; 122 } 123 124 /* 125 * i2c_init - Init function 126 * @speed: required i2c speed 127 * @slaveadd: slave address for the device 128 * 129 * Initialization function. 130 */ 131 void i2c_init(int speed, int slaveadd) 132 { 133 unsigned int enbl; 134 135 /* Disable i2c */ 136 enbl = readl(&i2c_regs_p->ic_enable); 137 enbl &= ~IC_ENABLE_0B; 138 writel(enbl, &i2c_regs_p->ic_enable); 139 140 writel((IC_CON_SD | IC_CON_SPD_FS | IC_CON_MM), &i2c_regs_p->ic_con); 141 writel(IC_RX_TL, &i2c_regs_p->ic_rx_tl); 142 writel(IC_TX_TL, &i2c_regs_p->ic_tx_tl); 143 i2c_set_bus_speed(speed); 144 writel(IC_STOP_DET, &i2c_regs_p->ic_intr_mask); 145 writel(slaveadd, &i2c_regs_p->ic_sar); 146 147 /* Enable i2c */ 148 enbl = readl(&i2c_regs_p->ic_enable); 149 enbl |= IC_ENABLE_0B; 150 writel(enbl, &i2c_regs_p->ic_enable); 151 } 152 153 /* 154 * i2c_setaddress - Sets the target slave address 155 * @i2c_addr: target i2c address 156 * 157 * Sets the target slave address. 158 */ 159 static void i2c_setaddress(unsigned int i2c_addr) 160 { 161 writel(i2c_addr, &i2c_regs_p->ic_tar); 162 } 163 164 /* 165 * i2c_flush_rxfifo - Flushes the i2c RX FIFO 166 * 167 * Flushes the i2c RX FIFO 168 */ 169 static void i2c_flush_rxfifo(void) 170 { 171 while (readl(&i2c_regs_p->ic_status) & IC_STATUS_RFNE) 172 readl(&i2c_regs_p->ic_cmd_data); 173 } 174 175 /* 176 * i2c_wait_for_bb - Waits for bus busy 177 * 178 * Waits for bus busy 179 */ 180 static int i2c_wait_for_bb(void) 181 { 182 unsigned long start_time_bb = get_timer(0); 183 184 while ((readl(&i2c_regs_p->ic_status) & IC_STATUS_MA) || 185 !(readl(&i2c_regs_p->ic_status) & IC_STATUS_TFE)) { 186 187 /* Evaluate timeout */ 188 if (get_timer(start_time_bb) > (unsigned long)(I2C_BYTE_TO_BB)) 189 return 1; 190 } 191 192 return 0; 193 } 194 195 /* check parameters for i2c_read and i2c_write */ 196 static int check_params(uint addr, int alen, uchar *buffer, int len) 197 { 198 if (buffer == NULL) { 199 printf("Buffer is invalid\n"); 200 return 1; 201 } 202 203 if (alen > 1) { 204 printf("addr len %d not supported\n", alen); 205 return 1; 206 } 207 208 if (addr + len > 256) { 209 printf("address out of range\n"); 210 return 1; 211 } 212 213 return 0; 214 } 215 216 static int i2c_xfer_init(uchar chip, uint addr) 217 { 218 if (i2c_wait_for_bb()) { 219 printf("Timed out waiting for bus\n"); 220 return 1; 221 } 222 223 i2c_setaddress(chip); 224 writel(addr, &i2c_regs_p->ic_cmd_data); 225 226 return 0; 227 } 228 229 static int i2c_xfer_finish(void) 230 { 231 ulong start_stop_det = get_timer(0); 232 233 while (1) { 234 if ((readl(&i2c_regs_p->ic_raw_intr_stat) & IC_STOP_DET)) { 235 readl(&i2c_regs_p->ic_clr_stop_det); 236 break; 237 } else if (get_timer(start_stop_det) > I2C_STOPDET_TO) { 238 break; 239 } 240 } 241 242 if (i2c_wait_for_bb()) { 243 printf("Timed out waiting for bus\n"); 244 return 1; 245 } 246 247 i2c_flush_rxfifo(); 248 249 /* Wait for read/write operation to complete on actual memory */ 250 udelay(10000); 251 252 return 0; 253 } 254 255 /* 256 * i2c_read - Read from i2c memory 257 * @chip: target i2c address 258 * @addr: address to read from 259 * @alen: 260 * @buffer: buffer for read data 261 * @len: no of bytes to be read 262 * 263 * Read from i2c memory. 264 */ 265 int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) 266 { 267 unsigned long start_time_rx; 268 269 if (check_params(addr, alen, buffer, len)) 270 return 1; 271 272 if (i2c_xfer_init(chip, addr)) 273 return 1; 274 275 start_time_rx = get_timer(0); 276 while (len) { 277 writel(IC_CMD, &i2c_regs_p->ic_cmd_data); 278 279 if (readl(&i2c_regs_p->ic_status) & IC_STATUS_RFNE) { 280 *buffer++ = (uchar)readl(&i2c_regs_p->ic_cmd_data); 281 len--; 282 start_time_rx = get_timer(0); 283 284 } else if (get_timer(start_time_rx) > I2C_BYTE_TO) { 285 printf("Timed out. i2c read Failed\n"); 286 return 1; 287 } 288 } 289 290 return i2c_xfer_finish(); 291 } 292 293 /* 294 * i2c_write - Write to i2c memory 295 * @chip: target i2c address 296 * @addr: address to read from 297 * @alen: 298 * @buffer: buffer for read data 299 * @len: no of bytes to be read 300 * 301 * Write to i2c memory. 302 */ 303 int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) 304 { 305 int nb = len; 306 unsigned long start_time_tx; 307 308 if (check_params(addr, alen, buffer, len)) 309 return 1; 310 311 if (i2c_xfer_init(chip, addr)) 312 return 1; 313 314 start_time_tx = get_timer(0); 315 while (len) { 316 if (readl(&i2c_regs_p->ic_status) & IC_STATUS_TFNF) { 317 writel(*buffer, &i2c_regs_p->ic_cmd_data); 318 buffer++; 319 len--; 320 start_time_tx = get_timer(0); 321 322 } else if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) { 323 printf("Timed out. i2c write Failed\n"); 324 return 1; 325 } 326 } 327 328 return i2c_xfer_finish(); 329 } 330 331 /* 332 * i2c_probe - Probe the i2c chip 333 */ 334 int i2c_probe(uchar chip) 335 { 336 u32 tmp; 337 338 /* 339 * Try to read the first location of the chip. 340 */ 341 return i2c_read(chip, 0, 1, (uchar *)&tmp, 1); 342 } 343