xref: /linux/sound/soc/codecs/sta32x.c (revision f04b1e760a51120f358826d815d12c3f8ecdf1b4)
1c034abf6SJohannes Stezenbach /*
2c034abf6SJohannes Stezenbach  * Codec driver for ST STA32x 2.1-channel high-efficiency digital audio system
3c034abf6SJohannes Stezenbach  *
4c034abf6SJohannes Stezenbach  * Copyright: 2011 Raumfeld GmbH
5c034abf6SJohannes Stezenbach  * Author: Johannes Stezenbach <js@sig21.net>
6c034abf6SJohannes Stezenbach  *
7c034abf6SJohannes Stezenbach  * based on code from:
8c034abf6SJohannes Stezenbach  *	Wolfson Microelectronics PLC.
9c034abf6SJohannes Stezenbach  *	  Mark Brown <broonie@opensource.wolfsonmicro.com>
10c034abf6SJohannes Stezenbach  *	Freescale Semiconductor, Inc.
11c034abf6SJohannes Stezenbach  *	  Timur Tabi <timur@freescale.com>
12c034abf6SJohannes Stezenbach  *
13c034abf6SJohannes Stezenbach  * This program is free software; you can redistribute  it and/or modify it
14c034abf6SJohannes Stezenbach  * under  the terms of  the GNU General  Public License as published by the
15c034abf6SJohannes Stezenbach  * Free Software Foundation;  either version 2 of the  License, or (at your
16c034abf6SJohannes Stezenbach  * option) any later version.
17c034abf6SJohannes Stezenbach  */
18c034abf6SJohannes Stezenbach 
19c034abf6SJohannes Stezenbach #define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__
20c034abf6SJohannes Stezenbach 
21c034abf6SJohannes Stezenbach #include <linux/module.h>
22c034abf6SJohannes Stezenbach #include <linux/moduleparam.h>
23c034abf6SJohannes Stezenbach #include <linux/init.h>
24c034abf6SJohannes Stezenbach #include <linux/delay.h>
25c034abf6SJohannes Stezenbach #include <linux/pm.h>
26c034abf6SJohannes Stezenbach #include <linux/i2c.h>
27*f04b1e76SThomas Niederprüm #include <linux/of_device.h>
28*f04b1e76SThomas Niederprüm #include <linux/of_gpio.h>
2929fdf4fbSMark Brown #include <linux/regmap.h>
30c034abf6SJohannes Stezenbach #include <linux/regulator/consumer.h>
31b66a2980SThomas Niederprüm #include <linux/gpio/consumer.h>
32c034abf6SJohannes Stezenbach #include <linux/slab.h>
333fb5eac5SJohannes Stezenbach #include <linux/workqueue.h>
34c034abf6SJohannes Stezenbach #include <sound/core.h>
35c034abf6SJohannes Stezenbach #include <sound/pcm.h>
36c034abf6SJohannes Stezenbach #include <sound/pcm_params.h>
37c034abf6SJohannes Stezenbach #include <sound/soc.h>
38c034abf6SJohannes Stezenbach #include <sound/soc-dapm.h>
39c034abf6SJohannes Stezenbach #include <sound/initval.h>
40c034abf6SJohannes Stezenbach #include <sound/tlv.h>
41c034abf6SJohannes Stezenbach 
42e012ba24SJohannes Stezenbach #include <sound/sta32x.h>
43c034abf6SJohannes Stezenbach #include "sta32x.h"
44c034abf6SJohannes Stezenbach 
45c034abf6SJohannes Stezenbach #define STA32X_RATES (SNDRV_PCM_RATE_32000 | \
46c034abf6SJohannes Stezenbach 		      SNDRV_PCM_RATE_44100 | \
47c034abf6SJohannes Stezenbach 		      SNDRV_PCM_RATE_48000 | \
48c034abf6SJohannes Stezenbach 		      SNDRV_PCM_RATE_88200 | \
49c034abf6SJohannes Stezenbach 		      SNDRV_PCM_RATE_96000 | \
50c034abf6SJohannes Stezenbach 		      SNDRV_PCM_RATE_176400 | \
51c034abf6SJohannes Stezenbach 		      SNDRV_PCM_RATE_192000)
52c034abf6SJohannes Stezenbach 
53c034abf6SJohannes Stezenbach #define STA32X_FORMATS \
54c034abf6SJohannes Stezenbach 	(SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \
55c034abf6SJohannes Stezenbach 	 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
56c034abf6SJohannes Stezenbach 	 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
57c034abf6SJohannes Stezenbach 	 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
58c034abf6SJohannes Stezenbach 	 SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE  | \
59c034abf6SJohannes Stezenbach 	 SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_S32_BE)
60c034abf6SJohannes Stezenbach 
61c034abf6SJohannes Stezenbach /* Power-up register defaults */
6229fdf4fbSMark Brown static const struct reg_default sta32x_regs[] = {
6329fdf4fbSMark Brown 	{  0x0, 0x63 },
6429fdf4fbSMark Brown 	{  0x1, 0x80 },
6529fdf4fbSMark Brown 	{  0x2, 0xc2 },
6629fdf4fbSMark Brown 	{  0x3, 0x40 },
6729fdf4fbSMark Brown 	{  0x4, 0xc2 },
6829fdf4fbSMark Brown 	{  0x5, 0x5c },
6929fdf4fbSMark Brown 	{  0x6, 0x10 },
7029fdf4fbSMark Brown 	{  0x7, 0xff },
7129fdf4fbSMark Brown 	{  0x8, 0x60 },
7229fdf4fbSMark Brown 	{  0x9, 0x60 },
7329fdf4fbSMark Brown 	{  0xa, 0x60 },
7429fdf4fbSMark Brown 	{  0xb, 0x80 },
7529fdf4fbSMark Brown 	{  0xc, 0x00 },
7629fdf4fbSMark Brown 	{  0xd, 0x00 },
7729fdf4fbSMark Brown 	{  0xe, 0x00 },
7829fdf4fbSMark Brown 	{  0xf, 0x40 },
7929fdf4fbSMark Brown 	{ 0x10, 0x80 },
8029fdf4fbSMark Brown 	{ 0x11, 0x77 },
8129fdf4fbSMark Brown 	{ 0x12, 0x6a },
8229fdf4fbSMark Brown 	{ 0x13, 0x69 },
8329fdf4fbSMark Brown 	{ 0x14, 0x6a },
8429fdf4fbSMark Brown 	{ 0x15, 0x69 },
8529fdf4fbSMark Brown 	{ 0x16, 0x00 },
8629fdf4fbSMark Brown 	{ 0x17, 0x00 },
8729fdf4fbSMark Brown 	{ 0x18, 0x00 },
8829fdf4fbSMark Brown 	{ 0x19, 0x00 },
8929fdf4fbSMark Brown 	{ 0x1a, 0x00 },
9029fdf4fbSMark Brown 	{ 0x1b, 0x00 },
9129fdf4fbSMark Brown 	{ 0x1c, 0x00 },
9229fdf4fbSMark Brown 	{ 0x1d, 0x00 },
9329fdf4fbSMark Brown 	{ 0x1e, 0x00 },
9429fdf4fbSMark Brown 	{ 0x1f, 0x00 },
9529fdf4fbSMark Brown 	{ 0x20, 0x00 },
9629fdf4fbSMark Brown 	{ 0x21, 0x00 },
9729fdf4fbSMark Brown 	{ 0x22, 0x00 },
9829fdf4fbSMark Brown 	{ 0x23, 0x00 },
9929fdf4fbSMark Brown 	{ 0x24, 0x00 },
10029fdf4fbSMark Brown 	{ 0x25, 0x00 },
10129fdf4fbSMark Brown 	{ 0x26, 0x00 },
10229fdf4fbSMark Brown 	{ 0x27, 0x2d },
10329fdf4fbSMark Brown 	{ 0x28, 0xc0 },
10429fdf4fbSMark Brown 	{ 0x2b, 0x00 },
10529fdf4fbSMark Brown 	{ 0x2c, 0x0c },
106c034abf6SJohannes Stezenbach };
107c034abf6SJohannes Stezenbach 
108a1be4ceaSThomas Niederprüm static const struct regmap_range sta32x_write_regs_range[] = {
109a1be4ceaSThomas Niederprüm 	regmap_reg_range(STA32X_CONFA,  STA32X_AUTO2),
110a1be4ceaSThomas Niederprüm 	regmap_reg_range(STA32X_C1CFG,  STA32X_FDRC2),
111a1be4ceaSThomas Niederprüm };
112a1be4ceaSThomas Niederprüm 
113a1be4ceaSThomas Niederprüm static const struct regmap_range sta32x_read_regs_range[] = {
114a1be4ceaSThomas Niederprüm 	regmap_reg_range(STA32X_CONFA,  STA32X_AUTO2),
115a1be4ceaSThomas Niederprüm 	regmap_reg_range(STA32X_C1CFG,  STA32X_FDRC2),
116a1be4ceaSThomas Niederprüm };
117a1be4ceaSThomas Niederprüm 
118a1be4ceaSThomas Niederprüm static const struct regmap_range sta32x_volatile_regs_range[] = {
119a1be4ceaSThomas Niederprüm 	regmap_reg_range(STA32X_CFADDR2, STA32X_CFUD),
120a1be4ceaSThomas Niederprüm };
121a1be4ceaSThomas Niederprüm 
122a1be4ceaSThomas Niederprüm static const struct regmap_access_table sta32x_write_regs = {
123a1be4ceaSThomas Niederprüm 	.yes_ranges =	sta32x_write_regs_range,
124a1be4ceaSThomas Niederprüm 	.n_yes_ranges =	ARRAY_SIZE(sta32x_write_regs_range),
125a1be4ceaSThomas Niederprüm };
126a1be4ceaSThomas Niederprüm 
127a1be4ceaSThomas Niederprüm static const struct regmap_access_table sta32x_read_regs = {
128a1be4ceaSThomas Niederprüm 	.yes_ranges =	sta32x_read_regs_range,
129a1be4ceaSThomas Niederprüm 	.n_yes_ranges =	ARRAY_SIZE(sta32x_read_regs_range),
130a1be4ceaSThomas Niederprüm };
131a1be4ceaSThomas Niederprüm 
132a1be4ceaSThomas Niederprüm static const struct regmap_access_table sta32x_volatile_regs = {
133a1be4ceaSThomas Niederprüm 	.yes_ranges =	sta32x_volatile_regs_range,
134a1be4ceaSThomas Niederprüm 	.n_yes_ranges =	ARRAY_SIZE(sta32x_volatile_regs_range),
135a1be4ceaSThomas Niederprüm };
136a1be4ceaSThomas Niederprüm 
137c034abf6SJohannes Stezenbach /* regulator power supply names */
138c034abf6SJohannes Stezenbach static const char *sta32x_supply_names[] = {
139c034abf6SJohannes Stezenbach 	"Vdda",	/* analog supply, 3.3VV */
140c034abf6SJohannes Stezenbach 	"Vdd3",	/* digital supply, 3.3V */
141c034abf6SJohannes Stezenbach 	"Vcc"	/* power amp spply, 10V - 36V */
142c034abf6SJohannes Stezenbach };
143c034abf6SJohannes Stezenbach 
144c034abf6SJohannes Stezenbach /* codec private data */
145c034abf6SJohannes Stezenbach struct sta32x_priv {
14629fdf4fbSMark Brown 	struct regmap *regmap;
147c034abf6SJohannes Stezenbach 	struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)];
148c034abf6SJohannes Stezenbach 	struct snd_soc_codec *codec;
149e012ba24SJohannes Stezenbach 	struct sta32x_platform_data *pdata;
150c034abf6SJohannes Stezenbach 
151c034abf6SJohannes Stezenbach 	unsigned int mclk;
152c034abf6SJohannes Stezenbach 	unsigned int format;
15354dc6cabSJohannes Stezenbach 
15454dc6cabSJohannes Stezenbach 	u32 coef_shadow[STA32X_COEF_COUNT];
1553fb5eac5SJohannes Stezenbach 	struct delayed_work watchdog_work;
1563fb5eac5SJohannes Stezenbach 	int shutdown;
157b66a2980SThomas Niederprüm 	struct gpio_desc *gpiod_nreset;
158a1be4ceaSThomas Niederprüm 	struct mutex coeff_lock;
159c034abf6SJohannes Stezenbach };
160c034abf6SJohannes Stezenbach 
161c034abf6SJohannes Stezenbach static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1);
162c034abf6SJohannes Stezenbach static const DECLARE_TLV_DB_SCALE(chvol_tlv, -7950, 50, 1);
163c034abf6SJohannes Stezenbach static const DECLARE_TLV_DB_SCALE(tone_tlv, -120, 200, 0);
164c034abf6SJohannes Stezenbach 
165c034abf6SJohannes Stezenbach static const char *sta32x_drc_ac[] = {
166c034abf6SJohannes Stezenbach 	"Anti-Clipping", "Dynamic Range Compression" };
167c034abf6SJohannes Stezenbach static const char *sta32x_auto_eq_mode[] = {
168c034abf6SJohannes Stezenbach 	"User", "Preset", "Loudness" };
169c034abf6SJohannes Stezenbach static const char *sta32x_auto_gc_mode[] = {
170c034abf6SJohannes Stezenbach 	"User", "AC no clipping", "AC limited clipping (10%)",
171c034abf6SJohannes Stezenbach 	"DRC nighttime listening mode" };
172c034abf6SJohannes Stezenbach static const char *sta32x_auto_xo_mode[] = {
173c034abf6SJohannes Stezenbach 	"User", "80Hz", "100Hz", "120Hz", "140Hz", "160Hz", "180Hz", "200Hz",
174c034abf6SJohannes Stezenbach 	"220Hz", "240Hz", "260Hz", "280Hz", "300Hz", "320Hz", "340Hz", "360Hz" };
175c034abf6SJohannes Stezenbach static const char *sta32x_preset_eq_mode[] = {
176c034abf6SJohannes Stezenbach 	"Flat", "Rock", "Soft Rock", "Jazz", "Classical", "Dance", "Pop", "Soft",
177c034abf6SJohannes Stezenbach 	"Hard", "Party", "Vocal", "Hip-Hop", "Dialog", "Bass-boost #1",
178c034abf6SJohannes Stezenbach 	"Bass-boost #2", "Bass-boost #3", "Loudness 1", "Loudness 2",
179c034abf6SJohannes Stezenbach 	"Loudness 3", "Loudness 4", "Loudness 5", "Loudness 6", "Loudness 7",
180c034abf6SJohannes Stezenbach 	"Loudness 8", "Loudness 9", "Loudness 10", "Loudness 11", "Loudness 12",
181c034abf6SJohannes Stezenbach 	"Loudness 13", "Loudness 14", "Loudness 15", "Loudness 16" };
182c034abf6SJohannes Stezenbach static const char *sta32x_limiter_select[] = {
183c034abf6SJohannes Stezenbach 	"Limiter Disabled", "Limiter #1", "Limiter #2" };
184c034abf6SJohannes Stezenbach static const char *sta32x_limiter_attack_rate[] = {
185c034abf6SJohannes Stezenbach 	"3.1584", "2.7072", "2.2560", "1.8048", "1.3536", "0.9024",
186c034abf6SJohannes Stezenbach 	"0.4512", "0.2256", "0.1504", "0.1123", "0.0902", "0.0752",
187c034abf6SJohannes Stezenbach 	"0.0645", "0.0564", "0.0501", "0.0451" };
188c034abf6SJohannes Stezenbach static const char *sta32x_limiter_release_rate[] = {
189c034abf6SJohannes Stezenbach 	"0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299",
190c034abf6SJohannes Stezenbach 	"0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137",
191c034abf6SJohannes Stezenbach 	"0.0134", "0.0117", "0.0110", "0.0104" };
19288483f59SThomas Niederprüm static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_attack_tlv,
193c034abf6SJohannes Stezenbach 	0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0),
194c034abf6SJohannes Stezenbach 	8, 16, TLV_DB_SCALE_ITEM(300, 100, 0),
19588483f59SThomas Niederprüm );
196c034abf6SJohannes Stezenbach 
19788483f59SThomas Niederprüm static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_release_tlv,
198c034abf6SJohannes Stezenbach 	0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
199c034abf6SJohannes Stezenbach 	1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0),
200c034abf6SJohannes Stezenbach 	2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0),
201c034abf6SJohannes Stezenbach 	3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0),
202c034abf6SJohannes Stezenbach 	8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0),
20388483f59SThomas Niederprüm );
204c034abf6SJohannes Stezenbach 
20588483f59SThomas Niederprüm static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_attack_tlv,
206c034abf6SJohannes Stezenbach 	0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0),
207c034abf6SJohannes Stezenbach 	8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0),
208c034abf6SJohannes Stezenbach 	14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0),
20988483f59SThomas Niederprüm );
210c034abf6SJohannes Stezenbach 
21188483f59SThomas Niederprüm static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_release_tlv,
212c034abf6SJohannes Stezenbach 	0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
213c034abf6SJohannes Stezenbach 	1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0),
214c034abf6SJohannes Stezenbach 	3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0),
215c034abf6SJohannes Stezenbach 	5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0),
216c034abf6SJohannes Stezenbach 	13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0),
21788483f59SThomas Niederprüm );
218c034abf6SJohannes Stezenbach 
219025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum,
220025c3fa9STakashi Iwai 			    STA32X_CONFD, STA32X_CONFD_DRC_SHIFT,
221025c3fa9STakashi Iwai 			    sta32x_drc_ac);
222025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_auto_eq_enum,
223025c3fa9STakashi Iwai 			    STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT,
224025c3fa9STakashi Iwai 			    sta32x_auto_eq_mode);
225025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_auto_gc_enum,
226025c3fa9STakashi Iwai 			    STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT,
227025c3fa9STakashi Iwai 			    sta32x_auto_gc_mode);
228025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_auto_xo_enum,
229025c3fa9STakashi Iwai 			    STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT,
230025c3fa9STakashi Iwai 			    sta32x_auto_xo_mode);
231025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_preset_eq_enum,
232025c3fa9STakashi Iwai 			    STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT,
233025c3fa9STakashi Iwai 			    sta32x_preset_eq_mode);
234025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch1_enum,
235025c3fa9STakashi Iwai 			    STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT,
236025c3fa9STakashi Iwai 			    sta32x_limiter_select);
237025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch2_enum,
238025c3fa9STakashi Iwai 			    STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT,
239025c3fa9STakashi Iwai 			    sta32x_limiter_select);
240025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch3_enum,
241025c3fa9STakashi Iwai 			    STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT,
242025c3fa9STakashi Iwai 			    sta32x_limiter_select);
243025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_attack_rate_enum,
244025c3fa9STakashi Iwai 			    STA32X_L1AR, STA32X_LxA_SHIFT,
245025c3fa9STakashi Iwai 			    sta32x_limiter_attack_rate);
246025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_attack_rate_enum,
247025c3fa9STakashi Iwai 			    STA32X_L2AR, STA32X_LxA_SHIFT,
248025c3fa9STakashi Iwai 			    sta32x_limiter_attack_rate);
249025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_release_rate_enum,
250025c3fa9STakashi Iwai 			    STA32X_L1AR, STA32X_LxR_SHIFT,
251025c3fa9STakashi Iwai 			    sta32x_limiter_release_rate);
252025c3fa9STakashi Iwai static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_release_rate_enum,
253025c3fa9STakashi Iwai 			    STA32X_L2AR, STA32X_LxR_SHIFT,
254025c3fa9STakashi Iwai 			    sta32x_limiter_release_rate);
25579688439SJohannes Stezenbach 
25679688439SJohannes Stezenbach /* byte array controls for setting biquad, mixer, scaling coefficients;
25779688439SJohannes Stezenbach  * for biquads all five coefficients need to be set in one go,
25879688439SJohannes Stezenbach  * mixer and pre/postscale coefs can be set individually;
25979688439SJohannes Stezenbach  * each coef is 24bit, the bytes are ordered in the same way
26079688439SJohannes Stezenbach  * as given in the STA32x data sheet (big endian; b1, b2, a1, a2, b0)
26179688439SJohannes Stezenbach  */
26279688439SJohannes Stezenbach 
26379688439SJohannes Stezenbach static int sta32x_coefficient_info(struct snd_kcontrol *kcontrol,
26479688439SJohannes Stezenbach 				   struct snd_ctl_elem_info *uinfo)
26579688439SJohannes Stezenbach {
26679688439SJohannes Stezenbach 	int numcoef = kcontrol->private_value >> 16;
26779688439SJohannes Stezenbach 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
26879688439SJohannes Stezenbach 	uinfo->count = 3 * numcoef;
26979688439SJohannes Stezenbach 	return 0;
27079688439SJohannes Stezenbach }
27179688439SJohannes Stezenbach 
27279688439SJohannes Stezenbach static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
27379688439SJohannes Stezenbach 				  struct snd_ctl_elem_value *ucontrol)
27479688439SJohannes Stezenbach {
275ea53bf77SLars-Peter Clausen 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
276a1be4ceaSThomas Niederprüm 	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
27779688439SJohannes Stezenbach 	int numcoef = kcontrol->private_value >> 16;
27879688439SJohannes Stezenbach 	int index = kcontrol->private_value & 0xffff;
279a1be4ceaSThomas Niederprüm 	unsigned int cfud, val;
280a1be4ceaSThomas Niederprüm 	int i, ret = 0;
281a1be4ceaSThomas Niederprüm 
282a1be4ceaSThomas Niederprüm 	mutex_lock(&sta32x->coeff_lock);
28379688439SJohannes Stezenbach 
28479688439SJohannes Stezenbach 	/* preserve reserved bits in STA32X_CFUD */
285a1be4ceaSThomas Niederprüm 	regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
286a1be4ceaSThomas Niederprüm 	cfud &= 0xf0;
287a1be4ceaSThomas Niederprüm 	/*
288a1be4ceaSThomas Niederprüm 	 * chip documentation does not say if the bits are self clearing,
289a1be4ceaSThomas Niederprüm 	 * so do it explicitly
290a1be4ceaSThomas Niederprüm 	 */
291a1be4ceaSThomas Niederprüm 	regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
29279688439SJohannes Stezenbach 
293a1be4ceaSThomas Niederprüm 	regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
294a1be4ceaSThomas Niederprüm 	if (numcoef == 1) {
295a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x04);
296a1be4ceaSThomas Niederprüm 	} else if (numcoef == 5) {
297a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x08);
298a1be4ceaSThomas Niederprüm 	} else {
299a1be4ceaSThomas Niederprüm 		ret = -EINVAL;
300a1be4ceaSThomas Niederprüm 		goto exit_unlock;
301a1be4ceaSThomas Niederprüm 	}
30279688439SJohannes Stezenbach 
303a1be4ceaSThomas Niederprüm 	for (i = 0; i < 3 * numcoef; i++) {
304a1be4ceaSThomas Niederprüm 		regmap_read(sta32x->regmap, STA32X_B1CF1 + i, &val);
305a1be4ceaSThomas Niederprüm 		ucontrol->value.bytes.data[i] = val;
306a1be4ceaSThomas Niederprüm 	}
307a1be4ceaSThomas Niederprüm 
308a1be4ceaSThomas Niederprüm exit_unlock:
309a1be4ceaSThomas Niederprüm 	mutex_unlock(&sta32x->coeff_lock);
310a1be4ceaSThomas Niederprüm 
311a1be4ceaSThomas Niederprüm 	return ret;
31279688439SJohannes Stezenbach }
31379688439SJohannes Stezenbach 
31479688439SJohannes Stezenbach static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
31579688439SJohannes Stezenbach 				  struct snd_ctl_elem_value *ucontrol)
31679688439SJohannes Stezenbach {
317ea53bf77SLars-Peter Clausen 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
31854dc6cabSJohannes Stezenbach 	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
31979688439SJohannes Stezenbach 	int numcoef = kcontrol->private_value >> 16;
32079688439SJohannes Stezenbach 	int index = kcontrol->private_value & 0xffff;
32179688439SJohannes Stezenbach 	unsigned int cfud;
32279688439SJohannes Stezenbach 	int i;
32379688439SJohannes Stezenbach 
32479688439SJohannes Stezenbach 	/* preserve reserved bits in STA32X_CFUD */
325a1be4ceaSThomas Niederprüm 	regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
326a1be4ceaSThomas Niederprüm 	cfud &= 0xf0;
327a1be4ceaSThomas Niederprüm 	/*
328a1be4ceaSThomas Niederprüm 	 * chip documentation does not say if the bits are self clearing,
329a1be4ceaSThomas Niederprüm 	 * so do it explicitly
330a1be4ceaSThomas Niederprüm 	 */
331a1be4ceaSThomas Niederprüm 	regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
33279688439SJohannes Stezenbach 
333a1be4ceaSThomas Niederprüm 	regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
33454dc6cabSJohannes Stezenbach 	for (i = 0; i < numcoef && (index + i < STA32X_COEF_COUNT); i++)
33554dc6cabSJohannes Stezenbach 		sta32x->coef_shadow[index + i] =
33654dc6cabSJohannes Stezenbach 			  (ucontrol->value.bytes.data[3 * i] << 16)
33754dc6cabSJohannes Stezenbach 			| (ucontrol->value.bytes.data[3 * i + 1] << 8)
33854dc6cabSJohannes Stezenbach 			| (ucontrol->value.bytes.data[3 * i + 2]);
33979688439SJohannes Stezenbach 	for (i = 0; i < 3 * numcoef; i++)
340a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_B1CF1 + i,
34179688439SJohannes Stezenbach 			     ucontrol->value.bytes.data[i]);
34279688439SJohannes Stezenbach 	if (numcoef == 1)
343a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
34479688439SJohannes Stezenbach 	else if (numcoef == 5)
345a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x02);
34679688439SJohannes Stezenbach 	else
34779688439SJohannes Stezenbach 		return -EINVAL;
34879688439SJohannes Stezenbach 
34979688439SJohannes Stezenbach 	return 0;
35079688439SJohannes Stezenbach }
35179688439SJohannes Stezenbach 
352878042d1SMark Brown static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec)
35354dc6cabSJohannes Stezenbach {
35454dc6cabSJohannes Stezenbach 	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
35554dc6cabSJohannes Stezenbach 	unsigned int cfud;
35654dc6cabSJohannes Stezenbach 	int i;
35754dc6cabSJohannes Stezenbach 
35854dc6cabSJohannes Stezenbach 	/* preserve reserved bits in STA32X_CFUD */
359a1be4ceaSThomas Niederprüm 	regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
360a1be4ceaSThomas Niederprüm 	cfud &= 0xf0;
36154dc6cabSJohannes Stezenbach 
36254dc6cabSJohannes Stezenbach 	for (i = 0; i < STA32X_COEF_COUNT; i++) {
363a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFADDR2, i);
364a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_B1CF1,
36554dc6cabSJohannes Stezenbach 			     (sta32x->coef_shadow[i] >> 16) & 0xff);
366a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_B1CF2,
36754dc6cabSJohannes Stezenbach 			     (sta32x->coef_shadow[i] >> 8) & 0xff);
368a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_B1CF3,
36954dc6cabSJohannes Stezenbach 			     (sta32x->coef_shadow[i]) & 0xff);
370a1be4ceaSThomas Niederprüm 		/*
371a1be4ceaSThomas Niederprüm 		 * chip documentation does not say if the bits are
372a1be4ceaSThomas Niederprüm 		 * self-clearing, so do it explicitly
373a1be4ceaSThomas Niederprüm 		 */
374a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
375a1be4ceaSThomas Niederprüm 		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
37654dc6cabSJohannes Stezenbach 	}
37754dc6cabSJohannes Stezenbach 	return 0;
37854dc6cabSJohannes Stezenbach }
37954dc6cabSJohannes Stezenbach 
380878042d1SMark Brown static int sta32x_cache_sync(struct snd_soc_codec *codec)
38154dc6cabSJohannes Stezenbach {
38270ff00f8SLars-Peter Clausen 	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
38354dc6cabSJohannes Stezenbach 	unsigned int mute;
38454dc6cabSJohannes Stezenbach 	int rc;
38554dc6cabSJohannes Stezenbach 
38654dc6cabSJohannes Stezenbach 	/* mute during register sync */
387a1be4ceaSThomas Niederprüm 	regmap_read(sta32x->regmap, STA32X_MMUTE, &mute);
388a1be4ceaSThomas Niederprüm 	regmap_write(sta32x->regmap, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE);
38954dc6cabSJohannes Stezenbach 	sta32x_sync_coef_shadow(codec);
39029fdf4fbSMark Brown 	rc = regcache_sync(sta32x->regmap);
391a1be4ceaSThomas Niederprüm 	regmap_write(sta32x->regmap, STA32X_MMUTE, mute);
39254dc6cabSJohannes Stezenbach 	return rc;
39354dc6cabSJohannes Stezenbach }
39454dc6cabSJohannes Stezenbach 
3953fb5eac5SJohannes Stezenbach /* work around ESD issue where sta32x resets and loses all configuration */
3963fb5eac5SJohannes Stezenbach static void sta32x_watchdog(struct work_struct *work)
3973fb5eac5SJohannes Stezenbach {
3983fb5eac5SJohannes Stezenbach 	struct sta32x_priv *sta32x = container_of(work, struct sta32x_priv,
3993fb5eac5SJohannes Stezenbach 						  watchdog_work.work);
4003fb5eac5SJohannes Stezenbach 	struct snd_soc_codec *codec = sta32x->codec;
4013fb5eac5SJohannes Stezenbach 	unsigned int confa, confa_cached;
4023fb5eac5SJohannes Stezenbach 
4033fb5eac5SJohannes Stezenbach 	/* check if sta32x has reset itself */
4043fb5eac5SJohannes Stezenbach 	confa_cached = snd_soc_read(codec, STA32X_CONFA);
40529fdf4fbSMark Brown 	regcache_cache_bypass(sta32x->regmap, true);
4063fb5eac5SJohannes Stezenbach 	confa = snd_soc_read(codec, STA32X_CONFA);
40729fdf4fbSMark Brown 	regcache_cache_bypass(sta32x->regmap, false);
4083fb5eac5SJohannes Stezenbach 	if (confa != confa_cached) {
40929fdf4fbSMark Brown 		regcache_mark_dirty(sta32x->regmap);
4103fb5eac5SJohannes Stezenbach 		sta32x_cache_sync(codec);
4113fb5eac5SJohannes Stezenbach 	}
4123fb5eac5SJohannes Stezenbach 
4133fb5eac5SJohannes Stezenbach 	if (!sta32x->shutdown)
414a14d9829SMark Brown 		queue_delayed_work(system_power_efficient_wq,
415a14d9829SMark Brown 				   &sta32x->watchdog_work,
4163fb5eac5SJohannes Stezenbach 				   round_jiffies_relative(HZ));
4173fb5eac5SJohannes Stezenbach }
4183fb5eac5SJohannes Stezenbach 
4193fb5eac5SJohannes Stezenbach static void sta32x_watchdog_start(struct sta32x_priv *sta32x)
4203fb5eac5SJohannes Stezenbach {
4213fb5eac5SJohannes Stezenbach 	if (sta32x->pdata->needs_esd_watchdog) {
4223fb5eac5SJohannes Stezenbach 		sta32x->shutdown = 0;
423a14d9829SMark Brown 		queue_delayed_work(system_power_efficient_wq,
424a14d9829SMark Brown 				   &sta32x->watchdog_work,
4253fb5eac5SJohannes Stezenbach 				   round_jiffies_relative(HZ));
4263fb5eac5SJohannes Stezenbach 	}
4273fb5eac5SJohannes Stezenbach }
4283fb5eac5SJohannes Stezenbach 
4293fb5eac5SJohannes Stezenbach static void sta32x_watchdog_stop(struct sta32x_priv *sta32x)
4303fb5eac5SJohannes Stezenbach {
4313fb5eac5SJohannes Stezenbach 	if (sta32x->pdata->needs_esd_watchdog) {
4323fb5eac5SJohannes Stezenbach 		sta32x->shutdown = 1;
4333fb5eac5SJohannes Stezenbach 		cancel_delayed_work_sync(&sta32x->watchdog_work);
4343fb5eac5SJohannes Stezenbach 	}
4353fb5eac5SJohannes Stezenbach }
4363fb5eac5SJohannes Stezenbach 
43779688439SJohannes Stezenbach #define SINGLE_COEF(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 | (1 << 16) }
44379688439SJohannes Stezenbach 
44479688439SJohannes Stezenbach #define BIQUAD_COEFS(xname, index) \
44579688439SJohannes Stezenbach {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
44679688439SJohannes Stezenbach 	.info = sta32x_coefficient_info, \
44779688439SJohannes Stezenbach 	.get = sta32x_coefficient_get,\
44879688439SJohannes Stezenbach 	.put = sta32x_coefficient_put, \
44979688439SJohannes Stezenbach 	.private_value = index | (5 << 16) }
45079688439SJohannes Stezenbach 
451c034abf6SJohannes Stezenbach static const struct snd_kcontrol_new sta32x_snd_controls[] = {
452c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Master Volume", STA32X_MVOL, 0, 0xff, 1, mvol_tlv),
453c034abf6SJohannes Stezenbach SOC_SINGLE("Master Switch", STA32X_MMUTE, 0, 1, 1),
454c034abf6SJohannes Stezenbach SOC_SINGLE("Ch1 Switch", STA32X_MMUTE, 1, 1, 1),
455c034abf6SJohannes Stezenbach SOC_SINGLE("Ch2 Switch", STA32X_MMUTE, 2, 1, 1),
456c034abf6SJohannes Stezenbach SOC_SINGLE("Ch3 Switch", STA32X_MMUTE, 3, 1, 1),
457c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Ch1 Volume", STA32X_C1VOL, 0, 0xff, 1, chvol_tlv),
458c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Ch2 Volume", STA32X_C2VOL, 0, 0xff, 1, chvol_tlv),
459c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Ch3 Volume", STA32X_C3VOL, 0, 0xff, 1, chvol_tlv),
460c034abf6SJohannes Stezenbach SOC_SINGLE("De-emphasis Filter Switch", STA32X_CONFD, STA32X_CONFD_DEMP_SHIFT, 1, 0),
461c034abf6SJohannes Stezenbach SOC_ENUM("Compressor/Limiter Switch", sta32x_drc_ac_enum),
462c034abf6SJohannes Stezenbach SOC_SINGLE("Miami Mode Switch", STA32X_CONFD, STA32X_CONFD_MME_SHIFT, 1, 0),
463c034abf6SJohannes Stezenbach SOC_SINGLE("Zero Cross Switch", STA32X_CONFE, STA32X_CONFE_ZCE_SHIFT, 1, 0),
464c034abf6SJohannes Stezenbach SOC_SINGLE("Soft Ramp Switch", STA32X_CONFE, STA32X_CONFE_SVE_SHIFT, 1, 0),
465c034abf6SJohannes Stezenbach SOC_SINGLE("Auto-Mute Switch", STA32X_CONFF, STA32X_CONFF_IDE_SHIFT, 1, 0),
466c034abf6SJohannes Stezenbach SOC_ENUM("Automode EQ", sta32x_auto_eq_enum),
467c034abf6SJohannes Stezenbach SOC_ENUM("Automode GC", sta32x_auto_gc_enum),
468c034abf6SJohannes Stezenbach SOC_ENUM("Automode XO", sta32x_auto_xo_enum),
469c034abf6SJohannes Stezenbach SOC_ENUM("Preset EQ", sta32x_preset_eq_enum),
470c034abf6SJohannes Stezenbach SOC_SINGLE("Ch1 Tone Control Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0),
471c034abf6SJohannes Stezenbach SOC_SINGLE("Ch2 Tone Control Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0),
472c034abf6SJohannes Stezenbach SOC_SINGLE("Ch1 EQ Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0),
473c034abf6SJohannes Stezenbach SOC_SINGLE("Ch2 EQ Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0),
474c034abf6SJohannes Stezenbach SOC_SINGLE("Ch1 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0),
475c034abf6SJohannes Stezenbach SOC_SINGLE("Ch2 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0),
476c034abf6SJohannes Stezenbach SOC_SINGLE("Ch3 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0),
477c034abf6SJohannes Stezenbach SOC_ENUM("Ch1 Limiter Select", sta32x_limiter_ch1_enum),
478c034abf6SJohannes Stezenbach SOC_ENUM("Ch2 Limiter Select", sta32x_limiter_ch2_enum),
479c034abf6SJohannes Stezenbach SOC_ENUM("Ch3 Limiter Select", sta32x_limiter_ch3_enum),
480c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Bass Tone Control", STA32X_TONE, STA32X_TONE_BTC_SHIFT, 15, 0, tone_tlv),
481c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Treble Tone Control", STA32X_TONE, STA32X_TONE_TTC_SHIFT, 15, 0, tone_tlv),
482c034abf6SJohannes Stezenbach SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum),
483c034abf6SJohannes Stezenbach SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum),
484c034abf6SJohannes Stezenbach SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum),
485b3619b28STakashi Iwai SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter2_release_rate_enum),
486c034abf6SJohannes Stezenbach 
487c034abf6SJohannes Stezenbach /* depending on mode, the attack/release thresholds have
488c034abf6SJohannes Stezenbach  * two different enum definitions; provide both
489c034abf6SJohannes Stezenbach  */
490c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter1 Attack Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT,
491c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_ac_attack_tlv),
492c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter2 Attack Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT,
493c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_ac_attack_tlv),
494c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter1 Release Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT,
495c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_ac_release_tlv),
496c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter2 Release Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT,
497c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_ac_release_tlv),
498c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter1 Attack Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT,
499c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_drc_attack_tlv),
500c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter2 Attack Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT,
501c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_drc_attack_tlv),
502c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter1 Release Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT,
503c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_drc_release_tlv),
504c034abf6SJohannes Stezenbach SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT,
505c034abf6SJohannes Stezenbach 	       16, 0, sta32x_limiter_drc_release_tlv),
50679688439SJohannes Stezenbach 
50779688439SJohannes Stezenbach BIQUAD_COEFS("Ch1 - Biquad 1", 0),
50879688439SJohannes Stezenbach BIQUAD_COEFS("Ch1 - Biquad 2", 5),
50979688439SJohannes Stezenbach BIQUAD_COEFS("Ch1 - Biquad 3", 10),
51079688439SJohannes Stezenbach BIQUAD_COEFS("Ch1 - Biquad 4", 15),
51179688439SJohannes Stezenbach BIQUAD_COEFS("Ch2 - Biquad 1", 20),
51279688439SJohannes Stezenbach BIQUAD_COEFS("Ch2 - Biquad 2", 25),
51379688439SJohannes Stezenbach BIQUAD_COEFS("Ch2 - Biquad 3", 30),
51479688439SJohannes Stezenbach BIQUAD_COEFS("Ch2 - Biquad 4", 35),
51579688439SJohannes Stezenbach BIQUAD_COEFS("High-pass", 40),
51679688439SJohannes Stezenbach BIQUAD_COEFS("Low-pass", 45),
51779688439SJohannes Stezenbach SINGLE_COEF("Ch1 - Prescale", 50),
51879688439SJohannes Stezenbach SINGLE_COEF("Ch2 - Prescale", 51),
51979688439SJohannes Stezenbach SINGLE_COEF("Ch1 - Postscale", 52),
52079688439SJohannes Stezenbach SINGLE_COEF("Ch2 - Postscale", 53),
52179688439SJohannes Stezenbach SINGLE_COEF("Ch3 - Postscale", 54),
52279688439SJohannes Stezenbach SINGLE_COEF("Thermal warning - Postscale", 55),
52379688439SJohannes Stezenbach SINGLE_COEF("Ch1 - Mix 1", 56),
52479688439SJohannes Stezenbach SINGLE_COEF("Ch1 - Mix 2", 57),
52579688439SJohannes Stezenbach SINGLE_COEF("Ch2 - Mix 1", 58),
52679688439SJohannes Stezenbach SINGLE_COEF("Ch2 - Mix 2", 59),
52779688439SJohannes Stezenbach SINGLE_COEF("Ch3 - Mix 1", 60),
52879688439SJohannes Stezenbach SINGLE_COEF("Ch3 - Mix 2", 61),
529c034abf6SJohannes Stezenbach };
530c034abf6SJohannes Stezenbach 
531c034abf6SJohannes Stezenbach static const struct snd_soc_dapm_widget sta32x_dapm_widgets[] = {
532c034abf6SJohannes Stezenbach SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
533c034abf6SJohannes Stezenbach SND_SOC_DAPM_OUTPUT("LEFT"),
534c034abf6SJohannes Stezenbach SND_SOC_DAPM_OUTPUT("RIGHT"),
535c034abf6SJohannes Stezenbach SND_SOC_DAPM_OUTPUT("SUB"),
536c034abf6SJohannes Stezenbach };
537c034abf6SJohannes Stezenbach 
538c034abf6SJohannes Stezenbach static const struct snd_soc_dapm_route sta32x_dapm_routes[] = {
539c034abf6SJohannes Stezenbach 	{ "LEFT", NULL, "DAC" },
540c034abf6SJohannes Stezenbach 	{ "RIGHT", NULL, "DAC" },
541c034abf6SJohannes Stezenbach 	{ "SUB", NULL, "DAC" },
542c034abf6SJohannes Stezenbach };
543c034abf6SJohannes Stezenbach 
544c034abf6SJohannes Stezenbach /* MCLK interpolation ratio per fs */
545c034abf6SJohannes Stezenbach static struct {
546c034abf6SJohannes Stezenbach 	int fs;
547c034abf6SJohannes Stezenbach 	int ir;
548c034abf6SJohannes Stezenbach } interpolation_ratios[] = {
549c034abf6SJohannes Stezenbach 	{ 32000, 0 },
550c034abf6SJohannes Stezenbach 	{ 44100, 0 },
551c034abf6SJohannes Stezenbach 	{ 48000, 0 },
552c034abf6SJohannes Stezenbach 	{ 88200, 1 },
553c034abf6SJohannes Stezenbach 	{ 96000, 1 },
554c034abf6SJohannes Stezenbach 	{ 176400, 2 },
555c034abf6SJohannes Stezenbach 	{ 192000, 2 },
556c034abf6SJohannes Stezenbach };
557c034abf6SJohannes Stezenbach 
558c034abf6SJohannes Stezenbach /* MCLK to fs clock ratios */
5591c34c876SThomas Niederprüm static int mcs_ratio_table[3][7] = {
5601c34c876SThomas Niederprüm 	{ 768, 512, 384, 256, 128, 576, 0 },
5611c34c876SThomas Niederprüm 	{ 384, 256, 192, 128,  64,   0 },
5621c34c876SThomas Niederprüm 	{ 384, 256, 192, 128,  64,   0 },
563c034abf6SJohannes Stezenbach };
564c034abf6SJohannes Stezenbach 
565c034abf6SJohannes Stezenbach /**
566c034abf6SJohannes Stezenbach  * sta32x_set_dai_sysclk - configure MCLK
567c034abf6SJohannes Stezenbach  * @codec_dai: the codec DAI
568c034abf6SJohannes Stezenbach  * @clk_id: the clock ID (ignored)
569c034abf6SJohannes Stezenbach  * @freq: the MCLK input frequency
570c034abf6SJohannes Stezenbach  * @dir: the clock direction (ignored)
571c034abf6SJohannes Stezenbach  *
572c034abf6SJohannes Stezenbach  * The value of MCLK is used to determine which sample rates are supported
573c034abf6SJohannes Stezenbach  * by the STA32X, based on the mclk_ratios table.
574c034abf6SJohannes Stezenbach  *
575c034abf6SJohannes Stezenbach  * This function must be called by the machine driver's 'startup' function,
576c034abf6SJohannes Stezenbach  * otherwise the list of supported sample rates will not be available in
577c034abf6SJohannes Stezenbach  * time for ALSA.
578c034abf6SJohannes Stezenbach  *
579c034abf6SJohannes Stezenbach  * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause
580c034abf6SJohannes Stezenbach  * theoretically possible sample rates to be enabled. Call it again with a
581c034abf6SJohannes Stezenbach  * proper value set one the external clock is set (most probably you would do
582c034abf6SJohannes Stezenbach  * that from a machine's driver 'hw_param' hook.
583c034abf6SJohannes Stezenbach  */
584c034abf6SJohannes Stezenbach static int sta32x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
585c034abf6SJohannes Stezenbach 		int clk_id, unsigned int freq, int dir)
586c034abf6SJohannes Stezenbach {
587c034abf6SJohannes Stezenbach 	struct snd_soc_codec *codec = codec_dai->codec;
588c034abf6SJohannes Stezenbach 	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
589c034abf6SJohannes Stezenbach 
5901c34c876SThomas Niederprüm 	dev_dbg(codec->dev, "mclk=%u\n", freq);
591c034abf6SJohannes Stezenbach 	sta32x->mclk = freq;
592c034abf6SJohannes Stezenbach 
593c034abf6SJohannes Stezenbach 	return 0;
594c034abf6SJohannes Stezenbach }
595c034abf6SJohannes Stezenbach 
596c034abf6SJohannes Stezenbach /**
597c034abf6SJohannes Stezenbach  * sta32x_set_dai_fmt - configure the codec for the selected audio format
598c034abf6SJohannes Stezenbach  * @codec_dai: the codec DAI
599c034abf6SJohannes Stezenbach  * @fmt: a SND_SOC_DAIFMT_x value indicating the data format
600c034abf6SJohannes Stezenbach  *
601c034abf6SJohannes Stezenbach  * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the
602c034abf6SJohannes Stezenbach  * codec accordingly.
603c034abf6SJohannes Stezenbach  */
604c034abf6SJohannes Stezenbach static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai,
605c034abf6SJohannes Stezenbach 			      unsigned int fmt)
606c034abf6SJohannes Stezenbach {
607c034abf6SJohannes Stezenbach 	struct snd_soc_codec *codec = codec_dai->codec;
608c034abf6SJohannes Stezenbach 	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
609a1be4ceaSThomas Niederprüm 	u8 confb = 0;
610c034abf6SJohannes Stezenbach 
611c034abf6SJohannes Stezenbach 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
612c034abf6SJohannes Stezenbach 	case SND_SOC_DAIFMT_CBS_CFS:
613c034abf6SJohannes Stezenbach 		break;
614c034abf6SJohannes Stezenbach 	default:
615c034abf6SJohannes Stezenbach 		return -EINVAL;
616c034abf6SJohannes Stezenbach 	}
617c034abf6SJohannes Stezenbach 
618c034abf6SJohannes Stezenbach 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
619c034abf6SJohannes Stezenbach 	case SND_SOC_DAIFMT_I2S:
620c034abf6SJohannes Stezenbach 	case SND_SOC_DAIFMT_RIGHT_J:
621c034abf6SJohannes Stezenbach 	case SND_SOC_DAIFMT_LEFT_J:
622c034abf6SJohannes Stezenbach 		sta32x->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
623c034abf6SJohannes Stezenbach 		break;
624c034abf6SJohannes Stezenbach 	default:
625c034abf6SJohannes Stezenbach 		return -EINVAL;
626c034abf6SJohannes Stezenbach 	}
627c034abf6SJohannes Stezenbach 
628c034abf6SJohannes Stezenbach 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
629c034abf6SJohannes Stezenbach 	case SND_SOC_DAIFMT_NB_NF:
630c034abf6SJohannes Stezenbach 		confb |= STA32X_CONFB_C2IM;
631c034abf6SJohannes Stezenbach 		break;
632c034abf6SJohannes Stezenbach 	case SND_SOC_DAIFMT_NB_IF:
633c034abf6SJohannes Stezenbach 		confb |= STA32X_CONFB_C1IM;
634c034abf6SJohannes Stezenbach 		break;
635c034abf6SJohannes Stezenbach 	default:
636c034abf6SJohannes Stezenbach 		return -EINVAL;
637c034abf6SJohannes Stezenbach 	}
638c034abf6SJohannes Stezenbach 
639a1be4ceaSThomas Niederprüm 	return regmap_update_bits(sta32x->regmap, STA32X_CONFB,
640a1be4ceaSThomas Niederprüm 				  STA32X_CONFB_C1IM | STA32X_CONFB_C2IM, confb);
641c034abf6SJohannes Stezenbach }
642c034abf6SJohannes Stezenbach 
643c034abf6SJohannes Stezenbach /**
644c034abf6SJohannes Stezenbach  * sta32x_hw_params - program the STA32X with the given hardware parameters.
645c034abf6SJohannes Stezenbach  * @substream: the audio stream
646c034abf6SJohannes Stezenbach  * @params: the hardware parameters to set
647c034abf6SJohannes Stezenbach  * @dai: the SOC DAI (ignored)
648c034abf6SJohannes Stezenbach  *
649c034abf6SJohannes Stezenbach  * This function programs the hardware with the values provided.
650c034abf6SJohannes Stezenbach  * Specifically, the sample rate and the data format.
651c034abf6SJohannes Stezenbach  */
652c034abf6SJohannes Stezenbach static int sta32x_hw_params(struct snd_pcm_substream *substream,
653c034abf6SJohannes Stezenbach 			    struct snd_pcm_hw_params *params,
654c034abf6SJohannes Stezenbach 			    struct snd_soc_dai *dai)
655c034abf6SJohannes Stezenbach {
656e6968a17SMark Brown 	struct snd_soc_codec *codec = dai->codec;
657c034abf6SJohannes Stezenbach 	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
6581c34c876SThomas Niederprüm 	int i, mcs = -EINVAL, ir = -EINVAL;
659a1be4ceaSThomas Niederprüm 	unsigned int confa, confb;
6601c34c876SThomas Niederprüm 	unsigned int rate, ratio;
6611c34c876SThomas Niederprüm 	int ret;
6621c34c876SThomas Niederprüm 
6631c34c876SThomas Niederprüm 	if (!sta32x->mclk) {
6641c34c876SThomas Niederprüm 		dev_err(codec->dev,
6651c34c876SThomas Niederprüm 			"sta32x->mclk is unset. Unable to determine ratio\n");
6661c34c876SThomas Niederprüm 		return -EIO;
6671c34c876SThomas Niederprüm 	}
668c034abf6SJohannes Stezenbach 
669c034abf6SJohannes Stezenbach 	rate = params_rate(params);
6701c34c876SThomas Niederprüm 	ratio = sta32x->mclk / rate;
6711c34c876SThomas Niederprüm 	dev_dbg(codec->dev, "rate: %u, ratio: %u\n", rate, ratio);
6721c34c876SThomas Niederprüm 
6731c34c876SThomas Niederprüm 	for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) {
674a595238bSAxel Lin 		if (interpolation_ratios[i].fs == rate) {
675c034abf6SJohannes Stezenbach 			ir = interpolation_ratios[i].ir;
676a595238bSAxel Lin 			break;
677a595238bSAxel Lin 		}
6781c34c876SThomas Niederprüm 	}
6791c34c876SThomas Niederprüm 
6801c34c876SThomas Niederprüm 	if (ir < 0) {
6811c34c876SThomas Niederprüm 		dev_err(codec->dev, "Unsupported samplerate: %u\n", rate);
682c034abf6SJohannes Stezenbach 		return -EINVAL;
6831c34c876SThomas Niederprüm 	}
6841c34c876SThomas Niederprüm 
6851c34c876SThomas Niederprüm 	for (i = 0; i < 6; i++) {
6861c34c876SThomas Niederprüm 		if (mcs_ratio_table[ir][i] == ratio) {
6871c34c876SThomas Niederprüm 			mcs = i;
688a595238bSAxel Lin 			break;
689a595238bSAxel Lin 		}
6901c34c876SThomas Niederprüm 	}
6911c34c876SThomas Niederprüm 
6921c34c876SThomas Niederprüm 	if (mcs < 0) {
6931c34c876SThomas Niederprüm 		dev_err(codec->dev, "Unresolvable ratio: %u\n", ratio);
694c034abf6SJohannes Stezenbach 		return -EINVAL;
6951c34c876SThomas Niederprüm 	}
696c034abf6SJohannes Stezenbach 
697a1be4ceaSThomas Niederprüm 	confa = (ir << STA32X_CONFA_IR_SHIFT) |
698a1be4ceaSThomas Niederprüm 		(mcs << STA32X_CONFA_MCS_SHIFT);
699a1be4ceaSThomas Niederprüm 	confb = 0;
700c034abf6SJohannes Stezenbach 
701737e0f89SMark Brown 	switch (params_width(params)) {
702737e0f89SMark Brown 	case 24:
703c034abf6SJohannes Stezenbach 		pr_debug("24bit\n");
704c034abf6SJohannes Stezenbach 		/* fall through */
705737e0f89SMark Brown 	case 32:
706c034abf6SJohannes Stezenbach 		pr_debug("24bit or 32bit\n");
707c034abf6SJohannes Stezenbach 		switch (sta32x->format) {
708c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_I2S:
709c034abf6SJohannes Stezenbach 			confb |= 0x0;
710c034abf6SJohannes Stezenbach 			break;
711c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_LEFT_J:
712c034abf6SJohannes Stezenbach 			confb |= 0x1;
713c034abf6SJohannes Stezenbach 			break;
714c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_RIGHT_J:
715c034abf6SJohannes Stezenbach 			confb |= 0x2;
716c034abf6SJohannes Stezenbach 			break;
717c034abf6SJohannes Stezenbach 		}
718c034abf6SJohannes Stezenbach 
719c034abf6SJohannes Stezenbach 		break;
720737e0f89SMark Brown 	case 20:
721c034abf6SJohannes Stezenbach 		pr_debug("20bit\n");
722c034abf6SJohannes Stezenbach 		switch (sta32x->format) {
723c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_I2S:
724c034abf6SJohannes Stezenbach 			confb |= 0x4;
725c034abf6SJohannes Stezenbach 			break;
726c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_LEFT_J:
727c034abf6SJohannes Stezenbach 			confb |= 0x5;
728c034abf6SJohannes Stezenbach 			break;
729c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_RIGHT_J:
730c034abf6SJohannes Stezenbach 			confb |= 0x6;
731c034abf6SJohannes Stezenbach 			break;
732c034abf6SJohannes Stezenbach 		}
733c034abf6SJohannes Stezenbach 
734c034abf6SJohannes Stezenbach 		break;
735737e0f89SMark Brown 	case 18:
736c034abf6SJohannes Stezenbach 		pr_debug("18bit\n");
737c034abf6SJohannes Stezenbach 		switch (sta32x->format) {
738c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_I2S:
739c034abf6SJohannes Stezenbach 			confb |= 0x8;
740c034abf6SJohannes Stezenbach 			break;
741c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_LEFT_J:
742c034abf6SJohannes Stezenbach 			confb |= 0x9;
743c034abf6SJohannes Stezenbach 			break;
744c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_RIGHT_J:
745c034abf6SJohannes Stezenbach 			confb |= 0xa;
746c034abf6SJohannes Stezenbach 			break;
747c034abf6SJohannes Stezenbach 		}
748c034abf6SJohannes Stezenbach 
749c034abf6SJohannes Stezenbach 		break;
750737e0f89SMark Brown 	case 16:
751c034abf6SJohannes Stezenbach 		pr_debug("16bit\n");
752c034abf6SJohannes Stezenbach 		switch (sta32x->format) {
753c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_I2S:
754c034abf6SJohannes Stezenbach 			confb |= 0x0;
755c034abf6SJohannes Stezenbach 			break;
756c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_LEFT_J:
757c034abf6SJohannes Stezenbach 			confb |= 0xd;
758c034abf6SJohannes Stezenbach 			break;
759c034abf6SJohannes Stezenbach 		case SND_SOC_DAIFMT_RIGHT_J:
760c034abf6SJohannes Stezenbach 			confb |= 0xe;
761c034abf6SJohannes Stezenbach 			break;
762c034abf6SJohannes Stezenbach 		}
763c034abf6SJohannes Stezenbach 
764c034abf6SJohannes Stezenbach 		break;
765c034abf6SJohannes Stezenbach 	default:
766c034abf6SJohannes Stezenbach 		return -EINVAL;
767c034abf6SJohannes Stezenbach 	}
768c034abf6SJohannes Stezenbach 
769a1be4ceaSThomas Niederprüm 	ret = regmap_update_bits(sta32x->regmap, STA32X_CONFA,
770a1be4ceaSThomas Niederprüm 				 STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK,
771a1be4ceaSThomas Niederprüm 				 confa);
772a1be4ceaSThomas Niederprüm 	if (ret < 0)
773a1be4ceaSThomas Niederprüm 		return ret;
774a1be4ceaSThomas Niederprüm 
775a1be4ceaSThomas Niederprüm 	ret = regmap_update_bits(sta32x->regmap, STA32X_CONFB,
776a1be4ceaSThomas Niederprüm 				 STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB,
777a1be4ceaSThomas Niederprüm 				 confb);
778a1be4ceaSThomas Niederprüm 	if (ret < 0)
779a1be4ceaSThomas Niederprüm 		return ret;
780a1be4ceaSThomas Niederprüm 
781a1be4ceaSThomas Niederprüm 	return 0;
782a1be4ceaSThomas Niederprüm }
783b66a2980SThomas Niederprüm 
784b66a2980SThomas Niederprüm static int sta32x_startup_sequence(struct sta32x_priv *sta32x)
785b66a2980SThomas Niederprüm {
786b66a2980SThomas Niederprüm 	if (sta32x->gpiod_nreset) {
787b66a2980SThomas Niederprüm 		gpiod_set_value(sta32x->gpiod_nreset, 0);
788b66a2980SThomas Niederprüm 		mdelay(1);
789b66a2980SThomas Niederprüm 		gpiod_set_value(sta32x->gpiod_nreset, 1);
790b66a2980SThomas Niederprüm 		mdelay(1);
791b66a2980SThomas Niederprüm 	}
792b66a2980SThomas Niederprüm 
793c034abf6SJohannes Stezenbach 	return 0;
794c034abf6SJohannes Stezenbach }
795c034abf6SJohannes Stezenbach 
796c034abf6SJohannes Stezenbach /**
797c034abf6SJohannes Stezenbach  * sta32x_set_bias_level - DAPM callback
798c034abf6SJohannes Stezenbach  * @codec: the codec device
799c034abf6SJohannes Stezenbach  * @level: DAPM power level
800c034abf6SJohannes Stezenbach  *
801c034abf6SJohannes Stezenbach  * This is called by ALSA to put the codec into low power mode
802c034abf6SJohannes Stezenbach  * or to wake it up.  If the codec is powered off completely
803c034abf6SJohannes Stezenbach  * all registers must be restored after power on.
804c034abf6SJohannes Stezenbach  */
805c034abf6SJohannes Stezenbach static int sta32x_set_bias_level(struct snd_soc_codec *codec,
806c034abf6SJohannes Stezenbach 				 enum snd_soc_bias_level level)
807c034abf6SJohannes Stezenbach {
808c034abf6SJohannes Stezenbach 	int ret;
809c034abf6SJohannes Stezenbach 	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
810c034abf6SJohannes Stezenbach 
811c034abf6SJohannes Stezenbach 	pr_debug("level = %d\n", level);
812c034abf6SJohannes Stezenbach 	switch (level) {
813c034abf6SJohannes Stezenbach 	case SND_SOC_BIAS_ON:
814c034abf6SJohannes Stezenbach 		break;
815c034abf6SJohannes Stezenbach 
816c034abf6SJohannes Stezenbach 	case SND_SOC_BIAS_PREPARE:
817c034abf6SJohannes Stezenbach 		/* Full power on */
818a1be4ceaSThomas Niederprüm 		regmap_update_bits(sta32x->regmap, STA32X_CONFF,
819c034abf6SJohannes Stezenbach 				    STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
820c034abf6SJohannes Stezenbach 				    STA32X_CONFF_PWDN | STA32X_CONFF_EAPD);
821c034abf6SJohannes Stezenbach 		break;
822c034abf6SJohannes Stezenbach 
823c034abf6SJohannes Stezenbach 	case SND_SOC_BIAS_STANDBY:
824c034abf6SJohannes Stezenbach 		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
825c034abf6SJohannes Stezenbach 			ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
826c034abf6SJohannes Stezenbach 						    sta32x->supplies);
827c034abf6SJohannes Stezenbach 			if (ret != 0) {
828c034abf6SJohannes Stezenbach 				dev_err(codec->dev,
829c034abf6SJohannes Stezenbach 					"Failed to enable supplies: %d\n", ret);
830c034abf6SJohannes Stezenbach 				return ret;
831c034abf6SJohannes Stezenbach 			}
832c034abf6SJohannes Stezenbach 
833b66a2980SThomas Niederprüm 			sta32x_startup_sequence(sta32x);
83454dc6cabSJohannes Stezenbach 			sta32x_cache_sync(codec);
8353fb5eac5SJohannes Stezenbach 			sta32x_watchdog_start(sta32x);
836c034abf6SJohannes Stezenbach 		}
837c034abf6SJohannes Stezenbach 
838a1be4ceaSThomas Niederprüm 		/* Power down */
839a1be4ceaSThomas Niederprüm 		regmap_update_bits(sta32x->regmap, STA32X_CONFF,
840c034abf6SJohannes Stezenbach 				   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
841a1be4ceaSThomas Niederprüm 				   0);
842c034abf6SJohannes Stezenbach 
843c034abf6SJohannes Stezenbach 		break;
844c034abf6SJohannes Stezenbach 
845c034abf6SJohannes Stezenbach 	case SND_SOC_BIAS_OFF:
846c034abf6SJohannes Stezenbach 		/* The chip runs through the power down sequence for us. */
847a1be4ceaSThomas Niederprüm 		regmap_update_bits(sta32x->regmap, STA32X_CONFF,
848a1be4ceaSThomas Niederprüm 				   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, 0);
849c034abf6SJohannes Stezenbach 		msleep(300);
8503fb5eac5SJohannes Stezenbach 		sta32x_watchdog_stop(sta32x);
851b66a2980SThomas Niederprüm 
852b66a2980SThomas Niederprüm 		if (sta32x->gpiod_nreset)
853b66a2980SThomas Niederprüm 			gpiod_set_value(sta32x->gpiod_nreset, 0);
854b66a2980SThomas Niederprüm 
855c034abf6SJohannes Stezenbach 		regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies),
856c034abf6SJohannes Stezenbach 				       sta32x->supplies);
857c034abf6SJohannes Stezenbach 		break;
858c034abf6SJohannes Stezenbach 	}
859c034abf6SJohannes Stezenbach 	codec->dapm.bias_level = level;
860c034abf6SJohannes Stezenbach 	return 0;
861c034abf6SJohannes Stezenbach }
862c034abf6SJohannes Stezenbach 
86385e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops sta32x_dai_ops = {
864c034abf6SJohannes Stezenbach 	.hw_params	= sta32x_hw_params,
865c034abf6SJohannes Stezenbach 	.set_sysclk	= sta32x_set_dai_sysclk,
866c034abf6SJohannes Stezenbach 	.set_fmt	= sta32x_set_dai_fmt,
867c034abf6SJohannes Stezenbach };
868c034abf6SJohannes Stezenbach 
869c034abf6SJohannes Stezenbach static struct snd_soc_dai_driver sta32x_dai = {
870c034abf6SJohannes Stezenbach 	.name = "STA32X",
871c034abf6SJohannes Stezenbach 	.playback = {
872c034abf6SJohannes Stezenbach 		.stream_name = "Playback",
873c034abf6SJohannes Stezenbach 		.channels_min = 2,
874c034abf6SJohannes Stezenbach 		.channels_max = 2,
875c034abf6SJohannes Stezenbach 		.rates = STA32X_RATES,
876c034abf6SJohannes Stezenbach 		.formats = STA32X_FORMATS,
877c034abf6SJohannes Stezenbach 	},
878c034abf6SJohannes Stezenbach 	.ops = &sta32x_dai_ops,
879c034abf6SJohannes Stezenbach };
880c034abf6SJohannes Stezenbach 
881c034abf6SJohannes Stezenbach static int sta32x_probe(struct snd_soc_codec *codec)
882c034abf6SJohannes Stezenbach {
883c034abf6SJohannes Stezenbach 	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
884a1be4ceaSThomas Niederprüm 	struct sta32x_platform_data *pdata = sta32x->pdata;
885e012ba24SJohannes Stezenbach 	int i, ret = 0, thermal = 0;
886c034abf6SJohannes Stezenbach 	ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
887c034abf6SJohannes Stezenbach 				    sta32x->supplies);
888c034abf6SJohannes Stezenbach 	if (ret != 0) {
889c034abf6SJohannes Stezenbach 		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
890aff041afSMark Brown 		return ret;
891c034abf6SJohannes Stezenbach 	}
892c034abf6SJohannes Stezenbach 
893b66a2980SThomas Niederprüm 	ret = sta32x_startup_sequence(sta32x);
894b66a2980SThomas Niederprüm 	if (ret < 0) {
895b66a2980SThomas Niederprüm 		dev_err(codec->dev, "Failed to startup device\n");
896b66a2980SThomas Niederprüm 		return ret;
897b66a2980SThomas Niederprüm 	}
898*f04b1e76SThomas Niederprüm 
899*f04b1e76SThomas Niederprüm 	/* CONFA */
900a1be4ceaSThomas Niederprüm 	if (!pdata->thermal_warning_recovery)
901e012ba24SJohannes Stezenbach 		thermal |= STA32X_CONFA_TWAB;
902a1be4ceaSThomas Niederprüm 	if (!pdata->thermal_warning_adjustment)
903e012ba24SJohannes Stezenbach 		thermal |= STA32X_CONFA_TWRB;
904*f04b1e76SThomas Niederprüm 	if (!pdata->fault_detect_recovery)
905*f04b1e76SThomas Niederprüm 		thermal |= STA32X_CONFA_FDRB;
906a1be4ceaSThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFA,
907*f04b1e76SThomas Niederprüm 			   STA32X_CONFA_TWAB | STA32X_CONFA_TWRB |
908*f04b1e76SThomas Niederprüm 			   STA32X_CONFA_FDRB,
909e012ba24SJohannes Stezenbach 			   thermal);
910c034abf6SJohannes Stezenbach 
911*f04b1e76SThomas Niederprüm 	/* CONFC */
912*f04b1e76SThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFC,
913*f04b1e76SThomas Niederprüm 			   STA32X_CONFC_CSZ_MASK,
914*f04b1e76SThomas Niederprüm 			   pdata->drop_compensation_ns
915*f04b1e76SThomas Niederprüm 				<< STA32X_CONFC_CSZ_SHIFT);
916*f04b1e76SThomas Niederprüm 
917*f04b1e76SThomas Niederprüm 	/* CONFE */
918*f04b1e76SThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
919*f04b1e76SThomas Niederprüm 			   STA32X_CONFE_MPCV,
920*f04b1e76SThomas Niederprüm 			   pdata->max_power_use_mpcc ?
921*f04b1e76SThomas Niederprüm 				STA32X_CONFE_MPCV : 0);
922*f04b1e76SThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
923*f04b1e76SThomas Niederprüm 			   STA32X_CONFE_MPC,
924*f04b1e76SThomas Niederprüm 			   pdata->max_power_correction ?
925*f04b1e76SThomas Niederprüm 				STA32X_CONFE_MPC : 0);
926*f04b1e76SThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
927*f04b1e76SThomas Niederprüm 			   STA32X_CONFE_AME,
928*f04b1e76SThomas Niederprüm 			   pdata->am_reduction_mode ?
929*f04b1e76SThomas Niederprüm 				STA32X_CONFE_AME : 0);
930*f04b1e76SThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
931*f04b1e76SThomas Niederprüm 			   STA32X_CONFE_PWMS,
932*f04b1e76SThomas Niederprüm 			   pdata->odd_pwm_speed_mode ?
933*f04b1e76SThomas Niederprüm 				STA32X_CONFE_PWMS : 0);
934*f04b1e76SThomas Niederprüm 
935*f04b1e76SThomas Niederprüm 	/*  CONFF */
936*f04b1e76SThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFF,
937*f04b1e76SThomas Niederprüm 			   STA32X_CONFF_IDE,
938*f04b1e76SThomas Niederprüm 			   pdata->invalid_input_detect_mute ?
939*f04b1e76SThomas Niederprüm 				STA32X_CONFF_IDE : 0);
940*f04b1e76SThomas Niederprüm 
941e012ba24SJohannes Stezenbach 	/* select output configuration  */
942a1be4ceaSThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_CONFF,
943c034abf6SJohannes Stezenbach 			   STA32X_CONFF_OCFG_MASK,
944a1be4ceaSThomas Niederprüm 			   pdata->output_conf
945e012ba24SJohannes Stezenbach 				<< STA32X_CONFF_OCFG_SHIFT);
946c034abf6SJohannes Stezenbach 
947e012ba24SJohannes Stezenbach 	/* channel to output mapping */
948a1be4ceaSThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_C1CFG,
949c034abf6SJohannes Stezenbach 			   STA32X_CxCFG_OM_MASK,
950a1be4ceaSThomas Niederprüm 			   pdata->ch1_output_mapping
951e012ba24SJohannes Stezenbach 				<< STA32X_CxCFG_OM_SHIFT);
952a1be4ceaSThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_C2CFG,
953c034abf6SJohannes Stezenbach 			   STA32X_CxCFG_OM_MASK,
954a1be4ceaSThomas Niederprüm 			   pdata->ch2_output_mapping
955e012ba24SJohannes Stezenbach 				<< STA32X_CxCFG_OM_SHIFT);
956a1be4ceaSThomas Niederprüm 	regmap_update_bits(sta32x->regmap, STA32X_C3CFG,
957c034abf6SJohannes Stezenbach 			   STA32X_CxCFG_OM_MASK,
958a1be4ceaSThomas Niederprüm 			   pdata->ch3_output_mapping
959e012ba24SJohannes Stezenbach 				<< STA32X_CxCFG_OM_SHIFT);
960c034abf6SJohannes Stezenbach 
96154dc6cabSJohannes Stezenbach 	/* initialize coefficient shadow RAM with reset values */
96254dc6cabSJohannes Stezenbach 	for (i = 4; i <= 49; i += 5)
96354dc6cabSJohannes Stezenbach 		sta32x->coef_shadow[i] = 0x400000;
96454dc6cabSJohannes Stezenbach 	for (i = 50; i <= 54; i++)
96554dc6cabSJohannes Stezenbach 		sta32x->coef_shadow[i] = 0x7fffff;
96654dc6cabSJohannes Stezenbach 	sta32x->coef_shadow[55] = 0x5a9df7;
96754dc6cabSJohannes Stezenbach 	sta32x->coef_shadow[56] = 0x7fffff;
96854dc6cabSJohannes Stezenbach 	sta32x->coef_shadow[59] = 0x7fffff;
96954dc6cabSJohannes Stezenbach 	sta32x->coef_shadow[60] = 0x400000;
97054dc6cabSJohannes Stezenbach 	sta32x->coef_shadow[61] = 0x400000;
97154dc6cabSJohannes Stezenbach 
9723fb5eac5SJohannes Stezenbach 	if (sta32x->pdata->needs_esd_watchdog)
9733fb5eac5SJohannes Stezenbach 		INIT_DELAYED_WORK(&sta32x->watchdog_work, sta32x_watchdog);
9743fb5eac5SJohannes Stezenbach 
975c034abf6SJohannes Stezenbach 	sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
976c034abf6SJohannes Stezenbach 	/* Bias level configuration will have done an extra enable */
977c034abf6SJohannes Stezenbach 	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
978c034abf6SJohannes Stezenbach 
979c034abf6SJohannes Stezenbach 	return 0;
980c034abf6SJohannes Stezenbach }
981c034abf6SJohannes Stezenbach 
982c034abf6SJohannes Stezenbach static int sta32x_remove(struct snd_soc_codec *codec)
983c034abf6SJohannes Stezenbach {
984c034abf6SJohannes Stezenbach 	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
985c034abf6SJohannes Stezenbach 
9863fb5eac5SJohannes Stezenbach 	sta32x_watchdog_stop(sta32x);
987c034abf6SJohannes Stezenbach 	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
988c034abf6SJohannes Stezenbach 
989c034abf6SJohannes Stezenbach 	return 0;
990c034abf6SJohannes Stezenbach }
991c034abf6SJohannes Stezenbach 
992c034abf6SJohannes Stezenbach static const struct snd_soc_codec_driver sta32x_codec = {
993c034abf6SJohannes Stezenbach 	.probe =		sta32x_probe,
994c034abf6SJohannes Stezenbach 	.remove =		sta32x_remove,
995c034abf6SJohannes Stezenbach 	.set_bias_level =	sta32x_set_bias_level,
996815b776cSLars-Peter Clausen 	.suspend_bias_off =	true,
997c034abf6SJohannes Stezenbach 	.controls =		sta32x_snd_controls,
998c034abf6SJohannes Stezenbach 	.num_controls =		ARRAY_SIZE(sta32x_snd_controls),
999c034abf6SJohannes Stezenbach 	.dapm_widgets =		sta32x_dapm_widgets,
1000c034abf6SJohannes Stezenbach 	.num_dapm_widgets =	ARRAY_SIZE(sta32x_dapm_widgets),
1001c034abf6SJohannes Stezenbach 	.dapm_routes =		sta32x_dapm_routes,
1002c034abf6SJohannes Stezenbach 	.num_dapm_routes =	ARRAY_SIZE(sta32x_dapm_routes),
1003c034abf6SJohannes Stezenbach };
1004c034abf6SJohannes Stezenbach 
100529fdf4fbSMark Brown static const struct regmap_config sta32x_regmap = {
100629fdf4fbSMark Brown 	.reg_bits =		8,
100729fdf4fbSMark Brown 	.val_bits =		8,
100829fdf4fbSMark Brown 	.max_register =		STA32X_FDRC2,
100929fdf4fbSMark Brown 	.reg_defaults =		sta32x_regs,
101029fdf4fbSMark Brown 	.num_reg_defaults =	ARRAY_SIZE(sta32x_regs),
101129fdf4fbSMark Brown 	.cache_type =		REGCACHE_RBTREE,
1012a1be4ceaSThomas Niederprüm 	.wr_table =		&sta32x_write_regs,
1013a1be4ceaSThomas Niederprüm 	.rd_table =		&sta32x_read_regs,
1014a1be4ceaSThomas Niederprüm 	.volatile_table =	&sta32x_volatile_regs,
1015a1be4ceaSThomas Niederprüm };
1016*f04b1e76SThomas Niederprüm 
1017*f04b1e76SThomas Niederprüm #ifdef CONFIG_OF
1018*f04b1e76SThomas Niederprüm static const struct of_device_id st32x_dt_ids[] = {
1019*f04b1e76SThomas Niederprüm 	{ .compatible = "st,sta32x", },
1020*f04b1e76SThomas Niederprüm 	{ }
102129fdf4fbSMark Brown };
1022*f04b1e76SThomas Niederprüm MODULE_DEVICE_TABLE(of, st32x_dt_ids);
1023*f04b1e76SThomas Niederprüm 
1024*f04b1e76SThomas Niederprüm static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x)
1025*f04b1e76SThomas Niederprüm {
1026*f04b1e76SThomas Niederprüm 	struct device_node *np = dev->of_node;
1027*f04b1e76SThomas Niederprüm 	struct sta32x_platform_data *pdata;
1028*f04b1e76SThomas Niederprüm 	u16 tmp;
1029*f04b1e76SThomas Niederprüm 
1030*f04b1e76SThomas Niederprüm 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
1031*f04b1e76SThomas Niederprüm 	if (!pdata)
1032*f04b1e76SThomas Niederprüm 		return -ENOMEM;
1033*f04b1e76SThomas Niederprüm 
1034*f04b1e76SThomas Niederprüm 	of_property_read_u8(np, "st,output-conf",
1035*f04b1e76SThomas Niederprüm 			    &pdata->output_conf);
1036*f04b1e76SThomas Niederprüm 	of_property_read_u8(np, "st,ch1-output-mapping",
1037*f04b1e76SThomas Niederprüm 			    &pdata->ch1_output_mapping);
1038*f04b1e76SThomas Niederprüm 	of_property_read_u8(np, "st,ch2-output-mapping",
1039*f04b1e76SThomas Niederprüm 			    &pdata->ch2_output_mapping);
1040*f04b1e76SThomas Niederprüm 	of_property_read_u8(np, "st,ch3-output-mapping",
1041*f04b1e76SThomas Niederprüm 			    &pdata->ch3_output_mapping);
1042*f04b1e76SThomas Niederprüm 
1043*f04b1e76SThomas Niederprüm 	if (of_get_property(np, "st,thermal-warning-recovery", NULL))
1044*f04b1e76SThomas Niederprüm 		pdata->thermal_warning_recovery = 1;
1045*f04b1e76SThomas Niederprüm 	if (of_get_property(np, "st,thermal-warning-adjustment", NULL))
1046*f04b1e76SThomas Niederprüm 		pdata->thermal_warning_adjustment = 1;
1047*f04b1e76SThomas Niederprüm 	if (of_get_property(np, "st,needs_esd_watchdog", NULL))
1048*f04b1e76SThomas Niederprüm 		pdata->needs_esd_watchdog = 1;
1049*f04b1e76SThomas Niederprüm 
1050*f04b1e76SThomas Niederprüm 	tmp = 140;
1051*f04b1e76SThomas Niederprüm 	of_property_read_u16(np, "st,drop-compensation-ns", &tmp);
1052*f04b1e76SThomas Niederprüm 	pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20;
1053*f04b1e76SThomas Niederprüm 
1054*f04b1e76SThomas Niederprüm 	/* CONFE */
1055*f04b1e76SThomas Niederprüm 	if (of_get_property(np, "st,max-power-use-mpcc", NULL))
1056*f04b1e76SThomas Niederprüm 		pdata->max_power_use_mpcc = 1;
1057*f04b1e76SThomas Niederprüm 
1058*f04b1e76SThomas Niederprüm 	if (of_get_property(np, "st,max-power-correction", NULL))
1059*f04b1e76SThomas Niederprüm 		pdata->max_power_correction = 1;
1060*f04b1e76SThomas Niederprüm 
1061*f04b1e76SThomas Niederprüm 	if (of_get_property(np, "st,am-reduction-mode", NULL))
1062*f04b1e76SThomas Niederprüm 		pdata->am_reduction_mode = 1;
1063*f04b1e76SThomas Niederprüm 
1064*f04b1e76SThomas Niederprüm 	if (of_get_property(np, "st,odd-pwm-speed-mode", NULL))
1065*f04b1e76SThomas Niederprüm 		pdata->odd_pwm_speed_mode = 1;
1066*f04b1e76SThomas Niederprüm 
1067*f04b1e76SThomas Niederprüm 	/* CONFF */
1068*f04b1e76SThomas Niederprüm 	if (of_get_property(np, "st,invalid-input-detect-mute", NULL))
1069*f04b1e76SThomas Niederprüm 		pdata->invalid_input_detect_mute = 1;
1070*f04b1e76SThomas Niederprüm 
1071*f04b1e76SThomas Niederprüm 	sta32x->pdata = pdata;
1072*f04b1e76SThomas Niederprüm 
1073*f04b1e76SThomas Niederprüm 	return 0;
1074*f04b1e76SThomas Niederprüm }
1075*f04b1e76SThomas Niederprüm #endif
107629fdf4fbSMark Brown 
10777a79e94eSBill Pemberton static int sta32x_i2c_probe(struct i2c_client *i2c,
1078c034abf6SJohannes Stezenbach 			    const struct i2c_device_id *id)
1079c034abf6SJohannes Stezenbach {
1080a1be4ceaSThomas Niederprüm 	struct device *dev = &i2c->dev;
1081c034abf6SJohannes Stezenbach 	struct sta32x_priv *sta32x;
1082aff041afSMark Brown 	int ret, i;
1083c034abf6SJohannes Stezenbach 
1084d999c021SAxel Lin 	sta32x = devm_kzalloc(&i2c->dev, sizeof(struct sta32x_priv),
1085d999c021SAxel Lin 			      GFP_KERNEL);
1086c034abf6SJohannes Stezenbach 	if (!sta32x)
1087c034abf6SJohannes Stezenbach 		return -ENOMEM;
1088c034abf6SJohannes Stezenbach 
1089a1be4ceaSThomas Niederprüm 	mutex_init(&sta32x->coeff_lock);
1090a1be4ceaSThomas Niederprüm 	sta32x->pdata = dev_get_platdata(dev);
1091b66a2980SThomas Niederprüm 
1092*f04b1e76SThomas Niederprüm #ifdef CONFIG_OF
1093*f04b1e76SThomas Niederprüm 	if (dev->of_node) {
1094*f04b1e76SThomas Niederprüm 		ret = sta32x_probe_dt(dev, sta32x);
1095*f04b1e76SThomas Niederprüm 		if (ret < 0)
1096*f04b1e76SThomas Niederprüm 			return ret;
1097*f04b1e76SThomas Niederprüm 	}
1098*f04b1e76SThomas Niederprüm #endif
1099*f04b1e76SThomas Niederprüm 
1100b66a2980SThomas Niederprüm 	/* GPIOs */
1101b66a2980SThomas Niederprüm 	sta32x->gpiod_nreset = devm_gpiod_get(dev, "reset");
1102b66a2980SThomas Niederprüm 	if (IS_ERR(sta32x->gpiod_nreset)) {
1103b66a2980SThomas Niederprüm 		ret = PTR_ERR(sta32x->gpiod_nreset);
1104b66a2980SThomas Niederprüm 		if (ret != -ENOENT && ret != -ENOSYS)
1105b66a2980SThomas Niederprüm 			return ret;
1106b66a2980SThomas Niederprüm 
1107b66a2980SThomas Niederprüm 		sta32x->gpiod_nreset = NULL;
1108b66a2980SThomas Niederprüm 	} else {
1109b66a2980SThomas Niederprüm 		gpiod_direction_output(sta32x->gpiod_nreset, 0);
1110b66a2980SThomas Niederprüm 	}
1111b66a2980SThomas Niederprüm 
1112aff041afSMark Brown 	/* regulators */
1113aff041afSMark Brown 	for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++)
1114aff041afSMark Brown 		sta32x->supplies[i].supply = sta32x_supply_names[i];
1115aff041afSMark Brown 
1116aff041afSMark Brown 	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(sta32x->supplies),
1117aff041afSMark Brown 				      sta32x->supplies);
1118aff041afSMark Brown 	if (ret != 0) {
1119aff041afSMark Brown 		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
1120aff041afSMark Brown 		return ret;
1121aff041afSMark Brown 	}
1122aff041afSMark Brown 
112329fdf4fbSMark Brown 	sta32x->regmap = devm_regmap_init_i2c(i2c, &sta32x_regmap);
112429fdf4fbSMark Brown 	if (IS_ERR(sta32x->regmap)) {
112529fdf4fbSMark Brown 		ret = PTR_ERR(sta32x->regmap);
1126a1be4ceaSThomas Niederprüm 		dev_err(dev, "Failed to init regmap: %d\n", ret);
112729fdf4fbSMark Brown 		return ret;
112829fdf4fbSMark Brown 	}
112929fdf4fbSMark Brown 
1130c034abf6SJohannes Stezenbach 	i2c_set_clientdata(i2c, sta32x);
1131c034abf6SJohannes Stezenbach 
1132a1be4ceaSThomas Niederprüm 	ret = snd_soc_register_codec(dev, &sta32x_codec, &sta32x_dai, 1);
1133a1be4ceaSThomas Niederprüm 	if (ret < 0)
1134a1be4ceaSThomas Niederprüm 		dev_err(dev, "Failed to register codec (%d)\n", ret);
1135c034abf6SJohannes Stezenbach 
1136d999c021SAxel Lin 	return ret;
1137c034abf6SJohannes Stezenbach }
1138c034abf6SJohannes Stezenbach 
11397a79e94eSBill Pemberton static int sta32x_i2c_remove(struct i2c_client *client)
1140c034abf6SJohannes Stezenbach {
1141c034abf6SJohannes Stezenbach 	snd_soc_unregister_codec(&client->dev);
1142c034abf6SJohannes Stezenbach 	return 0;
1143c034abf6SJohannes Stezenbach }
1144c034abf6SJohannes Stezenbach 
1145c034abf6SJohannes Stezenbach static const struct i2c_device_id sta32x_i2c_id[] = {
1146c034abf6SJohannes Stezenbach 	{ "sta326", 0 },
1147c034abf6SJohannes Stezenbach 	{ "sta328", 0 },
1148c034abf6SJohannes Stezenbach 	{ "sta329", 0 },
1149c034abf6SJohannes Stezenbach 	{ }
1150c034abf6SJohannes Stezenbach };
1151c034abf6SJohannes Stezenbach MODULE_DEVICE_TABLE(i2c, sta32x_i2c_id);
1152c034abf6SJohannes Stezenbach 
1153c034abf6SJohannes Stezenbach static struct i2c_driver sta32x_i2c_driver = {
1154c034abf6SJohannes Stezenbach 	.driver = {
1155c034abf6SJohannes Stezenbach 		.name = "sta32x",
1156c034abf6SJohannes Stezenbach 		.owner = THIS_MODULE,
1157*f04b1e76SThomas Niederprüm 		.of_match_table = of_match_ptr(st32x_dt_ids),
1158c034abf6SJohannes Stezenbach 	},
1159c034abf6SJohannes Stezenbach 	.probe =    sta32x_i2c_probe,
11607a79e94eSBill Pemberton 	.remove =   sta32x_i2c_remove,
1161c034abf6SJohannes Stezenbach 	.id_table = sta32x_i2c_id,
1162c034abf6SJohannes Stezenbach };
1163c034abf6SJohannes Stezenbach 
11640ead1136SSachin Kamat module_i2c_driver(sta32x_i2c_driver);
1165c034abf6SJohannes Stezenbach 
1166c034abf6SJohannes Stezenbach MODULE_DESCRIPTION("ASoC STA32X driver");
1167c034abf6SJohannes Stezenbach MODULE_AUTHOR("Johannes Stezenbach <js@sig21.net>");
1168c034abf6SJohannes Stezenbach MODULE_LICENSE("GPL");
1169