Files
2024-06-17 20:18:01 +08:00

694 lines
31 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* wm8988.c -- WM8988 ALSA SoC audio driver
*
* Copyright 2009 Wolfson Microelectronics plc
* Copyright 2005 Openedhand Ltd.
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include "cjc8988.h"
//*************************************************************************
// LINE Input 1 to ADC mode, slave mode, I2S format output, MCLK=12.288MHz, BCLK =3.072MHz, Fs=48KHz;
//
//static struct CJC8988_reg LINPUT1_TO_ADC[] = {
// {CJC8988_R0_LEFT_INPUT_VOLUME, 0x17}, // Audio input left channel volume; R/W
// {CJC8988_R1_RIGHT_INPUT_VOLUME, 0x17}, // Audio input right channel volume; R/W
// {CJC8988_R2_LOUT1_VOLUME, 0x79}, // Audio output letf channel1 volume; R/W
// {CJC8988_R3_ROUT1_VOLUME, 0x79}, // Audio output right channel1 volume; R/W
// {CJC8988_R5_ADC_DAC_CONTROL, 0x00}, // ADC and DAC CONTROL; R/W
// {CJC8988_R7_AUDIO_INTERFACE, 0x0A}, // Digital Audio interface format; R/W
// {CJC8988_R8_SAMPLE_RATE, 0x00}, // Clock and Sample rate control; R/W
// {CJC8988_R10_LEFT_DAC_VOLUME, 0xff}, // Left channel DAC digital volume; R/W
// {CJC8988_R11_RIGHT_DAC_VOLUME, 0xff}, // Right channel DAC digital volume; R/W
//
// {CJC8988_R12_BASS_CONTROL, 0x0f}, // BASS control; R/W
// {CJC8988_R13_TREBLE_CONTROL, 0x0f}, // Treble control; R/W
// {CJC8988_R16_3D_CONTROL, 0x00}, // 3D control; R/W
//
// {CJC8988_R21_LEFT_ADC_VOLUME, 0xc3}, // Left ADC digital volume; R/W
// {CJC8988_R22_RIGHT_ADC_VOLUME, 0xc3}, // Right ADC digital volume; R/W
//
// {CJC8988_R23_ADDITIONAL_CONTROL1, 0xc0}, // Additional control 1; R/W
// {CJC8988_R24_ADDITIONAL_CONTROL2, 0x04}, // Additional control 2; R/W
// {CJC8988_R27_ADDITIONAL_CONTROL3, 0x00}, // Additional control 3; R/W
//
// {CJC8988_R31_ADC_INPUT_MODE, 0x00}, // ADC input mode; R/W
//
// {CJC8988_R32_ADCL_SIGNAL_PATH, 0x00}, // Left ADC signal path control; R/W
// {CJC8988_R33_ADCR_SIGNAL_PATH, 0x00}, // Right ADC signal path control; R/W
//
// {CJC8988_R34_LEFT_OUT_MIX1_L, 0x52}, // Left DAC to left mixer disable; R/W
// {CJC8988_R35_LEFT_OUT_MIX2_L, 0x50}, // Right DAC to left mixer disable; R/W
// {CJC8988_R36_RIGHT_OUT_MIX1_L, 0x52}, // Left DAC to right mixer disable; R/W
// {CJC8988_R37_RIGHT_OUT_MIX2_L, 0x50}, // Right DAC to right mixer disable; R/W
//
// {CJC8988_R40_LOUT2_VOLUME, 0x79}, // Audio output left channel1 volume; R/W
// {CJC8988_R41_ROUT2_VOLUME, 0x79}, // Audio output right channel1 volume; R/W
// {CJC8988_R43_LOW_POWER_PLAYBACK, 0x00}, // Low power playback; R/W
//
// {CJC8988_R25_PWR_MGMT1_H, 0x7c}, // Power management1 and VMIDSEL; R/W
// {CJC8988_R26_PWR_MGMT2_L, 0x00}, // Power management2 and DAC left power down; R/W;
//};
//
//#define CJC8988_LINPUT1_TO_ADC_REG_NUM ARRAY_SIZE(LINPUT1_TO_ADC)
//
////*************************************************************************
//// DAC to LOUT1 mode, slave mode, I2S format input, MCLK=12.288MHz, BCLK =?MHz, Fs=48KHz;
////
//static struct CJC8988_reg DAC_TO_LOUT1_TEST[] = {
// {CJC8988_R0_LEFT_INPUT_VOLUME, 0x17}, // Audio input left channel volume; R/W
// {CJC8988_R1_RIGHT_INPUT_VOLUME, 0x17}, // Audio input right channel volume; R/W
// {CJC8988_R2_LOUT1_VOLUME, 0x30}, // Audio output letf channel1 volume; R/W
// {CJC8988_R3_ROUT1_VOLUME, 0x30}, // Audio output right channel1 volume; R/W
// {CJC8988_R5_ADC_DAC_CONTROL, 0x00}, // ADC and DAC CONTROL; R/W
// {CJC8988_R7_AUDIO_INTERFACE, 0x0D}, // Digital Audio interface format; R/W
// //{CJC8988_R7_AUDIO_INTERFACE, 0x01}, // Digital Audio interface format; R/W
// {CJC8988_R8_SAMPLE_RATE, 0x00}, // Clock and Sample rate control; R/W
// {CJC8988_R10_LEFT_DAC_VOLUME, 0xff}, // Left channel DAC digital volume; R/W
// {CJC8988_R11_RIGHT_DAC_VOLUME, 0xff}, // Right channel DAC digital volume; R/W
//
// {CJC8988_R12_BASS_CONTROL, 0x0f}, // BASS control; R/W
// {CJC8988_R13_TREBLE_CONTROL, 0x0f}, // Treble control; R/W
// {CJC8988_R16_3D_CONTROL, 0x00}, // 3D control; R/W
//
// {CJC8988_R21_LEFT_ADC_VOLUME, 0xc3}, // Left ADC digital volume; R/W
// {CJC8988_R22_RIGHT_ADC_VOLUME, 0xc3}, // Right ADC digital volume; R/W
//
// {CJC8988_R23_ADDITIONAL_CONTROL1, 0xc0}, // Additional control 1; R/W
// {CJC8988_R24_ADDITIONAL_CONTROL2, 0x04}, // Additional control 2; R/W
// {CJC8988_R27_ADDITIONAL_CONTROL3, 0x00}, // Additional control 3; R/W
//
// {CJC8988_R31_ADC_INPUT_MODE, 0x00}, // ADC input mode; R/W
//
// {CJC8988_R32_ADCL_SIGNAL_PATH, 0x00}, // Left ADC signal path control; R/W
// {CJC8988_R33_ADCR_SIGNAL_PATH, 0x00}, // Right ADC signal path control; R/W
//
// {CJC8988_R34_LEFT_OUT_MIX1_H, 0x52}, // Left DAC to left mixer enable; R/W
// {CJC8988_R35_LEFT_OUT_MIX2_L, 0x50}, // Right DAC to left mixer disable; R/W
// {CJC8988_R36_RIGHT_OUT_MIX1_L, 0x52}, // Left DAC to right mixer disable; R/W
// {CJC8988_R37_RIGHT_OUT_MIX2_H, 0x50}, // Right DAC to right mixer enable; R/W
//
// {CJC8988_R40_LOUT2_VOLUME, 0x79}, // Audio output left channel1 volume; R/W
// {CJC8988_R41_ROUT2_VOLUME, 0x79}, // Audio output right channel1 volume; R/W
// {CJC8988_R43_LOW_POWER_PLAYBACK, 0x08}, // Low power playback; R/W
//
// {CJC8988_R25_PWR_MGMT1_H, 0x40}, // Power management1 and VMIDSEL; R/W
// {CJC8988_R26_PWR_MGMT2_H, 0xf8}, // Power management2 and DAC left power up; R/W;
//};
//
//#define CJC8988_DAC_TO_LOUT1_REG_NUM_TEST ARRAY_SIZE(DAC_TO_LOUT1_TEST)
//
////*************************************************************************
//// DAC to LOUT1 mode, slave mode, I2S format input, MCLK=12.288MHz, BCLK =3.072MHz, Fs=48KHz;
////
//static struct CJC8988_reg DAC_TO_LOUT1[] = {
// {CJC8988_R0_LEFT_INPUT_VOLUME, 0x17}, // Audio input left channel volume; R/W
// {CJC8988_R1_RIGHT_INPUT_VOLUME, 0x17}, // Audio input right channel volume; R/W
// {CJC8988_R2_LOUT1_VOLUME, 0x79}, // Audio output letf channel1 volume; R/W
// {CJC8988_R3_ROUT1_VOLUME, 0x79}, // Audio output right channel1 volume; R/W
// {CJC8988_R5_ADC_DAC_CONTROL, 0x00}, // ADC and DAC CONTROL; R/W
// {CJC8988_R7_AUDIO_INTERFACE, 0x0A}, // Digital Audio interface format; R/W
// {CJC8988_R8_SAMPLE_RATE, 0x00}, // Clock and Sample rate control; R/W
// {CJC8988_R10_LEFT_DAC_VOLUME, 0xff}, // Left channel DAC digital volume; R/W
// {CJC8988_R11_RIGHT_DAC_VOLUME, 0xff}, // Right channel DAC digital volume; R/W
//
// {CJC8988_R12_BASS_CONTROL, 0x0f}, // BASS control; R/W
// {CJC8988_R13_TREBLE_CONTROL, 0x0f}, // Treble control; R/W
// {CJC8988_R16_3D_CONTROL, 0x00}, // 3D control; R/W
//
// {CJC8988_R21_LEFT_ADC_VOLUME, 0xc3}, // Left ADC digital volume; R/W
// {CJC8988_R22_RIGHT_ADC_VOLUME, 0xc3}, // Right ADC digital volume; R/W
//
// {CJC8988_R23_ADDITIONAL_CONTROL1, 0xc0}, // Additional control 1; R/W
// {CJC8988_R24_ADDITIONAL_CONTROL2, 0x00}, // Additional control 2; R/W
// {CJC8988_R27_ADDITIONAL_CONTROL3, 0x00}, // Additional control 3; R/W
//
// {CJC8988_R31_ADC_INPUT_MODE, 0x00}, // ADC input mode; R/W
//
// {CJC8988_R32_ADCL_SIGNAL_PATH, 0x00}, // Left ADC signal path control; R/W
// {CJC8988_R33_ADCR_SIGNAL_PATH, 0x00}, // Right ADC signal path control; R/W
//
// {CJC8988_R34_LEFT_OUT_MIX1_H, 0x52}, // Left DAC to left mixer enable; R/W
// {CJC8988_R35_LEFT_OUT_MIX2_L, 0x50}, // Right DAC to left mixer disable; R/W
// {CJC8988_R36_RIGHT_OUT_MIX1_L, 0x52}, // Left DAC to right mixer disable; R/W
// {CJC8988_R37_RIGHT_OUT_MIX2_H, 0x50}, // Right DAC to right mixer enable; R/W
//
// {CJC8988_R40_LOUT2_VOLUME, 0x79}, // Audio output left channel1 volume; R/W
// {CJC8988_R41_ROUT2_VOLUME, 0x79}, // Audio output right channel1 volume; R/W
// {CJC8988_R43_LOW_POWER_PLAYBACK, 0x08}, // Low power playback; R/W
//
// {CJC8988_R25_PWR_MGMT1_H, 0x40}, // Power management1 and VMIDSEL; R/W
// {CJC8988_R26_PWR_MGMT2_H, 0xf8}, // Power management2 and DAC left power up; R/W;
//};
//
//#define CJC8988_DAC_TO_LOUT1_REG_NUM ARRAY_SIZE(DAC_TO_LOUT1)
//
////*************************************************************************
//// LINE Input 1 to LOUT 1 mode, slave mode, I2S format, MCLK=12.288MHz, BCLK =3.072MHz, Fs=48KHz;
////
//static struct CJC8988_reg LINPUT1_TO_LOUT1[] = {
// {CJC8988_R0_LEFT_INPUT_VOLUME, 0x17}, // Audio input left channel volume; R/W
// {CJC8988_R1_RIGHT_INPUT_VOLUME, 0x17}, // Audio input right channel volume; R/W
// {CJC8988_R2_LOUT1_VOLUME, 0x79}, // Audio output letf channel1 volume; R/W
// {CJC8988_R3_ROUT1_VOLUME, 0x79}, // Audio output right channel1 volume; R/W
// {CJC8988_R5_ADC_DAC_CONTROL, 0x00}, // ADC and DAC CONTROL; R/W
// {CJC8988_R7_AUDIO_INTERFACE, 0x0A}, // Digital Audio interface format; R/W
// {CJC8988_R8_SAMPLE_RATE, 0x00}, // Clock and Sample rate control; R/W
// {CJC8988_R10_LEFT_DAC_VOLUME, 0xff}, // Left channel DAC digital volume; R/W
// {CJC8988_R11_RIGHT_DAC_VOLUME, 0xff}, // Right channel DAC digital volume; R/W
//
// {CJC8988_R12_BASS_CONTROL, 0x0f}, // BASS control; R/W
// {CJC8988_R13_TREBLE_CONTROL, 0x0f}, // Treble control; R/W
// {CJC8988_R16_3D_CONTROL, 0x00}, // 3D control; R/W
//
// {CJC8988_R21_LEFT_ADC_VOLUME, 0xc3}, // Left ADC digital volume; R/W
// {CJC8988_R22_RIGHT_ADC_VOLUME, 0xc3}, // Right ADC digital volume; R/W
//
// {CJC8988_R23_ADDITIONAL_CONTROL1, 0xc0}, // Additional control 1; R/W
// {CJC8988_R24_ADDITIONAL_CONTROL2, 0x00}, // Additional control 2; R/W
// {CJC8988_R27_ADDITIONAL_CONTROL3, 0x00}, // Additional control 3; R/W
//
// {CJC8988_R31_ADC_INPUT_MODE, 0x00}, // ADC input mode; R/W
//
// {CJC8988_R32_ADCL_SIGNAL_PATH, 0x00}, // Left ADC signal path control; R/W
// {CJC8988_R33_ADCR_SIGNAL_PATH, 0x00}, // Right ADC signal path control; R/W
//
// {CJC8988_R34_LEFT_OUT_MIX1_L, 0xA0}, // Left DAC to left mixer disable; R/W
// {CJC8988_R35_LEFT_OUT_MIX2_L, 0x50}, // Right DAC to left mixer disable; R/W
// {CJC8988_R36_RIGHT_OUT_MIX1_L, 0x50}, // Left DAC to right mixer disable; R/W
// {CJC8988_R37_RIGHT_OUT_MIX2_L, 0xA0}, // Right DAC to right mixer disable; R/W
//
// {CJC8988_R40_LOUT2_VOLUME, 0x79}, // Audio output left channel1 volume; R/W
// {CJC8988_R41_ROUT2_VOLUME, 0x79}, // Audio output right channel1 volume; R/W
// {CJC8988_R43_LOW_POWER_PLAYBACK, 0x00}, // Low power playback; R/W
//
// {CJC8988_R25_PWR_MGMT1_H, 0x40}, // Power management1 and VMIDSEL; R/W
// {CJC8988_R26_PWR_MGMT2_H, 0x78}, // Power management2 and DAC left power up; R/W;
//};
//
//#define CJC8988_LINPUT1_TO_LOUT1_REG_NUM ARRAY_SIZE(LINPUT1_TO_LOUT1)
//
////*************************************************************************
//// LINE Input 2 to ADC and DAC to LOUT 2 mode, slave mode, I2S format, MCLK=12MHz, BCLK = 12MHz, Fs=8KHz;
////
//static struct CJC8988_reg LINPUT2_ADC_TO_DAC_LOUT2_8[] = {
// {CJC8988_R0_LEFT_INPUT_VOLUME, 0x17}, // Audio input left channel volume; R/W
// {CJC8988_R1_RIGHT_INPUT_VOLUME, 0x17}, // Audio input right channel volume; R/W
// {CJC8988_R2_LOUT1_VOLUME, 0x79}, // Audio output letf channel1 volume; R/W
// {CJC8988_R3_ROUT1_VOLUME, 0x79}, // Audio output right channel1 volume; R/W
// {CJC8988_R5_ADC_DAC_CONTROL, 0x00}, // ADC and DAC CONTROL; R/W
// {CJC8988_R7_AUDIO_INTERFACE, 0x02}, // Digital Audio interface format; R/W
// {CJC8988_R8_SAMPLE_RATE, 0x0d}, // Clock and Sample rate control; R/W
// {CJC8988_R10_LEFT_DAC_VOLUME, 0xff}, // Left channel DAC digital volume; R/W
// {CJC8988_R11_RIGHT_DAC_VOLUME, 0xff}, // Right channel DAC digital volume; R/W
//
// {CJC8988_R12_BASS_CONTROL, 0x0f}, // BASS control; R/W
// {CJC8988_R13_TREBLE_CONTROL, 0x0f}, // Treble control; R/W
// {CJC8988_R16_3D_CONTROL, 0x00}, // 3D control; R/W
//
// {CJC8988_R21_LEFT_ADC_VOLUME, 0xc3}, // Left ADC digital volume; R/W
// {CJC8988_R22_RIGHT_ADC_VOLUME, 0xc3}, // Right ADC digital volume; R/W
//
// {CJC8988_R23_ADDITIONAL_CONTROL1, 0xc0}, // Additional control 1; R/W
// {CJC8988_R24_ADDITIONAL_CONTROL2, 0x00}, // Additional control 2; R/W
// {CJC8988_R27_ADDITIONAL_CONTROL3, 0x00}, // Additional control 3; R/W
//
// {CJC8988_R31_ADC_INPUT_MODE, 0x00}, // ADC input mode; R/W
//
// {CJC8988_R32_ADCL_SIGNAL_PATH, 0x40}, // Left ADC signal path control; R/W
// {CJC8988_R33_ADCR_SIGNAL_PATH, 0x40}, // Right ADC signal path control; R/W
//
// {CJC8988_R34_LEFT_OUT_MIX1_H, 0x52}, // Left DAC to left mixer disable; R/W
// {CJC8988_R35_LEFT_OUT_MIX2_L, 0x50}, // Right DAC to left mixer disable; R/W
// {CJC8988_R36_RIGHT_OUT_MIX1_L, 0x52}, // Left DAC to right mixer disable; R/W
// {CJC8988_R37_RIGHT_OUT_MIX2_H, 0x50}, // Right DAC to right mixer disable; R/W
//
// {CJC8988_R40_LOUT2_VOLUME, 0x79}, // Audio output left channel1 volume; R/W
// {CJC8988_R41_ROUT2_VOLUME, 0x79}, // Audio output right channel1 volume; R/W
// {CJC8988_R43_LOW_POWER_PLAYBACK, 0x08}, // Low power playback; R/W
//
// {CJC8988_R25_PWR_MGMT1_H, 0x7C}, // Power management1 and VMIDSEL; R/W
// {CJC8988_R26_PWR_MGMT2_H, 0xf8}, // Power management2 and DAC left power up; R/W;
//};
//
//#define CJC8988_LINPUT2_ADC_TO_DAC_LOUT2_8_REG_NUM ARRAY_SIZE(LINPUT2_ADC_TO_DAC_LOUT2_8)
//
////*************************************************************************
//// LINE Input 2 to ADC and DAC to LOUT 2 mode, slave mode, I2S format, MCLK=12MHz, BCLK = 12MHz, Fs=32KHz;
////
//static struct CJC8988_reg LINPUT2_ADC_TO_DAC_LOUT2_32[] = {
// {CJC8988_R0_LEFT_INPUT_VOLUME, 0x17}, // Audio input left channel volume; R/W
// {CJC8988_R1_RIGHT_INPUT_VOLUME, 0x17}, // Audio input right channel volume; R/W
// {CJC8988_R2_LOUT1_VOLUME, 0x79}, // Audio output letf channel1 volume; R/W
// {CJC8988_R3_ROUT1_VOLUME, 0x79}, // Audio output right channel1 volume; R/W
// {CJC8988_R5_ADC_DAC_CONTROL, 0x00}, // ADC and DAC CONTROL; R/W
// {CJC8988_R7_AUDIO_INTERFACE, 0x02}, // Digital Audio interface format; R/W
// {CJC8988_R8_SAMPLE_RATE, 0x19}, // Clock and Sample rate control; R/W
// {CJC8988_R10_LEFT_DAC_VOLUME, 0xff}, // Left channel DAC digital volume; R/W
// {CJC8988_R11_RIGHT_DAC_VOLUME, 0xff}, // Right channel DAC digital volume; R/W
//
// {CJC8988_R12_BASS_CONTROL, 0x0f}, // BASS control; R/W
// {CJC8988_R13_TREBLE_CONTROL, 0x0f}, // Treble control; R/W
// {CJC8988_R16_3D_CONTROL, 0x00}, // 3D control; R/W
//
// {CJC8988_R21_LEFT_ADC_VOLUME, 0xc3}, // Left ADC digital volume; R/W
// {CJC8988_R22_RIGHT_ADC_VOLUME, 0xc3}, // Right ADC digital volume; R/W
//
// {CJC8988_R23_ADDITIONAL_CONTROL1, 0xc0}, // Additional control 1; R/W
// {CJC8988_R24_ADDITIONAL_CONTROL2, 0x00}, // Additional control 2; R/W
// {CJC8988_R27_ADDITIONAL_CONTROL3, 0x00}, // Additional control 3; R/W
//
// {CJC8988_R31_ADC_INPUT_MODE, 0x00}, // ADC input mode; R/W
//
// {CJC8988_R32_ADCL_SIGNAL_PATH, 0x40}, // Left ADC signal path control; R/W
// {CJC8988_R33_ADCR_SIGNAL_PATH, 0x40}, // Right ADC signal path control; R/W
//
// {CJC8988_R34_LEFT_OUT_MIX1_H, 0x52}, // Left DAC to left mixer disable; R/W
// {CJC8988_R35_LEFT_OUT_MIX2_L, 0x50}, // Right DAC to left mixer disable; R/W
// {CJC8988_R36_RIGHT_OUT_MIX1_L, 0x52}, // Left DAC to right mixer disable; R/W
// {CJC8988_R37_RIGHT_OUT_MIX2_H, 0x50}, // Right DAC to right mixer disable; R/W
//
// {CJC8988_R40_LOUT2_VOLUME, 0x79}, // Audio output left channel1 volume; R/W
// {CJC8988_R41_ROUT2_VOLUME, 0x79}, // Audio output right channel1 volume; R/W
// {CJC8988_R43_LOW_POWER_PLAYBACK, 0x08}, // Low power playback; R/W
//
// {CJC8988_R25_PWR_MGMT1_H, 0x7C}, // Power management1 and VMIDSEL; R/W
// {CJC8988_R26_PWR_MGMT2_H, 0xf8}, // Power management2 and DAC left power up; R/W;
//};
//
//#define CJC8988_LINPUT2_ADC_TO_DAC_LOUT2_32_REG_NUM ARRAY_SIZE(LINPUT2_ADC_TO_DAC_LOUT2_32)
//
////*************************************************************************
//// LINE Input 2 to ADC and DAC to LOUT 2 mode, slave mode, I2S format, MCLK=12MHz, BCLK = 12MHz, Fs=44.1KHz;
////
//static struct CJC8988_reg LINPUT2_ADC_TO_DAC_LOUT2_44[] = {
// {CJC8988_R0_LEFT_INPUT_VOLUME, 0x17}, // Audio input left channel volume; R/W
// {CJC8988_R1_RIGHT_INPUT_VOLUME, 0x17}, // Audio input right channel volume; R/W
// {CJC8988_R2_LOUT1_VOLUME, 0x79}, // Audio output letf channel1 volume; R/W
// {CJC8988_R3_ROUT1_VOLUME, 0x79}, // Audio output right channel1 volume; R/W
// {CJC8988_R5_ADC_DAC_CONTROL, 0x00}, // ADC and DAC CONTROL; R/W
// {CJC8988_R7_AUDIO_INTERFACE, 0x02}, // Digital Audio interface format; R/W
// {CJC8988_R8_SAMPLE_RATE, 0x23}, // Clock and Sample rate control; R/W
// {CJC8988_R10_LEFT_DAC_VOLUME, 0xff}, // Left channel DAC digital volume; R/W
// {CJC8988_R11_RIGHT_DAC_VOLUME, 0xff}, // Right channel DAC digital volume; R/W
//
// {CJC8988_R12_BASS_CONTROL, 0x0f}, // BASS control; R/W
// {CJC8988_R13_TREBLE_CONTROL, 0x0f}, // Treble control; R/W
// {CJC8988_R16_3D_CONTROL, 0x00}, // 3D control; R/W
//
// {CJC8988_R21_LEFT_ADC_VOLUME, 0xc3}, // Left ADC digital volume; R/W
// {CJC8988_R22_RIGHT_ADC_VOLUME, 0xc3}, // Right ADC digital volume; R/W
//
// {CJC8988_R23_ADDITIONAL_CONTROL1, 0xc0}, // Additional control 1; R/W
// {CJC8988_R24_ADDITIONAL_CONTROL2, 0x00}, // Additional control 2; R/W
// {CJC8988_R27_ADDITIONAL_CONTROL3, 0x00}, // Additional control 3; R/W
//
// {CJC8988_R31_ADC_INPUT_MODE, 0x00}, // ADC input mode; R/W
//
// {CJC8988_R32_ADCL_SIGNAL_PATH, 0x40}, // Left ADC signal path control; R/W
// {CJC8988_R33_ADCR_SIGNAL_PATH, 0x40}, // Right ADC signal path control; R/W
//
// {CJC8988_R34_LEFT_OUT_MIX1_H, 0x52}, // Left DAC to left mixer disable; R/W
// {CJC8988_R35_LEFT_OUT_MIX2_L, 0x50}, // Right DAC to left mixer disable; R/W
// {CJC8988_R36_RIGHT_OUT_MIX1_L, 0x52}, // Left DAC to right mixer disable; R/W
// {CJC8988_R37_RIGHT_OUT_MIX2_H, 0x50}, // Right DAC to right mixer disable; R/W
//
// {CJC8988_R40_LOUT2_VOLUME, 0x79}, // Audio output left channel1 volume; R/W
// {CJC8988_R41_ROUT2_VOLUME, 0x79}, // Audio output right channel1 volume; R/W
// {CJC8988_R43_LOW_POWER_PLAYBACK, 0x08}, // Low power playback; R/W
//
// {CJC8988_R25_PWR_MGMT1_H, 0x7C}, // Power management1 and VMIDSEL; R/W
// {CJC8988_R26_PWR_MGMT2_H, 0xf8}, // Power management2 and DAC left power up; R/W;
//};
#define CJC8988_RATES ( \
SNDRV_PCM_RATE_96000 | \
SNDRV_PCM_RATE_48000 | \
SNDRV_PCM_RATE_32000 | \
SNDRV_PCM_RATE_16000 | \
SNDRV_PCM_RATE_8000)
// CJC8988 LS2K1000-创龙板
// 深位定死16位,只能播放16位
// 如果给32位,I2S bclk 与 lrc 无法对齐,从信号上看类似于 left-justify 模式
#define CJC8988_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
static unsigned char CJC8988_SR_TABLE[][7] = {
// 8K, 12K, 16K, 24K, 32K, 48K, 96K
{0x6, 0x8, 0xa, 0x1c, 0xc, 0x0, 0xe}, // 12288000
{0x7, 0x9, 0xb, 0x1d, 0xd, 0x1, 0xf}, // 18432000
};
/* codec private data */
struct cjc8988_priv {
struct regmap *regmap;
unsigned int mode;
unsigned int freq;
};
static const char * const input_channel_text[] = { "INPUT1", "INPUT2" };
static const struct soc_enum left_input_channel_enum[] = {
SOC_ENUM_SINGLE(CJC8988_R32_ADCL_SIGNAL_PATH, 6, ARRAY_SIZE(input_channel_text), input_channel_text)
};
static const struct soc_enum right_input_channel_enum[] = {
SOC_ENUM_SINGLE(CJC8988_R33_ADCR_SIGNAL_PATH, 6, ARRAY_SIZE(input_channel_text), input_channel_text)
};
static const struct snd_kcontrol_new cjc8988_snd_controls[] = {
SOC_DOUBLE_R_RANGE("Volume", CJC8988_R2_LOUT1_VOLUME, CJC8988_R3_ROUT1_VOLUME,
0x00, 0x2f, 0x79,0),
SOC_ENUM("L-Input", left_input_channel_enum),
SOC_ENUM("R-Input", right_input_channel_enum),
};
static struct reg_default cjc8988_reg_defaults[] = {
{CJC8988_R0_LEFT_INPUT_VOLUME, 0x17}, // Audio input left channel volume; R/W
{CJC8988_R1_RIGHT_INPUT_VOLUME, 0x17}, // Audio input right channel volume; R/W
{CJC8988_R2_LOUT1_VOLUME, 0x79}, // Audio output letf channel1 volume; R/W
{CJC8988_R3_ROUT1_VOLUME, 0x79}, // Audio output right channel1 volume; R/W
{CJC8988_R5_ADC_DAC_CONTROL, 0x00}, // ADC and DAC CONTROL; R/W
{CJC8988_R7_AUDIO_INTERFACE, 0x4E}, // Digital Audio interface format; R/W
{CJC8988_R8_SAMPLE_RATE, 0x00}, // Clock and Sample rate control; R/W
{CJC8988_R10_LEFT_DAC_VOLUME, 0xff}, // Left channel DAC digital volume; R/W
{CJC8988_R11_RIGHT_DAC_VOLUME, 0xff}, // Right channel DAC digital volume; R/W
{CJC8988_R12_BASS_CONTROL, 0x0f}, // BASS control; R/W
{CJC8988_R13_TREBLE_CONTROL, 0x0f}, // Treble control; R/W
{CJC8988_R16_3D_CONTROL, 0x00}, // 3D control; R/W
{CJC8988_R21_LEFT_ADC_VOLUME, 0xc3}, // Left ADC digital volume; R/W
{CJC8988_R22_RIGHT_ADC_VOLUME, 0xc3}, // Right ADC digital volume; R/W
{CJC8988_R23_ADDITIONAL_CONTROL1, 0xc0}, // Additional control 1; R/W
{CJC8988_R24_ADDITIONAL_CONTROL2, 0x04}, // Additional control 2; R/W
{CJC8988_R27_ADDITIONAL_CONTROL3, 0x00}, // Additional control 3; R/W
{CJC8988_R31_ADC_INPUT_MODE, 0x00}, // ADC input mode; R/W
// 0x40 : 默认 INPUT2,0x70 加上 MIC 增益,按需求定
// {CJC8988_R32_ADCL_SIGNAL_PATH, 0x70}, // Left ADC signal path control; R/W
// {CJC8988_R33_ADCR_SIGNAL_PATH, 0x70}, // Right ADC signal path control; R/W
{CJC8988_R32_ADCL_SIGNAL_PATH, 0x00}, // Left ADC signal path control; R/W
{CJC8988_R33_ADCR_SIGNAL_PATH, 0x00}, // Right ADC signal path control; R/W
{CJC8988_R34_LEFT_OUT_MIX1_H, 0x52}, // Left DAC to left mixer enable; R/W
{CJC8988_R35_LEFT_OUT_MIX2_L, 0x50}, // Right DAC to left mixer disable; R/W
{CJC8988_R36_RIGHT_OUT_MIX1_L, 0x52}, // Left DAC to right mixer disable; R/W
{CJC8988_R37_RIGHT_OUT_MIX2_H, 0x50}, // Right DAC to right mixer enable; R/W
{CJC8988_R40_LOUT2_VOLUME, 0x79}, // Audio output left channel1 volume; R/W
{CJC8988_R41_ROUT2_VOLUME, 0x79}, // Audio output right channel1 volume; R/W
{CJC8988_R43_LOW_POWER_PLAYBACK, 0x08}, // Low power playback; R/W
{CJC8988_R25_PWR_MGMT1_H, 0x7c}, // Power management1 and VMIDSEL; R/W
{CJC8988_R26_PWR_MGMT2_H, 0xf8}, // Power management2 and DAC left power up; R/W;
};
static void cjc8988_default_regs_change(unsigned int reg, unsigned int val)
{
int i;
for (i = 0; i < ARRAY_SIZE(cjc8988_reg_defaults); i++) {
if (reg == cjc8988_reg_defaults[i].reg)
{
cjc8988_reg_defaults[i].def = val;
break;
}
}
}
static bool cjc8988_valid_regs(struct device *dev, unsigned int reg)
{
switch (reg) {
case CJC8988_R0_LEFT_INPUT_VOLUME:
case CJC8988_R1_RIGHT_INPUT_VOLUME:
case CJC8988_R2_LOUT1_VOLUME:
case CJC8988_R3_ROUT1_VOLUME:
case CJC8988_R5_ADC_DAC_CONTROL:
case CJC8988_R7_AUDIO_INTERFACE:
case CJC8988_R8_SAMPLE_RATE:
case CJC8988_R10_LEFT_DAC_VOLUME:
case CJC8988_R11_RIGHT_DAC_VOLUME:
case CJC8988_R12_BASS_CONTROL:
case CJC8988_R13_TREBLE_CONTROL:
case CJC8988_R16_3D_CONTROL:
case CJC8988_R21_LEFT_ADC_VOLUME:
case CJC8988_R22_RIGHT_ADC_VOLUME:
case CJC8988_R23_ADDITIONAL_CONTROL1:
case CJC8988_R24_ADDITIONAL_CONTROL2:
case CJC8988_R27_ADDITIONAL_CONTROL3:
case CJC8988_R31_ADC_INPUT_MODE:
case CJC8988_R32_ADCL_SIGNAL_PATH:
case CJC8988_R33_ADCR_SIGNAL_PATH:
case CJC8988_R34_LEFT_OUT_MIX1_H:
case CJC8988_R35_LEFT_OUT_MIX2_L:
case CJC8988_R36_RIGHT_OUT_MIX1_L:
case CJC8988_R37_RIGHT_OUT_MIX2_H:
case CJC8988_R40_LOUT2_VOLUME:
case CJC8988_R41_ROUT2_VOLUME:
case CJC8988_R43_LOW_POWER_PLAYBACK:
case CJC8988_R25_PWR_MGMT1_H:
case CJC8988_R26_PWR_MGMT2_H:
return true;
default:
return false;
}
}
/*
* Note that this should be called from init rather than from hw_params.
*/
static int cjc8988_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
return 0;
}
static int cjc8988_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
return 0;
}
static int cjc8988_pcm_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
return 0;
}
static u8 cjc8988_get_depth(unsigned int bits)
{
switch (bits)
{
case 16:
return 0x01;
case 20:
return 0x05;
case 24:
return 0x09;
case 32:
return 0x0D;
default:
return 0x01;
}
}
static int cjc8988_sr_table_map_sample_index(unsigned int sample)
{
switch (sample)
{
case 8000:
return 0;
case 12000:
return 1;
case 16000:
return 2;
case 24000:
return 3;
case 32000:
return 4;
case 48000:
return 5;
case 96000:
return 6;
default:
return 0;
}
}
static u8 cjc8988_get_sample_rate(unsigned int freq, unsigned int sample)
{
int index = cjc8988_sr_table_map_sample_index(sample);
switch (freq)
{
case 12288000:
return CJC8988_SR_TABLE[0][index] << 1;
case 18432000:
return CJC8988_SR_TABLE[1][index] << 1;
default:
return 0;
}
}
static int cjc8988_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
u8 val;
struct cjc8988_priv *cjc8988;
cjc8988 = snd_soc_component_get_drvdata(dai->component);
// NOTE-TMP-REV
// 深位定死32位,目前能播放16位
// 如果codec只给16位,正弦信号半个周期会有尖峰,怀疑与时钟有关
// val = cjc8988_get_depth(params->msbits);
// snd_soc_component_write(dai->component, CJC8988_R7_AUDIO_INTERFACE,
// (val | cjc8988->mode << 6 | 2));
val = cjc8988_get_sample_rate(cjc8988->freq, params->rate_num);
snd_soc_component_write(dai->component, CJC8988_R8_SAMPLE_RATE,
val);
return 0;
}
static int cjc8988_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
return 0;
}
static int cjc8988_component_probe(struct snd_soc_component *component)
{
int i = 0;
for (i = 0; i < ARRAY_SIZE(cjc8988_reg_defaults); i++) {
snd_soc_component_write(component, cjc8988_reg_defaults[i].reg,
cjc8988_reg_defaults[i].def);
}
return 0;
}
static const struct snd_soc_dai_ops cjc8988_dai_ops = {
.startup = cjc8988_pcm_startup,
.hw_params = cjc8988_pcm_hw_params,
.set_fmt = cjc8988_set_dai_fmt,
.set_sysclk = cjc8988_set_dai_sysclk,
};
static struct snd_soc_dai_driver cjc8988_dai = {
.name = "cjc8988-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = CJC8988_RATES,
.formats = CJC8988_FORMATS,
},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
.rates = CJC8988_RATES,
.formats = CJC8988_FORMATS,
},
.ops = &cjc8988_dai_ops,
.symmetric_rates = 1,
};
static const struct snd_soc_component_driver cjc8988_component_driver = {
.probe = cjc8988_component_probe,
.set_bias_level = cjc8988_set_bias_level,
.controls = cjc8988_snd_controls,
.num_controls = ARRAY_SIZE(cjc8988_snd_controls),
// .dapm_widgets = cjc8988_dapm_widgets,
// .num_dapm_widgets = ARRAY_SIZE(cjc8988_dapm_widgets),
// .dapm_routes = cjc8988_dapm_routes,
// .num_dapm_routes = ARRAY_SIZE(cjc8988_dapm_routes),
.suspend_bias_off = 1,
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static const struct regmap_config cjc8988_regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = CJC8988_REG_NUM,
.writeable_reg = cjc8988_valid_regs,
.readable_reg = cjc8988_valid_regs,
.cache_type = REGCACHE_RBTREE,
.reg_defaults = cjc8988_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(cjc8988_reg_defaults),
};
static const struct i2c_device_id cjc8988_id[] = {
{ "cjc8988", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, cjc8988_id);
static int cjc8988_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
int ret;
struct device *dev = &i2c->dev;
struct cjc8988_priv * cjc8988 = devm_kzalloc(dev, sizeof(*cjc8988), GFP_KERNEL);
if (cjc8988 == NULL)
return -ENOMEM;
cjc8988->regmap = devm_regmap_init_i2c(i2c, &cjc8988_regmap);
if (IS_ERR(cjc8988->regmap)) {
ret = PTR_ERR(cjc8988->regmap);
dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
return ret;
}
if (device_property_present(dev, "master-mode")){
cjc8988->mode = 1;
}
else {
cjc8988->mode = 0;
}
device_property_read_u32(&i2c->dev, "clock-frequency", &cjc8988->freq);
i2c_set_clientdata(i2c, cjc8988);
if (device_property_present(dev, "cjc8988,adc-input2")){
cjc8988_default_regs_change(CJC8988_R32_ADCL_SIGNAL_PATH, 0x40);
cjc8988_default_regs_change(CJC8988_R33_ADCR_SIGNAL_PATH, 0x40);
}
return devm_snd_soc_register_component(dev,
&cjc8988_component_driver, &cjc8988_dai, 1);
}
static struct i2c_driver cjc8988_i2c_driver = {
.driver = {
.name = "cjc8988",
},
.probe = cjc8988_i2c_probe,
.id_table = cjc8988_id,
};
module_i2c_driver(cjc8988_i2c_driver);
MODULE_DESCRIPTION("ASoC CJC8988 driver");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_LICENSE("GPL");