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 24/* Register defines */ 25#define MV64x60_I2C_REG_SLAVE_ADDR 0x00 26#define MV64x60_I2C_REG_DATA 0x04 27#define MV64x60_I2C_REG_CONTROL 0x08 28#define MV64x60_I2C_REG_STATUS 0x0c 29#define MV64x60_I2C_REG_BAUD 0x0c 30#define MV64x60_I2C_REG_EXT_SLAVE_ADDR 0x10 31#define MV64x60_I2C_REG_SOFT_RESET 0x1c 32 33#define MV64x60_I2C_CONTROL_ACK 0x04 34#define MV64x60_I2C_CONTROL_IFLG 0x08 35#define MV64x60_I2C_CONTROL_STOP 0x10 36#define MV64x60_I2C_CONTROL_START 0x20 37#define MV64x60_I2C_CONTROL_TWSIEN 0x40 38#define MV64x60_I2C_CONTROL_INTEN 0x80 39 40#define MV64x60_I2C_STATUS_BUS_ERR 0x00 41#define MV64x60_I2C_STATUS_MAST_START 0x08 42#define MV64x60_I2C_STATUS_MAST_REPEAT_START 0x10 43#define MV64x60_I2C_STATUS_MAST_WR_ADDR_ACK 0x18 44#define MV64x60_I2C_STATUS_MAST_WR_ADDR_NO_ACK 0x20 45#define MV64x60_I2C_STATUS_MAST_WR_ACK 0x28 46#define MV64x60_I2C_STATUS_MAST_WR_NO_ACK 0x30 47#define MV64x60_I2C_STATUS_MAST_LOST_ARB 0x38 48#define MV64x60_I2C_STATUS_MAST_RD_ADDR_ACK 0x40 49#define MV64x60_I2C_STATUS_MAST_RD_ADDR_NO_ACK 0x48 50#define MV64x60_I2C_STATUS_MAST_RD_DATA_ACK 0x50 51#define MV64x60_I2C_STATUS_MAST_RD_DATA_NO_ACK 0x58 52#define MV64x60_I2C_STATUS_MAST_WR_ADDR_2_ACK 0xd0 53#define MV64x60_I2C_STATUS_MAST_WR_ADDR_2_NO_ACK 0xd8 54#define MV64x60_I2C_STATUS_MAST_RD_ADDR_2_ACK 0xe0 55#define MV64x60_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK 0xe8 56#define MV64x60_I2C_STATUS_NO_STATUS 0xf8 57 58static u8 *ctlr_base; 59 60static int mv64x60_i2c_wait_for_status(int wanted) 61{ 62 int i; 63 int status; 64 65 for (i=0; i<1000; i++) { 66 udelay(10); 67 status = in_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_STATUS)) 68 & 0xff; 69 if (status == wanted) 70 return status; 71 } 72 return -status; 73} 74 75static int mv64x60_i2c_control(int control, int status) 76{ 77 out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_CONTROL), control & 0xff); 78 return mv64x60_i2c_wait_for_status(status); 79} 80 81static int mv64x60_i2c_read_byte(int control, int status) 82{ 83 out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_CONTROL), control & 0xff); 84 if (mv64x60_i2c_wait_for_status(status) < 0) 85 return -1; 86 return in_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_DATA)) & 0xff; 87} 88 89static int mv64x60_i2c_write_byte(int data, int control, int status) 90{ 91 out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_DATA), data & 0xff); 92 out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_CONTROL), control & 0xff); 93 return mv64x60_i2c_wait_for_status(status); 94} 95 96int mv64x60_i2c_read(u32 devaddr, u8 *buf, u32 offset, u32 offset_size, 97 u32 count) 98{ 99 int i; 100 int data; 101 int control; 102 int status; 103 104 if (ctlr_base == NULL) 105 return -1; 106 107 /* send reset */ 108 out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_SOFT_RESET), 0); 109 out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_SLAVE_ADDR), 0); 110 out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_EXT_SLAVE_ADDR), 0); 111 out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_BAUD), (4 << 3) | 0x4); 112 113 if (mv64x60_i2c_control(MV64x60_I2C_CONTROL_TWSIEN, 114 MV64x60_I2C_STATUS_NO_STATUS) < 0) 115 return -1; 116 117 /* send start */ 118 control = MV64x60_I2C_CONTROL_START | MV64x60_I2C_CONTROL_TWSIEN; 119 status = MV64x60_I2C_STATUS_MAST_START; 120 if (mv64x60_i2c_control(control, status) < 0) 121 return -1; 122 123 /* select device for writing */ 124 data = devaddr & ~0x1; 125 control = MV64x60_I2C_CONTROL_TWSIEN; 126 status = MV64x60_I2C_STATUS_MAST_WR_ADDR_ACK; 127 if (mv64x60_i2c_write_byte(data, control, status) < 0) 128 return -1; 129 130 /* send offset of data */ 131 control = MV64x60_I2C_CONTROL_TWSIEN; 132 status = MV64x60_I2C_STATUS_MAST_WR_ACK; 133 if (offset_size > 1) { 134 if (mv64x60_i2c_write_byte(offset >> 8, control, status) < 0) 135 return -1; 136 } 137 if (mv64x60_i2c_write_byte(offset, control, status) < 0) 138 return -1; 139 140 /* resend start */ 141 control = MV64x60_I2C_CONTROL_START | MV64x60_I2C_CONTROL_TWSIEN; 142 status = MV64x60_I2C_STATUS_MAST_REPEAT_START; 143 if (mv64x60_i2c_control(control, status) < 0) 144 return -1; 145 146 /* select device for reading */ 147 data = devaddr | 0x1; 148 control = MV64x60_I2C_CONTROL_TWSIEN; 149 status = MV64x60_I2C_STATUS_MAST_RD_ADDR_ACK; 150 if (mv64x60_i2c_write_byte(data, control, status) < 0) 151 return -1; 152 153 /* read all but last byte of data */ 154 control = MV64x60_I2C_CONTROL_ACK | MV64x60_I2C_CONTROL_TWSIEN; 155 status = MV64x60_I2C_STATUS_MAST_RD_DATA_ACK; 156 157 for (i=1; i<count; i++) { 158 data = mv64x60_i2c_read_byte(control, status); 159 if (data < 0) { 160 printf("errors on iteration %d\n", i); 161 return -1; 162 } 163 *buf++ = data; 164 } 165 166 /* read last byte of data */ 167 control = MV64x60_I2C_CONTROL_TWSIEN; 168 status = MV64x60_I2C_STATUS_MAST_RD_DATA_NO_ACK; 169 data = mv64x60_i2c_read_byte(control, status); 170 if (data < 0) 171 return -1; 172 *buf++ = data; 173 174 /* send stop */ 175 control = MV64x60_I2C_CONTROL_STOP | MV64x60_I2C_CONTROL_TWSIEN; 176 status = MV64x60_I2C_STATUS_NO_STATUS; 177 if (mv64x60_i2c_control(control, status) < 0) 178 return -1; 179 180 return count; 181} 182 183int mv64x60_i2c_open(void) 184{ 185 u32 v; 186 void *devp; 187 188 devp = find_node_by_compatible(NULL, "marvell,mv64360-i2c"); 189 if (devp == NULL) 190 goto err_out; 191 if (getprop(devp, "virtual-reg", &v, sizeof(v)) != sizeof(v)) 192 goto err_out; 193 194 ctlr_base = (u8 *)v; 195 return 0; 196 197err_out: 198 return -1; 199} 200 201void mv64x60_i2c_close(void) 202{ 203 ctlr_base = NULL; 204} 205