1 /* 2 * i2c interface for the G400 MAVEN under BeOS 3 * 4 * Provides I2CR,I2CW - functions to parallel DACW,DACR 5 * Bus should be run at max. 100kHz: see original Philips I2C specification 6 * 7 * Much help was provided by observing the Linux i2c code, 8 * so thanks go to: Gerd Knorr 9 * 10 * Other authors: 11 * Mark Watson 6/2000, 12 * Rudolf Cornelissen 12/2002 13 */ 14 15 #define MODULE_BIT 0x00004000 16 17 #include "mga_std.h" 18 19 /*which device on the bus is the MAVEN?*/ 20 #define MAVEN_WRITE (0x1B<<1) 21 #define MAVEN_READ ((0x1B<<1)|1) 22 23 #define I2C_CLOCK 0x20 24 #define I2C_DATA 0x10 25 26 /* MGA-TVO I2C for G200, G400 */ 27 #define I2C_CLOCK 0x20 28 #define I2C_DATA 0x10 29 /* primary head DDC for Mystique(?), G100, G200, G400 */ 30 #define DDC1_CLK 0x08 31 #define DDC1_DATA 0x02 32 /* primary head DDC for Millennium, Millennium II */ 33 #define DDC1B_CLK 0x10 34 #define DDC1B_DATA 0x04 35 /* secondary head DDC for G400, G450 and G550 */ 36 #define DDC2_CLK 0x04 37 #define DDC2_DATA 0x01 38 39 status_t i2c_sec_tv_adapter() 40 { 41 status_t result = B_ERROR; 42 43 /* The secondary DDC channel only exist on dualhead cards */ 44 if (!si->ps.secondary_head) return result; 45 46 /* make sure the output lines will be active-low when enabled 47 * (they will be pulled 'passive-high' when disabled) */ 48 DXIW(GENIODATA,0x00); 49 /* send out B_STOP condition on secondary head DDC channel and use it to 50 * check for 'shortcut', indicating the Matrox VGA->TV adapter is connected */ 51 52 /* make sure SDA is low */ 53 DXIW(GENIOCTRL, (DXIR(GENIOCTRL) | DDC2_DATA)); 54 snooze(2); 55 /* make sure SCL should be high */ 56 DXIW(GENIOCTRL, (DXIR(GENIOCTRL) & ~DDC2_CLK)); 57 snooze(2); 58 /* if SCL is low then the bus is blocked by a TV adapter */ 59 if (!(DXIR(GENIODATA) & DDC2_CLK)) result = B_OK; 60 snooze(5); 61 /* set SDA while SCL should be set (generates actual bus-stop condition) */ 62 DXIW(GENIOCTRL, (DXIR(GENIOCTRL) & ~DDC2_DATA)); 63 snooze(5); 64 65 return result; 66 } 67 68 /*----------------------------- 69 *low level hardware access 70 */ 71 #define I2C_DELAY 2 72 #define I2C_TIMEOUT 100 73 static int i2c_set_lines(int clock,int data) 74 { 75 int count=0; 76 int program; 77 int required; 78 79 /*work out which bits to zero*/ 80 program = 81 (clock ? 0 : I2C_CLOCK)| 82 (data ? 0 : I2C_DATA); 83 84 /*what value do I require on data lines*/ 85 required = 86 (clock ? I2C_CLOCK : 0); 87 88 /*set the bits to zero*/ 89 DXIW(GENIOCTRL,program); /*drive these bits*/ 90 DXIW(GENIODATA,0x00); /*to zero*/ 91 92 /*wait a bit*/ 93 delay(I2C_DELAY); 94 95 /*loop until the clock is as required*/ 96 while ((DXIR(GENIODATA)&I2C_CLOCK)!=required) 97 { 98 delay(I2C_DELAY); 99 count++; 100 if (count>I2C_TIMEOUT) 101 { 102 LOG(8,("I2C: Timeout on set lines - clock:%d data:%d actual:%x\n",clock,data,DXIR(GENIODATA))); 103 return -1; 104 } 105 } 106 107 return 0; 108 } 109 110 static int i2c_get_data() 111 { 112 int data; 113 int clock; 114 int count=0; 115 116 do 117 { 118 /*read the data and clock lines*/ 119 data = DXIR(GENIODATA); 120 clock = (data&I2C_CLOCK) ? 1 : 0; 121 data = (data&I2C_DATA) ? 1 : 0; 122 123 /*manage timeout*/ 124 count++; 125 if (count>I2C_TIMEOUT) 126 { 127 return -1; 128 } 129 130 /*wait a bit, so not hammering bus*/ 131 delay(I2C_DELAY); 132 133 }while (!clock); /*wait for high clock*/ 134 135 return data; 136 } 137 138 139 /*----------------------- 140 *Standard I2C operations 141 */ 142 static void i2c_start() 143 { 144 int error=0; 145 146 error+= i2c_set_lines(0,1); 147 error+= i2c_set_lines(1,1); 148 error+= i2c_set_lines(1,0); 149 error+= i2c_set_lines(0,0); 150 151 if (error) 152 { 153 LOG(8,("I2C: start - %d\n",error)); 154 } 155 } 156 157 static void i2c_stop() 158 { 159 int error=0; 160 161 error+= i2c_set_lines(0,0); 162 error+= i2c_set_lines(1,0); 163 error+= i2c_set_lines(1,1); 164 error+= i2c_set_lines(0,1); 165 166 if (error) 167 { 168 LOG(8,("I2C: stop - %d\n",error)); 169 } 170 } 171 172 static void i2c_high() 173 { 174 int error=0; 175 176 error+= i2c_set_lines(0,1); 177 error+= i2c_set_lines(1,1); 178 error+= i2c_set_lines(0,1); 179 180 if (error) 181 { 182 LOG(8,("I2C: high - %d\n",error)); 183 } 184 } 185 186 static void i2c_low() 187 { 188 int error=0; 189 190 error+= i2c_set_lines(0,0); 191 error+= i2c_set_lines(1,0); 192 error+= i2c_set_lines(0,0); 193 194 if (error) 195 { 196 LOG(8,("I2C: low - %d\n",error)); 197 } 198 } 199 200 static int i2c_get_ack() 201 { 202 int error=0; 203 int ack; 204 205 error+= i2c_set_lines(0,1); 206 error+= i2c_set_lines(1,1); 207 ack = i2c_get_data(); 208 error+= i2c_set_lines(0,1); 209 210 if (error) 211 { 212 LOG(8,("I2C: get_ack - %d value:%x\n",error,ack)); 213 } 214 215 return ack; 216 } 217 218 static void i2c_send_ack() 219 { 220 int error=0; 221 222 error+= i2c_set_lines(0,0); 223 error+= i2c_set_lines(1,0); 224 error+= i2c_set_lines(0,0); 225 226 if (error) 227 { 228 LOG(8,("I2C: send_ack - %d\n",error)); 229 } 230 } 231 232 /*------------------------------ 233 *use above functions to send and receive bytes 234 */ 235 236 static int i2c_sendbyte(unsigned char data) 237 { 238 int i; 239 240 for (i=7; i>=0; i--) 241 { 242 if (data&(1<<i)) 243 { 244 i2c_high(); 245 } 246 else 247 { 248 i2c_low(); 249 } 250 } 251 252 return i2c_get_ack(); 253 } 254 255 static unsigned char i2c_readbyte(int ack_required) 256 { 257 int i; 258 unsigned char data=0; 259 260 /*read data*/ 261 i2c_set_lines(0,1); 262 for (i=7; i>=0; i--) 263 { 264 i2c_set_lines(1,1); 265 if (i2c_get_data()==1) 266 data |= (1<<i); 267 i2c_set_lines(0,1); 268 } 269 270 /*send acknowledge*/ 271 if (ack_required) i2c_send_ack(); 272 273 return data; 274 } 275 276 /*------------------------------------------- 277 *PUBLIC functions 278 */ 279 int i2c_maven_read(unsigned char address) 280 { 281 int error=0; 282 int data; 283 284 i2c_start(); 285 { 286 error+=i2c_sendbyte(MAVEN_READ); 287 error+=i2c_sendbyte(address); 288 data = i2c_readbyte(0); 289 } 290 i2c_stop(); 291 if (error>0) LOG(8,("I2C: MAVR ERROR - %x\n",error)); 292 return data; 293 } 294 295 void i2c_maven_write(unsigned char address, unsigned char data) 296 { 297 int error=0; 298 299 i2c_start(); 300 { 301 error+=i2c_sendbyte(MAVEN_WRITE); 302 error+=i2c_sendbyte(address); 303 error+=i2c_sendbyte(data); 304 } 305 i2c_stop(); 306 if (error>0) LOG(8,("I2C: MAVW ERROR - %x\n",error)); 307 } 308 309 status_t i2c_init(void) 310 { 311 /*init g400 i2c*/ 312 DXIW(GENIODATA,0x00); /*to zero*/ 313 DXIW(GENIOCTRL,0x30); /*drive clock and data*/ 314 DXIW(GENIOCTRL,0x00); /*stop driving*/ 315 316 return B_OK; 317 } 318 319 status_t i2c_maven_probe(void) 320 { 321 int ack; 322 323 /*scan the bus for the MAVEN*/ 324 i2c_start(); 325 { 326 ack = i2c_sendbyte(MAVEN_READ); 327 } 328 i2c_stop(); 329 if (ack==0) 330 { 331 return B_OK; 332 } 333 else 334 { 335 return B_ERROR; 336 } 337 } 338