xref: /haiku/src/add-ons/accelerants/matrox/engine/mga_i2c.c (revision 39ba57a99635e40e7f9ae237f37be0cdb0863aee)
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