18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for the PCM512x CODECs 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Mark Brown <broonie@kernel.org> 68c2ecf20Sopenharmony_ci * Copyright 2014 Linaro Ltd 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/clk.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 158c2ecf20Sopenharmony_ci#include <linux/regmap.h> 168c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 178c2ecf20Sopenharmony_ci#include <linux/gcd.h> 188c2ecf20Sopenharmony_ci#include <sound/soc.h> 198c2ecf20Sopenharmony_ci#include <sound/soc-dapm.h> 208c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 218c2ecf20Sopenharmony_ci#include <sound/tlv.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "pcm512x.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define PCM512x_NUM_SUPPLIES 3 268c2ecf20Sopenharmony_cistatic const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = { 278c2ecf20Sopenharmony_ci "AVDD", 288c2ecf20Sopenharmony_ci "DVDD", 298c2ecf20Sopenharmony_ci "CPVDD", 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistruct pcm512x_priv { 338c2ecf20Sopenharmony_ci struct regmap *regmap; 348c2ecf20Sopenharmony_ci struct clk *sclk; 358c2ecf20Sopenharmony_ci struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES]; 368c2ecf20Sopenharmony_ci struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES]; 378c2ecf20Sopenharmony_ci int fmt; 388c2ecf20Sopenharmony_ci int pll_in; 398c2ecf20Sopenharmony_ci int pll_out; 408c2ecf20Sopenharmony_ci int pll_r; 418c2ecf20Sopenharmony_ci int pll_j; 428c2ecf20Sopenharmony_ci int pll_d; 438c2ecf20Sopenharmony_ci int pll_p; 448c2ecf20Sopenharmony_ci unsigned long real_pll; 458c2ecf20Sopenharmony_ci unsigned long overclock_pll; 468c2ecf20Sopenharmony_ci unsigned long overclock_dac; 478c2ecf20Sopenharmony_ci unsigned long overclock_dsp; 488c2ecf20Sopenharmony_ci int mute; 498c2ecf20Sopenharmony_ci struct mutex mutex; 508c2ecf20Sopenharmony_ci unsigned int bclk_ratio; 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* 548c2ecf20Sopenharmony_ci * We can't use the same notifier block for more than one supply and 558c2ecf20Sopenharmony_ci * there's no way I can see to get from a callback to the caller 568c2ecf20Sopenharmony_ci * except container_of(). 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_ci#define PCM512x_REGULATOR_EVENT(n) \ 598c2ecf20Sopenharmony_cistatic int pcm512x_regulator_event_##n(struct notifier_block *nb, \ 608c2ecf20Sopenharmony_ci unsigned long event, void *data) \ 618c2ecf20Sopenharmony_ci{ \ 628c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = container_of(nb, struct pcm512x_priv, \ 638c2ecf20Sopenharmony_ci supply_nb[n]); \ 648c2ecf20Sopenharmony_ci if (event & REGULATOR_EVENT_DISABLE) { \ 658c2ecf20Sopenharmony_ci regcache_mark_dirty(pcm512x->regmap); \ 668c2ecf20Sopenharmony_ci regcache_cache_only(pcm512x->regmap, true); \ 678c2ecf20Sopenharmony_ci } \ 688c2ecf20Sopenharmony_ci return 0; \ 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ciPCM512x_REGULATOR_EVENT(0) 728c2ecf20Sopenharmony_ciPCM512x_REGULATOR_EVENT(1) 738c2ecf20Sopenharmony_ciPCM512x_REGULATOR_EVENT(2) 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic const struct reg_default pcm512x_reg_defaults[] = { 768c2ecf20Sopenharmony_ci { PCM512x_RESET, 0x00 }, 778c2ecf20Sopenharmony_ci { PCM512x_POWER, 0x00 }, 788c2ecf20Sopenharmony_ci { PCM512x_MUTE, 0x00 }, 798c2ecf20Sopenharmony_ci { PCM512x_DSP, 0x00 }, 808c2ecf20Sopenharmony_ci { PCM512x_PLL_REF, 0x00 }, 818c2ecf20Sopenharmony_ci { PCM512x_DAC_REF, 0x00 }, 828c2ecf20Sopenharmony_ci { PCM512x_DAC_ROUTING, 0x11 }, 838c2ecf20Sopenharmony_ci { PCM512x_DSP_PROGRAM, 0x01 }, 848c2ecf20Sopenharmony_ci { PCM512x_CLKDET, 0x00 }, 858c2ecf20Sopenharmony_ci { PCM512x_AUTO_MUTE, 0x00 }, 868c2ecf20Sopenharmony_ci { PCM512x_ERROR_DETECT, 0x00 }, 878c2ecf20Sopenharmony_ci { PCM512x_DIGITAL_VOLUME_1, 0x00 }, 888c2ecf20Sopenharmony_ci { PCM512x_DIGITAL_VOLUME_2, 0x30 }, 898c2ecf20Sopenharmony_ci { PCM512x_DIGITAL_VOLUME_3, 0x30 }, 908c2ecf20Sopenharmony_ci { PCM512x_DIGITAL_MUTE_1, 0x22 }, 918c2ecf20Sopenharmony_ci { PCM512x_DIGITAL_MUTE_2, 0x00 }, 928c2ecf20Sopenharmony_ci { PCM512x_DIGITAL_MUTE_3, 0x07 }, 938c2ecf20Sopenharmony_ci { PCM512x_OUTPUT_AMPLITUDE, 0x00 }, 948c2ecf20Sopenharmony_ci { PCM512x_ANALOG_GAIN_CTRL, 0x00 }, 958c2ecf20Sopenharmony_ci { PCM512x_UNDERVOLTAGE_PROT, 0x00 }, 968c2ecf20Sopenharmony_ci { PCM512x_ANALOG_MUTE_CTRL, 0x00 }, 978c2ecf20Sopenharmony_ci { PCM512x_ANALOG_GAIN_BOOST, 0x00 }, 988c2ecf20Sopenharmony_ci { PCM512x_VCOM_CTRL_1, 0x00 }, 998c2ecf20Sopenharmony_ci { PCM512x_VCOM_CTRL_2, 0x01 }, 1008c2ecf20Sopenharmony_ci { PCM512x_BCLK_LRCLK_CFG, 0x00 }, 1018c2ecf20Sopenharmony_ci { PCM512x_MASTER_MODE, 0x7c }, 1028c2ecf20Sopenharmony_ci { PCM512x_GPIO_DACIN, 0x00 }, 1038c2ecf20Sopenharmony_ci { PCM512x_GPIO_PLLIN, 0x00 }, 1048c2ecf20Sopenharmony_ci { PCM512x_SYNCHRONIZE, 0x10 }, 1058c2ecf20Sopenharmony_ci { PCM512x_PLL_COEFF_0, 0x00 }, 1068c2ecf20Sopenharmony_ci { PCM512x_PLL_COEFF_1, 0x00 }, 1078c2ecf20Sopenharmony_ci { PCM512x_PLL_COEFF_2, 0x00 }, 1088c2ecf20Sopenharmony_ci { PCM512x_PLL_COEFF_3, 0x00 }, 1098c2ecf20Sopenharmony_ci { PCM512x_PLL_COEFF_4, 0x00 }, 1108c2ecf20Sopenharmony_ci { PCM512x_DSP_CLKDIV, 0x00 }, 1118c2ecf20Sopenharmony_ci { PCM512x_DAC_CLKDIV, 0x00 }, 1128c2ecf20Sopenharmony_ci { PCM512x_NCP_CLKDIV, 0x00 }, 1138c2ecf20Sopenharmony_ci { PCM512x_OSR_CLKDIV, 0x00 }, 1148c2ecf20Sopenharmony_ci { PCM512x_MASTER_CLKDIV_1, 0x00 }, 1158c2ecf20Sopenharmony_ci { PCM512x_MASTER_CLKDIV_2, 0x00 }, 1168c2ecf20Sopenharmony_ci { PCM512x_FS_SPEED_MODE, 0x00 }, 1178c2ecf20Sopenharmony_ci { PCM512x_IDAC_1, 0x01 }, 1188c2ecf20Sopenharmony_ci { PCM512x_IDAC_2, 0x00 }, 1198c2ecf20Sopenharmony_ci}; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic bool pcm512x_readable(struct device *dev, unsigned int reg) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci switch (reg) { 1248c2ecf20Sopenharmony_ci case PCM512x_RESET: 1258c2ecf20Sopenharmony_ci case PCM512x_POWER: 1268c2ecf20Sopenharmony_ci case PCM512x_MUTE: 1278c2ecf20Sopenharmony_ci case PCM512x_PLL_EN: 1288c2ecf20Sopenharmony_ci case PCM512x_SPI_MISO_FUNCTION: 1298c2ecf20Sopenharmony_ci case PCM512x_DSP: 1308c2ecf20Sopenharmony_ci case PCM512x_GPIO_EN: 1318c2ecf20Sopenharmony_ci case PCM512x_BCLK_LRCLK_CFG: 1328c2ecf20Sopenharmony_ci case PCM512x_DSP_GPIO_INPUT: 1338c2ecf20Sopenharmony_ci case PCM512x_MASTER_MODE: 1348c2ecf20Sopenharmony_ci case PCM512x_PLL_REF: 1358c2ecf20Sopenharmony_ci case PCM512x_DAC_REF: 1368c2ecf20Sopenharmony_ci case PCM512x_GPIO_DACIN: 1378c2ecf20Sopenharmony_ci case PCM512x_GPIO_PLLIN: 1388c2ecf20Sopenharmony_ci case PCM512x_SYNCHRONIZE: 1398c2ecf20Sopenharmony_ci case PCM512x_PLL_COEFF_0: 1408c2ecf20Sopenharmony_ci case PCM512x_PLL_COEFF_1: 1418c2ecf20Sopenharmony_ci case PCM512x_PLL_COEFF_2: 1428c2ecf20Sopenharmony_ci case PCM512x_PLL_COEFF_3: 1438c2ecf20Sopenharmony_ci case PCM512x_PLL_COEFF_4: 1448c2ecf20Sopenharmony_ci case PCM512x_DSP_CLKDIV: 1458c2ecf20Sopenharmony_ci case PCM512x_DAC_CLKDIV: 1468c2ecf20Sopenharmony_ci case PCM512x_NCP_CLKDIV: 1478c2ecf20Sopenharmony_ci case PCM512x_OSR_CLKDIV: 1488c2ecf20Sopenharmony_ci case PCM512x_MASTER_CLKDIV_1: 1498c2ecf20Sopenharmony_ci case PCM512x_MASTER_CLKDIV_2: 1508c2ecf20Sopenharmony_ci case PCM512x_FS_SPEED_MODE: 1518c2ecf20Sopenharmony_ci case PCM512x_IDAC_1: 1528c2ecf20Sopenharmony_ci case PCM512x_IDAC_2: 1538c2ecf20Sopenharmony_ci case PCM512x_ERROR_DETECT: 1548c2ecf20Sopenharmony_ci case PCM512x_I2S_1: 1558c2ecf20Sopenharmony_ci case PCM512x_I2S_2: 1568c2ecf20Sopenharmony_ci case PCM512x_DAC_ROUTING: 1578c2ecf20Sopenharmony_ci case PCM512x_DSP_PROGRAM: 1588c2ecf20Sopenharmony_ci case PCM512x_CLKDET: 1598c2ecf20Sopenharmony_ci case PCM512x_AUTO_MUTE: 1608c2ecf20Sopenharmony_ci case PCM512x_DIGITAL_VOLUME_1: 1618c2ecf20Sopenharmony_ci case PCM512x_DIGITAL_VOLUME_2: 1628c2ecf20Sopenharmony_ci case PCM512x_DIGITAL_VOLUME_3: 1638c2ecf20Sopenharmony_ci case PCM512x_DIGITAL_MUTE_1: 1648c2ecf20Sopenharmony_ci case PCM512x_DIGITAL_MUTE_2: 1658c2ecf20Sopenharmony_ci case PCM512x_DIGITAL_MUTE_3: 1668c2ecf20Sopenharmony_ci case PCM512x_GPIO_OUTPUT_1: 1678c2ecf20Sopenharmony_ci case PCM512x_GPIO_OUTPUT_2: 1688c2ecf20Sopenharmony_ci case PCM512x_GPIO_OUTPUT_3: 1698c2ecf20Sopenharmony_ci case PCM512x_GPIO_OUTPUT_4: 1708c2ecf20Sopenharmony_ci case PCM512x_GPIO_OUTPUT_5: 1718c2ecf20Sopenharmony_ci case PCM512x_GPIO_OUTPUT_6: 1728c2ecf20Sopenharmony_ci case PCM512x_GPIO_CONTROL_1: 1738c2ecf20Sopenharmony_ci case PCM512x_GPIO_CONTROL_2: 1748c2ecf20Sopenharmony_ci case PCM512x_OVERFLOW: 1758c2ecf20Sopenharmony_ci case PCM512x_RATE_DET_1: 1768c2ecf20Sopenharmony_ci case PCM512x_RATE_DET_2: 1778c2ecf20Sopenharmony_ci case PCM512x_RATE_DET_3: 1788c2ecf20Sopenharmony_ci case PCM512x_RATE_DET_4: 1798c2ecf20Sopenharmony_ci case PCM512x_CLOCK_STATUS: 1808c2ecf20Sopenharmony_ci case PCM512x_ANALOG_MUTE_DET: 1818c2ecf20Sopenharmony_ci case PCM512x_GPIN: 1828c2ecf20Sopenharmony_ci case PCM512x_DIGITAL_MUTE_DET: 1838c2ecf20Sopenharmony_ci case PCM512x_OUTPUT_AMPLITUDE: 1848c2ecf20Sopenharmony_ci case PCM512x_ANALOG_GAIN_CTRL: 1858c2ecf20Sopenharmony_ci case PCM512x_UNDERVOLTAGE_PROT: 1868c2ecf20Sopenharmony_ci case PCM512x_ANALOG_MUTE_CTRL: 1878c2ecf20Sopenharmony_ci case PCM512x_ANALOG_GAIN_BOOST: 1888c2ecf20Sopenharmony_ci case PCM512x_VCOM_CTRL_1: 1898c2ecf20Sopenharmony_ci case PCM512x_VCOM_CTRL_2: 1908c2ecf20Sopenharmony_ci case PCM512x_CRAM_CTRL: 1918c2ecf20Sopenharmony_ci case PCM512x_FLEX_A: 1928c2ecf20Sopenharmony_ci case PCM512x_FLEX_B: 1938c2ecf20Sopenharmony_ci return true; 1948c2ecf20Sopenharmony_ci default: 1958c2ecf20Sopenharmony_ci /* There are 256 raw register addresses */ 1968c2ecf20Sopenharmony_ci return reg < 0xff; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic bool pcm512x_volatile(struct device *dev, unsigned int reg) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci switch (reg) { 2038c2ecf20Sopenharmony_ci case PCM512x_PLL_EN: 2048c2ecf20Sopenharmony_ci case PCM512x_OVERFLOW: 2058c2ecf20Sopenharmony_ci case PCM512x_RATE_DET_1: 2068c2ecf20Sopenharmony_ci case PCM512x_RATE_DET_2: 2078c2ecf20Sopenharmony_ci case PCM512x_RATE_DET_3: 2088c2ecf20Sopenharmony_ci case PCM512x_RATE_DET_4: 2098c2ecf20Sopenharmony_ci case PCM512x_CLOCK_STATUS: 2108c2ecf20Sopenharmony_ci case PCM512x_ANALOG_MUTE_DET: 2118c2ecf20Sopenharmony_ci case PCM512x_GPIN: 2128c2ecf20Sopenharmony_ci case PCM512x_DIGITAL_MUTE_DET: 2138c2ecf20Sopenharmony_ci case PCM512x_CRAM_CTRL: 2148c2ecf20Sopenharmony_ci return true; 2158c2ecf20Sopenharmony_ci default: 2168c2ecf20Sopenharmony_ci /* There are 256 raw register addresses */ 2178c2ecf20Sopenharmony_ci return reg < 0xff; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int pcm512x_overclock_pll_get(struct snd_kcontrol *kcontrol, 2228c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 2258c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = pcm512x->overclock_pll; 2288c2ecf20Sopenharmony_ci return 0; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol, 2328c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 2358c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci switch (snd_soc_component_get_bias_level(component)) { 2388c2ecf20Sopenharmony_ci case SND_SOC_BIAS_OFF: 2398c2ecf20Sopenharmony_ci case SND_SOC_BIAS_STANDBY: 2408c2ecf20Sopenharmony_ci break; 2418c2ecf20Sopenharmony_ci default: 2428c2ecf20Sopenharmony_ci return -EBUSY; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci pcm512x->overclock_pll = ucontrol->value.integer.value[0]; 2468c2ecf20Sopenharmony_ci return 0; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int pcm512x_overclock_dsp_get(struct snd_kcontrol *kcontrol, 2508c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 2538c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = pcm512x->overclock_dsp; 2568c2ecf20Sopenharmony_ci return 0; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol, 2608c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 2638c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci switch (snd_soc_component_get_bias_level(component)) { 2668c2ecf20Sopenharmony_ci case SND_SOC_BIAS_OFF: 2678c2ecf20Sopenharmony_ci case SND_SOC_BIAS_STANDBY: 2688c2ecf20Sopenharmony_ci break; 2698c2ecf20Sopenharmony_ci default: 2708c2ecf20Sopenharmony_ci return -EBUSY; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci pcm512x->overclock_dsp = ucontrol->value.integer.value[0]; 2748c2ecf20Sopenharmony_ci return 0; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic int pcm512x_overclock_dac_get(struct snd_kcontrol *kcontrol, 2788c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 2818c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = pcm512x->overclock_dac; 2848c2ecf20Sopenharmony_ci return 0; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic int pcm512x_overclock_dac_put(struct snd_kcontrol *kcontrol, 2888c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 2918c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci switch (snd_soc_component_get_bias_level(component)) { 2948c2ecf20Sopenharmony_ci case SND_SOC_BIAS_OFF: 2958c2ecf20Sopenharmony_ci case SND_SOC_BIAS_STANDBY: 2968c2ecf20Sopenharmony_ci break; 2978c2ecf20Sopenharmony_ci default: 2988c2ecf20Sopenharmony_ci return -EBUSY; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci pcm512x->overclock_dac = ucontrol->value.integer.value[0]; 3028c2ecf20Sopenharmony_ci return 0; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1); 3068c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0); 3078c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic const char * const pcm512x_dsp_program_texts[] = { 3108c2ecf20Sopenharmony_ci "FIR interpolation with de-emphasis", 3118c2ecf20Sopenharmony_ci "Low latency IIR with de-emphasis", 3128c2ecf20Sopenharmony_ci "High attenuation with de-emphasis", 3138c2ecf20Sopenharmony_ci "Fixed process flow", 3148c2ecf20Sopenharmony_ci "Ringing-less low latency FIR", 3158c2ecf20Sopenharmony_ci}; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic const unsigned int pcm512x_dsp_program_values[] = { 3188c2ecf20Sopenharmony_ci 1, 3198c2ecf20Sopenharmony_ci 2, 3208c2ecf20Sopenharmony_ci 3, 3218c2ecf20Sopenharmony_ci 5, 3228c2ecf20Sopenharmony_ci 7, 3238c2ecf20Sopenharmony_ci}; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic SOC_VALUE_ENUM_SINGLE_DECL(pcm512x_dsp_program, 3268c2ecf20Sopenharmony_ci PCM512x_DSP_PROGRAM, 0, 0x1f, 3278c2ecf20Sopenharmony_ci pcm512x_dsp_program_texts, 3288c2ecf20Sopenharmony_ci pcm512x_dsp_program_values); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic const char * const pcm512x_clk_missing_text[] = { 3318c2ecf20Sopenharmony_ci "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s" 3328c2ecf20Sopenharmony_ci}; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic const struct soc_enum pcm512x_clk_missing = 3358c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(PCM512x_CLKDET, 0, 8, pcm512x_clk_missing_text); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic const char * const pcm512x_autom_text[] = { 3388c2ecf20Sopenharmony_ci "21ms", "106ms", "213ms", "533ms", "1.07s", "2.13s", "5.33s", "10.66s" 3398c2ecf20Sopenharmony_ci}; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic const struct soc_enum pcm512x_autom_l = 3428c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATML_SHIFT, 8, 3438c2ecf20Sopenharmony_ci pcm512x_autom_text); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic const struct soc_enum pcm512x_autom_r = 3468c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATMR_SHIFT, 8, 3478c2ecf20Sopenharmony_ci pcm512x_autom_text); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic const char * const pcm512x_ramp_rate_text[] = { 3508c2ecf20Sopenharmony_ci "1 sample/update", "2 samples/update", "4 samples/update", 3518c2ecf20Sopenharmony_ci "Immediate" 3528c2ecf20Sopenharmony_ci}; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic const struct soc_enum pcm512x_vndf = 3558c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDF_SHIFT, 4, 3568c2ecf20Sopenharmony_ci pcm512x_ramp_rate_text); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic const struct soc_enum pcm512x_vnuf = 3598c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUF_SHIFT, 4, 3608c2ecf20Sopenharmony_ci pcm512x_ramp_rate_text); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic const struct soc_enum pcm512x_vedf = 3638c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDF_SHIFT, 4, 3648c2ecf20Sopenharmony_ci pcm512x_ramp_rate_text); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic const char * const pcm512x_ramp_step_text[] = { 3678c2ecf20Sopenharmony_ci "4dB/step", "2dB/step", "1dB/step", "0.5dB/step" 3688c2ecf20Sopenharmony_ci}; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic const struct soc_enum pcm512x_vnds = 3718c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDS_SHIFT, 4, 3728c2ecf20Sopenharmony_ci pcm512x_ramp_step_text); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic const struct soc_enum pcm512x_vnus = 3758c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUS_SHIFT, 4, 3768c2ecf20Sopenharmony_ci pcm512x_ramp_step_text); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic const struct soc_enum pcm512x_veds = 3798c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4, 3808c2ecf20Sopenharmony_ci pcm512x_ramp_step_text); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic int pcm512x_update_mute(struct pcm512x_priv *pcm512x) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci return regmap_update_bits( 3858c2ecf20Sopenharmony_ci pcm512x->regmap, PCM512x_MUTE, PCM512x_RQML | PCM512x_RQMR, 3868c2ecf20Sopenharmony_ci (!!(pcm512x->mute & 0x5) << PCM512x_RQML_SHIFT) 3878c2ecf20Sopenharmony_ci | (!!(pcm512x->mute & 0x3) << PCM512x_RQMR_SHIFT)); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol, 3918c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 3948c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci mutex_lock(&pcm512x->mutex); 3978c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4); 3988c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2); 3998c2ecf20Sopenharmony_ci mutex_unlock(&pcm512x->mutex); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci return 0; 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol, 4058c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 4088c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); 4098c2ecf20Sopenharmony_ci int ret, changed = 0; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci mutex_lock(&pcm512x->mutex); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) { 4148c2ecf20Sopenharmony_ci pcm512x->mute ^= 0x4; 4158c2ecf20Sopenharmony_ci changed = 1; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci if ((pcm512x->mute & 0x2) == (ucontrol->value.integer.value[1] << 1)) { 4188c2ecf20Sopenharmony_ci pcm512x->mute ^= 0x2; 4198c2ecf20Sopenharmony_ci changed = 1; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci if (changed) { 4238c2ecf20Sopenharmony_ci ret = pcm512x_update_mute(pcm512x); 4248c2ecf20Sopenharmony_ci if (ret != 0) { 4258c2ecf20Sopenharmony_ci dev_err(component->dev, 4268c2ecf20Sopenharmony_ci "Failed to update digital mute: %d\n", ret); 4278c2ecf20Sopenharmony_ci mutex_unlock(&pcm512x->mutex); 4288c2ecf20Sopenharmony_ci return ret; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci mutex_unlock(&pcm512x->mutex); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci return changed; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new pcm512x_controls[] = { 4388c2ecf20Sopenharmony_ciSOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2, 4398c2ecf20Sopenharmony_ci PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), 4408c2ecf20Sopenharmony_ciSOC_DOUBLE_TLV("Analogue Playback Volume", PCM512x_ANALOG_GAIN_CTRL, 4418c2ecf20Sopenharmony_ci PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), 4428c2ecf20Sopenharmony_ciSOC_DOUBLE_TLV("Analogue Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, 4438c2ecf20Sopenharmony_ci PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv), 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4468c2ecf20Sopenharmony_ci .name = "Digital Playback Switch", 4478c2ecf20Sopenharmony_ci .index = 0, 4488c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 4498c2ecf20Sopenharmony_ci .info = snd_ctl_boolean_stereo_info, 4508c2ecf20Sopenharmony_ci .get = pcm512x_digital_playback_switch_get, 4518c2ecf20Sopenharmony_ci .put = pcm512x_digital_playback_switch_put 4528c2ecf20Sopenharmony_ci}, 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ciSOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), 4558c2ecf20Sopenharmony_ciSOC_ENUM("DSP Program", pcm512x_dsp_program), 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ciSOC_ENUM("Clock Missing Period", pcm512x_clk_missing), 4588c2ecf20Sopenharmony_ciSOC_ENUM("Auto Mute Time Left", pcm512x_autom_l), 4598c2ecf20Sopenharmony_ciSOC_ENUM("Auto Mute Time Right", pcm512x_autom_r), 4608c2ecf20Sopenharmony_ciSOC_SINGLE("Auto Mute Mono Switch", PCM512x_DIGITAL_MUTE_3, 4618c2ecf20Sopenharmony_ci PCM512x_ACTL_SHIFT, 1, 0), 4628c2ecf20Sopenharmony_ciSOC_DOUBLE("Auto Mute Switch", PCM512x_DIGITAL_MUTE_3, PCM512x_AMLE_SHIFT, 4638c2ecf20Sopenharmony_ci PCM512x_AMRE_SHIFT, 1, 0), 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ciSOC_ENUM("Volume Ramp Down Rate", pcm512x_vndf), 4668c2ecf20Sopenharmony_ciSOC_ENUM("Volume Ramp Down Step", pcm512x_vnds), 4678c2ecf20Sopenharmony_ciSOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf), 4688c2ecf20Sopenharmony_ciSOC_ENUM("Volume Ramp Up Step", pcm512x_vnus), 4698c2ecf20Sopenharmony_ciSOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf), 4708c2ecf20Sopenharmony_ciSOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds), 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ciSOC_SINGLE_EXT("Max Overclock PLL", SND_SOC_NOPM, 0, 20, 0, 4738c2ecf20Sopenharmony_ci pcm512x_overclock_pll_get, pcm512x_overclock_pll_put), 4748c2ecf20Sopenharmony_ciSOC_SINGLE_EXT("Max Overclock DSP", SND_SOC_NOPM, 0, 40, 0, 4758c2ecf20Sopenharmony_ci pcm512x_overclock_dsp_get, pcm512x_overclock_dsp_put), 4768c2ecf20Sopenharmony_ciSOC_SINGLE_EXT("Max Overclock DAC", SND_SOC_NOPM, 0, 40, 0, 4778c2ecf20Sopenharmony_ci pcm512x_overclock_dac_get, pcm512x_overclock_dac_put), 4788c2ecf20Sopenharmony_ci}; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = { 4818c2ecf20Sopenharmony_ciSND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), 4828c2ecf20Sopenharmony_ciSND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("OUTL"), 4858c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("OUTR"), 4868c2ecf20Sopenharmony_ci}; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route pcm512x_dapm_routes[] = { 4898c2ecf20Sopenharmony_ci { "DACL", NULL, "Playback" }, 4908c2ecf20Sopenharmony_ci { "DACR", NULL, "Playback" }, 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci { "OUTL", NULL, "DACL" }, 4938c2ecf20Sopenharmony_ci { "OUTR", NULL, "DACR" }, 4948c2ecf20Sopenharmony_ci}; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic unsigned long pcm512x_pll_max(struct pcm512x_priv *pcm512x) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci return 25000000 + 25000000 * pcm512x->overclock_pll / 100; 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic unsigned long pcm512x_dsp_max(struct pcm512x_priv *pcm512x) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci return 50000000 + 50000000 * pcm512x->overclock_dsp / 100; 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic unsigned long pcm512x_dac_max(struct pcm512x_priv *pcm512x, 5078c2ecf20Sopenharmony_ci unsigned long rate) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci return rate + rate * pcm512x->overclock_dac / 100; 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic unsigned long pcm512x_sck_max(struct pcm512x_priv *pcm512x) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci if (!pcm512x->pll_out) 5158c2ecf20Sopenharmony_ci return 25000000; 5168c2ecf20Sopenharmony_ci return pcm512x_pll_max(pcm512x); 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic unsigned long pcm512x_ncp_target(struct pcm512x_priv *pcm512x, 5208c2ecf20Sopenharmony_ci unsigned long dac_rate) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci /* 5238c2ecf20Sopenharmony_ci * If the DAC is not actually overclocked, use the good old 5248c2ecf20Sopenharmony_ci * NCP target rate... 5258c2ecf20Sopenharmony_ci */ 5268c2ecf20Sopenharmony_ci if (dac_rate <= 6144000) 5278c2ecf20Sopenharmony_ci return 1536000; 5288c2ecf20Sopenharmony_ci /* 5298c2ecf20Sopenharmony_ci * ...but if the DAC is in fact overclocked, bump the NCP target 5308c2ecf20Sopenharmony_ci * rate to get the recommended dividers even when overclocking. 5318c2ecf20Sopenharmony_ci */ 5328c2ecf20Sopenharmony_ci return pcm512x_dac_max(pcm512x, 1536000); 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic const u32 pcm512x_dai_rates[] = { 5368c2ecf20Sopenharmony_ci 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 5378c2ecf20Sopenharmony_ci 88200, 96000, 176400, 192000, 384000, 5388c2ecf20Sopenharmony_ci}; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list constraints_slave = { 5418c2ecf20Sopenharmony_ci .count = ARRAY_SIZE(pcm512x_dai_rates), 5428c2ecf20Sopenharmony_ci .list = pcm512x_dai_rates, 5438c2ecf20Sopenharmony_ci}; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params, 5468c2ecf20Sopenharmony_ci struct snd_pcm_hw_rule *rule) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = rule->private; 5498c2ecf20Sopenharmony_ci struct snd_interval ranges[2]; 5508c2ecf20Sopenharmony_ci int frame_size; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci frame_size = snd_soc_params_to_frame_size(params); 5538c2ecf20Sopenharmony_ci if (frame_size < 0) 5548c2ecf20Sopenharmony_ci return frame_size; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci switch (frame_size) { 5578c2ecf20Sopenharmony_ci case 32: 5588c2ecf20Sopenharmony_ci /* No hole when the frame size is 32. */ 5598c2ecf20Sopenharmony_ci return 0; 5608c2ecf20Sopenharmony_ci case 48: 5618c2ecf20Sopenharmony_ci case 64: 5628c2ecf20Sopenharmony_ci /* There is only one hole in the range of supported 5638c2ecf20Sopenharmony_ci * rates, but it moves with the frame size. 5648c2ecf20Sopenharmony_ci */ 5658c2ecf20Sopenharmony_ci memset(ranges, 0, sizeof(ranges)); 5668c2ecf20Sopenharmony_ci ranges[0].min = 8000; 5678c2ecf20Sopenharmony_ci ranges[0].max = pcm512x_sck_max(pcm512x) / frame_size / 2; 5688c2ecf20Sopenharmony_ci ranges[1].min = DIV_ROUND_UP(16000000, frame_size); 5698c2ecf20Sopenharmony_ci ranges[1].max = 384000; 5708c2ecf20Sopenharmony_ci break; 5718c2ecf20Sopenharmony_ci default: 5728c2ecf20Sopenharmony_ci return -EINVAL; 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci return snd_interval_ranges(hw_param_interval(params, rule->var), 5768c2ecf20Sopenharmony_ci ARRAY_SIZE(ranges), ranges, 0); 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic int pcm512x_dai_startup_master(struct snd_pcm_substream *substream, 5808c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 5838c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); 5848c2ecf20Sopenharmony_ci struct device *dev = dai->dev; 5858c2ecf20Sopenharmony_ci struct snd_pcm_hw_constraint_ratnums *constraints_no_pll; 5868c2ecf20Sopenharmony_ci struct snd_ratnum *rats_no_pll; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (IS_ERR(pcm512x->sclk)) { 5898c2ecf20Sopenharmony_ci dev_err(dev, "Need SCLK for master mode: %ld\n", 5908c2ecf20Sopenharmony_ci PTR_ERR(pcm512x->sclk)); 5918c2ecf20Sopenharmony_ci return PTR_ERR(pcm512x->sclk); 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (pcm512x->pll_out) 5958c2ecf20Sopenharmony_ci return snd_pcm_hw_rule_add(substream->runtime, 0, 5968c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, 5978c2ecf20Sopenharmony_ci pcm512x_hw_rule_rate, 5988c2ecf20Sopenharmony_ci pcm512x, 5998c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_FRAME_BITS, 6008c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, -1); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci constraints_no_pll = devm_kzalloc(dev, sizeof(*constraints_no_pll), 6038c2ecf20Sopenharmony_ci GFP_KERNEL); 6048c2ecf20Sopenharmony_ci if (!constraints_no_pll) 6058c2ecf20Sopenharmony_ci return -ENOMEM; 6068c2ecf20Sopenharmony_ci constraints_no_pll->nrats = 1; 6078c2ecf20Sopenharmony_ci rats_no_pll = devm_kzalloc(dev, sizeof(*rats_no_pll), GFP_KERNEL); 6088c2ecf20Sopenharmony_ci if (!rats_no_pll) 6098c2ecf20Sopenharmony_ci return -ENOMEM; 6108c2ecf20Sopenharmony_ci constraints_no_pll->rats = rats_no_pll; 6118c2ecf20Sopenharmony_ci rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64; 6128c2ecf20Sopenharmony_ci rats_no_pll->den_min = 1; 6138c2ecf20Sopenharmony_ci rats_no_pll->den_max = 128; 6148c2ecf20Sopenharmony_ci rats_no_pll->den_step = 1; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci return snd_pcm_hw_constraint_ratnums(substream->runtime, 0, 6178c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, 6188c2ecf20Sopenharmony_ci constraints_no_pll); 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic int pcm512x_dai_startup_slave(struct snd_pcm_substream *substream, 6228c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 6258c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); 6268c2ecf20Sopenharmony_ci struct device *dev = dai->dev; 6278c2ecf20Sopenharmony_ci struct regmap *regmap = pcm512x->regmap; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (IS_ERR(pcm512x->sclk)) { 6308c2ecf20Sopenharmony_ci dev_info(dev, "No SCLK, using BCLK: %ld\n", 6318c2ecf20Sopenharmony_ci PTR_ERR(pcm512x->sclk)); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci /* Disable reporting of missing SCLK as an error */ 6348c2ecf20Sopenharmony_ci regmap_update_bits(regmap, PCM512x_ERROR_DETECT, 6358c2ecf20Sopenharmony_ci PCM512x_IDCH, PCM512x_IDCH); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci /* Switch PLL input to BCLK */ 6388c2ecf20Sopenharmony_ci regmap_update_bits(regmap, PCM512x_PLL_REF, 6398c2ecf20Sopenharmony_ci PCM512x_SREF, PCM512x_SREF_BCK); 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci return snd_pcm_hw_constraint_list(substream->runtime, 0, 6438c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, 6448c2ecf20Sopenharmony_ci &constraints_slave); 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic int pcm512x_dai_startup(struct snd_pcm_substream *substream, 6488c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 6518c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) { 6548c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFM: 6558c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFS: 6568c2ecf20Sopenharmony_ci return pcm512x_dai_startup_master(substream, dai); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBS_CFS: 6598c2ecf20Sopenharmony_ci return pcm512x_dai_startup_slave(substream, dai); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci default: 6628c2ecf20Sopenharmony_ci return -EINVAL; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_cistatic int pcm512x_set_bias_level(struct snd_soc_component *component, 6678c2ecf20Sopenharmony_ci enum snd_soc_bias_level level) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = dev_get_drvdata(component->dev); 6708c2ecf20Sopenharmony_ci int ret; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci switch (level) { 6738c2ecf20Sopenharmony_ci case SND_SOC_BIAS_ON: 6748c2ecf20Sopenharmony_ci case SND_SOC_BIAS_PREPARE: 6758c2ecf20Sopenharmony_ci break; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci case SND_SOC_BIAS_STANDBY: 6788c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, 6798c2ecf20Sopenharmony_ci PCM512x_RQST, 0); 6808c2ecf20Sopenharmony_ci if (ret != 0) { 6818c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to remove standby: %d\n", 6828c2ecf20Sopenharmony_ci ret); 6838c2ecf20Sopenharmony_ci return ret; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci break; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci case SND_SOC_BIAS_OFF: 6888c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, 6898c2ecf20Sopenharmony_ci PCM512x_RQST, PCM512x_RQST); 6908c2ecf20Sopenharmony_ci if (ret != 0) { 6918c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to request standby: %d\n", 6928c2ecf20Sopenharmony_ci ret); 6938c2ecf20Sopenharmony_ci return ret; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci break; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci return 0; 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic unsigned long pcm512x_find_sck(struct snd_soc_dai *dai, 7028c2ecf20Sopenharmony_ci unsigned long bclk_rate) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci struct device *dev = dai->dev; 7058c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 7068c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); 7078c2ecf20Sopenharmony_ci unsigned long sck_rate; 7088c2ecf20Sopenharmony_ci int pow2; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* 64 MHz <= pll_rate <= 100 MHz, VREF mode */ 7118c2ecf20Sopenharmony_ci /* 16 MHz <= sck_rate <= 25 MHz, VREF mode */ 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci /* select sck_rate as a multiple of bclk_rate but still with 7148c2ecf20Sopenharmony_ci * as many factors of 2 as possible, as that makes it easier 7158c2ecf20Sopenharmony_ci * to find a fast DAC rate 7168c2ecf20Sopenharmony_ci */ 7178c2ecf20Sopenharmony_ci pow2 = 1 << fls((pcm512x_pll_max(pcm512x) - 16000000) / bclk_rate); 7188c2ecf20Sopenharmony_ci for (; pow2; pow2 >>= 1) { 7198c2ecf20Sopenharmony_ci sck_rate = rounddown(pcm512x_pll_max(pcm512x), 7208c2ecf20Sopenharmony_ci bclk_rate * pow2); 7218c2ecf20Sopenharmony_ci if (sck_rate >= 16000000) 7228c2ecf20Sopenharmony_ci break; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci if (!pow2) { 7258c2ecf20Sopenharmony_ci dev_err(dev, "Impossible to generate a suitable SCK\n"); 7268c2ecf20Sopenharmony_ci return 0; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci dev_dbg(dev, "sck_rate %lu\n", sck_rate); 7308c2ecf20Sopenharmony_ci return sck_rate; 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci/* pll_rate = pllin_rate * R * J.D / P 7348c2ecf20Sopenharmony_ci * 1 <= R <= 16 7358c2ecf20Sopenharmony_ci * 1 <= J <= 63 7368c2ecf20Sopenharmony_ci * 0 <= D <= 9999 7378c2ecf20Sopenharmony_ci * 1 <= P <= 15 7388c2ecf20Sopenharmony_ci * 64 MHz <= pll_rate <= 100 MHz 7398c2ecf20Sopenharmony_ci * if D == 0 7408c2ecf20Sopenharmony_ci * 1 MHz <= pllin_rate / P <= 20 MHz 7418c2ecf20Sopenharmony_ci * else if D > 0 7428c2ecf20Sopenharmony_ci * 6.667 MHz <= pllin_rate / P <= 20 MHz 7438c2ecf20Sopenharmony_ci * 4 <= J <= 11 7448c2ecf20Sopenharmony_ci * R = 1 7458c2ecf20Sopenharmony_ci */ 7468c2ecf20Sopenharmony_cistatic int pcm512x_find_pll_coeff(struct snd_soc_dai *dai, 7478c2ecf20Sopenharmony_ci unsigned long pllin_rate, 7488c2ecf20Sopenharmony_ci unsigned long pll_rate) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci struct device *dev = dai->dev; 7518c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 7528c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); 7538c2ecf20Sopenharmony_ci unsigned long common; 7548c2ecf20Sopenharmony_ci int R, J, D, P; 7558c2ecf20Sopenharmony_ci unsigned long K; /* 10000 * J.D */ 7568c2ecf20Sopenharmony_ci unsigned long num; 7578c2ecf20Sopenharmony_ci unsigned long den; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci common = gcd(pll_rate, pllin_rate); 7608c2ecf20Sopenharmony_ci dev_dbg(dev, "pll %lu pllin %lu common %lu\n", 7618c2ecf20Sopenharmony_ci pll_rate, pllin_rate, common); 7628c2ecf20Sopenharmony_ci num = pll_rate / common; 7638c2ecf20Sopenharmony_ci den = pllin_rate / common; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci /* pllin_rate / P (or here, den) cannot be greater than 20 MHz */ 7668c2ecf20Sopenharmony_ci if (pllin_rate / den > 20000000 && num < 8) { 7678c2ecf20Sopenharmony_ci num *= DIV_ROUND_UP(pllin_rate / den, 20000000); 7688c2ecf20Sopenharmony_ci den *= DIV_ROUND_UP(pllin_rate / den, 20000000); 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci dev_dbg(dev, "num / den = %lu / %lu\n", num, den); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci P = den; 7738c2ecf20Sopenharmony_ci if (den <= 15 && num <= 16 * 63 7748c2ecf20Sopenharmony_ci && 1000000 <= pllin_rate / P && pllin_rate / P <= 20000000) { 7758c2ecf20Sopenharmony_ci /* Try the case with D = 0 */ 7768c2ecf20Sopenharmony_ci D = 0; 7778c2ecf20Sopenharmony_ci /* factor 'num' into J and R, such that R <= 16 and J <= 63 */ 7788c2ecf20Sopenharmony_ci for (R = 16; R; R--) { 7798c2ecf20Sopenharmony_ci if (num % R) 7808c2ecf20Sopenharmony_ci continue; 7818c2ecf20Sopenharmony_ci J = num / R; 7828c2ecf20Sopenharmony_ci if (J == 0 || J > 63) 7838c2ecf20Sopenharmony_ci continue; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci dev_dbg(dev, "R * J / P = %d * %d / %d\n", R, J, P); 7868c2ecf20Sopenharmony_ci pcm512x->real_pll = pll_rate; 7878c2ecf20Sopenharmony_ci goto done; 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci /* no luck */ 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci R = 1; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci if (num > 0xffffffffUL / 10000) 7958c2ecf20Sopenharmony_ci goto fallback; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci /* Try to find an exact pll_rate using the D > 0 case */ 7988c2ecf20Sopenharmony_ci common = gcd(10000 * num, den); 7998c2ecf20Sopenharmony_ci num = 10000 * num / common; 8008c2ecf20Sopenharmony_ci den /= common; 8018c2ecf20Sopenharmony_ci dev_dbg(dev, "num %lu den %lu common %lu\n", num, den, common); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci for (P = den; P <= 15; P++) { 8048c2ecf20Sopenharmony_ci if (pllin_rate / P < 6667000 || 200000000 < pllin_rate / P) 8058c2ecf20Sopenharmony_ci continue; 8068c2ecf20Sopenharmony_ci if (num * P % den) 8078c2ecf20Sopenharmony_ci continue; 8088c2ecf20Sopenharmony_ci K = num * P / den; 8098c2ecf20Sopenharmony_ci /* J == 12 is ok if D == 0 */ 8108c2ecf20Sopenharmony_ci if (K < 40000 || K > 120000) 8118c2ecf20Sopenharmony_ci continue; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci J = K / 10000; 8148c2ecf20Sopenharmony_ci D = K % 10000; 8158c2ecf20Sopenharmony_ci dev_dbg(dev, "J.D / P = %d.%04d / %d\n", J, D, P); 8168c2ecf20Sopenharmony_ci pcm512x->real_pll = pll_rate; 8178c2ecf20Sopenharmony_ci goto done; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci /* Fall back to an approximate pll_rate */ 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cifallback: 8238c2ecf20Sopenharmony_ci /* find smallest possible P */ 8248c2ecf20Sopenharmony_ci P = DIV_ROUND_UP(pllin_rate, 20000000); 8258c2ecf20Sopenharmony_ci if (!P) 8268c2ecf20Sopenharmony_ci P = 1; 8278c2ecf20Sopenharmony_ci else if (P > 15) { 8288c2ecf20Sopenharmony_ci dev_err(dev, "Need a slower clock as pll-input\n"); 8298c2ecf20Sopenharmony_ci return -EINVAL; 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci if (pllin_rate / P < 6667000) { 8328c2ecf20Sopenharmony_ci dev_err(dev, "Need a faster clock as pll-input\n"); 8338c2ecf20Sopenharmony_ci return -EINVAL; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci K = DIV_ROUND_CLOSEST_ULL(10000ULL * pll_rate * P, pllin_rate); 8368c2ecf20Sopenharmony_ci if (K < 40000) 8378c2ecf20Sopenharmony_ci K = 40000; 8388c2ecf20Sopenharmony_ci /* J == 12 is ok if D == 0 */ 8398c2ecf20Sopenharmony_ci if (K > 120000) 8408c2ecf20Sopenharmony_ci K = 120000; 8418c2ecf20Sopenharmony_ci J = K / 10000; 8428c2ecf20Sopenharmony_ci D = K % 10000; 8438c2ecf20Sopenharmony_ci dev_dbg(dev, "J.D / P ~ %d.%04d / %d\n", J, D, P); 8448c2ecf20Sopenharmony_ci pcm512x->real_pll = DIV_ROUND_DOWN_ULL((u64)K * pllin_rate, 10000 * P); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_cidone: 8478c2ecf20Sopenharmony_ci pcm512x->pll_r = R; 8488c2ecf20Sopenharmony_ci pcm512x->pll_j = J; 8498c2ecf20Sopenharmony_ci pcm512x->pll_d = D; 8508c2ecf20Sopenharmony_ci pcm512x->pll_p = P; 8518c2ecf20Sopenharmony_ci return 0; 8528c2ecf20Sopenharmony_ci} 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_cistatic unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai, 8558c2ecf20Sopenharmony_ci unsigned long osr_rate, 8568c2ecf20Sopenharmony_ci unsigned long pllin_rate) 8578c2ecf20Sopenharmony_ci{ 8588c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 8598c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); 8608c2ecf20Sopenharmony_ci unsigned long dac_rate; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci if (!pcm512x->pll_out) 8638c2ecf20Sopenharmony_ci return 0; /* no PLL to bypass, force SCK as DAC input */ 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci if (pllin_rate % osr_rate) 8668c2ecf20Sopenharmony_ci return 0; /* futile, quit early */ 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci /* run DAC no faster than 6144000 Hz */ 8698c2ecf20Sopenharmony_ci for (dac_rate = rounddown(pcm512x_dac_max(pcm512x, 6144000), osr_rate); 8708c2ecf20Sopenharmony_ci dac_rate; 8718c2ecf20Sopenharmony_ci dac_rate -= osr_rate) { 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci if (pllin_rate / dac_rate > 128) 8748c2ecf20Sopenharmony_ci return 0; /* DAC divider would be too big */ 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci if (!(pllin_rate % dac_rate)) 8778c2ecf20Sopenharmony_ci return dac_rate; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci dac_rate -= osr_rate; 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci return 0; 8838c2ecf20Sopenharmony_ci} 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_cistatic int pcm512x_set_dividers(struct snd_soc_dai *dai, 8868c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci struct device *dev = dai->dev; 8898c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 8908c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); 8918c2ecf20Sopenharmony_ci unsigned long pllin_rate = 0; 8928c2ecf20Sopenharmony_ci unsigned long pll_rate; 8938c2ecf20Sopenharmony_ci unsigned long sck_rate; 8948c2ecf20Sopenharmony_ci unsigned long mck_rate; 8958c2ecf20Sopenharmony_ci unsigned long bclk_rate; 8968c2ecf20Sopenharmony_ci unsigned long sample_rate; 8978c2ecf20Sopenharmony_ci unsigned long osr_rate; 8988c2ecf20Sopenharmony_ci unsigned long dacsrc_rate; 8998c2ecf20Sopenharmony_ci int bclk_div; 9008c2ecf20Sopenharmony_ci int lrclk_div; 9018c2ecf20Sopenharmony_ci int dsp_div; 9028c2ecf20Sopenharmony_ci int dac_div; 9038c2ecf20Sopenharmony_ci unsigned long dac_rate; 9048c2ecf20Sopenharmony_ci int ncp_div; 9058c2ecf20Sopenharmony_ci int osr_div; 9068c2ecf20Sopenharmony_ci int ret; 9078c2ecf20Sopenharmony_ci int idac; 9088c2ecf20Sopenharmony_ci int fssp; 9098c2ecf20Sopenharmony_ci int gpio; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci if (pcm512x->bclk_ratio > 0) { 9128c2ecf20Sopenharmony_ci lrclk_div = pcm512x->bclk_ratio; 9138c2ecf20Sopenharmony_ci } else { 9148c2ecf20Sopenharmony_ci lrclk_div = snd_soc_params_to_frame_size(params); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci if (lrclk_div == 0) { 9178c2ecf20Sopenharmony_ci dev_err(dev, "No LRCLK?\n"); 9188c2ecf20Sopenharmony_ci return -EINVAL; 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci if (!pcm512x->pll_out) { 9238c2ecf20Sopenharmony_ci sck_rate = clk_get_rate(pcm512x->sclk); 9248c2ecf20Sopenharmony_ci bclk_rate = params_rate(params) * lrclk_div; 9258c2ecf20Sopenharmony_ci bclk_div = DIV_ROUND_CLOSEST(sck_rate, bclk_rate); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci mck_rate = sck_rate; 9288c2ecf20Sopenharmony_ci } else { 9298c2ecf20Sopenharmony_ci ret = snd_soc_params_to_bclk(params); 9308c2ecf20Sopenharmony_ci if (ret < 0) { 9318c2ecf20Sopenharmony_ci dev_err(dev, "Failed to find suitable BCLK: %d\n", ret); 9328c2ecf20Sopenharmony_ci return ret; 9338c2ecf20Sopenharmony_ci } 9348c2ecf20Sopenharmony_ci if (ret == 0) { 9358c2ecf20Sopenharmony_ci dev_err(dev, "No BCLK?\n"); 9368c2ecf20Sopenharmony_ci return -EINVAL; 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci bclk_rate = ret; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci pllin_rate = clk_get_rate(pcm512x->sclk); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci sck_rate = pcm512x_find_sck(dai, bclk_rate); 9438c2ecf20Sopenharmony_ci if (!sck_rate) 9448c2ecf20Sopenharmony_ci return -EINVAL; 9458c2ecf20Sopenharmony_ci pll_rate = 4 * sck_rate; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci ret = pcm512x_find_pll_coeff(dai, pllin_rate, pll_rate); 9488c2ecf20Sopenharmony_ci if (ret != 0) 9498c2ecf20Sopenharmony_ci return ret; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci ret = regmap_write(pcm512x->regmap, 9528c2ecf20Sopenharmony_ci PCM512x_PLL_COEFF_0, pcm512x->pll_p - 1); 9538c2ecf20Sopenharmony_ci if (ret != 0) { 9548c2ecf20Sopenharmony_ci dev_err(dev, "Failed to write PLL P: %d\n", ret); 9558c2ecf20Sopenharmony_ci return ret; 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci ret = regmap_write(pcm512x->regmap, 9598c2ecf20Sopenharmony_ci PCM512x_PLL_COEFF_1, pcm512x->pll_j); 9608c2ecf20Sopenharmony_ci if (ret != 0) { 9618c2ecf20Sopenharmony_ci dev_err(dev, "Failed to write PLL J: %d\n", ret); 9628c2ecf20Sopenharmony_ci return ret; 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci ret = regmap_write(pcm512x->regmap, 9668c2ecf20Sopenharmony_ci PCM512x_PLL_COEFF_2, pcm512x->pll_d >> 8); 9678c2ecf20Sopenharmony_ci if (ret != 0) { 9688c2ecf20Sopenharmony_ci dev_err(dev, "Failed to write PLL D msb: %d\n", ret); 9698c2ecf20Sopenharmony_ci return ret; 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci ret = regmap_write(pcm512x->regmap, 9738c2ecf20Sopenharmony_ci PCM512x_PLL_COEFF_3, pcm512x->pll_d & 0xff); 9748c2ecf20Sopenharmony_ci if (ret != 0) { 9758c2ecf20Sopenharmony_ci dev_err(dev, "Failed to write PLL D lsb: %d\n", ret); 9768c2ecf20Sopenharmony_ci return ret; 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci ret = regmap_write(pcm512x->regmap, 9808c2ecf20Sopenharmony_ci PCM512x_PLL_COEFF_4, pcm512x->pll_r - 1); 9818c2ecf20Sopenharmony_ci if (ret != 0) { 9828c2ecf20Sopenharmony_ci dev_err(dev, "Failed to write PLL R: %d\n", ret); 9838c2ecf20Sopenharmony_ci return ret; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci mck_rate = pcm512x->real_pll; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci bclk_div = DIV_ROUND_CLOSEST(sck_rate, bclk_rate); 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci if (bclk_div > 128) { 9928c2ecf20Sopenharmony_ci dev_err(dev, "Failed to find BCLK divider\n"); 9938c2ecf20Sopenharmony_ci return -EINVAL; 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci /* the actual rate */ 9978c2ecf20Sopenharmony_ci sample_rate = sck_rate / bclk_div / lrclk_div; 9988c2ecf20Sopenharmony_ci osr_rate = 16 * sample_rate; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci /* run DSP no faster than 50 MHz */ 10018c2ecf20Sopenharmony_ci dsp_div = mck_rate > pcm512x_dsp_max(pcm512x) ? 2 : 1; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate); 10048c2ecf20Sopenharmony_ci if (dac_rate) { 10058c2ecf20Sopenharmony_ci /* the desired clock rate is "compatible" with the pll input 10068c2ecf20Sopenharmony_ci * clock, so use that clock as dac input instead of the pll 10078c2ecf20Sopenharmony_ci * output clock since the pll will introduce jitter and thus 10088c2ecf20Sopenharmony_ci * noise. 10098c2ecf20Sopenharmony_ci */ 10108c2ecf20Sopenharmony_ci dev_dbg(dev, "using pll input as dac input\n"); 10118c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF, 10128c2ecf20Sopenharmony_ci PCM512x_SDAC, PCM512x_SDAC_GPIO); 10138c2ecf20Sopenharmony_ci if (ret != 0) { 10148c2ecf20Sopenharmony_ci dev_err(component->dev, 10158c2ecf20Sopenharmony_ci "Failed to set gpio as dacref: %d\n", ret); 10168c2ecf20Sopenharmony_ci return ret; 10178c2ecf20Sopenharmony_ci } 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci gpio = PCM512x_GREF_GPIO1 + pcm512x->pll_in - 1; 10208c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_DACIN, 10218c2ecf20Sopenharmony_ci PCM512x_GREF, gpio); 10228c2ecf20Sopenharmony_ci if (ret != 0) { 10238c2ecf20Sopenharmony_ci dev_err(component->dev, 10248c2ecf20Sopenharmony_ci "Failed to set gpio %d as dacin: %d\n", 10258c2ecf20Sopenharmony_ci pcm512x->pll_in, ret); 10268c2ecf20Sopenharmony_ci return ret; 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci dacsrc_rate = pllin_rate; 10308c2ecf20Sopenharmony_ci } else { 10318c2ecf20Sopenharmony_ci /* run DAC no faster than 6144000 Hz */ 10328c2ecf20Sopenharmony_ci unsigned long dac_mul = pcm512x_dac_max(pcm512x, 6144000) 10338c2ecf20Sopenharmony_ci / osr_rate; 10348c2ecf20Sopenharmony_ci unsigned long sck_mul = sck_rate / osr_rate; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci for (; dac_mul; dac_mul--) { 10378c2ecf20Sopenharmony_ci if (!(sck_mul % dac_mul)) 10388c2ecf20Sopenharmony_ci break; 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci if (!dac_mul) { 10418c2ecf20Sopenharmony_ci dev_err(dev, "Failed to find DAC rate\n"); 10428c2ecf20Sopenharmony_ci return -EINVAL; 10438c2ecf20Sopenharmony_ci } 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci dac_rate = dac_mul * osr_rate; 10468c2ecf20Sopenharmony_ci dev_dbg(dev, "dac_rate %lu sample_rate %lu\n", 10478c2ecf20Sopenharmony_ci dac_rate, sample_rate); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF, 10508c2ecf20Sopenharmony_ci PCM512x_SDAC, PCM512x_SDAC_SCK); 10518c2ecf20Sopenharmony_ci if (ret != 0) { 10528c2ecf20Sopenharmony_ci dev_err(component->dev, 10538c2ecf20Sopenharmony_ci "Failed to set sck as dacref: %d\n", ret); 10548c2ecf20Sopenharmony_ci return ret; 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci dacsrc_rate = sck_rate; 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate); 10618c2ecf20Sopenharmony_ci if (osr_div > 128) { 10628c2ecf20Sopenharmony_ci dev_err(dev, "Failed to find OSR divider\n"); 10638c2ecf20Sopenharmony_ci return -EINVAL; 10648c2ecf20Sopenharmony_ci } 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci dac_div = DIV_ROUND_CLOSEST(dacsrc_rate, dac_rate); 10678c2ecf20Sopenharmony_ci if (dac_div > 128) { 10688c2ecf20Sopenharmony_ci dev_err(dev, "Failed to find DAC divider\n"); 10698c2ecf20Sopenharmony_ci return -EINVAL; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci dac_rate = dacsrc_rate / dac_div; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci ncp_div = DIV_ROUND_CLOSEST(dac_rate, 10748c2ecf20Sopenharmony_ci pcm512x_ncp_target(pcm512x, dac_rate)); 10758c2ecf20Sopenharmony_ci if (ncp_div > 128 || dac_rate / ncp_div > 2048000) { 10768c2ecf20Sopenharmony_ci /* run NCP no faster than 2048000 Hz, but why? */ 10778c2ecf20Sopenharmony_ci ncp_div = DIV_ROUND_UP(dac_rate, 2048000); 10788c2ecf20Sopenharmony_ci if (ncp_div > 128) { 10798c2ecf20Sopenharmony_ci dev_err(dev, "Failed to find NCP divider\n"); 10808c2ecf20Sopenharmony_ci return -EINVAL; 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci } 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci idac = mck_rate / (dsp_div * sample_rate); 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci ret = regmap_write(pcm512x->regmap, PCM512x_DSP_CLKDIV, dsp_div - 1); 10878c2ecf20Sopenharmony_ci if (ret != 0) { 10888c2ecf20Sopenharmony_ci dev_err(dev, "Failed to write DSP divider: %d\n", ret); 10898c2ecf20Sopenharmony_ci return ret; 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci ret = regmap_write(pcm512x->regmap, PCM512x_DAC_CLKDIV, dac_div - 1); 10938c2ecf20Sopenharmony_ci if (ret != 0) { 10948c2ecf20Sopenharmony_ci dev_err(dev, "Failed to write DAC divider: %d\n", ret); 10958c2ecf20Sopenharmony_ci return ret; 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci ret = regmap_write(pcm512x->regmap, PCM512x_NCP_CLKDIV, ncp_div - 1); 10998c2ecf20Sopenharmony_ci if (ret != 0) { 11008c2ecf20Sopenharmony_ci dev_err(dev, "Failed to write NCP divider: %d\n", ret); 11018c2ecf20Sopenharmony_ci return ret; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci ret = regmap_write(pcm512x->regmap, PCM512x_OSR_CLKDIV, osr_div - 1); 11058c2ecf20Sopenharmony_ci if (ret != 0) { 11068c2ecf20Sopenharmony_ci dev_err(dev, "Failed to write OSR divider: %d\n", ret); 11078c2ecf20Sopenharmony_ci return ret; 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci ret = regmap_write(pcm512x->regmap, 11118c2ecf20Sopenharmony_ci PCM512x_MASTER_CLKDIV_1, bclk_div - 1); 11128c2ecf20Sopenharmony_ci if (ret != 0) { 11138c2ecf20Sopenharmony_ci dev_err(dev, "Failed to write BCLK divider: %d\n", ret); 11148c2ecf20Sopenharmony_ci return ret; 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci ret = regmap_write(pcm512x->regmap, 11188c2ecf20Sopenharmony_ci PCM512x_MASTER_CLKDIV_2, lrclk_div - 1); 11198c2ecf20Sopenharmony_ci if (ret != 0) { 11208c2ecf20Sopenharmony_ci dev_err(dev, "Failed to write LRCLK divider: %d\n", ret); 11218c2ecf20Sopenharmony_ci return ret; 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci ret = regmap_write(pcm512x->regmap, PCM512x_IDAC_1, idac >> 8); 11258c2ecf20Sopenharmony_ci if (ret != 0) { 11268c2ecf20Sopenharmony_ci dev_err(dev, "Failed to write IDAC msb divider: %d\n", ret); 11278c2ecf20Sopenharmony_ci return ret; 11288c2ecf20Sopenharmony_ci } 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci ret = regmap_write(pcm512x->regmap, PCM512x_IDAC_2, idac & 0xff); 11318c2ecf20Sopenharmony_ci if (ret != 0) { 11328c2ecf20Sopenharmony_ci dev_err(dev, "Failed to write IDAC lsb divider: %d\n", ret); 11338c2ecf20Sopenharmony_ci return ret; 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci if (sample_rate <= pcm512x_dac_max(pcm512x, 48000)) 11378c2ecf20Sopenharmony_ci fssp = PCM512x_FSSP_48KHZ; 11388c2ecf20Sopenharmony_ci else if (sample_rate <= pcm512x_dac_max(pcm512x, 96000)) 11398c2ecf20Sopenharmony_ci fssp = PCM512x_FSSP_96KHZ; 11408c2ecf20Sopenharmony_ci else if (sample_rate <= pcm512x_dac_max(pcm512x, 192000)) 11418c2ecf20Sopenharmony_ci fssp = PCM512x_FSSP_192KHZ; 11428c2ecf20Sopenharmony_ci else 11438c2ecf20Sopenharmony_ci fssp = PCM512x_FSSP_384KHZ; 11448c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_FS_SPEED_MODE, 11458c2ecf20Sopenharmony_ci PCM512x_FSSP, fssp); 11468c2ecf20Sopenharmony_ci if (ret != 0) { 11478c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to set fs speed: %d\n", ret); 11488c2ecf20Sopenharmony_ci return ret; 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci dev_dbg(component->dev, "DSP divider %d\n", dsp_div); 11528c2ecf20Sopenharmony_ci dev_dbg(component->dev, "DAC divider %d\n", dac_div); 11538c2ecf20Sopenharmony_ci dev_dbg(component->dev, "NCP divider %d\n", ncp_div); 11548c2ecf20Sopenharmony_ci dev_dbg(component->dev, "OSR divider %d\n", osr_div); 11558c2ecf20Sopenharmony_ci dev_dbg(component->dev, "BCK divider %d\n", bclk_div); 11568c2ecf20Sopenharmony_ci dev_dbg(component->dev, "LRCK divider %d\n", lrclk_div); 11578c2ecf20Sopenharmony_ci dev_dbg(component->dev, "IDAC %d\n", idac); 11588c2ecf20Sopenharmony_ci dev_dbg(component->dev, "1<<FSSP %d\n", 1 << fssp); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci return 0; 11618c2ecf20Sopenharmony_ci} 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_cistatic int pcm512x_hw_params(struct snd_pcm_substream *substream, 11648c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 11658c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 11668c2ecf20Sopenharmony_ci{ 11678c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 11688c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); 11698c2ecf20Sopenharmony_ci int alen; 11708c2ecf20Sopenharmony_ci int gpio; 11718c2ecf20Sopenharmony_ci int clock_output; 11728c2ecf20Sopenharmony_ci int master_mode; 11738c2ecf20Sopenharmony_ci int ret; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci dev_dbg(component->dev, "hw_params %u Hz, %u channels\n", 11768c2ecf20Sopenharmony_ci params_rate(params), 11778c2ecf20Sopenharmony_ci params_channels(params)); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci switch (params_width(params)) { 11808c2ecf20Sopenharmony_ci case 16: 11818c2ecf20Sopenharmony_ci alen = PCM512x_ALEN_16; 11828c2ecf20Sopenharmony_ci break; 11838c2ecf20Sopenharmony_ci case 20: 11848c2ecf20Sopenharmony_ci alen = PCM512x_ALEN_20; 11858c2ecf20Sopenharmony_ci break; 11868c2ecf20Sopenharmony_ci case 24: 11878c2ecf20Sopenharmony_ci alen = PCM512x_ALEN_24; 11888c2ecf20Sopenharmony_ci break; 11898c2ecf20Sopenharmony_ci case 32: 11908c2ecf20Sopenharmony_ci alen = PCM512x_ALEN_32; 11918c2ecf20Sopenharmony_ci break; 11928c2ecf20Sopenharmony_ci default: 11938c2ecf20Sopenharmony_ci dev_err(component->dev, "Bad frame size: %d\n", 11948c2ecf20Sopenharmony_ci params_width(params)); 11958c2ecf20Sopenharmony_ci return -EINVAL; 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) { 11998c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBS_CFS: 12008c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, 12018c2ecf20Sopenharmony_ci PCM512x_BCLK_LRCLK_CFG, 12028c2ecf20Sopenharmony_ci PCM512x_BCKP 12038c2ecf20Sopenharmony_ci | PCM512x_BCKO | PCM512x_LRKO, 12048c2ecf20Sopenharmony_ci 0); 12058c2ecf20Sopenharmony_ci if (ret != 0) { 12068c2ecf20Sopenharmony_ci dev_err(component->dev, 12078c2ecf20Sopenharmony_ci "Failed to enable slave mode: %d\n", ret); 12088c2ecf20Sopenharmony_ci return ret; 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT, 12128c2ecf20Sopenharmony_ci PCM512x_DCAS, 0); 12138c2ecf20Sopenharmony_ci if (ret != 0) { 12148c2ecf20Sopenharmony_ci dev_err(component->dev, 12158c2ecf20Sopenharmony_ci "Failed to enable clock divider autoset: %d\n", 12168c2ecf20Sopenharmony_ci ret); 12178c2ecf20Sopenharmony_ci return ret; 12188c2ecf20Sopenharmony_ci } 12198c2ecf20Sopenharmony_ci return 0; 12208c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFM: 12218c2ecf20Sopenharmony_ci clock_output = PCM512x_BCKO | PCM512x_LRKO; 12228c2ecf20Sopenharmony_ci master_mode = PCM512x_RLRK | PCM512x_RBCK; 12238c2ecf20Sopenharmony_ci break; 12248c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFS: 12258c2ecf20Sopenharmony_ci clock_output = PCM512x_BCKO; 12268c2ecf20Sopenharmony_ci master_mode = PCM512x_RBCK; 12278c2ecf20Sopenharmony_ci break; 12288c2ecf20Sopenharmony_ci default: 12298c2ecf20Sopenharmony_ci return -EINVAL; 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1, 12338c2ecf20Sopenharmony_ci PCM512x_ALEN, alen); 12348c2ecf20Sopenharmony_ci if (ret != 0) { 12358c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to set frame size: %d\n", ret); 12368c2ecf20Sopenharmony_ci return ret; 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci if (pcm512x->pll_out) { 12408c2ecf20Sopenharmony_ci ret = regmap_write(pcm512x->regmap, PCM512x_FLEX_A, 0x11); 12418c2ecf20Sopenharmony_ci if (ret != 0) { 12428c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to set FLEX_A: %d\n", ret); 12438c2ecf20Sopenharmony_ci return ret; 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci ret = regmap_write(pcm512x->regmap, PCM512x_FLEX_B, 0xff); 12478c2ecf20Sopenharmony_ci if (ret != 0) { 12488c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to set FLEX_B: %d\n", ret); 12498c2ecf20Sopenharmony_ci return ret; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT, 12538c2ecf20Sopenharmony_ci PCM512x_IDFS | PCM512x_IDBK 12548c2ecf20Sopenharmony_ci | PCM512x_IDSK | PCM512x_IDCH 12558c2ecf20Sopenharmony_ci | PCM512x_IDCM | PCM512x_DCAS 12568c2ecf20Sopenharmony_ci | PCM512x_IPLK, 12578c2ecf20Sopenharmony_ci PCM512x_IDFS | PCM512x_IDBK 12588c2ecf20Sopenharmony_ci | PCM512x_IDSK | PCM512x_IDCH 12598c2ecf20Sopenharmony_ci | PCM512x_DCAS); 12608c2ecf20Sopenharmony_ci if (ret != 0) { 12618c2ecf20Sopenharmony_ci dev_err(component->dev, 12628c2ecf20Sopenharmony_ci "Failed to ignore auto-clock failures: %d\n", 12638c2ecf20Sopenharmony_ci ret); 12648c2ecf20Sopenharmony_ci return ret; 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci } else { 12678c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT, 12688c2ecf20Sopenharmony_ci PCM512x_IDFS | PCM512x_IDBK 12698c2ecf20Sopenharmony_ci | PCM512x_IDSK | PCM512x_IDCH 12708c2ecf20Sopenharmony_ci | PCM512x_IDCM | PCM512x_DCAS 12718c2ecf20Sopenharmony_ci | PCM512x_IPLK, 12728c2ecf20Sopenharmony_ci PCM512x_IDFS | PCM512x_IDBK 12738c2ecf20Sopenharmony_ci | PCM512x_IDSK | PCM512x_IDCH 12748c2ecf20Sopenharmony_ci | PCM512x_DCAS | PCM512x_IPLK); 12758c2ecf20Sopenharmony_ci if (ret != 0) { 12768c2ecf20Sopenharmony_ci dev_err(component->dev, 12778c2ecf20Sopenharmony_ci "Failed to ignore auto-clock failures: %d\n", 12788c2ecf20Sopenharmony_ci ret); 12798c2ecf20Sopenharmony_ci return ret; 12808c2ecf20Sopenharmony_ci } 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN, 12838c2ecf20Sopenharmony_ci PCM512x_PLLE, 0); 12848c2ecf20Sopenharmony_ci if (ret != 0) { 12858c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to disable pll: %d\n", ret); 12868c2ecf20Sopenharmony_ci return ret; 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci } 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci ret = pcm512x_set_dividers(dai, params); 12918c2ecf20Sopenharmony_ci if (ret != 0) 12928c2ecf20Sopenharmony_ci return ret; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci if (pcm512x->pll_out) { 12958c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_REF, 12968c2ecf20Sopenharmony_ci PCM512x_SREF, PCM512x_SREF_GPIO); 12978c2ecf20Sopenharmony_ci if (ret != 0) { 12988c2ecf20Sopenharmony_ci dev_err(component->dev, 12998c2ecf20Sopenharmony_ci "Failed to set gpio as pllref: %d\n", ret); 13008c2ecf20Sopenharmony_ci return ret; 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci gpio = PCM512x_GREF_GPIO1 + pcm512x->pll_in - 1; 13048c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_PLLIN, 13058c2ecf20Sopenharmony_ci PCM512x_GREF, gpio); 13068c2ecf20Sopenharmony_ci if (ret != 0) { 13078c2ecf20Sopenharmony_ci dev_err(component->dev, 13088c2ecf20Sopenharmony_ci "Failed to set gpio %d as pllin: %d\n", 13098c2ecf20Sopenharmony_ci pcm512x->pll_in, ret); 13108c2ecf20Sopenharmony_ci return ret; 13118c2ecf20Sopenharmony_ci } 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN, 13148c2ecf20Sopenharmony_ci PCM512x_PLLE, PCM512x_PLLE); 13158c2ecf20Sopenharmony_ci if (ret != 0) { 13168c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to enable pll: %d\n", ret); 13178c2ecf20Sopenharmony_ci return ret; 13188c2ecf20Sopenharmony_ci } 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_BCLK_LRCLK_CFG, 13228c2ecf20Sopenharmony_ci PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO, 13238c2ecf20Sopenharmony_ci clock_output); 13248c2ecf20Sopenharmony_ci if (ret != 0) { 13258c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to enable clock output: %d\n", ret); 13268c2ecf20Sopenharmony_ci return ret; 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_MASTER_MODE, 13308c2ecf20Sopenharmony_ci PCM512x_RLRK | PCM512x_RBCK, 13318c2ecf20Sopenharmony_ci master_mode); 13328c2ecf20Sopenharmony_ci if (ret != 0) { 13338c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to enable master mode: %d\n", ret); 13348c2ecf20Sopenharmony_ci return ret; 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci if (pcm512x->pll_out) { 13388c2ecf20Sopenharmony_ci gpio = PCM512x_G1OE << (pcm512x->pll_out - 1); 13398c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_EN, 13408c2ecf20Sopenharmony_ci gpio, gpio); 13418c2ecf20Sopenharmony_ci if (ret != 0) { 13428c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to enable gpio %d: %d\n", 13438c2ecf20Sopenharmony_ci pcm512x->pll_out, ret); 13448c2ecf20Sopenharmony_ci return ret; 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci gpio = PCM512x_GPIO_OUTPUT_1 + pcm512x->pll_out - 1; 13488c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, gpio, 13498c2ecf20Sopenharmony_ci PCM512x_GxSL, PCM512x_GxSL_PLLCK); 13508c2ecf20Sopenharmony_ci if (ret != 0) { 13518c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to output pll on %d: %d\n", 13528c2ecf20Sopenharmony_ci ret, pcm512x->pll_out); 13538c2ecf20Sopenharmony_ci return ret; 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci } 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE, 13588c2ecf20Sopenharmony_ci PCM512x_RQSY, PCM512x_RQSY_HALT); 13598c2ecf20Sopenharmony_ci if (ret != 0) { 13608c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to halt clocks: %d\n", ret); 13618c2ecf20Sopenharmony_ci return ret; 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE, 13658c2ecf20Sopenharmony_ci PCM512x_RQSY, PCM512x_RQSY_RESUME); 13668c2ecf20Sopenharmony_ci if (ret != 0) { 13678c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to resume clocks: %d\n", ret); 13688c2ecf20Sopenharmony_ci return ret; 13698c2ecf20Sopenharmony_ci } 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci return 0; 13728c2ecf20Sopenharmony_ci} 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_cistatic int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 13758c2ecf20Sopenharmony_ci{ 13768c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 13778c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci pcm512x->fmt = fmt; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci return 0; 13828c2ecf20Sopenharmony_ci} 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_cistatic int pcm512x_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) 13858c2ecf20Sopenharmony_ci{ 13868c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 13878c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci if (ratio > 256) 13908c2ecf20Sopenharmony_ci return -EINVAL; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci pcm512x->bclk_ratio = ratio; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci return 0; 13958c2ecf20Sopenharmony_ci} 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_cistatic int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 14008c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); 14018c2ecf20Sopenharmony_ci int ret; 14028c2ecf20Sopenharmony_ci unsigned int mute_det; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci mutex_lock(&pcm512x->mutex); 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci if (mute) { 14078c2ecf20Sopenharmony_ci pcm512x->mute |= 0x1; 14088c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_MUTE, 14098c2ecf20Sopenharmony_ci PCM512x_RQML | PCM512x_RQMR, 14108c2ecf20Sopenharmony_ci PCM512x_RQML | PCM512x_RQMR); 14118c2ecf20Sopenharmony_ci if (ret != 0) { 14128c2ecf20Sopenharmony_ci dev_err(component->dev, 14138c2ecf20Sopenharmony_ci "Failed to set digital mute: %d\n", ret); 14148c2ecf20Sopenharmony_ci goto unlock; 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci regmap_read_poll_timeout(pcm512x->regmap, 14188c2ecf20Sopenharmony_ci PCM512x_ANALOG_MUTE_DET, 14198c2ecf20Sopenharmony_ci mute_det, (mute_det & 0x3) == 0, 14208c2ecf20Sopenharmony_ci 200, 10000); 14218c2ecf20Sopenharmony_ci } else { 14228c2ecf20Sopenharmony_ci pcm512x->mute &= ~0x1; 14238c2ecf20Sopenharmony_ci ret = pcm512x_update_mute(pcm512x); 14248c2ecf20Sopenharmony_ci if (ret != 0) { 14258c2ecf20Sopenharmony_ci dev_err(component->dev, 14268c2ecf20Sopenharmony_ci "Failed to update digital mute: %d\n", ret); 14278c2ecf20Sopenharmony_ci goto unlock; 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci regmap_read_poll_timeout(pcm512x->regmap, 14318c2ecf20Sopenharmony_ci PCM512x_ANALOG_MUTE_DET, 14328c2ecf20Sopenharmony_ci mute_det, 14338c2ecf20Sopenharmony_ci (mute_det & 0x3) 14348c2ecf20Sopenharmony_ci == ((~pcm512x->mute >> 1) & 0x3), 14358c2ecf20Sopenharmony_ci 200, 10000); 14368c2ecf20Sopenharmony_ci } 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ciunlock: 14398c2ecf20Sopenharmony_ci mutex_unlock(&pcm512x->mutex); 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci return ret; 14428c2ecf20Sopenharmony_ci} 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops pcm512x_dai_ops = { 14458c2ecf20Sopenharmony_ci .startup = pcm512x_dai_startup, 14468c2ecf20Sopenharmony_ci .hw_params = pcm512x_hw_params, 14478c2ecf20Sopenharmony_ci .set_fmt = pcm512x_set_fmt, 14488c2ecf20Sopenharmony_ci .mute_stream = pcm512x_mute, 14498c2ecf20Sopenharmony_ci .set_bclk_ratio = pcm512x_set_bclk_ratio, 14508c2ecf20Sopenharmony_ci .no_capture_mute = 1, 14518c2ecf20Sopenharmony_ci}; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver pcm512x_dai = { 14548c2ecf20Sopenharmony_ci .name = "pcm512x-hifi", 14558c2ecf20Sopenharmony_ci .playback = { 14568c2ecf20Sopenharmony_ci .stream_name = "Playback", 14578c2ecf20Sopenharmony_ci .channels_min = 2, 14588c2ecf20Sopenharmony_ci .channels_max = 2, 14598c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_CONTINUOUS, 14608c2ecf20Sopenharmony_ci .rate_min = 8000, 14618c2ecf20Sopenharmony_ci .rate_max = 384000, 14628c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 14638c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | 14648c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE 14658c2ecf20Sopenharmony_ci }, 14668c2ecf20Sopenharmony_ci .ops = &pcm512x_dai_ops, 14678c2ecf20Sopenharmony_ci}; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver pcm512x_component_driver = { 14708c2ecf20Sopenharmony_ci .set_bias_level = pcm512x_set_bias_level, 14718c2ecf20Sopenharmony_ci .controls = pcm512x_controls, 14728c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(pcm512x_controls), 14738c2ecf20Sopenharmony_ci .dapm_widgets = pcm512x_dapm_widgets, 14748c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(pcm512x_dapm_widgets), 14758c2ecf20Sopenharmony_ci .dapm_routes = pcm512x_dapm_routes, 14768c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(pcm512x_dapm_routes), 14778c2ecf20Sopenharmony_ci .use_pmdown_time = 1, 14788c2ecf20Sopenharmony_ci .endianness = 1, 14798c2ecf20Sopenharmony_ci .non_legacy_dai_naming = 1, 14808c2ecf20Sopenharmony_ci}; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_cistatic const struct regmap_range_cfg pcm512x_range = { 14838c2ecf20Sopenharmony_ci .name = "Pages", .range_min = PCM512x_VIRT_BASE, 14848c2ecf20Sopenharmony_ci .range_max = PCM512x_MAX_REGISTER, 14858c2ecf20Sopenharmony_ci .selector_reg = PCM512x_PAGE, 14868c2ecf20Sopenharmony_ci .selector_mask = 0xff, 14878c2ecf20Sopenharmony_ci .window_start = 0, .window_len = 0x100, 14888c2ecf20Sopenharmony_ci}; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ciconst struct regmap_config pcm512x_regmap = { 14918c2ecf20Sopenharmony_ci .reg_bits = 8, 14928c2ecf20Sopenharmony_ci .val_bits = 8, 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci .readable_reg = pcm512x_readable, 14958c2ecf20Sopenharmony_ci .volatile_reg = pcm512x_volatile, 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci .ranges = &pcm512x_range, 14988c2ecf20Sopenharmony_ci .num_ranges = 1, 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci .max_register = PCM512x_MAX_REGISTER, 15018c2ecf20Sopenharmony_ci .reg_defaults = pcm512x_reg_defaults, 15028c2ecf20Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(pcm512x_reg_defaults), 15038c2ecf20Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 15048c2ecf20Sopenharmony_ci}; 15058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pcm512x_regmap); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ciint pcm512x_probe(struct device *dev, struct regmap *regmap) 15088c2ecf20Sopenharmony_ci{ 15098c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x; 15108c2ecf20Sopenharmony_ci int i, ret; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci pcm512x = devm_kzalloc(dev, sizeof(struct pcm512x_priv), GFP_KERNEL); 15138c2ecf20Sopenharmony_ci if (!pcm512x) 15148c2ecf20Sopenharmony_ci return -ENOMEM; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci mutex_init(&pcm512x->mutex); 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci dev_set_drvdata(dev, pcm512x); 15198c2ecf20Sopenharmony_ci pcm512x->regmap = regmap; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) 15228c2ecf20Sopenharmony_ci pcm512x->supplies[i].supply = pcm512x_supply_names[i]; 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(pcm512x->supplies), 15258c2ecf20Sopenharmony_ci pcm512x->supplies); 15268c2ecf20Sopenharmony_ci if (ret != 0) { 15278c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get supplies: %d\n", ret); 15288c2ecf20Sopenharmony_ci return ret; 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci pcm512x->supply_nb[0].notifier_call = pcm512x_regulator_event_0; 15328c2ecf20Sopenharmony_ci pcm512x->supply_nb[1].notifier_call = pcm512x_regulator_event_1; 15338c2ecf20Sopenharmony_ci pcm512x->supply_nb[2].notifier_call = pcm512x_regulator_event_2; 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) { 15368c2ecf20Sopenharmony_ci ret = devm_regulator_register_notifier( 15378c2ecf20Sopenharmony_ci pcm512x->supplies[i].consumer, 15388c2ecf20Sopenharmony_ci &pcm512x->supply_nb[i]); 15398c2ecf20Sopenharmony_ci if (ret != 0) { 15408c2ecf20Sopenharmony_ci dev_err(dev, 15418c2ecf20Sopenharmony_ci "Failed to register regulator notifier: %d\n", 15428c2ecf20Sopenharmony_ci ret); 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci } 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies), 15478c2ecf20Sopenharmony_ci pcm512x->supplies); 15488c2ecf20Sopenharmony_ci if (ret != 0) { 15498c2ecf20Sopenharmony_ci dev_err(dev, "Failed to enable supplies: %d\n", ret); 15508c2ecf20Sopenharmony_ci return ret; 15518c2ecf20Sopenharmony_ci } 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci /* Reset the device, verifying I/O in the process for I2C */ 15548c2ecf20Sopenharmony_ci ret = regmap_write(regmap, PCM512x_RESET, 15558c2ecf20Sopenharmony_ci PCM512x_RSTM | PCM512x_RSTR); 15568c2ecf20Sopenharmony_ci if (ret != 0) { 15578c2ecf20Sopenharmony_ci dev_err(dev, "Failed to reset device: %d\n", ret); 15588c2ecf20Sopenharmony_ci goto err; 15598c2ecf20Sopenharmony_ci } 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci ret = regmap_write(regmap, PCM512x_RESET, 0); 15628c2ecf20Sopenharmony_ci if (ret != 0) { 15638c2ecf20Sopenharmony_ci dev_err(dev, "Failed to reset device: %d\n", ret); 15648c2ecf20Sopenharmony_ci goto err; 15658c2ecf20Sopenharmony_ci } 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci pcm512x->sclk = devm_clk_get(dev, NULL); 15688c2ecf20Sopenharmony_ci if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER) { 15698c2ecf20Sopenharmony_ci ret = -EPROBE_DEFER; 15708c2ecf20Sopenharmony_ci goto err; 15718c2ecf20Sopenharmony_ci } 15728c2ecf20Sopenharmony_ci if (!IS_ERR(pcm512x->sclk)) { 15738c2ecf20Sopenharmony_ci ret = clk_prepare_enable(pcm512x->sclk); 15748c2ecf20Sopenharmony_ci if (ret != 0) { 15758c2ecf20Sopenharmony_ci dev_err(dev, "Failed to enable SCLK: %d\n", ret); 15768c2ecf20Sopenharmony_ci goto err; 15778c2ecf20Sopenharmony_ci } 15788c2ecf20Sopenharmony_ci } 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci /* Default to standby mode */ 15818c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, 15828c2ecf20Sopenharmony_ci PCM512x_RQST, PCM512x_RQST); 15838c2ecf20Sopenharmony_ci if (ret != 0) { 15848c2ecf20Sopenharmony_ci dev_err(dev, "Failed to request standby: %d\n", 15858c2ecf20Sopenharmony_ci ret); 15868c2ecf20Sopenharmony_ci goto err_clk; 15878c2ecf20Sopenharmony_ci } 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci pm_runtime_set_active(dev); 15908c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 15918c2ecf20Sopenharmony_ci pm_runtime_idle(dev); 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 15948c2ecf20Sopenharmony_ci if (dev->of_node) { 15958c2ecf20Sopenharmony_ci const struct device_node *np = dev->of_node; 15968c2ecf20Sopenharmony_ci u32 val; 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "pll-in", &val) >= 0) { 15998c2ecf20Sopenharmony_ci if (val > 6) { 16008c2ecf20Sopenharmony_ci dev_err(dev, "Invalid pll-in\n"); 16018c2ecf20Sopenharmony_ci ret = -EINVAL; 16028c2ecf20Sopenharmony_ci goto err_pm; 16038c2ecf20Sopenharmony_ci } 16048c2ecf20Sopenharmony_ci pcm512x->pll_in = val; 16058c2ecf20Sopenharmony_ci } 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "pll-out", &val) >= 0) { 16088c2ecf20Sopenharmony_ci if (val > 6) { 16098c2ecf20Sopenharmony_ci dev_err(dev, "Invalid pll-out\n"); 16108c2ecf20Sopenharmony_ci ret = -EINVAL; 16118c2ecf20Sopenharmony_ci goto err_pm; 16128c2ecf20Sopenharmony_ci } 16138c2ecf20Sopenharmony_ci pcm512x->pll_out = val; 16148c2ecf20Sopenharmony_ci } 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci if (!pcm512x->pll_in != !pcm512x->pll_out) { 16178c2ecf20Sopenharmony_ci dev_err(dev, 16188c2ecf20Sopenharmony_ci "Error: both pll-in and pll-out, or none\n"); 16198c2ecf20Sopenharmony_ci ret = -EINVAL; 16208c2ecf20Sopenharmony_ci goto err_pm; 16218c2ecf20Sopenharmony_ci } 16228c2ecf20Sopenharmony_ci if (pcm512x->pll_in && pcm512x->pll_in == pcm512x->pll_out) { 16238c2ecf20Sopenharmony_ci dev_err(dev, "Error: pll-in == pll-out\n"); 16248c2ecf20Sopenharmony_ci ret = -EINVAL; 16258c2ecf20Sopenharmony_ci goto err_pm; 16268c2ecf20Sopenharmony_ci } 16278c2ecf20Sopenharmony_ci } 16288c2ecf20Sopenharmony_ci#endif 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(dev, &pcm512x_component_driver, 16318c2ecf20Sopenharmony_ci &pcm512x_dai, 1); 16328c2ecf20Sopenharmony_ci if (ret != 0) { 16338c2ecf20Sopenharmony_ci dev_err(dev, "Failed to register CODEC: %d\n", ret); 16348c2ecf20Sopenharmony_ci goto err_pm; 16358c2ecf20Sopenharmony_ci } 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci return 0; 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_cierr_pm: 16408c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 16418c2ecf20Sopenharmony_cierr_clk: 16428c2ecf20Sopenharmony_ci if (!IS_ERR(pcm512x->sclk)) 16438c2ecf20Sopenharmony_ci clk_disable_unprepare(pcm512x->sclk); 16448c2ecf20Sopenharmony_cierr: 16458c2ecf20Sopenharmony_ci regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), 16468c2ecf20Sopenharmony_ci pcm512x->supplies); 16478c2ecf20Sopenharmony_ci return ret; 16488c2ecf20Sopenharmony_ci} 16498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pcm512x_probe); 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_civoid pcm512x_remove(struct device *dev) 16528c2ecf20Sopenharmony_ci{ 16538c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 16568c2ecf20Sopenharmony_ci if (!IS_ERR(pcm512x->sclk)) 16578c2ecf20Sopenharmony_ci clk_disable_unprepare(pcm512x->sclk); 16588c2ecf20Sopenharmony_ci regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), 16598c2ecf20Sopenharmony_ci pcm512x->supplies); 16608c2ecf20Sopenharmony_ci} 16618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pcm512x_remove); 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 16648c2ecf20Sopenharmony_cistatic int pcm512x_suspend(struct device *dev) 16658c2ecf20Sopenharmony_ci{ 16668c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); 16678c2ecf20Sopenharmony_ci int ret; 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, 16708c2ecf20Sopenharmony_ci PCM512x_RQPD, PCM512x_RQPD); 16718c2ecf20Sopenharmony_ci if (ret != 0) { 16728c2ecf20Sopenharmony_ci dev_err(dev, "Failed to request power down: %d\n", ret); 16738c2ecf20Sopenharmony_ci return ret; 16748c2ecf20Sopenharmony_ci } 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci ret = regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), 16778c2ecf20Sopenharmony_ci pcm512x->supplies); 16788c2ecf20Sopenharmony_ci if (ret != 0) { 16798c2ecf20Sopenharmony_ci dev_err(dev, "Failed to disable supplies: %d\n", ret); 16808c2ecf20Sopenharmony_ci return ret; 16818c2ecf20Sopenharmony_ci } 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci if (!IS_ERR(pcm512x->sclk)) 16848c2ecf20Sopenharmony_ci clk_disable_unprepare(pcm512x->sclk); 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci return 0; 16878c2ecf20Sopenharmony_ci} 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_cistatic int pcm512x_resume(struct device *dev) 16908c2ecf20Sopenharmony_ci{ 16918c2ecf20Sopenharmony_ci struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); 16928c2ecf20Sopenharmony_ci int ret; 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci if (!IS_ERR(pcm512x->sclk)) { 16958c2ecf20Sopenharmony_ci ret = clk_prepare_enable(pcm512x->sclk); 16968c2ecf20Sopenharmony_ci if (ret != 0) { 16978c2ecf20Sopenharmony_ci dev_err(dev, "Failed to enable SCLK: %d\n", ret); 16988c2ecf20Sopenharmony_ci return ret; 16998c2ecf20Sopenharmony_ci } 17008c2ecf20Sopenharmony_ci } 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies), 17038c2ecf20Sopenharmony_ci pcm512x->supplies); 17048c2ecf20Sopenharmony_ci if (ret != 0) { 17058c2ecf20Sopenharmony_ci dev_err(dev, "Failed to enable supplies: %d\n", ret); 17068c2ecf20Sopenharmony_ci return ret; 17078c2ecf20Sopenharmony_ci } 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci regcache_cache_only(pcm512x->regmap, false); 17108c2ecf20Sopenharmony_ci ret = regcache_sync(pcm512x->regmap); 17118c2ecf20Sopenharmony_ci if (ret != 0) { 17128c2ecf20Sopenharmony_ci dev_err(dev, "Failed to sync cache: %d\n", ret); 17138c2ecf20Sopenharmony_ci return ret; 17148c2ecf20Sopenharmony_ci } 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, 17178c2ecf20Sopenharmony_ci PCM512x_RQPD, 0); 17188c2ecf20Sopenharmony_ci if (ret != 0) { 17198c2ecf20Sopenharmony_ci dev_err(dev, "Failed to remove power down: %d\n", ret); 17208c2ecf20Sopenharmony_ci return ret; 17218c2ecf20Sopenharmony_ci } 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci return 0; 17248c2ecf20Sopenharmony_ci} 17258c2ecf20Sopenharmony_ci#endif 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ciconst struct dev_pm_ops pcm512x_pm_ops = { 17288c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL) 17298c2ecf20Sopenharmony_ci}; 17308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pcm512x_pm_ops); 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ASoC PCM512x codec driver"); 17338c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mark Brown <broonie@kernel.org>"); 17348c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1735