mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-16 14:02:10 +00:00
ASoC: Changes for v4.1
A selection of changes for v4.1 so far. The main things are: - Move of jack registration to the card where it belongs. - Support for DAPM routes specified by both the machine driver and DT. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJU960DAAoJECTWi3JdVIfQkKIH/RDvxRn8dvKOPF5U9Uix3chH JWKkzqfsMP0EpmQTzCQPp0ShAyYcWSbYsopicynPxUem5vS4Z8+UmOgEEgkj59pK USbF6v1jCQXA6BcbKyUcRRBD9FtRkfVDc7mYbRs2CcwQz2CGCgee41cvPM+2BT+z QdNC9UJARSweGvE1IUJSfpfYOly+BJ2s0/28RaQ0PGt+I0auoYx7IMFgMSDjv2p6 PY0kyQiwm3Kyj2uNXPZ5gEuPxlw/t8n4fbQNrBYAvxzN+EF5NrGdKE3N7MI1xRV/ EkFhzy+uM3X9c37tb2lT2fgPFlBc9rgPuLPSyoQ6nxa5ghCqAlgRhzpxRem8hhU= =VlCw -----END PGP SIGNATURE----- Merge tag 'asoc-v4.1' into asoc-next ASoC: Changes for v4.1 A selection of changes for v4.1 so far. The main things are: - Move of jack registration to the card where it belongs. - Support for DAPM routes specified by both the machine driver and DT. # gpg: Signature made Thu 05 Mar 2015 01:10:27 GMT using RSA key ID 5D5487D0 # gpg: WARNING: digest algorithm MD5 is deprecated # gpg: please see https://gnupg.org/faq/weak-digest-algos.html for more information # gpg: Oops: keyid_from_fingerprint: no pubkey # gpg: Good signature from "Mark Brown <broonie@sirena.org.uk>" # gpg: aka "Mark Brown <broonie@debian.org>" # gpg: aka "Mark Brown <broonie@kernel.org>" # gpg: aka "Mark Brown <broonie@tardis.ed.ac.uk>" # gpg: aka "Mark Brown <broonie@linaro.org>" # gpg: aka "Mark Brown <Mark.Brown@linaro.org>"
This commit is contained in:
commit
89a88dd3d6
@ -18,6 +18,7 @@ Required properties:
|
||||
* Headphones
|
||||
* Speakers
|
||||
* Mic Jack
|
||||
* Int Mic
|
||||
|
||||
- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
|
||||
connected to the CODEC.
|
||||
|
@ -366,4 +366,11 @@ static inline int params_physical_width(const struct snd_pcm_hw_params *p)
|
||||
return snd_pcm_format_physical_width(params_format(p));
|
||||
}
|
||||
|
||||
static inline void
|
||||
params_set_format(struct snd_pcm_hw_params *p, snd_pcm_format_t fmt)
|
||||
{
|
||||
snd_mask_set(hw_param_mask(p, SNDRV_PCM_HW_PARAM_FORMAT),
|
||||
(__force int)fmt);
|
||||
}
|
||||
|
||||
#endif /* __SOUND_PCM_PARAMS_H */
|
||||
|
@ -450,8 +450,10 @@ int soc_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai);
|
||||
|
||||
/* Jack reporting */
|
||||
int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
|
||||
struct snd_soc_jack *jack);
|
||||
int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type,
|
||||
struct snd_soc_jack *jack, struct snd_soc_jack_pin *pins,
|
||||
unsigned int num_pins);
|
||||
|
||||
void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask);
|
||||
int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
|
||||
struct snd_soc_jack_pin *pins);
|
||||
@ -659,7 +661,7 @@ struct snd_soc_jack_gpio {
|
||||
struct snd_soc_jack {
|
||||
struct mutex mutex;
|
||||
struct snd_jack *jack;
|
||||
struct snd_soc_codec *codec;
|
||||
struct snd_soc_card *card;
|
||||
struct list_head pins;
|
||||
int status;
|
||||
struct blocking_notifier_head notifier;
|
||||
@ -954,6 +956,9 @@ struct snd_soc_dai_link {
|
||||
unsigned int symmetric_channels:1;
|
||||
unsigned int symmetric_samplebits:1;
|
||||
|
||||
/* Mark this pcm with non atomic ops */
|
||||
bool nonatomic;
|
||||
|
||||
/* Do not create a PCM for this DAI link (Backend link) */
|
||||
unsigned int no_pcm:1;
|
||||
|
||||
@ -1071,11 +1076,16 @@ struct snd_soc_card {
|
||||
|
||||
/*
|
||||
* Card-specific routes and widgets.
|
||||
* Note: of_dapm_xxx for Device Tree; Otherwise for driver build-in.
|
||||
*/
|
||||
const struct snd_soc_dapm_widget *dapm_widgets;
|
||||
int num_dapm_widgets;
|
||||
const struct snd_soc_dapm_route *dapm_routes;
|
||||
int num_dapm_routes;
|
||||
const struct snd_soc_dapm_widget *of_dapm_widgets;
|
||||
int num_of_dapm_widgets;
|
||||
const struct snd_soc_dapm_route *of_dapm_routes;
|
||||
int num_of_dapm_routes;
|
||||
bool fully_routed;
|
||||
|
||||
struct work_struct deferred_resume_work;
|
||||
|
@ -187,6 +187,94 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* When the bit clock is input, limit the maximum rate according to the
|
||||
* Serial Clock Ratio Considerations section from the SSC documentation:
|
||||
*
|
||||
* The Transmitter and the Receiver can be programmed to operate
|
||||
* with the clock signals provided on either the TK or RK pins.
|
||||
* This allows the SSC to support many slave-mode data transfers.
|
||||
* In this case, the maximum clock speed allowed on the RK pin is:
|
||||
* - Peripheral clock divided by 2 if Receiver Frame Synchro is input
|
||||
* - Peripheral clock divided by 3 if Receiver Frame Synchro is output
|
||||
* In addition, the maximum clock speed allowed on the TK pin is:
|
||||
* - Peripheral clock divided by 6 if Transmit Frame Synchro is input
|
||||
* - Peripheral clock divided by 2 if Transmit Frame Synchro is output
|
||||
*
|
||||
* When the bit clock is output, limit the rate according to the
|
||||
* SSC divider restrictions.
|
||||
*/
|
||||
static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params,
|
||||
struct snd_pcm_hw_rule *rule)
|
||||
{
|
||||
struct atmel_ssc_info *ssc_p = rule->private;
|
||||
struct ssc_device *ssc = ssc_p->ssc;
|
||||
struct snd_interval *i = hw_param_interval(params, rule->var);
|
||||
struct snd_interval t;
|
||||
struct snd_ratnum r = {
|
||||
.den_min = 1,
|
||||
.den_max = 4095,
|
||||
.den_step = 1,
|
||||
};
|
||||
unsigned int num = 0, den = 0;
|
||||
int frame_size;
|
||||
int mck_div = 2;
|
||||
int ret;
|
||||
|
||||
frame_size = snd_soc_params_to_frame_size(params);
|
||||
if (frame_size < 0)
|
||||
return frame_size;
|
||||
|
||||
switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFS:
|
||||
if ((ssc_p->dir_mask & SSC_DIR_MASK_CAPTURE)
|
||||
&& ssc->clk_from_rk_pin)
|
||||
/* Receiver Frame Synchro (i.e. capture)
|
||||
* is output (format is _CFS) and the RK pin
|
||||
* is used for input (format is _CBM_).
|
||||
*/
|
||||
mck_div = 3;
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
if ((ssc_p->dir_mask & SSC_DIR_MASK_PLAYBACK)
|
||||
&& !ssc->clk_from_rk_pin)
|
||||
/* Transmit Frame Synchro (i.e. playback)
|
||||
* is input (format is _CFM) and the TK pin
|
||||
* is used for input (format _CBM_ but not
|
||||
* using the RK pin).
|
||||
*/
|
||||
mck_div = 6;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
r.num = ssc_p->mck_rate / mck_div / frame_size;
|
||||
|
||||
ret = snd_interval_ratnum(i, 1, &r, &num, &den);
|
||||
if (ret >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) {
|
||||
params->rate_num = num;
|
||||
params->rate_den = den;
|
||||
}
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_CBM_CFS:
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
t.min = 8000;
|
||||
t.max = ssc_p->mck_rate / mck_div / frame_size;
|
||||
t.openmin = t.openmax = 0;
|
||||
t.integer = 0;
|
||||
ret = snd_interval_refine(i, &t);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* DAI functions
|
||||
@ -200,6 +288,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
|
||||
struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
|
||||
struct atmel_pcm_dma_params *dma_params;
|
||||
int dir, dir_mask;
|
||||
int ret;
|
||||
|
||||
pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
|
||||
ssc_readl(ssc_p->ssc->regs, SR));
|
||||
@ -207,6 +296,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
|
||||
/* Enable PMC peripheral clock for this SSC */
|
||||
pr_debug("atmel_ssc_dai: Starting clock\n");
|
||||
clk_enable(ssc_p->ssc->clk);
|
||||
ssc_p->mck_rate = clk_get_rate(ssc_p->ssc->clk);
|
||||
|
||||
/* Reset the SSC to keep it at a clean status */
|
||||
ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
|
||||
@ -219,6 +309,17 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
|
||||
dir_mask = SSC_DIR_MASK_CAPTURE;
|
||||
}
|
||||
|
||||
ret = snd_pcm_hw_rule_add(substream->runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_RATE,
|
||||
atmel_ssc_hw_rule_rate,
|
||||
ssc_p,
|
||||
SNDRV_PCM_HW_PARAM_FRAME_BITS,
|
||||
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
|
||||
if (ret < 0) {
|
||||
dev_err(dai->dev, "Failed to specify rate rule: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dma_params = &ssc_dma_params[dai->id][dir];
|
||||
dma_params->ssc = ssc_p->ssc;
|
||||
dma_params->substream = substream;
|
||||
@ -783,8 +884,6 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
|
||||
# define atmel_ssc_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
|
||||
|
||||
#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
|
||||
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
@ -804,12 +903,16 @@ static struct snd_soc_dai_driver atmel_ssc_dai = {
|
||||
.playback = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = ATMEL_SSC_RATES,
|
||||
.rates = SNDRV_PCM_RATE_CONTINUOUS,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 384000,
|
||||
.formats = ATMEL_SSC_FORMATS,},
|
||||
.capture = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = ATMEL_SSC_RATES,
|
||||
.rates = SNDRV_PCM_RATE_CONTINUOUS,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 384000,
|
||||
.formats = ATMEL_SSC_FORMATS,},
|
||||
.ops = &atmel_ssc_dai_ops,
|
||||
};
|
||||
|
@ -115,6 +115,7 @@ struct atmel_ssc_info {
|
||||
unsigned short rcmr_period;
|
||||
struct atmel_pcm_dma_params *dma_params[2];
|
||||
struct atmel_ssc_state ssc_state;
|
||||
unsigned long mck_rate;
|
||||
};
|
||||
|
||||
int atmel_ssc_set_audio(int ssc_id);
|
||||
|
@ -141,7 +141,8 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_WM8770 if SPI_MASTER
|
||||
select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8782
|
||||
select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8804_I2C if I2C
|
||||
select SND_SOC_WM8804_SPI if SPI_MASTER
|
||||
select SND_SOC_WM8900 if I2C
|
||||
select SND_SOC_WM8903 if I2C
|
||||
select SND_SOC_WM8904 if I2C
|
||||
@ -744,8 +745,19 @@ config SND_SOC_WM8782
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8804
|
||||
tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver"
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8804_I2C
|
||||
tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver I2C"
|
||||
depends on I2C
|
||||
select SND_SOC_WM8804
|
||||
select REGMAP_I2C
|
||||
|
||||
config SND_SOC_WM8804_SPI
|
||||
tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver SPI"
|
||||
depends on SPI_MASTER
|
||||
select SND_SOC_WM8804
|
||||
select REGMAP_SPI
|
||||
|
||||
config SND_SOC_WM8900
|
||||
tristate
|
||||
|
@ -145,6 +145,8 @@ snd-soc-wm8770-objs := wm8770.o
|
||||
snd-soc-wm8776-objs := wm8776.o
|
||||
snd-soc-wm8782-objs := wm8782.o
|
||||
snd-soc-wm8804-objs := wm8804.o
|
||||
snd-soc-wm8804-i2c-objs := wm8804-i2c.o
|
||||
snd-soc-wm8804-spi-objs := wm8804-spi.o
|
||||
snd-soc-wm8900-objs := wm8900.o
|
||||
snd-soc-wm8903-objs := wm8903.o
|
||||
snd-soc-wm8904-objs := wm8904.o
|
||||
@ -323,6 +325,8 @@ obj-$(CONFIG_SND_SOC_WM8770) += snd-soc-wm8770.o
|
||||
obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o
|
||||
obj-$(CONFIG_SND_SOC_WM8782) += snd-soc-wm8782.o
|
||||
obj-$(CONFIG_SND_SOC_WM8804) += snd-soc-wm8804.o
|
||||
obj-$(CONFIG_SND_SOC_WM8804_I2C) += snd-soc-wm8804-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_WM8804_SPI) += snd-soc-wm8804-spi.o
|
||||
obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o
|
||||
obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o
|
||||
obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o
|
||||
|
@ -938,22 +938,15 @@ int adau1977_probe(struct device *dev, struct regmap *regmap,
|
||||
adau1977->dvdd_reg = NULL;
|
||||
}
|
||||
|
||||
adau1977->reset_gpio = devm_gpiod_get(dev, "reset");
|
||||
if (IS_ERR(adau1977->reset_gpio)) {
|
||||
ret = PTR_ERR(adau1977->reset_gpio);
|
||||
if (ret != -ENOENT && ret != -ENOSYS)
|
||||
return PTR_ERR(adau1977->reset_gpio);
|
||||
adau1977->reset_gpio = NULL;
|
||||
}
|
||||
adau1977->reset_gpio = devm_gpiod_get_optional(dev, "reset",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(adau1977->reset_gpio))
|
||||
return PTR_ERR(adau1977->reset_gpio);
|
||||
|
||||
dev_set_drvdata(dev, adau1977);
|
||||
|
||||
if (adau1977->reset_gpio) {
|
||||
ret = gpiod_direction_output(adau1977->reset_gpio, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (adau1977->reset_gpio)
|
||||
ndelay(100);
|
||||
}
|
||||
|
||||
ret = adau1977_power_enable(adau1977);
|
||||
if (ret)
|
||||
|
@ -437,20 +437,13 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client,
|
||||
}
|
||||
|
||||
/* Reset the Device */
|
||||
cs35l32->reset_gpio = devm_gpiod_get(&i2c_client->dev,
|
||||
"reset-gpios");
|
||||
if (IS_ERR(cs35l32->reset_gpio)) {
|
||||
ret = PTR_ERR(cs35l32->reset_gpio);
|
||||
if (ret != -ENOENT && ret != -ENOSYS)
|
||||
return ret;
|
||||
cs35l32->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
|
||||
"reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(cs35l32->reset_gpio))
|
||||
return PTR_ERR(cs35l32->reset_gpio);
|
||||
|
||||
cs35l32->reset_gpio = NULL;
|
||||
} else {
|
||||
ret = gpiod_direction_output(cs35l32->reset_gpio, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (cs35l32->reset_gpio)
|
||||
gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
|
||||
}
|
||||
|
||||
/* initialize codec */
|
||||
ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, ®);
|
||||
|
@ -605,21 +605,14 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client,
|
||||
return ret;
|
||||
}
|
||||
|
||||
cs4265->reset_gpio = devm_gpiod_get(&i2c_client->dev,
|
||||
"reset-gpios");
|
||||
if (IS_ERR(cs4265->reset_gpio)) {
|
||||
ret = PTR_ERR(cs4265->reset_gpio);
|
||||
if (ret != -ENOENT && ret != -ENOSYS)
|
||||
return ret;
|
||||
cs4265->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
|
||||
"reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(cs4265->reset_gpio))
|
||||
return PTR_ERR(cs4265->reset_gpio);
|
||||
|
||||
cs4265->reset_gpio = NULL;
|
||||
} else {
|
||||
ret = gpiod_direction_output(cs4265->reset_gpio, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (cs4265->reset_gpio) {
|
||||
mdelay(1);
|
||||
gpiod_set_value_cansleep(cs4265->reset_gpio, 1);
|
||||
|
||||
}
|
||||
|
||||
i2c_set_clientdata(i2c_client, cs4265);
|
||||
|
@ -26,8 +26,6 @@
|
||||
#include <sound/soc-dai.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
|
||||
#define DRV_NAME "max98357a"
|
||||
|
||||
static int max98357a_daiops_trigger(struct snd_pcm_substream *substream,
|
||||
int cmd, struct snd_soc_dai *dai)
|
||||
{
|
||||
@ -87,9 +85,9 @@ static struct snd_soc_dai_ops max98357a_dai_ops = {
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver max98357a_dai_driver = {
|
||||
.name = DRV_NAME,
|
||||
.name = "HiFi",
|
||||
.playback = {
|
||||
.stream_name = DRV_NAME "-playback",
|
||||
.stream_name = "HiFi Playback",
|
||||
.formats = SNDRV_PCM_FMTBIT_S16 |
|
||||
SNDRV_PCM_FMTBIT_S24 |
|
||||
SNDRV_PCM_FMTBIT_S32,
|
||||
@ -127,7 +125,7 @@ static int max98357a_platform_remove(struct platform_device *pdev)
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id max98357a_device_id[] = {
|
||||
{ .compatible = "maxim," DRV_NAME, },
|
||||
{ .compatible = "maxim,max98357a" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max98357a_device_id);
|
||||
@ -135,7 +133,7 @@ MODULE_DEVICE_TABLE(of, max98357a_device_id);
|
||||
|
||||
static struct platform_driver max98357a_platform_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.name = "max98357a",
|
||||
.of_match_table = of_match_ptr(max98357a_device_id),
|
||||
},
|
||||
.probe = max98357a_platform_probe,
|
||||
@ -145,4 +143,3 @@ module_platform_driver(max98357a_platform_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Maxim MAX98357A Codec Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
|
@ -54,6 +54,9 @@ struct pcm512x_priv {
|
||||
int pll_d;
|
||||
int pll_p;
|
||||
unsigned long real_pll;
|
||||
unsigned long overclock_pll;
|
||||
unsigned long overclock_dac;
|
||||
unsigned long overclock_dsp;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -224,6 +227,90 @@ static bool pcm512x_volatile(struct device *dev, unsigned int reg)
|
||||
}
|
||||
}
|
||||
|
||||
static int pcm512x_overclock_pll_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ucontrol->value.integer.value[0] = pcm512x->overclock_pll;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (codec->dapm.bias_level) {
|
||||
case SND_SOC_BIAS_OFF:
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
break;
|
||||
default:
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
pcm512x->overclock_pll = ucontrol->value.integer.value[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcm512x_overclock_dsp_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ucontrol->value.integer.value[0] = pcm512x->overclock_dsp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (codec->dapm.bias_level) {
|
||||
case SND_SOC_BIAS_OFF:
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
break;
|
||||
default:
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
pcm512x->overclock_dsp = ucontrol->value.integer.value[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcm512x_overclock_dac_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ucontrol->value.integer.value[0] = pcm512x->overclock_dac;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcm512x_overclock_dac_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (codec->dapm.bias_level) {
|
||||
case SND_SOC_BIAS_OFF:
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
break;
|
||||
default:
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
pcm512x->overclock_dac = ucontrol->value.integer.value[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1);
|
||||
static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0);
|
||||
@ -328,6 +415,13 @@ SOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf),
|
||||
SOC_ENUM("Volume Ramp Up Step", pcm512x_vnus),
|
||||
SOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf),
|
||||
SOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds),
|
||||
|
||||
SOC_SINGLE_EXT("Max Overclock PLL", SND_SOC_NOPM, 0, 20, 0,
|
||||
pcm512x_overclock_pll_get, pcm512x_overclock_pll_put),
|
||||
SOC_SINGLE_EXT("Max Overclock DSP", SND_SOC_NOPM, 0, 40, 0,
|
||||
pcm512x_overclock_dsp_get, pcm512x_overclock_dsp_put),
|
||||
SOC_SINGLE_EXT("Max Overclock DAC", SND_SOC_NOPM, 0, 40, 0,
|
||||
pcm512x_overclock_dac_get, pcm512x_overclock_dac_put),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = {
|
||||
@ -346,6 +440,45 @@ static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = {
|
||||
{ "OUTR", NULL, "DACR" },
|
||||
};
|
||||
|
||||
static unsigned long pcm512x_pll_max(struct pcm512x_priv *pcm512x)
|
||||
{
|
||||
return 25000000 + 25000000 * pcm512x->overclock_pll / 100;
|
||||
}
|
||||
|
||||
static unsigned long pcm512x_dsp_max(struct pcm512x_priv *pcm512x)
|
||||
{
|
||||
return 50000000 + 50000000 * pcm512x->overclock_dsp / 100;
|
||||
}
|
||||
|
||||
static unsigned long pcm512x_dac_max(struct pcm512x_priv *pcm512x,
|
||||
unsigned long rate)
|
||||
{
|
||||
return rate + rate * pcm512x->overclock_dac / 100;
|
||||
}
|
||||
|
||||
static unsigned long pcm512x_sck_max(struct pcm512x_priv *pcm512x)
|
||||
{
|
||||
if (!pcm512x->pll_out)
|
||||
return 25000000;
|
||||
return pcm512x_pll_max(pcm512x);
|
||||
}
|
||||
|
||||
static unsigned long pcm512x_ncp_target(struct pcm512x_priv *pcm512x,
|
||||
unsigned long dac_rate)
|
||||
{
|
||||
/*
|
||||
* If the DAC is not actually overclocked, use the good old
|
||||
* NCP target rate...
|
||||
*/
|
||||
if (dac_rate <= 6144000)
|
||||
return 1536000;
|
||||
/*
|
||||
* ...but if the DAC is in fact overclocked, bump the NCP target
|
||||
* rate to get the recommended dividers even when overclocking.
|
||||
*/
|
||||
return pcm512x_dac_max(pcm512x, 1536000);
|
||||
}
|
||||
|
||||
static const u32 pcm512x_dai_rates[] = {
|
||||
8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
|
||||
88200, 96000, 176400, 192000, 384000,
|
||||
@ -359,6 +492,7 @@ static const struct snd_pcm_hw_constraint_list constraints_slave = {
|
||||
static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params,
|
||||
struct snd_pcm_hw_rule *rule)
|
||||
{
|
||||
struct pcm512x_priv *pcm512x = rule->private;
|
||||
struct snd_interval ranges[2];
|
||||
int frame_size;
|
||||
|
||||
@ -377,7 +511,7 @@ static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params,
|
||||
*/
|
||||
memset(ranges, 0, sizeof(ranges));
|
||||
ranges[0].min = 8000;
|
||||
ranges[0].max = 25000000 / frame_size / 2;
|
||||
ranges[0].max = pcm512x_sck_max(pcm512x) / frame_size / 2;
|
||||
ranges[1].min = DIV_ROUND_UP(16000000, frame_size);
|
||||
ranges[1].max = 384000;
|
||||
break;
|
||||
@ -408,7 +542,7 @@ static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream,
|
||||
return snd_pcm_hw_rule_add(substream->runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_RATE,
|
||||
pcm512x_hw_rule_rate,
|
||||
NULL,
|
||||
pcm512x,
|
||||
SNDRV_PCM_HW_PARAM_FRAME_BITS,
|
||||
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
|
||||
|
||||
@ -517,6 +651,8 @@ static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai,
|
||||
unsigned long bclk_rate)
|
||||
{
|
||||
struct device *dev = dai->dev;
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned long sck_rate;
|
||||
int pow2;
|
||||
|
||||
@ -527,9 +663,10 @@ static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai,
|
||||
* as many factors of 2 as possible, as that makes it easier
|
||||
* to find a fast DAC rate
|
||||
*/
|
||||
pow2 = 1 << fls((25000000 - 16000000) / bclk_rate);
|
||||
pow2 = 1 << fls((pcm512x_pll_max(pcm512x) - 16000000) / bclk_rate);
|
||||
for (; pow2; pow2 >>= 1) {
|
||||
sck_rate = rounddown(25000000, bclk_rate * pow2);
|
||||
sck_rate = rounddown(pcm512x_pll_max(pcm512x),
|
||||
bclk_rate * pow2);
|
||||
if (sck_rate >= 16000000)
|
||||
break;
|
||||
}
|
||||
@ -678,7 +815,7 @@ static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai,
|
||||
return 0; /* futile, quit early */
|
||||
|
||||
/* run DAC no faster than 6144000 Hz */
|
||||
for (dac_rate = rounddown(6144000, osr_rate);
|
||||
for (dac_rate = rounddown(pcm512x_dac_max(pcm512x, 6144000), osr_rate);
|
||||
dac_rate;
|
||||
dac_rate -= osr_rate) {
|
||||
|
||||
@ -805,7 +942,7 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
|
||||
osr_rate = 16 * sample_rate;
|
||||
|
||||
/* run DSP no faster than 50 MHz */
|
||||
dsp_div = mck_rate > 50000000 ? 2 : 1;
|
||||
dsp_div = mck_rate > pcm512x_dsp_max(pcm512x) ? 2 : 1;
|
||||
|
||||
dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate);
|
||||
if (dac_rate) {
|
||||
@ -836,7 +973,8 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
|
||||
dacsrc_rate = pllin_rate;
|
||||
} else {
|
||||
/* run DAC no faster than 6144000 Hz */
|
||||
unsigned long dac_mul = 6144000 / osr_rate;
|
||||
unsigned long dac_mul = pcm512x_dac_max(pcm512x, 6144000)
|
||||
/ osr_rate;
|
||||
unsigned long sck_mul = sck_rate / osr_rate;
|
||||
|
||||
for (; dac_mul; dac_mul--) {
|
||||
@ -863,28 +1001,30 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
|
||||
dacsrc_rate = sck_rate;
|
||||
}
|
||||
|
||||
osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate);
|
||||
if (osr_div > 128) {
|
||||
dev_err(dev, "Failed to find OSR divider\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dac_div = DIV_ROUND_CLOSEST(dacsrc_rate, dac_rate);
|
||||
if (dac_div > 128) {
|
||||
dev_err(dev, "Failed to find DAC divider\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
dac_rate = dacsrc_rate / dac_div;
|
||||
|
||||
ncp_div = DIV_ROUND_CLOSEST(dacsrc_rate / dac_div, 1536000);
|
||||
if (ncp_div > 128 || dacsrc_rate / dac_div / ncp_div > 2048000) {
|
||||
ncp_div = DIV_ROUND_CLOSEST(dac_rate,
|
||||
pcm512x_ncp_target(pcm512x, dac_rate));
|
||||
if (ncp_div > 128 || dac_rate / ncp_div > 2048000) {
|
||||
/* run NCP no faster than 2048000 Hz, but why? */
|
||||
ncp_div = DIV_ROUND_UP(dacsrc_rate / dac_div, 2048000);
|
||||
ncp_div = DIV_ROUND_UP(dac_rate, 2048000);
|
||||
if (ncp_div > 128) {
|
||||
dev_err(dev, "Failed to find NCP divider\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate);
|
||||
if (osr_div > 128) {
|
||||
dev_err(dev, "Failed to find OSR divider\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
idac = mck_rate / (dsp_div * sample_rate);
|
||||
|
||||
ret = regmap_write(pcm512x->regmap, PCM512x_DSP_CLKDIV, dsp_div - 1);
|
||||
@ -937,11 +1077,11 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (sample_rate <= 48000)
|
||||
if (sample_rate <= pcm512x_dac_max(pcm512x, 48000))
|
||||
fssp = PCM512x_FSSP_48KHZ;
|
||||
else if (sample_rate <= 96000)
|
||||
else if (sample_rate <= pcm512x_dac_max(pcm512x, 96000))
|
||||
fssp = PCM512x_FSSP_96KHZ;
|
||||
else if (sample_rate <= 192000)
|
||||
else if (sample_rate <= pcm512x_dac_max(pcm512x, 192000))
|
||||
fssp = PCM512x_FSSP_192KHZ;
|
||||
else
|
||||
fssp = PCM512x_FSSP_384KHZ;
|
||||
|
@ -395,9 +395,20 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
|
||||
|
||||
rt286->jack = jack;
|
||||
|
||||
/* Send an initial empty report */
|
||||
snd_soc_jack_report(rt286->jack, 0,
|
||||
SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
|
||||
if (jack) {
|
||||
/* enable IRQ */
|
||||
if (rt286->jack->status | SND_JACK_HEADPHONE)
|
||||
snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO1");
|
||||
regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x2);
|
||||
/* Send an initial empty report */
|
||||
snd_soc_jack_report(rt286->jack, rt286->jack->status,
|
||||
SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
|
||||
} else {
|
||||
/* disable IRQ */
|
||||
regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x0);
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "LDO1");
|
||||
}
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1950,17 +1950,20 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
RT5670_DMIC1_DISABLED,
|
||||
RT5670_DMIC_DATA_GPIO6,
|
||||
RT5670_DMIC_DATA_IN2P,
|
||||
RT5670_DMIC_DATA_GPIO7,
|
||||
};
|
||||
|
||||
enum {
|
||||
RT5670_DMIC2_DISABLED,
|
||||
RT5670_DMIC_DATA_GPIO8,
|
||||
RT5670_DMIC_DATA_IN3N,
|
||||
};
|
||||
|
||||
enum {
|
||||
RT5670_DMIC3_DISABLED,
|
||||
RT5670_DMIC_DATA_GPIO9,
|
||||
RT5670_DMIC_DATA_GPIO10,
|
||||
RT5670_DMIC_DATA_GPIO5,
|
||||
|
@ -718,11 +718,24 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on)
|
||||
RT5677_LDO1_SEL_MASK, 0x0);
|
||||
regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2,
|
||||
RT5677_PWR_LDO1, RT5677_PWR_LDO1);
|
||||
regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1,
|
||||
RT5677_MCLK_SRC_MASK, RT5677_MCLK2_SRC);
|
||||
regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2,
|
||||
RT5677_PLL2_PR_SRC_MASK | RT5677_DSP_CLK_SRC_MASK,
|
||||
RT5677_PLL2_PR_SRC_MCLK2 | RT5677_DSP_CLK_SRC_BYPASS);
|
||||
switch (rt5677->type) {
|
||||
case RT5677:
|
||||
regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1,
|
||||
RT5677_MCLK_SRC_MASK, RT5677_MCLK2_SRC);
|
||||
regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2,
|
||||
RT5677_PLL2_PR_SRC_MASK |
|
||||
RT5677_DSP_CLK_SRC_MASK,
|
||||
RT5677_PLL2_PR_SRC_MCLK2 |
|
||||
RT5677_DSP_CLK_SRC_BYPASS);
|
||||
break;
|
||||
case RT5676:
|
||||
regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2,
|
||||
RT5677_DSP_CLK_SRC_MASK,
|
||||
RT5677_DSP_CLK_SRC_BYPASS);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x07ff);
|
||||
regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x07fd);
|
||||
rt5677_set_dsp_mode(codec, true);
|
||||
@ -4500,10 +4513,10 @@ static int rt5677_suspend(struct snd_soc_codec *codec)
|
||||
if (!rt5677->dsp_vad_en) {
|
||||
regcache_cache_only(rt5677->regmap, true);
|
||||
regcache_mark_dirty(rt5677->regmap);
|
||||
}
|
||||
|
||||
if (gpio_is_valid(rt5677->pow_ldo2))
|
||||
gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
|
||||
if (gpio_is_valid(rt5677->pow_ldo2))
|
||||
gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -4512,12 +4525,12 @@ static int rt5677_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (gpio_is_valid(rt5677->pow_ldo2)) {
|
||||
gpio_set_value_cansleep(rt5677->pow_ldo2, 1);
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
if (!rt5677->dsp_vad_en) {
|
||||
if (gpio_is_valid(rt5677->pow_ldo2)) {
|
||||
gpio_set_value_cansleep(rt5677->pow_ldo2, 1);
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
regcache_cache_only(rt5677->regmap, false);
|
||||
regcache_sync(rt5677->regmap);
|
||||
}
|
||||
@ -4733,7 +4746,8 @@ static const struct regmap_config rt5677_regmap = {
|
||||
};
|
||||
|
||||
static const struct i2c_device_id rt5677_i2c_id[] = {
|
||||
{ "rt5677", 0 },
|
||||
{ "rt5677", RT5677 },
|
||||
{ "rt5676", RT5676 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id);
|
||||
@ -4850,6 +4864,8 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
|
||||
|
||||
i2c_set_clientdata(i2c, rt5677);
|
||||
|
||||
rt5677->type = id->driver_data;
|
||||
|
||||
if (pdata)
|
||||
rt5677->pdata = *pdata;
|
||||
|
||||
|
@ -1665,6 +1665,11 @@ enum {
|
||||
RT5677_IRQ_JD3,
|
||||
};
|
||||
|
||||
enum rt5677_type {
|
||||
RT5677,
|
||||
RT5676,
|
||||
};
|
||||
|
||||
struct rt5677_priv {
|
||||
struct snd_soc_codec *codec;
|
||||
struct rt5677_platform_data pdata;
|
||||
@ -1681,6 +1686,7 @@ struct rt5677_priv {
|
||||
int pll_in;
|
||||
int pll_out;
|
||||
int pow_ldo2; /* POW_LDO2 pin */
|
||||
enum rt5677_type type;
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
struct gpio_chip gpio_chip;
|
||||
#endif
|
||||
|
@ -783,19 +783,21 @@ static inline void sn95031_enable_jack_btn(struct snd_soc_codec *codec)
|
||||
snd_soc_write(codec, SN95031_BTNCTRL2, 0x01);
|
||||
}
|
||||
|
||||
static int sn95031_get_headset_state(struct snd_soc_jack *mfld_jack)
|
||||
static int sn95031_get_headset_state(struct snd_soc_codec *codec,
|
||||
struct snd_soc_jack *mfld_jack)
|
||||
{
|
||||
int micbias = sn95031_get_mic_bias(mfld_jack->codec);
|
||||
int micbias = sn95031_get_mic_bias(codec);
|
||||
|
||||
int jack_type = snd_soc_jack_get_type(mfld_jack, micbias);
|
||||
|
||||
pr_debug("jack type detected = %d\n", jack_type);
|
||||
if (jack_type == SND_JACK_HEADSET)
|
||||
sn95031_enable_jack_btn(mfld_jack->codec);
|
||||
sn95031_enable_jack_btn(codec);
|
||||
return jack_type;
|
||||
}
|
||||
|
||||
void sn95031_jack_detection(struct mfld_jack_data *jack_data)
|
||||
void sn95031_jack_detection(struct snd_soc_codec *codec,
|
||||
struct mfld_jack_data *jack_data)
|
||||
{
|
||||
unsigned int status;
|
||||
unsigned int mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_HEADSET;
|
||||
@ -809,11 +811,11 @@ void sn95031_jack_detection(struct mfld_jack_data *jack_data)
|
||||
status = SND_JACK_HEADSET | SND_JACK_BTN_1;
|
||||
} else if (jack_data->intr_id & 0x4) {
|
||||
pr_debug("headset or headphones inserted\n");
|
||||
status = sn95031_get_headset_state(jack_data->mfld_jack);
|
||||
status = sn95031_get_headset_state(codec, jack_data->mfld_jack);
|
||||
} else if (jack_data->intr_id & 0x8) {
|
||||
pr_debug("headset or headphones removed\n");
|
||||
status = 0;
|
||||
sn95031_disable_jack_btn(jack_data->mfld_jack->codec);
|
||||
sn95031_disable_jack_btn(codec);
|
||||
} else {
|
||||
pr_err("unidentified interrupt\n");
|
||||
return;
|
||||
|
@ -127,6 +127,7 @@ struct mfld_jack_data {
|
||||
struct snd_soc_jack *mfld_jack;
|
||||
};
|
||||
|
||||
extern void sn95031_jack_detection(struct mfld_jack_data *jack_data);
|
||||
extern void sn95031_jack_detection(struct snd_soc_codec *codec,
|
||||
struct mfld_jack_data *jack_data);
|
||||
|
||||
#endif
|
||||
|
@ -1213,27 +1213,15 @@ static int sta350_i2c_probe(struct i2c_client *i2c,
|
||||
#endif
|
||||
|
||||
/* GPIOs */
|
||||
sta350->gpiod_nreset = devm_gpiod_get(dev, "reset");
|
||||
if (IS_ERR(sta350->gpiod_nreset)) {
|
||||
ret = PTR_ERR(sta350->gpiod_nreset);
|
||||
if (ret != -ENOENT && ret != -ENOSYS)
|
||||
return ret;
|
||||
sta350->gpiod_nreset = devm_gpiod_get_optional(dev, "reset",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(sta350->gpiod_nreset))
|
||||
return PTR_ERR(sta350->gpiod_nreset);
|
||||
|
||||
sta350->gpiod_nreset = NULL;
|
||||
} else {
|
||||
gpiod_direction_output(sta350->gpiod_nreset, 0);
|
||||
}
|
||||
|
||||
sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down");
|
||||
if (IS_ERR(sta350->gpiod_power_down)) {
|
||||
ret = PTR_ERR(sta350->gpiod_power_down);
|
||||
if (ret != -ENOENT && ret != -ENOSYS)
|
||||
return ret;
|
||||
|
||||
sta350->gpiod_power_down = NULL;
|
||||
} else {
|
||||
gpiod_direction_output(sta350->gpiod_power_down, 0);
|
||||
}
|
||||
sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(sta350->gpiod_power_down))
|
||||
return PTR_ERR(sta350->gpiod_power_down);
|
||||
|
||||
/* regulators */
|
||||
for (i = 0; i < ARRAY_SIZE(sta350->supplies); i++)
|
||||
|
@ -485,16 +485,9 @@ static int tas2552_probe(struct i2c_client *client,
|
||||
if (data == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
data->enable_gpio = devm_gpiod_get(dev, "enable");
|
||||
if (IS_ERR(data->enable_gpio)) {
|
||||
ret = PTR_ERR(data->enable_gpio);
|
||||
if (ret != -ENOENT && ret != -ENOSYS)
|
||||
return ret;
|
||||
|
||||
data->enable_gpio = NULL;
|
||||
} else {
|
||||
gpiod_direction_output(data->enable_gpio, 0);
|
||||
}
|
||||
data->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(data->enable_gpio))
|
||||
return PTR_ERR(data->enable_gpio);
|
||||
|
||||
data->tas2552_client = client;
|
||||
data->regmap = devm_regmap_init_i2c(client, &tas2552_regmap_config);
|
||||
|
64
sound/soc/codecs/wm8804-i2c.c
Normal file
64
sound/soc/codecs/wm8804-i2c.c
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* wm8804-i2c.c -- WM8804 S/PDIF transceiver driver - I2C
|
||||
*
|
||||
* Copyright 2015 Cirrus Logic Inc
|
||||
*
|
||||
* Author: Charles Keepax <ckeepax@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/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#include "wm8804.h"
|
||||
|
||||
static int wm8804_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
|
||||
regmap = devm_regmap_init_i2c(i2c, &wm8804_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
return wm8804_probe(&i2c->dev, regmap);
|
||||
}
|
||||
|
||||
static int wm8804_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
wm8804_remove(&i2c->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id wm8804_i2c_id[] = {
|
||||
{ "wm8804", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, wm8804_i2c_id);
|
||||
|
||||
static const struct of_device_id wm8804_of_match[] = {
|
||||
{ .compatible = "wlf,wm8804", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, wm8804_of_match);
|
||||
|
||||
static struct i2c_driver wm8804_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "wm8804",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8804_of_match,
|
||||
},
|
||||
.probe = wm8804_i2c_probe,
|
||||
.remove = wm8804_i2c_remove,
|
||||
.id_table = wm8804_i2c_id
|
||||
};
|
||||
|
||||
module_i2c_driver(wm8804_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC WM8804 driver - I2C");
|
||||
MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.wolfsonmicro.com>");
|
||||
MODULE_LICENSE("GPL");
|
56
sound/soc/codecs/wm8804-spi.c
Normal file
56
sound/soc/codecs/wm8804-spi.c
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* wm8804-spi.c -- WM8804 S/PDIF transceiver driver - SPI
|
||||
*
|
||||
* Copyright 2015 Cirrus Logic Inc
|
||||
*
|
||||
* Author: Charles Keepax <ckeepax@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/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include "wm8804.h"
|
||||
|
||||
static int wm8804_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
|
||||
regmap = devm_regmap_init_spi(spi, &wm8804_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
return wm8804_probe(&spi->dev, regmap);
|
||||
}
|
||||
|
||||
static int wm8804_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
wm8804_remove(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id wm8804_of_match[] = {
|
||||
{ .compatible = "wlf,wm8804", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, wm8804_of_match);
|
||||
|
||||
static struct spi_driver wm8804_spi_driver = {
|
||||
.driver = {
|
||||
.name = "wm8804",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8804_of_match,
|
||||
},
|
||||
.probe = wm8804_spi_probe,
|
||||
.remove = wm8804_spi_remove
|
||||
};
|
||||
|
||||
module_spi_driver(wm8804_spi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC WM8804 driver - SPI");
|
||||
MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.wolfsonmicro.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -15,10 +15,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
@ -185,9 +182,9 @@ static bool wm8804_volatile(struct device *dev, unsigned int reg)
|
||||
}
|
||||
}
|
||||
|
||||
static int wm8804_reset(struct snd_soc_codec *codec)
|
||||
static int wm8804_reset(struct wm8804_priv *wm8804)
|
||||
{
|
||||
return snd_soc_write(codec, WM8804_RST_DEVID1, 0x0);
|
||||
return regmap_write(wm8804->regmap, WM8804_RST_DEVID1, 0x0);
|
||||
}
|
||||
|
||||
static int wm8804_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
@ -518,100 +515,6 @@ static int wm8804_set_bias_level(struct snd_soc_codec *codec,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm8804_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8804_priv *wm8804;
|
||||
int i;
|
||||
|
||||
wm8804 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i)
|
||||
regulator_unregister_notifier(wm8804->supplies[i].consumer,
|
||||
&wm8804->disable_nb[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm8804_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8804_priv *wm8804;
|
||||
int i, id1, id2, ret;
|
||||
|
||||
wm8804 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++)
|
||||
wm8804->supplies[i].supply = wm8804_supply_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8804->supplies),
|
||||
wm8804->supplies);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
wm8804->disable_nb[0].notifier_call = wm8804_regulator_event_0;
|
||||
wm8804->disable_nb[1].notifier_call = wm8804_regulator_event_1;
|
||||
|
||||
/* This should really be moved into the regulator core */
|
||||
for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) {
|
||||
ret = regulator_register_notifier(wm8804->supplies[i].consumer,
|
||||
&wm8804->disable_nb[i]);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev,
|
||||
"Failed to register regulator notifier: %d\n",
|
||||
ret);
|
||||
}
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
|
||||
wm8804->supplies);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
id1 = snd_soc_read(codec, WM8804_RST_DEVID1);
|
||||
if (id1 < 0) {
|
||||
dev_err(codec->dev, "Failed to read device ID: %d\n", id1);
|
||||
ret = id1;
|
||||
goto err_reg_enable;
|
||||
}
|
||||
|
||||
id2 = snd_soc_read(codec, WM8804_DEVID2);
|
||||
if (id2 < 0) {
|
||||
dev_err(codec->dev, "Failed to read device ID: %d\n", id2);
|
||||
ret = id2;
|
||||
goto err_reg_enable;
|
||||
}
|
||||
|
||||
id2 = (id2 << 8) | id1;
|
||||
|
||||
if (id2 != 0x8805) {
|
||||
dev_err(codec->dev, "Invalid device ID: %#x\n", id2);
|
||||
ret = -EINVAL;
|
||||
goto err_reg_enable;
|
||||
}
|
||||
|
||||
ret = snd_soc_read(codec, WM8804_DEVREV);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Failed to read device revision: %d\n",
|
||||
ret);
|
||||
goto err_reg_enable;
|
||||
}
|
||||
dev_info(codec->dev, "revision %c\n", ret + 'A');
|
||||
|
||||
ret = wm8804_reset(codec);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
|
||||
goto err_reg_enable;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_reg_enable:
|
||||
regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops wm8804_dai_ops = {
|
||||
.hw_params = wm8804_hw_params,
|
||||
.set_fmt = wm8804_set_fmt,
|
||||
@ -649,8 +552,6 @@ static struct snd_soc_dai_driver wm8804_dai = {
|
||||
};
|
||||
|
||||
static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
|
||||
.probe = wm8804_probe,
|
||||
.remove = wm8804_remove,
|
||||
.set_bias_level = wm8804_set_bias_level,
|
||||
.idle_bias_off = true,
|
||||
|
||||
@ -658,13 +559,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
|
||||
.num_controls = ARRAY_SIZE(wm8804_snd_controls),
|
||||
};
|
||||
|
||||
static const struct of_device_id wm8804_of_match[] = {
|
||||
{ .compatible = "wlf,wm8804", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, wm8804_of_match);
|
||||
|
||||
static const struct regmap_config wm8804_regmap_config = {
|
||||
const struct regmap_config wm8804_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
@ -675,128 +570,110 @@ static const struct regmap_config wm8804_regmap_config = {
|
||||
.reg_defaults = wm8804_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(wm8804_reg_defaults),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(wm8804_regmap_config);
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static int wm8804_spi_probe(struct spi_device *spi)
|
||||
int wm8804_probe(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
struct wm8804_priv *wm8804;
|
||||
int ret;
|
||||
unsigned int id1, id2;
|
||||
int i, ret;
|
||||
|
||||
wm8804 = devm_kzalloc(&spi->dev, sizeof *wm8804, GFP_KERNEL);
|
||||
wm8804 = devm_kzalloc(dev, sizeof(*wm8804), GFP_KERNEL);
|
||||
if (!wm8804)
|
||||
return -ENOMEM;
|
||||
|
||||
wm8804->regmap = devm_regmap_init_spi(spi, &wm8804_regmap_config);
|
||||
if (IS_ERR(wm8804->regmap)) {
|
||||
ret = PTR_ERR(wm8804->regmap);
|
||||
return ret;
|
||||
}
|
||||
dev_set_drvdata(dev, wm8804);
|
||||
|
||||
spi_set_drvdata(spi, wm8804);
|
||||
wm8804->regmap = regmap;
|
||||
|
||||
ret = snd_soc_register_codec(&spi->dev,
|
||||
&soc_codec_dev_wm8804, &wm8804_dai, 1);
|
||||
for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++)
|
||||
wm8804->supplies[i].supply = wm8804_supply_names[i];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm8804_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver wm8804_spi_driver = {
|
||||
.driver = {
|
||||
.name = "wm8804",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8804_of_match,
|
||||
},
|
||||
.probe = wm8804_spi_probe,
|
||||
.remove = wm8804_spi_remove
|
||||
};
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C)
|
||||
static int wm8804_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct wm8804_priv *wm8804;
|
||||
int ret;
|
||||
|
||||
wm8804 = devm_kzalloc(&i2c->dev, sizeof *wm8804, GFP_KERNEL);
|
||||
if (!wm8804)
|
||||
return -ENOMEM;
|
||||
|
||||
wm8804->regmap = devm_regmap_init_i2c(i2c, &wm8804_regmap_config);
|
||||
if (IS_ERR(wm8804->regmap)) {
|
||||
ret = PTR_ERR(wm8804->regmap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(i2c, wm8804);
|
||||
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_wm8804, &wm8804_dai, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm8804_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
snd_soc_unregister_codec(&i2c->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id wm8804_i2c_id[] = {
|
||||
{ "wm8804", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, wm8804_i2c_id);
|
||||
|
||||
static struct i2c_driver wm8804_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "wm8804",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8804_of_match,
|
||||
},
|
||||
.probe = wm8804_i2c_probe,
|
||||
.remove = wm8804_i2c_remove,
|
||||
.id_table = wm8804_i2c_id
|
||||
};
|
||||
#endif
|
||||
|
||||
static int __init wm8804_modinit(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C)
|
||||
ret = i2c_add_driver(&wm8804_i2c_driver);
|
||||
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(wm8804->supplies),
|
||||
wm8804->supplies);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "Failed to register wm8804 I2C driver: %d\n",
|
||||
ret);
|
||||
dev_err(dev, "Failed to request supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
ret = spi_register_driver(&wm8804_spi_driver);
|
||||
if (ret != 0) {
|
||||
printk(KERN_ERR "Failed to register wm8804 SPI driver: %d\n",
|
||||
ret);
|
||||
|
||||
wm8804->disable_nb[0].notifier_call = wm8804_regulator_event_0;
|
||||
wm8804->disable_nb[1].notifier_call = wm8804_regulator_event_1;
|
||||
|
||||
/* This should really be moved into the regulator core */
|
||||
for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) {
|
||||
ret = regulator_register_notifier(wm8804->supplies[i].consumer,
|
||||
&wm8804->disable_nb[i]);
|
||||
if (ret != 0) {
|
||||
dev_err(dev,
|
||||
"Failed to register regulator notifier: %d\n",
|
||||
ret);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
|
||||
wm8804->supplies);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable supplies: %d\n", ret);
|
||||
goto err_reg_enable;
|
||||
}
|
||||
|
||||
ret = regmap_read(regmap, WM8804_RST_DEVID1, &id1);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to read device ID: %d\n", ret);
|
||||
goto err_reg_enable;
|
||||
}
|
||||
|
||||
ret = regmap_read(regmap, WM8804_DEVID2, &id2);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to read device ID: %d\n", ret);
|
||||
goto err_reg_enable;
|
||||
}
|
||||
|
||||
id2 = (id2 << 8) | id1;
|
||||
|
||||
if (id2 != 0x8805) {
|
||||
dev_err(dev, "Invalid device ID: %#x\n", id2);
|
||||
ret = -EINVAL;
|
||||
goto err_reg_enable;
|
||||
}
|
||||
|
||||
ret = regmap_read(regmap, WM8804_DEVREV, &id1);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to read device revision: %d\n",
|
||||
ret);
|
||||
goto err_reg_enable;
|
||||
}
|
||||
dev_info(dev, "revision %c\n", id1 + 'A');
|
||||
|
||||
ret = wm8804_reset(wm8804);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to issue reset: %d\n", ret);
|
||||
goto err_reg_enable;
|
||||
}
|
||||
|
||||
return snd_soc_register_codec(dev, &soc_codec_dev_wm8804,
|
||||
&wm8804_dai, 1);
|
||||
|
||||
err_reg_enable:
|
||||
regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
|
||||
return ret;
|
||||
}
|
||||
module_init(wm8804_modinit);
|
||||
EXPORT_SYMBOL_GPL(wm8804_probe);
|
||||
|
||||
static void __exit wm8804_exit(void)
|
||||
void wm8804_remove(struct device *dev)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_I2C)
|
||||
i2c_del_driver(&wm8804_i2c_driver);
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
spi_unregister_driver(&wm8804_spi_driver);
|
||||
#endif
|
||||
struct wm8804_priv *wm8804;
|
||||
int i;
|
||||
|
||||
wm8804 = dev_get_drvdata(dev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i)
|
||||
regulator_unregister_notifier(wm8804->supplies[i].consumer,
|
||||
&wm8804->disable_nb[i]);
|
||||
|
||||
snd_soc_unregister_codec(dev);
|
||||
}
|
||||
module_exit(wm8804_exit);
|
||||
EXPORT_SYMBOL_GPL(wm8804_remove);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC WM8804 driver");
|
||||
MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
|
||||
|
@ -13,6 +13,8 @@
|
||||
#ifndef _WM8804_H
|
||||
#define _WM8804_H
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/*
|
||||
* Register values.
|
||||
*/
|
||||
@ -62,4 +64,9 @@
|
||||
#define WM8804_MCLKDIV_256FS 0
|
||||
#define WM8804_MCLKDIV_128FS 1
|
||||
|
||||
extern const struct regmap_config wm8804_regmap_config;
|
||||
|
||||
int wm8804_probe(struct device *dev, struct regmap *regmap);
|
||||
void wm8804_remove(struct device *dev);
|
||||
|
||||
#endif /* _WM8804_H */
|
||||
|
@ -420,10 +420,9 @@ static int wm_coeff_put(struct snd_kcontrol *kcontrol,
|
||||
|
||||
memcpy(ctl->cache, p, ctl->len);
|
||||
|
||||
if (!ctl->enabled) {
|
||||
ctl->set = 1;
|
||||
ctl->set = 1;
|
||||
if (!ctl->enabled)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return wm_coeff_write_control(kcontrol, p, ctl->len);
|
||||
}
|
||||
@ -1185,7 +1184,6 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
|
||||
int ret, pos, blocks, type, offset, reg;
|
||||
char *file;
|
||||
struct wm_adsp_buf *buf;
|
||||
int tmp;
|
||||
|
||||
file = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (file == NULL)
|
||||
@ -1335,12 +1333,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
|
||||
}
|
||||
}
|
||||
|
||||
tmp = le32_to_cpu(blk->len) % 4;
|
||||
if (tmp)
|
||||
pos += le32_to_cpu(blk->len) + (4 - tmp) + sizeof(*blk);
|
||||
else
|
||||
pos += le32_to_cpu(blk->len) + sizeof(*blk);
|
||||
|
||||
pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03;
|
||||
blocks++;
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,16 @@
|
||||
config SND_DAVINCI_SOC
|
||||
tristate "SoC Audio for TI DAVINCI"
|
||||
tristate
|
||||
depends on ARCH_DAVINCI
|
||||
select SND_EDMA_SOC
|
||||
|
||||
config SND_EDMA_SOC
|
||||
tristate "SoC Audio for Texas Instruments chips using eDMA (AM33XX/43XX)"
|
||||
depends on SOC_AM33XX || SOC_AM43XX
|
||||
tristate "SoC Audio for Texas Instruments chips using eDMA"
|
||||
depends on SOC_AM33XX || SOC_AM43XX || ARCH_DAVINCI
|
||||
select SND_SOC_GENERIC_DMAENGINE_PCM
|
||||
help
|
||||
Say Y or M here if you want audio support for TI SoC which uses eDMA.
|
||||
The following line of SoCs are supported by this platform driver:
|
||||
- daVinci devices
|
||||
- AM335x
|
||||
- AM437x/AM438x
|
||||
|
||||
@ -17,7 +19,7 @@ config SND_DAVINCI_SOC_I2S
|
||||
|
||||
config SND_DAVINCI_SOC_MCASP
|
||||
tristate "Multichannel Audio Serial Port (McASP) support"
|
||||
depends on SND_DAVINCI_SOC || SND_OMAP_SOC || SND_EDMA_SOC
|
||||
depends on SND_OMAP_SOC || SND_EDMA_SOC
|
||||
help
|
||||
Say Y or M here if you want to have support for McASP IP found in
|
||||
various Texas Instruments SoCs like:
|
||||
@ -45,7 +47,7 @@ config SND_AM33XX_SOC_EVM
|
||||
|
||||
config SND_DAVINCI_SOC_EVM
|
||||
tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
|
||||
depends on SND_DAVINCI_SOC && I2C
|
||||
depends on SND_EDMA_SOC && I2C
|
||||
depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM
|
||||
select SND_DAVINCI_SOC_GENERIC_EVM
|
||||
help
|
||||
@ -73,7 +75,7 @@ endchoice
|
||||
|
||||
config SND_DM6467_SOC_EVM
|
||||
tristate "SoC Audio support for DaVinci DM6467 EVM"
|
||||
depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM && I2C
|
||||
depends on SND_EDMA_SOC && MACH_DAVINCI_DM6467_EVM && I2C
|
||||
select SND_DAVINCI_SOC_GENERIC_EVM
|
||||
select SND_SOC_SPDIF
|
||||
|
||||
@ -82,7 +84,7 @@ config SND_DM6467_SOC_EVM
|
||||
|
||||
config SND_DA830_SOC_EVM
|
||||
tristate "SoC Audio support for DA830/OMAP-L137 EVM"
|
||||
depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM && I2C
|
||||
depends on SND_EDMA_SOC && MACH_DAVINCI_DA830_EVM && I2C
|
||||
select SND_DAVINCI_SOC_GENERIC_EVM
|
||||
|
||||
help
|
||||
@ -91,7 +93,7 @@ config SND_DA830_SOC_EVM
|
||||
|
||||
config SND_DA850_SOC_EVM
|
||||
tristate "SoC Audio support for DA850/OMAP-L138 EVM"
|
||||
depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM && I2C
|
||||
depends on SND_EDMA_SOC && MACH_DAVINCI_DA850_EVM && I2C
|
||||
select SND_DAVINCI_SOC_GENERIC_EVM
|
||||
help
|
||||
Say Y if you want to add support for SoC audio on TI
|
||||
|
@ -1,11 +1,9 @@
|
||||
# DAVINCI Platform Support
|
||||
snd-soc-davinci-objs := davinci-pcm.o
|
||||
snd-soc-edma-objs := edma-pcm.o
|
||||
snd-soc-davinci-i2s-objs := davinci-i2s.o
|
||||
snd-soc-davinci-mcasp-objs:= davinci-mcasp.o
|
||||
snd-soc-davinci-vcif-objs:= davinci-vcif.o
|
||||
|
||||
obj-$(CONFIG_SND_DAVINCI_SOC) += snd-soc-davinci.o
|
||||
obj-$(CONFIG_SND_EDMA_SOC) += snd-soc-edma.o
|
||||
obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o
|
||||
obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o
|
||||
|
@ -23,8 +23,9 @@
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
|
||||
#include "davinci-pcm.h"
|
||||
#include "edma-pcm.h"
|
||||
#include "davinci-i2s.h"
|
||||
|
||||
|
||||
@ -122,7 +123,8 @@ static const unsigned char double_fmt[SNDRV_PCM_FORMAT_S32_LE + 1] = {
|
||||
|
||||
struct davinci_mcbsp_dev {
|
||||
struct device *dev;
|
||||
struct davinci_pcm_dma_params dma_params[2];
|
||||
struct snd_dmaengine_dai_dma_data dma_data[2];
|
||||
int dma_request[2];
|
||||
void __iomem *base;
|
||||
#define MOD_DSP_A 0
|
||||
#define MOD_DSP_B 1
|
||||
@ -419,8 +421,6 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
|
||||
struct davinci_pcm_dma_params *dma_params =
|
||||
&dev->dma_params[substream->stream];
|
||||
struct snd_interval *i = NULL;
|
||||
int mcbsp_word_length, master;
|
||||
unsigned int rcr, xcr, srgr, clk_div, freq, framesize;
|
||||
@ -532,8 +532,6 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
dma_params->acnt = dma_params->data_type = data_type[fmt];
|
||||
dma_params->fifo_level = 0;
|
||||
mcbsp_word_length = asp_word_length[fmt];
|
||||
|
||||
switch (master) {
|
||||
@ -600,15 +598,6 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int davinci_i2s_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
snd_soc_dai_set_dma_data(dai, substream, dev->dma_params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
@ -620,7 +609,6 @@ static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
|
||||
#define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000
|
||||
|
||||
static const struct snd_soc_dai_ops davinci_i2s_dai_ops = {
|
||||
.startup = davinci_i2s_startup,
|
||||
.shutdown = davinci_i2s_shutdown,
|
||||
.prepare = davinci_i2s_prepare,
|
||||
.trigger = davinci_i2s_trigger,
|
||||
@ -630,7 +618,18 @@ static const struct snd_soc_dai_ops davinci_i2s_dai_ops = {
|
||||
|
||||
};
|
||||
|
||||
static int davinci_i2s_dai_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
|
||||
dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_driver davinci_i2s_dai = {
|
||||
.probe = davinci_i2s_dai_probe,
|
||||
.playback = {
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
@ -651,11 +650,9 @@ static const struct snd_soc_component_driver davinci_i2s_component = {
|
||||
|
||||
static int davinci_i2s_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct davinci_mcbsp_dev *dev;
|
||||
struct resource *mem, *ioarea, *res;
|
||||
enum dma_event_q asp_chan_q = EVENTQ_0;
|
||||
enum dma_event_q ram_chan_q = EVENTQ_1;
|
||||
int *dma;
|
||||
int ret;
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
@ -676,22 +673,6 @@ static int davinci_i2s_probe(struct platform_device *pdev)
|
||||
GFP_KERNEL);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
if (pdata) {
|
||||
dev->enable_channel_combine = pdata->enable_channel_combine;
|
||||
dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].sram_size =
|
||||
pdata->sram_size_playback;
|
||||
dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].sram_size =
|
||||
pdata->sram_size_capture;
|
||||
dev->clk_input_pin = pdata->clk_input_pin;
|
||||
dev->i2s_accurate_sck = pdata->i2s_accurate_sck;
|
||||
asp_chan_q = pdata->asp_chan_q;
|
||||
ram_chan_q = pdata->ram_chan_q;
|
||||
}
|
||||
|
||||
dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].asp_chan_q = asp_chan_q;
|
||||
dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].ram_chan_q = ram_chan_q;
|
||||
dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].asp_chan_q = asp_chan_q;
|
||||
dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].ram_chan_q = ram_chan_q;
|
||||
|
||||
dev->clk = clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(dev->clk))
|
||||
@ -705,10 +686,10 @@ static int davinci_i2s_probe(struct platform_device *pdev)
|
||||
goto err_release_clk;
|
||||
}
|
||||
|
||||
dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].dma_addr =
|
||||
dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
|
||||
(dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG);
|
||||
|
||||
dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr =
|
||||
dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
|
||||
(dma_addr_t)(mem->start + DAVINCI_MCBSP_DRR_REG);
|
||||
|
||||
/* first TX, then RX */
|
||||
@ -718,7 +699,9 @@ static int davinci_i2s_probe(struct platform_device *pdev)
|
||||
ret = -ENXIO;
|
||||
goto err_release_clk;
|
||||
}
|
||||
dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].channel = res->start;
|
||||
dma = &dev->dma_request[SNDRV_PCM_STREAM_PLAYBACK];
|
||||
*dma = res->start;
|
||||
dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = dma;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
|
||||
if (!res) {
|
||||
@ -726,9 +709,11 @@ static int davinci_i2s_probe(struct platform_device *pdev)
|
||||
ret = -ENXIO;
|
||||
goto err_release_clk;
|
||||
}
|
||||
dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start;
|
||||
dev->dev = &pdev->dev;
|
||||
dma = &dev->dma_request[SNDRV_PCM_STREAM_CAPTURE];
|
||||
*dma = res->start;
|
||||
dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = dma;
|
||||
|
||||
dev->dev = &pdev->dev;
|
||||
dev_set_drvdata(&pdev->dev, dev);
|
||||
|
||||
ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component,
|
||||
@ -736,7 +721,7 @@ static int davinci_i2s_probe(struct platform_device *pdev)
|
||||
if (ret != 0)
|
||||
goto err_release_clk;
|
||||
|
||||
ret = davinci_soc_platform_register(&pdev->dev);
|
||||
ret = edma_pcm_platform_register(&pdev->dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
|
||||
goto err_unregister_component;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_data/davinci_asp.h>
|
||||
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/core.h>
|
||||
@ -36,7 +37,6 @@
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
#include <sound/omap-pcm.h>
|
||||
|
||||
#include "davinci-pcm.h"
|
||||
#include "edma-pcm.h"
|
||||
#include "davinci-mcasp.h"
|
||||
|
||||
@ -65,7 +65,6 @@ struct davinci_mcasp_context {
|
||||
};
|
||||
|
||||
struct davinci_mcasp {
|
||||
struct davinci_pcm_dma_params dma_params[2];
|
||||
struct snd_dmaengine_dai_dma_data dma_data[2];
|
||||
void __iomem *base;
|
||||
u32 fifo_base;
|
||||
@ -82,6 +81,7 @@ struct davinci_mcasp {
|
||||
u16 bclk_lrclk_ratio;
|
||||
int streams;
|
||||
u32 irq_request[2];
|
||||
int dma_request[2];
|
||||
|
||||
int sysclk_freq;
|
||||
bool bclk_master;
|
||||
@ -441,6 +441,18 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
|
||||
mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
|
||||
mcasp->bclk_master = 1;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFM:
|
||||
/* codec is clock slave and frame master */
|
||||
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
|
||||
mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
|
||||
|
||||
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
|
||||
mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
|
||||
|
||||
mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
|
||||
mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
|
||||
mcasp->bclk_master = 1;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBM_CFS:
|
||||
/* codec is clock master and frame slave */
|
||||
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
|
||||
@ -631,7 +643,6 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
|
||||
static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
|
||||
int period_words, int channels)
|
||||
{
|
||||
struct davinci_pcm_dma_params *dma_params = &mcasp->dma_params[stream];
|
||||
struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream];
|
||||
int i;
|
||||
u8 tx_ser = 0;
|
||||
@ -699,10 +710,8 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
|
||||
* For example if three serializers are enabled the DMA
|
||||
* need to transfer three words per DMA request.
|
||||
*/
|
||||
dma_params->fifo_level = active_serializers;
|
||||
dma_data->maxburst = active_serializers;
|
||||
} else {
|
||||
dma_params->fifo_level = 0;
|
||||
dma_data->maxburst = 0;
|
||||
}
|
||||
return 0;
|
||||
@ -734,7 +743,6 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
|
||||
/* Configure the burst size for platform drivers */
|
||||
if (numevt == 1)
|
||||
numevt = 0;
|
||||
dma_params->fifo_level = numevt;
|
||||
dma_data->maxburst = numevt;
|
||||
|
||||
return 0;
|
||||
@ -860,8 +868,6 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct davinci_pcm_dma_params *dma_params =
|
||||
&mcasp->dma_params[substream->stream];
|
||||
int word_length;
|
||||
int channels = params_channels(params);
|
||||
int period_size = params_period_size(params);
|
||||
@ -902,31 +908,26 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_U8:
|
||||
case SNDRV_PCM_FORMAT_S8:
|
||||
dma_params->data_type = 1;
|
||||
word_length = 8;
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_FORMAT_U16_LE:
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
dma_params->data_type = 2;
|
||||
word_length = 16;
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_FORMAT_U24_3LE:
|
||||
case SNDRV_PCM_FORMAT_S24_3LE:
|
||||
dma_params->data_type = 3;
|
||||
word_length = 24;
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_FORMAT_U24_LE:
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
dma_params->data_type = 4;
|
||||
word_length = 24;
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_FORMAT_U32_LE:
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
dma_params->data_type = 4;
|
||||
word_length = 32;
|
||||
break;
|
||||
|
||||
@ -935,11 +936,6 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (mcasp->version == MCASP_VERSION_2 && !dma_params->fifo_level)
|
||||
dma_params->acnt = 4;
|
||||
else
|
||||
dma_params->acnt = dma_params->data_type;
|
||||
|
||||
davinci_config_channel_size(mcasp, word_length);
|
||||
|
||||
if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE)
|
||||
@ -1043,17 +1039,8 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
if (mcasp->version >= MCASP_VERSION_3) {
|
||||
/* Using dmaengine PCM */
|
||||
dai->playback_dma_data =
|
||||
&mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
|
||||
dai->capture_dma_data =
|
||||
&mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
|
||||
} else {
|
||||
/* Using davinci-pcm */
|
||||
dai->playback_dma_data = mcasp->dma_params;
|
||||
dai->capture_dma_data = mcasp->dma_params;
|
||||
}
|
||||
dai->playback_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
|
||||
dai->capture_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1172,28 +1159,24 @@ static const struct snd_soc_component_driver davinci_mcasp_component = {
|
||||
static struct davinci_mcasp_pdata dm646x_mcasp_pdata = {
|
||||
.tx_dma_offset = 0x400,
|
||||
.rx_dma_offset = 0x400,
|
||||
.asp_chan_q = EVENTQ_0,
|
||||
.version = MCASP_VERSION_1,
|
||||
};
|
||||
|
||||
static struct davinci_mcasp_pdata da830_mcasp_pdata = {
|
||||
.tx_dma_offset = 0x2000,
|
||||
.rx_dma_offset = 0x2000,
|
||||
.asp_chan_q = EVENTQ_0,
|
||||
.version = MCASP_VERSION_2,
|
||||
};
|
||||
|
||||
static struct davinci_mcasp_pdata am33xx_mcasp_pdata = {
|
||||
.tx_dma_offset = 0,
|
||||
.rx_dma_offset = 0,
|
||||
.asp_chan_q = EVENTQ_0,
|
||||
.version = MCASP_VERSION_3,
|
||||
};
|
||||
|
||||
static struct davinci_mcasp_pdata dra7_mcasp_pdata = {
|
||||
.tx_dma_offset = 0x200,
|
||||
.rx_dma_offset = 0x284,
|
||||
.asp_chan_q = EVENTQ_0,
|
||||
.version = MCASP_VERSION_4,
|
||||
};
|
||||
|
||||
@ -1370,12 +1353,12 @@ nodata:
|
||||
|
||||
static int davinci_mcasp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct davinci_pcm_dma_params *dma_params;
|
||||
struct snd_dmaengine_dai_dma_data *dma_data;
|
||||
struct resource *mem, *ioarea, *res, *dat;
|
||||
struct davinci_mcasp_pdata *pdata;
|
||||
struct davinci_mcasp *mcasp;
|
||||
char *irq_name;
|
||||
int *dma;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
@ -1509,59 +1492,45 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
|
||||
if (dat)
|
||||
mcasp->dat_port = true;
|
||||
|
||||
dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
|
||||
dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
|
||||
dma_params->asp_chan_q = pdata->asp_chan_q;
|
||||
dma_params->ram_chan_q = pdata->ram_chan_q;
|
||||
dma_params->sram_pool = pdata->sram_pool;
|
||||
dma_params->sram_size = pdata->sram_size_playback;
|
||||
if (dat)
|
||||
dma_params->dma_addr = dat->start;
|
||||
dma_data->addr = dat->start;
|
||||
else
|
||||
dma_params->dma_addr = mem->start + pdata->tx_dma_offset;
|
||||
|
||||
/* Unconditional dmaengine stuff */
|
||||
dma_data->addr = dma_params->dma_addr;
|
||||
dma_data->addr = mem->start + pdata->tx_dma_offset;
|
||||
|
||||
dma = &mcasp->dma_request[SNDRV_PCM_STREAM_PLAYBACK];
|
||||
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
if (res)
|
||||
dma_params->channel = res->start;
|
||||
*dma = res->start;
|
||||
else
|
||||
dma_params->channel = pdata->tx_dma_channel;
|
||||
*dma = pdata->tx_dma_channel;
|
||||
|
||||
/* dmaengine filter data for DT and non-DT boot */
|
||||
if (pdev->dev.of_node)
|
||||
dma_data->filter_data = "tx";
|
||||
else
|
||||
dma_data->filter_data = &dma_params->channel;
|
||||
dma_data->filter_data = dma;
|
||||
|
||||
/* RX is not valid in DIT mode */
|
||||
if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
|
||||
dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE];
|
||||
dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
|
||||
dma_params->asp_chan_q = pdata->asp_chan_q;
|
||||
dma_params->ram_chan_q = pdata->ram_chan_q;
|
||||
dma_params->sram_pool = pdata->sram_pool;
|
||||
dma_params->sram_size = pdata->sram_size_capture;
|
||||
if (dat)
|
||||
dma_params->dma_addr = dat->start;
|
||||
dma_data->addr = dat->start;
|
||||
else
|
||||
dma_params->dma_addr = mem->start + pdata->rx_dma_offset;
|
||||
|
||||
/* Unconditional dmaengine stuff */
|
||||
dma_data->addr = dma_params->dma_addr;
|
||||
dma_data->addr = mem->start + pdata->rx_dma_offset;
|
||||
|
||||
dma = &mcasp->dma_request[SNDRV_PCM_STREAM_CAPTURE];
|
||||
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
|
||||
if (res)
|
||||
dma_params->channel = res->start;
|
||||
*dma = res->start;
|
||||
else
|
||||
dma_params->channel = pdata->rx_dma_channel;
|
||||
*dma = pdata->rx_dma_channel;
|
||||
|
||||
/* dmaengine filter data for DT and non-DT boot */
|
||||
if (pdev->dev.of_node)
|
||||
dma_data->filter_data = "rx";
|
||||
else
|
||||
dma_data->filter_data = &dma_params->channel;
|
||||
dma_data->filter_data = dma;
|
||||
}
|
||||
|
||||
if (mcasp->version < MCASP_VERSION_3) {
|
||||
@ -1584,17 +1553,11 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
|
||||
goto err;
|
||||
|
||||
switch (mcasp->version) {
|
||||
#if IS_BUILTIN(CONFIG_SND_DAVINCI_SOC) || \
|
||||
(IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
|
||||
IS_MODULE(CONFIG_SND_DAVINCI_SOC))
|
||||
case MCASP_VERSION_1:
|
||||
case MCASP_VERSION_2:
|
||||
ret = davinci_soc_platform_register(&pdev->dev);
|
||||
break;
|
||||
#endif
|
||||
#if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \
|
||||
(IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
|
||||
IS_MODULE(CONFIG_SND_EDMA_SOC))
|
||||
case MCASP_VERSION_1:
|
||||
case MCASP_VERSION_2:
|
||||
case MCASP_VERSION_3:
|
||||
ret = edma_pcm_platform_register(&pdev->dev);
|
||||
break;
|
||||
|
@ -1,861 +0,0 @@
|
||||
/*
|
||||
* ALSA PCM interface for the TI DAVINCI processor
|
||||
*
|
||||
* Author: Vladimir Barinov, <vbarinov@embeddedalley.com>
|
||||
* Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com>
|
||||
* added SRAM ping/pong (C) 2008 Troy Kisky <troy.kisky@boundarydevices.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/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/platform_data/edma.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <asm/dma.h>
|
||||
|
||||
#include "davinci-pcm.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
static void print_buf_info(int slot, char *name)
|
||||
{
|
||||
struct edmacc_param p;
|
||||
if (slot < 0)
|
||||
return;
|
||||
edma_read_slot(slot, &p);
|
||||
printk(KERN_DEBUG "%s: 0x%x, opt=%x, src=%x, a_b_cnt=%x dst=%x\n",
|
||||
name, slot, p.opt, p.src, p.a_b_cnt, p.dst);
|
||||
printk(KERN_DEBUG " src_dst_bidx=%x link_bcntrld=%x src_dst_cidx=%x ccnt=%x\n",
|
||||
p.src_dst_bidx, p.link_bcntrld, p.src_dst_cidx, p.ccnt);
|
||||
}
|
||||
#else
|
||||
static void print_buf_info(int slot, char *name)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct snd_pcm_hardware pcm_hardware_playback = {
|
||||
.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME|
|
||||
SNDRV_PCM_INFO_BATCH),
|
||||
.buffer_bytes_max = 128 * 1024,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 8 * 1024,
|
||||
.periods_min = 16,
|
||||
.periods_max = 255,
|
||||
.fifo_size = 0,
|
||||
};
|
||||
|
||||
static struct snd_pcm_hardware pcm_hardware_capture = {
|
||||
.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_BATCH),
|
||||
.buffer_bytes_max = 128 * 1024,
|
||||
.period_bytes_min = 32,
|
||||
.period_bytes_max = 8 * 1024,
|
||||
.periods_min = 16,
|
||||
.periods_max = 255,
|
||||
.fifo_size = 0,
|
||||
};
|
||||
|
||||
/*
|
||||
* How ping/pong works....
|
||||
*
|
||||
* Playback:
|
||||
* ram_params - copys 2*ping_size from start of SDRAM to iram,
|
||||
* links to ram_link2
|
||||
* ram_link2 - copys rest of SDRAM to iram in ping_size units,
|
||||
* links to ram_link
|
||||
* ram_link - copys entire SDRAM to iram in ping_size uints,
|
||||
* links to self
|
||||
*
|
||||
* asp_params - same as asp_link[0]
|
||||
* asp_link[0] - copys from lower half of iram to asp port
|
||||
* links to asp_link[1], triggers iram copy event on completion
|
||||
* asp_link[1] - copys from upper half of iram to asp port
|
||||
* links to asp_link[0], triggers iram copy event on completion
|
||||
* triggers interrupt only needed to let upper SOC levels update position
|
||||
* in stream on completion
|
||||
*
|
||||
* When playback is started:
|
||||
* ram_params started
|
||||
* asp_params started
|
||||
*
|
||||
* Capture:
|
||||
* ram_params - same as ram_link,
|
||||
* links to ram_link
|
||||
* ram_link - same as playback
|
||||
* links to self
|
||||
*
|
||||
* asp_params - same as playback
|
||||
* asp_link[0] - same as playback
|
||||
* asp_link[1] - same as playback
|
||||
*
|
||||
* When capture is started:
|
||||
* asp_params started
|
||||
*/
|
||||
struct davinci_runtime_data {
|
||||
spinlock_t lock;
|
||||
int period; /* current DMA period */
|
||||
int asp_channel; /* Master DMA channel */
|
||||
int asp_link[2]; /* asp parameter link channel, ping/pong */
|
||||
struct davinci_pcm_dma_params *params; /* DMA params */
|
||||
int ram_channel;
|
||||
int ram_link;
|
||||
int ram_link2;
|
||||
struct edmacc_param asp_params;
|
||||
struct edmacc_param ram_params;
|
||||
};
|
||||
|
||||
static void davinci_pcm_period_elapsed(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct davinci_runtime_data *prtd = substream->runtime->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
||||
prtd->period++;
|
||||
if (unlikely(prtd->period >= runtime->periods))
|
||||
prtd->period = 0;
|
||||
}
|
||||
|
||||
static void davinci_pcm_period_reset(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct davinci_runtime_data *prtd = substream->runtime->private_data;
|
||||
|
||||
prtd->period = 0;
|
||||
}
|
||||
/*
|
||||
* Not used with ping/pong
|
||||
*/
|
||||
static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct davinci_runtime_data *prtd = substream->runtime->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
unsigned int period_size;
|
||||
unsigned int dma_offset;
|
||||
dma_addr_t dma_pos;
|
||||
dma_addr_t src, dst;
|
||||
unsigned short src_bidx, dst_bidx;
|
||||
unsigned short src_cidx, dst_cidx;
|
||||
unsigned int data_type;
|
||||
unsigned short acnt;
|
||||
unsigned int count;
|
||||
unsigned int fifo_level;
|
||||
|
||||
period_size = snd_pcm_lib_period_bytes(substream);
|
||||
dma_offset = prtd->period * period_size;
|
||||
dma_pos = runtime->dma_addr + dma_offset;
|
||||
fifo_level = prtd->params->fifo_level;
|
||||
|
||||
pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d "
|
||||
"dma_ptr = %x period_size=%x\n", prtd->asp_link[0], dma_pos,
|
||||
period_size);
|
||||
|
||||
data_type = prtd->params->data_type;
|
||||
count = period_size / data_type;
|
||||
if (fifo_level)
|
||||
count /= fifo_level;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
src = dma_pos;
|
||||
dst = prtd->params->dma_addr;
|
||||
src_bidx = data_type;
|
||||
dst_bidx = 4;
|
||||
src_cidx = data_type * fifo_level;
|
||||
dst_cidx = 0;
|
||||
} else {
|
||||
src = prtd->params->dma_addr;
|
||||
dst = dma_pos;
|
||||
src_bidx = 0;
|
||||
dst_bidx = data_type;
|
||||
src_cidx = 0;
|
||||
dst_cidx = data_type * fifo_level;
|
||||
}
|
||||
|
||||
acnt = prtd->params->acnt;
|
||||
edma_set_src(prtd->asp_link[0], src, INCR, W8BIT);
|
||||
edma_set_dest(prtd->asp_link[0], dst, INCR, W8BIT);
|
||||
|
||||
edma_set_src_index(prtd->asp_link[0], src_bidx, src_cidx);
|
||||
edma_set_dest_index(prtd->asp_link[0], dst_bidx, dst_cidx);
|
||||
|
||||
if (!fifo_level)
|
||||
edma_set_transfer_params(prtd->asp_link[0], acnt, count, 1, 0,
|
||||
ASYNC);
|
||||
else
|
||||
edma_set_transfer_params(prtd->asp_link[0], acnt,
|
||||
fifo_level,
|
||||
count, fifo_level,
|
||||
ABSYNC);
|
||||
}
|
||||
|
||||
static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
|
||||
{
|
||||
struct snd_pcm_substream *substream = data;
|
||||
struct davinci_runtime_data *prtd = substream->runtime->private_data;
|
||||
|
||||
print_buf_info(prtd->ram_channel, "i ram_channel");
|
||||
pr_debug("davinci_pcm: link=%d, status=0x%x\n", link, ch_status);
|
||||
|
||||
if (unlikely(ch_status != EDMA_DMA_COMPLETE))
|
||||
return;
|
||||
|
||||
if (snd_pcm_running(substream)) {
|
||||
spin_lock(&prtd->lock);
|
||||
if (prtd->ram_channel < 0) {
|
||||
/* No ping/pong must fix up link dma data*/
|
||||
davinci_pcm_enqueue_dma(substream);
|
||||
}
|
||||
davinci_pcm_period_elapsed(substream);
|
||||
spin_unlock(&prtd->lock);
|
||||
snd_pcm_period_elapsed(substream);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GENERIC_ALLOCATOR
|
||||
static int allocate_sram(struct snd_pcm_substream *substream,
|
||||
struct gen_pool *sram_pool, unsigned size,
|
||||
struct snd_pcm_hardware *ppcm)
|
||||
{
|
||||
struct snd_dma_buffer *buf = &substream->dma_buffer;
|
||||
struct snd_dma_buffer *iram_dma = NULL;
|
||||
dma_addr_t iram_phys = 0;
|
||||
void *iram_virt = NULL;
|
||||
|
||||
if (buf->private_data || !size)
|
||||
return 0;
|
||||
|
||||
ppcm->period_bytes_max = size;
|
||||
iram_virt = gen_pool_dma_alloc(sram_pool, size, &iram_phys);
|
||||
if (!iram_virt)
|
||||
goto exit1;
|
||||
iram_dma = kzalloc(sizeof(*iram_dma), GFP_KERNEL);
|
||||
if (!iram_dma)
|
||||
goto exit2;
|
||||
iram_dma->area = iram_virt;
|
||||
iram_dma->addr = iram_phys;
|
||||
memset(iram_dma->area, 0, size);
|
||||
iram_dma->bytes = size;
|
||||
buf->private_data = iram_dma;
|
||||
return 0;
|
||||
exit2:
|
||||
if (iram_virt)
|
||||
gen_pool_free(sram_pool, (unsigned)iram_virt, size);
|
||||
exit1:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void davinci_free_sram(struct snd_pcm_substream *substream,
|
||||
struct snd_dma_buffer *iram_dma)
|
||||
{
|
||||
struct davinci_runtime_data *prtd = substream->runtime->private_data;
|
||||
struct gen_pool *sram_pool = prtd->params->sram_pool;
|
||||
|
||||
gen_pool_free(sram_pool, (unsigned) iram_dma->area, iram_dma->bytes);
|
||||
}
|
||||
#else
|
||||
static int allocate_sram(struct snd_pcm_substream *substream,
|
||||
struct gen_pool *sram_pool, unsigned size,
|
||||
struct snd_pcm_hardware *ppcm)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void davinci_free_sram(struct snd_pcm_substream *substream,
|
||||
struct snd_dma_buffer *iram_dma)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Only used with ping/pong.
|
||||
* This is called after runtime->dma_addr, period_bytes and data_type are valid
|
||||
*/
|
||||
static int ping_pong_dma_setup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
unsigned short ram_src_cidx, ram_dst_cidx;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct davinci_runtime_data *prtd = runtime->private_data;
|
||||
struct snd_dma_buffer *iram_dma =
|
||||
(struct snd_dma_buffer *)substream->dma_buffer.private_data;
|
||||
struct davinci_pcm_dma_params *params = prtd->params;
|
||||
unsigned int data_type = params->data_type;
|
||||
unsigned int acnt = params->acnt;
|
||||
/* divide by 2 for ping/pong */
|
||||
unsigned int ping_size = snd_pcm_lib_period_bytes(substream) >> 1;
|
||||
unsigned int fifo_level = prtd->params->fifo_level;
|
||||
unsigned int count;
|
||||
if ((data_type == 0) || (data_type > 4)) {
|
||||
printk(KERN_ERR "%s: data_type=%i\n", __func__, data_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
dma_addr_t asp_src_pong = iram_dma->addr + ping_size;
|
||||
ram_src_cidx = ping_size;
|
||||
ram_dst_cidx = -ping_size;
|
||||
edma_set_src(prtd->asp_link[1], asp_src_pong, INCR, W8BIT);
|
||||
|
||||
edma_set_src_index(prtd->asp_link[0], data_type,
|
||||
data_type * fifo_level);
|
||||
edma_set_src_index(prtd->asp_link[1], data_type,
|
||||
data_type * fifo_level);
|
||||
|
||||
edma_set_src(prtd->ram_link, runtime->dma_addr, INCR, W32BIT);
|
||||
} else {
|
||||
dma_addr_t asp_dst_pong = iram_dma->addr + ping_size;
|
||||
ram_src_cidx = -ping_size;
|
||||
ram_dst_cidx = ping_size;
|
||||
edma_set_dest(prtd->asp_link[1], asp_dst_pong, INCR, W8BIT);
|
||||
|
||||
edma_set_dest_index(prtd->asp_link[0], data_type,
|
||||
data_type * fifo_level);
|
||||
edma_set_dest_index(prtd->asp_link[1], data_type,
|
||||
data_type * fifo_level);
|
||||
|
||||
edma_set_dest(prtd->ram_link, runtime->dma_addr, INCR, W32BIT);
|
||||
}
|
||||
|
||||
if (!fifo_level) {
|
||||
count = ping_size / data_type;
|
||||
edma_set_transfer_params(prtd->asp_link[0], acnt, count,
|
||||
1, 0, ASYNC);
|
||||
edma_set_transfer_params(prtd->asp_link[1], acnt, count,
|
||||
1, 0, ASYNC);
|
||||
} else {
|
||||
count = ping_size / (data_type * fifo_level);
|
||||
edma_set_transfer_params(prtd->asp_link[0], acnt, fifo_level,
|
||||
count, fifo_level, ABSYNC);
|
||||
edma_set_transfer_params(prtd->asp_link[1], acnt, fifo_level,
|
||||
count, fifo_level, ABSYNC);
|
||||
}
|
||||
|
||||
edma_set_src_index(prtd->ram_link, ping_size, ram_src_cidx);
|
||||
edma_set_dest_index(prtd->ram_link, ping_size, ram_dst_cidx);
|
||||
edma_set_transfer_params(prtd->ram_link, ping_size, 2,
|
||||
runtime->periods, 2, ASYNC);
|
||||
|
||||
/* init master params */
|
||||
edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
|
||||
edma_read_slot(prtd->ram_link, &prtd->ram_params);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
struct edmacc_param p_ram;
|
||||
/* Copy entire iram buffer before playback started */
|
||||
prtd->ram_params.a_b_cnt = (1 << 16) | (ping_size << 1);
|
||||
/* 0 dst_bidx */
|
||||
prtd->ram_params.src_dst_bidx = (ping_size << 1);
|
||||
/* 0 dst_cidx */
|
||||
prtd->ram_params.src_dst_cidx = (ping_size << 1);
|
||||
prtd->ram_params.ccnt = 1;
|
||||
|
||||
/* Skip 1st period */
|
||||
edma_read_slot(prtd->ram_link, &p_ram);
|
||||
p_ram.src += (ping_size << 1);
|
||||
p_ram.ccnt -= 1;
|
||||
edma_write_slot(prtd->ram_link2, &p_ram);
|
||||
/*
|
||||
* When 1st started, ram -> iram dma channel will fill the
|
||||
* entire iram. Then, whenever a ping/pong asp buffer finishes,
|
||||
* 1/2 iram will be filled.
|
||||
*/
|
||||
prtd->ram_params.link_bcntrld =
|
||||
EDMA_CHAN_SLOT(prtd->ram_link2) << 5;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 1 asp tx or rx channel using 2 parameter channels
|
||||
* 1 ram to/from iram channel using 1 parameter channel
|
||||
*
|
||||
* Playback
|
||||
* ram copy channel kicks off first,
|
||||
* 1st ram copy of entire iram buffer completion kicks off asp channel
|
||||
* asp tcc always kicks off ram copy of 1/2 iram buffer
|
||||
*
|
||||
* Record
|
||||
* asp channel starts, tcc kicks off ram copy
|
||||
*/
|
||||
static int request_ping_pong(struct snd_pcm_substream *substream,
|
||||
struct davinci_runtime_data *prtd,
|
||||
struct snd_dma_buffer *iram_dma)
|
||||
{
|
||||
dma_addr_t asp_src_ping;
|
||||
dma_addr_t asp_dst_ping;
|
||||
int ret;
|
||||
struct davinci_pcm_dma_params *params = prtd->params;
|
||||
|
||||
/* Request ram master channel */
|
||||
ret = prtd->ram_channel = edma_alloc_channel(EDMA_CHANNEL_ANY,
|
||||
davinci_pcm_dma_irq, substream,
|
||||
prtd->params->ram_chan_q);
|
||||
if (ret < 0)
|
||||
goto exit1;
|
||||
|
||||
/* Request ram link channel */
|
||||
ret = prtd->ram_link = edma_alloc_slot(
|
||||
EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY);
|
||||
if (ret < 0)
|
||||
goto exit2;
|
||||
|
||||
ret = prtd->asp_link[1] = edma_alloc_slot(
|
||||
EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY);
|
||||
if (ret < 0)
|
||||
goto exit3;
|
||||
|
||||
prtd->ram_link2 = -1;
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
ret = prtd->ram_link2 = edma_alloc_slot(
|
||||
EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY);
|
||||
if (ret < 0)
|
||||
goto exit4;
|
||||
}
|
||||
/* circle ping-pong buffers */
|
||||
edma_link(prtd->asp_link[0], prtd->asp_link[1]);
|
||||
edma_link(prtd->asp_link[1], prtd->asp_link[0]);
|
||||
/* circle ram buffers */
|
||||
edma_link(prtd->ram_link, prtd->ram_link);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
asp_src_ping = iram_dma->addr;
|
||||
asp_dst_ping = params->dma_addr; /* fifo */
|
||||
} else {
|
||||
asp_src_ping = params->dma_addr; /* fifo */
|
||||
asp_dst_ping = iram_dma->addr;
|
||||
}
|
||||
/* ping */
|
||||
edma_set_src(prtd->asp_link[0], asp_src_ping, INCR, W16BIT);
|
||||
edma_set_dest(prtd->asp_link[0], asp_dst_ping, INCR, W16BIT);
|
||||
edma_set_src_index(prtd->asp_link[0], 0, 0);
|
||||
edma_set_dest_index(prtd->asp_link[0], 0, 0);
|
||||
|
||||
edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
|
||||
prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f) | TCINTEN);
|
||||
prtd->asp_params.opt |= TCCHEN |
|
||||
EDMA_TCC(prtd->ram_channel & 0x3f);
|
||||
edma_write_slot(prtd->asp_link[0], &prtd->asp_params);
|
||||
|
||||
/* pong */
|
||||
edma_set_src(prtd->asp_link[1], asp_src_ping, INCR, W16BIT);
|
||||
edma_set_dest(prtd->asp_link[1], asp_dst_ping, INCR, W16BIT);
|
||||
edma_set_src_index(prtd->asp_link[1], 0, 0);
|
||||
edma_set_dest_index(prtd->asp_link[1], 0, 0);
|
||||
|
||||
edma_read_slot(prtd->asp_link[1], &prtd->asp_params);
|
||||
prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f));
|
||||
/* interrupt after every pong completion */
|
||||
prtd->asp_params.opt |= TCINTEN | TCCHEN |
|
||||
EDMA_TCC(prtd->ram_channel & 0x3f);
|
||||
edma_write_slot(prtd->asp_link[1], &prtd->asp_params);
|
||||
|
||||
/* ram */
|
||||
edma_set_src(prtd->ram_link, iram_dma->addr, INCR, W32BIT);
|
||||
edma_set_dest(prtd->ram_link, iram_dma->addr, INCR, W32BIT);
|
||||
pr_debug("%s: audio dma channels/slots in use for ram:%u %u %u,"
|
||||
"for asp:%u %u %u\n", __func__,
|
||||
prtd->ram_channel, prtd->ram_link, prtd->ram_link2,
|
||||
prtd->asp_channel, prtd->asp_link[0],
|
||||
prtd->asp_link[1]);
|
||||
return 0;
|
||||
exit4:
|
||||
edma_free_channel(prtd->asp_link[1]);
|
||||
prtd->asp_link[1] = -1;
|
||||
exit3:
|
||||
edma_free_channel(prtd->ram_link);
|
||||
prtd->ram_link = -1;
|
||||
exit2:
|
||||
edma_free_channel(prtd->ram_channel);
|
||||
prtd->ram_channel = -1;
|
||||
exit1:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_dma_buffer *iram_dma;
|
||||
struct davinci_runtime_data *prtd = substream->runtime->private_data;
|
||||
struct davinci_pcm_dma_params *params = prtd->params;
|
||||
int ret;
|
||||
|
||||
if (!params)
|
||||
return -ENODEV;
|
||||
|
||||
/* Request asp master DMA channel */
|
||||
ret = prtd->asp_channel = edma_alloc_channel(params->channel,
|
||||
davinci_pcm_dma_irq, substream,
|
||||
prtd->params->asp_chan_q);
|
||||
if (ret < 0)
|
||||
goto exit1;
|
||||
|
||||
/* Request asp link channels */
|
||||
ret = prtd->asp_link[0] = edma_alloc_slot(
|
||||
EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY);
|
||||
if (ret < 0)
|
||||
goto exit2;
|
||||
|
||||
iram_dma = (struct snd_dma_buffer *)substream->dma_buffer.private_data;
|
||||
if (iram_dma) {
|
||||
if (request_ping_pong(substream, prtd, iram_dma) == 0)
|
||||
return 0;
|
||||
printk(KERN_WARNING "%s: dma channel allocation failed,"
|
||||
"not using sram\n", __func__);
|
||||
}
|
||||
|
||||
/* Issue transfer completion IRQ when the channel completes a
|
||||
* transfer, then always reload from the same slot (by a kind
|
||||
* of loopback link). The completion IRQ handler will update
|
||||
* the reload slot with a new buffer.
|
||||
*
|
||||
* REVISIT save p_ram here after setting up everything except
|
||||
* the buffer and its length (ccnt) ... use it as a template
|
||||
* so davinci_pcm_enqueue_dma() takes less time in IRQ.
|
||||
*/
|
||||
edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
|
||||
prtd->asp_params.opt |= TCINTEN |
|
||||
EDMA_TCC(EDMA_CHAN_SLOT(prtd->asp_channel));
|
||||
prtd->asp_params.link_bcntrld = EDMA_CHAN_SLOT(prtd->asp_link[0]) << 5;
|
||||
edma_write_slot(prtd->asp_link[0], &prtd->asp_params);
|
||||
return 0;
|
||||
exit2:
|
||||
edma_free_channel(prtd->asp_channel);
|
||||
prtd->asp_channel = -1;
|
||||
exit1:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct davinci_runtime_data *prtd = substream->runtime->private_data;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock(&prtd->lock);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
edma_start(prtd->asp_channel);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
|
||||
prtd->ram_channel >= 0) {
|
||||
/* copy 1st iram buffer */
|
||||
edma_start(prtd->ram_channel);
|
||||
}
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
edma_resume(prtd->asp_channel);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
edma_pause(prtd->asp_channel);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock(&prtd->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int davinci_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct davinci_runtime_data *prtd = substream->runtime->private_data;
|
||||
|
||||
davinci_pcm_period_reset(substream);
|
||||
if (prtd->ram_channel >= 0) {
|
||||
int ret = ping_pong_dma_setup(substream);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
edma_write_slot(prtd->ram_channel, &prtd->ram_params);
|
||||
edma_write_slot(prtd->asp_channel, &prtd->asp_params);
|
||||
|
||||
print_buf_info(prtd->ram_channel, "ram_channel");
|
||||
print_buf_info(prtd->ram_link, "ram_link");
|
||||
print_buf_info(prtd->ram_link2, "ram_link2");
|
||||
print_buf_info(prtd->asp_channel, "asp_channel");
|
||||
print_buf_info(prtd->asp_link[0], "asp_link[0]");
|
||||
print_buf_info(prtd->asp_link[1], "asp_link[1]");
|
||||
|
||||
/*
|
||||
* There is a phase offset of 2 periods between the position
|
||||
* used by dma setup and the position reported in the pointer
|
||||
* function.
|
||||
*
|
||||
* The phase offset, when not using ping-pong buffers, is due to
|
||||
* the two consecutive calls to davinci_pcm_enqueue_dma() below.
|
||||
*
|
||||
* Whereas here, with ping-pong buffers, the phase is due to
|
||||
* there being an entire buffer transfer complete before the
|
||||
* first dma completion event triggers davinci_pcm_dma_irq().
|
||||
*/
|
||||
davinci_pcm_period_elapsed(substream);
|
||||
davinci_pcm_period_elapsed(substream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
davinci_pcm_enqueue_dma(substream);
|
||||
davinci_pcm_period_elapsed(substream);
|
||||
|
||||
/* Copy self-linked parameter RAM entry into master channel */
|
||||
edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
|
||||
edma_write_slot(prtd->asp_channel, &prtd->asp_params);
|
||||
davinci_pcm_enqueue_dma(substream);
|
||||
davinci_pcm_period_elapsed(substream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t
|
||||
davinci_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct davinci_runtime_data *prtd = runtime->private_data;
|
||||
unsigned int offset;
|
||||
int asp_count;
|
||||
unsigned int period_size = snd_pcm_lib_period_bytes(substream);
|
||||
|
||||
/*
|
||||
* There is a phase offset of 2 periods between the position used by dma
|
||||
* setup and the position reported in the pointer function. Either +2 in
|
||||
* the dma setup or -2 here in the pointer function (with wrapping,
|
||||
* both) accounts for this offset -- choose the latter since it makes
|
||||
* the first-time setup clearer.
|
||||
*/
|
||||
spin_lock(&prtd->lock);
|
||||
asp_count = prtd->period - 2;
|
||||
spin_unlock(&prtd->lock);
|
||||
|
||||
if (asp_count < 0)
|
||||
asp_count += runtime->periods;
|
||||
asp_count *= period_size;
|
||||
|
||||
offset = bytes_to_frames(runtime, asp_count);
|
||||
if (offset >= runtime->buffer_size)
|
||||
offset = 0;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int davinci_pcm_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct davinci_runtime_data *prtd;
|
||||
struct snd_pcm_hardware *ppcm;
|
||||
int ret = 0;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct davinci_pcm_dma_params *pa;
|
||||
struct davinci_pcm_dma_params *params;
|
||||
|
||||
pa = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
if (!pa)
|
||||
return -ENODEV;
|
||||
params = &pa[substream->stream];
|
||||
|
||||
ppcm = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
|
||||
&pcm_hardware_playback : &pcm_hardware_capture;
|
||||
allocate_sram(substream, params->sram_pool, params->sram_size, ppcm);
|
||||
snd_soc_set_runtime_hwparams(substream, ppcm);
|
||||
/* ensure that buffer size is a multiple of period size */
|
||||
ret = snd_pcm_hw_constraint_integer(runtime,
|
||||
SNDRV_PCM_HW_PARAM_PERIODS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
prtd = kzalloc(sizeof(struct davinci_runtime_data), GFP_KERNEL);
|
||||
if (prtd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&prtd->lock);
|
||||
prtd->params = params;
|
||||
prtd->asp_channel = -1;
|
||||
prtd->asp_link[0] = prtd->asp_link[1] = -1;
|
||||
prtd->ram_channel = -1;
|
||||
prtd->ram_link = -1;
|
||||
prtd->ram_link2 = -1;
|
||||
|
||||
runtime->private_data = prtd;
|
||||
|
||||
ret = davinci_pcm_dma_request(substream);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "davinci_pcm: Failed to get dma channels\n");
|
||||
kfree(prtd);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int davinci_pcm_close(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct davinci_runtime_data *prtd = runtime->private_data;
|
||||
|
||||
if (prtd->ram_channel >= 0)
|
||||
edma_stop(prtd->ram_channel);
|
||||
if (prtd->asp_channel >= 0)
|
||||
edma_stop(prtd->asp_channel);
|
||||
if (prtd->asp_link[0] >= 0)
|
||||
edma_unlink(prtd->asp_link[0]);
|
||||
if (prtd->asp_link[1] >= 0)
|
||||
edma_unlink(prtd->asp_link[1]);
|
||||
if (prtd->ram_link >= 0)
|
||||
edma_unlink(prtd->ram_link);
|
||||
|
||||
if (prtd->asp_link[0] >= 0)
|
||||
edma_free_slot(prtd->asp_link[0]);
|
||||
if (prtd->asp_link[1] >= 0)
|
||||
edma_free_slot(prtd->asp_link[1]);
|
||||
if (prtd->asp_channel >= 0)
|
||||
edma_free_channel(prtd->asp_channel);
|
||||
if (prtd->ram_link >= 0)
|
||||
edma_free_slot(prtd->ram_link);
|
||||
if (prtd->ram_link2 >= 0)
|
||||
edma_free_slot(prtd->ram_link2);
|
||||
if (prtd->ram_channel >= 0)
|
||||
edma_free_channel(prtd->ram_channel);
|
||||
|
||||
kfree(prtd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int davinci_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
{
|
||||
return snd_pcm_lib_malloc_pages(substream,
|
||||
params_buffer_bytes(hw_params));
|
||||
}
|
||||
|
||||
static int davinci_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_pcm_lib_free_pages(substream);
|
||||
}
|
||||
|
||||
static int davinci_pcm_mmap(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
||||
return dma_mmap_writecombine(substream->pcm->card->dev, vma,
|
||||
runtime->dma_area,
|
||||
runtime->dma_addr,
|
||||
runtime->dma_bytes);
|
||||
}
|
||||
|
||||
static struct snd_pcm_ops davinci_pcm_ops = {
|
||||
.open = davinci_pcm_open,
|
||||
.close = davinci_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = davinci_pcm_hw_params,
|
||||
.hw_free = davinci_pcm_hw_free,
|
||||
.prepare = davinci_pcm_prepare,
|
||||
.trigger = davinci_pcm_trigger,
|
||||
.pointer = davinci_pcm_pointer,
|
||||
.mmap = davinci_pcm_mmap,
|
||||
};
|
||||
|
||||
static int davinci_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream,
|
||||
size_t size)
|
||||
{
|
||||
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
|
||||
struct snd_dma_buffer *buf = &substream->dma_buffer;
|
||||
|
||||
buf->dev.type = SNDRV_DMA_TYPE_DEV;
|
||||
buf->dev.dev = pcm->card->dev;
|
||||
buf->private_data = NULL;
|
||||
buf->area = dma_alloc_writecombine(pcm->card->dev, size,
|
||||
&buf->addr, GFP_KERNEL);
|
||||
|
||||
pr_debug("davinci_pcm: preallocate_dma_buffer: area=%p, addr=%p, "
|
||||
"size=%d\n", (void *) buf->area, (void *) buf->addr, size);
|
||||
|
||||
if (!buf->area)
|
||||
return -ENOMEM;
|
||||
|
||||
buf->bytes = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void davinci_pcm_free(struct snd_pcm *pcm)
|
||||
{
|
||||
struct snd_pcm_substream *substream;
|
||||
struct snd_dma_buffer *buf;
|
||||
int stream;
|
||||
|
||||
for (stream = 0; stream < 2; stream++) {
|
||||
struct snd_dma_buffer *iram_dma;
|
||||
substream = pcm->streams[stream].substream;
|
||||
if (!substream)
|
||||
continue;
|
||||
|
||||
buf = &substream->dma_buffer;
|
||||
if (!buf->area)
|
||||
continue;
|
||||
|
||||
dma_free_writecombine(pcm->card->dev, buf->bytes,
|
||||
buf->area, buf->addr);
|
||||
buf->area = NULL;
|
||||
iram_dma = buf->private_data;
|
||||
if (iram_dma) {
|
||||
davinci_free_sram(substream, iram_dma);
|
||||
kfree(iram_dma);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int davinci_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_card *card = rtd->card->snd_card;
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
int ret;
|
||||
|
||||
ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
|
||||
ret = davinci_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_PLAYBACK,
|
||||
pcm_hardware_playback.buffer_bytes_max);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
|
||||
ret = davinci_pcm_preallocate_dma_buffer(pcm,
|
||||
SNDRV_PCM_STREAM_CAPTURE,
|
||||
pcm_hardware_capture.buffer_bytes_max);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_platform_driver davinci_soc_platform = {
|
||||
.ops = &davinci_pcm_ops,
|
||||
.pcm_new = davinci_pcm_new,
|
||||
.pcm_free = davinci_pcm_free,
|
||||
};
|
||||
|
||||
int davinci_soc_platform_register(struct device *dev)
|
||||
{
|
||||
return devm_snd_soc_register_platform(dev, &davinci_soc_platform);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(davinci_soc_platform_register);
|
||||
|
||||
MODULE_AUTHOR("Vladimir Barinov");
|
||||
MODULE_DESCRIPTION("TI DAVINCI PCM DMA module");
|
||||
MODULE_LICENSE("GPL");
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* ALSA PCM interface for the TI DAVINCI processor
|
||||
*
|
||||
* Author: Vladimir Barinov, <vbarinov@embeddedalley.com>
|
||||
* Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.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 _DAVINCI_PCM_H
|
||||
#define _DAVINCI_PCM_H
|
||||
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/platform_data/davinci_asp.h>
|
||||
#include <linux/platform_data/edma.h>
|
||||
|
||||
struct davinci_pcm_dma_params {
|
||||
int channel; /* sync dma channel ID */
|
||||
unsigned short acnt;
|
||||
dma_addr_t dma_addr; /* device physical address for DMA */
|
||||
unsigned sram_size;
|
||||
struct gen_pool *sram_pool; /* SRAM gen_pool for ping pong */
|
||||
enum dma_event_q asp_chan_q; /* event queue number for ASP channel */
|
||||
enum dma_event_q ram_chan_q; /* event queue number for RAM channel */
|
||||
unsigned char data_type; /* xfer data type */
|
||||
unsigned char convert_mono_stereo;
|
||||
unsigned int fifo_level;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_DAVINCI_SOC)
|
||||
int davinci_soc_platform_register(struct device *dev);
|
||||
#else
|
||||
static inline int davinci_soc_platform_register(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SND_DAVINCI_SOC */
|
||||
|
||||
#endif
|
@ -33,8 +33,9 @@
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
|
||||
#include "davinci-pcm.h"
|
||||
#include "edma-pcm.h"
|
||||
#include "davinci-i2s.h"
|
||||
|
||||
#define MOD_REG_BIT(val, mask, set) do { \
|
||||
@ -47,7 +48,8 @@
|
||||
|
||||
struct davinci_vcif_dev {
|
||||
struct davinci_vc *davinci_vc;
|
||||
struct davinci_pcm_dma_params dma_params[2];
|
||||
struct snd_dmaengine_dai_dma_data dma_data[2];
|
||||
int dma_request[2];
|
||||
};
|
||||
|
||||
static void davinci_vcif_start(struct snd_pcm_substream *substream)
|
||||
@ -93,8 +95,6 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,
|
||||
{
|
||||
struct davinci_vcif_dev *davinci_vcif_dev = snd_soc_dai_get_drvdata(dai);
|
||||
struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
|
||||
struct davinci_pcm_dma_params *dma_params =
|
||||
&davinci_vcif_dev->dma_params[substream->stream];
|
||||
u32 w;
|
||||
|
||||
/* Restart the codec before setup */
|
||||
@ -113,16 +113,12 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,
|
||||
/* Determine xfer data type */
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_U8:
|
||||
dma_params->data_type = 0;
|
||||
|
||||
MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 |
|
||||
DAVINCI_VC_CTRL_RD_UNSIGNED |
|
||||
DAVINCI_VC_CTRL_WD_BITS_8 |
|
||||
DAVINCI_VC_CTRL_WD_UNSIGNED, 1);
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S8:
|
||||
dma_params->data_type = 1;
|
||||
|
||||
MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 |
|
||||
DAVINCI_VC_CTRL_WD_BITS_8, 1);
|
||||
|
||||
@ -130,8 +126,6 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,
|
||||
DAVINCI_VC_CTRL_WD_UNSIGNED, 0);
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
dma_params->data_type = 2;
|
||||
|
||||
MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 |
|
||||
DAVINCI_VC_CTRL_RD_UNSIGNED |
|
||||
DAVINCI_VC_CTRL_WD_BITS_8 |
|
||||
@ -142,8 +136,6 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dma_params->acnt = dma_params->data_type;
|
||||
|
||||
writel(w, davinci_vc->base + DAVINCI_VC_CTRL);
|
||||
|
||||
return 0;
|
||||
@ -172,24 +164,25 @@ static int davinci_vcif_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int davinci_vcif_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct davinci_vcif_dev *dev = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
snd_soc_dai_set_dma_data(dai, substream, dev->dma_params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DAVINCI_VCIF_RATES SNDRV_PCM_RATE_8000_48000
|
||||
|
||||
static const struct snd_soc_dai_ops davinci_vcif_dai_ops = {
|
||||
.startup = davinci_vcif_startup,
|
||||
.trigger = davinci_vcif_trigger,
|
||||
.hw_params = davinci_vcif_hw_params,
|
||||
};
|
||||
|
||||
static int davinci_vcif_dai_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct davinci_vcif_dev *dev = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
|
||||
dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_driver davinci_vcif_dai = {
|
||||
.probe = davinci_vcif_dai_probe,
|
||||
.playback = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
@ -225,16 +218,16 @@ static int davinci_vcif_probe(struct platform_device *pdev)
|
||||
|
||||
/* DMA tx params */
|
||||
davinci_vcif_dev->davinci_vc = davinci_vc;
|
||||
davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].channel =
|
||||
davinci_vc->davinci_vcif.dma_tx_channel;
|
||||
davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].dma_addr =
|
||||
davinci_vc->davinci_vcif.dma_tx_addr;
|
||||
davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data =
|
||||
&davinci_vc->davinci_vcif.dma_tx_channel;
|
||||
davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
|
||||
davinci_vc->davinci_vcif.dma_tx_addr;
|
||||
|
||||
/* DMA rx params */
|
||||
davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel =
|
||||
davinci_vc->davinci_vcif.dma_rx_channel;
|
||||
davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr =
|
||||
davinci_vc->davinci_vcif.dma_rx_addr;
|
||||
davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data =
|
||||
&davinci_vc->davinci_vcif.dma_rx_channel;
|
||||
davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
|
||||
davinci_vc->davinci_vcif.dma_rx_addr;
|
||||
|
||||
dev_set_drvdata(&pdev->dev, davinci_vcif_dev);
|
||||
|
||||
@ -245,7 +238,7 @@ static int davinci_vcif_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = davinci_soc_platform_register(&pdev->dev);
|
||||
ret = edma_pcm_platform_register(&pdev->dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
@ -512,6 +512,12 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
|
||||
memcpy(priv->dai_link, fsl_asoc_card_dai,
|
||||
sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link));
|
||||
|
||||
ret = snd_soc_of_parse_audio_routing(&priv->card, "audio-routing");
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret);
|
||||
goto asrc_fail;
|
||||
}
|
||||
|
||||
/* Normal DAI Link */
|
||||
priv->dai_link[0].cpu_of_node = cpu_np;
|
||||
priv->dai_link[0].codec_of_node = codec_np;
|
||||
|
@ -53,9 +53,9 @@ static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd)
|
||||
|
||||
/* Headphone jack detection */
|
||||
if (gpio_is_valid(data->jack_gpio)) {
|
||||
ret = snd_soc_jack_new(rtd->codec, "Headphone",
|
||||
SND_JACK_HEADPHONE | SND_JACK_BTN_0,
|
||||
&headset_jack);
|
||||
ret = snd_soc_card_jack_new(rtd->card, "Headphone",
|
||||
SND_JACK_HEADPHONE | SND_JACK_BTN_0,
|
||||
&headset_jack, NULL, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -205,16 +205,14 @@ static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd)
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
|
||||
/* Headphone jack detection */
|
||||
snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, &hp_jack);
|
||||
snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
|
||||
hp_jack_pins);
|
||||
snd_soc_card_jack_new(rtd->card, "Headphone", SND_JACK_HEADPHONE,
|
||||
&hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
|
||||
wm8350_hp_jack_detect(codec, WM8350_JDR, &hp_jack, SND_JACK_HEADPHONE);
|
||||
|
||||
/* Microphone jack detection */
|
||||
snd_soc_jack_new(codec, "Microphone",
|
||||
SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack);
|
||||
snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
|
||||
mic_jack_pins);
|
||||
snd_soc_card_jack_new(rtd->card, "Microphone",
|
||||
SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack,
|
||||
mic_jack_pins, ARRAY_SIZE(mic_jack_pins));
|
||||
wm8350_mic_jack_detect(codec, &mic_jack, SND_JACK_MICROPHONE,
|
||||
SND_JACK_BTN_0);
|
||||
|
||||
|
@ -176,11 +176,11 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
|
||||
return ret;
|
||||
|
||||
if (gpio_is_valid(priv->gpio_hp_det)) {
|
||||
snd_soc_jack_new(codec->codec, "Headphones", SND_JACK_HEADPHONE,
|
||||
&simple_card_hp_jack);
|
||||
snd_soc_jack_add_pins(&simple_card_hp_jack,
|
||||
ARRAY_SIZE(simple_card_hp_jack_pins),
|
||||
simple_card_hp_jack_pins);
|
||||
snd_soc_card_jack_new(rtd->card, "Headphones",
|
||||
SND_JACK_HEADPHONE,
|
||||
&simple_card_hp_jack,
|
||||
simple_card_hp_jack_pins,
|
||||
ARRAY_SIZE(simple_card_hp_jack_pins));
|
||||
|
||||
simple_card_hp_jack_gpio.gpio = priv->gpio_hp_det;
|
||||
simple_card_hp_jack_gpio.invert = priv->gpio_hp_det_invert;
|
||||
@ -189,11 +189,11 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
|
||||
}
|
||||
|
||||
if (gpio_is_valid(priv->gpio_mic_det)) {
|
||||
snd_soc_jack_new(codec->codec, "Mic Jack", SND_JACK_MICROPHONE,
|
||||
&simple_card_mic_jack);
|
||||
snd_soc_jack_add_pins(&simple_card_mic_jack,
|
||||
ARRAY_SIZE(simple_card_mic_jack_pins),
|
||||
simple_card_mic_jack_pins);
|
||||
snd_soc_card_jack_new(rtd->card, "Mic Jack",
|
||||
SND_JACK_MICROPHONE,
|
||||
&simple_card_mic_jack,
|
||||
simple_card_mic_jack_pins,
|
||||
ARRAY_SIZE(simple_card_mic_jack_pins));
|
||||
simple_card_mic_jack_gpio.gpio = priv->gpio_mic_det;
|
||||
simple_card_mic_jack_gpio.invert = priv->gpio_mic_det_invert;
|
||||
snd_soc_jack_add_gpios(&simple_card_mic_jack, 1,
|
||||
|
@ -80,15 +80,9 @@ static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
int ret = 0;
|
||||
ret = snd_soc_jack_new(codec, "Headset",
|
||||
SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_jack_add_pins(&broadwell_headset,
|
||||
ARRAY_SIZE(broadwell_headset_pins),
|
||||
broadwell_headset_pins);
|
||||
ret = snd_soc_card_jack_new(rtd->card, "Headset",
|
||||
SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset,
|
||||
broadwell_headset_pins, ARRAY_SIZE(broadwell_headset_pins));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -110,9 +104,7 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
channels->min = channels->max = 2;
|
||||
|
||||
/* set SSP0 to 16 bit */
|
||||
snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT -
|
||||
SNDRV_PCM_HW_PARAM_FIRST_MASK],
|
||||
SNDRV_PCM_FORMAT_S16_LE);
|
||||
params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,6 @@ static struct snd_soc_jack_gpio hs_jack_gpios[] = {
|
||||
static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime)
|
||||
{
|
||||
int ret;
|
||||
struct snd_soc_codec *codec = runtime->codec;
|
||||
struct snd_soc_card *card = runtime->card;
|
||||
struct byt_max98090_private *drv = snd_soc_card_get_drvdata(card);
|
||||
struct snd_soc_jack *jack = &drv->jack;
|
||||
@ -100,13 +99,9 @@ static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime)
|
||||
}
|
||||
|
||||
/* Enable jack detection */
|
||||
ret = snd_soc_jack_new(codec, "Headset",
|
||||
SND_JACK_LINEOUT | SND_JACK_HEADSET, jack);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_jack_add_pins(jack, ARRAY_SIZE(hs_jack_pins),
|
||||
hs_jack_pins);
|
||||
ret = snd_soc_card_jack_new(runtime->card, "Headset",
|
||||
SND_JACK_LINEOUT | SND_JACK_HEADSET, jack,
|
||||
hs_jack_pins, ARRAY_SIZE(hs_jack_pins));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -113,9 +113,7 @@ static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
channels->min = channels->max = 2;
|
||||
|
||||
/* set SSP2 to 24-bit */
|
||||
snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT -
|
||||
SNDRV_PCM_HW_PARAM_FIRST_MASK],
|
||||
SNDRV_PCM_FORMAT_S24_LE);
|
||||
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -169,17 +169,17 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_jack_new(codec, "Headphone Jack",
|
||||
SND_JACK_HEADPHONE,
|
||||
&ctx->hp_jack);
|
||||
ret = snd_soc_card_jack_new(runtime->card, "Headphone Jack",
|
||||
SND_JACK_HEADPHONE, &ctx->hp_jack,
|
||||
NULL, 0);
|
||||
if (ret) {
|
||||
dev_err(runtime->dev, "HP jack creation failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_jack_new(codec, "Mic Jack",
|
||||
SND_JACK_MICROPHONE,
|
||||
&ctx->mic_jack);
|
||||
ret = snd_soc_card_jack_new(runtime->card, "Mic Jack",
|
||||
SND_JACK_MICROPHONE, &ctx->mic_jack,
|
||||
NULL, 0);
|
||||
if (ret) {
|
||||
dev_err(runtime->dev, "Mic jack creation failed %d\n", ret);
|
||||
return ret;
|
||||
@ -203,9 +203,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
channels->min = channels->max = 2;
|
||||
|
||||
/* set SSP2 to 24-bit */
|
||||
snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT -
|
||||
SNDRV_PCM_HW_PARAM_FIRST_MASK],
|
||||
SNDRV_PCM_FORMAT_S24_LE);
|
||||
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -178,9 +178,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
channels->min = channels->max = 2;
|
||||
|
||||
/* set SSP2 to 24-bit */
|
||||
snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT -
|
||||
SNDRV_PCM_HW_PARAM_FIRST_MASK],
|
||||
SNDRV_PCM_FORMAT_S24_LE);
|
||||
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -217,7 +215,7 @@ static struct snd_soc_dai_link cht_dailink[] = {
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
.ignore_suspend = 1,
|
||||
.nonatomic = true,
|
||||
.dynamic = 1,
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
@ -240,13 +238,13 @@ static struct snd_soc_dai_link cht_dailink[] = {
|
||||
.cpu_dai_name = "ssp2-port",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
.no_pcm = 1,
|
||||
.nonatomic = true,
|
||||
.codec_dai_name = "rt5670-aif1",
|
||||
.codec_name = "i2c-10EC5670:00",
|
||||
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
|
||||
| SND_SOC_DAIFMT_CBS_CFS,
|
||||
.init = cht_codec_init,
|
||||
.be_hw_params_fixup = cht_codec_fixup,
|
||||
.ignore_suspend = 1,
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
.ops = &cht_be_ssp2_ops,
|
||||
@ -285,7 +283,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
||||
static struct platform_driver snd_cht_mc_driver = {
|
||||
.driver = {
|
||||
.name = "cht-bsw-rt5672",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = snd_cht_mc_probe,
|
||||
};
|
||||
|
@ -56,9 +56,7 @@ static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
channels->min = channels->max = 2;
|
||||
|
||||
/* set SSP0 to 16 bit */
|
||||
snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT -
|
||||
SNDRV_PCM_HW_PARAM_FIRST_MASK],
|
||||
SNDRV_PCM_FORMAT_S16_LE);
|
||||
params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -228,10 +228,13 @@ static void mfld_jack_check(unsigned int intr_status)
|
||||
{
|
||||
struct mfld_jack_data jack_data;
|
||||
|
||||
if (!mfld_codec)
|
||||
return;
|
||||
|
||||
jack_data.mfld_jack = &mfld_jack;
|
||||
jack_data.intr_id = intr_status;
|
||||
|
||||
sn95031_jack_detection(&jack_data);
|
||||
sn95031_jack_detection(mfld_codec, &jack_data);
|
||||
/* TODO: add american headset detection post gpiolib support */
|
||||
}
|
||||
|
||||
@ -240,8 +243,6 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
|
||||
struct snd_soc_dapm_context *dapm = &runtime->card->dapm;
|
||||
int ret_val;
|
||||
|
||||
mfld_codec = runtime->codec;
|
||||
|
||||
/* default is earpiece pin, userspace sets it explcitly */
|
||||
snd_soc_dapm_disable_pin(dapm, "Headphones");
|
||||
/* default is lineout NC, userspace sets it explcitly */
|
||||
@ -254,20 +255,15 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
|
||||
snd_soc_dapm_disable_pin(dapm, "LINEINR");
|
||||
|
||||
/* Headset and button jack detection */
|
||||
ret_val = snd_soc_jack_new(mfld_codec, "Intel(R) MID Audio Jack",
|
||||
SND_JACK_HEADSET | SND_JACK_BTN_0 |
|
||||
SND_JACK_BTN_1, &mfld_jack);
|
||||
ret_val = snd_soc_card_jack_new(runtime->card,
|
||||
"Intel(R) MID Audio Jack", SND_JACK_HEADSET |
|
||||
SND_JACK_BTN_0 | SND_JACK_BTN_1, &mfld_jack,
|
||||
mfld_jack_pins, ARRAY_SIZE(mfld_jack_pins));
|
||||
if (ret_val) {
|
||||
pr_err("jack creation failed\n");
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
ret_val = snd_soc_jack_add_pins(&mfld_jack,
|
||||
ARRAY_SIZE(mfld_jack_pins), mfld_jack_pins);
|
||||
if (ret_val) {
|
||||
pr_err("adding jack pins failed\n");
|
||||
return ret_val;
|
||||
}
|
||||
ret_val = snd_soc_jack_add_zones(&mfld_jack,
|
||||
ARRAY_SIZE(mfld_zones), mfld_zones);
|
||||
if (ret_val) {
|
||||
@ -275,6 +271,8 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
mfld_codec = runtime->codec;
|
||||
|
||||
/* we want to check if anything is inserted at boot,
|
||||
* so send a fake event to codec and it will read adc
|
||||
* to find if anything is there or not */
|
||||
@ -359,8 +357,6 @@ static irqreturn_t snd_mfld_jack_detection(int irq, void *data)
|
||||
{
|
||||
struct mfld_mc_private *mc_drv_ctx = (struct mfld_mc_private *) data;
|
||||
|
||||
if (mfld_jack.codec == NULL)
|
||||
return IRQ_HANDLED;
|
||||
mfld_jack_check(mc_drv_ctx->interrupt_status);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
@ -594,11 +594,13 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
|
||||
ret_val = stream->ops->stream_drop(sst->dev, str_id);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
dev_dbg(rtd->dev, "sst: in pause\n");
|
||||
status = SST_PLATFORM_PAUSED;
|
||||
ret_val = stream->ops->stream_pause(sst->dev, str_id);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
dev_dbg(rtd->dev, "sst: in pause release\n");
|
||||
status = SST_PLATFORM_RUNNING;
|
||||
ret_val = stream->ops->stream_pause_release(sst->dev, str_id);
|
||||
@ -665,6 +667,9 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
|
||||
static int sst_soc_probe(struct snd_soc_platform *platform)
|
||||
{
|
||||
struct sst_data *drv = dev_get_drvdata(platform->dev);
|
||||
|
||||
drv->soc_card = platform->component.card;
|
||||
return sst_dsp_init_v2_dpcm(platform);
|
||||
}
|
||||
|
||||
@ -727,9 +732,64 @@ static int sst_platform_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static int sst_soc_prepare(struct device *dev)
|
||||
{
|
||||
struct sst_data *drv = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
/* suspend all pcms first */
|
||||
snd_soc_suspend(drv->soc_card->dev);
|
||||
snd_soc_poweroff(drv->soc_card->dev);
|
||||
|
||||
/* set the SSPs to idle */
|
||||
for (i = 0; i < drv->soc_card->num_rtd; i++) {
|
||||
struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai;
|
||||
|
||||
if (dai->active) {
|
||||
send_ssp_cmd(dai, dai->name, 0);
|
||||
sst_handle_vb_timer(dai, false);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sst_soc_complete(struct device *dev)
|
||||
{
|
||||
struct sst_data *drv = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
/* restart SSPs */
|
||||
for (i = 0; i < drv->soc_card->num_rtd; i++) {
|
||||
struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai;
|
||||
|
||||
if (dai->active) {
|
||||
sst_handle_vb_timer(dai, true);
|
||||
send_ssp_cmd(dai, dai->name, 1);
|
||||
}
|
||||
}
|
||||
snd_soc_resume(drv->soc_card->dev);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define sst_soc_prepare NULL
|
||||
#define sst_soc_complete NULL
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static const struct dev_pm_ops sst_platform_pm = {
|
||||
.prepare = sst_soc_prepare,
|
||||
.complete = sst_soc_complete,
|
||||
};
|
||||
|
||||
static struct platform_driver sst_platform_driver = {
|
||||
.driver = {
|
||||
.name = "sst-mfld-platform",
|
||||
.pm = &sst_platform_pm,
|
||||
},
|
||||
.probe = sst_platform_probe,
|
||||
.remove = sst_platform_remove,
|
||||
|
@ -174,6 +174,7 @@ struct sst_data {
|
||||
struct sst_platform_data *pdata;
|
||||
struct snd_sst_bytes_v2 *byte_stream;
|
||||
struct mutex lock;
|
||||
struct snd_soc_card *soc_card;
|
||||
};
|
||||
int sst_register_dsp(struct sst_device *sst);
|
||||
int sst_unregister_dsp(struct sst_device *sst);
|
||||
|
@ -423,23 +423,135 @@ static int intel_sst_runtime_suspend(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int intel_sst_runtime_resume(struct device *dev)
|
||||
static int intel_sst_suspend(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
|
||||
struct sst_fw_save *fw_save;
|
||||
int i, ret = 0;
|
||||
|
||||
if (ctx->sst_state == SST_RESET) {
|
||||
ret = sst_load_fw(ctx);
|
||||
if (ret) {
|
||||
dev_err(dev, "FW download fail %d\n", ret);
|
||||
sst_set_fw_state_locked(ctx, SST_RESET);
|
||||
/* check first if we are already in SW reset */
|
||||
if (ctx->sst_state == SST_RESET)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* check if any stream is active and running
|
||||
* they should already by suspend by soc_suspend
|
||||
*/
|
||||
for (i = 1; i <= ctx->info.max_streams; i++) {
|
||||
struct stream_info *stream = &ctx->streams[i];
|
||||
|
||||
if (stream->status == STREAM_RUNNING) {
|
||||
dev_err(dev, "stream %d is running, cant susupend, abort\n", i);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
synchronize_irq(ctx->irq_num);
|
||||
flush_workqueue(ctx->post_msg_wq);
|
||||
|
||||
/* Move the SST state to Reset */
|
||||
sst_set_fw_state_locked(ctx, SST_RESET);
|
||||
|
||||
/* tell DSP we are suspending */
|
||||
if (ctx->ops->save_dsp_context(ctx))
|
||||
return -EBUSY;
|
||||
|
||||
/* save the memories */
|
||||
fw_save = kzalloc(sizeof(*fw_save), GFP_KERNEL);
|
||||
if (!fw_save)
|
||||
return -ENOMEM;
|
||||
fw_save->iram = kzalloc(ctx->iram_end - ctx->iram_base, GFP_KERNEL);
|
||||
if (!fw_save->iram) {
|
||||
ret = -ENOMEM;
|
||||
goto iram;
|
||||
}
|
||||
fw_save->dram = kzalloc(ctx->dram_end - ctx->dram_base, GFP_KERNEL);
|
||||
if (!fw_save->dram) {
|
||||
ret = -ENOMEM;
|
||||
goto dram;
|
||||
}
|
||||
fw_save->sram = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL);
|
||||
if (!fw_save->sram) {
|
||||
ret = -ENOMEM;
|
||||
goto sram;
|
||||
}
|
||||
|
||||
fw_save->ddr = kzalloc(ctx->ddr_end - ctx->ddr_base, GFP_KERNEL);
|
||||
if (!fw_save->ddr) {
|
||||
ret = -ENOMEM;
|
||||
goto ddr;
|
||||
}
|
||||
|
||||
memcpy32_fromio(fw_save->iram, ctx->iram, ctx->iram_end - ctx->iram_base);
|
||||
memcpy32_fromio(fw_save->dram, ctx->dram, ctx->dram_end - ctx->dram_base);
|
||||
memcpy32_fromio(fw_save->sram, ctx->mailbox, SST_MAILBOX_SIZE);
|
||||
memcpy32_fromio(fw_save->ddr, ctx->ddr, ctx->ddr_end - ctx->ddr_base);
|
||||
|
||||
ctx->fw_save = fw_save;
|
||||
ctx->ops->reset(ctx);
|
||||
return 0;
|
||||
ddr:
|
||||
kfree(fw_save->sram);
|
||||
sram:
|
||||
kfree(fw_save->dram);
|
||||
dram:
|
||||
kfree(fw_save->iram);
|
||||
iram:
|
||||
kfree(fw_save);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int intel_sst_resume(struct device *dev)
|
||||
{
|
||||
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
|
||||
struct sst_fw_save *fw_save = ctx->fw_save;
|
||||
int ret = 0;
|
||||
struct sst_block *block;
|
||||
|
||||
if (!fw_save)
|
||||
return 0;
|
||||
|
||||
sst_set_fw_state_locked(ctx, SST_FW_LOADING);
|
||||
|
||||
/* we have to restore the memory saved */
|
||||
ctx->ops->reset(ctx);
|
||||
|
||||
ctx->fw_save = NULL;
|
||||
|
||||
memcpy32_toio(ctx->iram, fw_save->iram, ctx->iram_end - ctx->iram_base);
|
||||
memcpy32_toio(ctx->dram, fw_save->dram, ctx->dram_end - ctx->dram_base);
|
||||
memcpy32_toio(ctx->mailbox, fw_save->sram, SST_MAILBOX_SIZE);
|
||||
memcpy32_toio(ctx->ddr, fw_save->ddr, ctx->ddr_end - ctx->ddr_base);
|
||||
|
||||
kfree(fw_save->sram);
|
||||
kfree(fw_save->dram);
|
||||
kfree(fw_save->iram);
|
||||
kfree(fw_save->ddr);
|
||||
kfree(fw_save);
|
||||
|
||||
block = sst_create_block(ctx, 0, FW_DWNL_ID);
|
||||
if (block == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
/* start and wait for ack */
|
||||
ctx->ops->start(ctx);
|
||||
ret = sst_wait_timeout(ctx, block);
|
||||
if (ret) {
|
||||
dev_err(ctx->dev, "fw download failed %d\n", ret);
|
||||
/* FW download failed due to timeout */
|
||||
ret = -EBUSY;
|
||||
|
||||
} else {
|
||||
sst_set_fw_state_locked(ctx, SST_FW_RUNNING);
|
||||
}
|
||||
|
||||
sst_free_block(ctx, block);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct dev_pm_ops intel_sst_pm = {
|
||||
.suspend = intel_sst_suspend,
|
||||
.resume = intel_sst_resume,
|
||||
.runtime_suspend = intel_sst_runtime_suspend,
|
||||
.runtime_resume = intel_sst_runtime_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(intel_sst_pm);
|
||||
|
@ -337,6 +337,13 @@ struct sst_shim_regs64 {
|
||||
u64 csr2;
|
||||
};
|
||||
|
||||
struct sst_fw_save {
|
||||
void *iram;
|
||||
void *dram;
|
||||
void *sram;
|
||||
void *ddr;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct intel_sst_drv - driver ops
|
||||
*
|
||||
@ -428,6 +435,8 @@ struct intel_sst_drv {
|
||||
* persistent till worker thread gets called
|
||||
*/
|
||||
char firmware_name[FW_NAME_SIZE];
|
||||
|
||||
struct sst_fw_save *fw_save;
|
||||
};
|
||||
|
||||
/* misc definitions */
|
||||
@ -544,4 +553,7 @@ int sst_alloc_drv_context(struct intel_sst_drv **ctx,
|
||||
int sst_context_init(struct intel_sst_drv *ctx);
|
||||
void sst_context_cleanup(struct intel_sst_drv *ctx);
|
||||
void sst_configure_runtime_pm(struct intel_sst_drv *ctx);
|
||||
void memcpy32_toio(void __iomem *dst, const void *src, int count);
|
||||
void memcpy32_fromio(void *dst, const void __iomem *src, int count);
|
||||
|
||||
#endif
|
||||
|
@ -138,12 +138,36 @@ int sst_get_stream(struct intel_sst_drv *ctx,
|
||||
static int sst_power_control(struct device *dev, bool state)
|
||||
{
|
||||
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
int usage_count = 0;
|
||||
|
||||
dev_dbg(ctx->dev, "state:%d", state);
|
||||
if (state == true)
|
||||
return pm_runtime_get_sync(dev);
|
||||
else
|
||||
#ifdef CONFIG_PM
|
||||
usage_count = atomic_read(&dev->power.usage_count);
|
||||
#else
|
||||
usage_count = 1;
|
||||
#endif
|
||||
|
||||
if (state == true) {
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
|
||||
dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Runtime get failed with err: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if ((ctx->sst_state == SST_RESET) && (usage_count == 1)) {
|
||||
ret = sst_load_fw(ctx);
|
||||
if (ret) {
|
||||
dev_err(dev, "FW download fail %d\n", ret);
|
||||
sst_set_fw_state_locked(ctx, SST_RESET);
|
||||
ret = sst_pm_runtime_put(ctx);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dev_dbg(ctx->dev, "Disable: pm usage count: %d\n", usage_count);
|
||||
return sst_pm_runtime_put(ctx);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -572,6 +596,35 @@ static int sst_stream_drop(struct device *dev, int str_id)
|
||||
return sst_drop_stream(ctx, str_id);
|
||||
}
|
||||
|
||||
static int sst_stream_pause(struct device *dev, int str_id)
|
||||
{
|
||||
struct stream_info *str_info;
|
||||
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
|
||||
|
||||
if (ctx->sst_state != SST_FW_RUNNING)
|
||||
return 0;
|
||||
|
||||
str_info = get_stream_info(ctx, str_id);
|
||||
if (!str_info)
|
||||
return -EINVAL;
|
||||
|
||||
return sst_pause_stream(ctx, str_id);
|
||||
}
|
||||
|
||||
static int sst_stream_resume(struct device *dev, int str_id)
|
||||
{
|
||||
struct stream_info *str_info;
|
||||
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
|
||||
|
||||
if (ctx->sst_state != SST_FW_RUNNING)
|
||||
return 0;
|
||||
|
||||
str_info = get_stream_info(ctx, str_id);
|
||||
if (!str_info)
|
||||
return -EINVAL;
|
||||
return sst_resume_stream(ctx, str_id);
|
||||
}
|
||||
|
||||
static int sst_stream_init(struct device *dev, struct pcm_stream_info *str_info)
|
||||
{
|
||||
int str_id = 0;
|
||||
@ -633,6 +686,8 @@ static struct sst_ops pcm_ops = {
|
||||
.stream_init = sst_stream_init,
|
||||
.stream_start = sst_stream_start,
|
||||
.stream_drop = sst_stream_drop,
|
||||
.stream_pause = sst_stream_pause,
|
||||
.stream_pause_release = sst_stream_resume,
|
||||
.stream_read_tstamp = sst_read_timestamp,
|
||||
.send_byte_stream = sst_send_byte_stream,
|
||||
.close = sst_close_pcm_stream,
|
||||
|
@ -39,7 +39,15 @@
|
||||
#include "sst.h"
|
||||
#include "../sst-dsp.h"
|
||||
|
||||
static inline void memcpy32_toio(void __iomem *dst, const void *src, int count)
|
||||
void memcpy32_toio(void __iomem *dst, const void *src, int count)
|
||||
{
|
||||
/* __iowrite32_copy uses 32-bit count values so divide by 4 for
|
||||
* right count in words
|
||||
*/
|
||||
__iowrite32_copy(dst, src, count/4);
|
||||
}
|
||||
|
||||
void memcpy32_fromio(void *dst, const void __iomem *src, int count)
|
||||
{
|
||||
/* __iowrite32_copy uses 32-bit count values so divide by 4 for
|
||||
* right count in words
|
||||
|
@ -100,17 +100,19 @@ config SND_OMAP_SOC_OMAP_TWL4030
|
||||
|
||||
config SND_OMAP_SOC_OMAP_ABE_TWL6040
|
||||
tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
|
||||
depends on TWL6040_CORE && SND_OMAP_SOC && (ARCH_OMAP4 || COMPILE_TEST)
|
||||
depends on TWL6040_CORE && SND_OMAP_SOC && (ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST)
|
||||
select SND_OMAP_SOC_DMIC
|
||||
select SND_OMAP_SOC_MCPDM
|
||||
select SND_SOC_TWL6040
|
||||
select SND_SOC_DMIC
|
||||
select COMMON_CLK_PALMAS if SOC_OMAP5
|
||||
help
|
||||
Say Y if you want to add support for SoC audio on OMAP boards using
|
||||
ABE and twl6040 codec. This driver currently supports:
|
||||
- SDP4430/Blaze boards
|
||||
- PandaBoard (4430)
|
||||
- PandaBoardES (4460)
|
||||
- omap5-uevm (5432)
|
||||
|
||||
config SND_OMAP_SOC_OMAP3_PANDORA
|
||||
tristate "SoC Audio support for OMAP3 Pandora"
|
||||
|
@ -479,8 +479,8 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
|
||||
|
||||
/* Add hook switch - can be used to control the codec from userspace
|
||||
* even if line discipline fails */
|
||||
ret = snd_soc_jack_new(rtd->codec, "hook_switch",
|
||||
SND_JACK_HEADSET, &ams_delta_hook_switch);
|
||||
ret = snd_soc_card_jack_new(card, "hook_switch", SND_JACK_HEADSET,
|
||||
&ams_delta_hook_switch, NULL, 0);
|
||||
if (ret)
|
||||
dev_warn(card->dev,
|
||||
"Failed to allocate resources for hook switch, "
|
||||
|
@ -182,17 +182,17 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
|
||||
|
||||
/* Headset jack detection only if it is supported */
|
||||
if (priv->jack_detection) {
|
||||
ret = snd_soc_jack_new(codec, "Headset Jack",
|
||||
SND_JACK_HEADSET, &hs_jack);
|
||||
ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
|
||||
SND_JACK_HEADSET, &hs_jack,
|
||||
hs_jack_pins,
|
||||
ARRAY_SIZE(hs_jack_pins));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
|
||||
hs_jack_pins);
|
||||
twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_route dmic_audio_map[] = {
|
||||
|
@ -39,7 +39,7 @@
|
||||
#define pcm_omap1510() 0
|
||||
#endif
|
||||
|
||||
static const struct snd_pcm_hardware omap_pcm_hardware = {
|
||||
static struct snd_pcm_hardware omap_pcm_hardware = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
@ -53,6 +53,24 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
|
||||
.buffer_bytes_max = 128 * 1024,
|
||||
};
|
||||
|
||||
/* sDMA supports only 1, 2, and 4 byte transfer elements. */
|
||||
static void omap_pcm_limit_supported_formats(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) {
|
||||
switch (snd_pcm_format_physical_width(i)) {
|
||||
case 8:
|
||||
case 16:
|
||||
case 32:
|
||||
omap_pcm_hardware.formats |= (1LL << i);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* this may get called several times by oss emulation */
|
||||
static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
@ -235,6 +253,7 @@ static struct snd_soc_platform_driver omap_soc_platform = {
|
||||
|
||||
int omap_pcm_platform_register(struct device *dev)
|
||||
{
|
||||
omap_pcm_limit_supported_formats();
|
||||
return devm_snd_soc_register_platform(dev, &omap_soc_platform);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_pcm_platform_register);
|
||||
|
@ -170,14 +170,10 @@ static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd)
|
||||
if (priv->jack_detect > 0) {
|
||||
hs_jack_gpios[0].gpio = priv->jack_detect;
|
||||
|
||||
ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
|
||||
&priv->hs_jack);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_jack_add_pins(&priv->hs_jack,
|
||||
ARRAY_SIZE(hs_jack_pins),
|
||||
hs_jack_pins);
|
||||
ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
|
||||
SND_JACK_HEADSET, &priv->hs_jack,
|
||||
hs_jack_pins,
|
||||
ARRAY_SIZE(hs_jack_pins));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -311,9 +311,9 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
|
||||
}
|
||||
|
||||
/* AV jack detection */
|
||||
err = snd_soc_jack_new(codec, "AV Jack",
|
||||
SND_JACK_HEADSET | SND_JACK_VIDEOOUT,
|
||||
&rx51_av_jack);
|
||||
err = snd_soc_card_jack_new(rtd->card, "AV Jack",
|
||||
SND_JACK_HEADSET | SND_JACK_VIDEOOUT,
|
||||
&rx51_av_jack, NULL, 0);
|
||||
if (err) {
|
||||
dev_err(card->dev, "Failed to add AV Jack\n");
|
||||
return err;
|
||||
|
@ -126,17 +126,12 @@ static const struct snd_soc_dapm_route hx4700_audio_map[] = {
|
||||
*/
|
||||
static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
int err;
|
||||
|
||||
/* Jack detection API stuff */
|
||||
err = snd_soc_jack_new(codec, "Headphone Jack",
|
||||
SND_JACK_HEADPHONE, &hs_jack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pin),
|
||||
hs_jack_pin);
|
||||
err = snd_soc_card_jack_new(rtd->card, "Headphone Jack",
|
||||
SND_JACK_HEADPHONE, &hs_jack, hs_jack_pin,
|
||||
ARRAY_SIZE(hs_jack_pin));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -75,17 +75,12 @@ static struct snd_soc_card palm27x_asoc;
|
||||
|
||||
static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
int err;
|
||||
|
||||
/* Jack detection API stuff */
|
||||
err = snd_soc_jack_new(codec, "Headphone Jack",
|
||||
SND_JACK_HEADPHONE, &hs_jack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
|
||||
hs_jack_pins);
|
||||
err = snd_soc_card_jack_new(rtd->card, "Headphone Jack",
|
||||
SND_JACK_HEADPHONE, &hs_jack, hs_jack_pins,
|
||||
ARRAY_SIZE(hs_jack_pins));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -78,15 +78,12 @@ static int ttc_pm860x_init(struct snd_soc_pcm_runtime *rtd)
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
|
||||
/* 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);
|
||||
snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE |
|
||||
SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
|
||||
&hs_jack, hs_jack_pins, ARRAY_SIZE(hs_jack_pins));
|
||||
snd_soc_card_jack_new(rtd->card, "Microphone Jack", SND_JACK_MICROPHONE,
|
||||
&mic_jack, mic_jack_pins,
|
||||
ARRAY_SIZE(mic_jack_pins));
|
||||
|
||||
/* headphone, microphone detection & headset short detection */
|
||||
pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
|
||||
|
@ -143,13 +143,9 @@ static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd)
|
||||
snd_soc_dapm_disable_pin(dapm, "MONO1");
|
||||
|
||||
/* Jack detection API stuff */
|
||||
ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
|
||||
&hs_jack);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
|
||||
hs_jack_pins);
|
||||
ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET,
|
||||
&hs_jack, hs_jack_pins,
|
||||
ARRAY_SIZE(hs_jack_pins));
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
|
@ -162,13 +162,8 @@ static struct platform_device *s3c24xx_snd_device;
|
||||
|
||||
static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
|
||||
snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
|
||||
&hp_jack);
|
||||
|
||||
snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
|
||||
hp_jack_pins);
|
||||
snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE,
|
||||
&hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
|
||||
|
||||
snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
|
||||
hp_jack_gpios);
|
||||
|
@ -260,12 +260,12 @@ static int littlemill_late_probe(struct snd_soc_card *card)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_jack_new(codec, "Headset",
|
||||
SND_JACK_HEADSET | SND_JACK_MECHANICAL |
|
||||
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
|
||||
SND_JACK_BTN_2 | SND_JACK_BTN_3 |
|
||||
SND_JACK_BTN_4 | SND_JACK_BTN_5,
|
||||
&littlemill_headset);
|
||||
ret = snd_soc_card_jack_new(card, "Headset",
|
||||
SND_JACK_HEADSET | SND_JACK_MECHANICAL |
|
||||
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
|
||||
SND_JACK_BTN_2 | SND_JACK_BTN_3 |
|
||||
SND_JACK_BTN_4 | SND_JACK_BTN_5,
|
||||
&littlemill_headset, NULL, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -56,16 +56,10 @@ static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_jack_new(codec, "Headset",
|
||||
SND_JACK_LINEOUT | SND_JACK_HEADSET |
|
||||
SND_JACK_BTN_0,
|
||||
&lowland_headset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_jack_add_pins(&lowland_headset,
|
||||
ARRAY_SIZE(lowland_headset_pins),
|
||||
lowland_headset_pins);
|
||||
ret = snd_soc_card_jack_new(rtd->card, "Headset", SND_JACK_LINEOUT |
|
||||
SND_JACK_HEADSET | SND_JACK_BTN_0,
|
||||
&lowland_headset, lowland_headset_pins,
|
||||
ARRAY_SIZE(lowland_headset_pins));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -211,13 +211,8 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream,
|
||||
|
||||
static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
|
||||
snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
|
||||
&hp_jack);
|
||||
|
||||
snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
|
||||
hp_jack_pins);
|
||||
snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE,
|
||||
&hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
|
||||
|
||||
snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
|
||||
hp_jack_gpios);
|
||||
|
@ -151,13 +151,10 @@ static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd)
|
||||
snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
|
||||
|
||||
/* Headphone jack detection */
|
||||
err = snd_soc_jack_new(codec, "Headphone Jack",
|
||||
SND_JACK_HEADPHONE, &smartq_jack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = snd_soc_jack_add_pins(&smartq_jack, ARRAY_SIZE(smartq_jack_pins),
|
||||
smartq_jack_pins);
|
||||
err = snd_soc_card_jack_new(rtd->card, "Headphone Jack",
|
||||
SND_JACK_HEADPHONE, &smartq_jack,
|
||||
smartq_jack_pins,
|
||||
ARRAY_SIZE(smartq_jack_pins));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -153,16 +153,10 @@ static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd)
|
||||
pr_err("Failed to request HP_SEL GPIO: %d\n", ret);
|
||||
gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity);
|
||||
|
||||
ret = snd_soc_jack_new(codec, "Headset",
|
||||
SND_JACK_LINEOUT | SND_JACK_HEADSET |
|
||||
SND_JACK_BTN_0,
|
||||
&speyside_headset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_jack_add_pins(&speyside_headset,
|
||||
ARRAY_SIZE(speyside_headset_pins),
|
||||
speyside_headset_pins);
|
||||
ret = snd_soc_card_jack_new(rtd->card, "Headset", SND_JACK_LINEOUT |
|
||||
SND_JACK_HEADSET | SND_JACK_BTN_0,
|
||||
&speyside_headset, speyside_headset_pins,
|
||||
ARRAY_SIZE(speyside_headset_pins));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -179,15 +179,10 @@ static int tobermory_late_probe(struct snd_soc_card *card)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_jack_new(codec, "Headset",
|
||||
SND_JACK_HEADSET | SND_JACK_BTN_0,
|
||||
&tobermory_headset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_jack_add_pins(&tobermory_headset,
|
||||
ARRAY_SIZE(tobermory_headset_pins),
|
||||
tobermory_headset_pins);
|
||||
ret = snd_soc_card_jack_new(card, "Headset", SND_JACK_HEADSET |
|
||||
SND_JACK_BTN_0, &tobermory_headset,
|
||||
tobermory_headset_pins,
|
||||
ARRAY_SIZE(tobermory_headset_pins));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1578,6 +1578,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
|
||||
snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
|
||||
card->num_dapm_widgets);
|
||||
|
||||
if (card->of_dapm_widgets)
|
||||
snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets,
|
||||
card->num_of_dapm_widgets);
|
||||
|
||||
/* initialise the sound card only once */
|
||||
if (card->probe) {
|
||||
ret = card->probe(card);
|
||||
@ -1633,6 +1637,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
|
||||
snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
|
||||
card->num_dapm_routes);
|
||||
|
||||
if (card->of_dapm_routes)
|
||||
snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes,
|
||||
card->num_of_dapm_routes);
|
||||
|
||||
for (i = 0; i < card->num_links; i++) {
|
||||
if (card->dai_link[i].dai_fmt)
|
||||
snd_soc_runtime_set_dai_fmt(&card->rtd[i],
|
||||
@ -3242,8 +3250,8 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
|
||||
widgets[i].name = wname;
|
||||
}
|
||||
|
||||
card->dapm_widgets = widgets;
|
||||
card->num_dapm_widgets = num_widgets;
|
||||
card->of_dapm_widgets = widgets;
|
||||
card->num_of_dapm_widgets = num_widgets;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -3327,8 +3335,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
|
||||
}
|
||||
}
|
||||
|
||||
card->num_dapm_routes = num_routes;
|
||||
card->dapm_routes = routes;
|
||||
card->num_of_dapm_routes = num_routes;
|
||||
card->of_dapm_routes = routes;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -22,30 +22,42 @@
|
||||
#include <trace/events/asoc.h>
|
||||
|
||||
/**
|
||||
* snd_soc_jack_new - Create a new jack
|
||||
* @codec: ASoC codec
|
||||
* snd_soc_card_jack_new - Create a new jack
|
||||
* @card: ASoC card
|
||||
* @id: an identifying string for this jack
|
||||
* @type: a bitmask of enum snd_jack_type values that can be detected by
|
||||
* this jack
|
||||
* @jack: structure to use for the jack
|
||||
* @pins: Array of jack pins to be added to the jack or NULL
|
||||
* @num_pins: Number of elements in the @pins array
|
||||
*
|
||||
* Creates a new jack object.
|
||||
*
|
||||
* Returns zero if successful, or a negative error code on failure.
|
||||
* On success jack will be initialised.
|
||||
*/
|
||||
int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
|
||||
struct snd_soc_jack *jack)
|
||||
int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type,
|
||||
struct snd_soc_jack *jack, struct snd_soc_jack_pin *pins,
|
||||
unsigned int num_pins)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_init(&jack->mutex);
|
||||
jack->codec = codec;
|
||||
jack->card = card;
|
||||
INIT_LIST_HEAD(&jack->pins);
|
||||
INIT_LIST_HEAD(&jack->jack_zones);
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier);
|
||||
|
||||
return snd_jack_new(codec->component.card->snd_card, id, type, &jack->jack);
|
||||
ret = snd_jack_new(card->snd_card, id, type, &jack->jack);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (num_pins)
|
||||
return snd_soc_jack_add_pins(jack, num_pins, pins);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_jack_new);
|
||||
EXPORT_SYMBOL_GPL(snd_soc_card_jack_new);
|
||||
|
||||
/**
|
||||
* snd_soc_jack_report - Report the current status for a jack
|
||||
@ -63,7 +75,6 @@ EXPORT_SYMBOL_GPL(snd_soc_jack_new);
|
||||
*/
|
||||
void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
|
||||
{
|
||||
struct snd_soc_codec *codec;
|
||||
struct snd_soc_dapm_context *dapm;
|
||||
struct snd_soc_jack_pin *pin;
|
||||
unsigned int sync = 0;
|
||||
@ -74,8 +85,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
|
||||
if (!jack)
|
||||
return;
|
||||
|
||||
codec = jack->codec;
|
||||
dapm = &codec->dapm;
|
||||
dapm = &jack->card->dapm;
|
||||
|
||||
mutex_lock(&jack->mutex);
|
||||
|
||||
@ -175,12 +185,12 @@ int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (!pins[i].pin) {
|
||||
dev_err(jack->codec->dev, "ASoC: No name for pin %d\n",
|
||||
dev_err(jack->card->dev, "ASoC: No name for pin %d\n",
|
||||
i);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!pins[i].mask) {
|
||||
dev_err(jack->codec->dev, "ASoC: No mask for pin %d"
|
||||
dev_err(jack->card->dev, "ASoC: No mask for pin %d"
|
||||
" (%s)\n", i, pins[i].pin);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -260,7 +270,7 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
|
||||
static irqreturn_t gpio_handler(int irq, void *data)
|
||||
{
|
||||
struct snd_soc_jack_gpio *gpio = data;
|
||||
struct device *dev = gpio->jack->codec->component.card->dev;
|
||||
struct device *dev = gpio->jack->card->dev;
|
||||
|
||||
trace_snd_soc_jack_irq(gpio->name);
|
||||
|
||||
@ -299,7 +309,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (!gpios[i].name) {
|
||||
dev_err(jack->codec->dev,
|
||||
dev_err(jack->card->dev,
|
||||
"ASoC: No name for gpio at index %d\n", i);
|
||||
ret = -EINVAL;
|
||||
goto undo;
|
||||
@ -320,7 +330,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
|
||||
} else {
|
||||
/* legacy GPIO number */
|
||||
if (!gpio_is_valid(gpios[i].gpio)) {
|
||||
dev_err(jack->codec->dev,
|
||||
dev_err(jack->card->dev,
|
||||
"ASoC: Invalid gpio %d\n",
|
||||
gpios[i].gpio);
|
||||
ret = -EINVAL;
|
||||
@ -350,7 +360,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
|
||||
if (gpios[i].wake) {
|
||||
ret = irq_set_irq_wake(gpiod_to_irq(gpios[i].desc), 1);
|
||||
if (ret != 0)
|
||||
dev_err(jack->codec->dev,
|
||||
dev_err(jack->card->dev,
|
||||
"ASoC: Failed to mark GPIO at index %d as wake source: %d\n",
|
||||
i, ret);
|
||||
}
|
||||
|
@ -2511,6 +2511,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
|
||||
/* DAPM dai link stream work */
|
||||
INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
|
||||
|
||||
pcm->nonatomic = rtd->dai_link->nonatomic;
|
||||
rtd->pcm = pcm;
|
||||
pcm->private_data = rtd;
|
||||
|
||||
|
@ -106,11 +106,10 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd)
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(rtd->card);
|
||||
|
||||
snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
|
||||
&tegra_alc5632_hs_jack);
|
||||
snd_soc_jack_add_pins(&tegra_alc5632_hs_jack,
|
||||
ARRAY_SIZE(tegra_alc5632_hs_jack_pins),
|
||||
tegra_alc5632_hs_jack_pins);
|
||||
snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET,
|
||||
&tegra_alc5632_hs_jack,
|
||||
tegra_alc5632_hs_jack_pins,
|
||||
ARRAY_SIZE(tegra_alc5632_hs_jack_pins));
|
||||
|
||||
if (gpio_is_valid(machine->gpio_hp_det)) {
|
||||
tegra_alc5632_hp_jack_gpio.gpio = machine->gpio_hp_det;
|
||||
|
@ -133,24 +133,26 @@ static const struct snd_soc_dapm_widget tegra_max98090_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_HP("Headphones", NULL),
|
||||
SND_SOC_DAPM_SPK("Speakers", NULL),
|
||||
SND_SOC_DAPM_MIC("Mic Jack", NULL),
|
||||
SND_SOC_DAPM_MIC("Int Mic", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new tegra_max98090_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Headphones"),
|
||||
SOC_DAPM_PIN_SWITCH("Speakers"),
|
||||
SOC_DAPM_PIN_SWITCH("Mic Jack"),
|
||||
SOC_DAPM_PIN_SWITCH("Int Mic"),
|
||||
};
|
||||
|
||||
static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct tegra_max98090 *machine = snd_soc_card_get_drvdata(rtd->card);
|
||||
|
||||
if (gpio_is_valid(machine->gpio_hp_det)) {
|
||||
snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE,
|
||||
&tegra_max98090_hp_jack);
|
||||
snd_soc_jack_add_pins(&tegra_max98090_hp_jack,
|
||||
ARRAY_SIZE(tegra_max98090_hp_jack_pins),
|
||||
tegra_max98090_hp_jack_pins);
|
||||
snd_soc_card_jack_new(rtd->card, "Headphones",
|
||||
SND_JACK_HEADPHONE,
|
||||
&tegra_max98090_hp_jack,
|
||||
tegra_max98090_hp_jack_pins,
|
||||
ARRAY_SIZE(tegra_max98090_hp_jack_pins));
|
||||
|
||||
tegra_max98090_hp_jack_gpio.gpio = machine->gpio_hp_det;
|
||||
snd_soc_jack_add_gpios(&tegra_max98090_hp_jack,
|
||||
@ -159,11 +161,11 @@ static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd)
|
||||
}
|
||||
|
||||
if (gpio_is_valid(machine->gpio_mic_det)) {
|
||||
snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
|
||||
&tegra_max98090_mic_jack);
|
||||
snd_soc_jack_add_pins(&tegra_max98090_mic_jack,
|
||||
ARRAY_SIZE(tegra_max98090_mic_jack_pins),
|
||||
tegra_max98090_mic_jack_pins);
|
||||
snd_soc_card_jack_new(rtd->card, "Mic Jack",
|
||||
SND_JACK_MICROPHONE,
|
||||
&tegra_max98090_mic_jack,
|
||||
tegra_max98090_mic_jack_pins,
|
||||
ARRAY_SIZE(tegra_max98090_mic_jack_pins));
|
||||
|
||||
tegra_max98090_mic_jack_gpio.gpio = machine->gpio_mic_det;
|
||||
snd_soc_jack_add_gpios(&tegra_max98090_mic_jack,
|
||||
|
@ -108,15 +108,11 @@ static const struct snd_kcontrol_new tegra_rt5640_controls[] = {
|
||||
|
||||
static int tegra_rt5640_asoc_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(rtd->card);
|
||||
|
||||
snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE,
|
||||
&tegra_rt5640_hp_jack);
|
||||
snd_soc_jack_add_pins(&tegra_rt5640_hp_jack,
|
||||
ARRAY_SIZE(tegra_rt5640_hp_jack_pins),
|
||||
tegra_rt5640_hp_jack_pins);
|
||||
snd_soc_card_jack_new(rtd->card, "Headphones", SND_JACK_HEADPHONE,
|
||||
&tegra_rt5640_hp_jack, tegra_rt5640_hp_jack_pins,
|
||||
ARRAY_SIZE(tegra_rt5640_hp_jack_pins));
|
||||
|
||||
if (gpio_is_valid(machine->gpio_hp_det)) {
|
||||
tegra_rt5640_hp_jack_gpio.gpio = machine->gpio_hp_det;
|
||||
|
@ -146,10 +146,9 @@ static int tegra_rt5677_asoc_init(struct snd_soc_pcm_runtime *rtd)
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(rtd->card);
|
||||
|
||||
snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
|
||||
&tegra_rt5677_hp_jack);
|
||||
snd_soc_jack_add_pins(&tegra_rt5677_hp_jack, 1,
|
||||
&tegra_rt5677_hp_jack_pins);
|
||||
snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE,
|
||||
&tegra_rt5677_hp_jack,
|
||||
&tegra_rt5677_hp_jack_pins, 1);
|
||||
|
||||
if (gpio_is_valid(machine->gpio_hp_det)) {
|
||||
tegra_rt5677_hp_jack_gpio.gpio = machine->gpio_hp_det;
|
||||
@ -158,10 +157,9 @@ static int tegra_rt5677_asoc_init(struct snd_soc_pcm_runtime *rtd)
|
||||
}
|
||||
|
||||
|
||||
snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
|
||||
&tegra_rt5677_mic_jack);
|
||||
snd_soc_jack_add_pins(&tegra_rt5677_mic_jack, 1,
|
||||
&tegra_rt5677_mic_jack_pins);
|
||||
snd_soc_card_jack_new(rtd->card, "Mic Jack", SND_JACK_MICROPHONE,
|
||||
&tegra_rt5677_mic_jack,
|
||||
&tegra_rt5677_mic_jack_pins, 1);
|
||||
|
||||
if (gpio_is_valid(machine->gpio_mic_present)) {
|
||||
tegra_rt5677_mic_jack_gpio.gpio = machine->gpio_mic_present;
|
||||
|
@ -177,21 +177,19 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
|
||||
|
||||
if (gpio_is_valid(machine->gpio_hp_det)) {
|
||||
tegra_wm8903_hp_jack_gpio.gpio = machine->gpio_hp_det;
|
||||
snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
|
||||
&tegra_wm8903_hp_jack);
|
||||
snd_soc_jack_add_pins(&tegra_wm8903_hp_jack,
|
||||
ARRAY_SIZE(tegra_wm8903_hp_jack_pins),
|
||||
tegra_wm8903_hp_jack_pins);
|
||||
snd_soc_card_jack_new(rtd->card, "Headphone Jack",
|
||||
SND_JACK_HEADPHONE, &tegra_wm8903_hp_jack,
|
||||
tegra_wm8903_hp_jack_pins,
|
||||
ARRAY_SIZE(tegra_wm8903_hp_jack_pins));
|
||||
snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack,
|
||||
1,
|
||||
&tegra_wm8903_hp_jack_gpio);
|
||||
}
|
||||
|
||||
snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
|
||||
&tegra_wm8903_mic_jack);
|
||||
snd_soc_jack_add_pins(&tegra_wm8903_mic_jack,
|
||||
ARRAY_SIZE(tegra_wm8903_mic_jack_pins),
|
||||
tegra_wm8903_mic_jack_pins);
|
||||
snd_soc_card_jack_new(rtd->card, "Mic Jack", SND_JACK_MICROPHONE,
|
||||
&tegra_wm8903_mic_jack,
|
||||
tegra_wm8903_mic_jack_pins,
|
||||
ARRAY_SIZE(tegra_wm8903_mic_jack_pins));
|
||||
wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE,
|
||||
0);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user