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