stm32_sai.c (3c6f6c53ab4df585639bbe647b45aa81ca54bdd2) | stm32_sai.c (5914d285f6b782892a91d6621723fdc41a775b15) |
---|---|
1/* 2 * STM32 ALSA SoC Digital Audio Interface (SAI) driver. 3 * 4 * Copyright (C) 2016, STMicroelectronics - All Rights Reserved 5 * Author(s): Olivier Moysan <olivier.moysan@st.com> for STMicroelectronics. 6 * 7 * License terms: GPL V2.0. 8 * 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. 12 * 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 16 * details. 17 */ 18 | 1/* 2 * STM32 ALSA SoC Digital Audio Interface (SAI) driver. 3 * 4 * Copyright (C) 2016, STMicroelectronics - All Rights Reserved 5 * Author(s): Olivier Moysan <olivier.moysan@st.com> for STMicroelectronics. 6 * 7 * License terms: GPL V2.0. 8 * 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. 12 * 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 16 * details. 17 */ 18 |
19#include <linux/bitfield.h> |
|
19#include <linux/clk.h> 20#include <linux/delay.h> 21#include <linux/module.h> 22#include <linux/of_platform.h> 23#include <linux/reset.h> 24 25#include <sound/dmaengine_pcm.h> 26#include <sound/core.h> 27 28#include "stm32_sai.h" 29 | 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> 25 26#include <sound/dmaengine_pcm.h> 27#include <sound/core.h> 28 29#include "stm32_sai.h" 30 |
31static LIST_HEAD(sync_providers); 32static DEFINE_MUTEX(sync_mutex); 33 34struct sync_provider { 35 struct list_head link; 36 struct device_node *node; 37 int (*sync_conf)(void *data, int synco); 38 void *data; 39}; 40 |
|
30static const struct stm32_sai_conf stm32_sai_conf_f4 = { 31 .version = SAI_STM32F4, 32}; 33 34static const struct stm32_sai_conf stm32_sai_conf_h7 = { 35 .version = SAI_STM32H7, 36}; 37 38static const struct of_device_id stm32_sai_ids[] = { 39 { .compatible = "st,stm32f4-sai", .data = (void *)&stm32_sai_conf_f4 }, 40 { .compatible = "st,stm32h7-sai", .data = (void *)&stm32_sai_conf_h7 }, 41 {} 42}; 43 | 41static const struct stm32_sai_conf stm32_sai_conf_f4 = { 42 .version = SAI_STM32F4, 43}; 44 45static const struct stm32_sai_conf stm32_sai_conf_h7 = { 46 .version = SAI_STM32H7, 47}; 48 49static const struct of_device_id stm32_sai_ids[] = { 50 { .compatible = "st,stm32f4-sai", .data = (void *)&stm32_sai_conf_f4 }, 51 { .compatible = "st,stm32h7-sai", .data = (void *)&stm32_sai_conf_h7 }, 52 {} 53}; 54 |
55static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci) 56{ 57 int ret; 58 59 /* Enable peripheral clock to allow GCR register access */ 60 ret = clk_prepare_enable(sai->pclk); 61 if (ret) { 62 dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret); 63 return ret; 64 } 65 66 writel_relaxed(FIELD_PREP(SAI_GCR_SYNCIN_MASK, (synci - 1)), sai->base); 67 68 clk_disable_unprepare(sai->pclk); 69 70 return 0; 71} 72 73static int stm32_sai_sync_conf_provider(void *data, int synco) 74{ 75 struct stm32_sai_data *sai = (struct stm32_sai_data *)data; 76 u32 prev_synco; 77 int ret; 78 79 /* Enable peripheral clock to allow GCR register access */ 80 ret = clk_prepare_enable(sai->pclk); 81 if (ret) { 82 dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret); 83 return ret; 84 } 85 86 dev_dbg(&sai->pdev->dev, "Set %s%s as synchro provider\n", 87 sai->pdev->dev.of_node->name, 88 synco == STM_SAI_SYNC_OUT_A ? "A" : "B"); 89 90 prev_synco = FIELD_GET(SAI_GCR_SYNCOUT_MASK, readl_relaxed(sai->base)); 91 if (prev_synco != STM_SAI_SYNC_OUT_NONE && synco != prev_synco) { 92 dev_err(&sai->pdev->dev, "%s%s already set as sync provider\n", 93 sai->pdev->dev.of_node->name, 94 prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B"); 95 clk_disable_unprepare(sai->pclk); 96 return -EINVAL; 97 } 98 99 writel_relaxed(FIELD_PREP(SAI_GCR_SYNCOUT_MASK, synco), sai->base); 100 101 clk_disable_unprepare(sai->pclk); 102 103 return 0; 104} 105 106static int stm32_sai_set_sync_provider(struct device_node *np, int synco) 107{ 108 struct sync_provider *provider; 109 int ret; 110 111 mutex_lock(&sync_mutex); 112 list_for_each_entry(provider, &sync_providers, link) { 113 if (provider->node == np) { 114 ret = provider->sync_conf(provider->data, synco); 115 mutex_unlock(&sync_mutex); 116 return ret; 117 } 118 } 119 mutex_unlock(&sync_mutex); 120 121 /* SAI sync provider not found */ 122 return -ENODEV; 123} 124 125static int stm32_sai_set_sync(struct stm32_sai_data *sai, 126 struct device_node *np_provider, 127 int synco, int synci) 128{ 129 int ret; 130 131 /* Configure sync client */ 132 stm32_sai_sync_conf_client(sai, synci); 133 134 /* Configure sync provider */ 135 ret = stm32_sai_set_sync_provider(np_provider, synco); 136 137 return ret; 138} 139 140static int stm32_sai_sync_add_provider(struct platform_device *pdev, 141 void *data) 142{ 143 struct sync_provider *sp; 144 145 sp = devm_kzalloc(&pdev->dev, sizeof(*sp), GFP_KERNEL); 146 if (!sp) 147 return -ENOMEM; 148 149 sp->node = of_node_get(pdev->dev.of_node); 150 sp->data = data; 151 sp->sync_conf = &stm32_sai_sync_conf_provider; 152 153 mutex_lock(&sync_mutex); 154 list_add(&sp->link, &sync_providers); 155 mutex_unlock(&sync_mutex); 156 157 return 0; 158} 159 160static void stm32_sai_sync_del_provider(struct device_node *np) 161{ 162 struct sync_provider *sp; 163 164 mutex_lock(&sync_mutex); 165 list_for_each_entry(sp, &sync_providers, link) { 166 if (sp->node == np) { 167 list_del(&sp->link); 168 of_node_put(sp->node); 169 break; 170 } 171 } 172 mutex_unlock(&sync_mutex); 173} 174 |
|
44static int stm32_sai_probe(struct platform_device *pdev) 45{ 46 struct device_node *np = pdev->dev.of_node; 47 struct stm32_sai_data *sai; 48 struct reset_control *rst; 49 struct resource *res; | 175static int stm32_sai_probe(struct platform_device *pdev) 176{ 177 struct device_node *np = pdev->dev.of_node; 178 struct stm32_sai_data *sai; 179 struct reset_control *rst; 180 struct resource *res; |
50 void __iomem *base; | |
51 const struct of_device_id *of_id; | 181 const struct of_device_id *of_id; |
182 int ret; |
|
52 53 sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); 54 if (!sai) 55 return -ENOMEM; 56 57 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 183 184 sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); 185 if (!sai) 186 return -ENOMEM; 187 188 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
58 base = devm_ioremap_resource(&pdev->dev, res); 59 if (IS_ERR(base)) 60 return PTR_ERR(base); | 189 sai->base = devm_ioremap_resource(&pdev->dev, res); 190 if (IS_ERR(sai->base)) 191 return PTR_ERR(sai->base); |
61 62 of_id = of_match_device(stm32_sai_ids, &pdev->dev); 63 if (of_id) 64 sai->conf = (struct stm32_sai_conf *)of_id->data; 65 else 66 return -EINVAL; 67 | 192 193 of_id = of_match_device(stm32_sai_ids, &pdev->dev); 194 if (of_id) 195 sai->conf = (struct stm32_sai_conf *)of_id->data; 196 else 197 return -EINVAL; 198 |
199 if (!STM_SAI_IS_F4(sai)) { 200 sai->pclk = devm_clk_get(&pdev->dev, "pclk"); 201 if (IS_ERR(sai->pclk)) { 202 dev_err(&pdev->dev, "missing bus clock pclk\n"); 203 return PTR_ERR(sai->pclk); 204 } 205 } 206 |
|
68 sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k"); 69 if (IS_ERR(sai->clk_x8k)) { 70 dev_err(&pdev->dev, "missing x8k parent clock\n"); 71 return PTR_ERR(sai->clk_x8k); 72 } 73 74 sai->clk_x11k = devm_clk_get(&pdev->dev, "x11k"); 75 if (IS_ERR(sai->clk_x11k)) { --- 11 unchanged lines hidden (view full) --- 87 /* reset */ 88 rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); 89 if (!IS_ERR(rst)) { 90 reset_control_assert(rst); 91 udelay(2); 92 reset_control_deassert(rst); 93 } 94 | 207 sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k"); 208 if (IS_ERR(sai->clk_x8k)) { 209 dev_err(&pdev->dev, "missing x8k parent clock\n"); 210 return PTR_ERR(sai->clk_x8k); 211 } 212 213 sai->clk_x11k = devm_clk_get(&pdev->dev, "x11k"); 214 if (IS_ERR(sai->clk_x11k)) { --- 11 unchanged lines hidden (view full) --- 226 /* reset */ 227 rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); 228 if (!IS_ERR(rst)) { 229 reset_control_assert(rst); 230 udelay(2); 231 reset_control_deassert(rst); 232 } 233 |
234 ret = stm32_sai_sync_add_provider(pdev, sai); 235 if (ret < 0) 236 return ret; 237 sai->set_sync = &stm32_sai_set_sync; 238 |
|
95 sai->pdev = pdev; 96 platform_set_drvdata(pdev, sai); 97 | 239 sai->pdev = pdev; 240 platform_set_drvdata(pdev, sai); 241 |
98 return of_platform_populate(np, NULL, NULL, &pdev->dev); | 242 ret = of_platform_populate(np, NULL, NULL, &pdev->dev); 243 if (ret < 0) 244 stm32_sai_sync_del_provider(np); 245 246 return ret; |
99} 100 101static int stm32_sai_remove(struct platform_device *pdev) 102{ 103 of_platform_depopulate(&pdev->dev); 104 | 247} 248 249static int stm32_sai_remove(struct platform_device *pdev) 250{ 251 of_platform_depopulate(&pdev->dev); 252 |
253 stm32_sai_sync_del_provider(pdev->dev.of_node); 254 |
|
105 return 0; 106} 107 108MODULE_DEVICE_TABLE(of, stm32_sai_ids); 109 110static struct platform_driver stm32_sai_driver = { 111 .driver = { 112 .name = "st,stm32-sai", --- 12 unchanged lines hidden --- | 255 return 0; 256} 257 258MODULE_DEVICE_TABLE(of, stm32_sai_ids); 259 260static struct platform_driver stm32_sai_driver = { 261 .driver = { 262 .name = "st,stm32-sai", --- 12 unchanged lines hidden --- |