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