1 /** 2 ****************************************************************************** 3 * @file cs43l22.c 4 * @author MCD Application Team 5 * @version V2.0.2 6 * @date 06-October-2015 7 * @brief This file provides the CS43L22 Audio Codec driver. 8 ****************************************************************************** 9 * @attention 10 * 11 * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> 12 * 13 * Redistribution and use in source and binary forms, with or without modification, 14 * are permitted provided that the following conditions are met: 15 * 1. Redistributions of source code must retain the above copyright notice, 16 * this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright notice, 18 * this list of conditions and the following disclaimer in the documentation 19 * and/or other materials provided with the distribution. 20 * 3. Neither the name of STMicroelectronics nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 * 35 ****************************************************************************** 36 */ 37 38 /* Includes ------------------------------------------------------------------*/ 39 #include "cs43l22.h" 40 41 /** @addtogroup BSP 42 * @{ 43 */ 44 45 /** @addtogroup Components 46 * @{ 47 */ 48 49 /** @addtogroup CS43L22 50 * @brief This file provides a set of functions needed to drive the 51 * CS43L22 audio codec. 52 * @{ 53 */ 54 55 /** @defgroup CS43L22_Private_Types 56 * @{ 57 */ 58 59 /** 60 * @} 61 */ 62 63 /** @defgroup CS43L22_Private_Defines 64 * @{ 65 */ 66 #define VOLUME_CONVERT(Volume) (((Volume) > 100)? 100:((uint8_t)(((Volume) * 255) / 100))) 67 /* Uncomment this line to enable verifying data sent to codec after each write 68 operation (for debug purpose) */ 69 #if !defined (VERIFY_WRITTENDATA) 70 /* #define VERIFY_WRITTENDATA */ 71 #endif /* VERIFY_WRITTENDATA */ 72 /** 73 * @} 74 */ 75 76 /** @defgroup CS43L22_Private_Macros 77 * @{ 78 */ 79 80 /** 81 * @} 82 */ 83 84 /** @defgroup CS43L22_Private_Variables 85 * @{ 86 */ 87 88 /* Audio codec driver structure initialization */ 89 AUDIO_DrvTypeDef cs43l22_drv = 90 { 91 cs43l22_Init, 92 cs43l22_DeInit, 93 cs43l22_ReadID, 94 95 cs43l22_Play, 96 cs43l22_Pause, 97 cs43l22_Resume, 98 cs43l22_Stop, 99 100 cs43l22_SetFrequency, 101 cs43l22_SetVolume, 102 cs43l22_SetMute, 103 cs43l22_SetOutputMode, 104 cs43l22_Reset, 105 }; 106 107 static uint8_t Is_cs43l22_Stop = 1; 108 109 volatile uint8_t OutputDev = 0; 110 111 /** 112 * @} 113 */ 114 115 /** @defgroup CS43L22_Function_Prototypes 116 * @{ 117 */ 118 static uint8_t CODEC_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value); 119 /** 120 * @} 121 */ 122 123 /** @defgroup CS43L22_Private_Functions 124 * @{ 125 */ 126 127 /** 128 * @brief Initializes the audio codec and the control interface. 129 * @param DeviceAddr: Device address on communication Bus. 130 * @param OutputDevice: can be OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, 131 * OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO . 132 * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max)) 133 * @retval 0 if correct communication, else wrong communication 134 */ 135 uint32_t cs43l22_Init(uint16_t DeviceAddr, uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq) 136 { 137 uint32_t counter = 0; 138 139 /* Initialize the Control interface of the Audio Codec */ 140 AUDIO_IO_Init(); 141 142 /* Keep Codec powered OFF */ 143 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL1, 0x01); 144 145 /*Save Output device for mute ON/OFF procedure*/ 146 switch (OutputDevice) 147 { 148 case OUTPUT_DEVICE_SPEAKER: 149 OutputDev = 0xFA; 150 break; 151 152 case OUTPUT_DEVICE_HEADPHONE: 153 OutputDev = 0xAF; 154 break; 155 156 case OUTPUT_DEVICE_BOTH: 157 OutputDev = 0xAA; 158 break; 159 160 case OUTPUT_DEVICE_AUTO: 161 OutputDev = 0x05; 162 break; 163 164 default: 165 OutputDev = 0x05; 166 break; 167 } 168 169 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL2, OutputDev); 170 171 /* Clock configuration: Auto detection */ 172 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_CLOCKING_CTL, 0x81); 173 174 /* Set the Slave Mode and the audio Standard */ 175 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_INTERFACE_CTL1, CODEC_STANDARD); 176 177 /* Set the Master volume */ 178 counter += cs43l22_SetVolume(DeviceAddr, Volume); 179 180 /* If the Speaker is enabled, set the Mono mode and volume attenuation level */ 181 if(OutputDevice != OUTPUT_DEVICE_HEADPHONE) 182 { 183 /* Set the Speaker Mono mode */ 184 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_PLAYBACK_CTL2, 0x06); 185 186 /* Set the Speaker attenuation level */ 187 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_SPEAKER_A_VOL, 0x00); 188 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_SPEAKER_B_VOL, 0x00); 189 } 190 191 /* Additional configuration for the CODEC. These configurations are done to reduce 192 the time needed for the Codec to power off. If these configurations are removed, 193 then a long delay should be added between powering off the Codec and switching 194 off the I2S peripheral MCLK clock (which is the operating clock for Codec). 195 If this delay is not inserted, then the codec will not shut down properly and 196 it results in high noise after shut down. */ 197 198 /* Disable the analog soft ramp */ 199 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_ANALOG_ZC_SR_SETT, 0x00); 200 /* Disable the digital soft ramp */ 201 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_MISC_CTL, 0x04); 202 /* Disable the limiter attack level */ 203 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_LIMIT_CTL1, 0x00); 204 /* Adjust Bass and Treble levels */ 205 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_TONE_CTL, 0x0F); 206 /* Adjust PCM volume level */ 207 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_PCMA_VOL, 0x0A); 208 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_PCMB_VOL, 0x0A); 209 210 /* Return communication control value */ 211 return counter; 212 } 213 214 /** 215 * @brief Deinitializes the audio codec. 216 * @param None 217 * @retval None 218 */ 219 void cs43l22_DeInit(void) 220 { 221 /* Deinitialize Audio Codec interface */ 222 AUDIO_IO_DeInit(); 223 } 224 225 /** 226 * @brief Get the CS43L22 ID. 227 * @param DeviceAddr: Device address on communication Bus. 228 * @retval The CS43L22 ID 229 */ 230 uint32_t cs43l22_ReadID(uint16_t DeviceAddr) 231 { 232 uint8_t Value; 233 /* Initialize the Control interface of the Audio Codec */ 234 AUDIO_IO_Init(); 235 236 Value = AUDIO_IO_Read(DeviceAddr, CS43L22_CHIPID_ADDR); 237 Value = (Value & CS43L22_ID_MASK); 238 239 return((uint32_t) Value); 240 } 241 242 /** 243 * @brief Start the audio Codec play feature. 244 * @note For this codec no Play options are required. 245 * @param DeviceAddr: Device address on communication Bus. 246 * @retval 0 if correct communication, else wrong communication 247 */ 248 uint32_t cs43l22_Play(uint16_t DeviceAddr, uint16_t* pBuffer, uint16_t Size) 249 { 250 uint32_t counter = 0; 251 252 if(Is_cs43l22_Stop == 1) 253 { 254 /* Enable the digital soft ramp */ 255 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_MISC_CTL, 0x06); 256 257 /* Enable Output device */ 258 counter += cs43l22_SetMute(DeviceAddr, AUDIO_MUTE_OFF); 259 260 /* Power on the Codec */ 261 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL1, 0x9E); 262 Is_cs43l22_Stop = 0; 263 } 264 265 /* Return communication control value */ 266 return counter; 267 } 268 269 /** 270 * @brief Pauses playing on the audio codec. 271 * @param DeviceAddr: Device address on communication Bus. 272 * @retval 0 if correct communication, else wrong communication 273 */ 274 uint32_t cs43l22_Pause(uint16_t DeviceAddr) 275 { 276 uint32_t counter = 0; 277 278 /* Pause the audio file playing */ 279 /* Mute the output first */ 280 counter += cs43l22_SetMute(DeviceAddr, AUDIO_MUTE_ON); 281 282 /* Put the Codec in Power save mode */ 283 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL1, 0x01); 284 285 return counter; 286 } 287 288 /** 289 * @brief Resumes playing on the audio codec. 290 * @param DeviceAddr: Device address on communication Bus. 291 * @retval 0 if correct communication, else wrong communication 292 */ 293 uint32_t cs43l22_Resume(uint16_t DeviceAddr) 294 { 295 uint32_t counter = 0; 296 volatile uint32_t index = 0x00; 297 /* Resumes the audio file playing */ 298 /* Unmute the output first */ 299 counter += cs43l22_SetMute(DeviceAddr, AUDIO_MUTE_OFF); 300 301 for(index = 0x00; index < 0xFF; index++); 302 303 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL2, OutputDev); 304 305 /* Exit the Power save mode */ 306 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL1, 0x9E); 307 308 return counter; 309 } 310 311 /** 312 * @brief Stops audio Codec playing. It powers down the codec. 313 * @param DeviceAddr: Device address on communication Bus. 314 * @param CodecPdwnMode: selects the power down mode. 315 * - CODEC_PDWN_HW: Physically power down the codec. When resuming from this 316 * mode, the codec is set to default configuration 317 * (user should re-Initialize the codec in order to 318 * play again the audio stream). 319 * @retval 0 if correct communication, else wrong communication 320 */ 321 uint32_t cs43l22_Stop(uint16_t DeviceAddr, uint32_t CodecPdwnMode) 322 { 323 uint32_t counter = 0; 324 325 /* Mute the output first */ 326 counter += cs43l22_SetMute(DeviceAddr, AUDIO_MUTE_ON); 327 328 /* Disable the digital soft ramp */ 329 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_MISC_CTL, 0x04); 330 331 /* Power down the DAC and the speaker (PMDAC and PMSPK bits)*/ 332 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL1, 0x9F); 333 334 Is_cs43l22_Stop = 1; 335 return counter; 336 } 337 338 /** 339 * @brief Sets higher or lower the codec volume level. 340 * @param DeviceAddr: Device address on communication Bus. 341 * @param Volume: a byte value from 0 to 255 (refer to codec registers 342 * description for more details). 343 * @retval 0 if correct communication, else wrong communication 344 */ 345 uint32_t cs43l22_SetVolume(uint16_t DeviceAddr, uint8_t Volume) 346 { 347 uint32_t counter = 0; 348 uint8_t convertedvol = VOLUME_CONVERT(Volume); 349 350 if(Volume > 0xE6) 351 { 352 /* Set the Master volume */ 353 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_MASTER_A_VOL, convertedvol - 0xE7); 354 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_MASTER_B_VOL, convertedvol - 0xE7); 355 } 356 else 357 { 358 /* Set the Master volume */ 359 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_MASTER_A_VOL, convertedvol + 0x19); 360 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_MASTER_B_VOL, convertedvol + 0x19); 361 } 362 363 return counter; 364 } 365 366 /** 367 * @brief Sets new frequency. 368 * @param DeviceAddr: Device address on communication Bus. 369 * @param AudioFreq: Audio frequency used to play the audio stream. 370 * @retval 0 if correct communication, else wrong communication 371 */ 372 uint32_t cs43l22_SetFrequency(uint16_t DeviceAddr, uint32_t AudioFreq) 373 { 374 return 0; 375 } 376 377 /** 378 * @brief Enables or disables the mute feature on the audio codec. 379 * @param DeviceAddr: Device address on communication Bus. 380 * @param Cmd: AUDIO_MUTE_ON to enable the mute or AUDIO_MUTE_OFF to disable the 381 * mute mode. 382 * @retval 0 if correct communication, else wrong communication 383 */ 384 uint32_t cs43l22_SetMute(uint16_t DeviceAddr, uint32_t Cmd) 385 { 386 uint32_t counter = 0; 387 388 /* Set the Mute mode */ 389 if(Cmd == AUDIO_MUTE_ON) 390 { 391 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL2, 0xFF); 392 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_HEADPHONE_A_VOL, 0x01); 393 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_HEADPHONE_B_VOL, 0x01); 394 } 395 else /* AUDIO_MUTE_OFF Disable the Mute */ 396 { 397 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_HEADPHONE_A_VOL, 0x00); 398 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_HEADPHONE_B_VOL, 0x00); 399 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL2, OutputDev); 400 } 401 return counter; 402 } 403 404 /** 405 * @brief Switch dynamically (while audio file is played) the output target 406 * (speaker or headphone). 407 * @note This function modifies a global variable of the audio codec driver: OutputDev. 408 * @param DeviceAddr: Device address on communication Bus. 409 * @param Output: specifies the audio output target: OUTPUT_DEVICE_SPEAKER, 410 * OUTPUT_DEVICE_HEADPHONE, OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO 411 * @retval 0 if correct communication, else wrong communication 412 */ 413 uint32_t cs43l22_SetOutputMode(uint16_t DeviceAddr, uint8_t Output) 414 { 415 uint32_t counter = 0; 416 417 switch (Output) 418 { 419 case OUTPUT_DEVICE_SPEAKER: 420 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL2, 0xFA); /* SPK always ON & HP always OFF */ 421 OutputDev = 0xFA; 422 break; 423 424 case OUTPUT_DEVICE_HEADPHONE: 425 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL2, 0xAF); /* SPK always OFF & HP always ON */ 426 OutputDev = 0xAF; 427 break; 428 429 case OUTPUT_DEVICE_BOTH: 430 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL2, 0xAA); /* SPK always ON & HP always ON */ 431 OutputDev = 0xAA; 432 break; 433 434 case OUTPUT_DEVICE_AUTO: 435 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL2, 0x05); /* Detect the HP or the SPK automatically */ 436 OutputDev = 0x05; 437 break; 438 439 default: 440 counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL2, 0x05); /* Detect the HP or the SPK automatically */ 441 OutputDev = 0x05; 442 break; 443 } 444 return counter; 445 } 446 447 /** 448 * @brief Resets cs43l22 registers. 449 * @param DeviceAddr: Device address on communication Bus. 450 * @retval 0 if correct communication, else wrong communication 451 */ 452 uint32_t cs43l22_Reset(uint16_t DeviceAddr) 453 { 454 return 0; 455 } 456 457 /** 458 * @brief Writes/Read a single data. 459 * @param Addr: I2C address 460 * @param Reg: Reg address 461 * @param Value: Data to be written 462 * @retval None 463 */ 464 static uint8_t CODEC_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value) 465 { 466 uint32_t result = 0; 467 468 AUDIO_IO_Write(Addr, Reg, Value); 469 470 #ifdef VERIFY_WRITTENDATA 471 /* Verify that the data has been correctly written */ 472 result = (AUDIO_IO_Read(Addr, Reg) == Value)? 0:1; 473 #endif /* VERIFY_WRITTENDATA */ 474 475 return result; 476 } 477 478 /** 479 * @} 480 */ 481 482 /** 483 * @} 484 */ 485 486 /** 487 * @} 488 */ 489 490 /** 491 * @} 492 */ 493 494 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 495