make the linux-ppc packags be in synch with other platforms
[tangerine.git] / arch / common / hidd.i2c / i2cclass.c
blob61db988989502381b1db69b687c8cfe41984b2dd
1 /*
2 Copyright © 2004-2006, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <exec/types.h>
7 #include <hidd/hidd.h>
8 #include <hidd/i2c.h>
9 #include <oop/oop.h>
11 #include <utility/tagitem.h>
12 #include <utility/hooks.h>
13 #include <devices/timer.h>
15 #include <proto/exec.h>
16 #include <proto/utility.h>
17 #include <proto/oop.h>
19 #include <aros/symbolsets.h>
21 #include "i2c.h"
23 #define DEBUG 1
24 #include <aros/debug.h>
25 #include <aros/atomic.h>
28 There are no static AttrBases in this class. Therefore it might be placed
29 directly in ROM without any harm
31 #undef HiddI2CAttrBase
32 #undef HiddI2CDeviceAttrBase
34 #define HiddI2CAttrBase (SD(cl)->hiddI2CAB)
35 #define HiddI2CDeviceAttrBase (SD(cl)->hiddI2CDeviceAB)
36 #define HiddAttrBase (SD(cl)->hiddAB)
38 static void I2C_UDelay(tDrvData *drv, ULONG delay)
40 drv->mp.mp_SigTask = FindTask(NULL);
41 drv->tr.tr_node.io_Command = TR_ADDREQUEST;
42 drv->tr.tr_time.tv_secs = delay / 100000;
43 drv->tr.tr_time.tv_micro = 10 * (delay % 100000);
45 DoIO((struct IORequest *)&drv->tr);
47 drv->mp.mp_SigTask = NULL;
51 static BOOL RaiseSCL(OOP_Class *cl, OOP_Object *o, BOOL sda, ULONG timeout)
53 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
55 int i;
56 BOOL scl;
58 I2C_PutBits(o, 1, sda);
59 I2C_UDelay(drv, drv->RiseFallTime);
61 for (i=timeout; i>0; i -= drv->RiseFallTime)
63 I2C_GetBits(o, &scl, &sda);
64 if (scl) break;
65 I2C_UDelay(drv, drv->RiseFallTime);
68 if (i <= 0)
70 bug("[I2C] RaiseSCL(<%s>,%d,%d) timeout\n", drv->name, sda, timeout);
71 return FALSE;
74 return TRUE;
77 static BOOL WriteBit(OOP_Class *cl, OOP_Object *o, BOOL sda, ULONG timeout)
79 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
81 BOOL r;
83 I2C_PutBits(o, 0, sda);
84 I2C_UDelay(drv, drv->RiseFallTime);
86 r = RaiseSCL(cl, o, sda, timeout);
87 I2C_UDelay(drv, drv->HoldTime);
89 I2C_PutBits(o, 0, sda);
90 I2C_UDelay(drv, drv->HoldTime);
92 return r;
95 static BOOL ReadBit(OOP_Class *cl, OOP_Object *o, BOOL *sda, ULONG timeout)
97 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
99 BOOL scl, r;
101 r = RaiseSCL(cl, o, 1, timeout);
102 I2C_UDelay(drv, drv->HoldTime);
104 I2C_GetBits(o, &scl, sda);
106 I2C_PutBits(o, 0, 1);
107 I2C_UDelay(drv, drv->HoldTime);
109 return r;
112 /*** Hidd::I2C */
114 void METHOD(I2C, Hidd_I2C, PutBits)
116 bug("[I2C] Pure virtual method I2C::PutBits() called!!!\n");
119 void METHOD(I2C, Hidd_I2C, GetBits)
121 bug("[I2C] Pure virtual method I2C::GetBits() called!!!\n");
124 BOOL METHOD(I2C, Hidd_I2C, Start)
126 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
128 LOCK_HW
130 if (!RaiseSCL(cl, o, 1, msg->timeout))
131 return FALSE;
133 I2C_PutBits(o, 1, 0);
134 I2C_UDelay(drv, drv->HoldTime);
135 I2C_PutBits(o, 0, 0);
136 I2C_UDelay(drv, drv->HoldTime);
138 D(bug("\n[I2C]: <"));
140 UNLOCK_HW
142 return TRUE;
145 BOOL METHOD(I2C, Hidd_I2C, Address)
147 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
148 tDevData *dev = (tDevData *)OOP_INST_DATA(SD(cl)->i2cDeviceClass, msg->device);
150 LOCK_HW
152 if (I2C_Start(o, dev->StartTimeout)) {
153 if (I2C_PutByte(o, msg->device, msg->address & 0xFF)) {
154 if ((msg->address & 0xF8) != 0xF0 &&
155 (msg->address & 0xFE) != 0x00)
156 return TRUE;
158 if (I2C_PutByte(o, msg->device, (msg->address >> 8) & 0xFF))
159 return TRUE;
162 I2C_Stop(o, msg->device);
165 UNLOCK_HW
167 return FALSE;
170 BOOL METHOD(I2C, Hidd_I2C, ProbeAddress)
172 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
174 struct TagItem attrs[] = {
175 { aHidd_I2CDevice_Driver, (IPTR)o },
176 { aHidd_I2CDevice_Address, msg->address },
177 { aHidd_I2CDevice_Name, (IPTR)"Probing" },
178 { TAG_DONE, 0UL }
181 BOOL r = FALSE;
183 D(bug("[I2C] I2C::ProbeAddress(%04x)\n", msg->address));
185 LOCK_HW
187 OOP_Object *probing = OOP_NewObject(SD(cl)->i2cDeviceClass, NULL, attrs);
189 if (probing)
191 r = I2C_Address(o, probing, msg->address);
192 if (r)
193 I2C_Stop(o, probing);
195 OOP_DisposeObject(probing);
198 UNLOCK_HW
200 return r;
204 void METHOD(I2C, Hidd_I2C, Stop)
206 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
208 LOCK_HW
210 I2C_PutBits(o, 0, 0);
211 I2C_UDelay(drv, drv->RiseFallTime);
213 I2C_PutBits(o, 1, 0);
214 I2C_UDelay(drv, drv->HoldTime);
215 I2C_PutBits(o, 1, 1);
216 I2C_UDelay(drv, drv->HoldTime);
218 D(bug(">\n"));
220 UNLOCK_HW
223 BOOL METHOD(I2C, Hidd_I2C, PutByte)
225 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
226 tDevData *dev = (tDevData *)OOP_INST_DATA(SD(cl)->i2cDeviceClass, msg->device);
228 BOOL r, scl, sda;
229 int i;
231 LOCK_HW
233 if (!WriteBit(cl, o, (msg->data >> 7) & 1, dev->ByteTimeout))
235 UNLOCK_HW
236 return FALSE;
239 for (i = 6; i >= 0; i--)
240 if (!WriteBit(cl, o, (msg->data >> i) & 1, dev->BitTimeout))
242 UNLOCK_HW
243 return FALSE;
246 I2C_PutBits(o, 0, 1);
247 I2C_UDelay(drv, drv->RiseFallTime);
249 r = RaiseSCL(cl, o, 1, drv->HoldTime);
251 if (r)
253 for (i = dev->AcknTimeout; i > 0; i -= drv->HoldTime)
255 I2C_UDelay(drv, drv->HoldTime);
256 I2C_GetBits(o, &scl, &sda);
257 if (sda == 0) break;
260 if (i <= 0) {
261 bug("[I2C] PutByte(<%s>, 0x%02x, %d, %d, %d) timeout",
262 drv->name, msg->data, dev->BitTimeout,
263 dev->ByteTimeout, dev->AcknTimeout);
264 r = FALSE;
267 D(bug("W%02x%c ", (int) msg->data, sda ? '-' : '+'));
270 I2C_PutBits(o, 0, 1);
271 I2C_UDelay(drv, drv->HoldTime);
273 UNLOCK_HW
275 return r;
278 BOOL METHOD(I2C, Hidd_I2C, GetByte)
280 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
281 tDevData *dev = (tDevData *)OOP_INST_DATA(SD(cl)->i2cDeviceClass, msg->device);
283 int i;
284 BOOL sda;
286 LOCK_HW
288 I2C_PutBits(o, 0, 1);
289 I2C_UDelay(drv, drv->RiseFallTime);
291 if (!ReadBit(cl, o, &sda, dev->ByteTimeout))
293 UNLOCK_HW
294 return FALSE;
298 *msg->data = (sda? 1:0) << 7;
300 for (i = 6; i >= 0; i--)
301 if (!ReadBit(cl, o, &sda, dev->BitTimeout))
303 UNLOCK_HW
304 return FALSE;
306 else
307 *msg->data |= (sda? 1:0) << i;
309 if (!WriteBit(cl, o, msg->last ? 1 : 0, dev->BitTimeout))
311 UNLOCK_HW
312 return FALSE;
315 D(bug("R%02x%c ", (int) *msg->data, msg->last ? '+' : '-'));
317 UNLOCK_HW
319 return TRUE;
322 BOOL METHOD(I2C, Hidd_I2C, WriteRead)
324 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
325 tDevData *dev = (tDevData *)OOP_INST_DATA(SD(cl)->i2cDeviceClass, msg->device);
327 BOOL r = TRUE;
328 int s = 0;
330 ULONG nWrite = msg->writeLength;
331 UBYTE *WriteBuffer = msg->writeBuffer;
332 ULONG nRead = msg->readLength;
333 UBYTE *ReadBuffer = msg->readBuffer;
335 LOCK_HW
337 if (r && nWrite > 0) {
338 r = I2C_Address(o, msg->device, dev->address & ~1);
339 if (r) {
340 for (; nWrite > 0; WriteBuffer++, nWrite--)
341 if (!(r = I2C_PutByte(o, msg->device, *WriteBuffer)))
342 break;
343 s++;
347 if (r && nRead > 0) {
348 r = I2C_Address(o, msg->device, dev->address | 1);
349 if (r) {
350 for (; nRead > 0; ReadBuffer++, nRead--)
351 if (!(r = I2C_GetByte(o, msg->device, ReadBuffer, nRead == 1)))
352 break;
353 s++;
357 if (s) I2C_Stop(o, msg->device);
359 UNLOCK_HW
361 return r;
364 /*** Root */
366 void METHOD(I2C, Root, Get)
368 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
370 ULONG idx;
372 if (IS_I2C_ATTR(msg->attrID, idx))
374 switch (idx)
376 case aoHidd_I2C_HoldTime:
377 *msg->storage = drv->HoldTime;
378 break;
380 case aoHidd_I2C_BitTimeout:
381 *msg->storage = drv->BitTimeout;
382 break;
384 case aoHidd_I2C_ByteTimeout:
385 *msg->storage = drv->ByteTimeout;
386 break;
388 case aoHidd_I2C_AcknTimeout:
389 *msg->storage = drv->AcknTimeout;
390 break;
392 case aoHidd_I2C_StartTimeout:
393 *msg->storage = drv->StartTimeout;
394 break;
396 case aoHidd_I2C_RiseFallTime:
397 *msg->storage = drv->RiseFallTime;
398 break;
400 case aoHidd_I2C_Name:
401 *msg->storage = (IPTR)drv->name;
402 break;
405 else
407 OOP_DoSuperMethod(cl, o, (OOP_Msg)msg);
411 void METHOD(I2C, Root, Set)
413 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
415 ULONG idx;
416 struct TagItem *tag;
417 const struct TagItem *tags = msg->attrList;
419 while ((tag = NextTagItem(&tags)))
421 if (IS_I2C_ATTR(tag->ti_Tag, idx))
423 switch (idx)
425 case aoHidd_I2C_HoldTime:
426 drv->HoldTime = tag->ti_Data;
427 break;
429 case aoHidd_I2C_BitTimeout:
430 drv->BitTimeout = tag->ti_Data;
431 break;
433 case aoHidd_I2C_ByteTimeout:
434 drv->ByteTimeout = tag->ti_Data;
435 break;
437 case aoHidd_I2C_AcknTimeout:
438 drv->AcknTimeout = tag->ti_Data;
439 break;
441 case aoHidd_I2C_StartTimeout:
442 drv->StartTimeout = tag->ti_Data;
443 break;
445 case aoHidd_I2C_RiseFallTime:
446 drv->RiseFallTime = tag->ti_Data;
447 break;
453 OOP_Object *METHOD(I2C, Root, New)
455 D(bug("[I2C] new()\n"));
457 o = (OOP_Object *)OOP_DoSuperMethod(cl, o, (OOP_Msg) msg);
458 if (o)
460 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
461 struct TagItem *tag;
462 const struct TagItem *tags = msg->attrList;
464 drv->HoldTime = 5;
465 drv->AcknTimeout = 5;
466 drv->BitTimeout = 5;
467 drv->ByteTimeout = 5;
468 drv->RiseFallTime = 2;
469 drv->StartTimeout = 5;
471 drv->name = (STRPTR)"bus?";
473 InitSemaphore(&drv->driver_lock);
475 D(bug("[I2C] Initializing MsgPort\n"));
477 /* Initialize MsgPort */
478 drv->mp.mp_SigBit = SIGB_SINGLE;
479 drv->mp.mp_Flags = PA_SIGNAL;
480 drv->mp.mp_SigTask = FindTask(NULL);
481 drv->mp.mp_Node.ln_Type = NT_MSGPORT;
482 NEWLIST(&drv->mp.mp_MsgList);
484 drv->tr.tr_node.io_Message.mn_ReplyPort = &drv->mp;
485 drv->tr.tr_node.io_Message.mn_Length = sizeof(drv->tr);
487 D(bug("[I2C] Trying to open UNIT_MICROHZ of timer.device\n"));
489 if (!OpenDevice((STRPTR)"timer.device", UNIT_MICROHZ, (struct IORequest *)&drv->tr, 0))
491 D(bug("[I2C] Everything OK\n"));
493 tags=msg->attrList;
495 while((tag = NextTagItem(&tags)))
497 ULONG idx;
499 if (IS_I2C_ATTR(tag->ti_Tag, idx))
501 switch(idx)
503 case aoHidd_I2C_Name:
504 drv->name = (STRPTR)tag->ti_Data;
505 break;
507 case aoHidd_I2C_HoldTime:
508 drv->HoldTime = tag->ti_Data;
509 break;
511 case aoHidd_I2C_BitTimeout:
512 drv->BitTimeout = tag->ti_Data;
513 break;
515 case aoHidd_I2C_ByteTimeout:
516 drv->ByteTimeout = tag->ti_Data;
517 break;
519 case aoHidd_I2C_AcknTimeout:
520 drv->AcknTimeout = tag->ti_Data;
521 break;
523 case aoHidd_I2C_StartTimeout:
524 drv->StartTimeout = tag->ti_Data;
525 break;
527 case aoHidd_I2C_RiseFallTime:
528 drv->RiseFallTime = tag->ti_Data;
529 break;
534 else
536 D(bug("[I2C] Opening of timer.device failed\n"));
537 OOP_MethodID disp_mid = OOP_GetMethodID((STRPTR)IID_Root, moRoot_Dispose);
538 OOP_CoerceMethod(cl, o, (OOP_Msg) &disp_mid);
539 o = NULL;
544 return o;
548 /* Class initialization and destruction */
550 //#undef UtilityBase
551 //#define UtilityBase (sd->utilitybase)
553 static int I2C_ExpungeClass(LIBBASETYPEPTR LIBBASE)
555 D(bug("[I2C] Base Class destruction\n"));
557 OOP_ReleaseAttrBase((STRPTR)IID_Hidd_I2C);
558 OOP_ReleaseAttrBase((STRPTR)IID_Hidd_I2C);
559 OOP_ReleaseAttrBase((STRPTR)IID_Hidd);
561 return TRUE;
564 static int I2C_InitClass(LIBBASETYPEPTR LIBBASE)
566 D(bug("[I2C] base class initialization\n"));
568 LIBBASE->sd.hiddI2CAB = OOP_ObtainAttrBase((STRPTR)IID_Hidd_I2C);
569 LIBBASE->sd.hiddI2CDeviceAB = OOP_ObtainAttrBase((STRPTR)IID_Hidd_I2CDevice);
570 LIBBASE->sd.hiddAB = OOP_ObtainAttrBase((STRPTR)IID_Hidd);
572 if (LIBBASE->sd.hiddI2CAB && LIBBASE->sd.hiddI2CDeviceAB && LIBBASE->sd.hiddAB)
574 D(bug("[I2C] Everything OK\n"));
575 return TRUE;
578 return FALSE;
581 ADD2INITLIB(I2C_InitClass, 0)
582 ADD2EXPUNGELIB(I2C_ExpungeClass, 0)