1/* 2 * Bootloader version of the i2c driver for the MV64x60. 3 * 4 * Author: Dale Farnsworth <dfarnsworth@mvista.com> 5 * Maintained by: Mark A. Greer <mgreer@mvista.com> 6 * 7 * 2003, 2007 (c) MontaVista, Software, Inc. This file is licensed under 8 * the terms of the GNU General Public License version 2. This program is 9 * licensed "as is" without any warranty of any kind, whether express or 10 * implied. 11 */ 12 13#include <stdarg.h> 14#include <stddef.h> 15#include "types.h" 16#include "elf.h" 17#include "page.h" 18#include "string.h" 19#include "stdio.h" 20#include "io.h" 21#include "ops.h" 22#include "mv64x60.h" 23 24extern void udelay(long); 25 26/* Register defines */ 27#define MV64x60_I2C_REG_SLAVE_ADDR 0x00 28#define MV64x60_I2C_REG_DATA 0x04 29#define MV64x60_I2C_REG_CONTROL 0x08 30#define MV64x60_I2C_REG_STATUS 0x0c 31#define MV64x60_I2C_REG_BAUD 0x0c 32#define MV64x60_I2C_REG_EXT_SLAVE_ADDR 0x10 33#define MV64x60_I2C_REG_SOFT_RESET 0x1c 34 35#define MV64x60_I2C_CONTROL_ACK 0x04 36#define MV64x60_I2C_CONTROL_IFLG 0x08 37#define MV64x60_I2C_CONTROL_STOP 0x10 38#define MV64x60_I2C_CONTROL_START 0x20 39#define MV64x60_I2C_CONTROL_TWSIEN 0x40 40#define MV64x60_I2C_CONTROL_INTEN 0x80 41 42#define MV64x60_I2C_STATUS_BUS_ERR 0x00 43#define MV64x60_I2C_STATUS_MAST_START 0x08 44#define MV64x60_I2C_STATUS_MAST_REPEAT_START 0x10 45#define MV64x60_I2C_STATUS_MAST_WR_ADDR_ACK 0x18 46#define MV64x60_I2C_STATUS_MAST_WR_ADDR_NO_ACK 0x20 47#define MV64x60_I2C_STATUS_MAST_WR_ACK 0x28 48#define MV64x60_I2C_STATUS_MAST_WR_NO_ACK 0x30 49#define MV64x60_I2C_STATUS_MAST_LOST_ARB 0x38 50#define MV64x60_I2C_STATUS_MAST_RD_ADDR_ACK 0x40 51#define MV64x60_I2C_STATUS_MAST_RD_ADDR_NO_ACK 0x48 52#define MV64x60_I2C_STATUS_MAST_RD_DATA_ACK 0x50 53#define MV64x60_I2C_STATUS_MAST_RD_DATA_NO_ACK 0x58 54#define MV64x60_I2C_STATUS_MAST_WR_ADDR_2_ACK 0xd0 55#define MV64x60_I2C_STATUS_MAST_WR_ADDR_2_NO_ACK 0xd8 56#define MV64x60_I2C_STATUS_MAST_RD_ADDR_2_ACK 0xe0 57#define MV64x60_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK 0xe8 58#define MV64x60_I2C_STATUS_NO_STATUS 0xf8 59 60static u8 *ctlr_base; 61 62static int mv64x60_i2c_wait_for_status(int wanted) 63{ 64 int i; 65 int status; 66 67 for (i=0; i<1000; i++) { 68 udelay(10); 69 status = in_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_STATUS)) 70 & 0xff; 71 if (status == wanted) 72 return status; 73 } 74 return -status; 75} 76 77static int mv64x60_i2c_control(int control, int status) 78{ 79 out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_CONTROL), control & 0xff); 80 return mv64x60_i2c_wait_for_status(status); 81} 82 83static int mv64x60_i2c_read_byte(int control, int status) 84{ 85 out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_CONTROL), control & 0xff); 86 if (mv64x60_i2c_wait_for_status(status) < 0) 87 return -1; 88 return in_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_DATA)) & 0xff; 89} 90 91static int mv64x60_i2c_write_byte(int data, int control, int status) 92{ 93 out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_DATA), data & 0xff); 94 out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_CONTROL), control & 0xff); 95 return mv64x60_i2c_wait_for_status(status); 96} 97 98int mv64x60_i2c_read(u32 devaddr, u8 *buf, u32 offset, u32 offset_size, 99 u32 count) 100{ 101 int i; 102 int data; 103 int control; 104 int status; 105 106 if (ctlr_base == NULL) 107 return -1; 108 109 /* send reset */ 110 out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_SOFT_RESET), 0); 111 out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_SLAVE_ADDR), 0); 112 out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_EXT_SLAVE_ADDR), 0); 113 out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_BAUD), (4 << 3) | 0x4); 114 115 if (mv64x60_i2c_control(MV64x60_I2C_CONTROL_TWSIEN, 116 MV64x60_I2C_STATUS_NO_STATUS) < 0) 117 return -1; 118 119 /* send start */ 120 control = MV64x60_I2C_CONTROL_START | MV64x60_I2C_CONTROL_TWSIEN; 121 status = MV64x60_I2C_STATUS_MAST_START; 122 if (mv64x60_i2c_control(control, status) < 0) 123 return -1; 124 125 /* select device for writing */ 126 data = devaddr & ~0x1; 127 control = MV64x60_I2C_CONTROL_TWSIEN; 128 status = MV64x60_I2C_STATUS_MAST_WR_ADDR_ACK; 129 if (mv64x60_i2c_write_byte(data, control, status) < 0) 130 return -1; 131 132 /* send offset of data */ 133 control = MV64x60_I2C_CONTROL_TWSIEN; 134 status = MV64x60_I2C_STATUS_MAST_WR_ACK; 135 if (offset_size > 1) { 136 if (mv64x60_i2c_write_byte(offset >> 8, control, status) < 0) 137 return -1; 138 } 139 if (mv64x60_i2c_write_byte(offset, control, status) < 0) 140 return -1; 141 142 /* resend start */ 143 control = MV64x60_I2C_CONTROL_START | MV64x60_I2C_CONTROL_TWSIEN; 144 status = MV64x60_I2C_STATUS_MAST_REPEAT_START; 145 if (mv64x60_i2c_control(control, status) < 0) 146 return -1; 147 148 /* select device for reading */ 149 data = devaddr | 0x1; 150 control = MV64x60_I2C_CONTROL_TWSIEN; 151 status = MV64x60_I2C_STATUS_MAST_RD_ADDR_ACK; 152 if (mv64x60_i2c_write_byte(data, control, status) < 0) 153 return -1; 154 155 /* read all but last byte of data */ 156 control = MV64x60_I2C_CONTROL_ACK | MV64x60_I2C_CONTROL_TWSIEN; 157 status = MV64x60_I2C_STATUS_MAST_RD_DATA_ACK; 158 159 for (i=1; i<count; i++) { 160 data = mv64x60_i2c_read_byte(control, status); 161 if (data < 0) { 162 printf("errors on iteration %d\n", i); 163 return -1; 164 } 165 *buf++ = data; 166 } 167 168 /* read last byte of data */ 169 control = MV64x60_I2C_CONTROL_TWSIEN; 170 status = MV64x60_I2C_STATUS_MAST_RD_DATA_NO_ACK; 171 data = mv64x60_i2c_read_byte(control, status); 172 if (data < 0) 173 return -1; 174 *buf++ = data; 175 176 /* send stop */ 177 control = MV64x60_I2C_CONTROL_STOP | MV64x60_I2C_CONTROL_TWSIEN; 178 status = MV64x60_I2C_STATUS_NO_STATUS; 179 if (mv64x60_i2c_control(control, status) < 0) 180 return -1; 181 182 return count; 183} 184 185int mv64x60_i2c_open(void) 186{ 187 u32 v; 188 void *devp; 189 190 devp = finddevice("/mv64x60/i2c"); 191 if (devp == NULL) 192 goto err_out; 193 if (getprop(devp, "virtual-reg", &v, sizeof(v)) != sizeof(v)) 194 goto err_out; 195 196 ctlr_base = (u8 *)v; 197 return 0; 198 199err_out: 200 return -1; 201} 202 203void mv64x60_i2c_close(void) 204{ 205 ctlr_base = NULL; 206} 207