2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-17 09:43:59 +08:00

ASoC: Updates for 3.6

This has been a pretty quiet release - very little activity in framework
 terms, mostly just a few new drivers and updates:
 
 - Added the ability to add and remove DAPM paths dynamically, mostly for
   reparenting on clock changes.
 - New machine drivers for Marvell Brownstone, ST-Ericsson Ux500
   reference platform and ttc-dkp.
 - New CPU drivers for Blackfin BF6xx SPORTs in I2S mode, Marvell MMP,
   Synopsis Designware I2S controllers, and SPEAr DMA and S/PDIF
 - New CODEC drivers for Dialog DA732x, ST STA529, ST-Ericsson AB8500, TI
   Isabelle and Wolfson Microelectronics WM5102 and WM5110
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJQByjoAAoJEBus8iNuMP3dRJEP/jCQWuIu1ELlcK31zyJOY9n+
 Lp5tB7fG8KkUyYkSOyH0ZHszUr3mH1+/U67JooVmQNm3ml9aWISIQ+W62KKyK2x5
 k0Oe+EOypRWQs7QOXjupgzmGgd/OJa2jIliJJ4/rB4k8/QJW9f0lf23K4lxd0dU1
 guZhjvpj/1NjeSoSKWf52+sA4rKZ/4i+h5kQJZ6bgDgVtbtS6MqxYc1za/mZU2/h
 TpTh1F2vCH9JS9KFiITx8JJBCkZ9QjtrFUwPjkHkjx+r5FMmoHMoQHCTlDiR5JBN
 O6SMk4Dw7c8olM/vGXLY3XHqmj+FG0WkAXTLkWVt8XaUGA2uaZ6KYmYlVYOuCujv
 7YeWyia0heXbU71NtTaYuGMYPt9Jv8hDez4CQceWz69Ep5VhpRMlpQuWtPPKEnbp
 SE91gFtxC0Fqhak8OIvXLzuB650aNInaffihOPZNV7aDdrN84OZL6tP2X/jlVHuU
 X34e0msuFyyMNMPPL/ttQD3m8LiEKAqa86s5Mo2gOyXWNA37hzv1qqbbHYtw01H8
 TeAj1nt8bPJTUOxbAddYcF7UpIt3D5KW5Q89A5E7Nk69PacddPfA5f06XewOG9Uf
 X8MjdSr2l55s1JokZRIjHdFAo7xn9iUd8NOY9iviZqiZYnlRJ1IEedjvjwzf1eOQ
 3t+N1HF7KNR3J3cG+uoi
 =JHE2
 -----END PGP SIGNATURE-----

Merge tag 'asoc-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-next

ASoC: Updates for 3.6

This has been a pretty quiet release - very little activity in framework
terms, mostly just a few new drivers and updates:

- Added the ability to add and remove DAPM paths dynamically, mostly for
  reparenting on clock changes.
- New machine drivers for Marvell Brownstone, ST-Ericsson Ux500
  reference platform and ttc-dkp.
- New CPU drivers for Blackfin BF6xx SPORTs in I2S mode, Marvell MMP,
  Synopsis Designware I2S controllers, and SPEAr DMA and S/PDIF
- New CODEC drivers for Dialog DA732x, ST STA529, ST-Ericsson AB8500, TI
  Isabelle and Wolfson Microelectronics WM5102 and WM5110
This commit is contained in:
Takashi Iwai 2012-07-19 08:03:20 +02:00
commit 4609ed6b1f
126 changed files with 16718 additions and 1343 deletions

View File

@ -6747,9 +6747,11 @@ F: include/linux/tifm.h
TI LM49xxx FAMILY ASoC CODEC DRIVERS TI LM49xxx FAMILY ASoC CODEC DRIVERS
M: M R Swami Reddy <mr.swami.reddy@ti.com> M: M R Swami Reddy <mr.swami.reddy@ti.com>
M: Vishwas A Deshpande <vishwas.a.deshpande@ti.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers) L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained S: Maintained
F: sound/soc/codecs/lm49453* F: sound/soc/codecs/lm49453*
F: sound/soc/codecs/isabelle*
TI TWL4030 SERIES SOC CODEC DRIVER TI TWL4030 SERIES SOC CODEC DRIVER
M: Peter Ujfalusi <peter.ujfalusi@ti.com> M: Peter Ujfalusi <peter.ujfalusi@ti.com>

View File

@ -25,6 +25,7 @@
#include <linux/mfd/tc3589x.h> #include <linux/mfd/tc3589x.h>
#include <linux/mfd/tps6105x.h> #include <linux/mfd/tps6105x.h>
#include <linux/mfd/abx500/ab8500-gpio.h> #include <linux/mfd/abx500/ab8500-gpio.h>
#include <linux/mfd/abx500/ab8500-codec.h>
#include <linux/leds-lp5521.h> #include <linux/leds-lp5521.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/smsc911x.h> #include <linux/smsc911x.h>
@ -97,6 +98,18 @@ static struct ab8500_gpio_platform_data ab8500_gpio_pdata = {
0x7A, 0x00, 0x00}, 0x7A, 0x00, 0x00},
}; };
/* ab8500-codec */
static struct ab8500_codec_platform_data ab8500_codec_pdata = {
.amics = {
.mic1_type = AMIC_TYPE_DIFFERENTIAL,
.mic2_type = AMIC_TYPE_DIFFERENTIAL,
.mic1a_micbias = AMIC_MICBIAS_VAMIC1,
.mic1b_micbias = AMIC_MICBIAS_VAMIC1,
.mic2_micbias = AMIC_MICBIAS_VAMIC2
},
.ear_cmv = EAR_CMV_0_95V
};
static struct gpio_keys_button snowball_key_array[] = { static struct gpio_keys_button snowball_key_array[] = {
{ {
.gpio = 32, .gpio = 32,
@ -195,6 +208,7 @@ static struct ab8500_platform_data ab8500_platdata = {
.regulator = ab8500_regulators, .regulator = ab8500_regulators,
.num_regulator = ARRAY_SIZE(ab8500_regulators), .num_regulator = ARRAY_SIZE(ab8500_regulators),
.gpio = &ab8500_gpio_pdata, .gpio = &ab8500_gpio_pdata,
.codec = &ab8500_codec_pdata,
}; };
static struct resource ab8500_resources[] = { static struct resource ab8500_resources[] = {

View File

@ -670,6 +670,12 @@ static inline int dmaengine_resume(struct dma_chan *chan)
return dmaengine_device_control(chan, DMA_RESUME, 0); return dmaengine_device_control(chan, DMA_RESUME, 0);
} }
static inline enum dma_status dmaengine_tx_status(struct dma_chan *chan,
dma_cookie_t cookie, struct dma_tx_state *state)
{
return chan->device->device_tx_status(chan, cookie, state);
}
static inline dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc) static inline dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)
{ {
return desc->tx_submit(desc); return desc->tx_submit(desc);

View File

@ -0,0 +1,52 @@
/*
* Copyright (C) ST-Ericsson SA 2012
*
* Author: Ola Lilja <ola.o.lilja@stericsson.com>
* for ST-Ericsson.
*
* License terms:
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#ifndef AB8500_CORE_CODEC_H
#define AB8500_CORE_CODEC_H
/* Mic-types */
enum amic_type {
AMIC_TYPE_SINGLE_ENDED,
AMIC_TYPE_DIFFERENTIAL
};
/* Mic-biases */
enum amic_micbias {
AMIC_MICBIAS_VAMIC1,
AMIC_MICBIAS_VAMIC2
};
/* Bias-voltage */
enum ear_cm_voltage {
EAR_CMV_0_95V,
EAR_CMV_1_10V,
EAR_CMV_1_27V,
EAR_CMV_1_58V
};
/* Analog microphone settings */
struct amic_settings {
enum amic_type mic1_type;
enum amic_type mic2_type;
enum amic_micbias mic1a_micbias;
enum amic_micbias mic1b_micbias;
enum amic_micbias mic2_micbias;
};
/* Platform data structure for the audio-parts of the AB8500 */
struct ab8500_codec_platform_data {
struct amic_settings amics;
enum ear_cm_voltage ear_cmv;
};
#endif

View File

@ -266,6 +266,7 @@ struct ab8500 {
struct regulator_reg_init; struct regulator_reg_init;
struct regulator_init_data; struct regulator_init_data;
struct ab8500_gpio_platform_data; struct ab8500_gpio_platform_data;
struct ab8500_codec_platform_data;
/** /**
* struct ab8500_platform_data - AB8500 platform data * struct ab8500_platform_data - AB8500 platform data
@ -284,6 +285,7 @@ struct ab8500_platform_data {
int num_regulator; int num_regulator;
struct regulator_init_data *regulator; struct regulator_init_data *regulator;
struct ab8500_gpio_platform_data *gpio; struct ab8500_gpio_platform_data *gpio;
struct ab8500_codec_platform_data *codec;
}; };
extern int __devinit ab8500_init(struct ab8500 *ab8500, extern int __devinit ab8500_init(struct ab8500 *ab8500,

View File

@ -0,0 +1,22 @@
/*
* MMP Platform AUDIO Management
*
* Copyright (c) 2011 Marvell Semiconductors Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef MMP_AUDIO_H
#define MMP_AUDIO_H
struct mmp_audio_platdata {
u32 period_max_capture;
u32 buffer_max_capture;
u32 period_max_playback;
u32 buffer_max_playback;
};
#endif /* MMP_AUDIO_H */

View File

@ -0,0 +1,69 @@
/*
* Copyright (ST) 2012 Rajeev Kumar (rajeev-dlh.kumar@st.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __SOUND_DESIGNWARE_I2S_H
#define __SOUND_DESIGNWARE_I2S_H
#include <linux/dmaengine.h>
#include <linux/types.h>
/*
* struct i2s_clk_config_data - represent i2s clk configuration data
* @chan_nr: number of channel
* @data_width: number of bits per sample (8/16/24/32 bit)
* @sample_rate: sampling frequency (8Khz, 16Khz, 32Khz, 44Khz, 48Khz)
*/
struct i2s_clk_config_data {
int chan_nr;
u32 data_width;
u32 sample_rate;
};
struct i2s_platform_data {
#define DWC_I2S_PLAY (1 << 0)
#define DWC_I2S_RECORD (1 << 1)
unsigned int cap;
int channel;
u32 snd_fmts;
u32 snd_rates;
void *play_dma_data;
void *capture_dma_data;
bool (*filter)(struct dma_chan *chan, void *slave);
int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
};
struct i2s_dma_data {
void *data;
dma_addr_t addr;
u32 max_burst;
enum dma_slave_buswidth addr_width;
bool (*filter)(struct dma_chan *chan, void *slave);
};
/* I2S DMA registers */
#define I2S_RXDMA 0x01C0
#define I2S_TXDMA 0x01C8
#define TWO_CHANNEL_SUPPORT 2 /* up to 2.0 */
#define FOUR_CHANNEL_SUPPORT 4 /* up to 3.1 */
#define SIX_CHANNEL_SUPPORT 6 /* up to 5.1 */
#define EIGHT_CHANNEL_SUPPORT 8 /* up to 7.1 */
#endif /* __SOUND_DESIGNWARE_I2S_H */

View File

@ -39,6 +39,7 @@ int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream,
const struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config); const struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config);
int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd); int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream); snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream);
snd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream);
int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
dma_filter_fn filter_fn, void *filter_data); dma_filter_fn filter_fn, void *filter_data);

View File

@ -1074,4 +1074,15 @@ static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max)
const char *snd_pcm_format_name(snd_pcm_format_t format); const char *snd_pcm_format_name(snd_pcm_format_t format);
/**
* Get a string naming the direction of a stream
*/
static inline const char *snd_pcm_stream_str(struct snd_pcm_substream *substream)
{
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
return "Playback";
else
return "Capture";
}
#endif /* __SOUND_PCM_H */ #endif /* __SOUND_PCM_H */

View File

@ -229,6 +229,10 @@ struct device;
{ .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \ { .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
.shift = wshift, .invert = winvert, \ .shift = wshift, .invert = winvert, \
.event = wevent, .event_flags = wflags} .event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_CLOCK_SUPPLY(wname) \
{ .id = snd_soc_dapm_clock_supply, .name = wname, \
.reg = SND_SOC_NOPM, .event = dapm_clock_event, \
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }
/* generic widgets */ /* generic widgets */
#define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \ #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \
@ -245,6 +249,7 @@ struct device;
.reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \ .reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD } .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }
/* dapm kcontrol types */ /* dapm kcontrol types */
#define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \ #define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
@ -327,6 +332,8 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event); struct snd_kcontrol *kcontrol, int event);
int dapm_regulator_event(struct snd_soc_dapm_widget *w, int dapm_regulator_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event); struct snd_kcontrol *kcontrol, int event);
int dapm_clock_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
/* dapm controls */ /* dapm controls */
int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
@ -367,6 +374,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm);
void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm); void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm);
int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route, int num); const struct snd_soc_dapm_route *route, int num);
int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route, int num);
int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm, int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route, int num); const struct snd_soc_dapm_route *route, int num);
@ -432,6 +441,7 @@ enum snd_soc_dapm_type {
snd_soc_dapm_post, /* machine specific post widget - exec last */ snd_soc_dapm_post, /* machine specific post widget - exec last */
snd_soc_dapm_supply, /* power/clock supply */ snd_soc_dapm_supply, /* power/clock supply */
snd_soc_dapm_regulator_supply, /* external regulator */ snd_soc_dapm_regulator_supply, /* external regulator */
snd_soc_dapm_clock_supply, /* external clock */
snd_soc_dapm_aif_in, /* audio interface input */ snd_soc_dapm_aif_in, /* audio interface input */
snd_soc_dapm_aif_out, /* audio interface output */ snd_soc_dapm_aif_out, /* audio interface output */
snd_soc_dapm_siggen, /* signal generator */ snd_soc_dapm_siggen, /* signal generator */
@ -537,6 +547,8 @@ struct snd_soc_dapm_widget {
struct list_head dirty; struct list_head dirty;
int inputs; int inputs;
int outputs; int outputs;
struct clk *clk;
}; };
struct snd_soc_dapm_update { struct snd_soc_dapm_update {

View File

@ -42,11 +42,22 @@
((unsigned long)&(struct soc_mixer_control) \ ((unsigned long)&(struct soc_mixer_control) \
{.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \ {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \
.max = xmax, .platform_max = xmax, .invert = xinvert}) .max = xmax, .platform_max = xmax, .invert = xinvert})
#define SOC_DOUBLE_R_RANGE_VALUE(xlreg, xrreg, xshift, xmin, xmax, xinvert) \
((unsigned long)&(struct soc_mixer_control) \
{.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \
.min = xmin, .max = xmax, .platform_max = xmax, .invert = xinvert})
#define SOC_SINGLE(xname, reg, shift, max, invert) \ #define SOC_SINGLE(xname, reg, shift, max, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
.put = snd_soc_put_volsw, \ .put = snd_soc_put_volsw, \
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
#define SOC_SINGLE_RANGE(xname, xreg, xshift, xmin, xmax, xinvert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.info = snd_soc_info_volsw_range, .get = snd_soc_get_volsw_range, \
.put = snd_soc_put_volsw_range, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .shift = xshift, .min = xmin,\
.max = xmax, .platform_max = xmax, .invert = xinvert} }
#define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ #define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
@ -67,6 +78,16 @@
{.reg = xreg, .rreg = xreg, \ {.reg = xreg, .rreg = xreg, \
.shift = xshift, .rshift = xshift, \ .shift = xshift, .rshift = xshift, \
.max = xmax, .min = xmin} } .max = xmax, .min = xmin} }
#define SOC_SINGLE_RANGE_TLV(xname, xreg, xshift, xmin, xmax, xinvert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
SNDRV_CTL_ELEM_ACCESS_READWRITE,\
.tlv.p = (tlv_array), \
.info = snd_soc_info_volsw_range, \
.get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .shift = xshift, .min = xmin,\
.max = xmax, .platform_max = xmax, .invert = xinvert} }
#define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \ #define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
@ -79,6 +100,13 @@
.get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \ .get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
.private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \ .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
xmax, xinvert) } xmax, xinvert) }
#define SOC_DOUBLE_R_RANGE(xname, reg_left, reg_right, xshift, xmin, \
xmax, xinvert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.info = snd_soc_info_volsw_range, \
.get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \
.private_value = SOC_DOUBLE_R_RANGE_VALUE(reg_left, reg_right, \
xshift, xmin, xmax, xinvert) }
#define SOC_DOUBLE_TLV(xname, reg, shift_left, shift_right, max, invert, tlv_array) \ #define SOC_DOUBLE_TLV(xname, reg, shift_left, shift_right, max, invert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
@ -97,6 +125,16 @@
.get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \ .get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
.private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \ .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
xmax, xinvert) } xmax, xinvert) }
#define SOC_DOUBLE_R_RANGE_TLV(xname, reg_left, reg_right, xshift, xmin, \
xmax, xinvert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
SNDRV_CTL_ELEM_ACCESS_READWRITE,\
.tlv.p = (tlv_array), \
.info = snd_soc_info_volsw_range, \
.get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \
.private_value = SOC_DOUBLE_R_RANGE_VALUE(reg_left, reg_right, \
xshift, xmin, xmax, xinvert) }
#define SOC_DOUBLE_R_SX_TLV(xname, xreg, xrreg, xshift, xmin, xmax, tlv_array) \ #define SOC_DOUBLE_R_SX_TLV(xname, xreg, xrreg, xshift, xmin, xmax, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
@ -460,6 +498,12 @@ int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol); struct snd_ctl_elem_value *ucontrol);
int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol); struct snd_ctl_elem_value *ucontrol);
int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_limit_volume(struct snd_soc_codec *codec, int snd_soc_limit_volume(struct snd_soc_codec *codec,
const char *name, int max); const char *name, int max);
int snd_soc_bytes_info(struct snd_kcontrol *kcontrol, int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
@ -785,13 +829,36 @@ struct snd_soc_dai_link {
/* config - must be set by machine driver */ /* config - must be set by machine driver */
const char *name; /* Codec name */ const char *name; /* Codec name */
const char *stream_name; /* Stream name */ const char *stream_name; /* Stream name */
const char *codec_name; /* for multi-codec */ /*
const struct device_node *codec_of_node; * You MAY specify the link's CPU-side device, either by device name,
const char *platform_name; /* for multi-platform */ * or by DT/OF node, but not both. If this information is omitted,
const struct device_node *platform_of_node; * the CPU-side DAI is matched using .cpu_dai_name only, which hence
* must be globally unique. These fields are currently typically used
* only for codec to codec links, or systems using device tree.
*/
const char *cpu_name;
const struct device_node *cpu_of_node;
/*
* You MAY specify the DAI name of the CPU DAI. If this information is
* omitted, the CPU-side DAI is matched using .cpu_name/.cpu_of_node
* only, which only works well when that device exposes a single DAI.
*/
const char *cpu_dai_name; const char *cpu_dai_name;
const struct device_node *cpu_dai_of_node; /*
* You MUST specify the link's codec, either by device name, or by
* DT/OF node, but not both.
*/
const char *codec_name;
const struct device_node *codec_of_node;
/* You MUST specify the DAI name within the codec */
const char *codec_dai_name; const char *codec_dai_name;
/*
* You MAY specify the link's platform/PCM/DMA driver, either by
* device name, or by DT/OF node, but not both. Some forms of link
* do not need a platform.
*/
const char *platform_name;
const struct device_node *platform_of_node;
int be_id; /* optional ID for machine driver BE identification */ int be_id; /* optional ID for machine driver BE identification */
const struct snd_soc_pcm_stream *params; const struct snd_soc_pcm_stream *params;

35
include/sound/spear_dma.h Normal file
View File

@ -0,0 +1,35 @@
/*
* linux/spear_dma.h
*
* Copyright (ST) 2012 Rajeev Kumar (rajeev-dlh.kumar@st.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef SPEAR_DMA_H
#define SPEAR_DMA_H
#include <linux/dmaengine.h>
struct spear_dma_data {
void *data;
dma_addr_t addr;
u32 max_burst;
enum dma_slave_buswidth addr_width;
bool (*filter)(struct dma_chan *chan, void *slave);
};
#endif /* SPEAR_DMA_H */

View File

@ -0,0 +1,29 @@
/*
* Copyright (ST) 2012 Vipin Kumar (vipin.kumar@st.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __SOUND_SPDIF_H
#define __SOUND_SPDIF_H
struct spear_spdif_platform_data {
/* DMA params */
void *dma_params;
bool (*filter)(struct dma_chan *chan, void *slave);
void (*reset_perip)(void);
};
#endif /* SOUND_SPDIF_H */

View File

@ -33,6 +33,7 @@ source "sound/soc/atmel/Kconfig"
source "sound/soc/au1x/Kconfig" source "sound/soc/au1x/Kconfig"
source "sound/soc/blackfin/Kconfig" source "sound/soc/blackfin/Kconfig"
source "sound/soc/davinci/Kconfig" source "sound/soc/davinci/Kconfig"
source "sound/soc/dwc/Kconfig"
source "sound/soc/ep93xx/Kconfig" source "sound/soc/ep93xx/Kconfig"
source "sound/soc/fsl/Kconfig" source "sound/soc/fsl/Kconfig"
source "sound/soc/jz4740/Kconfig" source "sound/soc/jz4740/Kconfig"

View File

@ -11,6 +11,7 @@ obj-$(CONFIG_SND_SOC) += atmel/
obj-$(CONFIG_SND_SOC) += au1x/ obj-$(CONFIG_SND_SOC) += au1x/
obj-$(CONFIG_SND_SOC) += blackfin/ obj-$(CONFIG_SND_SOC) += blackfin/
obj-$(CONFIG_SND_SOC) += davinci/ obj-$(CONFIG_SND_SOC) += davinci/
obj-$(CONFIG_SND_SOC) += dwc/
obj-$(CONFIG_SND_SOC) += ep93xx/ obj-$(CONFIG_SND_SOC) += ep93xx/
obj-$(CONFIG_SND_SOC) += fsl/ obj-$(CONFIG_SND_SOC) += fsl/
obj-$(CONFIG_SND_SOC) += jz4740/ obj-$(CONFIG_SND_SOC) += jz4740/

View File

@ -1,7 +1,8 @@
config SND_BF5XX_I2S config SND_BF5XX_I2S
tristate "SoC I2S Audio for the ADI BF5xx chip" tristate "SoC I2S Audio for the ADI Blackfin chip"
depends on BLACKFIN depends on BLACKFIN
select SND_BF5XX_SOC_SPORT select SND_BF5XX_SOC_SPORT if !BF60x
select SND_BF6XX_SOC_SPORT if BF60x
help help
Say Y or M if you want to add support for codecs attached to Say Y or M if you want to add support for codecs attached to
the Blackfin SPORT (synchronous serial ports) interface in I2S the Blackfin SPORT (synchronous serial ports) interface in I2S
@ -9,12 +10,14 @@ config SND_BF5XX_I2S
You will also need to select the audio interfaces to support below. You will also need to select the audio interfaces to support below.
config SND_BF5XX_SOC_SSM2602 config SND_BF5XX_SOC_SSM2602
tristate "SoC SSM2602 Audio support for BF52x ezkit" tristate "SoC SSM2602 Audio Codec Add-On Card support"
depends on SND_BF5XX_I2S && (SPI_MASTER || I2C) depends on SND_BF5XX_I2S && (SPI_MASTER || I2C)
select SND_BF5XX_SOC_I2S select SND_BF5XX_SOC_I2S if !BF60x
select SND_BF6XX_SOC_I2S if BF60x
select SND_SOC_SSM2602 select SND_SOC_SSM2602
help help
Say Y if you want to add support for SoC audio on BF527-EZKIT. Say Y if you want to add support for the Analog Devices
SSM2602 Audio Codec Add-On Card.
config SND_SOC_BFIN_EVAL_ADAU1701 config SND_SOC_BFIN_EVAL_ADAU1701
tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards" tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards"
@ -162,9 +165,15 @@ config SND_BF5XX_SOC_AD1980
config SND_BF5XX_SOC_SPORT config SND_BF5XX_SOC_SPORT
tristate tristate
config SND_BF6XX_SOC_SPORT
tristate
config SND_BF5XX_SOC_I2S config SND_BF5XX_SOC_I2S
tristate tristate
config SND_BF6XX_SOC_I2S
tristate
config SND_BF5XX_SOC_TDM config SND_BF5XX_SOC_TDM
tristate tristate
@ -173,7 +182,7 @@ config SND_BF5XX_SOC_AC97
config SND_BF5XX_SPORT_NUM config SND_BF5XX_SPORT_NUM
int "Set a SPORT for Sound chip" int "Set a SPORT for Sound chip"
depends on (SND_BF5XX_I2S || SND_BF5XX_AC97 || SND_BF5XX_TDM) depends on (SND_BF5XX_SOC_SPORT || SND_BF6XX_SOC_SPORT)
range 0 3 if BF54x range 0 3 if BF54x
range 0 1 if !BF54x range 0 1 if !BF54x
default 0 default 0

View File

@ -3,16 +3,20 @@ snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o
snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o
snd-bf5xx-tdm-objs := bf5xx-tdm-pcm.o snd-bf5xx-tdm-objs := bf5xx-tdm-pcm.o
snd-soc-bf5xx-sport-objs := bf5xx-sport.o snd-soc-bf5xx-sport-objs := bf5xx-sport.o
snd-soc-bf6xx-sport-objs := bf6xx-sport.o
snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o
snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o
snd-soc-bf6xx-i2s-objs := bf6xx-i2s.o
snd-soc-bf5xx-tdm-objs := bf5xx-tdm.o snd-soc-bf5xx-tdm-objs := bf5xx-tdm.o
obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o
obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o
obj-$(CONFIG_SND_BF5XX_TDM) += snd-bf5xx-tdm.o obj-$(CONFIG_SND_BF5XX_TDM) += snd-bf5xx-tdm.o
obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o
obj-$(CONFIG_SND_BF6XX_SOC_SPORT) += snd-soc-bf6xx-sport.o
obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o
obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o
obj-$(CONFIG_SND_BF6XX_SOC_I2S) += snd-soc-bf6xx-i2s.o
obj-$(CONFIG_SND_BF5XX_SOC_TDM) += snd-soc-bf5xx-tdm.o obj-$(CONFIG_SND_BF5XX_SOC_TDM) += snd-soc-bf5xx-tdm.o
# Blackfin Machine Support # Blackfin Machine Support

View File

@ -0,0 +1,234 @@
/*
* bf6xx-i2s.c - Analog Devices BF6XX i2s interface driver
*
* Copyright (c) 2012 Analog Devices Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/device.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dai.h>
#include "bf6xx-sport.h"
struct sport_params param;
static int bfin_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
struct sport_device *sport = snd_soc_dai_get_drvdata(cpu_dai);
struct device *dev = &sport->pdev->dev;
int ret = 0;
param.spctl &= ~(SPORT_CTL_OPMODE | SPORT_CTL_CKRE | SPORT_CTL_FSR
| SPORT_CTL_LFS | SPORT_CTL_LAFS);
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
param.spctl |= SPORT_CTL_OPMODE | SPORT_CTL_CKRE
| SPORT_CTL_LFS;
break;
case SND_SOC_DAIFMT_DSP_A:
param.spctl |= SPORT_CTL_FSR;
break;
case SND_SOC_DAIFMT_LEFT_J:
param.spctl |= SPORT_CTL_OPMODE | SPORT_CTL_LFS
| SPORT_CTL_LAFS;
break;
default:
dev_err(dev, "%s: Unknown DAI format type\n", __func__);
ret = -EINVAL;
break;
}
param.spctl &= ~(SPORT_CTL_ICLK | SPORT_CTL_IFS);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
break;
case SND_SOC_DAIFMT_CBS_CFS:
case SND_SOC_DAIFMT_CBM_CFS:
case SND_SOC_DAIFMT_CBS_CFM:
ret = -EINVAL;
break;
default:
dev_err(dev, "%s: Unknown DAI master type\n", __func__);
ret = -EINVAL;
break;
}
return ret;
}
static int bfin_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
struct device *dev = &sport->pdev->dev;
int ret = 0;
param.spctl &= ~SPORT_CTL_SLEN;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
param.spctl |= 0x70;
sport->wdsize = 1;
case SNDRV_PCM_FORMAT_S16_LE:
param.spctl |= 0xf0;
sport->wdsize = 2;
break;
case SNDRV_PCM_FORMAT_S24_LE:
param.spctl |= 0x170;
sport->wdsize = 3;
break;
case SNDRV_PCM_FORMAT_S32_LE:
param.spctl |= 0x1f0;
sport->wdsize = 4;
break;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
ret = sport_set_tx_params(sport, &param);
if (ret) {
dev_err(dev, "SPORT tx is busy!\n");
return ret;
}
} else {
ret = sport_set_rx_params(sport, &param);
if (ret) {
dev_err(dev, "SPORT rx is busy!\n");
return ret;
}
}
return 0;
}
#ifdef CONFIG_PM
static int bfin_i2s_suspend(struct snd_soc_dai *dai)
{
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
if (dai->capture_active)
sport_rx_stop(sport);
if (dai->playback_active)
sport_tx_stop(sport);
return 0;
}
static int bfin_i2s_resume(struct snd_soc_dai *dai)
{
struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
struct device *dev = &sport->pdev->dev;
int ret;
ret = sport_set_tx_params(sport, &param);
if (ret) {
dev_err(dev, "SPORT tx is busy!\n");
return ret;
}
ret = sport_set_rx_params(sport, &param);
if (ret) {
dev_err(dev, "SPORT rx is busy!\n");
return ret;
}
return 0;
}
#else
#define bfin_i2s_suspend NULL
#define bfin_i2s_resume NULL
#endif
#define BFIN_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
SNDRV_PCM_RATE_96000)
#define BFIN_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_ops bfin_i2s_dai_ops = {
.hw_params = bfin_i2s_hw_params,
.set_fmt = bfin_i2s_set_dai_fmt,
};
static struct snd_soc_dai_driver bfin_i2s_dai = {
.suspend = bfin_i2s_suspend,
.resume = bfin_i2s_resume,
.playback = {
.channels_min = 1,
.channels_max = 2,
.rates = BFIN_I2S_RATES,
.formats = BFIN_I2S_FORMATS,
},
.capture = {
.channels_min = 1,
.channels_max = 2,
.rates = BFIN_I2S_RATES,
.formats = BFIN_I2S_FORMATS,
},
.ops = &bfin_i2s_dai_ops,
};
static int __devinit bfin_i2s_probe(struct platform_device *pdev)
{
struct sport_device *sport;
struct device *dev = &pdev->dev;
int ret;
sport = sport_create(pdev);
if (!sport)
return -ENODEV;
/* register with the ASoC layers */
ret = snd_soc_register_dai(dev, &bfin_i2s_dai);
if (ret) {
dev_err(dev, "Failed to register DAI: %d\n", ret);
sport_delete(sport);
return ret;
}
platform_set_drvdata(pdev, sport);
return 0;
}
static int __devexit bfin_i2s_remove(struct platform_device *pdev)
{
struct sport_device *sport = platform_get_drvdata(pdev);
snd_soc_unregister_dai(&pdev->dev);
sport_delete(sport);
return 0;
}
static struct platform_driver bfin_i2s_driver = {
.probe = bfin_i2s_probe,
.remove = __devexit_p(bfin_i2s_remove),
.driver = {
.name = "bfin-i2s",
.owner = THIS_MODULE,
},
};
module_platform_driver(bfin_i2s_driver);
MODULE_DESCRIPTION("Analog Devices BF6XX i2s interface driver");
MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,422 @@
/*
* bf6xx_sport.c Analog Devices BF6XX SPORT driver
*
* Copyright (c) 2012 Analog Devices Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <asm/blackfin.h>
#include <asm/dma.h>
#include <asm/portmux.h>
#include "bf6xx-sport.h"
int sport_set_tx_params(struct sport_device *sport,
struct sport_params *params)
{
if (sport->tx_regs->spctl & SPORT_CTL_SPENPRI)
return -EBUSY;
sport->tx_regs->spctl = params->spctl | SPORT_CTL_SPTRAN;
sport->tx_regs->div = params->div;
SSYNC();
return 0;
}
EXPORT_SYMBOL(sport_set_tx_params);
int sport_set_rx_params(struct sport_device *sport,
struct sport_params *params)
{
if (sport->rx_regs->spctl & SPORT_CTL_SPENPRI)
return -EBUSY;
sport->rx_regs->spctl = params->spctl & ~SPORT_CTL_SPTRAN;
sport->rx_regs->div = params->div;
SSYNC();
return 0;
}
EXPORT_SYMBOL(sport_set_rx_params);
static int compute_wdsize(size_t wdsize)
{
switch (wdsize) {
case 1:
return WDSIZE_8 | PSIZE_8;
case 2:
return WDSIZE_16 | PSIZE_16;
default:
return WDSIZE_32 | PSIZE_32;
}
}
void sport_tx_start(struct sport_device *sport)
{
set_dma_next_desc_addr(sport->tx_dma_chan, sport->tx_desc);
set_dma_config(sport->tx_dma_chan, DMAFLOW_LIST | DI_EN
| compute_wdsize(sport->wdsize) | NDSIZE_6);
enable_dma(sport->tx_dma_chan);
sport->tx_regs->spctl |= SPORT_CTL_SPENPRI;
SSYNC();
}
EXPORT_SYMBOL(sport_tx_start);
void sport_rx_start(struct sport_device *sport)
{
set_dma_next_desc_addr(sport->rx_dma_chan, sport->rx_desc);
set_dma_config(sport->rx_dma_chan, DMAFLOW_LIST | DI_EN | WNR
| compute_wdsize(sport->wdsize) | NDSIZE_6);
enable_dma(sport->rx_dma_chan);
sport->rx_regs->spctl |= SPORT_CTL_SPENPRI;
SSYNC();
}
EXPORT_SYMBOL(sport_rx_start);
void sport_tx_stop(struct sport_device *sport)
{
sport->tx_regs->spctl &= ~SPORT_CTL_SPENPRI;
SSYNC();
disable_dma(sport->tx_dma_chan);
}
EXPORT_SYMBOL(sport_tx_stop);
void sport_rx_stop(struct sport_device *sport)
{
sport->rx_regs->spctl &= ~SPORT_CTL_SPENPRI;
SSYNC();
disable_dma(sport->rx_dma_chan);
}
EXPORT_SYMBOL(sport_rx_stop);
void sport_set_tx_callback(struct sport_device *sport,
void (*tx_callback)(void *), void *tx_data)
{
sport->tx_callback = tx_callback;
sport->tx_data = tx_data;
}
EXPORT_SYMBOL(sport_set_tx_callback);
void sport_set_rx_callback(struct sport_device *sport,
void (*rx_callback)(void *), void *rx_data)
{
sport->rx_callback = rx_callback;
sport->rx_data = rx_data;
}
EXPORT_SYMBOL(sport_set_rx_callback);
static void setup_desc(struct dmasg *desc, void *buf, int fragcount,
size_t fragsize, unsigned int cfg,
unsigned int count, size_t wdsize)
{
int i;
for (i = 0; i < fragcount; ++i) {
desc[i].next_desc_addr = &(desc[i + 1]);
desc[i].start_addr = (unsigned long)buf + i*fragsize;
desc[i].cfg = cfg;
desc[i].x_count = count;
desc[i].x_modify = wdsize;
desc[i].y_count = 0;
desc[i].y_modify = 0;
}
/* make circular */
desc[fragcount-1].next_desc_addr = desc;
}
int sport_config_tx_dma(struct sport_device *sport, void *buf,
int fragcount, size_t fragsize)
{
unsigned int count;
unsigned int cfg;
dma_addr_t addr;
count = fragsize/sport->wdsize;
if (sport->tx_desc)
dma_free_coherent(NULL, sport->tx_desc_size,
sport->tx_desc, 0);
sport->tx_desc = dma_alloc_coherent(NULL,
fragcount * sizeof(struct dmasg), &addr, 0);
sport->tx_desc_size = fragcount * sizeof(struct dmasg);
if (!sport->tx_desc)
return -ENOMEM;
sport->tx_buf = buf;
sport->tx_fragsize = fragsize;
sport->tx_frags = fragcount;
cfg = DMAFLOW_LIST | DI_EN | compute_wdsize(sport->wdsize) | NDSIZE_6;
setup_desc(sport->tx_desc, buf, fragcount, fragsize,
cfg|DMAEN, count, sport->wdsize);
return 0;
}
EXPORT_SYMBOL(sport_config_tx_dma);
int sport_config_rx_dma(struct sport_device *sport, void *buf,
int fragcount, size_t fragsize)
{
unsigned int count;
unsigned int cfg;
dma_addr_t addr;
count = fragsize/sport->wdsize;
if (sport->rx_desc)
dma_free_coherent(NULL, sport->rx_desc_size,
sport->rx_desc, 0);
sport->rx_desc = dma_alloc_coherent(NULL,
fragcount * sizeof(struct dmasg), &addr, 0);
sport->rx_desc_size = fragcount * sizeof(struct dmasg);
if (!sport->rx_desc)
return -ENOMEM;
sport->rx_buf = buf;
sport->rx_fragsize = fragsize;
sport->rx_frags = fragcount;
cfg = DMAFLOW_LIST | DI_EN | compute_wdsize(sport->wdsize)
| WNR | NDSIZE_6;
setup_desc(sport->rx_desc, buf, fragcount, fragsize,
cfg|DMAEN, count, sport->wdsize);
return 0;
}
EXPORT_SYMBOL(sport_config_rx_dma);
unsigned long sport_curr_offset_tx(struct sport_device *sport)
{
unsigned long curr = get_dma_curr_addr(sport->tx_dma_chan);
return (unsigned char *)curr - sport->tx_buf;
}
EXPORT_SYMBOL(sport_curr_offset_tx);
unsigned long sport_curr_offset_rx(struct sport_device *sport)
{
unsigned long curr = get_dma_curr_addr(sport->rx_dma_chan);
return (unsigned char *)curr - sport->rx_buf;
}
EXPORT_SYMBOL(sport_curr_offset_rx);
static irqreturn_t sport_tx_irq(int irq, void *dev_id)
{
struct sport_device *sport = dev_id;
static unsigned long status;
status = get_dma_curr_irqstat(sport->tx_dma_chan);
if (status & (DMA_DONE|DMA_ERR)) {
clear_dma_irqstat(sport->tx_dma_chan);
SSYNC();
}
if (sport->tx_callback)
sport->tx_callback(sport->tx_data);
return IRQ_HANDLED;
}
static irqreturn_t sport_rx_irq(int irq, void *dev_id)
{
struct sport_device *sport = dev_id;
unsigned long status;
status = get_dma_curr_irqstat(sport->rx_dma_chan);
if (status & (DMA_DONE|DMA_ERR)) {
clear_dma_irqstat(sport->rx_dma_chan);
SSYNC();
}
if (sport->rx_callback)
sport->rx_callback(sport->rx_data);
return IRQ_HANDLED;
}
static irqreturn_t sport_err_irq(int irq, void *dev_id)
{
struct sport_device *sport = dev_id;
struct device *dev = &sport->pdev->dev;
if (sport->tx_regs->spctl & SPORT_CTL_DERRPRI)
dev_err(dev, "sport error: TUVF\n");
if (sport->rx_regs->spctl & SPORT_CTL_DERRPRI)
dev_err(dev, "sport error: ROVF\n");
return IRQ_HANDLED;
}
static int sport_get_resource(struct sport_device *sport)
{
struct platform_device *pdev = sport->pdev;
struct device *dev = &pdev->dev;
struct bfin_snd_platform_data *pdata = dev->platform_data;
struct resource *res;
if (!pdata) {
dev_err(dev, "No platform data\n");
return -ENODEV;
}
sport->pin_req = pdata->pin_req;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "No tx MEM resource\n");
return -ENODEV;
}
sport->tx_regs = (struct sport_register *)res->start;
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res) {
dev_err(dev, "No rx MEM resource\n");
return -ENODEV;
}
sport->rx_regs = (struct sport_register *)res->start;
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!res) {
dev_err(dev, "No tx DMA resource\n");
return -ENODEV;
}
sport->tx_dma_chan = res->start;
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!res) {
dev_err(dev, "No rx DMA resource\n");
return -ENODEV;
}
sport->rx_dma_chan = res->start;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(dev, "No tx error irq resource\n");
return -ENODEV;
}
sport->tx_err_irq = res->start;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
if (!res) {
dev_err(dev, "No rx error irq resource\n");
return -ENODEV;
}
sport->rx_err_irq = res->start;
return 0;
}
static int sport_request_resource(struct sport_device *sport)
{
struct device *dev = &sport->pdev->dev;
int ret;
ret = peripheral_request_list(sport->pin_req, "soc-audio");
if (ret) {
dev_err(dev, "Unable to request sport pin\n");
return ret;
}
ret = request_dma(sport->tx_dma_chan, "SPORT TX Data");
if (ret) {
dev_err(dev, "Unable to allocate DMA channel for sport tx\n");
goto err_tx_dma;
}
set_dma_callback(sport->tx_dma_chan, sport_tx_irq, sport);
ret = request_dma(sport->rx_dma_chan, "SPORT RX Data");
if (ret) {
dev_err(dev, "Unable to allocate DMA channel for sport rx\n");
goto err_rx_dma;
}
set_dma_callback(sport->rx_dma_chan, sport_rx_irq, sport);
ret = request_irq(sport->tx_err_irq, sport_err_irq,
0, "SPORT TX ERROR", sport);
if (ret) {
dev_err(dev, "Unable to allocate tx error IRQ for sport\n");
goto err_tx_irq;
}
ret = request_irq(sport->rx_err_irq, sport_err_irq,
0, "SPORT RX ERROR", sport);
if (ret) {
dev_err(dev, "Unable to allocate rx error IRQ for sport\n");
goto err_rx_irq;
}
return 0;
err_rx_irq:
free_irq(sport->tx_err_irq, sport);
err_tx_irq:
free_dma(sport->rx_dma_chan);
err_rx_dma:
free_dma(sport->tx_dma_chan);
err_tx_dma:
peripheral_free_list(sport->pin_req);
return ret;
}
static void sport_free_resource(struct sport_device *sport)
{
free_irq(sport->rx_err_irq, sport);
free_irq(sport->tx_err_irq, sport);
free_dma(sport->rx_dma_chan);
free_dma(sport->tx_dma_chan);
peripheral_free_list(sport->pin_req);
}
struct sport_device *sport_create(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct sport_device *sport;
int ret;
sport = kzalloc(sizeof(*sport), GFP_KERNEL);
if (!sport) {
dev_err(dev, "Unable to allocate memory for sport device\n");
return NULL;
}
sport->pdev = pdev;
ret = sport_get_resource(sport);
if (ret) {
kfree(sport);
return NULL;
}
ret = sport_request_resource(sport);
if (ret) {
kfree(sport);
return NULL;
}
dev_dbg(dev, "SPORT create success\n");
return sport;
}
EXPORT_SYMBOL(sport_create);
void sport_delete(struct sport_device *sport)
{
sport_free_resource(sport);
}
EXPORT_SYMBOL(sport_delete);
MODULE_DESCRIPTION("Analog Devices BF6XX SPORT driver");
MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,82 @@
/*
* bf6xx_sport - Analog Devices BF6XX SPORT driver
*
* Copyright (c) 2012 Analog Devices Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _BF6XX_SPORT_H_
#define _BF6XX_SPORT_H_
#include <linux/platform_device.h>
#include <asm/bfin_sport3.h>
struct sport_device {
struct platform_device *pdev;
const unsigned short *pin_req;
struct sport_register *tx_regs;
struct sport_register *rx_regs;
int tx_dma_chan;
int rx_dma_chan;
int tx_err_irq;
int rx_err_irq;
void (*tx_callback)(void *data);
void *tx_data;
void (*rx_callback)(void *data);
void *rx_data;
struct dmasg *tx_desc;
struct dmasg *rx_desc;
unsigned int tx_desc_size;
unsigned int rx_desc_size;
unsigned char *tx_buf;
unsigned char *rx_buf;
unsigned int tx_fragsize;
unsigned int rx_fragsize;
unsigned int tx_frags;
unsigned int rx_frags;
unsigned int wdsize;
};
struct sport_params {
u32 spctl;
u32 div;
};
struct sport_device *sport_create(struct platform_device *pdev);
void sport_delete(struct sport_device *sport);
int sport_set_tx_params(struct sport_device *sport,
struct sport_params *params);
int sport_set_rx_params(struct sport_device *sport,
struct sport_params *params);
void sport_tx_start(struct sport_device *sport);
void sport_rx_start(struct sport_device *sport);
void sport_tx_stop(struct sport_device *sport);
void sport_rx_stop(struct sport_device *sport);
void sport_set_tx_callback(struct sport_device *sport,
void (*tx_callback)(void *), void *tx_data);
void sport_set_rx_callback(struct sport_device *sport,
void (*rx_callback)(void *), void *rx_data);
int sport_config_tx_dma(struct sport_device *sport, void *buf,
int fragcount, size_t fragsize);
int sport_config_rx_dma(struct sport_device *sport, void *buf,
int fragcount, size_t fragsize);
unsigned long sport_curr_offset_tx(struct sport_device *sport);
unsigned long sport_curr_offset_rx(struct sport_device *sport);
#endif

View File

@ -12,6 +12,7 @@ config SND_SOC_ALL_CODECS
tristate "Build all ASoC CODEC drivers" tristate "Build all ASoC CODEC drivers"
select SND_SOC_88PM860X if MFD_88PM860X select SND_SOC_88PM860X if MFD_88PM860X
select SND_SOC_L3 select SND_SOC_L3
select SND_SOC_AB8500_CODEC if ABX500_CORE
select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
select SND_SOC_AD1836 if SPI_MASTER select SND_SOC_AD1836 if SPI_MASTER
select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
@ -35,7 +36,9 @@ config SND_SOC_ALL_CODECS
select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
select SND_SOC_CX20442 select SND_SOC_CX20442
select SND_SOC_DA7210 if I2C select SND_SOC_DA7210 if I2C
select SND_SOC_DA732X if I2C
select SND_SOC_DFBMCS320 select SND_SOC_DFBMCS320
select SND_SOC_ISABELLE if I2C
select SND_SOC_JZ4740_CODEC select SND_SOC_JZ4740_CODEC
select SND_SOC_LM4857 if I2C select SND_SOC_LM4857 if I2C
select SND_SOC_LM49453 if I2C select SND_SOC_LM49453 if I2C
@ -54,6 +57,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_SPDIF select SND_SOC_SPDIF
select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI
select SND_SOC_STA32X if I2C select SND_SOC_STA32X if I2C
select SND_SOC_STA529 if I2C
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
select SND_SOC_TLV320AIC23 if I2C select SND_SOC_TLV320AIC23 if I2C
select SND_SOC_TLV320AIC26 if SPI_MASTER select SND_SOC_TLV320AIC26 if SPI_MASTER
@ -70,6 +74,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM2000 if I2C select SND_SOC_WM2000 if I2C
select SND_SOC_WM2200 if I2C select SND_SOC_WM2200 if I2C
select SND_SOC_WM5100 if I2C select SND_SOC_WM5100 if I2C
select SND_SOC_WM5102 if MFD_WM5102
select SND_SOC_WM5110 if MFD_WM5110
select SND_SOC_WM8350 if MFD_WM8350 select SND_SOC_WM8350 if MFD_WM8350
select SND_SOC_WM8400 if MFD_WM8400 select SND_SOC_WM8400 if MFD_WM8400
select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI
@ -126,11 +132,21 @@ config SND_SOC_ALL_CODECS
config SND_SOC_88PM860X config SND_SOC_88PM860X
tristate tristate
config SND_SOC_ARIZONA
tristate
default y if SND_SOC_WM5102=y
default y if SND_SOC_WM5110=y
default m if SND_SOC_WM5102=m
default m if SND_SOC_WM5110=m
config SND_SOC_WM_HUBS config SND_SOC_WM_HUBS
tristate tristate
default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y
default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m
config SND_SOC_AB8500_CODEC
tristate
config SND_SOC_AC97_CODEC config SND_SOC_AC97_CODEC
tristate tristate
select SND_AC97_CODEC select SND_AC97_CODEC
@ -219,12 +235,18 @@ config SND_SOC_L3
config SND_SOC_DA7210 config SND_SOC_DA7210
tristate tristate
config SND_SOC_DA732X
tristate
config SND_SOC_DFBMCS320 config SND_SOC_DFBMCS320
tristate tristate
config SND_SOC_DMIC config SND_SOC_DMIC
tristate tristate
config SND_SOC_ISABELLE
tristate
config SND_SOC_LM49453 config SND_SOC_LM49453
tristate tristate
@ -266,6 +288,9 @@ config SND_SOC_SSM2602
config SND_SOC_STA32X config SND_SOC_STA32X
tristate tristate
config SND_SOC_STA529
tristate
config SND_SOC_STAC9766 config SND_SOC_STAC9766
tristate tristate
@ -313,6 +338,12 @@ config SND_SOC_WM2200
config SND_SOC_WM5100 config SND_SOC_WM5100
tristate tristate
config SND_SOC_WM5102
tristate
config SND_SOC_WM5110
tristate
config SND_SOC_WM8350 config SND_SOC_WM8350
tristate tristate

View File

@ -1,4 +1,5 @@
snd-soc-88pm860x-objs := 88pm860x-codec.o snd-soc-88pm860x-objs := 88pm860x-codec.o
snd-soc-ab8500-codec-objs := ab8500-codec.o
snd-soc-ac97-objs := ac97.o snd-soc-ac97-objs := ac97.o
snd-soc-ad1836-objs := ad1836.o snd-soc-ad1836-objs := ad1836.o
snd-soc-ad193x-objs := ad193x.o snd-soc-ad193x-objs := ad193x.o
@ -13,6 +14,7 @@ snd-soc-ak4535-objs := ak4535.o
snd-soc-ak4641-objs := ak4641.o snd-soc-ak4641-objs := ak4641.o
snd-soc-ak4642-objs := ak4642.o snd-soc-ak4642-objs := ak4642.o
snd-soc-ak4671-objs := ak4671.o snd-soc-ak4671-objs := ak4671.o
snd-soc-arizona-objs := arizona.o
snd-soc-cq93vc-objs := cq93vc.o snd-soc-cq93vc-objs := cq93vc.o
snd-soc-cs42l51-objs := cs42l51.o snd-soc-cs42l51-objs := cs42l51.o
snd-soc-cs42l52-objs := cs42l52.o snd-soc-cs42l52-objs := cs42l52.o
@ -21,8 +23,10 @@ snd-soc-cs4270-objs := cs4270.o
snd-soc-cs4271-objs := cs4271.o snd-soc-cs4271-objs := cs4271.o
snd-soc-cx20442-objs := cx20442.o snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o snd-soc-da7210-objs := da7210.o
snd-soc-da732x-objs := da732x.o
snd-soc-dfbmcs320-objs := dfbmcs320.o snd-soc-dfbmcs320-objs := dfbmcs320.o
snd-soc-dmic-objs := dmic.o snd-soc-dmic-objs := dmic.o
snd-soc-isabelle-objs := isabelle.o
snd-soc-jz4740-codec-objs := jz4740.o snd-soc-jz4740-codec-objs := jz4740.o
snd-soc-l3-objs := l3.o snd-soc-l3-objs := l3.o
snd-soc-lm4857-objs := lm4857.o snd-soc-lm4857-objs := lm4857.o
@ -41,9 +45,11 @@ snd-soc-alc5623-objs := alc5623.o
snd-soc-alc5632-objs := alc5632.o snd-soc-alc5632-objs := alc5632.o
snd-soc-sigmadsp-objs := sigmadsp.o snd-soc-sigmadsp-objs := sigmadsp.o
snd-soc-sn95031-objs := sn95031.o snd-soc-sn95031-objs := sn95031.o
snd-soc-spdif-objs := spdif_transciever.o snd-soc-spdif-tx-objs := spdif_transciever.o
snd-soc-spdif-rx-objs := spdif_receiver.o
snd-soc-ssm2602-objs := ssm2602.o snd-soc-ssm2602-objs := ssm2602.o
snd-soc-sta32x-objs := sta32x.o snd-soc-sta32x-objs := sta32x.o
snd-soc-sta529-objs := sta529.o
snd-soc-stac9766-objs := stac9766.o snd-soc-stac9766-objs := stac9766.o
snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic23-objs := tlv320aic23.o
snd-soc-tlv320aic26-objs := tlv320aic26.o snd-soc-tlv320aic26-objs := tlv320aic26.o
@ -59,6 +65,8 @@ snd-soc-wm1250-ev1-objs := wm1250-ev1.o
snd-soc-wm2000-objs := wm2000.o snd-soc-wm2000-objs := wm2000.o
snd-soc-wm2200-objs := wm2200.o snd-soc-wm2200-objs := wm2200.o
snd-soc-wm5100-objs := wm5100.o wm5100-tables.o snd-soc-wm5100-objs := wm5100.o wm5100-tables.o
snd-soc-wm5102-objs := wm5102.o
snd-soc-wm5110-objs := wm5110.o
snd-soc-wm8350-objs := wm8350.o snd-soc-wm8350-objs := wm8350.o
snd-soc-wm8400-objs := wm8400.o snd-soc-wm8400-objs := wm8400.o
snd-soc-wm8510-objs := wm8510.o snd-soc-wm8510-objs := wm8510.o
@ -108,6 +116,7 @@ snd-soc-max9877-objs := max9877.o
snd-soc-tpa6130a2-objs := tpa6130a2.o snd-soc-tpa6130a2-objs := tpa6130a2.o
obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o
obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o
obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o
@ -124,6 +133,7 @@ obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o
obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o
obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o
obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o
obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o
@ -132,8 +142,10 @@ obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o
obj-$(CONFIG_SND_SOC_DFBMCS320) += snd-soc-dfbmcs320.o obj-$(CONFIG_SND_SOC_DFBMCS320) += snd-soc-dfbmcs320.o
obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o
obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o
@ -150,9 +162,10 @@ obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o
obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o
obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o
@ -168,6 +181,8 @@ obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o
obj-$(CONFIG_SND_SOC_WM2200) += snd-soc-wm2200.o obj-$(CONFIG_SND_SOC_WM2200) += snd-soc-wm2200.o
obj-$(CONFIG_SND_SOC_WM5100) += snd-soc-wm5100.o obj-$(CONFIG_SND_SOC_WM5100) += snd-soc-wm5100.o
obj-$(CONFIG_SND_SOC_WM5102) += snd-soc-wm5102.o
obj-$(CONFIG_SND_SOC_WM5110) += snd-soc-wm5110.o
obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o
obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o
obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,590 @@
/*
* Copyright (C) ST-Ericsson SA 2012
*
* Author: Ola Lilja <ola.o.lilja@stericsson.com>,
* Kristoffer Karlsson <kristoffer.karlsson@stericsson.com>,
* Roger Nilsson <roger.xr.nilsson@stericsson.com>,
* for ST-Ericsson.
*
* Based on the early work done by:
* Mikko J. Lehto <mikko.lehto@symbio.com>,
* Mikko Sarmanne <mikko.sarmanne@symbio.com>,
* for ST-Ericsson.
*
* License terms:
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#ifndef AB8500_CODEC_REGISTERS_H
#define AB8500_CODEC_REGISTERS_H
#define AB8500_SUPPORTED_RATE (SNDRV_PCM_RATE_48000)
#define AB8500_SUPPORTED_FMT (SNDRV_PCM_FMTBIT_S16_LE)
/* AB8500 audio bank (0x0d) register definitions */
#define AB8500_POWERUP 0x00
#define AB8500_AUDSWRESET 0x01
#define AB8500_ADPATHENA 0x02
#define AB8500_DAPATHENA 0x03
#define AB8500_ANACONF1 0x04
#define AB8500_ANACONF2 0x05
#define AB8500_DIGMICCONF 0x06
#define AB8500_ANACONF3 0x07
#define AB8500_ANACONF4 0x08
#define AB8500_DAPATHCONF 0x09
#define AB8500_MUTECONF 0x0A
#define AB8500_SHORTCIRCONF 0x0B
#define AB8500_ANACONF5 0x0C
#define AB8500_ENVCPCONF 0x0D
#define AB8500_SIGENVCONF 0x0E
#define AB8500_PWMGENCONF1 0x0F
#define AB8500_PWMGENCONF2 0x10
#define AB8500_PWMGENCONF3 0x11
#define AB8500_PWMGENCONF4 0x12
#define AB8500_PWMGENCONF5 0x13
#define AB8500_ANAGAIN1 0x14
#define AB8500_ANAGAIN2 0x15
#define AB8500_ANAGAIN3 0x16
#define AB8500_ANAGAIN4 0x17
#define AB8500_DIGLINHSLGAIN 0x18
#define AB8500_DIGLINHSRGAIN 0x19
#define AB8500_ADFILTCONF 0x1A
#define AB8500_DIGIFCONF1 0x1B
#define AB8500_DIGIFCONF2 0x1C
#define AB8500_DIGIFCONF3 0x1D
#define AB8500_DIGIFCONF4 0x1E
#define AB8500_ADSLOTSEL1 0x1F
#define AB8500_ADSLOTSEL2 0x20
#define AB8500_ADSLOTSEL3 0x21
#define AB8500_ADSLOTSEL4 0x22
#define AB8500_ADSLOTSEL5 0x23
#define AB8500_ADSLOTSEL6 0x24
#define AB8500_ADSLOTSEL7 0x25
#define AB8500_ADSLOTSEL8 0x26
#define AB8500_ADSLOTSEL9 0x27
#define AB8500_ADSLOTSEL10 0x28
#define AB8500_ADSLOTSEL11 0x29
#define AB8500_ADSLOTSEL12 0x2A
#define AB8500_ADSLOTSEL13 0x2B
#define AB8500_ADSLOTSEL14 0x2C
#define AB8500_ADSLOTSEL15 0x2D
#define AB8500_ADSLOTSEL16 0x2E
#define AB8500_ADSLOTHIZCTRL1 0x2F
#define AB8500_ADSLOTHIZCTRL2 0x30
#define AB8500_ADSLOTHIZCTRL3 0x31
#define AB8500_ADSLOTHIZCTRL4 0x32
#define AB8500_DASLOTCONF1 0x33
#define AB8500_DASLOTCONF2 0x34
#define AB8500_DASLOTCONF3 0x35
#define AB8500_DASLOTCONF4 0x36
#define AB8500_DASLOTCONF5 0x37
#define AB8500_DASLOTCONF6 0x38
#define AB8500_DASLOTCONF7 0x39
#define AB8500_DASLOTCONF8 0x3A
#define AB8500_CLASSDCONF1 0x3B
#define AB8500_CLASSDCONF2 0x3C
#define AB8500_CLASSDCONF3 0x3D
#define AB8500_DMICFILTCONF 0x3E
#define AB8500_DIGMULTCONF1 0x3F
#define AB8500_DIGMULTCONF2 0x40
#define AB8500_ADDIGGAIN1 0x41
#define AB8500_ADDIGGAIN2 0x42
#define AB8500_ADDIGGAIN3 0x43
#define AB8500_ADDIGGAIN4 0x44
#define AB8500_ADDIGGAIN5 0x45
#define AB8500_ADDIGGAIN6 0x46
#define AB8500_DADIGGAIN1 0x47
#define AB8500_DADIGGAIN2 0x48
#define AB8500_DADIGGAIN3 0x49
#define AB8500_DADIGGAIN4 0x4A
#define AB8500_DADIGGAIN5 0x4B
#define AB8500_DADIGGAIN6 0x4C
#define AB8500_ADDIGLOOPGAIN1 0x4D
#define AB8500_ADDIGLOOPGAIN2 0x4E
#define AB8500_HSLEARDIGGAIN 0x4F
#define AB8500_HSRDIGGAIN 0x50
#define AB8500_SIDFIRGAIN1 0x51
#define AB8500_SIDFIRGAIN2 0x52
#define AB8500_ANCCONF1 0x53
#define AB8500_ANCCONF2 0x54
#define AB8500_ANCCONF3 0x55
#define AB8500_ANCCONF4 0x56
#define AB8500_ANCCONF5 0x57
#define AB8500_ANCCONF6 0x58
#define AB8500_ANCCONF7 0x59
#define AB8500_ANCCONF8 0x5A
#define AB8500_ANCCONF9 0x5B
#define AB8500_ANCCONF10 0x5C
#define AB8500_ANCCONF11 0x5D
#define AB8500_ANCCONF12 0x5E
#define AB8500_ANCCONF13 0x5F
#define AB8500_ANCCONF14 0x60
#define AB8500_SIDFIRADR 0x61
#define AB8500_SIDFIRCOEF1 0x62
#define AB8500_SIDFIRCOEF2 0x63
#define AB8500_SIDFIRCONF 0x64
#define AB8500_AUDINTMASK1 0x65
#define AB8500_AUDINTSOURCE1 0x66
#define AB8500_AUDINTMASK2 0x67
#define AB8500_AUDINTSOURCE2 0x68
#define AB8500_FIFOCONF1 0x69
#define AB8500_FIFOCONF2 0x6A
#define AB8500_FIFOCONF3 0x6B
#define AB8500_FIFOCONF4 0x6C
#define AB8500_FIFOCONF5 0x6D
#define AB8500_FIFOCONF6 0x6E
#define AB8500_AUDREV 0x6F
#define AB8500_FIRST_REG AB8500_POWERUP
#define AB8500_LAST_REG AB8500_AUDREV
#define AB8500_CACHEREGNUM (AB8500_LAST_REG + 1)
#define AB8500_MASK_ALL 0xFF
#define AB8500_MASK_NONE 0x00
/* AB8500_POWERUP */
#define AB8500_POWERUP_POWERUP 7
#define AB8500_POWERUP_ENANA 3
/* AB8500_AUDSWRESET */
#define AB8500_AUDSWRESET_SWRESET 7
/* AB8500_ADPATHENA */
#define AB8500_ADPATHENA_ENAD12 7
#define AB8500_ADPATHENA_ENAD34 5
#define AB8500_ADPATHENA_ENAD5768 3
/* AB8500_DAPATHENA */
#define AB8500_DAPATHENA_ENDA1 7
#define AB8500_DAPATHENA_ENDA2 6
#define AB8500_DAPATHENA_ENDA3 5
#define AB8500_DAPATHENA_ENDA4 4
#define AB8500_DAPATHENA_ENDA5 3
#define AB8500_DAPATHENA_ENDA6 2
/* AB8500_ANACONF1 */
#define AB8500_ANACONF1_HSLOWPOW 7
#define AB8500_ANACONF1_DACLOWPOW1 6
#define AB8500_ANACONF1_DACLOWPOW0 5
#define AB8500_ANACONF1_EARDACLOWPOW 4
#define AB8500_ANACONF1_EARSELCM 2
#define AB8500_ANACONF1_HSHPEN 1
#define AB8500_ANACONF1_EARDRVLOWPOW 0
/* AB8500_ANACONF2 */
#define AB8500_ANACONF2_ENMIC1 7
#define AB8500_ANACONF2_ENMIC2 6
#define AB8500_ANACONF2_ENLINL 5
#define AB8500_ANACONF2_ENLINR 4
#define AB8500_ANACONF2_MUTMIC1 3
#define AB8500_ANACONF2_MUTMIC2 2
#define AB8500_ANACONF2_MUTLINL 1
#define AB8500_ANACONF2_MUTLINR 0
/* AB8500_DIGMICCONF */
#define AB8500_DIGMICCONF_ENDMIC1 7
#define AB8500_DIGMICCONF_ENDMIC2 6
#define AB8500_DIGMICCONF_ENDMIC3 5
#define AB8500_DIGMICCONF_ENDMIC4 4
#define AB8500_DIGMICCONF_ENDMIC5 3
#define AB8500_DIGMICCONF_ENDMIC6 2
#define AB8500_DIGMICCONF_HSFADSPEED 0
/* AB8500_ANACONF3 */
#define AB8500_ANACONF3_MIC1SEL 7
#define AB8500_ANACONF3_LINRSEL 6
#define AB8500_ANACONF3_ENDRVHSL 5
#define AB8500_ANACONF3_ENDRVHSR 4
#define AB8500_ANACONF3_ENADCMIC 2
#define AB8500_ANACONF3_ENADCLINL 1
#define AB8500_ANACONF3_ENADCLINR 0
/* AB8500_ANACONF4 */
#define AB8500_ANACONF4_DISPDVSS 7
#define AB8500_ANACONF4_ENEAR 6
#define AB8500_ANACONF4_ENHSL 5
#define AB8500_ANACONF4_ENHSR 4
#define AB8500_ANACONF4_ENHFL 3
#define AB8500_ANACONF4_ENHFR 2
#define AB8500_ANACONF4_ENVIB1 1
#define AB8500_ANACONF4_ENVIB2 0
/* AB8500_DAPATHCONF */
#define AB8500_DAPATHCONF_ENDACEAR 6
#define AB8500_DAPATHCONF_ENDACHSL 5
#define AB8500_DAPATHCONF_ENDACHSR 4
#define AB8500_DAPATHCONF_ENDACHFL 3
#define AB8500_DAPATHCONF_ENDACHFR 2
#define AB8500_DAPATHCONF_ENDACVIB1 1
#define AB8500_DAPATHCONF_ENDACVIB2 0
/* AB8500_MUTECONF */
#define AB8500_MUTECONF_MUTEAR 6
#define AB8500_MUTECONF_MUTHSL 5
#define AB8500_MUTECONF_MUTHSR 4
#define AB8500_MUTECONF_MUTDACEAR 2
#define AB8500_MUTECONF_MUTDACHSL 1
#define AB8500_MUTECONF_MUTDACHSR 0
/* AB8500_SHORTCIRCONF */
#define AB8500_SHORTCIRCONF_ENSHORTPWD 7
#define AB8500_SHORTCIRCONF_EARSHORTDIS 6
#define AB8500_SHORTCIRCONF_HSSHORTDIS 5
#define AB8500_SHORTCIRCONF_HSPULLDEN 4
#define AB8500_SHORTCIRCONF_HSOSCEN 2
#define AB8500_SHORTCIRCONF_HSFADDIS 1
#define AB8500_SHORTCIRCONF_HSZCDDIS 0
/* Zero cross should be disabled */
/* AB8500_ANACONF5 */
#define AB8500_ANACONF5_ENCPHS 7
#define AB8500_ANACONF5_HSLDACTOLOL 5
#define AB8500_ANACONF5_HSRDACTOLOR 4
#define AB8500_ANACONF5_ENLOL 3
#define AB8500_ANACONF5_ENLOR 2
#define AB8500_ANACONF5_HSAUTOEN 0
/* AB8500_ENVCPCONF */
#define AB8500_ENVCPCONF_ENVDETHTHRE 4
#define AB8500_ENVCPCONF_ENVDETLTHRE 0
#define AB8500_ENVCPCONF_ENVDETHTHRE_MAX 0x0F
#define AB8500_ENVCPCONF_ENVDETLTHRE_MAX 0x0F
/* AB8500_SIGENVCONF */
#define AB8500_SIGENVCONF_CPLVEN 5
#define AB8500_SIGENVCONF_ENVDETCPEN 4
#define AB8500_SIGENVCONF_ENVDETTIME 0
#define AB8500_SIGENVCONF_ENVDETTIME_MAX 0x0F
/* AB8500_PWMGENCONF1 */
#define AB8500_PWMGENCONF1_PWMTOVIB1 7
#define AB8500_PWMGENCONF1_PWMTOVIB2 6
#define AB8500_PWMGENCONF1_PWM1CTRL 5
#define AB8500_PWMGENCONF1_PWM2CTRL 4
#define AB8500_PWMGENCONF1_PWM1NCTRL 3
#define AB8500_PWMGENCONF1_PWM1PCTRL 2
#define AB8500_PWMGENCONF1_PWM2NCTRL 1
#define AB8500_PWMGENCONF1_PWM2PCTRL 0
/* AB8500_PWMGENCONF2 */
/* AB8500_PWMGENCONF3 */
/* AB8500_PWMGENCONF4 */
/* AB8500_PWMGENCONF5 */
#define AB8500_PWMGENCONFX_PWMVIBXPOL 7
#define AB8500_PWMGENCONFX_PWMVIBXDUTCYC 0
#define AB8500_PWMGENCONFX_PWMVIBXDUTCYC_MAX 0x64
/* AB8500_ANAGAIN1 */
/* AB8500_ANAGAIN2 */
#define AB8500_ANAGAINX_ENSEMICX 7
#define AB8500_ANAGAINX_LOWPOWMICX 6
#define AB8500_ANAGAINX_MICXGAIN 0
#define AB8500_ANAGAINX_MICXGAIN_MAX 0x1F
/* AB8500_ANAGAIN3 */
#define AB8500_ANAGAIN3_HSLGAIN 4
#define AB8500_ANAGAIN3_HSRGAIN 0
#define AB8500_ANAGAIN3_HSXGAIN_MAX 0x0F
/* AB8500_ANAGAIN4 */
#define AB8500_ANAGAIN4_LINLGAIN 4
#define AB8500_ANAGAIN4_LINRGAIN 0
#define AB8500_ANAGAIN4_LINXGAIN_MAX 0x0F
/* AB8500_DIGLINHSLGAIN */
/* AB8500_DIGLINHSRGAIN */
#define AB8500_DIGLINHSXGAIN_LINTOHSXGAIN 0
#define AB8500_DIGLINHSXGAIN_LINTOHSXGAIN_MAX 0x13
/* AB8500_ADFILTCONF */
#define AB8500_ADFILTCONF_AD1NH 7
#define AB8500_ADFILTCONF_AD2NH 6
#define AB8500_ADFILTCONF_AD3NH 5
#define AB8500_ADFILTCONF_AD4NH 4
#define AB8500_ADFILTCONF_AD1VOICE 3
#define AB8500_ADFILTCONF_AD2VOICE 2
#define AB8500_ADFILTCONF_AD3VOICE 1
#define AB8500_ADFILTCONF_AD4VOICE 0
/* AB8500_DIGIFCONF1 */
#define AB8500_DIGIFCONF1_ENMASTGEN 7
#define AB8500_DIGIFCONF1_IF1BITCLKOS1 6
#define AB8500_DIGIFCONF1_IF1BITCLKOS0 5
#define AB8500_DIGIFCONF1_ENFSBITCLK1 4
#define AB8500_DIGIFCONF1_IF0BITCLKOS1 2
#define AB8500_DIGIFCONF1_IF0BITCLKOS0 1
#define AB8500_DIGIFCONF1_ENFSBITCLK0 0
/* AB8500_DIGIFCONF2 */
#define AB8500_DIGIFCONF2_FSYNC0P 6
#define AB8500_DIGIFCONF2_BITCLK0P 5
#define AB8500_DIGIFCONF2_IF0DEL 4
#define AB8500_DIGIFCONF2_IF0FORMAT1 3
#define AB8500_DIGIFCONF2_IF0FORMAT0 2
#define AB8500_DIGIFCONF2_IF0WL1 1
#define AB8500_DIGIFCONF2_IF0WL0 0
/* AB8500_DIGIFCONF3 */
#define AB8500_DIGIFCONF3_IF0DATOIF1AD 7
#define AB8500_DIGIFCONF3_IF0CLKTOIF1CLK 6
#define AB8500_DIGIFCONF3_IF1MASTER 5
#define AB8500_DIGIFCONF3_IF1DATOIF0AD 3
#define AB8500_DIGIFCONF3_IF1CLKTOIF0CLK 2
#define AB8500_DIGIFCONF3_IF0MASTER 1
#define AB8500_DIGIFCONF3_IF0BFIFOEN 0
/* AB8500_DIGIFCONF4 */
#define AB8500_DIGIFCONF4_FSYNC1P 6
#define AB8500_DIGIFCONF4_BITCLK1P 5
#define AB8500_DIGIFCONF4_IF1DEL 4
#define AB8500_DIGIFCONF4_IF1FORMAT1 3
#define AB8500_DIGIFCONF4_IF1FORMAT0 2
#define AB8500_DIGIFCONF4_IF1WL1 1
#define AB8500_DIGIFCONF4_IF1WL0 0
/* AB8500_ADSLOTSELX */
#define AB8500_ADSLOTSELX_AD_OUT1_TO_SLOT_ODD 0x00
#define AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_ODD 0x01
#define AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_ODD 0x02
#define AB8500_ADSLOTSELX_AD_OUT4_TO_SLOT_ODD 0x03
#define AB8500_ADSLOTSELX_AD_OUT5_TO_SLOT_ODD 0x04
#define AB8500_ADSLOTSELX_AD_OUT6_TO_SLOT_ODD 0x05
#define AB8500_ADSLOTSELX_AD_OUT7_TO_SLOT_ODD 0x06
#define AB8500_ADSLOTSELX_AD_OUT8_TO_SLOT_ODD 0x07
#define AB8500_ADSLOTSELX_ZEROES_TO_SLOT_ODD 0x08
#define AB8500_ADSLOTSELX_TRISTATE_TO_SLOT_ODD 0x0F
#define AB8500_ADSLOTSELX_AD_OUT1_TO_SLOT_EVEN 0x00
#define AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_EVEN 0x10
#define AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN 0x20
#define AB8500_ADSLOTSELX_AD_OUT4_TO_SLOT_EVEN 0x30
#define AB8500_ADSLOTSELX_AD_OUT5_TO_SLOT_EVEN 0x40
#define AB8500_ADSLOTSELX_AD_OUT6_TO_SLOT_EVEN 0x50
#define AB8500_ADSLOTSELX_AD_OUT7_TO_SLOT_EVEN 0x60
#define AB8500_ADSLOTSELX_AD_OUT8_TO_SLOT_EVEN 0x70
#define AB8500_ADSLOTSELX_ZEROES_TO_SLOT_EVEN 0x80
#define AB8500_ADSLOTSELX_TRISTATE_TO_SLOT_EVEN 0xF0
#define AB8500_ADSLOTSELX_EVEN_SHIFT 0
#define AB8500_ADSLOTSELX_ODD_SHIFT 4
/* AB8500_ADSLOTHIZCTRL1 */
/* AB8500_ADSLOTHIZCTRL2 */
/* AB8500_ADSLOTHIZCTRL3 */
/* AB8500_ADSLOTHIZCTRL4 */
/* AB8500_DASLOTCONF1 */
#define AB8500_DASLOTCONF1_DA12VOICE 7
#define AB8500_DASLOTCONF1_SWAPDA12_34 6
#define AB8500_DASLOTCONF1_DAI7TOADO1 5
/* AB8500_DASLOTCONF2 */
#define AB8500_DASLOTCONF2_DAI8TOADO2 5
/* AB8500_DASLOTCONF3 */
#define AB8500_DASLOTCONF3_DA34VOICE 7
#define AB8500_DASLOTCONF3_DAI7TOADO3 5
/* AB8500_DASLOTCONF4 */
#define AB8500_DASLOTCONF4_DAI8TOADO4 5
/* AB8500_DASLOTCONF5 */
#define AB8500_DASLOTCONF5_DA56VOICE 7
#define AB8500_DASLOTCONF5_DAI7TOADO5 5
/* AB8500_DASLOTCONF6 */
#define AB8500_DASLOTCONF6_DAI8TOADO6 5
/* AB8500_DASLOTCONF7 */
#define AB8500_DASLOTCONF7_DAI8TOADO7 5
/* AB8500_DASLOTCONF8 */
#define AB8500_DASLOTCONF8_DAI7TOADO8 5
#define AB8500_DASLOTCONFX_SLTODAX_SHIFT 0
#define AB8500_DASLOTCONFX_SLTODAX_MASK 0x1F
/* AB8500_CLASSDCONF1 */
#define AB8500_CLASSDCONF1_PARLHF 7
#define AB8500_CLASSDCONF1_PARLVIB 6
#define AB8500_CLASSDCONF1_VIB1SWAPEN 3
#define AB8500_CLASSDCONF1_VIB2SWAPEN 2
#define AB8500_CLASSDCONF1_HFLSWAPEN 1
#define AB8500_CLASSDCONF1_HFRSWAPEN 0
/* AB8500_CLASSDCONF2 */
#define AB8500_CLASSDCONF2_FIRBYP3 7
#define AB8500_CLASSDCONF2_FIRBYP2 6
#define AB8500_CLASSDCONF2_FIRBYP1 5
#define AB8500_CLASSDCONF2_FIRBYP0 4
#define AB8500_CLASSDCONF2_HIGHVOLEN3 3
#define AB8500_CLASSDCONF2_HIGHVOLEN2 2
#define AB8500_CLASSDCONF2_HIGHVOLEN1 1
#define AB8500_CLASSDCONF2_HIGHVOLEN0 0
/* AB8500_CLASSDCONF3 */
#define AB8500_CLASSDCONF3_DITHHPGAIN 4
#define AB8500_CLASSDCONF3_DITHHPGAIN_MAX 0x0A
#define AB8500_CLASSDCONF3_DITHWGAIN 0
#define AB8500_CLASSDCONF3_DITHWGAIN_MAX 0x0A
/* AB8500_DMICFILTCONF */
#define AB8500_DMICFILTCONF_ANCINSEL 7
#define AB8500_DMICFILTCONF_DA3TOEAR 6
#define AB8500_DMICFILTCONF_DMIC1SINC3 5
#define AB8500_DMICFILTCONF_DMIC2SINC3 4
#define AB8500_DMICFILTCONF_DMIC3SINC3 3
#define AB8500_DMICFILTCONF_DMIC4SINC3 2
#define AB8500_DMICFILTCONF_DMIC5SINC3 1
#define AB8500_DMICFILTCONF_DMIC6SINC3 0
/* AB8500_DIGMULTCONF1 */
#define AB8500_DIGMULTCONF1_DATOHSLEN 7
#define AB8500_DIGMULTCONF1_DATOHSREN 6
#define AB8500_DIGMULTCONF1_AD1SEL 5
#define AB8500_DIGMULTCONF1_AD2SEL 4
#define AB8500_DIGMULTCONF1_AD3SEL 3
#define AB8500_DIGMULTCONF1_AD5SEL 2
#define AB8500_DIGMULTCONF1_AD6SEL 1
#define AB8500_DIGMULTCONF1_ANCSEL 0
/* AB8500_DIGMULTCONF2 */
#define AB8500_DIGMULTCONF2_DATOHFREN 7
#define AB8500_DIGMULTCONF2_DATOHFLEN 6
#define AB8500_DIGMULTCONF2_HFRSEL 5
#define AB8500_DIGMULTCONF2_HFLSEL 4
#define AB8500_DIGMULTCONF2_FIRSID1SEL 2
#define AB8500_DIGMULTCONF2_FIRSID2SEL 0
/* AB8500_ADDIGGAIN1 */
/* AB8500_ADDIGGAIN2 */
/* AB8500_ADDIGGAIN3 */
/* AB8500_ADDIGGAIN4 */
/* AB8500_ADDIGGAIN5 */
/* AB8500_ADDIGGAIN6 */
#define AB8500_ADDIGGAINX_FADEDISADX 6
#define AB8500_ADDIGGAINX_ADXGAIN_MAX 0x3F
/* AB8500_DADIGGAIN1 */
/* AB8500_DADIGGAIN2 */
/* AB8500_DADIGGAIN3 */
/* AB8500_DADIGGAIN4 */
/* AB8500_DADIGGAIN5 */
/* AB8500_DADIGGAIN6 */
#define AB8500_DADIGGAINX_FADEDISDAX 6
#define AB8500_DADIGGAINX_DAXGAIN_MAX 0x3F
/* AB8500_ADDIGLOOPGAIN1 */
/* AB8500_ADDIGLOOPGAIN2 */
#define AB8500_ADDIGLOOPGAINX_FADEDISADXL 6
#define AB8500_ADDIGLOOPGAINX_ADXLBGAIN_MAX 0x3F
/* AB8500_HSLEARDIGGAIN */
#define AB8500_HSLEARDIGGAIN_HSSINC1 7
#define AB8500_HSLEARDIGGAIN_FADEDISHSL 4
#define AB8500_HSLEARDIGGAIN_HSLDGAIN_MAX 0x09
/* AB8500_HSRDIGGAIN */
#define AB8500_HSRDIGGAIN_FADESPEED 6
#define AB8500_HSRDIGGAIN_FADEDISHSR 4
#define AB8500_HSRDIGGAIN_HSRDGAIN_MAX 0x09
/* AB8500_SIDFIRGAIN1 */
/* AB8500_SIDFIRGAIN2 */
#define AB8500_SIDFIRGAINX_FIRSIDXGAIN_MAX 0x1F
/* AB8500_ANCCONF1 */
#define AB8500_ANCCONF1_ANCIIRUPDATE 3
#define AB8500_ANCCONF1_ENANC 2
#define AB8500_ANCCONF1_ANCIIRINIT 1
#define AB8500_ANCCONF1_ANCFIRUPDATE 0
/* AB8500_ANCCONF2 */
#define AB8500_ANCCONF2_SHIFT 5
#define AB8500_ANCCONF2_MIN -0x10
#define AB8500_ANCCONF2_MAX 0xF
/* AB8500_ANCCONF3 */
#define AB8500_ANCCONF3_SHIFT 5
#define AB8500_ANCCONF3_MIN -0x10
#define AB8500_ANCCONF3_MAX 0xF
/* AB8500_ANCCONF4 */
#define AB8500_ANCCONF4_SHIFT 5
#define AB8500_ANCCONF4_MIN -0x10
#define AB8500_ANCCONF4_MAX 0xF
/* AB8500_ANC_FIR_COEFFS */
#define AB8500_ANC_FIR_COEFF_MIN -0x8000
#define AB8500_ANC_FIR_COEFF_MAX 0x7FFF
#define AB8500_ANC_FIR_COEFFS 15
/* AB8500_ANC_IIR_COEFFS */
#define AB8500_ANC_IIR_COEFF_MIN -0x800000
#define AB8500_ANC_IIR_COEFF_MAX 0x7FFFFF
#define AB8500_ANC_IIR_COEFFS 24
/* AB8500_ANC_WARP_DELAY */
#define AB8500_ANC_WARP_DELAY_SHIFT 16
#define AB8500_ANC_WARP_DELAY_MIN 0x0000
#define AB8500_ANC_WARP_DELAY_MAX 0xFFFF
/* AB8500_ANCCONF11 */
/* AB8500_ANCCONF12 */
/* AB8500_ANCCONF13 */
/* AB8500_ANCCONF14 */
/* AB8500_SIDFIRADR */
#define AB8500_SIDFIRADR_FIRSIDSET 7
#define AB8500_SIDFIRADR_ADDRESS_SHIFT 0
#define AB8500_SIDFIRADR_ADDRESS_MAX 0x7F
/* AB8500_SIDFIRCOEF1 */
/* AB8500_SIDFIRCOEF2 */
#define AB8500_SID_FIR_COEFF_MIN 0
#define AB8500_SID_FIR_COEFF_MAX 0xFFFF
#define AB8500_SID_FIR_COEFFS 128
/* AB8500_SIDFIRCONF */
#define AB8500_SIDFIRCONF_ENFIRSIDS 2
#define AB8500_SIDFIRCONF_FIRSIDSTOIF1 1
#define AB8500_SIDFIRCONF_FIRSIDBUSY 0
/* AB8500_AUDINTMASK1 */
/* AB8500_AUDINTSOURCE1 */
/* AB8500_AUDINTMASK2 */
/* AB8500_AUDINTSOURCE2 */
/* AB8500_FIFOCONF1 */
#define AB8500_FIFOCONF1_BFIFOMASK 0x80
#define AB8500_FIFOCONF1_BFIFO19M2 0x40
#define AB8500_FIFOCONF1_BFIFOINT_SHIFT 0
#define AB8500_FIFOCONF1_BFIFOINT_MAX 0x3F
/* AB8500_FIFOCONF2 */
#define AB8500_FIFOCONF2_BFIFOTX_SHIFT 0
#define AB8500_FIFOCONF2_BFIFOTX_MAX 0xFF
/* AB8500_FIFOCONF3 */
#define AB8500_FIFOCONF3_BFIFOEXSL_SHIFT 5
#define AB8500_FIFOCONF3_BFIFOEXSL_MAX 0x5
#define AB8500_FIFOCONF3_PREBITCLK0_SHIFT 2
#define AB8500_FIFOCONF3_PREBITCLK0_MAX 0x7
#define AB8500_FIFOCONF3_BFIFOMAST_SHIFT 1
#define AB8500_FIFOCONF3_BFIFORUN_SHIFT 0
/* AB8500_FIFOCONF4 */
#define AB8500_FIFOCONF4_BFIFOFRAMSW_SHIFT 0
#define AB8500_FIFOCONF4_BFIFOFRAMSW_MAX 0xFF
/* AB8500_FIFOCONF5 */
#define AB8500_FIFOCONF5_BFIFOWAKEUP_SHIFT 0
#define AB8500_FIFOCONF5_BFIFOWAKEUP_MAX 0xFF
/* AB8500_FIFOCONF6 */
#define AB8500_FIFOCONF6_BFIFOSAMPLE_SHIFT 0
#define AB8500_FIFOCONF6_BFIFOSAMPLE_MAX 0xFF
/* AB8500_AUDREV */
#endif

View File

@ -91,11 +91,6 @@ static int ac97_soc_probe(struct snd_soc_codec *codec)
return 0; return 0;
} }
static int ac97_soc_remove(struct snd_soc_codec *codec)
{
return 0;
}
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int ac97_soc_suspend(struct snd_soc_codec *codec) static int ac97_soc_suspend(struct snd_soc_codec *codec)
{ {
@ -119,7 +114,6 @@ static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
.write = ac97_write, .write = ac97_write,
.read = ac97_read, .read = ac97_read,
.probe = ac97_soc_probe, .probe = ac97_soc_probe,
.remove = ac97_soc_remove,
.suspend = ac97_soc_suspend, .suspend = ac97_soc_suspend,
.resume = ac97_soc_resume, .resume = ac97_soc_resume,
}; };

937
sound/soc/codecs/arizona.c Normal file
View File

@ -0,0 +1,937 @@
/*
* arizona.c - Wolfson Arizona class device shared support
*
* Copyright 2012 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/gcd.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>
#include <linux/mfd/arizona/core.h>
#include <linux/mfd/arizona/registers.h>
#include "arizona.h"
#define ARIZONA_AIF_BCLK_CTRL 0x00
#define ARIZONA_AIF_TX_PIN_CTRL 0x01
#define ARIZONA_AIF_RX_PIN_CTRL 0x02
#define ARIZONA_AIF_RATE_CTRL 0x03
#define ARIZONA_AIF_FORMAT 0x04
#define ARIZONA_AIF_TX_BCLK_RATE 0x05
#define ARIZONA_AIF_RX_BCLK_RATE 0x06
#define ARIZONA_AIF_FRAME_CTRL_1 0x07
#define ARIZONA_AIF_FRAME_CTRL_2 0x08
#define ARIZONA_AIF_FRAME_CTRL_3 0x09
#define ARIZONA_AIF_FRAME_CTRL_4 0x0A
#define ARIZONA_AIF_FRAME_CTRL_5 0x0B
#define ARIZONA_AIF_FRAME_CTRL_6 0x0C
#define ARIZONA_AIF_FRAME_CTRL_7 0x0D
#define ARIZONA_AIF_FRAME_CTRL_8 0x0E
#define ARIZONA_AIF_FRAME_CTRL_9 0x0F
#define ARIZONA_AIF_FRAME_CTRL_10 0x10
#define ARIZONA_AIF_FRAME_CTRL_11 0x11
#define ARIZONA_AIF_FRAME_CTRL_12 0x12
#define ARIZONA_AIF_FRAME_CTRL_13 0x13
#define ARIZONA_AIF_FRAME_CTRL_14 0x14
#define ARIZONA_AIF_FRAME_CTRL_15 0x15
#define ARIZONA_AIF_FRAME_CTRL_16 0x16
#define ARIZONA_AIF_FRAME_CTRL_17 0x17
#define ARIZONA_AIF_FRAME_CTRL_18 0x18
#define ARIZONA_AIF_TX_ENABLES 0x19
#define ARIZONA_AIF_RX_ENABLES 0x1A
#define ARIZONA_AIF_FORCE_WRITE 0x1B
#define arizona_fll_err(_fll, fmt, ...) \
dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
#define arizona_fll_warn(_fll, fmt, ...) \
dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
#define arizona_fll_dbg(_fll, fmt, ...) \
dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
#define arizona_aif_err(_dai, fmt, ...) \
dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
#define arizona_aif_warn(_dai, fmt, ...) \
dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
#define arizona_aif_dbg(_dai, fmt, ...) \
dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
"None",
"Tone Generator 1",
"Tone Generator 2",
"Haptics",
"AEC",
"Mic Mute Mixer",
"Noise Generator",
"IN1L",
"IN1R",
"IN2L",
"IN2R",
"IN3L",
"IN3R",
"IN4L",
"IN4R",
"AIF1RX1",
"AIF1RX2",
"AIF1RX3",
"AIF1RX4",
"AIF1RX5",
"AIF1RX6",
"AIF1RX7",
"AIF1RX8",
"AIF2RX1",
"AIF2RX2",
"AIF3RX1",
"AIF3RX2",
"SLIMRX1",
"SLIMRX2",
"SLIMRX3",
"SLIMRX4",
"SLIMRX5",
"SLIMRX6",
"SLIMRX7",
"SLIMRX8",
"EQ1",
"EQ2",
"EQ3",
"EQ4",
"DRC1L",
"DRC1R",
"DRC2L",
"DRC2R",
"LHPF1",
"LHPF2",
"LHPF3",
"LHPF4",
"DSP1.1",
"DSP1.2",
"DSP1.3",
"DSP1.4",
"DSP1.5",
"DSP1.6",
"ASRC1L",
"ASRC1R",
"ASRC2L",
"ASRC2R",
};
EXPORT_SYMBOL_GPL(arizona_mixer_texts);
int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
0x00, /* None */
0x04, /* Tone */
0x05,
0x06, /* Haptics */
0x08, /* AEC */
0x0c, /* Noise mixer */
0x0d, /* Comfort noise */
0x10, /* IN1L */
0x11,
0x12,
0x13,
0x14,
0x15,
0x16,
0x17,
0x20, /* AIF1RX1 */
0x21,
0x22,
0x23,
0x24,
0x25,
0x26,
0x27,
0x28, /* AIF2RX1 */
0x29,
0x30, /* AIF3RX1 */
0x31,
0x38, /* SLIMRX1 */
0x39,
0x3a,
0x3b,
0x3c,
0x3d,
0x3e,
0x3f,
0x50, /* EQ1 */
0x51,
0x52,
0x53,
0x58, /* DRC1L */
0x59,
0x5a,
0x5b,
0x60, /* LHPF1 */
0x61,
0x62,
0x63,
0x68, /* DSP1.1 */
0x69,
0x6a,
0x6b,
0x6c,
0x6d,
0x90, /* ASRC1L */
0x91,
0x92,
0x93,
};
EXPORT_SYMBOL_GPL(arizona_mixer_values);
const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
static const char *arizona_lhpf_mode_text[] = {
"Low-pass", "High-pass"
};
const struct soc_enum arizona_lhpf1_mode =
SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2,
arizona_lhpf_mode_text);
EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
const struct soc_enum arizona_lhpf2_mode =
SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2,
arizona_lhpf_mode_text);
EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
const struct soc_enum arizona_lhpf3_mode =
SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2,
arizona_lhpf_mode_text);
EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
const struct soc_enum arizona_lhpf4_mode =
SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2,
arizona_lhpf_mode_text);
EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
int event)
{
return 0;
}
EXPORT_SYMBOL_GPL(arizona_in_ev);
int arizona_out_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
return 0;
}
EXPORT_SYMBOL_GPL(arizona_out_ev);
int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
int source, unsigned int freq, int dir)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->arizona;
char *name;
unsigned int reg;
unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
unsigned int *clk;
switch (clk_id) {
case ARIZONA_CLK_SYSCLK:
name = "SYSCLK";
reg = ARIZONA_SYSTEM_CLOCK_1;
clk = &priv->sysclk;
mask |= ARIZONA_SYSCLK_FRAC;
break;
case ARIZONA_CLK_ASYNCCLK:
name = "ASYNCCLK";
reg = ARIZONA_ASYNC_CLOCK_1;
clk = &priv->asyncclk;
break;
default:
return -EINVAL;
}
switch (freq) {
case 5644800:
case 6144000:
break;
case 11289600:
case 12288000:
val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT;
break;
case 22579200:
case 24576000:
val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT;
break;
case 45158400:
case 49152000:
val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT;
break;
default:
return -EINVAL;
}
*clk = freq;
if (freq % 6144000)
val |= ARIZONA_SYSCLK_FRAC;
dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
return regmap_update_bits(arizona->regmap, reg, mask, val);
}
EXPORT_SYMBOL_GPL(arizona_set_sysclk);
static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_codec *codec = dai->codec;
int lrclk, bclk, mode, base;
base = dai->driver->base;
lrclk = 0;
bclk = 0;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_A:
mode = 0;
break;
case SND_SOC_DAIFMT_DSP_B:
mode = 1;
break;
case SND_SOC_DAIFMT_I2S:
mode = 2;
break;
case SND_SOC_DAIFMT_LEFT_J:
mode = 3;
break;
default:
arizona_aif_err(dai, "Unsupported DAI format %d\n",
fmt & SND_SOC_DAIFMT_FORMAT_MASK);
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
break;
case SND_SOC_DAIFMT_CBS_CFM:
lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
break;
case SND_SOC_DAIFMT_CBM_CFS:
bclk |= ARIZONA_AIF1_BCLK_MSTR;
break;
case SND_SOC_DAIFMT_CBM_CFM:
bclk |= ARIZONA_AIF1_BCLK_MSTR;
lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
break;
default:
arizona_aif_err(dai, "Unsupported master mode %d\n",
fmt & SND_SOC_DAIFMT_MASTER_MASK);
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
break;
case SND_SOC_DAIFMT_IB_IF:
bclk |= ARIZONA_AIF1_BCLK_INV;
lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
break;
case SND_SOC_DAIFMT_IB_NF:
bclk |= ARIZONA_AIF1_BCLK_INV;
break;
case SND_SOC_DAIFMT_NB_IF:
lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
break;
default:
return -EINVAL;
}
snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR,
bclk);
snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL,
ARIZONA_AIF1TX_LRCLK_INV |
ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL,
ARIZONA_AIF1RX_LRCLK_INV |
ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT,
ARIZONA_AIF1_FMT_MASK, mode);
return 0;
}
static const int arizona_48k_bclk_rates[] = {
-1,
48000,
64000,
96000,
128000,
192000,
256000,
384000,
512000,
768000,
1024000,
1536000,
2048000,
3072000,
4096000,
6144000,
8192000,
12288000,
24576000,
};
static const unsigned int arizona_48k_rates[] = {
12000,
24000,
48000,
96000,
192000,
384000,
768000,
4000,
8000,
16000,
32000,
64000,
128000,
256000,
512000,
};
static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
.count = ARRAY_SIZE(arizona_48k_rates),
.list = arizona_48k_rates,
};
static const int arizona_44k1_bclk_rates[] = {
-1,
44100,
58800,
88200,
117600,
177640,
235200,
352800,
470400,
705600,
940800,
1411200,
1881600,
2882400,
3763200,
5644800,
7526400,
11289600,
22579200,
};
static const unsigned int arizona_44k1_rates[] = {
11025,
22050,
44100,
88200,
176400,
352800,
705600,
};
static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
.count = ARRAY_SIZE(arizona_44k1_rates),
.list = arizona_44k1_rates,
};
static int arizona_sr_vals[] = {
0,
12000,
24000,
48000,
96000,
192000,
384000,
768000,
0,
11025,
22050,
44100,
88200,
176400,
352800,
705600,
4000,
8000,
16000,
32000,
64000,
128000,
256000,
512000,
};
static int arizona_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
const struct snd_pcm_hw_constraint_list *constraint;
unsigned int base_rate;
switch (dai_priv->clk) {
case ARIZONA_CLK_SYSCLK:
base_rate = priv->sysclk;
break;
case ARIZONA_CLK_ASYNCCLK:
base_rate = priv->asyncclk;
break;
default:
return 0;
}
if (base_rate % 8000)
constraint = &arizona_44k1_constraint;
else
constraint = &arizona_48k_constraint;
return snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
constraint);
}
static int arizona_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
int base = dai->driver->base;
const int *rates;
int i;
int bclk, lrclk, wl, frame, sr_val;
if (params_rate(params) % 8000)
rates = &arizona_44k1_bclk_rates[0];
else
rates = &arizona_48k_bclk_rates[0];
for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
if (rates[i] >= snd_soc_params_to_bclk(params) &&
rates[i] % params_rate(params) == 0) {
bclk = i;
break;
}
}
if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
params_rate(params));
return -EINVAL;
}
for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
if (arizona_sr_vals[i] == params_rate(params))
break;
if (i == ARRAY_SIZE(arizona_sr_vals)) {
arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
params_rate(params));
return -EINVAL;
}
sr_val = i;
lrclk = snd_soc_params_to_bclk(params) / params_rate(params);
arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
rates[bclk], rates[bclk] / lrclk);
wl = snd_pcm_format_width(params_format(params));
frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
/*
* We will need to be more flexible than this in future,
* currently we use a single sample rate for SYSCLK.
*/
switch (dai_priv->clk) {
case ARIZONA_CLK_SYSCLK:
snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
ARIZONA_AIF1_RATE_MASK, 0);
break;
case ARIZONA_CLK_ASYNCCLK:
snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
ARIZONA_AIF1_RATE_MASK, 8);
break;
default:
arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
return -EINVAL;
}
snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
ARIZONA_AIF1TX_BCPF_MASK, lrclk);
snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
ARIZONA_AIF1RX_BCPF_MASK, lrclk);
snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
ARIZONA_AIF1TX_WL_MASK |
ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
ARIZONA_AIF1RX_WL_MASK |
ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
return 0;
}
static const char *arizona_dai_clk_str(int clk_id)
{
switch (clk_id) {
case ARIZONA_CLK_SYSCLK:
return "SYSCLK";
case ARIZONA_CLK_ASYNCCLK:
return "ASYNCCLK";
default:
return "Unknown clock";
}
}
static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = dai->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
struct snd_soc_dapm_route routes[2];
switch (clk_id) {
case ARIZONA_CLK_SYSCLK:
case ARIZONA_CLK_ASYNCCLK:
break;
default:
return -EINVAL;
}
if (clk_id == dai_priv->clk)
return 0;
if (dai->active) {
dev_err(codec->dev, "Can't change clock on active DAI %d\n",
dai->id);
return -EBUSY;
}
memset(&routes, 0, sizeof(routes));
routes[0].sink = dai->driver->capture.stream_name;
routes[1].sink = dai->driver->playback.stream_name;
routes[0].source = arizona_dai_clk_str(dai_priv->clk);
routes[1].source = arizona_dai_clk_str(dai_priv->clk);
snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
routes[0].source = arizona_dai_clk_str(clk_id);
routes[1].source = arizona_dai_clk_str(clk_id);
snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
return snd_soc_dapm_sync(&codec->dapm);
}
const struct snd_soc_dai_ops arizona_dai_ops = {
.startup = arizona_startup,
.set_fmt = arizona_set_fmt,
.hw_params = arizona_hw_params,
.set_sysclk = arizona_dai_set_sysclk,
};
EXPORT_SYMBOL_GPL(arizona_dai_ops);
int arizona_init_dai(struct arizona_priv *priv, int id)
{
struct arizona_dai_priv *dai_priv = &priv->dai[id];
dai_priv->clk = ARIZONA_CLK_SYSCLK;
return 0;
}
EXPORT_SYMBOL_GPL(arizona_init_dai);
static irqreturn_t arizona_fll_lock(int irq, void *data)
{
struct arizona_fll *fll = data;
arizona_fll_dbg(fll, "Locked\n");
complete(&fll->lock);
return IRQ_HANDLED;
}
static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
{
struct arizona_fll *fll = data;
arizona_fll_dbg(fll, "clock OK\n");
complete(&fll->ok);
return IRQ_HANDLED;
}
static struct {
unsigned int min;
unsigned int max;
u16 fratio;
int ratio;
} fll_fratios[] = {
{ 0, 64000, 4, 16 },
{ 64000, 128000, 3, 8 },
{ 128000, 256000, 2, 4 },
{ 256000, 1000000, 1, 2 },
{ 1000000, 13500000, 0, 1 },
};
struct arizona_fll_cfg {
int n;
int theta;
int lambda;
int refdiv;
int outdiv;
int fratio;
};
static int arizona_calc_fll(struct arizona_fll *fll,
struct arizona_fll_cfg *cfg,
unsigned int Fref,
unsigned int Fout)
{
unsigned int target, div, gcd_fll;
int i, ratio;
arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
/* Fref must be <=13.5MHz */
div = 1;
cfg->refdiv = 0;
while ((Fref / div) > 13500000) {
div *= 2;
cfg->refdiv++;
if (div > 8) {
arizona_fll_err(fll,
"Can't scale %dMHz in to <=13.5MHz\n",
Fref);
return -EINVAL;
}
}
/* Apply the division for our remaining calculations */
Fref /= div;
/* Fvco should be over the targt; don't check the upper bound */
div = 1;
while (Fout * div < 90000000 * fll->vco_mult) {
div++;
if (div > 7) {
arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
Fout);
return -EINVAL;
}
}
target = Fout * div / fll->vco_mult;
cfg->outdiv = div;
arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
/* Find an appropraite FLL_FRATIO and factor it out of the target */
for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
cfg->fratio = fll_fratios[i].fratio;
ratio = fll_fratios[i].ratio;
break;
}
}
if (i == ARRAY_SIZE(fll_fratios)) {
arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
Fref);
return -EINVAL;
}
cfg->n = target / (ratio * Fref);
if (target % Fref) {
gcd_fll = gcd(target, ratio * Fref);
arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
cfg->theta = (target - (cfg->n * ratio * Fref))
/ gcd_fll;
cfg->lambda = (ratio * Fref) / gcd_fll;
} else {
cfg->theta = 0;
cfg->lambda = 0;
}
arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
cfg->n, cfg->theta, cfg->lambda);
arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
return 0;
}
static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
struct arizona_fll_cfg *cfg, int source)
{
regmap_update_bits(arizona->regmap, base + 3,
ARIZONA_FLL1_THETA_MASK, cfg->theta);
regmap_update_bits(arizona->regmap, base + 4,
ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
regmap_update_bits(arizona->regmap, base + 5,
ARIZONA_FLL1_FRATIO_MASK,
cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
regmap_update_bits(arizona->regmap, base + 6,
ARIZONA_FLL1_CLK_REF_DIV_MASK |
ARIZONA_FLL1_CLK_REF_SRC_MASK,
cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
regmap_update_bits(arizona->regmap, base + 2,
ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
ARIZONA_FLL1_CTRL_UPD | cfg->n);
}
int arizona_set_fll(struct arizona_fll *fll, int source,
unsigned int Fref, unsigned int Fout)
{
struct arizona *arizona = fll->arizona;
struct arizona_fll_cfg cfg, sync;
unsigned int reg, val;
int syncsrc;
bool ena;
int ret;
ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
if (ret != 0) {
arizona_fll_err(fll, "Failed to read current state: %d\n",
ret);
return ret;
}
ena = reg & ARIZONA_FLL1_ENA;
if (Fout) {
/* Do we have a 32kHz reference? */
regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
switch (val & ARIZONA_CLK_32K_SRC_MASK) {
case ARIZONA_CLK_SRC_MCLK1:
case ARIZONA_CLK_SRC_MCLK2:
syncsrc = val & ARIZONA_CLK_32K_SRC_MASK;
break;
default:
syncsrc = -1;
}
if (source == syncsrc)
syncsrc = -1;
if (syncsrc >= 0) {
ret = arizona_calc_fll(fll, &sync, Fref, Fout);
if (ret != 0)
return ret;
ret = arizona_calc_fll(fll, &cfg, 32768, Fout);
if (ret != 0)
return ret;
} else {
ret = arizona_calc_fll(fll, &cfg, Fref, Fout);
if (ret != 0)
return ret;
}
} else {
regmap_update_bits(arizona->regmap, fll->base + 1,
ARIZONA_FLL1_ENA, 0);
regmap_update_bits(arizona->regmap, fll->base + 0x11,
ARIZONA_FLL1_SYNC_ENA, 0);
if (ena)
pm_runtime_put_autosuspend(arizona->dev);
return 0;
}
regmap_update_bits(arizona->regmap, fll->base + 5,
ARIZONA_FLL1_OUTDIV_MASK,
cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
if (syncsrc >= 0) {
arizona_apply_fll(arizona, fll->base, &cfg, syncsrc);
arizona_apply_fll(arizona, fll->base + 0x10, &sync, source);
} else {
arizona_apply_fll(arizona, fll->base, &cfg, source);
}
if (!ena)
pm_runtime_get(arizona->dev);
/* Clear any pending completions */
try_wait_for_completion(&fll->ok);
regmap_update_bits(arizona->regmap, fll->base + 1,
ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
if (syncsrc >= 0)
regmap_update_bits(arizona->regmap, fll->base + 0x11,
ARIZONA_FLL1_SYNC_ENA,
ARIZONA_FLL1_SYNC_ENA);
ret = wait_for_completion_timeout(&fll->ok,
msecs_to_jiffies(25));
if (ret == 0)
arizona_fll_warn(fll, "Timed out waiting for lock\n");
return 0;
}
EXPORT_SYMBOL_GPL(arizona_set_fll);
int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
int ok_irq, struct arizona_fll *fll)
{
int ret;
init_completion(&fll->lock);
init_completion(&fll->ok);
fll->id = id;
fll->base = base;
fll->arizona = arizona;
snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
"FLL%d clock OK", id);
ret = arizona_request_irq(arizona, lock_irq, fll->lock_name,
arizona_fll_lock, fll);
if (ret != 0) {
dev_err(arizona->dev, "Failed to get FLL%d lock IRQ: %d\n",
id, ret);
}
ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
arizona_fll_clock_ok, fll);
if (ret != 0) {
dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
id, ret);
}
return 0;
}
EXPORT_SYMBOL_GPL(arizona_init_fll);
MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_LICENSE("GPL");

159
sound/soc/codecs/arizona.h Normal file
View File

@ -0,0 +1,159 @@
/*
* arizona.h - Wolfson Arizona class device shared support
*
* Copyright 2012 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASOC_ARIZONA_H
#define _ASOC_ARIZONA_H
#include <linux/completion.h>
#include <sound/soc.h>
#define ARIZONA_CLK_SYSCLK 1
#define ARIZONA_CLK_ASYNCCLK 2
#define ARIZONA_CLK_SRC_MCLK1 0x0
#define ARIZONA_CLK_SRC_MCLK2 0x1
#define ARIZONA_CLK_SRC_FLL1 0x4
#define ARIZONA_CLK_SRC_FLL2 0x5
#define ARIZONA_CLK_SRC_AIF1BCLK 0x8
#define ARIZONA_CLK_SRC_AIF2BCLK 0x9
#define ARIZONA_CLK_SRC_AIF3BCLK 0xa
#define ARIZONA_FLL_SRC_MCLK1 0
#define ARIZONA_FLL_SRC_MCLK2 1
#define ARIZONA_FLL_SRC_SLIMCLK 2
#define ARIZONA_FLL_SRC_FLL1 3
#define ARIZONA_FLL_SRC_FLL2 4
#define ARIZONA_FLL_SRC_AIF1BCLK 5
#define ARIZONA_FLL_SRC_AIF2BCLK 6
#define ARIZONA_FLL_SRC_AIF3BCLK 7
#define ARIZONA_FLL_SRC_AIF1LRCLK 8
#define ARIZONA_FLL_SRC_AIF2LRCLK 9
#define ARIZONA_FLL_SRC_AIF3LRCLK 10
#define ARIZONA_MIXER_VOL_MASK 0x00FE
#define ARIZONA_MIXER_VOL_SHIFT 1
#define ARIZONA_MIXER_VOL_WIDTH 7
#define ARIZONA_MAX_DAI 3
struct arizona;
struct arizona_dai_priv {
int clk;
};
struct arizona_priv {
struct arizona *arizona;
int sysclk;
int asyncclk;
struct arizona_dai_priv dai[ARIZONA_MAX_DAI];
};
#define ARIZONA_NUM_MIXER_INPUTS 57
extern const unsigned int arizona_mixer_tlv[];
extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];
extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
#define ARIZONA_MIXER_CONTROLS(name, base) \
SOC_SINGLE_RANGE_TLV(name " Input 1 Volume", base + 1, \
ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
arizona_mixer_tlv), \
SOC_SINGLE_RANGE_TLV(name " Input 2 Volume", base + 3, \
ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
arizona_mixer_tlv), \
SOC_SINGLE_RANGE_TLV(name " Input 3 Volume", base + 5, \
ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
arizona_mixer_tlv), \
SOC_SINGLE_RANGE_TLV(name " Input 4 Volume", base + 7, \
ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
arizona_mixer_tlv)
#define ARIZONA_MUX_ENUM_DECL(name, reg) \
SOC_VALUE_ENUM_SINGLE_DECL(name, reg, 0, 0xff, \
arizona_mixer_texts, arizona_mixer_values)
#define ARIZONA_MUX_CTL_DECL(name) \
const struct snd_kcontrol_new name##_mux = \
SOC_DAPM_VALUE_ENUM("Route", name##_enum)
#define ARIZONA_MIXER_ENUMS(name, base_reg) \
static ARIZONA_MUX_ENUM_DECL(name##_in1_enum, base_reg); \
static ARIZONA_MUX_ENUM_DECL(name##_in2_enum, base_reg + 2); \
static ARIZONA_MUX_ENUM_DECL(name##_in3_enum, base_reg + 4); \
static ARIZONA_MUX_ENUM_DECL(name##_in4_enum, base_reg + 6); \
static ARIZONA_MUX_CTL_DECL(name##_in1); \
static ARIZONA_MUX_CTL_DECL(name##_in2); \
static ARIZONA_MUX_CTL_DECL(name##_in3); \
static ARIZONA_MUX_CTL_DECL(name##_in4)
#define ARIZONA_MUX(name, ctrl) \
SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
#define ARIZONA_MIXER_WIDGETS(name, name_str) \
ARIZONA_MUX(name_str " Input 1", &name##_in1_mux), \
ARIZONA_MUX(name_str " Input 2", &name##_in2_mux), \
ARIZONA_MUX(name_str " Input 3", &name##_in3_mux), \
ARIZONA_MUX(name_str " Input 4", &name##_in4_mux), \
SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0)
#define ARIZONA_MIXER_ROUTES(widget, name) \
{ widget, NULL, name " Mixer" }, \
{ name " Mixer", NULL, name " Input 1" }, \
{ name " Mixer", NULL, name " Input 2" }, \
{ name " Mixer", NULL, name " Input 3" }, \
{ name " Mixer", NULL, name " Input 4" }, \
ARIZONA_MIXER_INPUT_ROUTES(name " Input 1"), \
ARIZONA_MIXER_INPUT_ROUTES(name " Input 2"), \
ARIZONA_MIXER_INPUT_ROUTES(name " Input 3"), \
ARIZONA_MIXER_INPUT_ROUTES(name " Input 4")
extern const struct soc_enum arizona_lhpf1_mode;
extern const struct soc_enum arizona_lhpf2_mode;
extern const struct soc_enum arizona_lhpf3_mode;
extern const struct soc_enum arizona_lhpf4_mode;
extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event);
extern int arizona_out_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event);
extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
int source, unsigned int freq, int dir);
extern const struct snd_soc_dai_ops arizona_dai_ops;
#define ARIZONA_FLL_NAME_LEN 20
struct arizona_fll {
struct arizona *arizona;
int id;
unsigned int base;
unsigned int vco_mult;
struct completion lock;
struct completion ok;
char lock_name[ARIZONA_FLL_NAME_LEN];
char clock_ok_name[ARIZONA_FLL_NAME_LEN];
};
extern int arizona_init_fll(struct arizona *arizona, int id, int base,
int lock_irq, int ok_irq, struct arizona_fll *fll);
extern int arizona_set_fll(struct arizona_fll *fll, int source,
unsigned int Fref, unsigned int Fout);
extern int arizona_init_dai(struct arizona_priv *priv, int dai);
#endif

View File

@ -14,7 +14,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/version.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/delay.h> #include <linux/delay.h>
@ -1217,11 +1216,11 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
return -ENOMEM; return -ENOMEM;
cs42l52->dev = &i2c_client->dev; cs42l52->dev = &i2c_client->dev;
cs42l52->regmap = regmap_init_i2c(i2c_client, &cs42l52_regmap); cs42l52->regmap = devm_regmap_init_i2c(i2c_client, &cs42l52_regmap);
if (IS_ERR(cs42l52->regmap)) { if (IS_ERR(cs42l52->regmap)) {
ret = PTR_ERR(cs42l52->regmap); ret = PTR_ERR(cs42l52->regmap);
dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
goto err; return ret;
} }
i2c_set_clientdata(i2c_client, cs42l52); i2c_set_clientdata(i2c_client, cs42l52);
@ -1243,7 +1242,7 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
dev_err(&i2c_client->dev, dev_err(&i2c_client->dev,
"CS42L52 Device ID (%X). Expected %X\n", "CS42L52 Device ID (%X). Expected %X\n",
devid, CS42L52_CHIP_ID); devid, CS42L52_CHIP_ID);
goto err_regmap; return ret;
} }
regcache_cache_only(cs42l52->regmap, true); regcache_cache_only(cs42l52->regmap, true);
@ -1251,23 +1250,13 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
ret = snd_soc_register_codec(&i2c_client->dev, ret = snd_soc_register_codec(&i2c_client->dev,
&soc_codec_dev_cs42l52, &cs42l52_dai, 1); &soc_codec_dev_cs42l52, &cs42l52_dai, 1);
if (ret < 0) if (ret < 0)
goto err_regmap; return ret;
return 0; return 0;
err_regmap:
regmap_exit(cs42l52->regmap);
err:
return ret;
} }
static int cs42l52_i2c_remove(struct i2c_client *client) static int cs42l52_i2c_remove(struct i2c_client *client)
{ {
struct cs42l52_private *cs42l52 = i2c_get_clientdata(client);
snd_soc_unregister_codec(&client->dev); snd_soc_unregister_codec(&client->dev);
regmap_exit(cs42l52->regmap);
return 0; return 0;
} }

View File

@ -1362,11 +1362,11 @@ static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client,
i2c_set_clientdata(i2c_client, cs42l73); i2c_set_clientdata(i2c_client, cs42l73);
cs42l73->regmap = regmap_init_i2c(i2c_client, &cs42l73_regmap); cs42l73->regmap = devm_regmap_init_i2c(i2c_client, &cs42l73_regmap);
if (IS_ERR(cs42l73->regmap)) { if (IS_ERR(cs42l73->regmap)) {
ret = PTR_ERR(cs42l73->regmap); ret = PTR_ERR(cs42l73->regmap);
dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
goto err; return ret;
} }
/* initialize codec */ /* initialize codec */
ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, &reg); ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, &reg);
@ -1384,13 +1384,13 @@ static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client,
dev_err(&i2c_client->dev, dev_err(&i2c_client->dev,
"CS42L73 Device ID (%X). Expected %X\n", "CS42L73 Device ID (%X). Expected %X\n",
devid, CS42L73_DEVID); devid, CS42L73_DEVID);
goto err_regmap; return ret;
} }
ret = regmap_read(cs42l73->regmap, CS42L73_REVID, &reg); ret = regmap_read(cs42l73->regmap, CS42L73_REVID, &reg);
if (ret < 0) { if (ret < 0) {
dev_err(&i2c_client->dev, "Get Revision ID failed\n"); dev_err(&i2c_client->dev, "Get Revision ID failed\n");
goto err_regmap; return ret;;
} }
dev_info(&i2c_client->dev, dev_info(&i2c_client->dev,
@ -1402,23 +1402,13 @@ static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client,
&soc_codec_dev_cs42l73, cs42l73_dai, &soc_codec_dev_cs42l73, cs42l73_dai,
ARRAY_SIZE(cs42l73_dai)); ARRAY_SIZE(cs42l73_dai));
if (ret < 0) if (ret < 0)
goto err_regmap; return ret;
return 0; return 0;
err_regmap:
regmap_exit(cs42l73->regmap);
err:
return ret;
} }
static __devexit int cs42l73_i2c_remove(struct i2c_client *client) static __devexit int cs42l73_i2c_remove(struct i2c_client *client)
{ {
struct cs42l73_private *cs42l73 = i2c_get_clientdata(client);
snd_soc_unregister_codec(&client->dev); snd_soc_unregister_codec(&client->dev);
regmap_exit(cs42l73->regmap);
return 0; return 0;
} }

1627
sound/soc/codecs/da732x.c Normal file

File diff suppressed because it is too large Load Diff

133
sound/soc/codecs/da732x.h Normal file
View File

@ -0,0 +1,133 @@
/*
* da732x.h -- Dialog DA732X ALSA SoC Audio Driver Header File
*
* Copyright (C) 2012 Dialog Semiconductor GmbH
*
* Author: Michal Hajduk <Michal.Hajduk@diasemi.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __DA732X_H_
#define __DA732X_H
#include <sound/soc.h>
/* General */
#define DA732X_U8_MASK 0xFF
#define DA732X_4BYTES 4
#define DA732X_3BYTES 3
#define DA732X_2BYTES 2
#define DA732X_1BYTE 1
#define DA732X_1BYTE_SHIFT 8
#define DA732X_2BYTES_SHIFT 16
#define DA732X_3BYTES_SHIFT 24
#define DA732X_4BYTES_SHIFT 32
#define DA732X_DACS_DIS 0x0
#define DA732X_HP_DIS 0x0
#define DA732X_CLEAR_REG 0x0
/* Calibration */
#define DA732X_DAC_OFFSET_STEP 0x20
#define DA732X_OUTPUT_OFFSET_STEP 0x80
#define DA732X_HP_OUT_TRIM_VAL 0x0
#define DA732X_WAIT_FOR_STABILIZATION 1
#define DA732X_HPL_DAC 0
#define DA732X_HPR_DAC 1
#define DA732X_HP_DACS 2
#define DA732X_HPL_AMP 0
#define DA732X_HPR_AMP 1
#define DA732X_HP_AMPS 2
/* Clock settings */
#define DA732X_STARTUP_DELAY 100
#define DA732X_PLL_OUT_196608 196608000
#define DA732X_PLL_OUT_180634 180633600
#define DA732X_PLL_OUT_SRM 188620800
#define DA732X_MCLK_10MHZ 10000000
#define DA732X_MCLK_20MHZ 20000000
#define DA732X_MCLK_40MHZ 40000000
#define DA732X_MCLK_54MHZ 54000000
#define DA732X_MCLK_RET_0_10MHZ 0
#define DA732X_MCLK_VAL_0_10MHZ 1
#define DA732X_MCLK_RET_10_20MHZ 1
#define DA732X_MCLK_VAL_10_20MHZ 2
#define DA732X_MCLK_RET_20_40MHZ 2
#define DA732X_MCLK_VAL_20_40MHZ 4
#define DA732X_MCLK_RET_40_54MHZ 3
#define DA732X_MCLK_VAL_40_54MHZ 8
#define DA732X_DAI_ID1 0
#define DA732X_DAI_ID2 1
#define DA732X_SRCCLK_PLL 0
#define DA732X_SRCCLK_MCLK 1
#define DA732X_LIN_LP_VOL 0x4F
#define DA732X_LP_VOL 0x40
/* Kcontrols */
#define DA732X_DAC_EN_MAX 2
#define DA732X_ADCL_MUX_MAX 2
#define DA732X_ADCR_MUX_MAX 3
#define DA732X_HPF_MODE_MAX 3
#define DA732X_HPF_MODE_SHIFT 4
#define DA732X_HPF_MUSIC_SHIFT 0
#define DA732X_HPF_MUSIC_MAX 4
#define DA732X_HPF_VOICE_SHIFT 4
#define DA732X_HPF_VOICE_MAX 8
#define DA732X_EQ_EN_MAX 1
#define DA732X_HPF_VOICE 1
#define DA732X_HPF_MUSIC 2
#define DA732X_HPF_DISABLED 0
#define DA732X_NO_INVERT 0
#define DA732X_INVERT 1
#define DA732X_SWITCH_MAX 1
#define DA732X_ENABLE_CP 1
#define DA732X_DISABLE_CP 0
#define DA732X_DISABLE_ALL_CLKS 0
#define DA732X_RESET_ADCS 0
/* dB values */
#define DA732X_MIC_VOL_DB_MIN 0
#define DA732X_MIC_VOL_DB_INC 50
#define DA732X_MIC_PRE_VOL_DB_MIN 0
#define DA732X_MIC_PRE_VOL_DB_INC 600
#define DA732X_AUX_VOL_DB_MIN -6000
#define DA732X_AUX_VOL_DB_INC 150
#define DA732X_HP_VOL_DB_MIN -2250
#define DA732X_HP_VOL_DB_INC 150
#define DA732X_LIN2_VOL_DB_MIN -1650
#define DA732X_LIN2_VOL_DB_INC 150
#define DA732X_LIN3_VOL_DB_MIN -1650
#define DA732X_LIN3_VOL_DB_INC 150
#define DA732X_LIN4_VOL_DB_MIN -2250
#define DA732X_LIN4_VOL_DB_INC 150
#define DA732X_EQ_BAND_VOL_DB_MIN -1050
#define DA732X_EQ_BAND_VOL_DB_INC 150
#define DA732X_DAC_VOL_DB_MIN -7725
#define DA732X_DAC_VOL_DB_INC 75
#define DA732X_ADC_VOL_DB_MIN 0
#define DA732X_ADC_VOL_DB_INC -1
#define DA732X_EQ_OVERALL_VOL_DB_MIN -1800
#define DA732X_EQ_OVERALL_VOL_DB_INC 600
#define DA732X_SOC_ENUM_DOUBLE_R(xreg, xrreg, xmax, xtext) \
{.reg = xreg, .reg2 = xrreg, .max = xmax, .texts = xtext}
enum da732x_sysctl {
DA732X_SR_8KHZ = 0x1,
DA732X_SR_11_025KHZ = 0x2,
DA732X_SR_12KHZ = 0x3,
DA732X_SR_16KHZ = 0x5,
DA732X_SR_22_05KHZ = 0x6,
DA732X_SR_24KHZ = 0x7,
DA732X_SR_32KHZ = 0x9,
DA732X_SR_44_1KHZ = 0xA,
DA732X_SR_48KHZ = 0xB,
DA732X_SR_88_1KHZ = 0xE,
DA732X_SR_96KHZ = 0xF,
};
#endif /* __DA732X_H_ */

View File

@ -0,0 +1,654 @@
/*
* da732x_reg.h --- Dialog DA732X ALSA SoC Audio Registers Header File
*
* Copyright (C) 2012 Dialog Semiconductor GmbH
*
* Author: Michal Hajduk <Michal.Hajduk@diasemi.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __DA732X_REG_H_
#define __DA732X_REG_H_
/* DA732X registers */
#define DA732X_REG_STATUS_EXT 0x00
#define DA732X_REG_STATUS 0x01
#define DA732X_REG_REF1 0x02
#define DA732X_REG_BIAS_EN 0x03
#define DA732X_REG_BIAS1 0x04
#define DA732X_REG_BIAS2 0x05
#define DA732X_REG_BIAS3 0x06
#define DA732X_REG_BIAS4 0x07
#define DA732X_REG_MICBIAS2 0x0F
#define DA732X_REG_MICBIAS1 0x10
#define DA732X_REG_MICDET 0x11
#define DA732X_REG_MIC1_PRE 0x12
#define DA732X_REG_MIC1 0x13
#define DA732X_REG_MIC2_PRE 0x14
#define DA732X_REG_MIC2 0x15
#define DA732X_REG_AUX1L 0x16
#define DA732X_REG_AUX1R 0x17
#define DA732X_REG_MIC3_PRE 0x18
#define DA732X_REG_MIC3 0x19
#define DA732X_REG_INP_PINBIAS 0x1A
#define DA732X_REG_INP_ZC_EN 0x1B
#define DA732X_REG_INP_MUX 0x1D
#define DA732X_REG_HP_DET 0x20
#define DA732X_REG_HPL_DAC_OFFSET 0x21
#define DA732X_REG_HPL_DAC_OFF_CNTL 0x22
#define DA732X_REG_HPL_OUT_OFFSET 0x23
#define DA732X_REG_HPL 0x24
#define DA732X_REG_HPL_VOL 0x25
#define DA732X_REG_HPR_DAC_OFFSET 0x26
#define DA732X_REG_HPR_DAC_OFF_CNTL 0x27
#define DA732X_REG_HPR_OUT_OFFSET 0x28
#define DA732X_REG_HPR 0x29
#define DA732X_REG_HPR_VOL 0x2A
#define DA732X_REG_LIN2 0x2B
#define DA732X_REG_LIN3 0x2C
#define DA732X_REG_LIN4 0x2D
#define DA732X_REG_OUT_ZC_EN 0x2E
#define DA732X_REG_HP_LIN1_GNDSEL 0x37
#define DA732X_REG_CP_HP1 0x3A
#define DA732X_REG_CP_HP2 0x3B
#define DA732X_REG_CP_CTRL1 0x40
#define DA732X_REG_CP_CTRL2 0x41
#define DA732X_REG_CP_CTRL3 0x42
#define DA732X_REG_CP_LEVEL_MASK 0x43
#define DA732X_REG_CP_DET 0x44
#define DA732X_REG_CP_STATUS 0x45
#define DA732X_REG_CP_THRESH1 0x46
#define DA732X_REG_CP_THRESH2 0x47
#define DA732X_REG_CP_THRESH3 0x48
#define DA732X_REG_CP_THRESH4 0x49
#define DA732X_REG_CP_THRESH5 0x4A
#define DA732X_REG_CP_THRESH6 0x4B
#define DA732X_REG_CP_THRESH7 0x4C
#define DA732X_REG_CP_THRESH8 0x4D
#define DA732X_REG_PLL_DIV_LO 0x50
#define DA732X_REG_PLL_DIV_MID 0x51
#define DA732X_REG_PLL_DIV_HI 0x52
#define DA732X_REG_PLL_CTRL 0x53
#define DA732X_REG_CLK_CTRL 0x54
#define DA732X_REG_CLK_DSP 0x5A
#define DA732X_REG_CLK_EN1 0x5B
#define DA732X_REG_CLK_EN2 0x5C
#define DA732X_REG_CLK_EN3 0x5D
#define DA732X_REG_CLK_EN4 0x5E
#define DA732X_REG_CLK_EN5 0x5F
#define DA732X_REG_AIF_MCLK 0x60
#define DA732X_REG_AIFA1 0x61
#define DA732X_REG_AIFA2 0x62
#define DA732X_REG_AIFA3 0x63
#define DA732X_REG_AIFB1 0x64
#define DA732X_REG_AIFB2 0x65
#define DA732X_REG_AIFB3 0x66
#define DA732X_REG_PC_CTRL 0x6A
#define DA732X_REG_DATA_ROUTE 0x70
#define DA732X_REG_DSP_CTRL 0x71
#define DA732X_REG_CIF_CTRL2 0x74
#define DA732X_REG_HANDSHAKE 0x75
#define DA732X_REG_MBOX0 0x76
#define DA732X_REG_MBOX1 0x77
#define DA732X_REG_MBOX2 0x78
#define DA732X_REG_MBOX_STATUS 0x79
#define DA732X_REG_SPARE1_OUT 0x7D
#define DA732X_REG_SPARE2_OUT 0x7E
#define DA732X_REG_SPARE1_IN 0x7F
#define DA732X_REG_ID 0x81
#define DA732X_REG_ADC1_PD 0x90
#define DA732X_REG_ADC1_HPF 0x93
#define DA732X_REG_ADC1_SEL 0x94
#define DA732X_REG_ADC1_EQ12 0x95
#define DA732X_REG_ADC1_EQ34 0x96
#define DA732X_REG_ADC1_EQ5 0x97
#define DA732X_REG_ADC2_PD 0x98
#define DA732X_REG_ADC2_HPF 0x9B
#define DA732X_REG_ADC2_SEL 0x9C
#define DA732X_REG_ADC2_EQ12 0x9D
#define DA732X_REG_ADC2_EQ34 0x9E
#define DA732X_REG_ADC2_EQ5 0x9F
#define DA732X_REG_DAC1_HPF 0xA0
#define DA732X_REG_DAC1_L_VOL 0xA1
#define DA732X_REG_DAC1_R_VOL 0xA2
#define DA732X_REG_DAC1_SEL 0xA3
#define DA732X_REG_DAC1_SOFTMUTE 0xA4
#define DA732X_REG_DAC1_EQ12 0xA5
#define DA732X_REG_DAC1_EQ34 0xA6
#define DA732X_REG_DAC1_EQ5 0xA7
#define DA732X_REG_DAC2_HPF 0xB0
#define DA732X_REG_DAC2_L_VOL 0xB1
#define DA732X_REG_DAC2_R_VOL 0xB2
#define DA732X_REG_DAC2_SEL 0xB3
#define DA732X_REG_DAC2_SOFTMUTE 0xB4
#define DA732X_REG_DAC2_EQ12 0xB5
#define DA732X_REG_DAC2_EQ34 0xB6
#define DA732X_REG_DAC2_EQ5 0xB7
#define DA732X_REG_DAC3_HPF 0xC0
#define DA732X_REG_DAC3_VOL 0xC1
#define DA732X_REG_DAC3_SEL 0xC3
#define DA732X_REG_DAC3_SOFTMUTE 0xC4
#define DA732X_REG_DAC3_EQ12 0xC5
#define DA732X_REG_DAC3_EQ34 0xC6
#define DA732X_REG_DAC3_EQ5 0xC7
#define DA732X_REG_BIQ_BYP 0xD2
#define DA732X_REG_DMA_CMD 0xD3
#define DA732X_REG_DMA_ADDR0 0xD4
#define DA732X_REG_DMA_ADDR1 0xD5
#define DA732X_REG_DMA_DATA0 0xD6
#define DA732X_REG_DMA_DATA1 0xD7
#define DA732X_REG_DMA_DATA2 0xD8
#define DA732X_REG_DMA_DATA3 0xD9
#define DA732X_REG_DMA_STATUS 0xDA
#define DA732X_REG_BROWNOUT 0xDF
#define DA732X_REG_UNLOCK 0xE0
#define DA732X_MAX_REG DA732X_REG_UNLOCK
/*
* Bits
*/
/* DA732X_REG_STATUS_EXT (addr=0x00) */
#define DA732X_STATUS_EXT_DSP (1 << 4)
#define DA732X_STATUS_EXT_CLEAR (0 << 0)
/* DA732X_REG_STATUS (addr=0x01) */
#define DA732X_STATUS_PLL_LOCK (1 << 0)
#define DA732X_STATUS_PLL_MCLK_DET (1 << 1)
#define DA732X_STATUS_HPDET_OUT (1 << 2)
#define DA732X_STATUS_INP_MIXDET_1 (1 << 3)
#define DA732X_STATUS_INP_MIXDET_2 (1 << 4)
#define DA732X_STATUS_BO_STATUS (1 << 5)
/* DA732X_REG_REF1 (addr=0x02) */
#define DA732X_VMID_FASTCHG (1 << 1)
#define DA732X_VMID_FASTDISCHG (1 << 2)
#define DA732X_REFBUFX2_EN (1 << 6)
#define DA732X_REFBUFX2_DIS (0 << 6)
/* DA732X_REG_BIAS_EN (addr=0x03) */
#define DA732X_BIAS_BOOST_MASK (3 << 0)
#define DA732X_BIAS_BOOST_100PC (0 << 0)
#define DA732X_BIAS_BOOST_133PC (1 << 0)
#define DA732X_BIAS_BOOST_88PC (2 << 0)
#define DA732X_BIAS_BOOST_50PC (3 << 0)
#define DA732X_BIAS_EN (1 << 7)
#define DA732X_BIAS_DIS (0 << 7)
/* DA732X_REG_BIAS1 (addr=0x04) */
#define DA732X_BIAS1_HP_DAC_BIAS_MASK (3 << 0)
#define DA732X_BIAS1_HP_DAC_BIAS_100PC (0 << 0)
#define DA732X_BIAS1_HP_DAC_BIAS_150PC (1 << 0)
#define DA732X_BIAS1_HP_DAC_BIAS_50PC (2 << 0)
#define DA732X_BIAS1_HP_DAC_BIAS_75PC (3 << 0)
#define DA732X_BIAS1_HP_OUT_BIAS_MASK (7 << 4)
#define DA732X_BIAS1_HP_OUT_BIAS_100PC (0 << 4)
#define DA732X_BIAS1_HP_OUT_BIAS_125PC (1 << 4)
#define DA732X_BIAS1_HP_OUT_BIAS_150PC (2 << 4)
#define DA732X_BIAS1_HP_OUT_BIAS_175PC (3 << 4)
#define DA732X_BIAS1_HP_OUT_BIAS_200PC (4 << 4)
#define DA732X_BIAS1_HP_OUT_BIAS_250PC (5 << 4)
#define DA732X_BIAS1_HP_OUT_BIAS_300PC (6 << 4)
#define DA732X_BIAS1_HP_OUT_BIAS_350PC (7 << 4)
/* DA732X_REG_BIAS2 (addr=0x05) */
#define DA732X_BIAS2_LINE2_DAC_BIAS_MASK (3 << 0)
#define DA732X_BIAS2_LINE2_DAC_BIAS_100PC (0 << 0)
#define DA732X_BIAS2_LINE2_DAC_BIAS_150PC (1 << 0)
#define DA732X_BIAS2_LINE2_DAC_BIAS_50PC (2 << 0)
#define DA732X_BIAS2_LINE2_DAC_BIAS_75PC (3 << 0)
#define DA732X_BIAS2_LINE2_OUT_BIAS_MASK (7 << 4)
#define DA732X_BIAS2_LINE2_OUT_BIAS_100PC (0 << 4)
#define DA732X_BIAS2_LINE2_OUT_BIAS_125PC (1 << 4)
#define DA732X_BIAS2_LINE2_OUT_BIAS_150PC (2 << 4)
#define DA732X_BIAS2_LINE2_OUT_BIAS_175PC (3 << 4)
#define DA732X_BIAS2_LINE2_OUT_BIAS_200PC (4 << 4)
#define DA732X_BIAS2_LINE2_OUT_BIAS_250PC (5 << 4)
#define DA732X_BIAS2_LINE2_OUT_BIAS_300PC (6 << 4)
#define DA732X_BIAS2_LINE2_OUT_BIAS_350PC (7 << 4)
/* DA732X_REG_BIAS3 (addr=0x06) */
#define DA732X_BIAS3_LINE3_DAC_BIAS_MASK (3 << 0)
#define DA732X_BIAS3_LINE3_DAC_BIAS_100PC (0 << 0)
#define DA732X_BIAS3_LINE3_DAC_BIAS_150PC (1 << 0)
#define DA732X_BIAS3_LINE3_DAC_BIAS_50PC (2 << 0)
#define DA732X_BIAS3_LINE3_DAC_BIAS_75PC (3 << 0)
#define DA732X_BIAS3_LINE3_OUT_BIAS_MASK (7 << 4)
#define DA732X_BIAS3_LINE3_OUT_BIAS_100PC (0 << 4)
#define DA732X_BIAS3_LINE3_OUT_BIAS_125PC (1 << 4)
#define DA732X_BIAS3_LINE3_OUT_BIAS_150PC (2 << 4)
#define DA732X_BIAS3_LINE3_OUT_BIAS_175PC (3 << 4)
#define DA732X_BIAS3_LINE3_OUT_BIAS_200PC (4 << 4)
#define DA732X_BIAS3_LINE3_OUT_BIAS_250PC (5 << 4)
#define DA732X_BIAS3_LINE3_OUT_BIAS_300PC (6 << 4)
#define DA732X_BIAS3_LINE3_OUT_BIAS_350PC (7 << 4)
/* DA732X_REG_BIAS4 (addr=0x07) */
#define DA732X_BIAS4_LINE4_DAC_BIAS_MASK (3 << 0)
#define DA732X_BIAS4_LINE4_DAC_BIAS_100PC (0 << 0)
#define DA732X_BIAS4_LINE4_DAC_BIAS_150PC (1 << 0)
#define DA732X_BIAS4_LINE4_DAC_BIAS_50PC (2 << 0)
#define DA732X_BIAS4_LINE4_DAC_BIAS_75PC (3 << 0)
#define DA732X_BIAS4_LINE4_OUT_BIAS_MASK (7 << 4)
#define DA732X_BIAS4_LINE4_OUT_BIAS_100PC (0 << 4)
#define DA732X_BIAS4_LINE4_OUT_BIAS_125PC (1 << 4)
#define DA732X_BIAS4_LINE4_OUT_BIAS_150PC (2 << 4)
#define DA732X_BIAS4_LINE4_OUT_BIAS_175PC (3 << 4)
#define DA732X_BIAS4_LINE4_OUT_BIAS_200PC (4 << 4)
#define DA732X_BIAS4_LINE4_OUT_BIAS_250PC (5 << 4)
#define DA732X_BIAS4_LINE4_OUT_BIAS_300PC (6 << 4)
#define DA732X_BIAS4_LINE4_OUT_BIAS_350PC (7 << 4)
/* DA732X_REG_SIF_VDD_SEL (addr=0x08) */
#define DA732X_SIF_VDD_SEL_AIFA_VDD2 (1 << 0)
#define DA732X_SIF_VDD_SEL_AIFB_VDD2 (1 << 1)
#define DA732X_SIF_VDD_SEL_CIFA_VDD2 (1 << 4)
/* DA732X_REG_MICBIAS2/1 (addr=0x0F/0x10) */
#define DA732X_MICBIAS_VOLTAGE_MASK (0x0F << 0)
#define DA732X_MICBIAS_VOLTAGE_2V (0x00 << 0)
#define DA732X_MICBIAS_VOLTAGE_2V05 (0x01 << 0)
#define DA732X_MICBIAS_VOLTAGE_2V1 (0x02 << 0)
#define DA732X_MICBIAS_VOLTAGE_2V15 (0x03 << 0)
#define DA732X_MICBIAS_VOLTAGE_2V2 (0x04 << 0)
#define DA732X_MICBIAS_VOLTAGE_2V25 (0x05 << 0)
#define DA732X_MICBIAS_VOLTAGE_2V3 (0x06 << 0)
#define DA732X_MICBIAS_VOLTAGE_2V35 (0x07 << 0)
#define DA732X_MICBIAS_VOLTAGE_2V4 (0x08 << 0)
#define DA732X_MICBIAS_VOLTAGE_2V45 (0x09 << 0)
#define DA732X_MICBIAS_VOLTAGE_2V5 (0x0A << 0)
#define DA732X_MICBIAS_EN (1 << 7)
#define DA732X_MICBIAS_EN_SHIFT 7
#define DA732X_MICBIAS_VOLTAGE_SHIFT 0
#define DA732X_MICBIAS_VOLTAGE_MAX 0x0B
/* DA732X_REG_MICDET (addr=0x11) */
#define DA732X_MICDET_INP_MICRES (1 << 0)
#define DA732X_MICDET_INP_MICHOOK (1 << 1)
#define DA732X_MICDET_INP_DEBOUNCE_PRD_8MS (0 << 0)
#define DA732X_MICDET_INP_DEBOUNCE_PRD_16MS (1 << 0)
#define DA732X_MICDET_INP_DEBOUNCE_PRD_32MS (2 << 0)
#define DA732X_MICDET_INP_DEBOUNCE_PRD_64MS (3 << 0)
#define DA732X_MICDET_INP_MICDET_EN (1 << 7)
/* DA732X_REG_MIC1/2/3_PRE (addr=0x11/0x14/0x18) */
#define DA732X_MICBOOST_MASK 0x7
#define DA732X_MICBOOST_SHIFT 0
#define DA732X_MICBOOST_MIN 0x1
#define DA732X_MICBOOST_MAX DA732X_MICBOOST_MASK
/* DA732X_REG_MIC1/2/3 (addr=0x13/0x15/0x19) */
#define DA732X_MIC_VOL_SHIFT 0
#define DA732X_MIC_VOL_VAL_MASK 0x1F
#define DA732X_MIC_MUTE_SHIFT 6
#define DA732X_MIC_EN_SHIFT 7
#define DA732X_MIC_VOL_VAL_MIN 0x7
#define DA732X_MIC_VOL_VAL_MAX DA732X_MIC_VOL_VAL_MASK
/* DA732X_REG_AUX1L/R (addr=0x16/0x17) */
#define DA732X_AUX_VOL_SHIFT 0
#define DA732X_AUX_VOL_MASK 0x7
#define DA732X_AUX_MUTE_SHIFT 6
#define DA732X_AUX_EN_SHIFT 7
#define DA732X_AUX_VOL_VAL_MAX DA732X_AUX_VOL_MASK
/* DA732X_REG_INP_PINBIAS (addr=0x1A) */
#define DA732X_INP_MICL_PINBIAS_EN (1 << 0)
#define DA732X_INP_MICR_PINBIAS_EN (1 << 1)
#define DA732X_INP_AUX1L_PINBIAS_EN (1 << 2)
#define DA732X_INP_AUX1R_PINBIAS_EN (1 << 3)
#define DA732X_INP_AUX2_PINBIAS_EN (1 << 4)
/* DA732X_REG_INP_ZC_EN (addr=0x1B) */
#define DA732X_MIC1_PRE_ZC_EN (1 << 0)
#define DA732X_MIC1_ZC_EN (1 << 1)
#define DA732X_MIC2_PRE_ZC_EN (1 << 2)
#define DA732X_MIC2_ZC_EN (1 << 3)
#define DA732X_AUXL_ZC_EN (1 << 4)
#define DA732X_AUXR_ZC_EN (1 << 5)
#define DA732X_MIC3_PRE_ZC_EN (1 << 6)
#define DA732X_MIC3_ZC_EN (1 << 7)
/* DA732X_REG_INP_MUX (addr=0x1D) */
#define DA732X_INP_ADC1L_MUX_SEL_AUX1L (0 << 0)
#define DA732X_INP_ADC1L_MUX_SEL_MIC1 (1 << 0)
#define DA732X_INP_ADC1R_MUX_SEL_MASK (3 << 2)
#define DA732X_INP_ADC1R_MUX_SEL_AUX1R (0 << 2)
#define DA732X_INP_ADC1R_MUX_SEL_MIC2 (1 << 2)
#define DA732X_INP_ADC1R_MUX_SEL_MIC3 (2 << 2)
#define DA732X_INP_ADC2L_MUX_SEL_AUX1L (0 << 4)
#define DA732X_INP_ADC2L_MUX_SEL_MICL (1 << 4)
#define DA732X_INP_ADC2R_MUX_SEL_MASK (3 << 6)
#define DA732X_INP_ADC2R_MUX_SEL_AUX1R (0 << 6)
#define DA732X_INP_ADC2R_MUX_SEL_MICR (1 << 6)
#define DA732X_INP_ADC2R_MUX_SEL_AUX2 (2 << 6)
#define DA732X_ADC1L_MUX_SEL_SHIFT 0
#define DA732X_ADC1R_MUX_SEL_SHIFT 2
#define DA732X_ADC2L_MUX_SEL_SHIFT 4
#define DA732X_ADC2R_MUX_SEL_SHIFT 6
/* DA732X_REG_HP_DET (addr=0x20) */
#define DA732X_HP_DET_AZ (1 << 0)
#define DA732X_HP_DET_SEL1 (1 << 1)
#define DA732X_HP_DET_IS_MASK (3 << 2)
#define DA732X_HP_DET_IS_0_5UA (0 << 2)
#define DA732X_HP_DET_IS_1UA (1 << 2)
#define DA732X_HP_DET_IS_2UA (2 << 2)
#define DA732X_HP_DET_IS_4UA (3 << 2)
#define DA732X_HP_DET_RS_MASK (3 << 4)
#define DA732X_HP_DET_RS_INFINITE (0 << 4)
#define DA732X_HP_DET_RS_100KOHM (1 << 4)
#define DA732X_HP_DET_RS_10KOHM (2 << 4)
#define DA732X_HP_DET_RS_1KOHM (3 << 4)
#define DA732X_HP_DET_EN (1 << 7)
/* DA732X_REG_HPL_DAC_OFFSET (addr=0x21/0x26) */
#define DA732X_HP_DAC_OFFSET_TRIM_MASK (0x3F << 0)
#define DA732X_HP_DAC_OFFSET_DAC_SIGN (1 << 6)
/* DA732X_REG_HPL_DAC_OFF_CNTL (addr=0x22/0x27) */
#define DA732X_HP_DAC_OFF_CNTL_CONT_MASK (7 << 0)
#define DA732X_HP_DAC_OFF_CNTL_COMPO (1 << 3)
#define DA732X_HP_DAC_OFF_CALIBRATION (1 << 0)
#define DA732X_HP_DAC_OFF_SCALE_STEPS (1 << 1)
#define DA732X_HP_DAC_OFF_MASK 0x7F
#define DA732X_HP_DAC_COMPO_SHIFT 3
/* DA732X_REG_HPL_OUT_OFFSET (addr=0x23/0x28) */
#define DA732X_HP_OUT_OFFSET_MASK (0xFF << 0)
#define DA732X_HP_DAC_OFFSET_TRIM_VAL 0x7F
/* DA732X_REG_HPL/R (addr=0x24/0x29) */
#define DA732X_HP_OUT_SIGN (1 << 0)
#define DA732X_HP_OUT_COMP (1 << 1)
#define DA732X_HP_OUT_RESERVED (1 << 2)
#define DA732X_HP_OUT_COMPO (1 << 3)
#define DA732X_HP_OUT_DAC_EN (1 << 4)
#define DA732X_HP_OUT_HIZ_EN (1 << 5)
#define DA732X_HP_OUT_HIZ_DIS (0 << 5)
#define DA732X_HP_OUT_MUTE (1 << 6)
#define DA732X_HP_OUT_EN (1 << 7)
#define DA732X_HP_OUT_COMPO_SHIFT 3
#define DA732X_HP_OUT_DAC_EN_SHIFT 4
#define DA732X_HP_HIZ_SHIFT 5
#define DA732X_HP_MUTE_SHIFT 6
#define DA732X_HP_OUT_EN_SHIFT 7
#define DA732X_OUT_HIZ_EN (1 << 5)
#define DA732X_OUT_HIZ_DIS (0 << 5)
/* DA732X_REG_HPL/R_VOL (addr=0x25/0x2A) */
#define DA732X_HP_VOL_VAL_MASK 0xF
#define DA732X_HP_VOL_SHIFT 0
#define DA732X_HP_VOL_VAL_MAX DA732X_HP_VOL_VAL_MASK
/* DA732X_REG_LIN2/3/4 (addr=0x2B/0x2C/0x2D) */
#define DA732X_LOUT_VOL_SHIFT 0
#define DA732X_LOUT_VOL_MASK 0x0F
#define DA732X_LOUT_DAC_OFF (0 << 4)
#define DA732X_LOUT_DAC_EN (1 << 4)
#define DA732X_LOUT_HIZ_N_DIS (0 << 5)
#define DA732X_LOUT_HIZ_N_EN (1 << 5)
#define DA732X_LOUT_UNMUTED (0 << 6)
#define DA732X_LOUT_MUTED (1 << 6)
#define DA732X_LOUT_EN (0 << 7)
#define DA732X_LOUT_DIS (1 << 7)
#define DA732X_LOUT_DAC_EN_SHIFT 4
#define DA732X_LOUT_MUTE_SHIFT 6
#define DA732X_LIN_OUT_EN_SHIFT 7
#define DA732X_LOUT_VOL_VAL_MAX DA732X_LOUT_VOL_MASK
/* DA732X_REG_OUT_ZC_EN (addr=0x2E) */
#define DA732X_HPL_ZC_EN_SHIFT 0
#define DA732X_HPR_ZC_EN_SHIFT 1
#define DA732X_HPL_ZC_EN (1 << 0)
#define DA732X_HPL_ZC_DIS (0 << 0)
#define DA732X_HPR_ZC_EN (1 << 1)
#define DA732X_HPR_ZC_DIS (0 << 1)
#define DA732X_LIN2_ZC_EN (1 << 2)
#define DA732X_LIN2_ZC_DIS (0 << 2)
#define DA732X_LIN3_ZC_EN (1 << 3)
#define DA732X_LIN3_ZC_DIS (0 << 3)
#define DA732X_LIN4_ZC_EN (1 << 4)
#define DA732X_LIN4_ZC_DIS (0 << 4)
/* DA732X_REG_HP_LIN1_GNDSEL (addr=0x37) */
#define DA732X_HP_OUT_GNDSEL (1 << 0)
/* DA732X_REG_CP_HP2 (addr=0x3a) */
#define DA732X_HP_CP_PULSESKIP (1 << 0)
#define DA732X_HP_CP_REG (1 << 1)
#define DA732X_HP_CP_EN (1 << 3)
#define DA732X_HP_CP_DIS (0 << 3)
/* DA732X_REG_CP_CTRL1 (addr=0x40) */
#define DA732X_CP_MODE_MASK (7 << 1)
#define DA732X_CP_CTRL_STANDBY (0 << 1)
#define DA732X_CP_CTRL_CPVDD6 (2 << 1)
#define DA732X_CP_CTRL_CPVDD5 (3 << 1)
#define DA732X_CP_CTRL_CPVDD4 (4 << 1)
#define DA732X_CP_CTRL_CPVDD3 (5 << 1)
#define DA732X_CP_CTRL_CPVDD2 (6 << 1)
#define DA732X_CP_CTRL_CPVDD1 (7 << 1)
#define DA723X_CP_DIS (0 << 7)
#define DA732X_CP_EN (1 << 7)
/* DA732X_REG_CP_CTRL2 (addr=0x41) */
#define DA732X_CP_BOOST (1 << 0)
#define DA732X_CP_MANAGE_MAGNITUDE (2 << 2)
/* DA732X_REG_CP_CTRL3 (addr=0x42) */
#define DA732X_CP_1MHZ (0 << 0)
#define DA732X_CP_500KHZ (1 << 0)
#define DA732X_CP_250KHZ (2 << 0)
#define DA732X_CP_125KHZ (3 << 0)
#define DA732X_CP_63KHZ (4 << 0)
#define DA732X_CP_0KHZ (5 << 0)
/* DA732X_REG_PLL_CTRL (addr=0x53) */
#define DA732X_PLL_INDIV_MASK (3 << 0)
#define DA732X_PLL_SRM_EN (1 << 2)
#define DA732X_PLL_EN (1 << 7)
#define DA732X_PLL_BYPASS (0 << 0)
/* DA732X_REG_CLK_CTRL (addr=0x54) */
#define DA732X_SR1_MASK (0xF)
#define DA732X_SR2_MASK (0xF0)
/* DA732X_REG_CLK_DSP (addr=0x5A) */
#define DA732X_DSP_FREQ_MASK (7 << 0)
#define DA732X_DSP_FREQ_12MHZ (0 << 0)
#define DA732X_DSP_FREQ_24MHZ (1 << 0)
#define DA732X_DSP_FREQ_36MHZ (2 << 0)
#define DA732X_DSP_FREQ_48MHZ (3 << 0)
#define DA732X_DSP_FREQ_60MHZ (4 << 0)
#define DA732X_DSP_FREQ_72MHZ (5 << 0)
#define DA732X_DSP_FREQ_84MHZ (6 << 0)
#define DA732X_DSP_FREQ_96MHZ (7 << 0)
/* DA732X_REG_CLK_EN1 (addr=0x5B) */
#define DA732X_DSP_CLK_EN (1 << 0)
#define DA732X_SYS3_CLK_EN (1 << 1)
#define DA732X_DSP12_CLK_EN (1 << 2)
#define DA732X_PC_CLK_EN (1 << 3)
#define DA732X_MCLK_SQR_EN (1 << 7)
/* DA732X_REG_CLK_EN2 (addr=0x5C) */
#define DA732X_UART_CLK_EN (1 << 1)
#define DA732X_CP_CLK_EN (1 << 2)
#define DA732X_CP_CLK_DIS (0 << 2)
/* DA732X_REG_CLK_EN3 (addr=0x5D) */
#define DA732X_ADCA_BB_CLK_EN (1 << 0)
#define DA732X_ADCC_BB_CLK_EN (1 << 4)
/* DA732X_REG_CLK_EN4 (addr=0x5E) */
#define DA732X_DACA_BB_CLK_EN (1 << 0)
#define DA732X_DACC_BB_CLK_EN (1 << 4)
#define DA732X_DACA_BB_CLK_SHIFT 0
#define DA732X_DACC_BB_CLK_SHIFT 4
/* DA732X_REG_CLK_EN5 (addr=0x5F) */
#define DA732X_DACE_BB_CLK_EN (1 << 0)
#define DA732X_DACE_BB_CLK_SHIFT 0
/* DA732X_REG_AIF_MCLK (addr=0x60) */
#define DA732X_AIFM_FRAME_64 (1 << 2)
#define DA732X_AIFM_SRC_SEL_AIFA (1 << 6)
#define DA732X_CLK_GENERATION_AIF_A (1 << 4)
#define DA732X_NO_CLK_GENERATION 0x0
/* DA732X_REG_AIFA1 (addr=0x61) */
#define DA732X_AIF_WORD_MASK (0x3 << 0)
#define DA732X_AIF_WORD_16 (0 << 0)
#define DA732X_AIF_WORD_20 (1 << 0)
#define DA732X_AIF_WORD_24 (2 << 0)
#define DA732X_AIF_WORD_32 (3 << 0)
#define DA732X_AIF_TDM_MONO_SHIFT (1 << 6)
#define DA732X_AIF1_CLK_MASK (1 << 7)
#define DA732X_AIF_SLAVE (0 << 7)
#define DA732X_AIF_CLK_FROM_SRC (1 << 7)
/* DA732X_REG_AIFA3 (addr=0x63) */
#define DA732X_AIF_MODE_SHIFT 0
#define DA732X_AIF_MODE_MASK 0x3
#define DA732X_AIF_I2S_MODE (0 << 0)
#define DA732X_AIF_LEFT_J_MODE (1 << 0)
#define DA732X_AIF_RIGHT_J_MODE (2 << 0)
#define DA732X_AIF_DSP_MODE (3 << 0)
#define DA732X_AIF_WCLK_INV (1 << 4)
#define DA732X_AIF_BCLK_INV (1 << 5)
#define DA732X_AIF_EN (1 << 7)
#define DA732X_AIF_EN_SHIFT 7
/* DA732X_REG_PC_CTRL (addr=0x6a) */
#define DA732X_PC_PULSE_AIFA (0 << 0)
#define DA732X_PC_PULSE_AIFB (1 << 0)
#define DA732X_PC_RESYNC_AUT (1 << 6)
#define DA732X_PC_RESYNC_NOT_AUT (0 << 6)
#define DA732X_PC_SAME (1 << 7)
/* DA732X_REG_DATA_ROUTE (addr=0x70) */
#define DA732X_ADC1_TO_AIFA (0 << 0)
#define DA732X_DSP_TO_AIFA (1 << 0)
#define DA732X_ADC2_TO_AIFB (0 << 1)
#define DA732X_DSP_TO_AIFB (1 << 1)
#define DA732X_AIFA_TO_DAC1L (0 << 2)
#define DA732X_DSP_TO_DAC1L (1 << 2)
#define DA732X_AIFA_TO_DAC1R (0 << 3)
#define DA732X_DSP_TO_DAC1R (1 << 3)
#define DA732X_AIFB_TO_DAC2L (0 << 4)
#define DA732X_DSP_TO_DAC2L (1 << 4)
#define DA732X_AIFB_TO_DAC2R (0 << 5)
#define DA732X_DSP_TO_DAC2R (1 << 5)
#define DA732X_AIFB_TO_DAC3 (0 << 6)
#define DA732X_DSP_TO_DAC3 (1 << 6)
#define DA732X_BYPASS_DSP (0 << 0)
#define DA732X_ALL_TO_DSP (0x7F << 0)
/* DA732X_REG_DSP_CTRL (addr=0x71) */
#define DA732X_DIGITAL_EN (1 << 0)
#define DA732X_DIGITAL_RESET (0 << 0)
#define DA732X_DSP_CORE_EN (1 << 1)
#define DA732X_DSP_CORE_RESET (0 << 1)
/* DA732X_REG_SPARE1_OUT (addr=0x7D)*/
#define DA732X_HP_DRIVER_EN (1 << 0)
#define DA732X_HP_GATE_LOW (1 << 2)
#define DA732X_HP_LOOP_GAIN_CTRL (1 << 3)
/* DA732X_REG_ID (addr=0x81)*/
#define DA732X_ID_MINOR_MASK (0xF << 0)
#define DA732X_ID_MAJOR_MASK (0xF << 4)
/* DA732X_REG_ADC1/2_PD (addr=0x90/0x98) */
#define DA732X_ADC_RST_MASK (0x3 << 0)
#define DA732X_ADC_PD_MASK (0x3 << 2)
#define DA732X_ADC_SET_ACT (0x3 << 0)
#define DA732X_ADC_SET_RST (0x0 << 0)
#define DA732X_ADC_ON (0x3 << 2)
#define DA732X_ADC_OFF (0x0 << 2)
/* DA732X_REG_ADC1/2_SEL (addr=0x94/0x9C) */
#define DA732X_ADC_VOL_VAL_MASK 0x7
#define DA732X_ADCL_VOL_SHIFT 0
#define DA732X_ADCR_VOL_SHIFT 4
#define DA732X_ADCL_EN_SHIFT 2
#define DA732X_ADCR_EN_SHIFT 3
#define DA732X_ADCL_EN (1 << 2)
#define DA732X_ADCR_EN (1 << 3)
#define DA732X_ADC_VOL_VAL_MAX DA732X_ADC_VOL_VAL_MASK
/*
* DA732X_REG_ADC1/2_HPF (addr=0x93/0x9b)
* DA732x_REG_DAC1/2/3_HPG (addr=0xA5/0xB5/0xC5)
*/
#define DA732X_HPF_MUSIC_EN (1 << 3)
#define DA732X_HPF_VOICE_EN ((1 << 3) | (1 << 7))
#define DA732X_HPF_MASK ((1 << 3) | (1 << 7))
#define DA732X_HPF_DIS ((0 << 3) | (0 << 7))
/* DA732X_REG_DAC1/2/3_VOL */
#define DA732X_DAC_VOL_VAL_MASK 0x7F
#define DA732X_DAC_VOL_SHIFT 0
#define DA732X_DAC_VOL_VAL_MAX DA732X_DAC_VOL_VAL_MASK
/* DA732X_REG_DAC1/2/3_SEL (addr=0xA3/0xB3/0xC3) */
#define DA732X_DACL_EN_SHIFT 3
#define DA732X_DACR_EN_SHIFT 7
#define DA732X_DACL_MUTE_SHIFT 2
#define DA732X_DACR_MUTE_SHIFT 6
#define DA732X_DACL_EN (1 << 3)
#define DA732X_DACR_EN (1 << 7)
#define DA732X_DACL_SDM (1 << 0)
#define DA732X_DACR_SDM (1 << 4)
#define DA732X_DACL_MUTE (1 << 2)
#define DA732X_DACR_MUTE (1 << 6)
/* DA732X_REG_DAC_SOFTMUTE (addr=0xA4/0xB4/0xC4) */
#define DA732X_SOFTMUTE_EN (1 << 7)
#define DA732X_GAIN_RAMPED (1 << 6)
#define DA732X_16_SAMPLES (4 << 0)
#define DA732X_SOFTMUTE_MASK (1 << 7)
#define DA732X_SOFTMUTE_SHIFT 7
/*
* DA732x_REG_ADC1/2_EQ12 (addr=0x95/0x9D)
* DA732x_REG_ADC1/2_EQ34 (addr=0x96/0x9E)
* DA732x_REG_ADC1/2_EQ5 (addr=0x97/0x9F)
* DA732x_REG_DAC1/2/3_EQ12 (addr=0xA5/0xB5/0xC5)
* DA732x_REG_DAC1/2/3_EQ34 (addr=0xA6/0xB6/0xC6)
* DA732x_REG_DAC1/2/3_EQ5 (addr=0xA7/0xB7/0xB7)
*/
#define DA732X_EQ_VOL_VAL_MASK 0xF
#define DA732X_EQ_BAND1_SHIFT 0
#define DA732X_EQ_BAND2_SHIFT 4
#define DA732X_EQ_BAND3_SHIFT 0
#define DA732X_EQ_BAND4_SHIFT 4
#define DA732X_EQ_BAND5_SHIFT 0
#define DA732X_EQ_OVERALL_SHIFT 4
#define DA732X_EQ_OVERALL_VOL_VAL_MASK 0x3
#define DA732X_EQ_DIS (0 << 7)
#define DA732X_EQ_EN (1 << 7)
#define DA732X_EQ_EN_SHIFT 7
#define DA732X_EQ_VOL_VAL_MAX DA732X_EQ_VOL_VAL_MASK
#define DA732X_EQ_OVERALL_VOL_VAL_MAX DA732X_EQ_OVERALL_VOL_VAL_MASK
/* DA732X_REG_DMA_CMD (addr=0xD3) */
#define DA732X_SEL_DSP_DMA_MASK (3 << 0)
#define DA732X_SEL_DSP_DMA_DIS (0 << 0)
#define DA732X_SEL_DSP_DMA_PMEM (1 << 0)
#define DA732X_SEL_DSP_DMA_XMEM (2 << 0)
#define DA732X_SEL_DSP_DMA_YMEM (3 << 0)
#define DA732X_DSP_RW_MASK (1 << 4)
#define DA732X_DSP_DMA_WRITE (0 << 4)
#define DA732X_DSP_DMA_READ (1 << 4)
/* DA732X_REG_DMA_STATUS (addr=0xDA) */
#define DA732X_DSP_DMA_FREE (0 << 0)
#define DA732X_DSP_DMA_BUSY (1 << 0)
#endif /* __DA732X_REG_H_ */

1176
sound/soc/codecs/isabelle.c Normal file

File diff suppressed because it is too large Load Diff

143
sound/soc/codecs/isabelle.h Normal file
View File

@ -0,0 +1,143 @@
/*
* isabelle.h - Low power high fidelity audio codec driver header file
*
* Copyright (c) 2012 Texas Instruments, Inc
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
*/
#ifndef _ISABELLE_H
#define _ISABELLE_H
#include <linux/bitops.h>
/* ISABELLE REGISTERS */
#define ISABELLE_PWR_CFG_REG 0x01
#define ISABELLE_PWR_EN_REG 0x02
#define ISABELLE_PS_EN1_REG 0x03
#define ISABELLE_INT1_STATUS_REG 0x04
#define ISABELLE_INT1_MASK_REG 0x05
#define ISABELLE_INT2_STATUS_REG 0x06
#define ISABELLE_INT2_MASK_REG 0x07
#define ISABELLE_HKCTL1_REG 0x08
#define ISABELLE_HKCTL2_REG 0x09
#define ISABELLE_HKCTL3_REG 0x0A
#define ISABELLE_ACCDET_STATUS_REG 0x0B
#define ISABELLE_BUTTON_ID_REG 0x0C
#define ISABELLE_PLL_CFG_REG 0x10
#define ISABELLE_PLL_EN_REG 0x11
#define ISABELLE_FS_RATE_CFG_REG 0x12
#define ISABELLE_INTF_CFG_REG 0x13
#define ISABELLE_INTF_EN_REG 0x14
#define ISABELLE_ULATX12_INTF_CFG_REG 0x15
#define ISABELLE_DL12_INTF_CFG_REG 0x16
#define ISABELLE_DL34_INTF_CFG_REG 0x17
#define ISABELLE_DL56_INTF_CFG_REG 0x18
#define ISABELLE_ATX_STPGA1_CFG_REG 0x19
#define ISABELLE_ATX_STPGA2_CFG_REG 0x1A
#define ISABELLE_VTX_STPGA1_CFG_REG 0x1B
#define ISABELLE_VTX2_STPGA2_CFG_REG 0x1C
#define ISABELLE_ATX1_DPGA_REG 0x1D
#define ISABELLE_ATX2_DPGA_REG 0x1E
#define ISABELLE_VTX1_DPGA_REG 0x1F
#define ISABELLE_VTX2_DPGA_REG 0x20
#define ISABELLE_TX_INPUT_CFG_REG 0x21
#define ISABELLE_RX_INPUT_CFG_REG 0x22
#define ISABELLE_RX_INPUT_CFG2_REG 0x23
#define ISABELLE_VOICE_HPF_CFG_REG 0x24
#define ISABELLE_AUDIO_HPF_CFG_REG 0x25
#define ISABELLE_RX1_DPGA_REG 0x26
#define ISABELLE_RX2_DPGA_REG 0x27
#define ISABELLE_RX3_DPGA_REG 0x28
#define ISABELLE_RX4_DPGA_REG 0x29
#define ISABELLE_RX5_DPGA_REG 0x2A
#define ISABELLE_RX6_DPGA_REG 0x2B
#define ISABELLE_ALU_TX_EN_REG 0x2C
#define ISABELLE_ALU_RX_EN_REG 0x2D
#define ISABELLE_IIR_RESYNC_REG 0x2E
#define ISABELLE_ABIAS_CFG_REG 0x30
#define ISABELLE_DBIAS_CFG_REG 0x31
#define ISABELLE_MIC1_GAIN_REG 0x32
#define ISABELLE_MIC2_GAIN_REG 0x33
#define ISABELLE_AMIC_CFG_REG 0x34
#define ISABELLE_DMIC_CFG_REG 0x35
#define ISABELLE_APGA_GAIN_REG 0x36
#define ISABELLE_APGA_CFG_REG 0x37
#define ISABELLE_TX_GAIN_DLY_REG 0x38
#define ISABELLE_RX_GAIN_DLY_REG 0x39
#define ISABELLE_RX_PWR_CTRL_REG 0x3A
#define ISABELLE_DPGA1LR_IN_SEL_REG 0x3B
#define ISABELLE_DPGA1L_GAIN_REG 0x3C
#define ISABELLE_DPGA1R_GAIN_REG 0x3D
#define ISABELLE_DPGA2L_IN_SEL_REG 0x3E
#define ISABELLE_DPGA2R_IN_SEL_REG 0x3F
#define ISABELLE_DPGA2L_GAIN_REG 0x40
#define ISABELLE_DPGA2R_GAIN_REG 0x41
#define ISABELLE_DPGA3LR_IN_SEL_REG 0x42
#define ISABELLE_DPGA3L_GAIN_REG 0x43
#define ISABELLE_DPGA3R_GAIN_REG 0x44
#define ISABELLE_DAC1_SOFTRAMP_REG 0x45
#define ISABELLE_DAC2_SOFTRAMP_REG 0x46
#define ISABELLE_DAC3_SOFTRAMP_REG 0x47
#define ISABELLE_DAC_CFG_REG 0x48
#define ISABELLE_EARDRV_CFG1_REG 0x49
#define ISABELLE_EARDRV_CFG2_REG 0x4A
#define ISABELLE_HSDRV_GAIN_REG 0x4B
#define ISABELLE_HSDRV_CFG1_REG 0x4C
#define ISABELLE_HSDRV_CFG2_REG 0x4D
#define ISABELLE_HS_NG_CFG1_REG 0x4E
#define ISABELLE_HS_NG_CFG2_REG 0x4F
#define ISABELLE_LINEAMP_GAIN_REG 0x50
#define ISABELLE_LINEAMP_CFG_REG 0x51
#define ISABELLE_HFL_VOL_CTRL_REG 0x52
#define ISABELLE_HFL_SFTVOL_CTRL_REG 0x53
#define ISABELLE_HFL_LIM_CTRL_1_REG 0x54
#define ISABELLE_HFL_LIM_CTRL_2_REG 0x55
#define ISABELLE_HFR_VOL_CTRL_REG 0x56
#define ISABELLE_HFR_SFTVOL_CTRL_REG 0x57
#define ISABELLE_HFR_LIM_CTRL_1_REG 0x58
#define ISABELLE_HFR_LIM_CTRL_2_REG 0x59
#define ISABELLE_HF_MODE_REG 0x5A
#define ISABELLE_HFLPGA_CFG_REG 0x5B
#define ISABELLE_HFRPGA_CFG_REG 0x5C
#define ISABELLE_HFDRV_CFG_REG 0x5D
#define ISABELLE_PDMOUT_CFG1_REG 0x5E
#define ISABELLE_PDMOUT_CFG2_REG 0x5F
#define ISABELLE_PDMOUT_L_WM_REG 0x60
#define ISABELLE_PDMOUT_R_WM_REG 0x61
#define ISABELLE_HF_NG_CFG1_REG 0x62
#define ISABELLE_HF_NG_CFG2_REG 0x63
/* ISABELLE_PWR_EN_REG (0x02h) */
#define ISABELLE_CHIP_EN BIT(0)
/* ISABELLE DAI FORMATS */
#define ISABELLE_AIF_FMT_MASK 0x70
#define ISABELLE_I2S_MODE 0x0
#define ISABELLE_LEFT_J_MODE 0x1
#define ISABELLE_PDM_MODE 0x2
#define ISABELLE_AIF_LENGTH_MASK 0x30
#define ISABELLE_AIF_LENGTH_20 0x00
#define ISABELLE_AIF_LENGTH_32 0x10
#define ISABELLE_AIF_MS 0x80
#define ISABELLE_FS_RATE_MASK 0xF
#define ISABELLE_FS_RATE_8 0x0
#define ISABELLE_FS_RATE_11 0x1
#define ISABELLE_FS_RATE_12 0x2
#define ISABELLE_FS_RATE_16 0x4
#define ISABELLE_FS_RATE_22 0x5
#define ISABELLE_FS_RATE_24 0x6
#define ISABELLE_FS_RATE_32 0x8
#define ISABELLE_FS_RATE_44 0x9
#define ISABELLE_FS_RATE_48 0xA
#define ISABELLE_MAX_REGISTER 0xFF
#endif

View File

@ -12,7 +12,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/version.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/delay.h> #include <linux/delay.h>
@ -1358,7 +1357,7 @@ static struct snd_soc_dai_ops lm49453_lineout_dai_ops = {
}; };
/* LM49453 dai structure. */ /* LM49453 dai structure. */
static const struct snd_soc_dai_driver lm49453_dai[] = { static struct snd_soc_dai_driver lm49453_dai[] = {
{ {
.name = "LM49453 Headset", .name = "LM49453 Headset",
.playback = { .playback = {

View File

@ -2216,7 +2216,7 @@ static irqreturn_t max98095_report_jack(int irq, void *data)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
int max98095_jack_detect_enable(struct snd_soc_codec *codec) static int max98095_jack_detect_enable(struct snd_soc_codec *codec)
{ {
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
int ret = 0; int ret = 0;
@ -2245,7 +2245,7 @@ int max98095_jack_detect_enable(struct snd_soc_codec *codec)
return ret; return ret;
} }
int max98095_jack_detect_disable(struct snd_soc_codec *codec) static int max98095_jack_detect_disable(struct snd_soc_codec *codec)
{ {
int ret = 0; int ret = 0;
@ -2286,6 +2286,7 @@ int max98095_jack_detect(struct snd_soc_codec *codec,
max98095_report_jack(client->irq, codec); max98095_report_jack(client->irq, codec);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(max98095_jack_detect);
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int max98095_suspend(struct snd_soc_codec *codec) static int max98095_suspend(struct snd_soc_codec *codec)

View File

@ -638,7 +638,7 @@ static __devinit int ml26124_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, priv); i2c_set_clientdata(i2c, priv);
priv->regmap = regmap_init_i2c(i2c, &ml26124_i2c_regmap); priv->regmap = devm_regmap_init_i2c(i2c, &ml26124_i2c_regmap);
if (IS_ERR(priv->regmap)) { if (IS_ERR(priv->regmap)) {
ret = PTR_ERR(priv->regmap); ret = PTR_ERR(priv->regmap);
dev_err(&i2c->dev, "regmap_init_i2c() failed: %d\n", ret); dev_err(&i2c->dev, "regmap_init_i2c() failed: %d\n", ret);
@ -651,10 +651,7 @@ static __devinit int ml26124_i2c_probe(struct i2c_client *i2c,
static __devexit int ml26124_i2c_remove(struct i2c_client *client) static __devexit int ml26124_i2c_remove(struct i2c_client *client)
{ {
struct ml26124_priv *priv = i2c_get_clientdata(client);
snd_soc_unregister_codec(&client->dev); snd_soc_unregister_codec(&client->dev);
regmap_exit(priv->regmap);
return 0; return 0;
} }

View File

@ -0,0 +1,67 @@
/*
* ALSA SoC SPDIF DIR (Digital Interface Reciever) driver
*
* Based on ALSA SoC SPDIF DIT driver
*
* This driver is used by controllers which can operate in DIR (SPDI/F) where
* no codec is needed. This file provides stub codec that can be used
* in these configurations. SPEAr SPDIF IN Audio controller uses this driver.
*
* Author: Vipin Kumar, <vipin.kumar@st.com>
* Copyright: (C) 2012 ST Microelectronics
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <sound/soc.h>
#include <sound/pcm.h>
#include <sound/initval.h>
#define STUB_RATES SNDRV_PCM_RATE_8000_192000
#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
static struct snd_soc_codec_driver soc_codec_spdif_dir;
static struct snd_soc_dai_driver dir_stub_dai = {
.name = "dir-hifi",
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 384,
.rates = STUB_RATES,
.formats = STUB_FORMATS,
},
};
static int spdif_dir_probe(struct platform_device *pdev)
{
return snd_soc_register_codec(&pdev->dev, &soc_codec_spdif_dir,
&dir_stub_dai, 1);
}
static int spdif_dir_remove(struct platform_device *pdev)
{
snd_soc_unregister_codec(&pdev->dev);
return 0;
}
static struct platform_driver spdif_dir_driver = {
.probe = spdif_dir_probe,
.remove = spdif_dir_remove,
.driver = {
.name = "spdif-dir",
.owner = THIS_MODULE,
},
};
module_platform_driver(spdif_dir_driver);
MODULE_DESCRIPTION("ASoC SPDIF DIR driver");
MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>");
MODULE_LICENSE("GPL");

442
sound/soc/codecs/sta529.c Normal file
View File

@ -0,0 +1,442 @@
/*
* ASoC codec driver for spear platform
*
* sound/soc/codecs/sta529.c -- spear ALSA Soc codec driver
*
* Copyright (C) 2012 ST Microelectronics
* Rajeev Kumar <rajeev-dlh.kumar@st.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/clk.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pm.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
/* STA529 Register offsets */
#define STA529_FFXCFG0 0x00
#define STA529_FFXCFG1 0x01
#define STA529_MVOL 0x02
#define STA529_LVOL 0x03
#define STA529_RVOL 0x04
#define STA529_TTF0 0x05
#define STA529_TTF1 0x06
#define STA529_TTP0 0x07
#define STA529_TTP1 0x08
#define STA529_S2PCFG0 0x0A
#define STA529_S2PCFG1 0x0B
#define STA529_P2SCFG0 0x0C
#define STA529_P2SCFG1 0x0D
#define STA529_PLLCFG0 0x14
#define STA529_PLLCFG1 0x15
#define STA529_PLLCFG2 0x16
#define STA529_PLLCFG3 0x17
#define STA529_PLLPFE 0x18
#define STA529_PLLST 0x19
#define STA529_ADCCFG 0x1E /*mic_select*/
#define STA529_CKOCFG 0x1F
#define STA529_MISC 0x20
#define STA529_PADST0 0x21
#define STA529_PADST1 0x22
#define STA529_FFXST 0x23
#define STA529_PWMIN1 0x2D
#define STA529_PWMIN2 0x2E
#define STA529_POWST 0x32
#define STA529_MAX_REGISTER 0x32
#define STA529_RATES (SNDRV_PCM_RATE_8000 | \
SNDRV_PCM_RATE_11025 | \
SNDRV_PCM_RATE_16000 | \
SNDRV_PCM_RATE_22050 | \
SNDRV_PCM_RATE_32000 | \
SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000)
#define STA529_FORMAT (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
#define S2PC_VALUE 0x98
#define CLOCK_OUT 0x60
#define LEFT_J_DATA_FORMAT 0x10
#define I2S_DATA_FORMAT 0x12
#define RIGHT_J_DATA_FORMAT 0x14
#define CODEC_MUTE_VAL 0x80
#define POWER_CNTLMSAK 0x40
#define POWER_STDBY 0x40
#define FFX_MASK 0x80
#define FFX_OFF 0x80
#define POWER_UP 0x00
#define FFX_CLK_ENB 0x01
#define FFX_CLK_DIS 0x00
#define FFX_CLK_MSK 0x01
#define PLAY_FREQ_RANGE_MSK 0x70
#define CAP_FREQ_RANGE_MSK 0x0C
#define PDATA_LEN_MSK 0xC0
#define BCLK_TO_FS_MSK 0x30
#define AUDIO_MUTE_MSK 0x80
static const struct reg_default sta529_reg_defaults[] = {
{ 0, 0x35 }, /* R0 - FFX Configuration reg 0 */
{ 1, 0xc8 }, /* R1 - FFX Configuration reg 1 */
{ 2, 0x50 }, /* R2 - Master Volume */
{ 3, 0x00 }, /* R3 - Left Volume */
{ 4, 0x00 }, /* R4 - Right Volume */
{ 10, 0xb2 }, /* R10 - S2P Config Reg 0 */
{ 11, 0x41 }, /* R11 - S2P Config Reg 1 */
{ 12, 0x92 }, /* R12 - P2S Config Reg 0 */
{ 13, 0x41 }, /* R13 - P2S Config Reg 1 */
{ 30, 0xd2 }, /* R30 - ADC Config Reg */
{ 31, 0x40 }, /* R31 - clock Out Reg */
{ 32, 0x21 }, /* R32 - Misc Register */
};
struct sta529 {
struct regmap *regmap;
};
static bool sta529_readable(struct device *dev, unsigned int reg)
{
switch (reg) {
case STA529_FFXCFG0:
case STA529_FFXCFG1:
case STA529_MVOL:
case STA529_LVOL:
case STA529_RVOL:
case STA529_S2PCFG0:
case STA529_S2PCFG1:
case STA529_P2SCFG0:
case STA529_P2SCFG1:
case STA529_ADCCFG:
case STA529_CKOCFG:
case STA529_MISC:
return true;
default:
return false;
}
}
static const char *pwm_mode_text[] = { "Binary", "Headphone", "Ternary",
"Phase-shift"};
static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -9150, 50, 0);
static const DECLARE_TLV_DB_SCALE(master_vol_tlv, -12750, 50, 0);
static const SOC_ENUM_SINGLE_DECL(pwm_src, STA529_FFXCFG1, 4, pwm_mode_text);
static const struct snd_kcontrol_new sta529_snd_controls[] = {
SOC_DOUBLE_R_TLV("Digital Playback Volume", STA529_LVOL, STA529_RVOL, 0,
127, 0, out_gain_tlv),
SOC_SINGLE_TLV("Master Playback Volume", STA529_MVOL, 0, 127, 1,
master_vol_tlv),
SOC_ENUM("PWM Select", pwm_src),
};
static int sta529_set_bias_level(struct snd_soc_codec *codec, enum
snd_soc_bias_level level)
{
struct sta529 *sta529 = snd_soc_codec_get_drvdata(codec);
switch (level) {
case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE:
snd_soc_update_bits(codec, STA529_FFXCFG0, POWER_CNTLMSAK,
POWER_UP);
snd_soc_update_bits(codec, STA529_MISC, FFX_CLK_MSK,
FFX_CLK_ENB);
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
regcache_sync(sta529->regmap);
snd_soc_update_bits(codec, STA529_FFXCFG0,
POWER_CNTLMSAK, POWER_STDBY);
/* Making FFX output to zero */
snd_soc_update_bits(codec, STA529_FFXCFG0, FFX_MASK,
FFX_OFF);
snd_soc_update_bits(codec, STA529_MISC, FFX_CLK_MSK,
FFX_CLK_DIS);
break;
case SND_SOC_BIAS_OFF:
break;
}
/*
* store the label for powers down audio subsystem for suspend.This is
* used by soc core layer
*/
codec->dapm.bias_level = level;
return 0;
}
static int sta529_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;
int pdata, play_freq_val, record_freq_val;
int bclk_to_fs_ratio;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
pdata = 1;
bclk_to_fs_ratio = 0;
break;
case SNDRV_PCM_FORMAT_S24_LE:
pdata = 2;
bclk_to_fs_ratio = 1;
break;
case SNDRV_PCM_FORMAT_S32_LE:
pdata = 3;
bclk_to_fs_ratio = 2;
break;
default:
dev_err(codec->dev, "Unsupported format\n");
return -EINVAL;
}
switch (params_rate(params)) {
case 8000:
case 11025:
play_freq_val = 0;
record_freq_val = 2;
break;
case 16000:
case 22050:
play_freq_val = 1;
record_freq_val = 0;
break;
case 32000:
case 44100:
case 48000:
play_freq_val = 2;
record_freq_val = 0;
break;
default:
dev_err(codec->dev, "Unsupported rate\n");
return -EINVAL;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
snd_soc_update_bits(codec, STA529_S2PCFG1, PDATA_LEN_MSK,
pdata << 6);
snd_soc_update_bits(codec, STA529_S2PCFG1, BCLK_TO_FS_MSK,
bclk_to_fs_ratio << 4);
snd_soc_update_bits(codec, STA529_MISC, PLAY_FREQ_RANGE_MSK,
play_freq_val << 4);
} else {
snd_soc_update_bits(codec, STA529_P2SCFG1, PDATA_LEN_MSK,
pdata << 6);
snd_soc_update_bits(codec, STA529_P2SCFG1, BCLK_TO_FS_MSK,
bclk_to_fs_ratio << 4);
snd_soc_update_bits(codec, STA529_MISC, CAP_FREQ_RANGE_MSK,
record_freq_val << 2);
}
return 0;
}
static int sta529_mute(struct snd_soc_dai *dai, int mute)
{
u8 val = 0;
if (mute)
val |= CODEC_MUTE_VAL;
snd_soc_update_bits(dai->codec, STA529_FFXCFG0, AUDIO_MUTE_MSK, val);
return 0;
}
static int sta529_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
u8 mode = 0;
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_LEFT_J:
mode = LEFT_J_DATA_FORMAT;
break;
case SND_SOC_DAIFMT_I2S:
mode = I2S_DATA_FORMAT;
break;
case SND_SOC_DAIFMT_RIGHT_J:
mode = RIGHT_J_DATA_FORMAT;
break;
default:
return -EINVAL;
}
snd_soc_update_bits(codec, STA529_S2PCFG0, 0x0D, mode);
return 0;
}
static const struct snd_soc_dai_ops sta529_dai_ops = {
.hw_params = sta529_hw_params,
.set_fmt = sta529_set_dai_fmt,
.digital_mute = sta529_mute,
};
static struct snd_soc_dai_driver sta529_dai = {
.name = "sta529-audio",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
.channels_max = 2,
.rates = STA529_RATES,
.formats = STA529_FORMAT,
},
.capture = {
.stream_name = "Capture",
.channels_min = 2,
.channels_max = 2,
.rates = STA529_RATES,
.formats = STA529_FORMAT,
},
.ops = &sta529_dai_ops,
};
static int sta529_probe(struct snd_soc_codec *codec)
{
struct sta529 *sta529 = snd_soc_codec_get_drvdata(codec);
int ret;
codec->control_data = sta529->regmap;
ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
/* power down chip */
static int sta529_remove(struct snd_soc_codec *codec)
{
sta529_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static int sta529_suspend(struct snd_soc_codec *codec)
{
sta529_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static int sta529_resume(struct snd_soc_codec *codec)
{
sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
struct snd_soc_codec_driver sta529_codec_driver = {
.probe = sta529_probe,
.remove = sta529_remove,
.set_bias_level = sta529_set_bias_level,
.suspend = sta529_suspend,
.resume = sta529_resume,
.controls = sta529_snd_controls,
.num_controls = ARRAY_SIZE(sta529_snd_controls),
};
static const struct regmap_config sta529_regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = STA529_MAX_REGISTER,
.readable_reg = sta529_readable,
.cache_type = REGCACHE_RBTREE,
.reg_defaults = sta529_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(sta529_reg_defaults),
};
static __devinit int sta529_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct sta529 *sta529;
int ret;
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EINVAL;
sta529 = devm_kzalloc(&i2c->dev, sizeof(struct sta529), GFP_KERNEL);
if (sta529 == NULL) {
dev_err(&i2c->dev, "Can not allocate memory\n");
return -ENOMEM;
}
sta529->regmap = devm_regmap_init_i2c(i2c, &sta529_regmap);
if (IS_ERR(sta529->regmap)) {
ret = PTR_ERR(sta529->regmap);
dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
return ret;
}
i2c_set_clientdata(i2c, sta529);
ret = snd_soc_register_codec(&i2c->dev,
&sta529_codec_driver, &sta529_dai, 1);
if (ret != 0)
dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
return ret;
}
static int __devexit sta529_i2c_remove(struct i2c_client *client)
{
snd_soc_unregister_codec(&client->dev);
return 0;
}
static const struct i2c_device_id sta529_i2c_id[] = {
{ "sta529", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, sta529_i2c_id);
static struct i2c_driver sta529_i2c_driver = {
.driver = {
.name = "sta529",
.owner = THIS_MODULE,
},
.probe = sta529_i2c_probe,
.remove = __devexit_p(sta529_i2c_remove),
.id_table = sta529_i2c_id,
};
module_i2c_driver(sta529_i2c_driver);
MODULE_DESCRIPTION("ASoC STA529 codec driver");
MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");
MODULE_LICENSE("GPL");

View File

@ -118,7 +118,9 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = {
0x00, 0x00, 0x00, 0x00, /* 88 */ 0x00, 0x00, 0x00, 0x00, /* 88 */
0x00, 0x00, 0x00, 0x00, /* 92 */ 0x00, 0x00, 0x00, 0x00, /* 92 */
0x00, 0x00, 0x00, 0x00, /* 96 */ 0x00, 0x00, 0x00, 0x00, /* 96 */
0x00, 0x00, 0x02, /* 100 */ 0x00, 0x00, 0x02, 0x00, /* 100 */
0x00, 0x00, 0x00, 0x00, /* 104 */
0x00, 0x00, /* 108 */
}; };
#define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \
@ -229,6 +231,25 @@ static const struct soc_enum aic3x_enum[] = {
SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf), SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf),
}; };
static const char *aic3x_agc_level[] =
{ "-5.5dB", "-8dB", "-10dB", "-12dB", "-14dB", "-17dB", "-20dB", "-24dB" };
static const struct soc_enum aic3x_agc_level_enum[] = {
SOC_ENUM_SINGLE(LAGC_CTRL_A, 4, 8, aic3x_agc_level),
SOC_ENUM_SINGLE(RAGC_CTRL_A, 4, 8, aic3x_agc_level),
};
static const char *aic3x_agc_attack[] = { "8ms", "11ms", "16ms", "20ms" };
static const struct soc_enum aic3x_agc_attack_enum[] = {
SOC_ENUM_SINGLE(LAGC_CTRL_A, 2, 4, aic3x_agc_attack),
SOC_ENUM_SINGLE(RAGC_CTRL_A, 2, 4, aic3x_agc_attack),
};
static const char *aic3x_agc_decay[] = { "100ms", "200ms", "400ms", "500ms" };
static const struct soc_enum aic3x_agc_decay_enum[] = {
SOC_ENUM_SINGLE(LAGC_CTRL_A, 0, 4, aic3x_agc_decay),
SOC_ENUM_SINGLE(RAGC_CTRL_A, 0, 4, aic3x_agc_decay),
};
/* /*
* DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps * DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps
*/ */
@ -353,6 +374,15 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
* adjust PGA to max value when ADC is on and will never go back. * adjust PGA to max value when ADC is on and will never go back.
*/ */
SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0), SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0),
SOC_ENUM("Left AGC Target level", aic3x_agc_level_enum[0]),
SOC_ENUM("Right AGC Target level", aic3x_agc_level_enum[1]),
SOC_ENUM("Left AGC Attack time", aic3x_agc_attack_enum[0]),
SOC_ENUM("Right AGC Attack time", aic3x_agc_attack_enum[1]),
SOC_ENUM("Left AGC Decay time", aic3x_agc_decay_enum[0]),
SOC_ENUM("Right AGC Decay time", aic3x_agc_decay_enum[1]),
/* De-emphasis */
SOC_DOUBLE("De-emphasis Switch", AIC3X_CODEC_DFILT_CTRL, 2, 0, 0x01, 0),
/* Input */ /* Input */
SOC_DOUBLE_R_TLV("PGA Capture Volume", LADC_VOL, RADC_VOL, SOC_DOUBLE_R_TLV("PGA Capture Volume", LADC_VOL, RADC_VOL,
@ -368,7 +398,7 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
static DECLARE_TLV_DB_SCALE(classd_amp_tlv, 0, 600, 0); static DECLARE_TLV_DB_SCALE(classd_amp_tlv, 0, 600, 0);
static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl = static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl =
SOC_DOUBLE_TLV("Class-D Amplifier Gain", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv); SOC_DOUBLE_TLV("Class-D Playback Volume", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv);
/* Left DAC Mux */ /* Left DAC Mux */
static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = static const struct snd_kcontrol_new aic3x_left_dac_mux_controls =
@ -970,6 +1000,12 @@ static int aic3x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
/* set clock on MCLK or GPIO2 or BCLK */
snd_soc_update_bits(codec, AIC3X_CLKGEN_CTRL_REG, PLLCLK_IN_MASK,
clk_id << PLLCLK_IN_SHIFT);
snd_soc_update_bits(codec, AIC3X_CLKGEN_CTRL_REG, CLKDIV_IN_MASK,
clk_id << CLKDIV_IN_SHIFT);
aic3x->sysclk = freq; aic3x->sysclk = freq;
return 0; return 0;
} }

View File

@ -13,7 +13,7 @@
#define _AIC3X_H #define _AIC3X_H
/* AIC3X register space */ /* AIC3X register space */
#define AIC3X_CACHEREGNUM 103 #define AIC3X_CACHEREGNUM 110
/* Page select register */ /* Page select register */
#define AIC3X_PAGE_SELECT 0 #define AIC3X_PAGE_SELECT 0
@ -74,6 +74,8 @@
#define HPLCOM_CFG 37 #define HPLCOM_CFG 37
/* Right High Power Output control registers */ /* Right High Power Output control registers */
#define HPRCOM_CFG 38 #define HPRCOM_CFG 38
/* High Power Output Stage Control Register */
#define HPOUT_SC 40
/* DAC Output Switching control registers */ /* DAC Output Switching control registers */
#define DAC_LINE_MUX 41 #define DAC_LINE_MUX 41
/* High Power Output Driver Pop Reduction registers */ /* High Power Output Driver Pop Reduction registers */
@ -148,6 +150,17 @@
#define AIC3X_GPIOB_REG 101 #define AIC3X_GPIOB_REG 101
/* Clock generation control register */ /* Clock generation control register */
#define AIC3X_CLKGEN_CTRL_REG 102 #define AIC3X_CLKGEN_CTRL_REG 102
/* New AGC registers */
#define LAGCN_ATTACK 103
#define LAGCN_DECAY 104
#define RAGCN_ATTACK 105
#define RAGCN_DECAY 106
/* New Programmable ADC Digital Path and I2C Bus Condition Register */
#define NEW_ADC_DIGITALPATH 107
/* Passive Analog Signal Bypass Selection During Powerdown Register */
#define PASSIVE_BYPASS 108
/* DAC Quiescent Current Adjustment Register */
#define DAC_ICC_ADJ 109
/* Page select register bits */ /* Page select register bits */
#define PAGE0_SELECT 0 #define PAGE0_SELECT 0
@ -163,6 +176,10 @@
#define DUAL_RATE_MODE ((1 << 5) | (1 << 6)) #define DUAL_RATE_MODE ((1 << 5) | (1 << 6))
#define LDAC2LCH (0x1 << 3) #define LDAC2LCH (0x1 << 3)
#define RDAC2RCH (0x1 << 1) #define RDAC2RCH (0x1 << 1)
#define LDAC2RCH (0x2 << 3)
#define RDAC2LCH (0x2 << 1)
#define LDAC2MONOMIX (0x3 << 3)
#define RDAC2MONOMIX (0x3 << 1)
/* PLL registers bitfields */ /* PLL registers bitfields */
#define PLLP_SHIFT 0 #define PLLP_SHIFT 0
@ -179,6 +196,14 @@
#define PLL_CLKIN_SHIFT 4 #define PLL_CLKIN_SHIFT 4
#define MCLK_SOURCE 0x0 #define MCLK_SOURCE 0x0
#define PLL_CLKDIV_SHIFT 0 #define PLL_CLKDIV_SHIFT 0
#define PLLCLK_IN_MASK 0x30
#define PLLCLK_IN_SHIFT 4
#define CLKDIV_IN_MASK 0xc0
#define CLKDIV_IN_SHIFT 6
/* clock in source */
#define CLKIN_MCLK 0
#define CLKIN_GPIO2 1
#define CLKIN_BCLK 2
/* Software reset register bits */ /* Software reset register bits */
#define SOFT_RESET 0x80 #define SOFT_RESET 0x80

View File

@ -553,7 +553,7 @@ static const struct snd_kcontrol_new vibrar_mux_controls =
/* Headset power mode */ /* Headset power mode */
static const char *twl6040_power_mode_texts[] = { static const char *twl6040_power_mode_texts[] = {
"Low-Power", "High-Perfomance", "Low-Power", "High-Performance",
}; };
static const struct soc_enum twl6040_power_mode_enum = static const struct soc_enum twl6040_power_mode_enum =

View File

@ -121,20 +121,23 @@ static const struct snd_soc_dai_ops wm1250_ev1_ops = {
.hw_params = wm1250_ev1_hw_params, .hw_params = wm1250_ev1_hw_params,
}; };
#define WM1250_EV1_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_64000)
static struct snd_soc_dai_driver wm1250_ev1_dai = { static struct snd_soc_dai_driver wm1250_ev1_dai = {
.name = "wm1250-ev1", .name = "wm1250-ev1",
.playback = { .playback = {
.stream_name = "Playback", .stream_name = "Playback",
.channels_min = 1, .channels_min = 1,
.channels_max = 2, .channels_max = 2,
.rates = SNDRV_PCM_RATE_8000, .rates = WM1250_EV1_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE, .formats = SNDRV_PCM_FMTBIT_S16_LE,
}, },
.capture = { .capture = {
.stream_name = "Capture", .stream_name = "Capture",
.channels_min = 1, .channels_min = 1,
.channels_max = 2, .channels_max = 2,
.rates = SNDRV_PCM_RATE_8000, .rates = WM1250_EV1_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE, .formats = SNDRV_PCM_FMTBIT_S16_LE,
}, },
.ops = &wm1250_ev1_ops, .ops = &wm1250_ev1_ops,

View File

@ -1,7 +1,7 @@
/* /*
* wm2000.c -- WM2000 ALSA Soc Audio driver * wm2000.c -- WM2000 ALSA Soc Audio driver
* *
* Copyright 2008-2010 Wolfson Microelectronics PLC. * Copyright 2008-2011 Wolfson Microelectronics PLC.
* *
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
* *
@ -674,9 +674,39 @@ static int wm2000_resume(struct snd_soc_codec *codec)
#define wm2000_resume NULL #define wm2000_resume NULL
#endif #endif
static bool wm2000_readable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case WM2000_REG_SYS_START:
case WM2000_REG_SPEECH_CLARITY:
case WM2000_REG_SYS_WATCHDOG:
case WM2000_REG_ANA_VMID_PD_TIME:
case WM2000_REG_ANA_VMID_PU_TIME:
case WM2000_REG_CAT_FLTR_INDX:
case WM2000_REG_CAT_GAIN_0:
case WM2000_REG_SYS_STATUS:
case WM2000_REG_SYS_MODE_CNTRL:
case WM2000_REG_SYS_START0:
case WM2000_REG_SYS_START1:
case WM2000_REG_ID1:
case WM2000_REG_ID2:
case WM2000_REG_REVISON:
case WM2000_REG_SYS_CTL1:
case WM2000_REG_SYS_CTL2:
case WM2000_REG_ANC_STAT:
case WM2000_REG_IF_CTL:
return true;
default:
return false;
}
}
static const struct regmap_config wm2000_regmap = { static const struct regmap_config wm2000_regmap = {
.reg_bits = 8, .reg_bits = 8,
.val_bits = 8, .val_bits = 8,
.max_register = WM2000_REG_IF_CTL,
.readable_reg = wm2000_readable_reg,
}; };
static int wm2000_probe(struct snd_soc_codec *codec) static int wm2000_probe(struct snd_soc_codec *codec)

View File

@ -1,7 +1,7 @@
/* /*
* wm5100-tables.c -- WM5100 ALSA SoC Audio driver data * wm5100-tables.c -- WM5100 ALSA SoC Audio driver data
* *
* Copyright 2011 Wolfson Microelectronics plc * Copyright 2011-2 Wolfson Microelectronics plc
* *
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
* *

View File

@ -1,7 +1,7 @@
/* /*
* wm5100.c -- WM5100 ALSA SoC Audio driver * wm5100.c -- WM5100 ALSA SoC Audio driver
* *
* Copyright 2011 Wolfson Microelectronics plc * Copyright 2011-2 Wolfson Microelectronics plc
* *
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
* *
@ -2378,13 +2378,6 @@ static int wm5100_remove(struct snd_soc_codec *codec)
return 0; return 0;
} }
static int wm5100_soc_volatile(struct snd_soc_codec *codec,
unsigned int reg)
{
return true;
}
static struct snd_soc_codec_driver soc_codec_dev_wm5100 = { static struct snd_soc_codec_driver soc_codec_dev_wm5100 = {
.probe = wm5100_probe, .probe = wm5100_probe,
.remove = wm5100_remove, .remove = wm5100_remove,
@ -2392,8 +2385,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5100 = {
.set_sysclk = wm5100_set_sysclk, .set_sysclk = wm5100_set_sysclk,
.set_pll = wm5100_set_fll, .set_pll = wm5100_set_fll,
.idle_bias_off = 1, .idle_bias_off = 1,
.reg_cache_size = WM5100_MAX_REGISTER,
.volatile_register = wm5100_soc_volatile,
.seq_notifier = wm5100_seq_notifier, .seq_notifier = wm5100_seq_notifier,
.controls = wm5100_snd_controls, .controls = wm5100_snd_controls,

903
sound/soc/codecs/wm5102.c Normal file
View File

@ -0,0 +1,903 @@
/*
* wm5102.c -- WM5102 ALSA SoC Audio driver
*
* Copyright 2012 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <linux/mfd/arizona/core.h>
#include <linux/mfd/arizona/registers.h>
#include "arizona.h"
#include "wm5102.h"
struct wm5102_priv {
struct arizona_priv core;
struct arizona_fll fll[2];
};
static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0);
static const struct snd_kcontrol_new wm5102_snd_controls[] = {
SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL,
ARIZONA_IN1_OSR_SHIFT, 1, 0),
SOC_SINGLE("IN2 High Performance Switch", ARIZONA_IN2L_CONTROL,
ARIZONA_IN2_OSR_SHIFT, 1, 0),
SOC_SINGLE("IN3 High Performance Switch", ARIZONA_IN3L_CONTROL,
ARIZONA_IN3_OSR_SHIFT, 1, 0),
SOC_DOUBLE_R_RANGE_TLV("IN1 Volume", ARIZONA_IN1L_CONTROL,
ARIZONA_IN1R_CONTROL,
ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_DOUBLE_R_RANGE_TLV("IN2 Volume", ARIZONA_IN2L_CONTROL,
ARIZONA_IN2R_CONTROL,
ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_DOUBLE_R_RANGE_TLV("IN3 Volume", ARIZONA_IN3L_CONTROL,
ARIZONA_IN3R_CONTROL,
ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_DOUBLE_R("IN1 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_1L,
ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("IN2 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_2L,
ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("IN3 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_3L,
ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R_TLV("IN1 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_DIG_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_DOUBLE_R_TLV("IN2 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_DIG_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_DOUBLE_R_TLV("IN3 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L,
ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_DIG_VOL_SHIFT,
0xbf, 0, digital_tlv),
ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ1 B3 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B3_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 B3 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B3_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 B3 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B3_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 B3 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B3_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 B4 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B4_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 B5 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B5_GAIN_SHIFT,
24, 0, eq_tlv),
ARIZONA_MIXER_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("DRC2L", ARIZONA_DRC2LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("DRC2R", ARIZONA_DRC2RMIX_INPUT_1_SOURCE),
SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5,
ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA),
SND_SOC_BYTES_MASK("DRC2", ARIZONA_DRC2_CTRL1, 5,
ARIZONA_DRC2R_ENA | ARIZONA_DRC2L_ENA),
ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE),
SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode),
SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE),
SOC_SINGLE_TLV("Noise Generator Volume", ARIZONA_COMFORT_NOISE_GENERATOR,
ARIZONA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, noise_tlv),
ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("HPOUT2L", ARIZONA_OUT2LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("HPOUT2R", ARIZONA_OUT2RMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EPOUT", ARIZONA_OUT3LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("SPKOUTL", ARIZONA_OUT4LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE),
SOC_SINGLE("HPOUT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_1L,
ARIZONA_OUT1_OSR_SHIFT, 1, 0),
SOC_SINGLE("OUT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_2L,
ARIZONA_OUT2_OSR_SHIFT, 1, 0),
SOC_SINGLE("EPOUT High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_3L,
ARIZONA_OUT3_OSR_SHIFT, 1, 0),
SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L,
ARIZONA_OUT4_OSR_SHIFT, 1, 0),
SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L,
ARIZONA_OUT5_OSR_SHIFT, 1, 0),
SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("OUT2 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_2L,
ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_MUTE_SHIFT, 1, 1),
SOC_SINGLE("EPOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L,
ARIZONA_OUT3L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L,
ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("SPKDAT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_5L,
ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L,
ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_DOUBLE_R_TLV("OUT2 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_2L,
ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("EPOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L,
ARIZONA_OUT3L_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_DOUBLE_R_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L,
ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,
ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_DOUBLE_R_RANGE_TLV("HPOUT1 Volume", ARIZONA_OUTPUT_PATH_CONFIG_1L,
ARIZONA_OUTPUT_PATH_CONFIG_1R,
ARIZONA_OUT1L_PGA_VOL_SHIFT,
0x34, 0x40, 0, ana_tlv),
SOC_DOUBLE_R_RANGE_TLV("OUT2 Volume", ARIZONA_OUTPUT_PATH_CONFIG_2L,
ARIZONA_OUTPUT_PATH_CONFIG_2R,
ARIZONA_OUT2L_PGA_VOL_SHIFT,
0x34, 0x40, 0, ana_tlv),
SOC_SINGLE_RANGE_TLV("EPOUT Volume", ARIZONA_OUTPUT_PATH_CONFIG_3L,
ARIZONA_OUT3L_PGA_VOL_SHIFT, 0x34, 0x40, 0, ana_tlv),
SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,
ARIZONA_SPK1R_MUTE_SHIFT, 1, 1),
ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF1TX4", ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF1TX5", ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF1TX6", ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF1TX7", ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
};
ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(EQ4, ARIZONA_EQ4MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(DRC2L, ARIZONA_DRC2LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(DRC2R, ARIZONA_DRC2RMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(Mic, ARIZONA_MICMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(Noise, ARIZONA_NOISEMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(PWM1, ARIZONA_PWM1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(PWM2, ARIZONA_PWM2MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(OUT2L, ARIZONA_OUT2LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(OUT2R, ARIZONA_OUT2RMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(OUT3, ARIZONA_OUT3LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(SPKOUTL, ARIZONA_OUT4LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(SPKOUTR, ARIZONA_OUT4RMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(SPKDAT1L, ARIZONA_OUT5LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(SPKDAT1R, ARIZONA_OUT5RMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF1TX1, ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF1TX2, ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF1TX3, ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF1TX4, ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF1TX5, ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF1TX6, ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF1TX7, ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
0, NULL, 0),
SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20),
SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0),
SND_SOC_DAPM_SIGGEN("TONE"),
SND_SOC_DAPM_SIGGEN("NOISE"),
SND_SOC_DAPM_INPUT("IN1L"),
SND_SOC_DAPM_INPUT("IN1R"),
SND_SOC_DAPM_INPUT("IN2L"),
SND_SOC_DAPM_INPUT("IN2R"),
SND_SOC_DAPM_INPUT("IN3L"),
SND_SOC_DAPM_INPUT("IN3R"),
SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
0, NULL, 0, arizona_in_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
0, NULL, 0, arizona_in_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
0, NULL, 0, arizona_in_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
0, NULL, 0, arizona_in_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT,
0, NULL, 0, arizona_in_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT,
0, NULL, 0, arizona_in_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2,
ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("MICBIAS3", ARIZONA_MIC_BIAS_CTRL_3,
ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("Noise Generator", ARIZONA_COMFORT_NOISE_GENERATOR,
ARIZONA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("Tone Generator 1", ARIZONA_TONE_GENERATOR_1,
ARIZONA_TONE1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("Tone Generator 2", ARIZONA_TONE_GENERATOR_1,
ARIZONA_TONE2_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("Mic Mute Mixer", ARIZONA_MIC_NOISE_MIX_CONTROL_1,
ARIZONA_MICMUTE_MIX_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("EQ1", ARIZONA_EQ1_1, ARIZONA_EQ1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("EQ2", ARIZONA_EQ2_1, ARIZONA_EQ2_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("EQ3", ARIZONA_EQ3_1, ARIZONA_EQ3_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("EQ4", ARIZONA_EQ4_1, ARIZONA_EQ4_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("DRC2L", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2L_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("DRC2R", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2R_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("LHPF2", ARIZONA_HPLPF2_1, ARIZONA_LHPF2_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("LHPF3", ARIZONA_HPLPF3_1, ARIZONA_LHPF3_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("LHPF4", ARIZONA_HPLPF4_1, ARIZONA_LHPF4_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("PWM1 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM1_ENA_SHIFT,
0, NULL, 0),
SND_SOC_DAPM_PGA("PWM2 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM2_ENA_SHIFT,
0, NULL, 0),
SND_SOC_DAPM_PGA("ASRC1L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1L_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("ASRC1R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1R_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0,
ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0,
ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0,
ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0,
ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0,
ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0,
ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0,
ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0,
ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0,
ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0,
ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,
ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,
ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0,
ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0,
ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT1R", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT2R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT5R", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT5R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
ARIZONA_MIXER_WIDGETS(EQ1, "EQ1"),
ARIZONA_MIXER_WIDGETS(EQ2, "EQ2"),
ARIZONA_MIXER_WIDGETS(EQ3, "EQ3"),
ARIZONA_MIXER_WIDGETS(EQ4, "EQ4"),
ARIZONA_MIXER_WIDGETS(DRC1L, "DRC1L"),
ARIZONA_MIXER_WIDGETS(DRC1R, "DRC1R"),
ARIZONA_MIXER_WIDGETS(DRC2L, "DRC2L"),
ARIZONA_MIXER_WIDGETS(DRC2R, "DRC2R"),
ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"),
ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"),
ARIZONA_MIXER_WIDGETS(LHPF3, "LHPF3"),
ARIZONA_MIXER_WIDGETS(LHPF4, "LHPF4"),
ARIZONA_MIXER_WIDGETS(Mic, "Mic"),
ARIZONA_MIXER_WIDGETS(Noise, "Noise"),
ARIZONA_MIXER_WIDGETS(PWM1, "PWM1"),
ARIZONA_MIXER_WIDGETS(PWM2, "PWM2"),
ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"),
ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"),
ARIZONA_MIXER_WIDGETS(OUT2L, "HPOUT2L"),
ARIZONA_MIXER_WIDGETS(OUT2R, "HPOUT2R"),
ARIZONA_MIXER_WIDGETS(OUT3, "EPOUT"),
ARIZONA_MIXER_WIDGETS(SPKOUTL, "SPKOUTL"),
ARIZONA_MIXER_WIDGETS(SPKOUTR, "SPKOUTR"),
ARIZONA_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"),
ARIZONA_MIXER_WIDGETS(SPKDAT1R, "SPKDAT1R"),
ARIZONA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
ARIZONA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
ARIZONA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
ARIZONA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
ARIZONA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
ARIZONA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
ARIZONA_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"),
ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),
ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
ARIZONA_MIXER_WIDGETS(ASRC1L, "ASRC1L"),
ARIZONA_MIXER_WIDGETS(ASRC1R, "ASRC1R"),
ARIZONA_MIXER_WIDGETS(ASRC2L, "ASRC2L"),
ARIZONA_MIXER_WIDGETS(ASRC2R, "ASRC2R"),
SND_SOC_DAPM_OUTPUT("HPOUT1L"),
SND_SOC_DAPM_OUTPUT("HPOUT1R"),
SND_SOC_DAPM_OUTPUT("HPOUT2L"),
SND_SOC_DAPM_OUTPUT("HPOUT2R"),
SND_SOC_DAPM_OUTPUT("EPOUTN"),
SND_SOC_DAPM_OUTPUT("EPOUTP"),
SND_SOC_DAPM_OUTPUT("SPKOUTLN"),
SND_SOC_DAPM_OUTPUT("SPKOUTLP"),
SND_SOC_DAPM_OUTPUT("SPKOUTRN"),
SND_SOC_DAPM_OUTPUT("SPKOUTRP"),
SND_SOC_DAPM_OUTPUT("SPKDAT1L"),
SND_SOC_DAPM_OUTPUT("SPKDAT1R"),
};
#define ARIZONA_MIXER_INPUT_ROUTES(name) \
{ name, "Noise Generator", "Noise Generator" }, \
{ name, "Tone Generator 1", "Tone Generator 1" }, \
{ name, "Tone Generator 2", "Tone Generator 2" }, \
{ name, "IN1L", "IN1L PGA" }, \
{ name, "IN1R", "IN1R PGA" }, \
{ name, "IN2L", "IN2L PGA" }, \
{ name, "IN2R", "IN2R PGA" }, \
{ name, "IN3L", "IN3L PGA" }, \
{ name, "IN3R", "IN3R PGA" }, \
{ name, "Mic Mute Mixer", "Mic Mute Mixer" }, \
{ name, "AIF1RX1", "AIF1RX1" }, \
{ name, "AIF1RX2", "AIF1RX2" }, \
{ name, "AIF1RX3", "AIF1RX3" }, \
{ name, "AIF1RX4", "AIF1RX4" }, \
{ name, "AIF1RX5", "AIF1RX5" }, \
{ name, "AIF1RX6", "AIF1RX6" }, \
{ name, "AIF1RX7", "AIF1RX7" }, \
{ name, "AIF1RX8", "AIF1RX8" }, \
{ name, "AIF2RX1", "AIF2RX1" }, \
{ name, "AIF2RX2", "AIF2RX2" }, \
{ name, "AIF3RX1", "AIF3RX1" }, \
{ name, "AIF3RX2", "AIF3RX2" }, \
{ name, "EQ1", "EQ1" }, \
{ name, "EQ2", "EQ2" }, \
{ name, "EQ3", "EQ3" }, \
{ name, "EQ4", "EQ4" }, \
{ name, "DRC1L", "DRC1L" }, \
{ name, "DRC1R", "DRC1R" }, \
{ name, "DRC2L", "DRC2L" }, \
{ name, "DRC2R", "DRC2R" }, \
{ name, "LHPF1", "LHPF1" }, \
{ name, "LHPF2", "LHPF2" }, \
{ name, "LHPF3", "LHPF3" }, \
{ name, "LHPF4", "LHPF4" }, \
{ name, "ASRC1L", "ASRC1L" }, \
{ name, "ASRC1R", "ASRC1R" }, \
{ name, "ASRC2L", "ASRC2L" }, \
{ name, "ASRC2R", "ASRC2R" }
static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
{ "AIF2 Capture", NULL, "DBVDD2" },
{ "AIF2 Playback", NULL, "DBVDD2" },
{ "AIF3 Capture", NULL, "DBVDD3" },
{ "AIF3 Playback", NULL, "DBVDD3" },
{ "OUT1L", NULL, "CPVDD" },
{ "OUT1R", NULL, "CPVDD" },
{ "OUT2L", NULL, "CPVDD" },
{ "OUT2R", NULL, "CPVDD" },
{ "OUT3L", NULL, "CPVDD" },
{ "OUT4L", NULL, "SPKVDDL" },
{ "OUT4R", NULL, "SPKVDDR" },
{ "OUT1L", NULL, "SYSCLK" },
{ "OUT1R", NULL, "SYSCLK" },
{ "OUT2L", NULL, "SYSCLK" },
{ "OUT2R", NULL, "SYSCLK" },
{ "OUT3L", NULL, "SYSCLK" },
{ "OUT4L", NULL, "SYSCLK" },
{ "OUT4R", NULL, "SYSCLK" },
{ "OUT5L", NULL, "SYSCLK" },
{ "OUT5R", NULL, "SYSCLK" },
{ "MICBIAS1", NULL, "MICVDD" },
{ "MICBIAS2", NULL, "MICVDD" },
{ "MICBIAS3", NULL, "MICVDD" },
{ "Noise Generator", NULL, "NOISE" },
{ "Tone Generator 1", NULL, "TONE" },
{ "Tone Generator 2", NULL, "TONE" },
{ "Mic Mute Mixer", NULL, "Noise Mixer" },
{ "Mic Mute Mixer", NULL, "Mic Mixer" },
{ "AIF1 Capture", NULL, "AIF1TX1" },
{ "AIF1 Capture", NULL, "AIF1TX2" },
{ "AIF1 Capture", NULL, "AIF1TX3" },
{ "AIF1 Capture", NULL, "AIF1TX4" },
{ "AIF1 Capture", NULL, "AIF1TX5" },
{ "AIF1 Capture", NULL, "AIF1TX6" },
{ "AIF1 Capture", NULL, "AIF1TX7" },
{ "AIF1 Capture", NULL, "AIF1TX8" },
{ "AIF1RX1", NULL, "AIF1 Playback" },
{ "AIF1RX2", NULL, "AIF1 Playback" },
{ "AIF1RX3", NULL, "AIF1 Playback" },
{ "AIF1RX4", NULL, "AIF1 Playback" },
{ "AIF1RX5", NULL, "AIF1 Playback" },
{ "AIF1RX6", NULL, "AIF1 Playback" },
{ "AIF1RX7", NULL, "AIF1 Playback" },
{ "AIF1RX8", NULL, "AIF1 Playback" },
{ "AIF2 Capture", NULL, "AIF2TX1" },
{ "AIF2 Capture", NULL, "AIF2TX2" },
{ "AIF2RX1", NULL, "AIF2 Playback" },
{ "AIF2RX2", NULL, "AIF2 Playback" },
{ "AIF3 Capture", NULL, "AIF3TX1" },
{ "AIF3 Capture", NULL, "AIF3TX2" },
{ "AIF3RX1", NULL, "AIF3 Playback" },
{ "AIF3RX2", NULL, "AIF3 Playback" },
{ "AIF1 Playback", NULL, "SYSCLK" },
{ "AIF2 Playback", NULL, "SYSCLK" },
{ "AIF3 Playback", NULL, "SYSCLK" },
{ "AIF1 Capture", NULL, "SYSCLK" },
{ "AIF2 Capture", NULL, "SYSCLK" },
{ "AIF3 Capture", NULL, "SYSCLK" },
ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"),
ARIZONA_MIXER_ROUTES("OUT2R", "HPOUT2R"),
ARIZONA_MIXER_ROUTES("OUT3L", "EPOUT"),
ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUTL"),
ARIZONA_MIXER_ROUTES("OUT4R", "SPKOUTR"),
ARIZONA_MIXER_ROUTES("OUT5L", "SPKDAT1L"),
ARIZONA_MIXER_ROUTES("OUT5R", "SPKDAT1R"),
ARIZONA_MIXER_ROUTES("PWM1 Driver", "PWM1"),
ARIZONA_MIXER_ROUTES("PWM2 Driver", "PWM2"),
ARIZONA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
ARIZONA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
ARIZONA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
ARIZONA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
ARIZONA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
ARIZONA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
ARIZONA_MIXER_ROUTES("AIF1TX7", "AIF1TX7"),
ARIZONA_MIXER_ROUTES("AIF1TX8", "AIF1TX8"),
ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
ARIZONA_MIXER_ROUTES("EQ1", "EQ1"),
ARIZONA_MIXER_ROUTES("EQ2", "EQ2"),
ARIZONA_MIXER_ROUTES("EQ3", "EQ3"),
ARIZONA_MIXER_ROUTES("EQ4", "EQ4"),
ARIZONA_MIXER_ROUTES("DRC1L", "DRC1L"),
ARIZONA_MIXER_ROUTES("DRC1R", "DRC1R"),
ARIZONA_MIXER_ROUTES("DRC2L", "DRC2L"),
ARIZONA_MIXER_ROUTES("DRC2R", "DRC2R"),
ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"),
ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"),
ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"),
ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"),
ARIZONA_MIXER_ROUTES("ASRC1L", "ASRC1L"),
ARIZONA_MIXER_ROUTES("ASRC1R", "ASRC1R"),
ARIZONA_MIXER_ROUTES("ASRC2L", "ASRC2L"),
ARIZONA_MIXER_ROUTES("ASRC2R", "ASRC2R"),
{ "HPOUT1L", NULL, "OUT1L" },
{ "HPOUT1R", NULL, "OUT1R" },
{ "HPOUT2L", NULL, "OUT2L" },
{ "HPOUT2R", NULL, "OUT2R" },
{ "EPOUTN", NULL, "OUT3L" },
{ "EPOUTP", NULL, "OUT3L" },
{ "SPKOUTLN", NULL, "OUT4L" },
{ "SPKOUTLP", NULL, "OUT4L" },
{ "SPKOUTRN", NULL, "OUT4R" },
{ "SPKOUTRP", NULL, "OUT4R" },
{ "SPKDAT1L", NULL, "OUT5L" },
{ "SPKDAT1R", NULL, "OUT5R" },
};
static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
unsigned int Fref, unsigned int Fout)
{
struct wm5102_priv *wm5102 = snd_soc_codec_get_drvdata(codec);
switch (fll_id) {
case WM5102_FLL1:
return arizona_set_fll(&wm5102->fll[0], source, Fref, Fout);
case WM5102_FLL2:
return arizona_set_fll(&wm5102->fll[1], source, Fref, Fout);
default:
return -EINVAL;
}
}
#define WM5102_RATES SNDRV_PCM_RATE_8000_192000
#define WM5102_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_driver wm5102_dai[] = {
{
.name = "wm5102-aif1",
.id = 1,
.base = ARIZONA_AIF1_BCLK_CTRL,
.playback = {
.stream_name = "AIF1 Playback",
.channels_min = 1,
.channels_max = 8,
.rates = WM5102_RATES,
.formats = WM5102_FORMATS,
},
.capture = {
.stream_name = "AIF1 Capture",
.channels_min = 1,
.channels_max = 8,
.rates = WM5102_RATES,
.formats = WM5102_FORMATS,
},
.ops = &arizona_dai_ops,
.symmetric_rates = 1,
},
{
.name = "wm5102-aif2",
.id = 2,
.base = ARIZONA_AIF2_BCLK_CTRL,
.playback = {
.stream_name = "AIF2 Playback",
.channels_min = 1,
.channels_max = 2,
.rates = WM5102_RATES,
.formats = WM5102_FORMATS,
},
.capture = {
.stream_name = "AIF2 Capture",
.channels_min = 1,
.channels_max = 2,
.rates = WM5102_RATES,
.formats = WM5102_FORMATS,
},
.ops = &arizona_dai_ops,
.symmetric_rates = 1,
},
{
.name = "wm5102-aif3",
.id = 3,
.base = ARIZONA_AIF3_BCLK_CTRL,
.playback = {
.stream_name = "AIF3 Playback",
.channels_min = 1,
.channels_max = 2,
.rates = WM5102_RATES,
.formats = WM5102_FORMATS,
},
.capture = {
.stream_name = "AIF3 Capture",
.channels_min = 1,
.channels_max = 2,
.rates = WM5102_RATES,
.formats = WM5102_FORMATS,
},
.ops = &arizona_dai_ops,
.symmetric_rates = 1,
},
};
static int wm5102_codec_probe(struct snd_soc_codec *codec)
{
struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
codec->control_data = priv->core.arizona->regmap;
return snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP);
}
#define WM5102_DIG_VU 0x0200
static unsigned int wm5102_digital_vu[] = {
ARIZONA_ADC_DIGITAL_VOLUME_1L,
ARIZONA_ADC_DIGITAL_VOLUME_1R,
ARIZONA_ADC_DIGITAL_VOLUME_2L,
ARIZONA_ADC_DIGITAL_VOLUME_2R,
ARIZONA_ADC_DIGITAL_VOLUME_3L,
ARIZONA_ADC_DIGITAL_VOLUME_3R,
ARIZONA_DAC_DIGITAL_VOLUME_1L,
ARIZONA_DAC_DIGITAL_VOLUME_1R,
ARIZONA_DAC_DIGITAL_VOLUME_2L,
ARIZONA_DAC_DIGITAL_VOLUME_2R,
ARIZONA_DAC_DIGITAL_VOLUME_3L,
ARIZONA_DAC_DIGITAL_VOLUME_3R,
ARIZONA_DAC_DIGITAL_VOLUME_4L,
ARIZONA_DAC_DIGITAL_VOLUME_4R,
ARIZONA_DAC_DIGITAL_VOLUME_5L,
ARIZONA_DAC_DIGITAL_VOLUME_5R,
};
static struct snd_soc_codec_driver soc_codec_dev_wm5102 = {
.probe = wm5102_codec_probe,
.idle_bias_off = true,
.set_sysclk = arizona_set_sysclk,
.set_pll = wm5102_set_fll,
.controls = wm5102_snd_controls,
.num_controls = ARRAY_SIZE(wm5102_snd_controls),
.dapm_widgets = wm5102_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm5102_dapm_widgets),
.dapm_routes = wm5102_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(wm5102_dapm_routes),
};
static int __devinit wm5102_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
struct wm5102_priv *wm5102;
int i;
wm5102 = devm_kzalloc(&pdev->dev, sizeof(struct wm5102_priv),
GFP_KERNEL);
if (wm5102 == NULL)
return -ENOMEM;
platform_set_drvdata(pdev, wm5102);
wm5102->core.arizona = arizona;
for (i = 0; i < ARRAY_SIZE(wm5102->fll); i++)
wm5102->fll[i].vco_mult = 1;
arizona_init_fll(arizona, 1, ARIZONA_FLL1_CONTROL_1 - 1,
ARIZONA_IRQ_FLL1_LOCK, ARIZONA_IRQ_FLL1_CLOCK_OK,
&wm5102->fll[0]);
arizona_init_fll(arizona, 2, ARIZONA_FLL2_CONTROL_1 - 1,
ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
&wm5102->fll[1]);
for (i = 0; i < ARRAY_SIZE(wm5102_dai); i++)
arizona_init_dai(&wm5102->core, i);
/* Latch volume update bits */
for (i = 0; i < ARRAY_SIZE(wm5102_digital_vu); i++)
regmap_update_bits(arizona->regmap, wm5102_digital_vu[i],
WM5102_DIG_VU, WM5102_DIG_VU);
pm_runtime_enable(&pdev->dev);
pm_runtime_idle(&pdev->dev);
return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5102,
wm5102_dai, ARRAY_SIZE(wm5102_dai));
}
static int __devexit wm5102_remove(struct platform_device *pdev)
{
snd_soc_unregister_codec(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return 0;
}
static struct platform_driver wm5102_codec_driver = {
.driver = {
.name = "wm5102-codec",
.owner = THIS_MODULE,
},
.probe = wm5102_probe,
.remove = __devexit_p(wm5102_remove),
};
module_platform_driver(wm5102_codec_driver);
MODULE_DESCRIPTION("ASoC WM5102 driver");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:wm5102-codec");

21
sound/soc/codecs/wm5102.h Normal file
View File

@ -0,0 +1,21 @@
/*
* wm5102.h -- WM5102 ALSA SoC Audio driver
*
* Copyright 2012 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _WM5102_H
#define _WM5102_H
#include "arizona.h"
#define WM5102_FLL1 1
#define WM5102_FLL2 2
#endif

950
sound/soc/codecs/wm5110.c Normal file
View File

@ -0,0 +1,950 @@
/*
* wm5110.c -- WM5110 ALSA SoC Audio driver
*
* Copyright 2012 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <linux/mfd/arizona/core.h>
#include <linux/mfd/arizona/registers.h>
#include "arizona.h"
#include "wm5110.h"
struct wm5110_priv {
struct arizona_priv core;
struct arizona_fll fll[2];
};
static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0);
static const struct snd_kcontrol_new wm5110_snd_controls[] = {
SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL,
ARIZONA_IN1_OSR_SHIFT, 1, 0),
SOC_SINGLE("IN2 High Performance Switch", ARIZONA_IN2L_CONTROL,
ARIZONA_IN2_OSR_SHIFT, 1, 0),
SOC_SINGLE("IN3 High Performance Switch", ARIZONA_IN3L_CONTROL,
ARIZONA_IN3_OSR_SHIFT, 1, 0),
SOC_SINGLE("IN4 High Performance Switch", ARIZONA_IN4L_CONTROL,
ARIZONA_IN4_OSR_SHIFT, 1, 0),
SOC_DOUBLE_R_RANGE_TLV("IN1 Volume", ARIZONA_IN1L_CONTROL,
ARIZONA_IN1R_CONTROL,
ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_DOUBLE_R_RANGE_TLV("IN2 Volume", ARIZONA_IN2L_CONTROL,
ARIZONA_IN2R_CONTROL,
ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_DOUBLE_R_RANGE_TLV("IN3 Volume", ARIZONA_IN3L_CONTROL,
ARIZONA_IN3R_CONTROL,
ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_DOUBLE_R("IN1 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_1L,
ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("IN2 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_2L,
ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("IN3 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_3L,
ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("IN4 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_4L,
ARIZONA_ADC_DIGITAL_VOLUME_4R, ARIZONA_IN4L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R_TLV("IN1 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_DIG_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_DOUBLE_R_TLV("IN2 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_DIG_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_DOUBLE_R_TLV("IN3 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L,
ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_DIG_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_DOUBLE_R_TLV("IN4 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_4L,
ARIZONA_ADC_DIGITAL_VOLUME_4R, ARIZONA_IN4L_DIG_VOL_SHIFT,
0xbf, 0, digital_tlv),
ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ1 B3 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B3_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 B3 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B3_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 B3 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B3_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 B3 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B3_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 B4 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B4_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 B5 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B5_GAIN_SHIFT,
24, 0, eq_tlv),
ARIZONA_MIXER_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("DRC2L", ARIZONA_DRC2LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("DRC2R", ARIZONA_DRC2RMIX_INPUT_1_SOURCE),
SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5,
ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA),
SND_SOC_BYTES_MASK("DRC2", ARIZONA_DRC2_CTRL1, 5,
ARIZONA_DRC2R_ENA | ARIZONA_DRC2L_ENA),
ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE),
SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode),
SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE),
SOC_SINGLE_TLV("Noise Generator Volume", ARIZONA_COMFORT_NOISE_GENERATOR,
ARIZONA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, noise_tlv),
ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("HPOUT2L", ARIZONA_OUT2LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("HPOUT2R", ARIZONA_OUT2RMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EPOUT", ARIZONA_OUT3LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("SPKOUTL", ARIZONA_OUT4LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("SPKDAT2L", ARIZONA_OUT6LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("SPKDAT2R", ARIZONA_OUT6RMIX_INPUT_1_SOURCE),
SOC_SINGLE("HPOUT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_1L,
ARIZONA_OUT1_OSR_SHIFT, 1, 0),
SOC_SINGLE("OUT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_2L,
ARIZONA_OUT2_OSR_SHIFT, 1, 0),
SOC_SINGLE("EPOUT High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_3L,
ARIZONA_OUT3_OSR_SHIFT, 1, 0),
SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L,
ARIZONA_OUT4_OSR_SHIFT, 1, 0),
SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L,
ARIZONA_OUT5_OSR_SHIFT, 1, 0),
SOC_SINGLE("SPKDAT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_6L,
ARIZONA_OUT6_OSR_SHIFT, 1, 0),
SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("OUT2 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_2L,
ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_MUTE_SHIFT, 1, 1),
SOC_SINGLE("EPOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L,
ARIZONA_OUT3L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L,
ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("SPKDAT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_5L,
ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("SPKDAT2 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_6L,
ARIZONA_DAC_DIGITAL_VOLUME_6R, ARIZONA_OUT6L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L,
ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_DOUBLE_R_TLV("OUT2 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_2L,
ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("EPOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L,
ARIZONA_OUT3L_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_DOUBLE_R_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L,
ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,
ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_DOUBLE_R_TLV("SPKDAT2 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_6L,
ARIZONA_DAC_DIGITAL_VOLUME_6R, ARIZONA_OUT6L_VOL_SHIFT,
0xbf, 0, digital_tlv),
SOC_DOUBLE_R_RANGE_TLV("HPOUT1 Volume", ARIZONA_OUTPUT_PATH_CONFIG_1L,
ARIZONA_OUTPUT_PATH_CONFIG_1R,
ARIZONA_OUT1L_PGA_VOL_SHIFT,
0x34, 0x40, 0, ana_tlv),
SOC_DOUBLE_R_RANGE_TLV("OUT2 Volume", ARIZONA_OUTPUT_PATH_CONFIG_2L,
ARIZONA_OUTPUT_PATH_CONFIG_2R,
ARIZONA_OUT2L_PGA_VOL_SHIFT,
0x34, 0x40, 0, ana_tlv),
SOC_SINGLE_RANGE_TLV("EPOUT Volume", ARIZONA_OUTPUT_PATH_CONFIG_3L,
ARIZONA_OUT3L_PGA_VOL_SHIFT, 0x34, 0x40, 0, ana_tlv),
SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,
ARIZONA_SPK1R_MUTE_SHIFT, 1, 1),
SOC_DOUBLE("SPKDAT2 Switch", ARIZONA_PDM_SPK2_CTRL_1, ARIZONA_SPK2L_MUTE_SHIFT,
ARIZONA_SPK2R_MUTE_SHIFT, 1, 1),
ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF1TX4", ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF1TX5", ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF1TX6", ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF1TX7", ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
};
ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(EQ4, ARIZONA_EQ4MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(DRC2L, ARIZONA_DRC2LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(DRC2R, ARIZONA_DRC2RMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(Mic, ARIZONA_MICMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(Noise, ARIZONA_NOISEMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(PWM1, ARIZONA_PWM1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(PWM2, ARIZONA_PWM2MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(OUT2L, ARIZONA_OUT2LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(OUT2R, ARIZONA_OUT2RMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(OUT3, ARIZONA_OUT3LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(SPKOUTL, ARIZONA_OUT4LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(SPKOUTR, ARIZONA_OUT4RMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(SPKDAT1L, ARIZONA_OUT5LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(SPKDAT1R, ARIZONA_OUT5RMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(SPKDAT2L, ARIZONA_OUT6LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(SPKDAT2R, ARIZONA_OUT6RMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF1TX1, ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF1TX2, ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF1TX3, ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF1TX4, ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF1TX5, ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF1TX6, ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF1TX7, ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
0, NULL, 0),
SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20),
SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0),
SND_SOC_DAPM_SIGGEN("TONE"),
SND_SOC_DAPM_SIGGEN("NOISE"),
SND_SOC_DAPM_INPUT("IN1L"),
SND_SOC_DAPM_INPUT("IN1R"),
SND_SOC_DAPM_INPUT("IN2L"),
SND_SOC_DAPM_INPUT("IN2R"),
SND_SOC_DAPM_INPUT("IN3L"),
SND_SOC_DAPM_INPUT("IN3R"),
SND_SOC_DAPM_INPUT("IN4L"),
SND_SOC_DAPM_INPUT("IN4R"),
SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
0, NULL, 0, arizona_in_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
0, NULL, 0, arizona_in_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
0, NULL, 0, arizona_in_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
0, NULL, 0, arizona_in_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT,
0, NULL, 0, arizona_in_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT,
0, NULL, 0, arizona_in_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("IN4L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4L_ENA_SHIFT,
0, NULL, 0, arizona_in_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("IN4R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4R_ENA_SHIFT,
0, NULL, 0, arizona_in_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2,
ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("MICBIAS3", ARIZONA_MIC_BIAS_CTRL_3,
ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("Noise Generator", ARIZONA_COMFORT_NOISE_GENERATOR,
ARIZONA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("Tone Generator 1", ARIZONA_TONE_GENERATOR_1,
ARIZONA_TONE1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("Tone Generator 2", ARIZONA_TONE_GENERATOR_1,
ARIZONA_TONE2_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("Mic Mute Mixer", ARIZONA_MIC_NOISE_MIX_CONTROL_1,
ARIZONA_MICMUTE_MIX_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("EQ1", ARIZONA_EQ1_1, ARIZONA_EQ1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("EQ2", ARIZONA_EQ2_1, ARIZONA_EQ2_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("EQ3", ARIZONA_EQ3_1, ARIZONA_EQ3_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("EQ4", ARIZONA_EQ4_1, ARIZONA_EQ4_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("DRC2L", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2L_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("DRC2R", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2R_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("LHPF2", ARIZONA_HPLPF2_1, ARIZONA_LHPF2_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("LHPF3", ARIZONA_HPLPF3_1, ARIZONA_LHPF3_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("LHPF4", ARIZONA_HPLPF4_1, ARIZONA_LHPF4_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("PWM1 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM1_ENA_SHIFT,
0, NULL, 0),
SND_SOC_DAPM_PGA("PWM2 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM2_ENA_SHIFT,
0, NULL, 0),
SND_SOC_DAPM_PGA("ASRC1L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1L_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("ASRC1R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1R_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
NULL, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0,
ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0,
ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0,
ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0,
ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0,
ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0,
ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0,
ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0,
ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0,
ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0,
ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,
ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,
ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0,
ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0,
ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT1R", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT2R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT5R", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT5R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT6L", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT6L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT6R", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT6R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
ARIZONA_MIXER_WIDGETS(EQ1, "EQ1"),
ARIZONA_MIXER_WIDGETS(EQ2, "EQ2"),
ARIZONA_MIXER_WIDGETS(EQ3, "EQ3"),
ARIZONA_MIXER_WIDGETS(EQ4, "EQ4"),
ARIZONA_MIXER_WIDGETS(DRC1L, "DRC1L"),
ARIZONA_MIXER_WIDGETS(DRC1R, "DRC1R"),
ARIZONA_MIXER_WIDGETS(DRC2L, "DRC2L"),
ARIZONA_MIXER_WIDGETS(DRC2R, "DRC2R"),
ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"),
ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"),
ARIZONA_MIXER_WIDGETS(LHPF3, "LHPF3"),
ARIZONA_MIXER_WIDGETS(LHPF4, "LHPF4"),
ARIZONA_MIXER_WIDGETS(Mic, "Mic"),
ARIZONA_MIXER_WIDGETS(Noise, "Noise"),
ARIZONA_MIXER_WIDGETS(PWM1, "PWM1"),
ARIZONA_MIXER_WIDGETS(PWM2, "PWM2"),
ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"),
ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"),
ARIZONA_MIXER_WIDGETS(OUT2L, "HPOUT2L"),
ARIZONA_MIXER_WIDGETS(OUT2R, "HPOUT2R"),
ARIZONA_MIXER_WIDGETS(OUT3, "EPOUT"),
ARIZONA_MIXER_WIDGETS(SPKOUTL, "SPKOUTL"),
ARIZONA_MIXER_WIDGETS(SPKOUTR, "SPKOUTR"),
ARIZONA_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"),
ARIZONA_MIXER_WIDGETS(SPKDAT1R, "SPKDAT1R"),
ARIZONA_MIXER_WIDGETS(SPKDAT2L, "SPKDAT2L"),
ARIZONA_MIXER_WIDGETS(SPKDAT2R, "SPKDAT2R"),
ARIZONA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
ARIZONA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
ARIZONA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
ARIZONA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
ARIZONA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
ARIZONA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
ARIZONA_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"),
ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),
ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
ARIZONA_MIXER_WIDGETS(ASRC1L, "ASRC1L"),
ARIZONA_MIXER_WIDGETS(ASRC1R, "ASRC1R"),
ARIZONA_MIXER_WIDGETS(ASRC2L, "ASRC2L"),
ARIZONA_MIXER_WIDGETS(ASRC2R, "ASRC2R"),
SND_SOC_DAPM_OUTPUT("HPOUT1L"),
SND_SOC_DAPM_OUTPUT("HPOUT1R"),
SND_SOC_DAPM_OUTPUT("HPOUT2L"),
SND_SOC_DAPM_OUTPUT("HPOUT2R"),
SND_SOC_DAPM_OUTPUT("EPOUTN"),
SND_SOC_DAPM_OUTPUT("EPOUTP"),
SND_SOC_DAPM_OUTPUT("SPKOUTLN"),
SND_SOC_DAPM_OUTPUT("SPKOUTLP"),
SND_SOC_DAPM_OUTPUT("SPKOUTRN"),
SND_SOC_DAPM_OUTPUT("SPKOUTRP"),
SND_SOC_DAPM_OUTPUT("SPKDAT1L"),
SND_SOC_DAPM_OUTPUT("SPKDAT1R"),
SND_SOC_DAPM_OUTPUT("SPKDAT2L"),
SND_SOC_DAPM_OUTPUT("SPKDAT2R"),
};
#define ARIZONA_MIXER_INPUT_ROUTES(name) \
{ name, "Noise Generator", "Noise Generator" }, \
{ name, "Tone Generator 1", "Tone Generator 1" }, \
{ name, "Tone Generator 2", "Tone Generator 2" }, \
{ name, "IN1L", "IN1L PGA" }, \
{ name, "IN1R", "IN1R PGA" }, \
{ name, "IN2L", "IN2L PGA" }, \
{ name, "IN2R", "IN2R PGA" }, \
{ name, "IN3L", "IN3L PGA" }, \
{ name, "IN3R", "IN3R PGA" }, \
{ name, "IN4L", "IN4L PGA" }, \
{ name, "IN4R", "IN4R PGA" }, \
{ name, "Mic Mute Mixer", "Mic Mute Mixer" }, \
{ name, "AIF1RX1", "AIF1RX1" }, \
{ name, "AIF1RX2", "AIF1RX2" }, \
{ name, "AIF1RX3", "AIF1RX3" }, \
{ name, "AIF1RX4", "AIF1RX4" }, \
{ name, "AIF1RX5", "AIF1RX5" }, \
{ name, "AIF1RX6", "AIF1RX6" }, \
{ name, "AIF1RX7", "AIF1RX7" }, \
{ name, "AIF1RX8", "AIF1RX8" }, \
{ name, "AIF2RX1", "AIF2RX1" }, \
{ name, "AIF2RX2", "AIF2RX2" }, \
{ name, "AIF3RX1", "AIF3RX1" }, \
{ name, "AIF3RX2", "AIF3RX2" }, \
{ name, "EQ1", "EQ1" }, \
{ name, "EQ2", "EQ2" }, \
{ name, "EQ3", "EQ3" }, \
{ name, "EQ4", "EQ4" }, \
{ name, "DRC1L", "DRC1L" }, \
{ name, "DRC1R", "DRC1R" }, \
{ name, "DRC2L", "DRC2L" }, \
{ name, "DRC2R", "DRC2R" }, \
{ name, "LHPF1", "LHPF1" }, \
{ name, "LHPF2", "LHPF2" }, \
{ name, "LHPF3", "LHPF3" }, \
{ name, "LHPF4", "LHPF4" }, \
{ name, "ASRC1L", "ASRC1L" }, \
{ name, "ASRC1R", "ASRC1R" }, \
{ name, "ASRC2L", "ASRC2L" }, \
{ name, "ASRC2R", "ASRC2R" }
static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
{ "AIF2 Capture", NULL, "DBVDD2" },
{ "AIF2 Playback", NULL, "DBVDD2" },
{ "AIF3 Capture", NULL, "DBVDD3" },
{ "AIF3 Playback", NULL, "DBVDD3" },
{ "OUT1L", NULL, "CPVDD" },
{ "OUT1R", NULL, "CPVDD" },
{ "OUT2L", NULL, "CPVDD" },
{ "OUT2R", NULL, "CPVDD" },
{ "OUT3L", NULL, "CPVDD" },
{ "OUT4L", NULL, "SPKVDDL" },
{ "OUT4R", NULL, "SPKVDDR" },
{ "OUT1L", NULL, "SYSCLK" },
{ "OUT1R", NULL, "SYSCLK" },
{ "OUT2L", NULL, "SYSCLK" },
{ "OUT2R", NULL, "SYSCLK" },
{ "OUT3L", NULL, "SYSCLK" },
{ "OUT4L", NULL, "SYSCLK" },
{ "OUT4R", NULL, "SYSCLK" },
{ "OUT5L", NULL, "SYSCLK" },
{ "OUT5R", NULL, "SYSCLK" },
{ "OUT6L", NULL, "SYSCLK" },
{ "OUT6R", NULL, "SYSCLK" },
{ "MICBIAS1", NULL, "MICVDD" },
{ "MICBIAS2", NULL, "MICVDD" },
{ "MICBIAS3", NULL, "MICVDD" },
{ "Noise Generator", NULL, "NOISE" },
{ "Tone Generator 1", NULL, "TONE" },
{ "Tone Generator 2", NULL, "TONE" },
{ "Mic Mute Mixer", NULL, "Noise Mixer" },
{ "Mic Mute Mixer", NULL, "Mic Mixer" },
{ "AIF1 Capture", NULL, "AIF1TX1" },
{ "AIF1 Capture", NULL, "AIF1TX2" },
{ "AIF1 Capture", NULL, "AIF1TX3" },
{ "AIF1 Capture", NULL, "AIF1TX4" },
{ "AIF1 Capture", NULL, "AIF1TX5" },
{ "AIF1 Capture", NULL, "AIF1TX6" },
{ "AIF1 Capture", NULL, "AIF1TX7" },
{ "AIF1 Capture", NULL, "AIF1TX8" },
{ "AIF1RX1", NULL, "AIF1 Playback" },
{ "AIF1RX2", NULL, "AIF1 Playback" },
{ "AIF1RX3", NULL, "AIF1 Playback" },
{ "AIF1RX4", NULL, "AIF1 Playback" },
{ "AIF1RX5", NULL, "AIF1 Playback" },
{ "AIF1RX6", NULL, "AIF1 Playback" },
{ "AIF1RX7", NULL, "AIF1 Playback" },
{ "AIF1RX8", NULL, "AIF1 Playback" },
{ "AIF2 Capture", NULL, "AIF2TX1" },
{ "AIF2 Capture", NULL, "AIF2TX2" },
{ "AIF2RX1", NULL, "AIF2 Playback" },
{ "AIF2RX2", NULL, "AIF2 Playback" },
{ "AIF3 Capture", NULL, "AIF3TX1" },
{ "AIF3 Capture", NULL, "AIF3TX2" },
{ "AIF3RX1", NULL, "AIF3 Playback" },
{ "AIF3RX2", NULL, "AIF3 Playback" },
{ "AIF1 Playback", NULL, "SYSCLK" },
{ "AIF2 Playback", NULL, "SYSCLK" },
{ "AIF3 Playback", NULL, "SYSCLK" },
{ "AIF1 Capture", NULL, "SYSCLK" },
{ "AIF2 Capture", NULL, "SYSCLK" },
{ "AIF3 Capture", NULL, "SYSCLK" },
ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"),
ARIZONA_MIXER_ROUTES("OUT2R", "HPOUT2R"),
ARIZONA_MIXER_ROUTES("OUT3L", "EPOUT"),
ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUTL"),
ARIZONA_MIXER_ROUTES("OUT4R", "SPKOUTR"),
ARIZONA_MIXER_ROUTES("OUT5L", "SPKDAT1L"),
ARIZONA_MIXER_ROUTES("OUT5R", "SPKDAT1R"),
ARIZONA_MIXER_ROUTES("OUT6L", "SPKDAT2L"),
ARIZONA_MIXER_ROUTES("OUT6R", "SPKDAT2R"),
ARIZONA_MIXER_ROUTES("PWM1 Driver", "PWM1"),
ARIZONA_MIXER_ROUTES("PWM2 Driver", "PWM2"),
ARIZONA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
ARIZONA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
ARIZONA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
ARIZONA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
ARIZONA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
ARIZONA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
ARIZONA_MIXER_ROUTES("AIF1TX7", "AIF1TX7"),
ARIZONA_MIXER_ROUTES("AIF1TX8", "AIF1TX8"),
ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
ARIZONA_MIXER_ROUTES("EQ1", "EQ1"),
ARIZONA_MIXER_ROUTES("EQ2", "EQ2"),
ARIZONA_MIXER_ROUTES("EQ3", "EQ3"),
ARIZONA_MIXER_ROUTES("EQ4", "EQ4"),
ARIZONA_MIXER_ROUTES("DRC1L", "DRC1L"),
ARIZONA_MIXER_ROUTES("DRC1R", "DRC1R"),
ARIZONA_MIXER_ROUTES("DRC2L", "DRC2L"),
ARIZONA_MIXER_ROUTES("DRC2R", "DRC2R"),
ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"),
ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"),
ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"),
ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"),
ARIZONA_MIXER_ROUTES("ASRC1L", "ASRC1L"),
ARIZONA_MIXER_ROUTES("ASRC1R", "ASRC1R"),
ARIZONA_MIXER_ROUTES("ASRC2L", "ASRC2L"),
ARIZONA_MIXER_ROUTES("ASRC2R", "ASRC2R"),
{ "HPOUT1L", NULL, "OUT1L" },
{ "HPOUT1R", NULL, "OUT1R" },
{ "HPOUT2L", NULL, "OUT2L" },
{ "HPOUT2R", NULL, "OUT2R" },
{ "EPOUTN", NULL, "OUT3L" },
{ "EPOUTP", NULL, "OUT3L" },
{ "SPKOUTLN", NULL, "OUT4L" },
{ "SPKOUTLP", NULL, "OUT4L" },
{ "SPKOUTRN", NULL, "OUT4R" },
{ "SPKOUTRP", NULL, "OUT4R" },
{ "SPKDAT1L", NULL, "OUT5L" },
{ "SPKDAT1R", NULL, "OUT5R" },
{ "SPKDAT2L", NULL, "OUT6L" },
{ "SPKDAT2R", NULL, "OUT6R" },
};
static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
unsigned int Fref, unsigned int Fout)
{
struct wm5110_priv *wm5110 = snd_soc_codec_get_drvdata(codec);
switch (fll_id) {
case WM5110_FLL1:
return arizona_set_fll(&wm5110->fll[0], source, Fref, Fout);
case WM5110_FLL2:
return arizona_set_fll(&wm5110->fll[1], source, Fref, Fout);
default:
return -EINVAL;
}
}
#define WM5110_RATES SNDRV_PCM_RATE_8000_192000
#define WM5110_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_driver wm5110_dai[] = {
{
.name = "wm5110-aif1",
.id = 1,
.base = ARIZONA_AIF1_BCLK_CTRL,
.playback = {
.stream_name = "AIF1 Playback",
.channels_min = 1,
.channels_max = 8,
.rates = WM5110_RATES,
.formats = WM5110_FORMATS,
},
.capture = {
.stream_name = "AIF1 Capture",
.channels_min = 1,
.channels_max = 8,
.rates = WM5110_RATES,
.formats = WM5110_FORMATS,
},
.ops = &arizona_dai_ops,
.symmetric_rates = 1,
},
{
.name = "wm5110-aif2",
.id = 2,
.base = ARIZONA_AIF2_BCLK_CTRL,
.playback = {
.stream_name = "AIF2 Playback",
.channels_min = 1,
.channels_max = 2,
.rates = WM5110_RATES,
.formats = WM5110_FORMATS,
},
.capture = {
.stream_name = "AIF2 Capture",
.channels_min = 1,
.channels_max = 2,
.rates = WM5110_RATES,
.formats = WM5110_FORMATS,
},
.ops = &arizona_dai_ops,
.symmetric_rates = 1,
},
{
.name = "wm5110-aif3",
.id = 3,
.base = ARIZONA_AIF3_BCLK_CTRL,
.playback = {
.stream_name = "AIF3 Playback",
.channels_min = 1,
.channels_max = 2,
.rates = WM5110_RATES,
.formats = WM5110_FORMATS,
},
.capture = {
.stream_name = "AIF3 Capture",
.channels_min = 1,
.channels_max = 2,
.rates = WM5110_RATES,
.formats = WM5110_FORMATS,
},
.ops = &arizona_dai_ops,
.symmetric_rates = 1,
},
};
static int wm5110_codec_probe(struct snd_soc_codec *codec)
{
struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
codec->control_data = priv->core.arizona->regmap;
return snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP);
}
#define WM5110_DIG_VU 0x0200
static unsigned int wm5110_digital_vu[] = {
ARIZONA_ADC_DIGITAL_VOLUME_1L,
ARIZONA_ADC_DIGITAL_VOLUME_1R,
ARIZONA_ADC_DIGITAL_VOLUME_2L,
ARIZONA_ADC_DIGITAL_VOLUME_2R,
ARIZONA_ADC_DIGITAL_VOLUME_3L,
ARIZONA_ADC_DIGITAL_VOLUME_3R,
ARIZONA_DAC_DIGITAL_VOLUME_1L,
ARIZONA_DAC_DIGITAL_VOLUME_1R,
ARIZONA_DAC_DIGITAL_VOLUME_2L,
ARIZONA_DAC_DIGITAL_VOLUME_2R,
ARIZONA_DAC_DIGITAL_VOLUME_3L,
ARIZONA_DAC_DIGITAL_VOLUME_3R,
ARIZONA_DAC_DIGITAL_VOLUME_4L,
ARIZONA_DAC_DIGITAL_VOLUME_4R,
ARIZONA_DAC_DIGITAL_VOLUME_5L,
ARIZONA_DAC_DIGITAL_VOLUME_5R,
};
static struct snd_soc_codec_driver soc_codec_dev_wm5110 = {
.probe = wm5110_codec_probe,
.idle_bias_off = true,
.set_sysclk = arizona_set_sysclk,
.set_pll = wm5110_set_fll,
.controls = wm5110_snd_controls,
.num_controls = ARRAY_SIZE(wm5110_snd_controls),
.dapm_widgets = wm5110_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm5110_dapm_widgets),
.dapm_routes = wm5110_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(wm5110_dapm_routes),
};
static int __devinit wm5110_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
struct wm5110_priv *wm5110;
int i;
wm5110 = devm_kzalloc(&pdev->dev, sizeof(struct wm5110_priv),
GFP_KERNEL);
if (wm5110 == NULL)
return -ENOMEM;
platform_set_drvdata(pdev, wm5110);
wm5110->core.arizona = arizona;
for (i = 0; i < ARRAY_SIZE(wm5110->fll); i++)
wm5110->fll[i].vco_mult = 3;
arizona_init_fll(arizona, 1, ARIZONA_FLL1_CONTROL_1 - 1,
ARIZONA_IRQ_FLL1_LOCK, ARIZONA_IRQ_FLL1_CLOCK_OK,
&wm5110->fll[0]);
arizona_init_fll(arizona, 2, ARIZONA_FLL2_CONTROL_1 - 1,
ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
&wm5110->fll[1]);
for (i = 0; i < ARRAY_SIZE(wm5110_dai); i++)
arizona_init_dai(&wm5110->core, i);
/* Latch volume update bits */
for (i = 0; i < ARRAY_SIZE(wm5110_digital_vu); i++)
regmap_update_bits(arizona->regmap, wm5110_digital_vu[i],
WM5110_DIG_VU, WM5110_DIG_VU);
pm_runtime_enable(&pdev->dev);
pm_runtime_idle(&pdev->dev);
return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110,
wm5110_dai, ARRAY_SIZE(wm5110_dai));
}
static int __devexit wm5110_remove(struct platform_device *pdev)
{
snd_soc_unregister_codec(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return 0;
}
static struct platform_driver wm5110_codec_driver = {
.driver = {
.name = "wm5110-codec",
.owner = THIS_MODULE,
},
.probe = wm5110_probe,
.remove = __devexit_p(wm5110_remove),
};
module_platform_driver(wm5110_codec_driver);
MODULE_DESCRIPTION("ASoC WM5110 driver");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:wm5110-codec");

21
sound/soc/codecs/wm5110.h Normal file
View File

@ -0,0 +1,21 @@
/*
* wm5110.h -- WM5110 ALSA SoC Audio driver
*
* Copyright 2012 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _WM5110_H
#define _WM5110_H
#include "arizona.h"
#define WM5110_FLL1 1
#define WM5110_FLL2 2
#endif

View File

@ -1,7 +1,7 @@
/* /*
* wm8350.c -- WM8350 ALSA SoC audio driver * wm8350.c -- WM8350 ALSA SoC audio driver
* *
* Copyright (C) 2007, 2008 Wolfson Microelectronics PLC. * Copyright (C) 2007-12 Wolfson Microelectronics PLC.
* *
* Author: Liam Girdwood <lrg@slimlogic.co.uk> * Author: Liam Girdwood <lrg@slimlogic.co.uk>
* *
@ -71,20 +71,6 @@ struct wm8350_data {
int fll_freq_in; int fll_freq_in;
}; };
static unsigned int wm8350_codec_read(struct snd_soc_codec *codec,
unsigned int reg)
{
struct wm8350 *wm8350 = codec->control_data;
return wm8350_reg_read(wm8350, reg);
}
static int wm8350_codec_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
struct wm8350 *wm8350 = codec->control_data;
return wm8350_reg_write(wm8350, reg, value);
}
/* /*
* Ramp OUT1 PGA volume to minimise pops at stream startup and shutdown. * Ramp OUT1 PGA volume to minimise pops at stream startup and shutdown.
*/ */
@ -1519,7 +1505,9 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec)
if (ret != 0) if (ret != 0)
return ret; return ret;
codec->control_data = wm8350; codec->control_data = wm8350->regmap;
snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
/* Put the codec into reset if it wasn't already */ /* Put the codec into reset if it wasn't already */
wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
@ -1629,8 +1617,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8350 = {
.remove = wm8350_codec_remove, .remove = wm8350_codec_remove,
.suspend = wm8350_suspend, .suspend = wm8350_suspend,
.resume = wm8350_resume, .resume = wm8350_resume,
.read = wm8350_codec_read,
.write = wm8350_codec_write,
.set_bias_level = wm8350_set_bias_level, .set_bias_level = wm8350_set_bias_level,
.controls = wm8350_snd_controls, .controls = wm8350_snd_controls,

View File

@ -1,7 +1,7 @@
/* /*
* wm8400.c -- WM8400 ALSA Soc Audio driver * wm8400.c -- WM8400 ALSA Soc Audio driver
* *
* Copyright 2008, 2009 Wolfson Microelectronics PLC. * Copyright 2008-11 Wolfson Microelectronics PLC.
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it

View File

@ -1,7 +1,7 @@
/* /*
* wm8580.c -- WM8580 ALSA Soc Audio driver * wm8580.c -- WM8580 ALSA Soc Audio driver
* *
* Copyright 2008, 2009 Wolfson Microelectronics PLC. * Copyright 2008-11 Wolfson Microelectronics PLC.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the * under the terms of the GNU General Public License as published by the

View File

@ -2,6 +2,7 @@
* wm8731.c -- WM8731 ALSA SoC Audio driver * wm8731.c -- WM8731 ALSA SoC Audio driver
* *
* Copyright 2005 Openedhand Ltd. * Copyright 2005 Openedhand Ltd.
* Copyright 2006-12 Wolfson Microelectronics, plc
* *
* Author: Richard Purdie <richard@openedhand.com> * Author: Richard Purdie <richard@openedhand.com>
* *

View File

@ -1,7 +1,7 @@
/* /*
* wm8741.c -- WM8741 ALSA SoC Audio driver * wm8741.c -- WM8741 ALSA SoC Audio driver
* *
* Copyright 2010 Wolfson Microelectronics plc * Copyright 2010-1 Wolfson Microelectronics plc
* *
* Author: Ian Lartey <ian@opensource.wolfsonmicro.com> * Author: Ian Lartey <ian@opensource.wolfsonmicro.com>
* *

View File

@ -1,7 +1,7 @@
/* /*
* wm8753.c -- WM8753 ALSA Soc Audio driver * wm8753.c -- WM8753 ALSA Soc Audio driver
* *
* Copyright 2003 Wolfson Microelectronics PLC. * Copyright 2003-11 Wolfson Microelectronics PLC.
* Author: Liam Girdwood <lrg@slimlogic.co.uk> * Author: Liam Girdwood <lrg@slimlogic.co.uk>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it

View File

@ -1,7 +1,7 @@
/* /*
* wm8776.c -- WM8776 ALSA SoC Audio driver * wm8776.c -- WM8776 ALSA SoC Audio driver
* *
* Copyright 2009 Wolfson Microelectronics plc * Copyright 2009-12 Wolfson Microelectronics plc
* *
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
* *

View File

@ -1,7 +1,7 @@
/* /*
* wm8804.c -- WM8804 S/PDIF transceiver driver * wm8804.c -- WM8804 S/PDIF transceiver driver
* *
* Copyright 2010 Wolfson Microelectronics plc * Copyright 2010-11 Wolfson Microelectronics plc
* *
* Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com> * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
* *

View File

@ -1,8 +1,8 @@
/* /*
* wm8903.c -- WM8903 ALSA SoC Audio driver * wm8903.c -- WM8903 ALSA SoC Audio driver
* *
* Copyright 2008 Wolfson Microelectronics * Copyright 2008-12 Wolfson Microelectronics
* Copyright 2011 NVIDIA, Inc. * Copyright 2011-2012 NVIDIA, Inc.
* *
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
* *
@ -116,6 +116,7 @@ static const struct reg_default wm8903_reg_defaults[] = {
struct wm8903_priv { struct wm8903_priv {
struct wm8903_platform_data *pdata; struct wm8903_platform_data *pdata;
struct device *dev;
struct snd_soc_codec *codec; struct snd_soc_codec *codec;
struct regmap *regmap; struct regmap *regmap;
@ -1635,17 +1636,27 @@ EXPORT_SYMBOL_GPL(wm8903_mic_detect);
static irqreturn_t wm8903_irq(int irq, void *data) static irqreturn_t wm8903_irq(int irq, void *data)
{ {
struct snd_soc_codec *codec = data; struct wm8903_priv *wm8903 = data;
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); int mic_report, ret;
int mic_report; unsigned int int_val, mask, int_pol;
int int_pol;
int int_val = 0;
int mask = ~snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1_MASK);
int_val = snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1) & mask; 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;
}
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) { if (int_val & WM8903_WSEQ_BUSY_EINT) {
dev_warn(codec->dev, "Write sequencer done\n"); dev_warn(wm8903->dev, "Write sequencer done\n");
} }
/* /*
@ -1656,22 +1667,28 @@ static irqreturn_t wm8903_irq(int irq, void *data)
* the polarity register. * the polarity register.
*/ */
mic_report = wm8903->mic_last_report; 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 #ifndef CONFIG_SND_SOC_WM8903_MODULE
if (int_val & (WM8903_MICSHRT_EINT | WM8903_MICDET_EINT)) 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 #endif
if (int_val & WM8903_MICSHRT_EINT) { 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; mic_report ^= wm8903->mic_short;
int_pol ^= WM8903_MICSHRT_INV; int_pol ^= WM8903_MICSHRT_INV;
} }
if (int_val & WM8903_MICDET_EINT) { 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; mic_report ^= wm8903->mic_det;
int_pol ^= WM8903_MICDET_INV; int_pol ^= WM8903_MICDET_INV;
@ -1679,8 +1696,8 @@ static irqreturn_t wm8903_irq(int irq, void *data)
msleep(wm8903->mic_delay); msleep(wm8903->mic_delay);
} }
snd_soc_update_bits(codec, WM8903_INTERRUPT_POLARITY_1, regmap_update_bits(wm8903->regmap, WM8903_INTERRUPT_POLARITY_1,
WM8903_MICSHRT_INV | WM8903_MICDET_INV, int_pol); WM8903_MICSHRT_INV | WM8903_MICDET_INV, int_pol);
snd_soc_jack_report(wm8903->mic_jack, mic_report, snd_soc_jack_report(wm8903->mic_jack, mic_report,
wm8903->mic_short | wm8903->mic_det); wm8903->mic_short | wm8903->mic_det);
@ -1774,7 +1791,6 @@ static int wm8903_gpio_request(struct gpio_chip *chip, unsigned offset)
static int wm8903_gpio_direction_in(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 wm8903_priv *wm8903 = gpio_to_wm8903(chip);
struct snd_soc_codec *codec = wm8903->codec;
unsigned int mask, val; unsigned int mask, val;
int ret; int ret;
@ -1782,8 +1798,8 @@ static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
val = (WM8903_GPn_FN_GPIO_INPUT << WM8903_GP1_FN_SHIFT) | val = (WM8903_GPn_FN_GPIO_INPUT << WM8903_GP1_FN_SHIFT) |
WM8903_GP1_DIR; WM8903_GP1_DIR;
ret = snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset, ret = regmap_update_bits(wm8903->regmap,
mask, val); WM8903_GPIO_CONTROL_1 + offset, mask, val);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -1793,10 +1809,9 @@ static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset) static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset)
{ {
struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
struct snd_soc_codec *codec = wm8903->codec; unsigned int reg;
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; return (reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT;
} }
@ -1805,7 +1820,6 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value) unsigned offset, int value)
{ {
struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
struct snd_soc_codec *codec = wm8903->codec;
unsigned int mask, val; unsigned int mask, val;
int ret; int ret;
@ -1813,8 +1827,8 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip,
val = (WM8903_GPn_FN_GPIO_OUTPUT << WM8903_GP1_FN_SHIFT) | val = (WM8903_GPn_FN_GPIO_OUTPUT << WM8903_GP1_FN_SHIFT) |
(value << WM8903_GP2_LVL_SHIFT); (value << WM8903_GP2_LVL_SHIFT);
ret = snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset, ret = regmap_update_bits(wm8903->regmap,
mask, val); WM8903_GPIO_CONTROL_1 + offset, mask, val);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -1824,11 +1838,10 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip,
static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{ {
struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); 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, regmap_update_bits(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset,
WM8903_GP1_LVL_MASK, WM8903_GP1_LVL_MASK,
!!value << WM8903_GP1_LVL_SHIFT); !!value << WM8903_GP1_LVL_SHIFT);
} }
static struct gpio_chip wm8903_template_chip = { static struct gpio_chip wm8903_template_chip = {
@ -1842,15 +1855,14 @@ static struct gpio_chip wm8903_template_chip = {
.can_sleep = 1, .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 = wm8903->pdata; struct wm8903_platform_data *pdata = wm8903->pdata;
int ret; int ret;
wm8903->gpio_chip = wm8903_template_chip; wm8903->gpio_chip = wm8903_template_chip;
wm8903->gpio_chip.ngpio = WM8903_NUM_GPIO; wm8903->gpio_chip.ngpio = WM8903_NUM_GPIO;
wm8903->gpio_chip.dev = codec->dev; wm8903->gpio_chip.dev = wm8903->dev;
if (pdata->gpio_base) if (pdata->gpio_base)
wm8903->gpio_chip.base = pdata->gpio_base; wm8903->gpio_chip.base = pdata->gpio_base;
@ -1859,24 +1871,23 @@ static void wm8903_init_gpio(struct snd_soc_codec *codec)
ret = gpiochip_add(&wm8903->gpio_chip); ret = gpiochip_add(&wm8903->gpio_chip);
if (ret != 0) 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; int ret;
ret = gpiochip_remove(&wm8903->gpio_chip); ret = gpiochip_remove(&wm8903->gpio_chip);
if (ret != 0) 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 #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 #endif
@ -1884,11 +1895,7 @@ static void wm8903_free_gpio(struct snd_soc_codec *codec)
static int wm8903_probe(struct snd_soc_codec *codec) static int wm8903_probe(struct snd_soc_codec *codec)
{ {
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
struct wm8903_platform_data *pdata = wm8903->pdata; int ret;
int ret, i;
int trigger, irq_pol;
u16 val;
bool mic_gpio = false;
wm8903->codec = codec; wm8903->codec = codec;
codec->control_data = wm8903->regmap; codec->control_data = wm8903->regmap;
@ -1899,121 +1906,16 @@ static int wm8903_probe(struct snd_soc_codec *codec)
return ret; return ret;
} }
/* Set up GPIOs, 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] & 0x7fff);
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;
}
}
/* Set up microphone detection */
snd_soc_write(codec, 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);
/* 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->irq_active_low) {
trigger = IRQF_TRIGGER_LOW;
irq_pol = WM8903_IRQ_POL;
} else {
trigger = IRQF_TRIGGER_HIGH;
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,
trigger | IRQF_ONESHOT,
"wm8903", codec);
if (ret != 0) {
dev_err(codec->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);
}
/* power on device */ /* power on device */
wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 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);
/* 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);
wm8903_init_gpio(codec);
return ret; return ret;
} }
/* power down chip */ /* power down chip */
static int wm8903_remove(struct snd_soc_codec *codec) static int wm8903_remove(struct snd_soc_codec *codec)
{ {
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
wm8903_free_gpio(codec);
wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
if (wm8903->irq)
free_irq(wm8903->irq, codec);
return 0; return 0;
} }
@ -2123,15 +2025,18 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
{ {
struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev); struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct wm8903_priv *wm8903; struct wm8903_priv *wm8903;
unsigned int val; int trigger;
int ret; bool mic_gpio = false;
unsigned int val, irq_pol;
int ret, i;
wm8903 = devm_kzalloc(&i2c->dev, sizeof(struct wm8903_priv), wm8903 = devm_kzalloc(&i2c->dev, sizeof(struct wm8903_priv),
GFP_KERNEL); GFP_KERNEL);
if (wm8903 == NULL) if (wm8903 == NULL)
return -ENOMEM; return -ENOMEM;
wm8903->dev = &i2c->dev;
wm8903->regmap = regmap_init_i2c(i2c, &wm8903_regmap); wm8903->regmap = devm_regmap_init_i2c(i2c, &wm8903_regmap);
if (IS_ERR(wm8903->regmap)) { if (IS_ERR(wm8903->regmap)) {
ret = PTR_ERR(wm8903->regmap); ret = PTR_ERR(wm8903->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n", dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@ -2140,7 +2045,6 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
} }
i2c_set_clientdata(i2c, wm8903); i2c_set_clientdata(i2c, wm8903);
wm8903->irq = i2c->irq;
/* If no platform data was supplied, create storage for defaults */ /* If no platform data was supplied, create storage for defaults */
if (pdata) { if (pdata) {
@ -2167,6 +2071,8 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
} }
} }
pdata = wm8903->pdata;
ret = regmap_read(wm8903->regmap, WM8903_SW_RESET_AND_ID, &val); ret = regmap_read(wm8903->regmap, WM8903_SW_RESET_AND_ID, &val);
if (ret != 0) { if (ret != 0) {
dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret); dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret);
@ -2189,6 +2095,107 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
/* Reset the device */ /* Reset the device */
regmap_write(wm8903->regmap, WM8903_SW_RESET_AND_ID, 0x8903); regmap_write(wm8903->regmap, WM8903_SW_RESET_AND_ID, 0x8903);
wm8903_init_gpio(wm8903);
/* 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;
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;
switch (val) {
case WM8903_GPn_FN_MICBIAS_CURRENT_DETECT:
case WM8903_GPn_FN_MICBIAS_SHORT_DETECT:
mic_gpio = true;
break;
default:
break;
}
}
/* 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)
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));
wm8903->mic_delay = pdata->micdet_delay;
if (i2c->irq) {
if (pdata->irq_active_low) {
trigger = IRQF_TRIGGER_LOW;
irq_pol = WM8903_IRQ_POL;
} else {
trigger = IRQF_TRIGGER_HIGH;
irq_pol = 0;
}
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", wm8903);
if (ret != 0) {
dev_err(wm8903->dev, "Failed to request IRQ: %d\n",
ret);
return ret;
}
/* Enable write sequencer interrupts */
regmap_update_bits(wm8903->regmap,
WM8903_INTERRUPT_STATUS_1_MASK,
WM8903_IM_WSEQ_BUSY_EINT, 0);
}
/* Latch volume update bits */
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 */
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, ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8903, &wm8903_dai, 1); &soc_codec_dev_wm8903, &wm8903_dai, 1);
if (ret != 0) if (ret != 0)
@ -2196,7 +2203,6 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
return 0; return 0;
err: err:
regmap_exit(wm8903->regmap);
return ret; return ret;
} }
@ -2204,7 +2210,9 @@ static __devexit int wm8903_i2c_remove(struct i2c_client *client)
{ {
struct wm8903_priv *wm8903 = i2c_get_clientdata(client); struct wm8903_priv *wm8903 = i2c_get_clientdata(client);
regmap_exit(wm8903->regmap); if (client->irq)
free_irq(client->irq, wm8903);
wm8903_free_gpio(wm8903);
snd_soc_unregister_codec(&client->dev); snd_soc_unregister_codec(&client->dev);
return 0; return 0;

View File

@ -1,7 +1,7 @@
/* /*
* wm8904.c -- WM8904 ALSA SoC Audio driver * wm8904.c -- WM8904 ALSA SoC Audio driver
* *
* Copyright 2009 Wolfson Microelectronics plc * Copyright 2009-12 Wolfson Microelectronics plc
* *
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
* *
@ -314,11 +314,6 @@ static bool wm8904_readable_register(struct device *dev, unsigned int reg)
} }
} }
static int wm8904_reset(struct snd_soc_codec *codec)
{
return snd_soc_write(codec, WM8904_SW_RESET_AND_ID, 0);
}
static int wm8904_configure_clocking(struct snd_soc_codec *codec) static int wm8904_configure_clocking(struct snd_soc_codec *codec)
{ {
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
@ -1945,25 +1940,6 @@ static struct snd_soc_dai_driver wm8904_dai = {
.symmetric_rates = 1, .symmetric_rates = 1,
}; };
#ifdef CONFIG_PM
static int wm8904_suspend(struct snd_soc_codec *codec)
{
wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static int wm8904_resume(struct snd_soc_codec *codec)
{
wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
#else
#define wm8904_suspend NULL
#define wm8904_resume NULL
#endif
static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec) static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec)
{ {
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
@ -2078,8 +2054,7 @@ static void wm8904_handle_pdata(struct snd_soc_codec *codec)
static int wm8904_probe(struct snd_soc_codec *codec) static int wm8904_probe(struct snd_soc_codec *codec)
{ {
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
struct wm8904_pdata *pdata = wm8904->pdata; int ret;
int ret, i;
codec->control_data = wm8904->regmap; codec->control_data = wm8904->regmap;
@ -2101,127 +2076,17 @@ static int wm8904_probe(struct snd_soc_codec *codec)
return ret; return ret;
} }
for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++)
wm8904->supplies[i].supply = wm8904_supply_names[i];
ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8904->supplies),
wm8904->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
wm8904->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
goto err_get;
}
ret = snd_soc_read(codec, WM8904_SW_RESET_AND_ID);
if (ret < 0) {
dev_err(codec->dev, "Failed to read ID register\n");
goto err_enable;
}
if (ret != 0x8904) {
dev_err(codec->dev, "Device is not a WM8904, ID is %x\n", ret);
ret = -EINVAL;
goto err_enable;
}
ret = snd_soc_read(codec, WM8904_REVISION);
if (ret < 0) {
dev_err(codec->dev, "Failed to read device revision: %d\n",
ret);
goto err_enable;
}
dev_info(codec->dev, "revision %c\n", ret + 'A');
ret = wm8904_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
goto err_enable;
}
regcache_cache_only(wm8904->regmap, true);
/* Change some default settings - latch VU and enable ZC */
snd_soc_update_bits(codec, WM8904_ADC_DIGITAL_VOLUME_LEFT,
WM8904_ADC_VU, WM8904_ADC_VU);
snd_soc_update_bits(codec, WM8904_ADC_DIGITAL_VOLUME_RIGHT,
WM8904_ADC_VU, WM8904_ADC_VU);
snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_VOLUME_LEFT,
WM8904_DAC_VU, WM8904_DAC_VU);
snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_VOLUME_RIGHT,
WM8904_DAC_VU, WM8904_DAC_VU);
snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT1_LEFT,
WM8904_HPOUT_VU | WM8904_HPOUTLZC,
WM8904_HPOUT_VU | WM8904_HPOUTLZC);
snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT1_RIGHT,
WM8904_HPOUT_VU | WM8904_HPOUTRZC,
WM8904_HPOUT_VU | WM8904_HPOUTRZC);
snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT2_LEFT,
WM8904_LINEOUT_VU | WM8904_LINEOUTLZC,
WM8904_LINEOUT_VU | WM8904_LINEOUTLZC);
snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT2_RIGHT,
WM8904_LINEOUT_VU | WM8904_LINEOUTRZC,
WM8904_LINEOUT_VU | WM8904_LINEOUTRZC);
snd_soc_update_bits(codec, WM8904_CLOCK_RATES_0,
WM8904_SR_MODE, 0);
/* Apply configuration from the platform data. */
if (wm8904->pdata) {
for (i = 0; i < WM8904_GPIO_REGS; i++) {
if (!pdata->gpio_cfg[i])
continue;
regmap_update_bits(wm8904->regmap,
WM8904_GPIO_CONTROL_1 + i,
0xffff,
pdata->gpio_cfg[i]);
}
/* Zero is the default value for these anyway */
for (i = 0; i < WM8904_MIC_REGS; i++)
regmap_update_bits(wm8904->regmap,
WM8904_MIC_BIAS_CONTROL_0 + i,
0xffff,
pdata->mic_cfg[i]);
}
/* Set Class W by default - this will be managed by the Class
* G widget at runtime where bypass paths are available.
*/
snd_soc_update_bits(codec, WM8904_CLASS_W_0,
WM8904_CP_DYN_PWR, WM8904_CP_DYN_PWR);
/* Use normal bias source */
snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
WM8904_POBCTRL, 0);
wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Bias level configuration will have done an extra enable */
regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
wm8904_handle_pdata(codec); wm8904_handle_pdata(codec);
wm8904_add_widgets(codec); wm8904_add_widgets(codec);
return 0; return 0;
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
err_get:
regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
return ret;
} }
static int wm8904_remove(struct snd_soc_codec *codec) static int wm8904_remove(struct snd_soc_codec *codec)
{ {
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF);
regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
kfree(wm8904->retune_mobile_texts); kfree(wm8904->retune_mobile_texts);
kfree(wm8904->drc_texts); kfree(wm8904->drc_texts);
@ -2231,8 +2096,6 @@ static int wm8904_remove(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_dev_wm8904 = { static struct snd_soc_codec_driver soc_codec_dev_wm8904 = {
.probe = wm8904_probe, .probe = wm8904_probe,
.remove = wm8904_remove, .remove = wm8904_remove,
.suspend = wm8904_suspend,
.resume = wm8904_resume,
.set_bias_level = wm8904_set_bias_level, .set_bias_level = wm8904_set_bias_level,
.idle_bias_off = true, .idle_bias_off = true,
}; };
@ -2254,14 +2117,15 @@ static __devinit int wm8904_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct wm8904_priv *wm8904; struct wm8904_priv *wm8904;
int ret; unsigned int val;
int ret, i;
wm8904 = devm_kzalloc(&i2c->dev, sizeof(struct wm8904_priv), wm8904 = devm_kzalloc(&i2c->dev, sizeof(struct wm8904_priv),
GFP_KERNEL); GFP_KERNEL);
if (wm8904 == NULL) if (wm8904 == NULL)
return -ENOMEM; return -ENOMEM;
wm8904->regmap = regmap_init_i2c(i2c, &wm8904_regmap); wm8904->regmap = devm_regmap_init_i2c(i2c, &wm8904_regmap);
if (IS_ERR(wm8904->regmap)) { if (IS_ERR(wm8904->regmap)) {
ret = PTR_ERR(wm8904->regmap); ret = PTR_ERR(wm8904->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n", dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@ -2273,23 +2137,121 @@ static __devinit int wm8904_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, wm8904); i2c_set_clientdata(i2c, wm8904);
wm8904->pdata = i2c->dev.platform_data; wm8904->pdata = i2c->dev.platform_data;
for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++)
wm8904->supplies[i].supply = wm8904_supply_names[i];
ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8904->supplies),
wm8904->supplies);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
wm8904->supplies);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
return ret;
}
ret = regmap_read(wm8904->regmap, WM8904_SW_RESET_AND_ID, &val);
if (ret < 0) {
dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret);
goto err_enable;
}
if (val != 0x8904) {
dev_err(&i2c->dev, "Device is not a WM8904, ID is %x\n", val);
ret = -EINVAL;
goto err_enable;
}
ret = regmap_read(wm8904->regmap, WM8904_REVISION, &val);
if (ret < 0) {
dev_err(&i2c->dev, "Failed to read device revision: %d\n",
ret);
goto err_enable;
}
dev_info(&i2c->dev, "revision %c\n", val + 'A');
ret = regmap_write(wm8904->regmap, WM8904_SW_RESET_AND_ID, 0);
if (ret < 0) {
dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret);
goto err_enable;
}
/* Change some default settings - latch VU and enable ZC */
regmap_update_bits(wm8904->regmap, WM8904_ADC_DIGITAL_VOLUME_LEFT,
WM8904_ADC_VU, WM8904_ADC_VU);
regmap_update_bits(wm8904->regmap, WM8904_ADC_DIGITAL_VOLUME_RIGHT,
WM8904_ADC_VU, WM8904_ADC_VU);
regmap_update_bits(wm8904->regmap, WM8904_DAC_DIGITAL_VOLUME_LEFT,
WM8904_DAC_VU, WM8904_DAC_VU);
regmap_update_bits(wm8904->regmap, WM8904_DAC_DIGITAL_VOLUME_RIGHT,
WM8904_DAC_VU, WM8904_DAC_VU);
regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT1_LEFT,
WM8904_HPOUT_VU | WM8904_HPOUTLZC,
WM8904_HPOUT_VU | WM8904_HPOUTLZC);
regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT1_RIGHT,
WM8904_HPOUT_VU | WM8904_HPOUTRZC,
WM8904_HPOUT_VU | WM8904_HPOUTRZC);
regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT2_LEFT,
WM8904_LINEOUT_VU | WM8904_LINEOUTLZC,
WM8904_LINEOUT_VU | WM8904_LINEOUTLZC);
regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT2_RIGHT,
WM8904_LINEOUT_VU | WM8904_LINEOUTRZC,
WM8904_LINEOUT_VU | WM8904_LINEOUTRZC);
regmap_update_bits(wm8904->regmap, WM8904_CLOCK_RATES_0,
WM8904_SR_MODE, 0);
/* Apply configuration from the platform data. */
if (wm8904->pdata) {
for (i = 0; i < WM8904_GPIO_REGS; i++) {
if (!wm8904->pdata->gpio_cfg[i])
continue;
regmap_update_bits(wm8904->regmap,
WM8904_GPIO_CONTROL_1 + i,
0xffff,
wm8904->pdata->gpio_cfg[i]);
}
/* Zero is the default value for these anyway */
for (i = 0; i < WM8904_MIC_REGS; i++)
regmap_update_bits(wm8904->regmap,
WM8904_MIC_BIAS_CONTROL_0 + i,
0xffff,
wm8904->pdata->mic_cfg[i]);
}
/* Set Class W by default - this will be managed by the Class
* G widget at runtime where bypass paths are available.
*/
regmap_update_bits(wm8904->regmap, WM8904_CLASS_W_0,
WM8904_CP_DYN_PWR, WM8904_CP_DYN_PWR);
/* Use normal bias source */
regmap_update_bits(wm8904->regmap, WM8904_BIAS_CONTROL_0,
WM8904_POBCTRL, 0);
/* Can leave the device powered off until we need it */
regcache_cache_only(wm8904->regmap, true);
regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
ret = snd_soc_register_codec(&i2c->dev, ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8904, &wm8904_dai, 1); &soc_codec_dev_wm8904, &wm8904_dai, 1);
if (ret != 0) if (ret != 0)
goto err; return ret;
return 0; return 0;
err: err_enable:
regmap_exit(wm8904->regmap); regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
return ret; return ret;
} }
static __devexit int wm8904_i2c_remove(struct i2c_client *client) static __devexit int wm8904_i2c_remove(struct i2c_client *client)
{ {
struct wm8904_priv *wm8904 = i2c_get_clientdata(client);
snd_soc_unregister_codec(&client->dev); snd_soc_unregister_codec(&client->dev);
regmap_exit(wm8904->regmap);
return 0; return 0;
} }
@ -2311,23 +2273,7 @@ static struct i2c_driver wm8904_i2c_driver = {
.id_table = wm8904_i2c_id, .id_table = wm8904_i2c_id,
}; };
static int __init wm8904_modinit(void) module_i2c_driver(wm8904_i2c_driver);
{
int ret = 0;
ret = i2c_add_driver(&wm8904_i2c_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register wm8904 I2C driver: %d\n",
ret);
}
return ret;
}
module_init(wm8904_modinit);
static void __exit wm8904_exit(void)
{
i2c_del_driver(&wm8904_i2c_driver);
}
module_exit(wm8904_exit);
MODULE_DESCRIPTION("ASoC WM8904 driver"); MODULE_DESCRIPTION("ASoC WM8904 driver");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");

View File

@ -1,6 +1,8 @@
/* /*
* wm8960.c -- WM8960 ALSA SoC Audio driver * wm8960.c -- WM8960 ALSA SoC Audio driver
* *
* Copyright 2007-11 Wolfson Microelectronics, plc
*
* Author: Liam Girdwood * Author: Liam Girdwood
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View File

@ -1,6 +1,8 @@
/* /*
* wm8961.c -- WM8961 ALSA SoC Audio driver * wm8961.c -- WM8961 ALSA SoC Audio driver
* *
* Copyright 2009-10 Wolfson Microelectronics, plc
*
* Author: Mark Brown * Author: Mark Brown
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View File

@ -1,7 +1,7 @@
/* /*
* wm8962.c -- WM8962 ALSA SoC Audio driver * wm8962.c -- WM8962 ALSA SoC Audio driver
* *
* Copyright 2010 Wolfson Microelectronics plc * Copyright 2010-2 Wolfson Microelectronics plc
* *
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
* *
@ -2580,6 +2580,9 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
WM8962_SAMPLE_RATE_INT_MODE | WM8962_SAMPLE_RATE_INT_MODE |
WM8962_SAMPLE_RATE_MASK, adctl3); WM8962_SAMPLE_RATE_MASK, adctl3);
dev_dbg(codec->dev, "hw_params set BCLK %dHz LRCLK %dHz\n",
wm8962->bclk, wm8962->lrclk);
if (codec->dapm.bias_level == SND_SOC_BIAS_ON) if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
wm8962_configure_bclk(codec); wm8962_configure_bclk(codec);
@ -3722,6 +3725,9 @@ static int wm8962_runtime_resume(struct device *dev)
} }
regcache_cache_only(wm8962->regmap, false); regcache_cache_only(wm8962->regmap, false);
wm8962_reset(wm8962);
regcache_sync(wm8962->regmap); regcache_sync(wm8962->regmap);
regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP, regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP,

View File

@ -1,7 +1,7 @@
/* /*
* wm8993.c -- WM8993 ALSA SoC audio driver * wm8993.c -- WM8993 ALSA SoC audio driver
* *
* Copyright 2009, 2010 Wolfson Microelectronics plc * Copyright 2009-12 Wolfson Microelectronics plc
* *
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
* *

View File

@ -1,7 +1,7 @@
/* /*
* wm8994.c -- WM8994 ALSA SoC Audio driver * wm8994.c -- WM8994 ALSA SoC Audio driver
* *
* Copyright 2009 Wolfson Microelectronics plc * Copyright 2009-12 Wolfson Microelectronics plc
* *
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
* *
@ -2967,23 +2967,8 @@ static struct snd_soc_dai_driver wm8994_dai[] = {
static int wm8994_codec_suspend(struct snd_soc_codec *codec) static int wm8994_codec_suspend(struct snd_soc_codec *codec)
{ {
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = wm8994->wm8994;
int i, ret; int i, ret;
switch (control->type) {
case WM8994:
snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, 0);
break;
case WM1811:
snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
WM1811_JACKDET_MODE_MASK, 0);
/* Fall through */
case WM8958:
snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
WM8958_MICD_ENA, 0);
break;
}
for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i], memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i],
sizeof(struct wm8994_fll_config)); sizeof(struct wm8994_fll_config));
@ -3033,28 +3018,6 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec)
i + 1, ret); i + 1, ret);
} }
switch (control->type) {
case WM8994:
if (wm8994->micdet[0].jack || wm8994->micdet[1].jack)
snd_soc_update_bits(codec, WM8994_MICBIAS,
WM8994_MICD_ENA, WM8994_MICD_ENA);
break;
case WM1811:
if (wm8994->jackdet && wm8994->jack_cb) {
/* Restart from idle */
snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
WM1811_JACKDET_MODE_MASK,
WM1811_JACKDET_MODE_JACK);
break;
}
break;
case WM8958:
if (wm8994->jack_cb)
snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
WM8958_MICD_ENA, WM8958_MICD_ENA);
break;
}
return 0; return 0;
} }
#else #else
@ -3729,9 +3692,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
if (wm8994->pdata && wm8994->pdata->micdet_irq) if (wm8994->pdata && wm8994->pdata->micdet_irq)
wm8994->micdet_irq = wm8994->pdata->micdet_irq; wm8994->micdet_irq = wm8994->pdata->micdet_irq;
else if (wm8994->pdata && wm8994->pdata->irq_base)
wm8994->micdet_irq = wm8994->pdata->irq_base +
WM8994_IRQ_MIC1_DET;
pm_runtime_enable(codec->dev); pm_runtime_enable(codec->dev);
pm_runtime_idle(codec->dev); pm_runtime_idle(codec->dev);
@ -3870,6 +3830,10 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
dev_warn(codec->dev, dev_warn(codec->dev,
"Failed to request Mic detect IRQ: %d\n", "Failed to request Mic detect IRQ: %d\n",
ret); ret);
} else {
wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_MIC1_DET,
wm8958_mic_irq, "Mic detect",
wm8994);
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* wm8996.c - WM8996 audio codec interface * wm8996.c - WM8996 audio codec interface
* *
* Copyright 2011 Wolfson Microelectronics PLC. * Copyright 2011-2 Wolfson Microelectronics PLC.
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
@ -296,184 +296,6 @@ static struct reg_default wm8996_reg[] = {
{ WM8996_RIGHT_PDM_SPEAKER, 0x1 }, { WM8996_RIGHT_PDM_SPEAKER, 0x1 },
{ WM8996_PDM_SPEAKER_MUTE_SEQUENCE, 0x69 }, { WM8996_PDM_SPEAKER_MUTE_SEQUENCE, 0x69 },
{ WM8996_PDM_SPEAKER_VOLUME, 0x66 }, { WM8996_PDM_SPEAKER_VOLUME, 0x66 },
{ WM8996_WRITE_SEQUENCER_0, 0x1 },
{ WM8996_WRITE_SEQUENCER_1, 0x1 },
{ WM8996_WRITE_SEQUENCER_3, 0x6 },
{ WM8996_WRITE_SEQUENCER_4, 0x40 },
{ WM8996_WRITE_SEQUENCER_5, 0x1 },
{ WM8996_WRITE_SEQUENCER_6, 0xf },
{ WM8996_WRITE_SEQUENCER_7, 0x6 },
{ WM8996_WRITE_SEQUENCER_8, 0x1 },
{ WM8996_WRITE_SEQUENCER_9, 0x3 },
{ WM8996_WRITE_SEQUENCER_10, 0x104 },
{ WM8996_WRITE_SEQUENCER_12, 0x60 },
{ WM8996_WRITE_SEQUENCER_13, 0x11 },
{ WM8996_WRITE_SEQUENCER_14, 0x401 },
{ WM8996_WRITE_SEQUENCER_16, 0x50 },
{ WM8996_WRITE_SEQUENCER_17, 0x3 },
{ WM8996_WRITE_SEQUENCER_18, 0x100 },
{ WM8996_WRITE_SEQUENCER_20, 0x51 },
{ WM8996_WRITE_SEQUENCER_21, 0x3 },
{ WM8996_WRITE_SEQUENCER_22, 0x104 },
{ WM8996_WRITE_SEQUENCER_23, 0xa },
{ WM8996_WRITE_SEQUENCER_24, 0x60 },
{ WM8996_WRITE_SEQUENCER_25, 0x3b },
{ WM8996_WRITE_SEQUENCER_26, 0x502 },
{ WM8996_WRITE_SEQUENCER_27, 0x100 },
{ WM8996_WRITE_SEQUENCER_28, 0x2fff },
{ WM8996_WRITE_SEQUENCER_32, 0x2fff },
{ WM8996_WRITE_SEQUENCER_36, 0x2fff },
{ WM8996_WRITE_SEQUENCER_40, 0x2fff },
{ WM8996_WRITE_SEQUENCER_44, 0x2fff },
{ WM8996_WRITE_SEQUENCER_48, 0x2fff },
{ WM8996_WRITE_SEQUENCER_52, 0x2fff },
{ WM8996_WRITE_SEQUENCER_56, 0x2fff },
{ WM8996_WRITE_SEQUENCER_60, 0x2fff },
{ WM8996_WRITE_SEQUENCER_64, 0x1 },
{ WM8996_WRITE_SEQUENCER_65, 0x1 },
{ WM8996_WRITE_SEQUENCER_67, 0x6 },
{ WM8996_WRITE_SEQUENCER_68, 0x40 },
{ WM8996_WRITE_SEQUENCER_69, 0x1 },
{ WM8996_WRITE_SEQUENCER_70, 0xf },
{ WM8996_WRITE_SEQUENCER_71, 0x6 },
{ WM8996_WRITE_SEQUENCER_72, 0x1 },
{ WM8996_WRITE_SEQUENCER_73, 0x3 },
{ WM8996_WRITE_SEQUENCER_74, 0x104 },
{ WM8996_WRITE_SEQUENCER_76, 0x60 },
{ WM8996_WRITE_SEQUENCER_77, 0x11 },
{ WM8996_WRITE_SEQUENCER_78, 0x401 },
{ WM8996_WRITE_SEQUENCER_80, 0x50 },
{ WM8996_WRITE_SEQUENCER_81, 0x3 },
{ WM8996_WRITE_SEQUENCER_82, 0x100 },
{ WM8996_WRITE_SEQUENCER_84, 0x60 },
{ WM8996_WRITE_SEQUENCER_85, 0x3b },
{ WM8996_WRITE_SEQUENCER_86, 0x502 },
{ WM8996_WRITE_SEQUENCER_87, 0x100 },
{ WM8996_WRITE_SEQUENCER_88, 0x2fff },
{ WM8996_WRITE_SEQUENCER_92, 0x2fff },
{ WM8996_WRITE_SEQUENCER_96, 0x2fff },
{ WM8996_WRITE_SEQUENCER_100, 0x2fff },
{ WM8996_WRITE_SEQUENCER_104, 0x2fff },
{ WM8996_WRITE_SEQUENCER_108, 0x2fff },
{ WM8996_WRITE_SEQUENCER_112, 0x2fff },
{ WM8996_WRITE_SEQUENCER_116, 0x2fff },
{ WM8996_WRITE_SEQUENCER_120, 0x2fff },
{ WM8996_WRITE_SEQUENCER_124, 0x2fff },
{ WM8996_WRITE_SEQUENCER_128, 0x1 },
{ WM8996_WRITE_SEQUENCER_129, 0x1 },
{ WM8996_WRITE_SEQUENCER_131, 0x6 },
{ WM8996_WRITE_SEQUENCER_132, 0x40 },
{ WM8996_WRITE_SEQUENCER_133, 0x1 },
{ WM8996_WRITE_SEQUENCER_134, 0xf },
{ WM8996_WRITE_SEQUENCER_135, 0x6 },
{ WM8996_WRITE_SEQUENCER_136, 0x1 },
{ WM8996_WRITE_SEQUENCER_137, 0x3 },
{ WM8996_WRITE_SEQUENCER_138, 0x106 },
{ WM8996_WRITE_SEQUENCER_140, 0x61 },
{ WM8996_WRITE_SEQUENCER_141, 0x11 },
{ WM8996_WRITE_SEQUENCER_142, 0x401 },
{ WM8996_WRITE_SEQUENCER_144, 0x50 },
{ WM8996_WRITE_SEQUENCER_145, 0x3 },
{ WM8996_WRITE_SEQUENCER_146, 0x102 },
{ WM8996_WRITE_SEQUENCER_148, 0x51 },
{ WM8996_WRITE_SEQUENCER_149, 0x3 },
{ WM8996_WRITE_SEQUENCER_150, 0x106 },
{ WM8996_WRITE_SEQUENCER_151, 0xa },
{ WM8996_WRITE_SEQUENCER_152, 0x61 },
{ WM8996_WRITE_SEQUENCER_153, 0x3b },
{ WM8996_WRITE_SEQUENCER_154, 0x502 },
{ WM8996_WRITE_SEQUENCER_155, 0x100 },
{ WM8996_WRITE_SEQUENCER_156, 0x2fff },
{ WM8996_WRITE_SEQUENCER_160, 0x2fff },
{ WM8996_WRITE_SEQUENCER_164, 0x2fff },
{ WM8996_WRITE_SEQUENCER_168, 0x2fff },
{ WM8996_WRITE_SEQUENCER_172, 0x2fff },
{ WM8996_WRITE_SEQUENCER_176, 0x2fff },
{ WM8996_WRITE_SEQUENCER_180, 0x2fff },
{ WM8996_WRITE_SEQUENCER_184, 0x2fff },
{ WM8996_WRITE_SEQUENCER_188, 0x2fff },
{ WM8996_WRITE_SEQUENCER_192, 0x1 },
{ WM8996_WRITE_SEQUENCER_193, 0x1 },
{ WM8996_WRITE_SEQUENCER_195, 0x6 },
{ WM8996_WRITE_SEQUENCER_196, 0x40 },
{ WM8996_WRITE_SEQUENCER_197, 0x1 },
{ WM8996_WRITE_SEQUENCER_198, 0xf },
{ WM8996_WRITE_SEQUENCER_199, 0x6 },
{ WM8996_WRITE_SEQUENCER_200, 0x1 },
{ WM8996_WRITE_SEQUENCER_201, 0x3 },
{ WM8996_WRITE_SEQUENCER_202, 0x106 },
{ WM8996_WRITE_SEQUENCER_204, 0x61 },
{ WM8996_WRITE_SEQUENCER_205, 0x11 },
{ WM8996_WRITE_SEQUENCER_206, 0x401 },
{ WM8996_WRITE_SEQUENCER_208, 0x50 },
{ WM8996_WRITE_SEQUENCER_209, 0x3 },
{ WM8996_WRITE_SEQUENCER_210, 0x102 },
{ WM8996_WRITE_SEQUENCER_212, 0x61 },
{ WM8996_WRITE_SEQUENCER_213, 0x3b },
{ WM8996_WRITE_SEQUENCER_214, 0x502 },
{ WM8996_WRITE_SEQUENCER_215, 0x100 },
{ WM8996_WRITE_SEQUENCER_216, 0x2fff },
{ WM8996_WRITE_SEQUENCER_220, 0x2fff },
{ WM8996_WRITE_SEQUENCER_224, 0x2fff },
{ WM8996_WRITE_SEQUENCER_228, 0x2fff },
{ WM8996_WRITE_SEQUENCER_232, 0x2fff },
{ WM8996_WRITE_SEQUENCER_236, 0x2fff },
{ WM8996_WRITE_SEQUENCER_240, 0x2fff },
{ WM8996_WRITE_SEQUENCER_244, 0x2fff },
{ WM8996_WRITE_SEQUENCER_248, 0x2fff },
{ WM8996_WRITE_SEQUENCER_252, 0x2fff },
{ WM8996_WRITE_SEQUENCER_256, 0x60 },
{ WM8996_WRITE_SEQUENCER_258, 0x601 },
{ WM8996_WRITE_SEQUENCER_260, 0x50 },
{ WM8996_WRITE_SEQUENCER_262, 0x100 },
{ WM8996_WRITE_SEQUENCER_264, 0x1 },
{ WM8996_WRITE_SEQUENCER_266, 0x104 },
{ WM8996_WRITE_SEQUENCER_267, 0x100 },
{ WM8996_WRITE_SEQUENCER_268, 0x2fff },
{ WM8996_WRITE_SEQUENCER_272, 0x2fff },
{ WM8996_WRITE_SEQUENCER_276, 0x2fff },
{ WM8996_WRITE_SEQUENCER_280, 0x2fff },
{ WM8996_WRITE_SEQUENCER_284, 0x2fff },
{ WM8996_WRITE_SEQUENCER_288, 0x2fff },
{ WM8996_WRITE_SEQUENCER_292, 0x2fff },
{ WM8996_WRITE_SEQUENCER_296, 0x2fff },
{ WM8996_WRITE_SEQUENCER_300, 0x2fff },
{ WM8996_WRITE_SEQUENCER_304, 0x2fff },
{ WM8996_WRITE_SEQUENCER_308, 0x2fff },
{ WM8996_WRITE_SEQUENCER_312, 0x2fff },
{ WM8996_WRITE_SEQUENCER_316, 0x2fff },
{ WM8996_WRITE_SEQUENCER_320, 0x61 },
{ WM8996_WRITE_SEQUENCER_322, 0x601 },
{ WM8996_WRITE_SEQUENCER_324, 0x50 },
{ WM8996_WRITE_SEQUENCER_326, 0x102 },
{ WM8996_WRITE_SEQUENCER_328, 0x1 },
{ WM8996_WRITE_SEQUENCER_330, 0x106 },
{ WM8996_WRITE_SEQUENCER_331, 0x100 },
{ WM8996_WRITE_SEQUENCER_332, 0x2fff },
{ WM8996_WRITE_SEQUENCER_336, 0x2fff },
{ WM8996_WRITE_SEQUENCER_340, 0x2fff },
{ WM8996_WRITE_SEQUENCER_344, 0x2fff },
{ WM8996_WRITE_SEQUENCER_348, 0x2fff },
{ WM8996_WRITE_SEQUENCER_352, 0x2fff },
{ WM8996_WRITE_SEQUENCER_356, 0x2fff },
{ WM8996_WRITE_SEQUENCER_360, 0x2fff },
{ WM8996_WRITE_SEQUENCER_364, 0x2fff },
{ WM8996_WRITE_SEQUENCER_368, 0x2fff },
{ WM8996_WRITE_SEQUENCER_372, 0x2fff },
{ WM8996_WRITE_SEQUENCER_376, 0x2fff },
{ WM8996_WRITE_SEQUENCER_380, 0x2fff },
{ WM8996_WRITE_SEQUENCER_384, 0x60 },
{ WM8996_WRITE_SEQUENCER_386, 0x601 },
{ WM8996_WRITE_SEQUENCER_388, 0x61 },
{ WM8996_WRITE_SEQUENCER_390, 0x601 },
{ WM8996_WRITE_SEQUENCER_392, 0x50 },
{ WM8996_WRITE_SEQUENCER_394, 0x300 },
{ WM8996_WRITE_SEQUENCER_396, 0x1 },
{ WM8996_WRITE_SEQUENCER_398, 0x304 },
{ WM8996_WRITE_SEQUENCER_400, 0x40 },
{ WM8996_WRITE_SEQUENCER_402, 0xf },
{ WM8996_WRITE_SEQUENCER_404, 0x1 },
{ WM8996_WRITE_SEQUENCER_407, 0x100 },
}; };
static const DECLARE_TLV_DB_SCALE(inpga_tlv, 0, 100, 0); static const DECLARE_TLV_DB_SCALE(inpga_tlv, 0, 100, 0);
@ -1706,18 +1528,6 @@ static bool wm8996_volatile_register(struct device *dev, unsigned int reg)
} }
} }
static int wm8996_reset(struct wm8996_priv *wm8996)
{
if (wm8996->pdata.ldo_ena > 0) {
gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 1);
return 0;
} else {
return regmap_write(wm8996->regmap, WM8996_SOFTWARE_RESET,
0x8915);
}
}
static const int bclk_divs[] = { static const int bclk_divs[] = {
1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96
}; };
@ -1809,8 +1619,10 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
regcache_cache_only(codec->control_data, true); regcache_cache_only(codec->control_data, true);
if (wm8996->pdata.ldo_ena >= 0) if (wm8996->pdata.ldo_ena >= 0) {
gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
regcache_cache_only(codec->control_data, true);
}
regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies),
wm8996->supplies); wm8996->supplies);
break; break;
@ -2807,7 +2619,7 @@ static int wm8996_probe(struct snd_soc_codec *codec)
int ret; int ret;
struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
struct i2c_client *i2c = to_i2c_client(codec->dev); struct i2c_client *i2c = to_i2c_client(codec->dev);
int i, irq_flags; int irq_flags;
wm8996->codec = codec; wm8996->codec = codec;
@ -2822,177 +2634,12 @@ static int wm8996_probe(struct snd_soc_codec *codec)
goto err; goto err;
} }
wm8996->disable_nb[0].notifier_call = wm8996_regulator_event_0;
wm8996->disable_nb[1].notifier_call = wm8996_regulator_event_1;
wm8996->disable_nb[2].notifier_call = wm8996_regulator_event_2;
/* This should really be moved into the regulator core */
for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) {
ret = regulator_register_notifier(wm8996->supplies[i].consumer,
&wm8996->disable_nb[i]);
if (ret != 0) {
dev_err(codec->dev,
"Failed to register regulator notifier: %d\n",
ret);
}
}
/* Apply platform data settings */
snd_soc_update_bits(codec, WM8996_LINE_INPUT_CONTROL,
WM8996_INL_MODE_MASK | WM8996_INR_MODE_MASK,
wm8996->pdata.inl_mode << WM8996_INL_MODE_SHIFT |
wm8996->pdata.inr_mode);
for (i = 0; i < ARRAY_SIZE(wm8996->pdata.gpio_default); i++) {
if (!wm8996->pdata.gpio_default[i])
continue;
snd_soc_write(codec, WM8996_GPIO_1 + i,
wm8996->pdata.gpio_default[i] & 0xffff);
}
if (wm8996->pdata.spkmute_seq)
snd_soc_update_bits(codec, WM8996_PDM_SPEAKER_MUTE_SEQUENCE,
WM8996_SPK_MUTE_ENDIAN |
WM8996_SPK_MUTE_SEQ1_MASK,
wm8996->pdata.spkmute_seq);
snd_soc_update_bits(codec, WM8996_ACCESSORY_DETECT_MODE_2,
WM8996_MICD_BIAS_SRC | WM8996_HPOUT1FB_SRC |
WM8996_MICD_SRC, wm8996->pdata.micdet_def);
/* Latch volume update bits */
snd_soc_update_bits(codec, WM8996_LEFT_LINE_INPUT_VOLUME,
WM8996_IN1_VU, WM8996_IN1_VU);
snd_soc_update_bits(codec, WM8996_RIGHT_LINE_INPUT_VOLUME,
WM8996_IN1_VU, WM8996_IN1_VU);
snd_soc_update_bits(codec, WM8996_DAC1_LEFT_VOLUME,
WM8996_DAC1_VU, WM8996_DAC1_VU);
snd_soc_update_bits(codec, WM8996_DAC1_RIGHT_VOLUME,
WM8996_DAC1_VU, WM8996_DAC1_VU);
snd_soc_update_bits(codec, WM8996_DAC2_LEFT_VOLUME,
WM8996_DAC2_VU, WM8996_DAC2_VU);
snd_soc_update_bits(codec, WM8996_DAC2_RIGHT_VOLUME,
WM8996_DAC2_VU, WM8996_DAC2_VU);
snd_soc_update_bits(codec, WM8996_OUTPUT1_LEFT_VOLUME,
WM8996_DAC1_VU, WM8996_DAC1_VU);
snd_soc_update_bits(codec, WM8996_OUTPUT1_RIGHT_VOLUME,
WM8996_DAC1_VU, WM8996_DAC1_VU);
snd_soc_update_bits(codec, WM8996_OUTPUT2_LEFT_VOLUME,
WM8996_DAC2_VU, WM8996_DAC2_VU);
snd_soc_update_bits(codec, WM8996_OUTPUT2_RIGHT_VOLUME,
WM8996_DAC2_VU, WM8996_DAC2_VU);
snd_soc_update_bits(codec, WM8996_DSP1_TX_LEFT_VOLUME,
WM8996_DSP1TX_VU, WM8996_DSP1TX_VU);
snd_soc_update_bits(codec, WM8996_DSP1_TX_RIGHT_VOLUME,
WM8996_DSP1TX_VU, WM8996_DSP1TX_VU);
snd_soc_update_bits(codec, WM8996_DSP2_TX_LEFT_VOLUME,
WM8996_DSP2TX_VU, WM8996_DSP2TX_VU);
snd_soc_update_bits(codec, WM8996_DSP2_TX_RIGHT_VOLUME,
WM8996_DSP2TX_VU, WM8996_DSP2TX_VU);
snd_soc_update_bits(codec, WM8996_DSP1_RX_LEFT_VOLUME,
WM8996_DSP1RX_VU, WM8996_DSP1RX_VU);
snd_soc_update_bits(codec, WM8996_DSP1_RX_RIGHT_VOLUME,
WM8996_DSP1RX_VU, WM8996_DSP1RX_VU);
snd_soc_update_bits(codec, WM8996_DSP2_RX_LEFT_VOLUME,
WM8996_DSP2RX_VU, WM8996_DSP2RX_VU);
snd_soc_update_bits(codec, WM8996_DSP2_RX_RIGHT_VOLUME,
WM8996_DSP2RX_VU, WM8996_DSP2RX_VU);
/* No support currently for the underclocked TDM modes and
* pick a default TDM layout with each channel pair working with
* slots 0 and 1. */
snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_0_CONFIGURATION,
WM8996_AIF1RX_CHAN0_SLOTS_MASK |
WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1RX_CHAN0_SLOTS_SHIFT | 0);
snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_1_CONFIGURATION,
WM8996_AIF1RX_CHAN1_SLOTS_MASK |
WM8996_AIF1RX_CHAN1_START_SLOT_MASK,
1 << WM8996_AIF1RX_CHAN1_SLOTS_SHIFT | 1);
snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_2_CONFIGURATION,
WM8996_AIF1RX_CHAN2_SLOTS_MASK |
WM8996_AIF1RX_CHAN2_START_SLOT_MASK,
1 << WM8996_AIF1RX_CHAN2_SLOTS_SHIFT | 0);
snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_3_CONFIGURATION,
WM8996_AIF1RX_CHAN3_SLOTS_MASK |
WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1RX_CHAN3_SLOTS_SHIFT | 1);
snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_4_CONFIGURATION,
WM8996_AIF1RX_CHAN4_SLOTS_MASK |
WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1RX_CHAN4_SLOTS_SHIFT | 0);
snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_5_CONFIGURATION,
WM8996_AIF1RX_CHAN5_SLOTS_MASK |
WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1RX_CHAN5_SLOTS_SHIFT | 1);
snd_soc_update_bits(codec, WM8996_AIF2RX_CHANNEL_0_CONFIGURATION,
WM8996_AIF2RX_CHAN0_SLOTS_MASK |
WM8996_AIF2RX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF2RX_CHAN0_SLOTS_SHIFT | 0);
snd_soc_update_bits(codec, WM8996_AIF2RX_CHANNEL_1_CONFIGURATION,
WM8996_AIF2RX_CHAN1_SLOTS_MASK |
WM8996_AIF2RX_CHAN1_START_SLOT_MASK,
1 << WM8996_AIF2RX_CHAN1_SLOTS_SHIFT | 1);
snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_0_CONFIGURATION,
WM8996_AIF1TX_CHAN0_SLOTS_MASK |
WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1TX_CHAN0_SLOTS_SHIFT | 0);
snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_1_CONFIGURATION,
WM8996_AIF1TX_CHAN1_SLOTS_MASK |
WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_2_CONFIGURATION,
WM8996_AIF1TX_CHAN2_SLOTS_MASK |
WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1TX_CHAN2_SLOTS_SHIFT | 0);
snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_3_CONFIGURATION,
WM8996_AIF1TX_CHAN3_SLOTS_MASK |
WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1TX_CHAN3_SLOTS_SHIFT | 1);
snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_4_CONFIGURATION,
WM8996_AIF1TX_CHAN4_SLOTS_MASK |
WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1TX_CHAN4_SLOTS_SHIFT | 0);
snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_5_CONFIGURATION,
WM8996_AIF1TX_CHAN5_SLOTS_MASK |
WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1TX_CHAN5_SLOTS_SHIFT | 1);
snd_soc_update_bits(codec, WM8996_AIF2TX_CHANNEL_0_CONFIGURATION,
WM8996_AIF2TX_CHAN0_SLOTS_MASK |
WM8996_AIF2TX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF2TX_CHAN0_SLOTS_SHIFT | 0);
snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_1_CONFIGURATION,
WM8996_AIF2TX_CHAN1_SLOTS_MASK |
WM8996_AIF2TX_CHAN1_START_SLOT_MASK,
1 << WM8996_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
if (wm8996->pdata.num_retune_mobile_cfgs) if (wm8996->pdata.num_retune_mobile_cfgs)
wm8996_retune_mobile_pdata(codec); wm8996_retune_mobile_pdata(codec);
else else
snd_soc_add_codec_controls(codec, wm8996_eq_controls, snd_soc_add_codec_controls(codec, wm8996_eq_controls,
ARRAY_SIZE(wm8996_eq_controls)); ARRAY_SIZE(wm8996_eq_controls));
/* If the TX LRCLK pins are not in LRCLK mode configure the
* AIFs to source their clocks from the RX LRCLKs.
*/
if ((snd_soc_read(codec, WM8996_GPIO_1)))
snd_soc_update_bits(codec, WM8996_AIF1_TX_LRCLK_2,
WM8996_AIF1TX_LRCLK_MODE,
WM8996_AIF1TX_LRCLK_MODE);
if ((snd_soc_read(codec, WM8996_GPIO_2)))
snd_soc_update_bits(codec, WM8996_AIF2_TX_LRCLK_2,
WM8996_AIF2TX_LRCLK_MODE,
WM8996_AIF2TX_LRCLK_MODE);
if (i2c->irq) { if (i2c->irq) {
if (wm8996->pdata.irq_flags) if (wm8996->pdata.irq_flags)
irq_flags = wm8996->pdata.irq_flags; irq_flags = wm8996->pdata.irq_flags;
@ -3036,9 +2683,7 @@ err:
static int wm8996_remove(struct snd_soc_codec *codec) static int wm8996_remove(struct snd_soc_codec *codec)
{ {
struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
struct i2c_client *i2c = to_i2c_client(codec->dev); struct i2c_client *i2c = to_i2c_client(codec->dev);
int i;
snd_soc_update_bits(codec, WM8996_INTERRUPT_CONTROL, snd_soc_update_bits(codec, WM8996_INTERRUPT_CONTROL,
WM8996_IM_IRQ, WM8996_IM_IRQ); WM8996_IM_IRQ, WM8996_IM_IRQ);
@ -3046,10 +2691,6 @@ static int wm8996_remove(struct snd_soc_codec *codec)
if (i2c->irq) if (i2c->irq)
free_irq(i2c->irq, codec); free_irq(i2c->irq, codec);
for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++)
regulator_unregister_notifier(wm8996->supplies[i].consumer,
&wm8996->disable_nb[i]);
return 0; return 0;
} }
@ -3163,6 +2804,21 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c,
goto err_gpio; goto err_gpio;
} }
wm8996->disable_nb[0].notifier_call = wm8996_regulator_event_0;
wm8996->disable_nb[1].notifier_call = wm8996_regulator_event_1;
wm8996->disable_nb[2].notifier_call = wm8996_regulator_event_2;
/* This should really be moved into the regulator core */
for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) {
ret = regulator_register_notifier(wm8996->supplies[i].consumer,
&wm8996->disable_nb[i]);
if (ret != 0) {
dev_err(&i2c->dev,
"Failed to register regulator notifier: %d\n",
ret);
}
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8996->supplies), ret = regulator_bulk_enable(ARRAY_SIZE(wm8996->supplies),
wm8996->supplies); wm8996->supplies);
if (ret != 0) { if (ret != 0) {
@ -3175,7 +2831,7 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c,
msleep(5); msleep(5);
} }
wm8996->regmap = regmap_init_i2c(i2c, &wm8996_regmap); wm8996->regmap = devm_regmap_init_i2c(i2c, &wm8996_regmap);
if (IS_ERR(wm8996->regmap)) { if (IS_ERR(wm8996->regmap)) {
ret = PTR_ERR(wm8996->regmap); ret = PTR_ERR(wm8996->regmap);
dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret); dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
@ -3203,14 +2859,198 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c,
dev_info(&i2c->dev, "revision %c\n", dev_info(&i2c->dev, "revision %c\n",
(reg & WM8996_CHIP_REV_MASK) + 'A'); (reg & WM8996_CHIP_REV_MASK) + 'A');
ret = wm8996_reset(wm8996); if (wm8996->pdata.ldo_ena > 0) {
if (ret < 0) { gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
dev_err(&i2c->dev, "Failed to issue reset\n"); regcache_cache_only(wm8996->regmap, true);
} else {
ret = regmap_write(wm8996->regmap, WM8996_SOFTWARE_RESET,
0x8915);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret);
goto err_regmap;
}
}
regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
/* Apply platform data settings */
regmap_update_bits(wm8996->regmap, WM8996_LINE_INPUT_CONTROL,
WM8996_INL_MODE_MASK | WM8996_INR_MODE_MASK,
wm8996->pdata.inl_mode << WM8996_INL_MODE_SHIFT |
wm8996->pdata.inr_mode);
for (i = 0; i < ARRAY_SIZE(wm8996->pdata.gpio_default); i++) {
if (!wm8996->pdata.gpio_default[i])
continue;
regmap_write(wm8996->regmap, WM8996_GPIO_1 + i,
wm8996->pdata.gpio_default[i] & 0xffff);
}
if (wm8996->pdata.spkmute_seq)
regmap_update_bits(wm8996->regmap,
WM8996_PDM_SPEAKER_MUTE_SEQUENCE,
WM8996_SPK_MUTE_ENDIAN |
WM8996_SPK_MUTE_SEQ1_MASK,
wm8996->pdata.spkmute_seq);
regmap_update_bits(wm8996->regmap, WM8996_ACCESSORY_DETECT_MODE_2,
WM8996_MICD_BIAS_SRC | WM8996_HPOUT1FB_SRC |
WM8996_MICD_SRC, wm8996->pdata.micdet_def);
/* Latch volume update bits */
regmap_update_bits(wm8996->regmap, WM8996_LEFT_LINE_INPUT_VOLUME,
WM8996_IN1_VU, WM8996_IN1_VU);
regmap_update_bits(wm8996->regmap, WM8996_RIGHT_LINE_INPUT_VOLUME,
WM8996_IN1_VU, WM8996_IN1_VU);
regmap_update_bits(wm8996->regmap, WM8996_DAC1_LEFT_VOLUME,
WM8996_DAC1_VU, WM8996_DAC1_VU);
regmap_update_bits(wm8996->regmap, WM8996_DAC1_RIGHT_VOLUME,
WM8996_DAC1_VU, WM8996_DAC1_VU);
regmap_update_bits(wm8996->regmap, WM8996_DAC2_LEFT_VOLUME,
WM8996_DAC2_VU, WM8996_DAC2_VU);
regmap_update_bits(wm8996->regmap, WM8996_DAC2_RIGHT_VOLUME,
WM8996_DAC2_VU, WM8996_DAC2_VU);
regmap_update_bits(wm8996->regmap, WM8996_OUTPUT1_LEFT_VOLUME,
WM8996_DAC1_VU, WM8996_DAC1_VU);
regmap_update_bits(wm8996->regmap, WM8996_OUTPUT1_RIGHT_VOLUME,
WM8996_DAC1_VU, WM8996_DAC1_VU);
regmap_update_bits(wm8996->regmap, WM8996_OUTPUT2_LEFT_VOLUME,
WM8996_DAC2_VU, WM8996_DAC2_VU);
regmap_update_bits(wm8996->regmap, WM8996_OUTPUT2_RIGHT_VOLUME,
WM8996_DAC2_VU, WM8996_DAC2_VU);
regmap_update_bits(wm8996->regmap, WM8996_DSP1_TX_LEFT_VOLUME,
WM8996_DSP1TX_VU, WM8996_DSP1TX_VU);
regmap_update_bits(wm8996->regmap, WM8996_DSP1_TX_RIGHT_VOLUME,
WM8996_DSP1TX_VU, WM8996_DSP1TX_VU);
regmap_update_bits(wm8996->regmap, WM8996_DSP2_TX_LEFT_VOLUME,
WM8996_DSP2TX_VU, WM8996_DSP2TX_VU);
regmap_update_bits(wm8996->regmap, WM8996_DSP2_TX_RIGHT_VOLUME,
WM8996_DSP2TX_VU, WM8996_DSP2TX_VU);
regmap_update_bits(wm8996->regmap, WM8996_DSP1_RX_LEFT_VOLUME,
WM8996_DSP1RX_VU, WM8996_DSP1RX_VU);
regmap_update_bits(wm8996->regmap, WM8996_DSP1_RX_RIGHT_VOLUME,
WM8996_DSP1RX_VU, WM8996_DSP1RX_VU);
regmap_update_bits(wm8996->regmap, WM8996_DSP2_RX_LEFT_VOLUME,
WM8996_DSP2RX_VU, WM8996_DSP2RX_VU);
regmap_update_bits(wm8996->regmap, WM8996_DSP2_RX_RIGHT_VOLUME,
WM8996_DSP2RX_VU, WM8996_DSP2RX_VU);
/* No support currently for the underclocked TDM modes and
* pick a default TDM layout with each channel pair working with
* slots 0 and 1. */
regmap_update_bits(wm8996->regmap,
WM8996_AIF1RX_CHANNEL_0_CONFIGURATION,
WM8996_AIF1RX_CHAN0_SLOTS_MASK |
WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1RX_CHAN0_SLOTS_SHIFT | 0);
regmap_update_bits(wm8996->regmap,
WM8996_AIF1RX_CHANNEL_1_CONFIGURATION,
WM8996_AIF1RX_CHAN1_SLOTS_MASK |
WM8996_AIF1RX_CHAN1_START_SLOT_MASK,
1 << WM8996_AIF1RX_CHAN1_SLOTS_SHIFT | 1);
regmap_update_bits(wm8996->regmap,
WM8996_AIF1RX_CHANNEL_2_CONFIGURATION,
WM8996_AIF1RX_CHAN2_SLOTS_MASK |
WM8996_AIF1RX_CHAN2_START_SLOT_MASK,
1 << WM8996_AIF1RX_CHAN2_SLOTS_SHIFT | 0);
regmap_update_bits(wm8996->regmap,
WM8996_AIF1RX_CHANNEL_3_CONFIGURATION,
WM8996_AIF1RX_CHAN3_SLOTS_MASK |
WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1RX_CHAN3_SLOTS_SHIFT | 1);
regmap_update_bits(wm8996->regmap,
WM8996_AIF1RX_CHANNEL_4_CONFIGURATION,
WM8996_AIF1RX_CHAN4_SLOTS_MASK |
WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1RX_CHAN4_SLOTS_SHIFT | 0);
regmap_update_bits(wm8996->regmap,
WM8996_AIF1RX_CHANNEL_5_CONFIGURATION,
WM8996_AIF1RX_CHAN5_SLOTS_MASK |
WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1RX_CHAN5_SLOTS_SHIFT | 1);
regmap_update_bits(wm8996->regmap,
WM8996_AIF2RX_CHANNEL_0_CONFIGURATION,
WM8996_AIF2RX_CHAN0_SLOTS_MASK |
WM8996_AIF2RX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF2RX_CHAN0_SLOTS_SHIFT | 0);
regmap_update_bits(wm8996->regmap,
WM8996_AIF2RX_CHANNEL_1_CONFIGURATION,
WM8996_AIF2RX_CHAN1_SLOTS_MASK |
WM8996_AIF2RX_CHAN1_START_SLOT_MASK,
1 << WM8996_AIF2RX_CHAN1_SLOTS_SHIFT | 1);
regmap_update_bits(wm8996->regmap,
WM8996_AIF1TX_CHANNEL_0_CONFIGURATION,
WM8996_AIF1TX_CHAN0_SLOTS_MASK |
WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1TX_CHAN0_SLOTS_SHIFT | 0);
regmap_update_bits(wm8996->regmap,
WM8996_AIF1TX_CHANNEL_1_CONFIGURATION,
WM8996_AIF1TX_CHAN1_SLOTS_MASK |
WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
regmap_update_bits(wm8996->regmap,
WM8996_AIF1TX_CHANNEL_2_CONFIGURATION,
WM8996_AIF1TX_CHAN2_SLOTS_MASK |
WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1TX_CHAN2_SLOTS_SHIFT | 0);
regmap_update_bits(wm8996->regmap,
WM8996_AIF1TX_CHANNEL_3_CONFIGURATION,
WM8996_AIF1TX_CHAN3_SLOTS_MASK |
WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1TX_CHAN3_SLOTS_SHIFT | 1);
regmap_update_bits(wm8996->regmap,
WM8996_AIF1TX_CHANNEL_4_CONFIGURATION,
WM8996_AIF1TX_CHAN4_SLOTS_MASK |
WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1TX_CHAN4_SLOTS_SHIFT | 0);
regmap_update_bits(wm8996->regmap,
WM8996_AIF1TX_CHANNEL_5_CONFIGURATION,
WM8996_AIF1TX_CHAN5_SLOTS_MASK |
WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF1TX_CHAN5_SLOTS_SHIFT | 1);
regmap_update_bits(wm8996->regmap,
WM8996_AIF2TX_CHANNEL_0_CONFIGURATION,
WM8996_AIF2TX_CHAN0_SLOTS_MASK |
WM8996_AIF2TX_CHAN0_START_SLOT_MASK,
1 << WM8996_AIF2TX_CHAN0_SLOTS_SHIFT | 0);
regmap_update_bits(wm8996->regmap,
WM8996_AIF1TX_CHANNEL_1_CONFIGURATION,
WM8996_AIF2TX_CHAN1_SLOTS_MASK |
WM8996_AIF2TX_CHAN1_START_SLOT_MASK,
1 << WM8996_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
/* If the TX LRCLK pins are not in LRCLK mode configure the
* AIFs to source their clocks from the RX LRCLKs.
*/
ret = regmap_read(wm8996->regmap, WM8996_GPIO_1, &reg);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to read GPIO1: %d\n", ret);
goto err_regmap; goto err_regmap;
} }
regcache_cache_only(wm8996->regmap, true); if (reg & WM8996_GP1_FN_MASK)
regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies); regmap_update_bits(wm8996->regmap, WM8996_AIF1_TX_LRCLK_2,
WM8996_AIF1TX_LRCLK_MODE,
WM8996_AIF1TX_LRCLK_MODE);
ret = regmap_read(wm8996->regmap, WM8996_GPIO_2, &reg);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to read GPIO2: %d\n", ret);
goto err_regmap;
}
if (reg & WM8996_GP2_FN_MASK)
regmap_update_bits(wm8996->regmap, WM8996_AIF2_TX_LRCLK_2,
WM8996_AIF2TX_LRCLK_MODE,
WM8996_AIF2TX_LRCLK_MODE);
wm8996_init_gpio(wm8996); wm8996_init_gpio(wm8996);
@ -3225,7 +3065,6 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c,
err_gpiolib: err_gpiolib:
wm8996_free_gpio(wm8996); wm8996_free_gpio(wm8996);
err_regmap: err_regmap:
regmap_exit(wm8996->regmap);
err_enable: err_enable:
if (wm8996->pdata.ldo_ena > 0) if (wm8996->pdata.ldo_ena > 0)
gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
@ -3241,14 +3080,18 @@ err:
static __devexit int wm8996_i2c_remove(struct i2c_client *client) static __devexit int wm8996_i2c_remove(struct i2c_client *client)
{ {
struct wm8996_priv *wm8996 = i2c_get_clientdata(client); struct wm8996_priv *wm8996 = i2c_get_clientdata(client);
int i;
snd_soc_unregister_codec(&client->dev); snd_soc_unregister_codec(&client->dev);
wm8996_free_gpio(wm8996); wm8996_free_gpio(wm8996);
regmap_exit(wm8996->regmap);
if (wm8996->pdata.ldo_ena > 0) { if (wm8996->pdata.ldo_ena > 0) {
gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
gpio_free(wm8996->pdata.ldo_ena); gpio_free(wm8996->pdata.ldo_ena);
} }
for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++)
regulator_unregister_notifier(wm8996->supplies[i].consumer,
&wm8996->disable_nb[i]);
return 0; return 0;
} }

View File

@ -3,7 +3,7 @@
* *
* Author: Mark Brown * Author: Mark Brown
* *
* Copyright 2009 Wolfson Microelectronics plc * Copyright 2009-12 Wolfson Microelectronics plc
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as

View File

@ -1,7 +1,7 @@
/* /*
* ALSA SoC WM9090 driver * ALSA SoC WM9090 driver
* *
* Copyright 2009, 2010 Wolfson Microelectronics * Copyright 2009-12 Wolfson Microelectronics
* *
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
* *

View File

@ -1,7 +1,7 @@
/* /*
* wm9712.c -- ALSA Soc WM9712 codec support * wm9712.c -- ALSA Soc WM9712 codec support
* *
* Copyright 2006 Wolfson Microelectronics PLC. * Copyright 2006-12 Wolfson Microelectronics PLC.
* Author: Liam Girdwood <lrg@slimlogic.co.uk> * Author: Liam Girdwood <lrg@slimlogic.co.uk>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it

View File

@ -1,7 +1,7 @@
/* /*
* wm9713.c -- ALSA Soc WM9713 codec support * wm9713.c -- ALSA Soc WM9713 codec support
* *
* Copyright 2006 Wolfson Microelectronics PLC. * Copyright 2006-10 Wolfson Microelectronics PLC.
* Author: Liam Girdwood <lrg@slimlogic.co.uk> * Author: Liam Girdwood <lrg@slimlogic.co.uk>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it

View File

@ -1,7 +1,7 @@
/* /*
* wm_hubs.c -- WM8993/4 common code * wm_hubs.c -- WM8993/4 common code
* *
* Copyright 2009 Wolfson Microelectronics plc * Copyright 2009-12 Wolfson Microelectronics plc
* *
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
* *

9
sound/soc/dwc/Kconfig Normal file
View File

@ -0,0 +1,9 @@
config SND_DESIGNWARE_I2S
tristate "Synopsys I2S Device Driver"
depends on CLKDEV_LOOKUP
help
Say Y or M if you want to add support for I2S driver for
Synopsys desigwnware I2S device. The device supports upto
maximum of 8 channels each for play and record.

3
sound/soc/dwc/Makefile Normal file
View File

@ -0,0 +1,3 @@
# SYNOPSYS Platform Support
obj-$(CONFIG_SND_DESIGNWARE_I2S) += designware_i2s.o

View File

@ -0,0 +1,455 @@
/*
* ALSA SoC Synopsys I2S Audio Layer
*
* sound/soc/spear/designware_i2s.c
*
* Copyright (C) 2010 ST Microelectronics
* Rajeev Kumar <rajeev-dlh.kumar@st.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <sound/designware_i2s.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
/* common register for all channel */
#define IER 0x000
#define IRER 0x004
#define ITER 0x008
#define CER 0x00C
#define CCR 0x010
#define RXFFR 0x014
#define TXFFR 0x018
/* I2STxRxRegisters for all channels */
#define LRBR_LTHR(x) (0x40 * x + 0x020)
#define RRBR_RTHR(x) (0x40 * x + 0x024)
#define RER(x) (0x40 * x + 0x028)
#define TER(x) (0x40 * x + 0x02C)
#define RCR(x) (0x40 * x + 0x030)
#define TCR(x) (0x40 * x + 0x034)
#define ISR(x) (0x40 * x + 0x038)
#define IMR(x) (0x40 * x + 0x03C)
#define ROR(x) (0x40 * x + 0x040)
#define TOR(x) (0x40 * x + 0x044)
#define RFCR(x) (0x40 * x + 0x048)
#define TFCR(x) (0x40 * x + 0x04C)
#define RFF(x) (0x40 * x + 0x050)
#define TFF(x) (0x40 * x + 0x054)
/* I2SCOMPRegisters */
#define I2S_COMP_PARAM_2 0x01F0
#define I2S_COMP_PARAM_1 0x01F4
#define I2S_COMP_VERSION 0x01F8
#define I2S_COMP_TYPE 0x01FC
#define MAX_CHANNEL_NUM 8
#define MIN_CHANNEL_NUM 2
struct dw_i2s_dev {
void __iomem *i2s_base;
struct clk *clk;
int active;
unsigned int capability;
struct device *dev;
/* data related to DMA transfers b/w i2s and DMAC */
struct i2s_dma_data play_dma_data;
struct i2s_dma_data capture_dma_data;
struct i2s_clk_config_data config;
int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
};
static inline void i2s_write_reg(void __iomem *io_base, int reg, u32 val)
{
writel(val, io_base + reg);
}
static inline u32 i2s_read_reg(void __iomem *io_base, int reg)
{
return readl(io_base + reg);
}
static inline void i2s_disable_channels(struct dw_i2s_dev *dev, u32 stream)
{
u32 i = 0;
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
for (i = 0; i < 4; i++)
i2s_write_reg(dev->i2s_base, TER(i), 0);
} else {
for (i = 0; i < 4; i++)
i2s_write_reg(dev->i2s_base, RER(i), 0);
}
}
static inline void i2s_clear_irqs(struct dw_i2s_dev *dev, u32 stream)
{
u32 i = 0;
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
for (i = 0; i < 4; i++)
i2s_write_reg(dev->i2s_base, TOR(i), 0);
} else {
for (i = 0; i < 4; i++)
i2s_write_reg(dev->i2s_base, ROR(i), 0);
}
}
static void i2s_start(struct dw_i2s_dev *dev,
struct snd_pcm_substream *substream)
{
i2s_write_reg(dev->i2s_base, IER, 1);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
i2s_write_reg(dev->i2s_base, ITER, 1);
else
i2s_write_reg(dev->i2s_base, IRER, 1);
i2s_write_reg(dev->i2s_base, CER, 1);
}
static void i2s_stop(struct dw_i2s_dev *dev,
struct snd_pcm_substream *substream)
{
u32 i = 0, irq;
i2s_clear_irqs(dev, substream->stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
i2s_write_reg(dev->i2s_base, ITER, 0);
for (i = 0; i < 4; i++) {
irq = i2s_read_reg(dev->i2s_base, IMR(i));
i2s_write_reg(dev->i2s_base, IMR(i), irq | 0x30);
}
} else {
i2s_write_reg(dev->i2s_base, IRER, 0);
for (i = 0; i < 4; i++) {
irq = i2s_read_reg(dev->i2s_base, IMR(i));
i2s_write_reg(dev->i2s_base, IMR(i), irq | 0x03);
}
}
if (!dev->active) {
i2s_write_reg(dev->i2s_base, CER, 0);
i2s_write_reg(dev->i2s_base, IER, 0);
}
}
static int dw_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
struct i2s_dma_data *dma_data = NULL;
if (!(dev->capability & DWC_I2S_RECORD) &&
(substream->stream == SNDRV_PCM_STREAM_CAPTURE))
return -EINVAL;
if (!(dev->capability & DWC_I2S_PLAY) &&
(substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
return -EINVAL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dma_data = &dev->play_dma_data;
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
dma_data = &dev->capture_dma_data;
snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data);
return 0;
}
static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
struct i2s_clk_config_data *config = &dev->config;
u32 ccr, xfer_resolution, ch_reg, irq;
int ret;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
config->data_width = 16;
ccr = 0x00;
xfer_resolution = 0x02;
break;
case SNDRV_PCM_FORMAT_S24_LE:
config->data_width = 24;
ccr = 0x08;
xfer_resolution = 0x04;
break;
case SNDRV_PCM_FORMAT_S32_LE:
config->data_width = 32;
ccr = 0x10;
xfer_resolution = 0x05;
break;
default:
dev_err(dev->dev, "designware-i2s: unsuppted PCM fmt");
return -EINVAL;
}
config->chan_nr = params_channels(params);
switch (config->chan_nr) {
case EIGHT_CHANNEL_SUPPORT:
ch_reg = 3;
case SIX_CHANNEL_SUPPORT:
ch_reg = 2;
case FOUR_CHANNEL_SUPPORT:
ch_reg = 1;
case TWO_CHANNEL_SUPPORT:
ch_reg = 0;
break;
default:
dev_err(dev->dev, "channel not supported\n");
}
i2s_disable_channels(dev, substream->stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
i2s_write_reg(dev->i2s_base, TCR(ch_reg), xfer_resolution);
i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02);
irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30);
i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
} else {
i2s_write_reg(dev->i2s_base, RCR(ch_reg), xfer_resolution);
i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07);
irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03);
i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
}
i2s_write_reg(dev->i2s_base, CCR, ccr);
config->sample_rate = params_rate(params);
if (!dev->i2s_clk_cfg)
return -EINVAL;
ret = dev->i2s_clk_cfg(config);
if (ret < 0) {
dev_err(dev->dev, "runtime audio clk config fail\n");
return ret;
}
return 0;
}
static void dw_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
snd_soc_dai_set_dma_data(dai, substream, NULL);
}
static int dw_i2s_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
int ret = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
dev->active++;
i2s_start(dev, substream);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
dev->active--;
i2s_stop(dev, substream);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static struct snd_soc_dai_ops dw_i2s_dai_ops = {
.startup = dw_i2s_startup,
.shutdown = dw_i2s_shutdown,
.hw_params = dw_i2s_hw_params,
.trigger = dw_i2s_trigger,
};
#ifdef CONFIG_PM
static int dw_i2s_suspend(struct snd_soc_dai *dai)
{
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
clk_disable(dev->clk);
return 0;
}
static int dw_i2s_resume(struct snd_soc_dai *dai)
{
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
clk_enable(dev->clk);
return 0;
}
#else
#define dw_i2s_suspend NULL
#define dw_i2s_resume NULL
#endif
static int dw_i2s_probe(struct platform_device *pdev)
{
const struct i2s_platform_data *pdata = pdev->dev.platform_data;
struct dw_i2s_dev *dev;
struct resource *res;
int ret;
unsigned int cap;
struct snd_soc_dai_driver *dw_i2s_dai;
if (!pdata) {
dev_err(&pdev->dev, "Invalid platform data\n");
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "no i2s resource defined\n");
return -ENODEV;
}
if (!devm_request_mem_region(&pdev->dev, res->start,
resource_size(res), pdev->name)) {
dev_err(&pdev->dev, "i2s region already claimed\n");
return -EBUSY;
}
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev) {
dev_warn(&pdev->dev, "kzalloc fail\n");
return -ENOMEM;
}
dev->i2s_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
if (!dev->i2s_base) {
dev_err(&pdev->dev, "ioremap fail for i2s_region\n");
return -ENOMEM;
}
cap = pdata->cap;
dev->capability = cap;
dev->i2s_clk_cfg = pdata->i2s_clk_cfg;
/* Set DMA slaves info */
dev->play_dma_data.data = pdata->play_dma_data;
dev->capture_dma_data.data = pdata->capture_dma_data;
dev->play_dma_data.addr = res->start + I2S_TXDMA;
dev->capture_dma_data.addr = res->start + I2S_RXDMA;
dev->play_dma_data.max_burst = 16;
dev->capture_dma_data.max_burst = 16;
dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
dev->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
dev->play_dma_data.filter = pdata->filter;
dev->capture_dma_data.filter = pdata->filter;
dev->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(dev->clk))
return PTR_ERR(dev->clk);
ret = clk_enable(dev->clk);
if (ret < 0)
goto err_clk_put;
dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL);
if (!dw_i2s_dai) {
dev_err(&pdev->dev, "mem allocation failed for dai driver\n");
ret = -ENOMEM;
goto err_clk_disable;
}
if (cap & DWC_I2S_PLAY) {
dev_dbg(&pdev->dev, " SPEAr: play supported\n");
dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM;
dw_i2s_dai->playback.channels_max = pdata->channel;
dw_i2s_dai->playback.formats = pdata->snd_fmts;
dw_i2s_dai->playback.rates = pdata->snd_rates;
}
if (cap & DWC_I2S_RECORD) {
dev_dbg(&pdev->dev, "SPEAr: record supported\n");
dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM;
dw_i2s_dai->capture.channels_max = pdata->channel;
dw_i2s_dai->capture.formats = pdata->snd_fmts;
dw_i2s_dai->capture.rates = pdata->snd_rates;
}
dw_i2s_dai->ops = &dw_i2s_dai_ops;
dw_i2s_dai->suspend = dw_i2s_suspend;
dw_i2s_dai->resume = dw_i2s_resume;
dev->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, dev);
ret = snd_soc_register_dai(&pdev->dev, dw_i2s_dai);
if (ret != 0) {
dev_err(&pdev->dev, "not able to register dai\n");
goto err_set_drvdata;
}
return 0;
err_set_drvdata:
dev_set_drvdata(&pdev->dev, NULL);
err_clk_disable:
clk_disable(dev->clk);
err_clk_put:
clk_put(dev->clk);
return ret;
}
static int dw_i2s_remove(struct platform_device *pdev)
{
struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
snd_soc_unregister_dai(&pdev->dev);
dev_set_drvdata(&pdev->dev, NULL);
clk_put(dev->clk);
return 0;
}
static struct platform_driver dw_i2s_driver = {
.probe = dw_i2s_probe,
.remove = dw_i2s_remove,
.driver = {
.name = "designware-i2s",
.owner = THIS_MODULE,
},
};
module_platform_driver(dw_i2s_driver);
MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");
MODULE_DESCRIPTION("DESIGNWARE I2S SoC Interface");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:designware_i2s");

View File

@ -136,7 +136,7 @@ static struct snd_pcm_ops ep93xx_pcm_ops = {
.hw_params = ep93xx_pcm_hw_params, .hw_params = ep93xx_pcm_hw_params,
.hw_free = ep93xx_pcm_hw_free, .hw_free = ep93xx_pcm_hw_free,
.trigger = snd_dmaengine_pcm_trigger, .trigger = snd_dmaengine_pcm_trigger,
.pointer = snd_dmaengine_pcm_pointer, .pointer = snd_dmaengine_pcm_pointer_no_residue,
.mmap = ep93xx_pcm_mmap, .mmap = ep93xx_pcm_mmap,
}; };

View File

@ -156,7 +156,7 @@ static void __init audmux_debugfs_init(void)
return; return;
} }
for (i = 0; i < MX31_AUDMUX_PORT6_SSI_PINS_6 + 1; i++) { for (i = 0; i < MX31_AUDMUX_PORT7_SSI_PINS_7 + 1; i++) {
snprintf(buf, sizeof(buf), "ssi%d", i); snprintf(buf, sizeof(buf), "ssi%d", i);
if (!debugfs_create_file(buf, 0444, audmux_debugfs_root, if (!debugfs_create_file(buf, 0444, audmux_debugfs_root,
(void *)i, &audmux_debugfs_fops)) (void *)i, &audmux_debugfs_fops))

View File

@ -14,6 +14,7 @@
#define MX31_AUDMUX_PORT4_SSI_PINS_4 3 #define MX31_AUDMUX_PORT4_SSI_PINS_4 3
#define MX31_AUDMUX_PORT5_SSI_PINS_5 4 #define MX31_AUDMUX_PORT5_SSI_PINS_5 4
#define MX31_AUDMUX_PORT6_SSI_PINS_6 5 #define MX31_AUDMUX_PORT6_SSI_PINS_6 5
#define MX31_AUDMUX_PORT7_SSI_PINS_7 6
#define MX51_AUDMUX_PORT1_SSI0 0 #define MX51_AUDMUX_PORT1_SSI0 0
#define MX51_AUDMUX_PORT2_SSI1 1 #define MX51_AUDMUX_PORT2_SSI1 1

View File

@ -111,22 +111,39 @@ static int __devinit imx_mc13783_probe(struct platform_device *pdev)
return ret; return ret;
} }
imx_audmux_v2_configure_port(MX31_AUDMUX_PORT4_SSI_PINS_4, if (machine_is_mx31_3ds()) {
IMX_AUDMUX_V2_PTCR_SYN, imx_audmux_v2_configure_port(MX31_AUDMUX_PORT4_SSI_PINS_4,
IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0) | IMX_AUDMUX_V2_PTCR_SYN,
IMX_AUDMUX_V2_PDCR_MODE(1) | IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0) |
IMX_AUDMUX_V2_PDCR_INMMASK(0xfc)); IMX_AUDMUX_V2_PDCR_MODE(1) |
imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0, IMX_AUDMUX_V2_PDCR_INMMASK(0xfc));
IMX_AUDMUX_V2_PTCR_SYN | imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0,
IMX_AUDMUX_V2_PTCR_TFSDIR | IMX_AUDMUX_V2_PTCR_SYN |
IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) | IMX_AUDMUX_V2_PTCR_TFSDIR |
IMX_AUDMUX_V2_PTCR_TCLKDIR | IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) | IMX_AUDMUX_V2_PTCR_TCLKDIR |
IMX_AUDMUX_V2_PTCR_RFSDIR | IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
IMX_AUDMUX_V2_PTCR_RFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) | IMX_AUDMUX_V2_PTCR_RFSDIR |
IMX_AUDMUX_V2_PTCR_RCLKDIR | IMX_AUDMUX_V2_PTCR_RFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
IMX_AUDMUX_V2_PTCR_RCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4), IMX_AUDMUX_V2_PTCR_RCLKDIR |
IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT4_SSI_PINS_4)); IMX_AUDMUX_V2_PTCR_RCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4),
IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT4_SSI_PINS_4));
} else if (machine_is_mx27_3ds()) {
imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
IMX_AUDMUX_V1_PCR_SYN |
IMX_AUDMUX_V1_PCR_TFSDIR |
IMX_AUDMUX_V1_PCR_TCLKDIR |
IMX_AUDMUX_V1_PCR_RFSDIR |
IMX_AUDMUX_V1_PCR_RCLKDIR |
IMX_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
IMX_AUDMUX_V1_PCR_RFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4)
);
imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR3_SSI_PINS_4,
IMX_AUDMUX_V1_PCR_SYN |
IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0)
);
}
return ret; return ret;
} }

View File

@ -141,7 +141,7 @@ static struct snd_pcm_ops imx_pcm_ops = {
.ioctl = snd_pcm_lib_ioctl, .ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_imx_pcm_hw_params, .hw_params = snd_imx_pcm_hw_params,
.trigger = snd_dmaengine_pcm_trigger, .trigger = snd_dmaengine_pcm_trigger,
.pointer = snd_dmaengine_pcm_pointer, .pointer = snd_dmaengine_pcm_pointer_no_residue,
.mmap = snd_imx_pcm_mmap, .mmap = snd_imx_pcm_mmap,
}; };

View File

@ -95,8 +95,7 @@ static int __devinit imx_sgtl5000_probe(struct platform_device *pdev)
return ret; return ret;
} }
imx_audmux_v2_configure_port(ext_port, imx_audmux_v2_configure_port(ext_port,
IMX_AUDMUX_V2_PTCR_SYN | IMX_AUDMUX_V2_PTCR_SYN,
IMX_AUDMUX_V2_PTCR_TCSEL(int_port),
IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
if (ret) { if (ret) {
dev_err(&pdev->dev, "audmux external port setup failed\n"); dev_err(&pdev->dev, "audmux external port setup failed\n");

View File

@ -141,7 +141,7 @@ static struct snd_pcm_ops mxs_pcm_ops = {
.ioctl = snd_pcm_lib_ioctl, .ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_mxs_pcm_hw_params, .hw_params = snd_mxs_pcm_hw_params,
.trigger = snd_dmaengine_pcm_trigger, .trigger = snd_dmaengine_pcm_trigger,
.pointer = snd_dmaengine_pcm_pointer, .pointer = snd_dmaengine_pcm_pointer_no_residue,
.mmap = snd_mxs_pcm_mmap, .mmap = snd_mxs_pcm_mmap,
}; };

View File

@ -133,7 +133,7 @@ static int __devinit mxs_sgtl5000_probe_dt(struct platform_device *pdev)
mxs_sgtl5000_dai[i].codec_name = NULL; mxs_sgtl5000_dai[i].codec_name = NULL;
mxs_sgtl5000_dai[i].codec_of_node = codec_np; mxs_sgtl5000_dai[i].codec_of_node = codec_np;
mxs_sgtl5000_dai[i].cpu_dai_name = NULL; mxs_sgtl5000_dai[i].cpu_dai_name = NULL;
mxs_sgtl5000_dai[i].cpu_dai_of_node = saif_np[i]; mxs_sgtl5000_dai[i].cpu_of_node = saif_np[i];
mxs_sgtl5000_dai[i].platform_name = NULL; mxs_sgtl5000_dai[i].platform_name = NULL;
mxs_sgtl5000_dai[i].platform_of_node = saif_np[i]; mxs_sgtl5000_dai[i].platform_of_node = saif_np[i];
} }

View File

@ -8,6 +8,15 @@ config SND_PXA2XX_SOC
the PXA2xx AC97, I2S or SSP interface. You will also need the PXA2xx AC97, I2S or SSP interface. You will also need
to select the audio interfaces to support below. to select the audio interfaces to support below.
config SND_MMP_SOC
bool "Soc Audio for Marvell MMP chips"
depends on ARCH_MMP
select SND_SOC_DMAENGINE_PCM
select SND_ARM
help
Say Y if you want to add support for codecs attached to
the MMP SSPA interface.
config SND_PXA2XX_AC97 config SND_PXA2XX_AC97
tristate tristate
select SND_AC97_CODEC select SND_AC97_CODEC
@ -26,6 +35,9 @@ config SND_PXA_SOC_SSP
tristate tristate
select PXA_SSP select PXA_SSP
config SND_MMP_SOC_SSPA
tristate
config SND_PXA2XX_SOC_CORGI config SND_PXA2XX_SOC_CORGI
tristate "SoC Audio support for Sharp Zaurus SL-C7x0" tristate "SoC Audio support for Sharp Zaurus SL-C7x0"
depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx
@ -138,6 +150,26 @@ config SND_SOC_TAVOREVB3
Say Y if you want to add support for SoC audio on the Say Y if you want to add support for SoC audio on the
Marvell Saarb reference platform. Marvell Saarb reference platform.
config SND_PXA910_SOC
tristate "SoC Audio for Marvell PXA910 chip"
depends on ARCH_MMP && SND
select SND_PCM
help
Say Y if you want to add support for SoC audio on the
Marvell PXA910 reference platform.
config SND_SOC_TTC_DKB
bool "SoC Audio support for TTC DKB"
depends on SND_PXA910_SOC && MACH_TTC_DKB
select PXA_SSP
select SND_PXA_SOC_SSP
select SND_MMP_SOC
select MFD_88PM860X
select SND_SOC_88PM860X
help
Say Y if you want to add support for SoC audio on TTC DKB
config SND_SOC_ZYLONITE config SND_SOC_ZYLONITE
tristate "SoC Audio support for Marvell Zylonite" tristate "SoC Audio support for Marvell Zylonite"
depends on SND_PXA2XX_SOC && MACH_ZYLONITE depends on SND_PXA2XX_SOC && MACH_ZYLONITE
@ -194,3 +226,13 @@ config SND_PXA2XX_SOC_IMOTE2
help help
Say Y if you want to add support for SoC audio on the Say Y if you want to add support for SoC audio on the
IMote 2. IMote 2.
config SND_MMP_SOC_BROWNSTONE
tristate "SoC Audio support for Marvell Brownstone"
depends on SND_MMP_SOC && MACH_BROWNSTONE
select SND_MMP_SOC_SSPA
select MFD_WM8994
select SND_SOC_WM8994
help
Say Y if you want to add support for SoC audio on the
Marvell Brownstone reference platform.

View File

@ -3,11 +3,15 @@ snd-soc-pxa2xx-objs := pxa2xx-pcm.o
snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o
snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o
snd-soc-pxa-ssp-objs := pxa-ssp.o snd-soc-pxa-ssp-objs := pxa-ssp.o
snd-soc-mmp-objs := mmp-pcm.o
snd-soc-mmp-sspa-objs := mmp-sspa.o
obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o
obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o
obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o
obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o
obj-$(CONFIG_SND_MMP_SOC) += snd-soc-mmp.o
obj-$(CONFIG_SND_MMP_SOC_SSPA) += snd-soc-mmp-sspa.o
# PXA Machine Support # PXA Machine Support
snd-soc-corgi-objs := corgi.o snd-soc-corgi-objs := corgi.o
@ -28,6 +32,8 @@ snd-soc-mioa701-objs := mioa701_wm9713.o
snd-soc-z2-objs := z2.o snd-soc-z2-objs := z2.o
snd-soc-imote2-objs := imote2.o snd-soc-imote2-objs := imote2.o
snd-soc-raumfeld-objs := raumfeld.o snd-soc-raumfeld-objs := raumfeld.o
snd-soc-brownstone-objs := brownstone.o
snd-soc-ttc-dkb-objs := ttc-dkb.o
obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o
obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o
@ -47,3 +53,5 @@ obj-$(CONFIG_SND_SOC_TAVOREVB3) += snd-soc-tavorevb3.o
obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o
obj-$(CONFIG_SND_MMP_SOC_BROWNSTONE) += snd-soc-brownstone.o
obj-$(CONFIG_SND_SOC_TTC_DKB) += snd-soc-ttc-dkb.o

174
sound/soc/pxa/brownstone.c Normal file
View File

@ -0,0 +1,174 @@
/*
* linux/sound/soc/pxa/brownstone.c
*
* Copyright (C) 2011 Marvell International Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include "../codecs/wm8994.h"
#include "mmp-sspa.h"
static const struct snd_kcontrol_new brownstone_dapm_control[] = {
SOC_DAPM_PIN_SWITCH("Ext Spk"),
};
static const struct snd_soc_dapm_widget brownstone_dapm_widgets[] = {
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_HP("Headset Stereophone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Main Mic", NULL),
};
static const struct snd_soc_dapm_route brownstone_audio_map[] = {
{"Ext Spk", NULL, "SPKOUTLP"},
{"Ext Spk", NULL, "SPKOUTLN"},
{"Ext Spk", NULL, "SPKOUTRP"},
{"Ext Spk", NULL, "SPKOUTRN"},
{"Headset Stereophone", NULL, "HPOUT1L"},
{"Headset Stereophone", NULL, "HPOUT1R"},
{"IN1RN", NULL, "Headset Mic"},
{"DMIC1DAT", NULL, "MICBIAS1"},
{"MICBIAS1", NULL, "Main Mic"},
};
static int brownstone_wm8994_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_enable_pin(dapm, "Ext Spk");
snd_soc_dapm_enable_pin(dapm, "Headset Stereophone");
snd_soc_dapm_enable_pin(dapm, "Headset Mic");
snd_soc_dapm_enable_pin(dapm, "Main Mic");
/* set endpoints to not connected */
snd_soc_dapm_nc_pin(dapm, "HPOUT2P");
snd_soc_dapm_nc_pin(dapm, "HPOUT2N");
snd_soc_dapm_nc_pin(dapm, "LINEOUT1N");
snd_soc_dapm_nc_pin(dapm, "LINEOUT1P");
snd_soc_dapm_nc_pin(dapm, "LINEOUT2N");
snd_soc_dapm_nc_pin(dapm, "LINEOUT2P");
snd_soc_dapm_nc_pin(dapm, "IN1LN");
snd_soc_dapm_nc_pin(dapm, "IN1LP");
snd_soc_dapm_nc_pin(dapm, "IN1RP");
snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN");
snd_soc_dapm_nc_pin(dapm, "IN2RN");
snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP");
snd_soc_dapm_nc_pin(dapm, "IN2LN");
snd_soc_dapm_sync(dapm);
return 0;
}
static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int freq_out, sspa_mclk, sysclk;
int sspa_div;
if (params_rate(params) > 11025) {
freq_out = params_rate(params) * 512;
sysclk = params_rate(params) * 256;
sspa_mclk = params_rate(params) * 64;
} else {
freq_out = params_rate(params) * 1024;
sysclk = params_rate(params) * 512;
sspa_mclk = params_rate(params) * 64;
}
sspa_div = freq_out;
do_div(sspa_div, sspa_mclk);
snd_soc_dai_set_sysclk(cpu_dai, MMP_SSPA_CLK_AUDIO, freq_out, 0);
snd_soc_dai_set_pll(cpu_dai, MMP_SYSCLK, 0, freq_out, sysclk);
snd_soc_dai_set_pll(cpu_dai, MMP_SSPA_CLK, 0, freq_out, sspa_mclk);
/* set wm8994 sysclk */
snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1, sysclk, 0);
return 0;
}
/* machine stream operations */
static struct snd_soc_ops brownstone_ops = {
.hw_params = brownstone_wm8994_hw_params,
};
static struct snd_soc_dai_link brownstone_wm8994_dai[] = {
{
.name = "WM8994",
.stream_name = "WM8994 HiFi",
.cpu_dai_name = "mmp-sspa-dai.0",
.codec_dai_name = "wm8994-aif1",
.platform_name = "mmp-pcm-audio",
.codec_name = "wm8994-codec",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
.ops = &brownstone_ops,
.init = brownstone_wm8994_init,
},
};
/* audio machine driver */
static struct snd_soc_card brownstone = {
.name = "brownstone",
.dai_link = brownstone_wm8994_dai,
.num_links = ARRAY_SIZE(brownstone_wm8994_dai),
.controls = brownstone_dapm_control,
.num_controls = ARRAY_SIZE(brownstone_dapm_control),
.dapm_widgets = brownstone_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(brownstone_dapm_widgets),
.dapm_routes = brownstone_audio_map,
.num_dapm_routes = ARRAY_SIZE(brownstone_audio_map),
};
static int __devinit brownstone_probe(struct platform_device *pdev)
{
int ret;
brownstone.dev = &pdev->dev;
ret = snd_soc_register_card(&brownstone);
if (ret)
dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
ret);
return ret;
}
static int __devexit brownstone_remove(struct platform_device *pdev)
{
snd_soc_unregister_card(&brownstone);
return 0;
}
static struct platform_driver mmp_driver = {
.driver = {
.name = "brownstone-audio",
.owner = THIS_MODULE,
},
.probe = brownstone_probe,
.remove = __devexit_p(brownstone_remove),
};
module_platform_driver(mmp_driver);
MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
MODULE_DESCRIPTION("ALSA SoC Brownstone");
MODULE_LICENSE("GPL");

297
sound/soc/pxa/mmp-pcm.c Normal file
View File

@ -0,0 +1,297 @@
/*
* linux/sound/soc/pxa/mmp-pcm.c
*
* Copyright (C) 2011 Marvell International Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/platform_data/mmp_audio.h>
#include <sound/pxa2xx-lib.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <mach/sram.h>
#include <sound/dmaengine_pcm.h>
struct mmp_dma_data {
int ssp_id;
struct resource *dma_res;
};
#define MMP_PCM_INFO (SNDRV_PCM_INFO_MMAP | \
SNDRV_PCM_INFO_MMAP_VALID | \
SNDRV_PCM_INFO_INTERLEAVED | \
SNDRV_PCM_INFO_PAUSE | \
SNDRV_PCM_INFO_RESUME)
#define MMP_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_pcm_hardware mmp_pcm_hardware[] = {
{
.info = MMP_PCM_INFO,
.formats = MMP_PCM_FORMATS,
.period_bytes_min = 1024,
.period_bytes_max = 2048,
.periods_min = 2,
.periods_max = 32,
.buffer_bytes_max = 4096,
.fifo_size = 32,
},
{
.info = MMP_PCM_INFO,
.formats = MMP_PCM_FORMATS,
.period_bytes_min = 1024,
.period_bytes_max = 2048,
.periods_min = 2,
.periods_max = 32,
.buffer_bytes_max = 4096,
.fifo_size = 32,
},
};
static int mmp_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct pxa2xx_pcm_dma_params *dma_params;
struct dma_slave_config slave_config;
int ret;
dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
if (!dma_params)
return 0;
ret = snd_hwparams_to_dma_slave_config(substream, params, &slave_config);
if (ret)
return ret;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
slave_config.dst_addr = dma_params->dev_addr;
slave_config.dst_maxburst = 4;
} else {
slave_config.src_addr = dma_params->dev_addr;
slave_config.src_maxburst = 4;
}
ret = dmaengine_slave_config(chan, &slave_config);
if (ret)
return ret;
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
return 0;
}
static bool filter(struct dma_chan *chan, void *param)
{
struct mmp_dma_data *dma_data = param;
bool found = false;
char *devname;
devname = kasprintf(GFP_KERNEL, "%s.%d", dma_data->dma_res->name,
dma_data->ssp_id);
if ((strcmp(dev_name(chan->device->dev), devname) == 0) &&
(chan->chan_id == dma_data->dma_res->start)) {
found = true;
}
kfree(devname);
return found;
}
static int mmp_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct platform_device *pdev = to_platform_device(rtd->platform->dev);
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct mmp_dma_data *dma_data;
struct resource *r;
int ret;
r = platform_get_resource(pdev, IORESOURCE_DMA, substream->stream);
if (!r)
return -EBUSY;
snd_soc_set_runtime_hwparams(substream,
&mmp_pcm_hardware[substream->stream]);
dma_data = devm_kzalloc(&pdev->dev,
sizeof(struct mmp_dma_data), GFP_KERNEL);
if (dma_data == NULL)
return -ENOMEM;
dma_data->dma_res = r;
dma_data->ssp_id = cpu_dai->id;
ret = snd_dmaengine_pcm_open(substream, filter, dma_data);
if (ret) {
devm_kfree(&pdev->dev, dma_data);
return ret;
}
snd_dmaengine_pcm_set_data(substream, dma_data);
return 0;
}
static int mmp_pcm_close(struct snd_pcm_substream *substream)
{
struct mmp_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct platform_device *pdev = to_platform_device(rtd->platform->dev);
snd_dmaengine_pcm_close(substream);
devm_kfree(&pdev->dev, dma_data);
return 0;
}
static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned long off = vma->vm_pgoff;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
return remap_pfn_range(vma, vma->vm_start,
__phys_to_pfn(runtime->dma_addr) + off,
vma->vm_end - vma->vm_start, vma->vm_page_prot);
}
struct snd_pcm_ops mmp_pcm_ops = {
.open = mmp_pcm_open,
.close = mmp_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = mmp_pcm_hw_params,
.trigger = snd_dmaengine_pcm_trigger,
.pointer = snd_dmaengine_pcm_pointer,
.mmap = mmp_pcm_mmap,
};
static void mmp_pcm_free_dma_buffers(struct snd_pcm *pcm)
{
struct snd_pcm_substream *substream;
struct snd_dma_buffer *buf;
int stream;
struct gen_pool *gpool;
gpool = sram_get_gpool("asram");
if (!gpool)
return;
for (stream = 0; stream < 2; stream++) {
size_t size = mmp_pcm_hardware[stream].buffer_bytes_max;
substream = pcm->streams[stream].substream;
if (!substream)
continue;
buf = &substream->dma_buffer;
if (!buf->area)
continue;
gen_pool_free(gpool, (unsigned long)buf->area, size);
buf->area = NULL;
}
return;
}
static int mmp_pcm_preallocate_dma_buffer(struct snd_pcm_substream *substream,
int stream)
{
struct snd_dma_buffer *buf = &substream->dma_buffer;
size_t size = mmp_pcm_hardware[stream].buffer_bytes_max;
struct gen_pool *gpool;
buf->dev.type = SNDRV_DMA_TYPE_DEV;
buf->dev.dev = substream->pcm->card->dev;
buf->private_data = NULL;
gpool = sram_get_gpool("asram");
if (!gpool)
return -ENOMEM;
buf->area = (unsigned char *)gen_pool_alloc(gpool, size);
if (!buf->area)
return -ENOMEM;
buf->addr = gen_pool_virt_to_phys(gpool, (unsigned long)buf->area);
buf->bytes = size;
return 0;
}
int mmp_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_pcm_substream *substream;
struct snd_pcm *pcm = rtd->pcm;
int ret = 0, stream;
for (stream = 0; stream < 2; stream++) {
substream = pcm->streams[stream].substream;
ret = mmp_pcm_preallocate_dma_buffer(substream, stream);
if (ret)
goto err;
}
return 0;
err:
mmp_pcm_free_dma_buffers(pcm);
return ret;
}
struct snd_soc_platform_driver mmp_soc_platform = {
.ops = &mmp_pcm_ops,
.pcm_new = mmp_pcm_new,
.pcm_free = mmp_pcm_free_dma_buffers,
};
static __devinit int mmp_pcm_probe(struct platform_device *pdev)
{
struct mmp_audio_platdata *pdata = pdev->dev.platform_data;
if (pdata) {
mmp_pcm_hardware[SNDRV_PCM_STREAM_PLAYBACK].buffer_bytes_max =
pdata->buffer_max_playback;
mmp_pcm_hardware[SNDRV_PCM_STREAM_PLAYBACK].period_bytes_max =
pdata->period_max_playback;
mmp_pcm_hardware[SNDRV_PCM_STREAM_CAPTURE].buffer_bytes_max =
pdata->buffer_max_capture;
mmp_pcm_hardware[SNDRV_PCM_STREAM_CAPTURE].period_bytes_max =
pdata->period_max_capture;
}
return snd_soc_register_platform(&pdev->dev, &mmp_soc_platform);
}
static int __devexit mmp_pcm_remove(struct platform_device *pdev)
{
snd_soc_unregister_platform(&pdev->dev);
return 0;
}
static struct platform_driver mmp_pcm_driver = {
.driver = {
.name = "mmp-pcm-audio",
.owner = THIS_MODULE,
},
.probe = mmp_pcm_probe,
.remove = __devexit_p(mmp_pcm_remove),
};
module_platform_driver(mmp_pcm_driver);
MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
MODULE_DESCRIPTION("MMP Soc Audio DMA module");
MODULE_LICENSE("GPL");

480
sound/soc/pxa/mmp-sspa.c Normal file
View File

@ -0,0 +1,480 @@
/*
* linux/sound/soc/pxa/mmp-sspa.c
* Base on pxa2xx-ssp.c
*
* Copyright (C) 2011 Marvell International Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/pxa2xx_ssp.h>
#include <linux/io.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/pxa2xx-lib.h>
#include "mmp-sspa.h"
/*
* SSPA audio private data
*/
struct sspa_priv {
struct ssp_device *sspa;
struct pxa2xx_pcm_dma_params *dma_params;
struct clk *audio_clk;
struct clk *sysclk;
int dai_fmt;
int running_cnt;
};
static void mmp_sspa_write_reg(struct ssp_device *sspa, u32 reg, u32 val)
{
__raw_writel(val, sspa->mmio_base + reg);
}
static u32 mmp_sspa_read_reg(struct ssp_device *sspa, u32 reg)
{
return __raw_readl(sspa->mmio_base + reg);
}
static void mmp_sspa_tx_enable(struct ssp_device *sspa)
{
unsigned int sspa_sp;
sspa_sp = mmp_sspa_read_reg(sspa, SSPA_TXSP);
sspa_sp |= SSPA_SP_S_EN;
sspa_sp |= SSPA_SP_WEN;
mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
}
static void mmp_sspa_tx_disable(struct ssp_device *sspa)
{
unsigned int sspa_sp;
sspa_sp = mmp_sspa_read_reg(sspa, SSPA_TXSP);
sspa_sp &= ~SSPA_SP_S_EN;
sspa_sp |= SSPA_SP_WEN;
mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
}
static void mmp_sspa_rx_enable(struct ssp_device *sspa)
{
unsigned int sspa_sp;
sspa_sp = mmp_sspa_read_reg(sspa, SSPA_RXSP);
sspa_sp |= SSPA_SP_S_EN;
sspa_sp |= SSPA_SP_WEN;
mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp);
}
static void mmp_sspa_rx_disable(struct ssp_device *sspa)
{
unsigned int sspa_sp;
sspa_sp = mmp_sspa_read_reg(sspa, SSPA_RXSP);
sspa_sp &= ~SSPA_SP_S_EN;
sspa_sp |= SSPA_SP_WEN;
mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp);
}
static int mmp_sspa_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct sspa_priv *priv = snd_soc_dai_get_drvdata(dai);
clk_enable(priv->sysclk);
clk_enable(priv->sspa->clk);
return 0;
}
static void mmp_sspa_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct sspa_priv *priv = snd_soc_dai_get_drvdata(dai);
clk_disable(priv->sspa->clk);
clk_disable(priv->sysclk);
return;
}
/*
* Set the SSP ports SYSCLK.
*/
static int mmp_sspa_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
struct sspa_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
int ret = 0;
switch (clk_id) {
case MMP_SSPA_CLK_AUDIO:
ret = clk_set_rate(priv->audio_clk, freq);
if (ret)
return ret;
break;
case MMP_SSPA_CLK_PLL:
case MMP_SSPA_CLK_VCXO:
/* not support yet */
return -EINVAL;
default:
return -EINVAL;
}
return 0;
}
static int mmp_sspa_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
int source, unsigned int freq_in,
unsigned int freq_out)
{
struct sspa_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
int ret = 0;
switch (pll_id) {
case MMP_SYSCLK:
ret = clk_set_rate(priv->sysclk, freq_out);
if (ret)
return ret;
break;
case MMP_SSPA_CLK:
ret = clk_set_rate(priv->sspa->clk, freq_out);
if (ret)
return ret;
break;
default:
return -ENODEV;
}
return 0;
}
/*
* Set up the sspa dai format. The sspa port must be inactive
* before calling this function as the physical
* interface format is changed.
*/
static int mmp_sspa_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *sspa = sspa_priv->sspa;
u32 sspa_sp, sspa_ctrl;
/* check if we need to change anything at all */
if (sspa_priv->dai_fmt == fmt)
return 0;
/* we can only change the settings if the port is not in use */
if ((mmp_sspa_read_reg(sspa, SSPA_TXSP) & SSPA_SP_S_EN) ||
(mmp_sspa_read_reg(sspa, SSPA_RXSP) & SSPA_SP_S_EN)) {
dev_err(&sspa->pdev->dev,
"can't change hardware dai format: stream is in use\n");
return -EINVAL;
}
/* reset port settings */
sspa_sp = SSPA_SP_WEN | SSPA_SP_S_RST | SSPA_SP_FFLUSH;
sspa_ctrl = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
sspa_sp |= SSPA_SP_MSL;
break;
case SND_SOC_DAIFMT_CBM_CFM:
break;
default:
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
sspa_sp |= SSPA_SP_FSP;
break;
default:
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
sspa_sp |= SSPA_TXSP_FPER(63);
sspa_sp |= SSPA_SP_FWID(31);
sspa_ctrl |= SSPA_CTL_XDATDLY(1);
break;
default:
return -EINVAL;
}
mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp);
sspa_sp &= ~(SSPA_SP_S_RST | SSPA_SP_FFLUSH);
mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp);
/*
* FIXME: hw issue, for the tx serial port,
* can not config the master/slave mode;
* so must clean this bit.
* The master/slave mode has been set in the
* rx port.
*/
sspa_sp &= ~SSPA_SP_MSL;
mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
mmp_sspa_write_reg(sspa, SSPA_TXCTL, sspa_ctrl);
mmp_sspa_write_reg(sspa, SSPA_RXCTL, sspa_ctrl);
/* Since we are configuring the timings for the format by hand
* we have to defer some things until hw_params() where we
* know parameters like the sample size.
*/
sspa_priv->dai_fmt = fmt;
return 0;
}
/*
* Set the SSPA audio DMA parameters and sample size.
* Can be called multiple times by oss emulation.
*/
static int mmp_sspa_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_dai *cpu_dai = rtd->cpu_dai;
struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(dai);
struct ssp_device *sspa = sspa_priv->sspa;
struct pxa2xx_pcm_dma_params *dma_params;
u32 sspa_ctrl;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
sspa_ctrl = mmp_sspa_read_reg(sspa, SSPA_TXCTL);
else
sspa_ctrl = mmp_sspa_read_reg(sspa, SSPA_RXCTL);
sspa_ctrl &= ~SSPA_CTL_XFRLEN1_MASK;
sspa_ctrl |= SSPA_CTL_XFRLEN1(params_channels(params) - 1);
sspa_ctrl &= ~SSPA_CTL_XWDLEN1_MASK;
sspa_ctrl |= SSPA_CTL_XWDLEN1(SSPA_CTL_32_BITS);
sspa_ctrl &= ~SSPA_CTL_XSSZ1_MASK;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_8_BITS);
break;
case SNDRV_PCM_FORMAT_S16_LE:
sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_16_BITS);
break;
case SNDRV_PCM_FORMAT_S20_3LE:
sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_20_BITS);
break;
case SNDRV_PCM_FORMAT_S24_3LE:
sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_24_BITS);
break;
case SNDRV_PCM_FORMAT_S32_LE:
sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_32_BITS);
break;
default:
return -EINVAL;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
mmp_sspa_write_reg(sspa, SSPA_TXCTL, sspa_ctrl);
mmp_sspa_write_reg(sspa, SSPA_TXFIFO_LL, 0x1);
} else {
mmp_sspa_write_reg(sspa, SSPA_RXCTL, sspa_ctrl);
mmp_sspa_write_reg(sspa, SSPA_RXFIFO_UL, 0x0);
}
dma_params = &sspa_priv->dma_params[substream->stream];
dma_params->dev_addr = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
(sspa->phys_base + SSPA_TXD) :
(sspa->phys_base + SSPA_RXD);
snd_soc_dai_set_dma_data(cpu_dai, substream, dma_params);
return 0;
}
static int mmp_sspa_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(dai);
struct ssp_device *sspa = sspa_priv->sspa;
int ret = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
/*
* whatever playback or capture, must enable rx.
* this is a hw issue, so need check if rx has been
* enabled or not; if has been enabled by another
* stream, do not enable again.
*/
if (!sspa_priv->running_cnt)
mmp_sspa_rx_enable(sspa);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
mmp_sspa_tx_enable(sspa);
sspa_priv->running_cnt++;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
sspa_priv->running_cnt--;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
mmp_sspa_tx_disable(sspa);
/* have no capture stream, disable rx port */
if (!sspa_priv->running_cnt)
mmp_sspa_rx_disable(sspa);
break;
default:
ret = -EINVAL;
}
return ret;
}
static int mmp_sspa_probe(struct snd_soc_dai *dai)
{
struct sspa_priv *priv = dev_get_drvdata(dai->dev);
snd_soc_dai_set_drvdata(dai, priv);
return 0;
}
#define MMP_SSPA_RATES SNDRV_PCM_RATE_8000_192000
#define MMP_SSPA_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_ops mmp_sspa_dai_ops = {
.startup = mmp_sspa_startup,
.shutdown = mmp_sspa_shutdown,
.trigger = mmp_sspa_trigger,
.hw_params = mmp_sspa_hw_params,
.set_sysclk = mmp_sspa_set_dai_sysclk,
.set_pll = mmp_sspa_set_dai_pll,
.set_fmt = mmp_sspa_set_dai_fmt,
};
struct snd_soc_dai_driver mmp_sspa_dai = {
.probe = mmp_sspa_probe,
.playback = {
.channels_min = 1,
.channels_max = 128,
.rates = MMP_SSPA_RATES,
.formats = MMP_SSPA_FORMATS,
},
.capture = {
.channels_min = 1,
.channels_max = 2,
.rates = MMP_SSPA_RATES,
.formats = MMP_SSPA_FORMATS,
},
.ops = &mmp_sspa_dai_ops,
};
static __devinit int asoc_mmp_sspa_probe(struct platform_device *pdev)
{
struct sspa_priv *priv;
struct resource *res;
priv = devm_kzalloc(&pdev->dev,
sizeof(struct sspa_priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->sspa = devm_kzalloc(&pdev->dev,
sizeof(struct ssp_device), GFP_KERNEL);
if (priv->sspa == NULL)
return -ENOMEM;
priv->dma_params = devm_kzalloc(&pdev->dev,
2 * sizeof(struct pxa2xx_pcm_dma_params), GFP_KERNEL);
if (priv->dma_params == NULL)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL)
return -ENOMEM;
priv->sspa->mmio_base = devm_request_and_ioremap(&pdev->dev, res);
if (priv->sspa->mmio_base == NULL)
return -ENODEV;
priv->sspa->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(priv->sspa->clk))
return PTR_ERR(priv->sspa->clk);
priv->audio_clk = clk_get(NULL, "mmp-audio");
if (IS_ERR(priv->audio_clk))
return PTR_ERR(priv->audio_clk);
priv->sysclk = clk_get(NULL, "mmp-sysclk");
if (IS_ERR(priv->sysclk)) {
clk_put(priv->audio_clk);
return PTR_ERR(priv->sysclk);
}
clk_enable(priv->audio_clk);
priv->dai_fmt = (unsigned int) -1;
platform_set_drvdata(pdev, priv);
return snd_soc_register_dai(&pdev->dev, &mmp_sspa_dai);
}
static int __devexit asoc_mmp_sspa_remove(struct platform_device *pdev)
{
struct sspa_priv *priv = platform_get_drvdata(pdev);
clk_disable(priv->audio_clk);
clk_put(priv->audio_clk);
clk_put(priv->sysclk);
snd_soc_unregister_dai(&pdev->dev);
return 0;
}
static struct platform_driver asoc_mmp_sspa_driver = {
.driver = {
.name = "mmp-sspa-dai",
.owner = THIS_MODULE,
},
.probe = asoc_mmp_sspa_probe,
.remove = __devexit_p(asoc_mmp_sspa_remove),
};
module_platform_driver(asoc_mmp_sspa_driver);
MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
MODULE_DESCRIPTION("MMP SSPA SoC Interface");
MODULE_LICENSE("GPL");

92
sound/soc/pxa/mmp-sspa.h Normal file
View File

@ -0,0 +1,92 @@
/*
* linux/sound/soc/pxa/mmp-sspa.h
*
* Copyright (C) 2011 Marvell International Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef _MMP_SSPA_H
#define _MMP_SSPA_H
/*
* SSPA Registers
*/
#define SSPA_RXD (0x00)
#define SSPA_RXID (0x04)
#define SSPA_RXCTL (0x08)
#define SSPA_RXSP (0x0c)
#define SSPA_RXFIFO_UL (0x10)
#define SSPA_RXINT_MASK (0x14)
#define SSPA_RXC (0x18)
#define SSPA_RXFIFO_NOFS (0x1c)
#define SSPA_RXFIFO_SIZE (0x20)
#define SSPA_TXD (0x80)
#define SSPA_TXID (0x84)
#define SSPA_TXCTL (0x88)
#define SSPA_TXSP (0x8c)
#define SSPA_TXFIFO_LL (0x90)
#define SSPA_TXINT_MASK (0x94)
#define SSPA_TXC (0x98)
#define SSPA_TXFIFO_NOFS (0x9c)
#define SSPA_TXFIFO_SIZE (0xa0)
/* SSPA Control Register */
#define SSPA_CTL_XPH (1 << 31) /* Read Phase */
#define SSPA_CTL_XFIG (1 << 15) /* Transmit Zeros when FIFO Empty */
#define SSPA_CTL_JST (1 << 3) /* Audio Sample Justification */
#define SSPA_CTL_XFRLEN2_MASK (7 << 24)
#define SSPA_CTL_XFRLEN2(x) ((x) << 24) /* Transmit Frame Length in Phase 2 */
#define SSPA_CTL_XWDLEN2_MASK (7 << 21)
#define SSPA_CTL_XWDLEN2(x) ((x) << 21) /* Transmit Word Length in Phase 2 */
#define SSPA_CTL_XDATDLY(x) ((x) << 19) /* Tansmit Data Delay */
#define SSPA_CTL_XSSZ2_MASK (7 << 16)
#define SSPA_CTL_XSSZ2(x) ((x) << 16) /* Transmit Sample Audio Size */
#define SSPA_CTL_XFRLEN1_MASK (7 << 8)
#define SSPA_CTL_XFRLEN1(x) ((x) << 8) /* Transmit Frame Length in Phase 1 */
#define SSPA_CTL_XWDLEN1_MASK (7 << 5)
#define SSPA_CTL_XWDLEN1(x) ((x) << 5) /* Transmit Word Length in Phase 1 */
#define SSPA_CTL_XSSZ1_MASK (7 << 0)
#define SSPA_CTL_XSSZ1(x) ((x) << 0) /* XSSZ1 */
#define SSPA_CTL_8_BITS (0x0) /* Sample Size */
#define SSPA_CTL_12_BITS (0x1)
#define SSPA_CTL_16_BITS (0x2)
#define SSPA_CTL_20_BITS (0x3)
#define SSPA_CTL_24_BITS (0x4)
#define SSPA_CTL_32_BITS (0x5)
/* SSPA Serial Port Register */
#define SSPA_SP_WEN (1 << 31) /* Write Configuration Enable */
#define SSPA_SP_MSL (1 << 18) /* Master Slave Configuration */
#define SSPA_SP_CLKP (1 << 17) /* CLKP Polarity Clock Edge Select */
#define SSPA_SP_FSP (1 << 16) /* FSP Polarity Clock Edge Select */
#define SSPA_SP_FFLUSH (1 << 2) /* FIFO Flush */
#define SSPA_SP_S_RST (1 << 1) /* Active High Reset Signal */
#define SSPA_SP_S_EN (1 << 0) /* Serial Clock Domain Enable */
#define SSPA_SP_FWID(x) ((x) << 20) /* Frame-Sync Width */
#define SSPA_TXSP_FPER(x) ((x) << 4) /* Frame-Sync Active */
/* sspa clock sources */
#define MMP_SSPA_CLK_PLL 0
#define MMP_SSPA_CLK_VCXO 1
#define MMP_SSPA_CLK_AUDIO 3
/* sspa pll id */
#define MMP_SYSCLK 0
#define MMP_SSPA_CLK 1
#endif /* _MMP_SSPA_H */

173
sound/soc/pxa/ttc-dkb.c Normal file
View File

@ -0,0 +1,173 @@
/*
* linux/sound/soc/pxa/ttc_dkb.c
*
* Copyright (C) 2012 Marvell International Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include <asm/mach-types.h>
#include <sound/pcm_params.h>
#include "../codecs/88pm860x-codec.h"
static struct snd_soc_jack hs_jack, mic_jack;
static struct snd_soc_jack_pin hs_jack_pins[] = {
{ .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, },
};
static struct snd_soc_jack_pin mic_jack_pins[] = {
{ .pin = "Headset Mic 2", .mask = SND_JACK_MICROPHONE, },
};
/* ttc machine dapm widgets */
static const struct snd_soc_dapm_widget ttc_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headset Stereophone", NULL),
SND_SOC_DAPM_LINE("Lineout Out 1", NULL),
SND_SOC_DAPM_LINE("Lineout Out 2", NULL),
SND_SOC_DAPM_SPK("Ext Speaker", NULL),
SND_SOC_DAPM_MIC("Ext Mic 1", NULL),
SND_SOC_DAPM_MIC("Headset Mic 2", NULL),
SND_SOC_DAPM_MIC("Ext Mic 3", NULL),
};
/* ttc machine audio map */
static const struct snd_soc_dapm_route ttc_audio_map[] = {
{"Headset Stereophone", NULL, "HS1"},
{"Headset Stereophone", NULL, "HS2"},
{"Ext Speaker", NULL, "LSP"},
{"Ext Speaker", NULL, "LSN"},
{"Lineout Out 1", NULL, "LINEOUT1"},
{"Lineout Out 2", NULL, "LINEOUT2"},
{"MIC1P", NULL, "Mic1 Bias"},
{"MIC1N", NULL, "Mic1 Bias"},
{"Mic1 Bias", NULL, "Ext Mic 1"},
{"MIC2P", NULL, "Mic1 Bias"},
{"MIC2N", NULL, "Mic1 Bias"},
{"Mic1 Bias", NULL, "Headset Mic 2"},
{"MIC3P", NULL, "Mic3 Bias"},
{"MIC3N", NULL, "Mic3 Bias"},
{"Mic3 Bias", NULL, "Ext Mic 3"},
};
static int ttc_pm860x_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
/* connected pins */
snd_soc_dapm_enable_pin(dapm, "Ext Speaker");
snd_soc_dapm_enable_pin(dapm, "Ext Mic 1");
snd_soc_dapm_enable_pin(dapm, "Ext Mic 3");
snd_soc_dapm_disable_pin(dapm, "Headset Mic 2");
snd_soc_dapm_disable_pin(dapm, "Headset Stereophone");
/* Headset jack detection */
snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
| SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
&hs_jack);
snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
hs_jack_pins);
snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE,
&mic_jack);
snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
mic_jack_pins);
/* headphone, microphone detection & headset short detection */
pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2);
pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE);
return 0;
}
/* ttc/td-dkb digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link ttc_pm860x_hifi_dai[] = {
{
.name = "88pm860x i2s",
.stream_name = "audio playback",
.codec_name = "88pm860x-codec",
.platform_name = "mmp-pcm-audio",
.cpu_dai_name = "pxa-ssp-dai.1",
.codec_dai_name = "88pm860x-i2s",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM,
.init = ttc_pm860x_init,
},
};
/* ttc/td audio machine driver */
static struct snd_soc_card ttc_dkb_card = {
.name = "ttc-dkb-hifi",
.dai_link = ttc_pm860x_hifi_dai,
.num_links = ARRAY_SIZE(ttc_pm860x_hifi_dai),
.dapm_widgets = ttc_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(ttc_dapm_widgets),
.dapm_routes = ttc_audio_map,
.num_dapm_routes = ARRAY_SIZE(ttc_audio_map),
};
static int __devinit ttc_dkb_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = &ttc_dkb_card;
int ret;
card->dev = &pdev->dev;
ret = snd_soc_register_card(card);
if (ret)
dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
ret);
return ret;
}
static int __devexit ttc_dkb_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
static struct platform_driver ttc_dkb_driver = {
.driver = {
.name = "ttc-dkb-audio",
.owner = THIS_MODULE,
},
.probe = ttc_dkb_probe,
.remove = __devexit_p(ttc_dkb_remove),
};
module_platform_driver(ttc_dkb_driver);
/* Module information */
MODULE_AUTHOR("Qiao Zhou, <zhouqiao@marvell.com>");
MODULE_DESCRIPTION("ALSA SoC TTC DKB");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:ttc-dkb-audio");

View File

@ -211,6 +211,11 @@ static int bbclk_ev(struct snd_soc_dapm_widget *w,
return 0; return 0;
} }
static const struct snd_kcontrol_new controls[] = {
SOC_DAPM_PIN_SWITCH("WM1250 Input"),
SOC_DAPM_PIN_SWITCH("WM1250 Output"),
};
static struct snd_soc_dapm_widget widgets[] = { static struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_HP("Headphone", NULL),
@ -282,6 +287,8 @@ static struct snd_soc_card littlemill = {
.set_bias_level = littlemill_set_bias_level, .set_bias_level = littlemill_set_bias_level,
.set_bias_level_post = littlemill_set_bias_level_post, .set_bias_level_post = littlemill_set_bias_level_post,
.controls = controls,
.num_controls = ARRAY_SIZE(controls),
.dapm_widgets = widgets, .dapm_widgets = widgets,
.num_dapm_widgets = ARRAY_SIZE(widgets), .num_dapm_widgets = ARRAY_SIZE(widgets),
.dapm_routes = audio_paths, .dapm_routes = audio_paths,

View File

@ -25,7 +25,6 @@
#include <sound/soc.h> #include <sound/soc.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <mach/regs-gpio.h>
#include <mach/dma.h> #include <mach/dma.h>
#include "dma.h" #include "dma.h"
@ -83,12 +82,9 @@ static int s3c2412_i2s_probe(struct snd_soc_dai *dai)
s3c2412_i2s.iis_cclk = s3c2412_i2s.iis_pclk; s3c2412_i2s.iis_cclk = s3c2412_i2s.iis_pclk;
/* Configure the I2S pins in correct mode */ /* Configure the I2S pins (GPE0...GPE4) in correct mode */
s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK); s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2),
s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK); S3C_GPIO_PULL_NONE);
s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK);
s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);
s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);
return 0; return 0;
} }

View File

@ -23,7 +23,6 @@
#include <sound/soc.h> #include <sound/soc.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <mach/regs-gpio.h>
#include <mach/dma.h> #include <mach/dma.h>
#include <plat/regs-iis.h> #include <plat/regs-iis.h>
@ -391,12 +390,9 @@ static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
} }
clk_enable(s3c24xx_i2s.iis_clk); clk_enable(s3c24xx_i2s.iis_clk);
/* Configure the I2S pins in correct mode */ /* Configure the I2S pins (GPE0...GPE4) in correct mode */
s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK); s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2),
s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK); S3C_GPIO_PULL_NONE);
s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK);
s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);
s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);
writel(S3C2410_IISCON_IISEN, s3c24xx_i2s.regs + S3C2410_IISCON); writel(S3C2410_IISCON_IISEN, s3c24xx_i2s.regs + S3C2410_IISCON);

View File

@ -149,31 +149,41 @@ static struct snd_soc_card smdk = {
.num_links = ARRAY_SIZE(smdk_dai), .num_links = ARRAY_SIZE(smdk_dai),
}; };
static struct platform_device *smdk_snd_device;
static int __init smdk_audio_init(void) static int __devinit smdk_audio_probe(struct platform_device *pdev)
{ {
int ret; int ret;
struct snd_soc_card *card = &smdk;
smdk_snd_device = platform_device_alloc("soc-audio", -1); card->dev = &pdev->dev;
if (!smdk_snd_device) ret = snd_soc_register_card(card);
return -ENOMEM;
platform_set_drvdata(smdk_snd_device, &smdk);
ret = platform_device_add(smdk_snd_device);
if (ret) if (ret)
platform_device_put(smdk_snd_device); dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret);
return ret; return ret;
} }
module_init(smdk_audio_init);
static void __exit smdk_audio_exit(void) static int __devexit smdk_audio_remove(struct platform_device *pdev)
{ {
platform_device_unregister(smdk_snd_device); struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
} }
module_exit(smdk_audio_exit);
static struct platform_driver smdk_audio_driver = {
.driver = {
.name = "smdk-audio",
.owner = THIS_MODULE,
},
.probe = smdk_audio_probe,
.remove = __devexit_p(smdk_audio_remove),
};
module_platform_driver(smdk_audio_driver);
MODULE_DESCRIPTION("ALSA SoC SMDK WM8994"); MODULE_DESCRIPTION("ALSA SoC SMDK WM8994");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:smdk-audio");

View File

@ -247,7 +247,7 @@ struct fsi_priv {
struct fsi_stream_handler { struct fsi_stream_handler {
int (*init)(struct fsi_priv *fsi, struct fsi_stream *io); int (*init)(struct fsi_priv *fsi, struct fsi_stream *io);
int (*quit)(struct fsi_priv *fsi, struct fsi_stream *io); int (*quit)(struct fsi_priv *fsi, struct fsi_stream *io);
int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io); int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev);
int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io); int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io);
int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io); int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io);
void (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io, void (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io,
@ -571,16 +571,16 @@ static int fsi_stream_transfer(struct fsi_stream *io)
#define fsi_stream_stop(fsi, io)\ #define fsi_stream_stop(fsi, io)\
fsi_stream_handler_call(io, start_stop, fsi, io, 0) fsi_stream_handler_call(io, start_stop, fsi, io, 0)
static int fsi_stream_probe(struct fsi_priv *fsi) static int fsi_stream_probe(struct fsi_priv *fsi, struct device *dev)
{ {
struct fsi_stream *io; struct fsi_stream *io;
int ret1, ret2; int ret1, ret2;
io = &fsi->playback; io = &fsi->playback;
ret1 = fsi_stream_handler_call(io, probe, fsi, io); ret1 = fsi_stream_handler_call(io, probe, fsi, io, dev);
io = &fsi->capture; io = &fsi->capture;
ret2 = fsi_stream_handler_call(io, probe, fsi, io); ret2 = fsi_stream_handler_call(io, probe, fsi, io, dev);
if (ret1 < 0) if (ret1 < 0)
return ret1; return ret1;
@ -1089,13 +1089,10 @@ static void fsi_dma_do_tasklet(unsigned long data)
{ {
struct fsi_stream *io = (struct fsi_stream *)data; struct fsi_stream *io = (struct fsi_stream *)data;
struct fsi_priv *fsi = fsi_stream_to_priv(io); struct fsi_priv *fsi = fsi_stream_to_priv(io);
struct dma_chan *chan;
struct snd_soc_dai *dai; struct snd_soc_dai *dai;
struct dma_async_tx_descriptor *desc; struct dma_async_tx_descriptor *desc;
struct scatterlist sg;
struct snd_pcm_runtime *runtime; struct snd_pcm_runtime *runtime;
enum dma_data_direction dir; enum dma_data_direction dir;
dma_cookie_t cookie;
int is_play = fsi_stream_is_play(fsi, io); int is_play = fsi_stream_is_play(fsi, io);
int len; int len;
dma_addr_t buf; dma_addr_t buf;
@ -1104,7 +1101,6 @@ static void fsi_dma_do_tasklet(unsigned long data)
return; return;
dai = fsi_get_dai(io->substream); dai = fsi_get_dai(io->substream);
chan = io->chan;
runtime = io->substream->runtime; runtime = io->substream->runtime;
dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
len = samples_to_bytes(runtime, io->period_samples); len = samples_to_bytes(runtime, io->period_samples);
@ -1112,14 +1108,8 @@ static void fsi_dma_do_tasklet(unsigned long data)
dma_sync_single_for_device(dai->dev, buf, len, dir); dma_sync_single_for_device(dai->dev, buf, len, dir);
sg_init_table(&sg, 1); desc = dmaengine_prep_slave_single(io->chan, buf, len, dir,
sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf)), DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
len , offset_in_page(buf));
sg_dma_address(&sg) = buf;
sg_dma_len(&sg) = len;
desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) { if (!desc) {
dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n"); dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n");
return; return;
@ -1128,13 +1118,12 @@ static void fsi_dma_do_tasklet(unsigned long data)
desc->callback = fsi_dma_complete; desc->callback = fsi_dma_complete;
desc->callback_param = io; desc->callback_param = io;
cookie = desc->tx_submit(desc); if (dmaengine_submit(desc) < 0) {
if (cookie < 0) {
dev_err(dai->dev, "tx_submit() fail\n"); dev_err(dai->dev, "tx_submit() fail\n");
return; return;
} }
dma_async_issue_pending(chan); dma_async_issue_pending(io->chan);
/* /*
* FIXME * FIXME
@ -1184,7 +1173,7 @@ static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
} }
static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io) static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev)
{ {
dma_cap_mask_t mask; dma_cap_mask_t mask;
@ -1192,8 +1181,19 @@ static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io)
dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SLAVE, mask);
io->chan = dma_request_channel(mask, fsi_dma_filter, &io->slave); io->chan = dma_request_channel(mask, fsi_dma_filter, &io->slave);
if (!io->chan) if (!io->chan) {
return -EIO;
/* switch to PIO handler */
if (fsi_stream_is_play(fsi, io))
fsi->playback.handler = &fsi_pio_push_handler;
else
fsi->capture.handler = &fsi_pio_pop_handler;
dev_info(dev, "switch handler (dma => pio)\n");
/* probe again */
return fsi_stream_probe(fsi, dev);
}
tasklet_init(&io->tasklet, fsi_dma_do_tasklet, (unsigned long)io); tasklet_init(&io->tasklet, fsi_dma_do_tasklet, (unsigned long)io);
@ -1683,7 +1683,7 @@ static int fsi_probe(struct platform_device *pdev)
master->fsia.master = master; master->fsia.master = master;
master->fsia.info = &info->port_a; master->fsia.info = &info->port_a;
fsi_handler_init(&master->fsia); fsi_handler_init(&master->fsia);
ret = fsi_stream_probe(&master->fsia); ret = fsi_stream_probe(&master->fsia, &pdev->dev);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "FSIA stream probe failed\n"); dev_err(&pdev->dev, "FSIA stream probe failed\n");
goto exit_iounmap; goto exit_iounmap;
@ -1694,7 +1694,7 @@ static int fsi_probe(struct platform_device *pdev)
master->fsib.master = master; master->fsib.master = master;
master->fsib.info = &info->port_b; master->fsib.info = &info->port_b;
fsi_handler_init(&master->fsib); fsi_handler_init(&master->fsib);
ret = fsi_stream_probe(&master->fsib); ret = fsi_stream_probe(&master->fsib, &pdev->dev);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "FSIB stream probe failed\n"); dev_err(&pdev->dev, "FSIB stream probe failed\n");
goto exit_fsia; goto exit_fsia;

View File

@ -812,13 +812,15 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
/* Find CPU DAI from registered DAIs*/ /* Find CPU DAI from registered DAIs*/
list_for_each_entry(cpu_dai, &dai_list, list) { list_for_each_entry(cpu_dai, &dai_list, list) {
if (dai_link->cpu_dai_of_node) { if (dai_link->cpu_of_node &&
if (cpu_dai->dev->of_node != dai_link->cpu_dai_of_node) (cpu_dai->dev->of_node != dai_link->cpu_of_node))
continue; continue;
} else { if (dai_link->cpu_name &&
if (strcmp(cpu_dai->name, dai_link->cpu_dai_name)) strcmp(dev_name(cpu_dai->dev), dai_link->cpu_name))
continue; continue;
} if (dai_link->cpu_dai_name &&
strcmp(cpu_dai->name, dai_link->cpu_dai_name))
continue;
rtd->cpu_dai = cpu_dai; rtd->cpu_dai = cpu_dai;
} }
@ -896,6 +898,28 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
return 0; return 0;
} }
static int soc_remove_platform(struct snd_soc_platform *platform)
{
int ret;
if (platform->driver->remove) {
ret = platform->driver->remove(platform);
if (ret < 0)
pr_err("asoc: failed to remove %s: %d\n",
platform->name, ret);
}
/* Make sure all DAPM widgets are freed */
snd_soc_dapm_free(&platform->dapm);
soc_cleanup_platform_debugfs(platform);
platform->probed = 0;
list_del(&platform->card_list);
module_put(platform->dev->driver->owner);
return 0;
}
static void soc_remove_codec(struct snd_soc_codec *codec) static void soc_remove_codec(struct snd_soc_codec *codec)
{ {
int err; int err;
@ -917,11 +941,9 @@ static void soc_remove_codec(struct snd_soc_codec *codec)
module_put(codec->dev->driver->owner); module_put(codec->dev->driver->owner);
} }
static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order) static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
{ {
struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
int err; int err;
@ -946,30 +968,6 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order)
list_del(&codec_dai->card_list); list_del(&codec_dai->card_list);
} }
/* remove the platform */
if (platform && platform->probed &&
platform->driver->remove_order == order) {
if (platform->driver->remove) {
err = platform->driver->remove(platform);
if (err < 0)
pr_err("asoc: failed to remove %s: %d\n",
platform->name, err);
}
/* Make sure all DAPM widgets are freed */
snd_soc_dapm_free(&platform->dapm);
soc_cleanup_platform_debugfs(platform);
platform->probed = 0;
list_del(&platform->card_list);
module_put(platform->dev->driver->owner);
}
/* remove the CODEC */
if (codec && codec->probed &&
codec->driver->remove_order == order)
soc_remove_codec(codec);
/* remove the cpu_dai */ /* remove the cpu_dai */
if (cpu_dai && cpu_dai->probed && if (cpu_dai && cpu_dai->probed &&
cpu_dai->driver->remove_order == order) { cpu_dai->driver->remove_order == order) {
@ -981,7 +979,43 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order)
} }
cpu_dai->probed = 0; cpu_dai->probed = 0;
list_del(&cpu_dai->card_list); list_del(&cpu_dai->card_list);
module_put(cpu_dai->dev->driver->owner);
if (!cpu_dai->codec) {
snd_soc_dapm_free(&cpu_dai->dapm);
module_put(cpu_dai->dev->driver->owner);
}
}
}
static void soc_remove_link_components(struct snd_soc_card *card, int num,
int order)
{
struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_codec *codec;
/* remove the platform */
if (platform && platform->probed &&
platform->driver->remove_order == order) {
soc_remove_platform(platform);
}
/* remove the CODEC-side CODEC */
if (codec_dai) {
codec = codec_dai->codec;
if (codec && codec->probed &&
codec->driver->remove_order == order)
soc_remove_codec(codec);
}
/* remove any CPU-side CODEC */
if (cpu_dai) {
codec = cpu_dai->codec;
if (codec && codec->probed &&
codec->driver->remove_order == order)
soc_remove_codec(codec);
} }
} }
@ -992,8 +1026,15 @@ static void soc_remove_dai_links(struct snd_soc_card *card)
for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
order++) { order++) {
for (dai = 0; dai < card->num_rtd; dai++) for (dai = 0; dai < card->num_rtd; dai++)
soc_remove_dai_link(card, dai, order); soc_remove_link_dais(card, dai, order);
} }
for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
order++) {
for (dai = 0; dai < card->num_rtd; dai++)
soc_remove_link_components(card, dai, order);
}
card->num_rtd = 0; card->num_rtd = 0;
} }
@ -1054,6 +1095,10 @@ static int soc_probe_codec(struct snd_soc_card *card,
} }
} }
/* If the driver didn't set I/O up try regmap */
if (!codec->control_data)
snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
if (driver->controls) if (driver->controls)
snd_soc_add_codec_controls(codec, driver->controls, snd_soc_add_codec_controls(codec, driver->controls,
driver->num_controls); driver->num_controls);
@ -1230,7 +1275,44 @@ out:
return 0; return 0;
} }
static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order) static int soc_probe_link_components(struct snd_soc_card *card, int num,
int order)
{
struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_platform *platform = rtd->platform;
int ret;
/* probe the CPU-side component, if it is a CODEC */
if (cpu_dai->codec &&
!cpu_dai->codec->probed &&
cpu_dai->codec->driver->probe_order == order) {
ret = soc_probe_codec(card, cpu_dai->codec);
if (ret < 0)
return ret;
}
/* probe the CODEC-side component */
if (!codec_dai->codec->probed &&
codec_dai->codec->driver->probe_order == order) {
ret = soc_probe_codec(card, codec_dai->codec);
if (ret < 0)
return ret;
}
/* probe the platform */
if (!platform->probed &&
platform->driver->probe_order == order) {
ret = soc_probe_platform(card, platform);
if (ret < 0)
return ret;
}
return 0;
}
static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
{ {
struct snd_soc_dai_link *dai_link = &card->dai_link[num]; struct snd_soc_dai_link *dai_link = &card->dai_link[num];
struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
@ -1255,11 +1337,14 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
/* probe the cpu_dai */ /* probe the cpu_dai */
if (!cpu_dai->probed && if (!cpu_dai->probed &&
cpu_dai->driver->probe_order == order) { cpu_dai->driver->probe_order == order) {
cpu_dai->dapm.card = card; if (!cpu_dai->codec) {
if (!try_module_get(cpu_dai->dev->driver->owner)) cpu_dai->dapm.card = card;
return -ENODEV; if (!try_module_get(cpu_dai->dev->driver->owner))
return -ENODEV;
snd_soc_dapm_new_dai_widgets(&cpu_dai->dapm, cpu_dai); list_add(&cpu_dai->dapm.list, &card->dapm_list);
snd_soc_dapm_new_dai_widgets(&cpu_dai->dapm, cpu_dai);
}
if (cpu_dai->driver->probe) { if (cpu_dai->driver->probe) {
ret = cpu_dai->driver->probe(cpu_dai); ret = cpu_dai->driver->probe(cpu_dai);
@ -1275,22 +1360,6 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
list_add(&cpu_dai->card_list, &card->dai_dev_list); list_add(&cpu_dai->card_list, &card->dai_dev_list);
} }
/* probe the CODEC */
if (!codec->probed &&
codec->driver->probe_order == order) {
ret = soc_probe_codec(card, codec);
if (ret < 0)
return ret;
}
/* probe the platform */
if (!platform->probed &&
platform->driver->probe_order == order) {
ret = soc_probe_platform(card, platform);
if (ret < 0)
return ret;
}
/* probe the CODEC DAI */ /* probe the CODEC DAI */
if (!codec_dai->probed && codec_dai->driver->probe_order == order) { if (!codec_dai->probed && codec_dai->driver->probe_order == order) {
if (codec_dai->driver->probe) { if (codec_dai->driver->probe) {
@ -1565,14 +1634,27 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
goto card_probe_error; goto card_probe_error;
} }
/* early DAI link probe */ /* probe all components used by DAI links on this card */
for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
order++) { order++) {
for (i = 0; i < card->num_links; i++) { for (i = 0; i < card->num_links; i++) {
ret = soc_probe_dai_link(card, i, order); ret = soc_probe_link_components(card, i, order);
if (ret < 0) { if (ret < 0) {
pr_err("asoc: failed to instantiate card %s: %d\n", pr_err("asoc: failed to instantiate card %s: %d\n",
card->name, ret); card->name, ret);
goto probe_dai_err;
}
}
}
/* probe all DAI links on this card */
for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
order++) {
for (i = 0; i < card->num_links; i++) {
ret = soc_probe_link_dais(card, i, order);
if (ret < 0) {
pr_err("asoc: failed to instantiate card %s: %d\n",
card->name, ret);
goto probe_dai_err; goto probe_dai_err;
} }
} }
@ -2789,6 +2871,104 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
} }
EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8);
/**
* snd_soc_info_volsw_range - single mixer info callback with range.
* @kcontrol: mixer control
* @uinfo: control element information
*
* Callback to provide information, within a range, about a single
* mixer control.
*
* returns 0 for success.
*/
int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
int platform_max;
int min = mc->min;
if (!mc->platform_max)
mc->platform_max = mc->max;
platform_max = mc->platform_max;
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = platform_max - min;
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_info_volsw_range);
/**
* snd_soc_put_volsw_range - single mixer put value callback with range.
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback to set the value, within a range, for a single mixer control.
*
* Returns 0 for success.
*/
int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
unsigned int shift = mc->shift;
int min = mc->min;
int max = mc->max;
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
unsigned int val, val_mask;
val = ((ucontrol->value.integer.value[0] + min) & mask);
if (invert)
val = max - val;
val_mask = mask << shift;
val = val << shift;
return snd_soc_update_bits_locked(codec, reg, val_mask, val);
}
EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range);
/**
* snd_soc_get_volsw_range - single mixer get callback with range
* @kcontrol: mixer control
* @ucontrol: control element information
*
* Callback to get the value, within a range, of a single mixer control.
*
* Returns 0 for success.
*/
int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
unsigned int shift = mc->shift;
int min = mc->min;
int max = mc->max;
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
ucontrol->value.integer.value[0] =
(snd_soc_read(codec, reg) >> shift) & mask;
if (invert)
ucontrol->value.integer.value[0] =
max - ucontrol->value.integer.value[0];
ucontrol->value.integer.value[0] =
ucontrol->value.integer.value[0] - min;
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range);
/** /**
* snd_soc_limit_volume - Set new limit to an existing volume control. * snd_soc_limit_volume - Set new limit to an existing volume control.
* *
@ -3346,6 +3526,12 @@ int snd_soc_register_card(struct snd_soc_card *card)
link->name); link->name);
return -EINVAL; return -EINVAL;
} }
/* Codec DAI name must be specified */
if (!link->codec_dai_name) {
dev_err(card->dev, "codec_dai_name not set for %s\n",
link->name);
return -EINVAL;
}
/* /*
* Platform may be specified by either name or OF node, but * Platform may be specified by either name or OF node, but
@ -3358,12 +3544,24 @@ int snd_soc_register_card(struct snd_soc_card *card)
} }
/* /*
* CPU DAI must be specified by 1 of name or OF node, * CPU device may be specified by either name or OF node, but
* not both or neither. * can be left unspecified, and will be matched based on DAI
* name alone..
*/ */
if (!!link->cpu_dai_name == !!link->cpu_dai_of_node) { if (link->cpu_name && link->cpu_of_node) {
dev_err(card->dev, dev_err(card->dev,
"Neither/both cpu_dai name/of_node are set for %s\n", "Neither/both cpu name/of_node are set for %s\n",
link->name);
return -EINVAL;
}
/*
* At least one of CPU DAI name or CPU device name/node must be
* specified
*/
if (!link->cpu_dai_name &&
!(link->cpu_name || link->cpu_of_node)) {
dev_err(card->dev,
"Neither cpu_dai_name nor cpu_name/of_node are set for %s\n",
link->name); link->name);
return -EINVAL; return -EINVAL;
} }
@ -3938,6 +4136,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
dev_err(card->dev, dev_err(card->dev,
"Property '%s' index %d could not be read: %d\n", "Property '%s' index %d could not be read: %d\n",
propname, 2 * i, ret); propname, 2 * i, ret);
kfree(routes);
return -EINVAL; return -EINVAL;
} }
ret = of_property_read_string_index(np, propname, ret = of_property_read_string_index(np, propname,
@ -3946,6 +4145,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
dev_err(card->dev, dev_err(card->dev,
"Property '%s' index %d could not be read: %d\n", "Property '%s' index %d could not be read: %d\n",
propname, (2 * i) + 1, ret); propname, (2 * i) + 1, ret);
kfree(routes);
return -EINVAL; return -EINVAL;
} }
} }

View File

@ -35,6 +35,7 @@
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/clk.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
@ -51,6 +52,7 @@ static int dapm_up_seq[] = {
[snd_soc_dapm_pre] = 0, [snd_soc_dapm_pre] = 0,
[snd_soc_dapm_supply] = 1, [snd_soc_dapm_supply] = 1,
[snd_soc_dapm_regulator_supply] = 1, [snd_soc_dapm_regulator_supply] = 1,
[snd_soc_dapm_clock_supply] = 1,
[snd_soc_dapm_micbias] = 2, [snd_soc_dapm_micbias] = 2,
[snd_soc_dapm_dai_link] = 2, [snd_soc_dapm_dai_link] = 2,
[snd_soc_dapm_dai] = 3, [snd_soc_dapm_dai] = 3,
@ -92,6 +94,7 @@ static int dapm_down_seq[] = {
[snd_soc_dapm_aif_out] = 10, [snd_soc_dapm_aif_out] = 10,
[snd_soc_dapm_dai] = 10, [snd_soc_dapm_dai] = 10,
[snd_soc_dapm_dai_link] = 11, [snd_soc_dapm_dai_link] = 11,
[snd_soc_dapm_clock_supply] = 12,
[snd_soc_dapm_regulator_supply] = 12, [snd_soc_dapm_regulator_supply] = 12,
[snd_soc_dapm_supply] = 12, [snd_soc_dapm_supply] = 12,
[snd_soc_dapm_post] = 13, [snd_soc_dapm_post] = 13,
@ -391,6 +394,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
case snd_soc_dapm_vmid: case snd_soc_dapm_vmid:
case snd_soc_dapm_supply: case snd_soc_dapm_supply:
case snd_soc_dapm_regulator_supply: case snd_soc_dapm_regulator_supply:
case snd_soc_dapm_clock_supply:
case snd_soc_dapm_aif_in: case snd_soc_dapm_aif_in:
case snd_soc_dapm_aif_out: case snd_soc_dapm_aif_out:
case snd_soc_dapm_dai: case snd_soc_dapm_dai:
@ -764,6 +768,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
switch (widget->id) { switch (widget->id) {
case snd_soc_dapm_supply: case snd_soc_dapm_supply:
case snd_soc_dapm_regulator_supply: case snd_soc_dapm_regulator_supply:
case snd_soc_dapm_clock_supply:
return 0; return 0;
default: default:
break; break;
@ -850,6 +855,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
switch (widget->id) { switch (widget->id) {
case snd_soc_dapm_supply: case snd_soc_dapm_supply:
case snd_soc_dapm_regulator_supply: case snd_soc_dapm_regulator_supply:
case snd_soc_dapm_clock_supply:
return 0; return 0;
default: default:
break; break;
@ -996,6 +1002,27 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
} }
EXPORT_SYMBOL_GPL(dapm_regulator_event); EXPORT_SYMBOL_GPL(dapm_regulator_event);
/*
* Handler for clock supply widget.
*/
int dapm_clock_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
if (!w->clk)
return -EIO;
#ifdef CONFIG_HAVE_CLK
if (SND_SOC_DAPM_EVENT_ON(event)) {
return clk_enable(w->clk);
} else {
clk_disable(w->clk);
return 0;
}
#endif
return 0;
}
EXPORT_SYMBOL_GPL(dapm_clock_event);
static int dapm_widget_power_check(struct snd_soc_dapm_widget *w) static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
{ {
if (w->power_checked) if (w->power_checked)
@ -1487,6 +1514,7 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
switch (w->id) { switch (w->id) {
case snd_soc_dapm_supply: case snd_soc_dapm_supply:
case snd_soc_dapm_regulator_supply: case snd_soc_dapm_regulator_supply:
case snd_soc_dapm_clock_supply:
/* Supplies can't affect their outputs, only their inputs */ /* Supplies can't affect their outputs, only their inputs */
break; break;
default: default:
@ -1587,6 +1615,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
break; break;
case snd_soc_dapm_supply: case snd_soc_dapm_supply:
case snd_soc_dapm_regulator_supply: case snd_soc_dapm_regulator_supply:
case snd_soc_dapm_clock_supply:
case snd_soc_dapm_micbias: case snd_soc_dapm_micbias:
if (d->target_bias_level < SND_SOC_BIAS_STANDBY) if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
d->target_bias_level = SND_SOC_BIAS_STANDBY; d->target_bias_level = SND_SOC_BIAS_STANDBY;
@ -1941,6 +1970,7 @@ static ssize_t dapm_widget_show(struct device *dev,
case snd_soc_dapm_mixer_named_ctl: case snd_soc_dapm_mixer_named_ctl:
case snd_soc_dapm_supply: case snd_soc_dapm_supply:
case snd_soc_dapm_regulator_supply: case snd_soc_dapm_regulator_supply:
case snd_soc_dapm_clock_supply:
if (w->name) if (w->name)
count += sprintf(buf + count, "%s: %s\n", count += sprintf(buf + count, "%s: %s\n",
w->name, w->power ? "On":"Off"); w->name, w->power ? "On":"Off");
@ -2187,6 +2217,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
case snd_soc_dapm_post: case snd_soc_dapm_post:
case snd_soc_dapm_supply: case snd_soc_dapm_supply:
case snd_soc_dapm_regulator_supply: case snd_soc_dapm_regulator_supply:
case snd_soc_dapm_clock_supply:
case snd_soc_dapm_aif_in: case snd_soc_dapm_aif_in:
case snd_soc_dapm_aif_out: case snd_soc_dapm_aif_out:
case snd_soc_dapm_dai: case snd_soc_dapm_dai:
@ -2221,6 +2252,10 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
path->connect = 0; path->connect = 0;
return 0; return 0;
} }
dapm_mark_dirty(wsource, "Route added");
dapm_mark_dirty(wsink, "Route added");
return 0; return 0;
err: err:
@ -2230,6 +2265,59 @@ err:
return ret; return ret;
} }
static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route)
{
struct snd_soc_dapm_path *path, *p;
const char *sink;
const char *source;
char prefixed_sink[80];
char prefixed_source[80];
if (route->control) {
dev_err(dapm->dev,
"Removal of routes with controls not supported\n");
return -EINVAL;
}
if (dapm->codec && dapm->codec->name_prefix) {
snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
dapm->codec->name_prefix, route->sink);
sink = prefixed_sink;
snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
dapm->codec->name_prefix, route->source);
source = prefixed_source;
} else {
sink = route->sink;
source = route->source;
}
path = NULL;
list_for_each_entry(p, &dapm->card->paths, list) {
if (strcmp(p->source->name, source) != 0)
continue;
if (strcmp(p->sink->name, sink) != 0)
continue;
path = p;
break;
}
if (path) {
dapm_mark_dirty(path->source, "Route removed");
dapm_mark_dirty(path->sink, "Route removed");
list_del(&path->list);
list_del(&path->list_sink);
list_del(&path->list_source);
kfree(path);
} else {
dev_warn(dapm->dev, "Route %s->%s does not exist\n",
source, sink);
}
return 0;
}
/** /**
* snd_soc_dapm_add_routes - Add routes between DAPM widgets * snd_soc_dapm_add_routes - Add routes between DAPM widgets
* @dapm: DAPM context * @dapm: DAPM context
@ -2246,15 +2334,15 @@ err:
int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route, int num) const struct snd_soc_dapm_route *route, int num)
{ {
int i, ret = 0; int i, r, ret = 0;
mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
ret = snd_soc_dapm_add_route(dapm, route); r = snd_soc_dapm_add_route(dapm, route);
if (ret < 0) { if (r < 0) {
dev_err(dapm->dev, "Failed to add route %s->%s\n", dev_err(dapm->dev, "Failed to add route %s->%s\n",
route->source, route->sink); route->source, route->sink);
break; ret = r;
} }
route++; route++;
} }
@ -2264,6 +2352,30 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
} }
EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
/**
* snd_soc_dapm_del_routes - Remove routes between DAPM widgets
* @dapm: DAPM context
* @route: audio routes
* @num: number of routes
*
* Removes routes from the DAPM context.
*/
int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route, int num)
{
int i, ret = 0;
mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
for (i = 0; i < num; i++) {
snd_soc_dapm_del_route(dapm, route);
route++;
}
mutex_unlock(&dapm->card->dapm_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes);
static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm, static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route) const struct snd_soc_dapm_route *route)
{ {
@ -2434,23 +2546,20 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
(struct soc_mixer_control *)kcontrol->private_value; (struct soc_mixer_control *)kcontrol->private_value;
unsigned int reg = mc->reg; unsigned int reg = mc->reg;
unsigned int shift = mc->shift; unsigned int shift = mc->shift;
unsigned int rshift = mc->rshift;
int max = mc->max; int max = mc->max;
unsigned int invert = mc->invert;
unsigned int mask = (1 << fls(max)) - 1; unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
if (snd_soc_volsw_is_stereo(mc))
dev_warn(widget->dapm->dev,
"Control '%s' is stereo, which is not supported\n",
kcontrol->id.name);
ucontrol->value.integer.value[0] = ucontrol->value.integer.value[0] =
(snd_soc_read(widget->codec, reg) >> shift) & mask; (snd_soc_read(widget->codec, reg) >> shift) & mask;
if (shift != rshift) if (invert)
ucontrol->value.integer.value[1] =
(snd_soc_read(widget->codec, reg) >> rshift) & mask;
if (invert) {
ucontrol->value.integer.value[0] = ucontrol->value.integer.value[0] =
max - ucontrol->value.integer.value[0]; max - ucontrol->value.integer.value[0];
if (shift != rshift)
ucontrol->value.integer.value[1] =
max - ucontrol->value.integer.value[1];
}
return 0; return 0;
} }
@ -2484,20 +2593,19 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_update update; struct snd_soc_dapm_update update;
int wi; int wi;
if (snd_soc_volsw_is_stereo(mc))
dev_warn(widget->dapm->dev,
"Control '%s' is stereo, which is not supported\n",
kcontrol->id.name);
val = (ucontrol->value.integer.value[0] & mask); val = (ucontrol->value.integer.value[0] & mask);
connect = !!val;
if (invert) if (invert)
val = max - val; val = max - val;
mask = mask << shift; mask = mask << shift;
val = val << shift; val = val << shift;
if (val)
/* new connection */
connect = invert ? 0 : 1;
else
/* old connection must be powered down */
connect = invert ? 1 : 0;
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
change = snd_soc_test_bits(widget->codec, reg, mask, val); change = snd_soc_test_bits(widget->codec, reg, mask, val);
@ -2873,6 +2981,19 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
return NULL; return NULL;
} }
break; break;
case snd_soc_dapm_clock_supply:
#ifdef CONFIG_CLKDEV_LOOKUP
w->clk = devm_clk_get(dapm->dev, w->name);
if (IS_ERR(w->clk)) {
ret = PTR_ERR(w->clk);
dev_err(dapm->dev, "Failed to request %s: %d\n",
w->name, ret);
return NULL;
}
#else
return NULL;
#endif
break;
default: default:
break; break;
} }
@ -2924,6 +3045,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
break; break;
case snd_soc_dapm_supply: case snd_soc_dapm_supply:
case snd_soc_dapm_regulator_supply: case snd_soc_dapm_regulator_supply:
case snd_soc_dapm_clock_supply:
w->power_check = dapm_supply_check_power; w->power_check = dapm_supply_check_power;
break; break;
case snd_soc_dapm_dai: case snd_soc_dapm_dai:

View File

@ -30,6 +30,7 @@
struct dmaengine_pcm_runtime_data { struct dmaengine_pcm_runtime_data {
struct dma_chan *dma_chan; struct dma_chan *dma_chan;
dma_cookie_t cookie;
unsigned int pos; unsigned int pos;
@ -153,7 +154,7 @@ static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream)
desc->callback = dmaengine_pcm_dma_complete; desc->callback = dmaengine_pcm_dma_complete;
desc->callback_param = substream; desc->callback_param = substream;
dmaengine_submit(desc); prtd->cookie = dmaengine_submit(desc);
return 0; return 0;
} }
@ -199,6 +200,20 @@ int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
} }
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_trigger); EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_trigger);
/**
* snd_dmaengine_pcm_pointer_no_residue - dmaengine based PCM pointer implementation
* @substream: PCM substream
*
* This function is deprecated and should not be used by new drivers, as its
* results may be unreliable.
*/
snd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream)
{
struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
return bytes_to_frames(substream->runtime, prtd->pos);
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer_no_residue);
/** /**
* snd_dmaengine_pcm_pointer - dmaengine based PCM pointer implementation * snd_dmaengine_pcm_pointer - dmaengine based PCM pointer implementation
* @substream: PCM substream * @substream: PCM substream
@ -209,7 +224,19 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_trigger);
snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
{ {
struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
return bytes_to_frames(substream->runtime, prtd->pos); struct dma_tx_state state;
enum dma_status status;
unsigned int buf_size;
unsigned int pos = 0;
status = dmaengine_tx_status(prtd->dma_chan, prtd->cookie, &state);
if (status == DMA_IN_PROGRESS || status == DMA_PAUSED) {
buf_size = snd_pcm_lib_buffer_bytes(substream);
if (state.residue > 0 && state.residue <= buf_size)
pos = buf_size - state.residue;
}
return bytes_to_frames(substream->runtime, pos);
} }
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer); EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer);
@ -243,7 +270,7 @@ static int dmaengine_pcm_request_channel(struct dmaengine_pcm_runtime_data *prtd
* Note that this function will use private_data field of the substream's * Note that this function will use private_data field of the substream's
* runtime. So it is not availabe to your pcm driver implementation. If you need * runtime. So it is not availabe to your pcm driver implementation. If you need
* to keep additional data attached to a substream use * to keep additional data attached to a substream use
* snd_dmaeinge_pcm_{set,get}_data. * snd_dmaengine_pcm_{set,get}_data.
*/ */
int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
dma_filter_fn filter_fn, void *filter_data) dma_filter_fn filter_fn, void *filter_data)

View File

@ -142,11 +142,16 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
case SND_SOC_REGMAP: case SND_SOC_REGMAP:
/* Device has made its own regmap arrangements */ /* Device has made its own regmap arrangements */
codec->using_regmap = true; codec->using_regmap = true;
if (!codec->control_data)
codec->control_data = dev_get_regmap(codec->dev, NULL);
ret = regmap_get_val_bytes(codec->control_data); if (codec->control_data) {
/* Errors are legitimate for non-integer byte multiples */ ret = regmap_get_val_bytes(codec->control_data);
if (ret > 0) /* Errors are legitimate for non-integer byte
codec->val_bytes = ret; * multiples */
if (ret > 0)
codec->val_bytes = ret;
}
break; break;
default: default:

View File

@ -1955,10 +1955,8 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
fe->dpcm[stream].runtime = fe_substream->runtime; fe->dpcm[stream].runtime = fe_substream->runtime;
if (dpcm_path_get(fe, stream, &list) <= 0) { if (dpcm_path_get(fe, stream, &list) <= 0) {
dev_warn(fe->dev, "asoc: %s no valid %s route\n", dev_dbg(fe->dev, "asoc: %s no valid %s route\n",
fe->dai_link->name, stream ? "capture" : "playback"); fe->dai_link->name, stream ? "capture" : "playback");
mutex_unlock(&fe->card->mutex);
return -EINVAL;
} }
/* calculate valid and active FE <-> BE dpcms */ /* calculate valid and active FE <-> BE dpcms */
@ -2003,7 +2001,6 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
/* create a new pcm */ /* create a new pcm */
int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
{ {
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_platform *platform = rtd->platform; struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@ -2042,7 +2039,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
capture, &pcm); capture, &pcm);
} }
if (ret < 0) { if (ret < 0) {
printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name); dev_err(rtd->card->dev, "can't create pcm for %s\n",
rtd->dai_link->name);
return ret; return ret;
} }
dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num, new_name); dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num, new_name);
@ -2099,14 +2097,14 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
if (platform->driver->pcm_new) { if (platform->driver->pcm_new) {
ret = platform->driver->pcm_new(rtd); ret = platform->driver->pcm_new(rtd);
if (ret < 0) { if (ret < 0) {
pr_err("asoc: platform pcm constructor failed\n"); dev_err(platform->dev, "pcm constructor failed\n");
return ret; return ret;
} }
} }
pcm->private_free = platform->driver->pcm_free; pcm->private_free = platform->driver->pcm_free;
out: out:
printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name, dev_info(rtd->card->dev, " %s <-> %s mapping ok\n", codec_dai->name,
cpu_dai->name); cpu_dai->name);
return ret; return ret;
} }

297
sound/soc/spear/spdif_in.c Normal file
View File

@ -0,0 +1,297 @@
/*
* ALSA SoC SPDIF In Audio Layer for spear processors
*
* Copyright (C) 2012 ST Microelectronics
* Vipin Kumar <vipin.kumar@st.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/spear_dma.h>
#include <sound/spear_spdif.h>
#include "spdif_in_regs.h"
struct spdif_in_params {
u32 format;
};
struct spdif_in_dev {
struct clk *clk;
struct spear_dma_data dma_params;
struct spdif_in_params saved_params;
void *io_base;
struct device *dev;
void (*reset_perip)(void);
int irq;
};
static void spdif_in_configure(struct spdif_in_dev *host)
{
u32 ctrl = SPDIF_IN_PRTYEN | SPDIF_IN_STATEN | SPDIF_IN_USREN |
SPDIF_IN_VALEN | SPDIF_IN_BLKEN;
ctrl |= SPDIF_MODE_16BIT | SPDIF_FIFO_THRES_16;
writel(ctrl, host->io_base + SPDIF_IN_CTRL);
writel(0xF, host->io_base + SPDIF_IN_IRQ_MASK);
}
static int spdif_in_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct spdif_in_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
return -EINVAL;
snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)&host->dma_params);
return 0;
}
static void spdif_in_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai);
if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
return;
writel(0x0, host->io_base + SPDIF_IN_IRQ_MASK);
snd_soc_dai_set_dma_data(dai, substream, NULL);
}
static void spdif_in_format(struct spdif_in_dev *host, u32 format)
{
u32 ctrl = readl(host->io_base + SPDIF_IN_CTRL);
switch (format) {
case SNDRV_PCM_FORMAT_S16_LE:
ctrl |= SPDIF_XTRACT_16BIT;
break;
case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
ctrl &= ~SPDIF_XTRACT_16BIT;
break;
}
writel(ctrl, host->io_base + SPDIF_IN_CTRL);
}
static int spdif_in_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai);
u32 format;
if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
return -EINVAL;
format = params_format(params);
host->saved_params.format = format;
return 0;
}
static int spdif_in_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai);
u32 ctrl;
int ret = 0;
if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
return -EINVAL;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
clk_enable(host->clk);
spdif_in_configure(host);
spdif_in_format(host, host->saved_params.format);
ctrl = readl(host->io_base + SPDIF_IN_CTRL);
ctrl |= SPDIF_IN_SAMPLE | SPDIF_IN_ENB;
writel(ctrl, host->io_base + SPDIF_IN_CTRL);
writel(0xF, host->io_base + SPDIF_IN_IRQ_MASK);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
ctrl = readl(host->io_base + SPDIF_IN_CTRL);
ctrl &= ~(SPDIF_IN_SAMPLE | SPDIF_IN_ENB);
writel(ctrl, host->io_base + SPDIF_IN_CTRL);
writel(0x0, host->io_base + SPDIF_IN_IRQ_MASK);
if (host->reset_perip)
host->reset_perip();
clk_disable(host->clk);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static struct snd_soc_dai_ops spdif_in_dai_ops = {
.startup = spdif_in_startup,
.shutdown = spdif_in_shutdown,
.trigger = spdif_in_trigger,
.hw_params = spdif_in_hw_params,
};
struct snd_soc_dai_driver spdif_in_dai = {
.capture = {
.channels_min = 2,
.channels_max = 2,
.rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \
SNDRV_PCM_RATE_192000),
.formats = SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
},
.ops = &spdif_in_dai_ops,
};
static irqreturn_t spdif_in_irq(int irq, void *arg)
{
struct spdif_in_dev *host = (struct spdif_in_dev *)arg;
u32 irq_status = readl(host->io_base + SPDIF_IN_IRQ);
if (!irq_status)
return IRQ_NONE;
if (irq_status & SPDIF_IRQ_FIFOWRITE)
dev_err(host->dev, "spdif in: fifo write error");
if (irq_status & SPDIF_IRQ_EMPTYFIFOREAD)
dev_err(host->dev, "spdif in: empty fifo read error");
if (irq_status & SPDIF_IRQ_FIFOFULL)
dev_err(host->dev, "spdif in: fifo full error");
if (irq_status & SPDIF_IRQ_OUTOFRANGE)
dev_err(host->dev, "spdif in: out of range error");
writel(0, host->io_base + SPDIF_IN_IRQ);
return IRQ_HANDLED;
}
static int spdif_in_probe(struct platform_device *pdev)
{
struct spdif_in_dev *host;
struct spear_spdif_platform_data *pdata;
struct resource *res, *res_fifo;
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -EINVAL;
res_fifo = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!res_fifo)
return -EINVAL;
if (!devm_request_mem_region(&pdev->dev, res->start,
resource_size(res), pdev->name)) {
dev_warn(&pdev->dev, "Failed to get memory resourse\n");
return -ENOENT;
}
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
if (!host) {
dev_warn(&pdev->dev, "kzalloc fail\n");
return -ENOMEM;
}
host->io_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
if (!host->io_base) {
dev_warn(&pdev->dev, "ioremap failed\n");
return -ENOMEM;
}
host->irq = platform_get_irq(pdev, 0);
if (host->irq < 0)
return -EINVAL;
host->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(host->clk))
return PTR_ERR(host->clk);
pdata = dev_get_platdata(&pdev->dev);
if (!pdata)
return -EINVAL;
host->dma_params.data = pdata->dma_params;
host->dma_params.addr = res_fifo->start;
host->dma_params.max_burst = 16;
host->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
host->dma_params.filter = pdata->filter;
host->reset_perip = pdata->reset_perip;
host->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, host);
ret = devm_request_irq(&pdev->dev, host->irq, spdif_in_irq, 0,
"spdif-in", host);
if (ret) {
clk_put(host->clk);
dev_warn(&pdev->dev, "request_irq failed\n");
return ret;
}
ret = snd_soc_register_dai(&pdev->dev, &spdif_in_dai);
if (ret != 0) {
clk_put(host->clk);
return ret;
}
return 0;
}
static int spdif_in_remove(struct platform_device *pdev)
{
struct spdif_in_dev *host = dev_get_drvdata(&pdev->dev);
snd_soc_unregister_dai(&pdev->dev);
dev_set_drvdata(&pdev->dev, NULL);
clk_put(host->clk);
return 0;
}
static struct platform_driver spdif_in_driver = {
.probe = spdif_in_probe,
.remove = spdif_in_remove,
.driver = {
.name = "spdif-in",
.owner = THIS_MODULE,
},
};
module_platform_driver(spdif_in_driver);
MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>");
MODULE_DESCRIPTION("SPEAr SPDIF IN SoC Interface");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:spdif_in");

Some files were not shown because too many files have changed in this diff Show More