revert between 56095 -> 55830 in arch
[AROS.git] / workbench / hidds / i2c / i2cclass.c
blob51c8033c2ed5d99a4148aa30441ada666eba76e2
1 /*
2 Copyright © 2004-2017, 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 0
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
33 #undef HiddAttrBase
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);
56 int i;
57 BOOL scl;
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);
65 if (scl) break;
66 I2C_UDelay(drv, drv->RiseFallTime);
69 if (i <= 0)
71 bug("[I2C] RaiseSCL(<%s>,%d,%d) timeout\n", drv->name, sda, timeout);
72 return FALSE;
75 return TRUE;
78 static BOOL WriteBit(OOP_Class *cl, OOP_Object *o, BOOL sda, ULONG timeout)
80 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
82 BOOL r;
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);
93 return r;
96 static BOOL ReadBit(OOP_Class *cl, OOP_Object *o, BOOL *sda, ULONG timeout)
98 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
100 BOOL scl, r;
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);
110 return r;
113 /*** Hidd::I2C */
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);
129 LOCK_HW
131 if (!RaiseSCL(cl, o, 1, msg->timeout)) {
132 UNLOCK_HW
133 return FALSE;
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]: <"));
143 UNLOCK_HW
145 return TRUE;
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);
153 LOCK_HW
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) {
159 UNLOCK_HW;
160 return TRUE;
163 if (I2C_PutByte(o, msg->device, (msg->address >> 8) & 0xFF)) {
164 UNLOCK_HW;
165 return TRUE;
169 I2C_Stop(o, msg->device);
172 UNLOCK_HW
174 return FALSE;
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" },
185 { TAG_DONE, 0UL }
188 BOOL r = FALSE;
190 D(bug("[I2C] I2C::ProbeAddress(%04x)\n", msg->address));
192 LOCK_HW
194 OOP_Object *probing = OOP_NewObject(SD(cl)->i2cDeviceClass, NULL, attrs);
196 if (probing)
198 r = I2C_Address(o, probing, msg->address);
199 if (r)
200 I2C_Stop(o, probing);
202 OOP_DisposeObject(probing);
205 UNLOCK_HW
207 return r;
211 void METHOD(I2C, Hidd_I2C, Stop)
213 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
215 LOCK_HW
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);
225 D(bug(">\n"));
227 UNLOCK_HW
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);
235 BOOL r, scl, sda;
236 int i;
238 LOCK_HW
240 if (!WriteBit(cl, o, (msg->data >> 7) & 1, dev->ByteTimeout))
242 UNLOCK_HW
243 return FALSE;
246 for (i = 6; i >= 0; i--)
247 if (!WriteBit(cl, o, (msg->data >> i) & 1, dev->BitTimeout))
249 UNLOCK_HW
250 return FALSE;
253 I2C_PutBits(o, 0, 1);
254 I2C_UDelay(drv, drv->RiseFallTime);
256 r = RaiseSCL(cl, o, 1, drv->HoldTime);
258 if (r)
260 for (i = dev->AcknTimeout; i > 0; i -= drv->HoldTime)
262 I2C_UDelay(drv, drv->HoldTime);
263 I2C_GetBits(o, &scl, &sda);
264 if (sda == 0) break;
267 if (i <= 0) {
268 D(bug("[I2C] PutByte(<%s>, 0x%02x, %d, %d, %d) timeout",
269 drv->name, msg->data, dev->BitTimeout,
270 dev->ByteTimeout, dev->AcknTimeout));
271 r = FALSE;
274 D(bug("W%02x%c ", (int) msg->data, sda ? '-' : '+'));
277 I2C_PutBits(o, 0, 1);
278 I2C_UDelay(drv, drv->HoldTime);
280 UNLOCK_HW
282 return r;
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);
290 int i;
291 BOOL sda;
293 LOCK_HW
295 I2C_PutBits(o, 0, 1);
296 I2C_UDelay(drv, drv->RiseFallTime);
298 if (!ReadBit(cl, o, &sda, dev->ByteTimeout))
300 UNLOCK_HW
301 return FALSE;
305 *msg->data = (sda? 1:0) << 7;
307 for (i = 6; i >= 0; i--)
308 if (!ReadBit(cl, o, &sda, dev->BitTimeout))
310 UNLOCK_HW
311 return FALSE;
313 else
314 *msg->data |= (sda? 1:0) << i;
316 if (!WriteBit(cl, o, msg->last ? 1 : 0, dev->BitTimeout))
318 UNLOCK_HW
319 return FALSE;
322 D(bug("R%02x%c ", (int) *msg->data, msg->last ? '+' : '-'));
324 UNLOCK_HW
326 return TRUE;
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);
334 BOOL r = TRUE;
335 int s = 0;
337 ULONG nWrite = msg->writeLength;
338 UBYTE *WriteBuffer = msg->writeBuffer;
339 ULONG nRead = msg->readLength;
340 UBYTE *ReadBuffer = msg->readBuffer;
342 LOCK_HW
344 if (r && nWrite > 0) {
345 r = I2C_Address(o, msg->device, dev->address & ~1);
346 if (r) {
347 for (; nWrite > 0; WriteBuffer++, nWrite--)
348 if (!(r = I2C_PutByte(o, msg->device, *WriteBuffer)))
349 break;
350 s++;
354 if (r && nRead > 0) {
355 r = I2C_Address(o, msg->device, dev->address | 1);
356 if (r) {
357 for (; nRead > 0; ReadBuffer++, nRead--)
358 if (!(r = I2C_GetByte(o, msg->device, ReadBuffer, nRead == 1)))
359 break;
360 s++;
364 if (s) I2C_Stop(o, msg->device);
366 UNLOCK_HW
368 return r;
371 /*** Root */
373 void METHOD(I2C, Root, Get)
375 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
377 ULONG idx;
379 if (IS_I2C_ATTR(msg->attrID, idx))
381 switch (idx)
383 case aoHidd_I2C_HoldTime:
384 *msg->storage = drv->HoldTime;
385 break;
387 case aoHidd_I2C_BitTimeout:
388 *msg->storage = drv->BitTimeout;
389 break;
391 case aoHidd_I2C_ByteTimeout:
392 *msg->storage = drv->ByteTimeout;
393 break;
395 case aoHidd_I2C_AcknTimeout:
396 *msg->storage = drv->AcknTimeout;
397 break;
399 case aoHidd_I2C_StartTimeout:
400 *msg->storage = drv->StartTimeout;
401 break;
403 case aoHidd_I2C_RiseFallTime:
404 *msg->storage = drv->RiseFallTime;
405 break;
407 case aoHidd_I2C_Name:
408 *msg->storage = (IPTR)drv->name;
409 break;
412 else
414 OOP_DoSuperMethod(cl, o, (OOP_Msg)msg);
418 void METHOD(I2C, Root, Set)
420 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
422 ULONG idx;
423 struct TagItem *tag;
424 struct TagItem *tags = msg->attrList;
426 while ((tag = NextTagItem(&tags)))
428 if (IS_I2C_ATTR(tag->ti_Tag, idx))
430 switch (idx)
432 case aoHidd_I2C_HoldTime:
433 drv->HoldTime = tag->ti_Data;
434 break;
436 case aoHidd_I2C_BitTimeout:
437 drv->BitTimeout = tag->ti_Data;
438 break;
440 case aoHidd_I2C_ByteTimeout:
441 drv->ByteTimeout = tag->ti_Data;
442 break;
444 case aoHidd_I2C_AcknTimeout:
445 drv->AcknTimeout = tag->ti_Data;
446 break;
448 case aoHidd_I2C_StartTimeout:
449 drv->StartTimeout = tag->ti_Data;
450 break;
452 case aoHidd_I2C_RiseFallTime:
453 drv->RiseFallTime = tag->ti_Data;
454 break;
460 OOP_Object *METHOD(I2C, Root, New)
462 D(bug("[I2C] new()\n"));
464 o = (OOP_Object *)OOP_DoSuperMethod(cl, o, (OOP_Msg) msg);
465 if (o)
467 tDrvData *drv = (tDrvData *)OOP_INST_DATA(cl, o);
468 struct TagItem *tag, *tags = msg->attrList;
470 drv->HoldTime = 5;
471 drv->AcknTimeout = 5;
472 drv->BitTimeout = 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"));
500 tags=msg->attrList;
502 while((tag = NextTagItem(&tags)))
504 ULONG idx;
506 if (IS_I2C_ATTR(tag->ti_Tag, idx))
508 switch(idx)
510 case aoHidd_I2C_Name:
511 drv->name = (STRPTR)tag->ti_Data;
512 break;
514 case aoHidd_I2C_HoldTime:
515 drv->HoldTime = tag->ti_Data;
516 break;
518 case aoHidd_I2C_BitTimeout:
519 drv->BitTimeout = tag->ti_Data;
520 break;
522 case aoHidd_I2C_ByteTimeout:
523 drv->ByteTimeout = tag->ti_Data;
524 break;
526 case aoHidd_I2C_AcknTimeout:
527 drv->AcknTimeout = tag->ti_Data;
528 break;
530 case aoHidd_I2C_StartTimeout:
531 drv->StartTimeout = tag->ti_Data;
532 break;
534 case aoHidd_I2C_RiseFallTime:
535 drv->RiseFallTime = tag->ti_Data;
536 break;
541 else
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);
546 o = NULL;
551 return o;
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 */
567 //#undef UtilityBase
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);
578 return TRUE;
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"));
592 return TRUE;
595 return FALSE;
598 ADD2INITLIB(I2C_InitClass, 0)
599 ADD2EXPUNGELIB(I2C_ExpungeClass, 0)