162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 88pm860x-codec.c -- 88PM860x ALSA SoC Audio Driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2010 Marvell International Ltd. 662306a36Sopenharmony_ci * Author: Haojian Zhuang <haojian.zhuang@marvell.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/i2c.h> 1262306a36Sopenharmony_ci#include <linux/platform_device.h> 1362306a36Sopenharmony_ci#include <linux/mfd/88pm860x.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/delay.h> 1662306a36Sopenharmony_ci#include <linux/regmap.h> 1762306a36Sopenharmony_ci#include <sound/core.h> 1862306a36Sopenharmony_ci#include <sound/pcm.h> 1962306a36Sopenharmony_ci#include <sound/pcm_params.h> 2062306a36Sopenharmony_ci#include <sound/soc.h> 2162306a36Sopenharmony_ci#include <sound/tlv.h> 2262306a36Sopenharmony_ci#include <sound/initval.h> 2362306a36Sopenharmony_ci#include <sound/jack.h> 2462306a36Sopenharmony_ci#include <trace/events/asoc.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "88pm860x-codec.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define MAX_NAME_LEN 20 2962306a36Sopenharmony_ci#define REG_CACHE_SIZE 0x40 3062306a36Sopenharmony_ci#define REG_CACHE_BASE 0xb0 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* Status Register 1 (0x01) */ 3362306a36Sopenharmony_ci#define REG_STATUS_1 0x01 3462306a36Sopenharmony_ci#define MIC_STATUS (1 << 7) 3562306a36Sopenharmony_ci#define HOOK_STATUS (1 << 6) 3662306a36Sopenharmony_ci#define HEADSET_STATUS (1 << 5) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* Mic Detection Register (0x37) */ 3962306a36Sopenharmony_ci#define REG_MIC_DET 0x37 4062306a36Sopenharmony_ci#define CONTINUOUS_POLLING (3 << 1) 4162306a36Sopenharmony_ci#define EN_MIC_DET (1 << 0) 4262306a36Sopenharmony_ci#define MICDET_MASK 0x07 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* Headset Detection Register (0x38) */ 4562306a36Sopenharmony_ci#define REG_HS_DET 0x38 4662306a36Sopenharmony_ci#define EN_HS_DET (1 << 0) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* Misc2 Register (0x42) */ 4962306a36Sopenharmony_ci#define REG_MISC2 0x42 5062306a36Sopenharmony_ci#define AUDIO_PLL (1 << 5) 5162306a36Sopenharmony_ci#define AUDIO_SECTION_RESET (1 << 4) 5262306a36Sopenharmony_ci#define AUDIO_SECTION_ON (1 << 3) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* PCM Interface Register 2 (0xb1) */ 5562306a36Sopenharmony_ci#define PCM_INF2_BCLK (1 << 6) /* Bit clock polarity */ 5662306a36Sopenharmony_ci#define PCM_INF2_FS (1 << 5) /* Frame Sync polarity */ 5762306a36Sopenharmony_ci#define PCM_INF2_MASTER (1 << 4) /* Master / Slave */ 5862306a36Sopenharmony_ci#define PCM_INF2_18WL (1 << 3) /* 18 / 16 bits */ 5962306a36Sopenharmony_ci#define PCM_GENERAL_I2S 0 6062306a36Sopenharmony_ci#define PCM_EXACT_I2S 1 6162306a36Sopenharmony_ci#define PCM_LEFT_I2S 2 6262306a36Sopenharmony_ci#define PCM_RIGHT_I2S 3 6362306a36Sopenharmony_ci#define PCM_SHORT_FS 4 6462306a36Sopenharmony_ci#define PCM_LONG_FS 5 6562306a36Sopenharmony_ci#define PCM_MODE_MASK 7 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* I2S Interface Register 4 (0xbe) */ 6862306a36Sopenharmony_ci#define I2S_EQU_BYP (1 << 6) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* DAC Offset Register (0xcb) */ 7162306a36Sopenharmony_ci#define DAC_MUTE (1 << 7) 7262306a36Sopenharmony_ci#define MUTE_LEFT (1 << 6) 7362306a36Sopenharmony_ci#define MUTE_RIGHT (1 << 2) 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* ADC Analog Register 1 (0xd0) */ 7662306a36Sopenharmony_ci#define REG_ADC_ANA_1 0xd0 7762306a36Sopenharmony_ci#define MIC1BIAS_MASK 0x60 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* Earpiece/Speaker Control Register 2 (0xda) */ 8062306a36Sopenharmony_ci#define REG_EAR2 0xda 8162306a36Sopenharmony_ci#define RSYNC_CHANGE (1 << 2) 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* Audio Supplies Register 2 (0xdc) */ 8462306a36Sopenharmony_ci#define REG_SUPPLIES2 0xdc 8562306a36Sopenharmony_ci#define LDO15_READY (1 << 4) 8662306a36Sopenharmony_ci#define LDO15_EN (1 << 3) 8762306a36Sopenharmony_ci#define CPUMP_READY (1 << 2) 8862306a36Sopenharmony_ci#define CPUMP_EN (1 << 1) 8962306a36Sopenharmony_ci#define AUDIO_EN (1 << 0) 9062306a36Sopenharmony_ci#define SUPPLY_MASK (LDO15_EN | CPUMP_EN | AUDIO_EN) 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* Audio Enable Register 1 (0xdd) */ 9362306a36Sopenharmony_ci#define ADC_MOD_RIGHT (1 << 1) 9462306a36Sopenharmony_ci#define ADC_MOD_LEFT (1 << 0) 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* Audio Enable Register 2 (0xde) */ 9762306a36Sopenharmony_ci#define ADC_LEFT (1 << 5) 9862306a36Sopenharmony_ci#define ADC_RIGHT (1 << 4) 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* DAC Enable Register 2 (0xe1) */ 10162306a36Sopenharmony_ci#define DAC_LEFT (1 << 5) 10262306a36Sopenharmony_ci#define DAC_RIGHT (1 << 4) 10362306a36Sopenharmony_ci#define MODULATOR (1 << 3) 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* Shorts Register (0xeb) */ 10662306a36Sopenharmony_ci#define REG_SHORTS 0xeb 10762306a36Sopenharmony_ci#define CLR_SHORT_LO2 (1 << 7) 10862306a36Sopenharmony_ci#define SHORT_LO2 (1 << 6) 10962306a36Sopenharmony_ci#define CLR_SHORT_LO1 (1 << 5) 11062306a36Sopenharmony_ci#define SHORT_LO1 (1 << 4) 11162306a36Sopenharmony_ci#define CLR_SHORT_HS2 (1 << 3) 11262306a36Sopenharmony_ci#define SHORT_HS2 (1 << 2) 11362306a36Sopenharmony_ci#define CLR_SHORT_HS1 (1 << 1) 11462306a36Sopenharmony_ci#define SHORT_HS1 (1 << 0) 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/* 11762306a36Sopenharmony_ci * This widget should be just after DAC & PGA in DAPM power-on sequence and 11862306a36Sopenharmony_ci * before DAC & PGA in DAPM power-off sequence. 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_ci#define PM860X_DAPM_OUTPUT(wname, wevent) \ 12162306a36Sopenharmony_ci SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, 0, 0, NULL, 0, wevent, \ 12262306a36Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD) 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistruct pm860x_det { 12562306a36Sopenharmony_ci struct snd_soc_jack *hp_jack; 12662306a36Sopenharmony_ci struct snd_soc_jack *mic_jack; 12762306a36Sopenharmony_ci int hp_det; 12862306a36Sopenharmony_ci int mic_det; 12962306a36Sopenharmony_ci int hook_det; 13062306a36Sopenharmony_ci int hs_shrt; 13162306a36Sopenharmony_ci int lo_shrt; 13262306a36Sopenharmony_ci}; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistruct pm860x_priv { 13562306a36Sopenharmony_ci unsigned int sysclk; 13662306a36Sopenharmony_ci unsigned int pcmclk; 13762306a36Sopenharmony_ci unsigned int dir; 13862306a36Sopenharmony_ci unsigned int filter; 13962306a36Sopenharmony_ci struct snd_soc_component *component; 14062306a36Sopenharmony_ci struct i2c_client *i2c; 14162306a36Sopenharmony_ci struct regmap *regmap; 14262306a36Sopenharmony_ci struct pm860x_chip *chip; 14362306a36Sopenharmony_ci struct pm860x_det det; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci int irq[4]; 14662306a36Sopenharmony_ci unsigned char name[4][MAX_NAME_LEN]; 14762306a36Sopenharmony_ci}; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */ 15062306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(dpga_tlv, -9450, 150, 1); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/* -9dB to 0db in 3dB steps */ 15362306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(adc_tlv, -900, 300, 0); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* {-23, -17, -13.5, -11, -9, -6, -3, 0}dB */ 15662306a36Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(mic_tlv, 15762306a36Sopenharmony_ci 0, 0, TLV_DB_SCALE_ITEM(-2300, 0, 0), 15862306a36Sopenharmony_ci 1, 1, TLV_DB_SCALE_ITEM(-1700, 0, 0), 15962306a36Sopenharmony_ci 2, 2, TLV_DB_SCALE_ITEM(-1350, 0, 0), 16062306a36Sopenharmony_ci 3, 3, TLV_DB_SCALE_ITEM(-1100, 0, 0), 16162306a36Sopenharmony_ci 4, 7, TLV_DB_SCALE_ITEM(-900, 300, 0) 16262306a36Sopenharmony_ci); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* {0, 0, 0, -6, 0, 6, 12, 18}dB */ 16562306a36Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(aux_tlv, 16662306a36Sopenharmony_ci 0, 2, TLV_DB_SCALE_ITEM(0, 0, 0), 16762306a36Sopenharmony_ci 3, 7, TLV_DB_SCALE_ITEM(-600, 600, 0) 16862306a36Sopenharmony_ci); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/* {-16, -13, -10, -7, -5.2, -3,3, -2.2, 0}dB, mute instead of -16dB */ 17162306a36Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(out_tlv, 17262306a36Sopenharmony_ci 0, 3, TLV_DB_SCALE_ITEM(-1600, 300, 1), 17362306a36Sopenharmony_ci 4, 4, TLV_DB_SCALE_ITEM(-520, 0, 0), 17462306a36Sopenharmony_ci 5, 5, TLV_DB_SCALE_ITEM(-330, 0, 0), 17562306a36Sopenharmony_ci 6, 7, TLV_DB_SCALE_ITEM(-220, 220, 0) 17662306a36Sopenharmony_ci); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(st_tlv, 17962306a36Sopenharmony_ci 0, 1, TLV_DB_SCALE_ITEM(-12041, 602, 0), 18062306a36Sopenharmony_ci 2, 3, TLV_DB_SCALE_ITEM(-11087, 250, 0), 18162306a36Sopenharmony_ci 4, 5, TLV_DB_SCALE_ITEM(-10643, 158, 0), 18262306a36Sopenharmony_ci 6, 7, TLV_DB_SCALE_ITEM(-10351, 116, 0), 18362306a36Sopenharmony_ci 8, 9, TLV_DB_SCALE_ITEM(-10133, 92, 0), 18462306a36Sopenharmony_ci 10, 13, TLV_DB_SCALE_ITEM(-9958, 70, 0), 18562306a36Sopenharmony_ci 14, 17, TLV_DB_SCALE_ITEM(-9689, 53, 0), 18662306a36Sopenharmony_ci 18, 271, TLV_DB_SCALE_ITEM(-9484, 37, 0) 18762306a36Sopenharmony_ci); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci/* Sidetone Gain = M * 2^(-5-N) */ 19062306a36Sopenharmony_cistruct st_gain { 19162306a36Sopenharmony_ci unsigned int db; 19262306a36Sopenharmony_ci unsigned int m; 19362306a36Sopenharmony_ci unsigned int n; 19462306a36Sopenharmony_ci}; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic struct st_gain st_table[] = { 19762306a36Sopenharmony_ci {-12041, 1, 15}, {-11439, 1, 14}, {-11087, 3, 15}, {-10837, 1, 13}, 19862306a36Sopenharmony_ci {-10643, 5, 15}, {-10485, 3, 14}, {-10351, 7, 15}, {-10235, 1, 12}, 19962306a36Sopenharmony_ci {-10133, 9, 15}, {-10041, 5, 14}, { -9958, 11, 15}, { -9883, 3, 13}, 20062306a36Sopenharmony_ci { -9813, 13, 15}, { -9749, 7, 14}, { -9689, 15, 15}, { -9633, 1, 11}, 20162306a36Sopenharmony_ci { -9580, 17, 15}, { -9531, 9, 14}, { -9484, 19, 15}, { -9439, 5, 13}, 20262306a36Sopenharmony_ci { -9397, 21, 15}, { -9356, 11, 14}, { -9318, 23, 15}, { -9281, 3, 12}, 20362306a36Sopenharmony_ci { -9245, 25, 15}, { -9211, 13, 14}, { -9178, 27, 15}, { -9147, 7, 13}, 20462306a36Sopenharmony_ci { -9116, 29, 15}, { -9087, 15, 14}, { -9058, 31, 15}, { -9031, 1, 10}, 20562306a36Sopenharmony_ci { -8978, 17, 14}, { -8929, 9, 13}, { -8882, 19, 14}, { -8837, 5, 12}, 20662306a36Sopenharmony_ci { -8795, 21, 14}, { -8754, 11, 13}, { -8716, 23, 14}, { -8679, 3, 11}, 20762306a36Sopenharmony_ci { -8643, 25, 14}, { -8609, 13, 13}, { -8576, 27, 14}, { -8545, 7, 12}, 20862306a36Sopenharmony_ci { -8514, 29, 14}, { -8485, 15, 13}, { -8456, 31, 14}, { -8429, 1, 9}, 20962306a36Sopenharmony_ci { -8376, 17, 13}, { -8327, 9, 12}, { -8280, 19, 13}, { -8235, 5, 11}, 21062306a36Sopenharmony_ci { -8193, 21, 13}, { -8152, 11, 12}, { -8114, 23, 13}, { -8077, 3, 10}, 21162306a36Sopenharmony_ci { -8041, 25, 13}, { -8007, 13, 12}, { -7974, 27, 13}, { -7943, 7, 11}, 21262306a36Sopenharmony_ci { -7912, 29, 13}, { -7883, 15, 12}, { -7854, 31, 13}, { -7827, 1, 8}, 21362306a36Sopenharmony_ci { -7774, 17, 12}, { -7724, 9, 11}, { -7678, 19, 12}, { -7633, 5, 10}, 21462306a36Sopenharmony_ci { -7591, 21, 12}, { -7550, 11, 11}, { -7512, 23, 12}, { -7475, 3, 9}, 21562306a36Sopenharmony_ci { -7439, 25, 12}, { -7405, 13, 11}, { -7372, 27, 12}, { -7341, 7, 10}, 21662306a36Sopenharmony_ci { -7310, 29, 12}, { -7281, 15, 11}, { -7252, 31, 12}, { -7225, 1, 7}, 21762306a36Sopenharmony_ci { -7172, 17, 11}, { -7122, 9, 10}, { -7075, 19, 11}, { -7031, 5, 9}, 21862306a36Sopenharmony_ci { -6989, 21, 11}, { -6948, 11, 10}, { -6910, 23, 11}, { -6873, 3, 8}, 21962306a36Sopenharmony_ci { -6837, 25, 11}, { -6803, 13, 10}, { -6770, 27, 11}, { -6739, 7, 9}, 22062306a36Sopenharmony_ci { -6708, 29, 11}, { -6679, 15, 10}, { -6650, 31, 11}, { -6623, 1, 6}, 22162306a36Sopenharmony_ci { -6570, 17, 10}, { -6520, 9, 9}, { -6473, 19, 10}, { -6429, 5, 8}, 22262306a36Sopenharmony_ci { -6386, 21, 10}, { -6346, 11, 9}, { -6307, 23, 10}, { -6270, 3, 7}, 22362306a36Sopenharmony_ci { -6235, 25, 10}, { -6201, 13, 9}, { -6168, 27, 10}, { -6137, 7, 8}, 22462306a36Sopenharmony_ci { -6106, 29, 10}, { -6077, 15, 9}, { -6048, 31, 10}, { -6021, 1, 5}, 22562306a36Sopenharmony_ci { -5968, 17, 9}, { -5918, 9, 8}, { -5871, 19, 9}, { -5827, 5, 7}, 22662306a36Sopenharmony_ci { -5784, 21, 9}, { -5744, 11, 8}, { -5705, 23, 9}, { -5668, 3, 6}, 22762306a36Sopenharmony_ci { -5633, 25, 9}, { -5599, 13, 8}, { -5566, 27, 9}, { -5535, 7, 7}, 22862306a36Sopenharmony_ci { -5504, 29, 9}, { -5475, 15, 8}, { -5446, 31, 9}, { -5419, 1, 4}, 22962306a36Sopenharmony_ci { -5366, 17, 8}, { -5316, 9, 7}, { -5269, 19, 8}, { -5225, 5, 6}, 23062306a36Sopenharmony_ci { -5182, 21, 8}, { -5142, 11, 7}, { -5103, 23, 8}, { -5066, 3, 5}, 23162306a36Sopenharmony_ci { -5031, 25, 8}, { -4997, 13, 7}, { -4964, 27, 8}, { -4932, 7, 6}, 23262306a36Sopenharmony_ci { -4902, 29, 8}, { -4873, 15, 7}, { -4844, 31, 8}, { -4816, 1, 3}, 23362306a36Sopenharmony_ci { -4764, 17, 7}, { -4714, 9, 6}, { -4667, 19, 7}, { -4623, 5, 5}, 23462306a36Sopenharmony_ci { -4580, 21, 7}, { -4540, 11, 6}, { -4501, 23, 7}, { -4464, 3, 4}, 23562306a36Sopenharmony_ci { -4429, 25, 7}, { -4395, 13, 6}, { -4362, 27, 7}, { -4330, 7, 5}, 23662306a36Sopenharmony_ci { -4300, 29, 7}, { -4270, 15, 6}, { -4242, 31, 7}, { -4214, 1, 2}, 23762306a36Sopenharmony_ci { -4162, 17, 6}, { -4112, 9, 5}, { -4065, 19, 6}, { -4021, 5, 4}, 23862306a36Sopenharmony_ci { -3978, 21, 6}, { -3938, 11, 5}, { -3899, 23, 6}, { -3862, 3, 3}, 23962306a36Sopenharmony_ci { -3827, 25, 6}, { -3793, 13, 5}, { -3760, 27, 6}, { -3728, 7, 4}, 24062306a36Sopenharmony_ci { -3698, 29, 6}, { -3668, 15, 5}, { -3640, 31, 6}, { -3612, 1, 1}, 24162306a36Sopenharmony_ci { -3560, 17, 5}, { -3510, 9, 4}, { -3463, 19, 5}, { -3419, 5, 3}, 24262306a36Sopenharmony_ci { -3376, 21, 5}, { -3336, 11, 4}, { -3297, 23, 5}, { -3260, 3, 2}, 24362306a36Sopenharmony_ci { -3225, 25, 5}, { -3191, 13, 4}, { -3158, 27, 5}, { -3126, 7, 3}, 24462306a36Sopenharmony_ci { -3096, 29, 5}, { -3066, 15, 4}, { -3038, 31, 5}, { -3010, 1, 0}, 24562306a36Sopenharmony_ci { -2958, 17, 4}, { -2908, 9, 3}, { -2861, 19, 4}, { -2816, 5, 2}, 24662306a36Sopenharmony_ci { -2774, 21, 4}, { -2734, 11, 3}, { -2695, 23, 4}, { -2658, 3, 1}, 24762306a36Sopenharmony_ci { -2623, 25, 4}, { -2589, 13, 3}, { -2556, 27, 4}, { -2524, 7, 2}, 24862306a36Sopenharmony_ci { -2494, 29, 4}, { -2464, 15, 3}, { -2436, 31, 4}, { -2408, 2, 0}, 24962306a36Sopenharmony_ci { -2356, 17, 3}, { -2306, 9, 2}, { -2259, 19, 3}, { -2214, 5, 1}, 25062306a36Sopenharmony_ci { -2172, 21, 3}, { -2132, 11, 2}, { -2093, 23, 3}, { -2056, 3, 0}, 25162306a36Sopenharmony_ci { -2021, 25, 3}, { -1987, 13, 2}, { -1954, 27, 3}, { -1922, 7, 1}, 25262306a36Sopenharmony_ci { -1892, 29, 3}, { -1862, 15, 2}, { -1834, 31, 3}, { -1806, 4, 0}, 25362306a36Sopenharmony_ci { -1754, 17, 2}, { -1704, 9, 1}, { -1657, 19, 2}, { -1612, 5, 0}, 25462306a36Sopenharmony_ci { -1570, 21, 2}, { -1530, 11, 1}, { -1491, 23, 2}, { -1454, 6, 0}, 25562306a36Sopenharmony_ci { -1419, 25, 2}, { -1384, 13, 1}, { -1352, 27, 2}, { -1320, 7, 0}, 25662306a36Sopenharmony_ci { -1290, 29, 2}, { -1260, 15, 1}, { -1232, 31, 2}, { -1204, 8, 0}, 25762306a36Sopenharmony_ci { -1151, 17, 1}, { -1102, 9, 0}, { -1055, 19, 1}, { -1010, 10, 0}, 25862306a36Sopenharmony_ci { -968, 21, 1}, { -928, 11, 0}, { -889, 23, 1}, { -852, 12, 0}, 25962306a36Sopenharmony_ci { -816, 25, 1}, { -782, 13, 0}, { -750, 27, 1}, { -718, 14, 0}, 26062306a36Sopenharmony_ci { -688, 29, 1}, { -658, 15, 0}, { -630, 31, 1}, { -602, 16, 0}, 26162306a36Sopenharmony_ci { -549, 17, 0}, { -500, 18, 0}, { -453, 19, 0}, { -408, 20, 0}, 26262306a36Sopenharmony_ci { -366, 21, 0}, { -325, 22, 0}, { -287, 23, 0}, { -250, 24, 0}, 26362306a36Sopenharmony_ci { -214, 25, 0}, { -180, 26, 0}, { -148, 27, 0}, { -116, 28, 0}, 26462306a36Sopenharmony_ci { -86, 29, 0}, { -56, 30, 0}, { -28, 31, 0}, { 0, 0, 0}, 26562306a36Sopenharmony_ci}; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol, 26862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci struct soc_mixer_control *mc = 27162306a36Sopenharmony_ci (struct soc_mixer_control *)kcontrol->private_value; 27262306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 27362306a36Sopenharmony_ci unsigned int reg = mc->reg; 27462306a36Sopenharmony_ci unsigned int reg2 = mc->rreg; 27562306a36Sopenharmony_ci int val[2], val2[2], i; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci val[0] = snd_soc_component_read(component, reg) & 0x3f; 27862306a36Sopenharmony_ci val[1] = (snd_soc_component_read(component, PM860X_SIDETONE_SHIFT) >> 4) & 0xf; 27962306a36Sopenharmony_ci val2[0] = snd_soc_component_read(component, reg2) & 0x3f; 28062306a36Sopenharmony_ci val2[1] = (snd_soc_component_read(component, PM860X_SIDETONE_SHIFT)) & 0xf; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(st_table); i++) { 28362306a36Sopenharmony_ci if ((st_table[i].m == val[0]) && (st_table[i].n == val[1])) 28462306a36Sopenharmony_ci ucontrol->value.integer.value[0] = i; 28562306a36Sopenharmony_ci if ((st_table[i].m == val2[0]) && (st_table[i].n == val2[1])) 28662306a36Sopenharmony_ci ucontrol->value.integer.value[1] = i; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci return 0; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol, 29262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci struct soc_mixer_control *mc = 29562306a36Sopenharmony_ci (struct soc_mixer_control *)kcontrol->private_value; 29662306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 29762306a36Sopenharmony_ci unsigned int reg = mc->reg; 29862306a36Sopenharmony_ci unsigned int reg2 = mc->rreg; 29962306a36Sopenharmony_ci int err; 30062306a36Sopenharmony_ci unsigned int val, val2; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci val = ucontrol->value.integer.value[0]; 30362306a36Sopenharmony_ci val2 = ucontrol->value.integer.value[1]; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (val >= ARRAY_SIZE(st_table) || val2 >= ARRAY_SIZE(st_table)) 30662306a36Sopenharmony_ci return -EINVAL; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci err = snd_soc_component_update_bits(component, reg, 0x3f, st_table[val].m); 30962306a36Sopenharmony_ci if (err < 0) 31062306a36Sopenharmony_ci return err; 31162306a36Sopenharmony_ci err = snd_soc_component_update_bits(component, PM860X_SIDETONE_SHIFT, 0xf0, 31262306a36Sopenharmony_ci st_table[val].n << 4); 31362306a36Sopenharmony_ci if (err < 0) 31462306a36Sopenharmony_ci return err; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci err = snd_soc_component_update_bits(component, reg2, 0x3f, st_table[val2].m); 31762306a36Sopenharmony_ci if (err < 0) 31862306a36Sopenharmony_ci return err; 31962306a36Sopenharmony_ci err = snd_soc_component_update_bits(component, PM860X_SIDETONE_SHIFT, 0x0f, 32062306a36Sopenharmony_ci st_table[val2].n); 32162306a36Sopenharmony_ci return err; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic int snd_soc_get_volsw_2r_out(struct snd_kcontrol *kcontrol, 32562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci struct soc_mixer_control *mc = 32862306a36Sopenharmony_ci (struct soc_mixer_control *)kcontrol->private_value; 32962306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 33062306a36Sopenharmony_ci unsigned int reg = mc->reg; 33162306a36Sopenharmony_ci unsigned int reg2 = mc->rreg; 33262306a36Sopenharmony_ci unsigned int shift = mc->shift; 33362306a36Sopenharmony_ci int max = mc->max, val, val2; 33462306a36Sopenharmony_ci unsigned int mask = (1 << fls(max)) - 1; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci val = snd_soc_component_read(component, reg) >> shift; 33762306a36Sopenharmony_ci val2 = snd_soc_component_read(component, reg2) >> shift; 33862306a36Sopenharmony_ci ucontrol->value.integer.value[0] = (max - val) & mask; 33962306a36Sopenharmony_ci ucontrol->value.integer.value[1] = (max - val2) & mask; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci return 0; 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol, 34562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci struct soc_mixer_control *mc = 34862306a36Sopenharmony_ci (struct soc_mixer_control *)kcontrol->private_value; 34962306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 35062306a36Sopenharmony_ci unsigned int reg = mc->reg; 35162306a36Sopenharmony_ci unsigned int reg2 = mc->rreg; 35262306a36Sopenharmony_ci unsigned int shift = mc->shift; 35362306a36Sopenharmony_ci int max = mc->max; 35462306a36Sopenharmony_ci unsigned int mask = (1 << fls(max)) - 1; 35562306a36Sopenharmony_ci int err; 35662306a36Sopenharmony_ci unsigned int val, val2, val_mask; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci val_mask = mask << shift; 35962306a36Sopenharmony_ci val = ((max - ucontrol->value.integer.value[0]) & mask); 36062306a36Sopenharmony_ci val2 = ((max - ucontrol->value.integer.value[1]) & mask); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci val = val << shift; 36362306a36Sopenharmony_ci val2 = val2 << shift; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci err = snd_soc_component_update_bits(component, reg, val_mask, val); 36662306a36Sopenharmony_ci if (err < 0) 36762306a36Sopenharmony_ci return err; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci err = snd_soc_component_update_bits(component, reg2, val_mask, val2); 37062306a36Sopenharmony_ci return err; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci/* DAPM Widget Events */ 37462306a36Sopenharmony_ci/* 37562306a36Sopenharmony_ci * A lot registers are belong to RSYNC domain. It requires enabling RSYNC bit 37662306a36Sopenharmony_ci * after updating these registers. Otherwise, these updated registers won't 37762306a36Sopenharmony_ci * be effective. 37862306a36Sopenharmony_ci */ 37962306a36Sopenharmony_cistatic int pm860x_rsync_event(struct snd_soc_dapm_widget *w, 38062306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* 38562306a36Sopenharmony_ci * In order to avoid current on the load, mute power-on and power-off 38662306a36Sopenharmony_ci * should be transients. 38762306a36Sopenharmony_ci * Unmute by DAC_MUTE. It should be unmuted when DAPM sequence is 38862306a36Sopenharmony_ci * finished. 38962306a36Sopenharmony_ci */ 39062306a36Sopenharmony_ci snd_soc_component_update_bits(component, PM860X_DAC_OFFSET, DAC_MUTE, 0); 39162306a36Sopenharmony_ci snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2, 39262306a36Sopenharmony_ci RSYNC_CHANGE, RSYNC_CHANGE); 39362306a36Sopenharmony_ci return 0; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic int pm860x_dac_event(struct snd_soc_dapm_widget *w, 39762306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 40062306a36Sopenharmony_ci unsigned int dac = 0; 40162306a36Sopenharmony_ci int data; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (!strcmp(w->name, "Left DAC")) 40462306a36Sopenharmony_ci dac = DAC_LEFT; 40562306a36Sopenharmony_ci if (!strcmp(w->name, "Right DAC")) 40662306a36Sopenharmony_ci dac = DAC_RIGHT; 40762306a36Sopenharmony_ci switch (event) { 40862306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMU: 40962306a36Sopenharmony_ci if (dac) { 41062306a36Sopenharmony_ci /* Auto mute in power-on sequence. */ 41162306a36Sopenharmony_ci dac |= MODULATOR; 41262306a36Sopenharmony_ci snd_soc_component_update_bits(component, PM860X_DAC_OFFSET, 41362306a36Sopenharmony_ci DAC_MUTE, DAC_MUTE); 41462306a36Sopenharmony_ci snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2, 41562306a36Sopenharmony_ci RSYNC_CHANGE, RSYNC_CHANGE); 41662306a36Sopenharmony_ci /* update dac */ 41762306a36Sopenharmony_ci snd_soc_component_update_bits(component, PM860X_DAC_EN_2, 41862306a36Sopenharmony_ci dac, dac); 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci break; 42162306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 42262306a36Sopenharmony_ci if (dac) { 42362306a36Sopenharmony_ci /* Auto mute in power-off sequence. */ 42462306a36Sopenharmony_ci snd_soc_component_update_bits(component, PM860X_DAC_OFFSET, 42562306a36Sopenharmony_ci DAC_MUTE, DAC_MUTE); 42662306a36Sopenharmony_ci snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2, 42762306a36Sopenharmony_ci RSYNC_CHANGE, RSYNC_CHANGE); 42862306a36Sopenharmony_ci /* update dac */ 42962306a36Sopenharmony_ci data = snd_soc_component_read(component, PM860X_DAC_EN_2); 43062306a36Sopenharmony_ci data &= ~dac; 43162306a36Sopenharmony_ci if (!(data & (DAC_LEFT | DAC_RIGHT))) 43262306a36Sopenharmony_ci data &= ~MODULATOR; 43362306a36Sopenharmony_ci snd_soc_component_write(component, PM860X_DAC_EN_2, data); 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci break; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci return 0; 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic const char *pm860x_opamp_texts[] = {"-50%", "-25%", "0%", "75%"}; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic const char *pm860x_pa_texts[] = {"-33%", "0%", "33%", "66%"}; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_hs1_opamp_enum, 44562306a36Sopenharmony_ci PM860X_HS1_CTRL, 5, pm860x_opamp_texts); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_hs2_opamp_enum, 44862306a36Sopenharmony_ci PM860X_HS2_CTRL, 5, pm860x_opamp_texts); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_hs1_pa_enum, 45162306a36Sopenharmony_ci PM860X_HS1_CTRL, 3, pm860x_pa_texts); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_hs2_pa_enum, 45462306a36Sopenharmony_ci PM860X_HS2_CTRL, 3, pm860x_pa_texts); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_lo1_opamp_enum, 45762306a36Sopenharmony_ci PM860X_LO1_CTRL, 5, pm860x_opamp_texts); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_lo2_opamp_enum, 46062306a36Sopenharmony_ci PM860X_LO2_CTRL, 5, pm860x_opamp_texts); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_lo1_pa_enum, 46362306a36Sopenharmony_ci PM860X_LO1_CTRL, 3, pm860x_pa_texts); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_lo2_pa_enum, 46662306a36Sopenharmony_ci PM860X_LO2_CTRL, 3, pm860x_pa_texts); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_spk_pa_enum, 46962306a36Sopenharmony_ci PM860X_EAR_CTRL_1, 5, pm860x_pa_texts); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_ear_pa_enum, 47262306a36Sopenharmony_ci PM860X_EAR_CTRL_2, 0, pm860x_pa_texts); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_spk_ear_opamp_enum, 47562306a36Sopenharmony_ci PM860X_EAR_CTRL_1, 3, pm860x_opamp_texts); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic const struct snd_kcontrol_new pm860x_snd_controls[] = { 47862306a36Sopenharmony_ci SOC_DOUBLE_R_TLV("ADC Capture Volume", PM860X_ADC_ANA_2, 47962306a36Sopenharmony_ci PM860X_ADC_ANA_3, 6, 3, 0, adc_tlv), 48062306a36Sopenharmony_ci SOC_DOUBLE_TLV("AUX Capture Volume", PM860X_ADC_ANA_3, 0, 3, 7, 0, 48162306a36Sopenharmony_ci aux_tlv), 48262306a36Sopenharmony_ci SOC_SINGLE_TLV("MIC1 Capture Volume", PM860X_ADC_ANA_2, 0, 7, 0, 48362306a36Sopenharmony_ci mic_tlv), 48462306a36Sopenharmony_ci SOC_SINGLE_TLV("MIC3 Capture Volume", PM860X_ADC_ANA_2, 3, 7, 0, 48562306a36Sopenharmony_ci mic_tlv), 48662306a36Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("Sidetone Volume", PM860X_SIDETONE_L_GAIN, 48762306a36Sopenharmony_ci PM860X_SIDETONE_R_GAIN, 0, ARRAY_SIZE(st_table)-1, 48862306a36Sopenharmony_ci 0, snd_soc_get_volsw_2r_st, 48962306a36Sopenharmony_ci snd_soc_put_volsw_2r_st, st_tlv), 49062306a36Sopenharmony_ci SOC_SINGLE_TLV("Speaker Playback Volume", PM860X_EAR_CTRL_1, 49162306a36Sopenharmony_ci 0, 7, 0, out_tlv), 49262306a36Sopenharmony_ci SOC_DOUBLE_R_TLV("Line Playback Volume", PM860X_LO1_CTRL, 49362306a36Sopenharmony_ci PM860X_LO2_CTRL, 0, 7, 0, out_tlv), 49462306a36Sopenharmony_ci SOC_DOUBLE_R_TLV("Headset Playback Volume", PM860X_HS1_CTRL, 49562306a36Sopenharmony_ci PM860X_HS2_CTRL, 0, 7, 0, out_tlv), 49662306a36Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("Hifi Left Playback Volume", 49762306a36Sopenharmony_ci PM860X_HIFIL_GAIN_LEFT, 49862306a36Sopenharmony_ci PM860X_HIFIL_GAIN_RIGHT, 0, 63, 0, 49962306a36Sopenharmony_ci snd_soc_get_volsw_2r_out, 50062306a36Sopenharmony_ci snd_soc_put_volsw_2r_out, dpga_tlv), 50162306a36Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("Hifi Right Playback Volume", 50262306a36Sopenharmony_ci PM860X_HIFIR_GAIN_LEFT, 50362306a36Sopenharmony_ci PM860X_HIFIR_GAIN_RIGHT, 0, 63, 0, 50462306a36Sopenharmony_ci snd_soc_get_volsw_2r_out, 50562306a36Sopenharmony_ci snd_soc_put_volsw_2r_out, dpga_tlv), 50662306a36Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("Lofi Playback Volume", PM860X_LOFI_GAIN_LEFT, 50762306a36Sopenharmony_ci PM860X_LOFI_GAIN_RIGHT, 0, 63, 0, 50862306a36Sopenharmony_ci snd_soc_get_volsw_2r_out, 50962306a36Sopenharmony_ci snd_soc_put_volsw_2r_out, dpga_tlv), 51062306a36Sopenharmony_ci SOC_ENUM("Headset1 Operational Amplifier Current", 51162306a36Sopenharmony_ci pm860x_hs1_opamp_enum), 51262306a36Sopenharmony_ci SOC_ENUM("Headset2 Operational Amplifier Current", 51362306a36Sopenharmony_ci pm860x_hs2_opamp_enum), 51462306a36Sopenharmony_ci SOC_ENUM("Headset1 Amplifier Current", pm860x_hs1_pa_enum), 51562306a36Sopenharmony_ci SOC_ENUM("Headset2 Amplifier Current", pm860x_hs2_pa_enum), 51662306a36Sopenharmony_ci SOC_ENUM("Lineout1 Operational Amplifier Current", 51762306a36Sopenharmony_ci pm860x_lo1_opamp_enum), 51862306a36Sopenharmony_ci SOC_ENUM("Lineout2 Operational Amplifier Current", 51962306a36Sopenharmony_ci pm860x_lo2_opamp_enum), 52062306a36Sopenharmony_ci SOC_ENUM("Lineout1 Amplifier Current", pm860x_lo1_pa_enum), 52162306a36Sopenharmony_ci SOC_ENUM("Lineout2 Amplifier Current", pm860x_lo2_pa_enum), 52262306a36Sopenharmony_ci SOC_ENUM("Speaker Operational Amplifier Current", 52362306a36Sopenharmony_ci pm860x_spk_ear_opamp_enum), 52462306a36Sopenharmony_ci SOC_ENUM("Speaker Amplifier Current", pm860x_spk_pa_enum), 52562306a36Sopenharmony_ci SOC_ENUM("Earpiece Amplifier Current", pm860x_ear_pa_enum), 52662306a36Sopenharmony_ci}; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci/* 52962306a36Sopenharmony_ci * DAPM Controls 53062306a36Sopenharmony_ci */ 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci/* AUX1 Switch */ 53362306a36Sopenharmony_cistatic const struct snd_kcontrol_new aux1_switch_controls = 53462306a36Sopenharmony_ci SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 4, 1, 0); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci/* AUX2 Switch */ 53762306a36Sopenharmony_cistatic const struct snd_kcontrol_new aux2_switch_controls = 53862306a36Sopenharmony_ci SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 5, 1, 0); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci/* Left Ex. PA Switch */ 54162306a36Sopenharmony_cistatic const struct snd_kcontrol_new lepa_switch_controls = 54262306a36Sopenharmony_ci SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 2, 1, 0); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci/* Right Ex. PA Switch */ 54562306a36Sopenharmony_cistatic const struct snd_kcontrol_new repa_switch_controls = 54662306a36Sopenharmony_ci SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 1, 1, 0); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci/* I2S Mux / Mux9 */ 54962306a36Sopenharmony_cistatic const char *i2s_din_text[] = { 55062306a36Sopenharmony_ci "DIN", "DIN1", 55162306a36Sopenharmony_ci}; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(i2s_din_enum, 55462306a36Sopenharmony_ci PM860X_I2S_IFACE_3, 1, i2s_din_text); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic const struct snd_kcontrol_new i2s_din_mux = 55762306a36Sopenharmony_ci SOC_DAPM_ENUM("I2S DIN Mux", i2s_din_enum); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci/* I2S Mic Mux / Mux8 */ 56062306a36Sopenharmony_cistatic const char *i2s_mic_text[] = { 56162306a36Sopenharmony_ci "Ex PA", "ADC", 56262306a36Sopenharmony_ci}; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(i2s_mic_enum, 56562306a36Sopenharmony_ci PM860X_I2S_IFACE_3, 4, i2s_mic_text); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cistatic const struct snd_kcontrol_new i2s_mic_mux = 56862306a36Sopenharmony_ci SOC_DAPM_ENUM("I2S Mic Mux", i2s_mic_enum); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci/* ADCL Mux / Mux2 */ 57162306a36Sopenharmony_cistatic const char *adcl_text[] = { 57262306a36Sopenharmony_ci "ADCR", "ADCL", 57362306a36Sopenharmony_ci}; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(adcl_enum, 57662306a36Sopenharmony_ci PM860X_PCM_IFACE_3, 4, adcl_text); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic const struct snd_kcontrol_new adcl_mux = 57962306a36Sopenharmony_ci SOC_DAPM_ENUM("ADC Left Mux", adcl_enum); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci/* ADCR Mux / Mux3 */ 58262306a36Sopenharmony_cistatic const char *adcr_text[] = { 58362306a36Sopenharmony_ci "ADCL", "ADCR", 58462306a36Sopenharmony_ci}; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(adcr_enum, 58762306a36Sopenharmony_ci PM860X_PCM_IFACE_3, 2, adcr_text); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_cistatic const struct snd_kcontrol_new adcr_mux = 59062306a36Sopenharmony_ci SOC_DAPM_ENUM("ADC Right Mux", adcr_enum); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci/* ADCR EC Mux / Mux6 */ 59362306a36Sopenharmony_cistatic const char *adcr_ec_text[] = { 59462306a36Sopenharmony_ci "ADCR", "EC", 59562306a36Sopenharmony_ci}; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(adcr_ec_enum, 59862306a36Sopenharmony_ci PM860X_ADC_EN_2, 3, adcr_ec_text); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic const struct snd_kcontrol_new adcr_ec_mux = 60162306a36Sopenharmony_ci SOC_DAPM_ENUM("ADCR EC Mux", adcr_ec_enum); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci/* EC Mux / Mux4 */ 60462306a36Sopenharmony_cistatic const char *ec_text[] = { 60562306a36Sopenharmony_ci "Left", "Right", "Left + Right", 60662306a36Sopenharmony_ci}; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(ec_enum, 60962306a36Sopenharmony_ci PM860X_EC_PATH, 1, ec_text); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_cistatic const struct snd_kcontrol_new ec_mux = 61262306a36Sopenharmony_ci SOC_DAPM_ENUM("EC Mux", ec_enum); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistatic const char *dac_text[] = { 61562306a36Sopenharmony_ci "No input", "Right", "Left", "No input", 61662306a36Sopenharmony_ci}; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci/* DAC Headset 1 Mux / Mux10 */ 61962306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(dac_hs1_enum, 62062306a36Sopenharmony_ci PM860X_ANA_INPUT_SEL_1, 0, dac_text); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic const struct snd_kcontrol_new dac_hs1_mux = 62362306a36Sopenharmony_ci SOC_DAPM_ENUM("DAC HS1 Mux", dac_hs1_enum); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci/* DAC Headset 2 Mux / Mux11 */ 62662306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(dac_hs2_enum, 62762306a36Sopenharmony_ci PM860X_ANA_INPUT_SEL_1, 2, dac_text); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_cistatic const struct snd_kcontrol_new dac_hs2_mux = 63062306a36Sopenharmony_ci SOC_DAPM_ENUM("DAC HS2 Mux", dac_hs2_enum); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci/* DAC Lineout 1 Mux / Mux12 */ 63362306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(dac_lo1_enum, 63462306a36Sopenharmony_ci PM860X_ANA_INPUT_SEL_1, 4, dac_text); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic const struct snd_kcontrol_new dac_lo1_mux = 63762306a36Sopenharmony_ci SOC_DAPM_ENUM("DAC LO1 Mux", dac_lo1_enum); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci/* DAC Lineout 2 Mux / Mux13 */ 64062306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(dac_lo2_enum, 64162306a36Sopenharmony_ci PM860X_ANA_INPUT_SEL_1, 6, dac_text); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic const struct snd_kcontrol_new dac_lo2_mux = 64462306a36Sopenharmony_ci SOC_DAPM_ENUM("DAC LO2 Mux", dac_lo2_enum); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci/* DAC Spearker Earphone Mux / Mux14 */ 64762306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(dac_spk_ear_enum, 64862306a36Sopenharmony_ci PM860X_ANA_INPUT_SEL_2, 0, dac_text); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cistatic const struct snd_kcontrol_new dac_spk_ear_mux = 65162306a36Sopenharmony_ci SOC_DAPM_ENUM("DAC SP Mux", dac_spk_ear_enum); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci/* Headset 1 Mux / Mux15 */ 65462306a36Sopenharmony_cistatic const char *in_text[] = { 65562306a36Sopenharmony_ci "Digital", "Analog", 65662306a36Sopenharmony_ci}; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(hs1_enum, 65962306a36Sopenharmony_ci PM860X_ANA_TO_ANA, 0, in_text); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic const struct snd_kcontrol_new hs1_mux = 66262306a36Sopenharmony_ci SOC_DAPM_ENUM("Headset1 Mux", hs1_enum); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci/* Headset 2 Mux / Mux16 */ 66562306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(hs2_enum, 66662306a36Sopenharmony_ci PM860X_ANA_TO_ANA, 1, in_text); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic const struct snd_kcontrol_new hs2_mux = 66962306a36Sopenharmony_ci SOC_DAPM_ENUM("Headset2 Mux", hs2_enum); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci/* Lineout 1 Mux / Mux17 */ 67262306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(lo1_enum, 67362306a36Sopenharmony_ci PM860X_ANA_TO_ANA, 2, in_text); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_cistatic const struct snd_kcontrol_new lo1_mux = 67662306a36Sopenharmony_ci SOC_DAPM_ENUM("Lineout1 Mux", lo1_enum); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci/* Lineout 2 Mux / Mux18 */ 67962306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(lo2_enum, 68062306a36Sopenharmony_ci PM860X_ANA_TO_ANA, 3, in_text); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic const struct snd_kcontrol_new lo2_mux = 68362306a36Sopenharmony_ci SOC_DAPM_ENUM("Lineout2 Mux", lo2_enum); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci/* Speaker Earpiece Demux */ 68662306a36Sopenharmony_cistatic const char *spk_text[] = { 68762306a36Sopenharmony_ci "Earpiece", "Speaker", 68862306a36Sopenharmony_ci}; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(spk_enum, 69162306a36Sopenharmony_ci PM860X_ANA_TO_ANA, 6, spk_text); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_cistatic const struct snd_kcontrol_new spk_demux = 69462306a36Sopenharmony_ci SOC_DAPM_ENUM("Speaker Earpiece Demux", spk_enum); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci/* MIC Mux / Mux1 */ 69762306a36Sopenharmony_cistatic const char *mic_text[] = { 69862306a36Sopenharmony_ci "Mic 1", "Mic 2", 69962306a36Sopenharmony_ci}; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(mic_enum, 70262306a36Sopenharmony_ci PM860X_ADC_ANA_4, 4, mic_text); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic const struct snd_kcontrol_new mic_mux = 70562306a36Sopenharmony_ci SOC_DAPM_ENUM("MIC Mux", mic_enum); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget pm860x_dapm_widgets[] = { 70862306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("PCM SDI", "PCM Playback", 0, 70962306a36Sopenharmony_ci PM860X_ADC_EN_2, 0, 0), 71062306a36Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("PCM SDO", "PCM Capture", 0, 71162306a36Sopenharmony_ci PM860X_PCM_IFACE_3, 1, 1), 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("I2S DIN", "I2S Playback", 0, 71562306a36Sopenharmony_ci SND_SOC_NOPM, 0, 0), 71662306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("I2S DIN1", "I2S Playback", 0, 71762306a36Sopenharmony_ci SND_SOC_NOPM, 0, 0), 71862306a36Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("I2S DOUT", "I2S Capture", 0, 71962306a36Sopenharmony_ci PM860X_I2S_IFACE_3, 5, 1), 72062306a36Sopenharmony_ci SND_SOC_DAPM_SUPPLY("I2S CLK", PM860X_DAC_EN_2, 0, 0, NULL, 0), 72162306a36Sopenharmony_ci SND_SOC_DAPM_MUX("I2S Mic Mux", SND_SOC_NOPM, 0, 0, &i2s_mic_mux), 72262306a36Sopenharmony_ci SND_SOC_DAPM_MUX("ADC Left Mux", SND_SOC_NOPM, 0, 0, &adcl_mux), 72362306a36Sopenharmony_ci SND_SOC_DAPM_MUX("ADC Right Mux", SND_SOC_NOPM, 0, 0, &adcr_mux), 72462306a36Sopenharmony_ci SND_SOC_DAPM_MUX("EC Mux", SND_SOC_NOPM, 0, 0, &ec_mux), 72562306a36Sopenharmony_ci SND_SOC_DAPM_MUX("ADCR EC Mux", SND_SOC_NOPM, 0, 0, &adcr_ec_mux), 72662306a36Sopenharmony_ci SND_SOC_DAPM_SWITCH("Left EPA", SND_SOC_NOPM, 0, 0, 72762306a36Sopenharmony_ci &lepa_switch_controls), 72862306a36Sopenharmony_ci SND_SOC_DAPM_SWITCH("Right EPA", SND_SOC_NOPM, 0, 0, 72962306a36Sopenharmony_ci &repa_switch_controls), 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci SND_SOC_DAPM_REG(snd_soc_dapm_supply, "Left ADC MOD", PM860X_ADC_EN_1, 73262306a36Sopenharmony_ci 0, 1, 1, 0), 73362306a36Sopenharmony_ci SND_SOC_DAPM_REG(snd_soc_dapm_supply, "Right ADC MOD", PM860X_ADC_EN_1, 73462306a36Sopenharmony_ci 1, 1, 1, 0), 73562306a36Sopenharmony_ci SND_SOC_DAPM_ADC("Left ADC", NULL, PM860X_ADC_EN_2, 5, 0), 73662306a36Sopenharmony_ci SND_SOC_DAPM_ADC("Right ADC", NULL, PM860X_ADC_EN_2, 4, 0), 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci SND_SOC_DAPM_SWITCH("AUX1 Switch", SND_SOC_NOPM, 0, 0, 73962306a36Sopenharmony_ci &aux1_switch_controls), 74062306a36Sopenharmony_ci SND_SOC_DAPM_SWITCH("AUX2 Switch", SND_SOC_NOPM, 0, 0, 74162306a36Sopenharmony_ci &aux2_switch_controls), 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci SND_SOC_DAPM_MUX("MIC Mux", SND_SOC_NOPM, 0, 0, &mic_mux), 74462306a36Sopenharmony_ci SND_SOC_DAPM_MICBIAS("Mic1 Bias", PM860X_ADC_ANA_1, 2, 0), 74562306a36Sopenharmony_ci SND_SOC_DAPM_MICBIAS("Mic3 Bias", PM860X_ADC_ANA_1, 7, 0), 74662306a36Sopenharmony_ci SND_SOC_DAPM_PGA("MIC1 Volume", PM860X_ADC_EN_1, 2, 0, NULL, 0), 74762306a36Sopenharmony_ci SND_SOC_DAPM_PGA("MIC3 Volume", PM860X_ADC_EN_1, 3, 0, NULL, 0), 74862306a36Sopenharmony_ci SND_SOC_DAPM_PGA("AUX1 Volume", PM860X_ADC_EN_1, 4, 0, NULL, 0), 74962306a36Sopenharmony_ci SND_SOC_DAPM_PGA("AUX2 Volume", PM860X_ADC_EN_1, 5, 0, NULL, 0), 75062306a36Sopenharmony_ci SND_SOC_DAPM_PGA("Sidetone PGA", PM860X_ADC_EN_2, 1, 0, NULL, 0), 75162306a36Sopenharmony_ci SND_SOC_DAPM_PGA("Lofi PGA", PM860X_ADC_EN_2, 2, 0, NULL, 0), 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("AUX1"), 75462306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("AUX2"), 75562306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("MIC1P"), 75662306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("MIC1N"), 75762306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("MIC2P"), 75862306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("MIC2N"), 75962306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("MIC3P"), 76062306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("MIC3N"), 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci SND_SOC_DAPM_DAC_E("Left DAC", NULL, SND_SOC_NOPM, 0, 0, 76362306a36Sopenharmony_ci pm860x_dac_event, 76462306a36Sopenharmony_ci SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), 76562306a36Sopenharmony_ci SND_SOC_DAPM_DAC_E("Right DAC", NULL, SND_SOC_NOPM, 0, 0, 76662306a36Sopenharmony_ci pm860x_dac_event, 76762306a36Sopenharmony_ci SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci SND_SOC_DAPM_MUX("I2S DIN Mux", SND_SOC_NOPM, 0, 0, &i2s_din_mux), 77062306a36Sopenharmony_ci SND_SOC_DAPM_MUX("DAC HS1 Mux", SND_SOC_NOPM, 0, 0, &dac_hs1_mux), 77162306a36Sopenharmony_ci SND_SOC_DAPM_MUX("DAC HS2 Mux", SND_SOC_NOPM, 0, 0, &dac_hs2_mux), 77262306a36Sopenharmony_ci SND_SOC_DAPM_MUX("DAC LO1 Mux", SND_SOC_NOPM, 0, 0, &dac_lo1_mux), 77362306a36Sopenharmony_ci SND_SOC_DAPM_MUX("DAC LO2 Mux", SND_SOC_NOPM, 0, 0, &dac_lo2_mux), 77462306a36Sopenharmony_ci SND_SOC_DAPM_MUX("DAC SP Mux", SND_SOC_NOPM, 0, 0, &dac_spk_ear_mux), 77562306a36Sopenharmony_ci SND_SOC_DAPM_MUX("Headset1 Mux", SND_SOC_NOPM, 0, 0, &hs1_mux), 77662306a36Sopenharmony_ci SND_SOC_DAPM_MUX("Headset2 Mux", SND_SOC_NOPM, 0, 0, &hs2_mux), 77762306a36Sopenharmony_ci SND_SOC_DAPM_MUX("Lineout1 Mux", SND_SOC_NOPM, 0, 0, &lo1_mux), 77862306a36Sopenharmony_ci SND_SOC_DAPM_MUX("Lineout2 Mux", SND_SOC_NOPM, 0, 0, &lo2_mux), 77962306a36Sopenharmony_ci SND_SOC_DAPM_MUX("Speaker Earpiece Demux", SND_SOC_NOPM, 0, 0, 78062306a36Sopenharmony_ci &spk_demux), 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci SND_SOC_DAPM_PGA("Headset1 PGA", PM860X_DAC_EN_1, 0, 0, NULL, 0), 78462306a36Sopenharmony_ci SND_SOC_DAPM_PGA("Headset2 PGA", PM860X_DAC_EN_1, 1, 0, NULL, 0), 78562306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("HS1"), 78662306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("HS2"), 78762306a36Sopenharmony_ci SND_SOC_DAPM_PGA("Lineout1 PGA", PM860X_DAC_EN_1, 2, 0, NULL, 0), 78862306a36Sopenharmony_ci SND_SOC_DAPM_PGA("Lineout2 PGA", PM860X_DAC_EN_1, 3, 0, NULL, 0), 78962306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("LINEOUT1"), 79062306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("LINEOUT2"), 79162306a36Sopenharmony_ci SND_SOC_DAPM_PGA("Earpiece PGA", PM860X_DAC_EN_1, 4, 0, NULL, 0), 79262306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("EARP"), 79362306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("EARN"), 79462306a36Sopenharmony_ci SND_SOC_DAPM_PGA("Speaker PGA", PM860X_DAC_EN_1, 5, 0, NULL, 0), 79562306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("LSP"), 79662306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("LSN"), 79762306a36Sopenharmony_ci SND_SOC_DAPM_REG(snd_soc_dapm_supply, "VCODEC", PM860X_AUDIO_SUPPLIES_2, 79862306a36Sopenharmony_ci 0, SUPPLY_MASK, SUPPLY_MASK, 0), 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci PM860X_DAPM_OUTPUT("RSYNC", pm860x_rsync_event), 80162306a36Sopenharmony_ci}; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_cistatic const struct snd_soc_dapm_route pm860x_dapm_routes[] = { 80462306a36Sopenharmony_ci /* supply */ 80562306a36Sopenharmony_ci {"Left DAC", NULL, "VCODEC"}, 80662306a36Sopenharmony_ci {"Right DAC", NULL, "VCODEC"}, 80762306a36Sopenharmony_ci {"Left ADC", NULL, "VCODEC"}, 80862306a36Sopenharmony_ci {"Right ADC", NULL, "VCODEC"}, 80962306a36Sopenharmony_ci {"Left ADC", NULL, "Left ADC MOD"}, 81062306a36Sopenharmony_ci {"Right ADC", NULL, "Right ADC MOD"}, 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci /* I2S Clock */ 81362306a36Sopenharmony_ci {"I2S DIN", NULL, "I2S CLK"}, 81462306a36Sopenharmony_ci {"I2S DIN1", NULL, "I2S CLK"}, 81562306a36Sopenharmony_ci {"I2S DOUT", NULL, "I2S CLK"}, 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci /* PCM/AIF1 Inputs */ 81862306a36Sopenharmony_ci {"PCM SDO", NULL, "ADC Left Mux"}, 81962306a36Sopenharmony_ci {"PCM SDO", NULL, "ADCR EC Mux"}, 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci /* PCM/AFI2 Outputs */ 82262306a36Sopenharmony_ci {"Lofi PGA", NULL, "PCM SDI"}, 82362306a36Sopenharmony_ci {"Lofi PGA", NULL, "Sidetone PGA"}, 82462306a36Sopenharmony_ci {"Left DAC", NULL, "Lofi PGA"}, 82562306a36Sopenharmony_ci {"Right DAC", NULL, "Lofi PGA"}, 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci /* I2S/AIF2 Inputs */ 82862306a36Sopenharmony_ci {"MIC Mux", "Mic 1", "MIC1P"}, 82962306a36Sopenharmony_ci {"MIC Mux", "Mic 1", "MIC1N"}, 83062306a36Sopenharmony_ci {"MIC Mux", "Mic 2", "MIC2P"}, 83162306a36Sopenharmony_ci {"MIC Mux", "Mic 2", "MIC2N"}, 83262306a36Sopenharmony_ci {"MIC1 Volume", NULL, "MIC Mux"}, 83362306a36Sopenharmony_ci {"MIC3 Volume", NULL, "MIC3P"}, 83462306a36Sopenharmony_ci {"MIC3 Volume", NULL, "MIC3N"}, 83562306a36Sopenharmony_ci {"Left ADC", NULL, "MIC1 Volume"}, 83662306a36Sopenharmony_ci {"Right ADC", NULL, "MIC3 Volume"}, 83762306a36Sopenharmony_ci {"ADC Left Mux", "ADCR", "Right ADC"}, 83862306a36Sopenharmony_ci {"ADC Left Mux", "ADCL", "Left ADC"}, 83962306a36Sopenharmony_ci {"ADC Right Mux", "ADCL", "Left ADC"}, 84062306a36Sopenharmony_ci {"ADC Right Mux", "ADCR", "Right ADC"}, 84162306a36Sopenharmony_ci {"Left EPA", "Switch", "Left DAC"}, 84262306a36Sopenharmony_ci {"Right EPA", "Switch", "Right DAC"}, 84362306a36Sopenharmony_ci {"EC Mux", "Left", "Left DAC"}, 84462306a36Sopenharmony_ci {"EC Mux", "Right", "Right DAC"}, 84562306a36Sopenharmony_ci {"EC Mux", "Left + Right", "Left DAC"}, 84662306a36Sopenharmony_ci {"EC Mux", "Left + Right", "Right DAC"}, 84762306a36Sopenharmony_ci {"ADCR EC Mux", "ADCR", "ADC Right Mux"}, 84862306a36Sopenharmony_ci {"ADCR EC Mux", "EC", "EC Mux"}, 84962306a36Sopenharmony_ci {"I2S Mic Mux", "Ex PA", "Left EPA"}, 85062306a36Sopenharmony_ci {"I2S Mic Mux", "Ex PA", "Right EPA"}, 85162306a36Sopenharmony_ci {"I2S Mic Mux", "ADC", "ADC Left Mux"}, 85262306a36Sopenharmony_ci {"I2S Mic Mux", "ADC", "ADCR EC Mux"}, 85362306a36Sopenharmony_ci {"I2S DOUT", NULL, "I2S Mic Mux"}, 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci /* I2S/AIF2 Outputs */ 85662306a36Sopenharmony_ci {"I2S DIN Mux", "DIN", "I2S DIN"}, 85762306a36Sopenharmony_ci {"I2S DIN Mux", "DIN1", "I2S DIN1"}, 85862306a36Sopenharmony_ci {"Left DAC", NULL, "I2S DIN Mux"}, 85962306a36Sopenharmony_ci {"Right DAC", NULL, "I2S DIN Mux"}, 86062306a36Sopenharmony_ci {"DAC HS1 Mux", "Left", "Left DAC"}, 86162306a36Sopenharmony_ci {"DAC HS1 Mux", "Right", "Right DAC"}, 86262306a36Sopenharmony_ci {"DAC HS2 Mux", "Left", "Left DAC"}, 86362306a36Sopenharmony_ci {"DAC HS2 Mux", "Right", "Right DAC"}, 86462306a36Sopenharmony_ci {"DAC LO1 Mux", "Left", "Left DAC"}, 86562306a36Sopenharmony_ci {"DAC LO1 Mux", "Right", "Right DAC"}, 86662306a36Sopenharmony_ci {"DAC LO2 Mux", "Left", "Left DAC"}, 86762306a36Sopenharmony_ci {"DAC LO2 Mux", "Right", "Right DAC"}, 86862306a36Sopenharmony_ci {"Headset1 Mux", "Digital", "DAC HS1 Mux"}, 86962306a36Sopenharmony_ci {"Headset2 Mux", "Digital", "DAC HS2 Mux"}, 87062306a36Sopenharmony_ci {"Lineout1 Mux", "Digital", "DAC LO1 Mux"}, 87162306a36Sopenharmony_ci {"Lineout2 Mux", "Digital", "DAC LO2 Mux"}, 87262306a36Sopenharmony_ci {"Headset1 PGA", NULL, "Headset1 Mux"}, 87362306a36Sopenharmony_ci {"Headset2 PGA", NULL, "Headset2 Mux"}, 87462306a36Sopenharmony_ci {"Lineout1 PGA", NULL, "Lineout1 Mux"}, 87562306a36Sopenharmony_ci {"Lineout2 PGA", NULL, "Lineout2 Mux"}, 87662306a36Sopenharmony_ci {"DAC SP Mux", "Left", "Left DAC"}, 87762306a36Sopenharmony_ci {"DAC SP Mux", "Right", "Right DAC"}, 87862306a36Sopenharmony_ci {"Speaker Earpiece Demux", "Speaker", "DAC SP Mux"}, 87962306a36Sopenharmony_ci {"Speaker PGA", NULL, "Speaker Earpiece Demux"}, 88062306a36Sopenharmony_ci {"Earpiece PGA", NULL, "Speaker Earpiece Demux"}, 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci {"RSYNC", NULL, "Headset1 PGA"}, 88362306a36Sopenharmony_ci {"RSYNC", NULL, "Headset2 PGA"}, 88462306a36Sopenharmony_ci {"RSYNC", NULL, "Lineout1 PGA"}, 88562306a36Sopenharmony_ci {"RSYNC", NULL, "Lineout2 PGA"}, 88662306a36Sopenharmony_ci {"RSYNC", NULL, "Speaker PGA"}, 88762306a36Sopenharmony_ci {"RSYNC", NULL, "Speaker PGA"}, 88862306a36Sopenharmony_ci {"RSYNC", NULL, "Earpiece PGA"}, 88962306a36Sopenharmony_ci {"RSYNC", NULL, "Earpiece PGA"}, 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci {"HS1", NULL, "RSYNC"}, 89262306a36Sopenharmony_ci {"HS2", NULL, "RSYNC"}, 89362306a36Sopenharmony_ci {"LINEOUT1", NULL, "RSYNC"}, 89462306a36Sopenharmony_ci {"LINEOUT2", NULL, "RSYNC"}, 89562306a36Sopenharmony_ci {"LSP", NULL, "RSYNC"}, 89662306a36Sopenharmony_ci {"LSN", NULL, "RSYNC"}, 89762306a36Sopenharmony_ci {"EARP", NULL, "RSYNC"}, 89862306a36Sopenharmony_ci {"EARN", NULL, "RSYNC"}, 89962306a36Sopenharmony_ci}; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci/* 90262306a36Sopenharmony_ci * Use MUTE_LEFT & MUTE_RIGHT to implement digital mute. 90362306a36Sopenharmony_ci * These bits can also be used to mute. 90462306a36Sopenharmony_ci */ 90562306a36Sopenharmony_cistatic int pm860x_mute_stream(struct snd_soc_dai *codec_dai, int mute, int direction) 90662306a36Sopenharmony_ci{ 90762306a36Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 90862306a36Sopenharmony_ci int data = 0, mask = MUTE_LEFT | MUTE_RIGHT; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci if (mute) 91162306a36Sopenharmony_ci data = mask; 91262306a36Sopenharmony_ci snd_soc_component_update_bits(component, PM860X_DAC_OFFSET, mask, data); 91362306a36Sopenharmony_ci snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2, 91462306a36Sopenharmony_ci RSYNC_CHANGE, RSYNC_CHANGE); 91562306a36Sopenharmony_ci return 0; 91662306a36Sopenharmony_ci} 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_cistatic int pm860x_pcm_hw_params(struct snd_pcm_substream *substream, 91962306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 92062306a36Sopenharmony_ci struct snd_soc_dai *dai) 92162306a36Sopenharmony_ci{ 92262306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 92362306a36Sopenharmony_ci unsigned char inf = 0, mask = 0; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci /* bit size */ 92662306a36Sopenharmony_ci switch (params_width(params)) { 92762306a36Sopenharmony_ci case 16: 92862306a36Sopenharmony_ci inf &= ~PCM_INF2_18WL; 92962306a36Sopenharmony_ci break; 93062306a36Sopenharmony_ci case 18: 93162306a36Sopenharmony_ci inf |= PCM_INF2_18WL; 93262306a36Sopenharmony_ci break; 93362306a36Sopenharmony_ci default: 93462306a36Sopenharmony_ci return -EINVAL; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci mask |= PCM_INF2_18WL; 93762306a36Sopenharmony_ci snd_soc_component_update_bits(component, PM860X_PCM_IFACE_2, mask, inf); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci /* sample rate */ 94062306a36Sopenharmony_ci switch (params_rate(params)) { 94162306a36Sopenharmony_ci case 8000: 94262306a36Sopenharmony_ci inf = 0; 94362306a36Sopenharmony_ci break; 94462306a36Sopenharmony_ci case 16000: 94562306a36Sopenharmony_ci inf = 3; 94662306a36Sopenharmony_ci break; 94762306a36Sopenharmony_ci case 32000: 94862306a36Sopenharmony_ci inf = 6; 94962306a36Sopenharmony_ci break; 95062306a36Sopenharmony_ci case 48000: 95162306a36Sopenharmony_ci inf = 8; 95262306a36Sopenharmony_ci break; 95362306a36Sopenharmony_ci default: 95462306a36Sopenharmony_ci return -EINVAL; 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci snd_soc_component_update_bits(component, PM860X_PCM_RATE, 0x0f, inf); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci return 0; 95962306a36Sopenharmony_ci} 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_cistatic int pm860x_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai, 96262306a36Sopenharmony_ci unsigned int fmt) 96362306a36Sopenharmony_ci{ 96462306a36Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 96562306a36Sopenharmony_ci struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component); 96662306a36Sopenharmony_ci unsigned char inf = 0, mask = 0; 96762306a36Sopenharmony_ci int ret = -EINVAL; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci /* set audio interface clocking */ 97262306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 97362306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBP_CFP: 97462306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBP_CFC: 97562306a36Sopenharmony_ci if (pm860x->dir == PM860X_CLK_DIR_OUT) { 97662306a36Sopenharmony_ci inf |= PCM_INF2_MASTER; 97762306a36Sopenharmony_ci ret = 0; 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci break; 98062306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBC_CFC: 98162306a36Sopenharmony_ci if (pm860x->dir == PM860X_CLK_DIR_IN) { 98262306a36Sopenharmony_ci inf &= ~PCM_INF2_MASTER; 98362306a36Sopenharmony_ci ret = 0; 98462306a36Sopenharmony_ci } 98562306a36Sopenharmony_ci break; 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 98962306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 99062306a36Sopenharmony_ci inf |= PCM_EXACT_I2S; 99162306a36Sopenharmony_ci ret = 0; 99262306a36Sopenharmony_ci break; 99362306a36Sopenharmony_ci } 99462306a36Sopenharmony_ci mask |= PCM_MODE_MASK; 99562306a36Sopenharmony_ci if (ret) 99662306a36Sopenharmony_ci return ret; 99762306a36Sopenharmony_ci snd_soc_component_update_bits(component, PM860X_PCM_IFACE_2, mask, inf); 99862306a36Sopenharmony_ci return 0; 99962306a36Sopenharmony_ci} 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_cistatic int pm860x_set_dai_sysclk(struct snd_soc_dai *codec_dai, 100262306a36Sopenharmony_ci int clk_id, unsigned int freq, int dir) 100362306a36Sopenharmony_ci{ 100462306a36Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 100562306a36Sopenharmony_ci struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci if (dir == PM860X_CLK_DIR_OUT) 100862306a36Sopenharmony_ci pm860x->dir = PM860X_CLK_DIR_OUT; 100962306a36Sopenharmony_ci else /* Slave mode is not supported */ 101062306a36Sopenharmony_ci return -EINVAL; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci return 0; 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_cistatic int pm860x_i2s_hw_params(struct snd_pcm_substream *substream, 101662306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 101762306a36Sopenharmony_ci struct snd_soc_dai *dai) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 102062306a36Sopenharmony_ci unsigned char inf; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci /* bit size */ 102362306a36Sopenharmony_ci switch (params_width(params)) { 102462306a36Sopenharmony_ci case 16: 102562306a36Sopenharmony_ci inf = 0; 102662306a36Sopenharmony_ci break; 102762306a36Sopenharmony_ci case 18: 102862306a36Sopenharmony_ci inf = PCM_INF2_18WL; 102962306a36Sopenharmony_ci break; 103062306a36Sopenharmony_ci default: 103162306a36Sopenharmony_ci return -EINVAL; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci snd_soc_component_update_bits(component, PM860X_I2S_IFACE_2, PCM_INF2_18WL, inf); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci /* sample rate */ 103662306a36Sopenharmony_ci switch (params_rate(params)) { 103762306a36Sopenharmony_ci case 8000: 103862306a36Sopenharmony_ci inf = 0; 103962306a36Sopenharmony_ci break; 104062306a36Sopenharmony_ci case 11025: 104162306a36Sopenharmony_ci inf = 1; 104262306a36Sopenharmony_ci break; 104362306a36Sopenharmony_ci case 16000: 104462306a36Sopenharmony_ci inf = 3; 104562306a36Sopenharmony_ci break; 104662306a36Sopenharmony_ci case 22050: 104762306a36Sopenharmony_ci inf = 4; 104862306a36Sopenharmony_ci break; 104962306a36Sopenharmony_ci case 32000: 105062306a36Sopenharmony_ci inf = 6; 105162306a36Sopenharmony_ci break; 105262306a36Sopenharmony_ci case 44100: 105362306a36Sopenharmony_ci inf = 7; 105462306a36Sopenharmony_ci break; 105562306a36Sopenharmony_ci case 48000: 105662306a36Sopenharmony_ci inf = 8; 105762306a36Sopenharmony_ci break; 105862306a36Sopenharmony_ci default: 105962306a36Sopenharmony_ci return -EINVAL; 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci snd_soc_component_update_bits(component, PM860X_I2S_IFACE_4, 0xf, inf); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci return 0; 106462306a36Sopenharmony_ci} 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_cistatic int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, 106762306a36Sopenharmony_ci unsigned int fmt) 106862306a36Sopenharmony_ci{ 106962306a36Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 107062306a36Sopenharmony_ci struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component); 107162306a36Sopenharmony_ci unsigned char inf = 0, mask = 0; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci /* set audio interface clocking */ 107662306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 107762306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBP_CFP: 107862306a36Sopenharmony_ci if (pm860x->dir == PM860X_CLK_DIR_OUT) 107962306a36Sopenharmony_ci inf |= PCM_INF2_MASTER; 108062306a36Sopenharmony_ci else 108162306a36Sopenharmony_ci return -EINVAL; 108262306a36Sopenharmony_ci break; 108362306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBC_CFC: 108462306a36Sopenharmony_ci if (pm860x->dir == PM860X_CLK_DIR_IN) 108562306a36Sopenharmony_ci inf &= ~PCM_INF2_MASTER; 108662306a36Sopenharmony_ci else 108762306a36Sopenharmony_ci return -EINVAL; 108862306a36Sopenharmony_ci break; 108962306a36Sopenharmony_ci default: 109062306a36Sopenharmony_ci return -EINVAL; 109162306a36Sopenharmony_ci } 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 109462306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 109562306a36Sopenharmony_ci inf |= PCM_EXACT_I2S; 109662306a36Sopenharmony_ci break; 109762306a36Sopenharmony_ci default: 109862306a36Sopenharmony_ci return -EINVAL; 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci mask |= PCM_MODE_MASK; 110162306a36Sopenharmony_ci snd_soc_component_update_bits(component, PM860X_I2S_IFACE_2, mask, inf); 110262306a36Sopenharmony_ci return 0; 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cistatic int pm860x_set_bias_level(struct snd_soc_component *component, 110662306a36Sopenharmony_ci enum snd_soc_bias_level level) 110762306a36Sopenharmony_ci{ 110862306a36Sopenharmony_ci struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component); 110962306a36Sopenharmony_ci int data; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci switch (level) { 111262306a36Sopenharmony_ci case SND_SOC_BIAS_ON: 111362306a36Sopenharmony_ci break; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci case SND_SOC_BIAS_PREPARE: 111662306a36Sopenharmony_ci break; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci case SND_SOC_BIAS_STANDBY: 111962306a36Sopenharmony_ci if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) { 112062306a36Sopenharmony_ci /* Enable Audio PLL & Audio section */ 112162306a36Sopenharmony_ci data = AUDIO_PLL | AUDIO_SECTION_ON; 112262306a36Sopenharmony_ci pm860x_reg_write(pm860x->i2c, REG_MISC2, data); 112362306a36Sopenharmony_ci udelay(300); 112462306a36Sopenharmony_ci data = AUDIO_PLL | AUDIO_SECTION_RESET 112562306a36Sopenharmony_ci | AUDIO_SECTION_ON; 112662306a36Sopenharmony_ci pm860x_reg_write(pm860x->i2c, REG_MISC2, data); 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci break; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci case SND_SOC_BIAS_OFF: 113162306a36Sopenharmony_ci data = AUDIO_PLL | AUDIO_SECTION_RESET | AUDIO_SECTION_ON; 113262306a36Sopenharmony_ci pm860x_set_bits(pm860x->i2c, REG_MISC2, data, 0); 113362306a36Sopenharmony_ci break; 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci return 0; 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cistatic const struct snd_soc_dai_ops pm860x_pcm_dai_ops = { 113962306a36Sopenharmony_ci .mute_stream = pm860x_mute_stream, 114062306a36Sopenharmony_ci .hw_params = pm860x_pcm_hw_params, 114162306a36Sopenharmony_ci .set_fmt = pm860x_pcm_set_dai_fmt, 114262306a36Sopenharmony_ci .set_sysclk = pm860x_set_dai_sysclk, 114362306a36Sopenharmony_ci .no_capture_mute = 1, 114462306a36Sopenharmony_ci}; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_cistatic const struct snd_soc_dai_ops pm860x_i2s_dai_ops = { 114762306a36Sopenharmony_ci .mute_stream = pm860x_mute_stream, 114862306a36Sopenharmony_ci .hw_params = pm860x_i2s_hw_params, 114962306a36Sopenharmony_ci .set_fmt = pm860x_i2s_set_dai_fmt, 115062306a36Sopenharmony_ci .set_sysclk = pm860x_set_dai_sysclk, 115162306a36Sopenharmony_ci .no_capture_mute = 1, 115262306a36Sopenharmony_ci}; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci#define PM860X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \ 115562306a36Sopenharmony_ci SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000) 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_cistatic struct snd_soc_dai_driver pm860x_dai[] = { 115862306a36Sopenharmony_ci { 115962306a36Sopenharmony_ci /* DAI PCM */ 116062306a36Sopenharmony_ci .name = "88pm860x-pcm", 116162306a36Sopenharmony_ci .id = 1, 116262306a36Sopenharmony_ci .playback = { 116362306a36Sopenharmony_ci .stream_name = "PCM Playback", 116462306a36Sopenharmony_ci .channels_min = 2, 116562306a36Sopenharmony_ci .channels_max = 2, 116662306a36Sopenharmony_ci .rates = PM860X_RATES, 116762306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | \ 116862306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S18_3LE, 116962306a36Sopenharmony_ci }, 117062306a36Sopenharmony_ci .capture = { 117162306a36Sopenharmony_ci .stream_name = "PCM Capture", 117262306a36Sopenharmony_ci .channels_min = 2, 117362306a36Sopenharmony_ci .channels_max = 2, 117462306a36Sopenharmony_ci .rates = PM860X_RATES, 117562306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | \ 117662306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S18_3LE, 117762306a36Sopenharmony_ci }, 117862306a36Sopenharmony_ci .ops = &pm860x_pcm_dai_ops, 117962306a36Sopenharmony_ci }, { 118062306a36Sopenharmony_ci /* DAI I2S */ 118162306a36Sopenharmony_ci .name = "88pm860x-i2s", 118262306a36Sopenharmony_ci .id = 2, 118362306a36Sopenharmony_ci .playback = { 118462306a36Sopenharmony_ci .stream_name = "I2S Playback", 118562306a36Sopenharmony_ci .channels_min = 2, 118662306a36Sopenharmony_ci .channels_max = 2, 118762306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_48000, 118862306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | \ 118962306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S18_3LE, 119062306a36Sopenharmony_ci }, 119162306a36Sopenharmony_ci .capture = { 119262306a36Sopenharmony_ci .stream_name = "I2S Capture", 119362306a36Sopenharmony_ci .channels_min = 2, 119462306a36Sopenharmony_ci .channels_max = 2, 119562306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_48000, 119662306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | \ 119762306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S18_3LE, 119862306a36Sopenharmony_ci }, 119962306a36Sopenharmony_ci .ops = &pm860x_i2s_dai_ops, 120062306a36Sopenharmony_ci }, 120162306a36Sopenharmony_ci}; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_cistatic irqreturn_t pm860x_component_handler(int irq, void *data) 120462306a36Sopenharmony_ci{ 120562306a36Sopenharmony_ci struct pm860x_priv *pm860x = data; 120662306a36Sopenharmony_ci int status, shrt, report = 0, mic_report = 0; 120762306a36Sopenharmony_ci int mask; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci status = pm860x_reg_read(pm860x->i2c, REG_STATUS_1); 121062306a36Sopenharmony_ci shrt = pm860x_reg_read(pm860x->i2c, REG_SHORTS); 121162306a36Sopenharmony_ci mask = pm860x->det.hs_shrt | pm860x->det.hook_det | pm860x->det.lo_shrt 121262306a36Sopenharmony_ci | pm860x->det.hp_det; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci#ifndef CONFIG_SND_SOC_88PM860X_MODULE 121562306a36Sopenharmony_ci if (status & (HEADSET_STATUS | MIC_STATUS | SHORT_HS1 | SHORT_HS2 | 121662306a36Sopenharmony_ci SHORT_LO1 | SHORT_LO2)) 121762306a36Sopenharmony_ci trace_snd_soc_jack_irq(dev_name(pm860x->component->dev)); 121862306a36Sopenharmony_ci#endif 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci if ((pm860x->det.hp_det & SND_JACK_HEADPHONE) 122162306a36Sopenharmony_ci && (status & HEADSET_STATUS)) 122262306a36Sopenharmony_ci report |= SND_JACK_HEADPHONE; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci if ((pm860x->det.mic_det & SND_JACK_MICROPHONE) 122562306a36Sopenharmony_ci && (status & MIC_STATUS)) 122662306a36Sopenharmony_ci mic_report |= SND_JACK_MICROPHONE; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci if (pm860x->det.hs_shrt && (shrt & (SHORT_HS1 | SHORT_HS2))) 122962306a36Sopenharmony_ci report |= pm860x->det.hs_shrt; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci if (pm860x->det.hook_det && (status & HOOK_STATUS)) 123262306a36Sopenharmony_ci report |= pm860x->det.hook_det; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci if (pm860x->det.lo_shrt && (shrt & (SHORT_LO1 | SHORT_LO2))) 123562306a36Sopenharmony_ci report |= pm860x->det.lo_shrt; 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci if (report) 123862306a36Sopenharmony_ci snd_soc_jack_report(pm860x->det.hp_jack, report, mask); 123962306a36Sopenharmony_ci if (mic_report) 124062306a36Sopenharmony_ci snd_soc_jack_report(pm860x->det.mic_jack, SND_JACK_MICROPHONE, 124162306a36Sopenharmony_ci SND_JACK_MICROPHONE); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci dev_dbg(pm860x->component->dev, "headphone report:0x%x, mask:%x\n", 124462306a36Sopenharmony_ci report, mask); 124562306a36Sopenharmony_ci dev_dbg(pm860x->component->dev, "microphone report:0x%x\n", mic_report); 124662306a36Sopenharmony_ci return IRQ_HANDLED; 124762306a36Sopenharmony_ci} 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ciint pm860x_hs_jack_detect(struct snd_soc_component *component, 125062306a36Sopenharmony_ci struct snd_soc_jack *jack, 125162306a36Sopenharmony_ci int det, int hook, int hs_shrt, int lo_shrt) 125262306a36Sopenharmony_ci{ 125362306a36Sopenharmony_ci struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component); 125462306a36Sopenharmony_ci int data; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci pm860x->det.hp_jack = jack; 125762306a36Sopenharmony_ci pm860x->det.hp_det = det; 125862306a36Sopenharmony_ci pm860x->det.hook_det = hook; 125962306a36Sopenharmony_ci pm860x->det.hs_shrt = hs_shrt; 126062306a36Sopenharmony_ci pm860x->det.lo_shrt = lo_shrt; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci if (det & SND_JACK_HEADPHONE) 126362306a36Sopenharmony_ci pm860x_set_bits(pm860x->i2c, REG_HS_DET, 126462306a36Sopenharmony_ci EN_HS_DET, EN_HS_DET); 126562306a36Sopenharmony_ci /* headset short detect */ 126662306a36Sopenharmony_ci if (hs_shrt) { 126762306a36Sopenharmony_ci data = CLR_SHORT_HS2 | CLR_SHORT_HS1; 126862306a36Sopenharmony_ci pm860x_set_bits(pm860x->i2c, REG_SHORTS, data, data); 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci /* Lineout short detect */ 127162306a36Sopenharmony_ci if (lo_shrt) { 127262306a36Sopenharmony_ci data = CLR_SHORT_LO2 | CLR_SHORT_LO1; 127362306a36Sopenharmony_ci pm860x_set_bits(pm860x->i2c, REG_SHORTS, data, data); 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci /* sync status */ 127762306a36Sopenharmony_ci pm860x_component_handler(0, pm860x); 127862306a36Sopenharmony_ci return 0; 127962306a36Sopenharmony_ci} 128062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pm860x_hs_jack_detect); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ciint pm860x_mic_jack_detect(struct snd_soc_component *component, 128362306a36Sopenharmony_ci struct snd_soc_jack *jack, int det) 128462306a36Sopenharmony_ci{ 128562306a36Sopenharmony_ci struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci pm860x->det.mic_jack = jack; 128862306a36Sopenharmony_ci pm860x->det.mic_det = det; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci if (det & SND_JACK_MICROPHONE) 129162306a36Sopenharmony_ci pm860x_set_bits(pm860x->i2c, REG_MIC_DET, 129262306a36Sopenharmony_ci MICDET_MASK, MICDET_MASK); 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci /* sync status */ 129562306a36Sopenharmony_ci pm860x_component_handler(0, pm860x); 129662306a36Sopenharmony_ci return 0; 129762306a36Sopenharmony_ci} 129862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pm860x_mic_jack_detect); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_cistatic int pm860x_probe(struct snd_soc_component *component) 130162306a36Sopenharmony_ci{ 130262306a36Sopenharmony_ci struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component); 130362306a36Sopenharmony_ci int i, ret; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci pm860x->component = component; 130662306a36Sopenharmony_ci snd_soc_component_init_regmap(component, pm860x->regmap); 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 130962306a36Sopenharmony_ci ret = request_threaded_irq(pm860x->irq[i], NULL, 131062306a36Sopenharmony_ci pm860x_component_handler, IRQF_ONESHOT, 131162306a36Sopenharmony_ci pm860x->name[i], pm860x); 131262306a36Sopenharmony_ci if (ret < 0) { 131362306a36Sopenharmony_ci dev_err(component->dev, "Failed to request IRQ!\n"); 131462306a36Sopenharmony_ci goto out; 131562306a36Sopenharmony_ci } 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci return 0; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ciout: 132162306a36Sopenharmony_ci while (--i >= 0) 132262306a36Sopenharmony_ci free_irq(pm860x->irq[i], pm860x); 132362306a36Sopenharmony_ci return ret; 132462306a36Sopenharmony_ci} 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_cistatic void pm860x_remove(struct snd_soc_component *component) 132762306a36Sopenharmony_ci{ 132862306a36Sopenharmony_ci struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component); 132962306a36Sopenharmony_ci int i; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci for (i = 3; i >= 0; i--) 133262306a36Sopenharmony_ci free_irq(pm860x->irq[i], pm860x); 133362306a36Sopenharmony_ci} 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_pm860x = { 133662306a36Sopenharmony_ci .probe = pm860x_probe, 133762306a36Sopenharmony_ci .remove = pm860x_remove, 133862306a36Sopenharmony_ci .set_bias_level = pm860x_set_bias_level, 133962306a36Sopenharmony_ci .controls = pm860x_snd_controls, 134062306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(pm860x_snd_controls), 134162306a36Sopenharmony_ci .dapm_widgets = pm860x_dapm_widgets, 134262306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(pm860x_dapm_widgets), 134362306a36Sopenharmony_ci .dapm_routes = pm860x_dapm_routes, 134462306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(pm860x_dapm_routes), 134562306a36Sopenharmony_ci .idle_bias_on = 1, 134662306a36Sopenharmony_ci .use_pmdown_time = 1, 134762306a36Sopenharmony_ci .endianness = 1, 134862306a36Sopenharmony_ci}; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_cistatic int pm860x_codec_probe(struct platform_device *pdev) 135162306a36Sopenharmony_ci{ 135262306a36Sopenharmony_ci struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); 135362306a36Sopenharmony_ci struct pm860x_priv *pm860x; 135462306a36Sopenharmony_ci struct resource *res; 135562306a36Sopenharmony_ci int i, ret; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci pm860x = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_priv), 135862306a36Sopenharmony_ci GFP_KERNEL); 135962306a36Sopenharmony_ci if (pm860x == NULL) 136062306a36Sopenharmony_ci return -ENOMEM; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci pm860x->chip = chip; 136362306a36Sopenharmony_ci pm860x->i2c = (chip->id == CHIP_PM8607) ? chip->client 136462306a36Sopenharmony_ci : chip->companion; 136562306a36Sopenharmony_ci pm860x->regmap = (chip->id == CHIP_PM8607) ? chip->regmap 136662306a36Sopenharmony_ci : chip->regmap_companion; 136762306a36Sopenharmony_ci platform_set_drvdata(pdev, pm860x); 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 137062306a36Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_IRQ, i); 137162306a36Sopenharmony_ci if (!res) { 137262306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to get IRQ resources\n"); 137362306a36Sopenharmony_ci return -EINVAL; 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci pm860x->irq[i] = res->start + chip->irq_base; 137662306a36Sopenharmony_ci strscpy(pm860x->name[i], res->name, MAX_NAME_LEN); 137762306a36Sopenharmony_ci } 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, 138062306a36Sopenharmony_ci &soc_component_dev_pm860x, 138162306a36Sopenharmony_ci pm860x_dai, ARRAY_SIZE(pm860x_dai)); 138262306a36Sopenharmony_ci if (ret) { 138362306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to register component\n"); 138462306a36Sopenharmony_ci return -EINVAL; 138562306a36Sopenharmony_ci } 138662306a36Sopenharmony_ci return ret; 138762306a36Sopenharmony_ci} 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_cistatic struct platform_driver pm860x_codec_driver = { 139062306a36Sopenharmony_ci .driver = { 139162306a36Sopenharmony_ci .name = "88pm860x-codec", 139262306a36Sopenharmony_ci }, 139362306a36Sopenharmony_ci .probe = pm860x_codec_probe, 139462306a36Sopenharmony_ci}; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_cimodule_platform_driver(pm860x_codec_driver); 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC 88PM860x driver"); 139962306a36Sopenharmony_ciMODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); 140062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 140162306a36Sopenharmony_ciMODULE_ALIAS("platform:88pm860x-codec"); 140262306a36Sopenharmony_ci 1403