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 @@
...
@@ -29,6 +29,7 @@
tcb0
=
&
tcb0
;
tcb0
=
&
tcb0
;
tcb1
=
&
tcb1
;
tcb1
=
&
tcb1
;
i2c0
=
&
i2c0
;
i2c0
=
&
i2c0
;
ssc0
=
&
ssc0
;
};
};
cpus
{
cpus
{
cpu
@
0
{
cpu
@
0
{
...
@@ -212,6 +213,13 @@
...
@@ -212,6 +213,13 @@
status
=
"disabled"
;
status
=
"disabled"
;
};
};
ssc0
:
ssc
@
fffbc000
{
compatible
=
"atmel,at91rm9200-ssc"
;
reg
=
<
0xfffbc000
0x4000
>;
interrupts
=
<
14
4
5
>;
status
=
"disable"
;
};
adc0
:
adc
@
fffe0000
{
adc0
:
adc
@
fffe0000
{
compatible
=
"atmel,at91sam9260-adc"
;
compatible
=
"atmel,at91sam9260-adc"
;
reg
=
<
0xfffe0000
0x100
>;
reg
=
<
0xfffe0000
0x100
>;
...
...
arch/arm/boot/dts/at91sam9263.dtsi
浏览文件 @
93ac820d
...
@@ -25,6 +25,8 @@
...
@@ -25,6 +25,8 @@
gpio4
=
&
pioE
;
gpio4
=
&
pioE
;
tcb0
=
&
tcb0
;
tcb0
=
&
tcb0
;
i2c0
=
&
i2c0
;
i2c0
=
&
i2c0
;
ssc0
=
&
ssc0
;
ssc1
=
&
ssc1
;
};
};
cpus
{
cpus
{
cpu
@
0
{
cpu
@
0
{
...
@@ -173,6 +175,20 @@
...
@@ -173,6 +175,20 @@
status
=
"disabled"
;
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
{
macb0
:
ethernet
@
fffbc000
{
compatible
=
"cdns,at32ap7000-macb"
,
"cdns,macb"
;
compatible
=
"cdns,at32ap7000-macb"
,
"cdns,macb"
;
reg
=
<
0xfffbc000
0x100
>;
reg
=
<
0xfffbc000
0x100
>;
...
...
arch/arm/boot/dts/at91sam9g20ek_common.dtsi
浏览文件 @
93ac820d
...
@@ -30,6 +30,16 @@
...
@@ -30,6 +30,16 @@
ahb {
ahb {
apb {
apb {
pinctrl@fffff400 {
board {
pinctrl_pck0_as_mck: pck0_as_mck {
atmel,pins =
<2 1 0x2 0x0>; /* PC1 periph B */
};
};
};
dbgu: serial@fffff200 {
dbgu: serial@fffff200 {
status = "okay";
status = "okay";
};
};
...
@@ -51,6 +61,11 @@
...
@@ -51,6 +61,11 @@
atmel,vbus-gpio = <&pioC 5 0>;
atmel,vbus-gpio = <&pioC 5 0>;
status = "okay";
status = "okay";
};
};
ssc0: ssc@fffbc000 {
status = "okay";
pinctrl-0 = <&pinctrl_ssc0_tx>;
};
};
};
nand0: nand@40000000 {
nand0: nand@40000000 {
...
@@ -114,7 +129,7 @@
...
@@ -114,7 +129,7 @@
reg = <0x50>;
reg = <0x50>;
};
};
wm8731@1b {
wm8731
: wm8731
@1b {
compatible = "wm8731";
compatible = "wm8731";
reg = <0x1b>;
reg = <0x1b>;
};
};
...
@@ -139,4 +154,19 @@
...
@@ -139,4 +154,19 @@
gpio-key,wakeup;
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 @@
...
@@ -31,6 +31,8 @@
tcb1
=
&
tcb1
;
tcb1
=
&
tcb1
;
i2c0
=
&
i2c0
;
i2c0
=
&
i2c0
;
i2c1
=
&
i2c1
;
i2c1
=
&
i2c1
;
ssc0
=
&
ssc0
;
ssc1
=
&
ssc1
;
};
};
cpus
{
cpus
{
cpu
@
0
{
cpu
@
0
{
...
@@ -226,6 +228,20 @@
...
@@ -226,6 +228,20 @@
status
=
"disabled"
;
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
{
adc0
:
adc
@
fffb0000
{
compatible
=
"atmel,at91sam9260-adc"
;
compatible
=
"atmel,at91sam9260-adc"
;
reg
=
<
0xfffb0000
0x100
>;
reg
=
<
0xfffb0000
0x100
>;
...
...
arch/arm/boot/dts/at91sam9x5.dtsi
浏览文件 @
93ac820d
...
@@ -30,6 +30,7 @@
...
@@ -30,6 +30,7 @@
i2c0
=
&
i2c0
;
i2c0
=
&
i2c0
;
i2c1
=
&
i2c1
;
i2c1
=
&
i2c1
;
i2c2
=
&
i2c2
;
i2c2
=
&
i2c2
;
ssc0
=
&
ssc0
;
};
};
cpus
{
cpus
{
cpu
@
0
{
cpu
@
0
{
...
@@ -87,6 +88,13 @@
...
@@ -87,6 +88,13 @@
interrupts
=
<
1
4
7
>;
interrupts
=
<
1
4
7
>;
};
};
ssc0
:
ssc
@
f0010000
{
compatible
=
"atmel,at91sam9g45-ssc"
;
reg
=
<
0xf0010000
0x4000
>;
interrupts
=
<
28
4
5
>;
status
=
"disable"
;
};
tcb0
:
timer
@
f8008000
{
tcb0
:
timer
@
f8008000
{
compatible
=
"atmel,at91sam9x5-tcb"
;
compatible
=
"atmel,at91sam9x5-tcb"
;
reg
=
<
0xf8008000
0x100
>;
reg
=
<
0xf8008000
0x100
>;
...
...
arch/arm/mach-at91/at91rm9200.c
浏览文件 @
93ac820d
...
@@ -184,9 +184,12 @@ static struct clk_lookup periph_clocks_lookups[] = {
...
@@ -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
(
"t0_clk"
,
"atmel_tcb.1"
,
&
tc3_clk
),
CLKDEV_CON_DEV_ID
(
"t1_clk"
,
"atmel_tcb.1"
,
&
tc4_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
(
"t2_clk"
,
"atmel_tcb.1"
,
&
tc5_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91rm9200_ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.1"
,
&
ssc1_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91rm9200_ssc.1"
,
&
ssc1_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.2"
,
&
ssc2_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
),
CLKDEV_CON_DEV_ID
(
NULL
,
"i2c-at91rm9200.0"
,
&
twi_clk
),
/* fake hclk clock */
/* fake hclk clock */
CLKDEV_CON_DEV_ID
(
"hclk"
,
"at91_ohci"
,
&
ohci_clk
),
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[] = {
...
@@ -752,7 +752,7 @@ static struct resource ssc0_resources[] = {
};
};
static
struct
platform_device
at91rm9200_ssc0_device
=
{
static
struct
platform_device
at91rm9200_ssc0_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
0
,
.
id
=
0
,
.
dev
=
{
.
dev
=
{
.
dma_mask
=
&
ssc0_dmamask
,
.
dma_mask
=
&
ssc0_dmamask
,
...
@@ -794,7 +794,7 @@ static struct resource ssc1_resources[] = {
...
@@ -794,7 +794,7 @@ static struct resource ssc1_resources[] = {
};
};
static
struct
platform_device
at91rm9200_ssc1_device
=
{
static
struct
platform_device
at91rm9200_ssc1_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
1
,
.
id
=
1
,
.
dev
=
{
.
dev
=
{
.
dma_mask
=
&
ssc1_dmamask
,
.
dma_mask
=
&
ssc1_dmamask
,
...
@@ -836,7 +836,7 @@ static struct resource ssc2_resources[] = {
...
@@ -836,7 +836,7 @@ static struct resource ssc2_resources[] = {
};
};
static
struct
platform_device
at91rm9200_ssc2_device
=
{
static
struct
platform_device
at91rm9200_ssc2_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
2
,
.
id
=
2
,
.
dev
=
{
.
dev
=
{
.
dma_mask
=
&
ssc2_dmamask
,
.
dma_mask
=
&
ssc2_dmamask
,
...
...
arch/arm/mach-at91/at91sam9260.c
浏览文件 @
93ac820d
...
@@ -210,7 +210,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
...
@@ -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
(
"t0_clk"
,
"atmel_tcb.1"
,
&
tc3_clk
),
CLKDEV_CON_DEV_ID
(
"t1_clk"
,
"atmel_tcb.1"
,
&
tc4_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
(
"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-at91sam9260.0"
,
&
twi_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"i2c-at91sam9g20.0"
,
&
twi_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"i2c-at91sam9g20.0"
,
&
twi_clk
),
/* more usart lookup table for DT entries */
/* more usart lookup table for DT entries */
...
...
arch/arm/mach-at91/at91sam9260_devices.c
浏览文件 @
93ac820d
...
@@ -742,7 +742,7 @@ static struct resource ssc_resources[] = {
...
@@ -742,7 +742,7 @@ static struct resource ssc_resources[] = {
};
};
static
struct
platform_device
at91sam9260_ssc_device
=
{
static
struct
platform_device
at91sam9260_ssc_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
0
,
.
id
=
0
,
.
dev
=
{
.
dev
=
{
.
dma_mask
=
&
ssc_dmamask
,
.
dma_mask
=
&
ssc_dmamask
,
...
...
arch/arm/mach-at91/at91sam9261.c
浏览文件 @
93ac820d
...
@@ -174,9 +174,12 @@ static struct clk_lookup periph_clocks_lookups[] = {
...
@@ -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
(
"t0_clk"
,
"atmel_tcb.0"
,
&
tc0_clk
),
CLKDEV_CON_DEV_ID
(
"t1_clk"
,
"atmel_tcb.0"
,
&
tc1_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
(
"t2_clk"
,
"atmel_tcb.0"
,
&
tc2_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91rm9200_ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.1"
,
&
ssc1_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91rm9200_ssc.1"
,
&
ssc1_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.2"
,
&
ssc2_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
(
"hclk"
,
"at91_ohci"
,
&
hck0
),
CLKDEV_CON_DEV_ID
(
NULL
,
"i2c-at91sam9261.0"
,
&
twi_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"i2c-at91sam9261.0"
,
&
twi_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"i2c-at91sam9g10.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[] = {
...
@@ -706,7 +706,7 @@ static struct resource ssc0_resources[] = {
};
};
static
struct
platform_device
at91sam9261_ssc0_device
=
{
static
struct
platform_device
at91sam9261_ssc0_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
0
,
.
id
=
0
,
.
dev
=
{
.
dev
=
{
.
dma_mask
=
&
ssc0_dmamask
,
.
dma_mask
=
&
ssc0_dmamask
,
...
@@ -748,7 +748,7 @@ static struct resource ssc1_resources[] = {
...
@@ -748,7 +748,7 @@ static struct resource ssc1_resources[] = {
};
};
static
struct
platform_device
at91sam9261_ssc1_device
=
{
static
struct
platform_device
at91sam9261_ssc1_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
1
,
.
id
=
1
,
.
dev
=
{
.
dev
=
{
.
dma_mask
=
&
ssc1_dmamask
,
.
dma_mask
=
&
ssc1_dmamask
,
...
@@ -790,7 +790,7 @@ static struct resource ssc2_resources[] = {
...
@@ -790,7 +790,7 @@ static struct resource ssc2_resources[] = {
};
};
static
struct
platform_device
at91sam9261_ssc2_device
=
{
static
struct
platform_device
at91sam9261_ssc2_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
2
,
.
id
=
2
,
.
dev
=
{
.
dev
=
{
.
dma_mask
=
&
ssc2_dmamask
,
.
dma_mask
=
&
ssc2_dmamask
,
...
...
arch/arm/mach-at91/at91sam9263.c
浏览文件 @
93ac820d
...
@@ -186,8 +186,10 @@ static struct clk *periph_clocks[] __initdata = {
...
@@ -186,8 +186,10 @@ static struct clk *periph_clocks[] __initdata = {
static
struct
clk_lookup
periph_clocks_lookups
[]
=
{
static
struct
clk_lookup
periph_clocks_lookups
[]
=
{
/* One additional fake clock for macb_hclk */
/* One additional fake clock for macb_hclk */
CLKDEV_CON_ID
(
"hclk"
,
&
macb_clk
),
CLKDEV_CON_ID
(
"hclk"
,
&
macb_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91rm9200_ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.1"
,
&
ssc1_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.0"
,
&
mmc0_clk
),
CLKDEV_CON_DEV_ID
(
"mci_clk"
,
"atmel_mci.1"
,
&
mmc1_clk
),
CLKDEV_CON_DEV_ID
(
"mci_clk"
,
"atmel_mci.1"
,
&
mmc1_clk
),
CLKDEV_CON_DEV_ID
(
"spi_clk"
,
"atmel_spi.0"
,
&
spi0_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[] = {
...
@@ -1199,7 +1199,7 @@ static struct resource ssc0_resources[] = {
};
};
static
struct
platform_device
at91sam9263_ssc0_device
=
{
static
struct
platform_device
at91sam9263_ssc0_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
0
,
.
id
=
0
,
.
dev
=
{
.
dev
=
{
.
dma_mask
=
&
ssc0_dmamask
,
.
dma_mask
=
&
ssc0_dmamask
,
...
@@ -1241,7 +1241,7 @@ static struct resource ssc1_resources[] = {
...
@@ -1241,7 +1241,7 @@ static struct resource ssc1_resources[] = {
};
};
static
struct
platform_device
at91sam9263_ssc1_device
=
{
static
struct
platform_device
at91sam9263_ssc1_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
1
,
.
id
=
1
,
.
dev
=
{
.
dev
=
{
.
dma_mask
=
&
ssc1_dmamask
,
.
dma_mask
=
&
ssc1_dmamask
,
...
...
arch/arm/mach-at91/at91sam9g45.c
浏览文件 @
93ac820d
...
@@ -239,8 +239,10 @@ static struct clk_lookup periph_clocks_lookups[] = {
...
@@ -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
(
"t0_clk"
,
"atmel_tcb.1"
,
&
tcb0_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"i2c-at91sam9g10.0"
,
&
twi0_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
(
NULL
,
"i2c-at91sam9g10.1"
,
&
twi1_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91sam9g45_ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.1"
,
&
ssc1_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-trng"
,
&
trng_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"atmel_sha"
,
&
aestdessha_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"atmel_sha"
,
&
aestdessha_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"atmel_tdes"
,
&
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[] = {
...
@@ -1459,7 +1459,7 @@ static struct resource ssc0_resources[] = {
};
};
static
struct
platform_device
at91sam9g45_ssc0_device
=
{
static
struct
platform_device
at91sam9g45_ssc0_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91sam9g45_
ssc"
,
.
id
=
0
,
.
id
=
0
,
.
dev
=
{
.
dev
=
{
.
dma_mask
=
&
ssc0_dmamask
,
.
dma_mask
=
&
ssc0_dmamask
,
...
@@ -1501,7 +1501,7 @@ static struct resource ssc1_resources[] = {
...
@@ -1501,7 +1501,7 @@ static struct resource ssc1_resources[] = {
};
};
static
struct
platform_device
at91sam9g45_ssc1_device
=
{
static
struct
platform_device
at91sam9g45_ssc1_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91sam9g45_
ssc"
,
.
id
=
1
,
.
id
=
1
,
.
dev
=
{
.
dev
=
{
.
dma_mask
=
&
ssc1_dmamask
,
.
dma_mask
=
&
ssc1_dmamask
,
...
...
arch/arm/mach-at91/at91sam9rl.c
浏览文件 @
93ac820d
...
@@ -184,8 +184,10 @@ static struct clk_lookup periph_clocks_lookups[] = {
...
@@ -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
(
"t0_clk"
,
"atmel_tcb.0"
,
&
tc0_clk
),
CLKDEV_CON_DEV_ID
(
"t1_clk"
,
"atmel_tcb.0"
,
&
tc1_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
(
"t2_clk"
,
"atmel_tcb.0"
,
&
tc2_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"at91rm9200_ssc.0"
,
&
ssc0_clk
),
CLKDEV_CON_DEV_ID
(
"pclk"
,
"ssc.1"
,
&
ssc1_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.0"
,
&
twi0_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"i2c-at91sam9g20.1"
,
&
twi1_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"i2c-at91sam9g20.1"
,
&
twi1_clk
),
CLKDEV_CON_ID
(
"pioA"
,
&
pioA_clk
),
CLKDEV_CON_ID
(
"pioA"
,
&
pioA_clk
),
...
...
arch/arm/mach-at91/at91sam9rl_devices.c
浏览文件 @
93ac820d
...
@@ -832,7 +832,7 @@ static struct resource ssc0_resources[] = {
...
@@ -832,7 +832,7 @@ static struct resource ssc0_resources[] = {
};
};
static
struct
platform_device
at91sam9rl_ssc0_device
=
{
static
struct
platform_device
at91sam9rl_ssc0_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
0
,
.
id
=
0
,
.
dev
=
{
.
dev
=
{
.
dma_mask
=
&
ssc0_dmamask
,
.
dma_mask
=
&
ssc0_dmamask
,
...
@@ -874,7 +874,7 @@ static struct resource ssc1_resources[] = {
...
@@ -874,7 +874,7 @@ static struct resource ssc1_resources[] = {
};
};
static
struct
platform_device
at91sam9rl_ssc1_device
=
{
static
struct
platform_device
at91sam9rl_ssc1_device
=
{
.
name
=
"ssc"
,
.
name
=
"
at91rm9200_
ssc"
,
.
id
=
1
,
.
id
=
1
,
.
dev
=
{
.
dev
=
{
.
dma_mask
=
&
ssc1_dmamask
,
.
dma_mask
=
&
ssc1_dmamask
,
...
...
arch/arm/mach-at91/at91sam9x5.c
浏览文件 @
93ac820d
...
@@ -231,6 +231,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
...
@@ -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
(
"t0_clk"
,
"f800c000.timer"
,
&
tcb0_clk
),
CLKDEV_CON_DEV_ID
(
"dma_clk"
,
"ffffec00.dma-controller"
,
&
dma0_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
(
"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
,
"f8010000.i2c"
,
&
twi0_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"f8014000.i2c"
,
&
twi1_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"f8014000.i2c"
,
&
twi1_clk
),
CLKDEV_CON_DEV_ID
(
NULL
,
"f8018000.i2c"
,
&
twi2_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[] = {
...
@@ -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
)
static
void
__init
ek_board_init
(
void
)
{
{
...
@@ -394,6 +404,7 @@ 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
);
at91_set_B_periph
(
AT91_PIN_PC1
,
0
);
/* SSC (for WM8731) */
/* SSC (for WM8731) */
at91_add_device_ssc
(
AT91SAM9260_ID_SSC
,
ATMEL_SSC_TX
);
at91_add_device_ssc
(
AT91SAM9260_ID_SSC
,
ATMEL_SSC_TX
);
ek_add_device_audio
();
}
}
MACHINE_START
(
AT91SAM9G20EK
,
"Atmel AT91SAM9G20-EK"
)
MACHINE_START
(
AT91SAM9G20EK
,
"Atmel AT91SAM9G20-EK"
)
...
...
drivers/misc/atmel-ssc.c
浏览文件 @
93ac820d
...
@@ -18,6 +18,8 @@
...
@@ -18,6 +18,8 @@
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/of.h>
/* Serialize access to ssc_list and user count */
/* Serialize access to ssc_list and user count */
static
DEFINE_SPINLOCK
(
user_lock
);
static
DEFINE_SPINLOCK
(
user_lock
);
static
LIST_HEAD
(
ssc_list
);
static
LIST_HEAD
(
ssc_list
);
...
@@ -29,7 +31,13 @@ struct ssc_device *ssc_request(unsigned int ssc_num)
...
@@ -29,7 +31,13 @@ struct ssc_device *ssc_request(unsigned int ssc_num)
spin_lock
(
&
user_lock
);
spin_lock
(
&
user_lock
);
list_for_each_entry
(
ssc
,
&
ssc_list
,
list
)
{
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
;
ssc_valid
=
1
;
break
;
break
;
}
}
...
@@ -68,39 +76,93 @@ void ssc_free(struct ssc_device *ssc)
...
@@ -68,39 +76,93 @@ void ssc_free(struct ssc_device *ssc)
}
}
EXPORT_SYMBOL
(
ssc_free
);
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
resource
*
regs
;
struct
ssc_device
*
ssc
;
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
)
{
if
(
!
ssc
)
{
dev_dbg
(
&
pdev
->
dev
,
"out of memory
\n
"
);
dev_dbg
(
&
pdev
->
dev
,
"out of memory
\n
"
);
retval
=
-
ENOMEM
;
return
-
ENOMEM
;
goto
out
;
}
}
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
);
regs
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
if
(
!
regs
)
{
if
(
!
regs
)
{
dev_dbg
(
&
pdev
->
dev
,
"no mmio resource defined
\n
"
);
dev_dbg
(
&
pdev
->
dev
,
"no mmio resource defined
\n
"
);
retval
=
-
ENXIO
;
return
-
ENXIO
;
goto
out_free
;
}
}
ssc
->
clk
=
clk_get
(
&
pdev
->
dev
,
"pclk"
);
ssc
->
regs
=
devm_request_and_ioremap
(
&
pdev
->
dev
,
regs
);
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
));
if
(
!
ssc
->
regs
)
{
if
(
!
ssc
->
regs
)
{
dev_dbg
(
&
pdev
->
dev
,
"ioremap failed
\n
"
);
dev_dbg
(
&
pdev
->
dev
,
"ioremap failed
\n
"
);
retval
=
-
EINVAL
;
return
-
EINVAL
;
goto
out_clk
;
}
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 */
/* disable all interrupts */
...
@@ -112,8 +174,7 @@ static int __init ssc_probe(struct platform_device *pdev)
...
@@ -112,8 +174,7 @@ static int __init ssc_probe(struct platform_device *pdev)
ssc
->
irq
=
platform_get_irq
(
pdev
,
0
);
ssc
->
irq
=
platform_get_irq
(
pdev
,
0
);
if
(
!
ssc
->
irq
)
{
if
(
!
ssc
->
irq
)
{
dev_dbg
(
&
pdev
->
dev
,
"could not get irq
\n
"
);
dev_dbg
(
&
pdev
->
dev
,
"could not get irq
\n
"
);
retval
=
-
ENXIO
;
return
-
ENXIO
;
goto
out_unmap
;
}
}
spin_lock
(
&
user_lock
);
spin_lock
(
&
user_lock
);
...
@@ -125,16 +186,7 @@ static int __init ssc_probe(struct platform_device *pdev)
...
@@ -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
"
,
dev_info
(
&
pdev
->
dev
,
"Atmel SSC device at 0x%p (irq %d)
\n
"
,
ssc
->
regs
,
ssc
->
irq
);
ssc
->
regs
,
ssc
->
irq
);
goto
out
;
return
0
;
out_unmap:
iounmap
(
ssc
->
regs
);
out_clk:
clk_put
(
ssc
->
clk
);
out_free:
kfree
(
ssc
);
out:
return
retval
;
}
}
static
int
__devexit
ssc_remove
(
struct
platform_device
*
pdev
)
static
int
__devexit
ssc_remove
(
struct
platform_device
*
pdev
)
...
@@ -142,34 +194,23 @@ 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
);
struct
ssc_device
*
ssc
=
platform_get_drvdata
(
pdev
);
spin_lock
(
&
user_lock
);
spin_lock
(
&
user_lock
);
iounmap
(
ssc
->
regs
);
clk_put
(
ssc
->
clk
);
list_del
(
&
ssc
->
list
);
list_del
(
&
ssc
->
list
);
kfree
(
ssc
);
spin_unlock
(
&
user_lock
);
spin_unlock
(
&
user_lock
);
return
0
;
return
0
;
}
}
static
struct
platform_driver
ssc_driver
=
{
static
struct
platform_driver
ssc_driver
=
{
.
remove
=
__devexit_p
(
ssc_remove
),
.
driver
=
{
.
driver
=
{
.
name
=
"ssc"
,
.
name
=
"ssc"
,
.
owner
=
THIS_MODULE
,
.
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
),
};
};
module_platform_driver
(
ssc_driver
);
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_AUTHOR
(
"Hans-Christian Egtvedt <hcegtvedt@atmel.com>"
);
MODULE_AUTHOR
(
"Hans-Christian Egtvedt <hcegtvedt@atmel.com>"
);
MODULE_DESCRIPTION
(
"SSC driver for Atmel AVR32 and AT91"
);
MODULE_DESCRIPTION
(
"SSC driver for Atmel AVR32 and AT91"
);
...
...
include/linux/atmel-ssc.h
浏览文件 @
93ac820d
...
@@ -5,10 +5,16 @@
...
@@ -5,10 +5,16 @@
#include <linux/list.h>
#include <linux/list.h>
#include <linux/io.h>
#include <linux/io.h>
struct
atmel_ssc_platform_data
{
int
use_dma
;
};
struct
ssc_device
{
struct
ssc_device
{
struct
list_head
list
;
struct
list_head
list
;
resource_size_t
phybase
;
void
__iomem
*
regs
;
void
__iomem
*
regs
;
struct
platform_device
*
pdev
;
struct
platform_device
*
pdev
;
struct
atmel_ssc_platform_data
*
pdata
;
struct
clk
*
clk
;
struct
clk
*
clk
;
int
user
;
int
user
;
int
irq
;
int
irq
;
...
...
sound/soc/atmel/Kconfig
浏览文件 @
93ac820d
...
@@ -6,6 +6,14 @@ config SND_ATMEL_SOC
...
@@ -6,6 +6,14 @@ config SND_ATMEL_SOC
the ATMEL SSC interface. You will also need
the ATMEL SSC interface. You will also need
to select the audio interfaces to support below.
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
config SND_ATMEL_SOC_SSC
tristate
tristate
depends on SND_ATMEL_SOC
depends on SND_ATMEL_SOC
...
@@ -16,8 +24,8 @@ config SND_ATMEL_SOC_SSC
...
@@ -16,8 +24,8 @@ config SND_ATMEL_SOC_SSC
config SND_AT91_SOC_SAM9G20_WM8731
config SND_AT91_SOC_SAM9G20_WM8731
tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
depends on ATMEL_SSC &&
ARCH_AT91SAM9G20 && SND_ATMEL_SOC && \
depends on ATMEL_SSC &&
SND_ATMEL_SOC && AT91_PROGRAMMABLE_CLOCKS
AT91_PROGRAMMABLE_CLOCKS
select SND_ATMEL_SOC_PDC
select SND_ATMEL_SOC_SSC
select SND_ATMEL_SOC_SSC
select SND_SOC_WM8731
select SND_SOC_WM8731
help
help
...
@@ -27,6 +35,7 @@ config SND_AT91_SOC_SAM9G20_WM8731
...
@@ -27,6 +35,7 @@ config SND_AT91_SOC_SAM9G20_WM8731
config SND_AT91_SOC_AFEB9260
config SND_AT91_SOC_AFEB9260
tristate "SoC Audio support for AFEB9260 board"
tristate "SoC Audio support for AFEB9260 board"
depends on ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
depends on ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
select SND_ATMEL_SOC_PDC
select SND_ATMEL_SOC_SSC
select SND_ATMEL_SOC_SSC
select SND_SOC_TLV320AIC23
select SND_SOC_TLV320AIC23
help
help
...
...
sound/soc/atmel/Makefile
浏览文件 @
93ac820d
# AT91 Platform Support
# AT91 Platform Support
snd-soc-atmel-pcm-objs
:=
atmel-pcm.o
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
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)
+=
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
obj-$(CONFIG_SND_ATMEL_SOC_SSC)
+=
snd-soc-atmel_ssc_dai.o
# AT91 Machine Support
# 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 @@
...
@@ -32,80 +32,25 @@
*/
*/
#include <linux/module.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/dma-mapping.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.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc.h>
#include "atmel-pcm.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
,
static
int
atmel_pcm_preallocate_dma_buffer
(
struct
snd_pcm
*
pcm
,
int
stream
)
int
stream
)
{
{
struct
snd_pcm_substream
*
substream
=
pcm
->
streams
[
stream
].
substream
;
struct
snd_pcm_substream
*
substream
=
pcm
->
streams
[
stream
].
substream
;
struct
snd_dma_buffer
*
buf
=
&
substream
->
dma_buffer
;
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
.
type
=
SNDRV_DMA_TYPE_DEV
;
buf
->
dev
.
dev
=
pcm
->
card
->
dev
;
buf
->
dev
.
dev
=
pcm
->
card
->
dev
;
buf
->
private_data
=
NULL
;
buf
->
private_data
=
NULL
;
buf
->
area
=
dma_alloc_coherent
(
pcm
->
card
->
dev
,
size
,
buf
->
area
=
dma_alloc_coherent
(
pcm
->
card
->
dev
,
size
,
&
buf
->
addr
,
GFP_KERNEL
);
&
buf
->
addr
,
GFP_KERNEL
);
pr_debug
(
"atmel-pcm:"
pr_debug
(
"atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%d
\n
"
,
"preallocate_dma_buffer: area=%p, addr=%p, size=%d
\n
"
,
(
void
*
)
buf
->
area
,
(
void
*
)
buf
->
addr
,
size
);
(
void
*
)
buf
->
area
,
(
void
*
)
buf
->
addr
,
size
);
if
(
!
buf
->
area
)
if
(
!
buf
->
area
)
return
-
ENOMEM
;
return
-
ENOMEM
;
...
@@ -113,258 +58,19 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
...
@@ -113,258 +58,19 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
buf
->
bytes
=
size
;
buf
->
bytes
=
size
;
return
0
;
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
;
int
atmel_pcm_mmap
(
struct
snd_pcm_substream
*
substream
,
}
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
,
struct
vm_area_struct
*
vma
)
struct
vm_area_struct
*
vma
)
{
{
return
remap_pfn_range
(
vma
,
vma
->
vm_start
,
return
remap_pfn_range
(
vma
,
vma
->
vm_start
,
substream
->
dma_buffer
.
addr
>>
PAGE_SHIFT
,
substream
->
dma_buffer
.
addr
>>
PAGE_SHIFT
,
vma
->
vm_end
-
vma
->
vm_start
,
vma
->
vm_page_prot
);
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
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_card
*
card
=
rtd
->
card
->
snd_card
;
struct
snd_pcm
*
pcm
=
rtd
->
pcm
;
struct
snd_pcm
*
pcm
=
rtd
->
pcm
;
...
@@ -376,6 +82,7 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
...
@@ -376,6 +82,7 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
card
->
dev
->
coherent_dma_mask
=
DMA_BIT_MASK
(
32
);
card
->
dev
->
coherent_dma_mask
=
DMA_BIT_MASK
(
32
);
if
(
pcm
->
streams
[
SNDRV_PCM_STREAM_PLAYBACK
].
substream
)
{
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
,
ret
=
atmel_pcm_preallocate_dma_buffer
(
pcm
,
SNDRV_PCM_STREAM_PLAYBACK
);
SNDRV_PCM_STREAM_PLAYBACK
);
if
(
ret
)
if
(
ret
)
...
@@ -383,8 +90,7 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
...
@@ -383,8 +90,7 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
}
}
if
(
pcm
->
streams
[
SNDRV_PCM_STREAM_CAPTURE
].
substream
)
{
if
(
pcm
->
streams
[
SNDRV_PCM_STREAM_CAPTURE
].
substream
)
{
pr_debug
(
"atmel-pcm:"
pr_debug
(
"atmel-pcm: allocating PCM capture DMA buffer
\n
"
);
"Allocating PCM capture DMA buffer
\n
"
);
ret
=
atmel_pcm_preallocate_dma_buffer
(
pcm
,
ret
=
atmel_pcm_preallocate_dma_buffer
(
pcm
,
SNDRV_PCM_STREAM_CAPTURE
);
SNDRV_PCM_STREAM_CAPTURE
);
if
(
ret
)
if
(
ret
)
...
@@ -393,8 +99,9 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
...
@@ -393,8 +99,9 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
out:
out:
return
ret
;
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_pcm_substream
*
substream
;
struct
snd_dma_buffer
*
buf
;
struct
snd_dma_buffer
*
buf
;
...
@@ -413,89 +120,5 @@ static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm)
...
@@ -413,89 +120,5 @@ static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm)
buf
->
area
=
NULL
;
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 @@
...
@@ -36,6 +36,8 @@
#include <linux/atmel-ssc.h>
#include <linux/atmel-ssc.h>
#define ATMEL_SSC_DMABUF_SIZE (64 * 1024)
/*
/*
* Registers and status bits that are required by the PCM driver.
* Registers and status bits that are required by the PCM driver.
*/
*/
...
@@ -50,6 +52,7 @@ struct atmel_pdc_regs {
...
@@ -50,6 +52,7 @@ struct atmel_pdc_regs {
struct
atmel_ssc_mask
{
struct
atmel_ssc_mask
{
u32
ssc_enable
;
/* SSC recv/trans enable */
u32
ssc_enable
;
/* SSC recv/trans enable */
u32
ssc_disable
;
/* SSC recv/trans disable */
u32
ssc_disable
;
/* SSC recv/trans disable */
u32
ssc_error
;
/* SSC error conditions */
u32
ssc_endx
;
/* SSC ENDTX or ENDRX */
u32
ssc_endx
;
/* SSC ENDTX or ENDRX */
u32
ssc_endbuf
;
/* SSC TXBUFE or RXBUFF */
u32
ssc_endbuf
;
/* SSC TXBUFE or RXBUFF */
u32
pdc_enable
;
/* PDC recv/trans enable */
u32
pdc_enable
;
/* PDC recv/trans enable */
...
@@ -80,4 +83,35 @@ struct atmel_pcm_dma_params {
...
@@ -80,4 +83,35 @@ struct atmel_pcm_dma_params {
#define ssc_readx(base, reg) (__raw_readl((base) + (reg)))
#define ssc_readx(base, reg) (__raw_readl((base) + (reg)))
#define ssc_writex(base, reg, value) __raw_writel((value), (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 */
#endif
/* _ATMEL_PCM_H */
sound/soc/atmel/atmel_ssc_dai.c
浏览文件 @
93ac820d
...
@@ -48,11 +48,7 @@
...
@@ -48,11 +48,7 @@
#include "atmel_ssc_dai.h"
#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
#define NUM_SSC_DEVICES 3
#endif
/*
/*
* SSC PDC registers required by the PCM DMA engine.
* 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] = {
...
@@ -107,7 +103,6 @@ static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
.
pdc
=
&
pdc_rx_reg
,
.
pdc
=
&
pdc_rx_reg
,
.
mask
=
&
ssc_rx_mask
,
.
mask
=
&
ssc_rx_mask
,
}
},
}
},
#if NUM_SSC_DEVICES == 3
{{
{{
.
name
=
"SSC1 PCM out"
,
.
name
=
"SSC1 PCM out"
,
.
pdc
=
&
pdc_tx_reg
,
.
pdc
=
&
pdc_tx_reg
,
...
@@ -128,7 +123,6 @@ static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
...
@@ -128,7 +123,6 @@ static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
.
pdc
=
&
pdc_rx_reg
,
.
pdc
=
&
pdc_rx_reg
,
.
mask
=
&
ssc_rx_mask
,
.
mask
=
&
ssc_rx_mask
,
}
},
}
},
#endif
};
};
...
@@ -139,7 +133,6 @@ static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = {
...
@@ -139,7 +133,6 @@ static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = {
.
dir_mask
=
SSC_DIR_MASK_UNUSED
,
.
dir_mask
=
SSC_DIR_MASK_UNUSED
,
.
initialized
=
0
,
.
initialized
=
0
,
},
},
#if NUM_SSC_DEVICES == 3
{
{
.
name
=
"ssc1"
,
.
name
=
"ssc1"
,
.
lock
=
__SPIN_LOCK_UNLOCKED
(
ssc_info
[
1
].
lock
),
.
lock
=
__SPIN_LOCK_UNLOCKED
(
ssc_info
[
1
].
lock
),
...
@@ -152,7 +145,6 @@ static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = {
...
@@ -152,7 +145,6 @@ static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = {
.
dir_mask
=
SSC_DIR_MASK_UNUSED
,
.
dir_mask
=
SSC_DIR_MASK_UNUSED
,
.
initialized
=
0
,
.
initialized
=
0
,
},
},
#endif
};
};
...
@@ -690,27 +682,9 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
...
@@ -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
)
static
int
atmel_ssc_probe
(
struct
snd_soc_dai
*
dai
)
{
{
struct
atmel_ssc_info
*
ssc_p
=
&
ssc_info
[
dai
->
id
];
struct
atmel_ssc_info
*
ssc_p
=
&
ssc_info
[
dai
->
id
];
int
ret
=
0
;
snd_soc_dai_set_drvdata
(
dai
,
ssc_p
);
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
;
return
0
;
}
}
...
@@ -728,30 +702,8 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = {
...
@@ -728,30 +702,8 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = {
.
set_clkdiv
=
atmel_ssc_set_dai_clkdiv
,
.
set_clkdiv
=
atmel_ssc_set_dai_clkdiv
,
};
};
static
struct
snd_soc_dai_driver
atmel_ssc_dai
[
NUM_SSC_DEVICES
]
=
{
static
struct
snd_soc_dai_driver
atmel_ssc_dai
=
{
{
.
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"
,
.
probe
=
atmel_ssc_probe
,
.
probe
=
atmel_ssc_probe
,
.
remove
=
atmel_ssc_remove
,
.
suspend
=
atmel_ssc_suspend
,
.
suspend
=
atmel_ssc_suspend
,
.
resume
=
atmel_ssc_resume
,
.
resume
=
atmel_ssc_resume
,
.
playback
=
{
.
playback
=
{
...
@@ -765,50 +717,50 @@ static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = {
...
@@ -765,50 +717,50 @@ static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = {
.
rates
=
ATMEL_SSC_RATES
,
.
rates
=
ATMEL_SSC_RATES
,
.
formats
=
ATMEL_SSC_FORMATS
,},
.
formats
=
ATMEL_SSC_FORMATS
,},
.
ops
=
&
atmel_ssc_dai_ops
,
.
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
);
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
BUG_ON
(
pdev
->
id
>=
ARRAY_SIZE
(
atmel_ssc_dai
));
struct
ssc_device
*
ssc
=
platform_get_drvdata
(
pdev
);
return
snd_soc_register_dai
(
&
pdev
->
dev
,
&
atmel_ssc_dai
[
pdev
->
id
]);
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
;
return
0
;
err_unregister_dai:
snd_soc_unregister_dai
(
dev
);
err:
return
ret
;
}
}
static
struct
platform_driver
asoc_ssc_driver
=
{
static
void
asoc_ssc_exit
(
struct
device
*
dev
)
.
driver
=
{
{
.
name
=
"atmel-ssc-dai"
,
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
.
owner
=
THIS_MODULE
,
struct
ssc_device
*
ssc
=
platform_get_drvdata
(
pdev
);
},
.
probe
=
asoc_ssc_probe
,
if
(
ssc
->
pdata
->
use_dma
)
.
remove
=
__devexit_p
(
asoc_ssc_remove
),
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.
* atmel_ssc_set_audio - Allocate the specified SSC for audio use.
...
@@ -816,50 +768,32 @@ static struct platform_driver asoc_ssc_driver = {
...
@@ -816,50 +768,32 @@ static struct platform_driver asoc_ssc_driver = {
int
atmel_ssc_set_audio
(
int
ssc_id
)
int
atmel_ssc_set_audio
(
int
ssc_id
)
{
{
struct
ssc_device
*
ssc
;
struct
ssc_device
*
ssc
;
static
struct
platform_device
*
dma_pdev
;
struct
platform_device
*
ssc_pdev
;
int
ret
;
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 */
/* If we can grab the SSC briefly to parent the DAI device off it */
ssc
=
ssc_request
(
ssc_id
);
ssc
=
ssc_request
(
ssc_id
);
if
(
IS_ERR
(
ssc
))
if
(
IS_ERR
(
ssc
))
{
pr_
warn
(
"Unable to parent ASoC SSC DAI on SSC: %ld
\n
"
,
pr_
err
(
"Unable to parent ASoC SSC DAI on SSC: %ld
\n
"
,
PTR_ERR
(
ssc
));
PTR_ERR
(
ssc
));
else
{
return
PTR_ERR
(
ssc
);
ssc_pdev
->
dev
.
parent
=
&
(
ssc
->
pdev
->
dev
);
}
else
{
ssc_
free
(
ssc
)
;
ssc_
info
[
ssc_id
].
ssc
=
ssc
;
}
}
ret
=
platform_device_add
(
ssc_pdev
);
ret
=
asoc_ssc_init
(
&
ssc
->
pdev
->
dev
);
if
(
ret
<
0
)
platform_device_put
(
ssc_pdev
);
return
ret
;
return
ret
;
}
}
EXPORT_SYMBOL_GPL
(
atmel_ssc_set_audio
);
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 information */
MODULE_AUTHOR
(
"Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com"
);
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 {
...
@@ -117,6 +117,7 @@ struct atmel_ssc_info {
struct
atmel_ssc_state
ssc_state
;
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 */
#endif
/* _AT91_SSC_DAI_H */
sound/soc/atmel/sam9g20_wm8731.c
浏览文件 @
93ac820d
...
@@ -38,6 +38,8 @@
...
@@ -38,6 +38,8 @@
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/i2c.h>
#include <linux/pinctrl/consumer.h>
#include <linux/atmel-ssc.h>
#include <linux/atmel-ssc.h>
#include <sound/core.h>
#include <sound/core.h>
...
@@ -179,10 +181,10 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
...
@@ -179,10 +181,10 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
static
struct
snd_soc_dai_link
at91sam9g20ek_dai
=
{
static
struct
snd_soc_dai_link
at91sam9g20ek_dai
=
{
.
name
=
"WM8731"
,
.
name
=
"WM8731"
,
.
stream_name
=
"WM8731 PCM"
,
.
stream_name
=
"WM8731 PCM"
,
.
cpu_dai_name
=
"at
mel-ssc-dai
.0"
,
.
cpu_dai_name
=
"at
91rm9200_ssc
.0"
,
.
codec_dai_name
=
"wm8731-hifi"
,
.
codec_dai_name
=
"wm8731-hifi"
,
.
init
=
at91sam9g20ek_wm8731_init
,
.
init
=
at91sam9g20ek_wm8731_init
,
.
platform_name
=
"at
mel-pcm-audio
"
,
.
platform_name
=
"at
91rm9200_ssc.0
"
,
.
codec_name
=
"wm8731.0-001b"
,
.
codec_name
=
"wm8731.0-001b"
,
.
ops
=
&
at91sam9g20ek_ops
,
.
ops
=
&
at91sam9g20ek_ops
,
};
};
...
@@ -195,20 +197,31 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = {
...
@@ -195,20 +197,31 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = {
.
set_bias_level
=
at91sam9g20ek_set_bias_level
,
.
set_bias_level
=
at91sam9g20ek_set_bias_level
,
};
};
static
struct
platform_device
*
at91sam9g20ek_snd_device
;
static
int
__devinit
at91sam9g20ek_audio_probe
(
struct
platform_device
*
pdev
)
static
int
__init
at91sam9g20ek_init
(
void
)
{
{
struct
device_node
*
np
=
pdev
->
dev
.
of_node
;
struct
device_node
*
codec_np
,
*
cpu_np
;
struct
clk
*
pllb
;
struct
clk
*
pllb
;
struct
snd_soc_card
*
card
=
&
snd_soc_at91sam9g20ek
;
struct
pinctrl
*
pinctrl
;
int
ret
;
int
ret
;
if
(
!
(
machine_is_at91sam9g20ek
()
||
machine_is_at91sam9g20ek_2mmc
()))
pinctrl
=
devm_pinctrl_get_select_default
(
&
pdev
->
dev
);
return
-
ENODEV
;
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
);
ret
=
atmel_ssc_set_audio
(
0
);
if
(
ret
!=
0
)
{
if
(
ret
)
{
pr_err
(
"Failed to set SSC 0 for audio: %d
\n
"
,
ret
);
dev_err
(
&
pdev
->
dev
,
"ssc channel is not valid
\n
"
);
return
ret
;
return
-
EINVAL
;
}
}
/*
/*
...
@@ -236,45 +249,92 @@ static int __init at91sam9g20ek_init(void)
...
@@ -236,45 +249,92 @@ static int __init at91sam9g20ek_init(void)
clk_set_rate
(
mclk
,
MCLK_RATE
);
clk_set_rate
(
mclk
,
MCLK_RATE
);
at91sam9g20ek_snd_device
=
platform_device_alloc
(
"soc-audio"
,
-
1
);
card
->
dev
=
&
pdev
->
dev
;
if
(
!
at91sam9g20ek_snd_device
)
{
printk
(
KERN_ERR
"ASoC: Platform device allocation failed
\n
"
);
/* Parse device node info */
ret
=
-
ENOMEM
;
if
(
np
)
{
goto
err_mclk
;
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
,
ret
=
snd_soc_register_card
(
card
);
&
snd_soc_at91sam9g20ek
);
ret
=
platform_device_add
(
at91sam9g20ek_snd_device
);
if
(
ret
)
{
if
(
ret
)
{
printk
(
KERN_ERR
"ASoC: Platform device allocation failed
\n
"
);
printk
(
KERN_ERR
"ASoC: snd_soc_register_card() failed
\n
"
);
goto
err_device_add
;
}
}
return
ret
;
return
ret
;
err_device_add:
platform_device_put
(
at91sam9g20ek_snd_device
);
err_mclk:
err_mclk:
clk_put
(
mclk
);
clk_put
(
mclk
);
mclk
=
NULL
;
mclk
=
NULL
;
err:
err:
atmel_ssc_put_audio
(
0
);
return
ret
;
return
ret
;
}
}
static
void
__exit
at91sam9g20ek_exit
(
void
)
static
int
__devexit
at91sam9g20ek_audio_remove
(
struct
platform_device
*
pdev
)
{
{
platform_device_unregister
(
at91sam9g20ek_snd_device
);
struct
snd_soc_card
*
card
=
platform_get_drvdata
(
pdev
);
at91sam9g20ek_snd_device
=
NULL
;
atmel_ssc_put_audio
(
0
);
snd_soc_unregister_card
(
card
);
clk_put
(
mclk
);
clk_put
(
mclk
);
mclk
=
NULL
;
mclk
=
NULL
;
return
0
;
}
}
module_init
(
at91sam9g20ek_init
);
#ifdef CONFIG_OF
module_exit
(
at91sam9g20ek_exit
);
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 information */
MODULE_AUTHOR
(
"Sedji Gaouaou <sedji.gaouaou@atmel.com>"
);
MODULE_AUTHOR
(
"Sedji Gaouaou <sedji.gaouaou@atmel.com>"
);
MODULE_DESCRIPTION
(
"ALSA SoC AT91SAM9G20EK_WM8731"
);
MODULE_DESCRIPTION
(
"ALSA SoC AT91SAM9G20EK_WM8731"
);
MODULE_ALIAS
(
"platform:at91sam9g20ek-audio"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_LICENSE
(
"GPL"
);
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录