Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: Add support for CS42L56 CODEC

This patch adds support for the Cirrus Logic Low Power Stereo I2C CODEC

Signed-off-by: Brian Austin <brian.austin@cirrus.com>
Signed-off-by: Mark Brown <broonie@linaro.org>

authored by

Brian Austin and committed by
Mark Brown
272b5edd eba17e68

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