Commit 1fa1e073 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/omap', 'asoc/topic/qcom',...

Merge remote-tracking branches 'asoc/topic/omap', 'asoc/topic/qcom', 'asoc/topic/rcar' and 'asoc/topic/rt286' into asoc-next
* Qualcomm Technologies LPASS CPU DAI
This node models the Qualcomm Technologies Low-Power Audio SubSystem (LPASS).
Required properties:
- compatible : "qcom,lpass-cpu"
- clocks : Must contain an entry for each entry in clock-names.
- clock-names : A list which must include the following entries:
* "ahbix-clk"
* "mi2s-osr-clk"
* "mi2s-bit-clk"
- interrupts : Must contain an entry for each entry in
interrupt-names.
- interrupt-names : A list which must include the following entries:
* "lpass-irq-lpaif"
- pinctrl-N : One property must exist for each entry in
pinctrl-names. See ../pinctrl/pinctrl-bindings.txt
for details of the property values.
- pinctrl-names : Must contain a "default" entry.
- reg : Must contain an address for each entry in reg-names.
- reg-names : A list which must include the following entries:
* "lpass-lpaif"
Optional properties:
- qcom,adsp : Phandle for the audio DSP node
Example:
lpass@28100000 {
compatible = "qcom,lpass-cpu";
clocks = <&lcc AHBIX_CLK>, <&lcc MI2S_OSR_CLK>, <&lcc MI2S_BIT_CLK>;
clock-names = "ahbix-clk", "mi2s-osr-clk", "mi2s-bit-clk";
interrupts = <0 85 1>;
interrupt-names = "lpass-irq-lpaif";
pinctrl-names = "default", "idle";
pinctrl-0 = <&mi2s_default>;
pinctrl-1 = <&mi2s_idle>;
reg = <0x28100000 0x10000>;
reg-names = "lpass-lpaif";
qcom,adsp = <&adsp>;
};
......@@ -29,9 +29,17 @@ SSI subnode properties:
- shared-pin : if shared clock pin
- pio-transfer : use PIO transfer mode
- no-busif : BUSIF is not ussed when [mem -> SSI] via DMA case
- dma : Should contain Audio DMAC entry
- dma-names : SSI case "rx" (=playback), "tx" (=capture)
SSIU case "rxu" (=playback), "txu" (=capture)
SRC subnode properties:
no properties at this point
- dma : Should contain Audio DMAC entry
- dma-names : "rx" (=playback), "tx" (=capture)
DVC subnode properties:
- dma : Should contain Audio DMAC entry
- dma-names : "tx" (=playback/capture)
DAI subnode properties:
- playback : list of playback modules
......@@ -45,56 +53,145 @@ rcar_sound: rcar_sound@ec500000 {
reg = <0 0xec500000 0 0x1000>, /* SCU */
<0 0xec5a0000 0 0x100>, /* ADG */
<0 0xec540000 0 0x1000>, /* SSIU */
<0 0xec541000 0 0x1280>; /* SSI */
<0 0xec541000 0 0x1280>, /* SSI */
<0 0xec740000 0 0x200>; /* Audio DMAC peri peri*/
reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
clocks = <&mstp10_clks R8A7790_CLK_SSI_ALL>,
<&mstp10_clks R8A7790_CLK_SSI9>, <&mstp10_clks R8A7790_CLK_SSI8>,
<&mstp10_clks R8A7790_CLK_SSI7>, <&mstp10_clks R8A7790_CLK_SSI6>,
<&mstp10_clks R8A7790_CLK_SSI5>, <&mstp10_clks R8A7790_CLK_SSI4>,
<&mstp10_clks R8A7790_CLK_SSI3>, <&mstp10_clks R8A7790_CLK_SSI2>,
<&mstp10_clks R8A7790_CLK_SSI1>, <&mstp10_clks R8A7790_CLK_SSI0>,
<&mstp10_clks R8A7790_CLK_SCU_SRC9>, <&mstp10_clks R8A7790_CLK_SCU_SRC8>,
<&mstp10_clks R8A7790_CLK_SCU_SRC7>, <&mstp10_clks R8A7790_CLK_SCU_SRC6>,
<&mstp10_clks R8A7790_CLK_SCU_SRC5>, <&mstp10_clks R8A7790_CLK_SCU_SRC4>,
<&mstp10_clks R8A7790_CLK_SCU_SRC3>, <&mstp10_clks R8A7790_CLK_SCU_SRC2>,
<&mstp10_clks R8A7790_CLK_SCU_SRC1>, <&mstp10_clks R8A7790_CLK_SCU_SRC0>,
<&mstp10_clks R8A7790_CLK_SCU_DVC0>, <&mstp10_clks R8A7790_CLK_SCU_DVC1>,
<&audio_clk_a>, <&audio_clk_b>, <&audio_clk_c>, <&m2_clk>;
clock-names = "ssi-all",
"ssi.9", "ssi.8", "ssi.7", "ssi.6", "ssi.5",
"ssi.4", "ssi.3", "ssi.2", "ssi.1", "ssi.0",
"src.9", "src.8", "src.7", "src.6", "src.5",
"src.4", "src.3", "src.2", "src.1", "src.0",
"dvc.0", "dvc.1",
"clk_a", "clk_b", "clk_c", "clk_i";
rcar_sound,dvc {
dvc0: dvc@0 { };
dvc1: dvc@1 { };
dvc0: dvc@0 {
dmas = <&audma0 0xbc>;
dma-names = "tx";
};
dvc1: dvc@1 {
dmas = <&audma0 0xbe>;
dma-names = "tx";
};
};
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 { };
src0: src@0 {
interrupts = <0 352 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x85>, <&audma1 0x9a>;
dma-names = "rx", "tx";
};
src1: src@1 {
interrupts = <0 353 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x87>, <&audma1 0x9c>;
dma-names = "rx", "tx";
};
src2: src@2 {
interrupts = <0 354 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x89>, <&audma1 0x9e>;
dma-names = "rx", "tx";
};
src3: src@3 {
interrupts = <0 355 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x8b>, <&audma1 0xa0>;
dma-names = "rx", "tx";
};
src4: src@4 {
interrupts = <0 356 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x8d>, <&audma1 0xb0>;
dma-names = "rx", "tx";
};
src5: src@5 {
interrupts = <0 357 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x8f>, <&audma1 0xb2>;
dma-names = "rx", "tx";
};
src6: src@6 {
interrupts = <0 358 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x91>, <&audma1 0xb4>;
dma-names = "rx", "tx";
};
src7: src@7 {
interrupts = <0 359 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x93>, <&audma1 0xb6>;
dma-names = "rx", "tx";
};
src8: src@8 {
interrupts = <0 360 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x95>, <&audma1 0xb8>;
dma-names = "rx", "tx";
};
src9: src@9 {
interrupts = <0 361 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x97>, <&audma1 0xba>;
dma-names = "rx", "tx";
};
};
rcar_sound,ssi {
ssi0: ssi@0 {
interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>;
dma-names = "rx", "tx", "rxu", "txu";
};
ssi1: ssi@1 {
interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x03>, <&audma1 0x04>, <&audma0 0x49>, <&audma1 0x4a>;
dma-names = "rx", "tx", "rxu", "txu";
};
ssi2: ssi@2 {
interrupts = <0 372 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x05>, <&audma1 0x06>, <&audma0 0x63>, <&audma1 0x64>;
dma-names = "rx", "tx", "rxu", "txu";
};
ssi3: ssi@3 {
interrupts = <0 373 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x07>, <&audma1 0x08>, <&audma0 0x6f>, <&audma1 0x70>;
dma-names = "rx", "tx", "rxu", "txu";
};
ssi4: ssi@4 {
interrupts = <0 374 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x09>, <&audma1 0x0a>, <&audma0 0x71>, <&audma1 0x72>;
dma-names = "rx", "tx", "rxu", "txu";
};
ssi5: ssi@5 {
interrupts = <0 375 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x0b>, <&audma1 0x0c>, <&audma0 0x73>, <&audma1 0x74>;
dma-names = "rx", "tx", "rxu", "txu";
};
ssi6: ssi@6 {
interrupts = <0 376 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x0d>, <&audma1 0x0e>, <&audma0 0x75>, <&audma1 0x76>;
dma-names = "rx", "tx", "rxu", "txu";
};
ssi7: ssi@7 {
interrupts = <0 377 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x0f>, <&audma1 0x10>, <&audma0 0x79>, <&audma1 0x7a>;
dma-names = "rx", "tx", "rxu", "txu";
};
ssi8: ssi@8 {
interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x11>, <&audma1 0x12>, <&audma0 0x7b>, <&audma1 0x7c>;
dma-names = "rx", "tx", "rxu", "txu";
};
ssi9: ssi@9 {
interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x13>, <&audma1 0x14>, <&audma0 0x7d>, <&audma1 0x7e>;
dma-names = "rx", "tx", "rxu", "txu";
};
};
......
Renesas Sampling Rate Convert Sound Card:
Renesas Sampling Rate Convert Sound Card specifies audio DAI connections of SoC <-> codec.
Required properties:
- compatible : "renesas,rsrc-card,<board>"
Examples with soctypes are:
- "renesas,rsrc-card,lager"
- "renesas,rsrc-card,koelsch"
Optional properties:
- card_name : User specified audio sound card name, one string
property.
- cpu : CPU sub-node
- codec : CODEC sub-node
Optional subnode properties:
- format : CPU/CODEC common audio format.
"i2s", "right_j", "left_j" , "dsp_a"
"dsp_b", "ac97", "pdm", "msb", "lsb"
- frame-master : Indicates dai-link frame master.
phandle to a cpu or codec subnode.
- bitclock-master : Indicates dai-link bit clock master.
phandle to a cpu or codec subnode.
- bitclock-inversion : bool property. Add this if the
dai-link uses bit clock inversion.
- frame-inversion : bool property. Add this if the
dai-link uses frame clock inversion.
- convert-rate : platform specified sampling rate convert
Required CPU/CODEC subnodes properties:
- sound-dai : phandle and port of CPU/CODEC
Optional CPU/CODEC subnodes properties:
- clocks / system-clock-frequency : specify subnode's clock if needed.
it can be specified via "clocks" if system has
clock node (= common clock), or "system-clock-frequency"
(if system doens't support common clock)
If a clock is specified, it is
enabled with clk_prepare_enable()
in dai startup() and disabled with
clk_disable_unprepare() in dai
shutdown().
Example
sound {
compatible = "renesas,rsrc-card,lager";
card-name = "rsnd-ak4643";
format = "left_j";
bitclock-master = <&sndcodec>;
frame-master = <&sndcodec>;
sndcpu: cpu {
sound-dai = <&rcar_sound>;
};
sndcodec: codec {
sound-dai = <&ak4643>;
system-clock-frequency = <11289600>;
};
};
* Sound complex for Storm boards
Models a soundcard for Storm boards with the Qualcomm Technologies IPQ806x SOC
connected to a MAX98357A DAC via I2S.
Required properties:
- compatible : "google,storm-audio"
- cpu : Phandle of the CPU DAI
- codec : Phandle of the codec DAI
Optional properties:
- qcom,model : The user-visible name of this sound card.
Example:
sound {
compatible = "google,storm-audio";
qcom,model = "ipq806x-storm";
cpu = <&lpass_cpu>;
codec = <&max98357a>;
};
......@@ -5271,6 +5271,13 @@ F: drivers/char/ipmi/
F: include/linux/ipmi*
F: include/uapi/linux/ipmi*
QCOM AUDIO (ASoC) DRIVERS
M: Patrick Lai <plai@codeaurora.org>
M: Banajit Goswami <bgoswami@codeaurora.org>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Supported
F: sound/soc/qcom/
IPS SCSI RAID DRIVER
M: Adaptec OEM Raid Solutions <aacraid@adaptec.com>
L: linux-scsi@vger.kernel.org
......
......@@ -47,6 +47,7 @@ source "sound/soc/kirkwood/Kconfig"
source "sound/soc/intel/Kconfig"
source "sound/soc/mxs/Kconfig"
source "sound/soc/pxa/Kconfig"
source "sound/soc/qcom/Kconfig"
source "sound/soc/rockchip/Kconfig"
source "sound/soc/samsung/Kconfig"
source "sound/soc/sh/Kconfig"
......
......@@ -28,6 +28,7 @@ obj-$(CONFIG_SND_SOC) += nuc900/
obj-$(CONFIG_SND_SOC) += omap/
obj-$(CONFIG_SND_SOC) += kirkwood/
obj-$(CONFIG_SND_SOC) += pxa/
obj-$(CONFIG_SND_SOC) += qcom/
obj-$(CONFIG_SND_SOC) += rockchip/
obj-$(CONFIG_SND_SOC) += samsung/
obj-$(CONFIG_SND_SOC) += sh/
......
......@@ -397,7 +397,7 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
if (jack) {
/* enable IRQ */
if (rt286->jack->status | SND_JACK_HEADPHONE)
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 */
......@@ -1048,7 +1048,6 @@ static int rt286_probe(struct snd_soc_codec *codec)
struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
rt286->codec = codec;
codec->dapm.bias_level = SND_SOC_BIAS_OFF;
if (rt286->i2c->irq) {
regmap_update_bits(rt286->regmap,
......@@ -1220,7 +1219,7 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
{
struct rt286_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct rt286_priv *rt286;
int i, ret;
int i, ret, val;
rt286 = devm_kzalloc(&i2c->dev, sizeof(*rt286),
GFP_KERNEL);
......@@ -1235,11 +1234,15 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
return ret;
}
regmap_read(rt286->regmap,
RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &ret);
if (ret != RT286_VENDOR_ID && ret != RT288_VENDOR_ID) {
ret = regmap_read(rt286->regmap,
RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &val);
if (ret != 0) {
dev_err(&i2c->dev, "I2C error %d\n", ret);
return ret;
}
if (val != RT286_VENDOR_ID && val != RT288_VENDOR_ID) {
dev_err(&i2c->dev,
"Device with ID register %x is not rt286\n", ret);
"Device with ID register %x is not rt286\n", val);
return -ENODEV;
}
......@@ -1247,6 +1250,14 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
rt286->i2c = i2c;
i2c_set_clientdata(i2c, rt286);
/* restore codec default */
for (i = 0; i < INDEX_CACHE_SIZE; i++)
regmap_write(rt286->regmap, rt286->index_cache[i].reg,
rt286->index_cache[i].def);
for (i = 0; i < ARRAY_SIZE(rt286_reg); i++)
regmap_write(rt286->regmap, rt286_reg[i].reg,
rt286_reg[i].def);
if (pdata)
rt286->pdata = *pdata;
......
......@@ -105,7 +105,7 @@ config SND_OMAP_SOC_OMAP_ABE_TWL6040
select SND_OMAP_SOC_MCPDM
select SND_SOC_TWL6040
select SND_SOC_DMIC
select COMMON_CLK_PALMAS if SOC_OMAP5
select COMMON_CLK_PALMAS if MFD_PALMAS
help
Say Y if you want to add support for SoC audio on OMAP boards using
ABE and twl6040 codec. This driver currently supports:
......
......@@ -98,12 +98,11 @@ static int n810_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
n810_ext_control(&codec->dapm);
n810_ext_control(&rtd->card->dapm);
return clk_prepare_enable(sys_clkout2);
}
......@@ -255,24 +254,6 @@ static const struct snd_kcontrol_new aic33_n810_controls[] = {
n810_get_input, n810_set_input),
};
static int n810_aic33_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
/* Not connected */
snd_soc_dapm_nc_pin(dapm, "MONO_LOUT");
snd_soc_dapm_nc_pin(dapm, "HPLCOM");
snd_soc_dapm_nc_pin(dapm, "HPRCOM");
snd_soc_dapm_nc_pin(dapm, "MIC3L");
snd_soc_dapm_nc_pin(dapm, "MIC3R");
snd_soc_dapm_nc_pin(dapm, "LINE1R");
snd_soc_dapm_nc_pin(dapm, "LINE2L");
snd_soc_dapm_nc_pin(dapm, "LINE2R");
return 0;
}
/* Digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link n810_dai = {
.name = "TLV320AIC33",
......@@ -283,7 +264,6 @@ static struct snd_soc_dai_link n810_dai = {
.codec_dai_name = "tlv320aic3x-hifi",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM,
.init = n810_aic33_init,
.ops = &n810_ops,
};
......@@ -300,6 +280,7 @@ static struct snd_soc_card snd_soc_n810 = {
.num_dapm_widgets = ARRAY_SIZE(aic33_dapm_widgets),
.dapm_routes = audio_map,
.num_dapm_routes = ARRAY_SIZE(audio_map),
.fully_routed = true,
};
static struct platform_device *n810_snd_device;
......
......@@ -142,8 +142,6 @@ static int hdmi_dai_hw_params(struct snd_pcm_substream *substream,
iec->status[0] |= IEC958_AES0_CON_EMPHASIS_NONE;
iec->status[0] |= IEC958_AES1_PRO_MODE_NOTID;
iec->status[1] = IEC958_AES1_CON_GENERAL;
iec->status[2] |= IEC958_AES2_CON_SOURCE_UNSPEC;
......
config SND_SOC_QCOM
tristate "ASoC support for QCOM platforms"
help
Say Y or M if you want to add support to use audio devices
in Qualcomm Technologies SOC-based platforms.
config SND_SOC_LPASS_CPU
tristate
depends on SND_SOC_QCOM
select REGMAP_MMIO
config SND_SOC_LPASS_PLATFORM
tristate
depends on SND_SOC_QCOM
select REGMAP_MMIO
config SND_SOC_STORM
tristate "ASoC I2S support for Storm boards"
depends on (ARCH_QCOM && SND_SOC_QCOM) || COMPILE_TEST
select SND_SOC_LPASS_CPU
select SND_SOC_LPASS_PLATFORM
select SND_SOC_MAX98357A
help
Say Y or M if you want add support for SoC audio on the
Qualcomm Technologies IPQ806X-based Storm board.
# Platform
snd-soc-lpass-cpu-objs := lpass-cpu.o
snd-soc-lpass-platform-objs := lpass-platform.o
obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o
obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o
# Machine
snd-soc-storm-objs := storm.o
obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
This diff is collapsed.
/*
* Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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.
*
* lpass-lpaif-ipq806x.h -- Definitions for the QTi LPAIF in the ipq806x LPASS
*/
#ifndef __LPASS_LPAIF_H__
#define __LPASS_LPAIF_H__
#define LPAIF_BANK_OFFSET 0x1000
/* LPAIF I2S */
#define LPAIF_I2SCTL_REG_BASE 0x0010
#define LPAIF_I2SCTL_REG_STRIDE 0x4
#define LPAIF_I2SCTL_REG_ADDR(addr, port) \
(LPAIF_I2SCTL_REG_BASE + (addr) + (LPAIF_I2SCTL_REG_STRIDE * (port)))
enum lpaif_i2s_ports {
LPAIF_I2S_PORT_MIN = 0,
LPAIF_I2S_PORT_CODEC_SPK = 0,
LPAIF_I2S_PORT_CODEC_MIC = 1,
LPAIF_I2S_PORT_SEC_SPK = 2,
LPAIF_I2S_PORT_SEC_MIC = 3,
LPAIF_I2S_PORT_MI2S = 4,
LPAIF_I2S_PORT_MAX = 4,
LPAIF_I2S_PORT_NUM = 5,
};
#define LPAIF_I2SCTL_REG(port) LPAIF_I2SCTL_REG_ADDR(0x0, (port))
#define LPAIF_I2SCTL_LOOPBACK_MASK 0x8000
#define LPAIF_I2SCTL_LOOPBACK_SHIFT 15
#define LPAIF_I2SCTL_LOOPBACK_DISABLE (0 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
#define LPAIF_I2SCTL_LOOPBACK_ENABLE (1 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
#define LPAIF_I2SCTL_SPKEN_MASK 0x4000
#define LPAIF_I2SCTL_SPKEN_SHIFT 14
#define LPAIF_I2SCTL_SPKEN_DISABLE (0 << LPAIF_I2SCTL_SPKEN_SHIFT)
#define LPAIF_I2SCTL_SPKEN_ENABLE (1 << LPAIF_I2SCTL_SPKEN_SHIFT)
#define LPAIF_I2SCTL_SPKMODE_MASK 0x3C00
#define LPAIF_I2SCTL_SPKMODE_SHIFT 10
#define LPAIF_I2SCTL_SPKMODE_NONE (0 << LPAIF_I2SCTL_SPKMODE_SHIFT)
#define LPAIF_I2SCTL_SPKMODE_SD0 (1 << LPAIF_I2SCTL_SPKMODE_SHIFT)
#define LPAIF_I2SCTL_SPKMODE_SD1 (2 << LPAIF_I2SCTL_SPKMODE_SHIFT)
#define LPAIF_I2SCTL_SPKMODE_SD2 (3 << LPAIF_I2SCTL_SPKMODE_SHIFT)
#define LPAIF_I2SCTL_SPKMODE_SD3 (4 << LPAIF_I2SCTL_SPKMODE_SHIFT)
#define LPAIF_I2SCTL_SPKMODE_QUAD01 (5 << LPAIF_I2SCTL_SPKMODE_SHIFT)
#define LPAIF_I2SCTL_SPKMODE_QUAD23 (6 << LPAIF_I2SCTL_SPKMODE_SHIFT)
#define LPAIF_I2SCTL_SPKMODE_6CH (7 << LPAIF_I2SCTL_SPKMODE_SHIFT)
#define LPAIF_I2SCTL_SPKMODE_8CH (8 << LPAIF_I2SCTL_SPKMODE_SHIFT)
#define LPAIF_I2SCTL_SPKMONO_MASK 0x0200
#define LPAIF_I2SCTL_SPKMONO_SHIFT 9
#define LPAIF_I2SCTL_SPKMONO_STEREO (0 << LPAIF_I2SCTL_SPKMONO_SHIFT)
#define LPAIF_I2SCTL_SPKMONO_MONO (1 << LPAIF_I2SCTL_SPKMONO_SHIFT)
#define LPAIF_I2SCTL_WSSRC_MASK 0x0004
#define LPAIF_I2SCTL_WSSRC_SHIFT 2
#define LPAIF_I2SCTL_WSSRC_INTERNAL (0 << LPAIF_I2SCTL_WSSRC_SHIFT)
#define LPAIF_I2SCTL_WSSRC_EXTERNAL (1 << LPAIF_I2SCTL_WSSRC_SHIFT)
#define LPAIF_I2SCTL_BITWIDTH_MASK 0x0003
#define LPAIF_I2SCTL_BITWIDTH_SHIFT 0
#define LPAIF_I2SCTL_BITWIDTH_16 (0 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
#define LPAIF_I2SCTL_BITWIDTH_24 (1 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
#define LPAIF_I2SCTL_BITWIDTH_32 (2 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
/* LPAIF IRQ */
#define LPAIF_IRQ_REG_BASE 0x3000
#define LPAIF_IRQ_REG_STRIDE 0x1000
#define LPAIF_IRQ_REG_ADDR(addr, port) \
(LPAIF_IRQ_REG_BASE + (addr) + (LPAIF_IRQ_REG_STRIDE * (port)))
enum lpaif_irq_ports {
LPAIF_IRQ_PORT_MIN = 0,
LPAIF_IRQ_PORT_HOST = 0,
LPAIF_IRQ_PORT_ADSP = 1,
LPAIF_IRQ_PORT_MAX = 2,
LPAIF_IRQ_PORT_NUM = 3,
};
#define LPAIF_IRQEN_REG(port) LPAIF_IRQ_REG_ADDR(0x0, (port))
#define LPAIF_IRQSTAT_REG(port) LPAIF_IRQ_REG_ADDR(0x4, (port))
#define LPAIF_IRQCLEAR_REG(port) LPAIF_IRQ_REG_ADDR(0xC, (port))
#define LPAIF_IRQ_BITSTRIDE 3
#define LPAIF_IRQ_PER(chan) (1 << (LPAIF_IRQ_BITSTRIDE * (chan)))
#define LPAIF_IRQ_XRUN(chan) (2 << (LPAIF_IRQ_BITSTRIDE * (chan)))
#define LPAIF_IRQ_ERR(chan) (4 << (LPAIF_IRQ_BITSTRIDE * (chan)))
#define LPAIF_IRQ_ALL(chan) (7 << (LPAIF_IRQ_BITSTRIDE * (chan)))
/* LPAIF DMA */
#define LPAIF_RDMA_REG_BASE 0x6000
#define LPAIF_RDMA_REG_STRIDE 0x1000
#define LPAIF_RDMA_REG_ADDR(addr, chan) \
(LPAIF_RDMA_REG_BASE + (addr) + (LPAIF_RDMA_REG_STRIDE * (chan)))
enum lpaif_dma_channels {
LPAIF_RDMA_CHAN_MIN = 0,
LPAIF_RDMA_CHAN_MI2S = 0,
LPAIF_RDMA_CHAN_PCM0 = 1,
LPAIF_RDMA_CHAN_PCM1 = 2,
LPAIF_RDMA_CHAN_MAX = 4,
LPAIF_RDMA_CHAN_NUM = 5,
};
#define LPAIF_RDMACTL_REG(chan) LPAIF_RDMA_REG_ADDR(0x00, (chan))
#define LPAIF_RDMABASE_REG(chan) LPAIF_RDMA_REG_ADDR(0x04, (chan))
#define LPAIF_RDMABUFF_REG(chan) LPAIF_RDMA_REG_ADDR(0x08, (chan))
#define LPAIF_RDMACURR_REG(chan) LPAIF_RDMA_REG_ADDR(0x0C, (chan))
#define LPAIF_RDMAPER_REG(chan) LPAIF_RDMA_REG_ADDR(0x10, (chan))
#define LPAIF_RDMACTL_BURSTEN_MASK 0x800
#define LPAIF_RDMACTL_BURSTEN_SHIFT 11
#define LPAIF_RDMACTL_BURSTEN_SINGLE (0 << LPAIF_RDMACTL_BURSTEN_SHIFT)
#define LPAIF_RDMACTL_BURSTEN_INCR4 (1 << LPAIF_RDMACTL_BURSTEN_SHIFT)
#define LPAIF_RDMACTL_WPSCNT_MASK 0x700
#define LPAIF_RDMACTL_WPSCNT_SHIFT 8
#define LPAIF_RDMACTL_WPSCNT_ONE (0 << LPAIF_RDMACTL_WPSCNT_SHIFT)
#define LPAIF_RDMACTL_WPSCNT_TWO (1 << LPAIF_RDMACTL_WPSCNT_SHIFT)
#define LPAIF_RDMACTL_WPSCNT_THREE (2 << LPAIF_RDMACTL_WPSCNT_SHIFT)
#define LPAIF_RDMACTL_WPSCNT_FOUR (3 << LPAIF_RDMACTL_WPSCNT_SHIFT)
#define LPAIF_RDMACTL_WPSCNT_SIX (5 << LPAIF_RDMACTL_WPSCNT_SHIFT)
#define LPAIF_RDMACTL_WPSCNT_EIGHT (7 << LPAIF_RDMACTL_WPSCNT_SHIFT)
#define LPAIF_RDMACTL_AUDINTF_MASK 0x0F0
#define LPAIF_RDMACTL_AUDINTF_SHIFT 4
#define LPAIF_RDMACTL_AUDINTF_NONE (0 << LPAIF_RDMACTL_AUDINTF_SHIFT)
#define LPAIF_RDMACTL_AUDINTF_CODEC (1 << LPAIF_RDMACTL_AUDINTF_SHIFT)
#define LPAIF_RDMACTL_AUDINTF_PCM (2 << LPAIF_RDMACTL_AUDINTF_SHIFT)
#define LPAIF_RDMACTL_AUDINTF_SEC_I2S (3 << LPAIF_RDMACTL_AUDINTF_SHIFT)
#define LPAIF_RDMACTL_AUDINTF_MI2S (4 << LPAIF_RDMACTL_AUDINTF_SHIFT)
#define LPAIF_RDMACTL_AUDINTF_HDMI (5 << LPAIF_RDMACTL_AUDINTF_SHIFT)
#define LPAIF_RDMACTL_AUDINTF_SEC_PCM (7 << LPAIF_RDMACTL_AUDINTF_SHIFT)
#define LPAIF_RDMACTL_FIFOWM_MASK 0x00E
#define LPAIF_RDMACTL_FIFOWM_SHIFT 1
#define LPAIF_RDMACTL_FIFOWM_1 (0 << LPAIF_RDMACTL_FIFOWM_SHIFT)
#define LPAIF_RDMACTL_FIFOWM_2 (1 << LPAIF_RDMACTL_FIFOWM_SHIFT)
#define LPAIF_RDMACTL_FIFOWM_3 (2 << LPAIF_RDMACTL_FIFOWM_SHIFT)
#define LPAIF_RDMACTL_FIFOWM_4 (3 << LPAIF_RDMACTL_FIFOWM_SHIFT)
#define LPAIF_RDMACTL_FIFOWM_5 (4 << LPAIF_RDMACTL_FIFOWM_SHIFT)
#define LPAIF_RDMACTL_FIFOWM_6 (5 << LPAIF_RDMACTL_FIFOWM_SHIFT)
#define LPAIF_RDMACTL_FIFOWM_7 (6 << LPAIF_RDMACTL_FIFOWM_SHIFT)
#define LPAIF_RDMACTL_FIFOWM_8 (7 << LPAIF_RDMACTL_FIFOWM_SHIFT)
#define LPAIF_RDMACTL_ENABLE_MASK 0x1
#define LPAIF_RDMACTL_ENABLE_SHIFT 0
#define LPAIF_RDMACTL_ENABLE_OFF (0 << LPAIF_RDMACTL_ENABLE_SHIFT)
#define LPAIF_RDMACTL_ENABLE_ON (1 << LPAIF_RDMACTL_ENABLE_SHIFT)
#endif /* __LPASS_LPAIF_H__ */
This diff is collapsed.
/*
* Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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.
*
* lpass.h - Definitions for the QTi LPASS
*/
#ifndef __LPASS_H__
#define __LPASS_H__
#include <linux/clk.h>
#include <linux/compiler.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#define LPASS_AHBIX_CLOCK_FREQUENCY 131072000
/* Both the CPU DAI and platform drivers will access this data */
struct lpass_data {
/* AHB-I/X bus clocks inside the low-power audio subsystem (LPASS) */
struct clk *ahbix_clk;
/* MI2S system clock */
struct clk *mi2s_osr_clk;
/* MI2S bit clock (derived from system clock by a divider */
struct clk *mi2s_bit_clk;
/* low-power audio interface (LPAIF) registers */
void __iomem *lpaif;
/* regmap backed by the low-power audio interface (LPAIF) registers */
struct regmap *lpaif_map;
/* interrupts from the low-power audio interface (LPAIF) */
int lpaif_irq;
};
/* register the platform driver from the CPU DAI driver */
int asoc_qcom_lpass_platform_register(struct platform_device *);
#endif /* __LPASS_H__ */
/*
* Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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.
*
* storm.c -- ALSA SoC machine driver for QTi ipq806x-based Storm board
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#define STORM_SYSCLK_MULT 4
static int storm_ops_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
struct snd_soc_card *card = soc_runtime->card;
snd_pcm_format_t format = params_format(params);
unsigned int rate = params_rate(params);
unsigned int sysclk_freq;
int bitwidth, ret;
bitwidth = snd_pcm_format_width(format);
if (bitwidth < 0) {
dev_err(card->dev, "%s() invalid bit width given: %d\n",
__func__, bitwidth);
return bitwidth;
}
/*
* as the CPU DAI is the I2S bus master and no system clock is needed by
* the MAX98357a DAC, simply set the system clock to be a constant
* multiple of the bit clock for the clock divider
*/
sysclk_freq = rate * bitwidth * 2 * STORM_SYSCLK_MULT;
ret = snd_soc_dai_set_sysclk(soc_runtime->cpu_dai, 0, sysclk_freq, 0);
if (ret) {
dev_err(card->dev, "%s() error setting sysclk to %u: %d\n",
__func__, sysclk_freq, ret);
return ret;
}
return 0;
}
static struct snd_soc_ops storm_soc_ops = {
.hw_params = storm_ops_hw_params,
};
static struct snd_soc_dai_link storm_dai_link = {
.name = "Primary",
.stream_name = "Primary",
.codec_dai_name = "HiFi",
.ops = &storm_soc_ops,
};
static struct snd_soc_card storm_soc_card = {
.name = "ipq806x-storm",
.dev = NULL,
};
static int storm_parse_of(struct snd_soc_card *card)
{
struct snd_soc_dai_link *dai_link = card->dai_link;
struct device_node *np = card->dev->of_node;
dai_link->cpu_of_node = of_parse_phandle(np, "cpu", 0);
if (!dai_link->cpu_of_node) {
dev_err(card->dev, "%s() error getting cpu phandle\n",
__func__);
return -EINVAL;
}
dai_link->platform_of_node = dai_link->cpu_of_node;
dai_link->codec_of_node = of_parse_phandle(np, "codec", 0);
if (!dai_link->codec_of_node) {
dev_err(card->dev, "%s() error getting codec phandle\n",
__func__);
return -EINVAL;
}
return 0;
}
static int storm_platform_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = &storm_soc_card;
int ret;
if (card->dev) {
dev_err(&pdev->dev, "%s() error, existing soundcard\n",
__func__);
return -ENODEV;
}
card->dev = &pdev->dev;
platform_set_drvdata(pdev, card);
ret = snd_soc_of_parse_card_name(card, "qcom,model");
if (ret) {
dev_err(&pdev->dev, "%s() error parsing card name: %d\n",
__func__, ret);
return ret;
}
card->dai_link = &storm_dai_link;
card->num_links = 1;
ret = storm_parse_of(card);
if (ret) {
dev_err(&pdev->dev, "%s() error resolving dai links: %d\n",
__func__, ret);
return ret;
}
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret == -EPROBE_DEFER) {
card->dev = NULL;
return ret;
} else if (ret) {
dev_err(&pdev->dev, "%s() error registering soundcard: %d\n",
__func__, ret);
return ret;
}
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id storm_device_id[] = {
{ .compatible = "google,storm-audio" },
{},
};
MODULE_DEVICE_TABLE(of, storm_device_id);
#endif
static struct platform_driver storm_platform_driver = {
.driver = {
.name = "storm-audio",
.of_match_table =
of_match_ptr(storm_device_id),
},
.probe = storm_platform_probe,
};
module_platform_driver(storm_platform_driver);
MODULE_DESCRIPTION("QTi IPQ806x-based Storm Machine Driver");
MODULE_LICENSE("GPL v2");
......@@ -36,11 +36,17 @@ config SND_SOC_SH4_SIU
config SND_SOC_RCAR
tristate "R-Car series SRU/SCU/SSIU/SSI support"
depends on DMA_OF
select SND_SIMPLE_CARD
select REGMAP_MMIO
help
This option enables R-Car SUR/SCU/SSIU/SSI sound support
config SND_SOC_RSRC_CARD
tristate "Renesas Sampling Rate Convert Sound Card"
help
This option enables simple sound if you need sampling rate convert
##
## Boards
##
......
snd-soc-rcar-objs := core.o gen.o src.o adg.o ssi.o dvc.o
obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o
\ No newline at end of file
snd-soc-rcar-objs := core.o gen.o dma.o src.o adg.o ssi.o dvc.o
obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o
snd-soc-rsrc-card-objs := rsrc-card.o
obj-$(CONFIG_SND_SOC_RSRC_CARD) += snd-soc-rsrc-card.o
......@@ -183,6 +183,8 @@ int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
rsnd_mod_bset(mod, DIV_EN, en, en);
dev_dbg(dev, "convert rate %d <-> %d\n", src_rate, dst_rate);
return 0;
}
......@@ -432,7 +434,5 @@ int rsnd_adg_probe(struct platform_device *pdev,
priv->adg = adg;
dev_dbg(dev, "adg probed\n");
return 0;
}
......@@ -94,21 +94,20 @@
*
*/
#include <linux/pm_runtime.h>
#include <linux/shdma-base.h>
#include "rsnd.h"
#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 = {
static const struct rsnd_of_data rsnd_of_data_gen1 = {
.flags = RSND_GEN1,
};
static struct rsnd_of_data rsnd_of_data_gen2 = {
static const struct rsnd_of_data rsnd_of_data_gen2 = {
.flags = RSND_GEN2,
};
static struct of_device_id rsnd_of_match[] = {
static const 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 },
{},
......@@ -138,15 +137,12 @@ char *rsnd_mod_name(struct rsnd_mod *mod)
return mod->ops->name;
}
char *rsnd_mod_dma_name(struct rsnd_mod *mod)
struct dma_chan *rsnd_mod_dma_req(struct rsnd_mod *mod)
{
if (!mod || !mod->ops)
return "unknown";
if (!mod->ops->dma_name)
return mod->ops->name;
if (!mod || !mod->ops || !mod->ops->dma_req)
return NULL;
return mod->ops->dma_name(mod);
return mod->ops->dma_req(mod);
}
int rsnd_mod_init(struct rsnd_mod *mod,
......@@ -174,228 +170,6 @@ void rsnd_mod_quit(struct rsnd_mod *mod)
clk_unprepare(mod->clk);
}
/*
* rsnd_dma functions
*/
void rsnd_dma_stop(struct rsnd_dma *dma)
{
dmaengine_terminate_all(dma->chan);
}
static void rsnd_dma_complete(void *data)
{
struct rsnd_dma *dma = (struct rsnd_dma *)data;
struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
/*
* Renesas sound Gen1 needs 1 DMAC,
* Gen2 needs 2 DMAC.
* In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri.
* But, Audio-DMAC-peri-peri doesn't have interrupt,
* and this driver is assuming that here.
*
* If Audio-DMAC-peri-peri has interrpt,
* rsnd_dai_pointer_update() will be called twice,
* ant it will breaks io->byte_pos
*/
rsnd_dai_pointer_update(io, io->byte_per_period);
}
void rsnd_dma_start(struct rsnd_dma *dma)
{
struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
struct snd_pcm_substream *substream = io->substream;
struct device *dev = rsnd_priv_to_dev(priv);
struct dma_async_tx_descriptor *desc;
desc = dmaengine_prep_dma_cyclic(dma->chan,
(dma->addr) ? dma->addr :
substream->runtime->dma_addr,
snd_pcm_lib_buffer_bytes(substream),
snd_pcm_lib_period_bytes(substream),
dma->dir,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
return;
}
desc->callback = rsnd_dma_complete;
desc->callback_param = dma;
if (dmaengine_submit(desc) < 0) {
dev_err(dev, "dmaengine_submit() fail\n");
return;
}
dma_async_issue_pending(dma->chan);
}
int rsnd_dma_available(struct rsnd_dma *dma)
{
return !!dma->chan;
}
#define DMA_NAME_SIZE 16
#define MOD_MAX 4 /* MEM/SSI/SRC/DVC */
static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod)
{
if (mod)
return snprintf(dma_name, DMA_NAME_SIZE / 2, "%s%d",
rsnd_mod_dma_name(mod), rsnd_mod_id(mod));
else
return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem");
}
static void rsnd_dma_of_name(struct rsnd_mod *mod_from,
struct rsnd_mod *mod_to,
char *dma_name)
{
int index = 0;
index = _rsnd_dma_of_name(dma_name + index, mod_from);
*(dma_name + index++) = '_';
index = _rsnd_dma_of_name(dma_name + index, mod_to);
}
static void rsnd_dma_of_path(struct rsnd_dma *dma,
int is_play,
struct rsnd_mod **mod_from,
struct rsnd_mod **mod_to)
{
struct rsnd_mod *this = rsnd_dma_to_mod(dma);
struct rsnd_dai_stream *io = rsnd_mod_to_io(this);
struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
struct rsnd_mod *mod[MOD_MAX];
int i, index;
for (i = 0; i < MOD_MAX; i++)
mod[i] = NULL;
/*
* in play case...
*
* src -> dst
*
* mem -> SSI
* mem -> SRC -> SSI
* mem -> SRC -> DVC -> SSI
*/
mod[0] = NULL; /* for "mem" */
index = 1;
for (i = 1; i < MOD_MAX; i++) {
if (!src) {
mod[i] = ssi;
} else if (!dvc) {
mod[i] = src;
src = NULL;
} else {
if ((!is_play) && (this == src))
this = dvc;
mod[i] = (is_play) ? src : dvc;
i++;
mod[i] = (is_play) ? dvc : src;
src = NULL;
dvc = NULL;
}
if (mod[i] == this)
index = i;
if (mod[i] == ssi)
break;
}
if (is_play) {
*mod_from = mod[index - 1];
*mod_to = mod[index];
} else {
*mod_from = mod[index];
*mod_to = mod[index - 1];
}
}
int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
int is_play, int id)
{
struct device *dev = rsnd_priv_to_dev(priv);
struct dma_slave_config cfg;
struct rsnd_mod *mod_from;
struct rsnd_mod *mod_to;
char dma_name[DMA_NAME_SIZE];
dma_cap_mask_t mask;
int ret;
if (dma->chan) {
dev_err(dev, "it already has dma channel\n");
return -EIO;
}
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
rsnd_dma_of_path(dma, is_play, &mod_from, &mod_to);
rsnd_dma_of_name(mod_from, mod_to, dma_name);
cfg.slave_id = id;
cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
cfg.src_addr = rsnd_gen_dma_addr(priv, mod_from, is_play, 1);
cfg.dst_addr = rsnd_gen_dma_addr(priv, mod_to, is_play, 0);
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
dev_dbg(dev, "dma : %s %pad -> %pad\n",
dma_name, &cfg.src_addr, &cfg.dst_addr);
dma->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
(void *)id, dev,
dma_name);
if (!dma->chan) {
dev_err(dev, "can't get dma channel\n");
goto rsnd_dma_channel_err;
}
ret = dmaengine_slave_config(dma->chan, &cfg);
if (ret < 0)
goto rsnd_dma_init_err;
dma->addr = is_play ? cfg.src_addr : cfg.dst_addr;
dma->dir = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
return 0;
rsnd_dma_init_err:
rsnd_dma_quit(priv, dma);
rsnd_dma_channel_err:
/*
* DMA failed. try to PIO mode
* see
* rsnd_ssi_fallback()
* rsnd_rdai_continuance_probe()
*/
return -EAGAIN;
}
void rsnd_dma_quit(struct rsnd_priv *priv,
struct rsnd_dma *dma)
{
if (dma->chan)
dma_release_channel(dma->chan);
dma->chan = NULL;
}
/*
* settting function
*/
......@@ -429,7 +203,7 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod)
({ \
struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \
struct device *dev = rsnd_priv_to_dev(priv); \
u32 mask = 1 << __rsnd_mod_shift_##func; \
u32 mask = (1 << __rsnd_mod_shift_##func) & ~(1 << 31); \
u32 call = __rsnd_mod_call_##func << __rsnd_mod_shift_##func; \
int ret = 0; \
if ((mod->status & mask) == call) { \
......@@ -471,7 +245,7 @@ static int rsnd_dai_connect(struct rsnd_mod *mod,
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
dev_err(dev, "%s%d is not empty\n",
dev_err(dev, "%s[%d] is not empty\n",
rsnd_mod_name(mod),
rsnd_mod_id(mod));
return -EIO;
......@@ -887,20 +661,28 @@ static int rsnd_dai_probe(struct platform_device *pdev,
drv[i].name = rdai[i].name;
drv[i].ops = &rsnd_soc_dai_ops;
if (pmod) {
snprintf(rdai[i].playback.name, RSND_DAI_NAME_SIZE,
"DAI%d Playback", i);
drv[i].playback.rates = RSND_RATES;
drv[i].playback.formats = RSND_FMTS;
drv[i].playback.channels_min = 2;
drv[i].playback.channels_max = 2;
drv[i].playback.stream_name = rdai[i].playback.name;
rdai[i].playback.info = &info->dai_info[i].playback;
rdai[i].playback.rdai = rdai + i;
rsnd_path_init(priv, &rdai[i], &rdai[i].playback);
}
if (cmod) {
snprintf(rdai[i].capture.name, RSND_DAI_NAME_SIZE,
"DAI%d Capture", i);
drv[i].capture.rates = RSND_RATES;
drv[i].capture.formats = RSND_FMTS;
drv[i].capture.channels_min = 2;
drv[i].capture.channels_max = 2;
drv[i].capture.stream_name = rdai[i].capture.name;
rdai[i].capture.info = &info->dai_info[i].capture;
rdai[i].capture.rdai = rdai + i;
......@@ -946,6 +728,15 @@ static int rsnd_pcm_open(struct snd_pcm_substream *substream)
static int rsnd_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
int ret;
ret = rsnd_dai_call(hw_params, io, substream, hw_params);
if (ret)
return ret;
return snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
}
......@@ -1210,6 +1001,7 @@ static int rsnd_probe(struct platform_device *pdev)
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv) = {
rsnd_gen_probe,
rsnd_dma_probe,
rsnd_ssi_probe,
rsnd_src_probe,
rsnd_dvc_probe,
......
This diff is collapsed.
......@@ -24,6 +24,9 @@ struct rsnd_dvc {
struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */
};
#define rsnd_dvc_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
#define rsnd_mod_to_dvc(_mod) \
container_of((_mod), struct rsnd_dvc, mod)
......@@ -33,7 +36,7 @@ struct rsnd_dvc {
((pos) = (struct rsnd_dvc *)(priv)->dvc + i); \
i++)
static const char const *dvc_ramp_rate[] = {
static const char * const dvc_ramp_rate[] = {
"128 dB/1 step", /* 00000 */
"64 dB/1 step", /* 00001 */
"32 dB/1 step", /* 00010 */
......@@ -116,17 +119,6 @@ static void rsnd_dvc_volume_update(struct rsnd_mod *mod)
rsnd_mod_write(mod, DVC_DVUER, 1);
}
static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod,
struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
dev_dbg(dev, "%s[%d] (Gen2) is probed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
return 0;
}
static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod,
struct rsnd_priv *priv)
{
......@@ -269,9 +261,17 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
return 0;
}
static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_mod *mod)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
return rsnd_dma_request_channel(rsnd_dvc_of_node(priv),
mod, "tx");
}
static struct rsnd_mod_ops rsnd_dvc_ops = {
.name = DVC_NAME,
.probe = rsnd_dvc_probe_gen2,
.dma_req = rsnd_dvc_dma_req,
.remove = rsnd_dvc_remove_gen2,
.init = rsnd_dvc_init,
.quit = rsnd_dvc_quit,
......@@ -370,8 +370,6 @@ int rsnd_dvc_probe(struct platform_device *pdev,
clk, RSND_MOD_DVC, i);
if (ret)
return ret;
dev_dbg(dev, "CMD%d probed\n", i);
}
return 0;
......
......@@ -28,6 +28,7 @@ struct rsnd_gen {
struct regmap *regmap[RSND_BASE_MAX];
struct regmap_field *regs[RSND_REG_MAX];
phys_addr_t res[RSND_REG_MAX];
};
#define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen)
......@@ -118,11 +119,19 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
mask, data);
}
#define rsnd_gen_regmap_init(priv, id_size, reg_id, conf) \
_rsnd_gen_regmap_init(priv, id_size, reg_id, conf, ARRAY_SIZE(conf))
phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id)
{
struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
return gen->res[reg_id];
}
#define rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf) \
_rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf, ARRAY_SIZE(conf))
static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
int id_size,
int reg_id,
const char *name,
struct rsnd_regmap_field_conf *conf,
int conf_size)
{
......@@ -141,8 +150,11 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
regc.reg_bits = 32;
regc.val_bits = 32;
regc.reg_stride = 4;
regc.name = name;
res = platform_get_resource(pdev, IORESOURCE_MEM, reg_id);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
if (!res)
res = platform_get_resource(pdev, IORESOURCE_MEM, reg_id);
if (!res)
return -ENODEV;
......@@ -156,6 +168,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
gen->base[reg_id] = base;
gen->regmap[reg_id] = regmap;
gen->res[reg_id] = res->start;
for (i = 0; i < conf_size; i++) {
......@@ -175,126 +188,12 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
return 0;
}
/*
* DMA read/write register offset
*
* RSND_xxx_I_N for Audio DMAC input
* RSND_xxx_O_N for Audio DMAC output
* RSND_xxx_I_P for Audio DMAC peri peri input
* RSND_xxx_O_P for Audio DMAC peri peri output
*
* ex) R-Car H2 case
* mod / DMAC in / DMAC out / DMAC PP in / DMAC pp out
* SSI : 0xec541000 / 0xec241008 / 0xec24100c
* SSIU: 0xec541000 / 0xec100000 / 0xec100000 / 0xec400000 / 0xec400000
* SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000
* CMD : 0xec500000 / / 0xec008000 0xec308000
*/
#define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8)
#define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc)
#define RDMA_SSIU_I_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i))
#define RDMA_SSIU_O_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i))
#define RDMA_SSIU_I_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i))
#define RDMA_SSIU_O_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i))
#define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i))
#define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i))
#define RDMA_SRC_I_P(addr, i) (addr ##_reg - 0x00200000 + (0x400 * i))
#define RDMA_SRC_O_P(addr, i) (addr ##_reg - 0x001fc000 + (0x400 * i))
#define RDMA_CMD_O_N(addr, i) (addr ##_reg - 0x004f8000 + (0x400 * i))
#define RDMA_CMD_O_P(addr, i) (addr ##_reg - 0x001f8000 + (0x400 * i))
static dma_addr_t
rsnd_gen2_dma_addr(struct rsnd_priv *priv,
struct rsnd_mod *mod,
int is_play, int is_from)
{
struct platform_device *pdev = rsnd_priv_to_pdev(priv);
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
dma_addr_t ssi_reg = platform_get_resource(pdev,
IORESOURCE_MEM, RSND_GEN2_SSI)->start;
dma_addr_t src_reg = platform_get_resource(pdev,
IORESOURCE_MEM, RSND_GEN2_SCU)->start;
int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod);
int use_src = !!rsnd_io_to_mod_src(io);
int use_dvc = !!rsnd_io_to_mod_dvc(io);
int id = rsnd_mod_id(mod);
struct dma_addr {
dma_addr_t out_addr;
dma_addr_t in_addr;
} dma_addrs[3][2][3] = {
/* SRC */
{{{ 0, 0 },
/* Capture */
{ RDMA_SRC_O_N(src, id), RDMA_SRC_I_P(src, id) },
{ RDMA_CMD_O_N(src, id), RDMA_SRC_I_P(src, id) } },
/* Playback */
{{ 0, 0, },
{ RDMA_SRC_O_P(src, id), RDMA_SRC_I_N(src, id) },
{ RDMA_CMD_O_P(src, id), RDMA_SRC_I_N(src, id) } }
},
/* SSI */
/* Capture */
{{{ RDMA_SSI_O_N(ssi, id), 0 },
{ RDMA_SSIU_O_P(ssi, id), 0 },
{ RDMA_SSIU_O_P(ssi, id), 0 } },
/* Playback */
{{ 0, RDMA_SSI_I_N(ssi, id) },
{ 0, RDMA_SSIU_I_P(ssi, id) },
{ 0, RDMA_SSIU_I_P(ssi, id) } }
},
/* SSIU */
/* Capture */
{{{ RDMA_SSIU_O_N(ssi, id), 0 },
{ RDMA_SSIU_O_P(ssi, id), 0 },
{ RDMA_SSIU_O_P(ssi, id), 0 } },
/* Playback */
{{ 0, RDMA_SSIU_I_N(ssi, id) },
{ 0, RDMA_SSIU_I_P(ssi, id) },
{ 0, RDMA_SSIU_I_P(ssi, id) } } },
};
/* it shouldn't happen */
if (use_dvc && !use_src)
dev_err(dev, "DVC is selected without SRC\n");
/* use SSIU or SSI ? */
if (is_ssi && (0 == strcmp(rsnd_mod_dma_name(mod), "ssiu")))
is_ssi++;
return (is_from) ?
dma_addrs[is_ssi][is_play][use_src + use_dvc].out_addr :
dma_addrs[is_ssi][is_play][use_src + use_dvc].in_addr;
}
dma_addr_t rsnd_gen_dma_addr(struct rsnd_priv *priv,
struct rsnd_mod *mod,
int is_play, int is_from)
{
/*
* gen1 uses default DMA addr
*/
if (rsnd_is_gen1(priv))
return 0;
if (!mod)
return 0;
return rsnd_gen2_dma_addr(priv, mod, is_play, is_from);
}
/*
* Gen2
*/
static int rsnd_gen2_probe(struct platform_device *pdev,
struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_regmap_field_conf conf_ssiu[] = {
RSND_GEN_S_REG(SSI_MODE0, 0x800),
RSND_GEN_S_REG(SSI_MODE1, 0x804),
......@@ -368,18 +267,16 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
int ret_adg;
int ret_ssi;
ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSIU, conf_ssiu);
ret_scu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SCU, conf_scu);
ret_adg = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_ADG, conf_adg);
ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSI, conf_ssi);
ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSIU, "ssiu", conf_ssiu);
ret_scu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SCU, "scu", conf_scu);
ret_adg = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_ADG, "adg", conf_adg);
ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSI, "ssi", conf_ssi);
if (ret_ssiu < 0 ||
ret_scu < 0 ||
ret_adg < 0 ||
ret_ssi < 0)
return ret_ssiu | ret_scu | ret_adg | ret_ssi;
dev_dbg(dev, "Gen2 is probed\n");
return 0;
}
......@@ -390,7 +287,6 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
static int rsnd_gen1_probe(struct platform_device *pdev,
struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_regmap_field_conf conf_sru[] = {
RSND_GEN_S_REG(SRC_ROUTE_SEL, 0x00),
RSND_GEN_S_REG(SRC_TMG_SEL0, 0x08),
......@@ -440,16 +336,14 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
int ret_adg;
int ret_ssi;
ret_sru = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SRU, conf_sru);
ret_adg = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, conf_adg);
ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, conf_ssi);
ret_sru = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SRU, "sru", conf_sru);
ret_adg = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, "adg", conf_adg);
ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, "ssi", conf_ssi);
if (ret_sru < 0 ||
ret_adg < 0 ||
ret_ssi < 0)
return ret_sru | ret_adg | ret_ssi;
dev_dbg(dev, "Gen1 is probed\n");
return 0;
}
......
......@@ -170,21 +170,47 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod);
/*
* R-Car DMA
*/
struct rsnd_dma {
struct sh_dmae_slave slave;
struct rsnd_dma;
struct rsnd_dma_ops {
void (*start)(struct rsnd_dma *dma);
void (*stop)(struct rsnd_dma *dma);
int (*init)(struct rsnd_priv *priv, struct rsnd_dma *dma, int id,
struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
void (*quit)(struct rsnd_dma *dma);
};
struct rsnd_dmaen {
struct dma_chan *chan;
enum dma_transfer_direction dir;
dma_addr_t addr;
};
struct rsnd_dmapp {
int dmapp_id;
u32 chcr;
};
struct rsnd_dma {
struct rsnd_dma_ops *ops;
dma_addr_t src_addr;
dma_addr_t dst_addr;
union {
struct rsnd_dmaen en;
struct rsnd_dmapp pp;
} dma;
};
#define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en)
#define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp)
void rsnd_dma_start(struct rsnd_dma *dma);
void rsnd_dma_stop(struct rsnd_dma *dma);
int rsnd_dma_available(struct rsnd_dma *dma);
int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
int is_play, int id);
void rsnd_dma_quit(struct rsnd_priv *priv,
struct rsnd_dma *dma);
int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id);
void rsnd_dma_quit(struct rsnd_dma *dma);
int rsnd_dma_probe(struct platform_device *pdev,
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv);
struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
struct rsnd_mod *mod, char *name);
#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
/*
* R-Car sound mod
......@@ -198,7 +224,7 @@ enum rsnd_mod_type {
struct rsnd_mod_ops {
char *name;
char* (*dma_name)(struct rsnd_mod *mod);
struct dma_chan* (*dma_req)(struct rsnd_mod *mod);
int (*probe)(struct rsnd_mod *mod,
struct rsnd_priv *priv);
int (*remove)(struct rsnd_mod *mod,
......@@ -213,6 +239,9 @@ struct rsnd_mod_ops {
struct rsnd_priv *priv);
int (*pcm_new)(struct rsnd_mod *mod,
struct snd_soc_pcm_runtime *rtd);
int (*hw_params)(struct rsnd_mod *mod,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params);
int (*fallback)(struct rsnd_mod *mod,
struct rsnd_priv *priv);
};
......@@ -236,6 +265,9 @@ struct rsnd_mod {
* 2 0: start 1: stop
* 3 0: pcm_new
* 4 0: fallback
*
* 31 bit is always called (see __rsnd_mod_call)
* 31 0: hw_params
*/
#define __rsnd_mod_shift_probe 0
#define __rsnd_mod_shift_remove 0
......@@ -245,6 +277,7 @@ struct rsnd_mod {
#define __rsnd_mod_shift_stop 2
#define __rsnd_mod_shift_pcm_new 3
#define __rsnd_mod_shift_fallback 4
#define __rsnd_mod_shift_hw_params 31 /* always called */
#define __rsnd_mod_call_probe 0
#define __rsnd_mod_call_remove 1
......@@ -254,10 +287,10 @@ struct rsnd_mod {
#define __rsnd_mod_call_stop 1
#define __rsnd_mod_call_pcm_new 0
#define __rsnd_mod_call_fallback 0
#define __rsnd_mod_call_hw_params 0
#define rsnd_mod_to_priv(mod) (rsnd_io_to_priv(rsnd_mod_to_io(mod)))
#define rsnd_mod_to_dma(mod) (&(mod)->dma)
#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
#define rsnd_mod_to_io(mod) ((mod)->io)
#define rsnd_mod_id(mod) ((mod)->id)
#define rsnd_mod_hw_start(mod) clk_enable((mod)->clk)
......@@ -270,13 +303,14 @@ int rsnd_mod_init(struct rsnd_mod *mod,
int id);
void rsnd_mod_quit(struct rsnd_mod *mod);
char *rsnd_mod_name(struct rsnd_mod *mod);
char *rsnd_mod_dma_name(struct rsnd_mod *mod);
struct dma_chan *rsnd_mod_dma_req(struct rsnd_mod *mod);
/*
* R-Car sound DAI
*/
#define RSND_DAI_NAME_SIZE 16
struct rsnd_dai_stream {
char name[RSND_DAI_NAME_SIZE];
struct snd_pcm_substream *substream;
struct rsnd_mod *mod[RSND_MOD_MAX];
struct rsnd_dai_path_info *info; /* rcar_snd.h */
......@@ -332,9 +366,7 @@ int rsnd_gen_probe(struct platform_device *pdev,
void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
struct rsnd_mod *mod,
enum rsnd_reg reg);
dma_addr_t rsnd_gen_dma_addr(struct rsnd_priv *priv,
struct rsnd_mod *mod,
int is_play, int is_from);
phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id);
#define rsnd_is_gen1(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1)
#define rsnd_is_gen2(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2)
......@@ -389,6 +421,11 @@ struct rsnd_priv {
*/
void *adg;
/*
* below value will be filled on rsnd_dma_probe()
*/
void *dma;
/*
* below value will be filled on rsnd_ssi_probe()
*/
......@@ -415,19 +452,6 @@ struct rsnd_priv {
#define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags)
#define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags)
#define rsnd_info_is_playback(priv, type) \
({ \
struct rcar_snd_info *info = rsnd_priv_to_info(priv); \
int i, is_play = 0; \
for (i = 0; i < info->dai_info_nr; i++) { \
if (info->dai_info[i].playback.type == (type)->info) { \
is_play = 1; \
break; \
} \
} \
is_play; \
})
/*
* rsnd_kctrl
*/
......@@ -506,6 +530,7 @@ void rsnd_ssi_remove(struct platform_device *pdev,
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
int rsnd_ssi_use_busif(struct rsnd_mod *mod);
/*
* R-Car DVC
......
This diff is collapsed.
......@@ -22,16 +22,20 @@
struct rsnd_src {
struct rsnd_src_platform_info *info; /* rcar_snd.h */
struct rsnd_mod mod;
struct rsnd_kctrl_cfg_s sen; /* sync convert enable */
struct rsnd_kctrl_cfg_s sync; /* sync convert */
u32 convert_rate; /* sampling rate convert */
int err;
};
#define RSND_SRC_NAME_SIZE 16
#define rsnd_src_convert_rate(p) ((p)->info->convert_rate)
#define rsnd_enable_sync_convert(src) ((src)->sen.val)
#define rsnd_src_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src")
#define rsnd_mod_to_src(_mod) \
container_of((_mod), struct rsnd_src, mod)
#define rsnd_src_dma_available(src) \
rsnd_dma_available(rsnd_mod_to_dma(&(src)->mod))
#define for_each_rsnd_src(pos, priv, i) \
for ((i) = 0; \
......@@ -113,6 +117,17 @@ struct rsnd_src {
/*
* Gen1/Gen2 common functions
*/
static struct dma_chan *rsnd_src_dma_req(struct rsnd_mod *mod)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
int is_play = rsnd_io_is_play(io);
return rsnd_dma_request_channel(rsnd_src_of_node(priv),
mod,
is_play ? "rx" : "tx");
}
int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
int use_busif)
{
......@@ -220,6 +235,30 @@ int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod)
return 0;
}
static u32 rsnd_src_convert_rate(struct rsnd_src *src)
{
struct rsnd_mod *mod = &src->mod;
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
u32 convert_rate;
if (!runtime)
return 0;
if (!rsnd_enable_sync_convert(src))
return src->convert_rate;
convert_rate = src->sync.val;
if (!convert_rate)
convert_rate = src->convert_rate;
if (!convert_rate)
convert_rate = runtime->rate;
return convert_rate;
}
unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
struct rsnd_dai_stream *io,
struct snd_pcm_runtime *runtime)
......@@ -276,7 +315,43 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod)
return 0;
}
static int rsnd_src_init(struct rsnd_mod *mod)
static int rsnd_src_hw_params(struct rsnd_mod *mod,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *fe_params)
{
struct rsnd_src *src = rsnd_mod_to_src(mod);
struct snd_soc_pcm_runtime *fe = substream->private_data;
/* default value (mainly for non-DT) */
src->convert_rate = src->info->convert_rate;
/*
* SRC assumes that it is used under DPCM if user want to use
* sampling rate convert. Then, SRC should be FE.
* And then, this function will be called *after* BE settings.
* this means, each BE already has fixuped hw_params.
* see
* dpcm_fe_dai_hw_params()
* dpcm_be_dai_hw_params()
*/
if (fe->dai_link->dynamic) {
int stream = substream->stream;
struct snd_soc_dpcm *dpcm;
struct snd_pcm_hw_params *be_params;
list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
be_params = &dpcm->hw_params;
if (params_rate(fe_params) != params_rate(be_params))
src->convert_rate = params_rate(be_params);
}
}
return 0;
}
static int rsnd_src_init(struct rsnd_mod *mod,
struct rsnd_priv *priv)
{
struct rsnd_src *src = rsnd_mod_to_src(mod);
......@@ -284,6 +359,9 @@ static int rsnd_src_init(struct rsnd_mod *mod)
src->err = 0;
/* reset sync convert_rate */
src->sync.val = 0;
/*
* Initialize the operation of the SRC internal circuits
* see rsnd_src_start()
......@@ -305,6 +383,11 @@ static int rsnd_src_quit(struct rsnd_mod *mod,
dev_warn(dev, "%s[%d] under/over flow err = %d\n",
rsnd_mod_name(mod), rsnd_mod_id(mod), src->err);
src->convert_rate = 0;
/* reset sync convert_rate */
src->sync.val = 0;
return 0;
}
......@@ -448,23 +531,12 @@ static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod)
return 0;
}
static int rsnd_src_probe_gen1(struct rsnd_mod *mod,
struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
dev_dbg(dev, "%s[%d] (Gen1) is probed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
return 0;
}
static int rsnd_src_init_gen1(struct rsnd_mod *mod,
struct rsnd_priv *priv)
{
int ret;
ret = rsnd_src_init(mod);
ret = rsnd_src_init(mod, priv);
if (ret < 0)
return ret;
......@@ -505,11 +577,12 @@ static int rsnd_src_stop_gen1(struct rsnd_mod *mod,
static struct rsnd_mod_ops rsnd_src_gen1_ops = {
.name = SRC_NAME,
.probe = rsnd_src_probe_gen1,
.dma_req = rsnd_src_dma_req,
.init = rsnd_src_init_gen1,
.quit = rsnd_src_quit,
.start = rsnd_src_start_gen1,
.stop = rsnd_src_stop_gen1,
.hw_params = rsnd_src_hw_params,
};
/*
......@@ -607,13 +680,17 @@ static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data)
if (rsnd_src_error_record_gen2(mod)) {
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct rsnd_src *src = rsnd_mod_to_src(mod);
struct device *dev = rsnd_priv_to_dev(priv);
_rsnd_src_stop_gen2(mod);
_rsnd_src_start_gen2(mod);
dev_dbg(dev, "%s[%d] restart\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
_rsnd_src_stop_gen2(mod);
if (src->err < 1024)
_rsnd_src_start_gen2(mod);
else
dev_warn(dev, "no more SRC restart\n");
}
return IRQ_HANDLED;
......@@ -627,6 +704,7 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod)
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct rsnd_src *src = rsnd_mod_to_src(mod);
u32 convert_rate = rsnd_src_convert_rate(src);
u32 cr, route;
uint ratio;
int ret;
......@@ -647,13 +725,21 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod)
if (ret < 0)
return ret;
rsnd_mod_write(mod, SRC_SRCCR, 0x00011110);
cr = 0x00011110;
route = 0x0;
if (convert_rate) {
/* Gen1/Gen2 are not compatible */
rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
route = 0x1;
if (rsnd_enable_sync_convert(src)) {
cr |= 0x1;
route |= rsnd_io_is_play(io) ?
(0x1 << 24) : (0x1 << 25);
}
}
rsnd_mod_write(mod, SRC_SRCCR, cr);
rsnd_mod_write(mod, SRC_ROUTE_MODE0, route);
switch (rsnd_mod_id(mod)) {
case 5:
case 6:
......@@ -708,24 +794,12 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
IRQF_SHARED,
dev_name(dev), mod);
if (ret)
goto rsnd_src_probe_gen2_fail;
return ret;
}
ret = rsnd_dma_init(priv,
rsnd_mod_to_dma(mod),
rsnd_info_is_playback(priv, src),
src->info->dma_id);
if (ret)
goto rsnd_src_probe_gen2_fail;
dev_dbg(dev, "%s[%d] (Gen2) is probed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
return ret;
rsnd_src_probe_gen2_fail:
dev_err(dev, "%s[%d] (Gen2) failed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
return ret;
}
......@@ -733,7 +807,7 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
static int rsnd_src_remove_gen2(struct rsnd_mod *mod,
struct rsnd_priv *priv)
{
rsnd_dma_quit(priv, rsnd_mod_to_dma(mod));
rsnd_dma_quit(rsnd_mod_to_dma(mod));
return 0;
}
......@@ -743,7 +817,7 @@ static int rsnd_src_init_gen2(struct rsnd_mod *mod,
{
int ret;
ret = rsnd_src_init(mod);
ret = rsnd_src_init(mod, priv);
if (ret < 0)
return ret;
......@@ -778,14 +852,91 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
return ret;
}
static void rsnd_src_reconvert_update(struct rsnd_mod *mod)
{
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct rsnd_src *src = rsnd_mod_to_src(mod);
u32 convert_rate = rsnd_src_convert_rate(src);
u32 fsrate;
if (!runtime)
return;
if (!convert_rate)
convert_rate = runtime->rate;
fsrate = 0x0400000 / convert_rate * runtime->rate;
/* update IFS */
rsnd_mod_write(mod, SRC_IFSVR, fsrate);
}
static int rsnd_src_pcm_new(struct rsnd_mod *mod,
struct snd_soc_pcm_runtime *rtd)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
struct rsnd_src *src = rsnd_mod_to_src(mod);
int ret;
/*
* enable SRC sync convert if possible
*/
/*
* Gen1 is not supported
*/
if (rsnd_is_gen1(priv))
return 0;
/*
* SRC sync convert needs clock master
*/
if (!rsnd_rdai_is_clk_master(rdai))
return 0;
/*
* We can't use SRC sync convert
* if it has DVC
*/
if (rsnd_io_to_mod_dvc(io))
return 0;
/*
* enable sync convert
*/
ret = rsnd_kctrl_new_s(mod, rtd,
rsnd_io_is_play(io) ?
"SRC Out Rate Switch" :
"SRC In Rate Switch",
rsnd_src_reconvert_update,
&src->sen, 1);
if (ret < 0)
return ret;
ret = rsnd_kctrl_new_s(mod, rtd,
rsnd_io_is_play(io) ?
"SRC Out Rate" :
"SRC In Rate",
rsnd_src_reconvert_update,
&src->sync, 192000);
return ret;
}
static struct rsnd_mod_ops rsnd_src_gen2_ops = {
.name = SRC_NAME,
.dma_req = rsnd_src_dma_req,
.probe = rsnd_src_probe_gen2,
.remove = rsnd_src_remove_gen2,
.init = rsnd_src_init_gen2,
.quit = rsnd_src_quit,
.start = rsnd_src_start_gen2,
.stop = rsnd_src_stop_gen2,
.hw_params = rsnd_src_hw_params,
.pcm_new = rsnd_src_pcm_new,
};
struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
......@@ -810,7 +961,7 @@ static void rsnd_of_parse_src(struct platform_device *pdev,
if (!of_data)
return;
src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
src_node = rsnd_src_of_node(priv);
if (!src_node)
return;
......@@ -893,8 +1044,6 @@ int rsnd_src_probe(struct platform_device *pdev,
ret = rsnd_mod_init(&src->mod, ops, clk, RSND_MOD_SRC, i);
if (ret)
return ret;
dev_dbg(dev, "SRC%d probed\n", i);
}
return 0;
......
......@@ -80,13 +80,13 @@ struct rsnd_ssi {
#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
#define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma))
#define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0)
#define rsnd_ssi_dma_available(ssi) \
rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod))
#define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent)
#define rsnd_ssi_mode_flags(p) ((p)->info->flags)
#define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id)
#define rsnd_ssi_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi")
static int rsnd_ssi_use_busif(struct rsnd_mod *mod)
int rsnd_ssi_use_busif(struct rsnd_mod *mod)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
......@@ -416,11 +416,14 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
/*
* restart SSI
*/
rsnd_ssi_stop(mod, priv);
rsnd_ssi_start(mod, priv);
dev_dbg(dev, "%s[%d] restart\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
rsnd_ssi_stop(mod, priv);
if (ssi->err < 1024)
rsnd_ssi_start(mod, priv);
else
dev_warn(dev, "no more SSI restart\n");
}
rsnd_ssi_record_error(ssi, status);
......@@ -442,12 +445,6 @@ static int rsnd_ssi_pio_probe(struct rsnd_mod *mod,
rsnd_ssi_interrupt,
IRQF_SHARED,
dev_name(dev), ssi);
if (ret)
dev_err(dev, "%s[%d] (PIO) request interrupt failed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
else
dev_dbg(dev, "%s[%d] (PIO) is probed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
return ret;
}
......@@ -474,23 +471,11 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
IRQF_SHARED,
dev_name(dev), ssi);
if (ret)
goto rsnd_ssi_dma_probe_fail;
return ret;
ret = rsnd_dma_init(
priv, rsnd_mod_to_dma(mod),
rsnd_info_is_playback(priv, ssi),
dma_id);
if (ret)
goto rsnd_ssi_dma_probe_fail;
dev_dbg(dev, "%s[%d] (DMA) is probed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
return ret;
rsnd_ssi_dma_probe_fail:
dev_err(dev, "%s[%d] (DMA) is failed\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
return ret;
}
......@@ -502,7 +487,7 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
struct device *dev = rsnd_priv_to_dev(priv);
int irq = ssi->info->irq;
rsnd_dma_quit(priv, rsnd_mod_to_dma(mod));
rsnd_dma_quit(rsnd_mod_to_dma(mod));
/* PIO will request IRQ again */
devm_free_irq(dev, irq, ssi);
......@@ -554,14 +539,25 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
return 0;
}
static char *rsnd_ssi_dma_name(struct rsnd_mod *mod)
static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_mod *mod)
{
return rsnd_ssi_use_busif(mod) ? "ssiu" : SSI_NAME;
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
int is_play = rsnd_io_is_play(io);
char *name;
if (rsnd_ssi_use_busif(mod))
name = is_play ? "rxu" : "txu";
else
name = is_play ? "rx" : "tx";
return rsnd_dma_request_channel(rsnd_ssi_of_node(priv),
mod, name);
}
static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
.name = SSI_NAME,
.dma_name = rsnd_ssi_dma_name,
.dma_req = rsnd_ssi_dma_req,
.probe = rsnd_ssi_dma_probe,
.remove = rsnd_ssi_dma_remove,
.init = rsnd_ssi_init,
......@@ -636,7 +632,7 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev,
if (!of_data)
return;
node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
node = rsnd_ssi_of_node(priv);
if (!node)
return;
......
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