Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
f2d4c127
Commit
f2d4c127
authored
Mar 13, 2016
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branches 'asoc/topic/pxa' and 'asoc/topic/qcom' into asoc-next
parents
88f18348
aa3e8388
568cecf4
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
396 additions
and
181 deletions
+396
-181
sound/soc/pxa/brownstone.c
sound/soc/pxa/brownstone.c
+0
-2
sound/soc/qcom/Kconfig
sound/soc/qcom/Kconfig
+5
-2
sound/soc/qcom/apq8016_sbc.c
sound/soc/qcom/apq8016_sbc.c
+7
-3
sound/soc/qcom/lpass-apq8016.c
sound/soc/qcom/lpass-apq8016.c
+24
-7
sound/soc/qcom/lpass-cpu.c
sound/soc/qcom/lpass-cpu.c
+114
-32
sound/soc/qcom/lpass-ipq806x.c
sound/soc/qcom/lpass-ipq806x.c
+9
-2
sound/soc/qcom/lpass-lpaif-reg.h
sound/soc/qcom/lpass-lpaif-reg.h
+83
-33
sound/soc/qcom/lpass-platform.c
sound/soc/qcom/lpass-platform.c
+147
-97
sound/soc/qcom/lpass.h
sound/soc/qcom/lpass.h
+7
-3
No files found.
sound/soc/pxa/brownstone.c
View file @
f2d4c127
...
...
@@ -52,7 +52,6 @@ static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream,
struct
snd_soc_dai
*
codec_dai
=
rtd
->
codec_dai
;
struct
snd_soc_dai
*
cpu_dai
=
rtd
->
cpu_dai
;
int
freq_out
,
sspa_mclk
,
sysclk
;
int
sspa_div
;
if
(
params_rate
(
params
)
>
11025
)
{
freq_out
=
params_rate
(
params
)
*
512
;
...
...
@@ -63,7 +62,6 @@ static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream,
sysclk
=
params_rate
(
params
)
*
512
;
sspa_mclk
=
params_rate
(
params
)
*
64
;
}
sspa_div
=
freq_out
/
sspa_mclk
;
snd_soc_dai_set_sysclk
(
cpu_dai
,
MMP_SSPA_CLK_AUDIO
,
freq_out
,
0
);
snd_soc_dai_set_pll
(
cpu_dai
,
MMP_SYSCLK
,
0
,
freq_out
,
sysclk
);
...
...
sound/soc/qcom/Kconfig
View file @
f2d4c127
...
...
@@ -11,21 +11,24 @@ config SND_SOC_LPASS_CPU
config SND_SOC_LPASS_PLATFORM
tristate
depends on HAS_DMA
select REGMAP_MMIO
config SND_SOC_LPASS_IPQ806X
tristate
depends on HAS_DMA
select SND_SOC_LPASS_CPU
select SND_SOC_LPASS_PLATFORM
config SND_SOC_LPASS_APQ8016
tristate
depends on HAS_DMA
select SND_SOC_LPASS_CPU
select SND_SOC_LPASS_PLATFORM
config SND_SOC_STORM
tristate "ASoC I2S support for Storm boards"
depends on SND_SOC_QCOM
depends on SND_SOC_QCOM
&& HAS_DMA
select SND_SOC_LPASS_IPQ806X
select SND_SOC_MAX98357A
help
...
...
@@ -34,7 +37,7 @@ config SND_SOC_STORM
config SND_SOC_APQ8016_SBC
tristate "SoC Audio support for APQ8016 SBC platforms"
depends on SND_SOC_QCOM
depends on SND_SOC_QCOM
&& HAS_DMA
select SND_SOC_LPASS_APQ8016
help
Support for Qualcomm Technologies LPASS audio block in
...
...
sound/soc/qcom/apq8016_sbc.c
View file @
f2d4c127
...
...
@@ -30,6 +30,7 @@ struct apq8016_sbc_data {
struct
snd_soc_dai_link
dai_link
[];
/* dynamically allocated */
};
#define MIC_CTRL_TER_WS_SLAVE_SEL BIT(21)
#define MIC_CTRL_QUA_WS_SLAVE_SEL_10 BIT(17)
#define MIC_CTRL_TLMM_SCLK_EN BIT(1)
#define SPKR_CTL_PRI_WS_SLAVE_SEL_11 (BIT(17) | BIT(16))
...
...
@@ -53,6 +54,12 @@ static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd)
MIC_CTRL_TLMM_SCLK_EN
,
pdata
->
mic_iomux
);
break
;
case
MI2S_TERTIARY
:
writel
(
readl
(
pdata
->
mic_iomux
)
|
MIC_CTRL_TER_WS_SLAVE_SEL
|
MIC_CTRL_TLMM_SCLK_EN
,
pdata
->
mic_iomux
);
break
;
default:
dev_err
(
card
->
dev
,
"unsupported cpu dai configuration
\n
"
);
...
...
@@ -126,9 +133,6 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card)
}
link
->
platform_of_node
=
link
->
cpu_of_node
;
/* For now we only support playback */
link
->
playback_only
=
true
;
ret
=
of_property_read_string
(
np
,
"link-name"
,
&
link
->
name
);
if
(
ret
)
{
dev_err
(
card
->
dev
,
"error getting codec dai_link name
\n
"
);
...
...
sound/soc/qcom/lpass-apq8016.c
View file @
f2d4c127
...
...
@@ -133,23 +133,36 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
},
};
static
int
apq8016_lpass_alloc_dma_channel
(
struct
lpass_data
*
drvdata
)
static
int
apq8016_lpass_alloc_dma_channel
(
struct
lpass_data
*
drvdata
,
int
direction
)
{
struct
lpass_variant
*
v
=
drvdata
->
variant
;
int
chan
=
find_first_zero_bit
(
&
drvdata
->
rdma_ch_bit_map
,
int
chan
=
0
;
if
(
direction
==
SNDRV_PCM_STREAM_PLAYBACK
)
{
chan
=
find_first_zero_bit
(
&
drvdata
->
dma_ch_bit_map
,
v
->
rdma_channels
);
if
(
chan
>=
v
->
rdma_channels
)
return
-
EBUSY
;
}
else
{
chan
=
find_next_zero_bit
(
&
drvdata
->
dma_ch_bit_map
,
v
->
wrdma_channel_start
+
v
->
wrdma_channels
,
v
->
wrdma_channel_start
);
if
(
chan
>=
v
->
wrdma_channel_start
+
v
->
wrdma_channels
)
return
-
EBUSY
;
}
set_bit
(
chan
,
&
drvdata
->
r
dma_ch_bit_map
);
set_bit
(
chan
,
&
drvdata
->
dma_ch_bit_map
);
return
chan
;
}
static
int
apq8016_lpass_free_dma_channel
(
struct
lpass_data
*
drvdata
,
int
chan
)
{
clear_bit
(
chan
,
&
drvdata
->
r
dma_ch_bit_map
);
clear_bit
(
chan
,
&
drvdata
->
dma_ch_bit_map
);
return
0
;
}
...
...
@@ -212,7 +225,11 @@ static struct lpass_variant apq8016_data = {
.
rdma_reg_base
=
0x8400
,
.
rdma_reg_stride
=
0x1000
,
.
rdma_channels
=
2
,
.
rdmactl_audif_start
=
1
,
.
dmactl_audif_start
=
1
,
.
wrdma_reg_base
=
0xB000
,
.
wrdma_reg_stride
=
0x1000
,
.
wrdma_channel_start
=
5
,
.
wrdma_channels
=
2
,
.
dai_driver
=
apq8016_lpass_cpu_dai_driver
,
.
num_dai
=
ARRAY_SIZE
(
apq8016_lpass_cpu_dai_driver
),
.
init
=
apq8016_lpass_init
,
...
...
sound/soc/qcom/lpass-cpu.c
View file @
f2d4c127
...
...
@@ -120,6 +120,7 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
return
-
EINVAL
;
}
if
(
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
{
switch
(
channels
)
{
case
1
:
regval
|=
LPAIF_I2SCTL_SPKMODE_SD0
;
...
...
@@ -146,6 +147,34 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
__func__
,
channels
);
return
-
EINVAL
;
}
}
else
{
switch
(
channels
)
{
case
1
:
regval
|=
LPAIF_I2SCTL_MICMODE_SD0
;
regval
|=
LPAIF_I2SCTL_MICMONO_MONO
;
break
;
case
2
:
regval
|=
LPAIF_I2SCTL_MICMODE_SD0
;
regval
|=
LPAIF_I2SCTL_MICMONO_STEREO
;
break
;
case
4
:
regval
|=
LPAIF_I2SCTL_MICMODE_QUAD01
;
regval
|=
LPAIF_I2SCTL_MICMONO_STEREO
;
break
;
case
6
:
regval
|=
LPAIF_I2SCTL_MICMODE_6CH
;
regval
|=
LPAIF_I2SCTL_MICMONO_STEREO
;
break
;
case
8
:
regval
|=
LPAIF_I2SCTL_MICMODE_8CH
;
regval
|=
LPAIF_I2SCTL_MICMONO_STEREO
;
break
;
default:
dev_err
(
dai
->
dev
,
"%s() invalid channels given: %u
\n
"
,
__func__
,
channels
);
return
-
EINVAL
;
}
}
ret
=
regmap_write
(
drvdata
->
lpaif_map
,
LPAIF_I2SCTL_REG
(
drvdata
->
variant
,
dai
->
driver
->
id
),
...
...
@@ -188,10 +217,19 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
{
struct
lpass_data
*
drvdata
=
snd_soc_dai_get_drvdata
(
dai
);
int
ret
;
unsigned
int
val
,
mask
;
if
(
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
{
val
=
LPAIF_I2SCTL_SPKEN_ENABLE
;
mask
=
LPAIF_I2SCTL_SPKEN_MASK
;
}
else
{
val
=
LPAIF_I2SCTL_MICEN_ENABLE
;
mask
=
LPAIF_I2SCTL_MICEN_MASK
;
}
ret
=
regmap_update_bits
(
drvdata
->
lpaif_map
,
LPAIF_I2SCTL_REG
(
drvdata
->
variant
,
dai
->
driver
->
id
),
LPAIF_I2SCTL_SPKEN_MASK
,
LPAIF_I2SCTL_SPKEN_ENABLE
);
mask
,
val
);
if
(
ret
)
dev_err
(
dai
->
dev
,
"%s() error writing to i2sctl reg: %d
\n
"
,
__func__
,
ret
);
...
...
@@ -204,16 +242,24 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
{
struct
lpass_data
*
drvdata
=
snd_soc_dai_get_drvdata
(
dai
);
int
ret
=
-
EINVAL
;
unsigned
int
val
,
mask
;
switch
(
cmd
)
{
case
SNDRV_PCM_TRIGGER_START
:
case
SNDRV_PCM_TRIGGER_RESUME
:
case
SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
if
(
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
{
val
=
LPAIF_I2SCTL_SPKEN_ENABLE
;
mask
=
LPAIF_I2SCTL_SPKEN_MASK
;
}
else
{
val
=
LPAIF_I2SCTL_MICEN_ENABLE
;
mask
=
LPAIF_I2SCTL_MICEN_MASK
;
}
ret
=
regmap_update_bits
(
drvdata
->
lpaif_map
,
LPAIF_I2SCTL_REG
(
drvdata
->
variant
,
dai
->
driver
->
id
),
LPAIF_I2SCTL_SPKEN_MASK
,
LPAIF_I2SCTL_SPKEN_ENABLE
);
mask
,
val
);
if
(
ret
)
dev_err
(
dai
->
dev
,
"%s() error writing to i2sctl reg: %d
\n
"
,
__func__
,
ret
);
...
...
@@ -221,11 +267,18 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
case
SNDRV_PCM_TRIGGER_STOP
:
case
SNDRV_PCM_TRIGGER_SUSPEND
:
case
SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
if
(
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
{
val
=
LPAIF_I2SCTL_SPKEN_DISABLE
;
mask
=
LPAIF_I2SCTL_SPKEN_MASK
;
}
else
{
val
=
LPAIF_I2SCTL_MICEN_DISABLE
;
mask
=
LPAIF_I2SCTL_MICEN_MASK
;
}
ret
=
regmap_update_bits
(
drvdata
->
lpaif_map
,
LPAIF_I2SCTL_REG
(
drvdata
->
variant
,
dai
->
driver
->
id
),
LPAIF_I2SCTL_SPKEN_MASK
,
LPAIF_I2SCTL_SPKEN_DISABLE
);
mask
,
val
);
if
(
ret
)
dev_err
(
dai
->
dev
,
"%s() error writing to i2sctl reg: %d
\n
"
,
__func__
,
ret
);
...
...
@@ -294,6 +347,17 @@ static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
return
true
;
}
for
(
i
=
0
;
i
<
v
->
wrdma_channels
;
++
i
)
{
if
(
reg
==
LPAIF_WRDMACTL_REG
(
v
,
i
+
v
->
wrdma_channel_start
))
return
true
;
if
(
reg
==
LPAIF_WRDMABASE_REG
(
v
,
i
+
v
->
wrdma_channel_start
))
return
true
;
if
(
reg
==
LPAIF_WRDMABUFF_REG
(
v
,
i
+
v
->
wrdma_channel_start
))
return
true
;
if
(
reg
==
LPAIF_WRDMAPER_REG
(
v
,
i
+
v
->
wrdma_channel_start
))
return
true
;
}
return
false
;
}
...
...
@@ -327,6 +391,19 @@ static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
return
true
;
}
for
(
i
=
0
;
i
<
v
->
wrdma_channels
;
++
i
)
{
if
(
reg
==
LPAIF_WRDMACTL_REG
(
v
,
i
+
v
->
wrdma_channel_start
))
return
true
;
if
(
reg
==
LPAIF_WRDMABASE_REG
(
v
,
i
+
v
->
wrdma_channel_start
))
return
true
;
if
(
reg
==
LPAIF_WRDMABUFF_REG
(
v
,
i
+
v
->
wrdma_channel_start
))
return
true
;
if
(
reg
==
LPAIF_WRDMACURR_REG
(
v
,
i
+
v
->
wrdma_channel_start
))
return
true
;
if
(
reg
==
LPAIF_WRDMAPER_REG
(
v
,
i
+
v
->
wrdma_channel_start
))
return
true
;
}
return
false
;
}
...
...
@@ -344,6 +421,10 @@ static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)
if
(
reg
==
LPAIF_RDMACURR_REG
(
v
,
i
))
return
true
;
for
(
i
=
0
;
i
<
v
->
wrdma_channels
;
++
i
)
if
(
reg
==
LPAIF_WRDMACURR_REG
(
v
,
i
+
v
->
wrdma_channel_start
))
return
true
;
return
false
;
}
...
...
@@ -398,8 +479,9 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
return
PTR_ERR
((
void
const
__force
*
)
drvdata
->
lpaif
);
}
lpass_cpu_regmap_config
.
max_register
=
LPAIF_RDMAPER_REG
(
variant
,
variant
->
rdma_channels
);
lpass_cpu_regmap_config
.
max_register
=
LPAIF_WRDMAPER_REG
(
variant
,
variant
->
wrdma_channels
+
variant
->
wrdma_channel_start
);
drvdata
->
lpaif_map
=
devm_regmap_init_mmio
(
&
pdev
->
dev
,
drvdata
->
lpaif
,
&
lpass_cpu_regmap_config
);
...
...
sound/soc/qcom/lpass-ipq806x.c
View file @
f2d4c127
...
...
@@ -63,9 +63,12 @@ static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = {
.
ops
=
&
asoc_qcom_lpass_cpu_dai_ops
,
};
static
int
ipq806x_lpass_alloc_dma_channel
(
struct
lpass_data
*
drvdata
)
static
int
ipq806x_lpass_alloc_dma_channel
(
struct
lpass_data
*
drvdata
,
int
dir
)
{
if
(
dir
==
SNDRV_PCM_STREAM_PLAYBACK
)
return
IPQ806X_LPAIF_RDMA_CHAN_MI2S
;
else
/* Capture currently not implemented */
return
-
EINVAL
;
}
static
int
ipq806x_lpass_free_dma_channel
(
struct
lpass_data
*
drvdata
,
int
chan
)
...
...
@@ -83,6 +86,10 @@ static struct lpass_variant ipq806x_data = {
.
rdma_reg_base
=
0x6000
,
.
rdma_reg_stride
=
0x1000
,
.
rdma_channels
=
4
,
.
wrdma_reg_base
=
0xB000
,
.
wrdma_reg_stride
=
0x1000
,
.
wrdma_channel_start
=
5
,
.
wrdma_channels
=
4
,
.
dai_driver
=
&
ipq806x_lpass_cpu_dai_driver
,
.
num_dai
=
1
,
.
alloc_dma_channel
=
ipq806x_lpass_alloc_dma_channel
,
...
...
sound/soc/qcom/lpass-lpaif-reg.h
View file @
f2d4c127
...
...
@@ -47,6 +47,28 @@
#define LPAIF_I2SCTL_SPKMONO_STEREO (0 << LPAIF_I2SCTL_SPKMONO_SHIFT)
#define LPAIF_I2SCTL_SPKMONO_MONO (1 << LPAIF_I2SCTL_SPKMONO_SHIFT)
#define LPAIF_I2SCTL_MICEN_MASK GENMASK(8, 8)
#define LPAIF_I2SCTL_MICEN_SHIFT 8
#define LPAIF_I2SCTL_MICEN_DISABLE (0 << LPAIF_I2SCTL_MICEN_SHIFT)
#define LPAIF_I2SCTL_MICEN_ENABLE (1 << LPAIF_I2SCTL_MICEN_SHIFT)
#define LPAIF_I2SCTL_MICMODE_MASK GENMASK(7, 4)
#define LPAIF_I2SCTL_MICMODE_SHIFT 4
#define LPAIF_I2SCTL_MICMODE_NONE (0 << LPAIF_I2SCTL_MICMODE_SHIFT)
#define LPAIF_I2SCTL_MICMODE_SD0 (1 << LPAIF_I2SCTL_MICMODE_SHIFT)
#define LPAIF_I2SCTL_MICMODE_SD1 (2 << LPAIF_I2SCTL_MICMODE_SHIFT)
#define LPAIF_I2SCTL_MICMODE_SD2 (3 << LPAIF_I2SCTL_MICMODE_SHIFT)
#define LPAIF_I2SCTL_MICMODE_SD3 (4 << LPAIF_I2SCTL_MICMODE_SHIFT)
#define LPAIF_I2SCTL_MICMODE_QUAD01 (5 << LPAIF_I2SCTL_MICMODE_SHIFT)
#define LPAIF_I2SCTL_MICMODE_QUAD23 (6 << LPAIF_I2SCTL_MICMODE_SHIFT)
#define LPAIF_I2SCTL_MICMODE_6CH (7 << LPAIF_I2SCTL_MICMODE_SHIFT)
#define LPAIF_I2SCTL_MICMODE_8CH (8 << LPAIF_I2SCTL_MICMODE_SHIFT)
#define LPAIF_I2SCTL_MIMONO_MASK GENMASK(3, 3)
#define LPAIF_I2SCTL_MICMONO_SHIFT 3
#define LPAIF_I2SCTL_MICMONO_STEREO (0 << LPAIF_I2SCTL_MICMONO_SHIFT)
#define LPAIF_I2SCTL_MICMONO_MONO (1 << LPAIF_I2SCTL_MICMONO_SHIFT)
#define LPAIF_I2SCTL_WSSRC_MASK 0x0004
#define LPAIF_I2SCTL_WSSRC_SHIFT 2
#define LPAIF_I2SCTL_WSSRC_INTERNAL (0 << LPAIF_I2SCTL_WSSRC_SHIFT)
...
...
@@ -90,37 +112,65 @@
#define LPAIF_RDMAPER_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x10, (chan))
#define LPAIF_RDMAPERCNT_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x14, (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_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)
#define LPAIF_WRDMA_REG_ADDR(v, addr, chan) \
(v->wrdma_reg_base + (addr) + \
v->wrdma_reg_stride * (chan - v->wrdma_channel_start))
#define LPAIF_WRDMACTL_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x00, (chan))
#define LPAIF_WRDMABASE_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x04, (chan))
#define LPAIF_WRDMABUFF_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x08, (chan))
#define LPAIF_WRDMACURR_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x0C, (chan))
#define LPAIF_WRDMAPER_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x10, (chan))
#define LPAIF_WRDMAPERCNT_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x14, (chan))
#define __LPAIF_DMA_REG(v, chan, dir, reg) \
(dir == SNDRV_PCM_STREAM_PLAYBACK) ? \
LPAIF_RDMA##reg##_REG(v, chan) : \
LPAIF_WRDMA##reg##_REG(v, chan)
#define LPAIF_DMACTL_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, CTL)
#define LPAIF_DMABASE_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, BASE)
#define LPAIF_DMABUFF_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, BUFF)
#define LPAIF_DMACURR_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, CURR)
#define LPAIF_DMAPER_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, PER)
#define LPAIF_DMAPERCNT_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, PERCNT)
#define LPAIF_DMACTL_BURSTEN_MASK 0x800
#define LPAIF_DMACTL_BURSTEN_SHIFT 11
#define LPAIF_DMACTL_BURSTEN_SINGLE (0 << LPAIF_DMACTL_BURSTEN_SHIFT)
#define LPAIF_DMACTL_BURSTEN_INCR4 (1 << LPAIF_DMACTL_BURSTEN_SHIFT)
#define LPAIF_DMACTL_WPSCNT_MASK 0x700
#define LPAIF_DMACTL_WPSCNT_SHIFT 8
#define LPAIF_DMACTL_WPSCNT_ONE (0 << LPAIF_DMACTL_WPSCNT_SHIFT)
#define LPAIF_DMACTL_WPSCNT_TWO (1 << LPAIF_DMACTL_WPSCNT_SHIFT)
#define LPAIF_DMACTL_WPSCNT_THREE (2 << LPAIF_DMACTL_WPSCNT_SHIFT)
#define LPAIF_DMACTL_WPSCNT_FOUR (3 << LPAIF_DMACTL_WPSCNT_SHIFT)
#define LPAIF_DMACTL_WPSCNT_SIX (5 << LPAIF_DMACTL_WPSCNT_SHIFT)
#define LPAIF_DMACTL_WPSCNT_EIGHT (7 << LPAIF_DMACTL_WPSCNT_SHIFT)
#define LPAIF_DMACTL_AUDINTF_MASK 0x0F0
#define LPAIF_DMACTL_AUDINTF_SHIFT 4
#define LPAIF_DMACTL_AUDINTF(id) (id << LPAIF_DMACTL_AUDINTF_SHIFT)
#define LPAIF_DMACTL_FIFOWM_MASK 0x00E
#define LPAIF_DMACTL_FIFOWM_SHIFT 1
#define LPAIF_DMACTL_FIFOWM_1 (0 << LPAIF_DMACTL_FIFOWM_SHIFT)
#define LPAIF_DMACTL_FIFOWM_2 (1 << LPAIF_DMACTL_FIFOWM_SHIFT)
#define LPAIF_DMACTL_FIFOWM_3 (2 << LPAIF_DMACTL_FIFOWM_SHIFT)
#define LPAIF_DMACTL_FIFOWM_4 (3 << LPAIF_DMACTL_FIFOWM_SHIFT)
#define LPAIF_DMACTL_FIFOWM_5 (4 << LPAIF_DMACTL_FIFOWM_SHIFT)
#define LPAIF_DMACTL_FIFOWM_6 (5 << LPAIF_DMACTL_FIFOWM_SHIFT)
#define LPAIF_DMACTL_FIFOWM_7 (6 << LPAIF_DMACTL_FIFOWM_SHIFT)
#define LPAIF_DMACTL_FIFOWM_8 (7 << LPAIF_DMACTL_FIFOWM_SHIFT)
#define LPAIF_DMACTL_ENABLE_MASK 0x1
#define LPAIF_DMACTL_ENABLE_SHIFT 0
#define LPAIF_DMACTL_ENABLE_OFF (0 << LPAIF_DMACTL_ENABLE_SHIFT)
#define LPAIF_DMACTL_ENABLE_ON (1 << LPAIF_DMACTL_ENABLE_SHIFT)
#define LPAIF_DMACTL_DYNCLK_MASK BIT(12)
#define LPAIF_DMACTL_DYNCLK_SHIFT 12
#define LPAIF_DMACTL_DYNCLK_OFF (0 << LPAIF_DMACTL_DYNCLK_SHIFT)
#define LPAIF_DMACTL_DYNCLK_ON (1 << LPAIF_DMACTL_DYNCLK_SHIFT)
#endif
/* __LPASS_LPAIF_REG_H__ */
sound/soc/qcom/lpass-platform.c
View file @
f2d4c127
...
...
@@ -26,6 +26,7 @@
struct
lpass_pcm_data
{
int
rdma_ch
;
int
wrdma_ch
;
int
i2s_port
;
};
...
...
@@ -90,8 +91,14 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
snd_pcm_format_t
format
=
params_format
(
params
);
unsigned
int
channels
=
params_channels
(
params
);
unsigned
int
regval
;
int
ch
,
dir
=
substream
->
stream
;
int
bitwidth
;
int
ret
,
rdma_port
=
pcm_data
->
i2s_port
+
v
->
rdmactl_audif_start
;
int
ret
,
dma_port
=
pcm_data
->
i2s_port
+
v
->
dmactl_audif_start
;
if
(
dir
==
SNDRV_PCM_STREAM_PLAYBACK
)
ch
=
pcm_data
->
rdma_ch
;
else
ch
=
pcm_data
->
wrdma_ch
;
bitwidth
=
snd_pcm_format_width
(
format
);
if
(
bitwidth
<
0
)
{
...
...
@@ -100,25 +107,25 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
return
bitwidth
;
}
regval
=
LPAIF_
R
DMACTL_BURSTEN_INCR4
|
LPAIF_
RDMACTL_AUDINTF
(
r
dma_port
)
|
LPAIF_
R
DMACTL_FIFOWM_8
;
regval
=
LPAIF_DMACTL_BURSTEN_INCR4
|
LPAIF_
DMACTL_AUDINTF
(
dma_port
)
|
LPAIF_DMACTL_FIFOWM_8
;
switch
(
bitwidth
)
{
case
16
:
switch
(
channels
)
{
case
1
:
case
2
:
regval
|=
LPAIF_
R
DMACTL_WPSCNT_ONE
;
regval
|=
LPAIF_DMACTL_WPSCNT_ONE
;
break
;
case
4
:
regval
|=
LPAIF_
R
DMACTL_WPSCNT_TWO
;
regval
|=
LPAIF_DMACTL_WPSCNT_TWO
;
break
;
case
6
:
regval
|=
LPAIF_
R
DMACTL_WPSCNT_THREE
;
regval
|=
LPAIF_DMACTL_WPSCNT_THREE
;
break
;
case
8
:
regval
|=
LPAIF_
R
DMACTL_WPSCNT_FOUR
;
regval
|=
LPAIF_DMACTL_WPSCNT_FOUR
;
break
;
default:
dev_err
(
soc_runtime
->
dev
,
"%s() invalid PCM config given: bw=%d, ch=%u
\n
"
,
...
...
@@ -130,19 +137,19 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
case
32
:
switch
(
channels
)
{
case
1
:
regval
|=
LPAIF_
R
DMACTL_WPSCNT_ONE
;
regval
|=
LPAIF_DMACTL_WPSCNT_ONE
;
break
;
case
2
:
regval
|=
LPAIF_
R
DMACTL_WPSCNT_TWO
;
regval
|=
LPAIF_DMACTL_WPSCNT_TWO
;
break
;
case
4
:
regval
|=
LPAIF_
R
DMACTL_WPSCNT_FOUR
;
regval
|=
LPAIF_DMACTL_WPSCNT_FOUR
;
break
;
case
6
:
regval
|=
LPAIF_
R
DMACTL_WPSCNT_SIX
;
regval
|=
LPAIF_DMACTL_WPSCNT_SIX
;
break
;
case
8
:
regval
|=
LPAIF_
R
DMACTL_WPSCNT_EIGHT
;
regval
|=
LPAIF_DMACTL_WPSCNT_EIGHT
;
break
;
default:
dev_err
(
soc_runtime
->
dev
,
"%s() invalid PCM config given: bw=%d, ch=%u
\n
"
,
...
...
@@ -157,7 +164,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
}
ret
=
regmap_write
(
drvdata
->
lpaif_map
,
LPAIF_
RDMACTL_REG
(
v
,
pcm_data
->
rdma_ch
),
regval
);
LPAIF_
DMACTL_REG
(
v
,
ch
,
dir
),
regval
);
if
(
ret
)
{
dev_err
(
soc_runtime
->
dev
,
"%s() error writing to rdmactl reg: %d
\n
"
,
__func__
,
ret
);
...
...
@@ -174,10 +181,15 @@ static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
struct
lpass_data
*
drvdata
=
snd_soc_platform_get_drvdata
(
soc_runtime
->
platform
);
struct
lpass_variant
*
v
=
drvdata
->
variant
;
unsigned
int
reg
;
int
ret
;
ret
=
regmap_write
(
drvdata
->
lpaif_map
,
LPAIF_RDMACTL_REG
(
v
,
pcm_data
->
rdma_ch
),
0
);
if
(
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
reg
=
LPAIF_RDMACTL_REG
(
v
,
pcm_data
->
rdma_ch
);
else
reg
=
LPAIF_WRDMACTL_REG
(
v
,
pcm_data
->
wrdma_ch
);
ret
=
regmap_write
(
drvdata
->
lpaif_map
,
reg
,
0
);
if
(
ret
)
dev_err
(
soc_runtime
->
dev
,
"%s() error writing to rdmactl reg: %d
\n
"
,
__func__
,
ret
);
...
...
@@ -193,10 +205,15 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
struct
lpass_data
*
drvdata
=
snd_soc_platform_get_drvdata
(
soc_runtime
->
platform
);
struct
lpass_variant
*
v
=
drvdata
->
variant
;
int
ret
,
ch
=
pcm_data
->
rdma_ch
;
int
ret
,
ch
,
dir
=
substream
->
stream
;
if
(
dir
==
SNDRV_PCM_STREAM_PLAYBACK
)
ch
=
pcm_data
->
rdma_ch
;
else
ch
=
pcm_data
->
wrdma_ch
;
ret
=
regmap_write
(
drvdata
->
lpaif_map
,
LPAIF_
RDMABASE_REG
(
v
,
ch
),
LPAIF_
DMABASE_REG
(
v
,
ch
,
dir
),
runtime
->
dma_addr
);
if
(
ret
)
{
dev_err
(
soc_runtime
->
dev
,
"%s() error writing to rdmabase reg: %d
\n
"
,
...
...
@@ -205,7 +222,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
}
ret
=
regmap_write
(
drvdata
->
lpaif_map
,
LPAIF_
RDMABUFF_REG
(
v
,
ch
),
LPAIF_
DMABUFF_REG
(
v
,
ch
,
dir
),
(
snd_pcm_lib_buffer_bytes
(
substream
)
>>
2
)
-
1
);
if
(
ret
)
{
dev_err
(
soc_runtime
->
dev
,
"%s() error writing to rdmabuff reg: %d
\n
"
,
...
...
@@ -214,7 +231,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
}
ret
=
regmap_write
(
drvdata
->
lpaif_map
,
LPAIF_
RDMAPER_REG
(
v
,
ch
),
LPAIF_
DMAPER_REG
(
v
,
ch
,
dir
),
(
snd_pcm_lib_period_bytes
(
substream
)
>>
2
)
-
1
);
if
(
ret
)
{
dev_err
(
soc_runtime
->
dev
,
"%s() error writing to rdmaper reg: %d
\n
"
,
...
...
@@ -223,8 +240,8 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
}
ret
=
regmap_update_bits
(
drvdata
->
lpaif_map
,
LPAIF_
RDMACTL_REG
(
v
,
ch
),
LPAIF_
RDMACTL_ENABLE_MASK
,
LPAIF_R
DMACTL_ENABLE_ON
);
LPAIF_
DMACTL_REG
(
v
,
ch
,
dir
),
LPAIF_
DMACTL_ENABLE_MASK
,
LPAIF_
DMACTL_ENABLE_ON
);
if
(
ret
)
{
dev_err
(
soc_runtime
->
dev
,
"%s() error writing to rdmactl reg: %d
\n
"
,
__func__
,
ret
);
...
...
@@ -242,7 +259,12 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
struct
lpass_data
*
drvdata
=
snd_soc_platform_get_drvdata
(
soc_runtime
->
platform
);
struct
lpass_variant
*
v
=
drvdata
->
variant
;
int
ret
,
ch
=
pcm_data
->
rdma_ch
;
int
ret
,
ch
,
dir
=
substream
->
stream
;
if
(
dir
==
SNDRV_PCM_STREAM_PLAYBACK
)
ch
=
pcm_data
->
rdma_ch
;
else
ch
=
pcm_data
->
wrdma_ch
;
switch
(
cmd
)
{
case
SNDRV_PCM_TRIGGER_START
:
...
...
@@ -269,9 +291,9 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
}
ret
=
regmap_update_bits
(
drvdata
->
lpaif_map
,
LPAIF_
RDMACTL_REG
(
v
,
ch
),
LPAIF_
R
DMACTL_ENABLE_MASK
,
LPAIF_
R
DMACTL_ENABLE_ON
);
LPAIF_
DMACTL_REG
(
v
,
ch
,
dir
),
LPAIF_DMACTL_ENABLE_MASK
,
LPAIF_DMACTL_ENABLE_ON
);
if
(
ret
)
{
dev_err
(
soc_runtime
->
dev
,
"%s() error writing to rdmactl reg: %d
\n
"
,
__func__
,
ret
);
...
...
@@ -282,9 +304,9 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
case
SNDRV_PCM_TRIGGER_SUSPEND
:
case
SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
ret
=
regmap_update_bits
(
drvdata
->
lpaif_map
,
LPAIF_
RDMACTL_REG
(
v
,
ch
),
LPAIF_
R
DMACTL_ENABLE_MASK
,
LPAIF_
R
DMACTL_ENABLE_OFF
);
LPAIF_
DMACTL_REG
(
v
,
ch
,
dir
),
LPAIF_DMACTL_ENABLE_MASK
,
LPAIF_DMACTL_ENABLE_OFF
);
if
(
ret
)
{
dev_err
(
soc_runtime
->
dev
,
"%s() error writing to rdmactl reg: %d
\n
"
,
__func__
,
ret
);
...
...
@@ -314,10 +336,15 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
snd_soc_platform_get_drvdata
(
soc_runtime
->
platform
);
struct
lpass_variant
*
v
=
drvdata
->
variant
;
unsigned
int
base_addr
,
curr_addr
;
int
ret
,
ch
=
pcm_data
->
rdma_ch
;
int
ret
,
ch
,
dir
=
substream
->
stream
;
if
(
dir
==
SNDRV_PCM_STREAM_PLAYBACK
)
ch
=
pcm_data
->
rdma_ch
;
else
ch
=
pcm_data
->
wrdma_ch
;
ret
=
regmap_read
(
drvdata
->
lpaif_map
,
LPAIF_
RDMABASE_REG
(
v
,
ch
),
&
base_addr
);
LPAIF_
DMABASE_REG
(
v
,
ch
,
dir
),
&
base_addr
);
if
(
ret
)
{
dev_err
(
soc_runtime
->
dev
,
"%s() error reading from rdmabase reg: %d
\n
"
,
__func__
,
ret
);
...
...
@@ -325,7 +352,7 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
}
ret
=
regmap_read
(
drvdata
->
lpaif_map
,
LPAIF_
RDMACURR_REG
(
v
,
ch
),
&
curr_addr
);
LPAIF_
DMACURR_REG
(
v
,
ch
,
dir
),
&
curr_addr
);
if
(
ret
)
{
dev_err
(
soc_runtime
->
dev
,
"%s() error reading from rdmacurr reg: %d
\n
"
,
__func__
,
ret
);
...
...
@@ -439,101 +466,124 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
return
IRQ_HANDLED
;
}
static
int
lpass_platform_alloc_buffer
(
struct
snd_pcm_substream
*
substream
,
struct
snd_soc_pcm_runtime
*
rt
)
{
struct
snd_dma_buffer
*
buf
=
&
substream
->
dma_buffer
;
size_t
size
=
lpass_platform_pcm_hardware
.
buffer_bytes_max
;
buf
->
dev
.
type
=
SNDRV_DMA_TYPE_DEV
;
buf
->
dev
.
dev
=
rt
->
platform
->
dev
;
buf
->
private_data
=
NULL
;
buf
->
area
=
dma_alloc_coherent
(
rt
->
platform
->
dev
,
size
,
&
buf
->
addr
,
GFP_KERNEL
);
if
(
!
buf
->
area
)
{
dev_err
(
rt
->
platform
->
dev
,
"%s: Could not allocate DMA buffer
\n
"
,
__func__
);
return
-
ENOMEM
;
}
buf
->
bytes
=
size
;
return
0
;
}
static
void
lpass_platform_free_buffer
(
struct
snd_pcm_substream
*
substream
,
struct
snd_soc_pcm_runtime
*
rt
)
{
struct
snd_dma_buffer
*
buf
=
&
substream
->
dma_buffer
;
if
(
buf
->
area
)
{
dma_free_coherent
(
rt
->
dev
,
buf
->
bytes
,
buf
->
area
,
buf
->
addr
);
}
buf
->
area
=
NULL
;
}
static
int
lpass_platform_pcm_new
(
struct
snd_soc_pcm_runtime
*
soc_runtime
)
{
struct
snd_pcm
*
pcm
=
soc_runtime
->
pcm
;
struct
snd_pcm_substream
*
substream
=
pcm
->
streams
[
SNDRV_PCM_STREAM_PLAYBACK
].
substream
;
struct
snd_pcm_substream
*
psubstream
,
*
csubstream
;
struct
snd_soc_dai
*
cpu_dai
=
soc_runtime
->
cpu_dai
;
struct
lpass_data
*
drvdata
=
snd_soc_platform_get_drvdata
(
soc_runtime
->
platform
);
struct
lpass_variant
*
v
=
drvdata
->
variant
;
int
ret
;
struct
lpass_pcm_data
*
data
;
size_t
size
=
lpass_platform_pcm_hardware
.
buffer_bytes_max
;
data
=
devm_kzalloc
(
soc_runtime
->
dev
,
sizeof
(
*
data
),
GFP_KERNEL
);
if
(
!
data
)
return
-
ENOMEM
;
data
->
i2s_port
=
cpu_dai
->
driver
->
id
;
snd_soc_pcm_set_drvdata
(
soc_runtime
,
data
);
psubstream
=
pcm
->
streams
[
SNDRV_PCM_STREAM_PLAYBACK
].
substream
;
if
(
psubstream
)
{
if
(
v
->
alloc_dma_channel
)
data
->
rdma_ch
=
v
->
alloc_dma_channel
(
drvdata
);
data
->
rdma_ch
=
v
->
alloc_dma_channel
(
drvdata
,
SNDRV_PCM_STREAM_PLAYBACK
);
if
(
IS_ERR_VALUE
(
data
->
rdma_ch
))
return
data
->
rdma_ch
;
drvdata
->
substream
[
data
->
rdma_ch
]
=
substream
;
data
->
i2s_port
=
cpu_dai
->
driver
->
id
;
snd_soc_pcm_set_drvdata
(
soc_runtime
,
data
);
drvdata
->
substream
[
data
->
rdma_ch
]
=
psubstream
;
ret
=
lpass_platform_alloc_buffer
(
substream
,
soc_runtime
);
ret
=
snd_dma_alloc_pages
(
SNDRV_DMA_TYPE_DEV
,
soc_runtime
->
platform
->
dev
,
size
,
&
psubstream
->
dma_buffer
);
if
(
ret
)
return
ret
;
goto
playback_alloc_err
;
ret
=
regmap_write
(
drvdata
->
lpaif_map
,
LPAIF_RDMACTL_REG
(
v
,
data
->
rdma_ch
),
0
);
if
(
ret
)
{
dev_err
(
soc_runtime
->
dev
,
"%s() error writing to rdmactl reg: %d
\n
"
,
dev_err
(
soc_runtime
->
dev
,
"%s() error writing to rdmactl reg: %d
\n
"
,
__func__
,
ret
);
goto
err_buf
;
goto
capture_alloc_err
;
}
}
csubstream
=
pcm
->
streams
[
SNDRV_PCM_STREAM_CAPTURE
].
substream
;
if
(
csubstream
)
{
if
(
v
->
alloc_dma_channel
)
data
->
wrdma_ch
=
v
->
alloc_dma_channel
(
drvdata
,
SNDRV_PCM_STREAM_CAPTURE
);
if
(
IS_ERR_VALUE
(
data
->
wrdma_ch
))
goto
capture_alloc_err
;
drvdata
->
substream
[
data
->
wrdma_ch
]
=
csubstream
;
ret
=
snd_dma_alloc_pages
(
SNDRV_DMA_TYPE_DEV
,
soc_runtime
->
platform
->
dev
,
size
,
&
csubstream
->
dma_buffer
);
if
(
ret
)
goto
capture_alloc_err
;
ret
=
regmap_write
(
drvdata
->
lpaif_map
,
LPAIF_WRDMACTL_REG
(
v
,
data
->
wrdma_ch
),
0
);
if
(
ret
)
{
dev_err
(
soc_runtime
->
dev
,
"%s() error writing to wrdmactl reg: %d
\n
"
,
__func__
,
ret
);
goto
capture_reg_err
;
}
}
return
0
;
err_buf:
lpass_platform_free_buffer
(
substream
,
soc_runtime
);
capture_reg_err:
if
(
csubstream
)
snd_dma_free_pages
(
&
csubstream
->
dma_buffer
);
capture_alloc_err:
if
(
psubstream
)
snd_dma_free_pages
(
&
psubstream
->
dma_buffer
);
playback_alloc_err:
dev_err
(
soc_runtime
->
dev
,
"Cannot allocate buffer(s)
\n
"
);
return
ret
;
}
static
void
lpass_platform_pcm_free
(
struct
snd_pcm
*
pcm
)
{
struct
snd_pcm_substream
*
substream
=
pcm
->
streams
[
SNDRV_PCM_STREAM_PLAYBACK
].
substream
;
struct
snd_soc_pcm_runtime
*
soc_runtime
=
substream
->
private_data
;
struct
lpass_data
*
drvdata
=
snd_soc_platform_get_drvdata
(
soc_runtime
->
platform
);
struct
lpass_pcm_data
*
data
=
snd_soc_pcm_get_drvdata
(
soc_runtime
);
struct
lpass_variant
*
v
=
drvdata
->
variant
;
drvdata
->
substream
[
data
->
rdma_ch
]
=
NULL
;
struct
snd_soc_pcm_runtime
*
rt
;
struct
lpass_data
*
drvdata
;
struct
lpass_pcm_data
*
data
;
struct
lpass_variant
*
v
;
struct
snd_pcm_substream
*
substream
;
int
ch
,
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
pcm
->
streams
);
i
++
)
{
substream
=
pcm
->
streams
[
i
].
substream
;
if
(
substream
)
{
rt
=
substream
->
private_data
;
data
=
snd_soc_pcm_get_drvdata
(
rt
);
drvdata
=
snd_soc_platform_get_drvdata
(
rt
->
platform
);
ch
=
(
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
?
data
->
rdma_ch
:
data
->
wrdma_ch
;
v
=
drvdata
->
variant
;
drvdata
->
substream
[
ch
]
=
NULL
;
if
(
v
->
free_dma_channel
)
v
->
free_dma_channel
(
drvdata
,
data
->
rdma_
ch
);
v
->
free_dma_channel
(
drvdata
,
ch
);
lpass_platform_free_buffer
(
substream
,
soc_runtime
);
snd_dma_free_pages
(
&
substream
->
dma_buffer
);
substream
->
dma_buffer
.
area
=
NULL
;
substream
->
dma_buffer
.
addr
=
0
;
}
}
}
static
struct
snd_soc_platform_driver
lpass_platform_driver
=
{
...
...
sound/soc/qcom/lpass.h
View file @
f2d4c127
...
...
@@ -50,7 +50,7 @@ struct lpass_data {
struct
lpass_variant
*
variant
;
/* bit map to keep track of static channel allocations */
unsigned
long
r
dma_ch_bit_map
;
unsigned
long
dma_ch_bit_map
;
/* used it for handling interrupt per dma channel */
struct
snd_pcm_substream
*
substream
[
LPASS_MAX_DMA_CHANNELS
];
...
...
@@ -71,16 +71,20 @@ struct lpass_variant {
u32
rdma_reg_base
;
u32
rdma_reg_stride
;
u32
rdma_channels
;
u32
wrdma_reg_base
;
u32
wrdma_reg_stride
;
u32
wrdma_channels
;
/**
* on SOCs like APQ8016 the channel control bits start
* at different offset to ipq806x
**/
u32
rdmactl_audif_start
;
u32
dmactl_audif_start
;
u32
wrdma_channel_start
;
/* SOC specific intialization like clocks */
int
(
*
init
)(
struct
platform_device
*
pdev
);
int
(
*
exit
)(
struct
platform_device
*
pdev
);
int
(
*
alloc_dma_channel
)(
struct
lpass_data
*
data
);
int
(
*
alloc_dma_channel
)(
struct
lpass_data
*
data
,
int
direction
);
int
(
*
free_dma_channel
)(
struct
lpass_data
*
data
,
int
ch
);
/* SOC specific dais */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment