aboutsummaryrefslogtreecommitdiff
path: root/sound/soc/codecs/wm8903.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/wm8903.c')
-rw-r--r--sound/soc/codecs/wm8903.c1110
1 files changed, 616 insertions, 494 deletions
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index ae1cadfae84..b84940c359a 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -1,8 +1,8 @@
/*
* wm8903.c -- WM8903 ALSA SoC Audio driver
*
- * Copyright 2008 Wolfson Microelectronics
- * Copyright 2011 NVIDIA, Inc.
+ * Copyright 2008-12 Wolfson Microelectronics
+ * Copyright 2011-2012 NVIDIA, Inc.
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
@@ -23,8 +23,9 @@
#include <linux/gpio.h>
#include <linux/pm.h>
#include <linux/i2c.h>
-#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
+#include <linux/irq.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h>
@@ -38,184 +39,86 @@
#include "wm8903.h"
/* Register defaults at reset */
-static u16 wm8903_reg_defaults[] = {
- 0x8903, /* R0 - SW Reset and ID */
- 0x0000, /* R1 - Revision Number */
- 0x0000, /* R2 */
- 0x0000, /* R3 */
- 0x0018, /* R4 - Bias Control 0 */
- 0x0000, /* R5 - VMID Control 0 */
- 0x0000, /* R6 - Mic Bias Control 0 */
- 0x0000, /* R7 */
- 0x0001, /* R8 - Analogue DAC 0 */
- 0x0000, /* R9 */
- 0x0001, /* R10 - Analogue ADC 0 */
- 0x0000, /* R11 */
- 0x0000, /* R12 - Power Management 0 */
- 0x0000, /* R13 - Power Management 1 */
- 0x0000, /* R14 - Power Management 2 */
- 0x0000, /* R15 - Power Management 3 */
- 0x0000, /* R16 - Power Management 4 */
- 0x0000, /* R17 - Power Management 5 */
- 0x0000, /* R18 - Power Management 6 */
- 0x0000, /* R19 */
- 0x0400, /* R20 - Clock Rates 0 */
- 0x0D07, /* R21 - Clock Rates 1 */
- 0x0000, /* R22 - Clock Rates 2 */
- 0x0000, /* R23 */
- 0x0050, /* R24 - Audio Interface 0 */
- 0x0242, /* R25 - Audio Interface 1 */
- 0x0008, /* R26 - Audio Interface 2 */
- 0x0022, /* R27 - Audio Interface 3 */
- 0x0000, /* R28 */
- 0x0000, /* R29 */
- 0x00C0, /* R30 - DAC Digital Volume Left */
- 0x00C0, /* R31 - DAC Digital Volume Right */
- 0x0000, /* R32 - DAC Digital 0 */
- 0x0000, /* R33 - DAC Digital 1 */
- 0x0000, /* R34 */
- 0x0000, /* R35 */
- 0x00C0, /* R36 - ADC Digital Volume Left */
- 0x00C0, /* R37 - ADC Digital Volume Right */
- 0x0000, /* R38 - ADC Digital 0 */
- 0x0073, /* R39 - Digital Microphone 0 */
- 0x09BF, /* R40 - DRC 0 */
- 0x3241, /* R41 - DRC 1 */
- 0x0020, /* R42 - DRC 2 */
- 0x0000, /* R43 - DRC 3 */
- 0x0085, /* R44 - Analogue Left Input 0 */
- 0x0085, /* R45 - Analogue Right Input 0 */
- 0x0044, /* R46 - Analogue Left Input 1 */
- 0x0044, /* R47 - Analogue Right Input 1 */
- 0x0000, /* R48 */
- 0x0000, /* R49 */
- 0x0008, /* R50 - Analogue Left Mix 0 */
- 0x0004, /* R51 - Analogue Right Mix 0 */
- 0x0000, /* R52 - Analogue Spk Mix Left 0 */
- 0x0000, /* R53 - Analogue Spk Mix Left 1 */
- 0x0000, /* R54 - Analogue Spk Mix Right 0 */
- 0x0000, /* R55 - Analogue Spk Mix Right 1 */
- 0x0000, /* R56 */
- 0x002D, /* R57 - Analogue OUT1 Left */
- 0x002D, /* R58 - Analogue OUT1 Right */
- 0x0039, /* R59 - Analogue OUT2 Left */
- 0x0039, /* R60 - Analogue OUT2 Right */
- 0x0100, /* R61 */
- 0x0139, /* R62 - Analogue OUT3 Left */
- 0x0139, /* R63 - Analogue OUT3 Right */
- 0x0000, /* R64 */
- 0x0000, /* R65 - Analogue SPK Output Control 0 */
- 0x0000, /* R66 */
- 0x0010, /* R67 - DC Servo 0 */
- 0x0100, /* R68 */
- 0x00A4, /* R69 - DC Servo 2 */
- 0x0807, /* R70 */
- 0x0000, /* R71 */
- 0x0000, /* R72 */
- 0x0000, /* R73 */
- 0x0000, /* R74 */
- 0x0000, /* R75 */
- 0x0000, /* R76 */
- 0x0000, /* R77 */
- 0x0000, /* R78 */
- 0x000E, /* R79 */
- 0x0000, /* R80 */
- 0x0000, /* R81 */
- 0x0000, /* R82 */
- 0x0000, /* R83 */
- 0x0000, /* R84 */
- 0x0000, /* R85 */
- 0x0000, /* R86 */
- 0x0006, /* R87 */
- 0x0000, /* R88 */
- 0x0000, /* R89 */
- 0x0000, /* R90 - Analogue HP 0 */
- 0x0060, /* R91 */
- 0x0000, /* R92 */
- 0x0000, /* R93 */
- 0x0000, /* R94 - Analogue Lineout 0 */
- 0x0060, /* R95 */
- 0x0000, /* R96 */
- 0x0000, /* R97 */
- 0x0000, /* R98 - Charge Pump 0 */
- 0x1F25, /* R99 */
- 0x2B19, /* R100 */
- 0x01C0, /* R101 */
- 0x01EF, /* R102 */
- 0x2B00, /* R103 */
- 0x0000, /* R104 - Class W 0 */
- 0x01C0, /* R105 */
- 0x1C10, /* R106 */
- 0x0000, /* R107 */
- 0x0000, /* R108 - Write Sequencer 0 */
- 0x0000, /* R109 - Write Sequencer 1 */
- 0x0000, /* R110 - Write Sequencer 2 */
- 0x0000, /* R111 - Write Sequencer 3 */
- 0x0000, /* R112 - Write Sequencer 4 */
- 0x0000, /* R113 */
- 0x0000, /* R114 - Control Interface */
- 0x0000, /* R115 */
- 0x00A8, /* R116 - GPIO Control 1 */
- 0x00A8, /* R117 - GPIO Control 2 */
- 0x00A8, /* R118 - GPIO Control 3 */
- 0x0220, /* R119 - GPIO Control 4 */
- 0x01A0, /* R120 - GPIO Control 5 */
- 0x0000, /* R121 - Interrupt Status 1 */
- 0xFFFF, /* R122 - Interrupt Status 1 Mask */
- 0x0000, /* R123 - Interrupt Polarity 1 */
- 0x0000, /* R124 */
- 0x0003, /* R125 */
- 0x0000, /* R126 - Interrupt Control */
- 0x0000, /* R127 */
- 0x0005, /* R128 */
- 0x0000, /* R129 - Control Interface Test 1 */
- 0x0000, /* R130 */
- 0x0000, /* R131 */
- 0x0000, /* R132 */
- 0x0000, /* R133 */
- 0x0000, /* R134 */
- 0x03FF, /* R135 */
- 0x0007, /* R136 */
- 0x0040, /* R137 */
- 0x0000, /* R138 */
- 0x0000, /* R139 */
- 0x0000, /* R140 */
- 0x0000, /* R141 */
- 0x0000, /* R142 */
- 0x0000, /* R143 */
- 0x0000, /* R144 */
- 0x0000, /* R145 */
- 0x0000, /* R146 */
- 0x0000, /* R147 */
- 0x4000, /* R148 */
- 0x6810, /* R149 - Charge Pump Test 1 */
- 0x0004, /* R150 */
- 0x0000, /* R151 */
- 0x0000, /* R152 */
- 0x0000, /* R153 */
- 0x0000, /* R154 */
- 0x0000, /* R155 */
- 0x0000, /* R156 */
- 0x0000, /* R157 */
- 0x0000, /* R158 */
- 0x0000, /* R159 */
- 0x0000, /* R160 */
- 0x0000, /* R161 */
- 0x0000, /* R162 */
- 0x0000, /* R163 */
- 0x0028, /* R164 - Clock Rate Test 4 */
- 0x0004, /* R165 */
- 0x0000, /* R166 */
- 0x0060, /* R167 */
- 0x0000, /* R168 */
- 0x0000, /* R169 */
- 0x0000, /* R170 */
- 0x0000, /* R171 */
- 0x0000, /* R172 - Analogue Output Bias 0 */
+static const struct reg_default wm8903_reg_defaults[] = {
+ { 4, 0x0018 }, /* R4 - Bias Control 0 */
+ { 5, 0x0000 }, /* R5 - VMID Control 0 */
+ { 6, 0x0000 }, /* R6 - Mic Bias Control 0 */
+ { 8, 0x0001 }, /* R8 - Analogue DAC 0 */
+ { 10, 0x0001 }, /* R10 - Analogue ADC 0 */
+ { 12, 0x0000 }, /* R12 - Power Management 0 */
+ { 13, 0x0000 }, /* R13 - Power Management 1 */
+ { 14, 0x0000 }, /* R14 - Power Management 2 */
+ { 15, 0x0000 }, /* R15 - Power Management 3 */
+ { 16, 0x0000 }, /* R16 - Power Management 4 */
+ { 17, 0x0000 }, /* R17 - Power Management 5 */
+ { 18, 0x0000 }, /* R18 - Power Management 6 */
+ { 20, 0x0400 }, /* R20 - Clock Rates 0 */
+ { 21, 0x0D07 }, /* R21 - Clock Rates 1 */
+ { 22, 0x0000 }, /* R22 - Clock Rates 2 */
+ { 24, 0x0050 }, /* R24 - Audio Interface 0 */
+ { 25, 0x0242 }, /* R25 - Audio Interface 1 */
+ { 26, 0x0008 }, /* R26 - Audio Interface 2 */
+ { 27, 0x0022 }, /* R27 - Audio Interface 3 */
+ { 30, 0x00C0 }, /* R30 - DAC Digital Volume Left */
+ { 31, 0x00C0 }, /* R31 - DAC Digital Volume Right */
+ { 32, 0x0000 }, /* R32 - DAC Digital 0 */
+ { 33, 0x0000 }, /* R33 - DAC Digital 1 */
+ { 36, 0x00C0 }, /* R36 - ADC Digital Volume Left */
+ { 37, 0x00C0 }, /* R37 - ADC Digital Volume Right */
+ { 38, 0x0000 }, /* R38 - ADC Digital 0 */
+ { 39, 0x0073 }, /* R39 - Digital Microphone 0 */
+ { 40, 0x09BF }, /* R40 - DRC 0 */
+ { 41, 0x3241 }, /* R41 - DRC 1 */
+ { 42, 0x0020 }, /* R42 - DRC 2 */
+ { 43, 0x0000 }, /* R43 - DRC 3 */
+ { 44, 0x0085 }, /* R44 - Analogue Left Input 0 */
+ { 45, 0x0085 }, /* R45 - Analogue Right Input 0 */
+ { 46, 0x0044 }, /* R46 - Analogue Left Input 1 */
+ { 47, 0x0044 }, /* R47 - Analogue Right Input 1 */
+ { 50, 0x0008 }, /* R50 - Analogue Left Mix 0 */
+ { 51, 0x0004 }, /* R51 - Analogue Right Mix 0 */
+ { 52, 0x0000 }, /* R52 - Analogue Spk Mix Left 0 */
+ { 53, 0x0000 }, /* R53 - Analogue Spk Mix Left 1 */
+ { 54, 0x0000 }, /* R54 - Analogue Spk Mix Right 0 */
+ { 55, 0x0000 }, /* R55 - Analogue Spk Mix Right 1 */
+ { 57, 0x002D }, /* R57 - Analogue OUT1 Left */
+ { 58, 0x002D }, /* R58 - Analogue OUT1 Right */
+ { 59, 0x0039 }, /* R59 - Analogue OUT2 Left */
+ { 60, 0x0039 }, /* R60 - Analogue OUT2 Right */
+ { 62, 0x0139 }, /* R62 - Analogue OUT3 Left */
+ { 63, 0x0139 }, /* R63 - Analogue OUT3 Right */
+ { 64, 0x0000 }, /* R65 - Analogue SPK Output Control 0 */
+ { 67, 0x0010 }, /* R67 - DC Servo 0 */
+ { 69, 0x00A4 }, /* R69 - DC Servo 2 */
+ { 90, 0x0000 }, /* R90 - Analogue HP 0 */
+ { 94, 0x0000 }, /* R94 - Analogue Lineout 0 */
+ { 98, 0x0000 }, /* R98 - Charge Pump 0 */
+ { 104, 0x0000 }, /* R104 - Class W 0 */
+ { 108, 0x0000 }, /* R108 - Write Sequencer 0 */
+ { 109, 0x0000 }, /* R109 - Write Sequencer 1 */
+ { 110, 0x0000 }, /* R110 - Write Sequencer 2 */
+ { 111, 0x0000 }, /* R111 - Write Sequencer 3 */
+ { 112, 0x0000 }, /* R112 - Write Sequencer 4 */
+ { 114, 0x0000 }, /* R114 - Control Interface */
+ { 116, 0x00A8 }, /* R116 - GPIO Control 1 */
+ { 117, 0x00A8 }, /* R117 - GPIO Control 2 */
+ { 118, 0x00A8 }, /* R118 - GPIO Control 3 */
+ { 119, 0x0220 }, /* R119 - GPIO Control 4 */
+ { 120, 0x01A0 }, /* R120 - GPIO Control 5 */
+ { 122, 0xFFFF }, /* R122 - Interrupt Status 1 Mask */
+ { 123, 0x0000 }, /* R123 - Interrupt Polarity 1 */
+ { 126, 0x0000 }, /* R126 - Interrupt Control */
+ { 129, 0x0000 }, /* R129 - Control Interface Test 1 */
+ { 149, 0x6810 }, /* R149 - Charge Pump Test 1 */
+ { 164, 0x0028 }, /* R164 - Clock Rate Test 4 */
+ { 172, 0x0000 }, /* R172 - Analogue Output Bias 0 */
};
struct wm8903_priv {
+ struct wm8903_platform_data *pdata;
+ struct device *dev;
struct snd_soc_codec *codec;
+ struct regmap *regmap;
int sysclk;
int irq;
@@ -240,15 +143,99 @@ struct wm8903_priv {
#endif
};
-static int wm8903_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
+static bool wm8903_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WM8903_SW_RESET_AND_ID:
+ case WM8903_REVISION_NUMBER:
+ case WM8903_BIAS_CONTROL_0:
+ case WM8903_VMID_CONTROL_0:
+ case WM8903_MIC_BIAS_CONTROL_0:
+ case WM8903_ANALOGUE_DAC_0:
+ case WM8903_ANALOGUE_ADC_0:
+ case WM8903_POWER_MANAGEMENT_0:
+ case WM8903_POWER_MANAGEMENT_1:
+ case WM8903_POWER_MANAGEMENT_2:
+ case WM8903_POWER_MANAGEMENT_3:
+ case WM8903_POWER_MANAGEMENT_4:
+ case WM8903_POWER_MANAGEMENT_5:
+ case WM8903_POWER_MANAGEMENT_6:
+ case WM8903_CLOCK_RATES_0:
+ case WM8903_CLOCK_RATES_1:
+ case WM8903_CLOCK_RATES_2:
+ case WM8903_AUDIO_INTERFACE_0:
+ case WM8903_AUDIO_INTERFACE_1:
+ case WM8903_AUDIO_INTERFACE_2:
+ case WM8903_AUDIO_INTERFACE_3:
+ case WM8903_DAC_DIGITAL_VOLUME_LEFT:
+ case WM8903_DAC_DIGITAL_VOLUME_RIGHT:
+ case WM8903_DAC_DIGITAL_0:
+ case WM8903_DAC_DIGITAL_1:
+ case WM8903_ADC_DIGITAL_VOLUME_LEFT:
+ case WM8903_ADC_DIGITAL_VOLUME_RIGHT:
+ case WM8903_ADC_DIGITAL_0:
+ case WM8903_DIGITAL_MICROPHONE_0:
+ case WM8903_DRC_0:
+ case WM8903_DRC_1:
+ case WM8903_DRC_2:
+ case WM8903_DRC_3:
+ case WM8903_ANALOGUE_LEFT_INPUT_0:
+ case WM8903_ANALOGUE_RIGHT_INPUT_0:
+ case WM8903_ANALOGUE_LEFT_INPUT_1:
+ case WM8903_ANALOGUE_RIGHT_INPUT_1:
+ case WM8903_ANALOGUE_LEFT_MIX_0:
+ case WM8903_ANALOGUE_RIGHT_MIX_0:
+ case WM8903_ANALOGUE_SPK_MIX_LEFT_0:
+ case WM8903_ANALOGUE_SPK_MIX_LEFT_1:
+ case WM8903_ANALOGUE_SPK_MIX_RIGHT_0:
+ case WM8903_ANALOGUE_SPK_MIX_RIGHT_1:
+ case WM8903_ANALOGUE_OUT1_LEFT:
+ case WM8903_ANALOGUE_OUT1_RIGHT:
+ case WM8903_ANALOGUE_OUT2_LEFT:
+ case WM8903_ANALOGUE_OUT2_RIGHT:
+ case WM8903_ANALOGUE_OUT3_LEFT:
+ case WM8903_ANALOGUE_OUT3_RIGHT:
+ case WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0:
+ case WM8903_DC_SERVO_0:
+ case WM8903_DC_SERVO_2:
+ case WM8903_DC_SERVO_READBACK_1:
+ case WM8903_DC_SERVO_READBACK_2:
+ case WM8903_DC_SERVO_READBACK_3:
+ case WM8903_DC_SERVO_READBACK_4:
+ case WM8903_ANALOGUE_HP_0:
+ case WM8903_ANALOGUE_LINEOUT_0:
+ case WM8903_CHARGE_PUMP_0:
+ case WM8903_CLASS_W_0:
+ case WM8903_WRITE_SEQUENCER_0:
+ case WM8903_WRITE_SEQUENCER_1:
+ case WM8903_WRITE_SEQUENCER_2:
+ case WM8903_WRITE_SEQUENCER_3:
+ case WM8903_WRITE_SEQUENCER_4:
+ case WM8903_CONTROL_INTERFACE:
+ case WM8903_GPIO_CONTROL_1:
+ case WM8903_GPIO_CONTROL_2:
+ case WM8903_GPIO_CONTROL_3:
+ case WM8903_GPIO_CONTROL_4:
+ case WM8903_GPIO_CONTROL_5:
+ case WM8903_INTERRUPT_STATUS_1:
+ case WM8903_INTERRUPT_STATUS_1_MASK:
+ case WM8903_INTERRUPT_POLARITY_1:
+ case WM8903_INTERRUPT_CONTROL:
+ case WM8903_CLOCK_RATE_TEST_4:
+ case WM8903_ANALOGUE_OUTPUT_BIAS_0:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool wm8903_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case WM8903_SW_RESET_AND_ID:
case WM8903_REVISION_NUMBER:
case WM8903_INTERRUPT_STATUS_1:
case WM8903_WRITE_SEQUENCER_4:
- case WM8903_POWER_MANAGEMENT_3:
- case WM8903_POWER_MANAGEMENT_2:
case WM8903_DC_SERVO_READBACK_1:
case WM8903_DC_SERVO_READBACK_2:
case WM8903_DC_SERVO_READBACK_3:
@@ -260,13 +247,6 @@ static int wm8903_volatile_register(struct snd_soc_codec *codec, unsigned int re
}
}
-static void wm8903_reset(struct snd_soc_codec *codec)
-{
- snd_soc_write(codec, WM8903_SW_RESET_AND_ID, 0);
- memcpy(codec->reg_cache, wm8903_reg_defaults,
- sizeof(wm8903_reg_defaults));
-}
-
static int wm8903_cp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -384,8 +364,7 @@ static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm,
static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
- struct snd_soc_codec *codec = widget->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
u16 reg;
int ret;
@@ -422,10 +401,8 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
}
#define SOC_DAPM_SINGLE_W(xname, reg, shift, max, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = snd_soc_info_volsw, \
- .get = snd_soc_dapm_get_volsw, .put = wm8903_class_w_put, \
- .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
+ SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
+ snd_soc_dapm_get_volsw, wm8903_class_w_put)
static int wm8903_deemph[] = { 0, 32000, 44100, 48000 };
@@ -462,7 +439,7 @@ static int wm8903_set_deemph(struct snd_soc_codec *codec)
static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = wm8903->deemph;
@@ -473,7 +450,7 @@ static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,
static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
int deemph = ucontrol->value.enumerated.item[0];
int ret = 0;
@@ -497,6 +474,8 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
/* ALSA can only do steps of .01dB */
static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
+
static const DECLARE_TLV_DB_SCALE(digital_sidetone_tlv, -3600, 300, 0);
static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
@@ -510,28 +489,28 @@ static const char *hpf_mode_text[] = {
"Hi-fi", "Voice 1", "Voice 2", "Voice 3"
};
-static const struct soc_enum hpf_mode =
- SOC_ENUM_SINGLE(WM8903_ADC_DIGITAL_0, 5, 4, hpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(hpf_mode,
+ WM8903_ADC_DIGITAL_0, 5, hpf_mode_text);
static const char *osr_text[] = {
"Low power", "High performance"
};
-static const struct soc_enum adc_osr =
- SOC_ENUM_SINGLE(WM8903_ANALOGUE_ADC_0, 0, 2, osr_text);
+static SOC_ENUM_SINGLE_DECL(adc_osr,
+ WM8903_ANALOGUE_ADC_0, 0, osr_text);
-static const struct soc_enum dac_osr =
- SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 0, 2, osr_text);
+static SOC_ENUM_SINGLE_DECL(dac_osr,
+ WM8903_DAC_DIGITAL_1, 0, osr_text);
static const char *drc_slope_text[] = {
"1", "1/2", "1/4", "1/8", "1/16", "0"
};
-static const struct soc_enum drc_slope_r0 =
- SOC_ENUM_SINGLE(WM8903_DRC_2, 3, 6, drc_slope_text);
+static SOC_ENUM_SINGLE_DECL(drc_slope_r0,
+ WM8903_DRC_2, 3, drc_slope_text);
-static const struct soc_enum drc_slope_r1 =
- SOC_ENUM_SINGLE(WM8903_DRC_2, 0, 6, drc_slope_text);
+static SOC_ENUM_SINGLE_DECL(drc_slope_r1,
+ WM8903_DRC_2, 0, drc_slope_text);
static const char *drc_attack_text[] = {
"instantaneous",
@@ -539,118 +518,125 @@ static const char *drc_attack_text[] = {
"46.4ms", "92.8ms", "185.6ms"
};
-static const struct soc_enum drc_attack =
- SOC_ENUM_SINGLE(WM8903_DRC_1, 12, 11, drc_attack_text);
+static SOC_ENUM_SINGLE_DECL(drc_attack,
+ WM8903_DRC_1, 12, drc_attack_text);
static const char *drc_decay_text[] = {
"186ms", "372ms", "743ms", "1.49s", "2.97s", "5.94s", "11.89s",
"23.87s", "47.56s"
};
-static const struct soc_enum drc_decay =
- SOC_ENUM_SINGLE(WM8903_DRC_1, 8, 9, drc_decay_text);
+static SOC_ENUM_SINGLE_DECL(drc_decay,
+ WM8903_DRC_1, 8, drc_decay_text);
static const char *drc_ff_delay_text[] = {
"5 samples", "9 samples"
};
-static const struct soc_enum drc_ff_delay =
- SOC_ENUM_SINGLE(WM8903_DRC_0, 5, 2, drc_ff_delay_text);
+static SOC_ENUM_SINGLE_DECL(drc_ff_delay,
+ WM8903_DRC_0, 5, drc_ff_delay_text);
static const char *drc_qr_decay_text[] = {
"0.725ms", "1.45ms", "5.8ms"
};
-static const struct soc_enum drc_qr_decay =
- SOC_ENUM_SINGLE(WM8903_DRC_1, 4, 3, drc_qr_decay_text);
+static SOC_ENUM_SINGLE_DECL(drc_qr_decay,
+ WM8903_DRC_1, 4, drc_qr_decay_text);
static const char *drc_smoothing_text[] = {
"Low", "Medium", "High"
};
-static const struct soc_enum drc_smoothing =
- SOC_ENUM_SINGLE(WM8903_DRC_0, 11, 3, drc_smoothing_text);
+static SOC_ENUM_SINGLE_DECL(drc_smoothing,
+ WM8903_DRC_0, 11, drc_smoothing_text);
static const char *soft_mute_text[] = {
"Fast (fs/2)", "Slow (fs/32)"
};
-static const struct soc_enum soft_mute =
- SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 10, 2, soft_mute_text);
+static SOC_ENUM_SINGLE_DECL(soft_mute,
+ WM8903_DAC_DIGITAL_1, 10, soft_mute_text);
static const char *mute_mode_text[] = {
"Hard", "Soft"
};
-static const struct soc_enum mute_mode =
- SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 9, 2, mute_mode_text);
+static SOC_ENUM_SINGLE_DECL(mute_mode,
+ WM8903_DAC_DIGITAL_1, 9, mute_mode_text);
static const char *companding_text[] = {
"ulaw", "alaw"
};
-static const struct soc_enum dac_companding =
- SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 0, 2, companding_text);
+static SOC_ENUM_SINGLE_DECL(dac_companding,
+ WM8903_AUDIO_INTERFACE_0, 0, companding_text);
-static const struct soc_enum adc_companding =
- SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 2, 2, companding_text);
+static SOC_ENUM_SINGLE_DECL(adc_companding,
+ WM8903_AUDIO_INTERFACE_0, 2, companding_text);
static const char *input_mode_text[] = {
"Single-Ended", "Differential Line", "Differential Mic"
};
-static const struct soc_enum linput_mode_enum =
- SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text);
+static SOC_ENUM_SINGLE_DECL(linput_mode_enum,
+ WM8903_ANALOGUE_LEFT_INPUT_1, 0, input_mode_text);
-static const struct soc_enum rinput_mode_enum =
- SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text);
+static SOC_ENUM_SINGLE_DECL(rinput_mode_enum,
+ WM8903_ANALOGUE_RIGHT_INPUT_1, 0, input_mode_text);
static const char *linput_mux_text[] = {
"IN1L", "IN2L", "IN3L"
};
-static const struct soc_enum linput_enum =
- SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 2, 3, linput_mux_text);
+static SOC_ENUM_SINGLE_DECL(linput_enum,
+ WM8903_ANALOGUE_LEFT_INPUT_1, 2, linput_mux_text);
-static const struct soc_enum linput_inv_enum =
- SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 4, 3, linput_mux_text);
+static SOC_ENUM_SINGLE_DECL(linput_inv_enum,
+ WM8903_ANALOGUE_LEFT_INPUT_1, 4, linput_mux_text);
static const char *rinput_mux_text[] = {
"IN1R", "IN2R", "IN3R"
};
-static const struct soc_enum rinput_enum =
- SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 2, 3, rinput_mux_text);
+static SOC_ENUM_SINGLE_DECL(rinput_enum,
+ WM8903_ANALOGUE_RIGHT_INPUT_1, 2, rinput_mux_text);
-static const struct soc_enum rinput_inv_enum =
- SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 4, 3, rinput_mux_text);
+static SOC_ENUM_SINGLE_DECL(rinput_inv_enum,
+ WM8903_ANALOGUE_RIGHT_INPUT_1, 4, rinput_mux_text);
static const char *sidetone_text[] = {
"None", "Left", "Right"
};
-static const struct soc_enum lsidetone_enum =
- SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 2, 3, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(lsidetone_enum,
+ WM8903_DAC_DIGITAL_0, 2, sidetone_text);
+
+static SOC_ENUM_SINGLE_DECL(rsidetone_enum,
+ WM8903_DAC_DIGITAL_0, 0, sidetone_text);
-static const struct soc_enum rsidetone_enum =
- SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 0, 3, sidetone_text);
+static const char *adcinput_text[] = {
+ "ADC", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(adcinput_enum,
+ WM8903_CLOCK_RATE_TEST_4, 9, adcinput_text);
static const char *aif_text[] = {
"Left", "Right"
};
-static const struct soc_enum lcapture_enum =
- SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 7, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(lcapture_enum,
+ WM8903_AUDIO_INTERFACE_0, 7, aif_text);
-static const struct soc_enum rcapture_enum =
- SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 6, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(rcapture_enum,
+ WM8903_AUDIO_INTERFACE_0, 6, aif_text);
-static const struct soc_enum lplay_enum =
- SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 5, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(lplay_enum,
+ WM8903_AUDIO_INTERFACE_0, 5, aif_text);
-static const struct soc_enum rplay_enum =
- SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 4, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(rplay_enum,
+ WM8903_AUDIO_INTERFACE_0, 4, aif_text);
static const struct snd_kcontrol_new wm8903_snd_controls[] = {
@@ -694,7 +680,7 @@ SOC_ENUM("DRC Smoothing Threshold", drc_smoothing),
SOC_SINGLE_TLV("DRC Startup Volume", WM8903_DRC_0, 6, 18, 0, drc_tlv_startup),
SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT,
- WM8903_ADC_DIGITAL_VOLUME_RIGHT, 1, 96, 0, digital_tlv),
+ WM8903_ADC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv),
SOC_ENUM("ADC Companding Mode", adc_companding),
SOC_SINGLE("ADC Companding Switch", WM8903_AUDIO_INTERFACE_0, 3, 1, 0),
@@ -710,6 +696,8 @@ SOC_ENUM("DAC Mute Mode", mute_mode),
SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0),
SOC_ENUM("DAC Companding Mode", dac_companding),
SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0),
+SOC_SINGLE_TLV("DAC Boost Volume", WM8903_AUDIO_INTERFACE_0, 9, 3, 0,
+ dac_boost_tlv),
SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0,
wm8903_get_deemph, wm8903_put_deemph),
@@ -769,6 +757,9 @@ static const struct snd_kcontrol_new lsidetone_mux =
static const struct snd_kcontrol_new rsidetone_mux =
SOC_DAPM_ENUM("DACR Sidetone Mux", rsidetone_enum);
+static const struct snd_kcontrol_new adcinput_mux =
+ SOC_DAPM_ENUM("ADC Input", adcinput_enum);
+
static const struct snd_kcontrol_new lcapture_mux =
SOC_DAPM_ENUM("Left Capture Mux", lcapture_enum);
@@ -819,6 +810,7 @@ SND_SOC_DAPM_INPUT("IN2L"),
SND_SOC_DAPM_INPUT("IN2R"),
SND_SOC_DAPM_INPUT("IN3L"),
SND_SOC_DAPM_INPUT("IN3R"),
+SND_SOC_DAPM_INPUT("DMICDAT"),
SND_SOC_DAPM_OUTPUT("HPOUTL"),
SND_SOC_DAPM_OUTPUT("HPOUTR"),
@@ -829,7 +821,7 @@ SND_SOC_DAPM_OUTPUT("LON"),
SND_SOC_DAPM_OUTPUT("ROP"),
SND_SOC_DAPM_OUTPUT("RON"),
-SND_SOC_DAPM_MICBIAS("Mic Bias", WM8903_MIC_BIAS_CONTROL_0, 0, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS", WM8903_MIC_BIAS_CONTROL_0, 0, 0, NULL, 0),
SND_SOC_DAPM_MUX("Left Input Mux", SND_SOC_NOPM, 0, 0, &linput_mux),
SND_SOC_DAPM_MUX("Left Input Inverting Mux", SND_SOC_NOPM, 0, 0,
@@ -844,6 +836,9 @@ SND_SOC_DAPM_MUX("Right Input Mode Mux", SND_SOC_NOPM, 0, 0, &rinput_mode_mux),
SND_SOC_DAPM_PGA("Left Input PGA", WM8903_POWER_MANAGEMENT_0, 1, 0, NULL, 0),
SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0),
+SND_SOC_DAPM_MUX("Left ADC Input", SND_SOC_NOPM, 0, 0, &adcinput_mux),
+SND_SOC_DAPM_MUX("Right ADC Input", SND_SOC_NOPM, 0, 0, &adcinput_mux),
+
SND_SOC_DAPM_ADC("ADCL", NULL, WM8903_POWER_MANAGEMENT_6, 1, 0),
SND_SOC_DAPM_ADC("ADCR", NULL, WM8903_POWER_MANAGEMENT_6, 0, 0),
@@ -875,34 +870,40 @@ SND_SOC_DAPM_MIXER("Left Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 1, 0,
SND_SOC_DAPM_MIXER("Right Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 0, 0,
right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
-SND_SOC_DAPM_PGA_S("Left Headphone Output PGA", 0, WM8903_ANALOGUE_HP_0,
- 4, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("Right Headphone Output PGA", 0, WM8903_ANALOGUE_HP_0,
+SND_SOC_DAPM_PGA_S("Left Headphone Output PGA", 0, WM8903_POWER_MANAGEMENT_2,
+ 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("Right Headphone Output PGA", 0, WM8903_POWER_MANAGEMENT_2,
0, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("Left Line Output PGA", 0, WM8903_ANALOGUE_LINEOUT_0, 4, 0,
+SND_SOC_DAPM_PGA_S("Left Line Output PGA", 0, WM8903_POWER_MANAGEMENT_3, 1, 0,
NULL, 0),
-SND_SOC_DAPM_PGA_S("Right Line Output PGA", 0, WM8903_ANALOGUE_LINEOUT_0, 0, 0,
+SND_SOC_DAPM_PGA_S("Right Line Output PGA", 0, WM8903_POWER_MANAGEMENT_3, 0, 0,
NULL, 0),
SND_SOC_DAPM_PGA_S("HPL_RMV_SHORT", 4, WM8903_ANALOGUE_HP_0, 7, 0, NULL, 0),
SND_SOC_DAPM_PGA_S("HPL_ENA_OUTP", 3, WM8903_ANALOGUE_HP_0, 6, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPL_ENA_DLY", 1, WM8903_ANALOGUE_HP_0, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPL_ENA_DLY", 2, WM8903_ANALOGUE_HP_0, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPL_ENA", 1, WM8903_ANALOGUE_HP_0, 4, 0, NULL, 0),
SND_SOC_DAPM_PGA_S("HPR_RMV_SHORT", 4, WM8903_ANALOGUE_HP_0, 3, 0, NULL, 0),
SND_SOC_DAPM_PGA_S("HPR_ENA_OUTP", 3, WM8903_ANALOGUE_HP_0, 2, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPR_ENA_DLY", 1, WM8903_ANALOGUE_HP_0, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPR_ENA_DLY", 2, WM8903_ANALOGUE_HP_0, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPR_ENA", 1, WM8903_ANALOGUE_HP_0, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA_S("LINEOUTL_RMV_SHORT", 4, WM8903_ANALOGUE_LINEOUT_0, 7, 0,
NULL, 0),
SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_OUTP", 3, WM8903_ANALOGUE_LINEOUT_0, 6, 0,
NULL, 0),
-SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_DLY", 1, WM8903_ANALOGUE_LINEOUT_0, 5, 0,
+SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_DLY", 2, WM8903_ANALOGUE_LINEOUT_0, 5, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA_S("LINEOUTL_ENA", 1, WM8903_ANALOGUE_LINEOUT_0, 4, 0,
NULL, 0),
SND_SOC_DAPM_PGA_S("LINEOUTR_RMV_SHORT", 4, WM8903_ANALOGUE_LINEOUT_0, 3, 0,
NULL, 0),
SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_OUTP", 3, WM8903_ANALOGUE_LINEOUT_0, 2, 0,
NULL, 0),
-SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_DLY", 1, WM8903_ANALOGUE_LINEOUT_0, 1, 0,
+SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_DLY", 2, WM8903_ANALOGUE_LINEOUT_0, 1, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA_S("LINEOUTR_ENA", 1, WM8903_ANALOGUE_LINEOUT_0, 0, 0,
NULL, 0),
SND_SOC_DAPM_SUPPLY("DCS Master", WM8903_DC_SERVO_0, 4, 0, NULL, 0),
@@ -926,10 +927,10 @@ SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8903_CLOCK_RATES_2, 1, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8903_CLOCK_RATES_2, 2, 0, NULL, 0),
};
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route wm8903_intercon[] = {
{ "CLK_DSP", NULL, "CLK_SYS" },
- { "Mic Bias", NULL, "CLK_SYS" },
+ { "MICBIAS", NULL, "CLK_SYS" },
{ "HPL_DCS", NULL, "CLK_SYS" },
{ "HPR_DCS", NULL, "CLK_SYS" },
{ "LINEOUTL_DCS", NULL, "CLK_SYS" },
@@ -975,6 +976,11 @@ static const struct snd_soc_dapm_route intercon[] = {
{ "Left Input PGA", NULL, "Left Input Mode Mux" },
{ "Right Input PGA", NULL, "Right Input Mode Mux" },
+ { "Left ADC Input", "ADC", "Left Input PGA" },
+ { "Left ADC Input", "DMIC", "DMICDAT" },
+ { "Right ADC Input", "ADC", "Right Input PGA" },
+ { "Right ADC Input", "DMIC", "DMICDAT" },
+
{ "Left Capture Mux", "Left", "ADCL" },
{ "Left Capture Mux", "Right", "ADCR" },
@@ -984,9 +990,9 @@ static const struct snd_soc_dapm_route intercon[] = {
{ "AIFTXL", NULL, "Left Capture Mux" },
{ "AIFTXR", NULL, "Right Capture Mux" },
- { "ADCL", NULL, "Left Input PGA" },
+ { "ADCL", NULL, "Left ADC Input" },
{ "ADCL", NULL, "CLK_DSP" },
- { "ADCR", NULL, "Right Input PGA" },
+ { "ADCR", NULL, "Right ADC Input" },
{ "ADCR", NULL, "CLK_DSP" },
{ "Left Playback Mux", "Left", "AIFRXL" },
@@ -1037,10 +1043,14 @@ static const struct snd_soc_dapm_route intercon[] = {
{ "Left Speaker PGA", NULL, "Left Speaker Mixer" },
{ "Right Speaker PGA", NULL, "Right Speaker Mixer" },
- { "HPL_ENA_DLY", NULL, "Left Headphone Output PGA" },
- { "HPR_ENA_DLY", NULL, "Right Headphone Output PGA" },
- { "LINEOUTL_ENA_DLY", NULL, "Left Line Output PGA" },
- { "LINEOUTR_ENA_DLY", NULL, "Right Line Output PGA" },
+ { "HPL_ENA", NULL, "Left Headphone Output PGA" },
+ { "HPR_ENA", NULL, "Right Headphone Output PGA" },
+ { "HPL_ENA_DLY", NULL, "HPL_ENA" },
+ { "HPR_ENA_DLY", NULL, "HPR_ENA" },
+ { "LINEOUTL_ENA", NULL, "Left Line Output PGA" },
+ { "LINEOUTR_ENA", NULL, "Right Line Output PGA" },
+ { "LINEOUTL_ENA_DLY", NULL, "LINEOUTL_ENA" },
+ { "LINEOUTR_ENA_DLY", NULL, "LINEOUTR_ENA" },
{ "HPL_DCS", NULL, "DCS Master" },
{ "HPR_DCS", NULL, "DCS Master" },
@@ -1073,23 +1083,14 @@ static const struct snd_soc_dapm_route intercon[] = {
{ "ROP", NULL, "Right Speaker PGA" },
{ "RON", NULL, "Right Speaker PGA" },
+ { "Charge Pump", NULL, "CLK_DSP" },
+
{ "Left Headphone Output PGA", NULL, "Charge Pump" },
{ "Right Headphone Output PGA", NULL, "Charge Pump" },
{ "Left Line Output PGA", NULL, "Charge Pump" },
{ "Right Line Output PGA", NULL, "Charge Pump" },
};
-static int wm8903_add_widgets(struct snd_soc_codec *codec)
-{
- struct snd_soc_dapm_context *dapm = &codec->dapm;
-
- snd_soc_dapm_new_controls(dapm, wm8903_dapm_widgets,
- ARRAY_SIZE(wm8903_dapm_widgets));
- snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
- return 0;
-}
-
static int wm8903_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
@@ -1434,8 +1435,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec =rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
int fs = params_rate(params);
int bclk;
@@ -1638,17 +1638,27 @@ EXPORT_SYMBOL_GPL(wm8903_mic_detect);
static irqreturn_t wm8903_irq(int irq, void *data)
{
- struct snd_soc_codec *codec = data;
- struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
- int mic_report;
- int int_pol;
- int int_val = 0;
- int mask = ~snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1_MASK);
+ struct wm8903_priv *wm8903 = data;
+ int mic_report, ret;
+ unsigned int int_val, mask, int_pol;
+
+ ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_STATUS_1_MASK,
+ &mask);
+ if (ret != 0) {
+ dev_err(wm8903->dev, "Failed to read IRQ mask: %d\n", ret);
+ return IRQ_NONE;
+ }
- int_val = snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1) & mask;
+ ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_STATUS_1, &int_val);
+ if (ret != 0) {
+ dev_err(wm8903->dev, "Failed to read IRQ status: %d\n", ret);
+ return IRQ_NONE;
+ }
+
+ int_val &= ~mask;
if (int_val & WM8903_WSEQ_BUSY_EINT) {
- dev_warn(codec->dev, "Write sequencer done\n");
+ dev_warn(wm8903->dev, "Write sequencer done\n");
}
/*
@@ -1659,22 +1669,28 @@ static irqreturn_t wm8903_irq(int irq, void *data)
* the polarity register.
*/
mic_report = wm8903->mic_last_report;
- int_pol = snd_soc_read(codec, WM8903_INTERRUPT_POLARITY_1);
+ ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_POLARITY_1,
+ &int_pol);
+ if (ret != 0) {
+ dev_err(wm8903->dev, "Failed to read interrupt polarity: %d\n",
+ ret);
+ return IRQ_HANDLED;
+ }
#ifndef CONFIG_SND_SOC_WM8903_MODULE
if (int_val & (WM8903_MICSHRT_EINT | WM8903_MICDET_EINT))
- trace_snd_soc_jack_irq(dev_name(codec->dev));
+ trace_snd_soc_jack_irq(dev_name(wm8903->dev));
#endif
if (int_val & WM8903_MICSHRT_EINT) {
- dev_dbg(codec->dev, "Microphone short (pol=%x)\n", int_pol);
+ dev_dbg(wm8903->dev, "Microphone short (pol=%x)\n", int_pol);
mic_report ^= wm8903->mic_short;
int_pol ^= WM8903_MICSHRT_INV;
}
if (int_val & WM8903_MICDET_EINT) {
- dev_dbg(codec->dev, "Microphone detect (pol=%x)\n", int_pol);
+ dev_dbg(wm8903->dev, "Microphone detect (pol=%x)\n", int_pol);
mic_report ^= wm8903->mic_det;
int_pol ^= WM8903_MICDET_INV;
@@ -1682,8 +1698,8 @@ static irqreturn_t wm8903_irq(int irq, void *data)
msleep(wm8903->mic_delay);
}
- snd_soc_update_bits(codec, WM8903_INTERRUPT_POLARITY_1,
- WM8903_MICSHRT_INV | WM8903_MICDET_INV, int_pol);
+ regmap_update_bits(wm8903->regmap, WM8903_INTERRUPT_POLARITY_1,
+ WM8903_MICSHRT_INV | WM8903_MICDET_INV, int_pol);
snd_soc_jack_report(wm8903->mic_jack, mic_report,
wm8903->mic_short | wm8903->mic_det);
@@ -1715,7 +1731,7 @@ static irqreturn_t wm8903_irq(int irq, void *data)
SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE)
-static struct snd_soc_dai_ops wm8903_dai_ops = {
+static const struct snd_soc_dai_ops wm8903_dai_ops = {
.hw_params = wm8903_hw_params,
.digital_mute = wm8903_digital_mute,
.set_fmt = wm8903_set_dai_fmt,
@@ -1742,7 +1758,7 @@ static struct snd_soc_dai_driver wm8903_dai = {
.symmetric_rates = 1,
};
-static int wm8903_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8903_suspend(struct snd_soc_codec *codec)
{
wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -1751,23 +1767,11 @@ static int wm8903_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8903_resume(struct snd_soc_codec *codec)
{
- int i;
- u16 *reg_cache = codec->reg_cache;
- u16 *tmp_cache = kmemdup(reg_cache, sizeof(wm8903_reg_defaults),
- GFP_KERNEL);
+ struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
- /* Bring the codec back up to standby first to minimise pop/clicks */
- wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ regcache_sync(wm8903->regmap);
- /* Sync back everything else */
- if (tmp_cache) {
- for (i = 2; i < ARRAY_SIZE(wm8903_reg_defaults); i++)
- if (tmp_cache[i] != reg_cache[i])
- snd_soc_write(codec, i, tmp_cache[i]);
- kfree(tmp_cache);
- } else {
- dev_err(codec->dev, "Failed to allocate temporary cache\n");
- }
+ wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
@@ -1789,24 +1793,27 @@ static int wm8903_gpio_request(struct gpio_chip *chip, unsigned offset)
static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
- struct snd_soc_codec *codec = wm8903->codec;
unsigned int mask, val;
+ int ret;
mask = WM8903_GP1_FN_MASK | WM8903_GP1_DIR_MASK;
val = (WM8903_GPn_FN_GPIO_INPUT << WM8903_GP1_FN_SHIFT) |
WM8903_GP1_DIR;
- return snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset,
- mask, val);
+ ret = regmap_update_bits(wm8903->regmap,
+ WM8903_GPIO_CONTROL_1 + offset, mask, val);
+ if (ret < 0)
+ return ret;
+
+ return 0;
}
static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
- struct snd_soc_codec *codec = wm8903->codec;
- int reg;
+ unsigned int reg;
- reg = snd_soc_read(codec, WM8903_GPIO_CONTROL_1 + offset);
+ regmap_read(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset, &reg);
return (reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT;
}
@@ -1815,25 +1822,28 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value)
{
struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
- struct snd_soc_codec *codec = wm8903->codec;
unsigned int mask, val;
+ int ret;
mask = WM8903_GP1_FN_MASK | WM8903_GP1_DIR_MASK | WM8903_GP1_LVL_MASK;
val = (WM8903_GPn_FN_GPIO_OUTPUT << WM8903_GP1_FN_SHIFT) |
(value << WM8903_GP2_LVL_SHIFT);
- return snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset,
- mask, val);
+ ret = regmap_update_bits(wm8903->regmap,
+ WM8903_GPIO_CONTROL_1 + offset, mask, val);
+ if (ret < 0)
+ return ret;
+
+ return 0;
}
static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
- struct snd_soc_codec *codec = wm8903->codec;
- snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset,
- WM8903_GP1_LVL_MASK,
- !!value << WM8903_GP1_LVL_SHIFT);
+ regmap_update_bits(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset,
+ WM8903_GP1_LVL_MASK,
+ !!value << WM8903_GP1_LVL_SHIFT);
}
static struct gpio_chip wm8903_template_chip = {
@@ -1847,119 +1857,283 @@ static struct gpio_chip wm8903_template_chip = {
.can_sleep = 1,
};
-static void wm8903_init_gpio(struct snd_soc_codec *codec)
+static void wm8903_init_gpio(struct wm8903_priv *wm8903)
{
- struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
- struct wm8903_platform_data *pdata = dev_get_platdata(codec->dev);
+ struct wm8903_platform_data *pdata = wm8903->pdata;
int ret;
wm8903->gpio_chip = wm8903_template_chip;
wm8903->gpio_chip.ngpio = WM8903_NUM_GPIO;
- wm8903->gpio_chip.dev = codec->dev;
+ wm8903->gpio_chip.dev = wm8903->dev;
- if (pdata && pdata->gpio_base)
+ if (pdata->gpio_base)
wm8903->gpio_chip.base = pdata->gpio_base;
else
wm8903->gpio_chip.base = -1;
ret = gpiochip_add(&wm8903->gpio_chip);
if (ret != 0)
- dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+ dev_err(wm8903->dev, "Failed to add GPIOs: %d\n", ret);
}
-static void wm8903_free_gpio(struct snd_soc_codec *codec)
+static void wm8903_free_gpio(struct wm8903_priv *wm8903)
{
- struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
int ret;
ret = gpiochip_remove(&wm8903->gpio_chip);
if (ret != 0)
- dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
+ dev_err(wm8903->dev, "Failed to remove GPIOs: %d\n", ret);
}
#else
-static void wm8903_init_gpio(struct snd_soc_codec *codec)
+static void wm8903_init_gpio(struct wm8903_priv *wm8903)
{
}
-static void wm8903_free_gpio(struct snd_soc_codec *codec)
+static void wm8903_free_gpio(struct wm8903_priv *wm8903)
{
}
#endif
static int wm8903_probe(struct snd_soc_codec *codec)
{
- struct wm8903_platform_data *pdata = dev_get_platdata(codec->dev);
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
- int ret, i;
- int trigger, irq_pol;
- u16 val;
wm8903->codec = codec;
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ /* power on device */
+ wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
+}
+
+/* power down chip */
+static int wm8903_remove(struct snd_soc_codec *codec)
+{
+ wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8903 = {
+ .probe = wm8903_probe,
+ .remove = wm8903_remove,
+ .suspend = wm8903_suspend,
+ .resume = wm8903_resume,
+ .set_bias_level = wm8903_set_bias_level,
+ .seq_notifier = wm8903_seq_notifier,
+ .controls = wm8903_snd_controls,
+ .num_controls = ARRAY_SIZE(wm8903_snd_controls),
+ .dapm_widgets = wm8903_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wm8903_dapm_widgets),
+ .dapm_routes = wm8903_intercon,
+ .num_dapm_routes = ARRAY_SIZE(wm8903_intercon),
+};
+
+static const struct regmap_config wm8903_regmap = {
+ .reg_bits = 8,
+ .val_bits = 16,
+
+ .max_register = WM8903_MAX_REGISTER,
+ .volatile_reg = wm8903_volatile_register,
+ .readable_reg = wm8903_readable_register,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = wm8903_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(wm8903_reg_defaults),
+};
+
+static int wm8903_set_pdata_irq_trigger(struct i2c_client *i2c,
+ struct wm8903_platform_data *pdata)
+{
+ struct irq_data *irq_data = irq_get_irq_data(i2c->irq);
+ if (!irq_data) {
+ dev_err(&i2c->dev, "Invalid IRQ: %d\n",
+ i2c->irq);
+ return -EINVAL;
+ }
+
+ switch (irqd_get_trigger_type(irq_data)) {
+ case IRQ_TYPE_NONE:
+ default:
+ /*
+ * We assume the controller imposes no restrictions,
+ * so we are able to select active-high
+ */
+ /* Fall-through */
+ case IRQ_TYPE_LEVEL_HIGH:
+ pdata->irq_active_low = false;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ pdata->irq_active_low = true;
+ break;
+ }
+
+ return 0;
+}
+
+static int wm8903_set_pdata_from_of(struct i2c_client *i2c,
+ struct wm8903_platform_data *pdata)
+{
+ const struct device_node *np = i2c->dev.of_node;
+ u32 val32;
+ int i;
+
+ if (of_property_read_u32(np, "micdet-cfg", &val32) >= 0)
+ pdata->micdet_cfg = val32;
+
+ if (of_property_read_u32(np, "micdet-delay", &val32) >= 0)
+ pdata->micdet_delay = val32;
+
+ if (of_property_read_u32_array(np, "gpio-cfg", pdata->gpio_cfg,
+ ARRAY_SIZE(pdata->gpio_cfg)) >= 0) {
+ /*
+ * In device tree: 0 means "write 0",
+ * 0xffffffff means "don't touch".
+ *
+ * In platform data: 0 means "don't touch",
+ * 0x8000 means "write 0".
+ *
+ * Note: WM8903_GPIO_CONFIG_ZERO == 0x8000.
+ *
+ * Convert from DT to pdata representation here,
+ * so no other code needs to change.
+ */
+ for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) {
+ if (pdata->gpio_cfg[i] == 0) {
+ pdata->gpio_cfg[i] = WM8903_GPIO_CONFIG_ZERO;
+ } else if (pdata->gpio_cfg[i] == 0xffffffff) {
+ pdata->gpio_cfg[i] = 0;
+ } else if (pdata->gpio_cfg[i] > 0x7fff) {
+ dev_err(&i2c->dev, "Invalid gpio-cfg[%d] %x\n",
+ i, pdata->gpio_cfg[i]);
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int wm8903_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev);
+ struct wm8903_priv *wm8903;
+ int trigger;
+ bool mic_gpio = false;
+ unsigned int val, irq_pol;
+ int ret, i;
+
+ wm8903 = devm_kzalloc(&i2c->dev, sizeof(struct wm8903_priv),
+ GFP_KERNEL);
+ if (wm8903 == NULL)
+ return -ENOMEM;
+ wm8903->dev = &i2c->dev;
+
+ wm8903->regmap = devm_regmap_init_i2c(i2c, &wm8903_regmap);
+ if (IS_ERR(wm8903->regmap)) {
+ ret = PTR_ERR(wm8903->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
return ret;
}
- val = snd_soc_read(codec, WM8903_SW_RESET_AND_ID);
- if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) {
- dev_err(codec->dev,
- "Device with ID register %x is not a WM8903\n", val);
- return -ENODEV;
+ i2c_set_clientdata(i2c, wm8903);
+
+ /* If no platform data was supplied, create storage for defaults */
+ if (pdata) {
+ wm8903->pdata = pdata;
+ } else {
+ wm8903->pdata = devm_kzalloc(&i2c->dev,
+ sizeof(struct wm8903_platform_data),
+ GFP_KERNEL);
+ if (wm8903->pdata == NULL) {
+ dev_err(&i2c->dev, "Failed to allocate pdata\n");
+ return -ENOMEM;
+ }
+
+ if (i2c->irq) {
+ ret = wm8903_set_pdata_irq_trigger(i2c, wm8903->pdata);
+ if (ret != 0)
+ return ret;
+ }
+
+ if (i2c->dev.of_node) {
+ ret = wm8903_set_pdata_from_of(i2c, wm8903->pdata);
+ if (ret != 0)
+ return ret;
+ }
+ }
+
+ pdata = wm8903->pdata;
+
+ ret = regmap_read(wm8903->regmap, WM8903_SW_RESET_AND_ID, &val);
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret);
+ goto err;
+ }
+ if (val != 0x8903) {
+ dev_err(&i2c->dev, "Device with ID %x is not a WM8903\n", val);
+ ret = -ENODEV;
+ goto err;
}
- val = snd_soc_read(codec, WM8903_REVISION_NUMBER);
- dev_info(codec->dev, "WM8903 revision %c\n",
+ ret = regmap_read(wm8903->regmap, WM8903_REVISION_NUMBER, &val);
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to read chip revision: %d\n", ret);
+ goto err;
+ }
+ dev_info(&i2c->dev, "WM8903 revision %c\n",
(val & WM8903_CHIP_REV_MASK) + 'A');
- wm8903_reset(codec);
+ /* Reset the device */
+ regmap_write(wm8903->regmap, WM8903_SW_RESET_AND_ID, 0x8903);
- /* Set up GPIOs and microphone detection */
- if (pdata) {
- bool mic_gpio = false;
+ wm8903_init_gpio(wm8903);
- for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) {
- if (pdata->gpio_cfg[i] == WM8903_GPIO_NO_CONFIG)
- continue;
+ /* Set up GPIO pin state, detect if any are MIC detect outputs */
+ for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) {
+ if ((!pdata->gpio_cfg[i]) ||
+ (pdata->gpio_cfg[i] > WM8903_GPIO_CONFIG_ZERO))
+ continue;
- snd_soc_write(codec, WM8903_GPIO_CONTROL_1 + i,
- pdata->gpio_cfg[i] & 0xffff);
+ regmap_write(wm8903->regmap, WM8903_GPIO_CONTROL_1 + i,
+ pdata->gpio_cfg[i] & 0x7fff);
- val = (pdata->gpio_cfg[i] & WM8903_GP1_FN_MASK)
- >> WM8903_GP1_FN_SHIFT;
+ val = (pdata->gpio_cfg[i] & WM8903_GP1_FN_MASK)
+ >> WM8903_GP1_FN_SHIFT;
- switch (val) {
- case WM8903_GPn_FN_MICBIAS_CURRENT_DETECT:
- case WM8903_GPn_FN_MICBIAS_SHORT_DETECT:
- mic_gpio = true;
- break;
- default:
- break;
- }
+ switch (val) {
+ case WM8903_GPn_FN_MICBIAS_CURRENT_DETECT:
+ case WM8903_GPn_FN_MICBIAS_SHORT_DETECT:
+ mic_gpio = true;
+ break;
+ default:
+ break;
}
+ }
- snd_soc_write(codec, WM8903_MIC_BIAS_CONTROL_0,
- pdata->micdet_cfg);
+ /* Set up microphone detection */
+ regmap_write(wm8903->regmap, WM8903_MIC_BIAS_CONTROL_0,
+ pdata->micdet_cfg);
- /* Microphone detection needs the WSEQ clock */
- if (pdata->micdet_cfg)
- snd_soc_update_bits(codec, WM8903_WRITE_SEQUENCER_0,
- WM8903_WSEQ_ENA, WM8903_WSEQ_ENA);
+ /* Microphone detection needs the WSEQ clock */
+ if (pdata->micdet_cfg)
+ regmap_update_bits(wm8903->regmap, WM8903_WRITE_SEQUENCER_0,
+ WM8903_WSEQ_ENA, WM8903_WSEQ_ENA);
- /* If microphone detection is enabled by pdata but
- * detected via IRQ then interrupts can be lost before
- * the machine driver has set up microphone detection
- * IRQs as the IRQs are clear on read. The detection
- * will be enabled when the machine driver configures.
- */
- WARN_ON(!mic_gpio && (pdata->micdet_cfg & WM8903_MICDET_ENA));
+ /* If microphone detection is enabled by pdata but
+ * detected via IRQ then interrupts can be lost before
+ * the machine driver has set up microphone detection
+ * IRQs as the IRQs are clear on read. The detection
+ * will be enabled when the machine driver configures.
+ */
+ WARN_ON(!mic_gpio && (pdata->micdet_cfg & WM8903_MICDET_ENA));
- wm8903->mic_delay = pdata->micdet_delay;
- }
-
- if (wm8903->irq) {
- if (pdata && pdata->irq_active_low) {
+ wm8903->mic_delay = pdata->micdet_delay;
+
+ if (i2c->irq) {
+ if (pdata->irq_active_low) {
trigger = IRQF_TRIGGER_LOW;
irq_pol = WM8903_IRQ_POL;
} else {
@@ -1967,115 +2141,83 @@ static int wm8903_probe(struct snd_soc_codec *codec)
irq_pol = 0;
}
- snd_soc_update_bits(codec, WM8903_INTERRUPT_CONTROL,
- WM8903_IRQ_POL, irq_pol);
-
- ret = request_threaded_irq(wm8903->irq, NULL, wm8903_irq,
+ regmap_update_bits(wm8903->regmap, WM8903_INTERRUPT_CONTROL,
+ WM8903_IRQ_POL, irq_pol);
+
+ ret = request_threaded_irq(i2c->irq, NULL, wm8903_irq,
trigger | IRQF_ONESHOT,
- "wm8903", codec);
+ "wm8903", wm8903);
if (ret != 0) {
- dev_err(codec->dev, "Failed to request IRQ: %d\n",
+ dev_err(wm8903->dev, "Failed to request IRQ: %d\n",
ret);
return ret;
}
/* Enable write sequencer interrupts */
- snd_soc_update_bits(codec, WM8903_INTERRUPT_STATUS_1_MASK,
- WM8903_IM_WSEQ_BUSY_EINT, 0);
+ regmap_update_bits(wm8903->regmap,
+ WM8903_INTERRUPT_STATUS_1_MASK,
+ WM8903_IM_WSEQ_BUSY_EINT, 0);
}
- /* power on device */
- wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
/* Latch volume update bits */
- val = snd_soc_read(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT);
- val |= WM8903_ADCVU;
- snd_soc_write(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT, val);
- snd_soc_write(codec, WM8903_ADC_DIGITAL_VOLUME_RIGHT, val);
-
- val = snd_soc_read(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT);
- val |= WM8903_DACVU;
- snd_soc_write(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT, val);
- snd_soc_write(codec, WM8903_DAC_DIGITAL_VOLUME_RIGHT, val);
-
- val = snd_soc_read(codec, WM8903_ANALOGUE_OUT1_LEFT);
- val |= WM8903_HPOUTVU;
- snd_soc_write(codec, WM8903_ANALOGUE_OUT1_LEFT, val);
- snd_soc_write(codec, WM8903_ANALOGUE_OUT1_RIGHT, val);
-
- val = snd_soc_read(codec, WM8903_ANALOGUE_OUT2_LEFT);
- val |= WM8903_LINEOUTVU;
- snd_soc_write(codec, WM8903_ANALOGUE_OUT2_LEFT, val);
- snd_soc_write(codec, WM8903_ANALOGUE_OUT2_RIGHT, val);
-
- val = snd_soc_read(codec, WM8903_ANALOGUE_OUT3_LEFT);
- val |= WM8903_SPKVU;
- snd_soc_write(codec, WM8903_ANALOGUE_OUT3_LEFT, val);
- snd_soc_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val);
+ regmap_update_bits(wm8903->regmap, WM8903_ADC_DIGITAL_VOLUME_LEFT,
+ WM8903_ADCVU, WM8903_ADCVU);
+ regmap_update_bits(wm8903->regmap, WM8903_ADC_DIGITAL_VOLUME_RIGHT,
+ WM8903_ADCVU, WM8903_ADCVU);
+
+ regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_VOLUME_LEFT,
+ WM8903_DACVU, WM8903_DACVU);
+ regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_VOLUME_RIGHT,
+ WM8903_DACVU, WM8903_DACVU);
+
+ regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT1_LEFT,
+ WM8903_HPOUTVU, WM8903_HPOUTVU);
+ regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT1_RIGHT,
+ WM8903_HPOUTVU, WM8903_HPOUTVU);
+
+ regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT2_LEFT,
+ WM8903_LINEOUTVU, WM8903_LINEOUTVU);
+ regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT2_RIGHT,
+ WM8903_LINEOUTVU, WM8903_LINEOUTVU);
+
+ regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT3_LEFT,
+ WM8903_SPKVU, WM8903_SPKVU);
+ regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT3_RIGHT,
+ WM8903_SPKVU, WM8903_SPKVU);
/* Enable DAC soft mute by default */
- snd_soc_update_bits(codec, WM8903_DAC_DIGITAL_1,
- WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE,
- WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE);
-
- snd_soc_add_controls(codec, wm8903_snd_controls,
- ARRAY_SIZE(wm8903_snd_controls));
- wm8903_add_widgets(codec);
-
- wm8903_init_gpio(codec);
-
- return ret;
-}
-
-/* power down chip */
-static int wm8903_remove(struct snd_soc_codec *codec)
-{
- wm8903_free_gpio(codec);
- wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static struct snd_soc_codec_driver soc_codec_dev_wm8903 = {
- .probe = wm8903_probe,
- .remove = wm8903_remove,
- .suspend = wm8903_suspend,
- .resume = wm8903_resume,
- .set_bias_level = wm8903_set_bias_level,
- .reg_cache_size = ARRAY_SIZE(wm8903_reg_defaults),
- .reg_word_size = sizeof(u16),
- .reg_cache_default = wm8903_reg_defaults,
- .volatile_register = wm8903_volatile_register,
- .seq_notifier = wm8903_seq_notifier,
-};
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
-{
- struct wm8903_priv *wm8903;
- int ret;
-
- wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL);
- if (wm8903 == NULL)
- return -ENOMEM;
-
- i2c_set_clientdata(i2c, wm8903);
- wm8903->irq = i2c->irq;
+ regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_1,
+ WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE,
+ WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE);
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8903, &wm8903_dai, 1);
- if (ret < 0)
- kfree(wm8903);
+ if (ret != 0)
+ goto err;
+
+ return 0;
+err:
return ret;
}
-static __devexit int wm8903_i2c_remove(struct i2c_client *client)
+static int wm8903_i2c_remove(struct i2c_client *client)
{
+ struct wm8903_priv *wm8903 = i2c_get_clientdata(client);
+
+ if (client->irq)
+ free_irq(client->irq, wm8903);
+ wm8903_free_gpio(wm8903);
snd_soc_unregister_codec(&client->dev);
- kfree(i2c_get_clientdata(client));
+
return 0;
}
+static const struct of_device_id wm8903_of_match[] = {
+ { .compatible = "wlf,wm8903", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, wm8903_of_match);
+
static const struct i2c_device_id wm8903_i2c_id[] = {
{ "wm8903", 0 },
{ }
@@ -2086,34 +2228,14 @@ static struct i2c_driver wm8903_i2c_driver = {
.driver = {
.name = "wm8903",
.owner = THIS_MODULE,
+ .of_match_table = wm8903_of_match,
},
.probe = wm8903_i2c_probe,
- .remove = __devexit_p(wm8903_i2c_remove),
+ .remove = wm8903_i2c_remove,
.id_table = wm8903_i2c_id,
};
-#endif
-static int __init wm8903_modinit(void)
-{
- int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- ret = i2c_add_driver(&wm8903_i2c_driver);
- if (ret != 0) {
- printk(KERN_ERR "Failed to register wm8903 I2C driver: %d\n",
- ret);
- }
-#endif
- return ret;
-}
-module_init(wm8903_modinit);
-
-static void __exit wm8903_exit(void)
-{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- i2c_del_driver(&wm8903_i2c_driver);
-#endif
-}
-module_exit(wm8903_exit);
+module_i2c_driver(wm8903_i2c_driver);
MODULE_DESCRIPTION("ASoC WM8903 driver");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.cm>");