1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * STM32 ALSA SoC Digital Audio Interface (SAI) driver.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2016, STMicroelectronics - All Rights Reserved
6*4882a593Smuzhiyun * Author(s): Olivier Moysan <olivier.moysan@st.com> for STMicroelectronics.
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <linux/bitfield.h>
10*4882a593Smuzhiyun #include <linux/clk.h>
11*4882a593Smuzhiyun #include <linux/delay.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/of_platform.h>
14*4882a593Smuzhiyun #include <linux/pinctrl/consumer.h>
15*4882a593Smuzhiyun #include <linux/reset.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <sound/dmaengine_pcm.h>
18*4882a593Smuzhiyun #include <sound/core.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include "stm32_sai.h"
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun static const struct stm32_sai_conf stm32_sai_conf_f4 = {
23*4882a593Smuzhiyun .version = STM_SAI_STM32F4,
24*4882a593Smuzhiyun .fifo_size = 8,
25*4882a593Smuzhiyun .has_spdif_pdm = false,
26*4882a593Smuzhiyun };
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun /*
29*4882a593Smuzhiyun * Default settings for stm32 H7 socs and next.
30*4882a593Smuzhiyun * These default settings will be overridden if the soc provides
31*4882a593Smuzhiyun * support of hardware configuration registers.
32*4882a593Smuzhiyun */
33*4882a593Smuzhiyun static const struct stm32_sai_conf stm32_sai_conf_h7 = {
34*4882a593Smuzhiyun .version = STM_SAI_STM32H7,
35*4882a593Smuzhiyun .fifo_size = 8,
36*4882a593Smuzhiyun .has_spdif_pdm = true,
37*4882a593Smuzhiyun };
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun static const struct of_device_id stm32_sai_ids[] = {
40*4882a593Smuzhiyun { .compatible = "st,stm32f4-sai", .data = (void *)&stm32_sai_conf_f4 },
41*4882a593Smuzhiyun { .compatible = "st,stm32h7-sai", .data = (void *)&stm32_sai_conf_h7 },
42*4882a593Smuzhiyun {}
43*4882a593Smuzhiyun };
44*4882a593Smuzhiyun
stm32_sai_pclk_disable(struct device * dev)45*4882a593Smuzhiyun static int stm32_sai_pclk_disable(struct device *dev)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun struct stm32_sai_data *sai = dev_get_drvdata(dev);
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun clk_disable_unprepare(sai->pclk);
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun return 0;
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun
stm32_sai_pclk_enable(struct device * dev)54*4882a593Smuzhiyun static int stm32_sai_pclk_enable(struct device *dev)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun struct stm32_sai_data *sai = dev_get_drvdata(dev);
57*4882a593Smuzhiyun int ret;
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun ret = clk_prepare_enable(sai->pclk);
60*4882a593Smuzhiyun if (ret) {
61*4882a593Smuzhiyun dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
62*4882a593Smuzhiyun return ret;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun return 0;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun
stm32_sai_sync_conf_client(struct stm32_sai_data * sai,int synci)68*4882a593Smuzhiyun static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun int ret;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /* Enable peripheral clock to allow GCR register access */
73*4882a593Smuzhiyun ret = stm32_sai_pclk_enable(&sai->pdev->dev);
74*4882a593Smuzhiyun if (ret)
75*4882a593Smuzhiyun return ret;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun writel_relaxed(FIELD_PREP(SAI_GCR_SYNCIN_MASK, (synci - 1)), sai->base);
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun stm32_sai_pclk_disable(&sai->pdev->dev);
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun return 0;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
stm32_sai_sync_conf_provider(struct stm32_sai_data * sai,int synco)84*4882a593Smuzhiyun static int stm32_sai_sync_conf_provider(struct stm32_sai_data *sai, int synco)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun u32 prev_synco;
87*4882a593Smuzhiyun int ret;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun /* Enable peripheral clock to allow GCR register access */
90*4882a593Smuzhiyun ret = stm32_sai_pclk_enable(&sai->pdev->dev);
91*4882a593Smuzhiyun if (ret)
92*4882a593Smuzhiyun return ret;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun dev_dbg(&sai->pdev->dev, "Set %pOFn%s as synchro provider\n",
95*4882a593Smuzhiyun sai->pdev->dev.of_node,
96*4882a593Smuzhiyun synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun prev_synco = FIELD_GET(SAI_GCR_SYNCOUT_MASK, readl_relaxed(sai->base));
99*4882a593Smuzhiyun if (prev_synco != STM_SAI_SYNC_OUT_NONE && synco != prev_synco) {
100*4882a593Smuzhiyun dev_err(&sai->pdev->dev, "%pOFn%s already set as sync provider\n",
101*4882a593Smuzhiyun sai->pdev->dev.of_node,
102*4882a593Smuzhiyun prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
103*4882a593Smuzhiyun stm32_sai_pclk_disable(&sai->pdev->dev);
104*4882a593Smuzhiyun return -EINVAL;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun writel_relaxed(FIELD_PREP(SAI_GCR_SYNCOUT_MASK, synco), sai->base);
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun stm32_sai_pclk_disable(&sai->pdev->dev);
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun return 0;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
stm32_sai_set_sync(struct stm32_sai_data * sai_client,struct device_node * np_provider,int synco,int synci)114*4882a593Smuzhiyun static int stm32_sai_set_sync(struct stm32_sai_data *sai_client,
115*4882a593Smuzhiyun struct device_node *np_provider,
116*4882a593Smuzhiyun int synco, int synci)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun struct platform_device *pdev = of_find_device_by_node(np_provider);
119*4882a593Smuzhiyun struct stm32_sai_data *sai_provider;
120*4882a593Smuzhiyun int ret;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun if (!pdev) {
123*4882a593Smuzhiyun dev_err(&sai_client->pdev->dev,
124*4882a593Smuzhiyun "Device not found for node %pOFn\n", np_provider);
125*4882a593Smuzhiyun of_node_put(np_provider);
126*4882a593Smuzhiyun return -ENODEV;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun sai_provider = platform_get_drvdata(pdev);
130*4882a593Smuzhiyun if (!sai_provider) {
131*4882a593Smuzhiyun dev_err(&sai_client->pdev->dev,
132*4882a593Smuzhiyun "SAI sync provider data not found\n");
133*4882a593Smuzhiyun ret = -EINVAL;
134*4882a593Smuzhiyun goto error;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun /* Configure sync client */
138*4882a593Smuzhiyun ret = stm32_sai_sync_conf_client(sai_client, synci);
139*4882a593Smuzhiyun if (ret < 0)
140*4882a593Smuzhiyun goto error;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun /* Configure sync provider */
143*4882a593Smuzhiyun ret = stm32_sai_sync_conf_provider(sai_provider, synco);
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun error:
146*4882a593Smuzhiyun put_device(&pdev->dev);
147*4882a593Smuzhiyun of_node_put(np_provider);
148*4882a593Smuzhiyun return ret;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
stm32_sai_probe(struct platform_device * pdev)151*4882a593Smuzhiyun static int stm32_sai_probe(struct platform_device *pdev)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun struct stm32_sai_data *sai;
154*4882a593Smuzhiyun struct reset_control *rst;
155*4882a593Smuzhiyun const struct of_device_id *of_id;
156*4882a593Smuzhiyun u32 val;
157*4882a593Smuzhiyun int ret;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
160*4882a593Smuzhiyun if (!sai)
161*4882a593Smuzhiyun return -ENOMEM;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun sai->base = devm_platform_ioremap_resource(pdev, 0);
164*4882a593Smuzhiyun if (IS_ERR(sai->base))
165*4882a593Smuzhiyun return PTR_ERR(sai->base);
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun of_id = of_match_device(stm32_sai_ids, &pdev->dev);
168*4882a593Smuzhiyun if (of_id)
169*4882a593Smuzhiyun memcpy(&sai->conf, (const struct stm32_sai_conf *)of_id->data,
170*4882a593Smuzhiyun sizeof(struct stm32_sai_conf));
171*4882a593Smuzhiyun else
172*4882a593Smuzhiyun return -EINVAL;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun if (!STM_SAI_IS_F4(sai)) {
175*4882a593Smuzhiyun sai->pclk = devm_clk_get(&pdev->dev, "pclk");
176*4882a593Smuzhiyun if (IS_ERR(sai->pclk)) {
177*4882a593Smuzhiyun if (PTR_ERR(sai->pclk) != -EPROBE_DEFER)
178*4882a593Smuzhiyun dev_err(&pdev->dev, "missing bus clock pclk: %ld\n",
179*4882a593Smuzhiyun PTR_ERR(sai->pclk));
180*4882a593Smuzhiyun return PTR_ERR(sai->pclk);
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k");
185*4882a593Smuzhiyun if (IS_ERR(sai->clk_x8k)) {
186*4882a593Smuzhiyun if (PTR_ERR(sai->clk_x8k) != -EPROBE_DEFER)
187*4882a593Smuzhiyun dev_err(&pdev->dev, "missing x8k parent clock: %ld\n",
188*4882a593Smuzhiyun PTR_ERR(sai->clk_x8k));
189*4882a593Smuzhiyun return PTR_ERR(sai->clk_x8k);
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun sai->clk_x11k = devm_clk_get(&pdev->dev, "x11k");
193*4882a593Smuzhiyun if (IS_ERR(sai->clk_x11k)) {
194*4882a593Smuzhiyun if (PTR_ERR(sai->clk_x11k) != -EPROBE_DEFER)
195*4882a593Smuzhiyun dev_err(&pdev->dev, "missing x11k parent clock: %ld\n",
196*4882a593Smuzhiyun PTR_ERR(sai->clk_x11k));
197*4882a593Smuzhiyun return PTR_ERR(sai->clk_x11k);
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun /* init irqs */
201*4882a593Smuzhiyun sai->irq = platform_get_irq(pdev, 0);
202*4882a593Smuzhiyun if (sai->irq < 0)
203*4882a593Smuzhiyun return sai->irq;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun /* reset */
206*4882a593Smuzhiyun rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
207*4882a593Smuzhiyun if (IS_ERR(rst)) {
208*4882a593Smuzhiyun if (PTR_ERR(rst) != -EPROBE_DEFER)
209*4882a593Smuzhiyun dev_err(&pdev->dev, "Reset controller error %ld\n",
210*4882a593Smuzhiyun PTR_ERR(rst));
211*4882a593Smuzhiyun return PTR_ERR(rst);
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun reset_control_assert(rst);
214*4882a593Smuzhiyun udelay(2);
215*4882a593Smuzhiyun reset_control_deassert(rst);
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun /* Enable peripheral clock to allow register access */
218*4882a593Smuzhiyun ret = clk_prepare_enable(sai->pclk);
219*4882a593Smuzhiyun if (ret) {
220*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to enable clock: %d\n", ret);
221*4882a593Smuzhiyun return ret;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun val = FIELD_GET(SAI_IDR_ID_MASK,
225*4882a593Smuzhiyun readl_relaxed(sai->base + STM_SAI_IDR));
226*4882a593Smuzhiyun if (val == SAI_IPIDR_NUMBER) {
227*4882a593Smuzhiyun val = readl_relaxed(sai->base + STM_SAI_HWCFGR);
228*4882a593Smuzhiyun sai->conf.fifo_size = FIELD_GET(SAI_HWCFGR_FIFO_SIZE, val);
229*4882a593Smuzhiyun sai->conf.has_spdif_pdm = !!FIELD_GET(SAI_HWCFGR_SPDIF_PDM,
230*4882a593Smuzhiyun val);
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun val = readl_relaxed(sai->base + STM_SAI_VERR);
233*4882a593Smuzhiyun sai->conf.version = val;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun dev_dbg(&pdev->dev, "SAI version: %lu.%lu registered\n",
236*4882a593Smuzhiyun FIELD_GET(SAI_VERR_MAJ_MASK, val),
237*4882a593Smuzhiyun FIELD_GET(SAI_VERR_MIN_MASK, val));
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun clk_disable_unprepare(sai->pclk);
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun sai->pdev = pdev;
242*4882a593Smuzhiyun sai->set_sync = &stm32_sai_set_sync;
243*4882a593Smuzhiyun platform_set_drvdata(pdev, sai);
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun return devm_of_platform_populate(&pdev->dev);
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
249*4882a593Smuzhiyun /*
250*4882a593Smuzhiyun * When pins are shared by two sai sub instances, pins have to be defined
251*4882a593Smuzhiyun * in sai parent node. In this case, pins state is not managed by alsa fw.
252*4882a593Smuzhiyun * These pins are managed in suspend/resume callbacks.
253*4882a593Smuzhiyun */
stm32_sai_suspend(struct device * dev)254*4882a593Smuzhiyun static int stm32_sai_suspend(struct device *dev)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun struct stm32_sai_data *sai = dev_get_drvdata(dev);
257*4882a593Smuzhiyun int ret;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun ret = stm32_sai_pclk_enable(dev);
260*4882a593Smuzhiyun if (ret)
261*4882a593Smuzhiyun return ret;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun sai->gcr = readl_relaxed(sai->base);
264*4882a593Smuzhiyun stm32_sai_pclk_disable(dev);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun return pinctrl_pm_select_sleep_state(dev);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
stm32_sai_resume(struct device * dev)269*4882a593Smuzhiyun static int stm32_sai_resume(struct device *dev)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun struct stm32_sai_data *sai = dev_get_drvdata(dev);
272*4882a593Smuzhiyun int ret;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun ret = stm32_sai_pclk_enable(dev);
275*4882a593Smuzhiyun if (ret)
276*4882a593Smuzhiyun return ret;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun writel_relaxed(sai->gcr, sai->base);
279*4882a593Smuzhiyun stm32_sai_pclk_disable(dev);
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun return pinctrl_pm_select_default_state(dev);
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun #endif /* CONFIG_PM_SLEEP */
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun static const struct dev_pm_ops stm32_sai_pm_ops = {
286*4882a593Smuzhiyun SET_SYSTEM_SLEEP_PM_OPS(stm32_sai_suspend, stm32_sai_resume)
287*4882a593Smuzhiyun };
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, stm32_sai_ids);
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun static struct platform_driver stm32_sai_driver = {
292*4882a593Smuzhiyun .driver = {
293*4882a593Smuzhiyun .name = "st,stm32-sai",
294*4882a593Smuzhiyun .of_match_table = stm32_sai_ids,
295*4882a593Smuzhiyun .pm = &stm32_sai_pm_ops,
296*4882a593Smuzhiyun },
297*4882a593Smuzhiyun .probe = stm32_sai_probe,
298*4882a593Smuzhiyun };
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun module_platform_driver(stm32_sai_driver);
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun MODULE_DESCRIPTION("STM32 Soc SAI Interface");
303*4882a593Smuzhiyun MODULE_AUTHOR("Olivier Moysan <olivier.moysan@st.com>");
304*4882a593Smuzhiyun MODULE_ALIAS("platform:st,stm32-sai");
305*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
306