162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * max98926.c -- ALSA SoC MAX98926 driver 462306a36Sopenharmony_ci * Copyright 2013-15 Maxim Integrated Products 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/delay.h> 762306a36Sopenharmony_ci#include <linux/i2c.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/regmap.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/cdev.h> 1262306a36Sopenharmony_ci#include <sound/pcm.h> 1362306a36Sopenharmony_ci#include <sound/pcm_params.h> 1462306a36Sopenharmony_ci#include <sound/soc.h> 1562306a36Sopenharmony_ci#include <sound/tlv.h> 1662306a36Sopenharmony_ci#include "max98926.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic const char * const max98926_boost_voltage_txt[] = { 1962306a36Sopenharmony_ci "8.5V", "8.25V", "8.0V", "7.75V", "7.5V", "7.25V", "7.0V", "6.75V", 2062306a36Sopenharmony_ci "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V" 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic const char *const max98926_pdm_ch_text[] = { 2462306a36Sopenharmony_ci "Current", "Voltage", 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic const char *const max98926_hpf_cutoff_txt[] = { 2862306a36Sopenharmony_ci "Disable", "DC Block", "100Hz", 2962306a36Sopenharmony_ci "200Hz", "400Hz", "800Hz", 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic const struct reg_default max98926_reg[] = { 3362306a36Sopenharmony_ci { 0x0B, 0x00 }, /* IRQ Enable0 */ 3462306a36Sopenharmony_ci { 0x0C, 0x00 }, /* IRQ Enable1 */ 3562306a36Sopenharmony_ci { 0x0D, 0x00 }, /* IRQ Enable2 */ 3662306a36Sopenharmony_ci { 0x0E, 0x00 }, /* IRQ Clear0 */ 3762306a36Sopenharmony_ci { 0x0F, 0x00 }, /* IRQ Clear1 */ 3862306a36Sopenharmony_ci { 0x10, 0x00 }, /* IRQ Clear2 */ 3962306a36Sopenharmony_ci { 0x11, 0xC0 }, /* Map0 */ 4062306a36Sopenharmony_ci { 0x12, 0x00 }, /* Map1 */ 4162306a36Sopenharmony_ci { 0x13, 0x00 }, /* Map2 */ 4262306a36Sopenharmony_ci { 0x14, 0xF0 }, /* Map3 */ 4362306a36Sopenharmony_ci { 0x15, 0x00 }, /* Map4 */ 4462306a36Sopenharmony_ci { 0x16, 0xAB }, /* Map5 */ 4562306a36Sopenharmony_ci { 0x17, 0x89 }, /* Map6 */ 4662306a36Sopenharmony_ci { 0x18, 0x00 }, /* Map7 */ 4762306a36Sopenharmony_ci { 0x19, 0x00 }, /* Map8 */ 4862306a36Sopenharmony_ci { 0x1A, 0x04 }, /* DAI Clock Mode 1 */ 4962306a36Sopenharmony_ci { 0x1B, 0x00 }, /* DAI Clock Mode 2 */ 5062306a36Sopenharmony_ci { 0x1C, 0x00 }, /* DAI Clock Divider Denominator MSBs */ 5162306a36Sopenharmony_ci { 0x1D, 0x00 }, /* DAI Clock Divider Denominator LSBs */ 5262306a36Sopenharmony_ci { 0x1E, 0xF0 }, /* DAI Clock Divider Numerator MSBs */ 5362306a36Sopenharmony_ci { 0x1F, 0x00 }, /* DAI Clock Divider Numerator LSBs */ 5462306a36Sopenharmony_ci { 0x20, 0x50 }, /* Format */ 5562306a36Sopenharmony_ci { 0x21, 0x00 }, /* TDM Slot Select */ 5662306a36Sopenharmony_ci { 0x22, 0x00 }, /* DOUT Configuration VMON */ 5762306a36Sopenharmony_ci { 0x23, 0x00 }, /* DOUT Configuration IMON */ 5862306a36Sopenharmony_ci { 0x24, 0x00 }, /* DOUT Configuration VBAT */ 5962306a36Sopenharmony_ci { 0x25, 0x00 }, /* DOUT Configuration VBST */ 6062306a36Sopenharmony_ci { 0x26, 0x00 }, /* DOUT Configuration FLAG */ 6162306a36Sopenharmony_ci { 0x27, 0xFF }, /* DOUT HiZ Configuration 1 */ 6262306a36Sopenharmony_ci { 0x28, 0xFF }, /* DOUT HiZ Configuration 2 */ 6362306a36Sopenharmony_ci { 0x29, 0xFF }, /* DOUT HiZ Configuration 3 */ 6462306a36Sopenharmony_ci { 0x2A, 0xFF }, /* DOUT HiZ Configuration 4 */ 6562306a36Sopenharmony_ci { 0x2B, 0x02 }, /* DOUT Drive Strength */ 6662306a36Sopenharmony_ci { 0x2C, 0x90 }, /* Filters */ 6762306a36Sopenharmony_ci { 0x2D, 0x00 }, /* Gain */ 6862306a36Sopenharmony_ci { 0x2E, 0x02 }, /* Gain Ramping */ 6962306a36Sopenharmony_ci { 0x2F, 0x00 }, /* Speaker Amplifier */ 7062306a36Sopenharmony_ci { 0x30, 0x0A }, /* Threshold */ 7162306a36Sopenharmony_ci { 0x31, 0x00 }, /* ALC Attack */ 7262306a36Sopenharmony_ci { 0x32, 0x80 }, /* ALC Atten and Release */ 7362306a36Sopenharmony_ci { 0x33, 0x00 }, /* ALC Infinite Hold Release */ 7462306a36Sopenharmony_ci { 0x34, 0x92 }, /* ALC Configuration */ 7562306a36Sopenharmony_ci { 0x35, 0x01 }, /* Boost Converter */ 7662306a36Sopenharmony_ci { 0x36, 0x00 }, /* Block Enable */ 7762306a36Sopenharmony_ci { 0x37, 0x00 }, /* Configuration */ 7862306a36Sopenharmony_ci { 0x38, 0x00 }, /* Global Enable */ 7962306a36Sopenharmony_ci { 0x3A, 0x00 }, /* Boost Limiter */ 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic const struct soc_enum max98926_voltage_enum[] = { 8362306a36Sopenharmony_ci SOC_ENUM_SINGLE(MAX98926_DAI_CLK_DIV_N_LSBS, 0, 8462306a36Sopenharmony_ci ARRAY_SIZE(max98926_pdm_ch_text), 8562306a36Sopenharmony_ci max98926_pdm_ch_text), 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic const struct snd_kcontrol_new max98926_voltage_control = 8962306a36Sopenharmony_ci SOC_DAPM_ENUM("Route", max98926_voltage_enum); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic const struct soc_enum max98926_current_enum[] = { 9262306a36Sopenharmony_ci SOC_ENUM_SINGLE(MAX98926_DAI_CLK_DIV_N_LSBS, 9362306a36Sopenharmony_ci MAX98926_PDM_SOURCE_1_SHIFT, 9462306a36Sopenharmony_ci ARRAY_SIZE(max98926_pdm_ch_text), 9562306a36Sopenharmony_ci max98926_pdm_ch_text), 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic const struct snd_kcontrol_new max98926_current_control = 9962306a36Sopenharmony_ci SOC_DAPM_ENUM("Route", max98926_current_enum); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic const struct snd_kcontrol_new max98926_mixer_controls[] = { 10262306a36Sopenharmony_ci SOC_DAPM_SINGLE("PCM Single Switch", MAX98926_SPK_AMP, 10362306a36Sopenharmony_ci MAX98926_INSELECT_MODE_SHIFT, 0, 0), 10462306a36Sopenharmony_ci SOC_DAPM_SINGLE("PDM Single Switch", MAX98926_SPK_AMP, 10562306a36Sopenharmony_ci MAX98926_INSELECT_MODE_SHIFT, 1, 0), 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic const struct snd_kcontrol_new max98926_dai_controls[] = { 10962306a36Sopenharmony_ci SOC_DAPM_SINGLE("Left", MAX98926_GAIN, 11062306a36Sopenharmony_ci MAX98926_DAC_IN_SEL_SHIFT, 0, 0), 11162306a36Sopenharmony_ci SOC_DAPM_SINGLE("Right", MAX98926_GAIN, 11262306a36Sopenharmony_ci MAX98926_DAC_IN_SEL_SHIFT, 1, 0), 11362306a36Sopenharmony_ci SOC_DAPM_SINGLE("LeftRight", MAX98926_GAIN, 11462306a36Sopenharmony_ci MAX98926_DAC_IN_SEL_SHIFT, 2, 0), 11562306a36Sopenharmony_ci SOC_DAPM_SINGLE("(Left+Right)/2 Switch", MAX98926_GAIN, 11662306a36Sopenharmony_ci MAX98926_DAC_IN_SEL_SHIFT, 3, 0), 11762306a36Sopenharmony_ci}; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget max98926_dapm_widgets[] = { 12062306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, 12162306a36Sopenharmony_ci SND_SOC_NOPM, 0, 0), 12262306a36Sopenharmony_ci SND_SOC_DAPM_DAC("Amp Enable", NULL, MAX98926_BLOCK_ENABLE, 12362306a36Sopenharmony_ci MAX98926_SPK_EN_SHIFT, 0), 12462306a36Sopenharmony_ci SND_SOC_DAPM_SUPPLY("Global Enable", MAX98926_GLOBAL_ENABLE, 12562306a36Sopenharmony_ci MAX98926_EN_SHIFT, 0, NULL, 0), 12662306a36Sopenharmony_ci SND_SOC_DAPM_SUPPLY("VI Enable", MAX98926_BLOCK_ENABLE, 12762306a36Sopenharmony_ci MAX98926_ADC_IMON_EN_WIDTH | 12862306a36Sopenharmony_ci MAX98926_ADC_VMON_EN_SHIFT, 12962306a36Sopenharmony_ci 0, NULL, 0), 13062306a36Sopenharmony_ci SND_SOC_DAPM_PGA("BST Enable", MAX98926_BLOCK_ENABLE, 13162306a36Sopenharmony_ci MAX98926_BST_EN_SHIFT, 0, NULL, 0), 13262306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("BE_OUT"), 13362306a36Sopenharmony_ci SND_SOC_DAPM_MIXER("PCM Sel", MAX98926_SPK_AMP, 13462306a36Sopenharmony_ci MAX98926_INSELECT_MODE_SHIFT, 0, 13562306a36Sopenharmony_ci &max98926_mixer_controls[0], 13662306a36Sopenharmony_ci ARRAY_SIZE(max98926_mixer_controls)), 13762306a36Sopenharmony_ci SND_SOC_DAPM_MIXER("DAI Sel", 13862306a36Sopenharmony_ci MAX98926_GAIN, MAX98926_DAC_IN_SEL_SHIFT, 0, 13962306a36Sopenharmony_ci &max98926_dai_controls[0], 14062306a36Sopenharmony_ci ARRAY_SIZE(max98926_dai_controls)), 14162306a36Sopenharmony_ci SND_SOC_DAPM_MUX("PDM CH1 Source", 14262306a36Sopenharmony_ci MAX98926_DAI_CLK_DIV_N_LSBS, 14362306a36Sopenharmony_ci MAX98926_PDM_CURRENT_SHIFT, 14462306a36Sopenharmony_ci 0, &max98926_current_control), 14562306a36Sopenharmony_ci SND_SOC_DAPM_MUX("PDM CH0 Source", 14662306a36Sopenharmony_ci MAX98926_DAI_CLK_DIV_N_LSBS, 14762306a36Sopenharmony_ci MAX98926_PDM_VOLTAGE_SHIFT, 14862306a36Sopenharmony_ci 0, &max98926_voltage_control), 14962306a36Sopenharmony_ci}; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic const struct snd_soc_dapm_route max98926_audio_map[] = { 15262306a36Sopenharmony_ci {"VI Enable", NULL, "DAI_OUT"}, 15362306a36Sopenharmony_ci {"DAI Sel", "Left", "VI Enable"}, 15462306a36Sopenharmony_ci {"DAI Sel", "Right", "VI Enable"}, 15562306a36Sopenharmony_ci {"DAI Sel", "LeftRight", "VI Enable"}, 15662306a36Sopenharmony_ci {"DAI Sel", "LeftRightDiv2", "VI Enable"}, 15762306a36Sopenharmony_ci {"PCM Sel", "PCM", "DAI Sel"}, 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci {"PDM CH1 Source", "Current", "DAI_OUT"}, 16062306a36Sopenharmony_ci {"PDM CH1 Source", "Voltage", "DAI_OUT"}, 16162306a36Sopenharmony_ci {"PDM CH0 Source", "Current", "DAI_OUT"}, 16262306a36Sopenharmony_ci {"PDM CH0 Source", "Voltage", "DAI_OUT"}, 16362306a36Sopenharmony_ci {"PCM Sel", "Analog", "PDM CH1 Source"}, 16462306a36Sopenharmony_ci {"PCM Sel", "Analog", "PDM CH0 Source"}, 16562306a36Sopenharmony_ci {"Amp Enable", NULL, "PCM Sel"}, 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci {"BST Enable", NULL, "Amp Enable"}, 16862306a36Sopenharmony_ci {"BE_OUT", NULL, "BST Enable"}, 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic bool max98926_volatile_register(struct device *dev, unsigned int reg) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci switch (reg) { 17462306a36Sopenharmony_ci case MAX98926_VBAT_DATA: 17562306a36Sopenharmony_ci case MAX98926_VBST_DATA: 17662306a36Sopenharmony_ci case MAX98926_LIVE_STATUS0: 17762306a36Sopenharmony_ci case MAX98926_LIVE_STATUS1: 17862306a36Sopenharmony_ci case MAX98926_LIVE_STATUS2: 17962306a36Sopenharmony_ci case MAX98926_STATE0: 18062306a36Sopenharmony_ci case MAX98926_STATE1: 18162306a36Sopenharmony_ci case MAX98926_STATE2: 18262306a36Sopenharmony_ci case MAX98926_FLAG0: 18362306a36Sopenharmony_ci case MAX98926_FLAG1: 18462306a36Sopenharmony_ci case MAX98926_FLAG2: 18562306a36Sopenharmony_ci case MAX98926_VERSION: 18662306a36Sopenharmony_ci return true; 18762306a36Sopenharmony_ci default: 18862306a36Sopenharmony_ci return false; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic bool max98926_readable_register(struct device *dev, unsigned int reg) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci switch (reg) { 19562306a36Sopenharmony_ci case MAX98926_IRQ_CLEAR0: 19662306a36Sopenharmony_ci case MAX98926_IRQ_CLEAR1: 19762306a36Sopenharmony_ci case MAX98926_IRQ_CLEAR2: 19862306a36Sopenharmony_ci case MAX98926_ALC_HOLD_RLS: 19962306a36Sopenharmony_ci return false; 20062306a36Sopenharmony_ci default: 20162306a36Sopenharmony_ci return true; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci}; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(max98926_spk_tlv, -600, 100, 0); 20662306a36Sopenharmony_cistatic DECLARE_TLV_DB_RANGE(max98926_current_tlv, 20762306a36Sopenharmony_ci 0, 11, TLV_DB_SCALE_ITEM(20, 20, 0), 20862306a36Sopenharmony_ci 12, 15, TLV_DB_SCALE_ITEM(320, 40, 0), 20962306a36Sopenharmony_ci); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(max98926_dac_hpf_cutoff, 21262306a36Sopenharmony_ci MAX98926_FILTERS, MAX98926_DAC_HPF_SHIFT, 21362306a36Sopenharmony_ci max98926_hpf_cutoff_txt); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(max98926_boost_voltage, 21662306a36Sopenharmony_ci MAX98926_CONFIGURATION, MAX98926_BST_VOUT_SHIFT, 21762306a36Sopenharmony_ci max98926_boost_voltage_txt); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic const struct snd_kcontrol_new max98926_snd_controls[] = { 22062306a36Sopenharmony_ci SOC_SINGLE_TLV("Speaker Volume", MAX98926_GAIN, 22162306a36Sopenharmony_ci MAX98926_SPK_GAIN_SHIFT, 22262306a36Sopenharmony_ci (1<<MAX98926_SPK_GAIN_WIDTH)-1, 0, 22362306a36Sopenharmony_ci max98926_spk_tlv), 22462306a36Sopenharmony_ci SOC_SINGLE("Ramp Switch", MAX98926_GAIN_RAMPING, 22562306a36Sopenharmony_ci MAX98926_SPK_RMP_EN_SHIFT, 1, 0), 22662306a36Sopenharmony_ci SOC_SINGLE("ZCD Switch", MAX98926_GAIN_RAMPING, 22762306a36Sopenharmony_ci MAX98926_SPK_ZCD_EN_SHIFT, 1, 0), 22862306a36Sopenharmony_ci SOC_SINGLE("ALC Switch", MAX98926_THRESHOLD, 22962306a36Sopenharmony_ci MAX98926_ALC_EN_SHIFT, 1, 0), 23062306a36Sopenharmony_ci SOC_SINGLE("ALC Threshold", MAX98926_THRESHOLD, 23162306a36Sopenharmony_ci MAX98926_ALC_TH_SHIFT, 23262306a36Sopenharmony_ci (1<<MAX98926_ALC_TH_WIDTH)-1, 0), 23362306a36Sopenharmony_ci SOC_ENUM("Boost Output Voltage", max98926_boost_voltage), 23462306a36Sopenharmony_ci SOC_SINGLE_TLV("Boost Current Limit", MAX98926_BOOST_LIMITER, 23562306a36Sopenharmony_ci MAX98926_BST_ILIM_SHIFT, 23662306a36Sopenharmony_ci (1<<MAX98926_BST_ILIM_SHIFT)-1, 0, 23762306a36Sopenharmony_ci max98926_current_tlv), 23862306a36Sopenharmony_ci SOC_ENUM("DAC HPF Cutoff", max98926_dac_hpf_cutoff), 23962306a36Sopenharmony_ci SOC_DOUBLE("PDM Channel One", MAX98926_DAI_CLK_DIV_N_LSBS, 24062306a36Sopenharmony_ci MAX98926_PDM_CHANNEL_1_SHIFT, 24162306a36Sopenharmony_ci MAX98926_PDM_CHANNEL_1_HIZ, 1, 0), 24262306a36Sopenharmony_ci SOC_DOUBLE("PDM Channel Zero", MAX98926_DAI_CLK_DIV_N_LSBS, 24362306a36Sopenharmony_ci MAX98926_PDM_CHANNEL_0_SHIFT, 24462306a36Sopenharmony_ci MAX98926_PDM_CHANNEL_0_HIZ, 1, 0), 24562306a36Sopenharmony_ci}; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic const struct { 24862306a36Sopenharmony_ci int rate; 24962306a36Sopenharmony_ci int sr; 25062306a36Sopenharmony_ci} rate_table[] = { 25162306a36Sopenharmony_ci { 25262306a36Sopenharmony_ci .rate = 8000, 25362306a36Sopenharmony_ci .sr = 0, 25462306a36Sopenharmony_ci }, 25562306a36Sopenharmony_ci { 25662306a36Sopenharmony_ci .rate = 11025, 25762306a36Sopenharmony_ci .sr = 1, 25862306a36Sopenharmony_ci }, 25962306a36Sopenharmony_ci { 26062306a36Sopenharmony_ci .rate = 12000, 26162306a36Sopenharmony_ci .sr = 2, 26262306a36Sopenharmony_ci }, 26362306a36Sopenharmony_ci { 26462306a36Sopenharmony_ci .rate = 16000, 26562306a36Sopenharmony_ci .sr = 3, 26662306a36Sopenharmony_ci }, 26762306a36Sopenharmony_ci { 26862306a36Sopenharmony_ci .rate = 22050, 26962306a36Sopenharmony_ci .sr = 4, 27062306a36Sopenharmony_ci }, 27162306a36Sopenharmony_ci { 27262306a36Sopenharmony_ci .rate = 24000, 27362306a36Sopenharmony_ci .sr = 5, 27462306a36Sopenharmony_ci }, 27562306a36Sopenharmony_ci { 27662306a36Sopenharmony_ci .rate = 32000, 27762306a36Sopenharmony_ci .sr = 6, 27862306a36Sopenharmony_ci }, 27962306a36Sopenharmony_ci { 28062306a36Sopenharmony_ci .rate = 44100, 28162306a36Sopenharmony_ci .sr = 7, 28262306a36Sopenharmony_ci }, 28362306a36Sopenharmony_ci { 28462306a36Sopenharmony_ci .rate = 48000, 28562306a36Sopenharmony_ci .sr = 8, 28662306a36Sopenharmony_ci }, 28762306a36Sopenharmony_ci}; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic void max98926_set_sense_data(struct max98926_priv *max98926) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci regmap_update_bits(max98926->regmap, 29262306a36Sopenharmony_ci MAX98926_DOUT_CFG_VMON, 29362306a36Sopenharmony_ci MAX98926_DAI_VMON_EN_MASK, 29462306a36Sopenharmony_ci MAX98926_DAI_VMON_EN_MASK); 29562306a36Sopenharmony_ci regmap_update_bits(max98926->regmap, 29662306a36Sopenharmony_ci MAX98926_DOUT_CFG_IMON, 29762306a36Sopenharmony_ci MAX98926_DAI_IMON_EN_MASK, 29862306a36Sopenharmony_ci MAX98926_DAI_IMON_EN_MASK); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (!max98926->interleave_mode) { 30162306a36Sopenharmony_ci /* set VMON slots */ 30262306a36Sopenharmony_ci regmap_update_bits(max98926->regmap, 30362306a36Sopenharmony_ci MAX98926_DOUT_CFG_VMON, 30462306a36Sopenharmony_ci MAX98926_DAI_VMON_SLOT_MASK, 30562306a36Sopenharmony_ci max98926->v_slot); 30662306a36Sopenharmony_ci /* set IMON slots */ 30762306a36Sopenharmony_ci regmap_update_bits(max98926->regmap, 30862306a36Sopenharmony_ci MAX98926_DOUT_CFG_IMON, 30962306a36Sopenharmony_ci MAX98926_DAI_IMON_SLOT_MASK, 31062306a36Sopenharmony_ci max98926->i_slot); 31162306a36Sopenharmony_ci } else { 31262306a36Sopenharmony_ci /* enable interleave mode */ 31362306a36Sopenharmony_ci regmap_update_bits(max98926->regmap, 31462306a36Sopenharmony_ci MAX98926_FORMAT, 31562306a36Sopenharmony_ci MAX98926_DAI_INTERLEAVE_MASK, 31662306a36Sopenharmony_ci MAX98926_DAI_INTERLEAVE_MASK); 31762306a36Sopenharmony_ci /* set interleave slots */ 31862306a36Sopenharmony_ci regmap_update_bits(max98926->regmap, 31962306a36Sopenharmony_ci MAX98926_DOUT_CFG_VBAT, 32062306a36Sopenharmony_ci MAX98926_DAI_INTERLEAVE_SLOT_MASK, 32162306a36Sopenharmony_ci max98926->v_slot); 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic int max98926_dai_set_fmt(struct snd_soc_dai *codec_dai, 32662306a36Sopenharmony_ci unsigned int fmt) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 32962306a36Sopenharmony_ci struct max98926_priv *max98926 = snd_soc_component_get_drvdata(component); 33062306a36Sopenharmony_ci unsigned int invert = 0; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 33562306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBC_CFC: 33662306a36Sopenharmony_ci max98926_set_sense_data(max98926); 33762306a36Sopenharmony_ci break; 33862306a36Sopenharmony_ci default: 33962306a36Sopenharmony_ci dev_err(component->dev, "DAI clock mode unsupported\n"); 34062306a36Sopenharmony_ci return -EINVAL; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 34462306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 34562306a36Sopenharmony_ci break; 34662306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_IF: 34762306a36Sopenharmony_ci invert = MAX98926_DAI_WCI_MASK; 34862306a36Sopenharmony_ci break; 34962306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 35062306a36Sopenharmony_ci invert = MAX98926_DAI_BCI_MASK; 35162306a36Sopenharmony_ci break; 35262306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_IF: 35362306a36Sopenharmony_ci invert = MAX98926_DAI_BCI_MASK | MAX98926_DAI_WCI_MASK; 35462306a36Sopenharmony_ci break; 35562306a36Sopenharmony_ci default: 35662306a36Sopenharmony_ci dev_err(component->dev, "DAI invert mode unsupported\n"); 35762306a36Sopenharmony_ci return -EINVAL; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci regmap_write(max98926->regmap, 36162306a36Sopenharmony_ci MAX98926_FORMAT, MAX98926_DAI_DLY_MASK); 36262306a36Sopenharmony_ci regmap_update_bits(max98926->regmap, MAX98926_FORMAT, 36362306a36Sopenharmony_ci MAX98926_DAI_BCI_MASK, invert); 36462306a36Sopenharmony_ci return 0; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic int max98926_dai_hw_params(struct snd_pcm_substream *substream, 36862306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 36962306a36Sopenharmony_ci struct snd_soc_dai *dai) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci int dai_sr = -EINVAL; 37262306a36Sopenharmony_ci int rate = params_rate(params), i; 37362306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 37462306a36Sopenharmony_ci struct max98926_priv *max98926 = snd_soc_component_get_drvdata(component); 37562306a36Sopenharmony_ci int blr_clk_ratio; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci switch (params_format(params)) { 37862306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 37962306a36Sopenharmony_ci regmap_update_bits(max98926->regmap, 38062306a36Sopenharmony_ci MAX98926_FORMAT, 38162306a36Sopenharmony_ci MAX98926_DAI_CHANSZ_MASK, 38262306a36Sopenharmony_ci MAX98926_DAI_CHANSZ_16); 38362306a36Sopenharmony_ci max98926->ch_size = 16; 38462306a36Sopenharmony_ci break; 38562306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 38662306a36Sopenharmony_ci regmap_update_bits(max98926->regmap, 38762306a36Sopenharmony_ci MAX98926_FORMAT, 38862306a36Sopenharmony_ci MAX98926_DAI_CHANSZ_MASK, 38962306a36Sopenharmony_ci MAX98926_DAI_CHANSZ_24); 39062306a36Sopenharmony_ci max98926->ch_size = 24; 39162306a36Sopenharmony_ci break; 39262306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S32_LE: 39362306a36Sopenharmony_ci regmap_update_bits(max98926->regmap, 39462306a36Sopenharmony_ci MAX98926_FORMAT, 39562306a36Sopenharmony_ci MAX98926_DAI_CHANSZ_MASK, 39662306a36Sopenharmony_ci MAX98926_DAI_CHANSZ_32); 39762306a36Sopenharmony_ci max98926->ch_size = 32; 39862306a36Sopenharmony_ci break; 39962306a36Sopenharmony_ci default: 40062306a36Sopenharmony_ci dev_dbg(component->dev, "format unsupported %d\n", 40162306a36Sopenharmony_ci params_format(params)); 40262306a36Sopenharmony_ci return -EINVAL; 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* BCLK/LRCLK ratio calculation */ 40662306a36Sopenharmony_ci blr_clk_ratio = params_channels(params) * max98926->ch_size; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci switch (blr_clk_ratio) { 40962306a36Sopenharmony_ci case 32: 41062306a36Sopenharmony_ci regmap_update_bits(max98926->regmap, 41162306a36Sopenharmony_ci MAX98926_DAI_CLK_MODE2, 41262306a36Sopenharmony_ci MAX98926_DAI_BSEL_MASK, 41362306a36Sopenharmony_ci MAX98926_DAI_BSEL_32); 41462306a36Sopenharmony_ci break; 41562306a36Sopenharmony_ci case 48: 41662306a36Sopenharmony_ci regmap_update_bits(max98926->regmap, 41762306a36Sopenharmony_ci MAX98926_DAI_CLK_MODE2, 41862306a36Sopenharmony_ci MAX98926_DAI_BSEL_MASK, 41962306a36Sopenharmony_ci MAX98926_DAI_BSEL_48); 42062306a36Sopenharmony_ci break; 42162306a36Sopenharmony_ci case 64: 42262306a36Sopenharmony_ci regmap_update_bits(max98926->regmap, 42362306a36Sopenharmony_ci MAX98926_DAI_CLK_MODE2, 42462306a36Sopenharmony_ci MAX98926_DAI_BSEL_MASK, 42562306a36Sopenharmony_ci MAX98926_DAI_BSEL_64); 42662306a36Sopenharmony_ci break; 42762306a36Sopenharmony_ci default: 42862306a36Sopenharmony_ci return -EINVAL; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci /* find the closest rate */ 43262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rate_table); i++) { 43362306a36Sopenharmony_ci if (rate_table[i].rate >= rate) { 43462306a36Sopenharmony_ci dai_sr = rate_table[i].sr; 43562306a36Sopenharmony_ci break; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci if (dai_sr < 0) 43962306a36Sopenharmony_ci return -EINVAL; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci /* set DAI_SR to correct LRCLK frequency */ 44262306a36Sopenharmony_ci regmap_update_bits(max98926->regmap, 44362306a36Sopenharmony_ci MAX98926_DAI_CLK_MODE2, 44462306a36Sopenharmony_ci MAX98926_DAI_SR_MASK, dai_sr << MAX98926_DAI_SR_SHIFT); 44562306a36Sopenharmony_ci return 0; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci#define MAX98926_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 44962306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic const struct snd_soc_dai_ops max98926_dai_ops = { 45262306a36Sopenharmony_ci .set_fmt = max98926_dai_set_fmt, 45362306a36Sopenharmony_ci .hw_params = max98926_dai_hw_params, 45462306a36Sopenharmony_ci}; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic struct snd_soc_dai_driver max98926_dai[] = { 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci .name = "max98926-aif1", 45962306a36Sopenharmony_ci .playback = { 46062306a36Sopenharmony_ci .stream_name = "HiFi Playback", 46162306a36Sopenharmony_ci .channels_min = 1, 46262306a36Sopenharmony_ci .channels_max = 2, 46362306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_48000, 46462306a36Sopenharmony_ci .formats = MAX98926_FORMATS, 46562306a36Sopenharmony_ci }, 46662306a36Sopenharmony_ci .capture = { 46762306a36Sopenharmony_ci .stream_name = "HiFi Capture", 46862306a36Sopenharmony_ci .channels_min = 1, 46962306a36Sopenharmony_ci .channels_max = 2, 47062306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_48000, 47162306a36Sopenharmony_ci .formats = MAX98926_FORMATS, 47262306a36Sopenharmony_ci }, 47362306a36Sopenharmony_ci .ops = &max98926_dai_ops, 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci}; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic int max98926_probe(struct snd_soc_component *component) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct max98926_priv *max98926 = snd_soc_component_get_drvdata(component); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci max98926->component = component; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci /* Hi-Z all the slots */ 48462306a36Sopenharmony_ci regmap_write(max98926->regmap, MAX98926_DOUT_HIZ_CFG4, 0xF0); 48562306a36Sopenharmony_ci return 0; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_max98926 = { 48962306a36Sopenharmony_ci .probe = max98926_probe, 49062306a36Sopenharmony_ci .controls = max98926_snd_controls, 49162306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(max98926_snd_controls), 49262306a36Sopenharmony_ci .dapm_routes = max98926_audio_map, 49362306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(max98926_audio_map), 49462306a36Sopenharmony_ci .dapm_widgets = max98926_dapm_widgets, 49562306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(max98926_dapm_widgets), 49662306a36Sopenharmony_ci .idle_bias_on = 1, 49762306a36Sopenharmony_ci .use_pmdown_time = 1, 49862306a36Sopenharmony_ci .endianness = 1, 49962306a36Sopenharmony_ci}; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic const struct regmap_config max98926_regmap = { 50262306a36Sopenharmony_ci .reg_bits = 8, 50362306a36Sopenharmony_ci .val_bits = 8, 50462306a36Sopenharmony_ci .max_register = MAX98926_VERSION, 50562306a36Sopenharmony_ci .reg_defaults = max98926_reg, 50662306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(max98926_reg), 50762306a36Sopenharmony_ci .volatile_reg = max98926_volatile_register, 50862306a36Sopenharmony_ci .readable_reg = max98926_readable_register, 50962306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 51062306a36Sopenharmony_ci}; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic int max98926_i2c_probe(struct i2c_client *i2c) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci int ret, reg; 51562306a36Sopenharmony_ci u32 value; 51662306a36Sopenharmony_ci struct max98926_priv *max98926; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci max98926 = devm_kzalloc(&i2c->dev, 51962306a36Sopenharmony_ci sizeof(*max98926), GFP_KERNEL); 52062306a36Sopenharmony_ci if (!max98926) 52162306a36Sopenharmony_ci return -ENOMEM; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci i2c_set_clientdata(i2c, max98926); 52462306a36Sopenharmony_ci max98926->regmap = devm_regmap_init_i2c(i2c, &max98926_regmap); 52562306a36Sopenharmony_ci if (IS_ERR(max98926->regmap)) { 52662306a36Sopenharmony_ci ret = PTR_ERR(max98926->regmap); 52762306a36Sopenharmony_ci dev_err(&i2c->dev, 52862306a36Sopenharmony_ci "Failed to allocate regmap: %d\n", ret); 52962306a36Sopenharmony_ci goto err_out; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci if (of_property_read_bool(i2c->dev.of_node, "maxim,interleave-mode") || 53262306a36Sopenharmony_ci of_property_read_bool(i2c->dev.of_node, "interleave-mode")) 53362306a36Sopenharmony_ci max98926->interleave_mode = true; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (!of_property_read_u32(i2c->dev.of_node, "vmon-slot-no", &value)) { 53662306a36Sopenharmony_ci if (value > MAX98926_DAI_VMON_SLOT_1E_1F) { 53762306a36Sopenharmony_ci dev_err(&i2c->dev, "vmon slot number is wrong:\n"); 53862306a36Sopenharmony_ci return -EINVAL; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci max98926->v_slot = value; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci if (!of_property_read_u32(i2c->dev.of_node, "imon-slot-no", &value)) { 54362306a36Sopenharmony_ci if (value > MAX98926_DAI_IMON_SLOT_1E_1F) { 54462306a36Sopenharmony_ci dev_err(&i2c->dev, "imon slot number is wrong:\n"); 54562306a36Sopenharmony_ci return -EINVAL; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci max98926->i_slot = value; 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci ret = regmap_read(max98926->regmap, 55062306a36Sopenharmony_ci MAX98926_VERSION, ®); 55162306a36Sopenharmony_ci if (ret < 0) { 55262306a36Sopenharmony_ci dev_err(&i2c->dev, "Failed to read: %x\n", reg); 55362306a36Sopenharmony_ci return ret; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci ret = devm_snd_soc_register_component(&i2c->dev, 55762306a36Sopenharmony_ci &soc_component_dev_max98926, 55862306a36Sopenharmony_ci max98926_dai, ARRAY_SIZE(max98926_dai)); 55962306a36Sopenharmony_ci if (ret < 0) 56062306a36Sopenharmony_ci dev_err(&i2c->dev, 56162306a36Sopenharmony_ci "Failed to register component: %d\n", ret); 56262306a36Sopenharmony_ci dev_info(&i2c->dev, "device version: %x\n", reg); 56362306a36Sopenharmony_cierr_out: 56462306a36Sopenharmony_ci return ret; 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cistatic const struct i2c_device_id max98926_i2c_id[] = { 56862306a36Sopenharmony_ci { "max98926", 0 }, 56962306a36Sopenharmony_ci { } 57062306a36Sopenharmony_ci}; 57162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, max98926_i2c_id); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci#ifdef CONFIG_OF 57462306a36Sopenharmony_cistatic const struct of_device_id max98926_of_match[] = { 57562306a36Sopenharmony_ci { .compatible = "maxim,max98926", }, 57662306a36Sopenharmony_ci { } 57762306a36Sopenharmony_ci}; 57862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, max98926_of_match); 57962306a36Sopenharmony_ci#endif 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_cistatic struct i2c_driver max98926_i2c_driver = { 58262306a36Sopenharmony_ci .driver = { 58362306a36Sopenharmony_ci .name = "max98926", 58462306a36Sopenharmony_ci .of_match_table = of_match_ptr(max98926_of_match), 58562306a36Sopenharmony_ci }, 58662306a36Sopenharmony_ci .probe = max98926_i2c_probe, 58762306a36Sopenharmony_ci .id_table = max98926_i2c_id, 58862306a36Sopenharmony_ci}; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cimodule_i2c_driver(max98926_i2c_driver) 59162306a36Sopenharmony_ciMODULE_DESCRIPTION("ALSA SoC MAX98926 driver"); 59262306a36Sopenharmony_ciMODULE_AUTHOR("Anish kumar <anish.kumar@maximintegrated.com>"); 59362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 594