2 * STM32 ALSA SoC Digital Audio Interface (SAI) driver.
4 * Copyright (C) 2016, STMicroelectronics - All Rights Reserved
5 * Author(s): Olivier Moysan <olivier.moysan@st.com> for STMicroelectronics.
7 * License terms: GPL V2.0.
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as published by
11 * the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
19 #include <linux/bitfield.h>
20 #include <linux/clk.h>
21 #include <linux/delay.h>
22 #include <linux/module.h>
23 #include <linux/of_platform.h>
24 #include <linux/reset.h>
26 #include <sound/dmaengine_pcm.h>
27 #include <sound/core.h>
29 #include "stm32_sai.h"
31 static const struct stm32_sai_conf stm32_sai_conf_f4
= {
32 .version
= SAI_STM32F4
,
35 static const struct stm32_sai_conf stm32_sai_conf_h7
= {
36 .version
= SAI_STM32H7
,
39 static const struct of_device_id stm32_sai_ids
[] = {
40 { .compatible
= "st,stm32f4-sai", .data
= (void *)&stm32_sai_conf_f4
},
41 { .compatible
= "st,stm32h7-sai", .data
= (void *)&stm32_sai_conf_h7
},
45 static int stm32_sai_sync_conf_client(struct stm32_sai_data
*sai
, int synci
)
49 /* Enable peripheral clock to allow GCR register access */
50 ret
= clk_prepare_enable(sai
->pclk
);
52 dev_err(&sai
->pdev
->dev
, "failed to enable clock: %d\n", ret
);
56 writel_relaxed(FIELD_PREP(SAI_GCR_SYNCIN_MASK
, (synci
- 1)), sai
->base
);
58 clk_disable_unprepare(sai
->pclk
);
63 static int stm32_sai_sync_conf_provider(struct stm32_sai_data
*sai
, int synco
)
68 /* Enable peripheral clock to allow GCR register access */
69 ret
= clk_prepare_enable(sai
->pclk
);
71 dev_err(&sai
->pdev
->dev
, "failed to enable clock: %d\n", ret
);
75 dev_dbg(&sai
->pdev
->dev
, "Set %s%s as synchro provider\n",
76 sai
->pdev
->dev
.of_node
->name
,
77 synco
== STM_SAI_SYNC_OUT_A
? "A" : "B");
79 prev_synco
= FIELD_GET(SAI_GCR_SYNCOUT_MASK
, readl_relaxed(sai
->base
));
80 if (prev_synco
!= STM_SAI_SYNC_OUT_NONE
&& synco
!= prev_synco
) {
81 dev_err(&sai
->pdev
->dev
, "%s%s already set as sync provider\n",
82 sai
->pdev
->dev
.of_node
->name
,
83 prev_synco
== STM_SAI_SYNC_OUT_A
? "A" : "B");
84 clk_disable_unprepare(sai
->pclk
);
88 writel_relaxed(FIELD_PREP(SAI_GCR_SYNCOUT_MASK
, synco
), sai
->base
);
90 clk_disable_unprepare(sai
->pclk
);
95 static int stm32_sai_set_sync(struct stm32_sai_data
*sai_client
,
96 struct device_node
*np_provider
,
99 struct platform_device
*pdev
= of_find_device_by_node(np_provider
);
100 struct stm32_sai_data
*sai_provider
;
104 dev_err(&sai_client
->pdev
->dev
,
105 "Device not found for node %s\n", np_provider
->name
);
109 sai_provider
= platform_get_drvdata(pdev
);
111 dev_err(&sai_client
->pdev
->dev
,
112 "SAI sync provider data not found\n");
116 /* Configure sync client */
117 ret
= stm32_sai_sync_conf_client(sai_client
, synci
);
121 /* Configure sync provider */
122 return stm32_sai_sync_conf_provider(sai_provider
, synco
);
125 static int stm32_sai_probe(struct platform_device
*pdev
)
127 struct stm32_sai_data
*sai
;
128 struct reset_control
*rst
;
129 struct resource
*res
;
130 const struct of_device_id
*of_id
;
132 sai
= devm_kzalloc(&pdev
->dev
, sizeof(*sai
), GFP_KERNEL
);
136 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
137 sai
->base
= devm_ioremap_resource(&pdev
->dev
, res
);
138 if (IS_ERR(sai
->base
))
139 return PTR_ERR(sai
->base
);
141 of_id
= of_match_device(stm32_sai_ids
, &pdev
->dev
);
143 sai
->conf
= (struct stm32_sai_conf
*)of_id
->data
;
147 if (!STM_SAI_IS_F4(sai
)) {
148 sai
->pclk
= devm_clk_get(&pdev
->dev
, "pclk");
149 if (IS_ERR(sai
->pclk
)) {
150 dev_err(&pdev
->dev
, "missing bus clock pclk\n");
151 return PTR_ERR(sai
->pclk
);
155 sai
->clk_x8k
= devm_clk_get(&pdev
->dev
, "x8k");
156 if (IS_ERR(sai
->clk_x8k
)) {
157 dev_err(&pdev
->dev
, "missing x8k parent clock\n");
158 return PTR_ERR(sai
->clk_x8k
);
161 sai
->clk_x11k
= devm_clk_get(&pdev
->dev
, "x11k");
162 if (IS_ERR(sai
->clk_x11k
)) {
163 dev_err(&pdev
->dev
, "missing x11k parent clock\n");
164 return PTR_ERR(sai
->clk_x11k
);
168 sai
->irq
= platform_get_irq(pdev
, 0);
170 dev_err(&pdev
->dev
, "no irq for node %s\n", pdev
->name
);
175 rst
= devm_reset_control_get_exclusive(&pdev
->dev
, NULL
);
177 reset_control_assert(rst
);
179 reset_control_deassert(rst
);
183 sai
->set_sync
= &stm32_sai_set_sync
;
184 platform_set_drvdata(pdev
, sai
);
186 return devm_of_platform_populate(&pdev
->dev
);
189 MODULE_DEVICE_TABLE(of
, stm32_sai_ids
);
191 static struct platform_driver stm32_sai_driver
= {
193 .name
= "st,stm32-sai",
194 .of_match_table
= stm32_sai_ids
,
196 .probe
= stm32_sai_probe
,
199 module_platform_driver(stm32_sai_driver
);
201 MODULE_DESCRIPTION("STM32 Soc SAI Interface");
202 MODULE_AUTHOR("Olivier Moysan <olivier.moysan@st.com>");
203 MODULE_ALIAS("platform:st,stm32-sai");
204 MODULE_LICENSE("GPL v2");