147306401SMarco Felsch // SPDX-License-Identifier: GPL-2.0-or-later
247306401SMarco Felsch //
347306401SMarco Felsch // File: sound/soc/codecs/ssm2602.c
447306401SMarco Felsch // Author: Cliff Cai <Cliff.Cai@analog.com>
547306401SMarco Felsch //
647306401SMarco Felsch // Created: Tue June 06 2008
747306401SMarco Felsch // Description: Driver for ssm2602 sound chip
847306401SMarco Felsch //
947306401SMarco Felsch // Modified:
1047306401SMarco Felsch // Copyright 2008 Analog Devices Inc.
1147306401SMarco Felsch //
1247306401SMarco Felsch // Bugs: Enter bugs at http://blackfin.uclinux.org/
13b7138212SCliff Cai
1437768e39SPhilipp Zabel #include <linux/delay.h>
15b7138212SCliff Cai #include <linux/module.h>
16bec3d9a9SLars-Peter Clausen #include <linux/regmap.h>
175a0e3ad6STejun Heo #include <linux/slab.h>
18c924dc68SLars-Peter Clausen
19b7138212SCliff Cai #include <sound/pcm.h>
20b7138212SCliff Cai #include <sound/pcm_params.h>
21b7138212SCliff Cai #include <sound/soc.h>
22f3eee00dSLars-Peter Clausen #include <sound/tlv.h>
23b7138212SCliff Cai
24b7138212SCliff Cai #include "ssm2602.h"
25b7138212SCliff Cai
26b7138212SCliff Cai /* codec private data */
27b7138212SCliff Cai struct ssm2602_priv {
28b7138212SCliff Cai unsigned int sysclk;
29f75ac2d9SLars-Peter Clausen const struct snd_pcm_hw_constraint_list *sysclk_constraints;
30b1f7b2b5SLars-Peter Clausen
31bec3d9a9SLars-Peter Clausen struct regmap *regmap;
32bec3d9a9SLars-Peter Clausen
33b1f7b2b5SLars-Peter Clausen enum ssm2602_type type;
3402890535SLars-Peter Clausen unsigned int clk_out_pwr;
35b7138212SCliff Cai };
36b7138212SCliff Cai
37b7138212SCliff Cai /*
38b7138212SCliff Cai * ssm2602 register cache
39b7138212SCliff Cai * We can't read the ssm2602 register space when we are
40b7138212SCliff Cai * using 2 wire for device control, so we cache them instead.
41b7138212SCliff Cai * There is no point in caching the reset register
42b7138212SCliff Cai */
43a01df75cSJames Kelly static const struct reg_default ssm2602_reg[SSM2602_CACHEREGNUM] = {
44a01df75cSJames Kelly { .reg = 0x00, .def = 0x0097 },
45a01df75cSJames Kelly { .reg = 0x01, .def = 0x0097 },
46a01df75cSJames Kelly { .reg = 0x02, .def = 0x0079 },
47a01df75cSJames Kelly { .reg = 0x03, .def = 0x0079 },
48a01df75cSJames Kelly { .reg = 0x04, .def = 0x000a },
49a01df75cSJames Kelly { .reg = 0x05, .def = 0x0008 },
50a01df75cSJames Kelly { .reg = 0x06, .def = 0x009f },
51a01df75cSJames Kelly { .reg = 0x07, .def = 0x000a },
52a01df75cSJames Kelly { .reg = 0x08, .def = 0x0000 },
53a01df75cSJames Kelly { .reg = 0x09, .def = 0x0000 }
54b7138212SCliff Cai };
55b7138212SCliff Cai
56*f63550e2SPaweł Anikiel /*
57*f63550e2SPaweł Anikiel * ssm2602 register patch
58*f63550e2SPaweł Anikiel * Workaround for playback distortions after power up: activates digital
59*f63550e2SPaweł Anikiel * core, and then powers on output, DAC, and whole chip at the same time
60*f63550e2SPaweł Anikiel */
61*f63550e2SPaweł Anikiel
62*f63550e2SPaweł Anikiel static const struct reg_sequence ssm2602_patch[] = {
63*f63550e2SPaweł Anikiel { SSM2602_ACTIVE, 0x01 },
64*f63550e2SPaweł Anikiel { SSM2602_PWR, 0x07 },
65*f63550e2SPaweł Anikiel { SSM2602_RESET, 0x00 },
66*f63550e2SPaweł Anikiel };
67*f63550e2SPaweł Anikiel
68b7138212SCliff Cai
69b7138212SCliff Cai /*Appending several "None"s just for OSS mixer use*/
70b7138212SCliff Cai static const char *ssm2602_input_select[] = {
71b38fbe30STakashi Iwai "Line", "Mic",
72b7138212SCliff Cai };
73b7138212SCliff Cai
74b7138212SCliff Cai static const char *ssm2602_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
75b7138212SCliff Cai
76b7138212SCliff Cai static const struct soc_enum ssm2602_enum[] = {
77b38fbe30STakashi Iwai SOC_ENUM_SINGLE(SSM2602_APANA, 2, ARRAY_SIZE(ssm2602_input_select),
78b38fbe30STakashi Iwai ssm2602_input_select),
79b38fbe30STakashi Iwai SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, ARRAY_SIZE(ssm2602_deemph),
80b38fbe30STakashi Iwai ssm2602_deemph),
81b7138212SCliff Cai };
82b7138212SCliff Cai
83f9d54802SLars-Peter Clausen static const DECLARE_TLV_DB_RANGE(ssm260x_outmix_tlv,
84f3eee00dSLars-Peter Clausen 0, 47, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
85f9d54802SLars-Peter Clausen 48, 127, TLV_DB_SCALE_ITEM(-7400, 100, 0)
86f9d54802SLars-Peter Clausen );
87f3eee00dSLars-Peter Clausen
88f3eee00dSLars-Peter Clausen static const DECLARE_TLV_DB_SCALE(ssm260x_inpga_tlv, -3450, 150, 0);
89f3eee00dSLars-Peter Clausen static const DECLARE_TLV_DB_SCALE(ssm260x_sidetone_tlv, -1500, 300, 0);
90f3eee00dSLars-Peter Clausen
91b1f7b2b5SLars-Peter Clausen static const struct snd_kcontrol_new ssm260x_snd_controls[] = {
92f3eee00dSLars-Peter Clausen SOC_DOUBLE_R_TLV("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 45, 0,
93f3eee00dSLars-Peter Clausen ssm260x_inpga_tlv),
94b7138212SCliff Cai SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1),
95b7138212SCliff Cai
96b7138212SCliff Cai SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1),
97b7138212SCliff Cai SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0),
98b7138212SCliff Cai
99b7138212SCliff Cai SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]),
100b7138212SCliff Cai };
101b7138212SCliff Cai
102b1f7b2b5SLars-Peter Clausen static const struct snd_kcontrol_new ssm2602_snd_controls[] = {
103f3eee00dSLars-Peter Clausen SOC_DOUBLE_R_TLV("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V,
104f3eee00dSLars-Peter Clausen 0, 127, 0, ssm260x_outmix_tlv),
105b1f7b2b5SLars-Peter Clausen SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V,
106b1f7b2b5SLars-Peter Clausen 7, 1, 0),
107f3eee00dSLars-Peter Clausen SOC_SINGLE_TLV("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1,
108f3eee00dSLars-Peter Clausen ssm260x_sidetone_tlv),
109b1f7b2b5SLars-Peter Clausen
110b1f7b2b5SLars-Peter Clausen SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
111b1f7b2b5SLars-Peter Clausen SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 8, 1, 0),
112b1f7b2b5SLars-Peter Clausen };
113b1f7b2b5SLars-Peter Clausen
114b7138212SCliff Cai /* Output Mixer */
115b1f7b2b5SLars-Peter Clausen static const struct snd_kcontrol_new ssm260x_output_mixer_controls[] = {
116b7138212SCliff Cai SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0),
117b7138212SCliff Cai SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0),
118b1f7b2b5SLars-Peter Clausen SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0),
119b7138212SCliff Cai };
120b7138212SCliff Cai
12137768e39SPhilipp Zabel static const struct snd_kcontrol_new mic_ctl =
12237768e39SPhilipp Zabel SOC_DAPM_SINGLE("Switch", SSM2602_APANA, 1, 1, 1);
12337768e39SPhilipp Zabel
124b7138212SCliff Cai /* Input mux */
125b7138212SCliff Cai static const struct snd_kcontrol_new ssm2602_input_mux_controls =
126b7138212SCliff Cai SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]);
127b7138212SCliff Cai
ssm2602_mic_switch_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)12837768e39SPhilipp Zabel static int ssm2602_mic_switch_event(struct snd_soc_dapm_widget *w,
12937768e39SPhilipp Zabel struct snd_kcontrol *kcontrol, int event)
13037768e39SPhilipp Zabel {
13137768e39SPhilipp Zabel /*
13237768e39SPhilipp Zabel * According to the ssm2603 data sheet (control register sequencing),
13337768e39SPhilipp Zabel * the digital core should be activated only after all necessary bits
13437768e39SPhilipp Zabel * in the power register are enabled, and a delay determined by the
13537768e39SPhilipp Zabel * decoupling capacitor on the VMID pin has passed. If the digital core
13637768e39SPhilipp Zabel * is activated too early, or even before the ADC is powered up, audible
13737768e39SPhilipp Zabel * artifacts appear at the beginning and end of the recorded signal.
13837768e39SPhilipp Zabel *
13937768e39SPhilipp Zabel * In practice, audible artifacts disappear well over 500 ms.
14037768e39SPhilipp Zabel */
14137768e39SPhilipp Zabel msleep(500);
14237768e39SPhilipp Zabel
14337768e39SPhilipp Zabel return 0;
14437768e39SPhilipp Zabel }
14537768e39SPhilipp Zabel
146b1f7b2b5SLars-Peter Clausen static const struct snd_soc_dapm_widget ssm260x_dapm_widgets[] = {
147b7138212SCliff Cai SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1),
148b7138212SCliff Cai SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1),
149b7138212SCliff Cai SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0),
150b1f7b2b5SLars-Peter Clausen
1513afb1b3eSMark Brown SND_SOC_DAPM_SUPPLY("Digital Core Power", SSM2602_ACTIVE, 0, 0, NULL, 0),
1522a43801aSLars-Peter Clausen
153b1f7b2b5SLars-Peter Clausen SND_SOC_DAPM_OUTPUT("LOUT"),
154b1f7b2b5SLars-Peter Clausen SND_SOC_DAPM_OUTPUT("ROUT"),
155b7138212SCliff Cai SND_SOC_DAPM_INPUT("RLINEIN"),
156b7138212SCliff Cai SND_SOC_DAPM_INPUT("LLINEIN"),
157b7138212SCliff Cai };
158b7138212SCliff Cai
159b1f7b2b5SLars-Peter Clausen static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = {
160b1f7b2b5SLars-Peter Clausen SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1,
161b1f7b2b5SLars-Peter Clausen ssm260x_output_mixer_controls,
162b1f7b2b5SLars-Peter Clausen ARRAY_SIZE(ssm260x_output_mixer_controls)),
163b1f7b2b5SLars-Peter Clausen
164b1f7b2b5SLars-Peter Clausen SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls),
165b1f7b2b5SLars-Peter Clausen SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1),
166b1f7b2b5SLars-Peter Clausen
16737768e39SPhilipp Zabel SND_SOC_DAPM_SWITCH_E("Mic Switch", SSM2602_APANA, 1, 1, &mic_ctl,
16837768e39SPhilipp Zabel ssm2602_mic_switch_event, SND_SOC_DAPM_PRE_PMU),
16937768e39SPhilipp Zabel
170b1f7b2b5SLars-Peter Clausen SND_SOC_DAPM_OUTPUT("LHPOUT"),
171b1f7b2b5SLars-Peter Clausen SND_SOC_DAPM_OUTPUT("RHPOUT"),
172b1f7b2b5SLars-Peter Clausen SND_SOC_DAPM_INPUT("MICIN"),
173b1f7b2b5SLars-Peter Clausen };
174b1f7b2b5SLars-Peter Clausen
175b1f7b2b5SLars-Peter Clausen static const struct snd_soc_dapm_widget ssm2604_dapm_widgets[] = {
176b1f7b2b5SLars-Peter Clausen SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0,
177b1f7b2b5SLars-Peter Clausen ssm260x_output_mixer_controls,
178b1f7b2b5SLars-Peter Clausen ARRAY_SIZE(ssm260x_output_mixer_controls) - 1), /* Last element is the mic */
179b1f7b2b5SLars-Peter Clausen };
180b1f7b2b5SLars-Peter Clausen
181b1f7b2b5SLars-Peter Clausen static const struct snd_soc_dapm_route ssm260x_routes[] = {
1822a43801aSLars-Peter Clausen {"DAC", NULL, "Digital Core Power"},
1832a43801aSLars-Peter Clausen {"ADC", NULL, "Digital Core Power"},
1842a43801aSLars-Peter Clausen
185b7138212SCliff Cai {"Output Mixer", "Line Bypass Switch", "Line Input"},
186b7138212SCliff Cai {"Output Mixer", "HiFi Playback Switch", "DAC"},
187b7138212SCliff Cai
188b7138212SCliff Cai {"ROUT", NULL, "Output Mixer"},
189b7138212SCliff Cai {"LOUT", NULL, "Output Mixer"},
190b7138212SCliff Cai
191b1f7b2b5SLars-Peter Clausen {"Line Input", NULL, "LLINEIN"},
192b1f7b2b5SLars-Peter Clausen {"Line Input", NULL, "RLINEIN"},
193b1f7b2b5SLars-Peter Clausen };
194b1f7b2b5SLars-Peter Clausen
195b1f7b2b5SLars-Peter Clausen static const struct snd_soc_dapm_route ssm2602_routes[] = {
196b1f7b2b5SLars-Peter Clausen {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
197b1f7b2b5SLars-Peter Clausen
198b1f7b2b5SLars-Peter Clausen {"RHPOUT", NULL, "Output Mixer"},
199b1f7b2b5SLars-Peter Clausen {"LHPOUT", NULL, "Output Mixer"},
200b1f7b2b5SLars-Peter Clausen
201b7138212SCliff Cai {"Input Mux", "Line", "Line Input"},
20237768e39SPhilipp Zabel {"Input Mux", "Mic", "Mic Switch"},
203b7138212SCliff Cai {"ADC", NULL, "Input Mux"},
204b7138212SCliff Cai
20537768e39SPhilipp Zabel {"Mic Switch", NULL, "Mic Bias"},
20637768e39SPhilipp Zabel
207b7138212SCliff Cai {"Mic Bias", NULL, "MICIN"},
208b7138212SCliff Cai };
209b7138212SCliff Cai
210b1f7b2b5SLars-Peter Clausen static const struct snd_soc_dapm_route ssm2604_routes[] = {
211b1f7b2b5SLars-Peter Clausen {"ADC", NULL, "Line Input"},
212b1f7b2b5SLars-Peter Clausen };
213b7138212SCliff Cai
2148b3f39daSLars-Peter Clausen static const unsigned int ssm2602_rates_12288000[] = {
2157ae2b55bSAndreas Pretzsch 8000, 16000, 32000, 48000, 96000,
2168b3f39daSLars-Peter Clausen };
2178b3f39daSLars-Peter Clausen
218f75ac2d9SLars-Peter Clausen static const struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = {
2198b3f39daSLars-Peter Clausen .list = ssm2602_rates_12288000,
2208b3f39daSLars-Peter Clausen .count = ARRAY_SIZE(ssm2602_rates_12288000),
2218b3f39daSLars-Peter Clausen };
2228b3f39daSLars-Peter Clausen
2238b3f39daSLars-Peter Clausen static const unsigned int ssm2602_rates_11289600[] = {
2243b2a0013SStefan Kristiansson 8000, 11025, 22050, 44100, 88200,
2258b3f39daSLars-Peter Clausen };
2268b3f39daSLars-Peter Clausen
227f75ac2d9SLars-Peter Clausen static const struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = {
2288b3f39daSLars-Peter Clausen .list = ssm2602_rates_11289600,
2298b3f39daSLars-Peter Clausen .count = ARRAY_SIZE(ssm2602_rates_11289600),
2308b3f39daSLars-Peter Clausen };
2318b3f39daSLars-Peter Clausen
2320b4cd2e0SLars-Peter Clausen struct ssm2602_coeff {
233b7138212SCliff Cai u32 mclk;
234b7138212SCliff Cai u32 rate;
2350b4cd2e0SLars-Peter Clausen u8 srate;
236b7138212SCliff Cai };
237b7138212SCliff Cai
2380b4cd2e0SLars-Peter Clausen #define SSM2602_COEFF_SRATE(sr, bosr, usb) (((sr) << 2) | ((bosr) << 1) | (usb))
2390b4cd2e0SLars-Peter Clausen
2400b4cd2e0SLars-Peter Clausen /* codec mclk clock coefficients */
2410b4cd2e0SLars-Peter Clausen static const struct ssm2602_coeff ssm2602_coeff_table[] = {
242b7138212SCliff Cai /* 48k */
2430b4cd2e0SLars-Peter Clausen {12288000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x0)},
2440b4cd2e0SLars-Peter Clausen {18432000, 48000, SSM2602_COEFF_SRATE(0x0, 0x1, 0x0)},
2450b4cd2e0SLars-Peter Clausen {12000000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x1)},
246b7138212SCliff Cai
247b7138212SCliff Cai /* 32k */
2480b4cd2e0SLars-Peter Clausen {12288000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x0)},
2490b4cd2e0SLars-Peter Clausen {18432000, 32000, SSM2602_COEFF_SRATE(0x6, 0x1, 0x0)},
2500b4cd2e0SLars-Peter Clausen {12000000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x1)},
251b7138212SCliff Cai
2527ae2b55bSAndreas Pretzsch /* 16k */
2537ae2b55bSAndreas Pretzsch {12288000, 16000, SSM2602_COEFF_SRATE(0x5, 0x0, 0x0)},
2547ae2b55bSAndreas Pretzsch {18432000, 16000, SSM2602_COEFF_SRATE(0x5, 0x1, 0x0)},
2557ae2b55bSAndreas Pretzsch {12000000, 16000, SSM2602_COEFF_SRATE(0xa, 0x0, 0x1)},
2567ae2b55bSAndreas Pretzsch
257b7138212SCliff Cai /* 8k */
2580b4cd2e0SLars-Peter Clausen {12288000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x0)},
2590b4cd2e0SLars-Peter Clausen {18432000, 8000, SSM2602_COEFF_SRATE(0x3, 0x1, 0x0)},
2600b4cd2e0SLars-Peter Clausen {11289600, 8000, SSM2602_COEFF_SRATE(0xb, 0x0, 0x0)},
2610b4cd2e0SLars-Peter Clausen {16934400, 8000, SSM2602_COEFF_SRATE(0xb, 0x1, 0x0)},
2620b4cd2e0SLars-Peter Clausen {12000000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x1)},
263b7138212SCliff Cai
264b7138212SCliff Cai /* 96k */
2650b4cd2e0SLars-Peter Clausen {12288000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x0)},
2660b4cd2e0SLars-Peter Clausen {18432000, 96000, SSM2602_COEFF_SRATE(0x7, 0x1, 0x0)},
2670b4cd2e0SLars-Peter Clausen {12000000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x1)},
268b7138212SCliff Cai
2693b2a0013SStefan Kristiansson /* 11.025k */
2703b2a0013SStefan Kristiansson {11289600, 11025, SSM2602_COEFF_SRATE(0xc, 0x0, 0x0)},
2713b2a0013SStefan Kristiansson {16934400, 11025, SSM2602_COEFF_SRATE(0xc, 0x1, 0x0)},
2723b2a0013SStefan Kristiansson {12000000, 11025, SSM2602_COEFF_SRATE(0xc, 0x1, 0x1)},
2733b2a0013SStefan Kristiansson
2743b2a0013SStefan Kristiansson /* 22.05k */
2753b2a0013SStefan Kristiansson {11289600, 22050, SSM2602_COEFF_SRATE(0xd, 0x0, 0x0)},
2763b2a0013SStefan Kristiansson {16934400, 22050, SSM2602_COEFF_SRATE(0xd, 0x1, 0x0)},
2773b2a0013SStefan Kristiansson {12000000, 22050, SSM2602_COEFF_SRATE(0xd, 0x1, 0x1)},
2783b2a0013SStefan Kristiansson
279b7138212SCliff Cai /* 44.1k */
2800b4cd2e0SLars-Peter Clausen {11289600, 44100, SSM2602_COEFF_SRATE(0x8, 0x0, 0x0)},
2810b4cd2e0SLars-Peter Clausen {16934400, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x0)},
2820b4cd2e0SLars-Peter Clausen {12000000, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x1)},
283b7138212SCliff Cai
284b7138212SCliff Cai /* 88.2k */
2850b4cd2e0SLars-Peter Clausen {11289600, 88200, SSM2602_COEFF_SRATE(0xf, 0x0, 0x0)},
2860b4cd2e0SLars-Peter Clausen {16934400, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x0)},
2870b4cd2e0SLars-Peter Clausen {12000000, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x1)},
288b7138212SCliff Cai };
289b7138212SCliff Cai
ssm2602_get_coeff(int mclk,int rate)2900b4cd2e0SLars-Peter Clausen static inline int ssm2602_get_coeff(int mclk, int rate)
291b7138212SCliff Cai {
292b7138212SCliff Cai int i;
293b7138212SCliff Cai
2940b4cd2e0SLars-Peter Clausen for (i = 0; i < ARRAY_SIZE(ssm2602_coeff_table); i++) {
2958076c586SPaweł Anikiel if (ssm2602_coeff_table[i].rate == rate) {
2968076c586SPaweł Anikiel if (ssm2602_coeff_table[i].mclk == mclk)
2970b4cd2e0SLars-Peter Clausen return ssm2602_coeff_table[i].srate;
2988076c586SPaweł Anikiel if (ssm2602_coeff_table[i].mclk == mclk / 2)
2998076c586SPaweł Anikiel return ssm2602_coeff_table[i].srate | SRATE_CORECLK_DIV2;
3008076c586SPaweł Anikiel }
301b7138212SCliff Cai }
3020b4cd2e0SLars-Peter Clausen return -EINVAL;
303b7138212SCliff Cai }
304b7138212SCliff Cai
ssm2602_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)305b7138212SCliff Cai static int ssm2602_hw_params(struct snd_pcm_substream *substream,
306dee89c4dSMark Brown struct snd_pcm_hw_params *params,
307dee89c4dSMark Brown struct snd_soc_dai *dai)
308b7138212SCliff Cai {
309ad4771efSKuninori Morimoto struct snd_soc_component *component = dai->component;
310ad4771efSKuninori Morimoto struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
3110b4cd2e0SLars-Peter Clausen int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params));
312bec3d9a9SLars-Peter Clausen unsigned int iface;
313b7138212SCliff Cai
3140b4cd2e0SLars-Peter Clausen if (srate < 0)
3150b4cd2e0SLars-Peter Clausen return srate;
316b7138212SCliff Cai
317bec3d9a9SLars-Peter Clausen regmap_write(ssm2602->regmap, SSM2602_SRATE, srate);
318b7138212SCliff Cai
319b7138212SCliff Cai /* bit size */
32000a37032SMark Brown switch (params_width(params)) {
32100a37032SMark Brown case 16:
322bec3d9a9SLars-Peter Clausen iface = 0x0;
323b7138212SCliff Cai break;
32400a37032SMark Brown case 20:
325bec3d9a9SLars-Peter Clausen iface = 0x4;
326b7138212SCliff Cai break;
32700a37032SMark Brown case 24:
328bec3d9a9SLars-Peter Clausen iface = 0x8;
329b7138212SCliff Cai break;
33000a37032SMark Brown case 32:
331bec3d9a9SLars-Peter Clausen iface = 0xc;
332b7138212SCliff Cai break;
333bec3d9a9SLars-Peter Clausen default:
334bec3d9a9SLars-Peter Clausen return -EINVAL;
335b7138212SCliff Cai }
336bec3d9a9SLars-Peter Clausen regmap_update_bits(ssm2602->regmap, SSM2602_IFACE,
337bec3d9a9SLars-Peter Clausen IFACE_AUDIO_DATA_LEN, iface);
338b7138212SCliff Cai return 0;
339b7138212SCliff Cai }
340b7138212SCliff Cai
ssm2602_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)341dee89c4dSMark Brown static int ssm2602_startup(struct snd_pcm_substream *substream,
342dee89c4dSMark Brown struct snd_soc_dai *dai)
343b7138212SCliff Cai {
344ad4771efSKuninori Morimoto struct snd_soc_component *component = dai->component;
345ad4771efSKuninori Morimoto struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
346b7138212SCliff Cai
3478b3f39daSLars-Peter Clausen if (ssm2602->sysclk_constraints) {
3488b3f39daSLars-Peter Clausen snd_pcm_hw_constraint_list(substream->runtime, 0,
3498b3f39daSLars-Peter Clausen SNDRV_PCM_HW_PARAM_RATE,
3508b3f39daSLars-Peter Clausen ssm2602->sysclk_constraints);
3518b3f39daSLars-Peter Clausen }
3528b3f39daSLars-Peter Clausen
353b7138212SCliff Cai return 0;
354b7138212SCliff Cai }
355b7138212SCliff Cai
ssm2602_mute(struct snd_soc_dai * dai,int mute,int direction)356bd63ed76SKuninori Morimoto static int ssm2602_mute(struct snd_soc_dai *dai, int mute, int direction)
357b7138212SCliff Cai {
358ad4771efSKuninori Morimoto struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(dai->component);
3592ee9c183SAxel Lin
360b7138212SCliff Cai if (mute)
361bec3d9a9SLars-Peter Clausen regmap_update_bits(ssm2602->regmap, SSM2602_APDIGI,
3622ee9c183SAxel Lin APDIGI_ENABLE_DAC_MUTE,
3632ee9c183SAxel Lin APDIGI_ENABLE_DAC_MUTE);
364b7138212SCliff Cai else
365bec3d9a9SLars-Peter Clausen regmap_update_bits(ssm2602->regmap, SSM2602_APDIGI,
3662ee9c183SAxel Lin APDIGI_ENABLE_DAC_MUTE, 0);
367b7138212SCliff Cai return 0;
368b7138212SCliff Cai }
369b7138212SCliff Cai
ssm2602_set_dai_sysclk(struct snd_soc_dai * codec_dai,int clk_id,unsigned int freq,int dir)370b7138212SCliff Cai static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,
371b7138212SCliff Cai int clk_id, unsigned int freq, int dir)
372b7138212SCliff Cai {
373ad4771efSKuninori Morimoto struct snd_soc_component *component = codec_dai->component;
374ad4771efSKuninori Morimoto struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
37502890535SLars-Peter Clausen
37602890535SLars-Peter Clausen if (dir == SND_SOC_CLOCK_IN) {
37702890535SLars-Peter Clausen if (clk_id != SSM2602_SYSCLK)
37802890535SLars-Peter Clausen return -EINVAL;
37902890535SLars-Peter Clausen
380b7138212SCliff Cai switch (freq) {
381b7138212SCliff Cai case 12288000:
382b7138212SCliff Cai case 18432000:
3838076c586SPaweł Anikiel case 24576000:
3848076c586SPaweł Anikiel case 36864000:
3858b3f39daSLars-Peter Clausen ssm2602->sysclk_constraints = &ssm2602_constraints_12288000;
3868b3f39daSLars-Peter Clausen break;
3878b3f39daSLars-Peter Clausen case 11289600:
3888b3f39daSLars-Peter Clausen case 16934400:
3898076c586SPaweł Anikiel case 22579200:
3908076c586SPaweł Anikiel case 33868800:
3918b3f39daSLars-Peter Clausen ssm2602->sysclk_constraints = &ssm2602_constraints_11289600;
3928b3f39daSLars-Peter Clausen break;
3938b3f39daSLars-Peter Clausen case 12000000:
3948076c586SPaweł Anikiel case 24000000:
3958b3f39daSLars-Peter Clausen ssm2602->sysclk_constraints = NULL;
39602890535SLars-Peter Clausen break;
39702890535SLars-Peter Clausen default:
398b7138212SCliff Cai return -EINVAL;
399b7138212SCliff Cai }
4008076c586SPaweł Anikiel
4018b3f39daSLars-Peter Clausen ssm2602->sysclk = freq;
40202890535SLars-Peter Clausen } else {
40302890535SLars-Peter Clausen unsigned int mask;
40402890535SLars-Peter Clausen
40502890535SLars-Peter Clausen switch (clk_id) {
40602890535SLars-Peter Clausen case SSM2602_CLK_CLKOUT:
40702890535SLars-Peter Clausen mask = PWR_CLK_OUT_PDN;
40802890535SLars-Peter Clausen break;
40902890535SLars-Peter Clausen case SSM2602_CLK_XTO:
41002890535SLars-Peter Clausen mask = PWR_OSC_PDN;
41102890535SLars-Peter Clausen break;
41202890535SLars-Peter Clausen default:
41302890535SLars-Peter Clausen return -EINVAL;
41402890535SLars-Peter Clausen }
41502890535SLars-Peter Clausen
41602890535SLars-Peter Clausen if (freq == 0)
41702890535SLars-Peter Clausen ssm2602->clk_out_pwr |= mask;
41802890535SLars-Peter Clausen else
41902890535SLars-Peter Clausen ssm2602->clk_out_pwr &= ~mask;
42002890535SLars-Peter Clausen
421bec3d9a9SLars-Peter Clausen regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
42202890535SLars-Peter Clausen PWR_CLK_OUT_PDN | PWR_OSC_PDN, ssm2602->clk_out_pwr);
42302890535SLars-Peter Clausen }
42402890535SLars-Peter Clausen
42502890535SLars-Peter Clausen return 0;
42602890535SLars-Peter Clausen }
427b7138212SCliff Cai
ssm2602_set_dai_fmt(struct snd_soc_dai * codec_dai,unsigned int fmt)428b7138212SCliff Cai static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
429b7138212SCliff Cai unsigned int fmt)
430b7138212SCliff Cai {
431ad4771efSKuninori Morimoto struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(codec_dai->component);
432bec3d9a9SLars-Peter Clausen unsigned int iface = 0;
433b7138212SCliff Cai
434b7138212SCliff Cai /* set master/slave audio interface */
4350160e883SMark Brown switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
4360160e883SMark Brown case SND_SOC_DAIFMT_CBP_CFP:
437b7138212SCliff Cai iface |= 0x0040;
438b7138212SCliff Cai break;
4390160e883SMark Brown case SND_SOC_DAIFMT_CBC_CFC:
440b7138212SCliff Cai break;
441b7138212SCliff Cai default:
442b7138212SCliff Cai return -EINVAL;
443b7138212SCliff Cai }
444b7138212SCliff Cai
445b7138212SCliff Cai /* interface format */
446b7138212SCliff Cai switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
447b7138212SCliff Cai case SND_SOC_DAIFMT_I2S:
448b7138212SCliff Cai iface |= 0x0002;
449b7138212SCliff Cai break;
450b7138212SCliff Cai case SND_SOC_DAIFMT_RIGHT_J:
451b7138212SCliff Cai break;
452b7138212SCliff Cai case SND_SOC_DAIFMT_LEFT_J:
453b7138212SCliff Cai iface |= 0x0001;
454b7138212SCliff Cai break;
455b7138212SCliff Cai case SND_SOC_DAIFMT_DSP_A:
456c6913485SJarkko Nikula iface |= 0x0013;
457b7138212SCliff Cai break;
458b7138212SCliff Cai case SND_SOC_DAIFMT_DSP_B:
459c6913485SJarkko Nikula iface |= 0x0003;
460b7138212SCliff Cai break;
461b7138212SCliff Cai default:
462b7138212SCliff Cai return -EINVAL;
463b7138212SCliff Cai }
464b7138212SCliff Cai
465b7138212SCliff Cai /* clock inversion */
466b7138212SCliff Cai switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
467b7138212SCliff Cai case SND_SOC_DAIFMT_NB_NF:
468b7138212SCliff Cai break;
469b7138212SCliff Cai case SND_SOC_DAIFMT_IB_IF:
470b7138212SCliff Cai iface |= 0x0090;
471b7138212SCliff Cai break;
472b7138212SCliff Cai case SND_SOC_DAIFMT_IB_NF:
473b7138212SCliff Cai iface |= 0x0080;
474b7138212SCliff Cai break;
475b7138212SCliff Cai case SND_SOC_DAIFMT_NB_IF:
476b7138212SCliff Cai iface |= 0x0010;
477b7138212SCliff Cai break;
478b7138212SCliff Cai default:
479b7138212SCliff Cai return -EINVAL;
480b7138212SCliff Cai }
481b7138212SCliff Cai
482b7138212SCliff Cai /* set iface */
483bec3d9a9SLars-Peter Clausen regmap_write(ssm2602->regmap, SSM2602_IFACE, iface);
484b7138212SCliff Cai return 0;
485b7138212SCliff Cai }
486b7138212SCliff Cai
ssm2602_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)487ad4771efSKuninori Morimoto static int ssm2602_set_bias_level(struct snd_soc_component *component,
488b7138212SCliff Cai enum snd_soc_bias_level level)
489b7138212SCliff Cai {
490ad4771efSKuninori Morimoto struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
491b7138212SCliff Cai
492b7138212SCliff Cai switch (level) {
493b7138212SCliff Cai case SND_SOC_BIAS_ON:
49402890535SLars-Peter Clausen /* vref/mid on, osc and clkout on if enabled */
495bec3d9a9SLars-Peter Clausen regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
49602890535SLars-Peter Clausen PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
49702890535SLars-Peter Clausen ssm2602->clk_out_pwr);
498b7138212SCliff Cai break;
499b7138212SCliff Cai case SND_SOC_BIAS_PREPARE:
500b7138212SCliff Cai break;
501b7138212SCliff Cai case SND_SOC_BIAS_STANDBY:
502b7138212SCliff Cai /* everything off except vref/vmid, */
503bec3d9a9SLars-Peter Clausen regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
50402890535SLars-Peter Clausen PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
50502890535SLars-Peter Clausen PWR_CLK_OUT_PDN | PWR_OSC_PDN);
506b7138212SCliff Cai break;
507b7138212SCliff Cai case SND_SOC_BIAS_OFF:
50802890535SLars-Peter Clausen /* everything off */
509bec3d9a9SLars-Peter Clausen regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
51002890535SLars-Peter Clausen PWR_POWER_OFF, PWR_POWER_OFF);
511b7138212SCliff Cai break;
512b7138212SCliff Cai
513b7138212SCliff Cai }
514b7138212SCliff Cai return 0;
515b7138212SCliff Cai }
516b7138212SCliff Cai
5173b2a0013SStefan Kristiansson #define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
5183b2a0013SStefan Kristiansson SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
5197ae2b55bSAndreas Pretzsch SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
5207ae2b55bSAndreas Pretzsch SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
5217ae2b55bSAndreas Pretzsch SNDRV_PCM_RATE_96000)
522b7138212SCliff Cai
5235de27b6cSKarl Beldan #define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
5245de27b6cSKarl Beldan SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
5255de27b6cSKarl Beldan
52685e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops ssm2602_dai_ops = {
5276335d055SEric Miao .startup = ssm2602_startup,
5286335d055SEric Miao .hw_params = ssm2602_hw_params,
529bd63ed76SKuninori Morimoto .mute_stream = ssm2602_mute,
5306335d055SEric Miao .set_sysclk = ssm2602_set_dai_sysclk,
5316335d055SEric Miao .set_fmt = ssm2602_set_dai_fmt,
532bd63ed76SKuninori Morimoto .no_capture_mute = 1,
5336335d055SEric Miao };
5346335d055SEric Miao
535f0fba2adSLiam Girdwood static struct snd_soc_dai_driver ssm2602_dai = {
536f0fba2adSLiam Girdwood .name = "ssm2602-hifi",
537b7138212SCliff Cai .playback = {
538b7138212SCliff Cai .stream_name = "Playback",
539b7138212SCliff Cai .channels_min = 2,
540b7138212SCliff Cai .channels_max = 2,
541b7138212SCliff Cai .rates = SSM2602_RATES,
5425de27b6cSKarl Beldan .formats = SSM2602_FORMATS,},
543b7138212SCliff Cai .capture = {
544b7138212SCliff Cai .stream_name = "Capture",
545b7138212SCliff Cai .channels_min = 2,
546b7138212SCliff Cai .channels_max = 2,
547b7138212SCliff Cai .rates = SSM2602_RATES,
5485de27b6cSKarl Beldan .formats = SSM2602_FORMATS,},
5496335d055SEric Miao .ops = &ssm2602_dai_ops,
5504735c8caSKuninori Morimoto .symmetric_rate = 1,
5514735c8caSKuninori Morimoto .symmetric_sample_bits = 1,
552b7138212SCliff Cai };
553b7138212SCliff Cai
ssm2602_resume(struct snd_soc_component * component)554ad4771efSKuninori Morimoto static int ssm2602_resume(struct snd_soc_component *component)
555b7138212SCliff Cai {
556ad4771efSKuninori Morimoto struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
557b7138212SCliff Cai
5589d863b88SLars-Peter Clausen regcache_sync(ssm2602->regmap);
55993547e89SCliff Cai
560b7138212SCliff Cai return 0;
561b7138212SCliff Cai }
562b7138212SCliff Cai
ssm2602_component_probe(struct snd_soc_component * component)563ad4771efSKuninori Morimoto static int ssm2602_component_probe(struct snd_soc_component *component)
564b7138212SCliff Cai {
565ad4771efSKuninori Morimoto struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
566ad4771efSKuninori Morimoto struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
5672ee9c183SAxel Lin int ret;
568b1f7b2b5SLars-Peter Clausen
569bec3d9a9SLars-Peter Clausen regmap_update_bits(ssm2602->regmap, SSM2602_LOUT1V,
5702ee9c183SAxel Lin LOUT1V_LRHP_BOTH, LOUT1V_LRHP_BOTH);
571bec3d9a9SLars-Peter Clausen regmap_update_bits(ssm2602->regmap, SSM2602_ROUT1V,
5722ee9c183SAxel Lin ROUT1V_RLHP_BOTH, ROUT1V_RLHP_BOTH);
573b1f7b2b5SLars-Peter Clausen
574ad4771efSKuninori Morimoto ret = snd_soc_add_component_controls(component, ssm2602_snd_controls,
575b1f7b2b5SLars-Peter Clausen ARRAY_SIZE(ssm2602_snd_controls));
576b1f7b2b5SLars-Peter Clausen if (ret)
577b1f7b2b5SLars-Peter Clausen return ret;
578b1f7b2b5SLars-Peter Clausen
579b1f7b2b5SLars-Peter Clausen ret = snd_soc_dapm_new_controls(dapm, ssm2602_dapm_widgets,
580b1f7b2b5SLars-Peter Clausen ARRAY_SIZE(ssm2602_dapm_widgets));
581b1f7b2b5SLars-Peter Clausen if (ret)
582b1f7b2b5SLars-Peter Clausen return ret;
583b1f7b2b5SLars-Peter Clausen
584b1f7b2b5SLars-Peter Clausen return snd_soc_dapm_add_routes(dapm, ssm2602_routes,
585b1f7b2b5SLars-Peter Clausen ARRAY_SIZE(ssm2602_routes));
586b1f7b2b5SLars-Peter Clausen }
587b1f7b2b5SLars-Peter Clausen
ssm2604_component_probe(struct snd_soc_component * component)588ad4771efSKuninori Morimoto static int ssm2604_component_probe(struct snd_soc_component *component)
589b1f7b2b5SLars-Peter Clausen {
590ad4771efSKuninori Morimoto struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
591b1f7b2b5SLars-Peter Clausen int ret;
592b1f7b2b5SLars-Peter Clausen
593b1f7b2b5SLars-Peter Clausen ret = snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets,
594b1f7b2b5SLars-Peter Clausen ARRAY_SIZE(ssm2604_dapm_widgets));
595b1f7b2b5SLars-Peter Clausen if (ret)
596b1f7b2b5SLars-Peter Clausen return ret;
597b1f7b2b5SLars-Peter Clausen
598b1f7b2b5SLars-Peter Clausen return snd_soc_dapm_add_routes(dapm, ssm2604_routes,
599b1f7b2b5SLars-Peter Clausen ARRAY_SIZE(ssm2604_routes));
600b1f7b2b5SLars-Peter Clausen }
601b1f7b2b5SLars-Peter Clausen
ssm260x_component_probe(struct snd_soc_component * component)602ad4771efSKuninori Morimoto static int ssm260x_component_probe(struct snd_soc_component *component)
603b1f7b2b5SLars-Peter Clausen {
604ad4771efSKuninori Morimoto struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
6052ee9c183SAxel Lin int ret;
606b7138212SCliff Cai
607bec3d9a9SLars-Peter Clausen ret = regmap_write(ssm2602->regmap, SSM2602_RESET, 0);
60893547e89SCliff Cai if (ret < 0) {
609ad4771efSKuninori Morimoto dev_err(component->dev, "Failed to issue reset: %d\n", ret);
61093547e89SCliff Cai return ret;
61193547e89SCliff Cai }
612b7138212SCliff Cai
613*f63550e2SPaweł Anikiel regmap_register_patch(ssm2602->regmap, ssm2602_patch,
614*f63550e2SPaweł Anikiel ARRAY_SIZE(ssm2602_patch));
615*f63550e2SPaweł Anikiel
616b7138212SCliff Cai /* set the update bits */
617bec3d9a9SLars-Peter Clausen regmap_update_bits(ssm2602->regmap, SSM2602_LINVOL,
6182ee9c183SAxel Lin LINVOL_LRIN_BOTH, LINVOL_LRIN_BOTH);
619bec3d9a9SLars-Peter Clausen regmap_update_bits(ssm2602->regmap, SSM2602_RINVOL,
6202ee9c183SAxel Lin RINVOL_RLIN_BOTH, RINVOL_RLIN_BOTH);
621b7138212SCliff Cai /*select Line in as default input*/
622bec3d9a9SLars-Peter Clausen regmap_write(ssm2602->regmap, SSM2602_APANA, APANA_SELECT_DAC |
623b7138212SCliff Cai APANA_ENABLE_MIC_BOOST);
624b7138212SCliff Cai
625b1f7b2b5SLars-Peter Clausen switch (ssm2602->type) {
626b1f7b2b5SLars-Peter Clausen case SSM2602:
627ad4771efSKuninori Morimoto ret = ssm2602_component_probe(component);
628b1f7b2b5SLars-Peter Clausen break;
629b1f7b2b5SLars-Peter Clausen case SSM2604:
630ad4771efSKuninori Morimoto ret = ssm2604_component_probe(component);
631b1f7b2b5SLars-Peter Clausen break;
632b1f7b2b5SLars-Peter Clausen }
633b7138212SCliff Cai
634b1f7b2b5SLars-Peter Clausen return ret;
635f0fba2adSLiam Girdwood }
636f0fba2adSLiam Girdwood
637ad4771efSKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_ssm2602 = {
638ad4771efSKuninori Morimoto .probe = ssm260x_component_probe,
639f0fba2adSLiam Girdwood .resume = ssm2602_resume,
640f0fba2adSLiam Girdwood .set_bias_level = ssm2602_set_bias_level,
641b1f7b2b5SLars-Peter Clausen .controls = ssm260x_snd_controls,
642b1f7b2b5SLars-Peter Clausen .num_controls = ARRAY_SIZE(ssm260x_snd_controls),
643b1f7b2b5SLars-Peter Clausen .dapm_widgets = ssm260x_dapm_widgets,
644b1f7b2b5SLars-Peter Clausen .num_dapm_widgets = ARRAY_SIZE(ssm260x_dapm_widgets),
645b1f7b2b5SLars-Peter Clausen .dapm_routes = ssm260x_routes,
646b1f7b2b5SLars-Peter Clausen .num_dapm_routes = ARRAY_SIZE(ssm260x_routes),
647ad4771efSKuninori Morimoto .suspend_bias_off = 1,
648ad4771efSKuninori Morimoto .idle_bias_on = 1,
649ad4771efSKuninori Morimoto .use_pmdown_time = 1,
650ad4771efSKuninori Morimoto .endianness = 1,
651f0fba2adSLiam Girdwood };
652b7138212SCliff Cai
ssm2602_register_volatile(struct device * dev,unsigned int reg)653bec3d9a9SLars-Peter Clausen static bool ssm2602_register_volatile(struct device *dev, unsigned int reg)
654bec3d9a9SLars-Peter Clausen {
655bec3d9a9SLars-Peter Clausen return reg == SSM2602_RESET;
656bec3d9a9SLars-Peter Clausen }
657bec3d9a9SLars-Peter Clausen
658c924dc68SLars-Peter Clausen const struct regmap_config ssm2602_regmap_config = {
659bec3d9a9SLars-Peter Clausen .val_bits = 9,
660bec3d9a9SLars-Peter Clausen .reg_bits = 7,
661bec3d9a9SLars-Peter Clausen
662bec3d9a9SLars-Peter Clausen .max_register = SSM2602_RESET,
663bec3d9a9SLars-Peter Clausen .volatile_reg = ssm2602_register_volatile,
664bec3d9a9SLars-Peter Clausen
665bec3d9a9SLars-Peter Clausen .cache_type = REGCACHE_RBTREE,
666a01df75cSJames Kelly .reg_defaults = ssm2602_reg,
667a01df75cSJames Kelly .num_reg_defaults = ARRAY_SIZE(ssm2602_reg),
668bec3d9a9SLars-Peter Clausen };
669c924dc68SLars-Peter Clausen EXPORT_SYMBOL_GPL(ssm2602_regmap_config);
670bec3d9a9SLars-Peter Clausen
ssm2602_probe(struct device * dev,enum ssm2602_type type,struct regmap * regmap)671c924dc68SLars-Peter Clausen int ssm2602_probe(struct device *dev, enum ssm2602_type type,
672c924dc68SLars-Peter Clausen struct regmap *regmap)
673b39e2855SMike Frysinger {
674b39e2855SMike Frysinger struct ssm2602_priv *ssm2602;
675b39e2855SMike Frysinger
676c924dc68SLars-Peter Clausen if (IS_ERR(regmap))
677c924dc68SLars-Peter Clausen return PTR_ERR(regmap);
678c924dc68SLars-Peter Clausen
679c924dc68SLars-Peter Clausen ssm2602 = devm_kzalloc(dev, sizeof(*ssm2602), GFP_KERNEL);
680b39e2855SMike Frysinger if (ssm2602 == NULL)
681b39e2855SMike Frysinger return -ENOMEM;
682b39e2855SMike Frysinger
683c924dc68SLars-Peter Clausen dev_set_drvdata(dev, ssm2602);
684fe2a08b3SStefan Kristiansson ssm2602->type = type;
685c924dc68SLars-Peter Clausen ssm2602->regmap = regmap;
686b39e2855SMike Frysinger
687ad4771efSKuninori Morimoto return devm_snd_soc_register_component(dev, &soc_component_dev_ssm2602,
688c924dc68SLars-Peter Clausen &ssm2602_dai, 1);
689b39e2855SMike Frysinger }
690c924dc68SLars-Peter Clausen EXPORT_SYMBOL_GPL(ssm2602_probe);
69164089b84SMark Brown
6927dcf2760SLars-Peter Clausen MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 driver");
693b7138212SCliff Cai MODULE_AUTHOR("Cliff Cai");
694b7138212SCliff Cai MODULE_LICENSE("GPL");
695