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/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 30 static const struct stm32_sai_conf stm32_sai_conf_f4 = { 31 .version = SAI_STM32F4, 32 }; 33 34 static const struct stm32_sai_conf stm32_sai_conf_h7 = { 35 .version = SAI_STM32H7, 36 }; 37 38 static 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 44 static 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; 50 void __iomem *base; 51 const struct of_device_id *of_id; 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); 58 base = devm_ioremap_resource(&pdev->dev, res); 59 if (IS_ERR(base)) 60 return PTR_ERR(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 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)) { 76 dev_err(&pdev->dev, "missing x11k parent clock\n"); 77 return PTR_ERR(sai->clk_x11k); 78 } 79 80 /* init irqs */ 81 sai->irq = platform_get_irq(pdev, 0); 82 if (sai->irq < 0) { 83 dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); 84 return sai->irq; 85 } 86 87 /* reset */ 88 rst = reset_control_get(&pdev->dev, NULL); 89 if (!IS_ERR(rst)) { 90 reset_control_assert(rst); 91 udelay(2); 92 reset_control_deassert(rst); 93 } 94 95 sai->pdev = pdev; 96 platform_set_drvdata(pdev, sai); 97 98 return of_platform_populate(np, NULL, NULL, &pdev->dev); 99 } 100 101 static int stm32_sai_remove(struct platform_device *pdev) 102 { 103 of_platform_depopulate(&pdev->dev); 104 105 return 0; 106 } 107 108 MODULE_DEVICE_TABLE(of, stm32_sai_ids); 109 110 static struct platform_driver stm32_sai_driver = { 111 .driver = { 112 .name = "st,stm32-sai", 113 .of_match_table = stm32_sai_ids, 114 }, 115 .probe = stm32_sai_probe, 116 .remove = stm32_sai_remove, 117 }; 118 119 module_platform_driver(stm32_sai_driver); 120 121 MODULE_DESCRIPTION("STM32 Soc SAI Interface"); 122 MODULE_AUTHOR("Olivier Moysan <olivier.moysan@st.com>"); 123 MODULE_ALIAS("platform:st,stm32-sai"); 124 MODULE_LICENSE("GPL v2"); 125