2 Copyright © 2004-2017, The AROS Development Team. All rights reserved.
6 #include <exec/types.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>
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
35 #define HiddI2CAttrBase (SD(cl)->hiddI2CAB)
36 #define HiddI2CDeviceAttrBase (SD(cl)->hiddI2CDeviceAB)
37 #define HiddAttrBase (SD(cl)->hiddAB)
39 static void I2C_UDelay(tDrvData
*drv
, ULONG delay
)
41 drv
->mp
.mp_SigTask
= FindTask(NULL
);
42 drv
->tr
.tr_node
.io_Command
= TR_ADDREQUEST
;
43 drv
->tr
.tr_time
.tv_secs
= delay
/ 10000;
44 drv
->tr
.tr_time
.tv_micro
= 10 * (delay
% 10000);
46 DoIO((struct IORequest
*)&drv
->tr
);
48 drv
->mp
.mp_SigTask
= NULL
;
52 static BOOL
RaiseSCL(OOP_Class
*cl
, OOP_Object
*o
, BOOL sda
, ULONG timeout
)
54 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
59 I2C_PutBits(o
, 1, sda
);
60 I2C_UDelay(drv
, drv
->RiseFallTime
);
62 for (i
=timeout
; i
>0; i
-= drv
->RiseFallTime
)
64 I2C_GetBits(o
, &scl
, &sda
);
66 I2C_UDelay(drv
, drv
->RiseFallTime
);
71 bug("[I2C] RaiseSCL(<%s>,%d,%d) timeout\n", drv
->name
, sda
, timeout
);
78 static BOOL
WriteBit(OOP_Class
*cl
, OOP_Object
*o
, BOOL sda
, ULONG timeout
)
80 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
84 I2C_PutBits(o
, 0, sda
);
85 I2C_UDelay(drv
, drv
->RiseFallTime
);
87 r
= RaiseSCL(cl
, o
, sda
, timeout
);
88 I2C_UDelay(drv
, drv
->HoldTime
);
90 I2C_PutBits(o
, 0, sda
);
91 I2C_UDelay(drv
, drv
->HoldTime
);
96 static BOOL
ReadBit(OOP_Class
*cl
, OOP_Object
*o
, BOOL
*sda
, ULONG timeout
)
98 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
102 r
= RaiseSCL(cl
, o
, 1, timeout
);
103 I2C_UDelay(drv
, drv
->HoldTime
);
105 I2C_GetBits(o
, &scl
, sda
);
107 I2C_PutBits(o
, 0, 1);
108 I2C_UDelay(drv
, drv
->HoldTime
);
115 void METHOD(I2C
, Hidd_I2C
, PutBits
)
117 bug("[I2C] Pure virtual method I2C::PutBits() called!!!\n");
120 void METHOD(I2C
, Hidd_I2C
, GetBits
)
122 bug("[I2C] Pure virtual method I2C::GetBits() called!!!\n");
125 BOOL
METHOD(I2C
, Hidd_I2C
, Start
)
127 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
131 if (!RaiseSCL(cl
, o
, 1, msg
->timeout
)) {
136 I2C_PutBits(o
, 1, 0);
137 I2C_UDelay(drv
, drv
->HoldTime
);
138 I2C_PutBits(o
, 0, 0);
139 I2C_UDelay(drv
, drv
->HoldTime
);
141 D(bug("\n[I2C]: <"));
148 BOOL
METHOD(I2C
, Hidd_I2C
, Address
)
150 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
151 tDevData
*dev
= (tDevData
*)OOP_INST_DATA(SD(cl
)->i2cDeviceClass
, msg
->device
);
155 if (I2C_Start(o
, dev
->StartTimeout
)) {
156 if (I2C_PutByte(o
, msg
->device
, msg
->address
& 0xFF)) {
157 if ((msg
->address
& 0xF8) != 0xF0 &&
158 (msg
->address
& 0xFE) != 0x00) {
163 if (I2C_PutByte(o
, msg
->device
, (msg
->address
>> 8) & 0xFF)) {
169 I2C_Stop(o
, msg
->device
);
177 BOOL
METHOD(I2C
, Hidd_I2C
, ProbeAddress
)
179 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
181 struct TagItem attrs
[] = {
182 { aHidd_I2CDevice_Driver
, (IPTR
)o
},
183 { aHidd_I2CDevice_Address
, msg
->address
},
184 { aHidd_I2CDevice_Name
, (IPTR
)"Probing" },
190 D(bug("[I2C] I2C::ProbeAddress(%04x)\n", msg
->address
));
194 OOP_Object
*probing
= OOP_NewObject(SD(cl
)->i2cDeviceClass
, NULL
, attrs
);
198 r
= I2C_Address(o
, probing
, msg
->address
);
200 I2C_Stop(o
, probing
);
202 OOP_DisposeObject(probing
);
211 void METHOD(I2C
, Hidd_I2C
, Stop
)
213 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
217 I2C_PutBits(o
, 0, 0);
218 I2C_UDelay(drv
, drv
->RiseFallTime
);
220 I2C_PutBits(o
, 1, 0);
221 I2C_UDelay(drv
, drv
->HoldTime
);
222 I2C_PutBits(o
, 1, 1);
223 I2C_UDelay(drv
, drv
->HoldTime
);
230 BOOL
METHOD(I2C
, Hidd_I2C
, PutByte
)
232 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
233 tDevData
*dev
= (tDevData
*)OOP_INST_DATA(SD(cl
)->i2cDeviceClass
, msg
->device
);
240 if (!WriteBit(cl
, o
, (msg
->data
>> 7) & 1, dev
->ByteTimeout
))
246 for (i
= 6; i
>= 0; i
--)
247 if (!WriteBit(cl
, o
, (msg
->data
>> i
) & 1, dev
->BitTimeout
))
253 I2C_PutBits(o
, 0, 1);
254 I2C_UDelay(drv
, drv
->RiseFallTime
);
256 r
= RaiseSCL(cl
, o
, 1, drv
->HoldTime
);
260 for (i
= dev
->AcknTimeout
; i
> 0; i
-= drv
->HoldTime
)
262 I2C_UDelay(drv
, drv
->HoldTime
);
263 I2C_GetBits(o
, &scl
, &sda
);
268 D(bug("[I2C] PutByte(<%s>, 0x%02x, %d, %d, %d) timeout",
269 drv
->name
, msg
->data
, dev
->BitTimeout
,
270 dev
->ByteTimeout
, dev
->AcknTimeout
));
274 D(bug("W%02x%c ", (int) msg
->data
, sda
? '-' : '+'));
277 I2C_PutBits(o
, 0, 1);
278 I2C_UDelay(drv
, drv
->HoldTime
);
285 BOOL
METHOD(I2C
, Hidd_I2C
, GetByte
)
287 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
288 tDevData
*dev
= (tDevData
*)OOP_INST_DATA(SD(cl
)->i2cDeviceClass
, msg
->device
);
295 I2C_PutBits(o
, 0, 1);
296 I2C_UDelay(drv
, drv
->RiseFallTime
);
298 if (!ReadBit(cl
, o
, &sda
, dev
->ByteTimeout
))
305 *msg
->data
= (sda
? 1:0) << 7;
307 for (i
= 6; i
>= 0; i
--)
308 if (!ReadBit(cl
, o
, &sda
, dev
->BitTimeout
))
314 *msg
->data
|= (sda
? 1:0) << i
;
316 if (!WriteBit(cl
, o
, msg
->last
? 1 : 0, dev
->BitTimeout
))
322 D(bug("R%02x%c ", (int) *msg
->data
, msg
->last
? '+' : '-'));
329 BOOL
METHOD(I2C
, Hidd_I2C
, WriteRead
)
331 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
332 tDevData
*dev
= (tDevData
*)OOP_INST_DATA(SD(cl
)->i2cDeviceClass
, msg
->device
);
337 ULONG nWrite
= msg
->writeLength
;
338 UBYTE
*WriteBuffer
= msg
->writeBuffer
;
339 ULONG nRead
= msg
->readLength
;
340 UBYTE
*ReadBuffer
= msg
->readBuffer
;
344 if (r
&& nWrite
> 0) {
345 r
= I2C_Address(o
, msg
->device
, dev
->address
& ~1);
347 for (; nWrite
> 0; WriteBuffer
++, nWrite
--)
348 if (!(r
= I2C_PutByte(o
, msg
->device
, *WriteBuffer
)))
354 if (r
&& nRead
> 0) {
355 r
= I2C_Address(o
, msg
->device
, dev
->address
| 1);
357 for (; nRead
> 0; ReadBuffer
++, nRead
--)
358 if (!(r
= I2C_GetByte(o
, msg
->device
, ReadBuffer
, nRead
== 1)))
364 if (s
) I2C_Stop(o
, msg
->device
);
373 void METHOD(I2C
, Root
, Get
)
375 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
379 if (IS_I2C_ATTR(msg
->attrID
, idx
))
383 case aoHidd_I2C_HoldTime
:
384 *msg
->storage
= drv
->HoldTime
;
387 case aoHidd_I2C_BitTimeout
:
388 *msg
->storage
= drv
->BitTimeout
;
391 case aoHidd_I2C_ByteTimeout
:
392 *msg
->storage
= drv
->ByteTimeout
;
395 case aoHidd_I2C_AcknTimeout
:
396 *msg
->storage
= drv
->AcknTimeout
;
399 case aoHidd_I2C_StartTimeout
:
400 *msg
->storage
= drv
->StartTimeout
;
403 case aoHidd_I2C_RiseFallTime
:
404 *msg
->storage
= drv
->RiseFallTime
;
407 case aoHidd_I2C_Name
:
408 *msg
->storage
= (IPTR
)drv
->name
;
414 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
418 void METHOD(I2C
, Root
, Set
)
420 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
424 struct TagItem
*tags
= msg
->attrList
;
426 while ((tag
= NextTagItem(&tags
)))
428 if (IS_I2C_ATTR(tag
->ti_Tag
, idx
))
432 case aoHidd_I2C_HoldTime
:
433 drv
->HoldTime
= tag
->ti_Data
;
436 case aoHidd_I2C_BitTimeout
:
437 drv
->BitTimeout
= tag
->ti_Data
;
440 case aoHidd_I2C_ByteTimeout
:
441 drv
->ByteTimeout
= tag
->ti_Data
;
444 case aoHidd_I2C_AcknTimeout
:
445 drv
->AcknTimeout
= tag
->ti_Data
;
448 case aoHidd_I2C_StartTimeout
:
449 drv
->StartTimeout
= tag
->ti_Data
;
452 case aoHidd_I2C_RiseFallTime
:
453 drv
->RiseFallTime
= tag
->ti_Data
;
460 OOP_Object
*METHOD(I2C
, Root
, New
)
462 D(bug("[I2C] new()\n"));
464 o
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
) msg
);
467 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
468 struct TagItem
*tag
, *tags
= msg
->attrList
;
471 drv
->AcknTimeout
= 5;
473 drv
->ByteTimeout
= 5;
474 drv
->RiseFallTime
= 2;
475 drv
->StartTimeout
= 5;
477 drv
->name
= (STRPTR
)"bus?";
479 InitSemaphore(&drv
->driver_lock
);
481 D(bug("[I2C] Initializing MsgPort\n"));
483 /* Initialize MsgPort */
484 memset( &drv
->mp
, 0, sizeof( drv
->mp
) );
485 drv
->mp
.mp_SigBit
= SIGB_SINGLE
;
486 drv
->mp
.mp_Flags
= PA_SIGNAL
;
487 drv
->mp
.mp_SigTask
= FindTask(NULL
);
488 drv
->mp
.mp_Node
.ln_Type
= NT_MSGPORT
;
489 NEWLIST(&drv
->mp
.mp_MsgList
);
491 drv
->tr
.tr_node
.io_Message
.mn_ReplyPort
= &drv
->mp
;
492 drv
->tr
.tr_node
.io_Message
.mn_Length
= sizeof(drv
->tr
);
494 D(bug("[I2C] Trying to open UNIT_MICROHZ of timer.device\n"));
496 if (!OpenDevice((STRPTR
)"timer.device", UNIT_MICROHZ
, (struct IORequest
*)&drv
->tr
, 0))
498 D(bug("[I2C] Everything OK\n"));
502 while((tag
= NextTagItem(&tags
)))
506 if (IS_I2C_ATTR(tag
->ti_Tag
, idx
))
510 case aoHidd_I2C_Name
:
511 drv
->name
= (STRPTR
)tag
->ti_Data
;
514 case aoHidd_I2C_HoldTime
:
515 drv
->HoldTime
= tag
->ti_Data
;
518 case aoHidd_I2C_BitTimeout
:
519 drv
->BitTimeout
= tag
->ti_Data
;
522 case aoHidd_I2C_ByteTimeout
:
523 drv
->ByteTimeout
= tag
->ti_Data
;
526 case aoHidd_I2C_AcknTimeout
:
527 drv
->AcknTimeout
= tag
->ti_Data
;
530 case aoHidd_I2C_StartTimeout
:
531 drv
->StartTimeout
= tag
->ti_Data
;
534 case aoHidd_I2C_RiseFallTime
:
535 drv
->RiseFallTime
= tag
->ti_Data
;
543 D(bug("[I2C] Opening of timer.device failed\n"));
544 OOP_MethodID disp_mid
= OOP_GetMethodID((STRPTR
)IID_Root
, moRoot_Dispose
);
545 OOP_CoerceMethod(cl
, o
, (OOP_Msg
) &disp_mid
);
554 VOID
METHOD(I2C
, Root
, Dispose
)
556 tDrvData
*drv
= (tDrvData
*)OOP_INST_DATA(cl
, o
);
558 D(bug("[I2C] Dispose()\n"));
560 CloseDevice((struct IORequest
*)&drv
->tr
);
562 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
565 /* Class initialization and destruction */
568 //#define UtilityBase (sd->utilitybase)
570 static int I2C_ExpungeClass(LIBBASETYPEPTR LIBBASE
)
572 D(bug("[I2C] Base Class destruction\n"));
574 OOP_ReleaseAttrBase(IID_Hidd_I2CDevice
);
575 OOP_ReleaseAttrBase(IID_Hidd_I2C
);
576 OOP_ReleaseAttrBase(IID_Hidd
);
581 static int I2C_InitClass(LIBBASETYPEPTR LIBBASE
)
583 D(bug("[I2C] base class initialization\n"));
585 LIBBASE
->sd
.hiddI2CAB
= OOP_ObtainAttrBase(IID_Hidd_I2C
);
586 LIBBASE
->sd
.hiddI2CDeviceAB
= OOP_ObtainAttrBase(IID_Hidd_I2CDevice
);
587 LIBBASE
->sd
.hiddAB
= OOP_ObtainAttrBase(IID_Hidd
);
589 if (LIBBASE
->sd
.hiddI2CAB
&& LIBBASE
->sd
.hiddI2CDeviceAB
&& LIBBASE
->sd
.hiddAB
)
591 D(bug("[I2C] Everything OK\n"));
598 ADD2INITLIB(I2C_InitClass
, 0)
599 ADD2EXPUNGELIB(I2C_ExpungeClass
, 0)