1 /* 2 * i2c interface. 3 * Bus should be run at max. 100kHz: see original Philips I2C specification 4 * 5 * Rudolf Cornelissen 12/2002-10/2005 6 */ 7 8 #define MODULE_BIT 0x00004000 9 10 #include "nv_std.h" 11 12 char i2c_flag_error (char ErrNo) 13 //error code list: 14 //0 - OK status 15 //1 - SCL locked low by device (bus is still busy) 16 //2 - SDA locked low by device (bus is still busy) 17 //3 - No Acknowledge from device (no handshake) 18 //4 - SDA not released for master to generate STOP bit 19 { 20 static char I2CError = 0; 21 22 if (!I2CError) I2CError = ErrNo; 23 if (ErrNo == -1) I2CError = 0; 24 return I2CError; 25 } 26 27 static void i2c_select_bus_set(bool set) 28 { 29 /* I/O pins set selection is only valid on dualhead cards */ 30 if (!si->ps.secondary_head) return; 31 32 /* select GPU I/O pins set to connect to I2C 'registers' */ 33 if (set) 34 { 35 NV_REG32(NV32_FUNCSEL) &= ~0x00000010; 36 NV_REG32(NV32_2FUNCSEL) |= 0x00000010; 37 } 38 else 39 { 40 NV_REG32(NV32_2FUNCSEL) &= ~0x00000010; 41 NV_REG32(NV32_FUNCSEL) |= 0x00000010; 42 } 43 } 44 45 static void OutSCL(uint8 BusNR, bool Bit) 46 { 47 uint8 data; 48 49 if (BusNR & 0x01) 50 { 51 data = (CRTCR(WR_I2CBUS_1) & 0xf0) | 0x01; 52 if (Bit) 53 CRTCW(WR_I2CBUS_1, (data | 0x20)); 54 else 55 CRTCW(WR_I2CBUS_1, (data & ~0x20)); 56 } 57 else 58 { 59 data = (CRTCR(WR_I2CBUS_0) & 0xf0) | 0x01; 60 if (Bit) 61 CRTCW(WR_I2CBUS_0, (data | 0x20)); 62 else 63 CRTCW(WR_I2CBUS_0, (data & ~0x20)); 64 } 65 } 66 67 static void OutSDA(uint8 BusNR, bool Bit) 68 { 69 uint8 data; 70 71 if (BusNR & 0x01) 72 { 73 data = (CRTCR(WR_I2CBUS_1) & 0xf0) | 0x01; 74 if (Bit) 75 CRTCW(WR_I2CBUS_1, (data | 0x10)); 76 else 77 CRTCW(WR_I2CBUS_1, (data & ~0x10)); 78 } 79 else 80 { 81 data = (CRTCR(WR_I2CBUS_0) & 0xf0) | 0x01; 82 if (Bit) 83 CRTCW(WR_I2CBUS_0, (data | 0x10)); 84 else 85 CRTCW(WR_I2CBUS_0, (data & ~0x10)); 86 } 87 } 88 89 static bool InSCL(uint8 BusNR) 90 { 91 if (BusNR & 0x01) 92 { 93 if ((CRTCR(RD_I2CBUS_1) & 0x04)) return true; 94 } 95 else 96 { 97 if ((CRTCR(RD_I2CBUS_0) & 0x04)) return true; 98 } 99 100 return false; 101 } 102 103 static bool InSDA(uint8 BusNR) 104 { 105 if (BusNR & 0x01) 106 { 107 if ((CRTCR(RD_I2CBUS_1) & 0x08)) return true; 108 } 109 else 110 { 111 if ((CRTCR(RD_I2CBUS_0) & 0x08)) return true; 112 } 113 114 return false; 115 } 116 117 static void TXBit (uint8 BusNR, bool Bit) 118 { 119 /* send out databit */ 120 if (Bit) 121 { 122 OutSDA(BusNR, true); 123 snooze(3); 124 if (!InSDA(BusNR)) i2c_flag_error (2); 125 } 126 else 127 { 128 OutSDA(BusNR, false); 129 } 130 /* generate clock pulse */ 131 snooze(6); 132 OutSCL(BusNR, true); 133 snooze(3); 134 if (!InSCL(BusNR)) i2c_flag_error (1); 135 snooze(6); 136 OutSCL(BusNR, false); 137 snooze(6); 138 } 139 140 static uint8 RXBit (uint8 BusNR) 141 { 142 uint8 Bit = 0; 143 144 /* set SDA so input is possible */ 145 OutSDA(BusNR, true); 146 /* generate clock pulse */ 147 snooze(6); 148 OutSCL(BusNR, true); 149 snooze(3); 150 if (!InSCL(BusNR)) i2c_flag_error (1); 151 snooze(3); 152 /* read databit */ 153 if (InSDA(BusNR)) Bit = 1; 154 /* finish clockpulse */ 155 OutSCL(BusNR, false); 156 snooze(6); 157 158 return Bit; 159 } 160 161 void i2c_bstart (uint8 BusNR) 162 { 163 /* select GPU I/O pins set */ 164 i2c_select_bus_set(BusNR & 0x02); 165 166 /* enable access to primary head */ 167 set_crtc_owner(0); 168 169 /* make sure SDA is high */ 170 OutSDA(BusNR, true); 171 snooze(3); 172 OutSCL(BusNR, true); 173 snooze(3); 174 if (!InSCL(BusNR)) i2c_flag_error (1); 175 snooze(6); 176 /* clear SDA while SCL set (bus-start condition) */ 177 OutSDA(BusNR, false); 178 snooze(6); 179 OutSCL(BusNR, false); 180 snooze(6); 181 182 LOG(4,("I2C: START condition generated on bus %d; status is %d\n", 183 BusNR, i2c_flag_error (0))); 184 } 185 186 void i2c_bstop (uint8 BusNR) 187 { 188 /* select GPU I/O pins set */ 189 i2c_select_bus_set(BusNR & 0x02); 190 191 /* enable access to primary head */ 192 set_crtc_owner(0); 193 194 /* make sure SDA is low */ 195 OutSDA(BusNR, false); 196 snooze(3); 197 OutSCL(BusNR, true); 198 snooze(3); 199 if (!InSCL(BusNR)) i2c_flag_error (1); 200 snooze(6); 201 /* set SDA while SCL set (bus-stop condition) */ 202 OutSDA(BusNR, true); 203 snooze(3); 204 if (!InSDA(BusNR)) i2c_flag_error (4); 205 snooze(3); 206 207 LOG(4,("I2C: STOP condition generated on bus %d; status is %d\n", 208 BusNR, i2c_flag_error (0))); 209 } 210 211 uint8 i2c_readbyte(uint8 BusNR, bool Ack) 212 { 213 uint8 cnt, bit, byte = 0; 214 215 /* select GPU I/O pins set */ 216 i2c_select_bus_set(BusNR & 0x02); 217 218 /* enable access to primary head */ 219 set_crtc_owner(0); 220 221 /* read data */ 222 for (cnt = 8; cnt > 0; cnt--) 223 { 224 byte <<= 1; 225 bit = RXBit (BusNR); 226 byte += bit; 227 } 228 /* send acknowledge */ 229 TXBit (BusNR, Ack); 230 231 LOG(4,("I2C: read byte ($%02x) from bus #%d; status is %d\n", 232 byte, BusNR, i2c_flag_error(0))); 233 234 return byte; 235 } 236 237 bool i2c_writebyte (uint8 BusNR, uint8 byte) 238 { 239 uint8 cnt; 240 bool bit; 241 uint8 tmp = byte; 242 243 /* select GPU I/O pins set */ 244 i2c_select_bus_set(BusNR & 0x02); 245 246 /* enable access to primary head */ 247 set_crtc_owner(0); 248 249 /* write data */ 250 for (cnt = 8; cnt > 0; cnt--) 251 { 252 bit = (tmp & 0x80); 253 TXBit (BusNR, bit); 254 tmp <<= 1; 255 } 256 /* read acknowledge */ 257 bit = RXBit (BusNR); 258 if (bit) i2c_flag_error (3); 259 260 LOG(4,("I2C: written byte ($%02x) to bus #%d; status is %d\n", 261 byte, BusNR, i2c_flag_error(0))); 262 263 return bit; 264 } 265 266 void i2c_readbuffer (uint8 BusNR, uint8* buf, uint8 size) 267 { 268 uint8 cnt; 269 270 for (cnt = 0; cnt < size; cnt++) 271 { 272 buf[cnt] = i2c_readbyte(BusNR, buf[cnt]); 273 } 274 } 275 276 void i2c_writebuffer (uint8 BusNR, uint8* buf, uint8 size) 277 { 278 uint8 cnt; 279 280 for (cnt = 0; cnt < size; cnt++) 281 { 282 i2c_writebyte(BusNR, buf[cnt]); 283 } 284 } 285 286 status_t i2c_init(void) 287 { 288 uint8 bus, buses; 289 bool *i2c_bus = &(si->ps.i2c_bus0); 290 status_t result = B_ERROR; 291 292 LOG(4,("I2C: searching for wired I2C buses...\n")); 293 294 /* enable access to primary head */ 295 set_crtc_owner(0); 296 297 /* preset no board wired buses */ 298 si->ps.i2c_bus0 = false; 299 si->ps.i2c_bus1 = false; 300 si->ps.i2c_bus2 = false; 301 si->ps.i2c_bus3 = false; 302 303 /* set number of buses to test for */ 304 buses = 2; 305 if (si->ps.secondary_head) buses = 4; 306 307 /* find existing buses */ 308 for (bus = 0; bus < buses; bus++) 309 { 310 /* reset status */ 311 i2c_flag_error (-1); 312 snooze(6); 313 /* init and/or stop I2C bus */ 314 i2c_bstop(bus); 315 /* check for hardware coupling of SCL and SDA -out and -in lines */ 316 snooze(6); 317 OutSCL(bus, false); 318 OutSDA(bus, true); 319 snooze(3); 320 if (InSCL(bus) || !InSDA(bus)) continue; 321 snooze(3); 322 OutSCL(bus, true); 323 OutSDA(bus, false); 324 snooze(3); 325 if (!InSCL(bus) || InSDA(bus)) continue; 326 i2c_bus[bus] = true; 327 snooze(3); 328 /* re-init bus */ 329 i2c_bstop(bus); 330 } 331 332 for (bus = 0; bus < buses; bus++) 333 { 334 if (i2c_bus[bus]) 335 { 336 LOG(4,("I2C: bus #%d wiring check: passed\n", bus)); 337 result = B_OK; 338 } 339 else 340 LOG(4,("I2C: bus #%d wiring check: failed\n", bus)); 341 } 342 343 return result; 344 } 345