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