cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ssm2602.c (18494B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2//
      3// File:         sound/soc/codecs/ssm2602.c
      4// Author:       Cliff Cai <Cliff.Cai@analog.com>
      5//
      6// Created:      Tue June 06 2008
      7// Description:  Driver for ssm2602 sound chip
      8//
      9// Modified:
     10//               Copyright 2008 Analog Devices Inc.
     11//
     12// Bugs:         Enter bugs at http://blackfin.uclinux.org/
     13
     14#include <linux/delay.h>
     15#include <linux/module.h>
     16#include <linux/regmap.h>
     17#include <linux/slab.h>
     18
     19#include <sound/pcm.h>
     20#include <sound/pcm_params.h>
     21#include <sound/soc.h>
     22#include <sound/tlv.h>
     23
     24#include "ssm2602.h"
     25
     26/* codec private data */
     27struct ssm2602_priv {
     28	unsigned int sysclk;
     29	const struct snd_pcm_hw_constraint_list *sysclk_constraints;
     30
     31	struct regmap *regmap;
     32
     33	enum ssm2602_type type;
     34	unsigned int clk_out_pwr;
     35};
     36
     37/*
     38 * ssm2602 register cache
     39 * We can't read the ssm2602 register space when we are
     40 * using 2 wire for device control, so we cache them instead.
     41 * There is no point in caching the reset register
     42 */
     43static const struct reg_default ssm2602_reg[SSM2602_CACHEREGNUM] = {
     44	{ .reg = 0x00, .def = 0x0097 },
     45	{ .reg = 0x01, .def = 0x0097 },
     46	{ .reg = 0x02, .def = 0x0079 },
     47	{ .reg = 0x03, .def = 0x0079 },
     48	{ .reg = 0x04, .def = 0x000a },
     49	{ .reg = 0x05, .def = 0x0008 },
     50	{ .reg = 0x06, .def = 0x009f },
     51	{ .reg = 0x07, .def = 0x000a },
     52	{ .reg = 0x08, .def = 0x0000 },
     53	{ .reg = 0x09, .def = 0x0000 }
     54};
     55
     56
     57/*Appending several "None"s just for OSS mixer use*/
     58static const char *ssm2602_input_select[] = {
     59	"Line", "Mic",
     60};
     61
     62static const char *ssm2602_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
     63
     64static const struct soc_enum ssm2602_enum[] = {
     65	SOC_ENUM_SINGLE(SSM2602_APANA, 2, ARRAY_SIZE(ssm2602_input_select),
     66			ssm2602_input_select),
     67	SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, ARRAY_SIZE(ssm2602_deemph),
     68			ssm2602_deemph),
     69};
     70
     71static const DECLARE_TLV_DB_RANGE(ssm260x_outmix_tlv,
     72	0, 47, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
     73	48, 127, TLV_DB_SCALE_ITEM(-7400, 100, 0)
     74);
     75
     76static const DECLARE_TLV_DB_SCALE(ssm260x_inpga_tlv, -3450, 150, 0);
     77static const DECLARE_TLV_DB_SCALE(ssm260x_sidetone_tlv, -1500, 300, 0);
     78
     79static const struct snd_kcontrol_new ssm260x_snd_controls[] = {
     80SOC_DOUBLE_R_TLV("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 45, 0,
     81	ssm260x_inpga_tlv),
     82SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1),
     83
     84SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1),
     85SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0),
     86
     87SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]),
     88};
     89
     90static const struct snd_kcontrol_new ssm2602_snd_controls[] = {
     91SOC_DOUBLE_R_TLV("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V,
     92	0, 127, 0, ssm260x_outmix_tlv),
     93SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V,
     94	7, 1, 0),
     95SOC_SINGLE_TLV("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1,
     96	ssm260x_sidetone_tlv),
     97
     98SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
     99SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 8, 1, 0),
    100};
    101
    102/* Output Mixer */
    103static const struct snd_kcontrol_new ssm260x_output_mixer_controls[] = {
    104SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0),
    105SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0),
    106SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0),
    107};
    108
    109static const struct snd_kcontrol_new mic_ctl =
    110	SOC_DAPM_SINGLE("Switch", SSM2602_APANA, 1, 1, 1);
    111
    112/* Input mux */
    113static const struct snd_kcontrol_new ssm2602_input_mux_controls =
    114SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]);
    115
    116static int ssm2602_mic_switch_event(struct snd_soc_dapm_widget *w,
    117				struct snd_kcontrol *kcontrol, int event)
    118{
    119	/*
    120	 * According to the ssm2603 data sheet (control register sequencing),
    121	 * the digital core should be activated only after all necessary bits
    122	 * in the power register are enabled, and a delay determined by the
    123	 * decoupling capacitor on the VMID pin has passed. If the digital core
    124	 * is activated too early, or even before the ADC is powered up, audible
    125	 * artifacts appear at the beginning and end of the recorded signal.
    126	 *
    127	 * In practice, audible artifacts disappear well over 500 ms.
    128	 */
    129	msleep(500);
    130
    131	return 0;
    132}
    133
    134static const struct snd_soc_dapm_widget ssm260x_dapm_widgets[] = {
    135SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1),
    136SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1),
    137SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0),
    138
    139SND_SOC_DAPM_SUPPLY("Digital Core Power", SSM2602_ACTIVE, 0, 0, NULL, 0),
    140
    141SND_SOC_DAPM_OUTPUT("LOUT"),
    142SND_SOC_DAPM_OUTPUT("ROUT"),
    143SND_SOC_DAPM_INPUT("RLINEIN"),
    144SND_SOC_DAPM_INPUT("LLINEIN"),
    145};
    146
    147static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = {
    148SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1,
    149	ssm260x_output_mixer_controls,
    150	ARRAY_SIZE(ssm260x_output_mixer_controls)),
    151
    152SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls),
    153SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1),
    154
    155SND_SOC_DAPM_SWITCH_E("Mic Switch", SSM2602_APANA, 1, 1, &mic_ctl,
    156		ssm2602_mic_switch_event, SND_SOC_DAPM_PRE_PMU),
    157
    158SND_SOC_DAPM_OUTPUT("LHPOUT"),
    159SND_SOC_DAPM_OUTPUT("RHPOUT"),
    160SND_SOC_DAPM_INPUT("MICIN"),
    161};
    162
    163static const struct snd_soc_dapm_widget ssm2604_dapm_widgets[] = {
    164SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0,
    165	ssm260x_output_mixer_controls,
    166	ARRAY_SIZE(ssm260x_output_mixer_controls) - 1), /* Last element is the mic */
    167};
    168
    169static const struct snd_soc_dapm_route ssm260x_routes[] = {
    170	{"DAC", NULL, "Digital Core Power"},
    171	{"ADC", NULL, "Digital Core Power"},
    172
    173	{"Output Mixer", "Line Bypass Switch", "Line Input"},
    174	{"Output Mixer", "HiFi Playback Switch", "DAC"},
    175
    176	{"ROUT", NULL, "Output Mixer"},
    177	{"LOUT", NULL, "Output Mixer"},
    178
    179	{"Line Input", NULL, "LLINEIN"},
    180	{"Line Input", NULL, "RLINEIN"},
    181};
    182
    183static const struct snd_soc_dapm_route ssm2602_routes[] = {
    184	{"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
    185
    186	{"RHPOUT", NULL, "Output Mixer"},
    187	{"LHPOUT", NULL, "Output Mixer"},
    188
    189	{"Input Mux", "Line", "Line Input"},
    190	{"Input Mux", "Mic", "Mic Switch"},
    191	{"ADC", NULL, "Input Mux"},
    192
    193	{"Mic Switch", NULL, "Mic Bias"},
    194
    195	{"Mic Bias", NULL, "MICIN"},
    196};
    197
    198static const struct snd_soc_dapm_route ssm2604_routes[] = {
    199	{"ADC", NULL, "Line Input"},
    200};
    201
    202static const unsigned int ssm2602_rates_12288000[] = {
    203	8000, 16000, 32000, 48000, 96000,
    204};
    205
    206static const struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = {
    207	.list = ssm2602_rates_12288000,
    208	.count = ARRAY_SIZE(ssm2602_rates_12288000),
    209};
    210
    211static const unsigned int ssm2602_rates_11289600[] = {
    212	8000, 11025, 22050, 44100, 88200,
    213};
    214
    215static const struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = {
    216	.list = ssm2602_rates_11289600,
    217	.count = ARRAY_SIZE(ssm2602_rates_11289600),
    218};
    219
    220struct ssm2602_coeff {
    221	u32 mclk;
    222	u32 rate;
    223	u8 srate;
    224};
    225
    226#define SSM2602_COEFF_SRATE(sr, bosr, usb) (((sr) << 2) | ((bosr) << 1) | (usb))
    227
    228/* codec mclk clock coefficients */
    229static const struct ssm2602_coeff ssm2602_coeff_table[] = {
    230	/* 48k */
    231	{12288000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x0)},
    232	{18432000, 48000, SSM2602_COEFF_SRATE(0x0, 0x1, 0x0)},
    233	{12000000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x1)},
    234
    235	/* 32k */
    236	{12288000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x0)},
    237	{18432000, 32000, SSM2602_COEFF_SRATE(0x6, 0x1, 0x0)},
    238	{12000000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x1)},
    239
    240	/* 16k */
    241	{12288000, 16000, SSM2602_COEFF_SRATE(0x5, 0x0, 0x0)},
    242	{18432000, 16000, SSM2602_COEFF_SRATE(0x5, 0x1, 0x0)},
    243	{12000000, 16000, SSM2602_COEFF_SRATE(0xa, 0x0, 0x1)},
    244
    245	/* 8k */
    246	{12288000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x0)},
    247	{18432000, 8000, SSM2602_COEFF_SRATE(0x3, 0x1, 0x0)},
    248	{11289600, 8000, SSM2602_COEFF_SRATE(0xb, 0x0, 0x0)},
    249	{16934400, 8000, SSM2602_COEFF_SRATE(0xb, 0x1, 0x0)},
    250	{12000000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x1)},
    251
    252	/* 96k */
    253	{12288000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x0)},
    254	{18432000, 96000, SSM2602_COEFF_SRATE(0x7, 0x1, 0x0)},
    255	{12000000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x1)},
    256
    257	/* 11.025k */
    258	{11289600, 11025, SSM2602_COEFF_SRATE(0xc, 0x0, 0x0)},
    259	{16934400, 11025, SSM2602_COEFF_SRATE(0xc, 0x1, 0x0)},
    260	{12000000, 11025, SSM2602_COEFF_SRATE(0xc, 0x1, 0x1)},
    261
    262	/* 22.05k */
    263	{11289600, 22050, SSM2602_COEFF_SRATE(0xd, 0x0, 0x0)},
    264	{16934400, 22050, SSM2602_COEFF_SRATE(0xd, 0x1, 0x0)},
    265	{12000000, 22050, SSM2602_COEFF_SRATE(0xd, 0x1, 0x1)},
    266
    267	/* 44.1k */
    268	{11289600, 44100, SSM2602_COEFF_SRATE(0x8, 0x0, 0x0)},
    269	{16934400, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x0)},
    270	{12000000, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x1)},
    271
    272	/* 88.2k */
    273	{11289600, 88200, SSM2602_COEFF_SRATE(0xf, 0x0, 0x0)},
    274	{16934400, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x0)},
    275	{12000000, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x1)},
    276};
    277
    278static inline int ssm2602_get_coeff(int mclk, int rate)
    279{
    280	int i;
    281
    282	for (i = 0; i < ARRAY_SIZE(ssm2602_coeff_table); i++) {
    283		if (ssm2602_coeff_table[i].rate == rate &&
    284			ssm2602_coeff_table[i].mclk == mclk)
    285			return ssm2602_coeff_table[i].srate;
    286	}
    287	return -EINVAL;
    288}
    289
    290static int ssm2602_hw_params(struct snd_pcm_substream *substream,
    291	struct snd_pcm_hw_params *params,
    292	struct snd_soc_dai *dai)
    293{
    294	struct snd_soc_component *component = dai->component;
    295	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
    296	int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params));
    297	unsigned int iface;
    298
    299	if (srate < 0)
    300		return srate;
    301
    302	regmap_write(ssm2602->regmap, SSM2602_SRATE, srate);
    303
    304	/* bit size */
    305	switch (params_width(params)) {
    306	case 16:
    307		iface = 0x0;
    308		break;
    309	case 20:
    310		iface = 0x4;
    311		break;
    312	case 24:
    313		iface = 0x8;
    314		break;
    315	case 32:
    316		iface = 0xc;
    317		break;
    318	default:
    319		return -EINVAL;
    320	}
    321	regmap_update_bits(ssm2602->regmap, SSM2602_IFACE,
    322		IFACE_AUDIO_DATA_LEN, iface);
    323	return 0;
    324}
    325
    326static int ssm2602_startup(struct snd_pcm_substream *substream,
    327			   struct snd_soc_dai *dai)
    328{
    329	struct snd_soc_component *component = dai->component;
    330	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
    331
    332	if (ssm2602->sysclk_constraints) {
    333		snd_pcm_hw_constraint_list(substream->runtime, 0,
    334				   SNDRV_PCM_HW_PARAM_RATE,
    335				   ssm2602->sysclk_constraints);
    336	}
    337
    338	return 0;
    339}
    340
    341static int ssm2602_mute(struct snd_soc_dai *dai, int mute, int direction)
    342{
    343	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(dai->component);
    344
    345	if (mute)
    346		regmap_update_bits(ssm2602->regmap, SSM2602_APDIGI,
    347				    APDIGI_ENABLE_DAC_MUTE,
    348				    APDIGI_ENABLE_DAC_MUTE);
    349	else
    350		regmap_update_bits(ssm2602->regmap, SSM2602_APDIGI,
    351				    APDIGI_ENABLE_DAC_MUTE, 0);
    352	return 0;
    353}
    354
    355static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,
    356		int clk_id, unsigned int freq, int dir)
    357{
    358	struct snd_soc_component *component = codec_dai->component;
    359	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
    360
    361	if (dir == SND_SOC_CLOCK_IN) {
    362		if (clk_id != SSM2602_SYSCLK)
    363			return -EINVAL;
    364
    365		switch (freq) {
    366		case 12288000:
    367		case 18432000:
    368			ssm2602->sysclk_constraints = &ssm2602_constraints_12288000;
    369			break;
    370		case 11289600:
    371		case 16934400:
    372			ssm2602->sysclk_constraints = &ssm2602_constraints_11289600;
    373			break;
    374		case 12000000:
    375			ssm2602->sysclk_constraints = NULL;
    376			break;
    377		default:
    378			return -EINVAL;
    379		}
    380		ssm2602->sysclk = freq;
    381	} else {
    382		unsigned int mask;
    383
    384		switch (clk_id) {
    385		case SSM2602_CLK_CLKOUT:
    386			mask = PWR_CLK_OUT_PDN;
    387			break;
    388		case SSM2602_CLK_XTO:
    389			mask = PWR_OSC_PDN;
    390			break;
    391		default:
    392			return -EINVAL;
    393		}
    394
    395		if (freq == 0)
    396			ssm2602->clk_out_pwr |= mask;
    397		else
    398			ssm2602->clk_out_pwr &= ~mask;
    399
    400		regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
    401			PWR_CLK_OUT_PDN | PWR_OSC_PDN, ssm2602->clk_out_pwr);
    402	}
    403
    404	return 0;
    405}
    406
    407static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
    408		unsigned int fmt)
    409{
    410	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(codec_dai->component);
    411	unsigned int iface = 0;
    412
    413	/* set master/slave audio interface */
    414	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
    415	case SND_SOC_DAIFMT_CBM_CFM:
    416		iface |= 0x0040;
    417		break;
    418	case SND_SOC_DAIFMT_CBS_CFS:
    419		break;
    420	default:
    421		return -EINVAL;
    422	}
    423
    424	/* interface format */
    425	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
    426	case SND_SOC_DAIFMT_I2S:
    427		iface |= 0x0002;
    428		break;
    429	case SND_SOC_DAIFMT_RIGHT_J:
    430		break;
    431	case SND_SOC_DAIFMT_LEFT_J:
    432		iface |= 0x0001;
    433		break;
    434	case SND_SOC_DAIFMT_DSP_A:
    435		iface |= 0x0013;
    436		break;
    437	case SND_SOC_DAIFMT_DSP_B:
    438		iface |= 0x0003;
    439		break;
    440	default:
    441		return -EINVAL;
    442	}
    443
    444	/* clock inversion */
    445	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
    446	case SND_SOC_DAIFMT_NB_NF:
    447		break;
    448	case SND_SOC_DAIFMT_IB_IF:
    449		iface |= 0x0090;
    450		break;
    451	case SND_SOC_DAIFMT_IB_NF:
    452		iface |= 0x0080;
    453		break;
    454	case SND_SOC_DAIFMT_NB_IF:
    455		iface |= 0x0010;
    456		break;
    457	default:
    458		return -EINVAL;
    459	}
    460
    461	/* set iface */
    462	regmap_write(ssm2602->regmap, SSM2602_IFACE, iface);
    463	return 0;
    464}
    465
    466static int ssm2602_set_bias_level(struct snd_soc_component *component,
    467				 enum snd_soc_bias_level level)
    468{
    469	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
    470
    471	switch (level) {
    472	case SND_SOC_BIAS_ON:
    473		/* vref/mid on, osc and clkout on if enabled */
    474		regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
    475			PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
    476			ssm2602->clk_out_pwr);
    477		break;
    478	case SND_SOC_BIAS_PREPARE:
    479		break;
    480	case SND_SOC_BIAS_STANDBY:
    481		/* everything off except vref/vmid, */
    482		regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
    483			PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
    484			PWR_CLK_OUT_PDN | PWR_OSC_PDN);
    485		break;
    486	case SND_SOC_BIAS_OFF:
    487		/* everything off */
    488		regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
    489			PWR_POWER_OFF, PWR_POWER_OFF);
    490		break;
    491
    492	}
    493	return 0;
    494}
    495
    496#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
    497		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
    498		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
    499		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
    500		SNDRV_PCM_RATE_96000)
    501
    502#define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
    503		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
    504
    505static const struct snd_soc_dai_ops ssm2602_dai_ops = {
    506	.startup	= ssm2602_startup,
    507	.hw_params	= ssm2602_hw_params,
    508	.mute_stream	= ssm2602_mute,
    509	.set_sysclk	= ssm2602_set_dai_sysclk,
    510	.set_fmt	= ssm2602_set_dai_fmt,
    511	.no_capture_mute = 1,
    512};
    513
    514static struct snd_soc_dai_driver ssm2602_dai = {
    515	.name = "ssm2602-hifi",
    516	.playback = {
    517		.stream_name = "Playback",
    518		.channels_min = 2,
    519		.channels_max = 2,
    520		.rates = SSM2602_RATES,
    521		.formats = SSM2602_FORMATS,},
    522	.capture = {
    523		.stream_name = "Capture",
    524		.channels_min = 2,
    525		.channels_max = 2,
    526		.rates = SSM2602_RATES,
    527		.formats = SSM2602_FORMATS,},
    528	.ops = &ssm2602_dai_ops,
    529	.symmetric_rate = 1,
    530	.symmetric_sample_bits = 1,
    531};
    532
    533static int ssm2602_resume(struct snd_soc_component *component)
    534{
    535	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
    536
    537	regcache_sync(ssm2602->regmap);
    538
    539	return 0;
    540}
    541
    542static int ssm2602_component_probe(struct snd_soc_component *component)
    543{
    544	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
    545	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
    546	int ret;
    547
    548	regmap_update_bits(ssm2602->regmap, SSM2602_LOUT1V,
    549			    LOUT1V_LRHP_BOTH, LOUT1V_LRHP_BOTH);
    550	regmap_update_bits(ssm2602->regmap, SSM2602_ROUT1V,
    551			    ROUT1V_RLHP_BOTH, ROUT1V_RLHP_BOTH);
    552
    553	ret = snd_soc_add_component_controls(component, ssm2602_snd_controls,
    554			ARRAY_SIZE(ssm2602_snd_controls));
    555	if (ret)
    556		return ret;
    557
    558	ret = snd_soc_dapm_new_controls(dapm, ssm2602_dapm_widgets,
    559			ARRAY_SIZE(ssm2602_dapm_widgets));
    560	if (ret)
    561		return ret;
    562
    563	return snd_soc_dapm_add_routes(dapm, ssm2602_routes,
    564			ARRAY_SIZE(ssm2602_routes));
    565}
    566
    567static int ssm2604_component_probe(struct snd_soc_component *component)
    568{
    569	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
    570	int ret;
    571
    572	ret = snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets,
    573			ARRAY_SIZE(ssm2604_dapm_widgets));
    574	if (ret)
    575		return ret;
    576
    577	return snd_soc_dapm_add_routes(dapm, ssm2604_routes,
    578			ARRAY_SIZE(ssm2604_routes));
    579}
    580
    581static int ssm260x_component_probe(struct snd_soc_component *component)
    582{
    583	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
    584	int ret;
    585
    586	ret = regmap_write(ssm2602->regmap, SSM2602_RESET, 0);
    587	if (ret < 0) {
    588		dev_err(component->dev, "Failed to issue reset: %d\n", ret);
    589		return ret;
    590	}
    591
    592	/* set the update bits */
    593	regmap_update_bits(ssm2602->regmap, SSM2602_LINVOL,
    594			    LINVOL_LRIN_BOTH, LINVOL_LRIN_BOTH);
    595	regmap_update_bits(ssm2602->regmap, SSM2602_RINVOL,
    596			    RINVOL_RLIN_BOTH, RINVOL_RLIN_BOTH);
    597	/*select Line in as default input*/
    598	regmap_write(ssm2602->regmap, SSM2602_APANA, APANA_SELECT_DAC |
    599			APANA_ENABLE_MIC_BOOST);
    600
    601	switch (ssm2602->type) {
    602	case SSM2602:
    603		ret = ssm2602_component_probe(component);
    604		break;
    605	case SSM2604:
    606		ret = ssm2604_component_probe(component);
    607		break;
    608	}
    609
    610	return ret;
    611}
    612
    613static const struct snd_soc_component_driver soc_component_dev_ssm2602 = {
    614	.probe			= ssm260x_component_probe,
    615	.resume			= ssm2602_resume,
    616	.set_bias_level		= ssm2602_set_bias_level,
    617	.controls		= ssm260x_snd_controls,
    618	.num_controls		= ARRAY_SIZE(ssm260x_snd_controls),
    619	.dapm_widgets		= ssm260x_dapm_widgets,
    620	.num_dapm_widgets	= ARRAY_SIZE(ssm260x_dapm_widgets),
    621	.dapm_routes		= ssm260x_routes,
    622	.num_dapm_routes	= ARRAY_SIZE(ssm260x_routes),
    623	.suspend_bias_off	= 1,
    624	.idle_bias_on		= 1,
    625	.use_pmdown_time	= 1,
    626	.endianness		= 1,
    627	.non_legacy_dai_naming	= 1,
    628};
    629
    630static bool ssm2602_register_volatile(struct device *dev, unsigned int reg)
    631{
    632	return reg == SSM2602_RESET;
    633}
    634
    635const struct regmap_config ssm2602_regmap_config = {
    636	.val_bits = 9,
    637	.reg_bits = 7,
    638
    639	.max_register = SSM2602_RESET,
    640	.volatile_reg = ssm2602_register_volatile,
    641
    642	.cache_type = REGCACHE_RBTREE,
    643	.reg_defaults = ssm2602_reg,
    644	.num_reg_defaults = ARRAY_SIZE(ssm2602_reg),
    645};
    646EXPORT_SYMBOL_GPL(ssm2602_regmap_config);
    647
    648int ssm2602_probe(struct device *dev, enum ssm2602_type type,
    649	struct regmap *regmap)
    650{
    651	struct ssm2602_priv *ssm2602;
    652
    653	if (IS_ERR(regmap))
    654		return PTR_ERR(regmap);
    655
    656	ssm2602 = devm_kzalloc(dev, sizeof(*ssm2602), GFP_KERNEL);
    657	if (ssm2602 == NULL)
    658		return -ENOMEM;
    659
    660	dev_set_drvdata(dev, ssm2602);
    661	ssm2602->type = type;
    662	ssm2602->regmap = regmap;
    663
    664	return devm_snd_soc_register_component(dev, &soc_component_dev_ssm2602,
    665		&ssm2602_dai, 1);
    666}
    667EXPORT_SYMBOL_GPL(ssm2602_probe);
    668
    669MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 driver");
    670MODULE_AUTHOR("Cliff Cai");
    671MODULE_LICENSE("GPL");