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
43b64af5
Commit
43b64af5
authored
Dec 12, 2016
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'asoc/topic/rcar' into asoc-next
parents
52708d05
b99258a3
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
516 additions
and
249 deletions
+516
-249
sound/soc/sh/Kconfig
sound/soc/sh/Kconfig
+2
-1
sound/soc/sh/rcar/adg.c
sound/soc/sh/rcar/adg.c
+37
-24
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/core.c
+128
-47
sound/soc/sh/rcar/dma.c
sound/soc/sh/rcar/dma.c
+195
-100
sound/soc/sh/rcar/dvc.c
sound/soc/sh/rcar/dvc.c
+0
-2
sound/soc/sh/rcar/gen.c
sound/soc/sh/rcar/gen.c
+10
-2
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/rsnd.h
+100
-56
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/src.c
+8
-5
sound/soc/sh/rcar/ssi.c
sound/soc/sh/rcar/ssi.c
+16
-12
sound/soc/sh/rcar/ssiu.c
sound/soc/sh/rcar/ssiu.c
+20
-0
No files found.
sound/soc/sh/Kconfig
View file @
43b64af5
menu "SoC Audio support for SuperH"
depends on SUPERH || ARCH_SHMOBILE
depends on SUPERH || ARCH_SHMOBILE
|| COMPILE_TEST
config SND_SOC_PCM_SH7760
tristate "SoC Audio support for Renesas SH7760"
...
...
@@ -37,6 +37,7 @@ config SND_SOC_SH4_SIU
config SND_SOC_RCAR
tristate "R-Car series SRU/SCU/SSIU/SSI support"
depends on COMMON_CLK
depends on OF || COMPILE_TEST
select SND_SIMPLE_CARD
select REGMAP_MMIO
help
...
...
sound/soc/sh/rcar/adg.c
View file @
43b64af5
...
...
@@ -34,6 +34,9 @@ struct rsnd_adg {
struct
clk_onecell_data
onecell
;
struct
rsnd_mod
mod
;
u32
flags
;
u32
ckr
;
u32
rbga
;
u32
rbgb
;
int
rbga_rate_for_441khz
;
/* RBGA */
int
rbgb_rate_for_48khz
;
/* RBGB */
...
...
@@ -316,9 +319,11 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
struct
rsnd_priv
*
priv
=
rsnd_mod_to_priv
(
ssi_mod
);
struct
rsnd_adg
*
adg
=
rsnd_priv_to_adg
(
priv
);
struct
device
*
dev
=
rsnd_priv_to_dev
(
priv
);
struct
rsnd_mod
*
adg_mod
=
rsnd_mod_get
(
adg
);
struct
clk
*
clk
;
int
i
;
u32
data
;
u32
ckr
=
0
;
int
sel_table
[]
=
{
[
CLKA
]
=
0x1
,
[
CLKB
]
=
0x2
,
...
...
@@ -360,15 +365,14 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
rsnd_adg_set_ssi_clk
(
ssi_mod
,
data
);
if
(
!
(
adg_mode_flags
(
adg
)
&
LRCLK_ASYNC
))
{
struct
rsnd_mod
*
adg_mod
=
rsnd_mod_get
(
adg
);
u32
ckr
=
0
;
if
(
0
==
(
rate
%
8000
))
ckr
=
0x80000000
;
rsnd_mod_bset
(
adg_mod
,
SSICKR
,
0x80000000
,
ckr
);
}
rsnd_mod_bset
(
adg_mod
,
BRGCKR
,
0x80FF0000
,
adg
->
ckr
|
ckr
);
rsnd_mod_write
(
adg_mod
,
BRRA
,
adg
->
rbga
);
rsnd_mod_write
(
adg_mod
,
BRRB
,
adg
->
rbgb
);
dev_dbg
(
dev
,
"ADG: %s[%d] selects 0x%x for %d
\n
"
,
rsnd_mod_name
(
ssi_mod
),
rsnd_mod_id
(
ssi_mod
),
data
,
rate
);
...
...
@@ -376,6 +380,25 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
return
0
;
}
void
rsnd_adg_clk_control
(
struct
rsnd_priv
*
priv
,
int
enable
)
{
struct
rsnd_adg
*
adg
=
rsnd_priv_to_adg
(
priv
);
struct
device
*
dev
=
rsnd_priv_to_dev
(
priv
);
struct
clk
*
clk
;
int
i
,
ret
;
for_each_rsnd_clk
(
clk
,
adg
,
i
)
{
ret
=
0
;
if
(
enable
)
ret
=
clk_prepare_enable
(
clk
);
else
clk_disable_unprepare
(
clk
);
if
(
ret
<
0
)
dev_warn
(
dev
,
"can't use clk %d
\n
"
,
i
);
}
}
static
void
rsnd_adg_get_clkin
(
struct
rsnd_priv
*
priv
,
struct
rsnd_adg
*
adg
)
{
...
...
@@ -387,27 +410,21 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv,
[
CLKC
]
=
"clk_c"
,
[
CLKI
]
=
"clk_i"
,
};
int
i
,
ret
;
int
i
;
for
(
i
=
0
;
i
<
CLKMAX
;
i
++
)
{
clk
=
devm_clk_get
(
dev
,
clk_name
[
i
]);
adg
->
clk
[
i
]
=
IS_ERR
(
clk
)
?
NULL
:
clk
;
}
for_each_rsnd_clk
(
clk
,
adg
,
i
)
{
ret
=
clk_prepare_enable
(
clk
);
if
(
ret
<
0
)
dev_warn
(
dev
,
"can't use clk %d
\n
"
,
i
);
for_each_rsnd_clk
(
clk
,
adg
,
i
)
dev_dbg
(
dev
,
"clk %d : %p : %ld
\n
"
,
i
,
clk
,
clk_get_rate
(
clk
));
}
}
static
void
rsnd_adg_get_clkout
(
struct
rsnd_priv
*
priv
,
struct
rsnd_adg
*
adg
)
{
struct
clk
*
clk
;
struct
rsnd_mod
*
adg_mod
=
rsnd_mod_get
(
adg
);
struct
device
*
dev
=
rsnd_priv_to_dev
(
priv
);
struct
device_node
*
np
=
dev
->
of_node
;
u32
ckr
,
rbgx
,
rbga
,
rbgb
;
...
...
@@ -532,13 +549,13 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
}
}
rsnd_mod_bset
(
adg_mod
,
SSICKR
,
0x80FF0000
,
ckr
)
;
rsnd_mod_write
(
adg_mod
,
BRRA
,
rbga
)
;
rsnd_mod_write
(
adg_mod
,
BRRB
,
rbgb
)
;
adg
->
ckr
=
ckr
;
adg
->
rbga
=
rbga
;
adg
->
rbgb
=
rbgb
;
for_each_rsnd_clkout
(
clk
,
adg
,
i
)
dev_dbg
(
dev
,
"clkout %d : %p : %ld
\n
"
,
i
,
clk
,
clk_get_rate
(
clk
));
dev_dbg
(
dev
,
"
SSI
CKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x
\n
"
,
dev_dbg
(
dev
,
"
BRG
CKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x
\n
"
,
ckr
,
rbga
,
rbgb
);
}
...
...
@@ -565,16 +582,12 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
priv
->
adg
=
adg
;
rsnd_adg_clk_enable
(
priv
);
return
0
;
}
void
rsnd_adg_remove
(
struct
rsnd_priv
*
priv
)
{
struct
rsnd_adg
*
adg
=
rsnd_priv_to_adg
(
priv
);
struct
clk
*
clk
;
int
i
;
for_each_rsnd_clk
(
clk
,
adg
,
i
)
{
clk_disable_unprepare
(
clk
);
}
rsnd_adg_clk_disable
(
priv
);
}
sound/soc/sh/rcar/core.c
View file @
43b64af5
...
...
@@ -306,7 +306,7 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
*/
u32
rsnd_get_dalign
(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
)
{
struct
rsnd_mod
*
ssi
=
rsnd_io_to_mod_ssi
(
io
);
struct
rsnd_mod
*
ssi
u
=
rsnd_io_to_mod_ssiu
(
io
);
struct
rsnd_mod
*
target
;
struct
snd_pcm_runtime
*
runtime
=
rsnd_io_to_runtime
(
io
);
u32
val
=
0x76543210
;
...
...
@@ -315,11 +315,11 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
if
(
rsnd_io_is_play
(
io
))
{
struct
rsnd_mod
*
src
=
rsnd_io_to_mod_src
(
io
);
target
=
src
?
src
:
ssi
;
target
=
src
?
src
:
ssi
u
;
}
else
{
struct
rsnd_mod
*
cmd
=
rsnd_io_to_mod_cmd
(
io
);
target
=
cmd
?
cmd
:
ssi
;
target
=
cmd
?
cmd
:
ssi
u
;
}
mask
<<=
runtime
->
channels
*
4
;
...
...
@@ -348,32 +348,28 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
/*
* rsnd_dai functions
*/
#define rsnd_mod_call(idx, io, func, param...) \
({ \
struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \
struct rsnd_mod *mod = (io)->mod[idx]; \
struct device *dev = rsnd_priv_to_dev(priv); \
u32 *status = mod->get_status(io, mod, idx); \
u32 mask = 0xF << __rsnd_mod_shift_##func; \
u8 val = (*status >> __rsnd_mod_shift_##func) & 0xF; \
u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \
int ret = 0; \
int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \
if (add == 0xF) \
call = 0; \
else \
*status = (*status & ~mask) + \
(add << __rsnd_mod_shift_##func); \
dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \
rsnd_mod_name(mod), rsnd_mod_id(mod), \
*status, call ? #func : ""); \
if (call) \
ret = (mod)->ops->func(mod, io, param); \
if (ret) \
dev_dbg(dev, "%s[%d] : rsnd_mod_call error %d\n", \
rsnd_mod_name(mod), rsnd_mod_id(mod), ret); \
ret; \
})
struct
rsnd_mod
*
rsnd_mod_next
(
int
*
iterator
,
struct
rsnd_dai_stream
*
io
,
enum
rsnd_mod_type
*
array
,
int
array_size
)
{
struct
rsnd_mod
*
mod
;
enum
rsnd_mod_type
type
;
int
max
=
array
?
array_size
:
RSND_MOD_MAX
;
for
(;
*
iterator
<
max
;
(
*
iterator
)
++
)
{
type
=
(
array
)
?
array
[
*
iterator
]
:
*
iterator
;
mod
=
io
->
mod
[
type
];
if
(
!
mod
)
continue
;
(
*
iterator
)
++
;
return
mod
;
}
return
NULL
;
}
static
enum
rsnd_mod_type
rsnd_mod_sequence
[][
RSND_MOD_MAX
]
=
{
{
...
...
@@ -409,17 +405,47 @@ static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = {
},
};
static
int
rsnd_status_update
(
u32
*
status
,
int
shift
,
int
add
,
int
timing
)
{
u32
mask
=
0xF
<<
shift
;
u8
val
=
(
*
status
>>
shift
)
&
0xF
;
u8
next_val
=
(
val
+
add
)
&
0xF
;
int
func_call
=
(
val
==
timing
);
if
(
next_val
==
0xF
)
/* underflow case */
func_call
=
0
;
else
*
status
=
(
*
status
&
~
mask
)
+
(
next_val
<<
shift
);
return
func_call
;
}
#define rsnd_dai_call(fn, io, param...) \
({ \
struct rsnd_priv *priv = rsnd_io_to_priv(io); \
struct device *dev = rsnd_priv_to_dev(priv); \
struct rsnd_mod *mod; \
int
type, is_play = rsnd_io_is_play(io);
\
int
is_play = rsnd_io_is_play(io);
\
int ret = 0, i; \
for (i = 0; i < RSND_MOD_MAX; i++) { \
type = rsnd_mod_sequence[is_play][i]; \
mod = (io)->mod[type]; \
if (!mod) \
continue; \
ret |= rsnd_mod_call(type, io, fn, param); \
enum rsnd_mod_type *types = rsnd_mod_sequence[is_play]; \
for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) { \
int tmp = 0; \
u32 *status = mod->get_status(io, mod, types[i]); \
int func_call = rsnd_status_update(status, \
__rsnd_mod_shift_##fn, \
__rsnd_mod_add_##fn, \
__rsnd_mod_call_##fn); \
dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \
rsnd_mod_name(mod), rsnd_mod_id(mod), *status, \
(func_call && (mod)->ops->fn) ? #fn : ""); \
if (func_call && (mod)->ops->fn) \
tmp = (mod)->ops->fn(mod, io, param); \
if (tmp) \
dev_err(dev, "%s[%d] : %s error %d\n", \
rsnd_mod_name(mod), rsnd_mod_id(mod), \
#fn, tmp); \
ret |= tmp; \
} \
ret; \
})
...
...
@@ -690,7 +716,33 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
return
0
;
}
static
int
rsnd_soc_dai_startup
(
struct
snd_pcm_substream
*
substream
,
struct
snd_soc_dai
*
dai
)
{
struct
rsnd_dai
*
rdai
=
rsnd_dai_to_rdai
(
dai
);
struct
rsnd_dai_stream
*
io
=
rsnd_rdai_to_io
(
rdai
,
substream
);
/*
* call rsnd_dai_call without spinlock
*/
return
rsnd_dai_call
(
nolock_start
,
io
,
priv
);
}
static
void
rsnd_soc_dai_shutdown
(
struct
snd_pcm_substream
*
substream
,
struct
snd_soc_dai
*
dai
)
{
struct
rsnd_dai
*
rdai
=
rsnd_dai_to_rdai
(
dai
);
struct
rsnd_dai_stream
*
io
=
rsnd_rdai_to_io
(
rdai
,
substream
);
/*
* call rsnd_dai_call without spinlock
*/
rsnd_dai_call
(
nolock_stop
,
io
,
priv
);
}
static
const
struct
snd_soc_dai_ops
rsnd_soc_dai_ops
=
{
.
startup
=
rsnd_soc_dai_startup
,
.
shutdown
=
rsnd_soc_dai_shutdown
,
.
trigger
=
rsnd_soc_dai_trigger
,
.
set_fmt
=
rsnd_soc_dai_set_fmt
,
.
set_tdm_slot
=
rsnd_soc_set_dai_tdm_slot
,
...
...
@@ -993,7 +1045,11 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod,
void
_rsnd_kctrl_remove
(
struct
rsnd_kctrl_cfg
*
cfg
)
{
if
(
cfg
->
card
&&
cfg
->
kctrl
)
snd_ctl_remove
(
cfg
->
card
,
cfg
->
kctrl
);
cfg
->
card
=
NULL
;
cfg
->
kctrl
=
NULL
;
}
int
rsnd_kctrl_new_m
(
struct
rsnd_mod
*
mod
,
...
...
@@ -1070,8 +1126,8 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
return
snd_pcm_lib_preallocate_pages_for_all
(
rtd
->
pcm
,
SNDRV_DMA_TYPE_
DEV
,
rtd
->
card
->
snd_card
->
dev
,
SNDRV_DMA_TYPE_
CONTINUOUS
,
snd_dma_continuous_data
(
GFP_KERNEL
)
,
PREALLOC_BUFFER
,
PREALLOC_BUFFER_MAX
);
}
...
...
@@ -1092,6 +1148,7 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
ret
=
rsnd_dai_call
(
probe
,
io
,
priv
);
if
(
ret
==
-
EAGAIN
)
{
struct
rsnd_mod
*
ssi_mod
=
rsnd_io_to_mod_ssi
(
io
);
struct
rsnd_mod
*
mod
;
int
i
;
/*
...
...
@@ -1111,8 +1168,8 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
* remove all mod from io
* and, re connect ssi
*/
for
(
i
=
0
;
i
<
RSND_MOD_MAX
;
i
++
)
rsnd_dai_disconnect
(
(
io
)
->
mod
[
i
]
,
io
,
i
);
for
_each_rsnd_mod
(
i
,
mod
,
io
)
rsnd_dai_disconnect
(
mod
,
io
,
i
);
rsnd_dai_connect
(
ssi_mod
,
io
,
RSND_MOD_SSI
);
/*
...
...
@@ -1251,9 +1308,33 @@ static int rsnd_remove(struct platform_device *pdev)
return
ret
;
}
static
int
rsnd_suspend
(
struct
device
*
dev
)
{
struct
rsnd_priv
*
priv
=
dev_get_drvdata
(
dev
);
rsnd_adg_clk_disable
(
priv
);
return
0
;
}
static
int
rsnd_resume
(
struct
device
*
dev
)
{
struct
rsnd_priv
*
priv
=
dev_get_drvdata
(
dev
);
rsnd_adg_clk_enable
(
priv
);
return
0
;
}
static
struct
dev_pm_ops
rsnd_pm_ops
=
{
.
suspend
=
rsnd_suspend
,
.
resume
=
rsnd_resume
,
};
static
struct
platform_driver
rsnd_driver
=
{
.
driver
=
{
.
name
=
"rcar_sound"
,
.
pm
=
&
rsnd_pm_ops
,
.
of_match_table
=
rsnd_of_match
,
},
.
probe
=
rsnd_probe
,
...
...
sound/soc/sh/rcar/dma.c
View file @
43b64af5
...
...
@@ -25,6 +25,10 @@
struct
rsnd_dmaen
{
struct
dma_chan
*
chan
;
dma_addr_t
dma_buf
;
unsigned
int
dma_len
;
unsigned
int
dma_period
;
unsigned
int
dma_cnt
;
};
struct
rsnd_dmapp
{
...
...
@@ -34,6 +38,8 @@ struct rsnd_dmapp {
struct
rsnd_dma
{
struct
rsnd_mod
mod
;
struct
rsnd_mod
*
mod_from
;
struct
rsnd_mod
*
mod_to
;
dma_addr_t
src_addr
;
dma_addr_t
dst_addr
;
union
{
...
...
@@ -56,10 +62,38 @@ struct rsnd_dma_ctrl {
/*
* Audio DMAC
*/
#define rsnd_dmaen_sync(dmaen, io, i) __rsnd_dmaen_sync(dmaen, io, i, 1)
#define rsnd_dmaen_unsync(dmaen, io, i) __rsnd_dmaen_sync(dmaen, io, i, 0)
static
void
__rsnd_dmaen_sync
(
struct
rsnd_dmaen
*
dmaen
,
struct
rsnd_dai_stream
*
io
,
int
i
,
int
sync
)
{
struct
device
*
dev
=
dmaen
->
chan
->
device
->
dev
;
enum
dma_data_direction
dir
;
int
is_play
=
rsnd_io_is_play
(
io
);
dma_addr_t
buf
;
int
len
,
max
;
size_t
period
;
len
=
dmaen
->
dma_len
;
period
=
dmaen
->
dma_period
;
max
=
len
/
period
;
i
=
i
%
max
;
buf
=
dmaen
->
dma_buf
+
(
period
*
i
);
dir
=
is_play
?
DMA_TO_DEVICE
:
DMA_FROM_DEVICE
;
if
(
sync
)
dma_sync_single_for_device
(
dev
,
buf
,
period
,
dir
);
else
dma_sync_single_for_cpu
(
dev
,
buf
,
period
,
dir
);
}
static
void
__rsnd_dmaen_complete
(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
)
{
struct
rsnd_priv
*
priv
=
rsnd_mod_to_priv
(
mod
);
struct
rsnd_dma
*
dma
=
rsnd_mod_to_dma
(
mod
);
struct
rsnd_dmaen
*
dmaen
=
rsnd_dma_to_dmaen
(
dma
);
bool
elapsed
=
false
;
unsigned
long
flags
;
...
...
@@ -76,9 +110,22 @@ static void __rsnd_dmaen_complete(struct rsnd_mod *mod,
*/
spin_lock_irqsave
(
&
priv
->
lock
,
flags
);
if
(
rsnd_io_is_working
(
io
))
if
(
rsnd_io_is_working
(
io
))
{
rsnd_dmaen_unsync
(
dmaen
,
io
,
dmaen
->
dma_cnt
);
/*
* Next period is already started.
* Let's sync Next Next period
* see
* rsnd_dmaen_start()
*/
rsnd_dmaen_sync
(
dmaen
,
io
,
dmaen
->
dma_cnt
+
2
);
elapsed
=
rsnd_dai_pointer_update
(
io
,
io
->
byte_per_period
);
dmaen
->
dma_cnt
++
;
}
spin_unlock_irqrestore
(
&
priv
->
lock
,
flags
);
if
(
elapsed
)
...
...
@@ -92,6 +139,20 @@ static void rsnd_dmaen_complete(void *data)
rsnd_mod_interrupt
(
mod
,
__rsnd_dmaen_complete
);
}
static
struct
dma_chan
*
rsnd_dmaen_request_channel
(
struct
rsnd_dai_stream
*
io
,
struct
rsnd_mod
*
mod_from
,
struct
rsnd_mod
*
mod_to
)
{
if
((
!
mod_from
&&
!
mod_to
)
||
(
mod_from
&&
mod_to
))
return
NULL
;
if
(
mod_from
)
return
rsnd_mod_dma_req
(
io
,
mod_from
);
else
return
rsnd_mod_dma_req
(
io
,
mod_to
);
}
static
int
rsnd_dmaen_stop
(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
,
struct
rsnd_priv
*
priv
)
...
...
@@ -99,7 +160,66 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod,
struct
rsnd_dma
*
dma
=
rsnd_mod_to_dma
(
mod
);
struct
rsnd_dmaen
*
dmaen
=
rsnd_dma_to_dmaen
(
dma
);
if
(
dmaen
->
chan
)
{
int
is_play
=
rsnd_io_is_play
(
io
);
dmaengine_terminate_all
(
dmaen
->
chan
);
dma_unmap_single
(
dmaen
->
chan
->
device
->
dev
,
dmaen
->
dma_buf
,
dmaen
->
dma_len
,
is_play
?
DMA_TO_DEVICE
:
DMA_FROM_DEVICE
);
}
return
0
;
}
static
int
rsnd_dmaen_nolock_stop
(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
,
struct
rsnd_priv
*
priv
)
{
struct
rsnd_dma
*
dma
=
rsnd_mod_to_dma
(
mod
);
struct
rsnd_dmaen
*
dmaen
=
rsnd_dma_to_dmaen
(
dma
);
/*
* DMAEngine release uses mutex lock.
* Thus, it shouldn't be called under spinlock.
* Let's call it under nolock_start
*/
if
(
dmaen
->
chan
)
dma_release_channel
(
dmaen
->
chan
);
dmaen
->
chan
=
NULL
;
return
0
;
}
static
int
rsnd_dmaen_nolock_start
(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
,
struct
rsnd_priv
*
priv
)
{
struct
rsnd_dma
*
dma
=
rsnd_mod_to_dma
(
mod
);
struct
rsnd_dmaen
*
dmaen
=
rsnd_dma_to_dmaen
(
dma
);
struct
device
*
dev
=
rsnd_priv_to_dev
(
priv
);
if
(
dmaen
->
chan
)
{
dev_err
(
dev
,
"it already has dma channel
\n
"
);
return
-
EIO
;
}
/*
* DMAEngine request uses mutex lock.
* Thus, it shouldn't be called under spinlock.
* Let's call it under nolock_start
*/
dmaen
->
chan
=
rsnd_dmaen_request_channel
(
io
,
dma
->
mod_from
,
dma
->
mod_to
);
if
(
IS_ERR_OR_NULL
(
dmaen
->
chan
))
{
int
ret
=
PTR_ERR
(
dmaen
->
chan
);
dmaen
->
chan
=
NULL
;
dev_err
(
dev
,
"can't get dma channel
\n
"
);
return
ret
;
}
return
0
;
}
...
...
@@ -113,12 +233,41 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
struct
snd_pcm_substream
*
substream
=
io
->
substream
;
struct
device
*
dev
=
rsnd_priv_to_dev
(
priv
);
struct
dma_async_tx_descriptor
*
desc
;
struct
dma_slave_config
cfg
=
{};
dma_addr_t
buf
;
size_t
len
;
size_t
period
;
int
is_play
=
rsnd_io_is_play
(
io
);
int
i
;
int
ret
;
cfg
.
direction
=
is_play
?
DMA_MEM_TO_DEV
:
DMA_DEV_TO_MEM
;
cfg
.
src_addr
=
dma
->
src_addr
;
cfg
.
dst_addr
=
dma
->
dst_addr
;
cfg
.
src_addr_width
=
DMA_SLAVE_BUSWIDTH_4_BYTES
;
cfg
.
dst_addr_width
=
DMA_SLAVE_BUSWIDTH_4_BYTES
;
dev_dbg
(
dev
,
"%s[%d] %pad -> %pad
\n
"
,
rsnd_mod_name
(
mod
),
rsnd_mod_id
(
mod
),
&
cfg
.
src_addr
,
&
cfg
.
dst_addr
);
ret
=
dmaengine_slave_config
(
dmaen
->
chan
,
&
cfg
);
if
(
ret
<
0
)
return
ret
;
len
=
snd_pcm_lib_buffer_bytes
(
substream
);
period
=
snd_pcm_lib_period_bytes
(
substream
);
buf
=
dma_map_single
(
dmaen
->
chan
->
device
->
dev
,
substream
->
runtime
->
dma_area
,
len
,
is_play
?
DMA_TO_DEVICE
:
DMA_FROM_DEVICE
);
if
(
dma_mapping_error
(
dmaen
->
chan
->
device
->
dev
,
buf
))
{
dev_err
(
dev
,
"dma map failed
\n
"
);
return
-
EIO
;
}
desc
=
dmaengine_prep_dma_cyclic
(
dmaen
->
chan
,
substream
->
runtime
->
dma_addr
,
snd_pcm_lib_buffer_bytes
(
substream
),
snd_pcm_lib_period_bytes
(
substream
),
buf
,
len
,
period
,
is_play
?
DMA_MEM_TO_DEV
:
DMA_DEV_TO_MEM
,
DMA_PREP_INTERRUPT
|
DMA_CTRL_ACK
);
...
...
@@ -130,6 +279,19 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
desc
->
callback
=
rsnd_dmaen_complete
;
desc
->
callback_param
=
rsnd_mod_get
(
dma
);
dmaen
->
dma_buf
=
buf
;
dmaen
->
dma_len
=
len
;
dmaen
->
dma_period
=
period
;
dmaen
->
dma_cnt
=
0
;
/*
* synchronize this and next period
* see
* __rsnd_dmaen_complete()
*/
for
(
i
=
0
;
i
<
2
;
i
++
)
rsnd_dmaen_sync
(
dmaen
,
io
,
i
);
if
(
dmaengine_submit
(
desc
)
<
0
)
{
dev_err
(
dev
,
"dmaengine_submit() fail
\n
"
);
return
-
EIO
;
...
...
@@ -143,110 +305,33 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
struct
dma_chan
*
rsnd_dma_request_channel
(
struct
device_node
*
of_node
,
struct
rsnd_mod
*
mod
,
char
*
name
)
{
struct
dma_chan
*
chan
;
struct
dma_chan
*
chan
=
NULL
;
struct
device_node
*
np
;
int
i
=
0
;
for_each_child_of_node
(
of_node
,
np
)
{
if
(
i
==
rsnd_mod_id
(
mod
))
break
;
if
(
i
==
rsnd_mod_id
(
mod
)
&&
(
!
chan
)
)
chan
=
of_dma_request_slave_channel
(
np
,
name
)
;
i
++
;
}
chan
=
of_dma_request_slave_channel
(
np
,
name
);
of_node_put
(
np
);
/* It should call of_node_put(), since, it is rsnd_xxx_of_node() */
of_node_put
(
of_node
);
return
chan
;
}
static
struct
dma_chan
*
rsnd_dmaen_request_channel
(
struct
rsnd_dai_stream
*
io
,
struct
rsnd_mod
*
mod_from
,
struct
rsnd_mod
*
mod_to
)
{
if
((
!
mod_from
&&
!
mod_to
)
||
(
mod_from
&&
mod_to
))
return
NULL
;
if
(
mod_from
)
return
rsnd_mod_dma_req
(
io
,
mod_from
);
else
return
rsnd_mod_dma_req
(
io
,
mod_to
);
}
static
int
rsnd_dmaen_remove
(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
,
struct
rsnd_priv
*
priv
)
{
struct
rsnd_dma
*
dma
=
rsnd_mod_to_dma
(
mod
);
struct
rsnd_dmaen
*
dmaen
=
rsnd_dma_to_dmaen
(
dma
);
if
(
dmaen
->
chan
)
dma_release_channel
(
dmaen
->
chan
);
dmaen
->
chan
=
NULL
;
return
0
;
}
static
int
rsnd_dmaen_attach
(
struct
rsnd_dai_stream
*
io
,
struct
rsnd_dma
*
dma
,
int
id
,
struct
rsnd_dma
*
dma
,
struct
rsnd_mod
*
mod_from
,
struct
rsnd_mod
*
mod_to
)
{
struct
rsnd_mod
*
mod
=
rsnd_mod_get
(
dma
);
struct
rsnd_dmaen
*
dmaen
=
rsnd_dma_to_dmaen
(
dma
);
struct
rsnd_priv
*
priv
=
rsnd_io_to_priv
(
io
);
struct
rsnd_dma_ctrl
*
dmac
=
rsnd_priv_to_dmac
(
priv
);
struct
device
*
dev
=
rsnd_priv_to_dev
(
priv
);
struct
dma_slave_config
cfg
=
{};
int
is_play
=
rsnd_io_is_play
(
io
);
int
ret
;
if
(
dmaen
->
chan
)
{
dev_err
(
dev
,
"it already has dma channel
\n
"
);
return
-
EIO
;
}
if
(
dev
->
of_node
)
{
dmaen
->
chan
=
rsnd_dmaen_request_channel
(
io
,
mod_from
,
mod_to
);
}
else
{
dma_cap_mask_t
mask
;
dma_cap_zero
(
mask
);
dma_cap_set
(
DMA_SLAVE
,
mask
);
dmaen
->
chan
=
dma_request_channel
(
mask
,
shdma_chan_filter
,
(
void
*
)(
uintptr_t
)
id
);
}
if
(
IS_ERR_OR_NULL
(
dmaen
->
chan
))
{
dmaen
->
chan
=
NULL
;
dev_err
(
dev
,
"can't get dma channel
\n
"
);
goto
rsnd_dma_channel_err
;
}
cfg
.
direction
=
is_play
?
DMA_MEM_TO_DEV
:
DMA_DEV_TO_MEM
;
cfg
.
src_addr
=
dma
->
src_addr
;
cfg
.
dst_addr
=
dma
->
dst_addr
;
cfg
.
src_addr_width
=
DMA_SLAVE_BUSWIDTH_4_BYTES
;
cfg
.
dst_addr_width
=
DMA_SLAVE_BUSWIDTH_4_BYTES
;
dev_dbg
(
dev
,
"%s[%d] %pad -> %pad
\n
"
,
rsnd_mod_name
(
mod
),
rsnd_mod_id
(
mod
),
&
cfg
.
src_addr
,
&
cfg
.
dst_addr
);
ret
=
dmaengine_slave_config
(
dmaen
->
chan
,
&
cfg
);
if
(
ret
<
0
)
goto
rsnd_dma_attach_err
;
dmac
->
dmaen_num
++
;
return
0
;
rsnd_dma_attach_err:
rsnd_dmaen_remove
(
mod
,
io
,
priv
);
rsnd_dma_channel_err:
struct
dma_chan
*
chan
;
/* try to get DMAEngine channel */
chan
=
rsnd_dmaen_request_channel
(
io
,
mod_from
,
mod_to
);
if
(
IS_ERR_OR_NULL
(
chan
))
{
/*
* DMA failed. try to PIO mode
* see
...
...
@@ -254,13 +339,21 @@ static int rsnd_dmaen_attach(struct rsnd_dai_stream *io,
* rsnd_rdai_continuance_probe()
*/
return
-
EAGAIN
;
}
dma_release_channel
(
chan
);
dmac
->
dmaen_num
++
;
return
0
;
}
static
struct
rsnd_mod_ops
rsnd_dmaen_ops
=
{
.
name
=
"audmac"
,
.
nolock_start
=
rsnd_dmaen_nolock_start
,
.
nolock_stop
=
rsnd_dmaen_nolock_stop
,
.
start
=
rsnd_dmaen_start
,
.
stop
=
rsnd_dmaen_stop
,
.
remove
=
rsnd_dmaen_remove
,
};
/*
...
...
@@ -394,7 +487,7 @@ static int rsnd_dmapp_start(struct rsnd_mod *mod,
}
static
int
rsnd_dmapp_attach
(
struct
rsnd_dai_stream
*
io
,
struct
rsnd_dma
*
dma
,
int
id
,
struct
rsnd_dma
*
dma
,
struct
rsnd_mod
*
mod_from
,
struct
rsnd_mod
*
mod_to
)
{
struct
rsnd_dmapp
*
dmapp
=
rsnd_dma_to_dmapp
(
dma
);
...
...
@@ -627,7 +720,7 @@ static void rsnd_dma_of_path(struct rsnd_mod *this,
}
int
rsnd_dma_attach
(
struct
rsnd_dai_stream
*
io
,
struct
rsnd_mod
*
mod
,
struct
rsnd_mod
**
dma_mod
,
int
id
)
struct
rsnd_mod
**
dma_mod
)
{
struct
rsnd_mod
*
mod_from
=
NULL
;
struct
rsnd_mod
*
mod_to
=
NULL
;
...
...
@@ -636,7 +729,7 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
struct
device
*
dev
=
rsnd_priv_to_dev
(
priv
);
struct
rsnd_mod_ops
*
ops
;
enum
rsnd_mod_type
type
;
int
(
*
attach
)(
struct
rsnd_dai_stream
*
io
,
struct
rsnd_dma
*
dma
,
int
id
,
int
(
*
attach
)(
struct
rsnd_dai_stream
*
io
,
struct
rsnd_dma
*
dma
,
struct
rsnd_mod
*
mod_from
,
struct
rsnd_mod
*
mod_to
);
int
is_play
=
rsnd_io_is_play
(
io
);
int
ret
,
dma_id
;
...
...
@@ -682,9 +775,6 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
*
dma_mod
=
rsnd_mod_get
(
dma
);
dma
->
src_addr
=
rsnd_dma_addr
(
io
,
mod_from
,
is_play
,
1
);
dma
->
dst_addr
=
rsnd_dma_addr
(
io
,
mod_to
,
is_play
,
0
);
ret
=
rsnd_mod_init
(
priv
,
*
dma_mod
,
ops
,
NULL
,
rsnd_mod_get_status
,
type
,
dma_id
);
if
(
ret
<
0
)
...
...
@@ -695,9 +785,14 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
rsnd_mod_name
(
mod_from
),
rsnd_mod_id
(
mod_from
),
rsnd_mod_name
(
mod_to
),
rsnd_mod_id
(
mod_to
));
ret
=
attach
(
io
,
dma
,
id
,
mod_from
,
mod_to
);
ret
=
attach
(
io
,
dma
,
mod_from
,
mod_to
);
if
(
ret
<
0
)
return
ret
;
dma
->
src_addr
=
rsnd_dma_addr
(
io
,
mod_from
,
is_play
,
1
);
dma
->
dst_addr
=
rsnd_dma_addr
(
io
,
mod_to
,
is_play
,
0
);
dma
->
mod_from
=
mod_from
;
dma
->
mod_to
=
mod_to
;
}
ret
=
rsnd_dai_connect
(
*
dma_mod
,
io
,
type
);
...
...
sound/soc/sh/rcar/dvc.c
View file @
43b64af5
...
...
@@ -48,8 +48,6 @@ struct rsnd_dvc {
#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id)
#define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
#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)
...
...
sound/soc/sh/rcar/gen.c
View file @
43b64af5
...
...
@@ -211,6 +211,14 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)
RSND_GEN_S_REG
(
SSI_MODE1
,
0x804
),
RSND_GEN_S_REG
(
SSI_MODE2
,
0x808
),
RSND_GEN_S_REG
(
SSI_CONTROL
,
0x810
),
RSND_GEN_S_REG
(
SSI_SYS_STATUS0
,
0x840
),
RSND_GEN_S_REG
(
SSI_SYS_STATUS1
,
0x844
),
RSND_GEN_S_REG
(
SSI_SYS_STATUS2
,
0x848
),
RSND_GEN_S_REG
(
SSI_SYS_STATUS3
,
0x84c
),
RSND_GEN_S_REG
(
SSI_SYS_STATUS4
,
0x880
),
RSND_GEN_S_REG
(
SSI_SYS_STATUS5
,
0x884
),
RSND_GEN_S_REG
(
SSI_SYS_STATUS6
,
0x888
),
RSND_GEN_S_REG
(
SSI_SYS_STATUS7
,
0x88c
),
/* FIXME: it needs SSI_MODE2/3 in the future */
RSND_GEN_M_REG
(
SSI_BUSIF_MODE
,
0x0
,
0x80
),
...
...
@@ -311,7 +319,7 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)
static
const
struct
rsnd_regmap_field_conf
conf_adg
[]
=
{
RSND_GEN_S_REG
(
BRRA
,
0x00
),
RSND_GEN_S_REG
(
BRRB
,
0x04
),
RSND_GEN_S_REG
(
SSI
CKR
,
0x08
),
RSND_GEN_S_REG
(
BRG
CKR
,
0x08
),
RSND_GEN_S_REG
(
AUDIO_CLK_SEL0
,
0x0c
),
RSND_GEN_S_REG
(
AUDIO_CLK_SEL1
,
0x10
),
RSND_GEN_S_REG
(
AUDIO_CLK_SEL2
,
0x14
),
...
...
@@ -362,7 +370,7 @@ static int rsnd_gen1_probe(struct rsnd_priv *priv)
static
const
struct
rsnd_regmap_field_conf
conf_adg
[]
=
{
RSND_GEN_S_REG
(
BRRA
,
0x00
),
RSND_GEN_S_REG
(
BRRB
,
0x04
),
RSND_GEN_S_REG
(
SSI
CKR
,
0x08
),
RSND_GEN_S_REG
(
BRG
CKR
,
0x08
),
RSND_GEN_S_REG
(
AUDIO_CLK_SEL0
,
0x0c
),
RSND_GEN_S_REG
(
AUDIO_CLK_SEL1
,
0x10
),
};
...
...
sound/soc/sh/rcar/rsnd.h
View file @
43b64af5
...
...
@@ -43,17 +43,7 @@
* see gen1/gen2 for detail
*/
enum
rsnd_reg
{
/* SCU (SRC/SSIU/MIX/CTU/DVC) */
RSND_REG_SSI_MODE
,
/* Gen2 only */
RSND_REG_SSI_MODE0
,
RSND_REG_SSI_MODE1
,
RSND_REG_SSI_MODE2
,
RSND_REG_SSI_CONTROL
,
RSND_REG_SSI_CTRL
,
/* Gen2 only */
RSND_REG_SSI_BUSIF_MODE
,
/* Gen2 only */
RSND_REG_SSI_BUSIF_ADINR
,
/* Gen2 only */
RSND_REG_SSI_BUSIF_DALIGN
,
/* Gen2 only */
RSND_REG_SSI_INT_ENABLE
,
/* Gen2 only */
/* SCU (MIX/CTU/DVC) */
RSND_REG_SRC_I_BUSIF_MODE
,
RSND_REG_SRC_O_BUSIF_MODE
,
RSND_REG_SRC_ROUTE_MODE0
,
...
...
@@ -63,29 +53,29 @@ enum rsnd_reg {
RSND_REG_SRC_IFSCR
,
RSND_REG_SRC_IFSVR
,
RSND_REG_SRC_SRCCR
,
RSND_REG_SRC_CTRL
,
/* Gen2 only */
RSND_REG_SRC_BSDSR
,
/* Gen2 only */
RSND_REG_SRC_BSISR
,
/* Gen2 only */
RSND_REG_SRC_INT_ENABLE0
,
/* Gen2 only */
RSND_REG_SRC_BUSIF_DALIGN
,
/* Gen2 only */
RSND_REG_SRCIN_TIMSEL0
,
/* Gen2 only */
RSND_REG_SRCIN_TIMSEL1
,
/* Gen2 only */
RSND_REG_SRCIN_TIMSEL2
,
/* Gen2 only */
RSND_REG_SRCIN_TIMSEL3
,
/* Gen2 only */
RSND_REG_SRCIN_TIMSEL4
,
/* Gen2 only */
RSND_REG_SRCOUT_TIMSEL0
,
/* Gen2 only */
RSND_REG_SRCOUT_TIMSEL1
,
/* Gen2 only */
RSND_REG_SRCOUT_TIMSEL2
,
/* Gen2 only */
RSND_REG_SRCOUT_TIMSEL3
,
/* Gen2 only */
RSND_REG_SRCOUT_TIMSEL4
,
/* Gen2 only */
RSND_REG_SRC_CTRL
,
RSND_REG_SRC_BSDSR
,
RSND_REG_SRC_BSISR
,
RSND_REG_SRC_INT_ENABLE0
,
RSND_REG_SRC_BUSIF_DALIGN
,
RSND_REG_SRCIN_TIMSEL0
,
RSND_REG_SRCIN_TIMSEL1
,
RSND_REG_SRCIN_TIMSEL2
,
RSND_REG_SRCIN_TIMSEL3
,
RSND_REG_SRCIN_TIMSEL4
,
RSND_REG_SRCOUT_TIMSEL0
,
RSND_REG_SRCOUT_TIMSEL1
,
RSND_REG_SRCOUT_TIMSEL2
,
RSND_REG_SRCOUT_TIMSEL3
,
RSND_REG_SRCOUT_TIMSEL4
,
RSND_REG_SCU_SYS_STATUS0
,
RSND_REG_SCU_SYS_STATUS1
,
/* Gen2 only */
RSND_REG_SCU_SYS_STATUS1
,
RSND_REG_SCU_SYS_INT_EN0
,
RSND_REG_SCU_SYS_INT_EN1
,
/* Gen2 only */
RSND_REG_CMD_CTRL
,
/* Gen2 only */
RSND_REG_CMD_BUSIF_DALIGN
,
/* Gen2 only */
RSND_REG_SCU_SYS_INT_EN1
,
RSND_REG_CMD_CTRL
,
RSND_REG_CMD_BUSIF_DALIGN
,
RSND_REG_CMD_ROUTE_SLCT
,
RSND_REG_CMDOUT_TIMSEL
,
/* Gen2 only */
RSND_REG_CMDOUT_TIMSEL
,
RSND_REG_CTU_SWRSR
,
RSND_REG_CTU_CTUIR
,
RSND_REG_CTU_ADINR
,
...
...
@@ -147,18 +137,38 @@ enum rsnd_reg {
RSND_REG_DVC_VOL6R
,
RSND_REG_DVC_VOL7R
,
RSND_REG_DVC_DVUER
,
RSND_REG_DVC_VRCTR
,
/* Gen2 only */
RSND_REG_DVC_VRPDR
,
/* Gen2 only */
RSND_REG_DVC_VRDBR
,
/* Gen2 only */
RSND_REG_DVC_VRCTR
,
RSND_REG_DVC_VRPDR
,
RSND_REG_DVC_VRDBR
,
/* ADG */
RSND_REG_BRRA
,
RSND_REG_BRRB
,
RSND_REG_
SSI
CKR
,
RSND_REG_DIV_EN
,
/* Gen2 only */
RSND_REG_
BRG
CKR
,
RSND_REG_DIV_EN
,
RSND_REG_AUDIO_CLK_SEL0
,
RSND_REG_AUDIO_CLK_SEL1
,
RSND_REG_AUDIO_CLK_SEL2
,
/* Gen2 only */
RSND_REG_AUDIO_CLK_SEL2
,
/* SSIU */
RSND_REG_SSI_MODE
,
RSND_REG_SSI_MODE0
,
RSND_REG_SSI_MODE1
,
RSND_REG_SSI_MODE2
,
RSND_REG_SSI_CONTROL
,
RSND_REG_SSI_CTRL
,
RSND_REG_SSI_BUSIF_MODE
,
RSND_REG_SSI_BUSIF_ADINR
,
RSND_REG_SSI_BUSIF_DALIGN
,
RSND_REG_SSI_INT_ENABLE
,
RSND_REG_SSI_SYS_STATUS0
,
RSND_REG_SSI_SYS_STATUS1
,
RSND_REG_SSI_SYS_STATUS2
,
RSND_REG_SSI_SYS_STATUS3
,
RSND_REG_SSI_SYS_STATUS4
,
RSND_REG_SSI_SYS_STATUS5
,
RSND_REG_SSI_SYS_STATUS6
,
RSND_REG_SSI_SYS_STATUS7
,
/* SSI */
RSND_REG_SSICR
,
...
...
@@ -199,7 +209,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
* R-Car DMA
*/
int
rsnd_dma_attach
(
struct
rsnd_dai_stream
*
io
,
struct
rsnd_mod
*
mod
,
struct
rsnd_mod
**
dma_mod
,
int
id
);
struct
rsnd_mod
*
mod
,
struct
rsnd_mod
**
dma_mod
);
int
rsnd_dma_probe
(
struct
rsnd_priv
*
priv
);
struct
dma_chan
*
rsnd_dma_request_channel
(
struct
device_node
*
of_node
,
struct
rsnd_mod
*
mod
,
char
*
name
);
...
...
@@ -259,6 +269,12 @@ struct rsnd_mod_ops {
int
(
*
fallback
)(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
,
struct
rsnd_priv
*
priv
);
int
(
*
nolock_start
)(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
,
struct
rsnd_priv
*
priv
);
int
(
*
nolock_stop
)(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
,
struct
rsnd_priv
*
priv
);
};
struct
rsnd_dai_stream
;
...
...
@@ -278,7 +294,7 @@ struct rsnd_mod {
*
* 0xH0000CBA
*
* A 0:
probe 1: remove
* A 0:
nolock_start 1: nolock_stop
* B 0: init 1: quit
* C 0: start 1: stop
*
...
...
@@ -288,19 +304,23 @@ struct rsnd_mod {
* H 0: fallback
* H 0: hw_params
*/
#define __rsnd_mod_shift_
probe
0
#define __rsnd_mod_shift_
remove
0
#define __rsnd_mod_shift_
nolock_start
0
#define __rsnd_mod_shift_
nolock_stop
0
#define __rsnd_mod_shift_init 4
#define __rsnd_mod_shift_quit 4
#define __rsnd_mod_shift_start 8
#define __rsnd_mod_shift_stop 8
#define __rsnd_mod_shift_probe 28
/* always called */
#define __rsnd_mod_shift_remove 28
/* always called */
#define __rsnd_mod_shift_irq 28
/* always called */
#define __rsnd_mod_shift_pcm_new 28
/* always called */
#define __rsnd_mod_shift_fallback 28
/* always called */
#define __rsnd_mod_shift_hw_params 28
/* always called */
#define __rsnd_mod_add_probe 1
#define __rsnd_mod_add_remove -1
#define __rsnd_mod_add_probe 0
#define __rsnd_mod_add_remove 0
#define __rsnd_mod_add_nolock_start 1
#define __rsnd_mod_add_nolock_stop -1
#define __rsnd_mod_add_init 1
#define __rsnd_mod_add_quit -1
#define __rsnd_mod_add_start 1
...
...
@@ -311,7 +331,7 @@ struct rsnd_mod {
#define __rsnd_mod_add_hw_params 0
#define __rsnd_mod_call_probe 0
#define __rsnd_mod_call_remove
1
#define __rsnd_mod_call_remove
0
#define __rsnd_mod_call_init 0
#define __rsnd_mod_call_quit 1
#define __rsnd_mod_call_start 0
...
...
@@ -320,6 +340,8 @@ struct rsnd_mod {
#define __rsnd_mod_call_pcm_new 0
#define __rsnd_mod_call_fallback 0
#define __rsnd_mod_call_hw_params 0
#define __rsnd_mod_call_nolock_start 0
#define __rsnd_mod_call_nolock_stop 1
#define rsnd_mod_to_priv(mod) ((mod)->priv)
#define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1)
...
...
@@ -346,6 +368,18 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod,
u32
*
rsnd_mod_get_status
(
struct
rsnd_dai_stream
*
io
,
struct
rsnd_mod
*
mod
,
enum
rsnd_mod_type
type
);
struct
rsnd_mod
*
rsnd_mod_next
(
int
*
iterator
,
struct
rsnd_dai_stream
*
io
,
enum
rsnd_mod_type
*
array
,
int
array_size
);
#define for_each_rsnd_mod(iterator, pos, io) \
for (iterator = 0; \
(pos = rsnd_mod_next(&iterator, io, NULL, 0));)
#define for_each_rsnd_mod_arrays(iterator, pos, io, array, size) \
for (iterator = 0; \
(pos = rsnd_mod_next(&iterator, io, array, size));)
#define for_each_rsnd_mod_array(iterator, pos, io, array) \
for_each_rsnd_mod_arrays(iterator, pos, io, array, ARRAY_SIZE(array))
void
rsnd_parse_connect_common
(
struct
rsnd_dai
*
rdai
,
struct
rsnd_mod
*
(
*
mod_get
)(
struct
rsnd_priv
*
priv
,
int
id
),
...
...
@@ -364,6 +398,18 @@ int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io);
int
rsnd_runtime_is_ssi_multi
(
struct
rsnd_dai_stream
*
io
);
int
rsnd_runtime_is_ssi_tdm
(
struct
rsnd_dai_stream
*
io
);
/*
* DT
*/
#define rsnd_parse_of_node(priv, node) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, node)
#define RSND_NODE_DAI "rcar_sound,dai"
#define RSND_NODE_SSI "rcar_sound,ssi"
#define RSND_NODE_SRC "rcar_sound,src"
#define RSND_NODE_CTU "rcar_sound,ctu"
#define RSND_NODE_MIX "rcar_sound,mix"
#define RSND_NODE_DVC "rcar_sound,dvc"
/*
* R-Car sound DAI
*/
...
...
@@ -382,6 +428,7 @@ struct rsnd_dai_stream {
};
#define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
#define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI)
#define rsnd_io_to_mod_ssiu(io) rsnd_io_to_mod((io), RSND_MOD_SSIU)
#define rsnd_io_to_mod_ssip(io) rsnd_io_to_mod((io), RSND_MOD_SSIP)
#define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC)
#define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU)
...
...
@@ -428,8 +475,7 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
int
rsnd_dai_connect
(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
,
enum
rsnd_mod_type
type
);
#define rsnd_dai_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dai")
#define rsnd_dai_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DAI)
/*
* R-Car Gen1/Gen2
...
...
@@ -453,6 +499,9 @@ int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
unsigned
int
out_rate
);
int
rsnd_adg_set_cmd_timsel_gen2
(
struct
rsnd_mod
*
mod
,
struct
rsnd_dai_stream
*
io
);
#define rsnd_adg_clk_enable(priv) rsnd_adg_clk_control(priv, 1)
#define rsnd_adg_clk_disable(priv) rsnd_adg_clk_control(priv, 0)
void
rsnd_adg_clk_control
(
struct
rsnd_priv
*
priv
,
int
enable
);
/*
* R-Car sound priv
...
...
@@ -606,8 +655,7 @@ u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io);
__rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))
int
__rsnd_ssi_is_pin_sharing
(
struct
rsnd_mod
*
mod
);
#define rsnd_ssi_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi")
#define rsnd_ssi_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSI)
void
rsnd_parse_connect_ssi
(
struct
rsnd_dai
*
rdai
,
struct
device_node
*
playback
,
struct
device_node
*
capture
);
...
...
@@ -633,8 +681,7 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
struct
rsnd_dai_stream
*
io
,
int
is_in
);
#define rsnd_src_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src")
#define rsnd_src_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SRC)
#define rsnd_parse_connect_src(rdai, playback, capture) \
rsnd_parse_connect_common(rdai, rsnd_src_mod_get, \
rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \
...
...
@@ -647,8 +694,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv);
void
rsnd_ctu_remove
(
struct
rsnd_priv
*
priv
);
int
rsnd_ctu_converted_channel
(
struct
rsnd_mod
*
mod
);
struct
rsnd_mod
*
rsnd_ctu_mod_get
(
struct
rsnd_priv
*
priv
,
int
id
);
#define rsnd_ctu_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu")
#define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU)
#define rsnd_parse_connect_ctu(rdai, playback, capture) \
rsnd_parse_connect_common(rdai, rsnd_ctu_mod_get, \
rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \
...
...
@@ -660,8 +706,7 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
int
rsnd_mix_probe
(
struct
rsnd_priv
*
priv
);
void
rsnd_mix_remove
(
struct
rsnd_priv
*
priv
);
struct
rsnd_mod
*
rsnd_mix_mod_get
(
struct
rsnd_priv
*
priv
,
int
id
);
#define rsnd_mix_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,mix")
#define rsnd_mix_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_MIX)
#define rsnd_parse_connect_mix(rdai, playback, capture) \
rsnd_parse_connect_common(rdai, rsnd_mix_mod_get, \
rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \
...
...
@@ -673,8 +718,7 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id);
int
rsnd_dvc_probe
(
struct
rsnd_priv
*
priv
);
void
rsnd_dvc_remove
(
struct
rsnd_priv
*
priv
);
struct
rsnd_mod
*
rsnd_dvc_mod_get
(
struct
rsnd_priv
*
priv
,
int
id
);
#define rsnd_dvc_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
#define rsnd_dvc_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DVC)
#define rsnd_parse_connect_dvc(rdai, playback, capture) \
rsnd_parse_connect_common(rdai, rsnd_dvc_mod_get, \
rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \
...
...
sound/soc/sh/rcar/src.c
View file @
43b64af5
...
...
@@ -189,6 +189,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
struct
rsnd_priv
*
priv
=
rsnd_mod_to_priv
(
mod
);
struct
device
*
dev
=
rsnd_priv_to_dev
(
priv
);
struct
snd_pcm_runtime
*
runtime
=
rsnd_io_to_runtime
(
io
);
int
use_src
=
0
;
u32
fin
,
fout
;
u32
ifscr
,
fsrate
,
adinr
;
u32
cr
,
route
;
...
...
@@ -214,6 +215,8 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
return
;
}
use_src
=
(
fin
!=
fout
)
|
rsnd_src_sync_is_enabled
(
mod
);
/*
* SRC_ADINR
*/
...
...
@@ -225,7 +228,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
*/
ifscr
=
0
;
fsrate
=
0
;
if
(
fin
!=
fout
)
{
if
(
use_src
)
{
u64
n
;
ifscr
=
1
;
...
...
@@ -239,7 +242,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
*/
cr
=
0x00011110
;
route
=
0x0
;
if
(
fin
!=
fout
)
{
if
(
use_src
)
{
route
=
0x1
;
if
(
rsnd_src_sync_is_enabled
(
mod
))
{
...
...
@@ -327,8 +330,8 @@ static void rsnd_src_status_clear(struct rsnd_mod *mod)
{
u32
val
=
OUF_SRC
(
rsnd_mod_id
(
mod
));
rsnd_mod_
bset
(
mod
,
SCU_SYS_STATUS0
,
val
,
val
);
rsnd_mod_
bset
(
mod
,
SCU_SYS_STATUS1
,
val
,
val
);
rsnd_mod_
write
(
mod
,
SCU_SYS_STATUS0
,
val
);
rsnd_mod_
write
(
mod
,
SCU_SYS_STATUS1
,
val
);
}
static
bool
rsnd_src_error_occurred
(
struct
rsnd_mod
*
mod
)
...
...
@@ -475,7 +478,7 @@ static int rsnd_src_probe_(struct rsnd_mod *mod,
return
ret
;
}
ret
=
rsnd_dma_attach
(
io
,
mod
,
&
src
->
dma
,
0
);
ret
=
rsnd_dma_attach
(
io
,
mod
,
&
src
->
dma
);
return
ret
;
}
...
...
sound/soc/sh/rcar/ssi.c
View file @
43b64af5
...
...
@@ -417,11 +417,14 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
int
chan
=
params_channels
(
params
);
/*
* Already working.
* It will happen if SSI has parent/child connection.
* snd_pcm_ops::hw_params will be called *before*
* snd_soc_dai_ops::trigger. Thus, ssi->usrcnt is 0
* in 1st call.
*/
if
(
ssi
->
usrcnt
>
1
)
{
if
(
ssi
->
usrcnt
)
{
/*
* Already working.
* It will happen if SSI has parent/child connection.
* it is error if child <-> parent SSI uses
* different channels.
*/
...
...
@@ -644,7 +647,11 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
if
(
ret
<
0
)
return
ret
;
ret
=
devm_request_irq
(
dev
,
ssi
->
irq
,
/*
* SSI might be called again as PIO fallback
* It is easy to manual handling for IRQ request/free
*/
ret
=
request_irq
(
ssi
->
irq
,
rsnd_ssi_interrupt
,
IRQF_SHARED
,
dev_name
(
dev
),
mod
);
...
...
@@ -669,7 +676,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
struct
rsnd_priv
*
priv
)
{
struct
rsnd_ssi
*
ssi
=
rsnd_mod_to_ssi
(
mod
);
int
dma_id
=
0
;
/* not needed */
int
ret
;
/*
...
...
@@ -684,7 +690,7 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
return
ret
;
/* SSI probe might be called many times in MUX multi path */
ret
=
rsnd_dma_attach
(
io
,
mod
,
&
ssi
->
dma
,
dma_id
);
ret
=
rsnd_dma_attach
(
io
,
mod
,
&
ssi
->
dma
);
return
ret
;
}
...
...
@@ -694,11 +700,9 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
struct
rsnd_priv
*
priv
)
{
struct
rsnd_ssi
*
ssi
=
rsnd_mod_to_ssi
(
mod
);
struct
device
*
dev
=
rsnd_priv_to_dev
(
priv
);
int
irq
=
ssi
->
irq
;
/* PIO will request IRQ again */
devm_free_irq
(
dev
,
irq
,
mod
);
free_irq
(
ssi
->
irq
,
mod
);
return
0
;
}
...
...
sound/soc/sh/rcar/ssiu.c
View file @
43b64af5
...
...
@@ -33,6 +33,26 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
u32
mask1
,
val1
;
u32
mask2
,
val2
;
/* clear status */
switch
(
id
)
{
case
0
:
case
1
:
case
2
:
case
3
:
case
4
:
rsnd_mod_write
(
mod
,
SSI_SYS_STATUS0
,
0xf
<<
(
id
*
4
));
rsnd_mod_write
(
mod
,
SSI_SYS_STATUS2
,
0xf
<<
(
id
*
4
));
rsnd_mod_write
(
mod
,
SSI_SYS_STATUS4
,
0xf
<<
(
id
*
4
));
rsnd_mod_write
(
mod
,
SSI_SYS_STATUS6
,
0xf
<<
(
id
*
4
));
break
;
case
9
:
rsnd_mod_write
(
mod
,
SSI_SYS_STATUS1
,
0xf
<<
4
);
rsnd_mod_write
(
mod
,
SSI_SYS_STATUS3
,
0xf
<<
4
);
rsnd_mod_write
(
mod
,
SSI_SYS_STATUS5
,
0xf
<<
4
);
rsnd_mod_write
(
mod
,
SSI_SYS_STATUS7
,
0xf
<<
4
);
break
;
}
/*
* SSI_MODE0
*/
...
...
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