blob: b808c65788fa0b5b8eb89a084f781c76dbcd7b89 [file] [log] [blame]
Johannes Stezenbachc034abf2011-06-22 14:59:24 +02001/*
2 * Codec driver for ST STA32x 2.1-channel high-efficiency digital audio system
3 *
4 * Copyright: 2011 Raumfeld GmbH
5 * Author: Johannes Stezenbach <js@sig21.net>
6 *
7 * based on code from:
8 * Wolfson Microelectronics PLC.
9 * Mark Brown <broonie@opensource.wolfsonmicro.com>
10 * Freescale Semiconductor, Inc.
11 * Timur Tabi <timur@freescale.com>
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version.
17 */
18
19#define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__
20
21#include <linux/module.h>
22#include <linux/moduleparam.h>
23#include <linux/init.h>
24#include <linux/delay.h>
25#include <linux/pm.h>
26#include <linux/i2c.h>
Mark Brown29fdf4f2012-09-10 10:59:56 +080027#include <linux/regmap.h>
Johannes Stezenbachc034abf2011-06-22 14:59:24 +020028#include <linux/regulator/consumer.h>
Thomas Niederprümb66a2982015-01-22 00:01:54 +010029#include <linux/gpio/consumer.h>
Johannes Stezenbachc034abf2011-06-22 14:59:24 +020030#include <linux/slab.h>
Johannes Stezenbach3fb5eac2011-11-14 17:23:18 +010031#include <linux/workqueue.h>
Johannes Stezenbachc034abf2011-06-22 14:59:24 +020032#include <sound/core.h>
33#include <sound/pcm.h>
34#include <sound/pcm_params.h>
35#include <sound/soc.h>
36#include <sound/soc-dapm.h>
37#include <sound/initval.h>
38#include <sound/tlv.h>
39
Johannes Stezenbache012ba22011-11-14 17:23:17 +010040#include <sound/sta32x.h>
Johannes Stezenbachc034abf2011-06-22 14:59:24 +020041#include "sta32x.h"
42
43#define STA32X_RATES (SNDRV_PCM_RATE_32000 | \
44 SNDRV_PCM_RATE_44100 | \
45 SNDRV_PCM_RATE_48000 | \
46 SNDRV_PCM_RATE_88200 | \
47 SNDRV_PCM_RATE_96000 | \
48 SNDRV_PCM_RATE_176400 | \
49 SNDRV_PCM_RATE_192000)
50
51#define STA32X_FORMATS \
52 (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
53 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
54 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
55 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
56 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \
57 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE)
58
59/* Power-up register defaults */
Mark Brown29fdf4f2012-09-10 10:59:56 +080060static const struct reg_default sta32x_regs[] = {
61 { 0x0, 0x63 },
62 { 0x1, 0x80 },
63 { 0x2, 0xc2 },
64 { 0x3, 0x40 },
65 { 0x4, 0xc2 },
66 { 0x5, 0x5c },
67 { 0x6, 0x10 },
68 { 0x7, 0xff },
69 { 0x8, 0x60 },
70 { 0x9, 0x60 },
71 { 0xa, 0x60 },
72 { 0xb, 0x80 },
73 { 0xc, 0x00 },
74 { 0xd, 0x00 },
75 { 0xe, 0x00 },
76 { 0xf, 0x40 },
77 { 0x10, 0x80 },
78 { 0x11, 0x77 },
79 { 0x12, 0x6a },
80 { 0x13, 0x69 },
81 { 0x14, 0x6a },
82 { 0x15, 0x69 },
83 { 0x16, 0x00 },
84 { 0x17, 0x00 },
85 { 0x18, 0x00 },
86 { 0x19, 0x00 },
87 { 0x1a, 0x00 },
88 { 0x1b, 0x00 },
89 { 0x1c, 0x00 },
90 { 0x1d, 0x00 },
91 { 0x1e, 0x00 },
92 { 0x1f, 0x00 },
93 { 0x20, 0x00 },
94 { 0x21, 0x00 },
95 { 0x22, 0x00 },
96 { 0x23, 0x00 },
97 { 0x24, 0x00 },
98 { 0x25, 0x00 },
99 { 0x26, 0x00 },
100 { 0x27, 0x2d },
101 { 0x28, 0xc0 },
102 { 0x2b, 0x00 },
103 { 0x2c, 0x0c },
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200104};
105
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100106static const struct regmap_range sta32x_write_regs_range[] = {
107 regmap_reg_range(STA32X_CONFA, STA32X_AUTO2),
108 regmap_reg_range(STA32X_C1CFG, STA32X_FDRC2),
109};
110
111static const struct regmap_range sta32x_read_regs_range[] = {
112 regmap_reg_range(STA32X_CONFA, STA32X_AUTO2),
113 regmap_reg_range(STA32X_C1CFG, STA32X_FDRC2),
114};
115
116static const struct regmap_range sta32x_volatile_regs_range[] = {
117 regmap_reg_range(STA32X_CFADDR2, STA32X_CFUD),
118};
119
120static const struct regmap_access_table sta32x_write_regs = {
121 .yes_ranges = sta32x_write_regs_range,
122 .n_yes_ranges = ARRAY_SIZE(sta32x_write_regs_range),
123};
124
125static const struct regmap_access_table sta32x_read_regs = {
126 .yes_ranges = sta32x_read_regs_range,
127 .n_yes_ranges = ARRAY_SIZE(sta32x_read_regs_range),
128};
129
130static const struct regmap_access_table sta32x_volatile_regs = {
131 .yes_ranges = sta32x_volatile_regs_range,
132 .n_yes_ranges = ARRAY_SIZE(sta32x_volatile_regs_range),
133};
134
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200135/* regulator power supply names */
136static const char *sta32x_supply_names[] = {
137 "Vdda", /* analog supply, 3.3VV */
138 "Vdd3", /* digital supply, 3.3V */
139 "Vcc" /* power amp spply, 10V - 36V */
140};
141
142/* codec private data */
143struct sta32x_priv {
Mark Brown29fdf4f2012-09-10 10:59:56 +0800144 struct regmap *regmap;
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200145 struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)];
146 struct snd_soc_codec *codec;
Johannes Stezenbache012ba22011-11-14 17:23:17 +0100147 struct sta32x_platform_data *pdata;
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200148
149 unsigned int mclk;
150 unsigned int format;
Johannes Stezenbach54dc6ca2011-11-14 17:23:16 +0100151
152 u32 coef_shadow[STA32X_COEF_COUNT];
Johannes Stezenbach3fb5eac2011-11-14 17:23:18 +0100153 struct delayed_work watchdog_work;
154 int shutdown;
Thomas Niederprümb66a2982015-01-22 00:01:54 +0100155 struct gpio_desc *gpiod_nreset;
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100156 struct mutex coeff_lock;
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200157};
158
159static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1);
160static const DECLARE_TLV_DB_SCALE(chvol_tlv, -7950, 50, 1);
161static const DECLARE_TLV_DB_SCALE(tone_tlv, -120, 200, 0);
162
163static const char *sta32x_drc_ac[] = {
164 "Anti-Clipping", "Dynamic Range Compression" };
165static const char *sta32x_auto_eq_mode[] = {
166 "User", "Preset", "Loudness" };
167static const char *sta32x_auto_gc_mode[] = {
168 "User", "AC no clipping", "AC limited clipping (10%)",
169 "DRC nighttime listening mode" };
170static const char *sta32x_auto_xo_mode[] = {
171 "User", "80Hz", "100Hz", "120Hz", "140Hz", "160Hz", "180Hz", "200Hz",
172 "220Hz", "240Hz", "260Hz", "280Hz", "300Hz", "320Hz", "340Hz", "360Hz" };
173static const char *sta32x_preset_eq_mode[] = {
174 "Flat", "Rock", "Soft Rock", "Jazz", "Classical", "Dance", "Pop", "Soft",
175 "Hard", "Party", "Vocal", "Hip-Hop", "Dialog", "Bass-boost #1",
176 "Bass-boost #2", "Bass-boost #3", "Loudness 1", "Loudness 2",
177 "Loudness 3", "Loudness 4", "Loudness 5", "Loudness 6", "Loudness 7",
178 "Loudness 8", "Loudness 9", "Loudness 10", "Loudness 11", "Loudness 12",
179 "Loudness 13", "Loudness 14", "Loudness 15", "Loudness 16" };
180static const char *sta32x_limiter_select[] = {
181 "Limiter Disabled", "Limiter #1", "Limiter #2" };
182static const char *sta32x_limiter_attack_rate[] = {
183 "3.1584", "2.7072", "2.2560", "1.8048", "1.3536", "0.9024",
184 "0.4512", "0.2256", "0.1504", "0.1123", "0.0902", "0.0752",
185 "0.0645", "0.0564", "0.0501", "0.0451" };
186static const char *sta32x_limiter_release_rate[] = {
187 "0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299",
188 "0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137",
189 "0.0134", "0.0117", "0.0110", "0.0104" };
Thomas Niederprüm88483f52015-01-22 00:01:55 +0100190static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_attack_tlv,
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200191 0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0),
192 8, 16, TLV_DB_SCALE_ITEM(300, 100, 0),
Thomas Niederprüm88483f52015-01-22 00:01:55 +0100193);
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200194
Thomas Niederprüm88483f52015-01-22 00:01:55 +0100195static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_release_tlv,
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200196 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
197 1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0),
198 2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0),
199 3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0),
200 8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0),
Thomas Niederprüm88483f52015-01-22 00:01:55 +0100201);
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200202
Thomas Niederprüm88483f52015-01-22 00:01:55 +0100203static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_attack_tlv,
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200204 0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0),
205 8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0),
206 14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0),
Thomas Niederprüm88483f52015-01-22 00:01:55 +0100207);
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200208
Thomas Niederprüm88483f52015-01-22 00:01:55 +0100209static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_release_tlv,
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200210 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
211 1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0),
212 3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0),
213 5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0),
214 13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0),
Thomas Niederprüm88483f52015-01-22 00:01:55 +0100215);
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200216
Takashi Iwai025c3fa2014-02-18 09:24:12 +0100217static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum,
218 STA32X_CONFD, STA32X_CONFD_DRC_SHIFT,
219 sta32x_drc_ac);
220static SOC_ENUM_SINGLE_DECL(sta32x_auto_eq_enum,
221 STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT,
222 sta32x_auto_eq_mode);
223static SOC_ENUM_SINGLE_DECL(sta32x_auto_gc_enum,
224 STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT,
225 sta32x_auto_gc_mode);
226static SOC_ENUM_SINGLE_DECL(sta32x_auto_xo_enum,
227 STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT,
228 sta32x_auto_xo_mode);
229static SOC_ENUM_SINGLE_DECL(sta32x_preset_eq_enum,
230 STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT,
231 sta32x_preset_eq_mode);
232static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch1_enum,
233 STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT,
234 sta32x_limiter_select);
235static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch2_enum,
236 STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT,
237 sta32x_limiter_select);
238static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch3_enum,
239 STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT,
240 sta32x_limiter_select);
241static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_attack_rate_enum,
242 STA32X_L1AR, STA32X_LxA_SHIFT,
243 sta32x_limiter_attack_rate);
244static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_attack_rate_enum,
245 STA32X_L2AR, STA32X_LxA_SHIFT,
246 sta32x_limiter_attack_rate);
247static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_release_rate_enum,
248 STA32X_L1AR, STA32X_LxR_SHIFT,
249 sta32x_limiter_release_rate);
250static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_release_rate_enum,
251 STA32X_L2AR, STA32X_LxR_SHIFT,
252 sta32x_limiter_release_rate);
Johannes Stezenbach79688432011-07-11 17:01:23 +0200253
254/* byte array controls for setting biquad, mixer, scaling coefficients;
255 * for biquads all five coefficients need to be set in one go,
256 * mixer and pre/postscale coefs can be set individually;
257 * each coef is 24bit, the bytes are ordered in the same way
258 * as given in the STA32x data sheet (big endian; b1, b2, a1, a2, b0)
259 */
260
261static int sta32x_coefficient_info(struct snd_kcontrol *kcontrol,
262 struct snd_ctl_elem_info *uinfo)
263{
264 int numcoef = kcontrol->private_value >> 16;
265 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
266 uinfo->count = 3 * numcoef;
267 return 0;
268}
269
270static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
271 struct snd_ctl_elem_value *ucontrol)
272{
Lars-Peter Clausenea53bf72014-03-18 09:02:04 +0100273 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100274 struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
Johannes Stezenbach79688432011-07-11 17:01:23 +0200275 int numcoef = kcontrol->private_value >> 16;
276 int index = kcontrol->private_value & 0xffff;
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100277 unsigned int cfud, val;
278 int i, ret = 0;
279
280 mutex_lock(&sta32x->coeff_lock);
Johannes Stezenbach79688432011-07-11 17:01:23 +0200281
282 /* preserve reserved bits in STA32X_CFUD */
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100283 regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
284 cfud &= 0xf0;
285 /*
286 * chip documentation does not say if the bits are self clearing,
287 * so do it explicitly
288 */
289 regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
Johannes Stezenbach79688432011-07-11 17:01:23 +0200290
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100291 regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
292 if (numcoef == 1) {
293 regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x04);
294 } else if (numcoef == 5) {
295 regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x08);
296 } else {
297 ret = -EINVAL;
298 goto exit_unlock;
299 }
Johannes Stezenbach79688432011-07-11 17:01:23 +0200300
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100301 for (i = 0; i < 3 * numcoef; i++) {
302 regmap_read(sta32x->regmap, STA32X_B1CF1 + i, &val);
303 ucontrol->value.bytes.data[i] = val;
304 }
305
306exit_unlock:
307 mutex_unlock(&sta32x->coeff_lock);
308
309 return ret;
Johannes Stezenbach79688432011-07-11 17:01:23 +0200310}
311
312static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
313 struct snd_ctl_elem_value *ucontrol)
314{
Lars-Peter Clausenea53bf72014-03-18 09:02:04 +0100315 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
Johannes Stezenbach54dc6ca2011-11-14 17:23:16 +0100316 struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
Johannes Stezenbach79688432011-07-11 17:01:23 +0200317 int numcoef = kcontrol->private_value >> 16;
318 int index = kcontrol->private_value & 0xffff;
319 unsigned int cfud;
320 int i;
321
322 /* preserve reserved bits in STA32X_CFUD */
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100323 regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
324 cfud &= 0xf0;
325 /*
326 * chip documentation does not say if the bits are self clearing,
327 * so do it explicitly
328 */
329 regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
Johannes Stezenbach79688432011-07-11 17:01:23 +0200330
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100331 regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
Johannes Stezenbach54dc6ca2011-11-14 17:23:16 +0100332 for (i = 0; i < numcoef && (index + i < STA32X_COEF_COUNT); i++)
333 sta32x->coef_shadow[index + i] =
334 (ucontrol->value.bytes.data[3 * i] << 16)
335 | (ucontrol->value.bytes.data[3 * i + 1] << 8)
336 | (ucontrol->value.bytes.data[3 * i + 2]);
Johannes Stezenbach79688432011-07-11 17:01:23 +0200337 for (i = 0; i < 3 * numcoef; i++)
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100338 regmap_write(sta32x->regmap, STA32X_B1CF1 + i,
339 ucontrol->value.bytes.data[i]);
Johannes Stezenbach79688432011-07-11 17:01:23 +0200340 if (numcoef == 1)
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100341 regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
Johannes Stezenbach79688432011-07-11 17:01:23 +0200342 else if (numcoef == 5)
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100343 regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x02);
Johannes Stezenbach79688432011-07-11 17:01:23 +0200344 else
345 return -EINVAL;
346
347 return 0;
348}
349
Mark Brown878042d2011-11-24 17:31:12 +0000350static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec)
Johannes Stezenbach54dc6ca2011-11-14 17:23:16 +0100351{
352 struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
353 unsigned int cfud;
354 int i;
355
356 /* preserve reserved bits in STA32X_CFUD */
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100357 regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
358 cfud &= 0xf0;
Johannes Stezenbach54dc6ca2011-11-14 17:23:16 +0100359
360 for (i = 0; i < STA32X_COEF_COUNT; i++) {
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100361 regmap_write(sta32x->regmap, STA32X_CFADDR2, i);
362 regmap_write(sta32x->regmap, STA32X_B1CF1,
363 (sta32x->coef_shadow[i] >> 16) & 0xff);
364 regmap_write(sta32x->regmap, STA32X_B1CF2,
365 (sta32x->coef_shadow[i] >> 8) & 0xff);
366 regmap_write(sta32x->regmap, STA32X_B1CF3,
367 (sta32x->coef_shadow[i]) & 0xff);
368 /*
369 * chip documentation does not say if the bits are
370 * self-clearing, so do it explicitly
371 */
372 regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
373 regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
Johannes Stezenbach54dc6ca2011-11-14 17:23:16 +0100374 }
375 return 0;
376}
377
Mark Brown878042d2011-11-24 17:31:12 +0000378static int sta32x_cache_sync(struct snd_soc_codec *codec)
Johannes Stezenbach54dc6ca2011-11-14 17:23:16 +0100379{
Lars-Peter Clausen70ff00f2014-02-22 18:27:17 +0100380 struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
Johannes Stezenbach54dc6ca2011-11-14 17:23:16 +0100381 unsigned int mute;
382 int rc;
383
Johannes Stezenbach54dc6ca2011-11-14 17:23:16 +0100384 /* mute during register sync */
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100385 regmap_read(sta32x->regmap, STA32X_MMUTE, &mute);
386 regmap_write(sta32x->regmap, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE);
Johannes Stezenbach54dc6ca2011-11-14 17:23:16 +0100387 sta32x_sync_coef_shadow(codec);
Mark Brown29fdf4f2012-09-10 10:59:56 +0800388 rc = regcache_sync(sta32x->regmap);
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100389 regmap_write(sta32x->regmap, STA32X_MMUTE, mute);
Johannes Stezenbach54dc6ca2011-11-14 17:23:16 +0100390 return rc;
391}
392
Johannes Stezenbach3fb5eac2011-11-14 17:23:18 +0100393/* work around ESD issue where sta32x resets and loses all configuration */
394static void sta32x_watchdog(struct work_struct *work)
395{
396 struct sta32x_priv *sta32x = container_of(work, struct sta32x_priv,
397 watchdog_work.work);
398 struct snd_soc_codec *codec = sta32x->codec;
399 unsigned int confa, confa_cached;
400
401 /* check if sta32x has reset itself */
402 confa_cached = snd_soc_read(codec, STA32X_CONFA);
Mark Brown29fdf4f2012-09-10 10:59:56 +0800403 regcache_cache_bypass(sta32x->regmap, true);
Johannes Stezenbach3fb5eac2011-11-14 17:23:18 +0100404 confa = snd_soc_read(codec, STA32X_CONFA);
Mark Brown29fdf4f2012-09-10 10:59:56 +0800405 regcache_cache_bypass(sta32x->regmap, false);
Johannes Stezenbach3fb5eac2011-11-14 17:23:18 +0100406 if (confa != confa_cached) {
Mark Brown29fdf4f2012-09-10 10:59:56 +0800407 regcache_mark_dirty(sta32x->regmap);
Johannes Stezenbach3fb5eac2011-11-14 17:23:18 +0100408 sta32x_cache_sync(codec);
409 }
410
411 if (!sta32x->shutdown)
Mark Browna14d9822013-07-18 22:43:19 +0100412 queue_delayed_work(system_power_efficient_wq,
413 &sta32x->watchdog_work,
414 round_jiffies_relative(HZ));
Johannes Stezenbach3fb5eac2011-11-14 17:23:18 +0100415}
416
417static void sta32x_watchdog_start(struct sta32x_priv *sta32x)
418{
419 if (sta32x->pdata->needs_esd_watchdog) {
420 sta32x->shutdown = 0;
Mark Browna14d9822013-07-18 22:43:19 +0100421 queue_delayed_work(system_power_efficient_wq,
422 &sta32x->watchdog_work,
423 round_jiffies_relative(HZ));
Johannes Stezenbach3fb5eac2011-11-14 17:23:18 +0100424 }
425}
426
427static void sta32x_watchdog_stop(struct sta32x_priv *sta32x)
428{
429 if (sta32x->pdata->needs_esd_watchdog) {
430 sta32x->shutdown = 1;
431 cancel_delayed_work_sync(&sta32x->watchdog_work);
432 }
433}
434
Johannes Stezenbach79688432011-07-11 17:01:23 +0200435#define SINGLE_COEF(xname, index) \
436{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
437 .info = sta32x_coefficient_info, \
438 .get = sta32x_coefficient_get,\
439 .put = sta32x_coefficient_put, \
440 .private_value = index | (1 << 16) }
441
442#define BIQUAD_COEFS(xname, index) \
443{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
444 .info = sta32x_coefficient_info, \
445 .get = sta32x_coefficient_get,\
446 .put = sta32x_coefficient_put, \
447 .private_value = index | (5 << 16) }
448
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200449static const struct snd_kcontrol_new sta32x_snd_controls[] = {
450SOC_SINGLE_TLV("Master Volume", STA32X_MVOL, 0, 0xff, 1, mvol_tlv),
451SOC_SINGLE("Master Switch", STA32X_MMUTE, 0, 1, 1),
452SOC_SINGLE("Ch1 Switch", STA32X_MMUTE, 1, 1, 1),
453SOC_SINGLE("Ch2 Switch", STA32X_MMUTE, 2, 1, 1),
454SOC_SINGLE("Ch3 Switch", STA32X_MMUTE, 3, 1, 1),
455SOC_SINGLE_TLV("Ch1 Volume", STA32X_C1VOL, 0, 0xff, 1, chvol_tlv),
456SOC_SINGLE_TLV("Ch2 Volume", STA32X_C2VOL, 0, 0xff, 1, chvol_tlv),
457SOC_SINGLE_TLV("Ch3 Volume", STA32X_C3VOL, 0, 0xff, 1, chvol_tlv),
458SOC_SINGLE("De-emphasis Filter Switch", STA32X_CONFD, STA32X_CONFD_DEMP_SHIFT, 1, 0),
459SOC_ENUM("Compressor/Limiter Switch", sta32x_drc_ac_enum),
460SOC_SINGLE("Miami Mode Switch", STA32X_CONFD, STA32X_CONFD_MME_SHIFT, 1, 0),
461SOC_SINGLE("Zero Cross Switch", STA32X_CONFE, STA32X_CONFE_ZCE_SHIFT, 1, 0),
462SOC_SINGLE("Soft Ramp Switch", STA32X_CONFE, STA32X_CONFE_SVE_SHIFT, 1, 0),
463SOC_SINGLE("Auto-Mute Switch", STA32X_CONFF, STA32X_CONFF_IDE_SHIFT, 1, 0),
464SOC_ENUM("Automode EQ", sta32x_auto_eq_enum),
465SOC_ENUM("Automode GC", sta32x_auto_gc_enum),
466SOC_ENUM("Automode XO", sta32x_auto_xo_enum),
467SOC_ENUM("Preset EQ", sta32x_preset_eq_enum),
468SOC_SINGLE("Ch1 Tone Control Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0),
469SOC_SINGLE("Ch2 Tone Control Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0),
470SOC_SINGLE("Ch1 EQ Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0),
471SOC_SINGLE("Ch2 EQ Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0),
472SOC_SINGLE("Ch1 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0),
473SOC_SINGLE("Ch2 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0),
474SOC_SINGLE("Ch3 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0),
475SOC_ENUM("Ch1 Limiter Select", sta32x_limiter_ch1_enum),
476SOC_ENUM("Ch2 Limiter Select", sta32x_limiter_ch2_enum),
477SOC_ENUM("Ch3 Limiter Select", sta32x_limiter_ch3_enum),
478SOC_SINGLE_TLV("Bass Tone Control", STA32X_TONE, STA32X_TONE_BTC_SHIFT, 15, 0, tone_tlv),
479SOC_SINGLE_TLV("Treble Tone Control", STA32X_TONE, STA32X_TONE_TTC_SHIFT, 15, 0, tone_tlv),
480SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum),
481SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum),
482SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum),
Takashi Iwaib3619b22014-02-27 07:41:32 +0100483SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter2_release_rate_enum),
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200484
485/* depending on mode, the attack/release thresholds have
486 * two different enum definitions; provide both
487 */
488SOC_SINGLE_TLV("Limiter1 Attack Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT,
489 16, 0, sta32x_limiter_ac_attack_tlv),
490SOC_SINGLE_TLV("Limiter2 Attack Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT,
491 16, 0, sta32x_limiter_ac_attack_tlv),
492SOC_SINGLE_TLV("Limiter1 Release Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT,
493 16, 0, sta32x_limiter_ac_release_tlv),
494SOC_SINGLE_TLV("Limiter2 Release Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT,
495 16, 0, sta32x_limiter_ac_release_tlv),
496SOC_SINGLE_TLV("Limiter1 Attack Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT,
497 16, 0, sta32x_limiter_drc_attack_tlv),
498SOC_SINGLE_TLV("Limiter2 Attack Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT,
499 16, 0, sta32x_limiter_drc_attack_tlv),
500SOC_SINGLE_TLV("Limiter1 Release Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT,
501 16, 0, sta32x_limiter_drc_release_tlv),
502SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT,
503 16, 0, sta32x_limiter_drc_release_tlv),
Johannes Stezenbach79688432011-07-11 17:01:23 +0200504
505BIQUAD_COEFS("Ch1 - Biquad 1", 0),
506BIQUAD_COEFS("Ch1 - Biquad 2", 5),
507BIQUAD_COEFS("Ch1 - Biquad 3", 10),
508BIQUAD_COEFS("Ch1 - Biquad 4", 15),
509BIQUAD_COEFS("Ch2 - Biquad 1", 20),
510BIQUAD_COEFS("Ch2 - Biquad 2", 25),
511BIQUAD_COEFS("Ch2 - Biquad 3", 30),
512BIQUAD_COEFS("Ch2 - Biquad 4", 35),
513BIQUAD_COEFS("High-pass", 40),
514BIQUAD_COEFS("Low-pass", 45),
515SINGLE_COEF("Ch1 - Prescale", 50),
516SINGLE_COEF("Ch2 - Prescale", 51),
517SINGLE_COEF("Ch1 - Postscale", 52),
518SINGLE_COEF("Ch2 - Postscale", 53),
519SINGLE_COEF("Ch3 - Postscale", 54),
520SINGLE_COEF("Thermal warning - Postscale", 55),
521SINGLE_COEF("Ch1 - Mix 1", 56),
522SINGLE_COEF("Ch1 - Mix 2", 57),
523SINGLE_COEF("Ch2 - Mix 1", 58),
524SINGLE_COEF("Ch2 - Mix 2", 59),
525SINGLE_COEF("Ch3 - Mix 1", 60),
526SINGLE_COEF("Ch3 - Mix 2", 61),
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200527};
528
529static const struct snd_soc_dapm_widget sta32x_dapm_widgets[] = {
530SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
531SND_SOC_DAPM_OUTPUT("LEFT"),
532SND_SOC_DAPM_OUTPUT("RIGHT"),
533SND_SOC_DAPM_OUTPUT("SUB"),
534};
535
536static const struct snd_soc_dapm_route sta32x_dapm_routes[] = {
537 { "LEFT", NULL, "DAC" },
538 { "RIGHT", NULL, "DAC" },
539 { "SUB", NULL, "DAC" },
540};
541
542/* MCLK interpolation ratio per fs */
543static struct {
544 int fs;
545 int ir;
546} interpolation_ratios[] = {
547 { 32000, 0 },
548 { 44100, 0 },
549 { 48000, 0 },
550 { 88200, 1 },
551 { 96000, 1 },
552 { 176400, 2 },
553 { 192000, 2 },
554};
555
556/* MCLK to fs clock ratios */
557static struct {
558 int ratio;
559 int mcs;
560} mclk_ratios[3][7] = {
561 { { 768, 0 }, { 512, 1 }, { 384, 2 }, { 256, 3 },
562 { 128, 4 }, { 576, 5 }, { 0, 0 } },
563 { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } },
564 { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } },
565};
566
567
568/**
569 * sta32x_set_dai_sysclk - configure MCLK
570 * @codec_dai: the codec DAI
571 * @clk_id: the clock ID (ignored)
572 * @freq: the MCLK input frequency
573 * @dir: the clock direction (ignored)
574 *
575 * The value of MCLK is used to determine which sample rates are supported
576 * by the STA32X, based on the mclk_ratios table.
577 *
578 * This function must be called by the machine driver's 'startup' function,
579 * otherwise the list of supported sample rates will not be available in
580 * time for ALSA.
581 *
582 * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause
583 * theoretically possible sample rates to be enabled. Call it again with a
584 * proper value set one the external clock is set (most probably you would do
585 * that from a machine's driver 'hw_param' hook.
586 */
587static int sta32x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
588 int clk_id, unsigned int freq, int dir)
589{
590 struct snd_soc_codec *codec = codec_dai->codec;
591 struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
592 int i, j, ir, fs;
593 unsigned int rates = 0;
594 unsigned int rate_min = -1;
595 unsigned int rate_max = 0;
596
597 pr_debug("mclk=%u\n", freq);
598 sta32x->mclk = freq;
599
600 if (sta32x->mclk) {
601 for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) {
602 ir = interpolation_ratios[i].ir;
603 fs = interpolation_ratios[i].fs;
604 for (j = 0; mclk_ratios[ir][j].ratio; j++) {
605 if (mclk_ratios[ir][j].ratio * fs == freq) {
606 rates |= snd_pcm_rate_to_rate_bit(fs);
607 if (fs < rate_min)
608 rate_min = fs;
609 if (fs > rate_max)
610 rate_max = fs;
Axel Lin7a748e42012-01-01 18:36:14 +0800611 break;
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200612 }
613 }
614 }
615 /* FIXME: soc should support a rate list */
616 rates &= ~SNDRV_PCM_RATE_KNOT;
617
618 if (!rates) {
619 dev_err(codec->dev, "could not find a valid sample rate\n");
620 return -EINVAL;
621 }
622 } else {
623 /* enable all possible rates */
624 rates = STA32X_RATES;
625 rate_min = 32000;
626 rate_max = 192000;
627 }
628
629 codec_dai->driver->playback.rates = rates;
630 codec_dai->driver->playback.rate_min = rate_min;
631 codec_dai->driver->playback.rate_max = rate_max;
632 return 0;
633}
634
635/**
636 * sta32x_set_dai_fmt - configure the codec for the selected audio format
637 * @codec_dai: the codec DAI
638 * @fmt: a SND_SOC_DAIFMT_x value indicating the data format
639 *
640 * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the
641 * codec accordingly.
642 */
643static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai,
644 unsigned int fmt)
645{
646 struct snd_soc_codec *codec = codec_dai->codec;
647 struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100648 u8 confb = 0;
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200649
650 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
651 case SND_SOC_DAIFMT_CBS_CFS:
652 break;
653 default:
654 return -EINVAL;
655 }
656
657 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
658 case SND_SOC_DAIFMT_I2S:
659 case SND_SOC_DAIFMT_RIGHT_J:
660 case SND_SOC_DAIFMT_LEFT_J:
661 sta32x->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
662 break;
663 default:
664 return -EINVAL;
665 }
666
667 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
668 case SND_SOC_DAIFMT_NB_NF:
669 confb |= STA32X_CONFB_C2IM;
670 break;
671 case SND_SOC_DAIFMT_NB_IF:
672 confb |= STA32X_CONFB_C1IM;
673 break;
674 default:
675 return -EINVAL;
676 }
677
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100678 return regmap_update_bits(sta32x->regmap, STA32X_CONFB,
679 STA32X_CONFB_C1IM | STA32X_CONFB_C2IM, confb);
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200680}
681
682/**
683 * sta32x_hw_params - program the STA32X with the given hardware parameters.
684 * @substream: the audio stream
685 * @params: the hardware parameters to set
686 * @dai: the SOC DAI (ignored)
687 *
688 * This function programs the hardware with the values provided.
689 * Specifically, the sample rate and the data format.
690 */
691static int sta32x_hw_params(struct snd_pcm_substream *substream,
692 struct snd_pcm_hw_params *params,
693 struct snd_soc_dai *dai)
694{
Mark Browne6968a12012-04-04 15:58:16 +0100695 struct snd_soc_codec *codec = dai->codec;
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200696 struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
697 unsigned int rate;
698 int i, mcs = -1, ir = -1;
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100699 unsigned int confa, confb;
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200700
701 rate = params_rate(params);
702 pr_debug("rate: %u\n", rate);
703 for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++)
Axel Lina5952382011-08-14 11:31:04 +0800704 if (interpolation_ratios[i].fs == rate) {
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200705 ir = interpolation_ratios[i].ir;
Axel Lina5952382011-08-14 11:31:04 +0800706 break;
707 }
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200708 if (ir < 0)
709 return -EINVAL;
710 for (i = 0; mclk_ratios[ir][i].ratio; i++)
Axel Lina5952382011-08-14 11:31:04 +0800711 if (mclk_ratios[ir][i].ratio * rate == sta32x->mclk) {
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200712 mcs = mclk_ratios[ir][i].mcs;
Axel Lina5952382011-08-14 11:31:04 +0800713 break;
714 }
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200715 if (mcs < 0)
716 return -EINVAL;
717
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100718 confa = (ir << STA32X_CONFA_IR_SHIFT) |
719 (mcs << STA32X_CONFA_MCS_SHIFT);
720 confb = 0;
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200721
Mark Brown737e0f82014-07-31 12:47:24 +0100722 switch (params_width(params)) {
723 case 24:
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200724 pr_debug("24bit\n");
725 /* fall through */
Mark Brown737e0f82014-07-31 12:47:24 +0100726 case 32:
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200727 pr_debug("24bit or 32bit\n");
728 switch (sta32x->format) {
729 case SND_SOC_DAIFMT_I2S:
730 confb |= 0x0;
731 break;
732 case SND_SOC_DAIFMT_LEFT_J:
733 confb |= 0x1;
734 break;
735 case SND_SOC_DAIFMT_RIGHT_J:
736 confb |= 0x2;
737 break;
738 }
739
740 break;
Mark Brown737e0f82014-07-31 12:47:24 +0100741 case 20:
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200742 pr_debug("20bit\n");
743 switch (sta32x->format) {
744 case SND_SOC_DAIFMT_I2S:
745 confb |= 0x4;
746 break;
747 case SND_SOC_DAIFMT_LEFT_J:
748 confb |= 0x5;
749 break;
750 case SND_SOC_DAIFMT_RIGHT_J:
751 confb |= 0x6;
752 break;
753 }
754
755 break;
Mark Brown737e0f82014-07-31 12:47:24 +0100756 case 18:
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200757 pr_debug("18bit\n");
758 switch (sta32x->format) {
759 case SND_SOC_DAIFMT_I2S:
760 confb |= 0x8;
761 break;
762 case SND_SOC_DAIFMT_LEFT_J:
763 confb |= 0x9;
764 break;
765 case SND_SOC_DAIFMT_RIGHT_J:
766 confb |= 0xa;
767 break;
768 }
769
770 break;
Mark Brown737e0f82014-07-31 12:47:24 +0100771 case 16:
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200772 pr_debug("16bit\n");
773 switch (sta32x->format) {
774 case SND_SOC_DAIFMT_I2S:
775 confb |= 0x0;
776 break;
777 case SND_SOC_DAIFMT_LEFT_J:
778 confb |= 0xd;
779 break;
780 case SND_SOC_DAIFMT_RIGHT_J:
781 confb |= 0xe;
782 break;
783 }
784
785 break;
786 default:
787 return -EINVAL;
788 }
789
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100790 ret = regmap_update_bits(sta32x->regmap, STA32X_CONFA,
791 STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK,
792 confa);
793 if (ret < 0)
794 return ret;
795
796 ret = regmap_update_bits(sta32x->regmap, STA32X_CONFB,
797 STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB,
798 confb);
799 if (ret < 0)
800 return ret;
801
802 return 0;
803}
Thomas Niederprümb66a2982015-01-22 00:01:54 +0100804
805static int sta32x_startup_sequence(struct sta32x_priv *sta32x)
806{
807 if (sta32x->gpiod_nreset) {
808 gpiod_set_value(sta32x->gpiod_nreset, 0);
809 mdelay(1);
810 gpiod_set_value(sta32x->gpiod_nreset, 1);
811 mdelay(1);
812 }
813
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200814 return 0;
815}
816
817/**
818 * sta32x_set_bias_level - DAPM callback
819 * @codec: the codec device
820 * @level: DAPM power level
821 *
822 * This is called by ALSA to put the codec into low power mode
823 * or to wake it up. If the codec is powered off completely
824 * all registers must be restored after power on.
825 */
826static int sta32x_set_bias_level(struct snd_soc_codec *codec,
827 enum snd_soc_bias_level level)
828{
829 int ret;
830 struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
831
832 pr_debug("level = %d\n", level);
833 switch (level) {
834 case SND_SOC_BIAS_ON:
835 break;
836
837 case SND_SOC_BIAS_PREPARE:
838 /* Full power on */
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100839 regmap_update_bits(sta32x->regmap, STA32X_CONFF,
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200840 STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
841 STA32X_CONFF_PWDN | STA32X_CONFF_EAPD);
842 break;
843
844 case SND_SOC_BIAS_STANDBY:
845 if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
846 ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
847 sta32x->supplies);
848 if (ret != 0) {
849 dev_err(codec->dev,
850 "Failed to enable supplies: %d\n", ret);
851 return ret;
852 }
853
Thomas Niederprümb66a2982015-01-22 00:01:54 +0100854 sta32x_startup_sequence(sta32x);
Johannes Stezenbach54dc6ca2011-11-14 17:23:16 +0100855 sta32x_cache_sync(codec);
Johannes Stezenbach3fb5eac2011-11-14 17:23:18 +0100856 sta32x_watchdog_start(sta32x);
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200857 }
858
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100859 /* Power down */
860 regmap_update_bits(sta32x->regmap, STA32X_CONFF,
861 STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
862 0);
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200863
864 break;
865
866 case SND_SOC_BIAS_OFF:
867 /* The chip runs through the power down sequence for us. */
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100868 regmap_update_bits(sta32x->regmap, STA32X_CONFF,
869 STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, 0);
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200870 msleep(300);
Johannes Stezenbach3fb5eac2011-11-14 17:23:18 +0100871 sta32x_watchdog_stop(sta32x);
Thomas Niederprümb66a2982015-01-22 00:01:54 +0100872
873 if (sta32x->gpiod_nreset)
874 gpiod_set_value(sta32x->gpiod_nreset, 0);
875
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200876 regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies),
877 sta32x->supplies);
878 break;
879 }
880 codec->dapm.bias_level = level;
881 return 0;
882}
883
Lars-Peter Clausen85e76522011-11-23 11:40:40 +0100884static const struct snd_soc_dai_ops sta32x_dai_ops = {
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200885 .hw_params = sta32x_hw_params,
886 .set_sysclk = sta32x_set_dai_sysclk,
887 .set_fmt = sta32x_set_dai_fmt,
888};
889
890static struct snd_soc_dai_driver sta32x_dai = {
891 .name = "STA32X",
892 .playback = {
893 .stream_name = "Playback",
894 .channels_min = 2,
895 .channels_max = 2,
896 .rates = STA32X_RATES,
897 .formats = STA32X_FORMATS,
898 },
899 .ops = &sta32x_dai_ops,
900};
901
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200902static int sta32x_probe(struct snd_soc_codec *codec)
903{
904 struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100905 struct sta32x_platform_data *pdata = sta32x->pdata;
Johannes Stezenbache012ba22011-11-14 17:23:17 +0100906 int i, ret = 0, thermal = 0;
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200907 ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
908 sta32x->supplies);
909 if (ret != 0) {
910 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
Mark Brownaff041a2012-09-10 10:59:51 +0800911 return ret;
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200912 }
913
Thomas Niederprümb66a2982015-01-22 00:01:54 +0100914 ret = sta32x_startup_sequence(sta32x);
915 if (ret < 0) {
916 dev_err(codec->dev, "Failed to startup device\n");
917 return ret;
918 }
Johannes Stezenbache012ba22011-11-14 17:23:17 +0100919 /* set thermal warning adjustment and recovery */
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100920 if (!pdata->thermal_warning_recovery)
Johannes Stezenbache012ba22011-11-14 17:23:17 +0100921 thermal |= STA32X_CONFA_TWAB;
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100922 if (!pdata->thermal_warning_adjustment)
Johannes Stezenbache012ba22011-11-14 17:23:17 +0100923 thermal |= STA32X_CONFA_TWRB;
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100924 regmap_update_bits(sta32x->regmap, STA32X_CONFA,
925 STA32X_CONFA_TWAB | STA32X_CONFA_TWRB,
926 thermal);
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200927
Johannes Stezenbache012ba22011-11-14 17:23:17 +0100928 /* select output configuration */
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100929 regmap_update_bits(sta32x->regmap, STA32X_CONFF,
930 STA32X_CONFF_OCFG_MASK,
931 pdata->output_conf
932 << STA32X_CONFF_OCFG_SHIFT);
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200933
Johannes Stezenbache012ba22011-11-14 17:23:17 +0100934 /* channel to output mapping */
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100935 regmap_update_bits(sta32x->regmap, STA32X_C1CFG,
936 STA32X_CxCFG_OM_MASK,
937 pdata->ch1_output_mapping
938 << STA32X_CxCFG_OM_SHIFT);
939 regmap_update_bits(sta32x->regmap, STA32X_C2CFG,
940 STA32X_CxCFG_OM_MASK,
941 pdata->ch2_output_mapping
942 << STA32X_CxCFG_OM_SHIFT);
943 regmap_update_bits(sta32x->regmap, STA32X_C3CFG,
944 STA32X_CxCFG_OM_MASK,
945 pdata->ch3_output_mapping
946 << STA32X_CxCFG_OM_SHIFT);
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200947
Johannes Stezenbach54dc6ca2011-11-14 17:23:16 +0100948 /* initialize coefficient shadow RAM with reset values */
949 for (i = 4; i <= 49; i += 5)
950 sta32x->coef_shadow[i] = 0x400000;
951 for (i = 50; i <= 54; i++)
952 sta32x->coef_shadow[i] = 0x7fffff;
953 sta32x->coef_shadow[55] = 0x5a9df7;
954 sta32x->coef_shadow[56] = 0x7fffff;
955 sta32x->coef_shadow[59] = 0x7fffff;
956 sta32x->coef_shadow[60] = 0x400000;
957 sta32x->coef_shadow[61] = 0x400000;
958
Johannes Stezenbach3fb5eac2011-11-14 17:23:18 +0100959 if (sta32x->pdata->needs_esd_watchdog)
960 INIT_DELAYED_WORK(&sta32x->watchdog_work, sta32x_watchdog);
961
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200962 sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
963 /* Bias level configuration will have done an extra enable */
964 regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
965
966 return 0;
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200967}
968
969static int sta32x_remove(struct snd_soc_codec *codec)
970{
971 struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
972
Johannes Stezenbach3fb5eac2011-11-14 17:23:18 +0100973 sta32x_watchdog_stop(sta32x);
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200974 regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200975
976 return 0;
977}
978
979static const struct snd_soc_codec_driver sta32x_codec = {
980 .probe = sta32x_probe,
981 .remove = sta32x_remove,
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200982 .set_bias_level = sta32x_set_bias_level,
Lars-Peter Clausen815b7762014-10-20 10:56:36 +0200983 .suspend_bias_off = true,
Johannes Stezenbachc034abf2011-06-22 14:59:24 +0200984 .controls = sta32x_snd_controls,
985 .num_controls = ARRAY_SIZE(sta32x_snd_controls),
986 .dapm_widgets = sta32x_dapm_widgets,
987 .num_dapm_widgets = ARRAY_SIZE(sta32x_dapm_widgets),
988 .dapm_routes = sta32x_dapm_routes,
989 .num_dapm_routes = ARRAY_SIZE(sta32x_dapm_routes),
990};
991
Mark Brown29fdf4f2012-09-10 10:59:56 +0800992static const struct regmap_config sta32x_regmap = {
993 .reg_bits = 8,
994 .val_bits = 8,
995 .max_register = STA32X_FDRC2,
996 .reg_defaults = sta32x_regs,
997 .num_reg_defaults = ARRAY_SIZE(sta32x_regs),
998 .cache_type = REGCACHE_RBTREE,
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +0100999 .wr_table = &sta32x_write_regs,
1000 .rd_table = &sta32x_read_regs,
1001 .volatile_table = &sta32x_volatile_regs,
1002};
Mark Brown29fdf4f2012-09-10 10:59:56 +08001003};
1004
Bill Pemberton7a79e942012-12-07 09:26:37 -05001005static int sta32x_i2c_probe(struct i2c_client *i2c,
1006 const struct i2c_device_id *id)
Johannes Stezenbachc034abf2011-06-22 14:59:24 +02001007{
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +01001008 struct device *dev = &i2c->dev;
Johannes Stezenbachc034abf2011-06-22 14:59:24 +02001009 struct sta32x_priv *sta32x;
Mark Brownaff041a2012-09-10 10:59:51 +08001010 int ret, i;
Johannes Stezenbachc034abf2011-06-22 14:59:24 +02001011
Axel Lind999c022011-12-29 12:06:39 +08001012 sta32x = devm_kzalloc(&i2c->dev, sizeof(struct sta32x_priv),
1013 GFP_KERNEL);
Johannes Stezenbachc034abf2011-06-22 14:59:24 +02001014 if (!sta32x)
1015 return -ENOMEM;
1016
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +01001017 mutex_init(&sta32x->coeff_lock);
1018 sta32x->pdata = dev_get_platdata(dev);
Thomas Niederprümb66a2982015-01-22 00:01:54 +01001019
1020 /* GPIOs */
1021 sta32x->gpiod_nreset = devm_gpiod_get(dev, "reset");
1022 if (IS_ERR(sta32x->gpiod_nreset)) {
1023 ret = PTR_ERR(sta32x->gpiod_nreset);
1024 if (ret != -ENOENT && ret != -ENOSYS)
1025 return ret;
1026
1027 sta32x->gpiod_nreset = NULL;
1028 } else {
1029 gpiod_direction_output(sta32x->gpiod_nreset, 0);
1030 }
1031
Mark Brownaff041a2012-09-10 10:59:51 +08001032 /* regulators */
1033 for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++)
1034 sta32x->supplies[i].supply = sta32x_supply_names[i];
1035
1036 ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(sta32x->supplies),
1037 sta32x->supplies);
1038 if (ret != 0) {
1039 dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
1040 return ret;
1041 }
1042
Mark Brown29fdf4f2012-09-10 10:59:56 +08001043 sta32x->regmap = devm_regmap_init_i2c(i2c, &sta32x_regmap);
1044 if (IS_ERR(sta32x->regmap)) {
1045 ret = PTR_ERR(sta32x->regmap);
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +01001046 dev_err(dev, "Failed to init regmap: %d\n", ret);
Mark Brown29fdf4f2012-09-10 10:59:56 +08001047 return ret;
1048 }
1049
Johannes Stezenbachc034abf2011-06-22 14:59:24 +02001050 i2c_set_clientdata(i2c, sta32x);
1051
Thomas Niederprüma1be4cea2015-01-22 00:01:53 +01001052 ret = snd_soc_register_codec(dev, &sta32x_codec, &sta32x_dai, 1);
1053 if (ret < 0)
1054 dev_err(dev, "Failed to register codec (%d)\n", ret);
Johannes Stezenbachc034abf2011-06-22 14:59:24 +02001055
Axel Lind999c022011-12-29 12:06:39 +08001056 return ret;
Johannes Stezenbachc034abf2011-06-22 14:59:24 +02001057}
1058
Bill Pemberton7a79e942012-12-07 09:26:37 -05001059static int sta32x_i2c_remove(struct i2c_client *client)
Johannes Stezenbachc034abf2011-06-22 14:59:24 +02001060{
Axel Line3d73c12011-08-18 15:31:04 +08001061 snd_soc_unregister_codec(&client->dev);
Johannes Stezenbachc034abf2011-06-22 14:59:24 +02001062 return 0;
1063}
1064
1065static const struct i2c_device_id sta32x_i2c_id[] = {
1066 { "sta326", 0 },
1067 { "sta328", 0 },
1068 { "sta329", 0 },
1069 { }
1070};
1071MODULE_DEVICE_TABLE(i2c, sta32x_i2c_id);
1072
1073static struct i2c_driver sta32x_i2c_driver = {
1074 .driver = {
1075 .name = "sta32x",
1076 .owner = THIS_MODULE,
1077 },
1078 .probe = sta32x_i2c_probe,
Bill Pemberton7a79e942012-12-07 09:26:37 -05001079 .remove = sta32x_i2c_remove,
Johannes Stezenbachc034abf2011-06-22 14:59:24 +02001080 .id_table = sta32x_i2c_id,
1081};
1082
Sachin Kamat0ead1132012-08-06 17:25:43 +05301083module_i2c_driver(sta32x_i2c_driver);
Johannes Stezenbachc034abf2011-06-22 14:59:24 +02001084
1085MODULE_DESCRIPTION("ASoC STA32X driver");
1086MODULE_AUTHOR("Johannes Stezenbach <js@sig21.net>");
1087MODULE_LICENSE("GPL");