162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// File: sound/soc/codecs/ssm2602.c 462306a36Sopenharmony_ci// Author: Cliff Cai <Cliff.Cai@analog.com> 562306a36Sopenharmony_ci// 662306a36Sopenharmony_ci// Created: Tue June 06 2008 762306a36Sopenharmony_ci// Description: Driver for ssm2602 sound chip 862306a36Sopenharmony_ci// 962306a36Sopenharmony_ci// Modified: 1062306a36Sopenharmony_ci// Copyright 2008 Analog Devices Inc. 1162306a36Sopenharmony_ci// 1262306a36Sopenharmony_ci// Bugs: Enter bugs at http://blackfin.uclinux.org/ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/regmap.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <sound/pcm.h> 2062306a36Sopenharmony_ci#include <sound/pcm_params.h> 2162306a36Sopenharmony_ci#include <sound/soc.h> 2262306a36Sopenharmony_ci#include <sound/tlv.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "ssm2602.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* codec private data */ 2762306a36Sopenharmony_cistruct ssm2602_priv { 2862306a36Sopenharmony_ci unsigned int sysclk; 2962306a36Sopenharmony_ci const struct snd_pcm_hw_constraint_list *sysclk_constraints; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci struct regmap *regmap; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci enum ssm2602_type type; 3462306a36Sopenharmony_ci unsigned int clk_out_pwr; 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* 3862306a36Sopenharmony_ci * ssm2602 register cache 3962306a36Sopenharmony_ci * We can't read the ssm2602 register space when we are 4062306a36Sopenharmony_ci * using 2 wire for device control, so we cache them instead. 4162306a36Sopenharmony_ci * There is no point in caching the reset register 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_cistatic const struct reg_default ssm2602_reg[SSM2602_CACHEREGNUM] = { 4462306a36Sopenharmony_ci { .reg = 0x00, .def = 0x0097 }, 4562306a36Sopenharmony_ci { .reg = 0x01, .def = 0x0097 }, 4662306a36Sopenharmony_ci { .reg = 0x02, .def = 0x0079 }, 4762306a36Sopenharmony_ci { .reg = 0x03, .def = 0x0079 }, 4862306a36Sopenharmony_ci { .reg = 0x04, .def = 0x000a }, 4962306a36Sopenharmony_ci { .reg = 0x05, .def = 0x0008 }, 5062306a36Sopenharmony_ci { .reg = 0x06, .def = 0x009f }, 5162306a36Sopenharmony_ci { .reg = 0x07, .def = 0x000a }, 5262306a36Sopenharmony_ci { .reg = 0x08, .def = 0x0000 }, 5362306a36Sopenharmony_ci { .reg = 0x09, .def = 0x0000 } 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * ssm2602 register patch 5862306a36Sopenharmony_ci * Workaround for playback distortions after power up: activates digital 5962306a36Sopenharmony_ci * core, and then powers on output, DAC, and whole chip at the same time 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic const struct reg_sequence ssm2602_patch[] = { 6362306a36Sopenharmony_ci { SSM2602_ACTIVE, 0x01 }, 6462306a36Sopenharmony_ci { SSM2602_PWR, 0x07 }, 6562306a36Sopenharmony_ci { SSM2602_RESET, 0x00 }, 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/*Appending several "None"s just for OSS mixer use*/ 7062306a36Sopenharmony_cistatic const char *ssm2602_input_select[] = { 7162306a36Sopenharmony_ci "Line", "Mic", 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic const char *ssm2602_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic const struct soc_enum ssm2602_enum[] = { 7762306a36Sopenharmony_ci SOC_ENUM_SINGLE(SSM2602_APANA, 2, ARRAY_SIZE(ssm2602_input_select), 7862306a36Sopenharmony_ci ssm2602_input_select), 7962306a36Sopenharmony_ci SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, ARRAY_SIZE(ssm2602_deemph), 8062306a36Sopenharmony_ci ssm2602_deemph), 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(ssm260x_outmix_tlv, 8462306a36Sopenharmony_ci 0, 47, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), 8562306a36Sopenharmony_ci 48, 127, TLV_DB_SCALE_ITEM(-7400, 100, 0) 8662306a36Sopenharmony_ci); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(ssm260x_inpga_tlv, -3450, 150, 0); 8962306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(ssm260x_sidetone_tlv, -1500, 300, 0); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic const struct snd_kcontrol_new ssm260x_snd_controls[] = { 9262306a36Sopenharmony_ciSOC_DOUBLE_R_TLV("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 45, 0, 9362306a36Sopenharmony_ci ssm260x_inpga_tlv), 9462306a36Sopenharmony_ciSOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1), 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ciSOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1), 9762306a36Sopenharmony_ciSOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0), 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ciSOC_ENUM("Playback De-emphasis", ssm2602_enum[1]), 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic const struct snd_kcontrol_new ssm2602_snd_controls[] = { 10362306a36Sopenharmony_ciSOC_DOUBLE_R_TLV("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V, 10462306a36Sopenharmony_ci 0, 127, 0, ssm260x_outmix_tlv), 10562306a36Sopenharmony_ciSOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V, 10662306a36Sopenharmony_ci 7, 1, 0), 10762306a36Sopenharmony_ciSOC_SINGLE_TLV("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1, 10862306a36Sopenharmony_ci ssm260x_sidetone_tlv), 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ciSOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0), 11162306a36Sopenharmony_ciSOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 8, 1, 0), 11262306a36Sopenharmony_ci}; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/* Output Mixer */ 11562306a36Sopenharmony_cistatic const struct snd_kcontrol_new ssm260x_output_mixer_controls[] = { 11662306a36Sopenharmony_ciSOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0), 11762306a36Sopenharmony_ciSOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0), 11862306a36Sopenharmony_ciSOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0), 11962306a36Sopenharmony_ci}; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic const struct snd_kcontrol_new mic_ctl = 12262306a36Sopenharmony_ci SOC_DAPM_SINGLE("Switch", SSM2602_APANA, 1, 1, 1); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/* Input mux */ 12562306a36Sopenharmony_cistatic const struct snd_kcontrol_new ssm2602_input_mux_controls = 12662306a36Sopenharmony_ciSOC_DAPM_ENUM("Input Select", ssm2602_enum[0]); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic int ssm2602_mic_switch_event(struct snd_soc_dapm_widget *w, 12962306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci /* 13262306a36Sopenharmony_ci * According to the ssm2603 data sheet (control register sequencing), 13362306a36Sopenharmony_ci * the digital core should be activated only after all necessary bits 13462306a36Sopenharmony_ci * in the power register are enabled, and a delay determined by the 13562306a36Sopenharmony_ci * decoupling capacitor on the VMID pin has passed. If the digital core 13662306a36Sopenharmony_ci * is activated too early, or even before the ADC is powered up, audible 13762306a36Sopenharmony_ci * artifacts appear at the beginning and end of the recorded signal. 13862306a36Sopenharmony_ci * 13962306a36Sopenharmony_ci * In practice, audible artifacts disappear well over 500 ms. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci msleep(500); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci return 0; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget ssm260x_dapm_widgets[] = { 14762306a36Sopenharmony_ciSND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1), 14862306a36Sopenharmony_ciSND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1), 14962306a36Sopenharmony_ciSND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0), 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ciSND_SOC_DAPM_SUPPLY("Digital Core Power", SSM2602_ACTIVE, 0, 0, NULL, 0), 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("LOUT"), 15462306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("ROUT"), 15562306a36Sopenharmony_ciSND_SOC_DAPM_INPUT("RLINEIN"), 15662306a36Sopenharmony_ciSND_SOC_DAPM_INPUT("LLINEIN"), 15762306a36Sopenharmony_ci}; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = { 16062306a36Sopenharmony_ciSND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1, 16162306a36Sopenharmony_ci ssm260x_output_mixer_controls, 16262306a36Sopenharmony_ci ARRAY_SIZE(ssm260x_output_mixer_controls)), 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ciSND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls), 16562306a36Sopenharmony_ciSND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1), 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ciSND_SOC_DAPM_SWITCH_E("Mic Switch", SSM2602_APANA, 1, 1, &mic_ctl, 16862306a36Sopenharmony_ci ssm2602_mic_switch_event, SND_SOC_DAPM_PRE_PMU), 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("LHPOUT"), 17162306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("RHPOUT"), 17262306a36Sopenharmony_ciSND_SOC_DAPM_INPUT("MICIN"), 17362306a36Sopenharmony_ci}; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget ssm2604_dapm_widgets[] = { 17662306a36Sopenharmony_ciSND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0, 17762306a36Sopenharmony_ci ssm260x_output_mixer_controls, 17862306a36Sopenharmony_ci ARRAY_SIZE(ssm260x_output_mixer_controls) - 1), /* Last element is the mic */ 17962306a36Sopenharmony_ci}; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic const struct snd_soc_dapm_route ssm260x_routes[] = { 18262306a36Sopenharmony_ci {"DAC", NULL, "Digital Core Power"}, 18362306a36Sopenharmony_ci {"ADC", NULL, "Digital Core Power"}, 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci {"Output Mixer", "Line Bypass Switch", "Line Input"}, 18662306a36Sopenharmony_ci {"Output Mixer", "HiFi Playback Switch", "DAC"}, 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci {"ROUT", NULL, "Output Mixer"}, 18962306a36Sopenharmony_ci {"LOUT", NULL, "Output Mixer"}, 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci {"Line Input", NULL, "LLINEIN"}, 19262306a36Sopenharmony_ci {"Line Input", NULL, "RLINEIN"}, 19362306a36Sopenharmony_ci}; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic const struct snd_soc_dapm_route ssm2602_routes[] = { 19662306a36Sopenharmony_ci {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci {"RHPOUT", NULL, "Output Mixer"}, 19962306a36Sopenharmony_ci {"LHPOUT", NULL, "Output Mixer"}, 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci {"Input Mux", "Line", "Line Input"}, 20262306a36Sopenharmony_ci {"Input Mux", "Mic", "Mic Switch"}, 20362306a36Sopenharmony_ci {"ADC", NULL, "Input Mux"}, 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci {"Mic Switch", NULL, "Mic Bias"}, 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci {"Mic Bias", NULL, "MICIN"}, 20862306a36Sopenharmony_ci}; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic const struct snd_soc_dapm_route ssm2604_routes[] = { 21162306a36Sopenharmony_ci {"ADC", NULL, "Line Input"}, 21262306a36Sopenharmony_ci}; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic const unsigned int ssm2602_rates_12288000[] = { 21562306a36Sopenharmony_ci 8000, 16000, 32000, 48000, 96000, 21662306a36Sopenharmony_ci}; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = { 21962306a36Sopenharmony_ci .list = ssm2602_rates_12288000, 22062306a36Sopenharmony_ci .count = ARRAY_SIZE(ssm2602_rates_12288000), 22162306a36Sopenharmony_ci}; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic const unsigned int ssm2602_rates_11289600[] = { 22462306a36Sopenharmony_ci 8000, 11025, 22050, 44100, 88200, 22562306a36Sopenharmony_ci}; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = { 22862306a36Sopenharmony_ci .list = ssm2602_rates_11289600, 22962306a36Sopenharmony_ci .count = ARRAY_SIZE(ssm2602_rates_11289600), 23062306a36Sopenharmony_ci}; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistruct ssm2602_coeff { 23362306a36Sopenharmony_ci u32 mclk; 23462306a36Sopenharmony_ci u32 rate; 23562306a36Sopenharmony_ci u8 srate; 23662306a36Sopenharmony_ci}; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci#define SSM2602_COEFF_SRATE(sr, bosr, usb) (((sr) << 2) | ((bosr) << 1) | (usb)) 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci/* codec mclk clock coefficients */ 24162306a36Sopenharmony_cistatic const struct ssm2602_coeff ssm2602_coeff_table[] = { 24262306a36Sopenharmony_ci /* 48k */ 24362306a36Sopenharmony_ci {12288000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x0)}, 24462306a36Sopenharmony_ci {18432000, 48000, SSM2602_COEFF_SRATE(0x0, 0x1, 0x0)}, 24562306a36Sopenharmony_ci {12000000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x1)}, 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* 32k */ 24862306a36Sopenharmony_ci {12288000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x0)}, 24962306a36Sopenharmony_ci {18432000, 32000, SSM2602_COEFF_SRATE(0x6, 0x1, 0x0)}, 25062306a36Sopenharmony_ci {12000000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x1)}, 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci /* 16k */ 25362306a36Sopenharmony_ci {12288000, 16000, SSM2602_COEFF_SRATE(0x5, 0x0, 0x0)}, 25462306a36Sopenharmony_ci {18432000, 16000, SSM2602_COEFF_SRATE(0x5, 0x1, 0x0)}, 25562306a36Sopenharmony_ci {12000000, 16000, SSM2602_COEFF_SRATE(0xa, 0x0, 0x1)}, 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* 8k */ 25862306a36Sopenharmony_ci {12288000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x0)}, 25962306a36Sopenharmony_ci {18432000, 8000, SSM2602_COEFF_SRATE(0x3, 0x1, 0x0)}, 26062306a36Sopenharmony_ci {11289600, 8000, SSM2602_COEFF_SRATE(0xb, 0x0, 0x0)}, 26162306a36Sopenharmony_ci {16934400, 8000, SSM2602_COEFF_SRATE(0xb, 0x1, 0x0)}, 26262306a36Sopenharmony_ci {12000000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x1)}, 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* 96k */ 26562306a36Sopenharmony_ci {12288000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x0)}, 26662306a36Sopenharmony_ci {18432000, 96000, SSM2602_COEFF_SRATE(0x7, 0x1, 0x0)}, 26762306a36Sopenharmony_ci {12000000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x1)}, 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* 11.025k */ 27062306a36Sopenharmony_ci {11289600, 11025, SSM2602_COEFF_SRATE(0xc, 0x0, 0x0)}, 27162306a36Sopenharmony_ci {16934400, 11025, SSM2602_COEFF_SRATE(0xc, 0x1, 0x0)}, 27262306a36Sopenharmony_ci {12000000, 11025, SSM2602_COEFF_SRATE(0xc, 0x1, 0x1)}, 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* 22.05k */ 27562306a36Sopenharmony_ci {11289600, 22050, SSM2602_COEFF_SRATE(0xd, 0x0, 0x0)}, 27662306a36Sopenharmony_ci {16934400, 22050, SSM2602_COEFF_SRATE(0xd, 0x1, 0x0)}, 27762306a36Sopenharmony_ci {12000000, 22050, SSM2602_COEFF_SRATE(0xd, 0x1, 0x1)}, 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* 44.1k */ 28062306a36Sopenharmony_ci {11289600, 44100, SSM2602_COEFF_SRATE(0x8, 0x0, 0x0)}, 28162306a36Sopenharmony_ci {16934400, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x0)}, 28262306a36Sopenharmony_ci {12000000, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x1)}, 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* 88.2k */ 28562306a36Sopenharmony_ci {11289600, 88200, SSM2602_COEFF_SRATE(0xf, 0x0, 0x0)}, 28662306a36Sopenharmony_ci {16934400, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x0)}, 28762306a36Sopenharmony_ci {12000000, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x1)}, 28862306a36Sopenharmony_ci}; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic inline int ssm2602_get_coeff(int mclk, int rate) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci int i; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ssm2602_coeff_table); i++) { 29562306a36Sopenharmony_ci if (ssm2602_coeff_table[i].rate == rate) { 29662306a36Sopenharmony_ci if (ssm2602_coeff_table[i].mclk == mclk) 29762306a36Sopenharmony_ci return ssm2602_coeff_table[i].srate; 29862306a36Sopenharmony_ci if (ssm2602_coeff_table[i].mclk == mclk / 2) 29962306a36Sopenharmony_ci return ssm2602_coeff_table[i].srate | SRATE_CORECLK_DIV2; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci return -EINVAL; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic int ssm2602_hw_params(struct snd_pcm_substream *substream, 30662306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 30762306a36Sopenharmony_ci struct snd_soc_dai *dai) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 31062306a36Sopenharmony_ci struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component); 31162306a36Sopenharmony_ci int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params)); 31262306a36Sopenharmony_ci unsigned int iface; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (srate < 0) 31562306a36Sopenharmony_ci return srate; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci regmap_write(ssm2602->regmap, SSM2602_SRATE, srate); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* bit size */ 32062306a36Sopenharmony_ci switch (params_width(params)) { 32162306a36Sopenharmony_ci case 16: 32262306a36Sopenharmony_ci iface = 0x0; 32362306a36Sopenharmony_ci break; 32462306a36Sopenharmony_ci case 20: 32562306a36Sopenharmony_ci iface = 0x4; 32662306a36Sopenharmony_ci break; 32762306a36Sopenharmony_ci case 24: 32862306a36Sopenharmony_ci iface = 0x8; 32962306a36Sopenharmony_ci break; 33062306a36Sopenharmony_ci case 32: 33162306a36Sopenharmony_ci iface = 0xc; 33262306a36Sopenharmony_ci break; 33362306a36Sopenharmony_ci default: 33462306a36Sopenharmony_ci return -EINVAL; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci regmap_update_bits(ssm2602->regmap, SSM2602_IFACE, 33762306a36Sopenharmony_ci IFACE_AUDIO_DATA_LEN, iface); 33862306a36Sopenharmony_ci return 0; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic int ssm2602_startup(struct snd_pcm_substream *substream, 34262306a36Sopenharmony_ci struct snd_soc_dai *dai) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 34562306a36Sopenharmony_ci struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (ssm2602->sysclk_constraints) { 34862306a36Sopenharmony_ci snd_pcm_hw_constraint_list(substream->runtime, 0, 34962306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, 35062306a36Sopenharmony_ci ssm2602->sysclk_constraints); 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci return 0; 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic int ssm2602_mute(struct snd_soc_dai *dai, int mute, int direction) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(dai->component); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (mute) 36162306a36Sopenharmony_ci regmap_update_bits(ssm2602->regmap, SSM2602_APDIGI, 36262306a36Sopenharmony_ci APDIGI_ENABLE_DAC_MUTE, 36362306a36Sopenharmony_ci APDIGI_ENABLE_DAC_MUTE); 36462306a36Sopenharmony_ci else 36562306a36Sopenharmony_ci regmap_update_bits(ssm2602->regmap, SSM2602_APDIGI, 36662306a36Sopenharmony_ci APDIGI_ENABLE_DAC_MUTE, 0); 36762306a36Sopenharmony_ci return 0; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai, 37162306a36Sopenharmony_ci int clk_id, unsigned int freq, int dir) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 37462306a36Sopenharmony_ci struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (dir == SND_SOC_CLOCK_IN) { 37762306a36Sopenharmony_ci if (clk_id != SSM2602_SYSCLK) 37862306a36Sopenharmony_ci return -EINVAL; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci switch (freq) { 38162306a36Sopenharmony_ci case 12288000: 38262306a36Sopenharmony_ci case 18432000: 38362306a36Sopenharmony_ci case 24576000: 38462306a36Sopenharmony_ci case 36864000: 38562306a36Sopenharmony_ci ssm2602->sysclk_constraints = &ssm2602_constraints_12288000; 38662306a36Sopenharmony_ci break; 38762306a36Sopenharmony_ci case 11289600: 38862306a36Sopenharmony_ci case 16934400: 38962306a36Sopenharmony_ci case 22579200: 39062306a36Sopenharmony_ci case 33868800: 39162306a36Sopenharmony_ci ssm2602->sysclk_constraints = &ssm2602_constraints_11289600; 39262306a36Sopenharmony_ci break; 39362306a36Sopenharmony_ci case 12000000: 39462306a36Sopenharmony_ci case 24000000: 39562306a36Sopenharmony_ci ssm2602->sysclk_constraints = NULL; 39662306a36Sopenharmony_ci break; 39762306a36Sopenharmony_ci default: 39862306a36Sopenharmony_ci return -EINVAL; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci ssm2602->sysclk = freq; 40262306a36Sopenharmony_ci } else { 40362306a36Sopenharmony_ci unsigned int mask; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci switch (clk_id) { 40662306a36Sopenharmony_ci case SSM2602_CLK_CLKOUT: 40762306a36Sopenharmony_ci mask = PWR_CLK_OUT_PDN; 40862306a36Sopenharmony_ci break; 40962306a36Sopenharmony_ci case SSM2602_CLK_XTO: 41062306a36Sopenharmony_ci mask = PWR_OSC_PDN; 41162306a36Sopenharmony_ci break; 41262306a36Sopenharmony_ci default: 41362306a36Sopenharmony_ci return -EINVAL; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (freq == 0) 41762306a36Sopenharmony_ci ssm2602->clk_out_pwr |= mask; 41862306a36Sopenharmony_ci else 41962306a36Sopenharmony_ci ssm2602->clk_out_pwr &= ~mask; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci regmap_update_bits(ssm2602->regmap, SSM2602_PWR, 42262306a36Sopenharmony_ci PWR_CLK_OUT_PDN | PWR_OSC_PDN, ssm2602->clk_out_pwr); 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci return 0; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai, 42962306a36Sopenharmony_ci unsigned int fmt) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(codec_dai->component); 43262306a36Sopenharmony_ci unsigned int iface = 0; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci /* set master/slave audio interface */ 43562306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 43662306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBP_CFP: 43762306a36Sopenharmony_ci iface |= 0x0040; 43862306a36Sopenharmony_ci break; 43962306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBC_CFC: 44062306a36Sopenharmony_ci break; 44162306a36Sopenharmony_ci default: 44262306a36Sopenharmony_ci return -EINVAL; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* interface format */ 44662306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 44762306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 44862306a36Sopenharmony_ci iface |= 0x0002; 44962306a36Sopenharmony_ci break; 45062306a36Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 45162306a36Sopenharmony_ci break; 45262306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 45362306a36Sopenharmony_ci iface |= 0x0001; 45462306a36Sopenharmony_ci break; 45562306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 45662306a36Sopenharmony_ci iface |= 0x0013; 45762306a36Sopenharmony_ci break; 45862306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: 45962306a36Sopenharmony_ci iface |= 0x0003; 46062306a36Sopenharmony_ci break; 46162306a36Sopenharmony_ci default: 46262306a36Sopenharmony_ci return -EINVAL; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci /* clock inversion */ 46662306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 46762306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 46862306a36Sopenharmony_ci break; 46962306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_IF: 47062306a36Sopenharmony_ci iface |= 0x0090; 47162306a36Sopenharmony_ci break; 47262306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 47362306a36Sopenharmony_ci iface |= 0x0080; 47462306a36Sopenharmony_ci break; 47562306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_IF: 47662306a36Sopenharmony_ci iface |= 0x0010; 47762306a36Sopenharmony_ci break; 47862306a36Sopenharmony_ci default: 47962306a36Sopenharmony_ci return -EINVAL; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* set iface */ 48362306a36Sopenharmony_ci regmap_write(ssm2602->regmap, SSM2602_IFACE, iface); 48462306a36Sopenharmony_ci return 0; 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic int ssm2602_set_bias_level(struct snd_soc_component *component, 48862306a36Sopenharmony_ci enum snd_soc_bias_level level) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci switch (level) { 49362306a36Sopenharmony_ci case SND_SOC_BIAS_ON: 49462306a36Sopenharmony_ci /* vref/mid on, osc and clkout on if enabled */ 49562306a36Sopenharmony_ci regmap_update_bits(ssm2602->regmap, SSM2602_PWR, 49662306a36Sopenharmony_ci PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN, 49762306a36Sopenharmony_ci ssm2602->clk_out_pwr); 49862306a36Sopenharmony_ci break; 49962306a36Sopenharmony_ci case SND_SOC_BIAS_PREPARE: 50062306a36Sopenharmony_ci break; 50162306a36Sopenharmony_ci case SND_SOC_BIAS_STANDBY: 50262306a36Sopenharmony_ci /* everything off except vref/vmid, */ 50362306a36Sopenharmony_ci regmap_update_bits(ssm2602->regmap, SSM2602_PWR, 50462306a36Sopenharmony_ci PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN, 50562306a36Sopenharmony_ci PWR_CLK_OUT_PDN | PWR_OSC_PDN); 50662306a36Sopenharmony_ci break; 50762306a36Sopenharmony_ci case SND_SOC_BIAS_OFF: 50862306a36Sopenharmony_ci /* everything off */ 50962306a36Sopenharmony_ci regmap_update_bits(ssm2602->regmap, SSM2602_PWR, 51062306a36Sopenharmony_ci PWR_POWER_OFF, PWR_POWER_OFF); 51162306a36Sopenharmony_ci break; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci return 0; 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ 51862306a36Sopenharmony_ci SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ 51962306a36Sopenharmony_ci SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ 52062306a36Sopenharmony_ci SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ 52162306a36Sopenharmony_ci SNDRV_PCM_RATE_96000) 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci#define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ 52462306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic const struct snd_soc_dai_ops ssm2602_dai_ops = { 52762306a36Sopenharmony_ci .startup = ssm2602_startup, 52862306a36Sopenharmony_ci .hw_params = ssm2602_hw_params, 52962306a36Sopenharmony_ci .mute_stream = ssm2602_mute, 53062306a36Sopenharmony_ci .set_sysclk = ssm2602_set_dai_sysclk, 53162306a36Sopenharmony_ci .set_fmt = ssm2602_set_dai_fmt, 53262306a36Sopenharmony_ci .no_capture_mute = 1, 53362306a36Sopenharmony_ci}; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic struct snd_soc_dai_driver ssm2602_dai = { 53662306a36Sopenharmony_ci .name = "ssm2602-hifi", 53762306a36Sopenharmony_ci .playback = { 53862306a36Sopenharmony_ci .stream_name = "Playback", 53962306a36Sopenharmony_ci .channels_min = 2, 54062306a36Sopenharmony_ci .channels_max = 2, 54162306a36Sopenharmony_ci .rates = SSM2602_RATES, 54262306a36Sopenharmony_ci .formats = SSM2602_FORMATS,}, 54362306a36Sopenharmony_ci .capture = { 54462306a36Sopenharmony_ci .stream_name = "Capture", 54562306a36Sopenharmony_ci .channels_min = 2, 54662306a36Sopenharmony_ci .channels_max = 2, 54762306a36Sopenharmony_ci .rates = SSM2602_RATES, 54862306a36Sopenharmony_ci .formats = SSM2602_FORMATS,}, 54962306a36Sopenharmony_ci .ops = &ssm2602_dai_ops, 55062306a36Sopenharmony_ci .symmetric_rate = 1, 55162306a36Sopenharmony_ci .symmetric_sample_bits = 1, 55262306a36Sopenharmony_ci}; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cistatic int ssm2602_resume(struct snd_soc_component *component) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci regcache_sync(ssm2602->regmap); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci return 0; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic int ssm2602_component_probe(struct snd_soc_component *component) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 56662306a36Sopenharmony_ci struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component); 56762306a36Sopenharmony_ci int ret; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci regmap_update_bits(ssm2602->regmap, SSM2602_LOUT1V, 57062306a36Sopenharmony_ci LOUT1V_LRHP_BOTH, LOUT1V_LRHP_BOTH); 57162306a36Sopenharmony_ci regmap_update_bits(ssm2602->regmap, SSM2602_ROUT1V, 57262306a36Sopenharmony_ci ROUT1V_RLHP_BOTH, ROUT1V_RLHP_BOTH); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci ret = snd_soc_add_component_controls(component, ssm2602_snd_controls, 57562306a36Sopenharmony_ci ARRAY_SIZE(ssm2602_snd_controls)); 57662306a36Sopenharmony_ci if (ret) 57762306a36Sopenharmony_ci return ret; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci ret = snd_soc_dapm_new_controls(dapm, ssm2602_dapm_widgets, 58062306a36Sopenharmony_ci ARRAY_SIZE(ssm2602_dapm_widgets)); 58162306a36Sopenharmony_ci if (ret) 58262306a36Sopenharmony_ci return ret; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci return snd_soc_dapm_add_routes(dapm, ssm2602_routes, 58562306a36Sopenharmony_ci ARRAY_SIZE(ssm2602_routes)); 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic int ssm2604_component_probe(struct snd_soc_component *component) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 59162306a36Sopenharmony_ci int ret; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci ret = snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets, 59462306a36Sopenharmony_ci ARRAY_SIZE(ssm2604_dapm_widgets)); 59562306a36Sopenharmony_ci if (ret) 59662306a36Sopenharmony_ci return ret; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci return snd_soc_dapm_add_routes(dapm, ssm2604_routes, 59962306a36Sopenharmony_ci ARRAY_SIZE(ssm2604_routes)); 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic int ssm260x_component_probe(struct snd_soc_component *component) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component); 60562306a36Sopenharmony_ci int ret; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci ret = regmap_write(ssm2602->regmap, SSM2602_RESET, 0); 60862306a36Sopenharmony_ci if (ret < 0) { 60962306a36Sopenharmony_ci dev_err(component->dev, "Failed to issue reset: %d\n", ret); 61062306a36Sopenharmony_ci return ret; 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci regmap_register_patch(ssm2602->regmap, ssm2602_patch, 61462306a36Sopenharmony_ci ARRAY_SIZE(ssm2602_patch)); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci /* set the update bits */ 61762306a36Sopenharmony_ci regmap_update_bits(ssm2602->regmap, SSM2602_LINVOL, 61862306a36Sopenharmony_ci LINVOL_LRIN_BOTH, LINVOL_LRIN_BOTH); 61962306a36Sopenharmony_ci regmap_update_bits(ssm2602->regmap, SSM2602_RINVOL, 62062306a36Sopenharmony_ci RINVOL_RLIN_BOTH, RINVOL_RLIN_BOTH); 62162306a36Sopenharmony_ci /*select Line in as default input*/ 62262306a36Sopenharmony_ci regmap_write(ssm2602->regmap, SSM2602_APANA, APANA_SELECT_DAC | 62362306a36Sopenharmony_ci APANA_ENABLE_MIC_BOOST); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci switch (ssm2602->type) { 62662306a36Sopenharmony_ci case SSM2602: 62762306a36Sopenharmony_ci ret = ssm2602_component_probe(component); 62862306a36Sopenharmony_ci break; 62962306a36Sopenharmony_ci case SSM2604: 63062306a36Sopenharmony_ci ret = ssm2604_component_probe(component); 63162306a36Sopenharmony_ci break; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci return ret; 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_ssm2602 = { 63862306a36Sopenharmony_ci .probe = ssm260x_component_probe, 63962306a36Sopenharmony_ci .resume = ssm2602_resume, 64062306a36Sopenharmony_ci .set_bias_level = ssm2602_set_bias_level, 64162306a36Sopenharmony_ci .controls = ssm260x_snd_controls, 64262306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(ssm260x_snd_controls), 64362306a36Sopenharmony_ci .dapm_widgets = ssm260x_dapm_widgets, 64462306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(ssm260x_dapm_widgets), 64562306a36Sopenharmony_ci .dapm_routes = ssm260x_routes, 64662306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(ssm260x_routes), 64762306a36Sopenharmony_ci .suspend_bias_off = 1, 64862306a36Sopenharmony_ci .idle_bias_on = 1, 64962306a36Sopenharmony_ci .use_pmdown_time = 1, 65062306a36Sopenharmony_ci .endianness = 1, 65162306a36Sopenharmony_ci}; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic bool ssm2602_register_volatile(struct device *dev, unsigned int reg) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci return reg == SSM2602_RESET; 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ciconst struct regmap_config ssm2602_regmap_config = { 65962306a36Sopenharmony_ci .val_bits = 9, 66062306a36Sopenharmony_ci .reg_bits = 7, 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci .max_register = SSM2602_RESET, 66362306a36Sopenharmony_ci .volatile_reg = ssm2602_register_volatile, 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 66662306a36Sopenharmony_ci .reg_defaults = ssm2602_reg, 66762306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(ssm2602_reg), 66862306a36Sopenharmony_ci}; 66962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ssm2602_regmap_config); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ciint ssm2602_probe(struct device *dev, enum ssm2602_type type, 67262306a36Sopenharmony_ci struct regmap *regmap) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci struct ssm2602_priv *ssm2602; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if (IS_ERR(regmap)) 67762306a36Sopenharmony_ci return PTR_ERR(regmap); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci ssm2602 = devm_kzalloc(dev, sizeof(*ssm2602), GFP_KERNEL); 68062306a36Sopenharmony_ci if (ssm2602 == NULL) 68162306a36Sopenharmony_ci return -ENOMEM; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci dev_set_drvdata(dev, ssm2602); 68462306a36Sopenharmony_ci ssm2602->type = type; 68562306a36Sopenharmony_ci ssm2602->regmap = regmap; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci return devm_snd_soc_register_component(dev, &soc_component_dev_ssm2602, 68862306a36Sopenharmony_ci &ssm2602_dai, 1); 68962306a36Sopenharmony_ci} 69062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ssm2602_probe); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 driver"); 69362306a36Sopenharmony_ciMODULE_AUTHOR("Cliff Cai"); 69462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 695