xref: /linux/sound/soc/codecs/sta32x.c (revision 9abcd24002bf7997be752b6b48b137c4db3a609b)
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 \
51a9b5bef8SCharles Keepax 	(SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S18_3LE | \
52a9b5bef8SCharles Keepax 	 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE | \
53a9b5bef8SCharles Keepax 	 SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S32_LE)
54c034abf6SJohannes Stezenbach 
55c034abf6SJohannes Stezenbach /* Power-up register defaults */
5629fdf4fbSMark Brown static const struct reg_default sta32x_regs[] = {
5729fdf4fbSMark Brown 	{  0x0, 0x63 },
5829fdf4fbSMark Brown 	{  0x1, 0x80 },
5929fdf4fbSMark Brown 	{  0x2, 0xc2 },
6029fdf4fbSMark Brown 	{  0x3, 0x40 },
6129fdf4fbSMark Brown 	{  0x4, 0xc2 },
6229fdf4fbSMark Brown 	{  0x5, 0x5c },
6329fdf4fbSMark Brown 	{  0x6, 0x10 },
6429fdf4fbSMark Brown 	{  0x7, 0xff },
6529fdf4fbSMark Brown 	{  0x8, 0x60 },
6629fdf4fbSMark Brown 	{  0x9, 0x60 },
6729fdf4fbSMark Brown 	{  0xa, 0x60 },
6829fdf4fbSMark Brown 	{  0xb, 0x80 },
6929fdf4fbSMark Brown 	{  0xc, 0x00 },
7029fdf4fbSMark Brown 	{  0xd, 0x00 },
7129fdf4fbSMark Brown 	{  0xe, 0x00 },
7229fdf4fbSMark Brown 	{  0xf, 0x40 },
7329fdf4fbSMark Brown 	{ 0x10, 0x80 },
7429fdf4fbSMark Brown 	{ 0x11, 0x77 },
7529fdf4fbSMark Brown 	{ 0x12, 0x6a },
7629fdf4fbSMark Brown 	{ 0x13, 0x69 },
7729fdf4fbSMark Brown 	{ 0x14, 0x6a },
7829fdf4fbSMark Brown 	{ 0x15, 0x69 },
7929fdf4fbSMark Brown 	{ 0x16, 0x00 },
8029fdf4fbSMark Brown 	{ 0x17, 0x00 },
8129fdf4fbSMark Brown 	{ 0x18, 0x00 },
8229fdf4fbSMark Brown 	{ 0x19, 0x00 },
8329fdf4fbSMark Brown 	{ 0x1a, 0x00 },
8429fdf4fbSMark Brown 	{ 0x1b, 0x00 },
8529fdf4fbSMark Brown 	{ 0x1c, 0x00 },
8629fdf4fbSMark Brown 	{ 0x1d, 0x00 },
8729fdf4fbSMark Brown 	{ 0x1e, 0x00 },
8829fdf4fbSMark Brown 	{ 0x1f, 0x00 },
8929fdf4fbSMark Brown 	{ 0x20, 0x00 },
9029fdf4fbSMark Brown 	{ 0x21, 0x00 },
9129fdf4fbSMark Brown 	{ 0x22, 0x00 },
9229fdf4fbSMark Brown 	{ 0x23, 0x00 },
9329fdf4fbSMark Brown 	{ 0x24, 0x00 },
9429fdf4fbSMark Brown 	{ 0x25, 0x00 },
9529fdf4fbSMark Brown 	{ 0x26, 0x00 },
9629fdf4fbSMark Brown 	{ 0x27, 0x2d },
9729fdf4fbSMark Brown 	{ 0x28, 0xc0 },
9829fdf4fbSMark Brown 	{ 0x2b, 0x00 },
9929fdf4fbSMark Brown 	{ 0x2c, 0x0c },
100c034abf6SJohannes Stezenbach };
101c034abf6SJohannes Stezenbach 
102a1be4ceaSThomas Niederprüm static const struct regmap_range sta32x_write_regs_range[] = {
103148388f3SThomas Niederprüm 	regmap_reg_range(STA32X_CONFA,  STA32X_FDRC2),
104a1be4ceaSThomas Niederprüm };
105a1be4ceaSThomas Niederprüm 
106a1be4ceaSThomas Niederprüm static const struct regmap_range sta32x_read_regs_range[] = {
107148388f3SThomas Niederprüm 	regmap_reg_range(STA32X_CONFA,  STA32X_FDRC2),
108a1be4ceaSThomas Niederprüm };
109a1be4ceaSThomas Niederprüm 
110a1be4ceaSThomas Niederprüm static const struct regmap_range sta32x_volatile_regs_range[] = {
111a1be4ceaSThomas Niederprüm 	regmap_reg_range(STA32X_CFADDR2, STA32X_CFUD),
112a1be4ceaSThomas Niederprüm };
113a1be4ceaSThomas Niederprüm 
114a1be4ceaSThomas Niederprüm static const struct regmap_access_table sta32x_write_regs = {
115a1be4ceaSThomas Niederprüm 	.yes_ranges =	sta32x_write_regs_range,
116a1be4ceaSThomas Niederprüm 	.n_yes_ranges =	ARRAY_SIZE(sta32x_write_regs_range),
117a1be4ceaSThomas Niederprüm };
118a1be4ceaSThomas Niederprüm 
119a1be4ceaSThomas Niederprüm static const struct regmap_access_table sta32x_read_regs = {
120a1be4ceaSThomas Niederprüm 	.yes_ranges =	sta32x_read_regs_range,
121a1be4ceaSThomas Niederprüm 	.n_yes_ranges =	ARRAY_SIZE(sta32x_read_regs_range),
122a1be4ceaSThomas Niederprüm };
123a1be4ceaSThomas Niederprüm 
124a1be4ceaSThomas Niederprüm static const struct regmap_access_table sta32x_volatile_regs = {
125a1be4ceaSThomas Niederprüm 	.yes_ranges =	sta32x_volatile_regs_range,
126a1be4ceaSThomas Niederprüm 	.n_yes_ranges =	ARRAY_SIZE(sta32x_volatile_regs_range),
127a1be4ceaSThomas Niederprüm };
128a1be4ceaSThomas Niederprüm 
129c034abf6SJohannes Stezenbach /* regulator power supply names */
130c034abf6SJohannes Stezenbach static const char *sta32x_supply_names[] = {
131c034abf6SJohannes Stezenbach 	"Vdda",	/* analog supply, 3.3VV */
132c034abf6SJohannes Stezenbach 	"Vdd3",	/* digital supply, 3.3V */
133c034abf6SJohannes Stezenbach 	"Vcc"	/* power amp spply, 10V - 36V */
134c034abf6SJohannes Stezenbach };
135c034abf6SJohannes Stezenbach 
136c034abf6SJohannes Stezenbach /* codec private data */
137c034abf6SJohannes Stezenbach struct sta32x_priv {
13829fdf4fbSMark Brown 	struct regmap *regmap;
139fce9ec95SDaniel Mack 	struct clk *xti_clk;
140c034abf6SJohannes Stezenbach 	struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)];
141ee183590SKuninori Morimoto 	struct snd_soc_component *component;
142e012ba24SJohannes Stezenbach 	struct sta32x_platform_data *pdata;
143c034abf6SJohannes Stezenbach 
144c034abf6SJohannes Stezenbach 	unsigned int mclk;
145c034abf6SJohannes Stezenbach 	unsigned int format;
14654dc6cabSJohannes Stezenbach 
14754dc6cabSJohannes Stezenbach 	u32 coef_shadow[STA32X_COEF_COUNT];
1483fb5eac5SJohannes Stezenbach 	struct delayed_work watchdog_work;
1493fb5eac5SJohannes Stezenbach 	int shutdown;
150b66a2980SThomas Niederprüm 	struct gpio_desc *gpiod_nreset;
151a1be4ceaSThomas Niederprüm 	struct mutex coeff_lock;
152c034abf6SJohannes Stezenbach };
153c034abf6SJohannes Stezenbach 
154c034abf6SJohannes Stezenbach static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1);
155c034abf6SJohannes Stezenbach static const DECLARE_TLV_DB_SCALE(chvol_tlv, -7950, 50, 1);
156c034abf6SJohannes Stezenbach static const DECLARE_TLV_DB_SCALE(tone_tlv, -120, 200, 0);
157c034abf6SJohannes Stezenbach 
158c034abf6SJohannes Stezenbach static const char *sta32x_drc_ac[] = {
159c034abf6SJohannes Stezenbach 	"Anti-Clipping", "Dynamic Range Compression" };
160c034abf6SJohannes Stezenbach static const char *sta32x_auto_eq_mode[] = {
161c034abf6SJohannes Stezenbach 	"User", "Preset", "Loudness" };
162c034abf6SJohannes Stezenbach static const char *sta32x_auto_gc_mode[] = {
163c034abf6SJohannes Stezenbach 	"User", "AC no clipping", "AC limited clipping (10%)",
164c034abf6SJohannes Stezenbach 	"DRC nighttime listening mode" };
165c034abf6SJohannes Stezenbach static const char *sta32x_auto_xo_mode[] = {
166c034abf6SJohannes Stezenbach 	"User", "80Hz", "100Hz", "120Hz", "140Hz", "160Hz", "180Hz", "200Hz",
167c034abf6SJohannes Stezenbach 	"220Hz", "240Hz", "260Hz", "280Hz", "300Hz", "320Hz", "340Hz", "360Hz" };
168c034abf6SJohannes Stezenbach static const char *sta32x_preset_eq_mode[] = {
169c034abf6SJohannes Stezenbach 	"Flat", "Rock", "Soft Rock", "Jazz", "Classical", "Dance", "Pop", "Soft",
170c034abf6SJohannes Stezenbach 	"Hard", "Party", "Vocal", "Hip-Hop", "Dialog", "Bass-boost #1",
171c034abf6SJohannes Stezenbach 	"Bass-boost #2", "Bass-boost #3", "Loudness 1", "Loudness 2",
172c034abf6SJohannes Stezenbach 	"Loudness 3", "Loudness 4", "Loudness 5", "Loudness 6", "Loudness 7",
173c034abf6SJohannes Stezenbach 	"Loudness 8", "Loudness 9", "Loudness 10", "Loudness 11", "Loudness 12",
174c034abf6SJohannes Stezenbach 	"Loudness 13", "Loudness 14", "Loudness 15", "Loudness 16" };
175c034abf6SJohannes Stezenbach static const char *sta32x_limiter_select[] = {
176c034abf6SJohannes Stezenbach 	"Limiter Disabled", "Limiter #1", "Limiter #2" };
177c034abf6SJohannes Stezenbach static const char *sta32x_limiter_attack_rate[] = {
178c034abf6SJohannes Stezenbach 	"3.1584", "2.7072", "2.2560", "1.8048", "1.3536", "0.9024",
179c034abf6SJohannes Stezenbach 	"0.4512", "0.2256", "0.1504", "0.1123", "0.0902", "0.0752",
180c034abf6SJohannes Stezenbach 	"0.0645", "0.0564", "0.0501", "0.0451" };
181c034abf6SJohannes Stezenbach static const char *sta32x_limiter_release_rate[] = {
182c034abf6SJohannes Stezenbach 	"0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299",
183c034abf6SJohannes Stezenbach 	"0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137",
184c034abf6SJohannes Stezenbach 	"0.0134", "0.0117", "0.0110", "0.0104" };
18588483f59SThomas Niederprüm static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_attack_tlv,
186c034abf6SJohannes Stezenbach 	0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0),
187c034abf6SJohannes Stezenbach 	8, 16, TLV_DB_SCALE_ITEM(300, 100, 0),
18888483f59SThomas Niederprüm );
189c034abf6SJohannes Stezenbach 
19088483f59SThomas Niederprüm static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_release_tlv,
191c034abf6SJohannes Stezenbach 	0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
192c034abf6SJohannes Stezenbach 	1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0),
193c034abf6SJohannes Stezenbach 	2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0),
194c034abf6SJohannes Stezenbach 	3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0),
195c034abf6SJohannes Stezenbach 	8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0),
19688483f59SThomas Niederprüm );
197c034abf6SJohannes Stezenbach 
19888483f59SThomas Niederprüm static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_attack_tlv,
199c034abf6SJohannes Stezenbach 	0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0),
200c034abf6SJohannes Stezenbach 	8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0),
201c034abf6SJohannes Stezenbach 	14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0),
20288483f59SThomas Niederprüm );
203c034abf6SJohannes Stezenbach 
20488483f59SThomas Niederprüm static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_release_tlv,
205c034abf6SJohannes Stezenbach 	0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
206c034abf6SJohannes Stezenbach 	1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0),
207c034abf6SJohannes Stezenbach 	3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0),
208c034abf6SJohannes Stezenbach 	5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0),
209c034abf6SJohannes Stezenbach 	13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0),
21088483f59SThomas Niederprüm );
211c034abf6SJohannes Stezenbach 
212025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum,
213025c3fa9STakashi Iwai 			    STA32X_CONFD, STA32X_CONFD_DRC_SHIFT,
214025c3fa9STakashi Iwai 			    sta32x_drc_ac);
215025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_auto_eq_enum,
216025c3fa9STakashi Iwai 			    STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT,
217025c3fa9STakashi Iwai 			    sta32x_auto_eq_mode);
218025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_auto_gc_enum,
219025c3fa9STakashi Iwai 			    STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT,
220025c3fa9STakashi Iwai 			    sta32x_auto_gc_mode);
221025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_auto_xo_enum,
222025c3fa9STakashi Iwai 			    STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT,
223025c3fa9STakashi Iwai 			    sta32x_auto_xo_mode);
224025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_preset_eq_enum,
225025c3fa9STakashi Iwai 			    STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT,
226025c3fa9STakashi Iwai 			    sta32x_preset_eq_mode);
227025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch1_enum,
228025c3fa9STakashi Iwai 			    STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT,
229025c3fa9STakashi Iwai 			    sta32x_limiter_select);
230025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch2_enum,
231025c3fa9STakashi Iwai 			    STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT,
232025c3fa9STakashi Iwai 			    sta32x_limiter_select);
233025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch3_enum,
234025c3fa9STakashi Iwai 			    STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT,
235025c3fa9STakashi Iwai 			    sta32x_limiter_select);
236025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_attack_rate_enum,
237025c3fa9STakashi Iwai 			    STA32X_L1AR, STA32X_LxA_SHIFT,
238025c3fa9STakashi Iwai 			    sta32x_limiter_attack_rate);
239025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_attack_rate_enum,
240025c3fa9STakashi Iwai 			    STA32X_L2AR, STA32X_LxA_SHIFT,
241025c3fa9STakashi Iwai 			    sta32x_limiter_attack_rate);
242025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_release_rate_enum,
243025c3fa9STakashi Iwai 			    STA32X_L1AR, STA32X_LxR_SHIFT,
244025c3fa9STakashi Iwai 			    sta32x_limiter_release_rate);
245025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_release_rate_enum,
246025c3fa9STakashi Iwai 			    STA32X_L2AR, STA32X_LxR_SHIFT,
247025c3fa9STakashi Iwai 			    sta32x_limiter_release_rate);
24879688439SJohannes Stezenbach 
24979688439SJohannes Stezenbach /* byte array controls for setting biquad, mixer, scaling coefficients;
25079688439SJohannes Stezenbach  * for biquads all five coefficients need to be set in one go,
25179688439SJohannes Stezenbach  * mixer and pre/postscale coefs can be set individually;
25279688439SJohannes Stezenbach  * each coef is 24bit, the bytes are ordered in the same way
25379688439SJohannes Stezenbach  * as given in the STA32x data sheet (big endian; b1, b2, a1, a2, b0)
25479688439SJohannes Stezenbach  */
25579688439SJohannes Stezenbach 
25679688439SJohannes Stezenbach static int sta32x_coefficient_info(struct snd_kcontrol *kcontrol,
25779688439SJohannes Stezenbach 				   struct snd_ctl_elem_info *uinfo)
25879688439SJohannes Stezenbach {
25979688439SJohannes Stezenbach 	int numcoef = kcontrol->private_value >> 16;
26079688439SJohannes Stezenbach 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
26179688439SJohannes Stezenbach 	uinfo->count = 3 * numcoef;
26279688439SJohannes Stezenbach 	return 0;
26379688439SJohannes Stezenbach }
26479688439SJohannes Stezenbach 
26579688439SJohannes Stezenbach static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
26679688439SJohannes Stezenbach 				  struct snd_ctl_elem_value *ucontrol)
26779688439SJohannes Stezenbach {
268ee183590SKuninori Morimoto 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
269ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
27079688439SJohannes Stezenbach 	int numcoef = kcontrol->private_value >> 16;
27179688439SJohannes Stezenbach 	int index = kcontrol->private_value & 0xffff;
272a1be4ceaSThomas Niederprüm 	unsigned int cfud, val;
273a1be4ceaSThomas Niederprüm 	int i, ret = 0;
274a1be4ceaSThomas Niederprüm 
275a1be4ceaSThomas Niederprüm 	mutex_lock(&sta32x->coeff_lock);
27679688439SJohannes Stezenbach 
27779688439SJohannes Stezenbach 	/* preserve reserved bits in STA32X_CFUD */
278a1be4ceaSThomas Niederprüm 	regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
279a1be4ceaSThomas Niederprüm 	cfud &= 0xf0;
280a1be4ceaSThomas Niederprüm 	/*
281a1be4ceaSThomas Niederprüm 	 * chip documentation does not say if the bits are self clearing,
282a1be4ceaSThomas Niederprüm 	 * so do it explicitly
283a1be4ceaSThomas Niederprüm 	 */
284a1be4ceaSThomas Niederprüm 	regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
28579688439SJohannes Stezenbach 
286a1be4ceaSThomas Niederprüm 	regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
287a1be4ceaSThomas Niederprüm 	if (numcoef == 1) {
288a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x04);
289a1be4ceaSThomas Niederprüm 	} else if (numcoef == 5) {
290a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x08);
291a1be4ceaSThomas Niederprüm 	} else {
292a1be4ceaSThomas Niederprüm 		ret = -EINVAL;
293a1be4ceaSThomas Niederprüm 		goto exit_unlock;
294a1be4ceaSThomas Niederprüm 	}
29579688439SJohannes Stezenbach 
296a1be4ceaSThomas Niederprüm 	for (i = 0; i < 3 * numcoef; i++) {
297a1be4ceaSThomas Niederprüm 		regmap_read(sta32x->regmap, STA32X_B1CF1 + i, &val);
298a1be4ceaSThomas Niederprüm 		ucontrol->value.bytes.data[i] = val;
299a1be4ceaSThomas Niederprüm 	}
300a1be4ceaSThomas Niederprüm 
301a1be4ceaSThomas Niederprüm exit_unlock:
302a1be4ceaSThomas Niederprüm 	mutex_unlock(&sta32x->coeff_lock);
303a1be4ceaSThomas Niederprüm 
304a1be4ceaSThomas Niederprüm 	return ret;
30579688439SJohannes Stezenbach }
30679688439SJohannes Stezenbach 
30779688439SJohannes Stezenbach static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
30879688439SJohannes Stezenbach 				  struct snd_ctl_elem_value *ucontrol)
30979688439SJohannes Stezenbach {
310ee183590SKuninori Morimoto 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
311ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
31279688439SJohannes Stezenbach 	int numcoef = kcontrol->private_value >> 16;
31379688439SJohannes Stezenbach 	int index = kcontrol->private_value & 0xffff;
31479688439SJohannes Stezenbach 	unsigned int cfud;
31579688439SJohannes Stezenbach 	int i;
31679688439SJohannes Stezenbach 
31779688439SJohannes Stezenbach 	/* preserve reserved bits in STA32X_CFUD */
318a1be4ceaSThomas Niederprüm 	regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
319a1be4ceaSThomas Niederprüm 	cfud &= 0xf0;
320a1be4ceaSThomas Niederprüm 	/*
321a1be4ceaSThomas Niederprüm 	 * chip documentation does not say if the bits are self clearing,
322a1be4ceaSThomas Niederprüm 	 * so do it explicitly
323a1be4ceaSThomas Niederprüm 	 */
324a1be4ceaSThomas Niederprüm 	regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
32579688439SJohannes Stezenbach 
326a1be4ceaSThomas Niederprüm 	regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
32754dc6cabSJohannes Stezenbach 	for (i = 0; i < numcoef && (index + i < STA32X_COEF_COUNT); i++)
32854dc6cabSJohannes Stezenbach 		sta32x->coef_shadow[index + i] =
32954dc6cabSJohannes Stezenbach 			  (ucontrol->value.bytes.data[3 * i] << 16)
33054dc6cabSJohannes Stezenbach 			| (ucontrol->value.bytes.data[3 * i + 1] << 8)
33154dc6cabSJohannes Stezenbach 			| (ucontrol->value.bytes.data[3 * i + 2]);
33279688439SJohannes Stezenbach 	for (i = 0; i < 3 * numcoef; i++)
333a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_B1CF1 + i,
33479688439SJohannes Stezenbach 			     ucontrol->value.bytes.data[i]);
33579688439SJohannes Stezenbach 	if (numcoef == 1)
336a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
33779688439SJohannes Stezenbach 	else if (numcoef == 5)
338a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x02);
33979688439SJohannes Stezenbach 	else
34079688439SJohannes Stezenbach 		return -EINVAL;
34179688439SJohannes Stezenbach 
34279688439SJohannes Stezenbach 	return 0;
34379688439SJohannes Stezenbach }
34479688439SJohannes Stezenbach 
345ee183590SKuninori Morimoto static int sta32x_sync_coef_shadow(struct snd_soc_component *component)
34654dc6cabSJohannes Stezenbach {
347ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
34854dc6cabSJohannes Stezenbach 	unsigned int cfud;
34954dc6cabSJohannes Stezenbach 	int i;
35054dc6cabSJohannes Stezenbach 
35154dc6cabSJohannes Stezenbach 	/* preserve reserved bits in STA32X_CFUD */
352a1be4ceaSThomas Niederprüm 	regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
353a1be4ceaSThomas Niederprüm 	cfud &= 0xf0;
35454dc6cabSJohannes Stezenbach 
35554dc6cabSJohannes Stezenbach 	for (i = 0; i < STA32X_COEF_COUNT; i++) {
356a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFADDR2, i);
357a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_B1CF1,
35854dc6cabSJohannes Stezenbach 			     (sta32x->coef_shadow[i] >> 16) & 0xff);
359a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_B1CF2,
36054dc6cabSJohannes Stezenbach 			     (sta32x->coef_shadow[i] >> 8) & 0xff);
361a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_B1CF3,
36254dc6cabSJohannes Stezenbach 			     (sta32x->coef_shadow[i]) & 0xff);
363a1be4ceaSThomas Niederprüm 		/*
364a1be4ceaSThomas Niederprüm 		 * chip documentation does not say if the bits are
365a1be4ceaSThomas Niederprüm 		 * self-clearing, so do it explicitly
366a1be4ceaSThomas Niederprüm 		 */
367a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
368a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
36954dc6cabSJohannes Stezenbach 	}
37054dc6cabSJohannes Stezenbach 	return 0;
37154dc6cabSJohannes Stezenbach }
37254dc6cabSJohannes Stezenbach 
373ee183590SKuninori Morimoto static int sta32x_cache_sync(struct snd_soc_component *component)
37454dc6cabSJohannes Stezenbach {
375ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
37654dc6cabSJohannes Stezenbach 	unsigned int mute;
37754dc6cabSJohannes Stezenbach 	int rc;
37854dc6cabSJohannes Stezenbach 
37954dc6cabSJohannes Stezenbach 	/* mute during register sync */
380a1be4ceaSThomas Niederprüm 	regmap_read(sta32x->regmap, STA32X_MMUTE, &mute);
381a1be4ceaSThomas Niederprüm 	regmap_write(sta32x->regmap, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE);
382ee183590SKuninori Morimoto 	sta32x_sync_coef_shadow(component);
38329fdf4fbSMark Brown 	rc = regcache_sync(sta32x->regmap);
384a1be4ceaSThomas Niederprüm 	regmap_write(sta32x->regmap, STA32X_MMUTE, mute);
38554dc6cabSJohannes Stezenbach 	return rc;
38654dc6cabSJohannes Stezenbach }
38754dc6cabSJohannes Stezenbach 
3883fb5eac5SJohannes Stezenbach /* work around ESD issue where sta32x resets and loses all configuration */
3893fb5eac5SJohannes Stezenbach static void sta32x_watchdog(struct work_struct *work)
3903fb5eac5SJohannes Stezenbach {
3913fb5eac5SJohannes Stezenbach 	struct sta32x_priv *sta32x = container_of(work, struct sta32x_priv,
3923fb5eac5SJohannes Stezenbach 						  watchdog_work.work);
393ee183590SKuninori Morimoto 	struct snd_soc_component *component = sta32x->component;
3943fb5eac5SJohannes Stezenbach 	unsigned int confa, confa_cached;
3953fb5eac5SJohannes Stezenbach 
3963fb5eac5SJohannes Stezenbach 	/* check if sta32x has reset itself */
397981abdfeSKuninori Morimoto 	confa_cached = snd_soc_component_read(component, STA32X_CONFA);
39829fdf4fbSMark Brown 	regcache_cache_bypass(sta32x->regmap, true);
399981abdfeSKuninori Morimoto 	confa = snd_soc_component_read(component, STA32X_CONFA);
40029fdf4fbSMark Brown 	regcache_cache_bypass(sta32x->regmap, false);
4013fb5eac5SJohannes Stezenbach 	if (confa != confa_cached) {
40229fdf4fbSMark Brown 		regcache_mark_dirty(sta32x->regmap);
403ee183590SKuninori Morimoto 		sta32x_cache_sync(component);
4043fb5eac5SJohannes Stezenbach 	}
4053fb5eac5SJohannes Stezenbach 
4063fb5eac5SJohannes Stezenbach 	if (!sta32x->shutdown)
407a14d9829SMark Brown 		queue_delayed_work(system_power_efficient_wq,
408a14d9829SMark Brown 				   &sta32x->watchdog_work,
4093fb5eac5SJohannes Stezenbach 				   round_jiffies_relative(HZ));
4103fb5eac5SJohannes Stezenbach }
4113fb5eac5SJohannes Stezenbach 
4123fb5eac5SJohannes Stezenbach static void sta32x_watchdog_start(struct sta32x_priv *sta32x)
4133fb5eac5SJohannes Stezenbach {
4143fb5eac5SJohannes Stezenbach 	if (sta32x->pdata->needs_esd_watchdog) {
4153fb5eac5SJohannes Stezenbach 		sta32x->shutdown = 0;
416a14d9829SMark Brown 		queue_delayed_work(system_power_efficient_wq,
417a14d9829SMark Brown 				   &sta32x->watchdog_work,
4183fb5eac5SJohannes Stezenbach 				   round_jiffies_relative(HZ));
4193fb5eac5SJohannes Stezenbach 	}
4203fb5eac5SJohannes Stezenbach }
4213fb5eac5SJohannes Stezenbach 
4223fb5eac5SJohannes Stezenbach static void sta32x_watchdog_stop(struct sta32x_priv *sta32x)
4233fb5eac5SJohannes Stezenbach {
4243fb5eac5SJohannes Stezenbach 	if (sta32x->pdata->needs_esd_watchdog) {
4253fb5eac5SJohannes Stezenbach 		sta32x->shutdown = 1;
4263fb5eac5SJohannes Stezenbach 		cancel_delayed_work_sync(&sta32x->watchdog_work);
4273fb5eac5SJohannes Stezenbach 	}
4283fb5eac5SJohannes Stezenbach }
4293fb5eac5SJohannes Stezenbach 
43079688439SJohannes Stezenbach #define SINGLE_COEF(xname, index) \
43179688439SJohannes Stezenbach {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
43279688439SJohannes Stezenbach 	.info = sta32x_coefficient_info, \
43379688439SJohannes Stezenbach 	.get = sta32x_coefficient_get,\
43479688439SJohannes Stezenbach 	.put = sta32x_coefficient_put, \
43579688439SJohannes Stezenbach 	.private_value = index | (1 << 16) }
43679688439SJohannes Stezenbach 
43779688439SJohannes Stezenbach #define BIQUAD_COEFS(xname, index) \
43879688439SJohannes Stezenbach {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
43979688439SJohannes Stezenbach 	.info = sta32x_coefficient_info, \
44079688439SJohannes Stezenbach 	.get = sta32x_coefficient_get,\
44179688439SJohannes Stezenbach 	.put = sta32x_coefficient_put, \
44279688439SJohannes Stezenbach 	.private_value = index | (5 << 16) }
44379688439SJohannes Stezenbach 
444c034abf6SJohannes Stezenbach static const struct snd_kcontrol_new sta32x_snd_controls[] = {
445c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Master Volume", STA32X_MVOL, 0, 0xff, 1, mvol_tlv),
446c034abf6SJohannes Stezenbach SOC_SINGLE("Master Switch", STA32X_MMUTE, 0, 1, 1),
447c034abf6SJohannes Stezenbach SOC_SINGLE("Ch1 Switch", STA32X_MMUTE, 1, 1, 1),
448c034abf6SJohannes Stezenbach SOC_SINGLE("Ch2 Switch", STA32X_MMUTE, 2, 1, 1),
449c034abf6SJohannes Stezenbach SOC_SINGLE("Ch3 Switch", STA32X_MMUTE, 3, 1, 1),
450c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Ch1 Volume", STA32X_C1VOL, 0, 0xff, 1, chvol_tlv),
451c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Ch2 Volume", STA32X_C2VOL, 0, 0xff, 1, chvol_tlv),
452c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Ch3 Volume", STA32X_C3VOL, 0, 0xff, 1, chvol_tlv),
453c034abf6SJohannes Stezenbach SOC_SINGLE("De-emphasis Filter Switch", STA32X_CONFD, STA32X_CONFD_DEMP_SHIFT, 1, 0),
454c034abf6SJohannes Stezenbach SOC_ENUM("Compressor/Limiter Switch", sta32x_drc_ac_enum),
455c034abf6SJohannes Stezenbach SOC_SINGLE("Miami Mode Switch", STA32X_CONFD, STA32X_CONFD_MME_SHIFT, 1, 0),
456c034abf6SJohannes Stezenbach SOC_SINGLE("Zero Cross Switch", STA32X_CONFE, STA32X_CONFE_ZCE_SHIFT, 1, 0),
457c034abf6SJohannes Stezenbach SOC_SINGLE("Soft Ramp Switch", STA32X_CONFE, STA32X_CONFE_SVE_SHIFT, 1, 0),
458c034abf6SJohannes Stezenbach SOC_SINGLE("Auto-Mute Switch", STA32X_CONFF, STA32X_CONFF_IDE_SHIFT, 1, 0),
459c034abf6SJohannes Stezenbach SOC_ENUM("Automode EQ", sta32x_auto_eq_enum),
460c034abf6SJohannes Stezenbach SOC_ENUM("Automode GC", sta32x_auto_gc_enum),
461c034abf6SJohannes Stezenbach SOC_ENUM("Automode XO", sta32x_auto_xo_enum),
462c034abf6SJohannes Stezenbach SOC_ENUM("Preset EQ", sta32x_preset_eq_enum),
463c034abf6SJohannes Stezenbach SOC_SINGLE("Ch1 Tone Control Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0),
464c034abf6SJohannes Stezenbach SOC_SINGLE("Ch2 Tone Control Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0),
465c034abf6SJohannes Stezenbach SOC_SINGLE("Ch1 EQ Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0),
466c034abf6SJohannes Stezenbach SOC_SINGLE("Ch2 EQ Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0),
467c034abf6SJohannes Stezenbach SOC_SINGLE("Ch1 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0),
468c034abf6SJohannes Stezenbach SOC_SINGLE("Ch2 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0),
469c034abf6SJohannes Stezenbach SOC_SINGLE("Ch3 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0),
470c034abf6SJohannes Stezenbach SOC_ENUM("Ch1 Limiter Select", sta32x_limiter_ch1_enum),
471c034abf6SJohannes Stezenbach SOC_ENUM("Ch2 Limiter Select", sta32x_limiter_ch2_enum),
472c034abf6SJohannes Stezenbach SOC_ENUM("Ch3 Limiter Select", sta32x_limiter_ch3_enum),
473c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Bass Tone Control", STA32X_TONE, STA32X_TONE_BTC_SHIFT, 15, 0, tone_tlv),
474c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Treble Tone Control", STA32X_TONE, STA32X_TONE_TTC_SHIFT, 15, 0, tone_tlv),
475c034abf6SJohannes Stezenbach SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum),
476c034abf6SJohannes Stezenbach SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum),
477c034abf6SJohannes Stezenbach SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum),
478b3619b28STakashi Iwai SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter2_release_rate_enum),
479c034abf6SJohannes Stezenbach 
480c034abf6SJohannes Stezenbach /* depending on mode, the attack/release thresholds have
481c034abf6SJohannes Stezenbach  * two different enum definitions; provide both
482c034abf6SJohannes Stezenbach  */
483c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter1 Attack Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT,
484c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_ac_attack_tlv),
485c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter2 Attack Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT,
486c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_ac_attack_tlv),
487c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter1 Release Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT,
488c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_ac_release_tlv),
489c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter2 Release Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT,
490c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_ac_release_tlv),
491c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter1 Attack Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT,
492c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_drc_attack_tlv),
493c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter2 Attack Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT,
494c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_drc_attack_tlv),
495c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter1 Release Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT,
496c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_drc_release_tlv),
497c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT,
498c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_drc_release_tlv),
49979688439SJohannes Stezenbach 
50079688439SJohannes Stezenbach BIQUAD_COEFS("Ch1 - Biquad 1", 0),
50179688439SJohannes Stezenbach BIQUAD_COEFS("Ch1 - Biquad 2", 5),
50279688439SJohannes Stezenbach BIQUAD_COEFS("Ch1 - Biquad 3", 10),
50379688439SJohannes Stezenbach BIQUAD_COEFS("Ch1 - Biquad 4", 15),
50479688439SJohannes Stezenbach BIQUAD_COEFS("Ch2 - Biquad 1", 20),
50579688439SJohannes Stezenbach BIQUAD_COEFS("Ch2 - Biquad 2", 25),
50679688439SJohannes Stezenbach BIQUAD_COEFS("Ch2 - Biquad 3", 30),
50779688439SJohannes Stezenbach BIQUAD_COEFS("Ch2 - Biquad 4", 35),
50879688439SJohannes Stezenbach BIQUAD_COEFS("High-pass", 40),
50979688439SJohannes Stezenbach BIQUAD_COEFS("Low-pass", 45),
51079688439SJohannes Stezenbach SINGLE_COEF("Ch1 - Prescale", 50),
51179688439SJohannes Stezenbach SINGLE_COEF("Ch2 - Prescale", 51),
51279688439SJohannes Stezenbach SINGLE_COEF("Ch1 - Postscale", 52),
51379688439SJohannes Stezenbach SINGLE_COEF("Ch2 - Postscale", 53),
51479688439SJohannes Stezenbach SINGLE_COEF("Ch3 - Postscale", 54),
51579688439SJohannes Stezenbach SINGLE_COEF("Thermal warning - Postscale", 55),
51679688439SJohannes Stezenbach SINGLE_COEF("Ch1 - Mix 1", 56),
51779688439SJohannes Stezenbach SINGLE_COEF("Ch1 - Mix 2", 57),
51879688439SJohannes Stezenbach SINGLE_COEF("Ch2 - Mix 1", 58),
51979688439SJohannes Stezenbach SINGLE_COEF("Ch2 - Mix 2", 59),
52079688439SJohannes Stezenbach SINGLE_COEF("Ch3 - Mix 1", 60),
52179688439SJohannes Stezenbach SINGLE_COEF("Ch3 - Mix 2", 61),
522c034abf6SJohannes Stezenbach };
523c034abf6SJohannes Stezenbach 
524c034abf6SJohannes Stezenbach static const struct snd_soc_dapm_widget sta32x_dapm_widgets[] = {
525c034abf6SJohannes Stezenbach SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
526c034abf6SJohannes Stezenbach SND_SOC_DAPM_OUTPUT("LEFT"),
527c034abf6SJohannes Stezenbach SND_SOC_DAPM_OUTPUT("RIGHT"),
528c034abf6SJohannes Stezenbach SND_SOC_DAPM_OUTPUT("SUB"),
529c034abf6SJohannes Stezenbach };
530c034abf6SJohannes Stezenbach 
531c034abf6SJohannes Stezenbach static const struct snd_soc_dapm_route sta32x_dapm_routes[] = {
532c034abf6SJohannes Stezenbach 	{ "LEFT", NULL, "DAC" },
533c034abf6SJohannes Stezenbach 	{ "RIGHT", NULL, "DAC" },
534c034abf6SJohannes Stezenbach 	{ "SUB", NULL, "DAC" },
535c034abf6SJohannes Stezenbach };
536c034abf6SJohannes Stezenbach 
537c034abf6SJohannes Stezenbach /* MCLK interpolation ratio per fs */
538c034abf6SJohannes Stezenbach static struct {
539c034abf6SJohannes Stezenbach 	int fs;
540c034abf6SJohannes Stezenbach 	int ir;
541c034abf6SJohannes Stezenbach } interpolation_ratios[] = {
542c034abf6SJohannes Stezenbach 	{ 32000, 0 },
543c034abf6SJohannes Stezenbach 	{ 44100, 0 },
544c034abf6SJohannes Stezenbach 	{ 48000, 0 },
545c034abf6SJohannes Stezenbach 	{ 88200, 1 },
546c034abf6SJohannes Stezenbach 	{ 96000, 1 },
547c034abf6SJohannes Stezenbach 	{ 176400, 2 },
548c034abf6SJohannes Stezenbach 	{ 192000, 2 },
549c034abf6SJohannes Stezenbach };
550c034abf6SJohannes Stezenbach 
551c034abf6SJohannes Stezenbach /* MCLK to fs clock ratios */
5521c34c876SThomas Niederprüm static int mcs_ratio_table[3][7] = {
5531c34c876SThomas Niederprüm 	{ 768, 512, 384, 256, 128, 576, 0 },
5541c34c876SThomas Niederprüm 	{ 384, 256, 192, 128,  64,   0 },
5551c34c876SThomas Niederprüm 	{ 384, 256, 192, 128,  64,   0 },
556c034abf6SJohannes Stezenbach };
557c034abf6SJohannes Stezenbach 
558c034abf6SJohannes Stezenbach /**
559c034abf6SJohannes Stezenbach  * sta32x_set_dai_sysclk - configure MCLK
560c034abf6SJohannes Stezenbach  * @codec_dai: the codec DAI
561c034abf6SJohannes Stezenbach  * @clk_id: the clock ID (ignored)
562c034abf6SJohannes Stezenbach  * @freq: the MCLK input frequency
563c034abf6SJohannes Stezenbach  * @dir: the clock direction (ignored)
564c034abf6SJohannes Stezenbach  *
565c034abf6SJohannes Stezenbach  * The value of MCLK is used to determine which sample rates are supported
566c034abf6SJohannes Stezenbach  * by the STA32X, based on the mclk_ratios table.
567c034abf6SJohannes Stezenbach  *
568c034abf6SJohannes Stezenbach  * This function must be called by the machine driver's 'startup' function,
569c034abf6SJohannes Stezenbach  * otherwise the list of supported sample rates will not be available in
570c034abf6SJohannes Stezenbach  * time for ALSA.
571c034abf6SJohannes Stezenbach  *
572c034abf6SJohannes Stezenbach  * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause
573c034abf6SJohannes Stezenbach  * theoretically possible sample rates to be enabled. Call it again with a
574c034abf6SJohannes Stezenbach  * proper value set one the external clock is set (most probably you would do
575c034abf6SJohannes Stezenbach  * that from a machine's driver 'hw_param' hook.
576c034abf6SJohannes Stezenbach  */
577c034abf6SJohannes Stezenbach static int sta32x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
578c034abf6SJohannes Stezenbach 		int clk_id, unsigned int freq, int dir)
579c034abf6SJohannes Stezenbach {
580ee183590SKuninori Morimoto 	struct snd_soc_component *component = codec_dai->component;
581ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
582c034abf6SJohannes Stezenbach 
583ee183590SKuninori Morimoto 	dev_dbg(component->dev, "mclk=%u\n", freq);
584c034abf6SJohannes Stezenbach 	sta32x->mclk = freq;
585c034abf6SJohannes Stezenbach 
586c034abf6SJohannes Stezenbach 	return 0;
587c034abf6SJohannes Stezenbach }
588c034abf6SJohannes Stezenbach 
589c034abf6SJohannes Stezenbach /**
590c034abf6SJohannes Stezenbach  * sta32x_set_dai_fmt - configure the codec for the selected audio format
591c034abf6SJohannes Stezenbach  * @codec_dai: the codec DAI
592c034abf6SJohannes Stezenbach  * @fmt: a SND_SOC_DAIFMT_x value indicating the data format
593c034abf6SJohannes Stezenbach  *
594c034abf6SJohannes Stezenbach  * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the
595c034abf6SJohannes Stezenbach  * codec accordingly.
596c034abf6SJohannes Stezenbach  */
597c034abf6SJohannes Stezenbach static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai,
598c034abf6SJohannes Stezenbach 			      unsigned int fmt)
599c034abf6SJohannes Stezenbach {
600ee183590SKuninori Morimoto 	struct snd_soc_component *component = codec_dai->component;
601ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
602a1be4ceaSThomas Niederprüm 	u8 confb = 0;
603c034abf6SJohannes Stezenbach 
604ef08b481SMark Brown 	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
605ef08b481SMark Brown 	case SND_SOC_DAIFMT_CBC_CFC:
606c034abf6SJohannes Stezenbach 		break;
607c034abf6SJohannes Stezenbach 	default:
608c034abf6SJohannes Stezenbach 		return -EINVAL;
609c034abf6SJohannes Stezenbach 	}
610c034abf6SJohannes Stezenbach 
611c034abf6SJohannes Stezenbach 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
612c034abf6SJohannes Stezenbach 	case SND_SOC_DAIFMT_I2S:
613c034abf6SJohannes Stezenbach 	case SND_SOC_DAIFMT_RIGHT_J:
614c034abf6SJohannes Stezenbach 	case SND_SOC_DAIFMT_LEFT_J:
615c034abf6SJohannes Stezenbach 		sta32x->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
616c034abf6SJohannes Stezenbach 		break;
617c034abf6SJohannes Stezenbach 	default:
618c034abf6SJohannes Stezenbach 		return -EINVAL;
619c034abf6SJohannes Stezenbach 	}
620c034abf6SJohannes Stezenbach 
621c034abf6SJohannes Stezenbach 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
622c034abf6SJohannes Stezenbach 	case SND_SOC_DAIFMT_NB_NF:
623c034abf6SJohannes Stezenbach 		confb |= STA32X_CONFB_C2IM;
624c034abf6SJohannes Stezenbach 		break;
625c034abf6SJohannes Stezenbach 	case SND_SOC_DAIFMT_NB_IF:
626c034abf6SJohannes Stezenbach 		confb |= STA32X_CONFB_C1IM;
627c034abf6SJohannes Stezenbach 		break;
628c034abf6SJohannes Stezenbach 	default:
629c034abf6SJohannes Stezenbach 		return -EINVAL;
630c034abf6SJohannes Stezenbach 	}
631c034abf6SJohannes Stezenbach 
632a1be4ceaSThomas Niederprüm 	return regmap_update_bits(sta32x->regmap, STA32X_CONFB,
633a1be4ceaSThomas Niederprüm 				  STA32X_CONFB_C1IM | STA32X_CONFB_C2IM, confb);
634c034abf6SJohannes Stezenbach }
635c034abf6SJohannes Stezenbach 
636c034abf6SJohannes Stezenbach /**
637c034abf6SJohannes Stezenbach  * sta32x_hw_params - program the STA32X with the given hardware parameters.
638c034abf6SJohannes Stezenbach  * @substream: the audio stream
639c034abf6SJohannes Stezenbach  * @params: the hardware parameters to set
640c034abf6SJohannes Stezenbach  * @dai: the SOC DAI (ignored)
641c034abf6SJohannes Stezenbach  *
642c034abf6SJohannes Stezenbach  * This function programs the hardware with the values provided.
643c034abf6SJohannes Stezenbach  * Specifically, the sample rate and the data format.
644c034abf6SJohannes Stezenbach  */
645c034abf6SJohannes Stezenbach static int sta32x_hw_params(struct snd_pcm_substream *substream,
646c034abf6SJohannes Stezenbach 			    struct snd_pcm_hw_params *params,
647c034abf6SJohannes Stezenbach 			    struct snd_soc_dai *dai)
648c034abf6SJohannes Stezenbach {
649ee183590SKuninori Morimoto 	struct snd_soc_component *component = dai->component;
650ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
6511c34c876SThomas Niederprüm 	int i, mcs = -EINVAL, ir = -EINVAL;
652a1be4ceaSThomas Niederprüm 	unsigned int confa, confb;
6531c34c876SThomas Niederprüm 	unsigned int rate, ratio;
6541c34c876SThomas Niederprüm 	int ret;
6551c34c876SThomas Niederprüm 
6561c34c876SThomas Niederprüm 	if (!sta32x->mclk) {
657ee183590SKuninori Morimoto 		dev_err(component->dev,
6581c34c876SThomas Niederprüm 			"sta32x->mclk is unset. Unable to determine ratio\n");
6591c34c876SThomas Niederprüm 		return -EIO;
6601c34c876SThomas Niederprüm 	}
661c034abf6SJohannes Stezenbach 
662c034abf6SJohannes Stezenbach 	rate = params_rate(params);
6631c34c876SThomas Niederprüm 	ratio = sta32x->mclk / rate;
664ee183590SKuninori Morimoto 	dev_dbg(component->dev, "rate: %u, ratio: %u\n", rate, ratio);
6651c34c876SThomas Niederprüm 
6661c34c876SThomas Niederprüm 	for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) {
667a595238bSAxel Lin 		if (interpolation_ratios[i].fs == rate) {
668c034abf6SJohannes Stezenbach 			ir = interpolation_ratios[i].ir;
669a595238bSAxel Lin 			break;
670a595238bSAxel Lin 		}
6711c34c876SThomas Niederprüm 	}
6721c34c876SThomas Niederprüm 
6731c34c876SThomas Niederprüm 	if (ir < 0) {
674ee183590SKuninori Morimoto 		dev_err(component->dev, "Unsupported samplerate: %u\n", rate);
675c034abf6SJohannes Stezenbach 		return -EINVAL;
6761c34c876SThomas Niederprüm 	}
6771c34c876SThomas Niederprüm 
6781c34c876SThomas Niederprüm 	for (i = 0; i < 6; i++) {
6791c34c876SThomas Niederprüm 		if (mcs_ratio_table[ir][i] == ratio) {
6801c34c876SThomas Niederprüm 			mcs = i;
681a595238bSAxel Lin 			break;
682a595238bSAxel Lin 		}
6831c34c876SThomas Niederprüm 	}
6841c34c876SThomas Niederprüm 
6851c34c876SThomas Niederprüm 	if (mcs < 0) {
686ee183590SKuninori Morimoto 		dev_err(component->dev, "Unresolvable ratio: %u\n", ratio);
687c034abf6SJohannes Stezenbach 		return -EINVAL;
6881c34c876SThomas Niederprüm 	}
689c034abf6SJohannes Stezenbach 
690a1be4ceaSThomas Niederprüm 	confa = (ir << STA32X_CONFA_IR_SHIFT) |
691a1be4ceaSThomas Niederprüm 		(mcs << STA32X_CONFA_MCS_SHIFT);
692a1be4ceaSThomas Niederprüm 	confb = 0;
693c034abf6SJohannes Stezenbach 
694737e0f89SMark Brown 	switch (params_width(params)) {
695737e0f89SMark Brown 	case 24:
696ee183590SKuninori Morimoto 		dev_dbg(component->dev, "24bit\n");
6973e146b55SGustavo A. R. Silva 		fallthrough;
698737e0f89SMark Brown 	case 32:
699ee183590SKuninori Morimoto 		dev_dbg(component->dev, "24bit or 32bit\n");
700c034abf6SJohannes Stezenbach 		switch (sta32x->format) {
701c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_I2S:
702c034abf6SJohannes Stezenbach 			confb |= 0x0;
703c034abf6SJohannes Stezenbach 			break;
704c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_LEFT_J:
705c034abf6SJohannes Stezenbach 			confb |= 0x1;
706c034abf6SJohannes Stezenbach 			break;
707c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_RIGHT_J:
708c034abf6SJohannes Stezenbach 			confb |= 0x2;
709c034abf6SJohannes Stezenbach 			break;
710c034abf6SJohannes Stezenbach 		}
711c034abf6SJohannes Stezenbach 
712c034abf6SJohannes Stezenbach 		break;
713737e0f89SMark Brown 	case 20:
714ee183590SKuninori Morimoto 		dev_dbg(component->dev, "20bit\n");
715c034abf6SJohannes Stezenbach 		switch (sta32x->format) {
716c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_I2S:
717c034abf6SJohannes Stezenbach 			confb |= 0x4;
718c034abf6SJohannes Stezenbach 			break;
719c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_LEFT_J:
720c034abf6SJohannes Stezenbach 			confb |= 0x5;
721c034abf6SJohannes Stezenbach 			break;
722c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_RIGHT_J:
723c034abf6SJohannes Stezenbach 			confb |= 0x6;
724c034abf6SJohannes Stezenbach 			break;
725c034abf6SJohannes Stezenbach 		}
726c034abf6SJohannes Stezenbach 
727c034abf6SJohannes Stezenbach 		break;
728737e0f89SMark Brown 	case 18:
729ee183590SKuninori Morimoto 		dev_dbg(component->dev, "18bit\n");
730c034abf6SJohannes Stezenbach 		switch (sta32x->format) {
731c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_I2S:
732c034abf6SJohannes Stezenbach 			confb |= 0x8;
733c034abf6SJohannes Stezenbach 			break;
734c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_LEFT_J:
735c034abf6SJohannes Stezenbach 			confb |= 0x9;
736c034abf6SJohannes Stezenbach 			break;
737c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_RIGHT_J:
738c034abf6SJohannes Stezenbach 			confb |= 0xa;
739c034abf6SJohannes Stezenbach 			break;
740c034abf6SJohannes Stezenbach 		}
741c034abf6SJohannes Stezenbach 
742c034abf6SJohannes Stezenbach 		break;
743737e0f89SMark Brown 	case 16:
744ee183590SKuninori Morimoto 		dev_dbg(component->dev, "16bit\n");
745c034abf6SJohannes Stezenbach 		switch (sta32x->format) {
746c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_I2S:
747c034abf6SJohannes Stezenbach 			confb |= 0x0;
748c034abf6SJohannes Stezenbach 			break;
749c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_LEFT_J:
750c034abf6SJohannes Stezenbach 			confb |= 0xd;
751c034abf6SJohannes Stezenbach 			break;
752c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_RIGHT_J:
753c034abf6SJohannes Stezenbach 			confb |= 0xe;
754c034abf6SJohannes Stezenbach 			break;
755c034abf6SJohannes Stezenbach 		}
756c034abf6SJohannes Stezenbach 
757c034abf6SJohannes Stezenbach 		break;
758c034abf6SJohannes Stezenbach 	default:
759c034abf6SJohannes Stezenbach 		return -EINVAL;
760c034abf6SJohannes Stezenbach 	}
761c034abf6SJohannes Stezenbach 
762a1be4ceaSThomas Niederprüm 	ret = regmap_update_bits(sta32x->regmap, STA32X_CONFA,
763a1be4ceaSThomas Niederprüm 				 STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK,
764a1be4ceaSThomas Niederprüm 				 confa);
765a1be4ceaSThomas Niederprüm 	if (ret < 0)
766a1be4ceaSThomas Niederprüm 		return ret;
767a1be4ceaSThomas Niederprüm 
768a1be4ceaSThomas Niederprüm 	ret = regmap_update_bits(sta32x->regmap, STA32X_CONFB,
769a1be4ceaSThomas Niederprüm 				 STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB,
770a1be4ceaSThomas Niederprüm 				 confb);
771a1be4ceaSThomas Niederprüm 	if (ret < 0)
772a1be4ceaSThomas Niederprüm 		return ret;
773a1be4ceaSThomas Niederprüm 
774a1be4ceaSThomas Niederprüm 	return 0;
775a1be4ceaSThomas Niederprüm }
776b66a2980SThomas Niederprüm 
777b66a2980SThomas Niederprüm static int sta32x_startup_sequence(struct sta32x_priv *sta32x)
778b66a2980SThomas Niederprüm {
779b66a2980SThomas Niederprüm 	if (sta32x->gpiod_nreset) {
780b66a2980SThomas Niederprüm 		gpiod_set_value(sta32x->gpiod_nreset, 0);
781b66a2980SThomas Niederprüm 		mdelay(1);
782b66a2980SThomas Niederprüm 		gpiod_set_value(sta32x->gpiod_nreset, 1);
783b66a2980SThomas Niederprüm 		mdelay(1);
784b66a2980SThomas Niederprüm 	}
785b66a2980SThomas Niederprüm 
786c034abf6SJohannes Stezenbach 	return 0;
787c034abf6SJohannes Stezenbach }
788c034abf6SJohannes Stezenbach 
789c034abf6SJohannes Stezenbach /**
790c034abf6SJohannes Stezenbach  * sta32x_set_bias_level - DAPM callback
791ee183590SKuninori Morimoto  * @component: the component device
792c034abf6SJohannes Stezenbach  * @level: DAPM power level
793c034abf6SJohannes Stezenbach  *
794ee183590SKuninori Morimoto  * This is called by ALSA to put the component into low power mode
795ee183590SKuninori Morimoto  * or to wake it up.  If the component is powered off completely
796c034abf6SJohannes Stezenbach  * all registers must be restored after power on.
797c034abf6SJohannes Stezenbach  */
798ee183590SKuninori Morimoto static int sta32x_set_bias_level(struct snd_soc_component *component,
799c034abf6SJohannes Stezenbach 				 enum snd_soc_bias_level level)
800c034abf6SJohannes Stezenbach {
801c034abf6SJohannes Stezenbach 	int ret;
802ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
803c034abf6SJohannes Stezenbach 
804ee183590SKuninori Morimoto 	dev_dbg(component->dev, "level = %d\n", level);
805c034abf6SJohannes Stezenbach 	switch (level) {
806c034abf6SJohannes Stezenbach 	case SND_SOC_BIAS_ON:
807c034abf6SJohannes Stezenbach 		break;
808c034abf6SJohannes Stezenbach 
809c034abf6SJohannes Stezenbach 	case SND_SOC_BIAS_PREPARE:
810c034abf6SJohannes Stezenbach 		/* Full power on */
811a1be4ceaSThomas Niederprüm 		regmap_update_bits(sta32x->regmap, STA32X_CONFF,
812c034abf6SJohannes Stezenbach 				    STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
813c034abf6SJohannes Stezenbach 				    STA32X_CONFF_PWDN | STA32X_CONFF_EAPD);
814c034abf6SJohannes Stezenbach 		break;
815c034abf6SJohannes Stezenbach 
816c034abf6SJohannes Stezenbach 	case SND_SOC_BIAS_STANDBY:
817ee183590SKuninori Morimoto 		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
818c034abf6SJohannes Stezenbach 			ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
819c034abf6SJohannes Stezenbach 						    sta32x->supplies);
820c034abf6SJohannes Stezenbach 			if (ret != 0) {
821ee183590SKuninori Morimoto 				dev_err(component->dev,
822c034abf6SJohannes Stezenbach 					"Failed to enable supplies: %d\n", ret);
823c034abf6SJohannes Stezenbach 				return ret;
824c034abf6SJohannes Stezenbach 			}
825c034abf6SJohannes Stezenbach 
826b66a2980SThomas Niederprüm 			sta32x_startup_sequence(sta32x);
827ee183590SKuninori Morimoto 			sta32x_cache_sync(component);
8283fb5eac5SJohannes Stezenbach 			sta32x_watchdog_start(sta32x);
829c034abf6SJohannes Stezenbach 		}
830c034abf6SJohannes Stezenbach 
831a1be4ceaSThomas Niederprüm 		/* Power down */
832a1be4ceaSThomas Niederprüm 		regmap_update_bits(sta32x->regmap, STA32X_CONFF,
833c034abf6SJohannes Stezenbach 				   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
834a1be4ceaSThomas Niederprüm 				   0);
835c034abf6SJohannes Stezenbach 
836c034abf6SJohannes Stezenbach 		break;
837c034abf6SJohannes Stezenbach 
838c034abf6SJohannes Stezenbach 	case SND_SOC_BIAS_OFF:
839c034abf6SJohannes Stezenbach 		/* The chip runs through the power down sequence for us. */
840a1be4ceaSThomas Niederprüm 		regmap_update_bits(sta32x->regmap, STA32X_CONFF,
841a1be4ceaSThomas Niederprüm 				   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, 0);
842c034abf6SJohannes Stezenbach 		msleep(300);
8433fb5eac5SJohannes Stezenbach 		sta32x_watchdog_stop(sta32x);
844b66a2980SThomas Niederprüm 
845b66a2980SThomas Niederprüm 		gpiod_set_value(sta32x->gpiod_nreset, 0);
846b66a2980SThomas Niederprüm 
847c034abf6SJohannes Stezenbach 		regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies),
848c034abf6SJohannes Stezenbach 				       sta32x->supplies);
849c034abf6SJohannes Stezenbach 		break;
850c034abf6SJohannes Stezenbach 	}
851c034abf6SJohannes Stezenbach 	return 0;
852c034abf6SJohannes Stezenbach }
853c034abf6SJohannes Stezenbach 
85485e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops sta32x_dai_ops = {
855c034abf6SJohannes Stezenbach 	.hw_params	= sta32x_hw_params,
856c034abf6SJohannes Stezenbach 	.set_sysclk	= sta32x_set_dai_sysclk,
857c034abf6SJohannes Stezenbach 	.set_fmt	= sta32x_set_dai_fmt,
858c034abf6SJohannes Stezenbach };
859c034abf6SJohannes Stezenbach 
860c034abf6SJohannes Stezenbach static struct snd_soc_dai_driver sta32x_dai = {
8613c9390adSThomas Niederprüm 	.name = "sta32x-hifi",
862c034abf6SJohannes Stezenbach 	.playback = {
863c034abf6SJohannes Stezenbach 		.stream_name = "Playback",
864c034abf6SJohannes Stezenbach 		.channels_min = 2,
865c034abf6SJohannes Stezenbach 		.channels_max = 2,
866c034abf6SJohannes Stezenbach 		.rates = STA32X_RATES,
867c034abf6SJohannes Stezenbach 		.formats = STA32X_FORMATS,
868c034abf6SJohannes Stezenbach 	},
869c034abf6SJohannes Stezenbach 	.ops = &sta32x_dai_ops,
870c034abf6SJohannes Stezenbach };
871c034abf6SJohannes Stezenbach 
872ee183590SKuninori Morimoto static int sta32x_probe(struct snd_soc_component *component)
873c034abf6SJohannes Stezenbach {
874ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
875a1be4ceaSThomas Niederprüm 	struct sta32x_platform_data *pdata = sta32x->pdata;
876e012ba24SJohannes Stezenbach 	int i, ret = 0, thermal = 0;
877fce9ec95SDaniel Mack 
878fce9ec95SDaniel Mack 	sta32x->component = component;
879fce9ec95SDaniel Mack 
880fce9ec95SDaniel Mack 	if (sta32x->xti_clk) {
881fce9ec95SDaniel Mack 		ret = clk_prepare_enable(sta32x->xti_clk);
882fce9ec95SDaniel Mack 		if (ret != 0) {
883fce9ec95SDaniel Mack 			dev_err(component->dev,
884fce9ec95SDaniel Mack 				"Failed to enable clock: %d\n", ret);
885fce9ec95SDaniel Mack 			return ret;
886fce9ec95SDaniel Mack 		}
887fce9ec95SDaniel Mack 	}
888fce9ec95SDaniel Mack 
889c034abf6SJohannes Stezenbach 	ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
890c034abf6SJohannes Stezenbach 				    sta32x->supplies);
891c034abf6SJohannes Stezenbach 	if (ret != 0) {
892ee183590SKuninori Morimoto 		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
8938dc10114SChuhong Yuan 		goto err_clk_disable_unprepare;
894c034abf6SJohannes Stezenbach 	}
895c034abf6SJohannes Stezenbach 
896b66a2980SThomas Niederprüm 	ret = sta32x_startup_sequence(sta32x);
897b66a2980SThomas Niederprüm 	if (ret < 0) {
898ee183590SKuninori Morimoto 		dev_err(component->dev, "Failed to startup device\n");
8998dc10114SChuhong Yuan 		goto err_regulator_bulk_disable;
900b66a2980SThomas Niederprüm 	}
901f04b1e76SThomas Niederprüm 
902f04b1e76SThomas Niederprüm 	/* CONFA */
903a1be4ceaSThomas Niederprüm 	if (!pdata->thermal_warning_recovery)
904e012ba24SJohannes Stezenbach 		thermal |= STA32X_CONFA_TWAB;
905a1be4ceaSThomas Niederprüm 	if (!pdata->thermal_warning_adjustment)
906e012ba24SJohannes Stezenbach 		thermal |= STA32X_CONFA_TWRB;
907f04b1e76SThomas Niederprüm 	if (!pdata->fault_detect_recovery)
908f04b1e76SThomas Niederprüm 		thermal |= STA32X_CONFA_FDRB;
909a1be4ceaSThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFA,
910f04b1e76SThomas Niederprüm 			   STA32X_CONFA_TWAB | STA32X_CONFA_TWRB |
911f04b1e76SThomas Niederprüm 			   STA32X_CONFA_FDRB,
912e012ba24SJohannes Stezenbach 			   thermal);
913c034abf6SJohannes Stezenbach 
914f04b1e76SThomas Niederprüm 	/* CONFC */
915f04b1e76SThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFC,
916f04b1e76SThomas Niederprüm 			   STA32X_CONFC_CSZ_MASK,
917f04b1e76SThomas Niederprüm 			   pdata->drop_compensation_ns
918f04b1e76SThomas Niederprüm 				<< STA32X_CONFC_CSZ_SHIFT);
919f04b1e76SThomas Niederprüm 
920f04b1e76SThomas Niederprüm 	/* CONFE */
921f04b1e76SThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
922f04b1e76SThomas Niederprüm 			   STA32X_CONFE_MPCV,
923f04b1e76SThomas Niederprüm 			   pdata->max_power_use_mpcc ?
924f04b1e76SThomas Niederprüm 				STA32X_CONFE_MPCV : 0);
925f04b1e76SThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
926f04b1e76SThomas Niederprüm 			   STA32X_CONFE_MPC,
927f04b1e76SThomas Niederprüm 			   pdata->max_power_correction ?
928f04b1e76SThomas Niederprüm 				STA32X_CONFE_MPC : 0);
929f04b1e76SThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
930f04b1e76SThomas Niederprüm 			   STA32X_CONFE_AME,
931f04b1e76SThomas Niederprüm 			   pdata->am_reduction_mode ?
932f04b1e76SThomas Niederprüm 				STA32X_CONFE_AME : 0);
933f04b1e76SThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
934f04b1e76SThomas Niederprüm 			   STA32X_CONFE_PWMS,
935f04b1e76SThomas Niederprüm 			   pdata->odd_pwm_speed_mode ?
936f04b1e76SThomas Niederprüm 				STA32X_CONFE_PWMS : 0);
937f04b1e76SThomas Niederprüm 
938f04b1e76SThomas Niederprüm 	/*  CONFF */
939f04b1e76SThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFF,
940f04b1e76SThomas Niederprüm 			   STA32X_CONFF_IDE,
941f04b1e76SThomas Niederprüm 			   pdata->invalid_input_detect_mute ?
942f04b1e76SThomas Niederprüm 				STA32X_CONFF_IDE : 0);
943f04b1e76SThomas Niederprüm 
944e012ba24SJohannes Stezenbach 	/* select output configuration  */
945a1be4ceaSThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFF,
946c034abf6SJohannes Stezenbach 			   STA32X_CONFF_OCFG_MASK,
947a1be4ceaSThomas Niederprüm 			   pdata->output_conf
948e012ba24SJohannes Stezenbach 				<< STA32X_CONFF_OCFG_SHIFT);
949c034abf6SJohannes Stezenbach 
950e012ba24SJohannes Stezenbach 	/* channel to output mapping */
951a1be4ceaSThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_C1CFG,
952c034abf6SJohannes Stezenbach 			   STA32X_CxCFG_OM_MASK,
953a1be4ceaSThomas Niederprüm 			   pdata->ch1_output_mapping
954e012ba24SJohannes Stezenbach 				<< STA32X_CxCFG_OM_SHIFT);
955a1be4ceaSThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_C2CFG,
956c034abf6SJohannes Stezenbach 			   STA32X_CxCFG_OM_MASK,
957a1be4ceaSThomas Niederprüm 			   pdata->ch2_output_mapping
958e012ba24SJohannes Stezenbach 				<< STA32X_CxCFG_OM_SHIFT);
959a1be4ceaSThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_C3CFG,
960c034abf6SJohannes Stezenbach 			   STA32X_CxCFG_OM_MASK,
961a1be4ceaSThomas Niederprüm 			   pdata->ch3_output_mapping
962e012ba24SJohannes Stezenbach 				<< STA32X_CxCFG_OM_SHIFT);
963c034abf6SJohannes Stezenbach 
96454dc6cabSJohannes Stezenbach 	/* initialize coefficient shadow RAM with reset values */
96554dc6cabSJohannes Stezenbach 	for (i = 4; i <= 49; i += 5)
96654dc6cabSJohannes Stezenbach 		sta32x->coef_shadow[i] = 0x400000;
96754dc6cabSJohannes Stezenbach 	for (i = 50; i <= 54; i++)
96854dc6cabSJohannes Stezenbach 		sta32x->coef_shadow[i] = 0x7fffff;
96954dc6cabSJohannes Stezenbach 	sta32x->coef_shadow[55] = 0x5a9df7;
97054dc6cabSJohannes Stezenbach 	sta32x->coef_shadow[56] = 0x7fffff;
97154dc6cabSJohannes Stezenbach 	sta32x->coef_shadow[59] = 0x7fffff;
97254dc6cabSJohannes Stezenbach 	sta32x->coef_shadow[60] = 0x400000;
97354dc6cabSJohannes Stezenbach 	sta32x->coef_shadow[61] = 0x400000;
97454dc6cabSJohannes Stezenbach 
9753fb5eac5SJohannes Stezenbach 	if (sta32x->pdata->needs_esd_watchdog)
9763fb5eac5SJohannes Stezenbach 		INIT_DELAYED_WORK(&sta32x->watchdog_work, sta32x_watchdog);
9773fb5eac5SJohannes Stezenbach 
978ee183590SKuninori Morimoto 	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
979c034abf6SJohannes Stezenbach 	/* Bias level configuration will have done an extra enable */
980c034abf6SJohannes Stezenbach 	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
981c034abf6SJohannes Stezenbach 
982c034abf6SJohannes Stezenbach 	return 0;
9838dc10114SChuhong Yuan 
9848dc10114SChuhong Yuan err_regulator_bulk_disable:
9858dc10114SChuhong Yuan 	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
9868dc10114SChuhong Yuan err_clk_disable_unprepare:
9878dc10114SChuhong Yuan 	if (sta32x->xti_clk)
9888dc10114SChuhong Yuan 		clk_disable_unprepare(sta32x->xti_clk);
9898dc10114SChuhong Yuan 	return ret;
990c034abf6SJohannes Stezenbach }
991c034abf6SJohannes Stezenbach 
992ee183590SKuninori Morimoto static void sta32x_remove(struct snd_soc_component *component)
993c034abf6SJohannes Stezenbach {
994ee183590SKuninori Morimoto 	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
995c034abf6SJohannes Stezenbach 
9963fb5eac5SJohannes Stezenbach 	sta32x_watchdog_stop(sta32x);
997c034abf6SJohannes Stezenbach 	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
998fce9ec95SDaniel Mack 
999fce9ec95SDaniel Mack 	if (sta32x->xti_clk)
1000fce9ec95SDaniel Mack 		clk_disable_unprepare(sta32x->xti_clk);
1001c034abf6SJohannes Stezenbach }
1002c034abf6SJohannes Stezenbach 
1003ee183590SKuninori Morimoto static const struct snd_soc_component_driver sta32x_component = {
1004c034abf6SJohannes Stezenbach 	.probe			= sta32x_probe,
1005c034abf6SJohannes Stezenbach 	.remove			= sta32x_remove,
1006c034abf6SJohannes Stezenbach 	.set_bias_level		= sta32x_set_bias_level,
1007c034abf6SJohannes Stezenbach 	.controls		= sta32x_snd_controls,
1008c034abf6SJohannes Stezenbach 	.num_controls		= ARRAY_SIZE(sta32x_snd_controls),
1009c034abf6SJohannes Stezenbach 	.dapm_widgets		= sta32x_dapm_widgets,
1010c034abf6SJohannes Stezenbach 	.num_dapm_widgets	= ARRAY_SIZE(sta32x_dapm_widgets),
1011c034abf6SJohannes Stezenbach 	.dapm_routes		= sta32x_dapm_routes,
1012c034abf6SJohannes Stezenbach 	.num_dapm_routes	= ARRAY_SIZE(sta32x_dapm_routes),
1013ee183590SKuninori Morimoto 	.suspend_bias_off	= 1,
1014ee183590SKuninori Morimoto 	.idle_bias_on		= 1,
1015ee183590SKuninori Morimoto 	.use_pmdown_time	= 1,
1016ee183590SKuninori Morimoto 	.endianness		= 1,
1017c034abf6SJohannes Stezenbach };
1018c034abf6SJohannes Stezenbach 
101929fdf4fbSMark Brown static const struct regmap_config sta32x_regmap = {
102029fdf4fbSMark Brown 	.reg_bits =		8,
102129fdf4fbSMark Brown 	.val_bits =		8,
102229fdf4fbSMark Brown 	.max_register =		STA32X_FDRC2,
102329fdf4fbSMark Brown 	.reg_defaults =		sta32x_regs,
102429fdf4fbSMark Brown 	.num_reg_defaults =	ARRAY_SIZE(sta32x_regs),
102529fdf4fbSMark Brown 	.cache_type =		REGCACHE_RBTREE,
1026a1be4ceaSThomas Niederprüm 	.wr_table =		&sta32x_write_regs,
1027a1be4ceaSThomas Niederprüm 	.rd_table =		&sta32x_read_regs,
1028a1be4ceaSThomas Niederprüm 	.volatile_table =	&sta32x_volatile_regs,
1029a1be4ceaSThomas Niederprüm };
1030f04b1e76SThomas Niederprüm 
1031f04b1e76SThomas Niederprüm #ifdef CONFIG_OF
1032f04b1e76SThomas Niederprüm static const struct of_device_id st32x_dt_ids[] = {
1033f04b1e76SThomas Niederprüm 	{ .compatible = "st,sta32x", },
1034f04b1e76SThomas Niederprüm 	{ }
103529fdf4fbSMark Brown };
1036f04b1e76SThomas Niederprüm MODULE_DEVICE_TABLE(of, st32x_dt_ids);
1037f04b1e76SThomas Niederprüm 
1038f04b1e76SThomas Niederprüm static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x)
1039f04b1e76SThomas Niederprüm {
1040f04b1e76SThomas Niederprüm 	struct device_node *np = dev->of_node;
1041f04b1e76SThomas Niederprüm 	struct sta32x_platform_data *pdata;
1042f04b1e76SThomas Niederprüm 	u16 tmp;
1043f04b1e76SThomas Niederprüm 
1044f04b1e76SThomas Niederprüm 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
1045f04b1e76SThomas Niederprüm 	if (!pdata)
1046f04b1e76SThomas Niederprüm 		return -ENOMEM;
1047f04b1e76SThomas Niederprüm 
1048f04b1e76SThomas Niederprüm 	of_property_read_u8(np, "st,output-conf",
1049f04b1e76SThomas Niederprüm 			    &pdata->output_conf);
1050f04b1e76SThomas Niederprüm 	of_property_read_u8(np, "st,ch1-output-mapping",
1051f04b1e76SThomas Niederprüm 			    &pdata->ch1_output_mapping);
1052f04b1e76SThomas Niederprüm 	of_property_read_u8(np, "st,ch2-output-mapping",
1053f04b1e76SThomas Niederprüm 			    &pdata->ch2_output_mapping);
1054f04b1e76SThomas Niederprüm 	of_property_read_u8(np, "st,ch3-output-mapping",
1055f04b1e76SThomas Niederprüm 			    &pdata->ch3_output_mapping);
1056f04b1e76SThomas Niederprüm 
10572d2998b8SRob Herring 	pdata->fault_detect_recovery =
10582d2998b8SRob Herring 		of_property_read_bool(np, "st,fault-detect-recovery");
10592d2998b8SRob Herring 	pdata->thermal_warning_recovery =
10602d2998b8SRob Herring 		of_property_read_bool(np, "st,thermal-warning-recovery");
10612d2998b8SRob Herring 	pdata->thermal_warning_adjustment =
10622d2998b8SRob Herring 		of_property_read_bool(np, "st,thermal-warning-adjustment");
10632d2998b8SRob Herring 	pdata->needs_esd_watchdog =
10642d2998b8SRob Herring 		of_property_read_bool(np, "st,needs_esd_watchdog");
1065f04b1e76SThomas Niederprüm 
1066f04b1e76SThomas Niederprüm 	tmp = 140;
1067f04b1e76SThomas Niederprüm 	of_property_read_u16(np, "st,drop-compensation-ns", &tmp);
1068f04b1e76SThomas Niederprüm 	pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20;
1069f04b1e76SThomas Niederprüm 
1070f04b1e76SThomas Niederprüm 	/* CONFE */
10712d2998b8SRob Herring 	pdata->max_power_use_mpcc =
10722d2998b8SRob Herring 		of_property_read_bool(np, "st,max-power-use-mpcc");
10732d2998b8SRob Herring 	pdata->max_power_correction =
10742d2998b8SRob Herring 		of_property_read_bool(np, "st,max-power-correction");
10752d2998b8SRob Herring 	pdata->am_reduction_mode =
10762d2998b8SRob Herring 		of_property_read_bool(np, "st,am-reduction-mode");
10772d2998b8SRob Herring 	pdata->odd_pwm_speed_mode =
10782d2998b8SRob Herring 		of_property_read_bool(np, "st,odd-pwm-speed-mode");
1079f04b1e76SThomas Niederprüm 
1080f04b1e76SThomas Niederprüm 	/* CONFF */
10812d2998b8SRob Herring 	pdata->invalid_input_detect_mute =
10822d2998b8SRob Herring 		of_property_read_bool(np, "st,invalid-input-detect-mute");
1083f04b1e76SThomas Niederprüm 
1084f04b1e76SThomas Niederprüm 	sta32x->pdata = pdata;
1085f04b1e76SThomas Niederprüm 
1086f04b1e76SThomas Niederprüm 	return 0;
1087f04b1e76SThomas Niederprüm }
1088f04b1e76SThomas Niederprüm #endif
108929fdf4fbSMark Brown 
10906f51c158SStephen Kitt static int sta32x_i2c_probe(struct i2c_client *i2c)
1091c034abf6SJohannes Stezenbach {
1092a1be4ceaSThomas Niederprüm 	struct device *dev = &i2c->dev;
1093c034abf6SJohannes Stezenbach 	struct sta32x_priv *sta32x;
1094aff041afSMark Brown 	int ret, i;
1095c034abf6SJohannes Stezenbach 
1096d999c021SAxel Lin 	sta32x = devm_kzalloc(&i2c->dev, sizeof(struct sta32x_priv),
1097d999c021SAxel Lin 			      GFP_KERNEL);
1098c034abf6SJohannes Stezenbach 	if (!sta32x)
1099c034abf6SJohannes Stezenbach 		return -ENOMEM;
1100c034abf6SJohannes Stezenbach 
1101a1be4ceaSThomas Niederprüm 	mutex_init(&sta32x->coeff_lock);
1102a1be4ceaSThomas Niederprüm 	sta32x->pdata = dev_get_platdata(dev);
1103b66a2980SThomas Niederprüm 
1104f04b1e76SThomas Niederprüm #ifdef CONFIG_OF
1105f04b1e76SThomas Niederprüm 	if (dev->of_node) {
1106f04b1e76SThomas Niederprüm 		ret = sta32x_probe_dt(dev, sta32x);
1107f04b1e76SThomas Niederprüm 		if (ret < 0)
1108f04b1e76SThomas Niederprüm 			return ret;
1109f04b1e76SThomas Niederprüm 	}
1110f04b1e76SThomas Niederprüm #endif
1111f04b1e76SThomas Niederprüm 
1112fce9ec95SDaniel Mack 	/* Clock */
1113fce9ec95SDaniel Mack 	sta32x->xti_clk = devm_clk_get(dev, "xti");
1114fce9ec95SDaniel Mack 	if (IS_ERR(sta32x->xti_clk)) {
1115fce9ec95SDaniel Mack 		ret = PTR_ERR(sta32x->xti_clk);
1116fce9ec95SDaniel Mack 
1117fce9ec95SDaniel Mack 		if (ret == -EPROBE_DEFER)
1118fce9ec95SDaniel Mack 			return ret;
1119fce9ec95SDaniel Mack 
1120fce9ec95SDaniel Mack 		sta32x->xti_clk = NULL;
1121fce9ec95SDaniel Mack 	}
1122fce9ec95SDaniel Mack 
1123b66a2980SThomas Niederprüm 	/* GPIOs */
11241137e580SUwe Kleine-König 	sta32x->gpiod_nreset = devm_gpiod_get_optional(dev, "reset",
11251137e580SUwe Kleine-König 						       GPIOD_OUT_LOW);
11261137e580SUwe Kleine-König 	if (IS_ERR(sta32x->gpiod_nreset))
11271137e580SUwe Kleine-König 		return PTR_ERR(sta32x->gpiod_nreset);
1128b66a2980SThomas Niederprüm 
1129aff041afSMark Brown 	/* regulators */
1130aff041afSMark Brown 	for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++)
1131aff041afSMark Brown 		sta32x->supplies[i].supply = sta32x_supply_names[i];
1132aff041afSMark Brown 
1133aff041afSMark Brown 	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(sta32x->supplies),
1134aff041afSMark Brown 				      sta32x->supplies);
1135aff041afSMark Brown 	if (ret != 0) {
1136aff041afSMark Brown 		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
1137aff041afSMark Brown 		return ret;
1138aff041afSMark Brown 	}
1139aff041afSMark Brown 
114029fdf4fbSMark Brown 	sta32x->regmap = devm_regmap_init_i2c(i2c, &sta32x_regmap);
114129fdf4fbSMark Brown 	if (IS_ERR(sta32x->regmap)) {
114229fdf4fbSMark Brown 		ret = PTR_ERR(sta32x->regmap);
1143a1be4ceaSThomas Niederprüm 		dev_err(dev, "Failed to init regmap: %d\n", ret);
114429fdf4fbSMark Brown 		return ret;
114529fdf4fbSMark Brown 	}
114629fdf4fbSMark Brown 
1147c034abf6SJohannes Stezenbach 	i2c_set_clientdata(i2c, sta32x);
1148c034abf6SJohannes Stezenbach 
1149ee183590SKuninori Morimoto 	ret = devm_snd_soc_register_component(dev, &sta32x_component,
1150ee183590SKuninori Morimoto 					      &sta32x_dai, 1);
1151a1be4ceaSThomas Niederprüm 	if (ret < 0)
1152ee183590SKuninori Morimoto 		dev_err(dev, "Failed to register component (%d)\n", ret);
1153c034abf6SJohannes Stezenbach 
1154d999c021SAxel Lin 	return ret;
1155c034abf6SJohannes Stezenbach }
1156c034abf6SJohannes Stezenbach 
1157c034abf6SJohannes Stezenbach static const struct i2c_device_id sta32x_i2c_id[] = {
1158c034abf6SJohannes Stezenbach 	{ "sta326", 0 },
1159c034abf6SJohannes Stezenbach 	{ "sta328", 0 },
1160c034abf6SJohannes Stezenbach 	{ "sta329", 0 },
1161c034abf6SJohannes Stezenbach 	{ }
1162c034abf6SJohannes Stezenbach };
1163c034abf6SJohannes Stezenbach MODULE_DEVICE_TABLE(i2c, sta32x_i2c_id);
1164c034abf6SJohannes Stezenbach 
1165c034abf6SJohannes Stezenbach static struct i2c_driver sta32x_i2c_driver = {
1166c034abf6SJohannes Stezenbach 	.driver = {
1167c034abf6SJohannes Stezenbach 		.name = "sta32x",
1168f04b1e76SThomas Niederprüm 		.of_match_table = of_match_ptr(st32x_dt_ids),
1169c034abf6SJohannes Stezenbach 	},
1170*9abcd240SUwe Kleine-König 	.probe = sta32x_i2c_probe,
1171c034abf6SJohannes Stezenbach 	.id_table = sta32x_i2c_id,
1172c034abf6SJohannes Stezenbach };
1173c034abf6SJohannes Stezenbach 
11740ead1136SSachin Kamat module_i2c_driver(sta32x_i2c_driver);
1175c034abf6SJohannes Stezenbach 
1176c034abf6SJohannes Stezenbach MODULE_DESCRIPTION("ASoC STA32X driver");
1177c034abf6SJohannes Stezenbach MODULE_AUTHOR("Johannes Stezenbach <js@sig21.net>");
1178c034abf6SJohannes Stezenbach MODULE_LICENSE("GPL");
1179