xref: /linux/sound/soc/codecs/sta32x.c (revision 8dc1011470315501914a4527276b7b93301f3d38)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2c034abf6SJohannes Stezenbach /*
3c034abf6SJohannes Stezenbach  * Codec driver for ST STA32x 2.1-channel high-efficiency digital audio system
4c034abf6SJohannes Stezenbach  *
5c034abf6SJohannes Stezenbach  * Copyright: 2011 Raumfeld GmbH
6c034abf6SJohannes Stezenbach  * Author: Johannes Stezenbach <js@sig21.net>
7c034abf6SJohannes Stezenbach  *
8c034abf6SJohannes Stezenbach  * based on code from:
9c034abf6SJohannes Stezenbach  *	Wolfson Microelectronics PLC.
10c034abf6SJohannes Stezenbach  *	  Mark Brown <broonie@opensource.wolfsonmicro.com>
11c034abf6SJohannes Stezenbach  *	Freescale Semiconductor, Inc.
12c034abf6SJohannes Stezenbach  *	  Timur Tabi <timur@freescale.com>
13c034abf6SJohannes Stezenbach  */
14c034abf6SJohannes Stezenbach 
15c034abf6SJohannes Stezenbach #define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__
16c034abf6SJohannes Stezenbach 
17c034abf6SJohannes Stezenbach #include <linux/module.h>
18c034abf6SJohannes Stezenbach #include <linux/moduleparam.h>
19c034abf6SJohannes Stezenbach #include <linux/init.h>
20fce9ec95SDaniel Mack #include <linux/clk.h>
21c034abf6SJohannes Stezenbach #include <linux/delay.h>
22c034abf6SJohannes Stezenbach #include <linux/pm.h>
23c034abf6SJohannes Stezenbach #include <linux/i2c.h>
24f04b1e76SThomas Niederprüm #include <linux/of_device.h>
25f04b1e76SThomas Niederprüm #include <linux/of_gpio.h>
2629fdf4fbSMark Brown #include <linux/regmap.h>
27c034abf6SJohannes Stezenbach #include <linux/regulator/consumer.h>
28b66a2980SThomas Niederprüm #include <linux/gpio/consumer.h>
29c034abf6SJohannes Stezenbach #include <linux/slab.h>
303fb5eac5SJohannes Stezenbach #include <linux/workqueue.h>
31c034abf6SJohannes Stezenbach #include <sound/core.h>
32c034abf6SJohannes Stezenbach #include <sound/pcm.h>
33c034abf6SJohannes Stezenbach #include <sound/pcm_params.h>
34c034abf6SJohannes Stezenbach #include <sound/soc.h>
35c034abf6SJohannes Stezenbach #include <sound/soc-dapm.h>
36c034abf6SJohannes Stezenbach #include <sound/initval.h>
37c034abf6SJohannes Stezenbach #include <sound/tlv.h>
38c034abf6SJohannes Stezenbach 
39e012ba24SJohannes Stezenbach #include <sound/sta32x.h>
40c034abf6SJohannes Stezenbach #include "sta32x.h"
41c034abf6SJohannes Stezenbach 
42c034abf6SJohannes Stezenbach #define STA32X_RATES (SNDRV_PCM_RATE_32000 | \
43c034abf6SJohannes Stezenbach 		      SNDRV_PCM_RATE_44100 | \
44c034abf6SJohannes Stezenbach 		      SNDRV_PCM_RATE_48000 | \
45c034abf6SJohannes Stezenbach 		      SNDRV_PCM_RATE_88200 | \
46c034abf6SJohannes Stezenbach 		      SNDRV_PCM_RATE_96000 | \
47c034abf6SJohannes Stezenbach 		      SNDRV_PCM_RATE_176400 | \
48c034abf6SJohannes Stezenbach 		      SNDRV_PCM_RATE_192000)
49c034abf6SJohannes Stezenbach 
50c034abf6SJohannes Stezenbach #define STA32X_FORMATS \
51c034abf6SJohannes Stezenbach 	(SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \
52c034abf6SJohannes Stezenbach 	 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
53c034abf6SJohannes Stezenbach 	 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
54c034abf6SJohannes Stezenbach 	 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
55c034abf6SJohannes Stezenbach 	 SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE  | \
56c034abf6SJohannes Stezenbach 	 SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_S32_BE)
57c034abf6SJohannes Stezenbach 
58c034abf6SJohannes Stezenbach /* Power-up register defaults */
5929fdf4fbSMark Brown static const struct reg_default sta32x_regs[] = {
6029fdf4fbSMark Brown 	{  0x0, 0x63 },
6129fdf4fbSMark Brown 	{  0x1, 0x80 },
6229fdf4fbSMark Brown 	{  0x2, 0xc2 },
6329fdf4fbSMark Brown 	{  0x3, 0x40 },
6429fdf4fbSMark Brown 	{  0x4, 0xc2 },
6529fdf4fbSMark Brown 	{  0x5, 0x5c },
6629fdf4fbSMark Brown 	{  0x6, 0x10 },
6729fdf4fbSMark Brown 	{  0x7, 0xff },
6829fdf4fbSMark Brown 	{  0x8, 0x60 },
6929fdf4fbSMark Brown 	{  0x9, 0x60 },
7029fdf4fbSMark Brown 	{  0xa, 0x60 },
7129fdf4fbSMark Brown 	{  0xb, 0x80 },
7229fdf4fbSMark Brown 	{  0xc, 0x00 },
7329fdf4fbSMark Brown 	{  0xd, 0x00 },
7429fdf4fbSMark Brown 	{  0xe, 0x00 },
7529fdf4fbSMark Brown 	{  0xf, 0x40 },
7629fdf4fbSMark Brown 	{ 0x10, 0x80 },
7729fdf4fbSMark Brown 	{ 0x11, 0x77 },
7829fdf4fbSMark Brown 	{ 0x12, 0x6a },
7929fdf4fbSMark Brown 	{ 0x13, 0x69 },
8029fdf4fbSMark Brown 	{ 0x14, 0x6a },
8129fdf4fbSMark Brown 	{ 0x15, 0x69 },
8229fdf4fbSMark Brown 	{ 0x16, 0x00 },
8329fdf4fbSMark Brown 	{ 0x17, 0x00 },
8429fdf4fbSMark Brown 	{ 0x18, 0x00 },
8529fdf4fbSMark Brown 	{ 0x19, 0x00 },
8629fdf4fbSMark Brown 	{ 0x1a, 0x00 },
8729fdf4fbSMark Brown 	{ 0x1b, 0x00 },
8829fdf4fbSMark Brown 	{ 0x1c, 0x00 },
8929fdf4fbSMark Brown 	{ 0x1d, 0x00 },
9029fdf4fbSMark Brown 	{ 0x1e, 0x00 },
9129fdf4fbSMark Brown 	{ 0x1f, 0x00 },
9229fdf4fbSMark Brown 	{ 0x20, 0x00 },
9329fdf4fbSMark Brown 	{ 0x21, 0x00 },
9429fdf4fbSMark Brown 	{ 0x22, 0x00 },
9529fdf4fbSMark Brown 	{ 0x23, 0x00 },
9629fdf4fbSMark Brown 	{ 0x24, 0x00 },
9729fdf4fbSMark Brown 	{ 0x25, 0x00 },
9829fdf4fbSMark Brown 	{ 0x26, 0x00 },
9929fdf4fbSMark Brown 	{ 0x27, 0x2d },
10029fdf4fbSMark Brown 	{ 0x28, 0xc0 },
10129fdf4fbSMark Brown 	{ 0x2b, 0x00 },
10229fdf4fbSMark Brown 	{ 0x2c, 0x0c },
103c034abf6SJohannes Stezenbach };
104c034abf6SJohannes Stezenbach 
105a1be4ceaSThomas Niederprüm static const struct regmap_range sta32x_write_regs_range[] = {
106148388f3SThomas Niederprüm 	regmap_reg_range(STA32X_CONFA,  STA32X_FDRC2),
107a1be4ceaSThomas Niederprüm };
108a1be4ceaSThomas Niederprüm 
109a1be4ceaSThomas Niederprüm static const struct regmap_range sta32x_read_regs_range[] = {
110148388f3SThomas Niederprüm 	regmap_reg_range(STA32X_CONFA,  STA32X_FDRC2),
111a1be4ceaSThomas Niederprüm };
112a1be4ceaSThomas Niederprüm 
113a1be4ceaSThomas Niederprüm static const struct regmap_range sta32x_volatile_regs_range[] = {
114a1be4ceaSThomas Niederprüm 	regmap_reg_range(STA32X_CFADDR2, STA32X_CFUD),
115a1be4ceaSThomas Niederprüm };
116a1be4ceaSThomas Niederprüm 
117a1be4ceaSThomas Niederprüm static const struct regmap_access_table sta32x_write_regs = {
118a1be4ceaSThomas Niederprüm 	.yes_ranges =	sta32x_write_regs_range,
119a1be4ceaSThomas Niederprüm 	.n_yes_ranges =	ARRAY_SIZE(sta32x_write_regs_range),
120a1be4ceaSThomas Niederprüm };
121a1be4ceaSThomas Niederprüm 
122a1be4ceaSThomas Niederprüm static const struct regmap_access_table sta32x_read_regs = {
123a1be4ceaSThomas Niederprüm 	.yes_ranges =	sta32x_read_regs_range,
124a1be4ceaSThomas Niederprüm 	.n_yes_ranges =	ARRAY_SIZE(sta32x_read_regs_range),
125a1be4ceaSThomas Niederprüm };
126a1be4ceaSThomas Niederprüm 
127a1be4ceaSThomas Niederprüm static const struct regmap_access_table sta32x_volatile_regs = {
128a1be4ceaSThomas Niederprüm 	.yes_ranges =	sta32x_volatile_regs_range,
129a1be4ceaSThomas Niederprüm 	.n_yes_ranges =	ARRAY_SIZE(sta32x_volatile_regs_range),
130a1be4ceaSThomas Niederprüm };
131a1be4ceaSThomas Niederprüm 
132c034abf6SJohannes Stezenbach /* regulator power supply names */
133c034abf6SJohannes Stezenbach static const char *sta32x_supply_names[] = {
134c034abf6SJohannes Stezenbach 	"Vdda",	/* analog supply, 3.3VV */
135c034abf6SJohannes Stezenbach 	"Vdd3",	/* digital supply, 3.3V */
136c034abf6SJohannes Stezenbach 	"Vcc"	/* power amp spply, 10V - 36V */
137c034abf6SJohannes Stezenbach };
138c034abf6SJohannes Stezenbach 
139c034abf6SJohannes Stezenbach /* codec private data */
140c034abf6SJohannes Stezenbach struct sta32x_priv {
14129fdf4fbSMark Brown 	struct regmap *regmap;
142fce9ec95SDaniel Mack 	struct clk *xti_clk;
143c034abf6SJohannes Stezenbach 	struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)];
144ee183590SKuninori Morimoto 	struct snd_soc_component *component;
145e012ba24SJohannes Stezenbach 	struct sta32x_platform_data *pdata;
146c034abf6SJohannes Stezenbach 
147c034abf6SJohannes Stezenbach 	unsigned int mclk;
148c034abf6SJohannes Stezenbach 	unsigned int format;
14954dc6cabSJohannes Stezenbach 
15054dc6cabSJohannes Stezenbach 	u32 coef_shadow[STA32X_COEF_COUNT];
1513fb5eac5SJohannes Stezenbach 	struct delayed_work watchdog_work;
1523fb5eac5SJohannes Stezenbach 	int shutdown;
153b66a2980SThomas Niederprüm 	struct gpio_desc *gpiod_nreset;
154a1be4ceaSThomas Niederprüm 	struct mutex coeff_lock;
155c034abf6SJohannes Stezenbach };
156c034abf6SJohannes Stezenbach 
157c034abf6SJohannes Stezenbach static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1);
158c034abf6SJohannes Stezenbach static const DECLARE_TLV_DB_SCALE(chvol_tlv, -7950, 50, 1);
159c034abf6SJohannes Stezenbach static const DECLARE_TLV_DB_SCALE(tone_tlv, -120, 200, 0);
160c034abf6SJohannes Stezenbach 
161c034abf6SJohannes Stezenbach static const char *sta32x_drc_ac[] = {
162c034abf6SJohannes Stezenbach 	"Anti-Clipping", "Dynamic Range Compression" };
163c034abf6SJohannes Stezenbach static const char *sta32x_auto_eq_mode[] = {
164c034abf6SJohannes Stezenbach 	"User", "Preset", "Loudness" };
165c034abf6SJohannes Stezenbach static const char *sta32x_auto_gc_mode[] = {
166c034abf6SJohannes Stezenbach 	"User", "AC no clipping", "AC limited clipping (10%)",
167c034abf6SJohannes Stezenbach 	"DRC nighttime listening mode" };
168c034abf6SJohannes Stezenbach static const char *sta32x_auto_xo_mode[] = {
169c034abf6SJohannes Stezenbach 	"User", "80Hz", "100Hz", "120Hz", "140Hz", "160Hz", "180Hz", "200Hz",
170c034abf6SJohannes Stezenbach 	"220Hz", "240Hz", "260Hz", "280Hz", "300Hz", "320Hz", "340Hz", "360Hz" };
171c034abf6SJohannes Stezenbach static const char *sta32x_preset_eq_mode[] = {
172c034abf6SJohannes Stezenbach 	"Flat", "Rock", "Soft Rock", "Jazz", "Classical", "Dance", "Pop", "Soft",
173c034abf6SJohannes Stezenbach 	"Hard", "Party", "Vocal", "Hip-Hop", "Dialog", "Bass-boost #1",
174c034abf6SJohannes Stezenbach 	"Bass-boost #2", "Bass-boost #3", "Loudness 1", "Loudness 2",
175c034abf6SJohannes Stezenbach 	"Loudness 3", "Loudness 4", "Loudness 5", "Loudness 6", "Loudness 7",
176c034abf6SJohannes Stezenbach 	"Loudness 8", "Loudness 9", "Loudness 10", "Loudness 11", "Loudness 12",
177c034abf6SJohannes Stezenbach 	"Loudness 13", "Loudness 14", "Loudness 15", "Loudness 16" };
178c034abf6SJohannes Stezenbach static const char *sta32x_limiter_select[] = {
179c034abf6SJohannes Stezenbach 	"Limiter Disabled", "Limiter #1", "Limiter #2" };
180c034abf6SJohannes Stezenbach static const char *sta32x_limiter_attack_rate[] = {
181c034abf6SJohannes Stezenbach 	"3.1584", "2.7072", "2.2560", "1.8048", "1.3536", "0.9024",
182c034abf6SJohannes Stezenbach 	"0.4512", "0.2256", "0.1504", "0.1123", "0.0902", "0.0752",
183c034abf6SJohannes Stezenbach 	"0.0645", "0.0564", "0.0501", "0.0451" };
184c034abf6SJohannes Stezenbach static const char *sta32x_limiter_release_rate[] = {
185c034abf6SJohannes Stezenbach 	"0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299",
186c034abf6SJohannes Stezenbach 	"0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137",
187c034abf6SJohannes Stezenbach 	"0.0134", "0.0117", "0.0110", "0.0104" };
18888483f59SThomas Niederprüm static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_attack_tlv,
189c034abf6SJohannes Stezenbach 	0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0),
190c034abf6SJohannes Stezenbach 	8, 16, TLV_DB_SCALE_ITEM(300, 100, 0),
19188483f59SThomas Niederprüm );
192c034abf6SJohannes Stezenbach 
19388483f59SThomas Niederprüm static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_release_tlv,
194c034abf6SJohannes Stezenbach 	0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
195c034abf6SJohannes Stezenbach 	1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0),
196c034abf6SJohannes Stezenbach 	2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0),
197c034abf6SJohannes Stezenbach 	3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0),
198c034abf6SJohannes Stezenbach 	8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0),
19988483f59SThomas Niederprüm );
200c034abf6SJohannes Stezenbach 
20188483f59SThomas Niederprüm static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_attack_tlv,
202c034abf6SJohannes Stezenbach 	0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0),
203c034abf6SJohannes Stezenbach 	8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0),
204c034abf6SJohannes Stezenbach 	14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0),
20588483f59SThomas Niederprüm );
206c034abf6SJohannes Stezenbach 
20788483f59SThomas Niederprüm static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_release_tlv,
208c034abf6SJohannes Stezenbach 	0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
209c034abf6SJohannes Stezenbach 	1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0),
210c034abf6SJohannes Stezenbach 	3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0),
211c034abf6SJohannes Stezenbach 	5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0),
212c034abf6SJohannes Stezenbach 	13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0),
21388483f59SThomas Niederprüm );
214c034abf6SJohannes Stezenbach 
215025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum,
216025c3fa9STakashi Iwai 			    STA32X_CONFD, STA32X_CONFD_DRC_SHIFT,
217025c3fa9STakashi Iwai 			    sta32x_drc_ac);
218025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_auto_eq_enum,
219025c3fa9STakashi Iwai 			    STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT,
220025c3fa9STakashi Iwai 			    sta32x_auto_eq_mode);
221025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_auto_gc_enum,
222025c3fa9STakashi Iwai 			    STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT,
223025c3fa9STakashi Iwai 			    sta32x_auto_gc_mode);
224025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_auto_xo_enum,
225025c3fa9STakashi Iwai 			    STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT,
226025c3fa9STakashi Iwai 			    sta32x_auto_xo_mode);
227025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_preset_eq_enum,
228025c3fa9STakashi Iwai 			    STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT,
229025c3fa9STakashi Iwai 			    sta32x_preset_eq_mode);
230025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch1_enum,
231025c3fa9STakashi Iwai 			    STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT,
232025c3fa9STakashi Iwai 			    sta32x_limiter_select);
233025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch2_enum,
234025c3fa9STakashi Iwai 			    STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT,
235025c3fa9STakashi Iwai 			    sta32x_limiter_select);
236025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch3_enum,
237025c3fa9STakashi Iwai 			    STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT,
238025c3fa9STakashi Iwai 			    sta32x_limiter_select);
239025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_attack_rate_enum,
240025c3fa9STakashi Iwai 			    STA32X_L1AR, STA32X_LxA_SHIFT,
241025c3fa9STakashi Iwai 			    sta32x_limiter_attack_rate);
242025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_attack_rate_enum,
243025c3fa9STakashi Iwai 			    STA32X_L2AR, STA32X_LxA_SHIFT,
244025c3fa9STakashi Iwai 			    sta32x_limiter_attack_rate);
245025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_release_rate_enum,
246025c3fa9STakashi Iwai 			    STA32X_L1AR, STA32X_LxR_SHIFT,
247025c3fa9STakashi Iwai 			    sta32x_limiter_release_rate);
248025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_release_rate_enum,
249025c3fa9STakashi Iwai 			    STA32X_L2AR, STA32X_LxR_SHIFT,
250025c3fa9STakashi Iwai 			    sta32x_limiter_release_rate);
25179688439SJohannes Stezenbach 
25279688439SJohannes Stezenbach /* byte array controls for setting biquad, mixer, scaling coefficients;
25379688439SJohannes Stezenbach  * for biquads all five coefficients need to be set in one go,
25479688439SJohannes Stezenbach  * mixer and pre/postscale coefs can be set individually;
25579688439SJohannes Stezenbach  * each coef is 24bit, the bytes are ordered in the same way
25679688439SJohannes Stezenbach  * as given in the STA32x data sheet (big endian; b1, b2, a1, a2, b0)
25779688439SJohannes Stezenbach  */
25879688439SJohannes Stezenbach 
25979688439SJohannes Stezenbach static int sta32x_coefficient_info(struct snd_kcontrol *kcontrol,
26079688439SJohannes Stezenbach 				   struct snd_ctl_elem_info *uinfo)
26179688439SJohannes Stezenbach {
26279688439SJohannes Stezenbach 	int numcoef = kcontrol->private_value >> 16;
26379688439SJohannes Stezenbach 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
26479688439SJohannes Stezenbach 	uinfo->count = 3 * numcoef;
26579688439SJohannes Stezenbach 	return 0;
26679688439SJohannes Stezenbach }
26779688439SJohannes Stezenbach 
26879688439SJohannes Stezenbach static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
26979688439SJohannes Stezenbach 				  struct snd_ctl_elem_value *ucontrol)
27079688439SJohannes Stezenbach {
271ee183590SKuninori Morimoto 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
272ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
27379688439SJohannes Stezenbach 	int numcoef = kcontrol->private_value >> 16;
27479688439SJohannes Stezenbach 	int index = kcontrol->private_value & 0xffff;
275a1be4ceaSThomas Niederprüm 	unsigned int cfud, val;
276a1be4ceaSThomas Niederprüm 	int i, ret = 0;
277a1be4ceaSThomas Niederprüm 
278a1be4ceaSThomas Niederprüm 	mutex_lock(&sta32x->coeff_lock);
27979688439SJohannes Stezenbach 
28079688439SJohannes Stezenbach 	/* preserve reserved bits in STA32X_CFUD */
281a1be4ceaSThomas Niederprüm 	regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
282a1be4ceaSThomas Niederprüm 	cfud &= 0xf0;
283a1be4ceaSThomas Niederprüm 	/*
284a1be4ceaSThomas Niederprüm 	 * chip documentation does not say if the bits are self clearing,
285a1be4ceaSThomas Niederprüm 	 * so do it explicitly
286a1be4ceaSThomas Niederprüm 	 */
287a1be4ceaSThomas Niederprüm 	regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
28879688439SJohannes Stezenbach 
289a1be4ceaSThomas Niederprüm 	regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
290a1be4ceaSThomas Niederprüm 	if (numcoef == 1) {
291a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x04);
292a1be4ceaSThomas Niederprüm 	} else if (numcoef == 5) {
293a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x08);
294a1be4ceaSThomas Niederprüm 	} else {
295a1be4ceaSThomas Niederprüm 		ret = -EINVAL;
296a1be4ceaSThomas Niederprüm 		goto exit_unlock;
297a1be4ceaSThomas Niederprüm 	}
29879688439SJohannes Stezenbach 
299a1be4ceaSThomas Niederprüm 	for (i = 0; i < 3 * numcoef; i++) {
300a1be4ceaSThomas Niederprüm 		regmap_read(sta32x->regmap, STA32X_B1CF1 + i, &val);
301a1be4ceaSThomas Niederprüm 		ucontrol->value.bytes.data[i] = val;
302a1be4ceaSThomas Niederprüm 	}
303a1be4ceaSThomas Niederprüm 
304a1be4ceaSThomas Niederprüm exit_unlock:
305a1be4ceaSThomas Niederprüm 	mutex_unlock(&sta32x->coeff_lock);
306a1be4ceaSThomas Niederprüm 
307a1be4ceaSThomas Niederprüm 	return ret;
30879688439SJohannes Stezenbach }
30979688439SJohannes Stezenbach 
31079688439SJohannes Stezenbach static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
31179688439SJohannes Stezenbach 				  struct snd_ctl_elem_value *ucontrol)
31279688439SJohannes Stezenbach {
313ee183590SKuninori Morimoto 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
314ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
31579688439SJohannes Stezenbach 	int numcoef = kcontrol->private_value >> 16;
31679688439SJohannes Stezenbach 	int index = kcontrol->private_value & 0xffff;
31779688439SJohannes Stezenbach 	unsigned int cfud;
31879688439SJohannes Stezenbach 	int i;
31979688439SJohannes Stezenbach 
32079688439SJohannes Stezenbach 	/* preserve reserved bits in STA32X_CFUD */
321a1be4ceaSThomas Niederprüm 	regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
322a1be4ceaSThomas Niederprüm 	cfud &= 0xf0;
323a1be4ceaSThomas Niederprüm 	/*
324a1be4ceaSThomas Niederprüm 	 * chip documentation does not say if the bits are self clearing,
325a1be4ceaSThomas Niederprüm 	 * so do it explicitly
326a1be4ceaSThomas Niederprüm 	 */
327a1be4ceaSThomas Niederprüm 	regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
32879688439SJohannes Stezenbach 
329a1be4ceaSThomas Niederprüm 	regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
33054dc6cabSJohannes Stezenbach 	for (i = 0; i < numcoef && (index + i < STA32X_COEF_COUNT); i++)
33154dc6cabSJohannes Stezenbach 		sta32x->coef_shadow[index + i] =
33254dc6cabSJohannes Stezenbach 			  (ucontrol->value.bytes.data[3 * i] << 16)
33354dc6cabSJohannes Stezenbach 			| (ucontrol->value.bytes.data[3 * i + 1] << 8)
33454dc6cabSJohannes Stezenbach 			| (ucontrol->value.bytes.data[3 * i + 2]);
33579688439SJohannes Stezenbach 	for (i = 0; i < 3 * numcoef; i++)
336a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_B1CF1 + i,
33779688439SJohannes Stezenbach 			     ucontrol->value.bytes.data[i]);
33879688439SJohannes Stezenbach 	if (numcoef == 1)
339a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
34079688439SJohannes Stezenbach 	else if (numcoef == 5)
341a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x02);
34279688439SJohannes Stezenbach 	else
34379688439SJohannes Stezenbach 		return -EINVAL;
34479688439SJohannes Stezenbach 
34579688439SJohannes Stezenbach 	return 0;
34679688439SJohannes Stezenbach }
34779688439SJohannes Stezenbach 
348ee183590SKuninori Morimoto static int sta32x_sync_coef_shadow(struct snd_soc_component *component)
34954dc6cabSJohannes Stezenbach {
350ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
35154dc6cabSJohannes Stezenbach 	unsigned int cfud;
35254dc6cabSJohannes Stezenbach 	int i;
35354dc6cabSJohannes Stezenbach 
35454dc6cabSJohannes Stezenbach 	/* preserve reserved bits in STA32X_CFUD */
355a1be4ceaSThomas Niederprüm 	regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
356a1be4ceaSThomas Niederprüm 	cfud &= 0xf0;
35754dc6cabSJohannes Stezenbach 
35854dc6cabSJohannes Stezenbach 	for (i = 0; i < STA32X_COEF_COUNT; i++) {
359a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFADDR2, i);
360a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_B1CF1,
36154dc6cabSJohannes Stezenbach 			     (sta32x->coef_shadow[i] >> 16) & 0xff);
362a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_B1CF2,
36354dc6cabSJohannes Stezenbach 			     (sta32x->coef_shadow[i] >> 8) & 0xff);
364a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_B1CF3,
36554dc6cabSJohannes Stezenbach 			     (sta32x->coef_shadow[i]) & 0xff);
366a1be4ceaSThomas Niederprüm 		/*
367a1be4ceaSThomas Niederprüm 		 * chip documentation does not say if the bits are
368a1be4ceaSThomas Niederprüm 		 * self-clearing, so do it explicitly
369a1be4ceaSThomas Niederprüm 		 */
370a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
371a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
37254dc6cabSJohannes Stezenbach 	}
37354dc6cabSJohannes Stezenbach 	return 0;
37454dc6cabSJohannes Stezenbach }
37554dc6cabSJohannes Stezenbach 
376ee183590SKuninori Morimoto static int sta32x_cache_sync(struct snd_soc_component *component)
37754dc6cabSJohannes Stezenbach {
378ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
37954dc6cabSJohannes Stezenbach 	unsigned int mute;
38054dc6cabSJohannes Stezenbach 	int rc;
38154dc6cabSJohannes Stezenbach 
38254dc6cabSJohannes Stezenbach 	/* mute during register sync */
383a1be4ceaSThomas Niederprüm 	regmap_read(sta32x->regmap, STA32X_MMUTE, &mute);
384a1be4ceaSThomas Niederprüm 	regmap_write(sta32x->regmap, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE);
385ee183590SKuninori Morimoto 	sta32x_sync_coef_shadow(component);
38629fdf4fbSMark Brown 	rc = regcache_sync(sta32x->regmap);
387a1be4ceaSThomas Niederprüm 	regmap_write(sta32x->regmap, STA32X_MMUTE, mute);
38854dc6cabSJohannes Stezenbach 	return rc;
38954dc6cabSJohannes Stezenbach }
39054dc6cabSJohannes Stezenbach 
3913fb5eac5SJohannes Stezenbach /* work around ESD issue where sta32x resets and loses all configuration */
3923fb5eac5SJohannes Stezenbach static void sta32x_watchdog(struct work_struct *work)
3933fb5eac5SJohannes Stezenbach {
3943fb5eac5SJohannes Stezenbach 	struct sta32x_priv *sta32x = container_of(work, struct sta32x_priv,
3953fb5eac5SJohannes Stezenbach 						  watchdog_work.work);
396ee183590SKuninori Morimoto 	struct snd_soc_component *component = sta32x->component;
3973fb5eac5SJohannes Stezenbach 	unsigned int confa, confa_cached;
3983fb5eac5SJohannes Stezenbach 
3993fb5eac5SJohannes Stezenbach 	/* check if sta32x has reset itself */
400ee183590SKuninori Morimoto 	confa_cached = snd_soc_component_read32(component, STA32X_CONFA);
40129fdf4fbSMark Brown 	regcache_cache_bypass(sta32x->regmap, true);
402ee183590SKuninori Morimoto 	confa = snd_soc_component_read32(component, STA32X_CONFA);
40329fdf4fbSMark Brown 	regcache_cache_bypass(sta32x->regmap, false);
4043fb5eac5SJohannes Stezenbach 	if (confa != confa_cached) {
40529fdf4fbSMark Brown 		regcache_mark_dirty(sta32x->regmap);
406ee183590SKuninori Morimoto 		sta32x_cache_sync(component);
4073fb5eac5SJohannes Stezenbach 	}
4083fb5eac5SJohannes Stezenbach 
4093fb5eac5SJohannes Stezenbach 	if (!sta32x->shutdown)
410a14d9829SMark Brown 		queue_delayed_work(system_power_efficient_wq,
411a14d9829SMark Brown 				   &sta32x->watchdog_work,
4123fb5eac5SJohannes Stezenbach 				   round_jiffies_relative(HZ));
4133fb5eac5SJohannes Stezenbach }
4143fb5eac5SJohannes Stezenbach 
4153fb5eac5SJohannes Stezenbach static void sta32x_watchdog_start(struct sta32x_priv *sta32x)
4163fb5eac5SJohannes Stezenbach {
4173fb5eac5SJohannes Stezenbach 	if (sta32x->pdata->needs_esd_watchdog) {
4183fb5eac5SJohannes Stezenbach 		sta32x->shutdown = 0;
419a14d9829SMark Brown 		queue_delayed_work(system_power_efficient_wq,
420a14d9829SMark Brown 				   &sta32x->watchdog_work,
4213fb5eac5SJohannes Stezenbach 				   round_jiffies_relative(HZ));
4223fb5eac5SJohannes Stezenbach 	}
4233fb5eac5SJohannes Stezenbach }
4243fb5eac5SJohannes Stezenbach 
4253fb5eac5SJohannes Stezenbach static void sta32x_watchdog_stop(struct sta32x_priv *sta32x)
4263fb5eac5SJohannes Stezenbach {
4273fb5eac5SJohannes Stezenbach 	if (sta32x->pdata->needs_esd_watchdog) {
4283fb5eac5SJohannes Stezenbach 		sta32x->shutdown = 1;
4293fb5eac5SJohannes Stezenbach 		cancel_delayed_work_sync(&sta32x->watchdog_work);
4303fb5eac5SJohannes Stezenbach 	}
4313fb5eac5SJohannes Stezenbach }
4323fb5eac5SJohannes Stezenbach 
43379688439SJohannes Stezenbach #define SINGLE_COEF(xname, index) \
43479688439SJohannes Stezenbach {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
43579688439SJohannes Stezenbach 	.info = sta32x_coefficient_info, \
43679688439SJohannes Stezenbach 	.get = sta32x_coefficient_get,\
43779688439SJohannes Stezenbach 	.put = sta32x_coefficient_put, \
43879688439SJohannes Stezenbach 	.private_value = index | (1 << 16) }
43979688439SJohannes Stezenbach 
44079688439SJohannes Stezenbach #define BIQUAD_COEFS(xname, index) \
44179688439SJohannes Stezenbach {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
44279688439SJohannes Stezenbach 	.info = sta32x_coefficient_info, \
44379688439SJohannes Stezenbach 	.get = sta32x_coefficient_get,\
44479688439SJohannes Stezenbach 	.put = sta32x_coefficient_put, \
44579688439SJohannes Stezenbach 	.private_value = index | (5 << 16) }
44679688439SJohannes Stezenbach 
447c034abf6SJohannes Stezenbach static const struct snd_kcontrol_new sta32x_snd_controls[] = {
448c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Master Volume", STA32X_MVOL, 0, 0xff, 1, mvol_tlv),
449c034abf6SJohannes Stezenbach SOC_SINGLE("Master Switch", STA32X_MMUTE, 0, 1, 1),
450c034abf6SJohannes Stezenbach SOC_SINGLE("Ch1 Switch", STA32X_MMUTE, 1, 1, 1),
451c034abf6SJohannes Stezenbach SOC_SINGLE("Ch2 Switch", STA32X_MMUTE, 2, 1, 1),
452c034abf6SJohannes Stezenbach SOC_SINGLE("Ch3 Switch", STA32X_MMUTE, 3, 1, 1),
453c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Ch1 Volume", STA32X_C1VOL, 0, 0xff, 1, chvol_tlv),
454c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Ch2 Volume", STA32X_C2VOL, 0, 0xff, 1, chvol_tlv),
455c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Ch3 Volume", STA32X_C3VOL, 0, 0xff, 1, chvol_tlv),
456c034abf6SJohannes Stezenbach SOC_SINGLE("De-emphasis Filter Switch", STA32X_CONFD, STA32X_CONFD_DEMP_SHIFT, 1, 0),
457c034abf6SJohannes Stezenbach SOC_ENUM("Compressor/Limiter Switch", sta32x_drc_ac_enum),
458c034abf6SJohannes Stezenbach SOC_SINGLE("Miami Mode Switch", STA32X_CONFD, STA32X_CONFD_MME_SHIFT, 1, 0),
459c034abf6SJohannes Stezenbach SOC_SINGLE("Zero Cross Switch", STA32X_CONFE, STA32X_CONFE_ZCE_SHIFT, 1, 0),
460c034abf6SJohannes Stezenbach SOC_SINGLE("Soft Ramp Switch", STA32X_CONFE, STA32X_CONFE_SVE_SHIFT, 1, 0),
461c034abf6SJohannes Stezenbach SOC_SINGLE("Auto-Mute Switch", STA32X_CONFF, STA32X_CONFF_IDE_SHIFT, 1, 0),
462c034abf6SJohannes Stezenbach SOC_ENUM("Automode EQ", sta32x_auto_eq_enum),
463c034abf6SJohannes Stezenbach SOC_ENUM("Automode GC", sta32x_auto_gc_enum),
464c034abf6SJohannes Stezenbach SOC_ENUM("Automode XO", sta32x_auto_xo_enum),
465c034abf6SJohannes Stezenbach SOC_ENUM("Preset EQ", sta32x_preset_eq_enum),
466c034abf6SJohannes Stezenbach SOC_SINGLE("Ch1 Tone Control Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0),
467c034abf6SJohannes Stezenbach SOC_SINGLE("Ch2 Tone Control Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0),
468c034abf6SJohannes Stezenbach SOC_SINGLE("Ch1 EQ Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0),
469c034abf6SJohannes Stezenbach SOC_SINGLE("Ch2 EQ Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0),
470c034abf6SJohannes Stezenbach SOC_SINGLE("Ch1 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0),
471c034abf6SJohannes Stezenbach SOC_SINGLE("Ch2 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0),
472c034abf6SJohannes Stezenbach SOC_SINGLE("Ch3 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0),
473c034abf6SJohannes Stezenbach SOC_ENUM("Ch1 Limiter Select", sta32x_limiter_ch1_enum),
474c034abf6SJohannes Stezenbach SOC_ENUM("Ch2 Limiter Select", sta32x_limiter_ch2_enum),
475c034abf6SJohannes Stezenbach SOC_ENUM("Ch3 Limiter Select", sta32x_limiter_ch3_enum),
476c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Bass Tone Control", STA32X_TONE, STA32X_TONE_BTC_SHIFT, 15, 0, tone_tlv),
477c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Treble Tone Control", STA32X_TONE, STA32X_TONE_TTC_SHIFT, 15, 0, tone_tlv),
478c034abf6SJohannes Stezenbach SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum),
479c034abf6SJohannes Stezenbach SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum),
480c034abf6SJohannes Stezenbach SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum),
481b3619b28STakashi Iwai SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter2_release_rate_enum),
482c034abf6SJohannes Stezenbach 
483c034abf6SJohannes Stezenbach /* depending on mode, the attack/release thresholds have
484c034abf6SJohannes Stezenbach  * two different enum definitions; provide both
485c034abf6SJohannes Stezenbach  */
486c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter1 Attack Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT,
487c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_ac_attack_tlv),
488c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter2 Attack Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT,
489c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_ac_attack_tlv),
490c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter1 Release Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT,
491c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_ac_release_tlv),
492c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter2 Release Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT,
493c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_ac_release_tlv),
494c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter1 Attack Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT,
495c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_drc_attack_tlv),
496c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter2 Attack Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT,
497c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_drc_attack_tlv),
498c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter1 Release Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT,
499c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_drc_release_tlv),
500c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT,
501c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_drc_release_tlv),
50279688439SJohannes Stezenbach 
50379688439SJohannes Stezenbach BIQUAD_COEFS("Ch1 - Biquad 1", 0),
50479688439SJohannes Stezenbach BIQUAD_COEFS("Ch1 - Biquad 2", 5),
50579688439SJohannes Stezenbach BIQUAD_COEFS("Ch1 - Biquad 3", 10),
50679688439SJohannes Stezenbach BIQUAD_COEFS("Ch1 - Biquad 4", 15),
50779688439SJohannes Stezenbach BIQUAD_COEFS("Ch2 - Biquad 1", 20),
50879688439SJohannes Stezenbach BIQUAD_COEFS("Ch2 - Biquad 2", 25),
50979688439SJohannes Stezenbach BIQUAD_COEFS("Ch2 - Biquad 3", 30),
51079688439SJohannes Stezenbach BIQUAD_COEFS("Ch2 - Biquad 4", 35),
51179688439SJohannes Stezenbach BIQUAD_COEFS("High-pass", 40),
51279688439SJohannes Stezenbach BIQUAD_COEFS("Low-pass", 45),
51379688439SJohannes Stezenbach SINGLE_COEF("Ch1 - Prescale", 50),
51479688439SJohannes Stezenbach SINGLE_COEF("Ch2 - Prescale", 51),
51579688439SJohannes Stezenbach SINGLE_COEF("Ch1 - Postscale", 52),
51679688439SJohannes Stezenbach SINGLE_COEF("Ch2 - Postscale", 53),
51779688439SJohannes Stezenbach SINGLE_COEF("Ch3 - Postscale", 54),
51879688439SJohannes Stezenbach SINGLE_COEF("Thermal warning - Postscale", 55),
51979688439SJohannes Stezenbach SINGLE_COEF("Ch1 - Mix 1", 56),
52079688439SJohannes Stezenbach SINGLE_COEF("Ch1 - Mix 2", 57),
52179688439SJohannes Stezenbach SINGLE_COEF("Ch2 - Mix 1", 58),
52279688439SJohannes Stezenbach SINGLE_COEF("Ch2 - Mix 2", 59),
52379688439SJohannes Stezenbach SINGLE_COEF("Ch3 - Mix 1", 60),
52479688439SJohannes Stezenbach SINGLE_COEF("Ch3 - Mix 2", 61),
525c034abf6SJohannes Stezenbach };
526c034abf6SJohannes Stezenbach 
527c034abf6SJohannes Stezenbach static const struct snd_soc_dapm_widget sta32x_dapm_widgets[] = {
528c034abf6SJohannes Stezenbach SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
529c034abf6SJohannes Stezenbach SND_SOC_DAPM_OUTPUT("LEFT"),
530c034abf6SJohannes Stezenbach SND_SOC_DAPM_OUTPUT("RIGHT"),
531c034abf6SJohannes Stezenbach SND_SOC_DAPM_OUTPUT("SUB"),
532c034abf6SJohannes Stezenbach };
533c034abf6SJohannes Stezenbach 
534c034abf6SJohannes Stezenbach static const struct snd_soc_dapm_route sta32x_dapm_routes[] = {
535c034abf6SJohannes Stezenbach 	{ "LEFT", NULL, "DAC" },
536c034abf6SJohannes Stezenbach 	{ "RIGHT", NULL, "DAC" },
537c034abf6SJohannes Stezenbach 	{ "SUB", NULL, "DAC" },
538c034abf6SJohannes Stezenbach };
539c034abf6SJohannes Stezenbach 
540c034abf6SJohannes Stezenbach /* MCLK interpolation ratio per fs */
541c034abf6SJohannes Stezenbach static struct {
542c034abf6SJohannes Stezenbach 	int fs;
543c034abf6SJohannes Stezenbach 	int ir;
544c034abf6SJohannes Stezenbach } interpolation_ratios[] = {
545c034abf6SJohannes Stezenbach 	{ 32000, 0 },
546c034abf6SJohannes Stezenbach 	{ 44100, 0 },
547c034abf6SJohannes Stezenbach 	{ 48000, 0 },
548c034abf6SJohannes Stezenbach 	{ 88200, 1 },
549c034abf6SJohannes Stezenbach 	{ 96000, 1 },
550c034abf6SJohannes Stezenbach 	{ 176400, 2 },
551c034abf6SJohannes Stezenbach 	{ 192000, 2 },
552c034abf6SJohannes Stezenbach };
553c034abf6SJohannes Stezenbach 
554c034abf6SJohannes Stezenbach /* MCLK to fs clock ratios */
5551c34c876SThomas Niederprüm static int mcs_ratio_table[3][7] = {
5561c34c876SThomas Niederprüm 	{ 768, 512, 384, 256, 128, 576, 0 },
5571c34c876SThomas Niederprüm 	{ 384, 256, 192, 128,  64,   0 },
5581c34c876SThomas Niederprüm 	{ 384, 256, 192, 128,  64,   0 },
559c034abf6SJohannes Stezenbach };
560c034abf6SJohannes Stezenbach 
561c034abf6SJohannes Stezenbach /**
562c034abf6SJohannes Stezenbach  * sta32x_set_dai_sysclk - configure MCLK
563c034abf6SJohannes Stezenbach  * @codec_dai: the codec DAI
564c034abf6SJohannes Stezenbach  * @clk_id: the clock ID (ignored)
565c034abf6SJohannes Stezenbach  * @freq: the MCLK input frequency
566c034abf6SJohannes Stezenbach  * @dir: the clock direction (ignored)
567c034abf6SJohannes Stezenbach  *
568c034abf6SJohannes Stezenbach  * The value of MCLK is used to determine which sample rates are supported
569c034abf6SJohannes Stezenbach  * by the STA32X, based on the mclk_ratios table.
570c034abf6SJohannes Stezenbach  *
571c034abf6SJohannes Stezenbach  * This function must be called by the machine driver's 'startup' function,
572c034abf6SJohannes Stezenbach  * otherwise the list of supported sample rates will not be available in
573c034abf6SJohannes Stezenbach  * time for ALSA.
574c034abf6SJohannes Stezenbach  *
575c034abf6SJohannes Stezenbach  * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause
576c034abf6SJohannes Stezenbach  * theoretically possible sample rates to be enabled. Call it again with a
577c034abf6SJohannes Stezenbach  * proper value set one the external clock is set (most probably you would do
578c034abf6SJohannes Stezenbach  * that from a machine's driver 'hw_param' hook.
579c034abf6SJohannes Stezenbach  */
580c034abf6SJohannes Stezenbach static int sta32x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
581c034abf6SJohannes Stezenbach 		int clk_id, unsigned int freq, int dir)
582c034abf6SJohannes Stezenbach {
583ee183590SKuninori Morimoto 	struct snd_soc_component *component = codec_dai->component;
584ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
585c034abf6SJohannes Stezenbach 
586ee183590SKuninori Morimoto 	dev_dbg(component->dev, "mclk=%u\n", freq);
587c034abf6SJohannes Stezenbach 	sta32x->mclk = freq;
588c034abf6SJohannes Stezenbach 
589c034abf6SJohannes Stezenbach 	return 0;
590c034abf6SJohannes Stezenbach }
591c034abf6SJohannes Stezenbach 
592c034abf6SJohannes Stezenbach /**
593c034abf6SJohannes Stezenbach  * sta32x_set_dai_fmt - configure the codec for the selected audio format
594c034abf6SJohannes Stezenbach  * @codec_dai: the codec DAI
595c034abf6SJohannes Stezenbach  * @fmt: a SND_SOC_DAIFMT_x value indicating the data format
596c034abf6SJohannes Stezenbach  *
597c034abf6SJohannes Stezenbach  * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the
598c034abf6SJohannes Stezenbach  * codec accordingly.
599c034abf6SJohannes Stezenbach  */
600c034abf6SJohannes Stezenbach static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai,
601c034abf6SJohannes Stezenbach 			      unsigned int fmt)
602c034abf6SJohannes Stezenbach {
603ee183590SKuninori Morimoto 	struct snd_soc_component *component = codec_dai->component;
604ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
605a1be4ceaSThomas Niederprüm 	u8 confb = 0;
606c034abf6SJohannes Stezenbach 
607c034abf6SJohannes Stezenbach 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
608c034abf6SJohannes Stezenbach 	case SND_SOC_DAIFMT_CBS_CFS:
609c034abf6SJohannes Stezenbach 		break;
610c034abf6SJohannes Stezenbach 	default:
611c034abf6SJohannes Stezenbach 		return -EINVAL;
612c034abf6SJohannes Stezenbach 	}
613c034abf6SJohannes Stezenbach 
614c034abf6SJohannes Stezenbach 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
615c034abf6SJohannes Stezenbach 	case SND_SOC_DAIFMT_I2S:
616c034abf6SJohannes Stezenbach 	case SND_SOC_DAIFMT_RIGHT_J:
617c034abf6SJohannes Stezenbach 	case SND_SOC_DAIFMT_LEFT_J:
618c034abf6SJohannes Stezenbach 		sta32x->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
619c034abf6SJohannes Stezenbach 		break;
620c034abf6SJohannes Stezenbach 	default:
621c034abf6SJohannes Stezenbach 		return -EINVAL;
622c034abf6SJohannes Stezenbach 	}
623c034abf6SJohannes Stezenbach 
624c034abf6SJohannes Stezenbach 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
625c034abf6SJohannes Stezenbach 	case SND_SOC_DAIFMT_NB_NF:
626c034abf6SJohannes Stezenbach 		confb |= STA32X_CONFB_C2IM;
627c034abf6SJohannes Stezenbach 		break;
628c034abf6SJohannes Stezenbach 	case SND_SOC_DAIFMT_NB_IF:
629c034abf6SJohannes Stezenbach 		confb |= STA32X_CONFB_C1IM;
630c034abf6SJohannes Stezenbach 		break;
631c034abf6SJohannes Stezenbach 	default:
632c034abf6SJohannes Stezenbach 		return -EINVAL;
633c034abf6SJohannes Stezenbach 	}
634c034abf6SJohannes Stezenbach 
635a1be4ceaSThomas Niederprüm 	return regmap_update_bits(sta32x->regmap, STA32X_CONFB,
636a1be4ceaSThomas Niederprüm 				  STA32X_CONFB_C1IM | STA32X_CONFB_C2IM, confb);
637c034abf6SJohannes Stezenbach }
638c034abf6SJohannes Stezenbach 
639c034abf6SJohannes Stezenbach /**
640c034abf6SJohannes Stezenbach  * sta32x_hw_params - program the STA32X with the given hardware parameters.
641c034abf6SJohannes Stezenbach  * @substream: the audio stream
642c034abf6SJohannes Stezenbach  * @params: the hardware parameters to set
643c034abf6SJohannes Stezenbach  * @dai: the SOC DAI (ignored)
644c034abf6SJohannes Stezenbach  *
645c034abf6SJohannes Stezenbach  * This function programs the hardware with the values provided.
646c034abf6SJohannes Stezenbach  * Specifically, the sample rate and the data format.
647c034abf6SJohannes Stezenbach  */
648c034abf6SJohannes Stezenbach static int sta32x_hw_params(struct snd_pcm_substream *substream,
649c034abf6SJohannes Stezenbach 			    struct snd_pcm_hw_params *params,
650c034abf6SJohannes Stezenbach 			    struct snd_soc_dai *dai)
651c034abf6SJohannes Stezenbach {
652ee183590SKuninori Morimoto 	struct snd_soc_component *component = dai->component;
653ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
6541c34c876SThomas Niederprüm 	int i, mcs = -EINVAL, ir = -EINVAL;
655a1be4ceaSThomas Niederprüm 	unsigned int confa, confb;
6561c34c876SThomas Niederprüm 	unsigned int rate, ratio;
6571c34c876SThomas Niederprüm 	int ret;
6581c34c876SThomas Niederprüm 
6591c34c876SThomas Niederprüm 	if (!sta32x->mclk) {
660ee183590SKuninori Morimoto 		dev_err(component->dev,
6611c34c876SThomas Niederprüm 			"sta32x->mclk is unset. Unable to determine ratio\n");
6621c34c876SThomas Niederprüm 		return -EIO;
6631c34c876SThomas Niederprüm 	}
664c034abf6SJohannes Stezenbach 
665c034abf6SJohannes Stezenbach 	rate = params_rate(params);
6661c34c876SThomas Niederprüm 	ratio = sta32x->mclk / rate;
667ee183590SKuninori Morimoto 	dev_dbg(component->dev, "rate: %u, ratio: %u\n", rate, ratio);
6681c34c876SThomas Niederprüm 
6691c34c876SThomas Niederprüm 	for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) {
670a595238bSAxel Lin 		if (interpolation_ratios[i].fs == rate) {
671c034abf6SJohannes Stezenbach 			ir = interpolation_ratios[i].ir;
672a595238bSAxel Lin 			break;
673a595238bSAxel Lin 		}
6741c34c876SThomas Niederprüm 	}
6751c34c876SThomas Niederprüm 
6761c34c876SThomas Niederprüm 	if (ir < 0) {
677ee183590SKuninori Morimoto 		dev_err(component->dev, "Unsupported samplerate: %u\n", rate);
678c034abf6SJohannes Stezenbach 		return -EINVAL;
6791c34c876SThomas Niederprüm 	}
6801c34c876SThomas Niederprüm 
6811c34c876SThomas Niederprüm 	for (i = 0; i < 6; i++) {
6821c34c876SThomas Niederprüm 		if (mcs_ratio_table[ir][i] == ratio) {
6831c34c876SThomas Niederprüm 			mcs = i;
684a595238bSAxel Lin 			break;
685a595238bSAxel Lin 		}
6861c34c876SThomas Niederprüm 	}
6871c34c876SThomas Niederprüm 
6881c34c876SThomas Niederprüm 	if (mcs < 0) {
689ee183590SKuninori Morimoto 		dev_err(component->dev, "Unresolvable ratio: %u\n", ratio);
690c034abf6SJohannes Stezenbach 		return -EINVAL;
6911c34c876SThomas Niederprüm 	}
692c034abf6SJohannes Stezenbach 
693a1be4ceaSThomas Niederprüm 	confa = (ir << STA32X_CONFA_IR_SHIFT) |
694a1be4ceaSThomas Niederprüm 		(mcs << STA32X_CONFA_MCS_SHIFT);
695a1be4ceaSThomas Niederprüm 	confb = 0;
696c034abf6SJohannes Stezenbach 
697737e0f89SMark Brown 	switch (params_width(params)) {
698737e0f89SMark Brown 	case 24:
699ee183590SKuninori Morimoto 		dev_dbg(component->dev, "24bit\n");
700c034abf6SJohannes Stezenbach 		/* fall through */
701737e0f89SMark Brown 	case 32:
702ee183590SKuninori Morimoto 		dev_dbg(component->dev, "24bit or 32bit\n");
703c034abf6SJohannes Stezenbach 		switch (sta32x->format) {
704c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_I2S:
705c034abf6SJohannes Stezenbach 			confb |= 0x0;
706c034abf6SJohannes Stezenbach 			break;
707c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_LEFT_J:
708c034abf6SJohannes Stezenbach 			confb |= 0x1;
709c034abf6SJohannes Stezenbach 			break;
710c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_RIGHT_J:
711c034abf6SJohannes Stezenbach 			confb |= 0x2;
712c034abf6SJohannes Stezenbach 			break;
713c034abf6SJohannes Stezenbach 		}
714c034abf6SJohannes Stezenbach 
715c034abf6SJohannes Stezenbach 		break;
716737e0f89SMark Brown 	case 20:
717ee183590SKuninori Morimoto 		dev_dbg(component->dev, "20bit\n");
718c034abf6SJohannes Stezenbach 		switch (sta32x->format) {
719c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_I2S:
720c034abf6SJohannes Stezenbach 			confb |= 0x4;
721c034abf6SJohannes Stezenbach 			break;
722c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_LEFT_J:
723c034abf6SJohannes Stezenbach 			confb |= 0x5;
724c034abf6SJohannes Stezenbach 			break;
725c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_RIGHT_J:
726c034abf6SJohannes Stezenbach 			confb |= 0x6;
727c034abf6SJohannes Stezenbach 			break;
728c034abf6SJohannes Stezenbach 		}
729c034abf6SJohannes Stezenbach 
730c034abf6SJohannes Stezenbach 		break;
731737e0f89SMark Brown 	case 18:
732ee183590SKuninori Morimoto 		dev_dbg(component->dev, "18bit\n");
733c034abf6SJohannes Stezenbach 		switch (sta32x->format) {
734c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_I2S:
735c034abf6SJohannes Stezenbach 			confb |= 0x8;
736c034abf6SJohannes Stezenbach 			break;
737c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_LEFT_J:
738c034abf6SJohannes Stezenbach 			confb |= 0x9;
739c034abf6SJohannes Stezenbach 			break;
740c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_RIGHT_J:
741c034abf6SJohannes Stezenbach 			confb |= 0xa;
742c034abf6SJohannes Stezenbach 			break;
743c034abf6SJohannes Stezenbach 		}
744c034abf6SJohannes Stezenbach 
745c034abf6SJohannes Stezenbach 		break;
746737e0f89SMark Brown 	case 16:
747ee183590SKuninori Morimoto 		dev_dbg(component->dev, "16bit\n");
748c034abf6SJohannes Stezenbach 		switch (sta32x->format) {
749c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_I2S:
750c034abf6SJohannes Stezenbach 			confb |= 0x0;
751c034abf6SJohannes Stezenbach 			break;
752c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_LEFT_J:
753c034abf6SJohannes Stezenbach 			confb |= 0xd;
754c034abf6SJohannes Stezenbach 			break;
755c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_RIGHT_J:
756c034abf6SJohannes Stezenbach 			confb |= 0xe;
757c034abf6SJohannes Stezenbach 			break;
758c034abf6SJohannes Stezenbach 		}
759c034abf6SJohannes Stezenbach 
760c034abf6SJohannes Stezenbach 		break;
761c034abf6SJohannes Stezenbach 	default:
762c034abf6SJohannes Stezenbach 		return -EINVAL;
763c034abf6SJohannes Stezenbach 	}
764c034abf6SJohannes Stezenbach 
765a1be4ceaSThomas Niederprüm 	ret = regmap_update_bits(sta32x->regmap, STA32X_CONFA,
766a1be4ceaSThomas Niederprüm 				 STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK,
767a1be4ceaSThomas Niederprüm 				 confa);
768a1be4ceaSThomas Niederprüm 	if (ret < 0)
769a1be4ceaSThomas Niederprüm 		return ret;
770a1be4ceaSThomas Niederprüm 
771a1be4ceaSThomas Niederprüm 	ret = regmap_update_bits(sta32x->regmap, STA32X_CONFB,
772a1be4ceaSThomas Niederprüm 				 STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB,
773a1be4ceaSThomas Niederprüm 				 confb);
774a1be4ceaSThomas Niederprüm 	if (ret < 0)
775a1be4ceaSThomas Niederprüm 		return ret;
776a1be4ceaSThomas Niederprüm 
777a1be4ceaSThomas Niederprüm 	return 0;
778a1be4ceaSThomas Niederprüm }
779b66a2980SThomas Niederprüm 
780b66a2980SThomas Niederprüm static int sta32x_startup_sequence(struct sta32x_priv *sta32x)
781b66a2980SThomas Niederprüm {
782b66a2980SThomas Niederprüm 	if (sta32x->gpiod_nreset) {
783b66a2980SThomas Niederprüm 		gpiod_set_value(sta32x->gpiod_nreset, 0);
784b66a2980SThomas Niederprüm 		mdelay(1);
785b66a2980SThomas Niederprüm 		gpiod_set_value(sta32x->gpiod_nreset, 1);
786b66a2980SThomas Niederprüm 		mdelay(1);
787b66a2980SThomas Niederprüm 	}
788b66a2980SThomas Niederprüm 
789c034abf6SJohannes Stezenbach 	return 0;
790c034abf6SJohannes Stezenbach }
791c034abf6SJohannes Stezenbach 
792c034abf6SJohannes Stezenbach /**
793c034abf6SJohannes Stezenbach  * sta32x_set_bias_level - DAPM callback
794ee183590SKuninori Morimoto  * @component: the component device
795c034abf6SJohannes Stezenbach  * @level: DAPM power level
796c034abf6SJohannes Stezenbach  *
797ee183590SKuninori Morimoto  * This is called by ALSA to put the component into low power mode
798ee183590SKuninori Morimoto  * or to wake it up.  If the component is powered off completely
799c034abf6SJohannes Stezenbach  * all registers must be restored after power on.
800c034abf6SJohannes Stezenbach  */
801ee183590SKuninori Morimoto static int sta32x_set_bias_level(struct snd_soc_component *component,
802c034abf6SJohannes Stezenbach 				 enum snd_soc_bias_level level)
803c034abf6SJohannes Stezenbach {
804c034abf6SJohannes Stezenbach 	int ret;
805ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
806c034abf6SJohannes Stezenbach 
807ee183590SKuninori Morimoto 	dev_dbg(component->dev, "level = %d\n", level);
808c034abf6SJohannes Stezenbach 	switch (level) {
809c034abf6SJohannes Stezenbach 	case SND_SOC_BIAS_ON:
810c034abf6SJohannes Stezenbach 		break;
811c034abf6SJohannes Stezenbach 
812c034abf6SJohannes Stezenbach 	case SND_SOC_BIAS_PREPARE:
813c034abf6SJohannes Stezenbach 		/* Full power on */
814a1be4ceaSThomas Niederprüm 		regmap_update_bits(sta32x->regmap, STA32X_CONFF,
815c034abf6SJohannes Stezenbach 				    STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
816c034abf6SJohannes Stezenbach 				    STA32X_CONFF_PWDN | STA32X_CONFF_EAPD);
817c034abf6SJohannes Stezenbach 		break;
818c034abf6SJohannes Stezenbach 
819c034abf6SJohannes Stezenbach 	case SND_SOC_BIAS_STANDBY:
820ee183590SKuninori Morimoto 		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
821c034abf6SJohannes Stezenbach 			ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
822c034abf6SJohannes Stezenbach 						    sta32x->supplies);
823c034abf6SJohannes Stezenbach 			if (ret != 0) {
824ee183590SKuninori Morimoto 				dev_err(component->dev,
825c034abf6SJohannes Stezenbach 					"Failed to enable supplies: %d\n", ret);
826c034abf6SJohannes Stezenbach 				return ret;
827c034abf6SJohannes Stezenbach 			}
828c034abf6SJohannes Stezenbach 
829b66a2980SThomas Niederprüm 			sta32x_startup_sequence(sta32x);
830ee183590SKuninori Morimoto 			sta32x_cache_sync(component);
8313fb5eac5SJohannes Stezenbach 			sta32x_watchdog_start(sta32x);
832c034abf6SJohannes Stezenbach 		}
833c034abf6SJohannes Stezenbach 
834a1be4ceaSThomas Niederprüm 		/* Power down */
835a1be4ceaSThomas Niederprüm 		regmap_update_bits(sta32x->regmap, STA32X_CONFF,
836c034abf6SJohannes Stezenbach 				   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
837a1be4ceaSThomas Niederprüm 				   0);
838c034abf6SJohannes Stezenbach 
839c034abf6SJohannes Stezenbach 		break;
840c034abf6SJohannes Stezenbach 
841c034abf6SJohannes Stezenbach 	case SND_SOC_BIAS_OFF:
842c034abf6SJohannes Stezenbach 		/* The chip runs through the power down sequence for us. */
843a1be4ceaSThomas Niederprüm 		regmap_update_bits(sta32x->regmap, STA32X_CONFF,
844a1be4ceaSThomas Niederprüm 				   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, 0);
845c034abf6SJohannes Stezenbach 		msleep(300);
8463fb5eac5SJohannes Stezenbach 		sta32x_watchdog_stop(sta32x);
847b66a2980SThomas Niederprüm 
848b66a2980SThomas Niederprüm 		gpiod_set_value(sta32x->gpiod_nreset, 0);
849b66a2980SThomas Niederprüm 
850c034abf6SJohannes Stezenbach 		regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies),
851c034abf6SJohannes Stezenbach 				       sta32x->supplies);
852c034abf6SJohannes Stezenbach 		break;
853c034abf6SJohannes Stezenbach 	}
854c034abf6SJohannes Stezenbach 	return 0;
855c034abf6SJohannes Stezenbach }
856c034abf6SJohannes Stezenbach 
85785e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops sta32x_dai_ops = {
858c034abf6SJohannes Stezenbach 	.hw_params	= sta32x_hw_params,
859c034abf6SJohannes Stezenbach 	.set_sysclk	= sta32x_set_dai_sysclk,
860c034abf6SJohannes Stezenbach 	.set_fmt	= sta32x_set_dai_fmt,
861c034abf6SJohannes Stezenbach };
862c034abf6SJohannes Stezenbach 
863c034abf6SJohannes Stezenbach static struct snd_soc_dai_driver sta32x_dai = {
8643c9390adSThomas Niederprüm 	.name = "sta32x-hifi",
865c034abf6SJohannes Stezenbach 	.playback = {
866c034abf6SJohannes Stezenbach 		.stream_name = "Playback",
867c034abf6SJohannes Stezenbach 		.channels_min = 2,
868c034abf6SJohannes Stezenbach 		.channels_max = 2,
869c034abf6SJohannes Stezenbach 		.rates = STA32X_RATES,
870c034abf6SJohannes Stezenbach 		.formats = STA32X_FORMATS,
871c034abf6SJohannes Stezenbach 	},
872c034abf6SJohannes Stezenbach 	.ops = &sta32x_dai_ops,
873c034abf6SJohannes Stezenbach };
874c034abf6SJohannes Stezenbach 
875ee183590SKuninori Morimoto static int sta32x_probe(struct snd_soc_component *component)
876c034abf6SJohannes Stezenbach {
877ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
878a1be4ceaSThomas Niederprüm 	struct sta32x_platform_data *pdata = sta32x->pdata;
879e012ba24SJohannes Stezenbach 	int i, ret = 0, thermal = 0;
880fce9ec95SDaniel Mack 
881fce9ec95SDaniel Mack 	sta32x->component = component;
882fce9ec95SDaniel Mack 
883fce9ec95SDaniel Mack 	if (sta32x->xti_clk) {
884fce9ec95SDaniel Mack 		ret = clk_prepare_enable(sta32x->xti_clk);
885fce9ec95SDaniel Mack 		if (ret != 0) {
886fce9ec95SDaniel Mack 			dev_err(component->dev,
887fce9ec95SDaniel Mack 				"Failed to enable clock: %d\n", ret);
888fce9ec95SDaniel Mack 			return ret;
889fce9ec95SDaniel Mack 		}
890fce9ec95SDaniel Mack 	}
891fce9ec95SDaniel Mack 
892c034abf6SJohannes Stezenbach 	ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
893c034abf6SJohannes Stezenbach 				    sta32x->supplies);
894c034abf6SJohannes Stezenbach 	if (ret != 0) {
895ee183590SKuninori Morimoto 		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
896*8dc10114SChuhong Yuan 		goto err_clk_disable_unprepare;
897c034abf6SJohannes Stezenbach 	}
898c034abf6SJohannes Stezenbach 
899b66a2980SThomas Niederprüm 	ret = sta32x_startup_sequence(sta32x);
900b66a2980SThomas Niederprüm 	if (ret < 0) {
901ee183590SKuninori Morimoto 		dev_err(component->dev, "Failed to startup device\n");
902*8dc10114SChuhong Yuan 		goto err_regulator_bulk_disable;
903b66a2980SThomas Niederprüm 	}
904f04b1e76SThomas Niederprüm 
905f04b1e76SThomas Niederprüm 	/* CONFA */
906a1be4ceaSThomas Niederprüm 	if (!pdata->thermal_warning_recovery)
907e012ba24SJohannes Stezenbach 		thermal |= STA32X_CONFA_TWAB;
908a1be4ceaSThomas Niederprüm 	if (!pdata->thermal_warning_adjustment)
909e012ba24SJohannes Stezenbach 		thermal |= STA32X_CONFA_TWRB;
910f04b1e76SThomas Niederprüm 	if (!pdata->fault_detect_recovery)
911f04b1e76SThomas Niederprüm 		thermal |= STA32X_CONFA_FDRB;
912a1be4ceaSThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFA,
913f04b1e76SThomas Niederprüm 			   STA32X_CONFA_TWAB | STA32X_CONFA_TWRB |
914f04b1e76SThomas Niederprüm 			   STA32X_CONFA_FDRB,
915e012ba24SJohannes Stezenbach 			   thermal);
916c034abf6SJohannes Stezenbach 
917f04b1e76SThomas Niederprüm 	/* CONFC */
918f04b1e76SThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFC,
919f04b1e76SThomas Niederprüm 			   STA32X_CONFC_CSZ_MASK,
920f04b1e76SThomas Niederprüm 			   pdata->drop_compensation_ns
921f04b1e76SThomas Niederprüm 				<< STA32X_CONFC_CSZ_SHIFT);
922f04b1e76SThomas Niederprüm 
923f04b1e76SThomas Niederprüm 	/* CONFE */
924f04b1e76SThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
925f04b1e76SThomas Niederprüm 			   STA32X_CONFE_MPCV,
926f04b1e76SThomas Niederprüm 			   pdata->max_power_use_mpcc ?
927f04b1e76SThomas Niederprüm 				STA32X_CONFE_MPCV : 0);
928f04b1e76SThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
929f04b1e76SThomas Niederprüm 			   STA32X_CONFE_MPC,
930f04b1e76SThomas Niederprüm 			   pdata->max_power_correction ?
931f04b1e76SThomas Niederprüm 				STA32X_CONFE_MPC : 0);
932f04b1e76SThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
933f04b1e76SThomas Niederprüm 			   STA32X_CONFE_AME,
934f04b1e76SThomas Niederprüm 			   pdata->am_reduction_mode ?
935f04b1e76SThomas Niederprüm 				STA32X_CONFE_AME : 0);
936f04b1e76SThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
937f04b1e76SThomas Niederprüm 			   STA32X_CONFE_PWMS,
938f04b1e76SThomas Niederprüm 			   pdata->odd_pwm_speed_mode ?
939f04b1e76SThomas Niederprüm 				STA32X_CONFE_PWMS : 0);
940f04b1e76SThomas Niederprüm 
941f04b1e76SThomas Niederprüm 	/*  CONFF */
942f04b1e76SThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFF,
943f04b1e76SThomas Niederprüm 			   STA32X_CONFF_IDE,
944f04b1e76SThomas Niederprüm 			   pdata->invalid_input_detect_mute ?
945f04b1e76SThomas Niederprüm 				STA32X_CONFF_IDE : 0);
946f04b1e76SThomas Niederprüm 
947e012ba24SJohannes Stezenbach 	/* select output configuration  */
948a1be4ceaSThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFF,
949c034abf6SJohannes Stezenbach 			   STA32X_CONFF_OCFG_MASK,
950a1be4ceaSThomas Niederprüm 			   pdata->output_conf
951e012ba24SJohannes Stezenbach 				<< STA32X_CONFF_OCFG_SHIFT);
952c034abf6SJohannes Stezenbach 
953e012ba24SJohannes Stezenbach 	/* channel to output mapping */
954a1be4ceaSThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_C1CFG,
955c034abf6SJohannes Stezenbach 			   STA32X_CxCFG_OM_MASK,
956a1be4ceaSThomas Niederprüm 			   pdata->ch1_output_mapping
957e012ba24SJohannes Stezenbach 				<< STA32X_CxCFG_OM_SHIFT);
958a1be4ceaSThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_C2CFG,
959c034abf6SJohannes Stezenbach 			   STA32X_CxCFG_OM_MASK,
960a1be4ceaSThomas Niederprüm 			   pdata->ch2_output_mapping
961e012ba24SJohannes Stezenbach 				<< STA32X_CxCFG_OM_SHIFT);
962a1be4ceaSThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_C3CFG,
963c034abf6SJohannes Stezenbach 			   STA32X_CxCFG_OM_MASK,
964a1be4ceaSThomas Niederprüm 			   pdata->ch3_output_mapping
965e012ba24SJohannes Stezenbach 				<< STA32X_CxCFG_OM_SHIFT);
966c034abf6SJohannes Stezenbach 
96754dc6cabSJohannes Stezenbach 	/* initialize coefficient shadow RAM with reset values */
96854dc6cabSJohannes Stezenbach 	for (i = 4; i <= 49; i += 5)
96954dc6cabSJohannes Stezenbach 		sta32x->coef_shadow[i] = 0x400000;
97054dc6cabSJohannes Stezenbach 	for (i = 50; i <= 54; i++)
97154dc6cabSJohannes Stezenbach 		sta32x->coef_shadow[i] = 0x7fffff;
97254dc6cabSJohannes Stezenbach 	sta32x->coef_shadow[55] = 0x5a9df7;
97354dc6cabSJohannes Stezenbach 	sta32x->coef_shadow[56] = 0x7fffff;
97454dc6cabSJohannes Stezenbach 	sta32x->coef_shadow[59] = 0x7fffff;
97554dc6cabSJohannes Stezenbach 	sta32x->coef_shadow[60] = 0x400000;
97654dc6cabSJohannes Stezenbach 	sta32x->coef_shadow[61] = 0x400000;
97754dc6cabSJohannes Stezenbach 
9783fb5eac5SJohannes Stezenbach 	if (sta32x->pdata->needs_esd_watchdog)
9793fb5eac5SJohannes Stezenbach 		INIT_DELAYED_WORK(&sta32x->watchdog_work, sta32x_watchdog);
9803fb5eac5SJohannes Stezenbach 
981ee183590SKuninori Morimoto 	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
982c034abf6SJohannes Stezenbach 	/* Bias level configuration will have done an extra enable */
983c034abf6SJohannes Stezenbach 	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
984c034abf6SJohannes Stezenbach 
985c034abf6SJohannes Stezenbach 	return 0;
986*8dc10114SChuhong Yuan 
987*8dc10114SChuhong Yuan err_regulator_bulk_disable:
988*8dc10114SChuhong Yuan 	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
989*8dc10114SChuhong Yuan err_clk_disable_unprepare:
990*8dc10114SChuhong Yuan 	if (sta32x->xti_clk)
991*8dc10114SChuhong Yuan 		clk_disable_unprepare(sta32x->xti_clk);
992*8dc10114SChuhong Yuan 	return ret;
993c034abf6SJohannes Stezenbach }
994c034abf6SJohannes Stezenbach 
995ee183590SKuninori Morimoto static void sta32x_remove(struct snd_soc_component *component)
996c034abf6SJohannes Stezenbach {
997ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
998c034abf6SJohannes Stezenbach 
9993fb5eac5SJohannes Stezenbach 	sta32x_watchdog_stop(sta32x);
1000c034abf6SJohannes Stezenbach 	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
1001fce9ec95SDaniel Mack 
1002fce9ec95SDaniel Mack 	if (sta32x->xti_clk)
1003fce9ec95SDaniel Mack 		clk_disable_unprepare(sta32x->xti_clk);
1004c034abf6SJohannes Stezenbach }
1005c034abf6SJohannes Stezenbach 
1006ee183590SKuninori Morimoto static const struct snd_soc_component_driver sta32x_component = {
1007c034abf6SJohannes Stezenbach 	.probe			= sta32x_probe,
1008c034abf6SJohannes Stezenbach 	.remove			= sta32x_remove,
1009c034abf6SJohannes Stezenbach 	.set_bias_level		= sta32x_set_bias_level,
1010c034abf6SJohannes Stezenbach 	.controls		= sta32x_snd_controls,
1011c034abf6SJohannes Stezenbach 	.num_controls		= ARRAY_SIZE(sta32x_snd_controls),
1012c034abf6SJohannes Stezenbach 	.dapm_widgets		= sta32x_dapm_widgets,
1013c034abf6SJohannes Stezenbach 	.num_dapm_widgets	= ARRAY_SIZE(sta32x_dapm_widgets),
1014c034abf6SJohannes Stezenbach 	.dapm_routes		= sta32x_dapm_routes,
1015c034abf6SJohannes Stezenbach 	.num_dapm_routes	= ARRAY_SIZE(sta32x_dapm_routes),
1016ee183590SKuninori Morimoto 	.suspend_bias_off	= 1,
1017ee183590SKuninori Morimoto 	.idle_bias_on		= 1,
1018ee183590SKuninori Morimoto 	.use_pmdown_time	= 1,
1019ee183590SKuninori Morimoto 	.endianness		= 1,
1020ee183590SKuninori Morimoto 	.non_legacy_dai_naming	= 1,
1021c034abf6SJohannes Stezenbach };
1022c034abf6SJohannes Stezenbach 
102329fdf4fbSMark Brown static const struct regmap_config sta32x_regmap = {
102429fdf4fbSMark Brown 	.reg_bits =		8,
102529fdf4fbSMark Brown 	.val_bits =		8,
102629fdf4fbSMark Brown 	.max_register =		STA32X_FDRC2,
102729fdf4fbSMark Brown 	.reg_defaults =		sta32x_regs,
102829fdf4fbSMark Brown 	.num_reg_defaults =	ARRAY_SIZE(sta32x_regs),
102929fdf4fbSMark Brown 	.cache_type =		REGCACHE_RBTREE,
1030a1be4ceaSThomas Niederprüm 	.wr_table =		&sta32x_write_regs,
1031a1be4ceaSThomas Niederprüm 	.rd_table =		&sta32x_read_regs,
1032a1be4ceaSThomas Niederprüm 	.volatile_table =	&sta32x_volatile_regs,
1033a1be4ceaSThomas Niederprüm };
1034f04b1e76SThomas Niederprüm 
1035f04b1e76SThomas Niederprüm #ifdef CONFIG_OF
1036f04b1e76SThomas Niederprüm static const struct of_device_id st32x_dt_ids[] = {
1037f04b1e76SThomas Niederprüm 	{ .compatible = "st,sta32x", },
1038f04b1e76SThomas Niederprüm 	{ }
103929fdf4fbSMark Brown };
1040f04b1e76SThomas Niederprüm MODULE_DEVICE_TABLE(of, st32x_dt_ids);
1041f04b1e76SThomas Niederprüm 
1042f04b1e76SThomas Niederprüm static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x)
1043f04b1e76SThomas Niederprüm {
1044f04b1e76SThomas Niederprüm 	struct device_node *np = dev->of_node;
1045f04b1e76SThomas Niederprüm 	struct sta32x_platform_data *pdata;
1046f04b1e76SThomas Niederprüm 	u16 tmp;
1047f04b1e76SThomas Niederprüm 
1048f04b1e76SThomas Niederprüm 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
1049f04b1e76SThomas Niederprüm 	if (!pdata)
1050f04b1e76SThomas Niederprüm 		return -ENOMEM;
1051f04b1e76SThomas Niederprüm 
1052f04b1e76SThomas Niederprüm 	of_property_read_u8(np, "st,output-conf",
1053f04b1e76SThomas Niederprüm 			    &pdata->output_conf);
1054f04b1e76SThomas Niederprüm 	of_property_read_u8(np, "st,ch1-output-mapping",
1055f04b1e76SThomas Niederprüm 			    &pdata->ch1_output_mapping);
1056f04b1e76SThomas Niederprüm 	of_property_read_u8(np, "st,ch2-output-mapping",
1057f04b1e76SThomas Niederprüm 			    &pdata->ch2_output_mapping);
1058f04b1e76SThomas Niederprüm 	of_property_read_u8(np, "st,ch3-output-mapping",
1059f04b1e76SThomas Niederprüm 			    &pdata->ch3_output_mapping);
1060f04b1e76SThomas Niederprüm 
1061466dee75SDaniel Mack 	if (of_get_property(np, "st,fault-detect-recovery", NULL))
1062466dee75SDaniel Mack 		pdata->fault_detect_recovery = 1;
1063f04b1e76SThomas Niederprüm 	if (of_get_property(np, "st,thermal-warning-recovery", NULL))
1064f04b1e76SThomas Niederprüm 		pdata->thermal_warning_recovery = 1;
1065f04b1e76SThomas Niederprüm 	if (of_get_property(np, "st,thermal-warning-adjustment", NULL))
1066f04b1e76SThomas Niederprüm 		pdata->thermal_warning_adjustment = 1;
1067f04b1e76SThomas Niederprüm 	if (of_get_property(np, "st,needs_esd_watchdog", NULL))
1068f04b1e76SThomas Niederprüm 		pdata->needs_esd_watchdog = 1;
1069f04b1e76SThomas Niederprüm 
1070f04b1e76SThomas Niederprüm 	tmp = 140;
1071f04b1e76SThomas Niederprüm 	of_property_read_u16(np, "st,drop-compensation-ns", &tmp);
1072f04b1e76SThomas Niederprüm 	pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20;
1073f04b1e76SThomas Niederprüm 
1074f04b1e76SThomas Niederprüm 	/* CONFE */
1075f04b1e76SThomas Niederprüm 	if (of_get_property(np, "st,max-power-use-mpcc", NULL))
1076f04b1e76SThomas Niederprüm 		pdata->max_power_use_mpcc = 1;
1077f04b1e76SThomas Niederprüm 
1078f04b1e76SThomas Niederprüm 	if (of_get_property(np, "st,max-power-correction", NULL))
1079f04b1e76SThomas Niederprüm 		pdata->max_power_correction = 1;
1080f04b1e76SThomas Niederprüm 
1081f04b1e76SThomas Niederprüm 	if (of_get_property(np, "st,am-reduction-mode", NULL))
1082f04b1e76SThomas Niederprüm 		pdata->am_reduction_mode = 1;
1083f04b1e76SThomas Niederprüm 
1084f04b1e76SThomas Niederprüm 	if (of_get_property(np, "st,odd-pwm-speed-mode", NULL))
1085f04b1e76SThomas Niederprüm 		pdata->odd_pwm_speed_mode = 1;
1086f04b1e76SThomas Niederprüm 
1087f04b1e76SThomas Niederprüm 	/* CONFF */
1088f04b1e76SThomas Niederprüm 	if (of_get_property(np, "st,invalid-input-detect-mute", NULL))
1089f04b1e76SThomas Niederprüm 		pdata->invalid_input_detect_mute = 1;
1090f04b1e76SThomas Niederprüm 
1091f04b1e76SThomas Niederprüm 	sta32x->pdata = pdata;
1092f04b1e76SThomas Niederprüm 
1093f04b1e76SThomas Niederprüm 	return 0;
1094f04b1e76SThomas Niederprüm }
1095f04b1e76SThomas Niederprüm #endif
109629fdf4fbSMark Brown 
10977a79e94eSBill Pemberton static int sta32x_i2c_probe(struct i2c_client *i2c,
1098c034abf6SJohannes Stezenbach 			    const struct i2c_device_id *id)
1099c034abf6SJohannes Stezenbach {
1100a1be4ceaSThomas Niederprüm 	struct device *dev = &i2c->dev;
1101c034abf6SJohannes Stezenbach 	struct sta32x_priv *sta32x;
1102aff041afSMark Brown 	int ret, i;
1103c034abf6SJohannes Stezenbach 
1104d999c021SAxel Lin 	sta32x = devm_kzalloc(&i2c->dev, sizeof(struct sta32x_priv),
1105d999c021SAxel Lin 			      GFP_KERNEL);
1106c034abf6SJohannes Stezenbach 	if (!sta32x)
1107c034abf6SJohannes Stezenbach 		return -ENOMEM;
1108c034abf6SJohannes Stezenbach 
1109a1be4ceaSThomas Niederprüm 	mutex_init(&sta32x->coeff_lock);
1110a1be4ceaSThomas Niederprüm 	sta32x->pdata = dev_get_platdata(dev);
1111b66a2980SThomas Niederprüm 
1112f04b1e76SThomas Niederprüm #ifdef CONFIG_OF
1113f04b1e76SThomas Niederprüm 	if (dev->of_node) {
1114f04b1e76SThomas Niederprüm 		ret = sta32x_probe_dt(dev, sta32x);
1115f04b1e76SThomas Niederprüm 		if (ret < 0)
1116f04b1e76SThomas Niederprüm 			return ret;
1117f04b1e76SThomas Niederprüm 	}
1118f04b1e76SThomas Niederprüm #endif
1119f04b1e76SThomas Niederprüm 
1120fce9ec95SDaniel Mack 	/* Clock */
1121fce9ec95SDaniel Mack 	sta32x->xti_clk = devm_clk_get(dev, "xti");
1122fce9ec95SDaniel Mack 	if (IS_ERR(sta32x->xti_clk)) {
1123fce9ec95SDaniel Mack 		ret = PTR_ERR(sta32x->xti_clk);
1124fce9ec95SDaniel Mack 
1125fce9ec95SDaniel Mack 		if (ret == -EPROBE_DEFER)
1126fce9ec95SDaniel Mack 			return ret;
1127fce9ec95SDaniel Mack 
1128fce9ec95SDaniel Mack 		sta32x->xti_clk = NULL;
1129fce9ec95SDaniel Mack 	}
1130fce9ec95SDaniel Mack 
1131b66a2980SThomas Niederprüm 	/* GPIOs */
11321137e580SUwe Kleine-König 	sta32x->gpiod_nreset = devm_gpiod_get_optional(dev, "reset",
11331137e580SUwe Kleine-König 						       GPIOD_OUT_LOW);
11341137e580SUwe Kleine-König 	if (IS_ERR(sta32x->gpiod_nreset))
11351137e580SUwe Kleine-König 		return PTR_ERR(sta32x->gpiod_nreset);
1136b66a2980SThomas Niederprüm 
1137aff041afSMark Brown 	/* regulators */
1138aff041afSMark Brown 	for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++)
1139aff041afSMark Brown 		sta32x->supplies[i].supply = sta32x_supply_names[i];
1140aff041afSMark Brown 
1141aff041afSMark Brown 	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(sta32x->supplies),
1142aff041afSMark Brown 				      sta32x->supplies);
1143aff041afSMark Brown 	if (ret != 0) {
1144aff041afSMark Brown 		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
1145aff041afSMark Brown 		return ret;
1146aff041afSMark Brown 	}
1147aff041afSMark Brown 
114829fdf4fbSMark Brown 	sta32x->regmap = devm_regmap_init_i2c(i2c, &sta32x_regmap);
114929fdf4fbSMark Brown 	if (IS_ERR(sta32x->regmap)) {
115029fdf4fbSMark Brown 		ret = PTR_ERR(sta32x->regmap);
1151a1be4ceaSThomas Niederprüm 		dev_err(dev, "Failed to init regmap: %d\n", ret);
115229fdf4fbSMark Brown 		return ret;
115329fdf4fbSMark Brown 	}
115429fdf4fbSMark Brown 
1155c034abf6SJohannes Stezenbach 	i2c_set_clientdata(i2c, sta32x);
1156c034abf6SJohannes Stezenbach 
1157ee183590SKuninori Morimoto 	ret = devm_snd_soc_register_component(dev, &sta32x_component,
1158ee183590SKuninori Morimoto 					      &sta32x_dai, 1);
1159a1be4ceaSThomas Niederprüm 	if (ret < 0)
1160ee183590SKuninori Morimoto 		dev_err(dev, "Failed to register component (%d)\n", ret);
1161c034abf6SJohannes Stezenbach 
1162d999c021SAxel Lin 	return ret;
1163c034abf6SJohannes Stezenbach }
1164c034abf6SJohannes Stezenbach 
1165c034abf6SJohannes Stezenbach static const struct i2c_device_id sta32x_i2c_id[] = {
1166c034abf6SJohannes Stezenbach 	{ "sta326", 0 },
1167c034abf6SJohannes Stezenbach 	{ "sta328", 0 },
1168c034abf6SJohannes Stezenbach 	{ "sta329", 0 },
1169c034abf6SJohannes Stezenbach 	{ }
1170c034abf6SJohannes Stezenbach };
1171c034abf6SJohannes Stezenbach MODULE_DEVICE_TABLE(i2c, sta32x_i2c_id);
1172c034abf6SJohannes Stezenbach 
1173c034abf6SJohannes Stezenbach static struct i2c_driver sta32x_i2c_driver = {
1174c034abf6SJohannes Stezenbach 	.driver = {
1175c034abf6SJohannes Stezenbach 		.name = "sta32x",
1176f04b1e76SThomas Niederprüm 		.of_match_table = of_match_ptr(st32x_dt_ids),
1177c034abf6SJohannes Stezenbach 	},
1178c034abf6SJohannes Stezenbach 	.probe =    sta32x_i2c_probe,
1179c034abf6SJohannes Stezenbach 	.id_table = sta32x_i2c_id,
1180c034abf6SJohannes Stezenbach };
1181c034abf6SJohannes Stezenbach 
11820ead1136SSachin Kamat module_i2c_driver(sta32x_i2c_driver);
1183c034abf6SJohannes Stezenbach 
1184c034abf6SJohannes Stezenbach MODULE_DESCRIPTION("ASoC STA32X driver");
1185c034abf6SJohannes Stezenbach MODULE_AUTHOR("Johannes Stezenbach <js@sig21.net>");
1186c034abf6SJohannes Stezenbach MODULE_LICENSE("GPL");
1187