1*272b5eddSBrian Austin /* 2*272b5eddSBrian Austin * cs42l56.c -- CS42L56 ALSA SoC audio driver 3*272b5eddSBrian Austin * 4*272b5eddSBrian Austin * Copyright 2014 CirrusLogic, Inc. 5*272b5eddSBrian Austin * 6*272b5eddSBrian Austin * Author: Brian Austin <brian.austin@cirrus.com> 7*272b5eddSBrian Austin * 8*272b5eddSBrian Austin * This program is free software; you can redistribute it and/or modify 9*272b5eddSBrian Austin * it under the terms of the GNU General Public License version 2 as 10*272b5eddSBrian Austin * published by the Free Software Foundation. 11*272b5eddSBrian Austin * 12*272b5eddSBrian Austin */ 13*272b5eddSBrian Austin 14*272b5eddSBrian Austin #include <linux/module.h> 15*272b5eddSBrian Austin #include <linux/moduleparam.h> 16*272b5eddSBrian Austin #include <linux/kernel.h> 17*272b5eddSBrian Austin #include <linux/init.h> 18*272b5eddSBrian Austin #include <linux/delay.h> 19*272b5eddSBrian Austin #include <linux/pm.h> 20*272b5eddSBrian Austin #include <linux/i2c.h> 21*272b5eddSBrian Austin #include <linux/input.h> 22*272b5eddSBrian Austin #include <linux/regmap.h> 23*272b5eddSBrian Austin #include <linux/slab.h> 24*272b5eddSBrian Austin #include <linux/workqueue.h> 25*272b5eddSBrian Austin #include <linux/platform_device.h> 26*272b5eddSBrian Austin #include <linux/regulator/consumer.h> 27*272b5eddSBrian Austin #include <linux/of_device.h> 28*272b5eddSBrian Austin #include <linux/of_gpio.h> 29*272b5eddSBrian Austin #include <sound/core.h> 30*272b5eddSBrian Austin #include <sound/pcm.h> 31*272b5eddSBrian Austin #include <sound/pcm_params.h> 32*272b5eddSBrian Austin #include <sound/soc.h> 33*272b5eddSBrian Austin #include <sound/soc-dapm.h> 34*272b5eddSBrian Austin #include <sound/initval.h> 35*272b5eddSBrian Austin #include <sound/tlv.h> 36*272b5eddSBrian Austin #include <sound/cs42l56.h> 37*272b5eddSBrian Austin #include "cs42l56.h" 38*272b5eddSBrian Austin 39*272b5eddSBrian Austin #define CS42L56_NUM_SUPPLIES 3 40*272b5eddSBrian Austin static const char *const cs42l56_supply_names[CS42L56_NUM_SUPPLIES] = { 41*272b5eddSBrian Austin "VA", 42*272b5eddSBrian Austin "VCP", 43*272b5eddSBrian Austin "VLDO", 44*272b5eddSBrian Austin }; 45*272b5eddSBrian Austin 46*272b5eddSBrian Austin struct cs42l56_private { 47*272b5eddSBrian Austin struct regmap *regmap; 48*272b5eddSBrian Austin struct snd_soc_codec *codec; 49*272b5eddSBrian Austin struct device *dev; 50*272b5eddSBrian Austin struct cs42l56_platform_data pdata; 51*272b5eddSBrian Austin struct regulator_bulk_data supplies[CS42L56_NUM_SUPPLIES]; 52*272b5eddSBrian Austin u32 mclk; 53*272b5eddSBrian Austin u8 mclk_prediv; 54*272b5eddSBrian Austin u8 mclk_div2; 55*272b5eddSBrian Austin u8 mclk_ratio; 56*272b5eddSBrian Austin u8 iface; 57*272b5eddSBrian Austin u8 iface_fmt; 58*272b5eddSBrian Austin u8 iface_inv; 59*272b5eddSBrian Austin #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) 60*272b5eddSBrian Austin struct input_dev *beep; 61*272b5eddSBrian Austin struct work_struct beep_work; 62*272b5eddSBrian Austin int beep_rate; 63*272b5eddSBrian Austin #endif 64*272b5eddSBrian Austin }; 65*272b5eddSBrian Austin 66*272b5eddSBrian Austin static const struct reg_default cs42l56_reg_defaults[] = { 67*272b5eddSBrian Austin { 1, 0x56 }, /* r01 - ID 1 */ 68*272b5eddSBrian Austin { 2, 0x04 }, /* r02 - ID 2 */ 69*272b5eddSBrian Austin { 3, 0x7f }, /* r03 - Power Ctl 1 */ 70*272b5eddSBrian Austin { 4, 0xff }, /* r04 - Power Ctl 2 */ 71*272b5eddSBrian Austin { 5, 0x00 }, /* ro5 - Clocking Ctl 1 */ 72*272b5eddSBrian Austin { 6, 0x0b }, /* r06 - Clocking Ctl 2 */ 73*272b5eddSBrian Austin { 7, 0x00 }, /* r07 - Serial Format */ 74*272b5eddSBrian Austin { 8, 0x05 }, /* r08 - Class H Ctl */ 75*272b5eddSBrian Austin { 9, 0x0c }, /* r09 - Misc Ctl */ 76*272b5eddSBrian Austin { 10, 0x80 }, /* r0a - INT Status */ 77*272b5eddSBrian Austin { 11, 0x00 }, /* r0b - Playback Ctl */ 78*272b5eddSBrian Austin { 12, 0x0c }, /* r0c - DSP Mute Ctl */ 79*272b5eddSBrian Austin { 13, 0x00 }, /* r0d - ADCA Mixer Volume */ 80*272b5eddSBrian Austin { 14, 0x00 }, /* r0e - ADCB Mixer Volume */ 81*272b5eddSBrian Austin { 15, 0x00 }, /* r0f - PCMA Mixer Volume */ 82*272b5eddSBrian Austin { 16, 0x00 }, /* r10 - PCMB Mixer Volume */ 83*272b5eddSBrian Austin { 17, 0x00 }, /* r11 - Analog Input Advisory Volume */ 84*272b5eddSBrian Austin { 18, 0x00 }, /* r12 - Digital Input Advisory Volume */ 85*272b5eddSBrian Austin { 19, 0x00 }, /* r13 - Master A Volume */ 86*272b5eddSBrian Austin { 20, 0x00 }, /* r14 - Master B Volume */ 87*272b5eddSBrian Austin { 21, 0x00 }, /* r15 - Beep Freq / On Time */ 88*272b5eddSBrian Austin { 22, 0x00 }, /* r16 - Beep Volume / Off Time */ 89*272b5eddSBrian Austin { 23, 0x00 }, /* r17 - Beep Tone Ctl */ 90*272b5eddSBrian Austin { 24, 0x88 }, /* r18 - Tone Ctl */ 91*272b5eddSBrian Austin { 25, 0x00 }, /* r19 - Channel Mixer & Swap */ 92*272b5eddSBrian Austin { 26, 0x00 }, /* r1a - AIN Ref Config / ADC Mux */ 93*272b5eddSBrian Austin { 27, 0xa0 }, /* r1b - High-Pass Filter Ctl */ 94*272b5eddSBrian Austin { 28, 0x00 }, /* r1c - Misc ADC Ctl */ 95*272b5eddSBrian Austin { 29, 0x00 }, /* r1d - Gain & Bias Ctl */ 96*272b5eddSBrian Austin { 30, 0x00 }, /* r1e - PGAA Mux & Volume */ 97*272b5eddSBrian Austin { 31, 0x00 }, /* r1f - PGAB Mux & Volume */ 98*272b5eddSBrian Austin { 32, 0x00 }, /* r20 - ADCA Attenuator */ 99*272b5eddSBrian Austin { 33, 0x00 }, /* r21 - ADCB Attenuator */ 100*272b5eddSBrian Austin { 34, 0x00 }, /* r22 - ALC Enable & Attack Rate */ 101*272b5eddSBrian Austin { 35, 0xbf }, /* r23 - ALC Release Rate */ 102*272b5eddSBrian Austin { 36, 0x00 }, /* r24 - ALC Threshold */ 103*272b5eddSBrian Austin { 37, 0x00 }, /* r25 - Noise Gate Ctl */ 104*272b5eddSBrian Austin { 38, 0x00 }, /* r26 - ALC, Limiter, SFT, ZeroCross */ 105*272b5eddSBrian Austin { 39, 0x00 }, /* r27 - Analog Mute, LO & HP Mux */ 106*272b5eddSBrian Austin { 40, 0x00 }, /* r28 - HP A Volume */ 107*272b5eddSBrian Austin { 41, 0x00 }, /* r29 - HP B Volume */ 108*272b5eddSBrian Austin { 42, 0x00 }, /* r2a - LINEOUT A Volume */ 109*272b5eddSBrian Austin { 43, 0x00 }, /* r2b - LINEOUT B Volume */ 110*272b5eddSBrian Austin { 44, 0x00 }, /* r2c - Limit Threshold Ctl */ 111*272b5eddSBrian Austin { 45, 0x7f }, /* r2d - Limiter Ctl & Release Rate */ 112*272b5eddSBrian Austin { 46, 0x00 }, /* r2e - Limiter Attack Rate */ 113*272b5eddSBrian Austin }; 114*272b5eddSBrian Austin 115*272b5eddSBrian Austin static bool cs42l56_readable_register(struct device *dev, unsigned int reg) 116*272b5eddSBrian Austin { 117*272b5eddSBrian Austin switch (reg) { 118*272b5eddSBrian Austin case CS42L56_CHIP_ID_1: 119*272b5eddSBrian Austin case CS42L56_CHIP_ID_2: 120*272b5eddSBrian Austin case CS42L56_PWRCTL_1: 121*272b5eddSBrian Austin case CS42L56_PWRCTL_2: 122*272b5eddSBrian Austin case CS42L56_CLKCTL_1: 123*272b5eddSBrian Austin case CS42L56_CLKCTL_2: 124*272b5eddSBrian Austin case CS42L56_SERIAL_FMT: 125*272b5eddSBrian Austin case CS42L56_CLASSH_CTL: 126*272b5eddSBrian Austin case CS42L56_MISC_CTL: 127*272b5eddSBrian Austin case CS42L56_INT_STATUS: 128*272b5eddSBrian Austin case CS42L56_PLAYBACK_CTL: 129*272b5eddSBrian Austin case CS42L56_DSP_MUTE_CTL: 130*272b5eddSBrian Austin case CS42L56_ADCA_MIX_VOLUME: 131*272b5eddSBrian Austin case CS42L56_ADCB_MIX_VOLUME: 132*272b5eddSBrian Austin case CS42L56_PCMA_MIX_VOLUME: 133*272b5eddSBrian Austin case CS42L56_PCMB_MIX_VOLUME: 134*272b5eddSBrian Austin case CS42L56_ANAINPUT_ADV_VOLUME: 135*272b5eddSBrian Austin case CS42L56_DIGINPUT_ADV_VOLUME: 136*272b5eddSBrian Austin case CS42L56_MASTER_A_VOLUME: 137*272b5eddSBrian Austin case CS42L56_MASTER_B_VOLUME: 138*272b5eddSBrian Austin case CS42L56_BEEP_FREQ_ONTIME: 139*272b5eddSBrian Austin case CS42L56_BEEP_FREQ_OFFTIME: 140*272b5eddSBrian Austin case CS42L56_BEEP_TONE_CFG: 141*272b5eddSBrian Austin case CS42L56_TONE_CTL: 142*272b5eddSBrian Austin case CS42L56_CHAN_MIX_SWAP: 143*272b5eddSBrian Austin case CS42L56_AIN_REFCFG_ADC_MUX: 144*272b5eddSBrian Austin case CS42L56_HPF_CTL: 145*272b5eddSBrian Austin case CS42L56_MISC_ADC_CTL: 146*272b5eddSBrian Austin case CS42L56_GAIN_BIAS_CTL: 147*272b5eddSBrian Austin case CS42L56_PGAA_MUX_VOLUME: 148*272b5eddSBrian Austin case CS42L56_PGAB_MUX_VOLUME: 149*272b5eddSBrian Austin case CS42L56_ADCA_ATTENUATOR: 150*272b5eddSBrian Austin case CS42L56_ADCB_ATTENUATOR: 151*272b5eddSBrian Austin case CS42L56_ALC_EN_ATTACK_RATE: 152*272b5eddSBrian Austin case CS42L56_ALC_RELEASE_RATE: 153*272b5eddSBrian Austin case CS42L56_ALC_THRESHOLD: 154*272b5eddSBrian Austin case CS42L56_NOISE_GATE_CTL: 155*272b5eddSBrian Austin case CS42L56_ALC_LIM_SFT_ZC: 156*272b5eddSBrian Austin case CS42L56_AMUTE_HPLO_MUX: 157*272b5eddSBrian Austin case CS42L56_HPA_VOLUME: 158*272b5eddSBrian Austin case CS42L56_HPB_VOLUME: 159*272b5eddSBrian Austin case CS42L56_LOA_VOLUME: 160*272b5eddSBrian Austin case CS42L56_LOB_VOLUME: 161*272b5eddSBrian Austin case CS42L56_LIM_THRESHOLD_CTL: 162*272b5eddSBrian Austin case CS42L56_LIM_CTL_RELEASE_RATE: 163*272b5eddSBrian Austin case CS42L56_LIM_ATTACK_RATE: 164*272b5eddSBrian Austin return true; 165*272b5eddSBrian Austin default: 166*272b5eddSBrian Austin return false; 167*272b5eddSBrian Austin } 168*272b5eddSBrian Austin } 169*272b5eddSBrian Austin 170*272b5eddSBrian Austin static bool cs42l56_volatile_register(struct device *dev, unsigned int reg) 171*272b5eddSBrian Austin { 172*272b5eddSBrian Austin switch (reg) { 173*272b5eddSBrian Austin case CS42L56_INT_STATUS: 174*272b5eddSBrian Austin return 1; 175*272b5eddSBrian Austin default: 176*272b5eddSBrian Austin return 0; 177*272b5eddSBrian Austin } 178*272b5eddSBrian Austin } 179*272b5eddSBrian Austin 180*272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(beep_tlv, -5000, 200, 0); 181*272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(hl_tlv, -6000, 50, 0); 182*272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(adv_tlv, -10200, 50, 0); 183*272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, 0); 184*272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0); 185*272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(preamp_tlv, 0, 1000, 0); 186*272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0); 187*272b5eddSBrian Austin 188*272b5eddSBrian Austin static const unsigned int ngnb_tlv[] = { 189*272b5eddSBrian Austin TLV_DB_RANGE_HEAD(2), 190*272b5eddSBrian Austin 0, 1, TLV_DB_SCALE_ITEM(-8200, 600, 0), 191*272b5eddSBrian Austin 2, 5, TLV_DB_SCALE_ITEM(-7600, 300, 0), 192*272b5eddSBrian Austin }; 193*272b5eddSBrian Austin static const unsigned int ngb_tlv[] = { 194*272b5eddSBrian Austin TLV_DB_RANGE_HEAD(2), 195*272b5eddSBrian Austin 0, 2, TLV_DB_SCALE_ITEM(-6400, 600, 0), 196*272b5eddSBrian Austin 3, 7, TLV_DB_SCALE_ITEM(-4600, 300, 0), 197*272b5eddSBrian Austin }; 198*272b5eddSBrian Austin static const unsigned int alc_tlv[] = { 199*272b5eddSBrian Austin TLV_DB_RANGE_HEAD(2), 200*272b5eddSBrian Austin 0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0), 201*272b5eddSBrian Austin 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0), 202*272b5eddSBrian Austin }; 203*272b5eddSBrian Austin 204*272b5eddSBrian Austin static const char * const beep_config_text[] = { 205*272b5eddSBrian Austin "Off", "Single", "Multiple", "Continuous" 206*272b5eddSBrian Austin }; 207*272b5eddSBrian Austin 208*272b5eddSBrian Austin static const struct soc_enum beep_config_enum = 209*272b5eddSBrian Austin SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 6, 210*272b5eddSBrian Austin ARRAY_SIZE(beep_config_text), beep_config_text); 211*272b5eddSBrian Austin 212*272b5eddSBrian Austin static const char * const beep_pitch_text[] = { 213*272b5eddSBrian Austin "C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5", 214*272b5eddSBrian Austin "C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7" 215*272b5eddSBrian Austin }; 216*272b5eddSBrian Austin 217*272b5eddSBrian Austin static const struct soc_enum beep_pitch_enum = 218*272b5eddSBrian Austin SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 4, 219*272b5eddSBrian Austin ARRAY_SIZE(beep_pitch_text), beep_pitch_text); 220*272b5eddSBrian Austin 221*272b5eddSBrian Austin static const char * const beep_ontime_text[] = { 222*272b5eddSBrian Austin "86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s", 223*272b5eddSBrian Austin "1.80 s", "2.20 s", "2.50 s", "2.80 s", "3.20 s", 224*272b5eddSBrian Austin "3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s" 225*272b5eddSBrian Austin }; 226*272b5eddSBrian Austin 227*272b5eddSBrian Austin static const struct soc_enum beep_ontime_enum = 228*272b5eddSBrian Austin SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 0, 229*272b5eddSBrian Austin ARRAY_SIZE(beep_ontime_text), beep_ontime_text); 230*272b5eddSBrian Austin 231*272b5eddSBrian Austin static const char * const beep_offtime_text[] = { 232*272b5eddSBrian Austin "1.23 s", "2.58 s", "3.90 s", "5.20 s", 233*272b5eddSBrian Austin "6.60 s", "8.05 s", "9.35 s", "10.80 s" 234*272b5eddSBrian Austin }; 235*272b5eddSBrian Austin 236*272b5eddSBrian Austin static const struct soc_enum beep_offtime_enum = 237*272b5eddSBrian Austin SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_OFFTIME, 5, 238*272b5eddSBrian Austin ARRAY_SIZE(beep_offtime_text), beep_offtime_text); 239*272b5eddSBrian Austin 240*272b5eddSBrian Austin static const char * const beep_treble_text[] = { 241*272b5eddSBrian Austin "5kHz", "7kHz", "10kHz", "15kHz" 242*272b5eddSBrian Austin }; 243*272b5eddSBrian Austin 244*272b5eddSBrian Austin static const struct soc_enum beep_treble_enum = 245*272b5eddSBrian Austin SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 3, 246*272b5eddSBrian Austin ARRAY_SIZE(beep_treble_text), beep_treble_text); 247*272b5eddSBrian Austin 248*272b5eddSBrian Austin static const char * const beep_bass_text[] = { 249*272b5eddSBrian Austin "50Hz", "100Hz", "200Hz", "250Hz" 250*272b5eddSBrian Austin }; 251*272b5eddSBrian Austin 252*272b5eddSBrian Austin static const struct soc_enum beep_bass_enum = 253*272b5eddSBrian Austin SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 1, 254*272b5eddSBrian Austin ARRAY_SIZE(beep_bass_text), beep_bass_text); 255*272b5eddSBrian Austin 256*272b5eddSBrian Austin static const char * const adc_swap_text[] = { 257*272b5eddSBrian Austin "None", "A+B/2", "A-B/2", "Swap" 258*272b5eddSBrian Austin }; 259*272b5eddSBrian Austin 260*272b5eddSBrian Austin static const struct soc_enum adc_swap_enum = 261*272b5eddSBrian Austin SOC_ENUM_SINGLE(CS42L56_MISC_ADC_CTL, 3, 262*272b5eddSBrian Austin ARRAY_SIZE(adc_swap_text), adc_swap_text); 263*272b5eddSBrian Austin 264*272b5eddSBrian Austin static const char * const pgaa_mux_text[] = { 265*272b5eddSBrian Austin "AIN1A", "AIN2A", "AIN3A"}; 266*272b5eddSBrian Austin 267*272b5eddSBrian Austin static const struct soc_enum pgaa_mux_enum = 268*272b5eddSBrian Austin SOC_ENUM_SINGLE(CS42L56_PGAA_MUX_VOLUME, 0, 269*272b5eddSBrian Austin ARRAY_SIZE(pgaa_mux_text), 270*272b5eddSBrian Austin pgaa_mux_text); 271*272b5eddSBrian Austin 272*272b5eddSBrian Austin static const struct snd_kcontrol_new pgaa_mux = 273*272b5eddSBrian Austin SOC_DAPM_ENUM("Route", pgaa_mux_enum); 274*272b5eddSBrian Austin 275*272b5eddSBrian Austin static const char * const pgab_mux_text[] = { 276*272b5eddSBrian Austin "AIN1B", "AIN2B", "AIN3B"}; 277*272b5eddSBrian Austin 278*272b5eddSBrian Austin static const struct soc_enum pgab_mux_enum = 279*272b5eddSBrian Austin SOC_ENUM_SINGLE(CS42L56_PGAB_MUX_VOLUME, 0, 280*272b5eddSBrian Austin ARRAY_SIZE(pgab_mux_text), 281*272b5eddSBrian Austin pgab_mux_text); 282*272b5eddSBrian Austin 283*272b5eddSBrian Austin static const struct snd_kcontrol_new pgab_mux = 284*272b5eddSBrian Austin SOC_DAPM_ENUM("Route", pgab_mux_enum); 285*272b5eddSBrian Austin 286*272b5eddSBrian Austin static const char * const adca_mux_text[] = { 287*272b5eddSBrian Austin "PGAA", "AIN1A", "AIN2A", "AIN3A"}; 288*272b5eddSBrian Austin 289*272b5eddSBrian Austin static const struct soc_enum adca_mux_enum = 290*272b5eddSBrian Austin SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 0, 291*272b5eddSBrian Austin ARRAY_SIZE(adca_mux_text), 292*272b5eddSBrian Austin adca_mux_text); 293*272b5eddSBrian Austin 294*272b5eddSBrian Austin static const struct snd_kcontrol_new adca_mux = 295*272b5eddSBrian Austin SOC_DAPM_ENUM("Route", adca_mux_enum); 296*272b5eddSBrian Austin 297*272b5eddSBrian Austin static const char * const adcb_mux_text[] = { 298*272b5eddSBrian Austin "PGAB", "AIN1B", "AIN2B", "AIN3B"}; 299*272b5eddSBrian Austin 300*272b5eddSBrian Austin static const struct soc_enum adcb_mux_enum = 301*272b5eddSBrian Austin SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 2, 302*272b5eddSBrian Austin ARRAY_SIZE(adcb_mux_text), 303*272b5eddSBrian Austin adcb_mux_text); 304*272b5eddSBrian Austin 305*272b5eddSBrian Austin static const struct snd_kcontrol_new adcb_mux = 306*272b5eddSBrian Austin SOC_DAPM_ENUM("Route", adcb_mux_enum); 307*272b5eddSBrian Austin 308*272b5eddSBrian Austin static const char * const left_swap_text[] = { 309*272b5eddSBrian Austin "Left", "LR 2", "Right"}; 310*272b5eddSBrian Austin 311*272b5eddSBrian Austin static const char * const right_swap_text[] = { 312*272b5eddSBrian Austin "Right", "LR 2", "Left"}; 313*272b5eddSBrian Austin 314*272b5eddSBrian Austin static const unsigned int swap_values[] = { 0, 1, 3 }; 315*272b5eddSBrian Austin 316*272b5eddSBrian Austin static const struct soc_enum adca_swap_enum = 317*272b5eddSBrian Austin SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 0, 3, 318*272b5eddSBrian Austin ARRAY_SIZE(left_swap_text), 319*272b5eddSBrian Austin left_swap_text, 320*272b5eddSBrian Austin swap_values); 321*272b5eddSBrian Austin 322*272b5eddSBrian Austin static const struct soc_enum pcma_swap_enum = 323*272b5eddSBrian Austin SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 4, 3, 324*272b5eddSBrian Austin ARRAY_SIZE(left_swap_text), 325*272b5eddSBrian Austin left_swap_text, 326*272b5eddSBrian Austin swap_values); 327*272b5eddSBrian Austin 328*272b5eddSBrian Austin static const struct soc_enum adcb_swap_enum = 329*272b5eddSBrian Austin SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 2, 3, 330*272b5eddSBrian Austin ARRAY_SIZE(right_swap_text), 331*272b5eddSBrian Austin right_swap_text, 332*272b5eddSBrian Austin swap_values); 333*272b5eddSBrian Austin 334*272b5eddSBrian Austin static const struct soc_enum pcmb_swap_enum = 335*272b5eddSBrian Austin SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 6, 3, 336*272b5eddSBrian Austin ARRAY_SIZE(right_swap_text), 337*272b5eddSBrian Austin right_swap_text, 338*272b5eddSBrian Austin swap_values); 339*272b5eddSBrian Austin 340*272b5eddSBrian Austin static const struct snd_kcontrol_new hpa_switch = 341*272b5eddSBrian Austin SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 6, 1, 1); 342*272b5eddSBrian Austin 343*272b5eddSBrian Austin static const struct snd_kcontrol_new hpb_switch = 344*272b5eddSBrian Austin SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 4, 1, 1); 345*272b5eddSBrian Austin 346*272b5eddSBrian Austin static const struct snd_kcontrol_new loa_switch = 347*272b5eddSBrian Austin SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 2, 1, 1); 348*272b5eddSBrian Austin 349*272b5eddSBrian Austin static const struct snd_kcontrol_new lob_switch = 350*272b5eddSBrian Austin SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 0, 1, 1); 351*272b5eddSBrian Austin 352*272b5eddSBrian Austin static const char * const hploa_input_text[] = { 353*272b5eddSBrian Austin "DACA", "PGAA"}; 354*272b5eddSBrian Austin 355*272b5eddSBrian Austin static const struct soc_enum lineouta_input_enum = 356*272b5eddSBrian Austin SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 2, 357*272b5eddSBrian Austin ARRAY_SIZE(hploa_input_text), 358*272b5eddSBrian Austin hploa_input_text); 359*272b5eddSBrian Austin 360*272b5eddSBrian Austin static const struct snd_kcontrol_new lineouta_input = 361*272b5eddSBrian Austin SOC_DAPM_ENUM("Route", lineouta_input_enum); 362*272b5eddSBrian Austin 363*272b5eddSBrian Austin static const struct soc_enum hpa_input_enum = 364*272b5eddSBrian Austin SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 0, 365*272b5eddSBrian Austin ARRAY_SIZE(hploa_input_text), 366*272b5eddSBrian Austin hploa_input_text); 367*272b5eddSBrian Austin 368*272b5eddSBrian Austin static const struct snd_kcontrol_new hpa_input = 369*272b5eddSBrian Austin SOC_DAPM_ENUM("Route", hpa_input_enum); 370*272b5eddSBrian Austin 371*272b5eddSBrian Austin static const char * const hplob_input_text[] = { 372*272b5eddSBrian Austin "DACB", "PGAB"}; 373*272b5eddSBrian Austin 374*272b5eddSBrian Austin static const struct soc_enum lineoutb_input_enum = 375*272b5eddSBrian Austin SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 3, 376*272b5eddSBrian Austin ARRAY_SIZE(hplob_input_text), 377*272b5eddSBrian Austin hplob_input_text); 378*272b5eddSBrian Austin 379*272b5eddSBrian Austin static const struct snd_kcontrol_new lineoutb_input = 380*272b5eddSBrian Austin SOC_DAPM_ENUM("Route", lineoutb_input_enum); 381*272b5eddSBrian Austin 382*272b5eddSBrian Austin static const struct soc_enum hpb_input_enum = 383*272b5eddSBrian Austin SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 1, 384*272b5eddSBrian Austin ARRAY_SIZE(hplob_input_text), 385*272b5eddSBrian Austin hplob_input_text); 386*272b5eddSBrian Austin 387*272b5eddSBrian Austin static const struct snd_kcontrol_new hpb_input = 388*272b5eddSBrian Austin SOC_DAPM_ENUM("Route", hpb_input_enum); 389*272b5eddSBrian Austin 390*272b5eddSBrian Austin static const char * const dig_mux_text[] = { 391*272b5eddSBrian Austin "ADC", "DSP"}; 392*272b5eddSBrian Austin 393*272b5eddSBrian Austin static const struct soc_enum dig_mux_enum = 394*272b5eddSBrian Austin SOC_ENUM_SINGLE(CS42L56_MISC_CTL, 7, 395*272b5eddSBrian Austin ARRAY_SIZE(dig_mux_text), 396*272b5eddSBrian Austin dig_mux_text); 397*272b5eddSBrian Austin 398*272b5eddSBrian Austin static const struct snd_kcontrol_new dig_mux = 399*272b5eddSBrian Austin SOC_DAPM_ENUM("Route", dig_mux_enum); 400*272b5eddSBrian Austin 401*272b5eddSBrian Austin static const char * const hpf_freq_text[] = { 402*272b5eddSBrian Austin "1.8Hz", "119Hz", "236Hz", "464Hz" 403*272b5eddSBrian Austin }; 404*272b5eddSBrian Austin 405*272b5eddSBrian Austin static const struct soc_enum hpfa_freq_enum = 406*272b5eddSBrian Austin SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 0, 407*272b5eddSBrian Austin ARRAY_SIZE(hpf_freq_text), hpf_freq_text); 408*272b5eddSBrian Austin 409*272b5eddSBrian Austin static const struct soc_enum hpfb_freq_enum = 410*272b5eddSBrian Austin SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 2, 411*272b5eddSBrian Austin ARRAY_SIZE(hpf_freq_text), hpf_freq_text); 412*272b5eddSBrian Austin 413*272b5eddSBrian Austin static const char * const ng_delay_text[] = { 414*272b5eddSBrian Austin "50ms", "100ms", "150ms", "200ms" 415*272b5eddSBrian Austin }; 416*272b5eddSBrian Austin 417*272b5eddSBrian Austin static const struct soc_enum ng_delay_enum = 418*272b5eddSBrian Austin SOC_ENUM_SINGLE(CS42L56_NOISE_GATE_CTL, 0, 419*272b5eddSBrian Austin ARRAY_SIZE(ng_delay_text), ng_delay_text); 420*272b5eddSBrian Austin 421*272b5eddSBrian Austin static const struct snd_kcontrol_new cs42l56_snd_controls[] = { 422*272b5eddSBrian Austin 423*272b5eddSBrian Austin SOC_DOUBLE_R_SX_TLV("Master Volume", CS42L56_MASTER_A_VOLUME, 424*272b5eddSBrian Austin CS42L56_MASTER_B_VOLUME, 0, 0x34, 0xfd, adv_tlv), 425*272b5eddSBrian Austin SOC_DOUBLE("Master Mute Switch", CS42L56_DSP_MUTE_CTL, 0, 1, 1, 1), 426*272b5eddSBrian Austin 427*272b5eddSBrian Austin SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", CS42L56_ADCA_MIX_VOLUME, 428*272b5eddSBrian Austin CS42L56_ADCB_MIX_VOLUME, 0, 0x88, 0xa9, hl_tlv), 429*272b5eddSBrian Austin SOC_DOUBLE("ADC Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 6, 7, 1, 1), 430*272b5eddSBrian Austin 431*272b5eddSBrian Austin SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume", CS42L56_PCMA_MIX_VOLUME, 432*272b5eddSBrian Austin CS42L56_PCMB_MIX_VOLUME, 0, 0x88, 0xa9, hl_tlv), 433*272b5eddSBrian Austin SOC_DOUBLE("PCM Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 4, 5, 1, 1), 434*272b5eddSBrian Austin 435*272b5eddSBrian Austin SOC_SINGLE_TLV("Analog Advisory Volume", 436*272b5eddSBrian Austin CS42L56_ANAINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv), 437*272b5eddSBrian Austin SOC_SINGLE_TLV("Digital Advisory Volume", 438*272b5eddSBrian Austin CS42L56_DIGINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv), 439*272b5eddSBrian Austin 440*272b5eddSBrian Austin SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L56_PGAA_MUX_VOLUME, 441*272b5eddSBrian Austin CS42L56_PGAB_MUX_VOLUME, 0, 0x34, 0xfd, pga_tlv), 442*272b5eddSBrian Austin SOC_DOUBLE_R_TLV("ADC Volume", CS42L56_ADCA_ATTENUATOR, 443*272b5eddSBrian Austin CS42L56_ADCB_ATTENUATOR, 0, 0x00, 1, adc_tlv), 444*272b5eddSBrian Austin SOC_DOUBLE("ADC Mute Switch", CS42L56_MISC_ADC_CTL, 2, 3, 1, 1), 445*272b5eddSBrian Austin SOC_DOUBLE("ADC Boost Switch", CS42L56_GAIN_BIAS_CTL, 3, 2, 1, 1), 446*272b5eddSBrian Austin 447*272b5eddSBrian Austin SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L56_HPA_VOLUME, 448*272b5eddSBrian Austin CS42L56_HPA_VOLUME, 0, 0x44, 0x55, hl_tlv), 449*272b5eddSBrian Austin SOC_DOUBLE_R_SX_TLV("LineOut Volume", CS42L56_LOA_VOLUME, 450*272b5eddSBrian Austin CS42L56_LOA_VOLUME, 0, 0x44, 0x55, hl_tlv), 451*272b5eddSBrian Austin 452*272b5eddSBrian Austin SOC_SINGLE_TLV("Bass Shelving Volume", CS42L56_TONE_CTL, 453*272b5eddSBrian Austin 0, 0x00, 1, tone_tlv), 454*272b5eddSBrian Austin SOC_SINGLE_TLV("Treble Shelving Volume", CS42L56_TONE_CTL, 455*272b5eddSBrian Austin 4, 0x00, 1, tone_tlv), 456*272b5eddSBrian Austin 457*272b5eddSBrian Austin SOC_DOUBLE_TLV("PGA Preamp Volume", CS42L56_GAIN_BIAS_CTL, 458*272b5eddSBrian Austin 4, 6, 0x02, 1, preamp_tlv), 459*272b5eddSBrian Austin 460*272b5eddSBrian Austin SOC_SINGLE("DSP Switch", CS42L56_PLAYBACK_CTL, 7, 1, 1), 461*272b5eddSBrian Austin SOC_SINGLE("Gang Playback Switch", CS42L56_PLAYBACK_CTL, 4, 1, 1), 462*272b5eddSBrian Austin SOC_SINGLE("Gang ADC Switch", CS42L56_MISC_ADC_CTL, 7, 1, 1), 463*272b5eddSBrian Austin SOC_SINGLE("Gang PGA Switch", CS42L56_MISC_ADC_CTL, 6, 1, 1), 464*272b5eddSBrian Austin 465*272b5eddSBrian Austin SOC_SINGLE("PCMA Invert", CS42L56_PLAYBACK_CTL, 2, 1, 1), 466*272b5eddSBrian Austin SOC_SINGLE("PCMB Invert", CS42L56_PLAYBACK_CTL, 3, 1, 1), 467*272b5eddSBrian Austin SOC_SINGLE("ADCA Invert", CS42L56_MISC_ADC_CTL, 2, 1, 1), 468*272b5eddSBrian Austin SOC_SINGLE("ADCB Invert", CS42L56_MISC_ADC_CTL, 3, 1, 1), 469*272b5eddSBrian Austin 470*272b5eddSBrian Austin SOC_ENUM("PCMA Swap", pcma_swap_enum), 471*272b5eddSBrian Austin SOC_ENUM("PCMB Swap", pcmb_swap_enum), 472*272b5eddSBrian Austin SOC_ENUM("ADCA Swap", adca_swap_enum), 473*272b5eddSBrian Austin SOC_ENUM("ADCB Swap", adcb_swap_enum), 474*272b5eddSBrian Austin 475*272b5eddSBrian Austin SOC_DOUBLE("HPF Switch", CS42L56_HPF_CTL, 5, 7, 1, 1), 476*272b5eddSBrian Austin SOC_DOUBLE("HPF Freeze Switch", CS42L56_HPF_CTL, 4, 6, 1, 1), 477*272b5eddSBrian Austin SOC_ENUM("HPFA Corner Freq", hpfa_freq_enum), 478*272b5eddSBrian Austin SOC_ENUM("HPFB Corner Freq", hpfb_freq_enum), 479*272b5eddSBrian Austin 480*272b5eddSBrian Austin SOC_SINGLE("Analog Soft Ramp", CS42L56_MISC_CTL, 4, 1, 1), 481*272b5eddSBrian Austin SOC_DOUBLE("Analog Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC, 482*272b5eddSBrian Austin 7, 5, 1, 1), 483*272b5eddSBrian Austin SOC_SINGLE("Analog Zero Cross", CS42L56_MISC_CTL, 3, 1, 1), 484*272b5eddSBrian Austin SOC_DOUBLE("Analog Zero Cross Disable", CS42L56_ALC_LIM_SFT_ZC, 485*272b5eddSBrian Austin 6, 4, 1, 1), 486*272b5eddSBrian Austin SOC_SINGLE("Digital Soft Ramp", CS42L56_MISC_CTL, 2, 1, 1), 487*272b5eddSBrian Austin SOC_SINGLE("Digital Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC, 488*272b5eddSBrian Austin 3, 1, 1), 489*272b5eddSBrian Austin 490*272b5eddSBrian Austin SOC_SINGLE("HL Deemphasis", CS42L56_PLAYBACK_CTL, 6, 1, 1), 491*272b5eddSBrian Austin 492*272b5eddSBrian Austin SOC_SINGLE("ALC Switch", CS42L56_ALC_EN_ATTACK_RATE, 6, 1, 1), 493*272b5eddSBrian Austin SOC_SINGLE("ALC Limit All Switch", CS42L56_ALC_RELEASE_RATE, 7, 1, 1), 494*272b5eddSBrian Austin SOC_SINGLE_RANGE("ALC Attack", CS42L56_ALC_EN_ATTACK_RATE, 495*272b5eddSBrian Austin 0, 0, 0x3f, 0), 496*272b5eddSBrian Austin SOC_SINGLE_RANGE("ALC Release", CS42L56_ALC_RELEASE_RATE, 497*272b5eddSBrian Austin 0, 0x3f, 0, 0), 498*272b5eddSBrian Austin SOC_SINGLE_TLV("ALC MAX", CS42L56_ALC_THRESHOLD, 499*272b5eddSBrian Austin 5, 0x07, 1, alc_tlv), 500*272b5eddSBrian Austin SOC_SINGLE_TLV("ALC MIN", CS42L56_ALC_THRESHOLD, 501*272b5eddSBrian Austin 2, 0x07, 1, alc_tlv), 502*272b5eddSBrian Austin 503*272b5eddSBrian Austin SOC_SINGLE("Limiter Switch", CS42L56_LIM_CTL_RELEASE_RATE, 7, 1, 1), 504*272b5eddSBrian Austin SOC_SINGLE("Limit All Switch", CS42L56_LIM_CTL_RELEASE_RATE, 6, 1, 1), 505*272b5eddSBrian Austin SOC_SINGLE_RANGE("Limiter Attack", CS42L56_LIM_ATTACK_RATE, 506*272b5eddSBrian Austin 0, 0, 0x3f, 0), 507*272b5eddSBrian Austin SOC_SINGLE_RANGE("Limiter Release", CS42L56_LIM_CTL_RELEASE_RATE, 508*272b5eddSBrian Austin 0, 0x3f, 0, 0), 509*272b5eddSBrian Austin SOC_SINGLE_TLV("Limiter MAX", CS42L56_LIM_THRESHOLD_CTL, 510*272b5eddSBrian Austin 5, 0x07, 1, alc_tlv), 511*272b5eddSBrian Austin SOC_SINGLE_TLV("Limiter Cushion", CS42L56_ALC_THRESHOLD, 512*272b5eddSBrian Austin 2, 0x07, 1, alc_tlv), 513*272b5eddSBrian Austin 514*272b5eddSBrian Austin SOC_SINGLE("NG Switch", CS42L56_NOISE_GATE_CTL, 6, 1, 1), 515*272b5eddSBrian Austin SOC_SINGLE("NG All Switch", CS42L56_NOISE_GATE_CTL, 7, 1, 1), 516*272b5eddSBrian Austin SOC_SINGLE("NG Boost Switch", CS42L56_NOISE_GATE_CTL, 5, 1, 1), 517*272b5eddSBrian Austin SOC_SINGLE_TLV("NG Unboost Threshold", CS42L56_NOISE_GATE_CTL, 518*272b5eddSBrian Austin 2, 0x07, 1, ngnb_tlv), 519*272b5eddSBrian Austin SOC_SINGLE_TLV("NG Boost Threshold", CS42L56_NOISE_GATE_CTL, 520*272b5eddSBrian Austin 2, 0x07, 1, ngb_tlv), 521*272b5eddSBrian Austin SOC_ENUM("NG Delay", ng_delay_enum), 522*272b5eddSBrian Austin 523*272b5eddSBrian Austin SOC_ENUM("Beep Config", beep_config_enum), 524*272b5eddSBrian Austin SOC_ENUM("Beep Pitch", beep_pitch_enum), 525*272b5eddSBrian Austin SOC_ENUM("Beep on Time", beep_ontime_enum), 526*272b5eddSBrian Austin SOC_ENUM("Beep off Time", beep_offtime_enum), 527*272b5eddSBrian Austin SOC_SINGLE_SX_TLV("Beep Volume", CS42L56_BEEP_FREQ_OFFTIME, 528*272b5eddSBrian Austin 0, 0x07, 0x23, beep_tlv), 529*272b5eddSBrian Austin SOC_SINGLE("Beep Tone Ctl Switch", CS42L56_BEEP_TONE_CFG, 0, 1, 1), 530*272b5eddSBrian Austin SOC_ENUM("Beep Treble Corner Freq", beep_treble_enum), 531*272b5eddSBrian Austin SOC_ENUM("Beep Bass Corner Freq", beep_bass_enum), 532*272b5eddSBrian Austin 533*272b5eddSBrian Austin }; 534*272b5eddSBrian Austin 535*272b5eddSBrian Austin static const struct snd_soc_dapm_widget cs42l56_dapm_widgets[] = { 536*272b5eddSBrian Austin 537*272b5eddSBrian Austin SND_SOC_DAPM_SIGGEN("Beep"), 538*272b5eddSBrian Austin SND_SOC_DAPM_SUPPLY("VBUF", CS42L56_PWRCTL_1, 5, 1, NULL, 0), 539*272b5eddSBrian Austin SND_SOC_DAPM_MICBIAS("MIC1 Bias", CS42L56_PWRCTL_1, 4, 1), 540*272b5eddSBrian Austin SND_SOC_DAPM_SUPPLY("Charge Pump", CS42L56_PWRCTL_1, 3, 1, NULL, 0), 541*272b5eddSBrian Austin 542*272b5eddSBrian Austin SND_SOC_DAPM_INPUT("AIN1A"), 543*272b5eddSBrian Austin SND_SOC_DAPM_INPUT("AIN2A"), 544*272b5eddSBrian Austin SND_SOC_DAPM_INPUT("AIN1B"), 545*272b5eddSBrian Austin SND_SOC_DAPM_INPUT("AIN2B"), 546*272b5eddSBrian Austin SND_SOC_DAPM_INPUT("AIN3A"), 547*272b5eddSBrian Austin SND_SOC_DAPM_INPUT("AIN3B"), 548*272b5eddSBrian Austin 549*272b5eddSBrian Austin SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, 550*272b5eddSBrian Austin SND_SOC_NOPM, 0, 0), 551*272b5eddSBrian Austin 552*272b5eddSBrian Austin SND_SOC_DAPM_AIF_IN("SDIN", NULL, 0, 553*272b5eddSBrian Austin SND_SOC_NOPM, 0, 0), 554*272b5eddSBrian Austin 555*272b5eddSBrian Austin SND_SOC_DAPM_MUX("Digital Output Mux", SND_SOC_NOPM, 556*272b5eddSBrian Austin 0, 0, &dig_mux), 557*272b5eddSBrian Austin 558*272b5eddSBrian Austin SND_SOC_DAPM_PGA("PGAA", SND_SOC_NOPM, 0, 0, NULL, 0), 559*272b5eddSBrian Austin SND_SOC_DAPM_PGA("PGAB", SND_SOC_NOPM, 0, 0, NULL, 0), 560*272b5eddSBrian Austin SND_SOC_DAPM_MUX("PGAA Input Mux", 561*272b5eddSBrian Austin SND_SOC_NOPM, 0, 0, &pgaa_mux), 562*272b5eddSBrian Austin SND_SOC_DAPM_MUX("PGAB Input Mux", 563*272b5eddSBrian Austin SND_SOC_NOPM, 0, 0, &pgab_mux), 564*272b5eddSBrian Austin 565*272b5eddSBrian Austin SND_SOC_DAPM_MUX("ADCA Mux", SND_SOC_NOPM, 566*272b5eddSBrian Austin 0, 0, &adca_mux), 567*272b5eddSBrian Austin SND_SOC_DAPM_MUX("ADCB Mux", SND_SOC_NOPM, 568*272b5eddSBrian Austin 0, 0, &adcb_mux), 569*272b5eddSBrian Austin 570*272b5eddSBrian Austin SND_SOC_DAPM_ADC("ADCA", NULL, CS42L56_PWRCTL_1, 1, 1), 571*272b5eddSBrian Austin SND_SOC_DAPM_ADC("ADCB", NULL, CS42L56_PWRCTL_1, 2, 1), 572*272b5eddSBrian Austin 573*272b5eddSBrian Austin SND_SOC_DAPM_DAC("DACA", NULL, SND_SOC_NOPM, 0, 0), 574*272b5eddSBrian Austin SND_SOC_DAPM_DAC("DACB", NULL, SND_SOC_NOPM, 0, 0), 575*272b5eddSBrian Austin 576*272b5eddSBrian Austin SND_SOC_DAPM_OUTPUT("HPA"), 577*272b5eddSBrian Austin SND_SOC_DAPM_OUTPUT("LOA"), 578*272b5eddSBrian Austin SND_SOC_DAPM_OUTPUT("HPB"), 579*272b5eddSBrian Austin SND_SOC_DAPM_OUTPUT("LOB"), 580*272b5eddSBrian Austin 581*272b5eddSBrian Austin SND_SOC_DAPM_SWITCH("Headphone Right", 582*272b5eddSBrian Austin CS42L56_PWRCTL_2, 4, 1, &hpb_switch), 583*272b5eddSBrian Austin SND_SOC_DAPM_SWITCH("Headphone Left", 584*272b5eddSBrian Austin CS42L56_PWRCTL_2, 6, 1, &hpa_switch), 585*272b5eddSBrian Austin 586*272b5eddSBrian Austin SND_SOC_DAPM_SWITCH("Lineout Right", 587*272b5eddSBrian Austin CS42L56_PWRCTL_2, 0, 1, &lob_switch), 588*272b5eddSBrian Austin SND_SOC_DAPM_SWITCH("Lineout Left", 589*272b5eddSBrian Austin CS42L56_PWRCTL_2, 2, 1, &loa_switch), 590*272b5eddSBrian Austin 591*272b5eddSBrian Austin SND_SOC_DAPM_MUX("LINEOUTA Input Mux", SND_SOC_NOPM, 592*272b5eddSBrian Austin 0, 0, &lineouta_input), 593*272b5eddSBrian Austin SND_SOC_DAPM_MUX("LINEOUTB Input Mux", SND_SOC_NOPM, 594*272b5eddSBrian Austin 0, 0, &lineoutb_input), 595*272b5eddSBrian Austin SND_SOC_DAPM_MUX("HPA Input Mux", SND_SOC_NOPM, 596*272b5eddSBrian Austin 0, 0, &hpa_input), 597*272b5eddSBrian Austin SND_SOC_DAPM_MUX("HPB Input Mux", SND_SOC_NOPM, 598*272b5eddSBrian Austin 0, 0, &hpb_input), 599*272b5eddSBrian Austin 600*272b5eddSBrian Austin }; 601*272b5eddSBrian Austin 602*272b5eddSBrian Austin static const struct snd_soc_dapm_route cs42l56_audio_map[] = { 603*272b5eddSBrian Austin 604*272b5eddSBrian Austin {"HiFi Capture", "DSP", "Digital Output Mux"}, 605*272b5eddSBrian Austin {"HiFi Capture", "ADC", "Digital Output Mux"}, 606*272b5eddSBrian Austin 607*272b5eddSBrian Austin {"Digital Output Mux", NULL, "ADCA"}, 608*272b5eddSBrian Austin {"Digital Output Mux", NULL, "ADCB"}, 609*272b5eddSBrian Austin 610*272b5eddSBrian Austin {"ADCB", NULL, "ADCB Mux"}, 611*272b5eddSBrian Austin {"ADCA", NULL, "ADCA Mux"}, 612*272b5eddSBrian Austin 613*272b5eddSBrian Austin {"ADCA Mux", NULL, "AIN3A"}, 614*272b5eddSBrian Austin {"ADCA Mux", NULL, "AIN2A"}, 615*272b5eddSBrian Austin {"ADCA Mux", NULL, "AIN1A"}, 616*272b5eddSBrian Austin {"ADCA Mux", NULL, "PGAA"}, 617*272b5eddSBrian Austin {"ADCB Mux", NULL, "AIN3B"}, 618*272b5eddSBrian Austin {"ADCB Mux", NULL, "AIN2B"}, 619*272b5eddSBrian Austin {"ADCB Mux", NULL, "AIN1B"}, 620*272b5eddSBrian Austin {"ADCB Mux", NULL, "PGAB"}, 621*272b5eddSBrian Austin 622*272b5eddSBrian Austin {"PGAA", "AIN1A", "PGAA Input Mux"}, 623*272b5eddSBrian Austin {"PGAA", "AIN2A", "PGAA Input Mux"}, 624*272b5eddSBrian Austin {"PGAA", "AIN3A", "PGAA Input Mux"}, 625*272b5eddSBrian Austin {"PGAB", "AIN1B", "PGAB Input Mux"}, 626*272b5eddSBrian Austin {"PGAB", "AIN2B", "PGAB Input Mux"}, 627*272b5eddSBrian Austin {"PGAB", "AIN3B", "PGAB Input Mux"}, 628*272b5eddSBrian Austin 629*272b5eddSBrian Austin {"PGAA Input Mux", NULL, "AIN1A"}, 630*272b5eddSBrian Austin {"PGAA Input Mux", NULL, "AIN2A"}, 631*272b5eddSBrian Austin {"PGAA Input Mux", NULL, "AIN3A"}, 632*272b5eddSBrian Austin {"PGAB Input Mux", NULL, "AIN1B"}, 633*272b5eddSBrian Austin {"PGAB Input Mux", NULL, "AIN2B"}, 634*272b5eddSBrian Austin {"PGAB Input Mux", NULL, "AIN3B"}, 635*272b5eddSBrian Austin 636*272b5eddSBrian Austin {"LOB", NULL, "Lineout Right"}, 637*272b5eddSBrian Austin {"LOA", NULL, "Lineout Left"}, 638*272b5eddSBrian Austin 639*272b5eddSBrian Austin {"Lineout Right", "Switch", "LINEOUTB Input Mux"}, 640*272b5eddSBrian Austin {"Lineout Left", "Switch", "LINEOUTA Input Mux"}, 641*272b5eddSBrian Austin 642*272b5eddSBrian Austin {"LINEOUTA Input Mux", "PGAA", "PGAA"}, 643*272b5eddSBrian Austin {"LINEOUTB Input Mux", "PGAB", "PGAB"}, 644*272b5eddSBrian Austin {"LINEOUTA Input Mux", "DACA", "DACA"}, 645*272b5eddSBrian Austin {"LINEOUTB Input Mux", "DACB", "DACB"}, 646*272b5eddSBrian Austin 647*272b5eddSBrian Austin {"HPA", NULL, "Headphone Left"}, 648*272b5eddSBrian Austin {"HPB", NULL, "Headphone Right"}, 649*272b5eddSBrian Austin 650*272b5eddSBrian Austin {"Headphone Right", "Switch", "HPB Input Mux"}, 651*272b5eddSBrian Austin {"Headphone Left", "Switch", "HPA Input Mux"}, 652*272b5eddSBrian Austin 653*272b5eddSBrian Austin {"HPA Input Mux", "PGAA", "PGAA"}, 654*272b5eddSBrian Austin {"HPB Input Mux", "PGAB", "PGAB"}, 655*272b5eddSBrian Austin {"HPA Input Mux", "DACA", "DACA"}, 656*272b5eddSBrian Austin {"HPB Input Mux", "DACB", "DACB"}, 657*272b5eddSBrian Austin 658*272b5eddSBrian Austin {"DACB", NULL, "HiFi Playback"}, 659*272b5eddSBrian Austin {"DACA", NULL, "HiFi Playback"}, 660*272b5eddSBrian Austin 661*272b5eddSBrian Austin }; 662*272b5eddSBrian Austin 663*272b5eddSBrian Austin struct cs42l56_clk_para { 664*272b5eddSBrian Austin u32 mclk; 665*272b5eddSBrian Austin u32 srate; 666*272b5eddSBrian Austin u8 ratio; 667*272b5eddSBrian Austin }; 668*272b5eddSBrian Austin 669*272b5eddSBrian Austin static const struct cs42l56_clk_para clk_ratio_table[] = { 670*272b5eddSBrian Austin /* 8k */ 671*272b5eddSBrian Austin { 6000000, 8000, CS42L56_MCLK_LRCLK_768 }, 672*272b5eddSBrian Austin { 6144000, 8000, CS42L56_MCLK_LRCLK_750 }, 673*272b5eddSBrian Austin { 12000000, 8000, CS42L56_MCLK_LRCLK_768 }, 674*272b5eddSBrian Austin { 12288000, 8000, CS42L56_MCLK_LRCLK_750 }, 675*272b5eddSBrian Austin { 24000000, 8000, CS42L56_MCLK_LRCLK_768 }, 676*272b5eddSBrian Austin { 24576000, 8000, CS42L56_MCLK_LRCLK_750 }, 677*272b5eddSBrian Austin /* 11.025k */ 678*272b5eddSBrian Austin { 5644800, 11025, CS42L56_MCLK_LRCLK_512}, 679*272b5eddSBrian Austin { 11289600, 11025, CS42L56_MCLK_LRCLK_512}, 680*272b5eddSBrian Austin { 22579200, 11025, CS42L56_MCLK_LRCLK_512 }, 681*272b5eddSBrian Austin /* 11.0294k */ 682*272b5eddSBrian Austin { 6000000, 110294, CS42L56_MCLK_LRCLK_544 }, 683*272b5eddSBrian Austin { 12000000, 110294, CS42L56_MCLK_LRCLK_544 }, 684*272b5eddSBrian Austin { 24000000, 110294, CS42L56_MCLK_LRCLK_544 }, 685*272b5eddSBrian Austin /* 12k */ 686*272b5eddSBrian Austin { 6000000, 12000, CS42L56_MCLK_LRCLK_500 }, 687*272b5eddSBrian Austin { 6144000, 12000, CS42L56_MCLK_LRCLK_512 }, 688*272b5eddSBrian Austin { 12000000, 12000, CS42L56_MCLK_LRCLK_500 }, 689*272b5eddSBrian Austin { 12288000, 12000, CS42L56_MCLK_LRCLK_512 }, 690*272b5eddSBrian Austin { 24000000, 12000, CS42L56_MCLK_LRCLK_500 }, 691*272b5eddSBrian Austin { 24576000, 12000, CS42L56_MCLK_LRCLK_512 }, 692*272b5eddSBrian Austin /* 16k */ 693*272b5eddSBrian Austin { 6000000, 16000, CS42L56_MCLK_LRCLK_375 }, 694*272b5eddSBrian Austin { 6144000, 16000, CS42L56_MCLK_LRCLK_384 }, 695*272b5eddSBrian Austin { 12000000, 16000, CS42L56_MCLK_LRCLK_375 }, 696*272b5eddSBrian Austin { 12288000, 16000, CS42L56_MCLK_LRCLK_384 }, 697*272b5eddSBrian Austin { 24000000, 16000, CS42L56_MCLK_LRCLK_375 }, 698*272b5eddSBrian Austin { 24576000, 16000, CS42L56_MCLK_LRCLK_384 }, 699*272b5eddSBrian Austin /* 22.050k */ 700*272b5eddSBrian Austin { 5644800, 22050, CS42L56_MCLK_LRCLK_256 }, 701*272b5eddSBrian Austin { 11289600, 22050, CS42L56_MCLK_LRCLK_256 }, 702*272b5eddSBrian Austin { 22579200, 22050, CS42L56_MCLK_LRCLK_256 }, 703*272b5eddSBrian Austin /* 22.0588k */ 704*272b5eddSBrian Austin { 6000000, 220588, CS42L56_MCLK_LRCLK_272 }, 705*272b5eddSBrian Austin { 12000000, 220588, CS42L56_MCLK_LRCLK_272 }, 706*272b5eddSBrian Austin { 24000000, 220588, CS42L56_MCLK_LRCLK_272 }, 707*272b5eddSBrian Austin /* 24k */ 708*272b5eddSBrian Austin { 6000000, 24000, CS42L56_MCLK_LRCLK_250 }, 709*272b5eddSBrian Austin { 6144000, 24000, CS42L56_MCLK_LRCLK_256 }, 710*272b5eddSBrian Austin { 12000000, 24000, CS42L56_MCLK_LRCLK_250 }, 711*272b5eddSBrian Austin { 12288000, 24000, CS42L56_MCLK_LRCLK_256 }, 712*272b5eddSBrian Austin { 24000000, 24000, CS42L56_MCLK_LRCLK_250 }, 713*272b5eddSBrian Austin { 24576000, 24000, CS42L56_MCLK_LRCLK_256 }, 714*272b5eddSBrian Austin /* 32k */ 715*272b5eddSBrian Austin { 6000000, 32000, CS42L56_MCLK_LRCLK_187P5 }, 716*272b5eddSBrian Austin { 6144000, 32000, CS42L56_MCLK_LRCLK_192 }, 717*272b5eddSBrian Austin { 12000000, 32000, CS42L56_MCLK_LRCLK_187P5 }, 718*272b5eddSBrian Austin { 12288000, 32000, CS42L56_MCLK_LRCLK_192 }, 719*272b5eddSBrian Austin { 24000000, 32000, CS42L56_MCLK_LRCLK_187P5 }, 720*272b5eddSBrian Austin { 24576000, 32000, CS42L56_MCLK_LRCLK_192 }, 721*272b5eddSBrian Austin /* 44.118k */ 722*272b5eddSBrian Austin { 6000000, 44118, CS42L56_MCLK_LRCLK_136 }, 723*272b5eddSBrian Austin { 12000000, 44118, CS42L56_MCLK_LRCLK_136 }, 724*272b5eddSBrian Austin { 24000000, 44118, CS42L56_MCLK_LRCLK_136 }, 725*272b5eddSBrian Austin /* 44.1k */ 726*272b5eddSBrian Austin { 5644800, 44100, CS42L56_MCLK_LRCLK_128 }, 727*272b5eddSBrian Austin { 11289600, 44100, CS42L56_MCLK_LRCLK_128 }, 728*272b5eddSBrian Austin { 22579200, 44100, CS42L56_MCLK_LRCLK_128 }, 729*272b5eddSBrian Austin /* 48k */ 730*272b5eddSBrian Austin { 6000000, 48000, CS42L56_MCLK_LRCLK_125 }, 731*272b5eddSBrian Austin { 6144000, 48000, CS42L56_MCLK_LRCLK_128 }, 732*272b5eddSBrian Austin { 12000000, 48000, CS42L56_MCLK_LRCLK_125 }, 733*272b5eddSBrian Austin { 12288000, 48000, CS42L56_MCLK_LRCLK_128 }, 734*272b5eddSBrian Austin { 24000000, 48000, CS42L56_MCLK_LRCLK_125 }, 735*272b5eddSBrian Austin { 24576000, 48000, CS42L56_MCLK_LRCLK_128 }, 736*272b5eddSBrian Austin }; 737*272b5eddSBrian Austin 738*272b5eddSBrian Austin static int cs42l56_get_mclk_ratio(int mclk, int rate) 739*272b5eddSBrian Austin { 740*272b5eddSBrian Austin int i; 741*272b5eddSBrian Austin 742*272b5eddSBrian Austin for (i = 0; i < ARRAY_SIZE(clk_ratio_table); i++) { 743*272b5eddSBrian Austin if (clk_ratio_table[i].mclk == mclk && 744*272b5eddSBrian Austin clk_ratio_table[i].srate == rate) 745*272b5eddSBrian Austin return clk_ratio_table[i].ratio; 746*272b5eddSBrian Austin } 747*272b5eddSBrian Austin return -EINVAL; 748*272b5eddSBrian Austin } 749*272b5eddSBrian Austin 750*272b5eddSBrian Austin static int cs42l56_set_sysclk(struct snd_soc_dai *codec_dai, 751*272b5eddSBrian Austin int clk_id, unsigned int freq, int dir) 752*272b5eddSBrian Austin { 753*272b5eddSBrian Austin struct snd_soc_codec *codec = codec_dai->codec; 754*272b5eddSBrian Austin struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); 755*272b5eddSBrian Austin 756*272b5eddSBrian Austin switch (freq) { 757*272b5eddSBrian Austin case CS42L56_MCLK_5P6448MHZ: 758*272b5eddSBrian Austin case CS42L56_MCLK_6MHZ: 759*272b5eddSBrian Austin case CS42L56_MCLK_6P144MHZ: 760*272b5eddSBrian Austin cs42l56->mclk_div2 = 0; 761*272b5eddSBrian Austin cs42l56->mclk_prediv = 0; 762*272b5eddSBrian Austin break; 763*272b5eddSBrian Austin case CS42L56_MCLK_11P2896MHZ: 764*272b5eddSBrian Austin case CS42L56_MCLK_12MHZ: 765*272b5eddSBrian Austin case CS42L56_MCLK_12P288MHZ: 766*272b5eddSBrian Austin cs42l56->mclk_div2 = 1; 767*272b5eddSBrian Austin cs42l56->mclk_prediv = 0; 768*272b5eddSBrian Austin break; 769*272b5eddSBrian Austin case CS42L56_MCLK_22P5792MHZ: 770*272b5eddSBrian Austin case CS42L56_MCLK_24MHZ: 771*272b5eddSBrian Austin case CS42L56_MCLK_24P576MHZ: 772*272b5eddSBrian Austin cs42l56->mclk_div2 = 1; 773*272b5eddSBrian Austin cs42l56->mclk_prediv = 1; 774*272b5eddSBrian Austin break; 775*272b5eddSBrian Austin default: 776*272b5eddSBrian Austin return -EINVAL; 777*272b5eddSBrian Austin } 778*272b5eddSBrian Austin cs42l56->mclk = freq; 779*272b5eddSBrian Austin 780*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_CLKCTL_1, 781*272b5eddSBrian Austin CS42L56_MCLK_PREDIV_MASK, 782*272b5eddSBrian Austin cs42l56->mclk_prediv); 783*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_CLKCTL_1, 784*272b5eddSBrian Austin CS42L56_MCLK_DIV2_MASK, 785*272b5eddSBrian Austin cs42l56->mclk_div2); 786*272b5eddSBrian Austin 787*272b5eddSBrian Austin return 0; 788*272b5eddSBrian Austin } 789*272b5eddSBrian Austin 790*272b5eddSBrian Austin static int cs42l56_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) 791*272b5eddSBrian Austin { 792*272b5eddSBrian Austin struct snd_soc_codec *codec = codec_dai->codec; 793*272b5eddSBrian Austin struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); 794*272b5eddSBrian Austin 795*272b5eddSBrian Austin switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 796*272b5eddSBrian Austin case SND_SOC_DAIFMT_CBM_CFM: 797*272b5eddSBrian Austin cs42l56->iface = CS42L56_MASTER_MODE; 798*272b5eddSBrian Austin break; 799*272b5eddSBrian Austin case SND_SOC_DAIFMT_CBS_CFS: 800*272b5eddSBrian Austin cs42l56->iface = CS42L56_SLAVE_MODE; 801*272b5eddSBrian Austin break; 802*272b5eddSBrian Austin default: 803*272b5eddSBrian Austin return -EINVAL; 804*272b5eddSBrian Austin } 805*272b5eddSBrian Austin 806*272b5eddSBrian Austin /* interface format */ 807*272b5eddSBrian Austin switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 808*272b5eddSBrian Austin case SND_SOC_DAIFMT_I2S: 809*272b5eddSBrian Austin cs42l56->iface_fmt = CS42L56_DIG_FMT_I2S; 810*272b5eddSBrian Austin break; 811*272b5eddSBrian Austin case SND_SOC_DAIFMT_LEFT_J: 812*272b5eddSBrian Austin cs42l56->iface_fmt = CS42L56_DIG_FMT_LEFT_J; 813*272b5eddSBrian Austin break; 814*272b5eddSBrian Austin default: 815*272b5eddSBrian Austin return -EINVAL; 816*272b5eddSBrian Austin } 817*272b5eddSBrian Austin 818*272b5eddSBrian Austin /* sclk inversion */ 819*272b5eddSBrian Austin switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 820*272b5eddSBrian Austin case SND_SOC_DAIFMT_NB_NF: 821*272b5eddSBrian Austin cs42l56->iface_inv = 0; 822*272b5eddSBrian Austin break; 823*272b5eddSBrian Austin case SND_SOC_DAIFMT_IB_NF: 824*272b5eddSBrian Austin cs42l56->iface_inv = CS42L56_SCLK_INV; 825*272b5eddSBrian Austin break; 826*272b5eddSBrian Austin default: 827*272b5eddSBrian Austin return -EINVAL; 828*272b5eddSBrian Austin } 829*272b5eddSBrian Austin 830*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_CLKCTL_1, 831*272b5eddSBrian Austin CS42L56_MS_MODE_MASK, cs42l56->iface); 832*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_SERIAL_FMT, 833*272b5eddSBrian Austin CS42L56_DIG_FMT_MASK, cs42l56->iface_fmt); 834*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_CLKCTL_1, 835*272b5eddSBrian Austin CS42L56_SCLK_INV_MASK, cs42l56->iface_inv); 836*272b5eddSBrian Austin return 0; 837*272b5eddSBrian Austin } 838*272b5eddSBrian Austin 839*272b5eddSBrian Austin static int cs42l56_digital_mute(struct snd_soc_dai *dai, int mute) 840*272b5eddSBrian Austin { 841*272b5eddSBrian Austin struct snd_soc_codec *codec = dai->codec; 842*272b5eddSBrian Austin 843*272b5eddSBrian Austin if (mute) { 844*272b5eddSBrian Austin /* Hit the DSP Mixer first */ 845*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_DSP_MUTE_CTL, 846*272b5eddSBrian Austin CS42L56_ADCAMIX_MUTE_MASK | 847*272b5eddSBrian Austin CS42L56_ADCBMIX_MUTE_MASK | 848*272b5eddSBrian Austin CS42L56_PCMAMIX_MUTE_MASK | 849*272b5eddSBrian Austin CS42L56_PCMBMIX_MUTE_MASK | 850*272b5eddSBrian Austin CS42L56_MSTB_MUTE_MASK | 851*272b5eddSBrian Austin CS42L56_MSTA_MUTE_MASK, 852*272b5eddSBrian Austin CS42L56_MUTE); 853*272b5eddSBrian Austin /* Mute ADC's */ 854*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_MISC_ADC_CTL, 855*272b5eddSBrian Austin CS42L56_ADCA_MUTE_MASK | 856*272b5eddSBrian Austin CS42L56_ADCB_MUTE_MASK, 857*272b5eddSBrian Austin CS42L56_MUTE); 858*272b5eddSBrian Austin /* HP And LO */ 859*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_HPA_VOLUME, 860*272b5eddSBrian Austin CS42L56_HP_MUTE_MASK, 861*272b5eddSBrian Austin CS42L56_MUTE); 862*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_HPB_VOLUME, 863*272b5eddSBrian Austin CS42L56_HP_MUTE_MASK, 864*272b5eddSBrian Austin CS42L56_MUTE); 865*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_LOA_VOLUME, 866*272b5eddSBrian Austin CS42L56_LO_MUTE_MASK, 867*272b5eddSBrian Austin CS42L56_MUTE); 868*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_LOB_VOLUME, 869*272b5eddSBrian Austin CS42L56_LO_MUTE_MASK, 870*272b5eddSBrian Austin CS42L56_MUTE); 871*272b5eddSBrian Austin 872*272b5eddSBrian Austin 873*272b5eddSBrian Austin } else { 874*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_DSP_MUTE_CTL, 875*272b5eddSBrian Austin CS42L56_ADCAMIX_MUTE_MASK | 876*272b5eddSBrian Austin CS42L56_ADCBMIX_MUTE_MASK | 877*272b5eddSBrian Austin CS42L56_PCMAMIX_MUTE_MASK | 878*272b5eddSBrian Austin CS42L56_PCMBMIX_MUTE_MASK | 879*272b5eddSBrian Austin CS42L56_MSTB_MUTE_MASK | 880*272b5eddSBrian Austin CS42L56_MSTA_MUTE_MASK, 881*272b5eddSBrian Austin CS42L56_UNMUTE); 882*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_MISC_ADC_CTL, 883*272b5eddSBrian Austin CS42L56_ADCA_MUTE_MASK | 884*272b5eddSBrian Austin CS42L56_ADCB_MUTE_MASK, 885*272b5eddSBrian Austin CS42L56_UNMUTE); 886*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_HPA_VOLUME, 887*272b5eddSBrian Austin CS42L56_HP_MUTE_MASK, 888*272b5eddSBrian Austin CS42L56_UNMUTE); 889*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_HPB_VOLUME, 890*272b5eddSBrian Austin CS42L56_HP_MUTE_MASK, 891*272b5eddSBrian Austin CS42L56_UNMUTE); 892*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_LOA_VOLUME, 893*272b5eddSBrian Austin CS42L56_LO_MUTE_MASK, 894*272b5eddSBrian Austin CS42L56_UNMUTE); 895*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_LOB_VOLUME, 896*272b5eddSBrian Austin CS42L56_LO_MUTE_MASK, 897*272b5eddSBrian Austin CS42L56_UNMUTE); 898*272b5eddSBrian Austin } 899*272b5eddSBrian Austin return 0; 900*272b5eddSBrian Austin } 901*272b5eddSBrian Austin 902*272b5eddSBrian Austin static int cs42l56_pcm_hw_params(struct snd_pcm_substream *substream, 903*272b5eddSBrian Austin struct snd_pcm_hw_params *params, 904*272b5eddSBrian Austin struct snd_soc_dai *dai) 905*272b5eddSBrian Austin { 906*272b5eddSBrian Austin struct snd_soc_codec *codec = dai->codec; 907*272b5eddSBrian Austin struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); 908*272b5eddSBrian Austin int ratio; 909*272b5eddSBrian Austin 910*272b5eddSBrian Austin ratio = cs42l56_get_mclk_ratio(cs42l56->mclk, params_rate(params)); 911*272b5eddSBrian Austin if (ratio >= 0) { 912*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_CLKCTL_2, 913*272b5eddSBrian Austin CS42L56_CLK_RATIO_MASK, ratio); 914*272b5eddSBrian Austin } else { 915*272b5eddSBrian Austin dev_err(codec->dev, "unsupported mclk/sclk/lrclk ratio\n"); 916*272b5eddSBrian Austin return -EINVAL; 917*272b5eddSBrian Austin } 918*272b5eddSBrian Austin 919*272b5eddSBrian Austin return 0; 920*272b5eddSBrian Austin } 921*272b5eddSBrian Austin 922*272b5eddSBrian Austin static int cs42l56_set_bias_level(struct snd_soc_codec *codec, 923*272b5eddSBrian Austin enum snd_soc_bias_level level) 924*272b5eddSBrian Austin { 925*272b5eddSBrian Austin struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); 926*272b5eddSBrian Austin int ret; 927*272b5eddSBrian Austin 928*272b5eddSBrian Austin switch (level) { 929*272b5eddSBrian Austin case SND_SOC_BIAS_ON: 930*272b5eddSBrian Austin break; 931*272b5eddSBrian Austin case SND_SOC_BIAS_PREPARE: 932*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_CLKCTL_1, 933*272b5eddSBrian Austin CS42L56_MCLK_DIS_MASK, 0); 934*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_PWRCTL_1, 935*272b5eddSBrian Austin CS42L56_PDN_ALL_MASK, 0); 936*272b5eddSBrian Austin break; 937*272b5eddSBrian Austin case SND_SOC_BIAS_STANDBY: 938*272b5eddSBrian Austin if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { 939*272b5eddSBrian Austin regcache_cache_only(cs42l56->regmap, false); 940*272b5eddSBrian Austin regcache_sync(cs42l56->regmap); 941*272b5eddSBrian Austin ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies), 942*272b5eddSBrian Austin cs42l56->supplies); 943*272b5eddSBrian Austin if (ret != 0) { 944*272b5eddSBrian Austin dev_err(cs42l56->dev, 945*272b5eddSBrian Austin "Failed to enable regulators: %d\n", 946*272b5eddSBrian Austin ret); 947*272b5eddSBrian Austin return ret; 948*272b5eddSBrian Austin } 949*272b5eddSBrian Austin } 950*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_PWRCTL_1, 951*272b5eddSBrian Austin CS42L56_PDN_ALL_MASK, 1); 952*272b5eddSBrian Austin break; 953*272b5eddSBrian Austin case SND_SOC_BIAS_OFF: 954*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_PWRCTL_1, 955*272b5eddSBrian Austin CS42L56_PDN_ALL_MASK, 1); 956*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_CLKCTL_1, 957*272b5eddSBrian Austin CS42L56_MCLK_DIS_MASK, 1); 958*272b5eddSBrian Austin regcache_cache_only(cs42l56->regmap, true); 959*272b5eddSBrian Austin regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies), 960*272b5eddSBrian Austin cs42l56->supplies); 961*272b5eddSBrian Austin break; 962*272b5eddSBrian Austin } 963*272b5eddSBrian Austin codec->dapm.bias_level = level; 964*272b5eddSBrian Austin 965*272b5eddSBrian Austin return 0; 966*272b5eddSBrian Austin } 967*272b5eddSBrian Austin 968*272b5eddSBrian Austin #define CS42L56_RATES (SNDRV_PCM_RATE_8000_48000) 969*272b5eddSBrian Austin 970*272b5eddSBrian Austin #define CS42L56_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ 971*272b5eddSBrian Austin SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \ 972*272b5eddSBrian Austin SNDRV_PCM_FMTBIT_S32_LE) 973*272b5eddSBrian Austin 974*272b5eddSBrian Austin 975*272b5eddSBrian Austin static struct snd_soc_dai_ops cs42l56_ops = { 976*272b5eddSBrian Austin .hw_params = cs42l56_pcm_hw_params, 977*272b5eddSBrian Austin .digital_mute = cs42l56_digital_mute, 978*272b5eddSBrian Austin .set_fmt = cs42l56_set_dai_fmt, 979*272b5eddSBrian Austin .set_sysclk = cs42l56_set_sysclk, 980*272b5eddSBrian Austin }; 981*272b5eddSBrian Austin 982*272b5eddSBrian Austin static struct snd_soc_dai_driver cs42l56_dai = { 983*272b5eddSBrian Austin .name = "cs42l56", 984*272b5eddSBrian Austin .playback = { 985*272b5eddSBrian Austin .stream_name = "HiFi Playback", 986*272b5eddSBrian Austin .channels_min = 1, 987*272b5eddSBrian Austin .channels_max = 2, 988*272b5eddSBrian Austin .rates = CS42L56_RATES, 989*272b5eddSBrian Austin .formats = CS42L56_FORMATS, 990*272b5eddSBrian Austin }, 991*272b5eddSBrian Austin .capture = { 992*272b5eddSBrian Austin .stream_name = "HiFi Capture", 993*272b5eddSBrian Austin .channels_min = 1, 994*272b5eddSBrian Austin .channels_max = 2, 995*272b5eddSBrian Austin .rates = CS42L56_RATES, 996*272b5eddSBrian Austin .formats = CS42L56_FORMATS, 997*272b5eddSBrian Austin }, 998*272b5eddSBrian Austin .ops = &cs42l56_ops, 999*272b5eddSBrian Austin }; 1000*272b5eddSBrian Austin 1001*272b5eddSBrian Austin static int cs42l56_suspend(struct snd_soc_codec *codec) 1002*272b5eddSBrian Austin { 1003*272b5eddSBrian Austin cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF); 1004*272b5eddSBrian Austin 1005*272b5eddSBrian Austin return 0; 1006*272b5eddSBrian Austin } 1007*272b5eddSBrian Austin 1008*272b5eddSBrian Austin static int cs42l56_resume(struct snd_soc_codec *codec) 1009*272b5eddSBrian Austin { 1010*272b5eddSBrian Austin cs42l56_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1011*272b5eddSBrian Austin 1012*272b5eddSBrian Austin return 0; 1013*272b5eddSBrian Austin } 1014*272b5eddSBrian Austin 1015*272b5eddSBrian Austin static int beep_freq[] = { 1016*272b5eddSBrian Austin 261, 522, 585, 667, 706, 774, 889, 1000, 1017*272b5eddSBrian Austin 1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182 1018*272b5eddSBrian Austin }; 1019*272b5eddSBrian Austin 1020*272b5eddSBrian Austin static void cs42l56_beep_work(struct work_struct *work) 1021*272b5eddSBrian Austin { 1022*272b5eddSBrian Austin struct cs42l56_private *cs42l56 = 1023*272b5eddSBrian Austin container_of(work, struct cs42l56_private, beep_work); 1024*272b5eddSBrian Austin struct snd_soc_codec *codec = cs42l56->codec; 1025*272b5eddSBrian Austin struct snd_soc_dapm_context *dapm = &codec->dapm; 1026*272b5eddSBrian Austin int i; 1027*272b5eddSBrian Austin int val = 0; 1028*272b5eddSBrian Austin int best = 0; 1029*272b5eddSBrian Austin 1030*272b5eddSBrian Austin if (cs42l56->beep_rate) { 1031*272b5eddSBrian Austin for (i = 0; i < ARRAY_SIZE(beep_freq); i++) { 1032*272b5eddSBrian Austin if (abs(cs42l56->beep_rate - beep_freq[i]) < 1033*272b5eddSBrian Austin abs(cs42l56->beep_rate - beep_freq[best])) 1034*272b5eddSBrian Austin best = i; 1035*272b5eddSBrian Austin } 1036*272b5eddSBrian Austin 1037*272b5eddSBrian Austin dev_dbg(codec->dev, "Set beep rate %dHz for requested %dHz\n", 1038*272b5eddSBrian Austin beep_freq[best], cs42l56->beep_rate); 1039*272b5eddSBrian Austin 1040*272b5eddSBrian Austin val = (best << CS42L56_BEEP_RATE_SHIFT); 1041*272b5eddSBrian Austin 1042*272b5eddSBrian Austin snd_soc_dapm_enable_pin(dapm, "Beep"); 1043*272b5eddSBrian Austin } else { 1044*272b5eddSBrian Austin dev_dbg(codec->dev, "Disabling beep\n"); 1045*272b5eddSBrian Austin snd_soc_dapm_disable_pin(dapm, "Beep"); 1046*272b5eddSBrian Austin } 1047*272b5eddSBrian Austin 1048*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_BEEP_FREQ_ONTIME, 1049*272b5eddSBrian Austin CS42L56_BEEP_FREQ_MASK, val); 1050*272b5eddSBrian Austin 1051*272b5eddSBrian Austin snd_soc_dapm_sync(dapm); 1052*272b5eddSBrian Austin } 1053*272b5eddSBrian Austin 1054*272b5eddSBrian Austin /* For usability define a way of injecting beep events for the device - 1055*272b5eddSBrian Austin * many systems will not have a keyboard. 1056*272b5eddSBrian Austin */ 1057*272b5eddSBrian Austin static int cs42l56_beep_event(struct input_dev *dev, unsigned int type, 1058*272b5eddSBrian Austin unsigned int code, int hz) 1059*272b5eddSBrian Austin { 1060*272b5eddSBrian Austin struct snd_soc_codec *codec = input_get_drvdata(dev); 1061*272b5eddSBrian Austin struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); 1062*272b5eddSBrian Austin 1063*272b5eddSBrian Austin dev_dbg(codec->dev, "Beep event %x %x\n", code, hz); 1064*272b5eddSBrian Austin 1065*272b5eddSBrian Austin switch (code) { 1066*272b5eddSBrian Austin case SND_BELL: 1067*272b5eddSBrian Austin if (hz) 1068*272b5eddSBrian Austin hz = 261; 1069*272b5eddSBrian Austin case SND_TONE: 1070*272b5eddSBrian Austin break; 1071*272b5eddSBrian Austin default: 1072*272b5eddSBrian Austin return -1; 1073*272b5eddSBrian Austin } 1074*272b5eddSBrian Austin 1075*272b5eddSBrian Austin /* Kick the beep from a workqueue */ 1076*272b5eddSBrian Austin cs42l56->beep_rate = hz; 1077*272b5eddSBrian Austin schedule_work(&cs42l56->beep_work); 1078*272b5eddSBrian Austin return 0; 1079*272b5eddSBrian Austin } 1080*272b5eddSBrian Austin 1081*272b5eddSBrian Austin static ssize_t cs42l56_beep_set(struct device *dev, 1082*272b5eddSBrian Austin struct device_attribute *attr, 1083*272b5eddSBrian Austin const char *buf, size_t count) 1084*272b5eddSBrian Austin { 1085*272b5eddSBrian Austin struct cs42l56_private *cs42l56 = dev_get_drvdata(dev); 1086*272b5eddSBrian Austin long int time; 1087*272b5eddSBrian Austin int ret; 1088*272b5eddSBrian Austin 1089*272b5eddSBrian Austin ret = kstrtol(buf, 10, &time); 1090*272b5eddSBrian Austin if (ret != 0) 1091*272b5eddSBrian Austin return ret; 1092*272b5eddSBrian Austin 1093*272b5eddSBrian Austin input_event(cs42l56->beep, EV_SND, SND_TONE, time); 1094*272b5eddSBrian Austin 1095*272b5eddSBrian Austin return count; 1096*272b5eddSBrian Austin } 1097*272b5eddSBrian Austin 1098*272b5eddSBrian Austin static DEVICE_ATTR(beep, 0200, NULL, cs42l56_beep_set); 1099*272b5eddSBrian Austin 1100*272b5eddSBrian Austin static void cs42l56_init_beep(struct snd_soc_codec *codec) 1101*272b5eddSBrian Austin { 1102*272b5eddSBrian Austin struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); 1103*272b5eddSBrian Austin int ret; 1104*272b5eddSBrian Austin 1105*272b5eddSBrian Austin cs42l56->beep = devm_input_allocate_device(codec->dev); 1106*272b5eddSBrian Austin if (!cs42l56->beep) { 1107*272b5eddSBrian Austin dev_err(codec->dev, "Failed to allocate beep device\n"); 1108*272b5eddSBrian Austin return; 1109*272b5eddSBrian Austin } 1110*272b5eddSBrian Austin 1111*272b5eddSBrian Austin INIT_WORK(&cs42l56->beep_work, cs42l56_beep_work); 1112*272b5eddSBrian Austin cs42l56->beep_rate = 0; 1113*272b5eddSBrian Austin 1114*272b5eddSBrian Austin cs42l56->beep->name = "CS42L56 Beep Generator"; 1115*272b5eddSBrian Austin cs42l56->beep->phys = dev_name(codec->dev); 1116*272b5eddSBrian Austin cs42l56->beep->id.bustype = BUS_I2C; 1117*272b5eddSBrian Austin 1118*272b5eddSBrian Austin cs42l56->beep->evbit[0] = BIT_MASK(EV_SND); 1119*272b5eddSBrian Austin cs42l56->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); 1120*272b5eddSBrian Austin cs42l56->beep->event = cs42l56_beep_event; 1121*272b5eddSBrian Austin cs42l56->beep->dev.parent = codec->dev; 1122*272b5eddSBrian Austin input_set_drvdata(cs42l56->beep, codec); 1123*272b5eddSBrian Austin 1124*272b5eddSBrian Austin ret = input_register_device(cs42l56->beep); 1125*272b5eddSBrian Austin if (ret != 0) { 1126*272b5eddSBrian Austin cs42l56->beep = NULL; 1127*272b5eddSBrian Austin dev_err(codec->dev, "Failed to register beep device\n"); 1128*272b5eddSBrian Austin } 1129*272b5eddSBrian Austin 1130*272b5eddSBrian Austin ret = device_create_file(codec->dev, &dev_attr_beep); 1131*272b5eddSBrian Austin if (ret != 0) { 1132*272b5eddSBrian Austin dev_err(codec->dev, "Failed to create keyclick file: %d\n", 1133*272b5eddSBrian Austin ret); 1134*272b5eddSBrian Austin } 1135*272b5eddSBrian Austin } 1136*272b5eddSBrian Austin 1137*272b5eddSBrian Austin static void cs42l56_free_beep(struct snd_soc_codec *codec) 1138*272b5eddSBrian Austin { 1139*272b5eddSBrian Austin struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); 1140*272b5eddSBrian Austin 1141*272b5eddSBrian Austin device_remove_file(codec->dev, &dev_attr_beep); 1142*272b5eddSBrian Austin cancel_work_sync(&cs42l56->beep_work); 1143*272b5eddSBrian Austin cs42l56->beep = NULL; 1144*272b5eddSBrian Austin 1145*272b5eddSBrian Austin snd_soc_update_bits(codec, CS42L56_BEEP_TONE_CFG, 1146*272b5eddSBrian Austin CS42L56_BEEP_EN_MASK, 0); 1147*272b5eddSBrian Austin } 1148*272b5eddSBrian Austin 1149*272b5eddSBrian Austin static int cs42l56_probe(struct snd_soc_codec *codec) 1150*272b5eddSBrian Austin { 1151*272b5eddSBrian Austin cs42l56_init_beep(codec); 1152*272b5eddSBrian Austin 1153*272b5eddSBrian Austin cs42l56_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1154*272b5eddSBrian Austin 1155*272b5eddSBrian Austin return 0; 1156*272b5eddSBrian Austin } 1157*272b5eddSBrian Austin 1158*272b5eddSBrian Austin static int cs42l56_remove(struct snd_soc_codec *codec) 1159*272b5eddSBrian Austin { 1160*272b5eddSBrian Austin struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); 1161*272b5eddSBrian Austin 1162*272b5eddSBrian Austin cs42l56_free_beep(codec); 1163*272b5eddSBrian Austin cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF); 1164*272b5eddSBrian Austin regulator_bulk_free(ARRAY_SIZE(cs42l56->supplies), cs42l56->supplies); 1165*272b5eddSBrian Austin 1166*272b5eddSBrian Austin return 0; 1167*272b5eddSBrian Austin } 1168*272b5eddSBrian Austin 1169*272b5eddSBrian Austin static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = { 1170*272b5eddSBrian Austin .probe = cs42l56_probe, 1171*272b5eddSBrian Austin .remove = cs42l56_remove, 1172*272b5eddSBrian Austin .suspend = cs42l56_suspend, 1173*272b5eddSBrian Austin .resume = cs42l56_resume, 1174*272b5eddSBrian Austin .set_bias_level = cs42l56_set_bias_level, 1175*272b5eddSBrian Austin 1176*272b5eddSBrian Austin .dapm_widgets = cs42l56_dapm_widgets, 1177*272b5eddSBrian Austin .num_dapm_widgets = ARRAY_SIZE(cs42l56_dapm_widgets), 1178*272b5eddSBrian Austin .dapm_routes = cs42l56_audio_map, 1179*272b5eddSBrian Austin .num_dapm_routes = ARRAY_SIZE(cs42l56_audio_map), 1180*272b5eddSBrian Austin 1181*272b5eddSBrian Austin .controls = cs42l56_snd_controls, 1182*272b5eddSBrian Austin .num_controls = ARRAY_SIZE(cs42l56_snd_controls), 1183*272b5eddSBrian Austin }; 1184*272b5eddSBrian Austin 1185*272b5eddSBrian Austin static struct regmap_config cs42l56_regmap = { 1186*272b5eddSBrian Austin .reg_bits = 8, 1187*272b5eddSBrian Austin .val_bits = 8, 1188*272b5eddSBrian Austin 1189*272b5eddSBrian Austin .max_register = CS42L56_MAX_REGISTER, 1190*272b5eddSBrian Austin .reg_defaults = cs42l56_reg_defaults, 1191*272b5eddSBrian Austin .num_reg_defaults = ARRAY_SIZE(cs42l56_reg_defaults), 1192*272b5eddSBrian Austin .readable_reg = cs42l56_readable_register, 1193*272b5eddSBrian Austin .volatile_reg = cs42l56_volatile_register, 1194*272b5eddSBrian Austin .cache_type = REGCACHE_RBTREE, 1195*272b5eddSBrian Austin }; 1196*272b5eddSBrian Austin 1197*272b5eddSBrian Austin static int cs42l56_handle_of_data(struct i2c_client *i2c_client, 1198*272b5eddSBrian Austin struct cs42l56_platform_data *pdata) 1199*272b5eddSBrian Austin { 1200*272b5eddSBrian Austin struct device_node *np = i2c_client->dev.of_node; 1201*272b5eddSBrian Austin u32 val32; 1202*272b5eddSBrian Austin 1203*272b5eddSBrian Austin if (of_property_read_bool(np, "cirrus,ain1a-reference-cfg")) 1204*272b5eddSBrian Austin pdata->ain1a_ref_cfg = true; 1205*272b5eddSBrian Austin 1206*272b5eddSBrian Austin if (of_property_read_bool(np, "cirrus,ain2a-reference-cfg")) 1207*272b5eddSBrian Austin pdata->ain2a_ref_cfg = true; 1208*272b5eddSBrian Austin 1209*272b5eddSBrian Austin if (of_property_read_bool(np, "cirrus,ain1b-reference-cfg")) 1210*272b5eddSBrian Austin pdata->ain1b_ref_cfg = true; 1211*272b5eddSBrian Austin 1212*272b5eddSBrian Austin if (of_property_read_bool(np, "cirrus,ain2b-reference-cfg")) 1213*272b5eddSBrian Austin pdata->ain2b_ref_cfg = true; 1214*272b5eddSBrian Austin 1215*272b5eddSBrian Austin if (of_property_read_u32(np, "cirrus,micbias-lvl", &val32) >= 0) 1216*272b5eddSBrian Austin pdata->micbias_lvl = val32; 1217*272b5eddSBrian Austin 1218*272b5eddSBrian Austin if (of_property_read_u32(np, "cirrus,chgfreq-divisor", &val32) >= 0) 1219*272b5eddSBrian Austin pdata->chgfreq = val32; 1220*272b5eddSBrian Austin 1221*272b5eddSBrian Austin if (of_property_read_u32(np, "cirrus,adaptive-pwr-cfg", &val32) >= 0) 1222*272b5eddSBrian Austin pdata->adaptive_pwr = val32; 1223*272b5eddSBrian Austin 1224*272b5eddSBrian Austin if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0) 1225*272b5eddSBrian Austin pdata->hpfa_freq = val32; 1226*272b5eddSBrian Austin 1227*272b5eddSBrian Austin if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0) 1228*272b5eddSBrian Austin pdata->hpfb_freq = val32; 1229*272b5eddSBrian Austin 1230*272b5eddSBrian Austin pdata->gpio_nreset = of_get_named_gpio(np, "cirrus,gpio-nreset", 0); 1231*272b5eddSBrian Austin 1232*272b5eddSBrian Austin return 0; 1233*272b5eddSBrian Austin } 1234*272b5eddSBrian Austin 1235*272b5eddSBrian Austin static int cs42l56_i2c_probe(struct i2c_client *i2c_client, 1236*272b5eddSBrian Austin const struct i2c_device_id *id) 1237*272b5eddSBrian Austin { 1238*272b5eddSBrian Austin struct cs42l56_private *cs42l56; 1239*272b5eddSBrian Austin struct cs42l56_platform_data *pdata = 1240*272b5eddSBrian Austin dev_get_platdata(&i2c_client->dev); 1241*272b5eddSBrian Austin int ret, i; 1242*272b5eddSBrian Austin unsigned int devid = 0; 1243*272b5eddSBrian Austin unsigned int alpha_rev, metal_rev; 1244*272b5eddSBrian Austin unsigned int reg; 1245*272b5eddSBrian Austin 1246*272b5eddSBrian Austin cs42l56 = devm_kzalloc(&i2c_client->dev, 1247*272b5eddSBrian Austin sizeof(struct cs42l56_private), 1248*272b5eddSBrian Austin GFP_KERNEL); 1249*272b5eddSBrian Austin if (cs42l56 == NULL) 1250*272b5eddSBrian Austin return -ENOMEM; 1251*272b5eddSBrian Austin cs42l56->dev = &i2c_client->dev; 1252*272b5eddSBrian Austin 1253*272b5eddSBrian Austin cs42l56->regmap = devm_regmap_init_i2c(i2c_client, &cs42l56_regmap); 1254*272b5eddSBrian Austin if (IS_ERR(cs42l56->regmap)) { 1255*272b5eddSBrian Austin ret = PTR_ERR(cs42l56->regmap); 1256*272b5eddSBrian Austin dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); 1257*272b5eddSBrian Austin return ret; 1258*272b5eddSBrian Austin } 1259*272b5eddSBrian Austin 1260*272b5eddSBrian Austin if (pdata) { 1261*272b5eddSBrian Austin cs42l56->pdata = *pdata; 1262*272b5eddSBrian Austin } else { 1263*272b5eddSBrian Austin pdata = devm_kzalloc(&i2c_client->dev, 1264*272b5eddSBrian Austin sizeof(struct cs42l56_platform_data), 1265*272b5eddSBrian Austin GFP_KERNEL); 1266*272b5eddSBrian Austin if (!pdata) { 1267*272b5eddSBrian Austin dev_err(&i2c_client->dev, 1268*272b5eddSBrian Austin "could not allocate pdata\n"); 1269*272b5eddSBrian Austin return -ENOMEM; 1270*272b5eddSBrian Austin } 1271*272b5eddSBrian Austin if (i2c_client->dev.of_node) { 1272*272b5eddSBrian Austin ret = cs42l56_handle_of_data(i2c_client, 1273*272b5eddSBrian Austin &cs42l56->pdata); 1274*272b5eddSBrian Austin if (ret != 0) 1275*272b5eddSBrian Austin return ret; 1276*272b5eddSBrian Austin } 1277*272b5eddSBrian Austin cs42l56->pdata = *pdata; 1278*272b5eddSBrian Austin } 1279*272b5eddSBrian Austin 1280*272b5eddSBrian Austin if (cs42l56->pdata.gpio_nreset) { 1281*272b5eddSBrian Austin ret = gpio_request_one(cs42l56->pdata.gpio_nreset, 1282*272b5eddSBrian Austin GPIOF_OUT_INIT_HIGH, "CS42L56 /RST"); 1283*272b5eddSBrian Austin if (ret < 0) { 1284*272b5eddSBrian Austin dev_err(&i2c_client->dev, 1285*272b5eddSBrian Austin "Failed to request /RST %d: %d\n", 1286*272b5eddSBrian Austin cs42l56->pdata.gpio_nreset, ret); 1287*272b5eddSBrian Austin return ret; 1288*272b5eddSBrian Austin } 1289*272b5eddSBrian Austin gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 0); 1290*272b5eddSBrian Austin gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 1); 1291*272b5eddSBrian Austin } 1292*272b5eddSBrian Austin 1293*272b5eddSBrian Austin 1294*272b5eddSBrian Austin i2c_set_clientdata(i2c_client, cs42l56); 1295*272b5eddSBrian Austin 1296*272b5eddSBrian Austin for (i = 0; i < ARRAY_SIZE(cs42l56->supplies); i++) 1297*272b5eddSBrian Austin cs42l56->supplies[i].supply = cs42l56_supply_names[i]; 1298*272b5eddSBrian Austin 1299*272b5eddSBrian Austin ret = devm_regulator_bulk_get(&i2c_client->dev, 1300*272b5eddSBrian Austin ARRAY_SIZE(cs42l56->supplies), 1301*272b5eddSBrian Austin cs42l56->supplies); 1302*272b5eddSBrian Austin if (ret != 0) { 1303*272b5eddSBrian Austin dev_err(&i2c_client->dev, 1304*272b5eddSBrian Austin "Failed to request supplies: %d\n", ret); 1305*272b5eddSBrian Austin return ret; 1306*272b5eddSBrian Austin } 1307*272b5eddSBrian Austin 1308*272b5eddSBrian Austin ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies), 1309*272b5eddSBrian Austin cs42l56->supplies); 1310*272b5eddSBrian Austin if (ret != 0) { 1311*272b5eddSBrian Austin dev_err(&i2c_client->dev, 1312*272b5eddSBrian Austin "Failed to enable supplies: %d\n", ret); 1313*272b5eddSBrian Austin return ret; 1314*272b5eddSBrian Austin } 1315*272b5eddSBrian Austin 1316*272b5eddSBrian Austin regcache_cache_bypass(cs42l56->regmap, true); 1317*272b5eddSBrian Austin 1318*272b5eddSBrian Austin ret = regmap_read(cs42l56->regmap, CS42L56_CHIP_ID_1, ®); 1319*272b5eddSBrian Austin devid = reg & CS42L56_CHIP_ID_MASK; 1320*272b5eddSBrian Austin if (devid != CS42L56_DEVID) { 1321*272b5eddSBrian Austin dev_err(&i2c_client->dev, 1322*272b5eddSBrian Austin "CS42L56 Device ID (%X). Expected %X\n", 1323*272b5eddSBrian Austin devid, CS42L56_DEVID); 1324*272b5eddSBrian Austin goto err_enable; 1325*272b5eddSBrian Austin } 1326*272b5eddSBrian Austin alpha_rev = reg & CS42L56_AREV_MASK; 1327*272b5eddSBrian Austin metal_rev = reg & CS42L56_MTLREV_MASK; 1328*272b5eddSBrian Austin 1329*272b5eddSBrian Austin dev_info(&i2c_client->dev, "Cirrus Logic CS42L56 "); 1330*272b5eddSBrian Austin dev_info(&i2c_client->dev, "Alpha Rev %X Metal Rev %X\n", 1331*272b5eddSBrian Austin alpha_rev, metal_rev); 1332*272b5eddSBrian Austin 1333*272b5eddSBrian Austin regcache_cache_bypass(cs42l56->regmap, false); 1334*272b5eddSBrian Austin 1335*272b5eddSBrian Austin if (cs42l56->pdata.ain1a_ref_cfg) 1336*272b5eddSBrian Austin regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, 1337*272b5eddSBrian Austin CS42L56_AIN1A_REF_MASK, 1); 1338*272b5eddSBrian Austin 1339*272b5eddSBrian Austin if (cs42l56->pdata.ain1b_ref_cfg) 1340*272b5eddSBrian Austin regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, 1341*272b5eddSBrian Austin CS42L56_AIN1B_REF_MASK, 1); 1342*272b5eddSBrian Austin 1343*272b5eddSBrian Austin if (cs42l56->pdata.ain2a_ref_cfg) 1344*272b5eddSBrian Austin regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, 1345*272b5eddSBrian Austin CS42L56_AIN2A_REF_MASK, 1); 1346*272b5eddSBrian Austin 1347*272b5eddSBrian Austin if (cs42l56->pdata.ain2b_ref_cfg) 1348*272b5eddSBrian Austin regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, 1349*272b5eddSBrian Austin CS42L56_AIN2B_REF_MASK, 1); 1350*272b5eddSBrian Austin 1351*272b5eddSBrian Austin if (cs42l56->pdata.micbias_lvl) 1352*272b5eddSBrian Austin regmap_update_bits(cs42l56->regmap, CS42L56_GAIN_BIAS_CTL, 1353*272b5eddSBrian Austin CS42L56_MIC_BIAS_MASK, 1354*272b5eddSBrian Austin cs42l56->pdata.micbias_lvl); 1355*272b5eddSBrian Austin 1356*272b5eddSBrian Austin if (cs42l56->pdata.chgfreq) 1357*272b5eddSBrian Austin regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL, 1358*272b5eddSBrian Austin CS42L56_CHRG_FREQ_MASK, 1359*272b5eddSBrian Austin cs42l56->pdata.chgfreq); 1360*272b5eddSBrian Austin 1361*272b5eddSBrian Austin if (cs42l56->pdata.hpfb_freq) 1362*272b5eddSBrian Austin regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL, 1363*272b5eddSBrian Austin CS42L56_HPFB_FREQ_MASK, 1364*272b5eddSBrian Austin cs42l56->pdata.hpfb_freq); 1365*272b5eddSBrian Austin 1366*272b5eddSBrian Austin if (cs42l56->pdata.hpfa_freq) 1367*272b5eddSBrian Austin regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL, 1368*272b5eddSBrian Austin CS42L56_HPFA_FREQ_MASK, 1369*272b5eddSBrian Austin cs42l56->pdata.hpfa_freq); 1370*272b5eddSBrian Austin 1371*272b5eddSBrian Austin if (cs42l56->pdata.adaptive_pwr) 1372*272b5eddSBrian Austin regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL, 1373*272b5eddSBrian Austin CS42L56_ADAPT_PWR_MASK, 1374*272b5eddSBrian Austin cs42l56->pdata.adaptive_pwr); 1375*272b5eddSBrian Austin 1376*272b5eddSBrian Austin ret = snd_soc_register_codec(&i2c_client->dev, 1377*272b5eddSBrian Austin &soc_codec_dev_cs42l56, &cs42l56_dai, 1); 1378*272b5eddSBrian Austin if (ret < 0) 1379*272b5eddSBrian Austin return ret; 1380*272b5eddSBrian Austin 1381*272b5eddSBrian Austin return 0; 1382*272b5eddSBrian Austin 1383*272b5eddSBrian Austin err_enable: 1384*272b5eddSBrian Austin regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies), 1385*272b5eddSBrian Austin cs42l56->supplies); 1386*272b5eddSBrian Austin return ret; 1387*272b5eddSBrian Austin } 1388*272b5eddSBrian Austin 1389*272b5eddSBrian Austin static int cs42l56_i2c_remove(struct i2c_client *client) 1390*272b5eddSBrian Austin { 1391*272b5eddSBrian Austin struct cs42l56_private *cs42l56 = i2c_get_clientdata(client); 1392*272b5eddSBrian Austin 1393*272b5eddSBrian Austin snd_soc_unregister_codec(&client->dev); 1394*272b5eddSBrian Austin regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies), 1395*272b5eddSBrian Austin cs42l56->supplies); 1396*272b5eddSBrian Austin return 0; 1397*272b5eddSBrian Austin } 1398*272b5eddSBrian Austin 1399*272b5eddSBrian Austin static const struct of_device_id cs42l56_of_match[] = { 1400*272b5eddSBrian Austin { .compatible = "cirrus,cs42l56", }, 1401*272b5eddSBrian Austin { } 1402*272b5eddSBrian Austin }; 1403*272b5eddSBrian Austin MODULE_DEVICE_TABLE(of, cs42l56_of_match); 1404*272b5eddSBrian Austin 1405*272b5eddSBrian Austin 1406*272b5eddSBrian Austin static const struct i2c_device_id cs42l56_id[] = { 1407*272b5eddSBrian Austin { "cs42l56", 0 }, 1408*272b5eddSBrian Austin { } 1409*272b5eddSBrian Austin }; 1410*272b5eddSBrian Austin MODULE_DEVICE_TABLE(i2c, cs42l56_id); 1411*272b5eddSBrian Austin 1412*272b5eddSBrian Austin static struct i2c_driver cs42l56_i2c_driver = { 1413*272b5eddSBrian Austin .driver = { 1414*272b5eddSBrian Austin .name = "cs42l56", 1415*272b5eddSBrian Austin .owner = THIS_MODULE, 1416*272b5eddSBrian Austin .of_match_table = cs42l56_of_match, 1417*272b5eddSBrian Austin }, 1418*272b5eddSBrian Austin .id_table = cs42l56_id, 1419*272b5eddSBrian Austin .probe = cs42l56_i2c_probe, 1420*272b5eddSBrian Austin .remove = cs42l56_i2c_remove, 1421*272b5eddSBrian Austin }; 1422*272b5eddSBrian Austin 1423*272b5eddSBrian Austin module_i2c_driver(cs42l56_i2c_driver); 1424*272b5eddSBrian Austin 1425*272b5eddSBrian Austin MODULE_DESCRIPTION("ASoC CS42L56 driver"); 1426*272b5eddSBrian Austin MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>"); 1427*272b5eddSBrian Austin MODULE_LICENSE("GPL"); 1428