|
1 // Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // \omap3530\omap3530_assp\shared\tps65950\tps65950.cpp |
|
15 // Access driver for TPS65950 |
|
16 // This file is part of the Beagle Base port |
|
17 // |
|
18 |
|
19 #include <e32cmn.h> |
|
20 #include <kernel.h> |
|
21 #include <nk_priv.h> |
|
22 //#include <e32atomics.h> |
|
23 #include <omap3530_i2c.h> |
|
24 #include <omap3530_i2creg.h> |
|
25 #include "tps65950.h" |
|
26 |
|
27 |
|
28 GLREF_C TInt InitInterrupts(); |
|
29 |
|
30 |
|
31 const TUint KGroupCount = 5; |
|
32 |
|
33 // One handle per group on TPS65950 |
|
34 static I2c::THandle I2cHandle[ KGroupCount ]; |
|
35 |
|
36 // One DCB per group |
|
37 static I2c::TConfigPb TheDcb[ KGroupCount ]; |
|
38 |
|
39 // I2C transfer object |
|
40 enum TPhase |
|
41 { |
|
42 EAddressPb, |
|
43 EDataPb |
|
44 }; |
|
45 static I2c::TTransferPb TheTransferPb[2]; |
|
46 |
|
47 // Group index to Group number |
|
48 static const TUint8 KGroupIndexToGroupNumber[ KGroupCount ] = |
|
49 { 0x12, 0x48, 0x49, 0x4a, 0x4b }; |
|
50 |
|
51 // Queue of requests |
|
52 static SDblQue TheQueue; |
|
53 |
|
54 // Current state |
|
55 enum TState |
|
56 { |
|
57 EIdle, |
|
58 EPending, |
|
59 EReading, |
|
60 EWriting, |
|
61 EUnprotectPhase0 |
|
62 }; |
|
63 static TState CurrentState; |
|
64 TPS65950::TReq* CurrentPhaseReq; |
|
65 TPS65950::TReq* PreviousPhaseReq; |
|
66 |
|
67 LOCAL_D TUint8 IsInitialized; // auto-cleared to EFalse |
|
68 |
|
69 const TUint8 KUnprotectPhase0Data = 0xCE; |
|
70 const TUint8 KUnprotectPhase1Data = 0xEC; |
|
71 |
|
72 static const TUint8 KUnprotectData[4] = |
|
73 { |
|
74 TPS65950::Register::PROTECT_KEY bitand TPS65950::Register::KRegisterMask, KUnprotectPhase0Data, |
|
75 TPS65950::Register::PROTECT_KEY bitand TPS65950::Register::KRegisterMask, KUnprotectPhase1Data, |
|
76 }; |
|
77 |
|
78 static const TUint8 KProtectData[2] = |
|
79 { |
|
80 TPS65950::Register::PROTECT_KEY bitand TPS65950::Register::KRegisterMask, 0 |
|
81 }; |
|
82 |
|
83 static TUint8 TempWriteBuf[2]; |
|
84 |
|
85 // Spinlock to protect queue when adding or removing items |
|
86 //static TSpinLock QueueLock(TSpinLock::EOrderGenericIrqLow1+1); |
|
87 static TSpinLock QueueLock(); |
|
88 |
|
89 GLDEF_D TDfcQue* TheDfcQue; |
|
90 |
|
91 const TInt KDfcQuePriority = 27; |
|
92 _LIT( KDriverNameDes, "tps65950" ); |
|
93 |
|
94 TInt TheProtectionUsageCount = 0; |
|
95 |
|
96 |
|
97 |
|
98 LOCAL_C void InternalPanic( TInt aLine ) |
|
99 { |
|
100 Kern::Fault( "tps65950", aLine ); |
|
101 } |
|
102 |
|
103 LOCAL_C void PanicClient( TPS65950::TPanic aPanic ) |
|
104 { |
|
105 Kern::PanicCurrentThread( KDriverNameDes, aPanic ); |
|
106 } |
|
107 |
|
108 namespace TPS65950 |
|
109 { |
|
110 void CompletionDfcFunction( TAny* aParam ); |
|
111 void SyncDfcFunction( TAny* aParam ); |
|
112 void DummyDfcFunction( TAny* aParam ); |
|
113 static TDfc CompletionDfc( CompletionDfcFunction, NULL, 1 ); |
|
114 static TDfc DummyDfc( CompletionDfcFunction, NULL, 1 ); |
|
115 |
|
116 FORCE_INLINE TReq& ReqFromLink( SDblQueLink* aLink ) |
|
117 { |
|
118 return *_LOFF( aLink, TReq, iLink ); |
|
119 } |
|
120 |
|
121 inline TBool AtomicSetPendingWasIdle() |
|
122 { |
|
123 // atomic if (CurrentState == idleState) {CurrentState=EPending, returns TRUE} else {idleState=CurrentState, CurrentState unchanged, return FALSE} |
|
124 TState idleState = EIdle; // required for atomic comparison |
|
125 //TBool wasIdle = __e32_atomic_cas_ord32( (TUint32*)&CurrentState, (TUint32*)&idleState, EPending ); |
|
126 //return wasIdle; |
|
127 |
|
128 if (CurrentState == idleState) |
|
129 { |
|
130 CurrentState = EPending; |
|
131 return ETrue; |
|
132 } |
|
133 else |
|
134 { |
|
135 idleState = CurrentState; |
|
136 return EFalse; |
|
137 } |
|
138 |
|
139 } |
|
140 |
|
141 |
|
142 void StartRead( TReq& aReq ) |
|
143 { |
|
144 __KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:StartRead(@%x) [%x:%x]", |
|
145 &aReq, |
|
146 KGroupIndexToGroupNumber[ aReq.iRegister >> Register::KGroupShift ], |
|
147 aReq.iRegister bitand Register::KRegisterMask ) ); |
|
148 |
|
149 //__e32_atomic_store_ord32( &CurrentState, EReading ); |
|
150 CurrentState = EReading; |
|
151 |
|
152 TheTransferPb[ EAddressPb ].iData = (TUint8*)&aReq.iRegister; // low byte is register address |
|
153 TheTransferPb[ EDataPb ].iType = I2c::TTransferPb::ERead; |
|
154 TheTransferPb[ EDataPb ].iData = &aReq.iReadValue; |
|
155 __DEBUG_ONLY( aReq.iReadValue = 0xEE ); |
|
156 TheTransferPb[ EDataPb ].iLength = 1; |
|
157 TheTransferPb[ EAddressPb ].iResult = KErrNone; |
|
158 TheTransferPb[ EDataPb ].iResult = KErrNone; |
|
159 |
|
160 TUint groupIndex = aReq.iRegister >> Register::KGroupShift; |
|
161 I2c::TransferA( I2cHandle[ groupIndex ], TheTransferPb[ EAddressPb ] ); |
|
162 |
|
163 __KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:StartRead(@%x)", &aReq ) ); |
|
164 } |
|
165 |
|
166 void StartWrite( TReq& aReq ) |
|
167 { |
|
168 __KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:StartWrite(@%x) [%x:%x]<-%x", |
|
169 &aReq, |
|
170 KGroupIndexToGroupNumber[ aReq.iRegister >> Register::KGroupShift ], |
|
171 aReq.iRegister bitand Register::KRegisterMask, |
|
172 aReq.iWriteValue ) ); |
|
173 |
|
174 //__e32_atomic_store_ord32( &CurrentState, EWriting ); |
|
175 CurrentState = EWriting; |
|
176 |
|
177 TempWriteBuf[0] = aReq.iRegister bitand Register::KRegisterMask; |
|
178 TempWriteBuf[1] = aReq.iWriteValue; |
|
179 TheTransferPb[ EDataPb ].iType = I2c::TTransferPb::EWrite; |
|
180 TheTransferPb[ EDataPb ].iData = &TempWriteBuf[0]; |
|
181 TheTransferPb[ EDataPb ].iLength = 2; |
|
182 TheTransferPb[ EDataPb ].iResult = KErrNone; |
|
183 |
|
184 TUint groupIndex = aReq.iRegister >> Register::KGroupShift; |
|
185 I2c::TransferA( I2cHandle[ groupIndex ], TheTransferPb[ EDataPb ] ); |
|
186 |
|
187 __KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:StartWrite(@%x)", &aReq ) ); |
|
188 } |
|
189 |
|
190 void StartUnprotectPhase0( TReq& aReq ) |
|
191 { |
|
192 __KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:StartUnprotectPhase0(@%x)", &aReq ) ); |
|
193 |
|
194 //__e32_atomic_store_ord32( &CurrentState, EUnprotectPhase0 ); |
|
195 CurrentState = EUnprotectPhase0; |
|
196 |
|
197 TheTransferPb[ EDataPb ].iType = I2c::TTransferPb::EWrite; |
|
198 TheTransferPb[ EDataPb ].iData = &KUnprotectData[0]; |
|
199 TheTransferPb[ EDataPb ].iLength = 2; |
|
200 TheTransferPb[ EDataPb ].iResult = KErrNone; |
|
201 |
|
202 const TUint groupIndex = Register::PROTECT_KEY >> Register::KGroupShift; |
|
203 I2c::TransferA( I2cHandle[ groupIndex ], TheTransferPb[ EDataPb ] ); |
|
204 |
|
205 __KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:StartUnprotectPhase0(@%x)", &aReq ) ); |
|
206 } |
|
207 |
|
208 void StartUnprotectPhase1( TReq& aReq ) |
|
209 { |
|
210 __KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:StartUnprotectPhase1(@%x)", &aReq ) ); |
|
211 |
|
212 // Set state to writing so that it will complete as a normal write |
|
213 //__e32_atomic_store_ord32( &CurrentState, EWriting ); |
|
214 CurrentState = EWriting; |
|
215 |
|
216 TheTransferPb[ EDataPb ].iData = &KUnprotectData[2]; |
|
217 TheTransferPb[ EDataPb ].iResult = KErrNone; |
|
218 |
|
219 const TUint groupIndex = Register::PROTECT_KEY >> Register::KGroupShift; |
|
220 I2c::TransferA( I2cHandle[ groupIndex ], TheTransferPb[ EDataPb ] ); |
|
221 |
|
222 __KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:StartUnprotectPhase1(@%x)", &aReq ) ); |
|
223 } |
|
224 |
|
225 void StartProtect( TReq& aReq ) |
|
226 { |
|
227 __KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:StartProtect(@%x)", &aReq ) ); |
|
228 |
|
229 //__e32_atomic_store_ord32( &CurrentState, EWriting ); |
|
230 CurrentState = EWriting; |
|
231 |
|
232 TheTransferPb[ EDataPb ].iType = I2c::TTransferPb::EWrite; |
|
233 TheTransferPb[ EDataPb ].iData = &KProtectData[0]; |
|
234 TheTransferPb[ EDataPb ].iLength = 2; |
|
235 TheTransferPb[ EDataPb ].iResult = KErrNone; |
|
236 |
|
237 const TUint groupIndex = Register::PROTECT_KEY >> Register::KGroupShift; |
|
238 I2c::TransferA( I2cHandle[ groupIndex ], TheTransferPb[ EDataPb ] ); |
|
239 |
|
240 __KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:StartWrite(@%x)", &aReq ) ); |
|
241 } |
|
242 |
|
243 |
|
244 void StartRequest() |
|
245 { |
|
246 __KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:StartRequest(%d)", CurrentState ) ); |
|
247 __ASSERT_DEBUG( EPending == CurrentState, InternalPanic( __LINE__ ) ); |
|
248 |
|
249 // We don't need to take lock here because we're currently idle so it's not possible |
|
250 // for there to be a change in which item is queue head. The link pointers of the |
|
251 // head item could change if another thread is queueing a new request, but that doesn't |
|
252 // affect any of the fields we care about here |
|
253 __ASSERT_DEBUG( !TheQueue.IsEmpty(), InternalPanic( __LINE__ ) ); |
|
254 |
|
255 if( !CurrentPhaseReq ) |
|
256 { |
|
257 PreviousPhaseReq = NULL; |
|
258 CurrentPhaseReq = &ReqFromLink( TheQueue.First() ); |
|
259 } |
|
260 |
|
261 FOREVER |
|
262 { |
|
263 if( !CurrentPhaseReq ) |
|
264 { |
|
265 __ASSERT_DEBUG( PreviousPhaseReq, InternalPanic( __LINE__ ) ); |
|
266 |
|
267 // we didn't find any phases to execute, so complete request |
|
268 // by faking a write completion on the previous phase |
|
269 CurrentPhaseReq = PreviousPhaseReq; |
|
270 //__e32_atomic_store_ord32( &CurrentState, EWriting ); |
|
271 CurrentState = EWriting; |
|
272 |
|
273 // Queue DFC instead of calling directly to avoid recursion if multiple items on queue |
|
274 // complete without any action |
|
275 CompletionDfc.Enque(); |
|
276 break; |
|
277 } |
|
278 else |
|
279 { |
|
280 TReq::TAction action = CurrentPhaseReq->iAction; |
|
281 |
|
282 __KTRACE_OPT( KTPS65950, Kern::Printf( "=TPS65950:StartRequest:req@%x:a=%x", CurrentPhaseReq, action ) ); |
|
283 |
|
284 if( (TReq::ERead == action) || (TReq::EClearSet == action) ) |
|
285 { |
|
286 StartRead( *CurrentPhaseReq ); |
|
287 break; |
|
288 } |
|
289 else if( TReq::EWrite == action ) |
|
290 { |
|
291 StartWrite( *CurrentPhaseReq ); |
|
292 break; |
|
293 } |
|
294 else if( TReq::EDisableProtect == action ) |
|
295 { |
|
296 if( ++TheProtectionUsageCount == 1 ) |
|
297 { |
|
298 // Currently protected, start an unprotect sequence |
|
299 StartUnprotectPhase0( *CurrentPhaseReq ); |
|
300 break; |
|
301 } |
|
302 else |
|
303 { |
|
304 goto move_to_next_phase; |
|
305 } |
|
306 } |
|
307 else if( TReq::ERestoreProtect == action ) |
|
308 { |
|
309 if( --TheProtectionUsageCount == 0 ) |
|
310 { |
|
311 StartProtect( *CurrentPhaseReq ); |
|
312 break; |
|
313 } |
|
314 else |
|
315 { |
|
316 move_to_next_phase: |
|
317 // already unprotected, skip to next phase |
|
318 CurrentPhaseReq->iResult = KErrNone; |
|
319 PreviousPhaseReq = CurrentPhaseReq; |
|
320 CurrentPhaseReq = CurrentPhaseReq->iNextPhase; |
|
321 } |
|
322 } |
|
323 else |
|
324 { |
|
325 InternalPanic( __LINE__ ); |
|
326 } |
|
327 } |
|
328 } |
|
329 |
|
330 |
|
331 __KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:StartRequest(%d)", CurrentState ) ); |
|
332 } |
|
333 |
|
334 void DummyDfcFunction( TAny* /*aParam*/ ) |
|
335 { |
|
336 __KTRACE_OPT( KTPS65950, Kern::Printf( "TPS65950:DummyDFC(%d)", CurrentState ) ); |
|
337 } |
|
338 |
|
339 void CompletionDfcFunction( TAny* /*aParam*/ ) |
|
340 { |
|
341 __KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:DFC(%d)", CurrentState ) ); |
|
342 __ASSERT_DEBUG( EIdle != CurrentState, InternalPanic( __LINE__ ) ); |
|
343 __ASSERT_DEBUG( CurrentPhaseReq, InternalPanic( __LINE__ ) ); |
|
344 |
|
345 TInt result = TheTransferPb[ EDataPb ].iResult; |
|
346 if( KErrNone != TheTransferPb[ EAddressPb ].iResult ) |
|
347 { |
|
348 result = TheTransferPb[ EAddressPb ].iResult; |
|
349 } |
|
350 |
|
351 TReq& req = *CurrentPhaseReq; |
|
352 TBool completed = ETrue; |
|
353 |
|
354 if( KErrNone == result) |
|
355 { |
|
356 if( EReading == CurrentState ) |
|
357 { |
|
358 __KTRACE_OPT( KTPS65950, Kern::Printf( "=TPS65950:DFC:Read [%x:%x]=%x", |
|
359 KGroupIndexToGroupNumber[ req.iRegister >> Register::KGroupShift ], |
|
360 req.iRegister bitand Register::KRegisterMask, |
|
361 req.iReadValue ) ); |
|
362 |
|
363 if( TReq::EClearSet == req.iAction) |
|
364 { |
|
365 // Start write phase of a ClearSet |
|
366 req.iWriteValue = (req.iReadValue bitand ~req.iClearMask) bitor req.iSetMask; |
|
367 StartWrite( req ); |
|
368 completed = EFalse; |
|
369 } |
|
370 } |
|
371 else if( EUnprotectPhase0 == CurrentState ) |
|
372 { |
|
373 StartUnprotectPhase1( req ); |
|
374 completed = EFalse; |
|
375 } |
|
376 } |
|
377 |
|
378 if( completed || (KErrNone != result) ) |
|
379 { |
|
380 // Read or write, protect has completed, or final write stage of a ClearSet or unprotect, or error |
|
381 PreviousPhaseReq = CurrentPhaseReq; |
|
382 CurrentPhaseReq = req.iNextPhase; |
|
383 |
|
384 if( CurrentPhaseReq ) |
|
385 { |
|
386 // start next phase |
|
387 //__e32_atomic_store_ord32( &CurrentState, EPending ); |
|
388 CurrentState = EPending; |
|
389 StartRequest(); |
|
390 } |
|
391 else |
|
392 { |
|
393 //__e32_atomic_store_ord32( &CurrentState, EIdle ); |
|
394 CurrentState = EIdle; |
|
395 // From now a concurrent ExecAsync() can start a new request if it adds an item to the queue |
|
396 |
|
397 // remove item from queue and complete |
|
398 TUint irq = __SPIN_LOCK_IRQSAVE( QueueLock ); |
|
399 ReqFromLink( TheQueue.First() ).iLink.Deque(); |
|
400 TBool queueEmpty = TheQueue.IsEmpty(); |
|
401 __SPIN_UNLOCK_IRQRESTORE( QueueLock, irq ); |
|
402 |
|
403 // If queue was empty inside spinlock but an ExecAsync() adds an item before the if statement below, |
|
404 // the ExecAsync() will start the new request |
|
405 if( !queueEmpty ) |
|
406 { |
|
407 if( AtomicSetPendingWasIdle() ) |
|
408 { |
|
409 // ExecAsync didn't start a request |
|
410 StartRequest(); |
|
411 } |
|
412 } |
|
413 |
|
414 // Notify client of completion |
|
415 req.iResult = result; |
|
416 if( req.iCompletionDfc ) |
|
417 { |
|
418 req.iCompletionDfc->Enque(); |
|
419 } |
|
420 } |
|
421 } |
|
422 |
|
423 __KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:DFC(%d)", CurrentState ) ); |
|
424 } |
|
425 |
|
426 // Used to complete synchronous operations |
|
427 void SyncDfcFunction( TAny* aParam ) |
|
428 { |
|
429 NKern::FSSignal( reinterpret_cast<NFastSemaphore*>( aParam ) ); |
|
430 } |
|
431 |
|
432 |
|
433 EXPORT_C void ExecAsync( TReq& aRequest ) |
|
434 { |
|
435 __KTRACE_OPT( KTPS65950, Kern::Printf( "+TPS65950:ExecAsync(@%x)", &aRequest ) ); |
|
436 |
|
437 __ASSERT_DEBUG( (TUint)aRequest.iAction <= TReq::ERestoreProtect, PanicClient( EBadAction ) ); |
|
438 __ASSERT_DEBUG( (TReq::EDisableProtect == aRequest.iAction) |
|
439 || (TReq::ERestoreProtect == aRequest.iAction) |
|
440 || (((TUint)aRequest.iRegister >> Register::KGroupShift) < KGroupCount), PanicClient( EBadGroup ) ); |
|
441 |
|
442 TUint irq = __SPIN_LOCK_IRQSAVE( QueueLock ); |
|
443 TheQueue.Add( &aRequest.iLink ); |
|
444 __SPIN_UNLOCK_IRQRESTORE( QueueLock, irq ); |
|
445 |
|
446 if( AtomicSetPendingWasIdle() ) |
|
447 { |
|
448 StartRequest(); |
|
449 } |
|
450 |
|
451 __KTRACE_OPT( KTPS65950, Kern::Printf( "-TPS65950:ExecAsync" ) ); |
|
452 } |
|
453 |
|
454 EXPORT_C TInt WriteSync( TUint16 aRegister, TUint8 aValue ) |
|
455 { |
|
456 __ASSERT_NO_FAST_MUTEX; |
|
457 |
|
458 NFastSemaphore sem; |
|
459 TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 ); |
|
460 TReq req; |
|
461 req.iRegister = aRegister; |
|
462 req.iAction = TReq::EWrite; |
|
463 req.iCompletionDfc = &dfc; |
|
464 req.iWriteValue = aValue; |
|
465 req.iNextPhase = NULL; |
|
466 |
|
467 NKern::FSSetOwner( &sem, NULL ); |
|
468 ExecAsync( req ); |
|
469 NKern::FSWait( &sem ); |
|
470 |
|
471 return req.iResult; |
|
472 } |
|
473 |
|
474 EXPORT_C TInt ReadSync( TUint16 aRegister, TUint8& aValue ) |
|
475 { |
|
476 __ASSERT_NO_FAST_MUTEX; |
|
477 |
|
478 NFastSemaphore sem; |
|
479 TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 ); |
|
480 TReq req; |
|
481 req.iRegister = aRegister; |
|
482 req.iAction = TReq::ERead; |
|
483 req.iCompletionDfc = &dfc; |
|
484 req.iNextPhase = NULL; |
|
485 |
|
486 NKern::FSSetOwner( &sem, NULL ); |
|
487 ExecAsync( req ); |
|
488 NKern::FSWait( &sem ); |
|
489 |
|
490 aValue = req.iReadValue; |
|
491 return req.iResult; |
|
492 } |
|
493 |
|
494 EXPORT_C TInt ClearSetSync( TUint16 aRegister, TUint8 aClearMask, TUint8 aSetMask ) |
|
495 { |
|
496 __ASSERT_NO_FAST_MUTEX; |
|
497 |
|
498 NFastSemaphore sem; |
|
499 TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 ); |
|
500 TReq req; |
|
501 req.iRegister = aRegister; |
|
502 req.iAction = TReq::EClearSet; |
|
503 req.iCompletionDfc = &dfc; |
|
504 req.iClearMask = aClearMask; |
|
505 req.iSetMask = aSetMask; |
|
506 req.iNextPhase = NULL; |
|
507 |
|
508 NKern::FSSetOwner( &sem, NULL ); |
|
509 ExecAsync( req ); |
|
510 NKern::FSWait( &sem ); |
|
511 |
|
512 return req.iResult; |
|
513 } |
|
514 |
|
515 EXPORT_C TInt DisableProtect() |
|
516 { |
|
517 __ASSERT_NO_FAST_MUTEX; |
|
518 |
|
519 NFastSemaphore sem; |
|
520 TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 ); |
|
521 TReq req; |
|
522 req.iAction = TReq::EDisableProtect; |
|
523 req.iCompletionDfc = &dfc; |
|
524 req.iNextPhase = NULL; |
|
525 |
|
526 NKern::FSSetOwner( &sem, NULL ); |
|
527 ExecAsync( req ); |
|
528 NKern::FSWait( &sem ); |
|
529 |
|
530 return req.iResult; |
|
531 } |
|
532 |
|
533 EXPORT_C TInt RestoreProtect() |
|
534 { |
|
535 __ASSERT_NO_FAST_MUTEX; |
|
536 |
|
537 NFastSemaphore sem; |
|
538 TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 ); |
|
539 TReq req; |
|
540 req.iAction = TReq::ERestoreProtect; |
|
541 req.iCompletionDfc = &dfc; |
|
542 req.iNextPhase = NULL; |
|
543 |
|
544 NKern::FSSetOwner( &sem, NULL ); |
|
545 ExecAsync( req ); |
|
546 NKern::FSWait( &sem ); |
|
547 |
|
548 return req.iResult; |
|
549 } |
|
550 |
|
551 |
|
552 TInt Init() |
|
553 { |
|
554 // Create DFC queue |
|
555 TInt r = Kern::DfcQCreate( TheDfcQue, KDfcQuePriority, &KDriverNameDes ); |
|
556 if( KErrNone != r ) |
|
557 { |
|
558 return r; |
|
559 } |
|
560 |
|
561 TPS65950::CompletionDfc.SetDfcQ( TheDfcQue ); |
|
562 TPS65950::DummyDfc.SetDfcQ( TheDfcQue ); |
|
563 |
|
564 // Open I2c handles |
|
565 for( TInt i = 0; i < KGroupCount; ++i ) |
|
566 { |
|
567 TheDcb[i].iUnit = I2c::E1; // Master / slave |
|
568 TheDcb[i].iRole = I2c::EMaster; |
|
569 TheDcb[i].iMode = I2c::E7Bit; |
|
570 TheDcb[i].iExclusiveClient = NULL; |
|
571 TheDcb[i].iRate = I2c::E400K; |
|
572 TheDcb[i].iOwnAddress = 0x01; |
|
573 TheDcb[i].iDfcQueue = TheDfcQue; |
|
574 TheDcb[i].iDeviceAddress = KGroupIndexToGroupNumber[i]; |
|
575 |
|
576 I2cHandle[i] = I2c::Open( TheDcb[i] ); |
|
577 if( I2cHandle[i] < 0 ) |
|
578 { |
|
579 return I2cHandle[i]; |
|
580 } |
|
581 } |
|
582 |
|
583 // Setup transfer linked list |
|
584 TheTransferPb[ EAddressPb ].iType = I2c::TTransferPb::EWrite; // address write |
|
585 TheTransferPb[ EAddressPb ].iLength = 1; |
|
586 TheTransferPb[ EAddressPb ].iCompletionDfc = &TPS65950::DummyDfc; |
|
587 TheTransferPb[ EAddressPb ].iNextPhase = &TheTransferPb[ EDataPb ]; |
|
588 TheTransferPb[ EDataPb ].iCompletionDfc = &TPS65950::CompletionDfc; |
|
589 TheTransferPb[ EDataPb ].iNextPhase = NULL; |
|
590 |
|
591 return r; |
|
592 } |
|
593 |
|
594 inline TInt BcdToDecimal( TUint8 aBcd ) |
|
595 { |
|
596 return ( aBcd bitand 0xF ) + ( (aBcd >> 4) * 10); |
|
597 } |
|
598 |
|
599 inline TUint8 DecimalToBcd( TInt aDecimal ) |
|
600 { |
|
601 TUint tens = (aDecimal / 10); |
|
602 return ( tens << 4 ) + ( aDecimal - tens ); |
|
603 } |
|
604 |
|
605 EXPORT_C TInt GetRtcData( TRtcTime& aTime ) |
|
606 { |
|
607 __ASSERT_NO_FAST_MUTEX; |
|
608 |
|
609 NFastSemaphore sem; |
|
610 TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 ); |
|
611 TReq req[8]; // 9 stages to the operation |
|
612 req[0].iRegister = RTC_CTRL_REG::Addr; |
|
613 req[0].iAction = TReq::EClearSet; |
|
614 req[0].iSetMask = RTC_CTRL_REG::GET_TIME; |
|
615 req[0].iClearMask = 0; |
|
616 req[0].iCompletionDfc = NULL; |
|
617 req[0].iNextPhase = &req[1]; |
|
618 |
|
619 req[1].iRegister = Register::SECONDS_REG; |
|
620 req[1].iAction = TReq::ERead; |
|
621 req[1].iCompletionDfc = NULL; |
|
622 req[1].iNextPhase = &req[2]; |
|
623 |
|
624 req[2].iRegister = Register::MINUTES_REG; |
|
625 req[2].iAction = TReq::ERead; |
|
626 req[2].iCompletionDfc = NULL; |
|
627 req[2].iNextPhase = &req[3]; |
|
628 |
|
629 req[3].iRegister = Register::HOURS_REG; |
|
630 req[3].iAction = TReq::ERead; |
|
631 req[3].iCompletionDfc = NULL; |
|
632 req[3].iNextPhase = &req[4]; |
|
633 |
|
634 req[4].iRegister = Register::DAYS_REG; |
|
635 req[4].iAction = TReq::ERead; |
|
636 req[4].iCompletionDfc = NULL; |
|
637 req[4].iNextPhase = &req[5]; |
|
638 |
|
639 req[5].iRegister = Register::MONTHS_REG; |
|
640 req[5].iAction = TReq::ERead; |
|
641 req[5].iCompletionDfc = NULL; |
|
642 req[5].iNextPhase = &req[6]; |
|
643 |
|
644 req[6].iRegister = Register::YEARS_REG; |
|
645 req[6].iAction = TReq::ERead; |
|
646 req[6].iCompletionDfc = NULL; |
|
647 req[6].iNextPhase = &req[7]; |
|
648 |
|
649 req[7].iRegister = RTC_CTRL_REG::Addr; |
|
650 req[7].iAction = TReq::EClearSet; |
|
651 req[7].iSetMask = 0; |
|
652 req[7].iClearMask = RTC_CTRL_REG::GET_TIME; |
|
653 req[7].iCompletionDfc = &dfc; |
|
654 req[7].iNextPhase = NULL; |
|
655 |
|
656 NKern::FSSetOwner( &sem, NULL ); |
|
657 ExecAsync( req[0] ); |
|
658 NKern::FSWait( &sem ); |
|
659 |
|
660 aTime.iSecond = BcdToDecimal( req[1].iReadValue ); |
|
661 aTime.iMinute = BcdToDecimal( req[2].iReadValue ); |
|
662 aTime.iHour = BcdToDecimal( req[3].iReadValue ); |
|
663 aTime.iDay = BcdToDecimal( req[4].iReadValue ); |
|
664 aTime.iMonth = BcdToDecimal( req[5].iReadValue ); |
|
665 aTime.iYear = BcdToDecimal( req[6].iReadValue ); |
|
666 |
|
667 return KErrNone; |
|
668 } |
|
669 |
|
670 #define BCD0(a) ((a)%10) |
|
671 #define BCD1(a) (((a)/10)<<4) |
|
672 #define TOBCD(i) (BCD1(i)|BCD0(i)) |
|
673 |
|
674 EXPORT_C TInt SetRtcData( const TRtcTime& aTime ) |
|
675 { |
|
676 __ASSERT_NO_FAST_MUTEX; |
|
677 |
|
678 NFastSemaphore sem; |
|
679 TDfc dfc( SyncDfcFunction, &sem, TheDfcQue, 2 ); |
|
680 TReq req[8]; // 9 stages to the operation |
|
681 req[0].iRegister = RTC_CTRL_REG::Addr; |
|
682 req[0].iAction = TReq::EClearSet; |
|
683 req[0].iSetMask = 0; |
|
684 req[0].iClearMask = RTC_CTRL_REG::STOP_RTC; |
|
685 req[0].iCompletionDfc = NULL; |
|
686 req[0].iNextPhase = &req[1]; |
|
687 |
|
688 req[1].iRegister = Register::SECONDS_REG; |
|
689 req[1].iAction = TReq::EWrite; |
|
690 req[1].iWriteValue = DecimalToBcd( aTime.iSecond ); |
|
691 req[1].iCompletionDfc = NULL; |
|
692 req[1].iNextPhase = &req[2]; |
|
693 |
|
694 req[2].iRegister = Register::MINUTES_REG; |
|
695 req[2].iAction = TReq::EWrite; |
|
696 req[2].iWriteValue = DecimalToBcd( aTime.iMinute ); |
|
697 req[2].iCompletionDfc = NULL; |
|
698 req[2].iNextPhase = &req[3]; |
|
699 |
|
700 req[3].iRegister = Register::HOURS_REG; |
|
701 req[3].iAction = TReq::EWrite; |
|
702 req[3].iWriteValue = DecimalToBcd( aTime.iHour ); |
|
703 req[3].iCompletionDfc = NULL; |
|
704 req[3].iNextPhase = &req[4]; |
|
705 |
|
706 req[4].iRegister = Register::DAYS_REG; |
|
707 req[4].iAction = TReq::EWrite; |
|
708 req[4].iWriteValue = DecimalToBcd( aTime.iDay ); |
|
709 req[4].iCompletionDfc = NULL; |
|
710 req[4].iNextPhase = &req[5]; |
|
711 |
|
712 req[5].iRegister = Register::MONTHS_REG; |
|
713 req[5].iAction = TReq::EWrite; |
|
714 req[5].iWriteValue = DecimalToBcd( aTime.iMonth ); |
|
715 req[5].iCompletionDfc = NULL; |
|
716 req[5].iNextPhase = &req[6]; |
|
717 |
|
718 req[6].iRegister = Register::YEARS_REG; |
|
719 req[6].iAction = TReq::EWrite; |
|
720 req[6].iWriteValue = DecimalToBcd( aTime.iYear ); |
|
721 req[6].iCompletionDfc = NULL; |
|
722 req[6].iNextPhase = &req[7]; |
|
723 |
|
724 req[7].iRegister = RTC_CTRL_REG::Addr; |
|
725 req[7].iAction = TReq::EClearSet; |
|
726 req[7].iSetMask = RTC_CTRL_REG::STOP_RTC; |
|
727 req[7].iClearMask = 0; |
|
728 req[7].iCompletionDfc = &dfc; |
|
729 req[7].iNextPhase = NULL; |
|
730 |
|
731 NKern::FSSetOwner( &sem, NULL ); |
|
732 ExecAsync( req[0] ); |
|
733 NKern::FSWait( &sem ); |
|
734 |
|
735 return KErrNone; |
|
736 } |
|
737 |
|
738 EXPORT_C TBool Initialized() |
|
739 { |
|
740 return IsInitialized; |
|
741 } |
|
742 |
|
743 } // namespace TPS65950 |
|
744 |
|
745 |
|
746 |
|
747 |
|
748 DECLARE_STANDARD_EXTENSION() |
|
749 { |
|
750 TInt r = TPS65950::Init(); |
|
751 if( KErrNone == r ) |
|
752 { |
|
753 r = InitInterrupts(); |
|
754 } |
|
755 |
|
756 IsInitialized = ( KErrNone == r ); |
|
757 |
|
758 return r; |
|
759 } |
|
760 |