Commit b51086ea authored by Mark Brown's avatar Mark Brown

Merge tag 'asoc-v3.15-3' into asoc-next

ASoC: Updates for v3.15

A few more updates for the merge window:

 - Fixes for the simple-card DAI format DT mess.
 - A new driver for Cirrus cs42xx8 devices.
 - DT support for a couple more devices.
 - A revert of a previous buggy fix for soc-pcm, plus a few more fixes
   and cleanups.

# gpg: Signature made Sun 23 Mar 2014 16:56:11 GMT using RSA key ID 7EA229BD
# 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>"
parents 10885d87 e090d5b6
......@@ -11,14 +11,17 @@ Mandatory properties:
* marvell,audio-controller: a phandle that points to the audio
controller of the Armada 370 SoC.
* marvell,audio-codec: a phandle that points to the analog audio
codec connected to the Armada 370 SoC.
* marvell,audio-codec: a set of three phandles that points to:
1/ the analog audio codec connected to the Armada 370 SoC
2/ the S/PDIF transceiver
3/ the S/PDIF receiver
Example:
sound {
compatible = "marvell,a370db-audio";
marvell,audio-controller = <&audio_controller>;
marvell,audio-codec = <&audio_codec>;
marvell,audio-codec = <&audio_codec &spdif_out &spdif_in>;
status = "okay";
};
CS42448/CS42888 audio CODEC
Required properties:
- compatible : must contain one of "cirrus,cs42448" and "cirrus,cs42888"
- reg : the I2C address of the device for I2C
- clocks : a list of phandles + clock-specifiers, one for each entry in
clock-names
- clock-names : must contain "mclk"
- VA-supply, VD-supply, VLS-supply, VLC-supply: power supplies for the device,
as covered in Documentation/devicetree/bindings/regulator/regulator.txt
Example:
codec: cs42888@48 {
compatible = "cirrus,cs42888";
reg = <0x48>;
clocks = <&codec_mclk 0>;
clock-names = "mclk";
VA-supply = <&reg_audio>;
VD-supply = <&reg_audio>;
VLS-supply = <&reg_audio>;
VLC-supply = <&reg_audio>;
};
Renesas R-Car sound
Required properties:
- compatible : "renesas,rcar_sound-gen1" if generation1
"renesas,rcar_sound-gen2" if generation2
- reg : Should contain the register physical address.
required register is
SRU/ADG/SSI if generation1
SRU/ADG/SSIU/SSI if generation2
- rcar_sound,ssi : SSI subnode
- rcar_sound,scu : SCU subnode
- rcar_sound,dai : DAI subnode
SSI subnode properties:
- interrupts : Should contain SSI interrupt for PIO transfer
- shared-pin : if shared clock pin
DAI subnode properties:
- playback : list of playback modules
- capture : list of capture modules
Example:
rcar_sound: rcar_sound@0xffd90000 {
#sound-dai-cells = <1>;
compatible = "renesas,rcar_sound-gen2";
reg = <0 0xec500000 0 0x1000>, /* SCU */
<0 0xec5a0000 0 0x100>, /* ADG */
<0 0xec540000 0 0x1000>, /* SSIU */
<0 0xec541000 0 0x1280>; /* SSI */
rcar_sound,src {
src0: src@0 { };
src1: src@1 { };
src2: src@2 { };
src3: src@3 { };
src4: src@4 { };
src5: src@5 { };
src6: src@6 { };
src7: src@7 { };
src8: src@8 { };
src9: src@9 { };
};
rcar_sound,ssi {
ssi0: ssi@0 {
interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>;
};
ssi1: ssi@1 {
interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>;
};
ssi2: ssi@2 {
interrupts = <0 372 IRQ_TYPE_LEVEL_HIGH>;
};
ssi3: ssi@3 {
interrupts = <0 373 IRQ_TYPE_LEVEL_HIGH>;
};
ssi4: ssi@4 {
interrupts = <0 374 IRQ_TYPE_LEVEL_HIGH>;
};
ssi5: ssi@5 {
interrupts = <0 375 IRQ_TYPE_LEVEL_HIGH>;
};
ssi6: ssi@6 {
interrupts = <0 376 IRQ_TYPE_LEVEL_HIGH>;
};
ssi7: ssi@7 {
interrupts = <0 377 IRQ_TYPE_LEVEL_HIGH>;
};
ssi8: ssi@8 {
interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>;
};
ssi9: ssi@9 {
interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>;
};
};
rcar_sound,dai {
dai0 {
playback = <&ssi5 &src5>;
capture = <&ssi6>;
};
dai1 {
playback = <&ssi3>;
};
dai2 {
capture = <&ssi4>;
};
dai3 {
playback = <&ssi7>;
};
dai4 {
capture = <&ssi8>;
};
};
};
......@@ -43,6 +43,12 @@ Optional CPU/CODEC subnodes properties:
clock node (= common clock), or "system-clock-frequency"
(if system doens't support common clock)
Note:
* For 'format', 'frame-master', 'bitclock-master', 'bitclock-inversion' and
'frame-inversion', the simple card will use the settings of CODEC for both
CPU and CODEC sides as we need to keep the settings identical for both ends
of the link.
Example:
sound {
......
......@@ -1107,6 +1107,19 @@ struct soc_enum {
const unsigned int *values;
};
/**
* snd_soc_component_to_codec() - Casts a component to the CODEC it is embedded in
* @component: The component to cast to a CODEC
*
* This function must only be used on components that are known to be CODECs.
* Otherwise the behavior is undefined.
*/
static inline struct snd_soc_codec *snd_soc_component_to_codec(
struct snd_soc_component *component)
{
return container_of(component, struct snd_soc_codec, component);
}
/* codec IO */
unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
unsigned int snd_soc_write(struct snd_soc_codec *codec,
......
......@@ -44,6 +44,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_CS42L73 if I2C
select SND_SOC_CS4270 if I2C
select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
select SND_SOC_CS42XX8_I2C if I2C
select SND_SOC_CX20442 if TTY
select SND_SOC_DA7210 if I2C
select SND_SOC_DA7213 if I2C
......@@ -304,6 +305,15 @@ config SND_SOC_CS4271
tristate "Cirrus Logic CS4271 CODEC"
depends on SND_SOC_I2C_AND_SPI
config SND_SOC_CS42XX8
tristate
config SND_SOC_CS42XX8_I2C
tristate "Cirrus Logic CS42448/CS42888 CODEC (I2C)"
depends on I2C
select SND_SOC_CS42XX8
select REGMAP_I2C
config SND_SOC_CX20442
tristate
depends on TTY
......
......@@ -30,6 +30,8 @@ snd-soc-cs42l52-objs := cs42l52.o
snd-soc-cs42l73-objs := cs42l73.o
snd-soc-cs4270-objs := cs4270.o
snd-soc-cs4271-objs := cs4271.o
snd-soc-cs42xx8-objs := cs42xx8.o
snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o
snd-soc-da7213-objs := da7213.o
......@@ -179,6 +181,8 @@ obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o
obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o
obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o
obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o
......
/*
* Cirrus Logic CS42448/CS42888 Audio CODEC DAI I2C driver
*
* Copyright (C) 2014 Freescale Semiconductor, Inc.
*
* Author: Nicolin Chen <Guangyu.Chen@freescale.com>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <sound/soc.h>
#include "cs42xx8.h"
static int cs42xx8_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
u32 ret = cs42xx8_probe(&i2c->dev,
devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config));
if (ret)
return ret;
pm_runtime_enable(&i2c->dev);
pm_request_idle(&i2c->dev);
return 0;
}
static int cs42xx8_i2c_remove(struct i2c_client *i2c)
{
snd_soc_unregister_codec(&i2c->dev);
pm_runtime_disable(&i2c->dev);
return 0;
}
static struct i2c_device_id cs42xx8_i2c_id[] = {
{"cs42448", (kernel_ulong_t)&cs42448_data},
{"cs42888", (kernel_ulong_t)&cs42888_data},
{}
};
MODULE_DEVICE_TABLE(i2c, cs42xx8_i2c_id);
static struct i2c_driver cs42xx8_i2c_driver = {
.driver = {
.name = "cs42xx8",
.owner = THIS_MODULE,
.pm = &cs42xx8_pm,
},
.probe = cs42xx8_i2c_probe,
.remove = cs42xx8_i2c_remove,
.id_table = cs42xx8_i2c_id,
};
module_i2c_driver(cs42xx8_i2c_driver);
MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec I2C Driver");
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_LICENSE("GPL");
This diff is collapsed.
This diff is collapsed.
......@@ -918,8 +918,7 @@ static int isabelle_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_codec *codec = dai->codec;
u16 aif = 0;
unsigned int fs_val = 0;
......
......@@ -2343,7 +2343,6 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
max98090->devtype = id->driver_data;
i2c_set_clientdata(i2c, max98090);
max98090->control_data = i2c;
max98090->pdata = i2c->dev.platform_data;
max98090->irq = i2c->irq;
......
......@@ -1523,7 +1523,6 @@ struct max98090_priv {
struct regmap *regmap;
struct snd_soc_codec *codec;
enum max98090_type devtype;
void *control_data;
struct max98090_pdata *pdata;
unsigned int sysclk;
unsigned int bclk;
......
......@@ -106,8 +106,7 @@ static int mc13783_pcm_hw_params_dac(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_codec *codec = dai->codec;
unsigned int rate = params_rate(params);
int i;
......@@ -126,8 +125,7 @@ static int mc13783_pcm_hw_params_codec(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_codec *codec = dai->codec;
unsigned int rate = params_rate(params);
unsigned int val;
......
......@@ -1594,8 +1594,7 @@ static int get_clk_info(int sclk, int rate)
static int rt5640_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_codec *codec = dai->codec;
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
unsigned int val_len = 0, val_clk, mask_clk;
int dai_sel, pre_div, bclk_ms, frame_size;
......
......@@ -337,18 +337,9 @@ struct snd_soc_dai_driver sirf_audio_codec_dai = {
static int sirf_audio_codec_probe(struct snd_soc_codec *codec)
{
int ret;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec);
pm_runtime_enable(codec->dev);
codec->control_data = sirf_audio_codec->regmap;
ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
if (of_device_is_compatible(codec->dev->of_node, "sirf,prima2-audio-codec")) {
snd_soc_dapm_new_controls(dapm,
......
......@@ -193,8 +193,7 @@ static int sta529_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_codec *codec = dai->codec;
int pdata, play_freq_val, record_freq_val;
int bclk_to_fs_ratio;
......
......@@ -129,7 +129,7 @@ static const struct regmap_range_cfg aic31xx_ranges[] = {
},
};
struct regmap_config aic31xx_i2c_regmap = {
static const struct regmap_config aic31xx_i2c_regmap = {
.reg_bits = 8,
.val_bits = 8,
.writeable_reg = aic31xx_writeable,
......@@ -321,9 +321,9 @@ static const struct snd_kcontrol_new ldac_in_control =
static const struct snd_kcontrol_new rdac_in_control =
SOC_DAPM_ENUM("DAC Right Input", rdac_in_enum);
int aic31xx_wait_bits(struct aic31xx_priv *aic31xx, unsigned int reg,
unsigned int mask, unsigned int wbits, int sleep,
int count)
static int aic31xx_wait_bits(struct aic31xx_priv *aic31xx, unsigned int reg,
unsigned int mask, unsigned int wbits, int sleep,
int count)
{
unsigned int bits;
int counter = count;
......@@ -753,10 +753,9 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec,
static int aic31xx_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *tmp)
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_codec *codec = dai->codec;
u8 data = 0;
dev_dbg(codec->dev, "## %s: format %d width %d rate %d\n",
......@@ -943,7 +942,6 @@ static void aic31xx_clk_on(struct snd_soc_codec *codec)
static void aic31xx_clk_off(struct snd_soc_codec *codec)
{
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
u8 mask = AIC31XX_PM_MASK;
u8 off = 0;
......@@ -1021,7 +1019,8 @@ static int aic31xx_set_bias_level(struct snd_soc_codec *codec,
}
break;
case SND_SOC_BIAS_OFF:
aic31xx_power_off(codec);
if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
aic31xx_power_off(codec);
break;
}
codec->dapm.bias_level = level;
......@@ -1050,18 +1049,9 @@ static int aic31xx_codec_probe(struct snd_soc_codec *codec)
dev_dbg(aic31xx->dev, "## %s\n", __func__);
aic31xx = snd_soc_codec_get_drvdata(codec);
codec->control_data = aic31xx->regmap;
aic31xx->codec = codec;
ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
if (ret != 0) {
dev_err(codec->dev, "snd_soc_codec_set_cache_io failed %d\n",
ret);
return ret;
}
for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) {
aic31xx->disable_nb[i].nb.notifier_call =
aic31xx_regulator_event;
......@@ -1187,7 +1177,7 @@ static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx)
}
#endif /* CONFIG_OF */
void aic31xx_device_init(struct aic31xx_priv *aic31xx)
static void aic31xx_device_init(struct aic31xx_priv *aic31xx)
{
int ret, i;
......@@ -1238,7 +1228,6 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
return -ENOMEM;
aic31xx->regmap = devm_regmap_init_i2c(i2c, regmap_config);
if (IS_ERR(aic31xx->regmap)) {
ret = PTR_ERR(aic31xx->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
......@@ -1251,18 +1240,14 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
aic31xx_device_init(aic31xx);
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx,
return snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx,
aic31xx_dai_driver,
ARRAY_SIZE(aic31xx_dai_driver));
return ret;
}
static int aic31xx_i2c_remove(struct i2c_client *i2c)
{
struct aic31xx_priv *aic31xx = dev_get_drvdata(&i2c->dev);
kfree(aic31xx);
snd_soc_unregister_codec(&i2c->dev);
return 0;
}
......@@ -1284,7 +1269,7 @@ static struct i2c_driver aic31xx_i2c_driver = {
.of_match_table = of_match_ptr(tlv320aic31xx_of_match),
},
.probe = aic31xx_i2c_probe,
.remove = (aic31xx_i2c_remove),
.remove = aic31xx_i2c_remove,
.id_table = aic31xx_i2c_id,
};
......
......@@ -203,8 +203,7 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_codec *codec = dai->codec;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
u8 hw_params;
......
......@@ -566,8 +566,7 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_codec *codec = dai->codec;
u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
/* shut down WSPLL power if running from this clock */
......
......@@ -504,8 +504,7 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_codec *codec = dai->codec;
struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
u16 paifa = 0;
u16 paifb = 0;
......
......@@ -123,35 +123,29 @@ static const struct snd_soc_dapm_route audio_map[] = {
/* Logic for a aic3x as connected on a davinci-evm */
static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct device_node *np = codec->card->dev->of_node;
int ret;
/* Add davinci-evm specific widgets */
snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
snd_soc_dapm_new_controls(&card->dapm, aic3x_dapm_widgets,
ARRAY_SIZE(aic3x_dapm_widgets));
if (np) {
ret = snd_soc_of_parse_audio_routing(codec->card,
"ti,audio-routing");
ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
if (ret)
return ret;
} else {
/* Set up davinci-evm specific audio path audio_map */
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
snd_soc_dapm_add_routes(&card->dapm, audio_map,
ARRAY_SIZE(audio_map));
}
/* not connected */
snd_soc_dapm_disable_pin(dapm, "MONO_LOUT");
snd_soc_dapm_disable_pin(dapm, "HPLCOM");
snd_soc_dapm_disable_pin(dapm, "HPRCOM");
/* always connected */
snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
snd_soc_dapm_enable_pin(dapm, "Line Out");
snd_soc_dapm_enable_pin(dapm, "Mic Jack");
snd_soc_dapm_enable_pin(dapm, "Line In");
snd_soc_dapm_nc_pin(&codec->dapm, "MONO_LOUT");
snd_soc_dapm_nc_pin(&codec->dapm, "HPLCOM");
snd_soc_dapm_nc_pin(&codec->dapm, "HPRCOM");
return 0;
}
......
......@@ -1026,6 +1026,7 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
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;
......@@ -1095,6 +1096,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
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;
......@@ -1105,7 +1107,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
dma_params->dma_addr = mem->start + pdata->tx_dma_offset;
/* Unconditional dmaengine stuff */
mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = dma_params->dma_addr;
dma_data->addr = dma_params->dma_addr;
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (res)
......@@ -1113,7 +1115,14 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
else
dma_params->channel = 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_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;
......@@ -1124,7 +1133,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
dma_params->dma_addr = mem->start + pdata->rx_dma_offset;
/* Unconditional dmaengine stuff */
mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = dma_params->dma_addr;
dma_data->addr = dma_params->dma_addr;
if (mcasp->version < MCASP_VERSION_3) {
mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE;
......@@ -1140,9 +1149,11 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
else
dma_params->channel = pdata->rx_dma_channel;
/* Unconditional dmaengine stuff */
mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = "tx";
mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = "rx";
/* 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;
dev_set_drvdata(&pdev->dev, mcasp);
......
/*
* edma-pcm.c - eDMA PCM driver using dmaengine for AM3xxx, AM4xxx
*
* Copyright (C) 2014 Texas Instruments, Inc.
*
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
*
* Based on: sound/soc/tegra/tegra_pcm.c
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
#include <linux/edma.h>
static const struct snd_pcm_hardware edma_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_INTERLEAVED,
.buffer_bytes_max = 128 * 1024,
.period_bytes_min = 32,
.period_bytes_max = 64 * 1024,
.periods_min = 2,
.periods_max = 19, /* Limit by edma dmaengine driver */
};
static const struct snd_dmaengine_pcm_config edma_dmaengine_pcm_config = {
.pcm_hardware = &edma_pcm_hardware,
.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
.compat_filter_fn = edma_filter_fn,
.prealloc_buffer_size = 128 * 1024,
};
int edma_pcm_platform_register(struct device *dev)
{
return devm_snd_dmaengine_pcm_register(dev, &edma_dmaengine_pcm_config,
SND_DMAENGINE_PCM_FLAG_COMPAT);
}
EXPORT_SYMBOL_GPL(edma_pcm_platform_register);
MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
MODULE_DESCRIPTION("eDMA PCM ASoC platform driver");
MODULE_LICENSE("GPL");
/*
* edma-pcm.h - eDMA PCM driver using dmaengine for AM3xxx, AM4xxx
*
* Copyright (C) 2014 Texas Instruments, Inc.
*
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
*
* Based on: sound/soc/tegra/tegra_pcm.h
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#ifndef __EDMA_PCM_H__
#define __EDMA_PCM_H__
int edma_pcm_platform_register(struct device *dev);
#endif /* __EDMA_PCM_H__ */
......@@ -20,7 +20,6 @@
struct simple_card_data {
struct snd_soc_card snd_card;
unsigned int daifmt;
struct asoc_simple_dai cpu_dai;
struct asoc_simple_dai codec_dai;
struct snd_soc_dai_link snd_link;
......@@ -105,12 +104,12 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
/* get dai->name */
ret = snd_soc_of_get_dai_name(np, name);
if (ret < 0)
goto parse_error;
return ret;
/* parse TDM slot */
ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width);
if (ret)
goto parse_error;
return ret;
/*
* bitclock-inversion, frame-inversion
......@@ -130,7 +129,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
clk = of_clk_get(np, 0);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
goto parse_error;
return ret;
}
dai->sysclk = clk_get_rate(clk);
......@@ -144,12 +143,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
dai->sysclk = clk_get_rate(clk);
}
ret = 0;
parse_error:
of_node_put(node);
return ret;
return 0;
}
static int asoc_simple_card_parse_of(struct device_node *node,
......@@ -157,15 +151,18 @@ static int asoc_simple_card_parse_of(struct device_node *node,
struct device *dev)
{
struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link;
struct asoc_simple_dai *codec_dai = &priv->codec_dai;
struct asoc_simple_dai *cpu_dai = &priv->cpu_dai;
struct device_node *np;
char *name;
unsigned int daifmt;
int ret;
/* parsing the card name from DT */
snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name");
/* get CPU/CODEC common format via simple-audio-card,format */
priv->daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") &
daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") &
(SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK);
/* off-codec widgets */
......@@ -187,25 +184,35 @@ static int asoc_simple_card_parse_of(struct device_node *node,
/* CPU sub-node */
ret = -EINVAL;
np = of_get_child_by_name(node, "simple-audio-card,cpu");
if (np)
ret = asoc_simple_card_sub_parse_of(np, priv->daifmt,
&priv->cpu_dai,
if (np) {
ret = asoc_simple_card_sub_parse_of(np, daifmt,
cpu_dai,
&dai_link->cpu_of_node,
&dai_link->cpu_dai_name);
of_node_put(np);
}
if (ret < 0)
return ret;
/* CODEC sub-node */
ret = -EINVAL;
np = of_get_child_by_name(node, "simple-audio-card,codec");
if (np)
ret = asoc_simple_card_sub_parse_of(np, priv->daifmt,
&priv->codec_dai,
if (np) {
ret = asoc_simple_card_sub_parse_of(np, daifmt,
codec_dai,
&dai_link->codec_of_node,
&dai_link->codec_dai_name);
of_node_put(np);
}
if (ret < 0)
return ret;
/*
* overwrite cpu_dai->fmt as its DAIFMT_MASTER bit is based on CODEC
* while the other bits should be identical unless buggy SW/HW design.
*/
cpu_dai->fmt = codec_dai->fmt;
if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name)
return -EINVAL;
......@@ -224,15 +231,15 @@ static int asoc_simple_card_parse_of(struct device_node *node,
dai_link->platform_of_node = dai_link->cpu_of_node;
dev_dbg(dev, "card-name : %s\n", name);
dev_dbg(dev, "platform : %04x\n", priv->daifmt);
dev_dbg(dev, "platform : %04x\n", daifmt);
dev_dbg(dev, "cpu : %s / %04x / %d\n",
dai_link->cpu_dai_name,
priv->cpu_dai.fmt,
priv->cpu_dai.sysclk);
cpu_dai->fmt,
cpu_dai->sysclk);
dev_dbg(dev, "codec : %s / %04x / %d\n",
dai_link->codec_dai_name,
priv->codec_dai.fmt,
priv->codec_dai.sysclk);
codec_dai->fmt,
codec_dai->sysclk);
/*
* soc_bind_dai_link() will check cpu name
......@@ -248,6 +255,27 @@ static int asoc_simple_card_parse_of(struct device_node *node,
return 0;
}
/* update the reference count of the devices nodes at end of probe */
static int asoc_simple_card_unref(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
struct snd_soc_dai_link *dai_link;
struct device_node *np;
int num_links;
for (num_links = 0, dai_link = card->dai_link;
num_links < card->num_links;
num_links++, dai_link++) {
np = (struct device_node *) dai_link->cpu_of_node;
if (np)
of_node_put(np);
np = (struct device_node *) dai_link->codec_of_node;
if (np)
of_node_put(np);
}
return 0;
}
static int asoc_simple_card_probe(struct platform_device *pdev)
{
struct simple_card_data *priv;
......@@ -275,7 +303,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
if (ret < 0) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "parse error %d\n", ret);
return ret;
goto err;
}
} else {
struct asoc_simple_card_info *cinfo;
......@@ -318,7 +346,11 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
snd_soc_card_set_drvdata(&priv->snd_card, priv);
return devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
err:
asoc_simple_card_unref(pdev);
return ret;
}
static const struct of_device_id asoc_simple_of_match[] = {
......
......@@ -53,6 +53,7 @@ enum soc_mic_bias_zones {
static unsigned int hs_switch;
static unsigned int lo_dac;
static struct snd_soc_codec *mfld_codec;
struct mfld_mc_private {
void __iomem *int_base;
......@@ -100,8 +101,8 @@ static int headset_get_switch(struct snd_kcontrol *kcontrol,
static int headset_set_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_context *dapm = &card->dapm;
if (ucontrol->value.integer.value[0] == hs_switch)
return 0;
......@@ -127,10 +128,8 @@ static int headset_set_switch(struct snd_kcontrol *kcontrol,
return 0;
}
static void lo_enable_out_pins(struct snd_soc_codec *codec)
static void lo_enable_out_pins(struct snd_soc_dapm_context *dapm)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTL");
snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTR");
snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTL");
......@@ -156,8 +155,8 @@ static int lo_get_switch(struct snd_kcontrol *kcontrol,
static int lo_set_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_context *dapm = &card->dapm;
if (ucontrol->value.integer.value[0] == lo_dac)
return 0;
......@@ -167,35 +166,35 @@ static int lo_set_switch(struct snd_kcontrol *kcontrol,
/* we dont want to work with last state of lineout so just enable all
* pins and then disable pins not required
*/
lo_enable_out_pins(codec);
lo_enable_out_pins(dapm);
switch (ucontrol->value.integer.value[0]) {
case 0:
pr_debug("set vibra path\n");
snd_soc_dapm_disable_pin_unlocked(dapm, "VIB1OUT");
snd_soc_dapm_disable_pin_unlocked(dapm, "VIB2OUT");
snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0);
snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0);
break;
case 1:
pr_debug("set hs path\n");
snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x22);
snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x22);
break;
case 2:
pr_debug("set spkr path\n");
snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTL");
snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTR");
snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x44);
snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x44);
break;
case 3:
pr_debug("set null path\n");
snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTL");
snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTR");
snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x66);
snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x66);
break;
}
......@@ -238,26 +237,11 @@ static void mfld_jack_check(unsigned int intr_status)
static int mfld_init(struct snd_soc_pcm_runtime *runtime)
{
struct snd_soc_codec *codec = runtime->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dapm_context *dapm = &runtime->card->dapm;
int ret_val;
/* Add jack sense widgets */
snd_soc_dapm_new_controls(dapm, mfld_widgets, ARRAY_SIZE(mfld_widgets));
/* Set up the map */
snd_soc_dapm_add_routes(dapm, mfld_map, ARRAY_SIZE(mfld_map));
mfld_codec = runtime->codec;
/* always connected */
snd_soc_dapm_enable_pin(dapm, "Headphones");
snd_soc_dapm_enable_pin(dapm, "Mic");
ret_val = snd_soc_add_codec_controls(codec, mfld_snd_controls,
ARRAY_SIZE(mfld_snd_controls));
if (ret_val) {
pr_err("soc_add_controls failed %d", ret_val);
return ret_val;
}
/* default is earpiece pin, userspace sets it explcitly */
snd_soc_dapm_disable_pin(dapm, "Headphones");
/* default is lineout NC, userspace sets it explcitly */
......@@ -270,7 +254,7 @@ 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(codec, "Intel(R) MID Audio Jack",
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);
if (ret_val) {
......@@ -352,6 +336,13 @@ static struct snd_soc_card snd_soc_card_mfld = {
.owner = THIS_MODULE,
.dai_link = mfld_msic_dailink,
.num_links = ARRAY_SIZE(mfld_msic_dailink),
.controls = mfld_snd_controls,
.num_controls = ARRAY_SIZE(mfld_snd_controls),
.dapm_widgets = mfld_widgets,
.num_dapm_widgets = ARRAY_SIZE(mfld_widgets),
.dapm_routes = mfld_map,
.num_dapm_routes = ARRAY_SIZE(mfld_map),
};
static irqreturn_t snd_mfld_jack_intr_handler(int irq, void *dev)
......
......@@ -10,6 +10,7 @@ config SND_KIRKWOOD_SOC_ARMADA370_DB
tristate "SoC Audio support for Armada 370 DB"
depends on SND_KIRKWOOD_SOC && (ARCH_MVEBU || COMPILE_TEST) && I2C
select SND_SOC_CS42L51
select SND_SOC_SPDIF
help
Say Y if you want to add support for SoC audio on
the Armada 370 Development Board.
......
......@@ -67,6 +67,20 @@ static struct snd_soc_dai_link a370db_dai[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
.ops = &a370db_ops,
},
{
.name = "S/PDIF out",
.stream_name = "spdif-out",
.cpu_dai_name = "spdif",
.codec_dai_name = "dit-hifi",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
},
{
.name = "S/PDIF in",
.stream_name = "spdif-in",
.cpu_dai_name = "spdif",
.codec_dai_name = "dir-hifi",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
},
};
static struct snd_soc_card a370db = {
......@@ -95,6 +109,20 @@ static int a370db_probe(struct platform_device *pdev)
of_parse_phandle(pdev->dev.of_node,
"marvell,audio-codec", 0);
a370db_dai[1].cpu_of_node = a370db_dai[0].cpu_of_node;
a370db_dai[1].platform_of_node = a370db_dai[0].cpu_of_node;
a370db_dai[1].codec_of_node =
of_parse_phandle(pdev->dev.of_node,
"marvell,audio-codec", 1);
a370db_dai[2].cpu_of_node = a370db_dai[0].cpu_of_node;
a370db_dai[2].platform_of_node = a370db_dai[0].cpu_of_node;
a370db_dai[2].codec_of_node =
of_parse_phandle(pdev->dev.of_node,
"marvell,audio-codec", 2);
return devm_snd_soc_register_card(card->dev, card);
}
......
......@@ -203,8 +203,7 @@ static const struct snd_soc_dapm_route dmic_audio_map[] = {
static int omap_abe_dmic_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
return snd_soc_dapm_add_routes(dapm, dmic_audio_map,
ARRAY_SIZE(dmic_audio_map));
......
......@@ -392,6 +392,7 @@ static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg)
}
int rsnd_adg_probe(struct platform_device *pdev,
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv)
{
struct rsnd_adg *adg;
......
......@@ -100,6 +100,21 @@
#define RSND_RATES SNDRV_PCM_RATE_8000_96000
#define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
static struct rsnd_of_data rsnd_of_data_gen1 = {
.flags = RSND_GEN1,
};
static struct rsnd_of_data rsnd_of_data_gen2 = {
.flags = RSND_GEN2,
};
static struct of_device_id rsnd_of_match[] = {
{ .compatible = "renesas,rcar_sound-gen1", .data = &rsnd_of_data_gen1 },
{ .compatible = "renesas,rcar_sound-gen2", .data = &rsnd_of_data_gen2 },
{},
};
MODULE_DEVICE_TABLE(of, rsnd_of_match);
/*
* rsnd_platform functions
*/
......@@ -620,7 +635,92 @@ static int rsnd_path_init(struct rsnd_priv *priv,
return ret;
}
static void rsnd_of_parse_dai(struct platform_device *pdev,
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv)
{
struct device_node *dai_node, *dai_np;
struct device_node *ssi_node, *ssi_np;
struct device_node *src_node, *src_np;
struct device_node *playback, *capture;
struct rsnd_dai_platform_info *dai_info;
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
struct device *dev = &pdev->dev;
int nr, i;
int dai_i, ssi_i, src_i;
if (!of_data)
return;
dai_node = of_get_child_by_name(dev->of_node, "rcar_sound,dai");
if (!dai_node)
return;
nr = of_get_child_count(dai_node);
if (!nr)
return;
dai_info = devm_kzalloc(dev,
sizeof(struct rsnd_dai_platform_info) * nr,
GFP_KERNEL);
if (!dai_info) {
dev_err(dev, "dai info allocation error\n");
return;
}
info->dai_info_nr = nr;
info->dai_info = dai_info;
ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
#define mod_parse(name) \
if (name##_node) { \
struct rsnd_##name##_platform_info *name##_info; \
\
name##_i = 0; \
for_each_child_of_node(name##_node, name##_np) { \
name##_info = info->name##_info + name##_i; \
\
if (name##_np == playback) \
dai_info->playback.name = name##_info; \
if (name##_np == capture) \
dai_info->capture.name = name##_info; \
\
name##_i++; \
} \
}
/*
* parse all dai
*/
dai_i = 0;
for_each_child_of_node(dai_node, dai_np) {
dai_info = info->dai_info + dai_i;
for (i = 0;; i++) {
playback = of_parse_phandle(dai_np, "playback", i);
capture = of_parse_phandle(dai_np, "capture", i);
if (!playback && !capture)
break;
mod_parse(ssi);
mod_parse(src);
if (playback)
of_node_put(playback);
if (capture)
of_node_put(capture);
}
dai_i++;
}
}
static int rsnd_dai_probe(struct platform_device *pdev,
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv)
{
struct snd_soc_dai_driver *drv;
......@@ -628,13 +728,16 @@ static int rsnd_dai_probe(struct platform_device *pdev,
struct rsnd_dai *rdai;
struct rsnd_mod *pmod, *cmod;
struct device *dev = rsnd_priv_to_dev(priv);
int dai_nr = info->dai_info_nr;
int dai_nr;
int i;
rsnd_of_parse_dai(pdev, of_data, priv);
/*
* dai_nr should be set via dai_info_nr,
* but allow it to keeping compatible
*/
dai_nr = info->dai_info_nr;
if (!dai_nr) {
/* get max dai nr */
for (dai_nr = 0; dai_nr < 32; dai_nr++) {
......@@ -802,7 +905,10 @@ static int rsnd_probe(struct platform_device *pdev)
struct rsnd_priv *priv;
struct device *dev = &pdev->dev;
struct rsnd_dai *rdai;
const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev);
const struct rsnd_of_data *of_data;
int (*probe_func[])(struct platform_device *pdev,
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv) = {
rsnd_gen_probe,
rsnd_ssi_probe,
......@@ -812,7 +918,16 @@ static int rsnd_probe(struct platform_device *pdev)
};
int ret, i;
info = pdev->dev.platform_data;
info = NULL;
of_data = NULL;
if (of_id) {
info = devm_kzalloc(&pdev->dev,
sizeof(struct rcar_snd_info), GFP_KERNEL);
of_data = of_id->data;
} else {
info = pdev->dev.platform_data;
}
if (!info) {
dev_err(dev, "driver needs R-Car sound information\n");
return -ENODEV;
......@@ -835,7 +950,7 @@ static int rsnd_probe(struct platform_device *pdev)
* init each module
*/
for (i = 0; i < ARRAY_SIZE(probe_func); i++) {
ret = probe_func[i](pdev, priv);
ret = probe_func[i](pdev, of_data, priv);
if (ret)
return ret;
}
......@@ -903,6 +1018,7 @@ static int rsnd_remove(struct platform_device *pdev)
static struct platform_driver rsnd_driver = {
.driver = {
.name = "rcar_sound",
.of_match_table = rsnd_of_match,
},
.probe = rsnd_probe,
.remove = rsnd_remove,
......
......@@ -359,13 +359,28 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
/*
* Gen
*/
static void rsnd_of_parse_gen(struct platform_device *pdev,
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv)
{
struct rcar_snd_info *info = priv->info;
if (!of_data)
return;
info->flags = of_data->flags;
}
int rsnd_gen_probe(struct platform_device *pdev,
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_gen *gen;
int ret;
rsnd_of_parse_gen(pdev, of_data, priv);
gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
if (!gen) {
dev_err(dev, "GEN allocate failed\n");
......
......@@ -17,6 +17,8 @@
#include <linux/io.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/sh_dma.h>
#include <linux/workqueue.h>
#include <sound/rcar_snd.h>
......@@ -113,6 +115,7 @@ enum rsnd_reg {
#define RSND_REG_SRCOUT_TIMSEL4 RSND_REG_SHARE18
#define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19
struct rsnd_of_data;
struct rsnd_priv;
struct rsnd_mod;
struct rsnd_dai;
......@@ -260,6 +263,7 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
* R-Car Gen1/Gen2
*/
int rsnd_gen_probe(struct platform_device *pdev,
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv);
void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
struct rsnd_mod *mod,
......@@ -273,6 +277,7 @@ void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod);
int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate);
int rsnd_adg_probe(struct platform_device *pdev,
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv);
int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
struct rsnd_mod *mod,
......@@ -290,6 +295,10 @@ int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod,
/*
* R-Car sound priv
*/
struct rsnd_of_data {
u32 flags;
};
struct rsnd_priv {
struct device *dev;
......@@ -348,6 +357,7 @@ struct rsnd_priv {
* R-Car SRC
*/
int rsnd_src_probe(struct platform_device *pdev,
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv);
struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
......@@ -366,6 +376,7 @@ int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod,
* R-Car SSI
*/
int rsnd_ssi_probe(struct platform_device *pdev,
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv);
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv,
......
......@@ -628,7 +628,41 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
return &((struct rsnd_src *)(priv->src) + id)->mod;
}
static void rsnd_of_parse_src(struct platform_device *pdev,
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv)
{
struct device_node *src_node;
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
struct rsnd_src_platform_info *src_info;
struct device *dev = &pdev->dev;
int nr;
if (!of_data)
return;
src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
if (!src_node)
return;
nr = of_get_child_count(src_node);
if (!nr)
return;
src_info = devm_kzalloc(dev,
sizeof(struct rsnd_src_platform_info) * nr,
GFP_KERNEL);
if (!src_info) {
dev_err(dev, "src info allocation error\n");
return;
}
info->src_info = src_info;
info->src_info_nr = nr;
}
int rsnd_src_probe(struct platform_device *pdev,
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv)
{
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
......@@ -639,6 +673,8 @@ int rsnd_src_probe(struct platform_device *pdev,
char name[RSND_SRC_NAME_SIZE];
int i, nr;
rsnd_of_parse_src(pdev, of_data, priv);
/*
* init SRC
*/
......
......@@ -588,7 +588,61 @@ static void rsnd_ssi_parent_clk_setup(struct rsnd_priv *priv, struct rsnd_ssi *s
}
}
static void rsnd_of_parse_ssi(struct platform_device *pdev,
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv)
{
struct device_node *node;
struct device_node *np;
struct rsnd_ssi_platform_info *ssi_info;
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
struct device *dev = &pdev->dev;
int nr, i;
if (!of_data)
return;
node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
if (!node)
return;
nr = of_get_child_count(node);
if (!nr)
return;
ssi_info = devm_kzalloc(dev,
sizeof(struct rsnd_ssi_platform_info) * nr,
GFP_KERNEL);
if (!ssi_info) {
dev_err(dev, "ssi info allocation error\n");
return;
}
info->ssi_info = ssi_info;
info->ssi_info_nr = nr;
i = -1;
for_each_child_of_node(node, np) {
i++;
ssi_info = info->ssi_info + i;
/*
* pin settings
*/
if (of_get_property(np, "shared-pin", NULL))
ssi_info->flags |= RSND_SSI_CLK_PIN_SHARE;
/*
* irq
*/
ssi_info->pio_irq = irq_of_parse_and_map(np, 0);
}
}
int rsnd_ssi_probe(struct platform_device *pdev,
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv)
{
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
......@@ -600,6 +654,8 @@ int rsnd_ssi_probe(struct platform_device *pdev,
char name[RSND_SSI_NAME_SIZE];
int i, nr;
rsnd_of_parse_ssi(pdev, of_data, priv);
/*
* init SSI
*/
......
......@@ -23,21 +23,6 @@
static int hw_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
int ret;
if (!snd_soc_codec_volatile_register(codec, reg) &&
reg < codec->driver->reg_cache_size &&
!codec->cache_bypass) {
ret = snd_soc_cache_write(codec, reg, value);
if (ret < 0)
return -1;
}
if (codec->cache_only) {
codec->cache_sync = 1;
return 0;
}
return regmap_write(codec->control_data, reg, value);
}
......@@ -46,23 +31,11 @@ static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg)
int ret;
unsigned int val;
if (reg >= codec->driver->reg_cache_size ||
snd_soc_codec_volatile_register(codec, reg) ||
codec->cache_bypass) {
if (codec->cache_only)
return -1;
ret = regmap_read(codec->control_data, reg, &val);
if (ret == 0)
return val;
else
return -1;
}
ret = snd_soc_cache_read(codec, reg, &val);
if (ret < 0)
ret = regmap_read(codec->control_data, reg, &val);
if (ret == 0)
return val;
else
return -1;
return val;
}
/**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment