xref: /haiku/src/add-ons/accelerants/skeleton/engine/i2c.c (revision f2ced752a08ff5d2618826bcd3ae3976c9f3e92e)
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 
19 int i2c_set_lines(int clock, int data);
20 int i2c_get_data(void);
21 void i2c_start(void);
22 void i2c_stop(void);
23 void i2c_high(void);
24 void i2c_low(void);
25 int i2c_get_ack(void);
26 void i2c_send_ack(void);
27 int i2c_sendbyte(unsigned char data);
28 unsigned 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 
50 status_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
84 int 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 
121 int 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  */
153 void 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 
168 void 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 
183 void 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 
197 void 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 
211 int 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 
229 void 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 
247 int 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 
266 unsigned 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  */
290 int 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 
306 void 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 
320 status_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 
330 status_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