18084945dSLadislav Michl // SPDX-License-Identifier: GPL-2.0 28084945dSLadislav Michl // 38084945dSLadislav Michl // MAX9867 ALSA SoC codec driver 48084945dSLadislav Michl // 58084945dSLadislav Michl // Copyright 2013-2015 Maxim Integrated Products 68084945dSLadislav Michl // Copyright 2018 Ladislav Michl <ladis@linux-mips.org> 78084945dSLadislav Michl // 8805d132dSanish kumar 9*448b06baSBenjamin Bara #include <linux/clk.h> 10805d132dSanish kumar #include <linux/delay.h> 11805d132dSanish kumar #include <linux/i2c.h> 12805d132dSanish kumar #include <linux/module.h> 13805d132dSanish kumar #include <linux/regmap.h> 14805d132dSanish kumar #include <sound/pcm_params.h> 15805d132dSanish kumar #include <sound/soc.h> 16805d132dSanish kumar #include <sound/tlv.h> 17805d132dSanish kumar #include "max9867.h" 18805d132dSanish kumar 19a11ffbbaSPavel Dobias struct max9867_priv { 20*448b06baSBenjamin Bara struct clk *mclk; 21a11ffbbaSPavel Dobias struct regmap *regmap; 22a11ffbbaSPavel Dobias const struct snd_pcm_hw_constraint_list *constraints; 23a11ffbbaSPavel Dobias unsigned int sysclk, pclk; 242594d0aaSMark Brown bool provider, dsp_a; 25a11ffbbaSPavel Dobias unsigned int adc_dac_active; 26a11ffbbaSPavel Dobias }; 27a11ffbbaSPavel Dobias 28805d132dSanish kumar static const char *const max9867_spmode[] = { 29805d132dSanish kumar "Stereo Diff", "Mono Diff", 30805d132dSanish kumar "Stereo Cap", "Mono Cap", 31805d132dSanish kumar "Stereo Single", "Mono Single", 32805d132dSanish kumar "Stereo Single Fast", "Mono Single Fast" 33805d132dSanish kumar }; 34805d132dSanish kumar static const char *const max9867_filter_text[] = {"IIR", "FIR"}; 35805d132dSanish kumar 36af53d573SPavel Dobias static const char *const max9867_adc_dac_filter_text[] = { 37af53d573SPavel Dobias "Disabled", 38af53d573SPavel Dobias "Elliptical/16/256", 39af53d573SPavel Dobias "Butterworth/16/500", 40af53d573SPavel Dobias "Elliptical/8/256", 41af53d573SPavel Dobias "Butterworth/8/500", 42af53d573SPavel Dobias "Butterworth/8-24" 43af53d573SPavel Dobias }; 44af53d573SPavel Dobias 45a11ffbbaSPavel Dobias enum max9867_adc_dac { 46a11ffbbaSPavel Dobias MAX9867_ADC_LEFT, 47a11ffbbaSPavel Dobias MAX9867_ADC_RIGHT, 48a11ffbbaSPavel Dobias MAX9867_DAC_LEFT, 49a11ffbbaSPavel Dobias MAX9867_DAC_RIGHT, 50a11ffbbaSPavel Dobias }; 51a11ffbbaSPavel Dobias 52a11ffbbaSPavel Dobias static int max9867_adc_dac_event(struct snd_soc_dapm_widget *w, 53a11ffbbaSPavel Dobias struct snd_kcontrol *kcontrol, int event) 54a11ffbbaSPavel Dobias { 55a11ffbbaSPavel Dobias struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 56a11ffbbaSPavel Dobias struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); 57a11ffbbaSPavel Dobias enum max9867_adc_dac adc_dac; 58a11ffbbaSPavel Dobias 59a11ffbbaSPavel Dobias if (!strcmp(w->name, "ADCL")) 60a11ffbbaSPavel Dobias adc_dac = MAX9867_ADC_LEFT; 61a11ffbbaSPavel Dobias else if (!strcmp(w->name, "ADCR")) 62a11ffbbaSPavel Dobias adc_dac = MAX9867_ADC_RIGHT; 63a11ffbbaSPavel Dobias else if (!strcmp(w->name, "DACL")) 64a11ffbbaSPavel Dobias adc_dac = MAX9867_DAC_LEFT; 65a11ffbbaSPavel Dobias else if (!strcmp(w->name, "DACR")) 66a11ffbbaSPavel Dobias adc_dac = MAX9867_DAC_RIGHT; 67a11ffbbaSPavel Dobias else 68a11ffbbaSPavel Dobias return 0; 69a11ffbbaSPavel Dobias 70a11ffbbaSPavel Dobias if (SND_SOC_DAPM_EVENT_ON(event)) 71a11ffbbaSPavel Dobias max9867->adc_dac_active |= BIT(adc_dac); 72a11ffbbaSPavel Dobias else if (SND_SOC_DAPM_EVENT_OFF(event)) 73a11ffbbaSPavel Dobias max9867->adc_dac_active &= ~BIT(adc_dac); 74a11ffbbaSPavel Dobias 75a11ffbbaSPavel Dobias return 0; 76a11ffbbaSPavel Dobias } 77a11ffbbaSPavel Dobias 78a11ffbbaSPavel Dobias static int max9867_filter_get(struct snd_kcontrol *kcontrol, 79a11ffbbaSPavel Dobias struct snd_ctl_elem_value *ucontrol) 80a11ffbbaSPavel Dobias { 81a11ffbbaSPavel Dobias struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 82a11ffbbaSPavel Dobias struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); 83a11ffbbaSPavel Dobias unsigned int reg; 84a11ffbbaSPavel Dobias int ret; 85a11ffbbaSPavel Dobias 86a11ffbbaSPavel Dobias ret = regmap_read(max9867->regmap, MAX9867_CODECFLTR, ®); 87a11ffbbaSPavel Dobias if (ret) 88a11ffbbaSPavel Dobias return -EINVAL; 89a11ffbbaSPavel Dobias 90a11ffbbaSPavel Dobias if (reg & MAX9867_CODECFLTR_MODE) 91a11ffbbaSPavel Dobias ucontrol->value.enumerated.item[0] = 1; 92a11ffbbaSPavel Dobias else 93a11ffbbaSPavel Dobias ucontrol->value.enumerated.item[0] = 0; 94a11ffbbaSPavel Dobias 95a11ffbbaSPavel Dobias return 0; 96a11ffbbaSPavel Dobias } 97a11ffbbaSPavel Dobias 98a11ffbbaSPavel Dobias static int max9867_filter_set(struct snd_kcontrol *kcontrol, 99a11ffbbaSPavel Dobias struct snd_ctl_elem_value *ucontrol) 100a11ffbbaSPavel Dobias { 101a11ffbbaSPavel Dobias struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 102a11ffbbaSPavel Dobias struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); 103a11ffbbaSPavel Dobias unsigned int reg, mode = ucontrol->value.enumerated.item[0]; 104a11ffbbaSPavel Dobias int ret; 105a11ffbbaSPavel Dobias 106a11ffbbaSPavel Dobias if (mode > 1) 107a11ffbbaSPavel Dobias return -EINVAL; 108a11ffbbaSPavel Dobias 109a11ffbbaSPavel Dobias /* don't allow change if ADC/DAC active */ 110a11ffbbaSPavel Dobias if (max9867->adc_dac_active) 111a11ffbbaSPavel Dobias return -EBUSY; 112a11ffbbaSPavel Dobias 113a11ffbbaSPavel Dobias /* read current filter mode */ 114a11ffbbaSPavel Dobias ret = regmap_read(max9867->regmap, MAX9867_CODECFLTR, ®); 115a11ffbbaSPavel Dobias if (ret) 116a11ffbbaSPavel Dobias return -EINVAL; 117a11ffbbaSPavel Dobias 118a11ffbbaSPavel Dobias if (mode) 119a11ffbbaSPavel Dobias mode = MAX9867_CODECFLTR_MODE; 120a11ffbbaSPavel Dobias 121a11ffbbaSPavel Dobias /* check if change is needed */ 122a11ffbbaSPavel Dobias if ((reg & MAX9867_CODECFLTR_MODE) == mode) 123a11ffbbaSPavel Dobias return 0; 124a11ffbbaSPavel Dobias 125a11ffbbaSPavel Dobias /* shutdown codec before switching filter mode */ 126a11ffbbaSPavel Dobias regmap_update_bits(max9867->regmap, MAX9867_PWRMAN, 127a11ffbbaSPavel Dobias MAX9867_PWRMAN_SHDN, 0); 128a11ffbbaSPavel Dobias 129a11ffbbaSPavel Dobias /* switch filter mode */ 130a11ffbbaSPavel Dobias regmap_update_bits(max9867->regmap, MAX9867_CODECFLTR, 131a11ffbbaSPavel Dobias MAX9867_CODECFLTR_MODE, mode); 132a11ffbbaSPavel Dobias 133a11ffbbaSPavel Dobias /* out of shutdown now */ 134a11ffbbaSPavel Dobias regmap_update_bits(max9867->regmap, MAX9867_PWRMAN, 135a11ffbbaSPavel Dobias MAX9867_PWRMAN_SHDN, MAX9867_PWRMAN_SHDN); 136a11ffbbaSPavel Dobias 137a11ffbbaSPavel Dobias return 0; 138a11ffbbaSPavel Dobias } 139a11ffbbaSPavel Dobias 140a11ffbbaSPavel Dobias static SOC_ENUM_SINGLE_EXT_DECL(max9867_filter, max9867_filter_text); 141af53d573SPavel Dobias static SOC_ENUM_SINGLE_DECL(max9867_dac_filter, MAX9867_CODECFLTR, 0, 142af53d573SPavel Dobias max9867_adc_dac_filter_text); 143af53d573SPavel Dobias static SOC_ENUM_SINGLE_DECL(max9867_adc_filter, MAX9867_CODECFLTR, 4, 144af53d573SPavel Dobias max9867_adc_dac_filter_text); 145805d132dSanish kumar static SOC_ENUM_SINGLE_DECL(max9867_spkmode, MAX9867_MODECONFIG, 0, 146805d132dSanish kumar max9867_spmode); 147bc2610a6SLadislav Michl static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max9867_master_tlv, 148bc2610a6SLadislav Michl 0, 2, TLV_DB_SCALE_ITEM(-8600, 200, 1), 149bc2610a6SLadislav Michl 3, 17, TLV_DB_SCALE_ITEM(-7800, 400, 0), 150bc2610a6SLadislav Michl 18, 25, TLV_DB_SCALE_ITEM(-2000, 200, 0), 151bc2610a6SLadislav Michl 26, 34, TLV_DB_SCALE_ITEM( -500, 100, 0), 152bc2610a6SLadislav Michl 35, 40, TLV_DB_SCALE_ITEM( 350, 50, 0), 153bc2610a6SLadislav Michl ); 154bc2610a6SLadislav Michl static DECLARE_TLV_DB_SCALE(max9867_mic_tlv, 0, 100, 0); 155bc2610a6SLadislav Michl static DECLARE_TLV_DB_SCALE(max9867_line_tlv, -600, 200, 0); 156bc2610a6SLadislav Michl static DECLARE_TLV_DB_SCALE(max9867_adc_tlv, -1200, 100, 0); 157bc2610a6SLadislav Michl static DECLARE_TLV_DB_SCALE(max9867_dac_tlv, -1500, 100, 0); 158bc2610a6SLadislav Michl static DECLARE_TLV_DB_SCALE(max9867_dacboost_tlv, 0, 600, 0); 159bc2610a6SLadislav Michl static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max9867_micboost_tlv, 160bc2610a6SLadislav Michl 0, 2, TLV_DB_SCALE_ITEM(-2000, 2000, 1), 161bc2610a6SLadislav Michl 3, 3, TLV_DB_SCALE_ITEM(3000, 0, 0), 162349fa18cSTakashi Sakamoto ); 163805d132dSanish kumar 164805d132dSanish kumar static const struct snd_kcontrol_new max9867_snd_controls[] = { 165bc2610a6SLadislav Michl SOC_DOUBLE_R_TLV("Master Playback Volume", MAX9867_LEFTVOL, 1668ba4dc3cSPavel Dobias MAX9867_RIGHTVOL, 0, 40, 1, max9867_master_tlv), 167bc2610a6SLadislav Michl SOC_DOUBLE_R_TLV("Line Capture Volume", MAX9867_LEFTLINELVL, 168bc2610a6SLadislav Michl MAX9867_RIGHTLINELVL, 0, 15, 1, max9867_line_tlv), 169bc2610a6SLadislav Michl SOC_DOUBLE_R_TLV("Mic Capture Volume", MAX9867_LEFTMICGAIN, 170bc2610a6SLadislav Michl MAX9867_RIGHTMICGAIN, 0, 20, 1, max9867_mic_tlv), 171bc2610a6SLadislav Michl SOC_DOUBLE_R_TLV("Mic Boost Capture Volume", MAX9867_LEFTMICGAIN, 1728ba4dc3cSPavel Dobias MAX9867_RIGHTMICGAIN, 5, 3, 0, max9867_micboost_tlv), 173bc2610a6SLadislav Michl SOC_SINGLE("Digital Sidetone Volume", MAX9867_SIDETONE, 0, 31, 1), 174bc2610a6SLadislav Michl SOC_SINGLE_TLV("Digital Playback Volume", MAX9867_DACLEVEL, 0, 15, 1, 175bc2610a6SLadislav Michl max9867_dac_tlv), 176bc2610a6SLadislav Michl SOC_SINGLE_TLV("Digital Boost Playback Volume", MAX9867_DACLEVEL, 4, 3, 0, 177bc2610a6SLadislav Michl max9867_dacboost_tlv), 17853a58bf9SPavel Dobias SOC_DOUBLE_TLV("Digital Capture Volume", MAX9867_ADCLEVEL, 4, 0, 15, 1, 179bc2610a6SLadislav Michl max9867_adc_tlv), 180805d132dSanish kumar SOC_ENUM("Speaker Mode", max9867_spkmode), 181805d132dSanish kumar SOC_SINGLE("Volume Smoothing Switch", MAX9867_MODECONFIG, 6, 1, 0), 182bc2610a6SLadislav Michl SOC_SINGLE("Line ZC Switch", MAX9867_MODECONFIG, 5, 1, 0), 183a11ffbbaSPavel Dobias SOC_ENUM_EXT("DSP Filter", max9867_filter, max9867_filter_get, max9867_filter_set), 184af53d573SPavel Dobias SOC_ENUM("ADC Filter", max9867_adc_filter), 185af53d573SPavel Dobias SOC_ENUM("DAC Filter", max9867_dac_filter), 18680b9fa4dSPavel Dobias SOC_SINGLE("Mono Playback Switch", MAX9867_IFC1B, 3, 1, 0), 187805d132dSanish kumar }; 188805d132dSanish kumar 189bc2610a6SLadislav Michl /* Input mixer */ 190bc2610a6SLadislav Michl static const struct snd_kcontrol_new max9867_input_mixer_controls[] = { 191bc2610a6SLadislav Michl SOC_DAPM_DOUBLE("Line Capture Switch", MAX9867_INPUTCONFIG, 7, 5, 1, 0), 192bc2610a6SLadislav Michl SOC_DAPM_DOUBLE("Mic Capture Switch", MAX9867_INPUTCONFIG, 6, 4, 1, 0), 193bc2610a6SLadislav Michl }; 194805d132dSanish kumar 195bc2610a6SLadislav Michl /* Output mixer */ 196bc2610a6SLadislav Michl static const struct snd_kcontrol_new max9867_output_mixer_controls[] = { 197bc2610a6SLadislav Michl SOC_DAPM_DOUBLE_R("Line Bypass Switch", 198bc2610a6SLadislav Michl MAX9867_LEFTLINELVL, MAX9867_RIGHTLINELVL, 6, 1, 1), 199bc2610a6SLadislav Michl }; 200805d132dSanish kumar 201bc2610a6SLadislav Michl /* Sidetone mixer */ 202bc2610a6SLadislav Michl static const struct snd_kcontrol_new max9867_sidetone_mixer_controls[] = { 203bc2610a6SLadislav Michl SOC_DAPM_DOUBLE("Sidetone Switch", MAX9867_SIDETONE, 6, 7, 1, 0), 204bc2610a6SLadislav Michl }; 205805d132dSanish kumar 206bc2610a6SLadislav Michl /* Line out switch */ 207bc2610a6SLadislav Michl static const struct snd_kcontrol_new max9867_line_out_control = 208bc2610a6SLadislav Michl SOC_DAPM_DOUBLE_R("Switch", 209bc2610a6SLadislav Michl MAX9867_LEFTVOL, MAX9867_RIGHTVOL, 6, 1, 1); 210bc2610a6SLadislav Michl 211980b63f8SPavel Dobias /* DMIC mux */ 212980b63f8SPavel Dobias static const char *const dmic_mux_text[] = { 213980b63f8SPavel Dobias "ADC", "DMIC" 214980b63f8SPavel Dobias }; 215980b63f8SPavel Dobias static SOC_ENUM_SINGLE_DECL(left_dmic_mux_enum, 216980b63f8SPavel Dobias MAX9867_MICCONFIG, 5, dmic_mux_text); 217980b63f8SPavel Dobias static SOC_ENUM_SINGLE_DECL(right_dmic_mux_enum, 218980b63f8SPavel Dobias MAX9867_MICCONFIG, 4, dmic_mux_text); 219980b63f8SPavel Dobias static const struct snd_kcontrol_new max9867_left_dmic_mux = 220980b63f8SPavel Dobias SOC_DAPM_ENUM("DMICL Mux", left_dmic_mux_enum); 221980b63f8SPavel Dobias static const struct snd_kcontrol_new max9867_right_dmic_mux = 222980b63f8SPavel Dobias SOC_DAPM_ENUM("DMICR Mux", right_dmic_mux_enum); 223805d132dSanish kumar 224805d132dSanish kumar static const struct snd_soc_dapm_widget max9867_dapm_widgets[] = { 225bc2610a6SLadislav Michl SND_SOC_DAPM_INPUT("MICL"), 226bc2610a6SLadislav Michl SND_SOC_DAPM_INPUT("MICR"), 227980b63f8SPavel Dobias SND_SOC_DAPM_INPUT("DMICL"), 228980b63f8SPavel Dobias SND_SOC_DAPM_INPUT("DMICR"), 229bc2610a6SLadislav Michl SND_SOC_DAPM_INPUT("LINL"), 230bc2610a6SLadislav Michl SND_SOC_DAPM_INPUT("LINR"), 231805d132dSanish kumar 23229c859dfSPavel Dobias SND_SOC_DAPM_PGA("Left Line Input", SND_SOC_NOPM, 0, 0, NULL, 0), 23329c859dfSPavel Dobias SND_SOC_DAPM_PGA("Right Line Input", SND_SOC_NOPM, 0, 0, NULL, 0), 234bc2610a6SLadislav Michl SND_SOC_DAPM_MIXER_NAMED_CTL("Input Mixer", SND_SOC_NOPM, 0, 0, 235bc2610a6SLadislav Michl max9867_input_mixer_controls, 236bc2610a6SLadislav Michl ARRAY_SIZE(max9867_input_mixer_controls)), 237980b63f8SPavel Dobias SND_SOC_DAPM_MUX("DMICL Mux", SND_SOC_NOPM, 0, 0, 238980b63f8SPavel Dobias &max9867_left_dmic_mux), 239980b63f8SPavel Dobias SND_SOC_DAPM_MUX("DMICR Mux", SND_SOC_NOPM, 0, 0, 240980b63f8SPavel Dobias &max9867_right_dmic_mux), 241a11ffbbaSPavel Dobias SND_SOC_DAPM_ADC_E("ADCL", "HiFi Capture", SND_SOC_NOPM, 0, 0, 242a11ffbbaSPavel Dobias max9867_adc_dac_event, 243a11ffbbaSPavel Dobias SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 244a11ffbbaSPavel Dobias SND_SOC_DAPM_ADC_E("ADCR", "HiFi Capture", SND_SOC_NOPM, 0, 0, 245a11ffbbaSPavel Dobias max9867_adc_dac_event, 246a11ffbbaSPavel Dobias SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 247805d132dSanish kumar 248bc2610a6SLadislav Michl SND_SOC_DAPM_MIXER("Digital", SND_SOC_NOPM, 0, 0, 249bc2610a6SLadislav Michl max9867_sidetone_mixer_controls, 250bc2610a6SLadislav Michl ARRAY_SIZE(max9867_sidetone_mixer_controls)), 251bc2610a6SLadislav Michl SND_SOC_DAPM_MIXER_NAMED_CTL("Output Mixer", SND_SOC_NOPM, 0, 0, 252bc2610a6SLadislav Michl max9867_output_mixer_controls, 253bc2610a6SLadislav Michl ARRAY_SIZE(max9867_output_mixer_controls)), 254a11ffbbaSPavel Dobias SND_SOC_DAPM_DAC_E("DACL", "HiFi Playback", SND_SOC_NOPM, 0, 0, 255a11ffbbaSPavel Dobias max9867_adc_dac_event, 256a11ffbbaSPavel Dobias SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 257a11ffbbaSPavel Dobias SND_SOC_DAPM_DAC_E("DACR", "HiFi Playback", SND_SOC_NOPM, 0, 0, 258a11ffbbaSPavel Dobias max9867_adc_dac_event, 259a11ffbbaSPavel Dobias SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 260bc2610a6SLadislav Michl SND_SOC_DAPM_SWITCH("Master Playback", SND_SOC_NOPM, 0, 0, 261bc2610a6SLadislav Michl &max9867_line_out_control), 262bc2610a6SLadislav Michl SND_SOC_DAPM_OUTPUT("LOUT"), 263bc2610a6SLadislav Michl SND_SOC_DAPM_OUTPUT("ROUT"), 264805d132dSanish kumar }; 265805d132dSanish kumar 266805d132dSanish kumar static const struct snd_soc_dapm_route max9867_audio_map[] = { 267bc2610a6SLadislav Michl {"Left Line Input", NULL, "LINL"}, 268bc2610a6SLadislav Michl {"Right Line Input", NULL, "LINR"}, 269bc2610a6SLadislav Michl {"Input Mixer", "Mic Capture Switch", "MICL"}, 270bc2610a6SLadislav Michl {"Input Mixer", "Mic Capture Switch", "MICR"}, 271bc2610a6SLadislav Michl {"Input Mixer", "Line Capture Switch", "Left Line Input"}, 272bc2610a6SLadislav Michl {"Input Mixer", "Line Capture Switch", "Right Line Input"}, 273980b63f8SPavel Dobias {"DMICL Mux", "DMIC", "DMICL"}, 274980b63f8SPavel Dobias {"DMICR Mux", "DMIC", "DMICR"}, 275980b63f8SPavel Dobias {"DMICL Mux", "ADC", "Input Mixer"}, 276980b63f8SPavel Dobias {"DMICR Mux", "ADC", "Input Mixer"}, 277980b63f8SPavel Dobias {"ADCL", NULL, "DMICL Mux"}, 278980b63f8SPavel Dobias {"ADCR", NULL, "DMICR Mux"}, 279805d132dSanish kumar 280bc2610a6SLadislav Michl {"Digital", "Sidetone Switch", "ADCL"}, 281bc2610a6SLadislav Michl {"Digital", "Sidetone Switch", "ADCR"}, 282bc2610a6SLadislav Michl {"DACL", NULL, "Digital"}, 283bc2610a6SLadislav Michl {"DACR", NULL, "Digital"}, 284bc2610a6SLadislav Michl 285bc2610a6SLadislav Michl {"Output Mixer", "Line Bypass Switch", "Left Line Input"}, 286bc2610a6SLadislav Michl {"Output Mixer", "Line Bypass Switch", "Right Line Input"}, 287bc2610a6SLadislav Michl {"Output Mixer", NULL, "DACL"}, 288bc2610a6SLadislav Michl {"Output Mixer", NULL, "DACR"}, 289bc2610a6SLadislav Michl {"Master Playback", "Switch", "Output Mixer"}, 290bc2610a6SLadislav Michl {"LOUT", NULL, "Master Playback"}, 291bc2610a6SLadislav Michl {"ROUT", NULL, "Master Playback"}, 292805d132dSanish kumar }; 293805d132dSanish kumar 294715ee191SLadislav Michl static const unsigned int max9867_rates_44k1[] = { 295715ee191SLadislav Michl 11025, 22050, 44100, 296805d132dSanish kumar }; 297805d132dSanish kumar 298715ee191SLadislav Michl static const struct snd_pcm_hw_constraint_list max9867_constraints_44k1 = { 299715ee191SLadislav Michl .list = max9867_rates_44k1, 300715ee191SLadislav Michl .count = ARRAY_SIZE(max9867_rates_44k1), 301805d132dSanish kumar }; 302805d132dSanish kumar 303715ee191SLadislav Michl static const unsigned int max9867_rates_48k[] = { 304715ee191SLadislav Michl 8000, 16000, 32000, 48000, 305715ee191SLadislav Michl }; 306715ee191SLadislav Michl 307715ee191SLadislav Michl static const struct snd_pcm_hw_constraint_list max9867_constraints_48k = { 308715ee191SLadislav Michl .list = max9867_rates_48k, 309715ee191SLadislav Michl .count = ARRAY_SIZE(max9867_rates_48k), 310715ee191SLadislav Michl }; 311715ee191SLadislav Michl 312715ee191SLadislav Michl static int max9867_startup(struct snd_pcm_substream *substream, 313715ee191SLadislav Michl struct snd_soc_dai *dai) 314805d132dSanish kumar { 315715ee191SLadislav Michl struct max9867_priv *max9867 = 316715ee191SLadislav Michl snd_soc_component_get_drvdata(dai->component); 317805d132dSanish kumar 318715ee191SLadislav Michl if (max9867->constraints) 319715ee191SLadislav Michl snd_pcm_hw_constraint_list(substream->runtime, 0, 320715ee191SLadislav Michl SNDRV_PCM_HW_PARAM_RATE, max9867->constraints); 321805d132dSanish kumar 322715ee191SLadislav Michl return 0; 323805d132dSanish kumar } 324805d132dSanish kumar 325805d132dSanish kumar static int max9867_dai_hw_params(struct snd_pcm_substream *substream, 326805d132dSanish kumar struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 327805d132dSanish kumar { 328082d3c99SPavel Dobias int value, freq = 0; 329715ee191SLadislav Michl unsigned long int rate, ratio; 33091880a6bSKuninori Morimoto struct snd_soc_component *component = dai->component; 33191880a6bSKuninori Morimoto struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); 332715ee191SLadislav Michl unsigned int ni = DIV_ROUND_CLOSEST_ULL(96ULL * 0x10000 * params_rate(params), 333715ee191SLadislav Michl max9867->pclk); 334805d132dSanish kumar 335805d132dSanish kumar /* set up the ni value */ 336805d132dSanish kumar regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH, 337715ee191SLadislav Michl MAX9867_NI_HIGH_MASK, (0xFF00 & ni) >> 8); 338805d132dSanish kumar regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW, 339715ee191SLadislav Michl MAX9867_NI_LOW_MASK, 0x00FF & ni); 3402594d0aaSMark Brown if (max9867->provider) { 341715ee191SLadislav Michl if (max9867->dsp_a) { 342715ee191SLadislav Michl value = MAX9867_IFC1B_48X; 343715ee191SLadislav Michl } else { 344715ee191SLadislav Michl rate = params_rate(params) * 2 * params_width(params); 345715ee191SLadislav Michl ratio = max9867->pclk / rate; 346715ee191SLadislav Michl switch (params_width(params)) { 347715ee191SLadislav Michl case 8: 348715ee191SLadislav Michl case 16: 349715ee191SLadislav Michl switch (ratio) { 350715ee191SLadislav Michl case 2: 351715ee191SLadislav Michl value = MAX9867_IFC1B_PCLK_2; 352715ee191SLadislav Michl break; 353715ee191SLadislav Michl case 4: 354715ee191SLadislav Michl value = MAX9867_IFC1B_PCLK_4; 355715ee191SLadislav Michl break; 356715ee191SLadislav Michl case 8: 357715ee191SLadislav Michl value = MAX9867_IFC1B_PCLK_8; 358715ee191SLadislav Michl break; 359715ee191SLadislav Michl case 16: 360715ee191SLadislav Michl value = MAX9867_IFC1B_PCLK_16; 361715ee191SLadislav Michl break; 362715ee191SLadislav Michl default: 363715ee191SLadislav Michl return -EINVAL; 364715ee191SLadislav Michl } 365715ee191SLadislav Michl break; 366715ee191SLadislav Michl case 24: 367715ee191SLadislav Michl value = MAX9867_IFC1B_48X; 368715ee191SLadislav Michl break; 369715ee191SLadislav Michl case 32: 370715ee191SLadislav Michl value = MAX9867_IFC1B_64X; 371715ee191SLadislav Michl break; 372715ee191SLadislav Michl default: 373715ee191SLadislav Michl return -EINVAL; 374715ee191SLadislav Michl } 375715ee191SLadislav Michl } 376715ee191SLadislav Michl regmap_update_bits(max9867->regmap, MAX9867_IFC1B, 377715ee191SLadislav Michl MAX9867_IFC1B_BCLK_MASK, value); 378082d3c99SPavel Dobias 379082d3c99SPavel Dobias /* Exact integer mode available for 8kHz and 16kHz sample rates 380082d3c99SPavel Dobias * and certain PCLK (prescaled MCLK) values. 381082d3c99SPavel Dobias */ 382082d3c99SPavel Dobias if (params_rate(params) == 8000 || 383082d3c99SPavel Dobias params_rate(params) == 16000) { 384082d3c99SPavel Dobias switch (max9867->pclk) { 385082d3c99SPavel Dobias case 12000000: 386082d3c99SPavel Dobias freq = 0x08; 387082d3c99SPavel Dobias break; 388082d3c99SPavel Dobias case 13000000: 389082d3c99SPavel Dobias freq = 0x0A; 390082d3c99SPavel Dobias break; 391082d3c99SPavel Dobias case 16000000: 392082d3c99SPavel Dobias freq = 0x0C; 393082d3c99SPavel Dobias break; 394082d3c99SPavel Dobias case 19200000: 395082d3c99SPavel Dobias freq = 0x0E; 396082d3c99SPavel Dobias break; 397082d3c99SPavel Dobias } 398082d3c99SPavel Dobias } 399082d3c99SPavel Dobias if (freq && params_rate(params) == 16000) 400082d3c99SPavel Dobias freq++; 401082d3c99SPavel Dobias 402082d3c99SPavel Dobias /* If exact integer mode not available, the freq value 403082d3c99SPavel Dobias * remains zero, i.e. normal mode is used. 404082d3c99SPavel Dobias */ 405082d3c99SPavel Dobias regmap_update_bits(max9867->regmap, MAX9867_SYSCLK, 406082d3c99SPavel Dobias MAX9867_FREQ_MASK, freq); 407715ee191SLadislav Michl } else { 408805d132dSanish kumar /* 409805d132dSanish kumar * digital pll locks on to any externally supplied LRCLK signal 410805d132dSanish kumar * and also enable rapid lock mode. 411805d132dSanish kumar */ 412805d132dSanish kumar regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW, 413805d132dSanish kumar MAX9867_RAPID_LOCK, MAX9867_RAPID_LOCK); 414805d132dSanish kumar regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH, 415805d132dSanish kumar MAX9867_PLL, MAX9867_PLL); 416805d132dSanish kumar } 417805d132dSanish kumar return 0; 418805d132dSanish kumar } 419805d132dSanish kumar 42018e028e2SKuninori Morimoto static int max9867_mute(struct snd_soc_dai *dai, int mute, int direction) 421805d132dSanish kumar { 42291880a6bSKuninori Morimoto struct snd_soc_component *component = dai->component; 42391880a6bSKuninori Morimoto struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); 424805d132dSanish kumar 425bc2610a6SLadislav Michl return regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL, 426bc2610a6SLadislav Michl 1 << 6, !!mute << 6); 427805d132dSanish kumar } 428805d132dSanish kumar 429805d132dSanish kumar static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai, 430805d132dSanish kumar int clk_id, unsigned int freq, int dir) 431805d132dSanish kumar { 43291880a6bSKuninori Morimoto struct snd_soc_component *component = codec_dai->component; 43391880a6bSKuninori Morimoto struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); 434805d132dSanish kumar int value = 0; 435805d132dSanish kumar 436805d132dSanish kumar /* Set the prescaler based on the master clock frequency*/ 437805d132dSanish kumar if (freq >= 10000000 && freq <= 20000000) { 438805d132dSanish kumar value |= MAX9867_PSCLK_10_20; 439805d132dSanish kumar max9867->pclk = freq; 440805d132dSanish kumar } else if (freq >= 20000000 && freq <= 40000000) { 441805d132dSanish kumar value |= MAX9867_PSCLK_20_40; 442805d132dSanish kumar max9867->pclk = freq / 2; 443805d132dSanish kumar } else if (freq >= 40000000 && freq <= 60000000) { 444805d132dSanish kumar value |= MAX9867_PSCLK_40_60; 445805d132dSanish kumar max9867->pclk = freq / 4; 446805d132dSanish kumar } else { 4478b9c716aSLadislav Michl dev_err(component->dev, 4488b9c716aSLadislav Michl "Invalid clock frequency %uHz (required 10-60MHz)\n", 4498b9c716aSLadislav Michl freq); 450805d132dSanish kumar return -EINVAL; 451805d132dSanish kumar } 452715ee191SLadislav Michl if (freq % 48000 == 0) 453715ee191SLadislav Michl max9867->constraints = &max9867_constraints_48k; 454715ee191SLadislav Michl else if (freq % 44100 == 0) 455715ee191SLadislav Michl max9867->constraints = &max9867_constraints_44k1; 456715ee191SLadislav Michl else 457715ee191SLadislav Michl dev_warn(component->dev, 458715ee191SLadislav Michl "Unable to set exact rate with %uHz clock frequency\n", 459715ee191SLadislav Michl freq); 460805d132dSanish kumar max9867->sysclk = freq; 461715ee191SLadislav Michl value = value << MAX9867_PSCLK_SHIFT; 462805d132dSanish kumar regmap_update_bits(max9867->regmap, MAX9867_SYSCLK, 463805d132dSanish kumar MAX9867_PSCLK_MASK, value); 464805d132dSanish kumar return 0; 465805d132dSanish kumar } 466805d132dSanish kumar 467805d132dSanish kumar static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai, 468805d132dSanish kumar unsigned int fmt) 469805d132dSanish kumar { 47091880a6bSKuninori Morimoto struct snd_soc_component *component = codec_dai->component; 47191880a6bSKuninori Morimoto struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); 472715ee191SLadislav Michl u8 iface1A, iface1B; 473805d132dSanish kumar 4742594d0aaSMark Brown switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 4752594d0aaSMark Brown case SND_SOC_DAIFMT_CBP_CFP: 4762594d0aaSMark Brown max9867->provider = true; 477715ee191SLadislav Michl iface1A = MAX9867_MASTER; 478715ee191SLadislav Michl iface1B = MAX9867_IFC1B_48X; 479805d132dSanish kumar break; 4802594d0aaSMark Brown case SND_SOC_DAIFMT_CBC_CFC: 4812594d0aaSMark Brown max9867->provider = false; 482715ee191SLadislav Michl iface1A = iface1B = 0; 483805d132dSanish kumar break; 484805d132dSanish kumar default: 485805d132dSanish kumar return -EINVAL; 486805d132dSanish kumar } 487805d132dSanish kumar 48879e13974SLadislav Michl switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 48979e13974SLadislav Michl case SND_SOC_DAIFMT_I2S: 490715ee191SLadislav Michl max9867->dsp_a = false; 491805d132dSanish kumar iface1A |= MAX9867_I2S_DLY; 49279e13974SLadislav Michl break; 49379e13974SLadislav Michl case SND_SOC_DAIFMT_DSP_A: 494715ee191SLadislav Michl max9867->dsp_a = true; 49579e13974SLadislav Michl iface1A |= MAX9867_TDM_MODE | MAX9867_SDOUT_HIZ; 49679e13974SLadislav Michl break; 49779e13974SLadislav Michl default: 49879e13974SLadislav Michl return -EINVAL; 49979e13974SLadislav Michl } 500805d132dSanish kumar 501805d132dSanish kumar /* Clock inversion bits, BCI and WCI */ 502805d132dSanish kumar switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 503805d132dSanish kumar case SND_SOC_DAIFMT_NB_NF: 504805d132dSanish kumar break; 505805d132dSanish kumar case SND_SOC_DAIFMT_IB_IF: 506805d132dSanish kumar iface1A |= MAX9867_WCI_MODE | MAX9867_BCI_MODE; 507805d132dSanish kumar break; 508805d132dSanish kumar case SND_SOC_DAIFMT_IB_NF: 509805d132dSanish kumar iface1A |= MAX9867_BCI_MODE; 510805d132dSanish kumar break; 511805d132dSanish kumar case SND_SOC_DAIFMT_NB_IF: 512805d132dSanish kumar iface1A |= MAX9867_WCI_MODE; 513805d132dSanish kumar break; 514805d132dSanish kumar default: 515805d132dSanish kumar return -EINVAL; 516805d132dSanish kumar } 517805d132dSanish kumar 5189fe78b28SVinod Koul regmap_write(max9867->regmap, MAX9867_IFC1A, iface1A); 51980b9fa4dSPavel Dobias regmap_update_bits(max9867->regmap, MAX9867_IFC1B, 52080b9fa4dSPavel Dobias MAX9867_IFC1B_BCLK_MASK, iface1B); 521715ee191SLadislav Michl 522805d132dSanish kumar return 0; 523805d132dSanish kumar } 524805d132dSanish kumar 525eb59d73cSArvind Yadav static const struct snd_soc_dai_ops max9867_dai_ops = { 526805d132dSanish kumar .set_sysclk = max9867_set_dai_sysclk, 527715ee191SLadislav Michl .set_fmt = max9867_dai_set_fmt, 52818e028e2SKuninori Morimoto .mute_stream = max9867_mute, 529715ee191SLadislav Michl .startup = max9867_startup, 530805d132dSanish kumar .hw_params = max9867_dai_hw_params, 53118e028e2SKuninori Morimoto .no_capture_mute = 1, 532805d132dSanish kumar }; 533805d132dSanish kumar 534805d132dSanish kumar static struct snd_soc_dai_driver max9867_dai[] = { 535805d132dSanish kumar { 536805d132dSanish kumar .name = "max9867-aif1", 537805d132dSanish kumar .playback = { 538805d132dSanish kumar .stream_name = "HiFi Playback", 539e6ceb922SLadislav Michl .channels_min = 2, 540805d132dSanish kumar .channels_max = 2, 541715ee191SLadislav Michl .rates = SNDRV_PCM_RATE_8000_48000, 542715ee191SLadislav Michl .formats = SNDRV_PCM_FMTBIT_S16_LE, 543805d132dSanish kumar }, 544805d132dSanish kumar .capture = { 545805d132dSanish kumar .stream_name = "HiFi Capture", 546e6ceb922SLadislav Michl .channels_min = 2, 547805d132dSanish kumar .channels_max = 2, 548715ee191SLadislav Michl .rates = SNDRV_PCM_RATE_8000_48000, 549715ee191SLadislav Michl .formats = SNDRV_PCM_FMTBIT_S16_LE, 550805d132dSanish kumar }, 551805d132dSanish kumar .ops = &max9867_dai_ops, 552cb40d1b4SKuninori Morimoto .symmetric_rate = 1, 553805d132dSanish kumar } 554805d132dSanish kumar }; 555805d132dSanish kumar 55629f58ff0SLadislav Michl #ifdef CONFIG_PM 55729f58ff0SLadislav Michl static int max9867_suspend(struct snd_soc_component *component) 558805d132dSanish kumar { 55929f58ff0SLadislav Michl snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF); 560805d132dSanish kumar 561805d132dSanish kumar return 0; 562805d132dSanish kumar } 563805d132dSanish kumar 56429f58ff0SLadislav Michl static int max9867_resume(struct snd_soc_component *component) 565805d132dSanish kumar { 56629f58ff0SLadislav Michl snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY); 567805d132dSanish kumar 568805d132dSanish kumar return 0; 569805d132dSanish kumar } 57029f58ff0SLadislav Michl #else 57129f58ff0SLadislav Michl #define max9867_suspend NULL 57229f58ff0SLadislav Michl #define max9867_resume NULL 573805d132dSanish kumar #endif 574805d132dSanish kumar 57529f58ff0SLadislav Michl static int max9867_set_bias_level(struct snd_soc_component *component, 57629f58ff0SLadislav Michl enum snd_soc_bias_level level) 57729f58ff0SLadislav Michl { 57829f58ff0SLadislav Michl int err; 57929f58ff0SLadislav Michl struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); 58029f58ff0SLadislav Michl 58129f58ff0SLadislav Michl switch (level) { 582*448b06baSBenjamin Bara case SND_SOC_BIAS_ON: 583*448b06baSBenjamin Bara err = clk_prepare_enable(max9867->mclk); 584*448b06baSBenjamin Bara if (err) 585*448b06baSBenjamin Bara return err; 586*448b06baSBenjamin Bara break; 58729f58ff0SLadislav Michl case SND_SOC_BIAS_STANDBY: 58829f58ff0SLadislav Michl if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) { 58929f58ff0SLadislav Michl err = regcache_sync(max9867->regmap); 59029f58ff0SLadislav Michl if (err) 59129f58ff0SLadislav Michl return err; 59229f58ff0SLadislav Michl 59329c859dfSPavel Dobias err = regmap_write(max9867->regmap, 59429c859dfSPavel Dobias MAX9867_PWRMAN, 0xff); 59529f58ff0SLadislav Michl if (err) 59629f58ff0SLadislav Michl return err; 59729f58ff0SLadislav Michl } 59829f58ff0SLadislav Michl break; 59929f58ff0SLadislav Michl case SND_SOC_BIAS_OFF: 60029c859dfSPavel Dobias err = regmap_write(max9867->regmap, MAX9867_PWRMAN, 0); 60129f58ff0SLadislav Michl if (err) 60229f58ff0SLadislav Michl return err; 60329f58ff0SLadislav Michl 60429f58ff0SLadislav Michl regcache_mark_dirty(max9867->regmap); 605*448b06baSBenjamin Bara clk_disable_unprepare(max9867->mclk); 60629f58ff0SLadislav Michl break; 60729f58ff0SLadislav Michl default: 60829f58ff0SLadislav Michl break; 60929f58ff0SLadislav Michl } 61029f58ff0SLadislav Michl 61129f58ff0SLadislav Michl return 0; 61229f58ff0SLadislav Michl } 61329f58ff0SLadislav Michl 61491880a6bSKuninori Morimoto static const struct snd_soc_component_driver max9867_component = { 615805d132dSanish kumar .controls = max9867_snd_controls, 616805d132dSanish kumar .num_controls = ARRAY_SIZE(max9867_snd_controls), 617805d132dSanish kumar .dapm_routes = max9867_audio_map, 618805d132dSanish kumar .num_dapm_routes = ARRAY_SIZE(max9867_audio_map), 619805d132dSanish kumar .dapm_widgets = max9867_dapm_widgets, 620805d132dSanish kumar .num_dapm_widgets = ARRAY_SIZE(max9867_dapm_widgets), 62129f58ff0SLadislav Michl .suspend = max9867_suspend, 62229f58ff0SLadislav Michl .resume = max9867_resume, 62329f58ff0SLadislav Michl .set_bias_level = max9867_set_bias_level, 62491880a6bSKuninori Morimoto .idle_bias_on = 1, 62591880a6bSKuninori Morimoto .use_pmdown_time = 1, 62691880a6bSKuninori Morimoto .endianness = 1, 627805d132dSanish kumar }; 628805d132dSanish kumar 629805d132dSanish kumar static bool max9867_volatile_register(struct device *dev, unsigned int reg) 630805d132dSanish kumar { 631805d132dSanish kumar switch (reg) { 632805d132dSanish kumar case MAX9867_STATUS: 633805d132dSanish kumar case MAX9867_JACKSTATUS: 634805d132dSanish kumar case MAX9867_AUXHIGH: 635805d132dSanish kumar case MAX9867_AUXLOW: 636805d132dSanish kumar return true; 637805d132dSanish kumar default: 638805d132dSanish kumar return false; 639805d132dSanish kumar } 640805d132dSanish kumar } 641805d132dSanish kumar 642250a99e7SAxel Lin static const struct regmap_config max9867_regmap = { 643805d132dSanish kumar .reg_bits = 8, 644805d132dSanish kumar .val_bits = 8, 645805d132dSanish kumar .max_register = MAX9867_REVISION, 646805d132dSanish kumar .volatile_reg = max9867_volatile_register, 647805d132dSanish kumar .cache_type = REGCACHE_RBTREE, 648805d132dSanish kumar }; 649805d132dSanish kumar 650fead49e3SStephen Kitt static int max9867_i2c_probe(struct i2c_client *i2c) 651805d132dSanish kumar { 652805d132dSanish kumar struct max9867_priv *max9867; 6538efc1afdSLadislav Michl int ret, reg; 654805d132dSanish kumar 655933662f2SLadislav Michl max9867 = devm_kzalloc(&i2c->dev, sizeof(*max9867), GFP_KERNEL); 656805d132dSanish kumar if (!max9867) 657805d132dSanish kumar return -ENOMEM; 658805d132dSanish kumar 659805d132dSanish kumar i2c_set_clientdata(i2c, max9867); 660805d132dSanish kumar max9867->regmap = devm_regmap_init_i2c(i2c, &max9867_regmap); 661805d132dSanish kumar if (IS_ERR(max9867->regmap)) { 662805d132dSanish kumar ret = PTR_ERR(max9867->regmap); 6638b9c716aSLadislav Michl dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); 664805d132dSanish kumar return ret; 665805d132dSanish kumar } 666933662f2SLadislav Michl ret = regmap_read(max9867->regmap, MAX9867_REVISION, ®); 667805d132dSanish kumar if (ret < 0) { 668805d132dSanish kumar dev_err(&i2c->dev, "Failed to read: %d\n", ret); 669805d132dSanish kumar return ret; 670805d132dSanish kumar } 671805d132dSanish kumar dev_info(&i2c->dev, "device revision: %x\n", reg); 67291880a6bSKuninori Morimoto ret = devm_snd_soc_register_component(&i2c->dev, &max9867_component, 673805d132dSanish kumar max9867_dai, ARRAY_SIZE(max9867_dai)); 674*448b06baSBenjamin Bara if (ret < 0) { 67591880a6bSKuninori Morimoto dev_err(&i2c->dev, "Failed to register component: %d\n", ret); 676805d132dSanish kumar return ret; 677805d132dSanish kumar } 678805d132dSanish kumar 679*448b06baSBenjamin Bara max9867->mclk = devm_clk_get(&i2c->dev, NULL); 680*448b06baSBenjamin Bara if (IS_ERR(max9867->mclk)) 681*448b06baSBenjamin Bara return PTR_ERR(max9867->mclk); 682*448b06baSBenjamin Bara 683*448b06baSBenjamin Bara return 0; 684*448b06baSBenjamin Bara } 685*448b06baSBenjamin Bara 686805d132dSanish kumar static const struct i2c_device_id max9867_i2c_id[] = { 687805d132dSanish kumar { "max9867", 0 }, 6881b36e4a2SAxel Lin { } 689805d132dSanish kumar }; 69056af0e4cSJavier Martinez Canillas MODULE_DEVICE_TABLE(i2c, max9867_i2c_id); 691805d132dSanish kumar 692682e2219SKrzysztof Kozlowski #ifdef CONFIG_OF 693805d132dSanish kumar static const struct of_device_id max9867_of_match[] = { 694805d132dSanish kumar { .compatible = "maxim,max9867", }, 695805d132dSanish kumar { } 696805d132dSanish kumar }; 69756af0e4cSJavier Martinez Canillas MODULE_DEVICE_TABLE(of, max9867_of_match); 698682e2219SKrzysztof Kozlowski #endif 699805d132dSanish kumar 700805d132dSanish kumar static struct i2c_driver max9867_i2c_driver = { 701805d132dSanish kumar .driver = { 702805d132dSanish kumar .name = "max9867", 703805d132dSanish kumar .of_match_table = of_match_ptr(max9867_of_match), 704805d132dSanish kumar }, 705fead49e3SStephen Kitt .probe_new = max9867_i2c_probe, 706805d132dSanish kumar .id_table = max9867_i2c_id, 707805d132dSanish kumar }; 708805d132dSanish kumar 709805d132dSanish kumar module_i2c_driver(max9867_i2c_driver); 710805d132dSanish kumar 7118084945dSLadislav Michl MODULE_AUTHOR("Ladislav Michl <ladis@linux-mips.org>"); 7128084945dSLadislav Michl MODULE_DESCRIPTION("ASoC MAX9867 driver"); 713805d132dSanish kumar MODULE_LICENSE("GPL"); 714