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
9a6806c0
Commit
9a6806c0
authored
Dec 10, 2012
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'asoc/topic/kirkwood' into asoc-next
parents
18620cc5
1703470a
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
168 additions
and
94 deletions
+168
-94
sound/soc/kirkwood/kirkwood-dma.c
sound/soc/kirkwood/kirkwood-dma.c
+10
-6
sound/soc/kirkwood/kirkwood-i2s.c
sound/soc/kirkwood/kirkwood-i2s.c
+149
-86
sound/soc/kirkwood/kirkwood.h
sound/soc/kirkwood/kirkwood.h
+9
-2
No files found.
sound/soc/kirkwood/kirkwood-dma.c
View file @
9a6806c0
...
...
@@ -22,12 +22,16 @@
#include "kirkwood.h"
#define KIRKWOOD_RATES \
(SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
(SNDRV_PCM_RATE_8000_192000 | \
SNDRV_PCM_RATE_CONTINUOUS | \
SNDRV_PCM_RATE_KNOT)
#define KIRKWOOD_FORMATS \
(SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
SNDRV_PCM_FMTBIT_S32_LE | \
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | \
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE)
struct
kirkwood_dma_priv
{
struct
snd_pcm_substream
*
play_stream
;
...
...
@@ -43,10 +47,10 @@ static struct snd_pcm_hardware kirkwood_dma_snd_hw = {
SNDRV_PCM_INFO_PAUSE
),
.
formats
=
KIRKWOOD_FORMATS
,
.
rates
=
KIRKWOOD_RATES
,
.
rate_min
=
441
00
,
.
rate_max
=
96
000
,
.
rate_min
=
80
00
,
.
rate_max
=
384
000
,
.
channels_min
=
1
,
.
channels_max
=
2
,
.
channels_max
=
8
,
.
buffer_bytes_max
=
KIRKWOOD_SND_MAX_PERIOD_BYTES
*
KIRKWOOD_SND_MAX_PERIODS
,
.
period_bytes_min
=
KIRKWOOD_SND_MIN_PERIOD_BYTES
,
.
period_bytes_max
=
KIRKWOOD_SND_MAX_PERIOD_BYTES
,
...
...
sound/soc/kirkwood/kirkwood-i2s.c
View file @
9a6806c0
...
...
@@ -99,6 +99,29 @@ static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
}
while
(
value
==
0
);
}
static
void
kirkwood_set_rate
(
struct
snd_soc_dai
*
dai
,
struct
kirkwood_dma_data
*
priv
,
unsigned
long
rate
)
{
uint32_t
clks_ctrl
;
if
(
rate
==
44100
||
rate
==
48000
||
rate
==
96000
)
{
/* use internal dco for supported rates */
dev_dbg
(
dai
->
dev
,
"%s: dco set rate = %lu
\n
"
,
__func__
,
rate
);
kirkwood_set_dco
(
priv
->
io
,
rate
);
clks_ctrl
=
KIRKWOOD_MCLK_SOURCE_DCO
;
}
else
if
(
!
IS_ERR
(
priv
->
extclk
))
{
/* use optional external clk for other rates */
dev_dbg
(
dai
->
dev
,
"%s: extclk set rate = %lu -> %lu
\n
"
,
__func__
,
rate
,
256
*
rate
);
clk_set_rate
(
priv
->
extclk
,
256
*
rate
);
clks_ctrl
=
KIRKWOOD_MCLK_SOURCE_EXTCLK
;
}
writel
(
clks_ctrl
,
priv
->
io
+
KIRKWOOD_CLOCKS_CTRL
);
}
static
int
kirkwood_i2s_startup
(
struct
snd_pcm_substream
*
substream
,
struct
snd_soc_dai
*
dai
)
{
...
...
@@ -113,26 +136,21 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
struct
snd_soc_dai
*
dai
)
{
struct
kirkwood_dma_data
*
priv
=
snd_soc_dai_get_drvdata
(
dai
);
unsigned
int
i2s_reg
,
reg
;
unsigned
long
i2s_value
,
value
;
uint32_t
ctl_play
,
ctl_rec
;
unsigned
int
i2s_reg
;
unsigned
long
i2s_value
;
if
(
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
{
i2s_reg
=
KIRKWOOD_I2S_PLAYCTL
;
reg
=
KIRKWOOD_PLAYCTL
;
}
else
{
i2s_reg
=
KIRKWOOD_I2S_RECCTL
;
reg
=
KIRKWOOD_RECCTL
;
}
/* set dco conf */
kirkwood_set_dco
(
priv
->
io
,
params_rate
(
params
));
kirkwood_set_rate
(
dai
,
priv
,
params_rate
(
params
));
i2s_value
=
readl
(
priv
->
io
+
i2s_reg
);
i2s_value
&=
~
KIRKWOOD_I2S_CTL_SIZE_MASK
;
value
=
readl
(
priv
->
io
+
reg
);
value
&=
~
KIRKWOOD_PLAYCTL_SIZE_MASK
;
/*
* Size settings in play/rec i2s control regs and play/rec control
* regs must be the same.
...
...
@@ -140,38 +158,57 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
switch
(
params_format
(
params
))
{
case
SNDRV_PCM_FORMAT_S16_LE
:
i2s_value
|=
KIRKWOOD_I2S_CTL_SIZE_16
;
value
|=
KIRKWOOD_PLAYCTL_SIZE_16_C
;
ctl_play
=
KIRKWOOD_PLAYCTL_SIZE_16_C
|
KIRKWOOD_PLAYCTL_I2S_EN
;
ctl_rec
=
KIRKWOOD_RECCTL_SIZE_16_C
|
KIRKWOOD_RECCTL_I2S_EN
;
break
;
/*
* doesn't work... S20_3LE != kirkwood 20bit format ?
*
case SNDRV_PCM_FORMAT_S20_3LE:
i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20;
value |= KIRKWOOD_PLAYCTL_SIZE_20;
ctl_play = KIRKWOOD_PLAYCTL_SIZE_20 |
KIRKWOOD_PLAYCTL_I2S_EN;
ctl_rec = KIRKWOOD_RECCTL_SIZE_20 |
KIRKWOOD_RECCTL_I2S_EN;
break;
*/
case
SNDRV_PCM_FORMAT_S24_LE
:
i2s_value
|=
KIRKWOOD_I2S_CTL_SIZE_24
;
value
|=
KIRKWOOD_PLAYCTL_SIZE_24
;
ctl_play
=
KIRKWOOD_PLAYCTL_SIZE_24
|
KIRKWOOD_PLAYCTL_I2S_EN
;
ctl_rec
=
KIRKWOOD_RECCTL_SIZE_24
|
KIRKWOOD_RECCTL_I2S_EN
;
break
;
case
SNDRV_PCM_FORMAT_S32_LE
:
i2s_value
|=
KIRKWOOD_I2S_CTL_SIZE_32
;
value
|=
KIRKWOOD_PLAYCTL_SIZE_32
;
ctl_play
=
KIRKWOOD_PLAYCTL_SIZE_32
|
KIRKWOOD_PLAYCTL_I2S_EN
;
ctl_rec
=
KIRKWOOD_RECCTL_SIZE_32
|
KIRKWOOD_RECCTL_I2S_EN
;
break
;
default:
return
-
EINVAL
;
}
if
(
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
{
value
&=
~
KIRKWOOD_PLAYCTL_MONO_MASK
;
if
(
params_channels
(
params
)
==
1
)
value
|=
KIRKWOOD_PLAYCTL_MONO_BOTH
;
ctl_play
|=
KIRKWOOD_PLAYCTL_MONO_BOTH
;
else
value
|=
KIRKWOOD_PLAYCTL_MONO_OFF
;
ctl_play
|=
KIRKWOOD_PLAYCTL_MONO_OFF
;
priv
->
ctl_play
&=
~
(
KIRKWOOD_PLAYCTL_MONO_MASK
|
KIRKWOOD_PLAYCTL_I2S_EN
|
KIRKWOOD_PLAYCTL_SPDIF_EN
|
KIRKWOOD_PLAYCTL_SIZE_MASK
);
priv
->
ctl_play
|=
ctl_play
;
}
else
{
priv
->
ctl_rec
&=
~
KIRKWOOD_RECCTL_SIZE_MASK
;
priv
->
ctl_rec
|=
ctl_rec
;
}
writel
(
i2s_value
,
priv
->
io
+
i2s_reg
);
writel
(
value
,
priv
->
io
+
reg
);
return
0
;
}
...
...
@@ -205,20 +242,18 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
switch
(
cmd
)
{
case
SNDRV_PCM_TRIGGER_START
:
/* configure */
ctl
=
priv
->
ctl_play
;
value
=
ctl
&
~
(
KIRKWOOD_PLAYCTL_I2S_EN
|
KIRKWOOD_PLAYCTL_SPDIF_EN
);
writel
(
value
,
priv
->
io
+
KIRKWOOD_PLAYCTL
);
/* enable interrupts */
value
=
readl
(
priv
->
io
+
KIRKWOOD_INT_MASK
);
value
|=
KIRKWOOD_INT_CAUSE_PLAY_BYTES
;
writel
(
value
,
priv
->
io
+
KIRKWOOD_INT_MASK
);
/* configure audio & enable i2s playback */
ctl
&=
~
KIRKWOOD_PLAYCTL_BURST_MASK
;
ctl
&=
~
(
KIRKWOOD_PLAYCTL_PAUSE
|
KIRKWOOD_PLAYCTL_I2S_MUTE
|
KIRKWOOD_PLAYCTL_SPDIF_EN
);
if
(
priv
->
burst
==
32
)
ctl
|=
KIRKWOOD_PLAYCTL_BURST_32
;
else
ctl
|=
KIRKWOOD_PLAYCTL_BURST_128
;
ctl
|=
KIRKWOOD_PLAYCTL_I2S_EN
;
/* enable playback */
writel
(
ctl
,
priv
->
io
+
KIRKWOOD_PLAYCTL
);
break
;
...
...
@@ -259,30 +294,24 @@ static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
int
cmd
,
struct
snd_soc_dai
*
dai
)
{
struct
kirkwood_dma_data
*
priv
=
snd_soc_dai_get_drvdata
(
dai
);
u
nsigned
long
value
;
u
int32_t
ctl
,
value
;
value
=
readl
(
priv
->
io
+
KIRKWOOD_RECCTL
);
switch
(
cmd
)
{
case
SNDRV_PCM_TRIGGER_START
:
/* configure */
ctl
=
priv
->
ctl_rec
;
value
=
ctl
&
~
KIRKWOOD_RECCTL_I2S_EN
;
writel
(
value
,
priv
->
io
+
KIRKWOOD_RECCTL
);
/* enable interrupts */
value
=
readl
(
priv
->
io
+
KIRKWOOD_INT_MASK
);
value
|=
KIRKWOOD_INT_CAUSE_REC_BYTES
;
writel
(
value
,
priv
->
io
+
KIRKWOOD_INT_MASK
);
/* configure audio & enable i2s record */
value
=
readl
(
priv
->
io
+
KIRKWOOD_RECCTL
);
value
&=
~
KIRKWOOD_RECCTL_BURST_MASK
;
value
&=
~
KIRKWOOD_RECCTL_MONO
;
value
&=
~
(
KIRKWOOD_RECCTL_PAUSE
|
KIRKWOOD_RECCTL_MUTE
|
KIRKWOOD_RECCTL_SPDIF_EN
);
if
(
priv
->
burst
==
32
)
value
|=
KIRKWOOD_RECCTL_BURST_32
;
else
value
|=
KIRKWOOD_RECCTL_BURST_128
;
value
|=
KIRKWOOD_RECCTL_I2S_EN
;
writel
(
value
,
priv
->
io
+
KIRKWOOD_RECCTL
);
/* enable record */
writel
(
ctl
,
priv
->
io
+
KIRKWOOD_RECCTL
);
break
;
case
SNDRV_PCM_TRIGGER_STOP
:
...
...
@@ -389,90 +418,125 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai = {
.
channels_min
=
1
,
.
channels_max
=
2
,
.
rates
=
KIRKWOOD_I2S_RATES
,
.
formats
=
KIRKWOOD_I2S_FORMATS
,},
.
formats
=
KIRKWOOD_I2S_FORMATS
,
},
.
capture
=
{
.
channels_min
=
1
,
.
channels_max
=
2
,
.
rates
=
KIRKWOOD_I2S_RATES
,
.
formats
=
KIRKWOOD_I2S_FORMATS
,},
.
formats
=
KIRKWOOD_I2S_FORMATS
,
},
.
ops
=
&
kirkwood_i2s_dai_ops
,
};
static
struct
snd_soc_dai_driver
kirkwood_i2s_dai_extclk
=
{
.
probe
=
kirkwood_i2s_probe
,
.
remove
=
kirkwood_i2s_remove
,
.
playback
=
{
.
channels_min
=
1
,
.
channels_max
=
2
,
.
rates
=
SNDRV_PCM_RATE_8000_192000
|
SNDRV_PCM_RATE_CONTINUOUS
|
SNDRV_PCM_RATE_KNOT
,
.
formats
=
KIRKWOOD_I2S_FORMATS
,
},
.
capture
=
{
.
channels_min
=
1
,
.
channels_max
=
2
,
.
rates
=
SNDRV_PCM_RATE_8000_192000
|
SNDRV_PCM_RATE_CONTINUOUS
|
SNDRV_PCM_RATE_KNOT
,
.
formats
=
KIRKWOOD_I2S_FORMATS
,
},
.
ops
=
&
kirkwood_i2s_dai_ops
,
};
static
__devinit
int
kirkwood_i2s_dev_probe
(
struct
platform_device
*
pdev
)
{
struct
resource
*
mem
;
struct
kirkwood_asoc_platform_data
*
data
=
pdev
->
dev
.
platform_data
;
struct
kirkwood_asoc_platform_data
*
data
=
pdev
->
dev
.
platform_data
;
struct
snd_soc_dai_driver
*
soc_dai
=
&
kirkwood_i2s_dai
;
struct
kirkwood_dma_data
*
priv
;
struct
resource
*
mem
;
int
err
;
priv
=
kzalloc
(
sizeof
(
struct
kirkwood_dma_data
),
GFP_KERNEL
);
priv
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
priv
),
GFP_KERNEL
);
if
(
!
priv
)
{
dev_err
(
&
pdev
->
dev
,
"allocation failed
\n
"
);
err
=
-
ENOMEM
;
goto
error
;
return
-
ENOMEM
;
}
dev_set_drvdata
(
&
pdev
->
dev
,
priv
);
mem
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
if
(
!
mem
)
{
dev_err
(
&
pdev
->
dev
,
"platform_get_resource failed
\n
"
);
err
=
-
ENXIO
;
goto
err_alloc
;
}
priv
->
mem
=
request_mem_region
(
mem
->
start
,
SZ_16K
,
DRV_NAME
);
if
(
!
priv
->
mem
)
{
dev_err
(
&
pdev
->
dev
,
"request_mem_region failed
\n
"
);
err
=
-
EBUSY
;
goto
err_alloc
;
return
-
ENXIO
;
}
priv
->
io
=
ioremap
(
priv
->
mem
->
start
,
SZ_16K
);
priv
->
io
=
devm_request_and_ioremap
(
&
pdev
->
dev
,
mem
);
if
(
!
priv
->
io
)
{
dev_err
(
&
pdev
->
dev
,
"ioremap failed
\n
"
);
err
=
-
ENOMEM
;
goto
err_iomem
;
dev_err
(
&
pdev
->
dev
,
"devm_request_and_ioremap failed
\n
"
);
return
-
ENOMEM
;
}
priv
->
irq
=
platform_get_irq
(
pdev
,
0
);
if
(
priv
->
irq
<=
0
)
{
dev_err
(
&
pdev
->
dev
,
"platform_get_irq failed
\n
"
);
err
=
-
ENXIO
;
goto
err_ioremap
;
return
-
ENXIO
;
}
if
(
!
data
)
{
dev_err
(
&
pdev
->
dev
,
"no platform data ?!
\n
"
);
err
=
-
EINVAL
;
goto
err_ioremap
;
return
-
EINVAL
;
}
priv
->
burst
=
data
->
burst
;
priv
->
clk
=
clk_get
(
&
pdev
->
dev
,
NULL
);
priv
->
clk
=
devm_
clk_get
(
&
pdev
->
dev
,
NULL
);
if
(
IS_ERR
(
priv
->
clk
))
{
dev_err
(
&
pdev
->
dev
,
"no clock
\n
"
);
err
=
PTR_ERR
(
priv
->
clk
);
goto
err_ioremap
;
return
PTR_ERR
(
priv
->
clk
);
}
err
=
clk_prepare_enable
(
priv
->
clk
);
if
(
err
<
0
)
return
err
;
priv
->
extclk
=
clk_get
(
&
pdev
->
dev
,
"extclk"
);
if
(
!
IS_ERR
(
priv
->
extclk
))
{
if
(
priv
->
extclk
==
priv
->
clk
)
{
clk_put
(
priv
->
extclk
);
priv
->
extclk
=
ERR_PTR
(
-
EINVAL
);
}
else
{
dev_info
(
&
pdev
->
dev
,
"found external clock
\n
"
);
clk_prepare_enable
(
priv
->
extclk
);
soc_dai
=
&
kirkwood_i2s_dai_extclk
;
}
}
/* Some sensible defaults - this reflects the powerup values */
priv
->
ctl_play
=
KIRKWOOD_PLAYCTL_SIZE_24
;
priv
->
ctl_rec
=
KIRKWOOD_RECCTL_SIZE_24
;
/* Select the burst size */
if
(
data
->
burst
==
32
)
{
priv
->
ctl_play
|=
KIRKWOOD_PLAYCTL_BURST_32
;
priv
->
ctl_rec
|=
KIRKWOOD_RECCTL_BURST_32
;
}
else
{
priv
->
ctl_play
|=
KIRKWOOD_PLAYCTL_BURST_128
;
priv
->
ctl_rec
|=
KIRKWOOD_RECCTL_BURST_128
;
}
clk_prepare_enable
(
priv
->
clk
);
err
=
snd_soc_register_dai
(
&
pdev
->
dev
,
&
kirkwood_i2s
_dai
);
err
=
snd_soc_register_dai
(
&
pdev
->
dev
,
soc
_dai
);
if
(
!
err
)
return
0
;
dev_err
(
&
pdev
->
dev
,
"snd_soc_register_dai failed
\n
"
);
if
(
!
IS_ERR
(
priv
->
extclk
))
{
clk_disable_unprepare
(
priv
->
extclk
);
clk_put
(
priv
->
extclk
);
}
clk_disable_unprepare
(
priv
->
clk
);
clk_put
(
priv
->
clk
);
err_ioremap:
iounmap
(
priv
->
io
);
err_iomem:
release_mem_region
(
priv
->
mem
->
start
,
SZ_16K
);
err_alloc:
kfree
(
priv
);
error:
return
err
;
}
...
...
@@ -482,12 +546,11 @@ static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev)
snd_soc_unregister_dai
(
&
pdev
->
dev
);
if
(
!
IS_ERR
(
priv
->
extclk
))
{
clk_disable_unprepare
(
priv
->
extclk
);
clk_put
(
priv
->
extclk
);
}
clk_disable_unprepare
(
priv
->
clk
);
clk_put
(
priv
->
clk
);
iounmap
(
priv
->
io
);
release_mem_region
(
priv
->
mem
->
start
,
SZ_16K
);
kfree
(
priv
);
return
0
;
}
...
...
sound/soc/kirkwood/kirkwood.h
View file @
9a6806c0
...
...
@@ -77,6 +77,11 @@
#define KIRKWOOD_DCO_SPCR_STATUS 0x120c
#define KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK (1<<16)
#define KIRKWOOD_CLOCKS_CTRL 0x1230
#define KIRKWOOD_MCLK_SOURCE_MASK (3<<0)
#define KIRKWOOD_MCLK_SOURCE_DCO (0<<0)
#define KIRKWOOD_MCLK_SOURCE_EXTCLK (3<<0)
#define KIRKWOOD_ERR_CAUSE 0x1300
#define KIRKWOOD_ERR_MASK 0x1304
...
...
@@ -119,11 +124,13 @@
#define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x4000
struct
kirkwood_dma_data
{
struct
resource
*
mem
;
void
__iomem
*
io
;
struct
clk
*
clk
;
struct
clk
*
extclk
;
uint32_t
ctl_play
;
uint32_t
ctl_rec
;
int
irq
;
int
burst
;
struct
clk
*
clk
;
};
#endif
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