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
Kirill Smelkov
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
Hide 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
;
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,31 +120,60 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
return
-
EINVAL
;
}
switch
(
channels
)
{
case
1
:
regval
|=
LPAIF_I2SCTL_SPKMODE_SD0
;
regval
|=
LPAIF_I2SCTL_SPKMONO_MONO
;
break
;
case
2
:
regval
|=
LPAIF_I2SCTL_SPKMODE_SD0
;
regval
|=
LPAIF_I2SCTL_SPKMONO_STEREO
;
break
;
case
4
:
regval
|=
LPAIF_I2SCTL_SPKMODE_QUAD01
;
regval
|=
LPAIF_I2SCTL_SPKMONO_STEREO
;
break
;
case
6
:
regval
|=
LPAIF_I2SCTL_SPKMODE_6CH
;
regval
|=
LPAIF_I2SCTL_SPKMONO_STEREO
;
break
;
case
8
:
regval
|=
LPAIF_I2SCTL_SPKMODE_8CH
;
regval
|=
LPAIF_I2SCTL_SPKMONO_STEREO
;
break
;
default:
dev_err
(
dai
->
dev
,
"%s() invalid channels given: %u
\n
"
,
__func__
,
channels
);
return
-
EINVAL
;
if
(
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
{
switch
(
channels
)
{
case
1
:
regval
|=
LPAIF_I2SCTL_SPKMODE_SD0
;
regval
|=
LPAIF_I2SCTL_SPKMONO_MONO
;
break
;
case
2
:
regval
|=
LPAIF_I2SCTL_SPKMODE_SD0
;
regval
|=
LPAIF_I2SCTL_SPKMONO_STEREO
;
break
;
case
4
:
regval
|=
LPAIF_I2SCTL_SPKMODE_QUAD01
;
regval
|=
LPAIF_I2SCTL_SPKMONO_STEREO
;
break
;
case
6
:
regval
|=
LPAIF_I2SCTL_SPKMODE_6CH
;
regval
|=
LPAIF_I2SCTL_SPKMONO_STEREO
;
break
;
case
8
:
regval
|=
LPAIF_I2SCTL_SPKMODE_8CH
;
regval
|=
LPAIF_I2SCTL_SPKMONO_STEREO
;
break
;
default:
dev_err
(
dai
->
dev
,
"%s() invalid channels given: %u
\n
"
,
__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
,
...
...
@@ -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
)
{
return
IPQ806X_LPAIF_RDMA_CHAN_MI2S
;
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
;
if
(
v
->
alloc_dma_channel
)
data
->
rdma_ch
=
v
->
alloc_dma_channel
(
drv
data
);
data
->
i2s_port
=
cpu_dai
->
driver
->
id
;
snd_soc_pcm_set_drvdata
(
soc_runtime
,
data
);
if
(
IS_ERR_VALUE
(
data
->
rdma_ch
))
return
data
->
rdma_ch
;
psubstream
=
pcm
->
streams
[
SNDRV_PCM_STREAM_PLAYBACK
].
substream
;
if
(
psubstream
)
{
if
(
v
->
alloc_dma_channel
)
data
->
rdma_ch
=
v
->
alloc_dma_channel
(
drvdata
,
SNDRV_PCM_STREAM_PLAYBACK
);
drvdata
->
substream
[
data
->
rdma_ch
]
=
substream
;
data
->
i2s_port
=
cpu_dai
->
driver
->
id
;
if
(
IS_ERR_VALUE
(
data
->
rdma_ch
))
return
data
->
rdma_ch
;
snd_soc_pcm_set_drvdata
(
soc_runtime
,
data
)
;
drvdata
->
substream
[
data
->
rdma_ch
]
=
psubstream
;
ret
=
lpass_platform_alloc_buffer
(
substream
,
soc_runtime
);
if
(
ret
)
return
ret
;
ret
=
snd_dma_alloc_pages
(
SNDRV_DMA_TYPE_DEV
,
soc_runtime
->
platform
->
dev
,
size
,
&
psubstream
->
dma_buffer
);
if
(
ret
)
goto
playback_alloc_err
;
ret
=
regmap_write
(
drvdata
->
lpaif_map
,
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
"
,
if
(
ret
)
{
dev_err
(
soc_runtime
->
dev
,
"%s() error writing to rdmactl reg: %d
\n
"
,
__func__
,
ret
);
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
err_buf
;
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
;
if
(
v
->
free_dma_channel
)
v
->
free_dma_channel
(
drvdata
,
data
->
rdma_ch
);
lpass_platform_free_buffer
(
substream
,
soc_runtime
);
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
,
ch
);
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