navienginebsp/ne1_tb/specific/cs42l51.cpp
changeset 0 5de814552237
equal deleted inserted replaced
-1:000000000000 0:5de814552237
       
     1 /*
       
     2 * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  
       
    15 * ne1_tb\specific\cs42l51.cpp
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 
       
    21 #include <kernel/kern_priv.h>
       
    22 #include <naviengine.h>
       
    23 #include <naviengine_priv.h>
       
    24 #include <gpio.h>
       
    25 #include "cs42l51.h"
       
    26 
       
    27 #define __THREAD_AND_CPU 	Kern::Printf("(Thread %T, CPU: %d)\n", NKern::CurrentThread(), NKern::CurrentCpu())
       
    28 //#define __KTRACE_SCODEC(s) s
       
    29 #define __KTRACE_SCODEC(s)  __KTRACE_OPT(KSOUND1, s)
       
    30 
       
    31 
       
    32 #if _DEBUG
       
    33 static const char KCodecPanicCat[] = "AUDIO CODEC, line:";
       
    34 #endif
       
    35 
       
    36 // other constants
       
    37 const TUint KCodecCSIChannel = 0;
       
    38 const TInt8 KBufGranularity = 8; // width of a transfer word in bits
       
    39 
       
    40 // CSI configuration parameters for the data transmission to the Codec.
       
    41 const TConfigSpiV01 KCodecSpiV01Config =
       
    42 	{
       
    43 	ESpiWordWidth_8, //iWordWidth
       
    44 	260000,          //iClkSpeed
       
    45 	ESpiPolarityHighFallingEdge, //iClkMode
       
    46 	40,            // iTimeoutPeriod
       
    47 	EBigEndian,    // iEndianness
       
    48 	EMsbFirst,     // iBitOrder
       
    49 	0,             // iTransactionWaitCycles
       
    50 	ESpiCSPinActiveLow //iCsPinActiveMode
       
    51 	};
       
    52 
       
    53 // static members
       
    54 RCS42AudioCodec* RCS42AudioCodec::iSelf = 0;
       
    55 TInt RCS42AudioCodec::iRefCnt = 0;
       
    56 
       
    57 // default constructor
       
    58 RCS42AudioCodec::RCS42AudioCodec() :
       
    59 	iHeaderBuff(KCodecSpiV01Config)
       
    60 	{
       
    61 	}
       
    62 
       
    63 TInt RCS42AudioCodec::Create()
       
    64 	{
       
    65 	__KTRACE_SCODEC(Kern::Printf("\n\nRCS42AudioCodec::Create()"));
       
    66 	if (!iSelf)
       
    67 		{
       
    68 		iSelf = new RCS42AudioCodec;
       
    69 		if(!iSelf)
       
    70 			{
       
    71 			return KErrNoMemory;
       
    72 			}
       
    73 		}
       
    74 	return KErrNone;
       
    75 	}
       
    76 
       
    77 // free resources when the driver is beeing closed.
       
    78 void RCS42AudioCodec::Destroy()
       
    79 	{
       
    80 	__KTRACE_SCODEC(Kern::Printf("RCS42AudioCodec::Destroy()"));
       
    81 	__ASSERT_DEBUG(iSelf, Kern::Fault(KCodecPanicCat, __LINE__));
       
    82 
       
    83 	delete iSelf;
       
    84 	iSelf = 0; // static member
       
    85 	}
       
    86 
       
    87 // this static method is called from DNE1_TBSoundScPddChannel::PowerUp()
       
    88 // to open an instance to the codec. If this is the first instance
       
    89 // beeing opened - the codec is initialized.
       
    90 TInt RCS42AudioCodec::Open(RCS42AudioCodec* &aSelf)
       
    91 	{
       
    92 	__KTRACE_SCODEC(Kern::Printf("RCS42AudioCodec::Open()"));
       
    93 
       
    94 	TInt r = KErrNone;
       
    95 	if(!iSelf)
       
    96 		{
       
    97 		r = Create();
       
    98 		if(r != KErrNone)
       
    99 			{
       
   100 			return r;
       
   101 			}
       
   102 		}
       
   103 
       
   104 	if (iRefCnt == 0)
       
   105 		{
       
   106 		r = iSelf->Init();
       
   107 		if (r != KErrNone)
       
   108 			{
       
   109 			iSelf->PowerDown();
       
   110 			return r;
       
   111 			}
       
   112 		}
       
   113 	// increment the reference counter
       
   114 	++iRefCnt;
       
   115 
       
   116 	// copy object address back to the client
       
   117 	aSelf = iSelf;
       
   118 
       
   119 	return KErrNone;
       
   120 	}
       
   121 
       
   122 // this static method is called from DNE1_TBSoundScPddChannel::PowerDown()
       
   123 // to close the reference and power down the codec if the last reference is beeing closed.
       
   124 void RCS42AudioCodec::Close(RCS42AudioCodec* &aSelf)
       
   125 	{
       
   126 	__KTRACE_SCODEC(Kern::Printf("RCS42AudioCodec::Close()"))	;
       
   127 
       
   128 	if (!aSelf || aSelf != iSelf)
       
   129 		{
       
   130 		return;
       
   131 		}
       
   132 
       
   133 	// decrement the reference counter
       
   134 	--iRefCnt;
       
   135 
       
   136 	// if closing the last instance - power down the codec
       
   137 	if (iRefCnt == 0)
       
   138 		{
       
   139 		iSelf->PowerDown();
       
   140 		aSelf = 0;
       
   141 		Destroy();
       
   142 		}
       
   143 	}
       
   144 
       
   145 // this method powers down the codec
       
   146 void RCS42AudioCodec::PowerDown()
       
   147 	{
       
   148 	if (iSelf)
       
   149 		{
       
   150 		iSelf->StartWrite();
       
   151 		iSelf->Write(KHwCS42L51DACOutputControl,
       
   152 				KHtCS42L51DACOutputControl_DACAB_MUTE);
       
   153 
       
   154 		// - set PDN bit
       
   155 		iSelf->Write(KHwCS42L51PwrCtrl, KHtCS42L51PwrCtrl_PDN);
       
   156 
       
   157 #ifdef _DEBUG
       
   158 		TInt r = iSelf->StopWrite();
       
   159 		__ASSERT_DEBUG(r == KErrNone, Kern::Printf("Coulnd't power down the CODEC r=%d ", r));
       
   160 		__ASSERT_DEBUG(r == KErrNone, Kern::Fault(KCodecPanicCat, __LINE__));
       
   161 #else
       
   162 		iSelf->StopWrite();
       
   163 #endif
       
   164 
       
   165 		// put !reset back to low..
       
   166 		GPIO::SetOutputState(KCodecResetPin, GPIO::ELow);
       
   167 		}
       
   168 	}
       
   169 
       
   170 
       
   171 // this is an internal method - to synchronously write the data to the bus. It sets up the transfer
       
   172 // and waits for Interrupt - which puts back the CS (Chip Select) pin - to low after the
       
   173 // data was sent out of the bus.
       
   174 TInt RCS42AudioCodec::DoWrite(TUint16 aRegAddr, TUint16 aData)
       
   175 	{
       
   176 	__KTRACE_SCODEC(Kern::Printf("RCS42AudioCodec::DoWrite()"));
       
   177 	TInt r = KErrNone;
       
   178 
       
   179 	iTransBuff().iRegister = aRegAddr;
       
   180 	iTransBuff().iData = aData;
       
   181 
       
   182 	// create a transfer object..
       
   183 	TIicBusTransfer transfer(TIicBusTransfer::EMasterWrite, KBufGranularity, &iTransBuff);
       
   184 
       
   185 	// Create transaction
       
   186 	TIicBusTransaction transaction(&iHeaderBuff, &transfer);
       
   187 
       
   188 	// synchronously queue the write transaction
       
   189 	r = IicBus::QueueTransaction(iCsiBusConfig, &transaction);
       
   190 	return r;
       
   191 	}
       
   192 
       
   193 // to avoid multiple checking for each Write() call - if they are called in a row,
       
   194 // precede each block of writes to be checked with StartWrite() which clears the iResult.
       
   195 void RCS42AudioCodec::StartWrite()
       
   196 	{
       
   197 #if _DEBUG
       
   198 	iStartWriteCalled = ETrue;
       
   199 #endif
       
   200 	iResult = KErrNone;
       
   201 	}
       
   202 
       
   203 // After each block calls to Write() check the global status of them by calling this method.
       
   204 TInt RCS42AudioCodec::StopWrite()
       
   205 	{
       
   206 #if _DEBUG
       
   207 	iStartWriteCalled = EFalse;
       
   208 #endif
       
   209 	return iResult;
       
   210 	}
       
   211 
       
   212 // this is an internal method - used to configure the codec. It can be called
       
   213 // multiple times - whithout checkin for results. Precondition is - to call StartWrite()
       
   214 // and the overall result of multiple calls to this method are gathered using StopWrite()
       
   215 void RCS42AudioCodec::Write(TUint16 aRegAddr, TUint16 aData)
       
   216 	{
       
   217 	__ASSERT_DEBUG(iStartWriteCalled, Kern::Printf("block of multiple Write() calls should be preceded with StartWrite()"));
       
   218 	__ASSERT_DEBUG(iStartWriteCalled, Kern::Fault(KCodecPanicCat, __LINE__));
       
   219 
       
   220 	if (iResult != KErrNone)
       
   221 		{
       
   222 		return; // there was an error during one of previous write calls, just return
       
   223 		}
       
   224 	// if all calls proceeding StartWrite() were successful, continue to call the proper write
       
   225 	iResult = DoWrite(aRegAddr, aData);
       
   226 	}
       
   227 
       
   228 // This method is used to configure the CSI interface and then - the Codec.
       
   229 TInt RCS42AudioCodec::Init()
       
   230 	{
       
   231 	__KTRACE_SCODEC(Kern::Printf("RCS42AudioCodec::Init()"));
       
   232 	TUint32 val;
       
   233 
       
   234 	// First byte for the Cocec's write request on the CSI bus: (first seven bits-address, 8th-Write idication)
       
   235 	iTransBuff().iAddress = KCodecWriteCommand;
       
   236 
       
   237 	// Enter the BusRealisation config specific to CSI
       
   238 	SET_BUS_TYPE(iCsiBusConfig,DIicBusChannel::ESpi); //Bus Type
       
   239 	SET_CHAN_NUM(iCsiBusConfig,(TUint8)KCodecCSIChannel); // SPI uses channel numbers 1,2 (CSI0 and CSI1)
       
   240 	SET_SLAVE_ADDR(iCsiBusConfig,KCodecCSPin); //  Codec Pin Number
       
   241 
       
   242 	// enable and configure pin 25 - it is connected to the chip's reset line
       
   243 	GPIO::SetPinMode(KCodecResetPin, GPIO::EEnabled);
       
   244 	GPIO::SetPinDirection(KCodecResetPin, GPIO::EOutput);
       
   245 	GPIO::SetDebounceTime(KCodecResetPin, 0);
       
   246 
       
   247 	//====================================
       
   248 	//configure the CODEC:
       
   249 	// put !reset line high to start the power-up sequence..
       
   250 	GPIO::SetOutputState(KCodecResetPin, GPIO::EHigh);
       
   251 
       
   252 	// start multiple Write() block here
       
   253 	StartWrite();
       
   254 
       
   255 	// Write are used here..
       
   256 	// power-up sequence..
       
   257 	Write(KHwCS42L51PwrCtrl, KHtCS42L51PwrCtrl_PDN);
       
   258 	Write(KHwCS42L51PwrCtrl, KHtCS42L51PwrCtrl_PDN_ALL);
       
   259 
       
   260 	// freeze all registers.. until are set-up..
       
   261 	Write(KHwCS42L51DACControl, KHtCS42L51DACControl_FREEZE);
       
   262 
       
   263 	// Mic power control and speed control (0x03)
       
   264 	Write(KHwCS42L51MicPwrSpeed, KHtCS42L51MicPwrSpeed_AUTO
       
   265 			| KHtCS42L51MicPwrSpeed_MCLKDIV2); // auto,
       
   266 
       
   267 	// interface control (0x04) // serial port settings..
       
   268 	// I2s, Slave, SDOUT->SDIN internally connected.. Digimix->ON?
       
   269 
       
   270 	// use I2S format, Slave
       
   271 	iInterfaceCtrlVal = KHCS42L51CtrlI2sUpto24bit << KHsCS42L51CtrlFormat;
       
   272 
       
   273 	// Digital & Mic mix
       
   274 	iInterfaceCtrlVal |= KHtCS42L51Ctrl_DIGMIX | KHtCS42L51Ctrl_MICMIX;
       
   275 	Write(KHwCS42L51Ctrl, iInterfaceCtrlVal);
       
   276 
       
   277 	// MIC Control - enable mic pre-amplifierboost (there is also ADC digital boost)
       
   278 	// which we can use in addition to this one - but it would- work fine whitout any.
       
   279 	val = KHtCS42L51MicCtrl_MICA_BOOST;
       
   280 	Write(KHwCS42L51MicCtrl, val);
       
   281 
       
   282 	// ADCx Input Select, Invert & Mute
       
   283 	/*
       
   284 	 PDN_PGAx AINx_MUX[1:0] Selected Path to ADC
       
   285 	 0 	  00 		AIN1x-->PGAx
       
   286 	 0	  01 		AIN2x-->PGAx
       
   287 	 0 	  10 		AIN3x/MICINx-->PGAx
       
   288 	 0 	  11 		AIN3x/MICINx-->Pre-Amp(+16/+32 dB Gain)-->PGAx
       
   289 	 1 	  00 		AIN1x
       
   290 	 1 	  01 		AIN2x
       
   291 	 1 	  10 		AIN3x/MICINx
       
   292 	 1 	  11 		Reserved */
       
   293 
       
   294 	val = 3 << KHsCS42L51ADCInputMute_AINA_MUX;
       
   295 	val |= 3 << KHsCS42L51ADCInputMute_AINB_MUX;
       
   296 	Write(KHwCS42L51ADCInputMute, val);
       
   297 
       
   298 	// DAC output select (0x08)
       
   299 	// HP_GAIN2 HP_GAIN1 HP_GAIN0 DAC_SNGVOL INV_PCMB INV_PCMA DACB_MUTE DACA_MUTE
       
   300 	Write(KHwCS42L51DACOutputControl, KHtCS42L51DACOutputControl_DAC_SNGVOL);
       
   301 
       
   302 	// ALCX & PGAX ctrl, A(0x0A), B (0x0B)
       
   303 	Write(KHwCS42L51ALC_PGA_A_Control, 0);
       
   304 	Write(KHwCS42L51ALC_PGA_B_Control, 0);
       
   305 
       
   306 	// ADCx Mixer Volume Ctrl A(0x0E), B (0x0F)
       
   307 	Write(KHwCS42L51ALC_ADC_A_MixVolume, KHbCS42L51ALC_Volume_Min);
       
   308 	Write(KHwCS42L51ALC_ADC_B_MixVolume, KHbCS42L51ALC_Volume_Min);
       
   309 
       
   310 	// PCMx Volume Ctrl A(0x10), B (0x11)
       
   311 	Write(KHwCS42L51ALC_PCM_A_MixVolume, 0x18);
       
   312 	Write(KHwCS42L51ALC_PCM_B_MixVolume, 0x18);
       
   313 
       
   314 	// Volume Control: AOUTA (Address 16h) & AOUTB (Address 17h)
       
   315 	Write(KHwCS42L51ALC_Out_A_Volume, KHbCS42L51ALC_Volume_Min);
       
   316 	Write(KHwCS42L51ALC_Out_B_Volume, KHbCS42L51ALC_Volume_Min);
       
   317 
       
   318 	// DAC Control (Address 09h)
       
   319 	//  	7	  	 6	   	 5	     4	 	 3		2	   1	 	0
       
   320 	// DATA_SEL1 DATA_SEL0 FREEZE Reserved DEEMPH AMUTE DAC_SZC1 DAC_SZC0
       
   321 	// DATA_SEL1 DATA_SEL0:
       
   322 	// 00 - PCM Serial Port to DAC
       
   323 	// 01 - Signal Processing Engine to DAC
       
   324 	// 10 - ADC Serial Port to DAC    (11 - Reserved)
       
   325 	Write(KHwCS42L51DACControl, 1<<KHsCS42L51DACControl_DATA_SEL); // also clearing freeze bit will update settings..
       
   326 
       
   327 	// let's rock!! - boost bass and treble a bit ;)
       
   328 	// values for nibbles change from 0: +12dB (maximum) boost,
       
   329 	// to 15:(minimum) -10.5dB boost. 8: 0dB - play 'as it is'
       
   330 	val = (5 << KHsCS42L51ALC_ToneCtrl_TREB) | (6
       
   331 			<< KHsCS42L51ALC_ToneCtrl_BASS);
       
   332 	Write(KHwCS42L51ALC_ToneCtrl, val);
       
   333 
       
   334 	// power-up sequence..   - clear PDN ..after loading register settings..
       
   335 	Write(KHwCS42L51PwrCtrl, 0);
       
   336 
       
   337 	// This will return the error status, if any of Write() was not successful or KErrNone otherwise
       
   338 	return StopWrite();
       
   339 	}
       
   340 
       
   341 // this method is called from the sound-driver thread context to set the requested playback volume
       
   342 TInt RCS42AudioCodec::SetPlayVolume(TInt aVolume)
       
   343 	{
       
   344 	__KTRACE_SCODEC(Kern::Printf("RCS42AudioCodec::SetPlayVolume(%d)"));
       
   345 	// +12 db = 0001 1000 (24)
       
   346 	// 0db 	  = 0000 0000 (0)
       
   347 	//-0.5db  = 1111 1111 (255)
       
   348 	//-102db  = 0001 1001 (25)
       
   349 	TUint8 volume = 0xff & (aVolume + KHbCS42L51ALC_Volume_Min);
       
   350 
       
   351 	StartWrite();
       
   352 	Write(KHwCS42L51ALC_Out_A_Volume, volume);
       
   353 	Write(KHwCS42L51ALC_Out_B_Volume, volume);
       
   354 	TInt r = StopWrite();
       
   355 
       
   356 	return r;
       
   357 	}
       
   358 
       
   359 // this method is called from the sound-driver thread context to set the requested record volume
       
   360 TInt RCS42AudioCodec::SetRecordVolume(TInt aVolume)
       
   361 	{
       
   362 	__KTRACE_SCODEC(Kern::Printf("RCS42AudioCodec::SetRecordVolume(%d)"));
       
   363 	// +12 db = 0001 1000 (24)
       
   364 	// 0db 	  = 0000 0000 (0)
       
   365 	//-0.5db  = 1111 1111 (255)
       
   366 	//-102db  = 0001 1001 (25)
       
   367 	TUint8 volume = 0xff & (aVolume + KHbCS42L51ALC_Volume_Min);
       
   368 
       
   369 	StartWrite();
       
   370 	Write(KHwCS42L51ALC_ADC_A_MixVolume, volume);
       
   371 	Write(KHwCS42L51ALC_ADC_B_MixVolume, volume);
       
   372 	TInt r = StopWrite();
       
   373 
       
   374 	return r;
       
   375 	}