mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-17 01:34:00 +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:
commit
4609ed6b1f
@ -6747,9 +6747,11 @@ F: include/linux/tifm.h
|
||||
|
||||
TI LM49xxx FAMILY ASoC CODEC DRIVERS
|
||||
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)
|
||||
S: Maintained
|
||||
F: sound/soc/codecs/lm49453*
|
||||
F: sound/soc/codecs/isabelle*
|
||||
|
||||
TI TWL4030 SERIES SOC CODEC DRIVER
|
||||
M: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/mfd/tc3589x.h>
|
||||
#include <linux/mfd/tps6105x.h>
|
||||
#include <linux/mfd/abx500/ab8500-gpio.h>
|
||||
#include <linux/mfd/abx500/ab8500-codec.h>
|
||||
#include <linux/leds-lp5521.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/smsc911x.h>
|
||||
@ -97,6 +98,18 @@ static struct ab8500_gpio_platform_data ab8500_gpio_pdata = {
|
||||
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[] = {
|
||||
{
|
||||
.gpio = 32,
|
||||
@ -195,6 +208,7 @@ static struct ab8500_platform_data ab8500_platdata = {
|
||||
.regulator = ab8500_regulators,
|
||||
.num_regulator = ARRAY_SIZE(ab8500_regulators),
|
||||
.gpio = &ab8500_gpio_pdata,
|
||||
.codec = &ab8500_codec_pdata,
|
||||
};
|
||||
|
||||
static struct resource ab8500_resources[] = {
|
||||
|
@ -670,6 +670,12 @@ static inline int dmaengine_resume(struct dma_chan *chan)
|
||||
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)
|
||||
{
|
||||
return desc->tx_submit(desc);
|
||||
|
52
include/linux/mfd/abx500/ab8500-codec.h
Normal file
52
include/linux/mfd/abx500/ab8500-codec.h
Normal 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
|
@ -266,6 +266,7 @@ struct ab8500 {
|
||||
struct regulator_reg_init;
|
||||
struct regulator_init_data;
|
||||
struct ab8500_gpio_platform_data;
|
||||
struct ab8500_codec_platform_data;
|
||||
|
||||
/**
|
||||
* struct ab8500_platform_data - AB8500 platform data
|
||||
@ -284,6 +285,7 @@ struct ab8500_platform_data {
|
||||
int num_regulator;
|
||||
struct regulator_init_data *regulator;
|
||||
struct ab8500_gpio_platform_data *gpio;
|
||||
struct ab8500_codec_platform_data *codec;
|
||||
};
|
||||
|
||||
extern int __devinit ab8500_init(struct ab8500 *ab8500,
|
||||
|
22
include/linux/platform_data/mmp_audio.h
Normal file
22
include/linux/platform_data/mmp_audio.h
Normal 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 */
|
69
include/sound/designware_i2s.h
Normal file
69
include/sound/designware_i2s.h
Normal 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 */
|
@ -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);
|
||||
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_no_residue(struct snd_pcm_substream *substream);
|
||||
|
||||
int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
|
||||
dma_filter_fn filter_fn, void *filter_data);
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
|
@ -229,6 +229,10 @@ struct device;
|
||||
{ .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
|
||||
.shift = wshift, .invert = winvert, \
|
||||
.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 */
|
||||
#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, \
|
||||
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }
|
||||
|
||||
|
||||
/* dapm kcontrol types */
|
||||
#define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \
|
||||
{ .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);
|
||||
int dapm_regulator_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event);
|
||||
int dapm_clock_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event);
|
||||
|
||||
/* dapm controls */
|
||||
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);
|
||||
int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
|
||||
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,
|
||||
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_supply, /* power/clock supply */
|
||||
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_out, /* audio interface output */
|
||||
snd_soc_dapm_siggen, /* signal generator */
|
||||
@ -537,6 +547,8 @@ struct snd_soc_dapm_widget {
|
||||
struct list_head dirty;
|
||||
int inputs;
|
||||
int outputs;
|
||||
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
struct snd_soc_dapm_update {
|
||||
|
@ -42,11 +42,22 @@
|
||||
((unsigned long)&(struct soc_mixer_control) \
|
||||
{.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \
|
||||
.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) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
|
||||
.put = snd_soc_put_volsw, \
|
||||
.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) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
|
||||
@ -67,6 +78,16 @@
|
||||
{.reg = xreg, .rreg = xreg, \
|
||||
.shift = xshift, .rshift = xshift, \
|
||||
.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) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
|
||||
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
|
||||
@ -79,6 +100,13 @@
|
||||
.get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
|
||||
.private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
|
||||
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) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
|
||||
@ -97,6 +125,16 @@
|
||||
.get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
|
||||
.private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
|
||||
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) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
|
||||
.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);
|
||||
int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
|
||||
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,
|
||||
const char *name, int max);
|
||||
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 */
|
||||
const char *name; /* Codec name */
|
||||
const char *stream_name; /* Stream name */
|
||||
const char *codec_name; /* for multi-codec */
|
||||
const struct device_node *codec_of_node;
|
||||
const char *platform_name; /* for multi-platform */
|
||||
const struct device_node *platform_of_node;
|
||||
/*
|
||||
* You MAY specify the link's CPU-side device, either by device name,
|
||||
* or by DT/OF node, but not both. If this information is omitted,
|
||||
* 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 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;
|
||||
/*
|
||||
* 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 */
|
||||
|
||||
const struct snd_soc_pcm_stream *params;
|
||||
|
35
include/sound/spear_dma.h
Normal file
35
include/sound/spear_dma.h
Normal 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 */
|
29
include/sound/spear_spdif.h
Normal file
29
include/sound/spear_spdif.h
Normal 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 */
|
@ -33,6 +33,7 @@ source "sound/soc/atmel/Kconfig"
|
||||
source "sound/soc/au1x/Kconfig"
|
||||
source "sound/soc/blackfin/Kconfig"
|
||||
source "sound/soc/davinci/Kconfig"
|
||||
source "sound/soc/dwc/Kconfig"
|
||||
source "sound/soc/ep93xx/Kconfig"
|
||||
source "sound/soc/fsl/Kconfig"
|
||||
source "sound/soc/jz4740/Kconfig"
|
||||
|
@ -11,6 +11,7 @@ obj-$(CONFIG_SND_SOC) += atmel/
|
||||
obj-$(CONFIG_SND_SOC) += au1x/
|
||||
obj-$(CONFIG_SND_SOC) += blackfin/
|
||||
obj-$(CONFIG_SND_SOC) += davinci/
|
||||
obj-$(CONFIG_SND_SOC) += dwc/
|
||||
obj-$(CONFIG_SND_SOC) += ep93xx/
|
||||
obj-$(CONFIG_SND_SOC) += fsl/
|
||||
obj-$(CONFIG_SND_SOC) += jz4740/
|
||||
|
@ -1,7 +1,8 @@
|
||||
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
|
||||
select SND_BF5XX_SOC_SPORT
|
||||
select SND_BF5XX_SOC_SPORT if !BF60x
|
||||
select SND_BF6XX_SOC_SPORT if BF60x
|
||||
help
|
||||
Say Y or M if you want to add support for codecs attached to
|
||||
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.
|
||||
|
||||
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)
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_BF5XX_SOC_I2S if !BF60x
|
||||
select SND_BF6XX_SOC_I2S if BF60x
|
||||
select SND_SOC_SSM2602
|
||||
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
|
||||
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
|
||||
tristate
|
||||
|
||||
config SND_BF6XX_SOC_SPORT
|
||||
tristate
|
||||
|
||||
config SND_BF5XX_SOC_I2S
|
||||
tristate
|
||||
|
||||
config SND_BF6XX_SOC_I2S
|
||||
tristate
|
||||
|
||||
config SND_BF5XX_SOC_TDM
|
||||
tristate
|
||||
|
||||
@ -173,7 +182,7 @@ config SND_BF5XX_SOC_AC97
|
||||
|
||||
config SND_BF5XX_SPORT_NUM
|
||||
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 1 if !BF54x
|
||||
default 0
|
||||
|
@ -3,16 +3,20 @@ snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o
|
||||
snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o
|
||||
snd-bf5xx-tdm-objs := bf5xx-tdm-pcm.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-i2s-objs := bf5xx-i2s.o
|
||||
snd-soc-bf6xx-i2s-objs := bf6xx-i2s.o
|
||||
snd-soc-bf5xx-tdm-objs := bf5xx-tdm.o
|
||||
|
||||
obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o
|
||||
obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o
|
||||
obj-$(CONFIG_SND_BF5XX_TDM) += snd-bf5xx-tdm.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_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
|
||||
|
||||
# Blackfin Machine Support
|
||||
|
234
sound/soc/blackfin/bf6xx-i2s.c
Normal file
234
sound/soc/blackfin/bf6xx-i2s.c
Normal 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, ¶m);
|
||||
if (ret) {
|
||||
dev_err(dev, "SPORT tx is busy!\n");
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
ret = sport_set_rx_params(sport, ¶m);
|
||||
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, ¶m);
|
||||
if (ret) {
|
||||
dev_err(dev, "SPORT tx is busy!\n");
|
||||
return ret;
|
||||
}
|
||||
ret = sport_set_rx_params(sport, ¶m);
|
||||
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");
|
422
sound/soc/blackfin/bf6xx-sport.c
Normal file
422
sound/soc/blackfin/bf6xx-sport.c
Normal 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");
|
82
sound/soc/blackfin/bf6xx-sport.h
Normal file
82
sound/soc/blackfin/bf6xx-sport.h
Normal 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
|
@ -12,6 +12,7 @@ config SND_SOC_ALL_CODECS
|
||||
tristate "Build all ASoC CODEC drivers"
|
||||
select SND_SOC_88PM860X if MFD_88PM860X
|
||||
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_AD1836 if SPI_MASTER
|
||||
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_CX20442
|
||||
select SND_SOC_DA7210 if I2C
|
||||
select SND_SOC_DA732X if I2C
|
||||
select SND_SOC_DFBMCS320
|
||||
select SND_SOC_ISABELLE if I2C
|
||||
select SND_SOC_JZ4740_CODEC
|
||||
select SND_SOC_LM4857 if I2C
|
||||
select SND_SOC_LM49453 if I2C
|
||||
@ -54,6 +57,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_SPDIF
|
||||
select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_STA32X if I2C
|
||||
select SND_SOC_STA529 if I2C
|
||||
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
|
||||
select SND_SOC_TLV320AIC23 if I2C
|
||||
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_WM2200 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_WM8400 if MFD_WM8400
|
||||
select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI
|
||||
@ -126,11 +132,21 @@ config SND_SOC_ALL_CODECS
|
||||
config SND_SOC_88PM860X
|
||||
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
|
||||
tristate
|
||||
default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y
|
||||
default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m
|
||||
|
||||
config SND_SOC_AB8500_CODEC
|
||||
tristate
|
||||
|
||||
config SND_SOC_AC97_CODEC
|
||||
tristate
|
||||
select SND_AC97_CODEC
|
||||
@ -219,12 +235,18 @@ config SND_SOC_L3
|
||||
config SND_SOC_DA7210
|
||||
tristate
|
||||
|
||||
config SND_SOC_DA732X
|
||||
tristate
|
||||
|
||||
config SND_SOC_DFBMCS320
|
||||
tristate
|
||||
|
||||
config SND_SOC_DMIC
|
||||
tristate
|
||||
|
||||
config SND_SOC_ISABELLE
|
||||
tristate
|
||||
|
||||
config SND_SOC_LM49453
|
||||
tristate
|
||||
|
||||
@ -266,6 +288,9 @@ config SND_SOC_SSM2602
|
||||
config SND_SOC_STA32X
|
||||
tristate
|
||||
|
||||
config SND_SOC_STA529
|
||||
tristate
|
||||
|
||||
config SND_SOC_STAC9766
|
||||
tristate
|
||||
|
||||
@ -313,6 +338,12 @@ config SND_SOC_WM2200
|
||||
config SND_SOC_WM5100
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM5102
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM5110
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8350
|
||||
tristate
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
snd-soc-88pm860x-objs := 88pm860x-codec.o
|
||||
snd-soc-ab8500-codec-objs := ab8500-codec.o
|
||||
snd-soc-ac97-objs := ac97.o
|
||||
snd-soc-ad1836-objs := ad1836.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-ak4642-objs := ak4642.o
|
||||
snd-soc-ak4671-objs := ak4671.o
|
||||
snd-soc-arizona-objs := arizona.o
|
||||
snd-soc-cq93vc-objs := cq93vc.o
|
||||
snd-soc-cs42l51-objs := cs42l51.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-cx20442-objs := cx20442.o
|
||||
snd-soc-da7210-objs := da7210.o
|
||||
snd-soc-da732x-objs := da732x.o
|
||||
snd-soc-dfbmcs320-objs := dfbmcs320.o
|
||||
snd-soc-dmic-objs := dmic.o
|
||||
snd-soc-isabelle-objs := isabelle.o
|
||||
snd-soc-jz4740-codec-objs := jz4740.o
|
||||
snd-soc-l3-objs := l3.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-sigmadsp-objs := sigmadsp.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-sta32x-objs := sta32x.o
|
||||
snd-soc-sta529-objs := sta529.o
|
||||
snd-soc-stac9766-objs := stac9766.o
|
||||
snd-soc-tlv320aic23-objs := tlv320aic23.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-wm2200-objs := wm2200.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-wm8400-objs := wm8400.o
|
||||
snd-soc-wm8510-objs := wm8510.o
|
||||
@ -108,6 +116,7 @@ snd-soc-max9877-objs := max9877.o
|
||||
snd-soc-tpa6130a2-objs := tpa6130a2.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_AD1836) += snd-soc-ad1836.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_ALC5623) += snd-soc-alc5623.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_CS42L51) += snd-soc-cs42l51.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_CX20442) += snd-soc-cx20442.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_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_L3) += snd-soc-l3.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_SIGMADSP) += snd-soc-sigmadsp.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_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_TLV320AIC23) += snd-soc-tlv320aic23.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_WM2200) += snd-soc-wm2200.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_WM8400) += snd-soc-wm8400.o
|
||||
obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o
|
||||
|
2522
sound/soc/codecs/ab8500-codec.c
Normal file
2522
sound/soc/codecs/ab8500-codec.c
Normal file
File diff suppressed because it is too large
Load Diff
590
sound/soc/codecs/ab8500-codec.h
Normal file
590
sound/soc/codecs/ab8500-codec.h
Normal 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
|
@ -91,11 +91,6 @@ static int ac97_soc_probe(struct snd_soc_codec *codec)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ac97_soc_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
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,
|
||||
.read = ac97_read,
|
||||
.probe = ac97_soc_probe,
|
||||
.remove = ac97_soc_remove,
|
||||
.suspend = ac97_soc_suspend,
|
||||
.resume = ac97_soc_resume,
|
||||
};
|
||||
|
937
sound/soc/codecs/arizona.c
Normal file
937
sound/soc/codecs/arizona.c
Normal 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, ®);
|
||||
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
159
sound/soc/codecs/arizona.h
Normal 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
|
@ -14,7 +14,6 @@
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
@ -1217,11 +1216,11 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
|
||||
return -ENOMEM;
|
||||
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)) {
|
||||
ret = PTR_ERR(cs42l52->regmap);
|
||||
dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
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,
|
||||
"CS42L52 Device ID (%X). Expected %X\n",
|
||||
devid, CS42L52_CHIP_ID);
|
||||
goto err_regmap;
|
||||
return ret;
|
||||
}
|
||||
|
||||
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,
|
||||
&soc_codec_dev_cs42l52, &cs42l52_dai, 1);
|
||||
if (ret < 0)
|
||||
goto err_regmap;
|
||||
return ret;
|
||||
return 0;
|
||||
|
||||
err_regmap:
|
||||
regmap_exit(cs42l52->regmap);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cs42l52_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct cs42l52_private *cs42l52 = i2c_get_clientdata(client);
|
||||
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
regmap_exit(cs42l52->regmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1362,11 +1362,11 @@ static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client,
|
||||
|
||||
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)) {
|
||||
ret = PTR_ERR(cs42l73->regmap);
|
||||
dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
/* initialize codec */
|
||||
ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, ®);
|
||||
@ -1384,13 +1384,13 @@ static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client,
|
||||
dev_err(&i2c_client->dev,
|
||||
"CS42L73 Device ID (%X). Expected %X\n",
|
||||
devid, CS42L73_DEVID);
|
||||
goto err_regmap;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_read(cs42l73->regmap, CS42L73_REVID, ®);
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c_client->dev, "Get Revision ID failed\n");
|
||||
goto err_regmap;
|
||||
return ret;;
|
||||
}
|
||||
|
||||
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,
|
||||
ARRAY_SIZE(cs42l73_dai));
|
||||
if (ret < 0)
|
||||
goto err_regmap;
|
||||
return ret;
|
||||
return 0;
|
||||
|
||||
err_regmap:
|
||||
regmap_exit(cs42l73->regmap);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __devexit int cs42l73_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct cs42l73_private *cs42l73 = i2c_get_clientdata(client);
|
||||
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
regmap_exit(cs42l73->regmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
1627
sound/soc/codecs/da732x.c
Normal file
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
133
sound/soc/codecs/da732x.h
Normal 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_ */
|
654
sound/soc/codecs/da732x_reg.h
Normal file
654
sound/soc/codecs/da732x_reg.h
Normal 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
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
143
sound/soc/codecs/isabelle.h
Normal 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
|
@ -12,7 +12,6 @@
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
@ -1358,7 +1357,7 @@ static struct snd_soc_dai_ops lm49453_lineout_dai_ops = {
|
||||
};
|
||||
|
||||
/* LM49453 dai structure. */
|
||||
static const struct snd_soc_dai_driver lm49453_dai[] = {
|
||||
static struct snd_soc_dai_driver lm49453_dai[] = {
|
||||
{
|
||||
.name = "LM49453 Headset",
|
||||
.playback = {
|
||||
|
@ -2216,7 +2216,7 @@ static irqreturn_t max98095_report_jack(int irq, void *data)
|
||||
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);
|
||||
int ret = 0;
|
||||
@ -2245,7 +2245,7 @@ int max98095_jack_detect_enable(struct snd_soc_codec *codec)
|
||||
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;
|
||||
|
||||
@ -2286,6 +2286,7 @@ int max98095_jack_detect(struct snd_soc_codec *codec,
|
||||
max98095_report_jack(client->irq, codec);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(max98095_jack_detect);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int max98095_suspend(struct snd_soc_codec *codec)
|
||||
|
@ -638,7 +638,7 @@ static __devinit int ml26124_i2c_probe(struct i2c_client *i2c,
|
||||
|
||||
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)) {
|
||||
ret = PTR_ERR(priv->regmap);
|
||||
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)
|
||||
{
|
||||
struct ml26124_priv *priv = i2c_get_clientdata(client);
|
||||
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
regmap_exit(priv->regmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
67
sound/soc/codecs/spdif_receiver.c
Normal file
67
sound/soc/codecs/spdif_receiver.c
Normal 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
442
sound/soc/codecs/sta529.c
Normal 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");
|
@ -118,7 +118,9 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = {
|
||||
0x00, 0x00, 0x00, 0x00, /* 88 */
|
||||
0x00, 0x00, 0x00, 0x00, /* 92 */
|
||||
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) \
|
||||
@ -229,6 +231,25 @@ static const struct soc_enum aic3x_enum[] = {
|
||||
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
|
||||
*/
|
||||
@ -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.
|
||||
*/
|
||||
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 */
|
||||
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 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 */
|
||||
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 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;
|
||||
return 0;
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
#define _AIC3X_H
|
||||
|
||||
/* AIC3X register space */
|
||||
#define AIC3X_CACHEREGNUM 103
|
||||
#define AIC3X_CACHEREGNUM 110
|
||||
|
||||
/* Page select register */
|
||||
#define AIC3X_PAGE_SELECT 0
|
||||
@ -74,6 +74,8 @@
|
||||
#define HPLCOM_CFG 37
|
||||
/* Right High Power Output control registers */
|
||||
#define HPRCOM_CFG 38
|
||||
/* High Power Output Stage Control Register */
|
||||
#define HPOUT_SC 40
|
||||
/* DAC Output Switching control registers */
|
||||
#define DAC_LINE_MUX 41
|
||||
/* High Power Output Driver Pop Reduction registers */
|
||||
@ -148,6 +150,17 @@
|
||||
#define AIC3X_GPIOB_REG 101
|
||||
/* Clock generation control register */
|
||||
#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 */
|
||||
#define PAGE0_SELECT 0
|
||||
@ -163,6 +176,10 @@
|
||||
#define DUAL_RATE_MODE ((1 << 5) | (1 << 6))
|
||||
#define LDAC2LCH (0x1 << 3)
|
||||
#define RDAC2RCH (0x1 << 1)
|
||||
#define LDAC2RCH (0x2 << 3)
|
||||
#define RDAC2LCH (0x2 << 1)
|
||||
#define LDAC2MONOMIX (0x3 << 3)
|
||||
#define RDAC2MONOMIX (0x3 << 1)
|
||||
|
||||
/* PLL registers bitfields */
|
||||
#define PLLP_SHIFT 0
|
||||
@ -179,6 +196,14 @@
|
||||
#define PLL_CLKIN_SHIFT 4
|
||||
#define MCLK_SOURCE 0x0
|
||||
#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 */
|
||||
#define SOFT_RESET 0x80
|
||||
|
@ -553,7 +553,7 @@ static const struct snd_kcontrol_new vibrar_mux_controls =
|
||||
|
||||
/* Headset power mode */
|
||||
static const char *twl6040_power_mode_texts[] = {
|
||||
"Low-Power", "High-Perfomance",
|
||||
"Low-Power", "High-Performance",
|
||||
};
|
||||
|
||||
static const struct soc_enum twl6040_power_mode_enum =
|
||||
|
@ -121,20 +121,23 @@ static const struct snd_soc_dai_ops wm1250_ev1_ops = {
|
||||
.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 = {
|
||||
.name = "wm1250-ev1",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000,
|
||||
.rates = WM1250_EV1_RATES,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000,
|
||||
.rates = WM1250_EV1_RATES,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.ops = &wm1250_ev1_ops,
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
@ -674,9 +674,39 @@ static int wm2000_resume(struct snd_soc_codec *codec)
|
||||
#define wm2000_resume NULL
|
||||
#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 = {
|
||||
.reg_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)
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
@ -2378,13 +2378,6 @@ static int wm5100_remove(struct snd_soc_codec *codec)
|
||||
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 = {
|
||||
.probe = wm5100_probe,
|
||||
.remove = wm5100_remove,
|
||||
@ -2392,8 +2385,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5100 = {
|
||||
.set_sysclk = wm5100_set_sysclk,
|
||||
.set_pll = wm5100_set_fll,
|
||||
.idle_bias_off = 1,
|
||||
.reg_cache_size = WM5100_MAX_REGISTER,
|
||||
.volatile_register = wm5100_soc_volatile,
|
||||
|
||||
.seq_notifier = wm5100_seq_notifier,
|
||||
.controls = wm5100_snd_controls,
|
||||
|
903
sound/soc/codecs/wm5102.c
Normal file
903
sound/soc/codecs/wm5102.c
Normal 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
21
sound/soc/codecs/wm5102.h
Normal 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
950
sound/soc/codecs/wm5110.c
Normal 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
21
sound/soc/codecs/wm5110.h
Normal 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
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
@ -71,20 +71,6 @@ struct wm8350_data {
|
||||
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.
|
||||
*/
|
||||
@ -1519,7 +1505,9 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec)
|
||||
if (ret != 0)
|
||||
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 */
|
||||
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,
|
||||
.suspend = wm8350_suspend,
|
||||
.resume = wm8350_resume,
|
||||
.read = wm8350_codec_read,
|
||||
.write = wm8350_codec_write,
|
||||
.set_bias_level = wm8350_set_bias_level,
|
||||
|
||||
.controls = wm8350_snd_controls,
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
|
@ -2,6 +2,7 @@
|
||||
* wm8731.c -- WM8731 ALSA SoC Audio driver
|
||||
*
|
||||
* Copyright 2005 Openedhand Ltd.
|
||||
* Copyright 2006-12 Wolfson Microelectronics, plc
|
||||
*
|
||||
* Author: Richard Purdie <richard@openedhand.com>
|
||||
*
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
|
@ -1,8 +1,8 @@
|
||||
/*
|
||||
* wm8903.c -- WM8903 ALSA SoC Audio driver
|
||||
*
|
||||
* Copyright 2008 Wolfson Microelectronics
|
||||
* Copyright 2011 NVIDIA, Inc.
|
||||
* Copyright 2008-12 Wolfson Microelectronics
|
||||
* Copyright 2011-2012 NVIDIA, Inc.
|
||||
*
|
||||
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
|
||||
*
|
||||
@ -116,6 +116,7 @@ static const struct reg_default wm8903_reg_defaults[] = {
|
||||
|
||||
struct wm8903_priv {
|
||||
struct wm8903_platform_data *pdata;
|
||||
struct device *dev;
|
||||
struct snd_soc_codec *codec;
|
||||
struct regmap *regmap;
|
||||
|
||||
@ -1635,17 +1636,27 @@ EXPORT_SYMBOL_GPL(wm8903_mic_detect);
|
||||
|
||||
static irqreturn_t wm8903_irq(int irq, void *data)
|
||||
{
|
||||
struct snd_soc_codec *codec = data;
|
||||
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
|
||||
int mic_report;
|
||||
int int_pol;
|
||||
int int_val = 0;
|
||||
int mask = ~snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1_MASK);
|
||||
struct wm8903_priv *wm8903 = data;
|
||||
int mic_report, ret;
|
||||
unsigned int int_val, mask, int_pol;
|
||||
|
||||
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) {
|
||||
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.
|
||||
*/
|
||||
mic_report = wm8903->mic_last_report;
|
||||
int_pol = snd_soc_read(codec, WM8903_INTERRUPT_POLARITY_1);
|
||||
ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_POLARITY_1,
|
||||
&int_pol);
|
||||
if (ret != 0) {
|
||||
dev_err(wm8903->dev, "Failed to read interrupt polarity: %d\n",
|
||||
ret);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SND_SOC_WM8903_MODULE
|
||||
if (int_val & (WM8903_MICSHRT_EINT | WM8903_MICDET_EINT))
|
||||
trace_snd_soc_jack_irq(dev_name(codec->dev));
|
||||
trace_snd_soc_jack_irq(dev_name(wm8903->dev));
|
||||
#endif
|
||||
|
||||
if (int_val & WM8903_MICSHRT_EINT) {
|
||||
dev_dbg(codec->dev, "Microphone short (pol=%x)\n", int_pol);
|
||||
dev_dbg(wm8903->dev, "Microphone short (pol=%x)\n", int_pol);
|
||||
|
||||
mic_report ^= wm8903->mic_short;
|
||||
int_pol ^= WM8903_MICSHRT_INV;
|
||||
}
|
||||
|
||||
if (int_val & WM8903_MICDET_EINT) {
|
||||
dev_dbg(codec->dev, "Microphone detect (pol=%x)\n", int_pol);
|
||||
dev_dbg(wm8903->dev, "Microphone detect (pol=%x)\n", int_pol);
|
||||
|
||||
mic_report ^= wm8903->mic_det;
|
||||
int_pol ^= WM8903_MICDET_INV;
|
||||
@ -1679,8 +1696,8 @@ static irqreturn_t wm8903_irq(int irq, void *data)
|
||||
msleep(wm8903->mic_delay);
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, WM8903_INTERRUPT_POLARITY_1,
|
||||
WM8903_MICSHRT_INV | WM8903_MICDET_INV, int_pol);
|
||||
regmap_update_bits(wm8903->regmap, WM8903_INTERRUPT_POLARITY_1,
|
||||
WM8903_MICSHRT_INV | WM8903_MICDET_INV, int_pol);
|
||||
|
||||
snd_soc_jack_report(wm8903->mic_jack, mic_report,
|
||||
wm8903->mic_short | wm8903->mic_det);
|
||||
@ -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)
|
||||
{
|
||||
struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
|
||||
struct snd_soc_codec *codec = wm8903->codec;
|
||||
unsigned int mask, val;
|
||||
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) |
|
||||
WM8903_GP1_DIR;
|
||||
|
||||
ret = snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset,
|
||||
mask, val);
|
||||
ret = regmap_update_bits(wm8903->regmap,
|
||||
WM8903_GPIO_CONTROL_1 + offset, mask, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -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)
|
||||
{
|
||||
struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
|
||||
struct snd_soc_codec *codec = wm8903->codec;
|
||||
int reg;
|
||||
unsigned int reg;
|
||||
|
||||
reg = snd_soc_read(codec, WM8903_GPIO_CONTROL_1 + offset);
|
||||
regmap_read(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset, ®);
|
||||
|
||||
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)
|
||||
{
|
||||
struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
|
||||
struct snd_soc_codec *codec = wm8903->codec;
|
||||
unsigned int mask, val;
|
||||
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) |
|
||||
(value << WM8903_GP2_LVL_SHIFT);
|
||||
|
||||
ret = snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset,
|
||||
mask, val);
|
||||
ret = regmap_update_bits(wm8903->regmap,
|
||||
WM8903_GPIO_CONTROL_1 + offset, mask, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -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)
|
||||
{
|
||||
struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
|
||||
struct snd_soc_codec *codec = wm8903->codec;
|
||||
|
||||
snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset,
|
||||
WM8903_GP1_LVL_MASK,
|
||||
!!value << WM8903_GP1_LVL_SHIFT);
|
||||
regmap_update_bits(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset,
|
||||
WM8903_GP1_LVL_MASK,
|
||||
!!value << WM8903_GP1_LVL_SHIFT);
|
||||
}
|
||||
|
||||
static struct gpio_chip wm8903_template_chip = {
|
||||
@ -1842,15 +1855,14 @@ static struct gpio_chip wm8903_template_chip = {
|
||||
.can_sleep = 1,
|
||||
};
|
||||
|
||||
static void wm8903_init_gpio(struct snd_soc_codec *codec)
|
||||
static void wm8903_init_gpio(struct wm8903_priv *wm8903)
|
||||
{
|
||||
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8903_platform_data *pdata = wm8903->pdata;
|
||||
int ret;
|
||||
|
||||
wm8903->gpio_chip = wm8903_template_chip;
|
||||
wm8903->gpio_chip.ngpio = WM8903_NUM_GPIO;
|
||||
wm8903->gpio_chip.dev = codec->dev;
|
||||
wm8903->gpio_chip.dev = wm8903->dev;
|
||||
|
||||
if (pdata->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);
|
||||
if (ret != 0)
|
||||
dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
|
||||
dev_err(wm8903->dev, "Failed to add GPIOs: %d\n", ret);
|
||||
}
|
||||
|
||||
static void wm8903_free_gpio(struct snd_soc_codec *codec)
|
||||
static void wm8903_free_gpio(struct wm8903_priv *wm8903)
|
||||
{
|
||||
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
ret = gpiochip_remove(&wm8903->gpio_chip);
|
||||
if (ret != 0)
|
||||
dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
|
||||
dev_err(wm8903->dev, "Failed to remove GPIOs: %d\n", ret);
|
||||
}
|
||||
#else
|
||||
static void wm8903_init_gpio(struct snd_soc_codec *codec)
|
||||
static void wm8903_init_gpio(struct wm8903_priv *wm8903)
|
||||
{
|
||||
}
|
||||
|
||||
static void wm8903_free_gpio(struct snd_soc_codec *codec)
|
||||
static void wm8903_free_gpio(struct wm8903_priv *wm8903)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
@ -1884,11 +1895,7 @@ static void wm8903_free_gpio(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_platform_data *pdata = wm8903->pdata;
|
||||
int ret, i;
|
||||
int trigger, irq_pol;
|
||||
u16 val;
|
||||
bool mic_gpio = false;
|
||||
int ret;
|
||||
|
||||
wm8903->codec = codec;
|
||||
codec->control_data = wm8903->regmap;
|
||||
@ -1899,121 +1906,16 @@ static int wm8903_probe(struct snd_soc_codec *codec)
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
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);
|
||||
if (wm8903->irq)
|
||||
free_irq(wm8903->irq, codec);
|
||||
|
||||
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_priv *wm8903;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
int trigger;
|
||||
bool mic_gpio = false;
|
||||
unsigned int val, irq_pol;
|
||||
int ret, i;
|
||||
|
||||
wm8903 = devm_kzalloc(&i2c->dev, sizeof(struct wm8903_priv),
|
||||
GFP_KERNEL);
|
||||
if (wm8903 == NULL)
|
||||
return -ENOMEM;
|
||||
wm8903->dev = &i2c->dev;
|
||||
|
||||
wm8903->regmap = regmap_init_i2c(i2c, &wm8903_regmap);
|
||||
wm8903->regmap = devm_regmap_init_i2c(i2c, &wm8903_regmap);
|
||||
if (IS_ERR(wm8903->regmap)) {
|
||||
ret = PTR_ERR(wm8903->regmap);
|
||||
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
|
||||
@ -2140,7 +2045,6 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
|
||||
}
|
||||
|
||||
i2c_set_clientdata(i2c, wm8903);
|
||||
wm8903->irq = i2c->irq;
|
||||
|
||||
/* If no platform data was supplied, create storage for defaults */
|
||||
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);
|
||||
if (ret != 0) {
|
||||
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 */
|
||||
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,
|
||||
&soc_codec_dev_wm8903, &wm8903_dai, 1);
|
||||
if (ret != 0)
|
||||
@ -2196,7 +2203,6 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
|
||||
|
||||
return 0;
|
||||
err:
|
||||
regmap_exit(wm8903->regmap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2204,7 +2210,9 @@ static __devexit int wm8903_i2c_remove(struct i2c_client *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);
|
||||
|
||||
return 0;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
@ -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)
|
||||
{
|
||||
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,
|
||||
};
|
||||
|
||||
#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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8904_pdata *pdata = wm8904->pdata;
|
||||
int ret, i;
|
||||
int ret;
|
||||
|
||||
codec->control_data = wm8904->regmap;
|
||||
|
||||
@ -2101,127 +2076,17 @@ static int wm8904_probe(struct snd_soc_codec *codec)
|
||||
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_add_widgets(codec);
|
||||
|
||||
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)
|
||||
{
|
||||
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->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 = {
|
||||
.probe = wm8904_probe,
|
||||
.remove = wm8904_remove,
|
||||
.suspend = wm8904_suspend,
|
||||
.resume = wm8904_resume,
|
||||
.set_bias_level = wm8904_set_bias_level,
|
||||
.idle_bias_off = true,
|
||||
};
|
||||
@ -2254,14 +2117,15 @@ static __devinit int wm8904_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct wm8904_priv *wm8904;
|
||||
int ret;
|
||||
unsigned int val;
|
||||
int ret, i;
|
||||
|
||||
wm8904 = devm_kzalloc(&i2c->dev, sizeof(struct wm8904_priv),
|
||||
GFP_KERNEL);
|
||||
if (wm8904 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
wm8904->regmap = regmap_init_i2c(i2c, &wm8904_regmap);
|
||||
wm8904->regmap = devm_regmap_init_i2c(i2c, &wm8904_regmap);
|
||||
if (IS_ERR(wm8904->regmap)) {
|
||||
ret = PTR_ERR(wm8904->regmap);
|
||||
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);
|
||||
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,
|
||||
&soc_codec_dev_wm8904, &wm8904_dai, 1);
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
regmap_exit(wm8904->regmap);
|
||||
err_enable:
|
||||
regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __devexit int wm8904_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct wm8904_priv *wm8904 = i2c_get_clientdata(client);
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
regmap_exit(wm8904->regmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2311,23 +2273,7 @@ static struct i2c_driver wm8904_i2c_driver = {
|
||||
.id_table = wm8904_i2c_id,
|
||||
};
|
||||
|
||||
static int __init wm8904_modinit(void)
|
||||
{
|
||||
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_i2c_driver(wm8904_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC WM8904 driver");
|
||||
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
|
||||
|
@ -1,6 +1,8 @@
|
||||
/*
|
||||
* wm8960.c -- WM8960 ALSA SoC Audio driver
|
||||
*
|
||||
* Copyright 2007-11 Wolfson Microelectronics, plc
|
||||
*
|
||||
* Author: Liam Girdwood
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -1,6 +1,8 @@
|
||||
/*
|
||||
* wm8961.c -- WM8961 ALSA SoC Audio driver
|
||||
*
|
||||
* Copyright 2009-10 Wolfson Microelectronics, plc
|
||||
*
|
||||
* Author: Mark Brown
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
@ -2580,6 +2580,9 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
|
||||
WM8962_SAMPLE_RATE_INT_MODE |
|
||||
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)
|
||||
wm8962_configure_bclk(codec);
|
||||
|
||||
@ -3722,6 +3725,9 @@ static int wm8962_runtime_resume(struct device *dev)
|
||||
}
|
||||
|
||||
regcache_cache_only(wm8962->regmap, false);
|
||||
|
||||
wm8962_reset(wm8962);
|
||||
|
||||
regcache_sync(wm8962->regmap);
|
||||
|
||||
regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP,
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
@ -2967,23 +2967,8 @@ static struct snd_soc_dai_driver wm8994_dai[] = {
|
||||
static int wm8994_codec_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8994 *control = wm8994->wm8994;
|
||||
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++) {
|
||||
memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i],
|
||||
sizeof(struct wm8994_fll_config));
|
||||
@ -3033,28 +3018,6 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec)
|
||||
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;
|
||||
}
|
||||
#else
|
||||
@ -3729,9 +3692,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
|
||||
|
||||
if (wm8994->pdata && 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_idle(codec->dev);
|
||||
@ -3870,6 +3830,10 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
|
||||
dev_warn(codec->dev,
|
||||
"Failed to request Mic detect IRQ: %d\n",
|
||||
ret);
|
||||
} else {
|
||||
wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_MIC1_DET,
|
||||
wm8958_mic_irq, "Mic detect",
|
||||
wm8994);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* wm8996.c - WM8996 audio codec interface
|
||||
*
|
||||
* Copyright 2011 Wolfson Microelectronics PLC.
|
||||
* Copyright 2011-2 Wolfson Microelectronics PLC.
|
||||
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
|
||||
*
|
||||
* 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_PDM_SPEAKER_MUTE_SEQUENCE, 0x69 },
|
||||
{ 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);
|
||||
@ -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[] = {
|
||||
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:
|
||||
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);
|
||||
regcache_cache_only(codec->control_data, true);
|
||||
}
|
||||
regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies),
|
||||
wm8996->supplies);
|
||||
break;
|
||||
@ -2807,7 +2619,7 @@ static int wm8996_probe(struct snd_soc_codec *codec)
|
||||
int ret;
|
||||
struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
|
||||
struct i2c_client *i2c = to_i2c_client(codec->dev);
|
||||
int i, irq_flags;
|
||||
int irq_flags;
|
||||
|
||||
wm8996->codec = codec;
|
||||
|
||||
@ -2822,177 +2634,12 @@ static int wm8996_probe(struct snd_soc_codec *codec)
|
||||
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)
|
||||
wm8996_retune_mobile_pdata(codec);
|
||||
else
|
||||
snd_soc_add_codec_controls(codec, 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 (wm8996->pdata.irq_flags)
|
||||
irq_flags = wm8996->pdata.irq_flags;
|
||||
@ -3036,9 +2683,7 @@ err:
|
||||
|
||||
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);
|
||||
int i;
|
||||
|
||||
snd_soc_update_bits(codec, WM8996_INTERRUPT_CONTROL,
|
||||
WM8996_IM_IRQ, WM8996_IM_IRQ);
|
||||
@ -3046,10 +2691,6 @@ static int wm8996_remove(struct snd_soc_codec *codec)
|
||||
if (i2c->irq)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -3163,6 +2804,21 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c,
|
||||
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),
|
||||
wm8996->supplies);
|
||||
if (ret != 0) {
|
||||
@ -3175,7 +2831,7 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c,
|
||||
msleep(5);
|
||||
}
|
||||
|
||||
wm8996->regmap = regmap_init_i2c(i2c, &wm8996_regmap);
|
||||
wm8996->regmap = devm_regmap_init_i2c(i2c, &wm8996_regmap);
|
||||
if (IS_ERR(wm8996->regmap)) {
|
||||
ret = PTR_ERR(wm8996->regmap);
|
||||
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",
|
||||
(reg & WM8996_CHIP_REV_MASK) + 'A');
|
||||
|
||||
ret = wm8996_reset(wm8996);
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c->dev, "Failed to issue reset\n");
|
||||
if (wm8996->pdata.ldo_ena > 0) {
|
||||
gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
|
||||
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, ®);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c->dev, "Failed to read GPIO1: %d\n", ret);
|
||||
goto err_regmap;
|
||||
}
|
||||
|
||||
regcache_cache_only(wm8996->regmap, true);
|
||||
regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
|
||||
if (reg & WM8996_GP1_FN_MASK)
|
||||
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, ®);
|
||||
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);
|
||||
|
||||
@ -3225,7 +3065,6 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c,
|
||||
err_gpiolib:
|
||||
wm8996_free_gpio(wm8996);
|
||||
err_regmap:
|
||||
regmap_exit(wm8996->regmap);
|
||||
err_enable:
|
||||
if (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)
|
||||
{
|
||||
struct wm8996_priv *wm8996 = i2c_get_clientdata(client);
|
||||
int i;
|
||||
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
wm8996_free_gpio(wm8996);
|
||||
regmap_exit(wm8996->regmap);
|
||||
if (wm8996->pdata.ldo_ena > 0) {
|
||||
gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ALSA SoC WM9090 driver
|
||||
*
|
||||
* Copyright 2009, 2010 Wolfson Microelectronics
|
||||
* Copyright 2009-12 Wolfson Microelectronics
|
||||
*
|
||||
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
|
||||
*
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
|
9
sound/soc/dwc/Kconfig
Normal file
9
sound/soc/dwc/Kconfig
Normal 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
3
sound/soc/dwc/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
# SYNOPSYS Platform Support
|
||||
obj-$(CONFIG_SND_DESIGNWARE_I2S) += designware_i2s.o
|
||||
|
455
sound/soc/dwc/designware_i2s.c
Normal file
455
sound/soc/dwc/designware_i2s.c
Normal 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");
|
@ -136,7 +136,7 @@ static struct snd_pcm_ops ep93xx_pcm_ops = {
|
||||
.hw_params = ep93xx_pcm_hw_params,
|
||||
.hw_free = ep93xx_pcm_hw_free,
|
||||
.trigger = snd_dmaengine_pcm_trigger,
|
||||
.pointer = snd_dmaengine_pcm_pointer,
|
||||
.pointer = snd_dmaengine_pcm_pointer_no_residue,
|
||||
.mmap = ep93xx_pcm_mmap,
|
||||
};
|
||||
|
||||
|
@ -156,7 +156,7 @@ static void __init audmux_debugfs_init(void)
|
||||
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);
|
||||
if (!debugfs_create_file(buf, 0444, audmux_debugfs_root,
|
||||
(void *)i, &audmux_debugfs_fops))
|
||||
|
@ -14,6 +14,7 @@
|
||||
#define MX31_AUDMUX_PORT4_SSI_PINS_4 3
|
||||
#define MX31_AUDMUX_PORT5_SSI_PINS_5 4
|
||||
#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_PORT2_SSI1 1
|
||||
|
@ -111,22 +111,39 @@ static int __devinit imx_mc13783_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
imx_audmux_v2_configure_port(MX31_AUDMUX_PORT4_SSI_PINS_4,
|
||||
IMX_AUDMUX_V2_PTCR_SYN,
|
||||
IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0) |
|
||||
IMX_AUDMUX_V2_PDCR_MODE(1) |
|
||||
IMX_AUDMUX_V2_PDCR_INMMASK(0xfc));
|
||||
imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0,
|
||||
IMX_AUDMUX_V2_PTCR_SYN |
|
||||
IMX_AUDMUX_V2_PTCR_TFSDIR |
|
||||
IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
|
||||
IMX_AUDMUX_V2_PTCR_TCLKDIR |
|
||||
IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
|
||||
IMX_AUDMUX_V2_PTCR_RFSDIR |
|
||||
IMX_AUDMUX_V2_PTCR_RFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
|
||||
IMX_AUDMUX_V2_PTCR_RCLKDIR |
|
||||
IMX_AUDMUX_V2_PTCR_RCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4),
|
||||
IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT4_SSI_PINS_4));
|
||||
if (machine_is_mx31_3ds()) {
|
||||
imx_audmux_v2_configure_port(MX31_AUDMUX_PORT4_SSI_PINS_4,
|
||||
IMX_AUDMUX_V2_PTCR_SYN,
|
||||
IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0) |
|
||||
IMX_AUDMUX_V2_PDCR_MODE(1) |
|
||||
IMX_AUDMUX_V2_PDCR_INMMASK(0xfc));
|
||||
imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0,
|
||||
IMX_AUDMUX_V2_PTCR_SYN |
|
||||
IMX_AUDMUX_V2_PTCR_TFSDIR |
|
||||
IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
|
||||
IMX_AUDMUX_V2_PTCR_TCLKDIR |
|
||||
IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
|
||||
IMX_AUDMUX_V2_PTCR_RFSDIR |
|
||||
IMX_AUDMUX_V2_PTCR_RFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
|
||||
IMX_AUDMUX_V2_PTCR_RCLKDIR |
|
||||
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;
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ static struct snd_pcm_ops imx_pcm_ops = {
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = snd_imx_pcm_hw_params,
|
||||
.trigger = snd_dmaengine_pcm_trigger,
|
||||
.pointer = snd_dmaengine_pcm_pointer,
|
||||
.pointer = snd_dmaengine_pcm_pointer_no_residue,
|
||||
.mmap = snd_imx_pcm_mmap,
|
||||
};
|
||||
|
||||
|
@ -95,8 +95,7 @@ static int __devinit imx_sgtl5000_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
imx_audmux_v2_configure_port(ext_port,
|
||||
IMX_AUDMUX_V2_PTCR_SYN |
|
||||
IMX_AUDMUX_V2_PTCR_TCSEL(int_port),
|
||||
IMX_AUDMUX_V2_PTCR_SYN,
|
||||
IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "audmux external port setup failed\n");
|
||||
|
@ -141,7 +141,7 @@ static struct snd_pcm_ops mxs_pcm_ops = {
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = snd_mxs_pcm_hw_params,
|
||||
.trigger = snd_dmaengine_pcm_trigger,
|
||||
.pointer = snd_dmaengine_pcm_pointer,
|
||||
.pointer = snd_dmaengine_pcm_pointer_no_residue,
|
||||
.mmap = snd_mxs_pcm_mmap,
|
||||
};
|
||||
|
||||
|
@ -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_of_node = codec_np;
|
||||
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_of_node = saif_np[i];
|
||||
}
|
||||
|
@ -8,6 +8,15 @@ config SND_PXA2XX_SOC
|
||||
the PXA2xx AC97, I2S or SSP interface. You will also need
|
||||
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
|
||||
tristate
|
||||
select SND_AC97_CODEC
|
||||
@ -26,6 +35,9 @@ config SND_PXA_SOC_SSP
|
||||
tristate
|
||||
select PXA_SSP
|
||||
|
||||
config SND_MMP_SOC_SSPA
|
||||
tristate
|
||||
|
||||
config SND_PXA2XX_SOC_CORGI
|
||||
tristate "SoC Audio support for Sharp Zaurus SL-C7x0"
|
||||
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
|
||||
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
|
||||
tristate "SoC Audio support for Marvell Zylonite"
|
||||
depends on SND_PXA2XX_SOC && MACH_ZYLONITE
|
||||
@ -194,3 +226,13 @@ config SND_PXA2XX_SOC_IMOTE2
|
||||
help
|
||||
Say Y if you want to add support for SoC audio on the
|
||||
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.
|
||||
|
@ -3,11 +3,15 @@ snd-soc-pxa2xx-objs := pxa2xx-pcm.o
|
||||
snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o
|
||||
snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.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_AC97) += snd-soc-pxa2xx-ac97.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_MMP_SOC) += snd-soc-mmp.o
|
||||
obj-$(CONFIG_SND_MMP_SOC_SSPA) += snd-soc-mmp-sspa.o
|
||||
|
||||
# PXA Machine Support
|
||||
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-imote2-objs := imote2.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_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_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.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
174
sound/soc/pxa/brownstone.c
Normal 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
297
sound/soc/pxa/mmp-pcm.c
Normal 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
480
sound/soc/pxa/mmp-sspa.c
Normal 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
92
sound/soc/pxa/mmp-sspa.h
Normal 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
173
sound/soc/pxa/ttc-dkb.c
Normal 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");
|
@ -211,6 +211,11 @@ static int bbclk_ev(struct snd_soc_dapm_widget *w,
|
||||
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[] = {
|
||||
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_post = littlemill_set_bias_level_post,
|
||||
|
||||
.controls = controls,
|
||||
.num_controls = ARRAY_SIZE(controls),
|
||||
.dapm_widgets = widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(widgets),
|
||||
.dapm_routes = audio_paths,
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include <mach/regs-gpio.h>
|
||||
#include <mach/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;
|
||||
|
||||
/* Configure the I2S pins in correct mode */
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);
|
||||
/* Configure the I2S pins (GPE0...GPE4) in correct mode */
|
||||
s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2),
|
||||
S3C_GPIO_PULL_NONE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include <mach/regs-gpio.h>
|
||||
#include <mach/dma.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);
|
||||
|
||||
/* Configure the I2S pins in correct mode */
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);
|
||||
/* Configure the I2S pins (GPE0...GPE4) in correct mode */
|
||||
s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2),
|
||||
S3C_GPIO_PULL_NONE);
|
||||
|
||||
writel(S3C2410_IISCON_IISEN, s3c24xx_i2s.regs + S3C2410_IISCON);
|
||||
|
||||
|
@ -149,31 +149,41 @@ static struct snd_soc_card smdk = {
|
||||
.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;
|
||||
struct snd_soc_card *card = &smdk;
|
||||
|
||||
smdk_snd_device = platform_device_alloc("soc-audio", -1);
|
||||
if (!smdk_snd_device)
|
||||
return -ENOMEM;
|
||||
card->dev = &pdev->dev;
|
||||
ret = snd_soc_register_card(card);
|
||||
|
||||
platform_set_drvdata(smdk_snd_device, &smdk);
|
||||
|
||||
ret = platform_device_add(smdk_snd_device);
|
||||
if (ret)
|
||||
platform_device_put(smdk_snd_device);
|
||||
dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", 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_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:smdk-audio");
|
||||
|
@ -247,7 +247,7 @@ struct fsi_priv {
|
||||
struct fsi_stream_handler {
|
||||
int (*init)(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 (*remove)(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)\
|
||||
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;
|
||||
int ret1, ret2;
|
||||
|
||||
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;
|
||||
ret2 = fsi_stream_handler_call(io, probe, fsi, io);
|
||||
ret2 = fsi_stream_handler_call(io, probe, fsi, io, dev);
|
||||
|
||||
if (ret1 < 0)
|
||||
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_priv *fsi = fsi_stream_to_priv(io);
|
||||
struct dma_chan *chan;
|
||||
struct snd_soc_dai *dai;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
struct scatterlist sg;
|
||||
struct snd_pcm_runtime *runtime;
|
||||
enum dma_data_direction dir;
|
||||
dma_cookie_t cookie;
|
||||
int is_play = fsi_stream_is_play(fsi, io);
|
||||
int len;
|
||||
dma_addr_t buf;
|
||||
@ -1104,7 +1101,6 @@ static void fsi_dma_do_tasklet(unsigned long data)
|
||||
return;
|
||||
|
||||
dai = fsi_get_dai(io->substream);
|
||||
chan = io->chan;
|
||||
runtime = io->substream->runtime;
|
||||
dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
|
||||
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);
|
||||
|
||||
sg_init_table(&sg, 1);
|
||||
sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf)),
|
||||
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);
|
||||
desc = dmaengine_prep_slave_single(io->chan, buf, len, dir,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc) {
|
||||
dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n");
|
||||
return;
|
||||
@ -1128,13 +1118,12 @@ static void fsi_dma_do_tasklet(unsigned long data)
|
||||
desc->callback = fsi_dma_complete;
|
||||
desc->callback_param = io;
|
||||
|
||||
cookie = desc->tx_submit(desc);
|
||||
if (cookie < 0) {
|
||||
if (dmaengine_submit(desc) < 0) {
|
||||
dev_err(dai->dev, "tx_submit() fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dma_async_issue_pending(chan);
|
||||
dma_async_issue_pending(io->chan);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -1192,8 +1181,19 @@ static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io)
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
io->chan = dma_request_channel(mask, fsi_dma_filter, &io->slave);
|
||||
if (!io->chan)
|
||||
return -EIO;
|
||||
if (!io->chan) {
|
||||
|
||||
/* 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);
|
||||
|
||||
@ -1683,7 +1683,7 @@ static int fsi_probe(struct platform_device *pdev)
|
||||
master->fsia.master = master;
|
||||
master->fsia.info = &info->port_a;
|
||||
fsi_handler_init(&master->fsia);
|
||||
ret = fsi_stream_probe(&master->fsia);
|
||||
ret = fsi_stream_probe(&master->fsia, &pdev->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "FSIA stream probe failed\n");
|
||||
goto exit_iounmap;
|
||||
@ -1694,7 +1694,7 @@ static int fsi_probe(struct platform_device *pdev)
|
||||
master->fsib.master = master;
|
||||
master->fsib.info = &info->port_b;
|
||||
fsi_handler_init(&master->fsib);
|
||||
ret = fsi_stream_probe(&master->fsib);
|
||||
ret = fsi_stream_probe(&master->fsib, &pdev->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "FSIB stream probe failed\n");
|
||||
goto exit_fsia;
|
||||
|
@ -812,13 +812,15 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
|
||||
|
||||
/* Find CPU DAI from registered DAIs*/
|
||||
list_for_each_entry(cpu_dai, &dai_list, list) {
|
||||
if (dai_link->cpu_dai_of_node) {
|
||||
if (cpu_dai->dev->of_node != dai_link->cpu_dai_of_node)
|
||||
continue;
|
||||
} else {
|
||||
if (strcmp(cpu_dai->name, dai_link->cpu_dai_name))
|
||||
continue;
|
||||
}
|
||||
if (dai_link->cpu_of_node &&
|
||||
(cpu_dai->dev->of_node != dai_link->cpu_of_node))
|
||||
continue;
|
||||
if (dai_link->cpu_name &&
|
||||
strcmp(dev_name(cpu_dai->dev), dai_link->cpu_name))
|
||||
continue;
|
||||
if (dai_link->cpu_dai_name &&
|
||||
strcmp(cpu_dai->name, dai_link->cpu_dai_name))
|
||||
continue;
|
||||
|
||||
rtd->cpu_dai = cpu_dai;
|
||||
}
|
||||
@ -896,6 +898,28 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
|
||||
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)
|
||||
{
|
||||
int err;
|
||||
@ -917,11 +941,9 @@ static void soc_remove_codec(struct snd_soc_codec *codec)
|
||||
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_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;
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
if (cpu_dai && cpu_dai->probed &&
|
||||
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;
|
||||
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;
|
||||
order++) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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)
|
||||
snd_soc_add_codec_controls(codec, driver->controls,
|
||||
driver->num_controls);
|
||||
@ -1230,7 +1275,44 @@ out:
|
||||
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_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 */
|
||||
if (!cpu_dai->probed &&
|
||||
cpu_dai->driver->probe_order == order) {
|
||||
cpu_dai->dapm.card = card;
|
||||
if (!try_module_get(cpu_dai->dev->driver->owner))
|
||||
return -ENODEV;
|
||||
if (!cpu_dai->codec) {
|
||||
cpu_dai->dapm.card = card;
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
if (!codec_dai->probed && codec_dai->driver->probe_order == order) {
|
||||
if (codec_dai->driver->probe) {
|
||||
@ -1565,14 +1634,27 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
|
||||
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;
|
||||
order++) {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -2789,6 +2871,104 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
|
||||
}
|
||||
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.
|
||||
*
|
||||
@ -3346,6 +3526,12 @@ int snd_soc_register_card(struct snd_soc_card *card)
|
||||
link->name);
|
||||
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
|
||||
@ -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,
|
||||
* not both or neither.
|
||||
* CPU device may be specified by either name or OF node, but
|
||||
* 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,
|
||||
"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);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -3938,6 +4136,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
|
||||
dev_err(card->dev,
|
||||
"Property '%s' index %d could not be read: %d\n",
|
||||
propname, 2 * i, ret);
|
||||
kfree(routes);
|
||||
return -EINVAL;
|
||||
}
|
||||
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,
|
||||
"Property '%s' index %d could not be read: %d\n",
|
||||
propname, (2 * i) + 1, ret);
|
||||
kfree(routes);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
@ -51,6 +52,7 @@ static int dapm_up_seq[] = {
|
||||
[snd_soc_dapm_pre] = 0,
|
||||
[snd_soc_dapm_supply] = 1,
|
||||
[snd_soc_dapm_regulator_supply] = 1,
|
||||
[snd_soc_dapm_clock_supply] = 1,
|
||||
[snd_soc_dapm_micbias] = 2,
|
||||
[snd_soc_dapm_dai_link] = 2,
|
||||
[snd_soc_dapm_dai] = 3,
|
||||
@ -92,6 +94,7 @@ static int dapm_down_seq[] = {
|
||||
[snd_soc_dapm_aif_out] = 10,
|
||||
[snd_soc_dapm_dai] = 10,
|
||||
[snd_soc_dapm_dai_link] = 11,
|
||||
[snd_soc_dapm_clock_supply] = 12,
|
||||
[snd_soc_dapm_regulator_supply] = 12,
|
||||
[snd_soc_dapm_supply] = 12,
|
||||
[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_supply:
|
||||
case snd_soc_dapm_regulator_supply:
|
||||
case snd_soc_dapm_clock_supply:
|
||||
case snd_soc_dapm_aif_in:
|
||||
case snd_soc_dapm_aif_out:
|
||||
case snd_soc_dapm_dai:
|
||||
@ -764,6 +768,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
|
||||
switch (widget->id) {
|
||||
case snd_soc_dapm_supply:
|
||||
case snd_soc_dapm_regulator_supply:
|
||||
case snd_soc_dapm_clock_supply:
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
@ -850,6 +855,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
|
||||
switch (widget->id) {
|
||||
case snd_soc_dapm_supply:
|
||||
case snd_soc_dapm_regulator_supply:
|
||||
case snd_soc_dapm_clock_supply:
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
@ -996,6 +1002,27 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
|
||||
}
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
case snd_soc_dapm_supply:
|
||||
case snd_soc_dapm_regulator_supply:
|
||||
case snd_soc_dapm_clock_supply:
|
||||
/* Supplies can't affect their outputs, only their inputs */
|
||||
break;
|
||||
default:
|
||||
@ -1587,6 +1615,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
|
||||
break;
|
||||
case snd_soc_dapm_supply:
|
||||
case snd_soc_dapm_regulator_supply:
|
||||
case snd_soc_dapm_clock_supply:
|
||||
case snd_soc_dapm_micbias:
|
||||
if (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_supply:
|
||||
case snd_soc_dapm_regulator_supply:
|
||||
case snd_soc_dapm_clock_supply:
|
||||
if (w->name)
|
||||
count += sprintf(buf + count, "%s: %s\n",
|
||||
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_supply:
|
||||
case snd_soc_dapm_regulator_supply:
|
||||
case snd_soc_dapm_clock_supply:
|
||||
case snd_soc_dapm_aif_in:
|
||||
case snd_soc_dapm_aif_out:
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dapm_mark_dirty(wsource, "Route added");
|
||||
dapm_mark_dirty(wsink, "Route added");
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
@ -2230,6 +2265,59 @@ err:
|
||||
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
|
||||
* @dapm: DAPM context
|
||||
@ -2246,15 +2334,15 @@ err:
|
||||
int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
|
||||
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);
|
||||
for (i = 0; i < num; i++) {
|
||||
ret = snd_soc_dapm_add_route(dapm, route);
|
||||
if (ret < 0) {
|
||||
r = snd_soc_dapm_add_route(dapm, route);
|
||||
if (r < 0) {
|
||||
dev_err(dapm->dev, "Failed to add route %s->%s\n",
|
||||
route->source, route->sink);
|
||||
break;
|
||||
ret = r;
|
||||
}
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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,
|
||||
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;
|
||||
unsigned int reg = mc->reg;
|
||||
unsigned int shift = mc->shift;
|
||||
unsigned int rshift = mc->rshift;
|
||||
int max = mc->max;
|
||||
unsigned int invert = mc->invert;
|
||||
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] =
|
||||
(snd_soc_read(widget->codec, reg) >> shift) & mask;
|
||||
if (shift != rshift)
|
||||
ucontrol->value.integer.value[1] =
|
||||
(snd_soc_read(widget->codec, reg) >> rshift) & mask;
|
||||
if (invert) {
|
||||
if (invert)
|
||||
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;
|
||||
}
|
||||
@ -2484,20 +2593,19 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_soc_dapm_update update;
|
||||
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);
|
||||
connect = !!val;
|
||||
|
||||
if (invert)
|
||||
val = max - val;
|
||||
mask = mask << 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);
|
||||
|
||||
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;
|
||||
}
|
||||
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:
|
||||
break;
|
||||
}
|
||||
@ -2924,6 +3045,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
|
||||
break;
|
||||
case snd_soc_dapm_supply:
|
||||
case snd_soc_dapm_regulator_supply:
|
||||
case snd_soc_dapm_clock_supply:
|
||||
w->power_check = dapm_supply_check_power;
|
||||
break;
|
||||
case snd_soc_dapm_dai:
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
struct dmaengine_pcm_runtime_data {
|
||||
struct dma_chan *dma_chan;
|
||||
dma_cookie_t cookie;
|
||||
|
||||
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_param = substream;
|
||||
dmaengine_submit(desc);
|
||||
prtd->cookie = dmaengine_submit(desc);
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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)
|
||||
{
|
||||
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);
|
||||
|
||||
@ -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
|
||||
* runtime. So it is not availabe to your pcm driver implementation. If you need
|
||||
* 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,
|
||||
dma_filter_fn filter_fn, void *filter_data)
|
||||
|
@ -142,11 +142,16 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
|
||||
case SND_SOC_REGMAP:
|
||||
/* Device has made its own regmap arrangements */
|
||||
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);
|
||||
/* Errors are legitimate for non-integer byte multiples */
|
||||
if (ret > 0)
|
||||
codec->val_bytes = ret;
|
||||
if (codec->control_data) {
|
||||
ret = regmap_get_val_bytes(codec->control_data);
|
||||
/* Errors are legitimate for non-integer byte
|
||||
* multiples */
|
||||
if (ret > 0)
|
||||
codec->val_bytes = ret;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1955,10 +1955,8 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
|
||||
fe->dpcm[stream].runtime = fe_substream->runtime;
|
||||
|
||||
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");
|
||||
mutex_unlock(&fe->card->mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
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_dai *codec_dai = rtd->codec_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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
ret = platform->driver->pcm_new(rtd);
|
||||
if (ret < 0) {
|
||||
pr_err("asoc: platform pcm constructor failed\n");
|
||||
dev_err(platform->dev, "pcm constructor failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
pcm->private_free = platform->driver->pcm_free;
|
||||
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);
|
||||
return ret;
|
||||
}
|
||||
|
297
sound/soc/spear/spdif_in.c
Normal file
297
sound/soc/spear/spdif_in.c
Normal 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
Loading…
Reference in New Issue
Block a user