18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Cirrus Logic CS42448/CS42888 Audio CODEC Digital Audio Interface (DAI) driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2014 Freescale Semiconductor, Inc. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Author: Nicolin Chen <Guangyu.Chen@freescale.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public License 98c2ecf20Sopenharmony_ci * version 2. This program is licensed "as is" without any warranty of any 108c2ecf20Sopenharmony_ci * kind, whether express or implied. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/clk.h> 148c2ecf20Sopenharmony_ci#include <linux/delay.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/of_device.h> 178c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 188c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 198c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 208c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 218c2ecf20Sopenharmony_ci#include <sound/soc.h> 228c2ecf20Sopenharmony_ci#include <sound/tlv.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "cs42xx8.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define CS42XX8_NUM_SUPPLIES 4 278c2ecf20Sopenharmony_cistatic const char *const cs42xx8_supply_names[CS42XX8_NUM_SUPPLIES] = { 288c2ecf20Sopenharmony_ci "VA", 298c2ecf20Sopenharmony_ci "VD", 308c2ecf20Sopenharmony_ci "VLS", 318c2ecf20Sopenharmony_ci "VLC", 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define CS42XX8_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 358c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S20_3LE | \ 368c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | \ 378c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* codec private data */ 408c2ecf20Sopenharmony_cistruct cs42xx8_priv { 418c2ecf20Sopenharmony_ci struct regulator_bulk_data supplies[CS42XX8_NUM_SUPPLIES]; 428c2ecf20Sopenharmony_ci const struct cs42xx8_driver_data *drvdata; 438c2ecf20Sopenharmony_ci struct regmap *regmap; 448c2ecf20Sopenharmony_ci struct clk *clk; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci bool slave_mode; 478c2ecf20Sopenharmony_ci unsigned long sysclk; 488c2ecf20Sopenharmony_ci u32 tx_channels; 498c2ecf20Sopenharmony_ci struct gpio_desc *gpiod_reset; 508c2ecf20Sopenharmony_ci u32 rate[2]; 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* -127.5dB to 0dB with step of 0.5dB */ 548c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); 558c2ecf20Sopenharmony_ci/* -64dB to 24dB with step of 0.5dB */ 568c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(adc_tlv, -6400, 50, 0); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic const char *const cs42xx8_adc_single[] = { "Differential", "Single-Ended" }; 598c2ecf20Sopenharmony_cistatic const char *const cs42xx8_szc[] = { "Immediate Change", "Zero Cross", 608c2ecf20Sopenharmony_ci "Soft Ramp", "Soft Ramp on Zero Cross" }; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic const struct soc_enum adc1_single_enum = 638c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 4, 2, cs42xx8_adc_single); 648c2ecf20Sopenharmony_cistatic const struct soc_enum adc2_single_enum = 658c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 3, 2, cs42xx8_adc_single); 668c2ecf20Sopenharmony_cistatic const struct soc_enum adc3_single_enum = 678c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 2, 2, cs42xx8_adc_single); 688c2ecf20Sopenharmony_cistatic const struct soc_enum dac_szc_enum = 698c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(CS42XX8_TXCTL, 5, 4, cs42xx8_szc); 708c2ecf20Sopenharmony_cistatic const struct soc_enum adc_szc_enum = 718c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(CS42XX8_TXCTL, 0, 4, cs42xx8_szc); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cs42xx8_snd_controls[] = { 748c2ecf20Sopenharmony_ci SOC_DOUBLE_R_TLV("DAC1 Playback Volume", CS42XX8_VOLAOUT1, 758c2ecf20Sopenharmony_ci CS42XX8_VOLAOUT2, 0, 0xff, 1, dac_tlv), 768c2ecf20Sopenharmony_ci SOC_DOUBLE_R_TLV("DAC2 Playback Volume", CS42XX8_VOLAOUT3, 778c2ecf20Sopenharmony_ci CS42XX8_VOLAOUT4, 0, 0xff, 1, dac_tlv), 788c2ecf20Sopenharmony_ci SOC_DOUBLE_R_TLV("DAC3 Playback Volume", CS42XX8_VOLAOUT5, 798c2ecf20Sopenharmony_ci CS42XX8_VOLAOUT6, 0, 0xff, 1, dac_tlv), 808c2ecf20Sopenharmony_ci SOC_DOUBLE_R_TLV("DAC4 Playback Volume", CS42XX8_VOLAOUT7, 818c2ecf20Sopenharmony_ci CS42XX8_VOLAOUT8, 0, 0xff, 1, dac_tlv), 828c2ecf20Sopenharmony_ci SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", CS42XX8_VOLAIN1, 838c2ecf20Sopenharmony_ci CS42XX8_VOLAIN2, 0, -0x80, 0x30, 7, 0, adc_tlv), 848c2ecf20Sopenharmony_ci SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", CS42XX8_VOLAIN3, 858c2ecf20Sopenharmony_ci CS42XX8_VOLAIN4, 0, -0x80, 0x30, 7, 0, adc_tlv), 868c2ecf20Sopenharmony_ci SOC_DOUBLE("DAC1 Invert Switch", CS42XX8_DACINV, 0, 1, 1, 0), 878c2ecf20Sopenharmony_ci SOC_DOUBLE("DAC2 Invert Switch", CS42XX8_DACINV, 2, 3, 1, 0), 888c2ecf20Sopenharmony_ci SOC_DOUBLE("DAC3 Invert Switch", CS42XX8_DACINV, 4, 5, 1, 0), 898c2ecf20Sopenharmony_ci SOC_DOUBLE("DAC4 Invert Switch", CS42XX8_DACINV, 6, 7, 1, 0), 908c2ecf20Sopenharmony_ci SOC_DOUBLE("ADC1 Invert Switch", CS42XX8_ADCINV, 0, 1, 1, 0), 918c2ecf20Sopenharmony_ci SOC_DOUBLE("ADC2 Invert Switch", CS42XX8_ADCINV, 2, 3, 1, 0), 928c2ecf20Sopenharmony_ci SOC_SINGLE("ADC High-Pass Filter Switch", CS42XX8_ADCCTL, 7, 1, 1), 938c2ecf20Sopenharmony_ci SOC_SINGLE("DAC De-emphasis Switch", CS42XX8_ADCCTL, 5, 1, 0), 948c2ecf20Sopenharmony_ci SOC_ENUM("ADC1 Single Ended Mode Switch", adc1_single_enum), 958c2ecf20Sopenharmony_ci SOC_ENUM("ADC2 Single Ended Mode Switch", adc2_single_enum), 968c2ecf20Sopenharmony_ci SOC_SINGLE("DAC Single Volume Control Switch", CS42XX8_TXCTL, 7, 1, 0), 978c2ecf20Sopenharmony_ci SOC_ENUM("DAC Soft Ramp & Zero Cross Control Switch", dac_szc_enum), 988c2ecf20Sopenharmony_ci SOC_SINGLE("DAC Auto Mute Switch", CS42XX8_TXCTL, 4, 1, 0), 998c2ecf20Sopenharmony_ci SOC_SINGLE("Mute ADC Serial Port Switch", CS42XX8_TXCTL, 3, 1, 0), 1008c2ecf20Sopenharmony_ci SOC_SINGLE("ADC Single Volume Control Switch", CS42XX8_TXCTL, 2, 1, 0), 1018c2ecf20Sopenharmony_ci SOC_ENUM("ADC Soft Ramp & Zero Cross Control Switch", adc_szc_enum), 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cs42xx8_adc3_snd_controls[] = { 1058c2ecf20Sopenharmony_ci SOC_DOUBLE_R_S_TLV("ADC3 Capture Volume", CS42XX8_VOLAIN5, 1068c2ecf20Sopenharmony_ci CS42XX8_VOLAIN6, 0, -0x80, 0x30, 7, 0, adc_tlv), 1078c2ecf20Sopenharmony_ci SOC_DOUBLE("ADC3 Invert Switch", CS42XX8_ADCINV, 4, 5, 1, 0), 1088c2ecf20Sopenharmony_ci SOC_ENUM("ADC3 Single Ended Mode Switch", adc3_single_enum), 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget cs42xx8_dapm_widgets[] = { 1128c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC("DAC1", "Playback", CS42XX8_PWRCTL, 1, 1), 1138c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC("DAC2", "Playback", CS42XX8_PWRCTL, 2, 1), 1148c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC("DAC3", "Playback", CS42XX8_PWRCTL, 3, 1), 1158c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC("DAC4", "Playback", CS42XX8_PWRCTL, 4, 1), 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("AOUT1L"), 1188c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("AOUT1R"), 1198c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("AOUT2L"), 1208c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("AOUT2R"), 1218c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("AOUT3L"), 1228c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("AOUT3R"), 1238c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("AOUT4L"), 1248c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("AOUT4R"), 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci SND_SOC_DAPM_ADC("ADC1", "Capture", CS42XX8_PWRCTL, 5, 1), 1278c2ecf20Sopenharmony_ci SND_SOC_DAPM_ADC("ADC2", "Capture", CS42XX8_PWRCTL, 6, 1), 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("AIN1L"), 1308c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("AIN1R"), 1318c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("AIN2L"), 1328c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("AIN2R"), 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("PWR", CS42XX8_PWRCTL, 0, 1, NULL, 0), 1358c2ecf20Sopenharmony_ci}; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget cs42xx8_adc3_dapm_widgets[] = { 1388c2ecf20Sopenharmony_ci SND_SOC_DAPM_ADC("ADC3", "Capture", CS42XX8_PWRCTL, 7, 1), 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("AIN3L"), 1418c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("AIN3R"), 1428c2ecf20Sopenharmony_ci}; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route cs42xx8_dapm_routes[] = { 1458c2ecf20Sopenharmony_ci /* Playback */ 1468c2ecf20Sopenharmony_ci { "AOUT1L", NULL, "DAC1" }, 1478c2ecf20Sopenharmony_ci { "AOUT1R", NULL, "DAC1" }, 1488c2ecf20Sopenharmony_ci { "DAC1", NULL, "PWR" }, 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci { "AOUT2L", NULL, "DAC2" }, 1518c2ecf20Sopenharmony_ci { "AOUT2R", NULL, "DAC2" }, 1528c2ecf20Sopenharmony_ci { "DAC2", NULL, "PWR" }, 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci { "AOUT3L", NULL, "DAC3" }, 1558c2ecf20Sopenharmony_ci { "AOUT3R", NULL, "DAC3" }, 1568c2ecf20Sopenharmony_ci { "DAC3", NULL, "PWR" }, 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci { "AOUT4L", NULL, "DAC4" }, 1598c2ecf20Sopenharmony_ci { "AOUT4R", NULL, "DAC4" }, 1608c2ecf20Sopenharmony_ci { "DAC4", NULL, "PWR" }, 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* Capture */ 1638c2ecf20Sopenharmony_ci { "ADC1", NULL, "AIN1L" }, 1648c2ecf20Sopenharmony_ci { "ADC1", NULL, "AIN1R" }, 1658c2ecf20Sopenharmony_ci { "ADC1", NULL, "PWR" }, 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci { "ADC2", NULL, "AIN2L" }, 1688c2ecf20Sopenharmony_ci { "ADC2", NULL, "AIN2R" }, 1698c2ecf20Sopenharmony_ci { "ADC2", NULL, "PWR" }, 1708c2ecf20Sopenharmony_ci}; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = { 1738c2ecf20Sopenharmony_ci /* Capture */ 1748c2ecf20Sopenharmony_ci { "ADC3", NULL, "AIN3L" }, 1758c2ecf20Sopenharmony_ci { "ADC3", NULL, "AIN3R" }, 1768c2ecf20Sopenharmony_ci { "ADC3", NULL, "PWR" }, 1778c2ecf20Sopenharmony_ci}; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistruct cs42xx8_ratios { 1808c2ecf20Sopenharmony_ci unsigned int mfreq; 1818c2ecf20Sopenharmony_ci unsigned int min_mclk; 1828c2ecf20Sopenharmony_ci unsigned int max_mclk; 1838c2ecf20Sopenharmony_ci unsigned int ratio[3]; 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/* 1878c2ecf20Sopenharmony_ci * According to reference mannual, define the cs42xx8_ratio struct 1888c2ecf20Sopenharmony_ci * MFreq2 | MFreq1 | MFreq0 | Description | SSM | DSM | QSM | 1898c2ecf20Sopenharmony_ci * 0 | 0 | 0 |1.029MHz to 12.8MHz | 256 | 128 | 64 | 1908c2ecf20Sopenharmony_ci * 0 | 0 | 1 |1.536MHz to 19.2MHz | 384 | 192 | 96 | 1918c2ecf20Sopenharmony_ci * 0 | 1 | 0 |2.048MHz to 25.6MHz | 512 | 256 | 128 | 1928c2ecf20Sopenharmony_ci * 0 | 1 | 1 |3.072MHz to 38.4MHz | 768 | 384 | 192 | 1938c2ecf20Sopenharmony_ci * 1 | x | x |4.096MHz to 51.2MHz |1024 | 512 | 256 | 1948c2ecf20Sopenharmony_ci */ 1958c2ecf20Sopenharmony_cistatic const struct cs42xx8_ratios cs42xx8_ratios[] = { 1968c2ecf20Sopenharmony_ci { 0, 1029000, 12800000, {256, 128, 64} }, 1978c2ecf20Sopenharmony_ci { 2, 1536000, 19200000, {384, 192, 96} }, 1988c2ecf20Sopenharmony_ci { 4, 2048000, 25600000, {512, 256, 128} }, 1998c2ecf20Sopenharmony_ci { 6, 3072000, 38400000, {768, 384, 192} }, 2008c2ecf20Sopenharmony_ci { 8, 4096000, 51200000, {1024, 512, 256} }, 2018c2ecf20Sopenharmony_ci}; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai, 2048c2ecf20Sopenharmony_ci int clk_id, unsigned int freq, int dir) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 2078c2ecf20Sopenharmony_ci struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci cs42xx8->sysclk = freq; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return 0; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai, 2158c2ecf20Sopenharmony_ci unsigned int format) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 2188c2ecf20Sopenharmony_ci struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component); 2198c2ecf20Sopenharmony_ci u32 val; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* Set DAI format */ 2228c2ecf20Sopenharmony_ci switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { 2238c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 2248c2ecf20Sopenharmony_ci val = CS42XX8_INTF_DAC_DIF_LEFTJ | CS42XX8_INTF_ADC_DIF_LEFTJ; 2258c2ecf20Sopenharmony_ci break; 2268c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 2278c2ecf20Sopenharmony_ci val = CS42XX8_INTF_DAC_DIF_I2S | CS42XX8_INTF_ADC_DIF_I2S; 2288c2ecf20Sopenharmony_ci break; 2298c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 2308c2ecf20Sopenharmony_ci val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ; 2318c2ecf20Sopenharmony_ci break; 2328c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 2338c2ecf20Sopenharmony_ci val = CS42XX8_INTF_DAC_DIF_TDM | CS42XX8_INTF_ADC_DIF_TDM; 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci default: 2368c2ecf20Sopenharmony_ci dev_err(component->dev, "unsupported dai format\n"); 2378c2ecf20Sopenharmony_ci return -EINVAL; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci regmap_update_bits(cs42xx8->regmap, CS42XX8_INTF, 2418c2ecf20Sopenharmony_ci CS42XX8_INTF_DAC_DIF_MASK | 2428c2ecf20Sopenharmony_ci CS42XX8_INTF_ADC_DIF_MASK, val); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* Set master/slave audio interface */ 2458c2ecf20Sopenharmony_ci switch (format & SND_SOC_DAIFMT_MASTER_MASK) { 2468c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBS_CFS: 2478c2ecf20Sopenharmony_ci cs42xx8->slave_mode = true; 2488c2ecf20Sopenharmony_ci break; 2498c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFM: 2508c2ecf20Sopenharmony_ci cs42xx8->slave_mode = false; 2518c2ecf20Sopenharmony_ci break; 2528c2ecf20Sopenharmony_ci default: 2538c2ecf20Sopenharmony_ci dev_err(component->dev, "unsupported master/slave mode\n"); 2548c2ecf20Sopenharmony_ci return -EINVAL; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return 0; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic int cs42xx8_hw_params(struct snd_pcm_substream *substream, 2618c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 2628c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 2658c2ecf20Sopenharmony_ci struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component); 2668c2ecf20Sopenharmony_ci bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; 2678c2ecf20Sopenharmony_ci u32 ratio[2]; 2688c2ecf20Sopenharmony_ci u32 rate[2]; 2698c2ecf20Sopenharmony_ci u32 fm[2]; 2708c2ecf20Sopenharmony_ci u32 i, val, mask; 2718c2ecf20Sopenharmony_ci bool condition1, condition2; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (tx) 2748c2ecf20Sopenharmony_ci cs42xx8->tx_channels = params_channels(params); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci rate[tx] = params_rate(params); 2778c2ecf20Sopenharmony_ci rate[!tx] = cs42xx8->rate[!tx]; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci ratio[tx] = rate[tx] > 0 ? cs42xx8->sysclk / rate[tx] : 0; 2808c2ecf20Sopenharmony_ci ratio[!tx] = rate[!tx] > 0 ? cs42xx8->sysclk / rate[!tx] : 0; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* Get functional mode for tx and rx according to rate */ 2838c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 2848c2ecf20Sopenharmony_ci if (cs42xx8->slave_mode) { 2858c2ecf20Sopenharmony_ci fm[i] = CS42XX8_FM_AUTO; 2868c2ecf20Sopenharmony_ci } else { 2878c2ecf20Sopenharmony_ci if (rate[i] < 50000) { 2888c2ecf20Sopenharmony_ci fm[i] = CS42XX8_FM_SINGLE; 2898c2ecf20Sopenharmony_ci } else if (rate[i] > 50000 && rate[i] < 100000) { 2908c2ecf20Sopenharmony_ci fm[i] = CS42XX8_FM_DOUBLE; 2918c2ecf20Sopenharmony_ci } else if (rate[i] > 100000 && rate[i] < 200000) { 2928c2ecf20Sopenharmony_ci fm[i] = CS42XX8_FM_QUAD; 2938c2ecf20Sopenharmony_ci } else { 2948c2ecf20Sopenharmony_ci dev_err(component->dev, 2958c2ecf20Sopenharmony_ci "unsupported sample rate\n"); 2968c2ecf20Sopenharmony_ci return -EINVAL; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) { 3028c2ecf20Sopenharmony_ci /* Is the ratio[tx] valid ? */ 3038c2ecf20Sopenharmony_ci condition1 = ((fm[tx] == CS42XX8_FM_AUTO) ? 3048c2ecf20Sopenharmony_ci (cs42xx8_ratios[i].ratio[0] == ratio[tx] || 3058c2ecf20Sopenharmony_ci cs42xx8_ratios[i].ratio[1] == ratio[tx] || 3068c2ecf20Sopenharmony_ci cs42xx8_ratios[i].ratio[2] == ratio[tx]) : 3078c2ecf20Sopenharmony_ci (cs42xx8_ratios[i].ratio[fm[tx]] == ratio[tx])) && 3088c2ecf20Sopenharmony_ci cs42xx8->sysclk >= cs42xx8_ratios[i].min_mclk && 3098c2ecf20Sopenharmony_ci cs42xx8->sysclk <= cs42xx8_ratios[i].max_mclk; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (!ratio[tx]) 3128c2ecf20Sopenharmony_ci condition1 = true; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci /* Is the ratio[!tx] valid ? */ 3158c2ecf20Sopenharmony_ci condition2 = ((fm[!tx] == CS42XX8_FM_AUTO) ? 3168c2ecf20Sopenharmony_ci (cs42xx8_ratios[i].ratio[0] == ratio[!tx] || 3178c2ecf20Sopenharmony_ci cs42xx8_ratios[i].ratio[1] == ratio[!tx] || 3188c2ecf20Sopenharmony_ci cs42xx8_ratios[i].ratio[2] == ratio[!tx]) : 3198c2ecf20Sopenharmony_ci (cs42xx8_ratios[i].ratio[fm[!tx]] == ratio[!tx])); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (!ratio[!tx]) 3228c2ecf20Sopenharmony_ci condition2 = true; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* 3258c2ecf20Sopenharmony_ci * Both ratio[tx] and ratio[!tx] is valid, then we get 3268c2ecf20Sopenharmony_ci * a proper MFreq. 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_ci if (condition1 && condition2) 3298c2ecf20Sopenharmony_ci break; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(cs42xx8_ratios)) { 3338c2ecf20Sopenharmony_ci dev_err(component->dev, "unsupported sysclk ratio\n"); 3348c2ecf20Sopenharmony_ci return -EINVAL; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci cs42xx8->rate[tx] = params_rate(params); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci mask = CS42XX8_FUNCMOD_MFREQ_MASK; 3408c2ecf20Sopenharmony_ci val = cs42xx8_ratios[i].mfreq; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD, 3438c2ecf20Sopenharmony_ci CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask, 3448c2ecf20Sopenharmony_ci CS42XX8_FUNCMOD_xC_FM(tx, fm[tx]) | val); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic int cs42xx8_hw_free(struct snd_pcm_substream *substream, 3508c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 3538c2ecf20Sopenharmony_ci struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component); 3548c2ecf20Sopenharmony_ci bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* Clear stored rate */ 3578c2ecf20Sopenharmony_ci cs42xx8->rate[tx] = 0; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD, 3608c2ecf20Sopenharmony_ci CS42XX8_FUNCMOD_xC_FM_MASK(tx), 3618c2ecf20Sopenharmony_ci CS42XX8_FUNCMOD_xC_FM(tx, CS42XX8_FM_AUTO)); 3628c2ecf20Sopenharmony_ci return 0; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic int cs42xx8_mute(struct snd_soc_dai *dai, int mute, int direction) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 3688c2ecf20Sopenharmony_ci struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component); 3698c2ecf20Sopenharmony_ci u8 dac_unmute = cs42xx8->tx_channels ? 3708c2ecf20Sopenharmony_ci ~((0x1 << cs42xx8->tx_channels) - 1) : 0; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE, 3738c2ecf20Sopenharmony_ci mute ? CS42XX8_DACMUTE_ALL : dac_unmute); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci return 0; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops cs42xx8_dai_ops = { 3798c2ecf20Sopenharmony_ci .set_fmt = cs42xx8_set_dai_fmt, 3808c2ecf20Sopenharmony_ci .set_sysclk = cs42xx8_set_dai_sysclk, 3818c2ecf20Sopenharmony_ci .hw_params = cs42xx8_hw_params, 3828c2ecf20Sopenharmony_ci .hw_free = cs42xx8_hw_free, 3838c2ecf20Sopenharmony_ci .mute_stream = cs42xx8_mute, 3848c2ecf20Sopenharmony_ci .no_capture_mute = 1, 3858c2ecf20Sopenharmony_ci}; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver cs42xx8_dai = { 3888c2ecf20Sopenharmony_ci .playback = { 3898c2ecf20Sopenharmony_ci .stream_name = "Playback", 3908c2ecf20Sopenharmony_ci .channels_min = 1, 3918c2ecf20Sopenharmony_ci .channels_max = 8, 3928c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_192000, 3938c2ecf20Sopenharmony_ci .formats = CS42XX8_FORMATS, 3948c2ecf20Sopenharmony_ci }, 3958c2ecf20Sopenharmony_ci .capture = { 3968c2ecf20Sopenharmony_ci .stream_name = "Capture", 3978c2ecf20Sopenharmony_ci .channels_min = 1, 3988c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_192000, 3998c2ecf20Sopenharmony_ci .formats = CS42XX8_FORMATS, 4008c2ecf20Sopenharmony_ci }, 4018c2ecf20Sopenharmony_ci .ops = &cs42xx8_dai_ops, 4028c2ecf20Sopenharmony_ci}; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic const struct reg_default cs42xx8_reg[] = { 4058c2ecf20Sopenharmony_ci { 0x02, 0x00 }, /* Power Control */ 4068c2ecf20Sopenharmony_ci { 0x03, 0xF0 }, /* Functional Mode */ 4078c2ecf20Sopenharmony_ci { 0x04, 0x46 }, /* Interface Formats */ 4088c2ecf20Sopenharmony_ci { 0x05, 0x00 }, /* ADC Control & DAC De-Emphasis */ 4098c2ecf20Sopenharmony_ci { 0x06, 0x10 }, /* Transition Control */ 4108c2ecf20Sopenharmony_ci { 0x07, 0x00 }, /* DAC Channel Mute */ 4118c2ecf20Sopenharmony_ci { 0x08, 0x00 }, /* Volume Control AOUT1 */ 4128c2ecf20Sopenharmony_ci { 0x09, 0x00 }, /* Volume Control AOUT2 */ 4138c2ecf20Sopenharmony_ci { 0x0a, 0x00 }, /* Volume Control AOUT3 */ 4148c2ecf20Sopenharmony_ci { 0x0b, 0x00 }, /* Volume Control AOUT4 */ 4158c2ecf20Sopenharmony_ci { 0x0c, 0x00 }, /* Volume Control AOUT5 */ 4168c2ecf20Sopenharmony_ci { 0x0d, 0x00 }, /* Volume Control AOUT6 */ 4178c2ecf20Sopenharmony_ci { 0x0e, 0x00 }, /* Volume Control AOUT7 */ 4188c2ecf20Sopenharmony_ci { 0x0f, 0x00 }, /* Volume Control AOUT8 */ 4198c2ecf20Sopenharmony_ci { 0x10, 0x00 }, /* DAC Channel Invert */ 4208c2ecf20Sopenharmony_ci { 0x11, 0x00 }, /* Volume Control AIN1 */ 4218c2ecf20Sopenharmony_ci { 0x12, 0x00 }, /* Volume Control AIN2 */ 4228c2ecf20Sopenharmony_ci { 0x13, 0x00 }, /* Volume Control AIN3 */ 4238c2ecf20Sopenharmony_ci { 0x14, 0x00 }, /* Volume Control AIN4 */ 4248c2ecf20Sopenharmony_ci { 0x15, 0x00 }, /* Volume Control AIN5 */ 4258c2ecf20Sopenharmony_ci { 0x16, 0x00 }, /* Volume Control AIN6 */ 4268c2ecf20Sopenharmony_ci { 0x17, 0x00 }, /* ADC Channel Invert */ 4278c2ecf20Sopenharmony_ci { 0x18, 0x00 }, /* Status Control */ 4288c2ecf20Sopenharmony_ci { 0x1a, 0x00 }, /* Status Mask */ 4298c2ecf20Sopenharmony_ci { 0x1b, 0x00 }, /* MUTEC Pin Control */ 4308c2ecf20Sopenharmony_ci}; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic bool cs42xx8_volatile_register(struct device *dev, unsigned int reg) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci switch (reg) { 4358c2ecf20Sopenharmony_ci case CS42XX8_STATUS: 4368c2ecf20Sopenharmony_ci return true; 4378c2ecf20Sopenharmony_ci default: 4388c2ecf20Sopenharmony_ci return false; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic bool cs42xx8_writeable_register(struct device *dev, unsigned int reg) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci switch (reg) { 4458c2ecf20Sopenharmony_ci case CS42XX8_CHIPID: 4468c2ecf20Sopenharmony_ci case CS42XX8_STATUS: 4478c2ecf20Sopenharmony_ci return false; 4488c2ecf20Sopenharmony_ci default: 4498c2ecf20Sopenharmony_ci return true; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ciconst struct regmap_config cs42xx8_regmap_config = { 4548c2ecf20Sopenharmony_ci .reg_bits = 8, 4558c2ecf20Sopenharmony_ci .val_bits = 8, 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci .max_register = CS42XX8_LASTREG, 4588c2ecf20Sopenharmony_ci .reg_defaults = cs42xx8_reg, 4598c2ecf20Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(cs42xx8_reg), 4608c2ecf20Sopenharmony_ci .volatile_reg = cs42xx8_volatile_register, 4618c2ecf20Sopenharmony_ci .writeable_reg = cs42xx8_writeable_register, 4628c2ecf20Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 4638c2ecf20Sopenharmony_ci}; 4648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cs42xx8_regmap_config); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cistatic int cs42xx8_component_probe(struct snd_soc_component *component) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component); 4698c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci switch (cs42xx8->drvdata->num_adcs) { 4728c2ecf20Sopenharmony_ci case 3: 4738c2ecf20Sopenharmony_ci snd_soc_add_component_controls(component, cs42xx8_adc3_snd_controls, 4748c2ecf20Sopenharmony_ci ARRAY_SIZE(cs42xx8_adc3_snd_controls)); 4758c2ecf20Sopenharmony_ci snd_soc_dapm_new_controls(dapm, cs42xx8_adc3_dapm_widgets, 4768c2ecf20Sopenharmony_ci ARRAY_SIZE(cs42xx8_adc3_dapm_widgets)); 4778c2ecf20Sopenharmony_ci snd_soc_dapm_add_routes(dapm, cs42xx8_adc3_dapm_routes, 4788c2ecf20Sopenharmony_ci ARRAY_SIZE(cs42xx8_adc3_dapm_routes)); 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci default: 4818c2ecf20Sopenharmony_ci break; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci /* Mute all DAC channels */ 4858c2ecf20Sopenharmony_ci regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE, CS42XX8_DACMUTE_ALL); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci return 0; 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver cs42xx8_driver = { 4918c2ecf20Sopenharmony_ci .probe = cs42xx8_component_probe, 4928c2ecf20Sopenharmony_ci .controls = cs42xx8_snd_controls, 4938c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(cs42xx8_snd_controls), 4948c2ecf20Sopenharmony_ci .dapm_widgets = cs42xx8_dapm_widgets, 4958c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(cs42xx8_dapm_widgets), 4968c2ecf20Sopenharmony_ci .dapm_routes = cs42xx8_dapm_routes, 4978c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(cs42xx8_dapm_routes), 4988c2ecf20Sopenharmony_ci .use_pmdown_time = 1, 4998c2ecf20Sopenharmony_ci .endianness = 1, 5008c2ecf20Sopenharmony_ci .non_legacy_dai_naming = 1, 5018c2ecf20Sopenharmony_ci}; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ciconst struct cs42xx8_driver_data cs42448_data = { 5048c2ecf20Sopenharmony_ci .name = "cs42448", 5058c2ecf20Sopenharmony_ci .num_adcs = 3, 5068c2ecf20Sopenharmony_ci}; 5078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cs42448_data); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ciconst struct cs42xx8_driver_data cs42888_data = { 5108c2ecf20Sopenharmony_ci .name = "cs42888", 5118c2ecf20Sopenharmony_ci .num_adcs = 2, 5128c2ecf20Sopenharmony_ci}; 5138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cs42888_data); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ciconst struct of_device_id cs42xx8_of_match[] = { 5168c2ecf20Sopenharmony_ci { .compatible = "cirrus,cs42448", .data = &cs42448_data, }, 5178c2ecf20Sopenharmony_ci { .compatible = "cirrus,cs42888", .data = &cs42888_data, }, 5188c2ecf20Sopenharmony_ci { /* sentinel */ } 5198c2ecf20Sopenharmony_ci}; 5208c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, cs42xx8_of_match); 5218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cs42xx8_of_match); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ciint cs42xx8_probe(struct device *dev, struct regmap *regmap) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci const struct of_device_id *of_id; 5268c2ecf20Sopenharmony_ci struct cs42xx8_priv *cs42xx8; 5278c2ecf20Sopenharmony_ci int ret, val, i; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if (IS_ERR(regmap)) { 5308c2ecf20Sopenharmony_ci ret = PTR_ERR(regmap); 5318c2ecf20Sopenharmony_ci dev_err(dev, "failed to allocate regmap: %d\n", ret); 5328c2ecf20Sopenharmony_ci return ret; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci cs42xx8 = devm_kzalloc(dev, sizeof(*cs42xx8), GFP_KERNEL); 5368c2ecf20Sopenharmony_ci if (cs42xx8 == NULL) 5378c2ecf20Sopenharmony_ci return -ENOMEM; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci cs42xx8->regmap = regmap; 5408c2ecf20Sopenharmony_ci dev_set_drvdata(dev, cs42xx8); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci of_id = of_match_device(cs42xx8_of_match, dev); 5438c2ecf20Sopenharmony_ci if (of_id) 5448c2ecf20Sopenharmony_ci cs42xx8->drvdata = of_id->data; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if (!cs42xx8->drvdata) { 5478c2ecf20Sopenharmony_ci dev_err(dev, "failed to find driver data\n"); 5488c2ecf20Sopenharmony_ci return -EINVAL; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci cs42xx8->gpiod_reset = devm_gpiod_get_optional(dev, "reset", 5528c2ecf20Sopenharmony_ci GPIOD_OUT_HIGH); 5538c2ecf20Sopenharmony_ci if (IS_ERR(cs42xx8->gpiod_reset)) 5548c2ecf20Sopenharmony_ci return PTR_ERR(cs42xx8->gpiod_reset); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 0); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci cs42xx8->clk = devm_clk_get(dev, "mclk"); 5598c2ecf20Sopenharmony_ci if (IS_ERR(cs42xx8->clk)) { 5608c2ecf20Sopenharmony_ci dev_err(dev, "failed to get the clock: %ld\n", 5618c2ecf20Sopenharmony_ci PTR_ERR(cs42xx8->clk)); 5628c2ecf20Sopenharmony_ci return -EINVAL; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci cs42xx8->sysclk = clk_get_rate(cs42xx8->clk); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cs42xx8->supplies); i++) 5688c2ecf20Sopenharmony_ci cs42xx8->supplies[i].supply = cs42xx8_supply_names[i]; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci ret = devm_regulator_bulk_get(dev, 5718c2ecf20Sopenharmony_ci ARRAY_SIZE(cs42xx8->supplies), cs42xx8->supplies); 5728c2ecf20Sopenharmony_ci if (ret) { 5738c2ecf20Sopenharmony_ci dev_err(dev, "failed to request supplies: %d\n", ret); 5748c2ecf20Sopenharmony_ci return ret; 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies), 5788c2ecf20Sopenharmony_ci cs42xx8->supplies); 5798c2ecf20Sopenharmony_ci if (ret) { 5808c2ecf20Sopenharmony_ci dev_err(dev, "failed to enable supplies: %d\n", ret); 5818c2ecf20Sopenharmony_ci return ret; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci /* Make sure hardware reset done */ 5858c2ecf20Sopenharmony_ci msleep(5); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* Validate the chip ID */ 5888c2ecf20Sopenharmony_ci ret = regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val); 5898c2ecf20Sopenharmony_ci if (ret < 0) { 5908c2ecf20Sopenharmony_ci dev_err(dev, "failed to get device ID, ret = %d", ret); 5918c2ecf20Sopenharmony_ci goto err_enable; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci /* The top four bits of the chip ID should be 0000 */ 5958c2ecf20Sopenharmony_ci if (((val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4) != 0x00) { 5968c2ecf20Sopenharmony_ci dev_err(dev, "unmatched chip ID: %d\n", 5978c2ecf20Sopenharmony_ci (val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4); 5988c2ecf20Sopenharmony_ci ret = -EINVAL; 5998c2ecf20Sopenharmony_ci goto err_enable; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci dev_info(dev, "found device, revision %X\n", 6038c2ecf20Sopenharmony_ci val & CS42XX8_CHIPID_REV_ID_MASK); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci cs42xx8_dai.name = cs42xx8->drvdata->name; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci /* Each adc supports stereo input */ 6088c2ecf20Sopenharmony_ci cs42xx8_dai.capture.channels_max = cs42xx8->drvdata->num_adcs * 2; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(dev, &cs42xx8_driver, &cs42xx8_dai, 1); 6118c2ecf20Sopenharmony_ci if (ret) { 6128c2ecf20Sopenharmony_ci dev_err(dev, "failed to register component:%d\n", ret); 6138c2ecf20Sopenharmony_ci goto err_enable; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci regcache_cache_only(cs42xx8->regmap, true); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cierr_enable: 6198c2ecf20Sopenharmony_ci regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies), 6208c2ecf20Sopenharmony_ci cs42xx8->supplies); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci return ret; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cs42xx8_probe); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 6278c2ecf20Sopenharmony_cistatic int cs42xx8_runtime_resume(struct device *dev) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev); 6308c2ecf20Sopenharmony_ci int ret; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci ret = clk_prepare_enable(cs42xx8->clk); 6338c2ecf20Sopenharmony_ci if (ret) { 6348c2ecf20Sopenharmony_ci dev_err(dev, "failed to enable mclk: %d\n", ret); 6358c2ecf20Sopenharmony_ci return ret; 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 0); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies), 6418c2ecf20Sopenharmony_ci cs42xx8->supplies); 6428c2ecf20Sopenharmony_ci if (ret) { 6438c2ecf20Sopenharmony_ci dev_err(dev, "failed to enable supplies: %d\n", ret); 6448c2ecf20Sopenharmony_ci goto err_clk; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* Make sure hardware reset done */ 6488c2ecf20Sopenharmony_ci msleep(5); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci regcache_cache_only(cs42xx8->regmap, false); 6518c2ecf20Sopenharmony_ci regcache_mark_dirty(cs42xx8->regmap); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci ret = regcache_sync(cs42xx8->regmap); 6548c2ecf20Sopenharmony_ci if (ret) { 6558c2ecf20Sopenharmony_ci dev_err(dev, "failed to sync regmap: %d\n", ret); 6568c2ecf20Sopenharmony_ci goto err_bulk; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci return 0; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_cierr_bulk: 6628c2ecf20Sopenharmony_ci regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies), 6638c2ecf20Sopenharmony_ci cs42xx8->supplies); 6648c2ecf20Sopenharmony_cierr_clk: 6658c2ecf20Sopenharmony_ci clk_disable_unprepare(cs42xx8->clk); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci return ret; 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_cistatic int cs42xx8_runtime_suspend(struct device *dev) 6718c2ecf20Sopenharmony_ci{ 6728c2ecf20Sopenharmony_ci struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci regcache_cache_only(cs42xx8->regmap, true); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies), 6778c2ecf20Sopenharmony_ci cs42xx8->supplies); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 1); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci clk_disable_unprepare(cs42xx8->clk); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci return 0; 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci#endif 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ciconst struct dev_pm_ops cs42xx8_pm = { 6888c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 6898c2ecf20Sopenharmony_ci pm_runtime_force_resume) 6908c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL) 6918c2ecf20Sopenharmony_ci}; 6928c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cs42xx8_pm); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec Driver"); 6958c2ecf20Sopenharmony_ciMODULE_AUTHOR("Freescale Semiconductor, Inc."); 6968c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 697