1091b52d5Sshatty /*
2091b52d5Sshatty * i2c interface for the G400 MAVEN under BeOS
3091b52d5Sshatty *
4091b52d5Sshatty * Provides I2CR,I2CW - functions to parallel DACW,DACR
5f36d53a4Sshatty * Bus should be run at max. 100kHz: see original Philips I2C specification
6091b52d5Sshatty *
7091b52d5Sshatty * Much help was provided by observing the Linux i2c code,
8091b52d5Sshatty * so thanks go to: Gerd Knorr
9f36d53a4Sshatty *
10f36d53a4Sshatty * Other authors:
11f36d53a4Sshatty * Mark Watson 6/2000,
12f36d53a4Sshatty * Rudolf Cornelissen 12/2002
13091b52d5Sshatty */
14f36d53a4Sshatty
15091b52d5Sshatty #define MODULE_BIT 0x00004000
16091b52d5Sshatty
17091b52d5Sshatty #include "mga_std.h"
18091b52d5Sshatty
19091b52d5Sshatty /*which device on the bus is the MAVEN?*/
20091b52d5Sshatty #define MAVEN_WRITE (0x1B<<1)
21091b52d5Sshatty #define MAVEN_READ ((0x1B<<1)|1)
22091b52d5Sshatty
23091b52d5Sshatty #define I2C_CLOCK 0x20
24091b52d5Sshatty #define I2C_DATA 0x10
25091b52d5Sshatty
26f36d53a4Sshatty /* MGA-TVO I2C for G200, G400 */
27f36d53a4Sshatty #define I2C_CLOCK 0x20
28f36d53a4Sshatty #define I2C_DATA 0x10
29f36d53a4Sshatty /* primary head DDC for Mystique(?), G100, G200, G400 */
30f36d53a4Sshatty #define DDC1_CLK 0x08
31f36d53a4Sshatty #define DDC1_DATA 0x02
32f36d53a4Sshatty /* primary head DDC for Millennium, Millennium II */
33f36d53a4Sshatty #define DDC1B_CLK 0x10
34f36d53a4Sshatty #define DDC1B_DATA 0x04
35f36d53a4Sshatty /* secondary head DDC for G400, G450 and G550 */
36f36d53a4Sshatty #define DDC2_CLK 0x04
37f36d53a4Sshatty #define DDC2_DATA 0x01
38f36d53a4Sshatty
i2c_sec_tv_adapter()39f36d53a4Sshatty status_t i2c_sec_tv_adapter()
40f36d53a4Sshatty {
41f36d53a4Sshatty status_t result = B_ERROR;
42f36d53a4Sshatty
43f36d53a4Sshatty /* The secondary DDC channel only exist on dualhead cards */
44f36d53a4Sshatty if (!si->ps.secondary_head) return result;
45f36d53a4Sshatty
46f36d53a4Sshatty /* make sure the output lines will be active-low when enabled
47f36d53a4Sshatty * (they will be pulled 'passive-high' when disabled) */
48f36d53a4Sshatty DXIW(GENIODATA,0x00);
49f36d53a4Sshatty /* send out B_STOP condition on secondary head DDC channel and use it to
50f36d53a4Sshatty * check for 'shortcut', indicating the Matrox VGA->TV adapter is connected */
51f36d53a4Sshatty
52f36d53a4Sshatty /* make sure SDA is low */
53f36d53a4Sshatty DXIW(GENIOCTRL, (DXIR(GENIOCTRL) | DDC2_DATA));
54f36d53a4Sshatty snooze(2);
55f36d53a4Sshatty /* make sure SCL should be high */
56f36d53a4Sshatty DXIW(GENIOCTRL, (DXIR(GENIOCTRL) & ~DDC2_CLK));
57f36d53a4Sshatty snooze(2);
58f36d53a4Sshatty /* if SCL is low then the bus is blocked by a TV adapter */
59f36d53a4Sshatty if (!(DXIR(GENIODATA) & DDC2_CLK)) result = B_OK;
60f36d53a4Sshatty snooze(5);
61f36d53a4Sshatty /* set SDA while SCL should be set (generates actual bus-stop condition) */
62f36d53a4Sshatty DXIW(GENIOCTRL, (DXIR(GENIOCTRL) & ~DDC2_DATA));
63f36d53a4Sshatty snooze(5);
64f36d53a4Sshatty
65f36d53a4Sshatty return result;
66f36d53a4Sshatty }
67f36d53a4Sshatty
68091b52d5Sshatty /*-----------------------------
69091b52d5Sshatty *low level hardware access
70091b52d5Sshatty */
71091b52d5Sshatty #define I2C_DELAY 2
72091b52d5Sshatty #define I2C_TIMEOUT 100
i2c_set_lines(int clock,int data)73*39ba57a9Sshatty static int i2c_set_lines(int clock,int data)
74091b52d5Sshatty {
75091b52d5Sshatty int count=0;
76091b52d5Sshatty int program;
77091b52d5Sshatty int required;
78091b52d5Sshatty
79091b52d5Sshatty /*work out which bits to zero*/
80091b52d5Sshatty program =
81091b52d5Sshatty (clock ? 0 : I2C_CLOCK)|
82091b52d5Sshatty (data ? 0 : I2C_DATA);
83091b52d5Sshatty
84091b52d5Sshatty /*what value do I require on data lines*/
85091b52d5Sshatty required =
86091b52d5Sshatty (clock ? I2C_CLOCK : 0);
87091b52d5Sshatty
88091b52d5Sshatty /*set the bits to zero*/
89091b52d5Sshatty DXIW(GENIOCTRL,program); /*drive these bits*/
90091b52d5Sshatty DXIW(GENIODATA,0x00); /*to zero*/
91091b52d5Sshatty
92091b52d5Sshatty /*wait a bit*/
93091b52d5Sshatty delay(I2C_DELAY);
94091b52d5Sshatty
95091b52d5Sshatty /*loop until the clock is as required*/
96091b52d5Sshatty while ((DXIR(GENIODATA)&I2C_CLOCK)!=required)
97091b52d5Sshatty {
98091b52d5Sshatty delay(I2C_DELAY);
99091b52d5Sshatty count++;
100091b52d5Sshatty if (count>I2C_TIMEOUT)
101091b52d5Sshatty {
102091b52d5Sshatty LOG(8,("I2C: Timeout on set lines - clock:%d data:%d actual:%x\n",clock,data,DXIR(GENIODATA)));
103091b52d5Sshatty return -1;
104091b52d5Sshatty }
105091b52d5Sshatty }
106091b52d5Sshatty
107091b52d5Sshatty return 0;
108091b52d5Sshatty }
109091b52d5Sshatty
i2c_get_data()110*39ba57a9Sshatty static int i2c_get_data()
111091b52d5Sshatty {
112091b52d5Sshatty int data;
113091b52d5Sshatty int clock;
114091b52d5Sshatty int count=0;
115091b52d5Sshatty
116091b52d5Sshatty do
117091b52d5Sshatty {
118091b52d5Sshatty /*read the data and clock lines*/
119091b52d5Sshatty data = DXIR(GENIODATA);
120091b52d5Sshatty clock = (data&I2C_CLOCK) ? 1 : 0;
121091b52d5Sshatty data = (data&I2C_DATA) ? 1 : 0;
122091b52d5Sshatty
123091b52d5Sshatty /*manage timeout*/
124091b52d5Sshatty count++;
125091b52d5Sshatty if (count>I2C_TIMEOUT)
126091b52d5Sshatty {
127091b52d5Sshatty return -1;
128091b52d5Sshatty }
129091b52d5Sshatty
130091b52d5Sshatty /*wait a bit, so not hammering bus*/
131091b52d5Sshatty delay(I2C_DELAY);
132091b52d5Sshatty
133091b52d5Sshatty }while (!clock); /*wait for high clock*/
134091b52d5Sshatty
135091b52d5Sshatty return data;
136091b52d5Sshatty }
137091b52d5Sshatty
138091b52d5Sshatty
139091b52d5Sshatty /*-----------------------
140091b52d5Sshatty *Standard I2C operations
141091b52d5Sshatty */
i2c_start()142*39ba57a9Sshatty static void i2c_start()
143091b52d5Sshatty {
144091b52d5Sshatty int error=0;
145091b52d5Sshatty
146091b52d5Sshatty error+= i2c_set_lines(0,1);
147091b52d5Sshatty error+= i2c_set_lines(1,1);
148091b52d5Sshatty error+= i2c_set_lines(1,0);
149091b52d5Sshatty error+= i2c_set_lines(0,0);
150091b52d5Sshatty
151091b52d5Sshatty if (error)
152091b52d5Sshatty {
153091b52d5Sshatty LOG(8,("I2C: start - %d\n",error));
154091b52d5Sshatty }
155091b52d5Sshatty }
156091b52d5Sshatty
i2c_stop()157*39ba57a9Sshatty static void i2c_stop()
158091b52d5Sshatty {
159091b52d5Sshatty int error=0;
160091b52d5Sshatty
161091b52d5Sshatty error+= i2c_set_lines(0,0);
162091b52d5Sshatty error+= i2c_set_lines(1,0);
163091b52d5Sshatty error+= i2c_set_lines(1,1);
164091b52d5Sshatty error+= i2c_set_lines(0,1);
165091b52d5Sshatty
166091b52d5Sshatty if (error)
167091b52d5Sshatty {
168091b52d5Sshatty LOG(8,("I2C: stop - %d\n",error));
169091b52d5Sshatty }
170091b52d5Sshatty }
171091b52d5Sshatty
i2c_high()172*39ba57a9Sshatty static void i2c_high()
173091b52d5Sshatty {
174091b52d5Sshatty int error=0;
175091b52d5Sshatty
176091b52d5Sshatty error+= i2c_set_lines(0,1);
177091b52d5Sshatty error+= i2c_set_lines(1,1);
178091b52d5Sshatty error+= i2c_set_lines(0,1);
179091b52d5Sshatty
180091b52d5Sshatty if (error)
181091b52d5Sshatty {
182091b52d5Sshatty LOG(8,("I2C: high - %d\n",error));
183091b52d5Sshatty }
184091b52d5Sshatty }
185091b52d5Sshatty
i2c_low()186*39ba57a9Sshatty static void i2c_low()
187091b52d5Sshatty {
188091b52d5Sshatty int error=0;
189091b52d5Sshatty
190091b52d5Sshatty error+= i2c_set_lines(0,0);
191091b52d5Sshatty error+= i2c_set_lines(1,0);
192091b52d5Sshatty error+= i2c_set_lines(0,0);
193091b52d5Sshatty
194091b52d5Sshatty if (error)
195091b52d5Sshatty {
196091b52d5Sshatty LOG(8,("I2C: low - %d\n",error));
197091b52d5Sshatty }
198091b52d5Sshatty }
199091b52d5Sshatty
i2c_get_ack()200*39ba57a9Sshatty static int i2c_get_ack()
201091b52d5Sshatty {
202091b52d5Sshatty int error=0;
203091b52d5Sshatty int ack;
204091b52d5Sshatty
205091b52d5Sshatty error+= i2c_set_lines(0,1);
206091b52d5Sshatty error+= i2c_set_lines(1,1);
207091b52d5Sshatty ack = i2c_get_data();
208091b52d5Sshatty error+= i2c_set_lines(0,1);
209091b52d5Sshatty
210091b52d5Sshatty if (error)
211091b52d5Sshatty {
212091b52d5Sshatty LOG(8,("I2C: get_ack - %d value:%x\n",error,ack));
213091b52d5Sshatty }
214091b52d5Sshatty
215091b52d5Sshatty return ack;
216091b52d5Sshatty }
217091b52d5Sshatty
i2c_send_ack()218*39ba57a9Sshatty static void i2c_send_ack()
219091b52d5Sshatty {
220091b52d5Sshatty int error=0;
221091b52d5Sshatty
222091b52d5Sshatty error+= i2c_set_lines(0,0);
223091b52d5Sshatty error+= i2c_set_lines(1,0);
224091b52d5Sshatty error+= i2c_set_lines(0,0);
225091b52d5Sshatty
226091b52d5Sshatty if (error)
227091b52d5Sshatty {
228091b52d5Sshatty LOG(8,("I2C: send_ack - %d\n",error));
229091b52d5Sshatty }
230091b52d5Sshatty }
231091b52d5Sshatty
232091b52d5Sshatty /*------------------------------
233091b52d5Sshatty *use above functions to send and receive bytes
234091b52d5Sshatty */
235091b52d5Sshatty
i2c_sendbyte(unsigned char data)236*39ba57a9Sshatty static int i2c_sendbyte(unsigned char data)
237091b52d5Sshatty {
238091b52d5Sshatty int i;
239091b52d5Sshatty
240091b52d5Sshatty for (i=7; i>=0; i--)
241091b52d5Sshatty {
242091b52d5Sshatty if (data&(1<<i))
243091b52d5Sshatty {
244091b52d5Sshatty i2c_high();
245091b52d5Sshatty }
246091b52d5Sshatty else
247091b52d5Sshatty {
248091b52d5Sshatty i2c_low();
249091b52d5Sshatty }
250091b52d5Sshatty }
251091b52d5Sshatty
252091b52d5Sshatty return i2c_get_ack();
253091b52d5Sshatty }
254091b52d5Sshatty
i2c_readbyte(int ack_required)255*39ba57a9Sshatty static unsigned char i2c_readbyte(int ack_required)
256091b52d5Sshatty {
257091b52d5Sshatty int i;
258091b52d5Sshatty unsigned char data=0;
259091b52d5Sshatty
260091b52d5Sshatty /*read data*/
261091b52d5Sshatty i2c_set_lines(0,1);
262091b52d5Sshatty for (i=7; i>=0; i--)
263091b52d5Sshatty {
264091b52d5Sshatty i2c_set_lines(1,1);
265091b52d5Sshatty if (i2c_get_data()==1)
266091b52d5Sshatty data |= (1<<i);
267091b52d5Sshatty i2c_set_lines(0,1);
268091b52d5Sshatty }
269091b52d5Sshatty
270091b52d5Sshatty /*send acknowledge*/
271091b52d5Sshatty if (ack_required) i2c_send_ack();
272091b52d5Sshatty
273091b52d5Sshatty return data;
274091b52d5Sshatty }
275091b52d5Sshatty
276091b52d5Sshatty /*-------------------------------------------
277091b52d5Sshatty *PUBLIC functions
278091b52d5Sshatty */
i2c_maven_read(unsigned char address)279091b52d5Sshatty int i2c_maven_read(unsigned char address)
280091b52d5Sshatty {
281091b52d5Sshatty int error=0;
282091b52d5Sshatty int data;
283091b52d5Sshatty
284091b52d5Sshatty i2c_start();
285091b52d5Sshatty {
286091b52d5Sshatty error+=i2c_sendbyte(MAVEN_READ);
287091b52d5Sshatty error+=i2c_sendbyte(address);
288091b52d5Sshatty data = i2c_readbyte(0);
289091b52d5Sshatty }
290091b52d5Sshatty i2c_stop();
291091b52d5Sshatty if (error>0) LOG(8,("I2C: MAVR ERROR - %x\n",error));
292091b52d5Sshatty return data;
293091b52d5Sshatty }
294091b52d5Sshatty
i2c_maven_write(unsigned char address,unsigned char data)295091b52d5Sshatty void i2c_maven_write(unsigned char address, unsigned char data)
296091b52d5Sshatty {
297091b52d5Sshatty int error=0;
298091b52d5Sshatty
299091b52d5Sshatty i2c_start();
300091b52d5Sshatty {
301091b52d5Sshatty error+=i2c_sendbyte(MAVEN_WRITE);
302091b52d5Sshatty error+=i2c_sendbyte(address);
303091b52d5Sshatty error+=i2c_sendbyte(data);
304091b52d5Sshatty }
305091b52d5Sshatty i2c_stop();
306091b52d5Sshatty if (error>0) LOG(8,("I2C: MAVW ERROR - %x\n",error));
307091b52d5Sshatty }
308091b52d5Sshatty
i2c_init(void)309091b52d5Sshatty status_t i2c_init(void)
310091b52d5Sshatty {
311091b52d5Sshatty /*init g400 i2c*/
312091b52d5Sshatty DXIW(GENIODATA,0x00); /*to zero*/
313091b52d5Sshatty DXIW(GENIOCTRL,0x30); /*drive clock and data*/
314091b52d5Sshatty DXIW(GENIOCTRL,0x00); /*stop driving*/
315091b52d5Sshatty
316091b52d5Sshatty return B_OK;
317091b52d5Sshatty }
318091b52d5Sshatty
i2c_maven_probe(void)319091b52d5Sshatty status_t i2c_maven_probe(void)
320091b52d5Sshatty {
321091b52d5Sshatty int ack;
322091b52d5Sshatty
323091b52d5Sshatty /*scan the bus for the MAVEN*/
324091b52d5Sshatty i2c_start();
325091b52d5Sshatty {
326091b52d5Sshatty ack = i2c_sendbyte(MAVEN_READ);
327091b52d5Sshatty }
328091b52d5Sshatty i2c_stop();
329091b52d5Sshatty if (ack==0)
330091b52d5Sshatty {
331091b52d5Sshatty return B_OK;
332091b52d5Sshatty }
333091b52d5Sshatty else
334091b52d5Sshatty {
335091b52d5Sshatty return B_ERROR;
336091b52d5Sshatty }
337091b52d5Sshatty }
338