Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
93ac820d
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
13
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
93ac820d
编写于
12月 10, 2012
作者:
M
Mark Brown
浏览文件
操作
浏览文件
下载
差异文件
Merge remote-tracking branch 'asoc/topic/atmel' into asoc-next
上级
daa5ab9e
3951e4aa
变更
32
隐藏空白更改
内联
并排
Showing
32 changed file
with
1108 addition
and
611 deletion
+1108
-611
Documentation/devicetree/bindings/misc/atmel-ssc.txt
Documentation/devicetree/bindings/misc/atmel-ssc.txt
+15
-0
Documentation/devicetree/bindings/sound/atmel-at91sam9g20ek-wm8731-audio.txt
...etree/bindings/sound/atmel-at91sam9g20ek-wm8731-audio.txt
+26
-0
arch/arm/boot/dts/at91sam9260.dtsi
arch/arm/boot/dts/at91sam9260.dtsi
+8
-0
arch/arm/boot/dts/at91sam9263.dtsi
arch/arm/boot/dts/at91sam9263.dtsi
+16
-0
arch/arm/boot/dts/at91sam9g20ek_common.dtsi
arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+31
-1
arch/arm/boot/dts/at91sam9g45.dtsi
arch/arm/boot/dts/at91sam9g45.dtsi
+16
-0
arch/arm/boot/dts/at91sam9x5.dtsi
arch/arm/boot/dts/at91sam9x5.dtsi
+8
-0
arch/arm/mach-at91/at91rm9200.c
arch/arm/mach-at91/at91rm9200.c
+6
-3
arch/arm/mach-at91/at91rm9200_devices.c
arch/arm/mach-at91/at91rm9200_devices.c
+3
-3
arch/arm/mach-at91/at91sam9260.c
arch/arm/mach-at91/at91sam9260.c
+2
-1
arch/arm/mach-at91/at91sam9260_devices.c
arch/arm/mach-at91/at91sam9260_devices.c
+1
-1
arch/arm/mach-at91/at91sam9261.c
arch/arm/mach-at91/at91sam9261.c
+6
-3
arch/arm/mach-at91/at91sam9261_devices.c
arch/arm/mach-at91/at91sam9261_devices.c
+3
-3
arch/arm/mach-at91/at91sam9263.c
arch/arm/mach-at91/at91sam9263.c
+4
-2
arch/arm/mach-at91/at91sam9263_devices.c
arch/arm/mach-at91/at91sam9263_devices.c
+2
-2
arch/arm/mach-at91/at91sam9g45.c
arch/arm/mach-at91/at91sam9g45.c
+4
-2
arch/arm/mach-at91/at91sam9g45_devices.c
arch/arm/mach-at91/at91sam9g45_devices.c
+2
-2
arch/arm/mach-at91/at91sam9rl.c
arch/arm/mach-at91/at91sam9rl.c
+4
-2
arch/arm/mach-at91/at91sam9rl_devices.c
arch/arm/mach-at91/at91sam9rl_devices.c
+2
-2
arch/arm/mach-at91/at91sam9x5.c
arch/arm/mach-at91/at91sam9x5.c
+1
-0
arch/arm/mach-at91/board-sam9g20ek.c
arch/arm/mach-at91/board-sam9g20ek.c
+11
-0
drivers/misc/atmel-ssc.c
drivers/misc/atmel-ssc.c
+88
-47
include/linux/atmel-ssc.h
include/linux/atmel-ssc.h
+6
-0
sound/soc/atmel/Kconfig
sound/soc/atmel/Kconfig
+11
-2
sound/soc/atmel/Makefile
sound/soc/atmel/Makefile
+4
-0
sound/soc/atmel/atmel-pcm-dma.c
sound/soc/atmel/atmel-pcm-dma.c
+240
-0
sound/soc/atmel/atmel-pcm-pdc.c
sound/soc/atmel/atmel-pcm-pdc.c
+401
-0
sound/soc/atmel/atmel-pcm.c
sound/soc/atmel/atmel-pcm.c
+12
-389
sound/soc/atmel/atmel-pcm.h
sound/soc/atmel/atmel-pcm.h
+34
-0
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/atmel/atmel_ssc_dai.c
+51
-117
sound/soc/atmel/atmel_ssc_dai.h
sound/soc/atmel/atmel_ssc_dai.h
+2
-1
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/atmel/sam9g20_wm8731.c
+88
-28
未找到文件。
Documentation/devicetree/bindings/misc/atmel-ssc.txt
0 → 100644
浏览文件 @
93ac820d
* Atmel SSC driver.
Required properties:
- compatible: "atmel,at91rm9200-ssc" or "atmel,at91sam9g45-ssc"
- atmel,at91rm9200-ssc: support pdc transfer
- atmel,at91sam9g45-ssc: support dma transfer
- reg: Should contain SSC registers location and length
- interrupts: Should contain SSC interrupt
Example:
ssc0: ssc@fffbc000 {
compatible = "atmel,at91rm9200-ssc";
reg = <0xfffbc000 0x4000>;
interrupts = <14 4 5>;
};
Documentation/devicetree/bindings/sound/atmel-at91sam9g20ek-wm8731-audio.txt
0 → 100644
浏览文件 @
93ac820d
* Atmel at91sam9g20ek wm8731 audio complex
Required properties:
- compatible: "atmel,at91sam9g20ek-wm8731-audio"
- atmel,model: The user-visible name of this sound complex.
- atmel,audio-routing: A list of the connections between audio components.
- atmel,ssc-controller: The phandle of the SSC controller
- atmel,audio-codec: The phandle of the WM8731 audio codec
Optional properties:
- pinctrl-names, pinctrl-0: Please refer to pinctrl-bindings.txt
Example:
sound {
compatible = "atmel,at91sam9g20ek-wm8731-audio";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pck0_as_mck>;
atmel,model = "wm8731 @ AT91SAMG20EK";
atmel,audio-routing =
"Ext Spk", "LHPOUT",
"Int MIC", "MICIN";
atmel,ssc-controller = <&ssc0>;
atmel,audio-codec = <&wm8731>;
};
arch/arm/boot/dts/at91sam9260.dtsi
浏览文件 @
93ac820d
...
...
@@ -29,6 +29,7 @@
tcb0
=
&
tcb0
;
tcb1
=
&
tcb1
;
i2c0
=
&
i2c0
;
ssc0
=
&
ssc0
;
};
cpus
{
cpu
@
0
{
...
...
@@ -212,6 +213,13 @@
status
=
"disabled"
;
};
ssc0
:
ssc
@
fffbc000
{
compatible
=
"atmel,at91rm9200-ssc"
;
reg
=
<
0xfffbc000
0x4000
>;
interrupts
=
<
14
4
5
>;
status
=
"disable"
;
};
adc0
:
adc
@
fffe0000
{
compatible
=
"atmel,at91sam9260-adc"
;
reg
=
<
0xfffe0000
0x100
>;
...
...
arch/arm/boot/dts/at91sam9263.dtsi
浏览文件 @
93ac820d
...
...
@@ -25,6 +25,8 @@
gpio4
=
&
pioE
;
tcb0
=
&
tcb0
;
i2c0
=
&
i2c0
;
ssc0
=
&
ssc0
;
ssc1
=
&
ssc1
;
};
cpus
{
cpu
@
0
{
...
...
@@ -173,6 +175,20 @@
status
=
"disabled"
;
};
ssc0
:
ssc
@
fff98000
{
compatible
=
"atmel,at91rm9200-ssc"
;
reg
=
<
0xfff98000
0x4000
>;
interrupts
=
<
16
4
5
>;
status
=
"disable"
;
};
ssc1
:
ssc
@
fff9c000
{
compatible
=
"atmel,at91rm9200-ssc"
;
reg
=
<
0xfff9c000
0x4000
>;
interrupts
=
<
17
4
5
>;
status
=
"disable"
;
};
macb0
:
ethernet
@
fffbc000
{
compatible
=
"cdns,at32ap7000-macb"
,
"cdns,macb"
;
reg
=
<
0xfffbc000
0x100
>;
...
...
arch/arm/boot/dts/at91sam9g20ek_common.dtsi
浏览文件 @
93ac820d
...
...
@@ -30,6 +30,16 @@
ahb {
apb {
pinctrl@fffff400 {
board {
pinctrl_pck0_as_mck: pck0_as_mck {
atmel,pins =
<2 1 0x2 0x0>; /* PC1 periph B */
};
};
};
dbgu: serial@fffff200 {
status = "okay";
};
...
...
@@ -51,6 +61,11 @@
atmel,vbus-gpio = <&pioC 5 0>;
status = "okay";
};
ssc0: ssc@fffbc000 {
status = "okay";
pinctrl-0 = <&pinctrl_ssc0_tx>;
};
};
nand0: nand@40000000 {
...
...
@@ -114,7 +129,7 @@
reg = <0x50>;
};
wm8731@1b {
wm8731
: wm8731
@1b {
compatible = "wm8731";
reg = <0x1b>;
};
...
...
@@ -139,4 +154,19 @@
gpio-key,wakeup;
};
};
sound {
compatible = "atmel,at91sam9g20ek-wm8731-audio";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pck0_as_mck>;
atmel,model = "wm8731 @ AT91SAMG20EK";
atmel,audio-routing =
"Ext Spk", "LHPOUT",
"Int Mic", "MICIN";
atmel,ssc-controller = <&ssc0>;
atmel,audio-codec = <&wm8731>;
};
};
arch/arm/boot/dts/at91sam9g45.dtsi
浏览文件 @
93ac820d
...
...
@@ -31,6 +31,8 @@
tcb1
=
&
tcb1
;
i2c0
=
&
i2c0
;
i2c1
=
&
i2c1
;
ssc0
=
&
ssc0
;
ssc1
=
&
ssc1
;
};
cpus
{
cpu
@
0
{
...
...
@@ -226,6 +228,20 @@
status
=
"disabled"
;
};
ssc0
:
ssc
@
fff9c000
{
compatible
=
"atmel,at91sam9g45-ssc"
;
reg
=
<
0xfff9c000
0x4000
>;
interrupts
=
<
16
4
5
>;
status
=
"disable"
;
};
ssc1
:
ssc
@
fffa0000
{
compatible
=
"atmel,at91sam9g45-ssc"
;
reg
=
<
0xfffa0000
0x4000
>;
interrupts
=
<
17
4
5
>;
status
=
"disable"
;
};
adc0
:
adc
@
fffb0000
{
compatible
=
"atmel,at91sam9260-adc"
;
reg
=
<
0xfffb0000
0x100
>;
...
...
arch/arm/boot/dts/at91sam9x5.dtsi
浏览文件 @
93ac820d
...
...
@@ -30,6 +30,7 @@
i2c0
=
&
i2c0
;
i2c1
=
&
i2c1
;
i2c2
=
&
i2c2
;
ssc0
=
&
ssc0
;
};
cpus
{
cpu
@
0
{
...
...
@@ -87,6 +88,13 @@
interrupts
=
<
1
4
7
>;
};
ssc0
:
ssc
@
f0010000
{
compatible
=
"atmel,at91sam9g45-ssc"
;
reg
=
<
0xf0010000
0x4000
>;
interrupts
=
<
28
4
5
>;
status
=
"disable"
;
};
tcb0
:
timer
@
f8008000
{
compatible
=
"atmel,at91sam9x5-tcb"
;
reg
=
<
0xf8008000
0x100
>;
...
...
arch/arm/mach-at91/at91rm9200.c
浏览文件 @
93ac820d
...
...
@@ -184,9 +184,12 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID
(
"t0_clk"
,
"atmel_tcb.1"
,
&
tc3_clk
),
CLKDEV_CON_DEV_ID
(
"t1_clk"
,
"atmel_tcb.1"
,
&
tc4_clk
),
CLKDEV_CON_DEV_ID
(
"t2_clk"
,
"atmel_tcb.1"
,
&
tc5_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.1"
,
&
ssc1_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.2"
,
&
ssc2_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91rm9200_ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91rm9200_ssc.1"
,
&
ssc1_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91rm9200_ssc.2"
,
&
ssc2_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"fffd0000.ssc"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"fffd4000.ssc"
,
&
ssc1_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"fffd8000.ssc"
,
&
ssc2_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"i2c-at91rm9200.0"
,
&
twi_clk
),
/* fake hclk clock */
CLKDEV_CON_DEV_ID
(
"hclk"
,
"at91_ohci"
,
&
ohci_clk
),
...
...
arch/arm/mach-at91/at91rm9200_devices.c
浏览文件 @
93ac820d
...
...
@@ -752,7 +752,7 @@ static struct resource ssc0_resources[] = {
};
static
struct
platform_device
at91rm9200_ssc0_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
0
,
.
dev
=
{
.
dma_mask
=
&
ssc0_dmamask
,
...
...
@@ -794,7 +794,7 @@ static struct resource ssc1_resources[] = {
};
static
struct
platform_device
at91rm9200_ssc1_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
1
,
.
dev
=
{
.
dma_mask
=
&
ssc1_dmamask
,
...
...
@@ -836,7 +836,7 @@ static struct resource ssc2_resources[] = {
};
static
struct
platform_device
at91rm9200_ssc2_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
2
,
.
dev
=
{
.
dma_mask
=
&
ssc2_dmamask
,
...
...
arch/arm/mach-at91/at91sam9260.c
浏览文件 @
93ac820d
...
...
@@ -210,7 +210,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID
(
"t0_clk"
,
"atmel_tcb.1"
,
&
tc3_clk
),
CLKDEV_CON_DEV_ID
(
"t1_clk"
,
"atmel_tcb.1"
,
&
tc4_clk
),
CLKDEV_CON_DEV_ID
(
"t2_clk"
,
"atmel_tcb.1"
,
&
tc5_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.0"
,
&
ssc_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91rm9200_ssc.0"
,
&
ssc_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"fffbc000.ssc"
,
&
ssc_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"i2c-at91sam9260.0"
,
&
twi_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"i2c-at91sam9g20.0"
,
&
twi_clk
),
/* more usart lookup table for DT entries */
...
...
arch/arm/mach-at91/at91sam9260_devices.c
浏览文件 @
93ac820d
...
...
@@ -742,7 +742,7 @@ static struct resource ssc_resources[] = {
};
static
struct
platform_device
at91sam9260_ssc_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
0
,
.
dev
=
{
.
dma_mask
=
&
ssc_dmamask
,
...
...
arch/arm/mach-at91/at91sam9261.c
浏览文件 @
93ac820d
...
...
@@ -174,9 +174,12 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID
(
"t0_clk"
,
"atmel_tcb.0"
,
&
tc0_clk
),
CLKDEV_CON_DEV_ID
(
"t1_clk"
,
"atmel_tcb.0"
,
&
tc1_clk
),
CLKDEV_CON_DEV_ID
(
"t2_clk"
,
"atmel_tcb.0"
,
&
tc2_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.1"
,
&
ssc1_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.2"
,
&
ssc2_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91rm9200_ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91rm9200_ssc.1"
,
&
ssc1_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91rm9200_ssc.2"
,
&
ssc2_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"fffbc000.ssc"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"fffc0000.ssc"
,
&
ssc1_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"fffc4000.ssc"
,
&
ssc2_clk
),
CLKDEV_CON_DEV_ID
(
"hclk"
,
"at91_ohci"
,
&
hck0
),
CLKDEV_CON_DEV_ID
(
NULL
,
"i2c-at91sam9261.0"
,
&
twi_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"i2c-at91sam9g10.0"
,
&
twi_clk
),
...
...
arch/arm/mach-at91/at91sam9261_devices.c
浏览文件 @
93ac820d
...
...
@@ -706,7 +706,7 @@ static struct resource ssc0_resources[] = {
};
static
struct
platform_device
at91sam9261_ssc0_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
0
,
.
dev
=
{
.
dma_mask
=
&
ssc0_dmamask
,
...
...
@@ -748,7 +748,7 @@ static struct resource ssc1_resources[] = {
};
static
struct
platform_device
at91sam9261_ssc1_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
1
,
.
dev
=
{
.
dma_mask
=
&
ssc1_dmamask
,
...
...
@@ -790,7 +790,7 @@ static struct resource ssc2_resources[] = {
};
static
struct
platform_device
at91sam9261_ssc2_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
2
,
.
dev
=
{
.
dma_mask
=
&
ssc2_dmamask
,
...
...
arch/arm/mach-at91/at91sam9263.c
浏览文件 @
93ac820d
...
...
@@ -186,8 +186,10 @@ static struct clk *periph_clocks[] __initdata = {
static
struct
clk_lookup
periph_clocks_lookups
[]
=
{
/* One additional fake clock for macb_hclk */
CLKDEV_CON_ID
(
"hclk"
,
&
macb_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.1"
,
&
ssc1_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91rm9200_ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91rm9200_ssc.1"
,
&
ssc1_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"fff98000.ssc"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"fff9c000.ssc"
,
&
ssc1_clk
),
CLKDEV_CON_DEV_ID
(
"mci_clk"
,
"atmel_mci.0"
,
&
mmc0_clk
),
CLKDEV_CON_DEV_ID
(
"mci_clk"
,
"atmel_mci.1"
,
&
mmc1_clk
),
CLKDEV_CON_DEV_ID
(
"spi_clk"
,
"atmel_spi.0"
,
&
spi0_clk
),
...
...
arch/arm/mach-at91/at91sam9263_devices.c
浏览文件 @
93ac820d
...
...
@@ -1199,7 +1199,7 @@ static struct resource ssc0_resources[] = {
};
static
struct
platform_device
at91sam9263_ssc0_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
0
,
.
dev
=
{
.
dma_mask
=
&
ssc0_dmamask
,
...
...
@@ -1241,7 +1241,7 @@ static struct resource ssc1_resources[] = {
};
static
struct
platform_device
at91sam9263_ssc1_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
1
,
.
dev
=
{
.
dma_mask
=
&
ssc1_dmamask
,
...
...
arch/arm/mach-at91/at91sam9g45.c
浏览文件 @
93ac820d
...
...
@@ -239,8 +239,10 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID
(
"t0_clk"
,
"atmel_tcb.1"
,
&
tcb0_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"i2c-at91sam9g10.0"
,
&
twi0_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"i2c-at91sam9g10.1"
,
&
twi1_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.1"
,
&
ssc1_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91sam9g45_ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91sam9g45_ssc.1"
,
&
ssc1_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"fff9c000.ssc"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"fffa0000.ssc"
,
&
ssc1_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"atmel-trng"
,
&
trng_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"atmel_sha"
,
&
aestdessha_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"atmel_tdes"
,
&
aestdessha_clk
),
...
...
arch/arm/mach-at91/at91sam9g45_devices.c
浏览文件 @
93ac820d
...
...
@@ -1459,7 +1459,7 @@ static struct resource ssc0_resources[] = {
};
static
struct
platform_device
at91sam9g45_ssc0_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91sam9g45_
ssc"
,
.
id
=
0
,
.
dev
=
{
.
dma_mask
=
&
ssc0_dmamask
,
...
...
@@ -1501,7 +1501,7 @@ static struct resource ssc1_resources[] = {
};
static
struct
platform_device
at91sam9g45_ssc1_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91sam9g45_
ssc"
,
.
id
=
1
,
.
dev
=
{
.
dma_mask
=
&
ssc1_dmamask
,
...
...
arch/arm/mach-at91/at91sam9rl.c
浏览文件 @
93ac820d
...
...
@@ -184,8 +184,10 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID
(
"t0_clk"
,
"atmel_tcb.0"
,
&
tc0_clk
),
CLKDEV_CON_DEV_ID
(
"t1_clk"
,
"atmel_tcb.0"
,
&
tc1_clk
),
CLKDEV_CON_DEV_ID
(
"t2_clk"
,
"atmel_tcb.0"
,
&
tc2_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.1"
,
&
ssc1_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91rm9200_ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91rm9200_ssc.1"
,
&
ssc1_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"fffc0000.ssc"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"fffc4000.ssc"
,
&
ssc1_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"i2c-at91sam9g20.0"
,
&
twi0_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"i2c-at91sam9g20.1"
,
&
twi1_clk
),
CLKDEV_CON_ID
(
"pioA"
,
&
pioA_clk
),
...
...
arch/arm/mach-at91/at91sam9rl_devices.c
浏览文件 @
93ac820d
...
...
@@ -832,7 +832,7 @@ static struct resource ssc0_resources[] = {
};
static
struct
platform_device
at91sam9rl_ssc0_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
0
,
.
dev
=
{
.
dma_mask
=
&
ssc0_dmamask
,
...
...
@@ -874,7 +874,7 @@ static struct resource ssc1_resources[] = {
};
static
struct
platform_device
at91sam9rl_ssc1_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
1
,
.
dev
=
{
.
dma_mask
=
&
ssc1_dmamask
,
...
...
arch/arm/mach-at91/at91sam9x5.c
浏览文件 @
93ac820d
...
...
@@ -231,6 +231,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID
(
"t0_clk"
,
"f800c000.timer"
,
&
tcb0_clk
),
CLKDEV_CON_DEV_ID
(
"dma_clk"
,
"ffffec00.dma-controller"
,
&
dma0_clk
),
CLKDEV_CON_DEV_ID
(
"dma_clk"
,
"ffffee00.dma-controller"
,
&
dma1_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"f0010000.ssc"
,
&
ssc_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"f8010000.i2c"
,
&
twi0_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"f8014000.i2c"
,
&
twi1_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"f8018000.i2c"
,
&
twi2_clk
),
...
...
arch/arm/mach-at91/board-sam9g20ek.c
浏览文件 @
93ac820d
...
...
@@ -353,6 +353,16 @@ static struct i2c_board_info __initdata ek_i2c_devices[] = {
},
};
static
struct
platform_device
sam9g20ek_audio_device
=
{
.
name
=
"at91sam9g20ek-audio"
,
.
id
=
-
1
,
};
static
void
__init
ek_add_device_audio
(
void
)
{
platform_device_register
(
&
sam9g20ek_audio_device
);
}
static
void
__init
ek_board_init
(
void
)
{
...
...
@@ -394,6 +404,7 @@ static void __init ek_board_init(void)
at91_set_B_periph
(
AT91_PIN_PC1
,
0
);
/* SSC (for WM8731) */
at91_add_device_ssc
(
AT91SAM9260_ID_SSC
,
ATMEL_SSC_TX
);
ek_add_device_audio
();
}
MACHINE_START
(
AT91SAM9G20EK
,
"Atmel AT91SAM9G20-EK"
)
...
...
drivers/misc/atmel-ssc.c
浏览文件 @
93ac820d
...
...
@@ -18,6 +18,8 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of.h>
/* Serialize access to ssc_list and user count */
static
DEFINE_SPINLOCK
(
user_lock
);
static
LIST_HEAD
(
ssc_list
);
...
...
@@ -29,7 +31,13 @@ struct ssc_device *ssc_request(unsigned int ssc_num)
spin_lock
(
&
user_lock
);
list_for_each_entry
(
ssc
,
&
ssc_list
,
list
)
{
if
(
ssc
->
pdev
->
id
==
ssc_num
)
{
if
(
ssc
->
pdev
->
dev
.
of_node
)
{
if
(
of_alias_get_id
(
ssc
->
pdev
->
dev
.
of_node
,
"ssc"
)
==
ssc_num
)
{
ssc_valid
=
1
;
break
;
}
}
else
if
(
ssc
->
pdev
->
id
==
ssc_num
)
{
ssc_valid
=
1
;
break
;
}
...
...
@@ -68,39 +76,93 @@ void ssc_free(struct ssc_device *ssc)
}
EXPORT_SYMBOL
(
ssc_free
);
static
int
__init
ssc_probe
(
struct
platform_device
*
pdev
)
static
struct
atmel_ssc_platform_data
at91rm9200_config
=
{
.
use_dma
=
0
,
};
static
struct
atmel_ssc_platform_data
at91sam9g45_config
=
{
.
use_dma
=
1
,
};
static
const
struct
platform_device_id
atmel_ssc_devtypes
[]
=
{
{
.
name
=
"at91rm9200_ssc"
,
.
driver_data
=
(
unsigned
long
)
&
at91rm9200_config
,
},
{
.
name
=
"at91sam9g45_ssc"
,
.
driver_data
=
(
unsigned
long
)
&
at91sam9g45_config
,
},
{
/* sentinel */
}
};
#ifdef CONFIG_OF
static
const
struct
of_device_id
atmel_ssc_dt_ids
[]
=
{
{
.
compatible
=
"atmel,at91rm9200-ssc"
,
.
data
=
&
at91rm9200_config
,
},
{
.
compatible
=
"atmel,at91sam9g45-ssc"
,
.
data
=
&
at91sam9g45_config
,
},
{
/* sentinel */
}
};
MODULE_DEVICE_TABLE
(
of
,
atmel_ssc_dt_ids
);
#endif
static
inline
const
struct
atmel_ssc_platform_data
*
__init
atmel_ssc_get_driver_data
(
struct
platform_device
*
pdev
)
{
if
(
pdev
->
dev
.
of_node
)
{
const
struct
of_device_id
*
match
;
match
=
of_match_node
(
atmel_ssc_dt_ids
,
pdev
->
dev
.
of_node
);
if
(
match
==
NULL
)
return
NULL
;
return
match
->
data
;
}
return
(
struct
atmel_ssc_platform_data
*
)
platform_get_device_id
(
pdev
)
->
driver_data
;
}
static
int
ssc_probe
(
struct
platform_device
*
pdev
)
{
int
retval
=
0
;
struct
resource
*
regs
;
struct
ssc_device
*
ssc
;
const
struct
atmel_ssc_platform_data
*
plat_dat
;
ssc
=
kzalloc
(
sizeof
(
struct
ssc_device
),
GFP_KERNEL
);
ssc
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
struct
ssc_device
),
GFP_KERNEL
);
if
(
!
ssc
)
{
dev_dbg
(
&
pdev
->
dev
,
"out of memory
\n
"
);
retval
=
-
ENOMEM
;
goto
out
;
return
-
ENOMEM
;
}
ssc
->
pdev
=
pdev
;
plat_dat
=
atmel_ssc_get_driver_data
(
pdev
);
if
(
!
plat_dat
)
return
-
ENODEV
;
ssc
->
pdata
=
(
struct
atmel_ssc_platform_data
*
)
plat_dat
;
regs
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
if
(
!
regs
)
{
dev_dbg
(
&
pdev
->
dev
,
"no mmio resource defined
\n
"
);
retval
=
-
ENXIO
;
goto
out_free
;
return
-
ENXIO
;
}
ssc
->
clk
=
clk_get
(
&
pdev
->
dev
,
"pclk"
);
if
(
IS_ERR
(
ssc
->
clk
))
{
dev_dbg
(
&
pdev
->
dev
,
"no pclk clock defined
\n
"
);
retval
=
-
ENXIO
;
goto
out_free
;
}
ssc
->
pdev
=
pdev
;
ssc
->
regs
=
ioremap
(
regs
->
start
,
resource_size
(
regs
));
ssc
->
regs
=
devm_request_and_ioremap
(
&
pdev
->
dev
,
regs
);
if
(
!
ssc
->
regs
)
{
dev_dbg
(
&
pdev
->
dev
,
"ioremap failed
\n
"
);
retval
=
-
EINVAL
;
goto
out_clk
;
return
-
EINVAL
;
}
ssc
->
phybase
=
regs
->
start
;
ssc
->
clk
=
devm_clk_get
(
&
pdev
->
dev
,
"pclk"
);
if
(
IS_ERR
(
ssc
->
clk
))
{
dev_dbg
(
&
pdev
->
dev
,
"no pclk clock defined
\n
"
);
return
-
ENXIO
;
}
/* disable all interrupts */
...
...
@@ -112,8 +174,7 @@ static int __init ssc_probe(struct platform_device *pdev)
ssc
->
irq
=
platform_get_irq
(
pdev
,
0
);
if
(
!
ssc
->
irq
)
{
dev_dbg
(
&
pdev
->
dev
,
"could not get irq
\n
"
);
retval
=
-
ENXIO
;
goto
out_unmap
;
return
-
ENXIO
;
}
spin_lock
(
&
user_lock
);
...
...
@@ -125,16 +186,7 @@ static int __init ssc_probe(struct platform_device *pdev)
dev_info
(
&
pdev
->
dev
,
"Atmel SSC device at 0x%p (irq %d)
\n
"
,
ssc
->
regs
,
ssc
->
irq
);
goto
out
;
out_unmap:
iounmap
(
ssc
->
regs
);
out_clk:
clk_put
(
ssc
->
clk
);
out_free:
kfree
(
ssc
);
out:
return
retval
;
return
0
;
}
static
int
__devexit
ssc_remove
(
struct
platform_device
*
pdev
)
...
...
@@ -142,34 +194,23 @@ static int __devexit ssc_remove(struct platform_device *pdev)
struct
ssc_device
*
ssc
=
platform_get_drvdata
(
pdev
);
spin_lock
(
&
user_lock
);
iounmap
(
ssc
->
regs
);
clk_put
(
ssc
->
clk
);
list_del
(
&
ssc
->
list
);
kfree
(
ssc
);
spin_unlock
(
&
user_lock
);
return
0
;
}
static
struct
platform_driver
ssc_driver
=
{
.
remove
=
__devexit_p
(
ssc_remove
),
.
driver
=
{
.
name
=
"ssc"
,
.
owner
=
THIS_MODULE
,
.
of_match_table
=
of_match_ptr
(
atmel_ssc_dt_ids
),
},
.
id_table
=
atmel_ssc_devtypes
,
.
probe
=
ssc_probe
,
.
remove
=
__devexit_p
(
ssc_remove
),
};
static
int
__init
ssc_init
(
void
)
{
return
platform_driver_probe
(
&
ssc_driver
,
ssc_probe
);
}
module_init
(
ssc_init
);
static
void
__exit
ssc_exit
(
void
)
{
platform_driver_unregister
(
&
ssc_driver
);
}
module_exit
(
ssc_exit
);
module_platform_driver
(
ssc_driver
);
MODULE_AUTHOR
(
"Hans-Christian Egtvedt <hcegtvedt@atmel.com>"
);
MODULE_DESCRIPTION
(
"SSC driver for Atmel AVR32 and AT91"
);
...
...
include/linux/atmel-ssc.h
浏览文件 @
93ac820d
...
...
@@ -5,10 +5,16 @@
#include <linux/list.h>
#include <linux/io.h>
struct
atmel_ssc_platform_data
{
int
use_dma
;
};
struct
ssc_device
{
struct
list_head
list
;
resource_size_t
phybase
;
void
__iomem
*
regs
;
struct
platform_device
*
pdev
;
struct
atmel_ssc_platform_data
*
pdata
;
struct
clk
*
clk
;
int
user
;
int
irq
;
...
...
sound/soc/atmel/Kconfig
浏览文件 @
93ac820d
...
...
@@ -6,6 +6,14 @@ config SND_ATMEL_SOC
the ATMEL SSC interface. You will also need
to select the audio interfaces to support below.
config SND_ATMEL_SOC_PDC
tristate
depends on SND_ATMEL_SOC
config SND_ATMEL_SOC_DMA
tristate
depends on SND_ATMEL_SOC
config SND_ATMEL_SOC_SSC
tristate
depends on SND_ATMEL_SOC
...
...
@@ -16,8 +24,8 @@ config SND_ATMEL_SOC_SSC
config SND_AT91_SOC_SAM9G20_WM8731
tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
depends on ATMEL_SSC &&
ARCH_AT91SAM9G20 && SND_ATMEL_SOC && \
AT91_PROGRAMMABLE_CLOCKS
depends on ATMEL_SSC &&
SND_ATMEL_SOC && AT91_PROGRAMMABLE_CLOCKS
select SND_ATMEL_SOC_PDC
select SND_ATMEL_SOC_SSC
select SND_SOC_WM8731
help
...
...
@@ -27,6 +35,7 @@ config SND_AT91_SOC_SAM9G20_WM8731
config SND_AT91_SOC_AFEB9260
tristate "SoC Audio support for AFEB9260 board"
depends on ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
select SND_ATMEL_SOC_PDC
select SND_ATMEL_SOC_SSC
select SND_SOC_TLV320AIC23
help
...
...
sound/soc/atmel/Makefile
浏览文件 @
93ac820d
# AT91 Platform Support
snd-soc-atmel-pcm-objs
:=
atmel-pcm.o
snd-soc-atmel-pcm-pdc-objs
:=
atmel-pcm-pdc.o
snd-soc-atmel-pcm-dma-objs
:=
atmel-pcm-dma.o
snd-soc-atmel_ssc_dai-objs
:=
atmel_ssc_dai.o
obj-$(CONFIG_SND_ATMEL_SOC)
+=
snd-soc-atmel-pcm.o
obj-$(CONFIG_SND_ATMEL_SOC_PDC)
+=
snd-soc-atmel-pcm-pdc.o
obj-$(CONFIG_SND_ATMEL_SOC_DMA)
+=
snd-soc-atmel-pcm-dma.o
obj-$(CONFIG_SND_ATMEL_SOC_SSC)
+=
snd-soc-atmel_ssc_dai.o
# AT91 Machine Support
...
...
sound/soc/atmel/atmel-pcm-dma.c
0 → 100644
浏览文件 @
93ac820d
/*
* atmel-pcm-dma.c -- ALSA PCM DMA support for the Atmel SoC.
*
* Copyright (C) 2012 Atmel
*
* Author: Bo Shen <voice.shen@atmel.com>
*
* Based on atmel-pcm by:
* Sedji Gaouaou <sedji.gaouaou@atmel.com>
* Copyright 2008 Atmel
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/atmel-ssc.h>
#include <linux/platform_data/dma-atmel.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
#include "atmel-pcm.h"
/*--------------------------------------------------------------------------*\
* Hardware definition
\*--------------------------------------------------------------------------*/
static
const
struct
snd_pcm_hardware
atmel_pcm_dma_hardware
=
{
.
info
=
SNDRV_PCM_INFO_MMAP
|
SNDRV_PCM_INFO_MMAP_VALID
|
SNDRV_PCM_INFO_INTERLEAVED
|
SNDRV_PCM_INFO_RESUME
|
SNDRV_PCM_INFO_PAUSE
,
.
formats
=
SNDRV_PCM_FMTBIT_S16_LE
,
.
period_bytes_min
=
256
,
/* lighting DMA overhead */
.
period_bytes_max
=
2
*
0xffff
,
/* if 2 bytes format */
.
periods_min
=
8
,
.
periods_max
=
1024
,
/* no limit */
.
buffer_bytes_max
=
ATMEL_SSC_DMABUF_SIZE
,
};
/**
* atmel_pcm_dma_irq: SSC interrupt handler for DMAENGINE enabled SSC
*
* We use DMAENGINE to send/receive data to/from SSC so this ISR is only to
* check if any overrun occured.
*/
static
void
atmel_pcm_dma_irq
(
u32
ssc_sr
,
struct
snd_pcm_substream
*
substream
)
{
struct
atmel_pcm_dma_params
*
prtd
;
prtd
=
snd_dmaengine_pcm_get_data
(
substream
);
if
(
ssc_sr
&
prtd
->
mask
->
ssc_error
)
{
if
(
snd_pcm_running
(
substream
))
pr_warn
(
"atmel-pcm: buffer %s on %s (SSC_SR=%#x)
\n
"
,
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
?
"underrun"
:
"overrun"
,
prtd
->
name
,
ssc_sr
);
/* stop RX and capture: will be enabled again at restart */
ssc_writex
(
prtd
->
ssc
->
regs
,
SSC_CR
,
prtd
->
mask
->
ssc_disable
);
snd_pcm_stop
(
substream
,
SNDRV_PCM_STATE_XRUN
);
/* now drain RHR and read status to remove xrun condition */
ssc_readx
(
prtd
->
ssc
->
regs
,
SSC_RHR
);
ssc_readx
(
prtd
->
ssc
->
regs
,
SSC_SR
);
}
}
/*--------------------------------------------------------------------------*\
* DMAENGINE operations
\*--------------------------------------------------------------------------*/
static
bool
filter
(
struct
dma_chan
*
chan
,
void
*
slave
)
{
struct
at_dma_slave
*
sl
=
slave
;
if
(
sl
->
dma_dev
==
chan
->
device
->
dev
)
{
chan
->
private
=
sl
;
return
true
;
}
else
{
return
false
;
}
}
static
int
atmel_pcm_configure_dma
(
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_hw_params
*
params
)
{
struct
atmel_pcm_dma_params
*
prtd
;
struct
ssc_device
*
ssc
;
struct
dma_chan
*
dma_chan
;
struct
dma_slave_config
slave_config
;
int
ret
;
prtd
=
snd_dmaengine_pcm_get_data
(
substream
);
ssc
=
prtd
->
ssc
;
ret
=
snd_hwparams_to_dma_slave_config
(
substream
,
params
,
&
slave_config
);
if
(
ret
)
{
pr_err
(
"atmel-pcm: hwparams to dma slave configure failed
\n
"
);
return
ret
;
}
if
(
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
{
slave_config
.
dst_addr
=
(
dma_addr_t
)
ssc
->
phybase
+
SSC_THR
;
slave_config
.
dst_maxburst
=
1
;
}
else
{
slave_config
.
src_addr
=
(
dma_addr_t
)
ssc
->
phybase
+
SSC_RHR
;
slave_config
.
src_maxburst
=
1
;
}
slave_config
.
device_fc
=
false
;
dma_chan
=
snd_dmaengine_pcm_get_chan
(
substream
);
if
(
dmaengine_slave_config
(
dma_chan
,
&
slave_config
))
{
pr_err
(
"atmel-pcm: failed to configure dma channel
\n
"
);
ret
=
-
EBUSY
;
return
ret
;
}
return
0
;
}
static
int
atmel_pcm_hw_params
(
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_hw_params
*
params
)
{
struct
snd_soc_pcm_runtime
*
rtd
=
substream
->
private_data
;
struct
atmel_pcm_dma_params
*
prtd
;
struct
ssc_device
*
ssc
;
struct
at_dma_slave
*
sdata
=
NULL
;
int
ret
;
snd_pcm_set_runtime_buffer
(
substream
,
&
substream
->
dma_buffer
);
prtd
=
snd_soc_dai_get_dma_data
(
rtd
->
cpu_dai
,
substream
);
ssc
=
prtd
->
ssc
;
if
(
ssc
->
pdev
)
sdata
=
ssc
->
pdev
->
dev
.
platform_data
;
ret
=
snd_dmaengine_pcm_open
(
substream
,
filter
,
sdata
);
if
(
ret
)
{
pr_err
(
"atmel-pcm: dmaengine pcm open failed
\n
"
);
return
-
EINVAL
;
}
snd_dmaengine_pcm_set_data
(
substream
,
prtd
);
ret
=
atmel_pcm_configure_dma
(
substream
,
params
);
if
(
ret
)
{
pr_err
(
"atmel-pcm: failed to configure dmai
\n
"
);
goto
err
;
}
prtd
->
dma_intr_handler
=
atmel_pcm_dma_irq
;
return
0
;
err:
snd_dmaengine_pcm_close
(
substream
);
return
ret
;
}
static
int
atmel_pcm_dma_prepare
(
struct
snd_pcm_substream
*
substream
)
{
struct
atmel_pcm_dma_params
*
prtd
;
prtd
=
snd_dmaengine_pcm_get_data
(
substream
);
ssc_writex
(
prtd
->
ssc
->
regs
,
SSC_IER
,
prtd
->
mask
->
ssc_error
);
ssc_writex
(
prtd
->
ssc
->
regs
,
SSC_CR
,
prtd
->
mask
->
ssc_enable
);
return
0
;
}
static
int
atmel_pcm_open
(
struct
snd_pcm_substream
*
substream
)
{
snd_soc_set_runtime_hwparams
(
substream
,
&
atmel_pcm_dma_hardware
);
return
0
;
}
static
int
atmel_pcm_close
(
struct
snd_pcm_substream
*
substream
)
{
snd_dmaengine_pcm_close
(
substream
);
return
0
;
}
static
struct
snd_pcm_ops
atmel_pcm_ops
=
{
.
open
=
atmel_pcm_open
,
.
close
=
atmel_pcm_close
,
.
ioctl
=
snd_pcm_lib_ioctl
,
.
hw_params
=
atmel_pcm_hw_params
,
.
prepare
=
atmel_pcm_dma_prepare
,
.
trigger
=
snd_dmaengine_pcm_trigger
,
.
pointer
=
snd_dmaengine_pcm_pointer_no_residue
,
.
mmap
=
atmel_pcm_mmap
,
};
static
struct
snd_soc_platform_driver
atmel_soc_platform
=
{
.
ops
=
&
atmel_pcm_ops
,
.
pcm_new
=
atmel_pcm_new
,
.
pcm_free
=
atmel_pcm_free
,
};
int
atmel_pcm_dma_platform_register
(
struct
device
*
dev
)
{
return
snd_soc_register_platform
(
dev
,
&
atmel_soc_platform
);
}
EXPORT_SYMBOL
(
atmel_pcm_dma_platform_register
);
void
atmel_pcm_dma_platform_unregister
(
struct
device
*
dev
)
{
snd_soc_unregister_platform
(
dev
);
}
EXPORT_SYMBOL
(
atmel_pcm_dma_platform_unregister
);
MODULE_AUTHOR
(
"Bo Shen <voice.shen@atmel.com>"
);
MODULE_DESCRIPTION
(
"Atmel DMA based PCM module"
);
MODULE_LICENSE
(
"GPL"
);
sound/soc/atmel/atmel-pcm-pdc.c
0 → 100644
浏览文件 @
93ac820d
/*
* atmel-pcm.c -- ALSA PCM interface for the Atmel atmel SoC.
*
* Copyright (C) 2005 SAN People
* Copyright (C) 2008 Atmel
*
* Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com>
*
* Based on at91-pcm. by:
* Frank Mandarino <fmandarino@endrelia.com>
* Copyright 2006 Endrelia Technologies Inc.
*
* Based on pxa2xx-pcm.c by:
*
* Author: Nicolas Pitre
* Created: Nov 30, 2004
* Copyright: (C) 2004 MontaVista Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/atmel_pdc.h>
#include <linux/atmel-ssc.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include "atmel-pcm.h"
/*--------------------------------------------------------------------------*\
* Hardware definition
\*--------------------------------------------------------------------------*/
/* TODO: These values were taken from the AT91 platform driver, check
* them against real values for AT32
*/
static
const
struct
snd_pcm_hardware
atmel_pcm_hardware
=
{
.
info
=
SNDRV_PCM_INFO_MMAP
|
SNDRV_PCM_INFO_MMAP_VALID
|
SNDRV_PCM_INFO_INTERLEAVED
|
SNDRV_PCM_INFO_PAUSE
,
.
formats
=
SNDRV_PCM_FMTBIT_S16_LE
,
.
period_bytes_min
=
32
,
.
period_bytes_max
=
8192
,
.
periods_min
=
2
,
.
periods_max
=
1024
,
.
buffer_bytes_max
=
ATMEL_SSC_DMABUF_SIZE
,
};
/*--------------------------------------------------------------------------*\
* Data types
\*--------------------------------------------------------------------------*/
struct
atmel_runtime_data
{
struct
atmel_pcm_dma_params
*
params
;
dma_addr_t
dma_buffer
;
/* physical address of dma buffer */
dma_addr_t
dma_buffer_end
;
/* first address beyond DMA buffer */
size_t
period_size
;
dma_addr_t
period_ptr
;
/* physical address of next period */
/* PDC register save */
u32
pdc_xpr_save
;
u32
pdc_xcr_save
;
u32
pdc_xnpr_save
;
u32
pdc_xncr_save
;
};
/*--------------------------------------------------------------------------*\
* ISR
\*--------------------------------------------------------------------------*/
static
void
atmel_pcm_dma_irq
(
u32
ssc_sr
,
struct
snd_pcm_substream
*
substream
)
{
struct
atmel_runtime_data
*
prtd
=
substream
->
runtime
->
private_data
;
struct
atmel_pcm_dma_params
*
params
=
prtd
->
params
;
static
int
count
;
count
++
;
if
(
ssc_sr
&
params
->
mask
->
ssc_endbuf
)
{
pr_warn
(
"atmel-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)
\n
"
,
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
?
"underrun"
:
"overrun"
,
params
->
name
,
ssc_sr
,
count
);
/* re-start the PDC */
ssc_writex
(
params
->
ssc
->
regs
,
ATMEL_PDC_PTCR
,
params
->
mask
->
pdc_disable
);
prtd
->
period_ptr
+=
prtd
->
period_size
;
if
(
prtd
->
period_ptr
>=
prtd
->
dma_buffer_end
)
prtd
->
period_ptr
=
prtd
->
dma_buffer
;
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xpr
,
prtd
->
period_ptr
);
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xcr
,
prtd
->
period_size
/
params
->
pdc_xfer_size
);
ssc_writex
(
params
->
ssc
->
regs
,
ATMEL_PDC_PTCR
,
params
->
mask
->
pdc_enable
);
}
if
(
ssc_sr
&
params
->
mask
->
ssc_endx
)
{
/* Load the PDC next pointer and counter registers */
prtd
->
period_ptr
+=
prtd
->
period_size
;
if
(
prtd
->
period_ptr
>=
prtd
->
dma_buffer_end
)
prtd
->
period_ptr
=
prtd
->
dma_buffer
;
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xnpr
,
prtd
->
period_ptr
);
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xncr
,
prtd
->
period_size
/
params
->
pdc_xfer_size
);
}
snd_pcm_period_elapsed
(
substream
);
}
/*--------------------------------------------------------------------------*\
* PCM operations
\*--------------------------------------------------------------------------*/
static
int
atmel_pcm_hw_params
(
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_hw_params
*
params
)
{
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
struct
atmel_runtime_data
*
prtd
=
runtime
->
private_data
;
struct
snd_soc_pcm_runtime
*
rtd
=
substream
->
private_data
;
/* this may get called several times by oss emulation
* with different params */
snd_pcm_set_runtime_buffer
(
substream
,
&
substream
->
dma_buffer
);
runtime
->
dma_bytes
=
params_buffer_bytes
(
params
);
prtd
->
params
=
snd_soc_dai_get_dma_data
(
rtd
->
cpu_dai
,
substream
);
prtd
->
params
->
dma_intr_handler
=
atmel_pcm_dma_irq
;
prtd
->
dma_buffer
=
runtime
->
dma_addr
;
prtd
->
dma_buffer_end
=
runtime
->
dma_addr
+
runtime
->
dma_bytes
;
prtd
->
period_size
=
params_period_bytes
(
params
);
pr_debug
(
"atmel-pcm: "
"hw_params: DMA for %s initialized "
"(dma_bytes=%u, period_size=%u)
\n
"
,
prtd
->
params
->
name
,
runtime
->
dma_bytes
,
prtd
->
period_size
);
return
0
;
}
static
int
atmel_pcm_hw_free
(
struct
snd_pcm_substream
*
substream
)
{
struct
atmel_runtime_data
*
prtd
=
substream
->
runtime
->
private_data
;
struct
atmel_pcm_dma_params
*
params
=
prtd
->
params
;
if
(
params
!=
NULL
)
{
ssc_writex
(
params
->
ssc
->
regs
,
SSC_PDC_PTCR
,
params
->
mask
->
pdc_disable
);
prtd
->
params
->
dma_intr_handler
=
NULL
;
}
return
0
;
}
static
int
atmel_pcm_prepare
(
struct
snd_pcm_substream
*
substream
)
{
struct
atmel_runtime_data
*
prtd
=
substream
->
runtime
->
private_data
;
struct
atmel_pcm_dma_params
*
params
=
prtd
->
params
;
ssc_writex
(
params
->
ssc
->
regs
,
SSC_IDR
,
params
->
mask
->
ssc_endx
|
params
->
mask
->
ssc_endbuf
);
ssc_writex
(
params
->
ssc
->
regs
,
ATMEL_PDC_PTCR
,
params
->
mask
->
pdc_disable
);
return
0
;
}
static
int
atmel_pcm_trigger
(
struct
snd_pcm_substream
*
substream
,
int
cmd
)
{
struct
snd_pcm_runtime
*
rtd
=
substream
->
runtime
;
struct
atmel_runtime_data
*
prtd
=
rtd
->
private_data
;
struct
atmel_pcm_dma_params
*
params
=
prtd
->
params
;
int
ret
=
0
;
pr_debug
(
"atmel-pcm:buffer_size = %ld,"
"dma_area = %p, dma_bytes = %u
\n
"
,
rtd
->
buffer_size
,
rtd
->
dma_area
,
rtd
->
dma_bytes
);
switch
(
cmd
)
{
case
SNDRV_PCM_TRIGGER_START
:
prtd
->
period_ptr
=
prtd
->
dma_buffer
;
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xpr
,
prtd
->
period_ptr
);
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xcr
,
prtd
->
period_size
/
params
->
pdc_xfer_size
);
prtd
->
period_ptr
+=
prtd
->
period_size
;
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xnpr
,
prtd
->
period_ptr
);
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xncr
,
prtd
->
period_size
/
params
->
pdc_xfer_size
);
pr_debug
(
"atmel-pcm: trigger: "
"period_ptr=%lx, xpr=%u, "
"xcr=%u, xnpr=%u, xncr=%u
\n
"
,
(
unsigned
long
)
prtd
->
period_ptr
,
ssc_readx
(
params
->
ssc
->
regs
,
params
->
pdc
->
xpr
),
ssc_readx
(
params
->
ssc
->
regs
,
params
->
pdc
->
xcr
),
ssc_readx
(
params
->
ssc
->
regs
,
params
->
pdc
->
xnpr
),
ssc_readx
(
params
->
ssc
->
regs
,
params
->
pdc
->
xncr
));
ssc_writex
(
params
->
ssc
->
regs
,
SSC_IER
,
params
->
mask
->
ssc_endx
|
params
->
mask
->
ssc_endbuf
);
ssc_writex
(
params
->
ssc
->
regs
,
SSC_PDC_PTCR
,
params
->
mask
->
pdc_enable
);
pr_debug
(
"sr=%u imr=%u
\n
"
,
ssc_readx
(
params
->
ssc
->
regs
,
SSC_SR
),
ssc_readx
(
params
->
ssc
->
regs
,
SSC_IER
));
break
;
/* SNDRV_PCM_TRIGGER_START */
case
SNDRV_PCM_TRIGGER_STOP
:
case
SNDRV_PCM_TRIGGER_SUSPEND
:
case
SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
ssc_writex
(
params
->
ssc
->
regs
,
ATMEL_PDC_PTCR
,
params
->
mask
->
pdc_disable
);
break
;
case
SNDRV_PCM_TRIGGER_RESUME
:
case
SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
ssc_writex
(
params
->
ssc
->
regs
,
ATMEL_PDC_PTCR
,
params
->
mask
->
pdc_enable
);
break
;
default:
ret
=
-
EINVAL
;
}
return
ret
;
}
static
snd_pcm_uframes_t
atmel_pcm_pointer
(
struct
snd_pcm_substream
*
substream
)
{
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
struct
atmel_runtime_data
*
prtd
=
runtime
->
private_data
;
struct
atmel_pcm_dma_params
*
params
=
prtd
->
params
;
dma_addr_t
ptr
;
snd_pcm_uframes_t
x
;
ptr
=
(
dma_addr_t
)
ssc_readx
(
params
->
ssc
->
regs
,
params
->
pdc
->
xpr
);
x
=
bytes_to_frames
(
runtime
,
ptr
-
prtd
->
dma_buffer
);
if
(
x
==
runtime
->
buffer_size
)
x
=
0
;
return
x
;
}
static
int
atmel_pcm_open
(
struct
snd_pcm_substream
*
substream
)
{
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
struct
atmel_runtime_data
*
prtd
;
int
ret
=
0
;
snd_soc_set_runtime_hwparams
(
substream
,
&
atmel_pcm_hardware
);
/* ensure that buffer size is a multiple of period size */
ret
=
snd_pcm_hw_constraint_integer
(
runtime
,
SNDRV_PCM_HW_PARAM_PERIODS
);
if
(
ret
<
0
)
goto
out
;
prtd
=
kzalloc
(
sizeof
(
struct
atmel_runtime_data
),
GFP_KERNEL
);
if
(
prtd
==
NULL
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
runtime
->
private_data
=
prtd
;
out:
return
ret
;
}
static
int
atmel_pcm_close
(
struct
snd_pcm_substream
*
substream
)
{
struct
atmel_runtime_data
*
prtd
=
substream
->
runtime
->
private_data
;
kfree
(
prtd
);
return
0
;
}
static
struct
snd_pcm_ops
atmel_pcm_ops
=
{
.
open
=
atmel_pcm_open
,
.
close
=
atmel_pcm_close
,
.
ioctl
=
snd_pcm_lib_ioctl
,
.
hw_params
=
atmel_pcm_hw_params
,
.
hw_free
=
atmel_pcm_hw_free
,
.
prepare
=
atmel_pcm_prepare
,
.
trigger
=
atmel_pcm_trigger
,
.
pointer
=
atmel_pcm_pointer
,
.
mmap
=
atmel_pcm_mmap
,
};
/*--------------------------------------------------------------------------*\
* ASoC platform driver
\*--------------------------------------------------------------------------*/
#ifdef CONFIG_PM
static
int
atmel_pcm_suspend
(
struct
snd_soc_dai
*
dai
)
{
struct
snd_pcm_runtime
*
runtime
=
dai
->
runtime
;
struct
atmel_runtime_data
*
prtd
;
struct
atmel_pcm_dma_params
*
params
;
if
(
!
runtime
)
return
0
;
prtd
=
runtime
->
private_data
;
params
=
prtd
->
params
;
/* disable the PDC and save the PDC registers */
ssc_writel
(
params
->
ssc
->
regs
,
PDC_PTCR
,
params
->
mask
->
pdc_disable
);
prtd
->
pdc_xpr_save
=
ssc_readx
(
params
->
ssc
->
regs
,
params
->
pdc
->
xpr
);
prtd
->
pdc_xcr_save
=
ssc_readx
(
params
->
ssc
->
regs
,
params
->
pdc
->
xcr
);
prtd
->
pdc_xnpr_save
=
ssc_readx
(
params
->
ssc
->
regs
,
params
->
pdc
->
xnpr
);
prtd
->
pdc_xncr_save
=
ssc_readx
(
params
->
ssc
->
regs
,
params
->
pdc
->
xncr
);
return
0
;
}
static
int
atmel_pcm_resume
(
struct
snd_soc_dai
*
dai
)
{
struct
snd_pcm_runtime
*
runtime
=
dai
->
runtime
;
struct
atmel_runtime_data
*
prtd
;
struct
atmel_pcm_dma_params
*
params
;
if
(
!
runtime
)
return
0
;
prtd
=
runtime
->
private_data
;
params
=
prtd
->
params
;
/* restore the PDC registers and enable the PDC */
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xpr
,
prtd
->
pdc_xpr_save
);
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xcr
,
prtd
->
pdc_xcr_save
);
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xnpr
,
prtd
->
pdc_xnpr_save
);
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xncr
,
prtd
->
pdc_xncr_save
);
ssc_writel
(
params
->
ssc
->
regs
,
PDC_PTCR
,
params
->
mask
->
pdc_enable
);
return
0
;
}
#else
#define atmel_pcm_suspend NULL
#define atmel_pcm_resume NULL
#endif
static
struct
snd_soc_platform_driver
atmel_soc_platform
=
{
.
ops
=
&
atmel_pcm_ops
,
.
pcm_new
=
atmel_pcm_new
,
.
pcm_free
=
atmel_pcm_free
,
.
suspend
=
atmel_pcm_suspend
,
.
resume
=
atmel_pcm_resume
,
};
int
atmel_pcm_pdc_platform_register
(
struct
device
*
dev
)
{
return
snd_soc_register_platform
(
dev
,
&
atmel_soc_platform
);
}
EXPORT_SYMBOL
(
atmel_pcm_pdc_platform_register
);
void
atmel_pcm_pdc_platform_unregister
(
struct
device
*
dev
)
{
snd_soc_unregister_platform
(
dev
);
}
EXPORT_SYMBOL
(
atmel_pcm_pdc_platform_unregister
);
MODULE_AUTHOR
(
"Sedji Gaouaou <sedji.gaouaou@atmel.com>"
);
MODULE_DESCRIPTION
(
"Atmel PCM module"
);
MODULE_LICENSE
(
"GPL"
);
sound/soc/atmel/atmel-pcm.c
浏览文件 @
93ac820d
...
...
@@ -32,80 +32,25 @@
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/atmel_pdc.h>
#include <linux/atmel-ssc.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include "atmel-pcm.h"
/*--------------------------------------------------------------------------*\
* Hardware definition
\*--------------------------------------------------------------------------*/
/* TODO: These values were taken from the AT91 platform driver, check
* them against real values for AT32
*/
static
const
struct
snd_pcm_hardware
atmel_pcm_hardware
=
{
.
info
=
SNDRV_PCM_INFO_MMAP
|
SNDRV_PCM_INFO_MMAP_VALID
|
SNDRV_PCM_INFO_INTERLEAVED
|
SNDRV_PCM_INFO_PAUSE
,
.
formats
=
SNDRV_PCM_FMTBIT_S16_LE
,
.
period_bytes_min
=
32
,
.
period_bytes_max
=
8192
,
.
periods_min
=
2
,
.
periods_max
=
1024
,
.
buffer_bytes_max
=
32
*
1024
,
};
/*--------------------------------------------------------------------------*\
* Data types
\*--------------------------------------------------------------------------*/
struct
atmel_runtime_data
{
struct
atmel_pcm_dma_params
*
params
;
dma_addr_t
dma_buffer
;
/* physical address of dma buffer */
dma_addr_t
dma_buffer_end
;
/* first address beyond DMA buffer */
size_t
period_size
;
dma_addr_t
period_ptr
;
/* physical address of next period */
/* PDC register save */
u32
pdc_xpr_save
;
u32
pdc_xcr_save
;
u32
pdc_xnpr_save
;
u32
pdc_xncr_save
;
};
/*--------------------------------------------------------------------------*\
* Helper functions
\*--------------------------------------------------------------------------*/
static
int
atmel_pcm_preallocate_dma_buffer
(
struct
snd_pcm
*
pcm
,
int
stream
)
{
struct
snd_pcm_substream
*
substream
=
pcm
->
streams
[
stream
].
substream
;
struct
snd_dma_buffer
*
buf
=
&
substream
->
dma_buffer
;
size_t
size
=
atmel_pcm_hardware
.
buffer_bytes_max
;
size_t
size
=
ATMEL_SSC_DMABUF_SIZE
;
buf
->
dev
.
type
=
SNDRV_DMA_TYPE_DEV
;
buf
->
dev
.
dev
=
pcm
->
card
->
dev
;
buf
->
private_data
=
NULL
;
buf
->
area
=
dma_alloc_coherent
(
pcm
->
card
->
dev
,
size
,
&
buf
->
addr
,
GFP_KERNEL
);
pr_debug
(
"atmel-pcm:"
"preallocate_dma_buffer: area=%p, addr=%p, size=%d
\n
"
,
(
void
*
)
buf
->
area
,
(
void
*
)
buf
->
addr
,
size
);
&
buf
->
addr
,
GFP_KERNEL
);
pr_debug
(
"atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%d
\n
"
,
(
void
*
)
buf
->
area
,
(
void
*
)
buf
->
addr
,
size
);
if
(
!
buf
->
area
)
return
-
ENOMEM
;
...
...
@@ -113,258 +58,19 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
buf
->
bytes
=
size
;
return
0
;
}
/*--------------------------------------------------------------------------*\
* ISR
\*--------------------------------------------------------------------------*/
static
void
atmel_pcm_dma_irq
(
u32
ssc_sr
,
struct
snd_pcm_substream
*
substream
)
{
struct
atmel_runtime_data
*
prtd
=
substream
->
runtime
->
private_data
;
struct
atmel_pcm_dma_params
*
params
=
prtd
->
params
;
static
int
count
;
count
++
;
if
(
ssc_sr
&
params
->
mask
->
ssc_endbuf
)
{
pr_warning
(
"atmel-pcm: buffer %s on %s"
" (SSC_SR=%#x, count=%d)
\n
"
,
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
?
"underrun"
:
"overrun"
,
params
->
name
,
ssc_sr
,
count
);
/* re-start the PDC */
ssc_writex
(
params
->
ssc
->
regs
,
ATMEL_PDC_PTCR
,
params
->
mask
->
pdc_disable
);
prtd
->
period_ptr
+=
prtd
->
period_size
;
if
(
prtd
->
period_ptr
>=
prtd
->
dma_buffer_end
)
prtd
->
period_ptr
=
prtd
->
dma_buffer
;
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xpr
,
prtd
->
period_ptr
);
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xcr
,
prtd
->
period_size
/
params
->
pdc_xfer_size
);
ssc_writex
(
params
->
ssc
->
regs
,
ATMEL_PDC_PTCR
,
params
->
mask
->
pdc_enable
);
}
if
(
ssc_sr
&
params
->
mask
->
ssc_endx
)
{
/* Load the PDC next pointer and counter registers */
prtd
->
period_ptr
+=
prtd
->
period_size
;
if
(
prtd
->
period_ptr
>=
prtd
->
dma_buffer_end
)
prtd
->
period_ptr
=
prtd
->
dma_buffer
;
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xnpr
,
prtd
->
period_ptr
);
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xncr
,
prtd
->
period_size
/
params
->
pdc_xfer_size
);
}
snd_pcm_period_elapsed
(
substream
);
}
/*--------------------------------------------------------------------------*\
* PCM operations
\*--------------------------------------------------------------------------*/
static
int
atmel_pcm_hw_params
(
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_hw_params
*
params
)
{
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
struct
atmel_runtime_data
*
prtd
=
runtime
->
private_data
;
struct
snd_soc_pcm_runtime
*
rtd
=
substream
->
private_data
;
/* this may get called several times by oss emulation
* with different params */
snd_pcm_set_runtime_buffer
(
substream
,
&
substream
->
dma_buffer
);
runtime
->
dma_bytes
=
params_buffer_bytes
(
params
);
prtd
->
params
=
snd_soc_dai_get_dma_data
(
rtd
->
cpu_dai
,
substream
);
prtd
->
params
->
dma_intr_handler
=
atmel_pcm_dma_irq
;
prtd
->
dma_buffer
=
runtime
->
dma_addr
;
prtd
->
dma_buffer_end
=
runtime
->
dma_addr
+
runtime
->
dma_bytes
;
prtd
->
period_size
=
params_period_bytes
(
params
);
pr_debug
(
"atmel-pcm: "
"hw_params: DMA for %s initialized "
"(dma_bytes=%u, period_size=%u)
\n
"
,
prtd
->
params
->
name
,
runtime
->
dma_bytes
,
prtd
->
period_size
);
return
0
;
}
static
int
atmel_pcm_hw_free
(
struct
snd_pcm_substream
*
substream
)
{
struct
atmel_runtime_data
*
prtd
=
substream
->
runtime
->
private_data
;
struct
atmel_pcm_dma_params
*
params
=
prtd
->
params
;
if
(
params
!=
NULL
)
{
ssc_writex
(
params
->
ssc
->
regs
,
SSC_PDC_PTCR
,
params
->
mask
->
pdc_disable
);
prtd
->
params
->
dma_intr_handler
=
NULL
;
}
return
0
;
}
static
int
atmel_pcm_prepare
(
struct
snd_pcm_substream
*
substream
)
{
struct
atmel_runtime_data
*
prtd
=
substream
->
runtime
->
private_data
;
struct
atmel_pcm_dma_params
*
params
=
prtd
->
params
;
ssc_writex
(
params
->
ssc
->
regs
,
SSC_IDR
,
params
->
mask
->
ssc_endx
|
params
->
mask
->
ssc_endbuf
);
ssc_writex
(
params
->
ssc
->
regs
,
ATMEL_PDC_PTCR
,
params
->
mask
->
pdc_disable
);
return
0
;
}
static
int
atmel_pcm_trigger
(
struct
snd_pcm_substream
*
substream
,
int
cmd
)
{
struct
snd_pcm_runtime
*
rtd
=
substream
->
runtime
;
struct
atmel_runtime_data
*
prtd
=
rtd
->
private_data
;
struct
atmel_pcm_dma_params
*
params
=
prtd
->
params
;
int
ret
=
0
;
pr_debug
(
"atmel-pcm:buffer_size = %ld,"
"dma_area = %p, dma_bytes = %u
\n
"
,
rtd
->
buffer_size
,
rtd
->
dma_area
,
rtd
->
dma_bytes
);
switch
(
cmd
)
{
case
SNDRV_PCM_TRIGGER_START
:
prtd
->
period_ptr
=
prtd
->
dma_buffer
;
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xpr
,
prtd
->
period_ptr
);
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xcr
,
prtd
->
period_size
/
params
->
pdc_xfer_size
);
prtd
->
period_ptr
+=
prtd
->
period_size
;
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xnpr
,
prtd
->
period_ptr
);
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xncr
,
prtd
->
period_size
/
params
->
pdc_xfer_size
);
pr_debug
(
"atmel-pcm: trigger: "
"period_ptr=%lx, xpr=%u, "
"xcr=%u, xnpr=%u, xncr=%u
\n
"
,
(
unsigned
long
)
prtd
->
period_ptr
,
ssc_readx
(
params
->
ssc
->
regs
,
params
->
pdc
->
xpr
),
ssc_readx
(
params
->
ssc
->
regs
,
params
->
pdc
->
xcr
),
ssc_readx
(
params
->
ssc
->
regs
,
params
->
pdc
->
xnpr
),
ssc_readx
(
params
->
ssc
->
regs
,
params
->
pdc
->
xncr
));
ssc_writex
(
params
->
ssc
->
regs
,
SSC_IER
,
params
->
mask
->
ssc_endx
|
params
->
mask
->
ssc_endbuf
);
ssc_writex
(
params
->
ssc
->
regs
,
SSC_PDC_PTCR
,
params
->
mask
->
pdc_enable
);
pr_debug
(
"sr=%u imr=%u
\n
"
,
ssc_readx
(
params
->
ssc
->
regs
,
SSC_SR
),
ssc_readx
(
params
->
ssc
->
regs
,
SSC_IER
));
break
;
/* SNDRV_PCM_TRIGGER_START */
case
SNDRV_PCM_TRIGGER_STOP
:
case
SNDRV_PCM_TRIGGER_SUSPEND
:
case
SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
ssc_writex
(
params
->
ssc
->
regs
,
ATMEL_PDC_PTCR
,
params
->
mask
->
pdc_disable
);
break
;
case
SNDRV_PCM_TRIGGER_RESUME
:
case
SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
ssc_writex
(
params
->
ssc
->
regs
,
ATMEL_PDC_PTCR
,
params
->
mask
->
pdc_enable
);
break
;
default:
ret
=
-
EINVAL
;
}
return
ret
;
}
static
snd_pcm_uframes_t
atmel_pcm_pointer
(
struct
snd_pcm_substream
*
substream
)
{
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
struct
atmel_runtime_data
*
prtd
=
runtime
->
private_data
;
struct
atmel_pcm_dma_params
*
params
=
prtd
->
params
;
dma_addr_t
ptr
;
snd_pcm_uframes_t
x
;
ptr
=
(
dma_addr_t
)
ssc_readx
(
params
->
ssc
->
regs
,
params
->
pdc
->
xpr
);
x
=
bytes_to_frames
(
runtime
,
ptr
-
prtd
->
dma_buffer
);
if
(
x
==
runtime
->
buffer_size
)
x
=
0
;
return
x
;
}
static
int
atmel_pcm_open
(
struct
snd_pcm_substream
*
substream
)
{
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
struct
atmel_runtime_data
*
prtd
;
int
ret
=
0
;
snd_soc_set_runtime_hwparams
(
substream
,
&
atmel_pcm_hardware
);
/* ensure that buffer size is a multiple of period size */
ret
=
snd_pcm_hw_constraint_integer
(
runtime
,
SNDRV_PCM_HW_PARAM_PERIODS
);
if
(
ret
<
0
)
goto
out
;
prtd
=
kzalloc
(
sizeof
(
struct
atmel_runtime_data
),
GFP_KERNEL
);
if
(
prtd
==
NULL
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
runtime
->
private_data
=
prtd
;
out:
return
ret
;
}
static
int
atmel_pcm_close
(
struct
snd_pcm_substream
*
substream
)
{
struct
atmel_runtime_data
*
prtd
=
substream
->
runtime
->
private_data
;
kfree
(
prtd
);
return
0
;
}
static
int
atmel_pcm_mmap
(
struct
snd_pcm_substream
*
substream
,
int
atmel_pcm_mmap
(
struct
snd_pcm_substream
*
substream
,
struct
vm_area_struct
*
vma
)
{
return
remap_pfn_range
(
vma
,
vma
->
vm_start
,
substream
->
dma_buffer
.
addr
>>
PAGE_SHIFT
,
vma
->
vm_end
-
vma
->
vm_start
,
vma
->
vm_page_prot
);
}
EXPORT_SYMBOL_GPL
(
atmel_pcm_mmap
);
static
struct
snd_pcm_ops
atmel_pcm_ops
=
{
.
open
=
atmel_pcm_open
,
.
close
=
atmel_pcm_close
,
.
ioctl
=
snd_pcm_lib_ioctl
,
.
hw_params
=
atmel_pcm_hw_params
,
.
hw_free
=
atmel_pcm_hw_free
,
.
prepare
=
atmel_pcm_prepare
,
.
trigger
=
atmel_pcm_trigger
,
.
pointer
=
atmel_pcm_pointer
,
.
mmap
=
atmel_pcm_mmap
,
};
/*--------------------------------------------------------------------------*\
* ASoC platform driver
\*--------------------------------------------------------------------------*/
static
u64
atmel_pcm_dmamask
=
DMA_BIT_MASK
(
32
);
static
int
atmel_pcm_new
(
struct
snd_soc_pcm_runtime
*
rtd
)
int
atmel_pcm_new
(
struct
snd_soc_pcm_runtime
*
rtd
)
{
struct
snd_card
*
card
=
rtd
->
card
->
snd_card
;
struct
snd_pcm
*
pcm
=
rtd
->
pcm
;
...
...
@@ -376,6 +82,7 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
card
->
dev
->
coherent_dma_mask
=
DMA_BIT_MASK
(
32
);
if
(
pcm
->
streams
[
SNDRV_PCM_STREAM_PLAYBACK
].
substream
)
{
pr_debug
(
"atmel-pcm: allocating PCM playback DMA buffer
\n
"
);
ret
=
atmel_pcm_preallocate_dma_buffer
(
pcm
,
SNDRV_PCM_STREAM_PLAYBACK
);
if
(
ret
)
...
...
@@ -383,8 +90,7 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
}
if
(
pcm
->
streams
[
SNDRV_PCM_STREAM_CAPTURE
].
substream
)
{
pr_debug
(
"atmel-pcm:"
"Allocating PCM capture DMA buffer
\n
"
);
pr_debug
(
"atmel-pcm: allocating PCM capture DMA buffer
\n
"
);
ret
=
atmel_pcm_preallocate_dma_buffer
(
pcm
,
SNDRV_PCM_STREAM_CAPTURE
);
if
(
ret
)
...
...
@@ -393,8 +99,9 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
out:
return
ret
;
}
EXPORT_SYMBOL_GPL
(
atmel_pcm_new
);
static
void
atmel_pcm_free_dma_buffers
(
struct
snd_pcm
*
pcm
)
void
atmel_pcm_free
(
struct
snd_pcm
*
pcm
)
{
struct
snd_pcm_substream
*
substream
;
struct
snd_dma_buffer
*
buf
;
...
...
@@ -413,89 +120,5 @@ static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm)
buf
->
area
=
NULL
;
}
}
EXPORT_SYMBOL_GPL
(
atmel_pcm_free
);
#ifdef CONFIG_PM
static
int
atmel_pcm_suspend
(
struct
snd_soc_dai
*
dai
)
{
struct
snd_pcm_runtime
*
runtime
=
dai
->
runtime
;
struct
atmel_runtime_data
*
prtd
;
struct
atmel_pcm_dma_params
*
params
;
if
(
!
runtime
)
return
0
;
prtd
=
runtime
->
private_data
;
params
=
prtd
->
params
;
/* disable the PDC and save the PDC registers */
ssc_writel
(
params
->
ssc
->
regs
,
PDC_PTCR
,
params
->
mask
->
pdc_disable
);
prtd
->
pdc_xpr_save
=
ssc_readx
(
params
->
ssc
->
regs
,
params
->
pdc
->
xpr
);
prtd
->
pdc_xcr_save
=
ssc_readx
(
params
->
ssc
->
regs
,
params
->
pdc
->
xcr
);
prtd
->
pdc_xnpr_save
=
ssc_readx
(
params
->
ssc
->
regs
,
params
->
pdc
->
xnpr
);
prtd
->
pdc_xncr_save
=
ssc_readx
(
params
->
ssc
->
regs
,
params
->
pdc
->
xncr
);
return
0
;
}
static
int
atmel_pcm_resume
(
struct
snd_soc_dai
*
dai
)
{
struct
snd_pcm_runtime
*
runtime
=
dai
->
runtime
;
struct
atmel_runtime_data
*
prtd
;
struct
atmel_pcm_dma_params
*
params
;
if
(
!
runtime
)
return
0
;
prtd
=
runtime
->
private_data
;
params
=
prtd
->
params
;
/* restore the PDC registers and enable the PDC */
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xpr
,
prtd
->
pdc_xpr_save
);
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xcr
,
prtd
->
pdc_xcr_save
);
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xnpr
,
prtd
->
pdc_xnpr_save
);
ssc_writex
(
params
->
ssc
->
regs
,
params
->
pdc
->
xncr
,
prtd
->
pdc_xncr_save
);
ssc_writel
(
params
->
ssc
->
regs
,
PDC_PTCR
,
params
->
mask
->
pdc_enable
);
return
0
;
}
#else
#define atmel_pcm_suspend NULL
#define atmel_pcm_resume NULL
#endif
static
struct
snd_soc_platform_driver
atmel_soc_platform
=
{
.
ops
=
&
atmel_pcm_ops
,
.
pcm_new
=
atmel_pcm_new
,
.
pcm_free
=
atmel_pcm_free_dma_buffers
,
.
suspend
=
atmel_pcm_suspend
,
.
resume
=
atmel_pcm_resume
,
};
static
int
__devinit
atmel_soc_platform_probe
(
struct
platform_device
*
pdev
)
{
return
snd_soc_register_platform
(
&
pdev
->
dev
,
&
atmel_soc_platform
);
}
static
int
__devexit
atmel_soc_platform_remove
(
struct
platform_device
*
pdev
)
{
snd_soc_unregister_platform
(
&
pdev
->
dev
);
return
0
;
}
static
struct
platform_driver
atmel_pcm_driver
=
{
.
driver
=
{
.
name
=
"atmel-pcm-audio"
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
atmel_soc_platform_probe
,
.
remove
=
__devexit_p
(
atmel_soc_platform_remove
),
};
module_platform_driver
(
atmel_pcm_driver
);
MODULE_AUTHOR
(
"Sedji Gaouaou <sedji.gaouaou@atmel.com>"
);
MODULE_DESCRIPTION
(
"Atmel PCM module"
);
MODULE_LICENSE
(
"GPL"
);
sound/soc/atmel/atmel-pcm.h
浏览文件 @
93ac820d
...
...
@@ -36,6 +36,8 @@
#include <linux/atmel-ssc.h>
#define ATMEL_SSC_DMABUF_SIZE (64 * 1024)
/*
* Registers and status bits that are required by the PCM driver.
*/
...
...
@@ -50,6 +52,7 @@ struct atmel_pdc_regs {
struct
atmel_ssc_mask
{
u32
ssc_enable
;
/* SSC recv/trans enable */
u32
ssc_disable
;
/* SSC recv/trans disable */
u32
ssc_error
;
/* SSC error conditions */
u32
ssc_endx
;
/* SSC ENDTX or ENDRX */
u32
ssc_endbuf
;
/* SSC TXBUFE or RXBUFF */
u32
pdc_enable
;
/* PDC recv/trans enable */
...
...
@@ -80,4 +83,35 @@ struct atmel_pcm_dma_params {
#define ssc_readx(base, reg) (__raw_readl((base) + (reg)))
#define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg))
int
atmel_pcm_new
(
struct
snd_soc_pcm_runtime
*
rtd
);
void
atmel_pcm_free
(
struct
snd_pcm
*
pcm
);
int
atmel_pcm_mmap
(
struct
snd_pcm_substream
*
substream
,
struct
vm_area_struct
*
vma
);
#ifdef CONFIG_SND_ATMEL_SOC_PDC
int
atmel_pcm_pdc_platform_register
(
struct
device
*
dev
);
void
atmel_pcm_pdc_platform_unregister
(
struct
device
*
dev
);
#else
static
inline
int
atmel_pcm_pdc_platform_register
(
struct
device
*
dev
)
{
return
0
;
}
static
inline
void
atmel_pcm_pdc_platform_unregister
(
struct
device
*
dev
)
{
}
#endif
#ifdef CONFIG_SND_ATMEL_SOC_DMA
int
atmel_pcm_dma_platform_register
(
struct
device
*
dev
);
void
atmel_pcm_dma_platform_unregister
(
struct
device
*
dev
);
#else
static
inline
int
atmel_pcm_dma_platform_register
(
struct
device
*
dev
)
{
return
0
;
}
static
inline
void
atmel_pcm_dma_platform_unregister
(
struct
device
*
dev
)
{
}
#endif
#endif
/* _ATMEL_PCM_H */
sound/soc/atmel/atmel_ssc_dai.c
浏览文件 @
93ac820d
...
...
@@ -48,11 +48,7 @@
#include "atmel_ssc_dai.h"
#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20)
#define NUM_SSC_DEVICES 1
#else
#define NUM_SSC_DEVICES 3
#endif
/*
* SSC PDC registers required by the PCM DMA engine.
...
...
@@ -107,7 +103,6 @@ static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
.
pdc
=
&
pdc_rx_reg
,
.
mask
=
&
ssc_rx_mask
,
}
},
#if NUM_SSC_DEVICES == 3
{{
.
name
=
"SSC1 PCM out"
,
.
pdc
=
&
pdc_tx_reg
,
...
...
@@ -128,7 +123,6 @@ static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
.
pdc
=
&
pdc_rx_reg
,
.
mask
=
&
ssc_rx_mask
,
}
},
#endif
};
...
...
@@ -139,7 +133,6 @@ static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = {
.
dir_mask
=
SSC_DIR_MASK_UNUSED
,
.
initialized
=
0
,
},
#if NUM_SSC_DEVICES == 3
{
.
name
=
"ssc1"
,
.
lock
=
__SPIN_LOCK_UNLOCKED
(
ssc_info
[
1
].
lock
),
...
...
@@ -152,7 +145,6 @@ static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = {
.
dir_mask
=
SSC_DIR_MASK_UNUSED
,
.
initialized
=
0
,
},
#endif
};
...
...
@@ -690,27 +682,9 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
static
int
atmel_ssc_probe
(
struct
snd_soc_dai
*
dai
)
{
struct
atmel_ssc_info
*
ssc_p
=
&
ssc_info
[
dai
->
id
];
int
ret
=
0
;
snd_soc_dai_set_drvdata
(
dai
,
ssc_p
);
/*
* Request SSC device
*/
ssc_p
->
ssc
=
ssc_request
(
dai
->
id
);
if
(
IS_ERR
(
ssc_p
->
ssc
))
{
printk
(
KERN_ERR
"ASoC: Failed to request SSC %d
\n
"
,
dai
->
id
);
ret
=
PTR_ERR
(
ssc_p
->
ssc
);
}
return
ret
;
}
static
int
atmel_ssc_remove
(
struct
snd_soc_dai
*
dai
)
{
struct
atmel_ssc_info
*
ssc_p
=
snd_soc_dai_get_drvdata
(
dai
);
ssc_free
(
ssc_p
->
ssc
);
return
0
;
}
...
...
@@ -728,30 +702,8 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = {
.
set_clkdiv
=
atmel_ssc_set_dai_clkdiv
,
};
static
struct
snd_soc_dai_driver
atmel_ssc_dai
[
NUM_SSC_DEVICES
]
=
{
{
.
name
=
"atmel-ssc-dai.0"
,
.
probe
=
atmel_ssc_probe
,
.
remove
=
atmel_ssc_remove
,
.
suspend
=
atmel_ssc_suspend
,
.
resume
=
atmel_ssc_resume
,
.
playback
=
{
.
channels_min
=
1
,
.
channels_max
=
2
,
.
rates
=
ATMEL_SSC_RATES
,
.
formats
=
ATMEL_SSC_FORMATS
,},
.
capture
=
{
.
channels_min
=
1
,
.
channels_max
=
2
,
.
rates
=
ATMEL_SSC_RATES
,
.
formats
=
ATMEL_SSC_FORMATS
,},
.
ops
=
&
atmel_ssc_dai_ops
,
},
#if NUM_SSC_DEVICES == 3
{
.
name
=
"atmel-ssc-dai.1"
,
static
struct
snd_soc_dai_driver
atmel_ssc_dai
=
{
.
probe
=
atmel_ssc_probe
,
.
remove
=
atmel_ssc_remove
,
.
suspend
=
atmel_ssc_suspend
,
.
resume
=
atmel_ssc_resume
,
.
playback
=
{
...
...
@@ -765,50 +717,50 @@ static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = {
.
rates
=
ATMEL_SSC_RATES
,
.
formats
=
ATMEL_SSC_FORMATS
,},
.
ops
=
&
atmel_ssc_dai_ops
,
},
{
.
name
=
"atmel-ssc-dai.2"
,
.
probe
=
atmel_ssc_probe
,
.
remove
=
atmel_ssc_remove
,
.
suspend
=
atmel_ssc_suspend
,
.
resume
=
atmel_ssc_resume
,
.
playback
=
{
.
channels_min
=
1
,
.
channels_max
=
2
,
.
rates
=
ATMEL_SSC_RATES
,
.
formats
=
ATMEL_SSC_FORMATS
,},
.
capture
=
{
.
channels_min
=
1
,
.
channels_max
=
2
,
.
rates
=
ATMEL_SSC_RATES
,
.
formats
=
ATMEL_SSC_FORMATS
,},
.
ops
=
&
atmel_ssc_dai_ops
,
},
#endif
};
static
__devinit
int
asoc_ssc_probe
(
struct
platform_device
*
p
dev
)
static
int
asoc_ssc_init
(
struct
device
*
dev
)
{
BUG_ON
(
pdev
->
id
<
0
);
BUG_ON
(
pdev
->
id
>=
ARRAY_SIZE
(
atmel_ssc_dai
));
return
snd_soc_register_dai
(
&
pdev
->
dev
,
&
atmel_ssc_dai
[
pdev
->
id
]);
}
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
ssc_device
*
ssc
=
platform_get_drvdata
(
pdev
);
int
ret
;
ret
=
snd_soc_register_dai
(
dev
,
&
atmel_ssc_dai
);
if
(
ret
)
{
dev_err
(
dev
,
"Could not register DAI: %d
\n
"
,
ret
);
goto
err
;
}
if
(
ssc
->
pdata
->
use_dma
)
ret
=
atmel_pcm_dma_platform_register
(
dev
);
else
ret
=
atmel_pcm_pdc_platform_register
(
dev
);
if
(
ret
)
{
dev_err
(
dev
,
"Could not register PCM: %d
\n
"
,
ret
);
goto
err_unregister_dai
;
};
static
int
__devexit
asoc_ssc_remove
(
struct
platform_device
*
pdev
)
{
snd_soc_unregister_dai
(
&
pdev
->
dev
);
return
0
;
err_unregister_dai:
snd_soc_unregister_dai
(
dev
);
err:
return
ret
;
}
static
struct
platform_driver
asoc_ssc_driver
=
{
.
driver
=
{
.
name
=
"atmel-ssc-dai"
,
.
owner
=
THIS_MODULE
,
},
static
void
asoc_ssc_exit
(
struct
device
*
dev
)
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
ssc_device
*
ssc
=
platform_get_drvdata
(
pdev
);
.
probe
=
asoc_ssc_probe
,
.
remove
=
__devexit_p
(
asoc_ssc_remove
),
};
if
(
ssc
->
pdata
->
use_dma
)
atmel_pcm_dma_platform_unregister
(
dev
);
else
atmel_pcm_pdc_platform_unregister
(
dev
);
snd_soc_unregister_dai
(
dev
);
}
/**
* atmel_ssc_set_audio - Allocate the specified SSC for audio use.
...
...
@@ -816,50 +768,32 @@ static struct platform_driver asoc_ssc_driver = {
int
atmel_ssc_set_audio
(
int
ssc_id
)
{
struct
ssc_device
*
ssc
;
static
struct
platform_device
*
dma_pdev
;
struct
platform_device
*
ssc_pdev
;
int
ret
;
if
(
ssc_id
<
0
||
ssc_id
>=
ARRAY_SIZE
(
atmel_ssc_dai
))
return
-
EINVAL
;
/* Allocate a dummy device for DMA if we don't have one already */
if
(
!
dma_pdev
)
{
dma_pdev
=
platform_device_alloc
(
"atmel-pcm-audio"
,
-
1
);
if
(
!
dma_pdev
)
return
-
ENOMEM
;
ret
=
platform_device_add
(
dma_pdev
);
if
(
ret
<
0
)
{
platform_device_put
(
dma_pdev
);
dma_pdev
=
NULL
;
return
ret
;
}
}
ssc_pdev
=
platform_device_alloc
(
"atmel-ssc-dai"
,
ssc_id
);
if
(
!
ssc_pdev
)
return
-
ENOMEM
;
/* If we can grab the SSC briefly to parent the DAI device off it */
ssc
=
ssc_request
(
ssc_id
);
if
(
IS_ERR
(
ssc
))
pr_
warn
(
"Unable to parent ASoC SSC DAI on SSC: %ld
\n
"
,
if
(
IS_ERR
(
ssc
))
{
pr_
err
(
"Unable to parent ASoC SSC DAI on SSC: %ld
\n
"
,
PTR_ERR
(
ssc
));
else
{
ssc_pdev
->
dev
.
parent
=
&
(
ssc
->
pdev
->
dev
);
ssc_
free
(
ssc
)
;
return
PTR_ERR
(
ssc
);
}
else
{
ssc_
info
[
ssc_id
].
ssc
=
ssc
;
}
ret
=
platform_device_add
(
ssc_pdev
);
if
(
ret
<
0
)
platform_device_put
(
ssc_pdev
);
ret
=
asoc_ssc_init
(
&
ssc
->
pdev
->
dev
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
atmel_ssc_set_audio
);
module_platform_driver
(
asoc_ssc_driver
);
void
atmel_ssc_put_audio
(
int
ssc_id
)
{
struct
ssc_device
*
ssc
=
ssc_info
[
ssc_id
].
ssc
;
ssc_free
(
ssc
);
asoc_ssc_exit
(
&
ssc
->
pdev
->
dev
);
}
EXPORT_SYMBOL_GPL
(
atmel_ssc_put_audio
);
/* Module information */
MODULE_AUTHOR
(
"Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com"
);
...
...
sound/soc/atmel/atmel_ssc_dai.h
浏览文件 @
93ac820d
...
...
@@ -117,6 +117,7 @@ struct atmel_ssc_info {
struct
atmel_ssc_state
ssc_state
;
};
int
atmel_ssc_set_audio
(
int
ssc
);
int
atmel_ssc_set_audio
(
int
ssc_id
);
void
atmel_ssc_put_audio
(
int
ssc_id
);
#endif
/* _AT91_SSC_DAI_H */
sound/soc/atmel/sam9g20_wm8731.c
浏览文件 @
93ac820d
...
...
@@ -38,6 +38,8 @@
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/pinctrl/consumer.h>
#include <linux/atmel-ssc.h>
#include <sound/core.h>
...
...
@@ -179,10 +181,10 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
static
struct
snd_soc_dai_link
at91sam9g20ek_dai
=
{
.
name
=
"WM8731"
,
.
stream_name
=
"WM8731 PCM"
,
.
cpu_dai_name
=
"at
mel-ssc-dai
.0"
,
.
cpu_dai_name
=
"at
91rm9200_ssc
.0"
,
.
codec_dai_name
=
"wm8731-hifi"
,
.
init
=
at91sam9g20ek_wm8731_init
,
.
platform_name
=
"at
mel-pcm-audio
"
,
.
platform_name
=
"at
91rm9200_ssc.0
"
,
.
codec_name
=
"wm8731.0-001b"
,
.
ops
=
&
at91sam9g20ek_ops
,
};
...
...
@@ -195,20 +197,31 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = {
.
set_bias_level
=
at91sam9g20ek_set_bias_level
,
};
static
struct
platform_device
*
at91sam9g20ek_snd_device
;
static
int
__init
at91sam9g20ek_init
(
void
)
static
int
__devinit
at91sam9g20ek_audio_probe
(
struct
platform_device
*
pdev
)
{
struct
device_node
*
np
=
pdev
->
dev
.
of_node
;
struct
device_node
*
codec_np
,
*
cpu_np
;
struct
clk
*
pllb
;
struct
snd_soc_card
*
card
=
&
snd_soc_at91sam9g20ek
;
struct
pinctrl
*
pinctrl
;
int
ret
;
if
(
!
(
machine_is_at91sam9g20ek
()
||
machine_is_at91sam9g20ek_2mmc
()))
return
-
ENODEV
;
pinctrl
=
devm_pinctrl_get_select_default
(
&
pdev
->
dev
);
if
(
IS_ERR
(
pinctrl
))
{
dev_err
(
&
pdev
->
dev
,
"Failed to request pinctrl for mck
\n
"
);
return
PTR_ERR
(
pinctrl
);
}
if
(
!
np
)
{
if
(
!
(
machine_is_at91sam9g20ek
()
||
machine_is_at91sam9g20ek_2mmc
()))
return
-
ENODEV
;
}
ret
=
atmel_ssc_set_audio
(
0
);
if
(
ret
!=
0
)
{
pr_err
(
"Failed to set SSC 0 for audio: %d
\n
"
,
ret
);
return
ret
;
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"ssc channel is not valid
\n
"
);
return
-
EINVAL
;
}
/*
...
...
@@ -236,45 +249,92 @@ static int __init at91sam9g20ek_init(void)
clk_set_rate
(
mclk
,
MCLK_RATE
);
at91sam9g20ek_snd_device
=
platform_device_alloc
(
"soc-audio"
,
-
1
);
if
(
!
at91sam9g20ek_snd_device
)
{
printk
(
KERN_ERR
"ASoC: Platform device allocation failed
\n
"
);
ret
=
-
ENOMEM
;
goto
err_mclk
;
card
->
dev
=
&
pdev
->
dev
;
/* Parse device node info */
if
(
np
)
{
ret
=
snd_soc_of_parse_card_name
(
card
,
"atmel,model"
);
if
(
ret
)
goto
err
;
ret
=
snd_soc_of_parse_audio_routing
(
card
,
"atmel,audio-routing"
);
if
(
ret
)
goto
err
;
/* Parse codec info */
at91sam9g20ek_dai
.
codec_name
=
NULL
;
codec_np
=
of_parse_phandle
(
np
,
"atmel,audio-codec"
,
0
);
if
(
!
codec_np
)
{
dev_err
(
&
pdev
->
dev
,
"codec info missing
\n
"
);
return
-
EINVAL
;
}
at91sam9g20ek_dai
.
codec_of_node
=
codec_np
;
/* Parse dai and platform info */
at91sam9g20ek_dai
.
cpu_dai_name
=
NULL
;
at91sam9g20ek_dai
.
platform_name
=
NULL
;
cpu_np
=
of_parse_phandle
(
np
,
"atmel,ssc-controller"
,
0
);
if
(
!
cpu_np
)
{
dev_err
(
&
pdev
->
dev
,
"dai and pcm info missing
\n
"
);
return
-
EINVAL
;
}
at91sam9g20ek_dai
.
cpu_of_node
=
cpu_np
;
at91sam9g20ek_dai
.
platform_of_node
=
cpu_np
;
of_node_put
(
codec_np
);
of_node_put
(
cpu_np
);
}
platform_set_drvdata
(
at91sam9g20ek_snd_device
,
&
snd_soc_at91sam9g20ek
);
ret
=
platform_device_add
(
at91sam9g20ek_snd_device
);
ret
=
snd_soc_register_card
(
card
);
if
(
ret
)
{
printk
(
KERN_ERR
"ASoC: Platform device allocation failed
\n
"
);
goto
err_device_add
;
printk
(
KERN_ERR
"ASoC: snd_soc_register_card() failed
\n
"
);
}
return
ret
;
err_device_add:
platform_device_put
(
at91sam9g20ek_snd_device
);
err_mclk:
clk_put
(
mclk
);
mclk
=
NULL
;
err:
atmel_ssc_put_audio
(
0
);
return
ret
;
}
static
void
__exit
at91sam9g20ek_exit
(
void
)
static
int
__devexit
at91sam9g20ek_audio_remove
(
struct
platform_device
*
pdev
)
{
platform_device_unregister
(
at91sam9g20ek_snd_device
);
at91sam9g20ek_snd_device
=
NULL
;
struct
snd_soc_card
*
card
=
platform_get_drvdata
(
pdev
);
atmel_ssc_put_audio
(
0
);
snd_soc_unregister_card
(
card
);
clk_put
(
mclk
);
mclk
=
NULL
;
return
0
;
}
module_init
(
at91sam9g20ek_init
);
module_exit
(
at91sam9g20ek_exit
);
#ifdef CONFIG_OF
static
const
struct
of_device_id
at91sam9g20ek_wm8731_dt_ids
[]
=
{
{
.
compatible
=
"atmel,at91sam9g20ek-wm8731-audio"
,
},
{
}
};
MODULE_DEVICE_TABLE
(
of
,
at91sam9g20ek_wm8731_dt_ids
);
#endif
static
struct
platform_driver
at91sam9g20ek_audio_driver
=
{
.
driver
=
{
.
name
=
"at91sam9g20ek-audio"
,
.
owner
=
THIS_MODULE
,
.
of_match_table
=
of_match_ptr
(
at91sam9g20ek_wm8731_dt_ids
),
},
.
probe
=
at91sam9g20ek_audio_probe
,
.
remove
=
__devexit_p
(
at91sam9g20ek_audio_remove
),
};
module_platform_driver
(
at91sam9g20ek_audio_driver
);
/* Module information */
MODULE_AUTHOR
(
"Sedji Gaouaou <sedji.gaouaou@atmel.com>"
);
MODULE_DESCRIPTION
(
"ALSA SoC AT91SAM9G20EK_WM8731"
);
MODULE_ALIAS
(
"platform:at91sam9g20ek-audio"
);
MODULE_LICENSE
(
"GPL"
);
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录