mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
ASoC: stm32: add SAI driver
This patch implements SAI ASoC driver for STM32. Signed-off-by: olivier moysan <olivier.moysan@st.com> Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
committed by
Mark Brown
parent
b45c4f117b
commit
3e086edfe0
@@ -63,6 +63,7 @@ source "sound/soc/sh/Kconfig"
|
||||
source "sound/soc/sirf/Kconfig"
|
||||
source "sound/soc/spear/Kconfig"
|
||||
source "sound/soc/sti/Kconfig"
|
||||
source "sound/soc/stm/Kconfig"
|
||||
source "sound/soc/sunxi/Kconfig"
|
||||
source "sound/soc/tegra/Kconfig"
|
||||
source "sound/soc/txx9/Kconfig"
|
||||
|
||||
@@ -43,6 +43,7 @@ obj-$(CONFIG_SND_SOC) += sh/
|
||||
obj-$(CONFIG_SND_SOC) += sirf/
|
||||
obj-$(CONFIG_SND_SOC) += spear/
|
||||
obj-$(CONFIG_SND_SOC) += sti/
|
||||
obj-$(CONFIG_SND_SOC) += stm/
|
||||
obj-$(CONFIG_SND_SOC) += sunxi/
|
||||
obj-$(CONFIG_SND_SOC) += tegra/
|
||||
obj-$(CONFIG_SND_SOC) += txx9/
|
||||
|
||||
8
sound/soc/stm/Kconfig
Normal file
8
sound/soc/stm/Kconfig
Normal file
@@ -0,0 +1,8 @@
|
||||
menuconfig SND_SOC_STM32
|
||||
tristate "STMicroelectronics STM32 SOC audio support"
|
||||
depends on ARCH_STM32 || COMPILE_TEST
|
||||
depends on SND_SOC
|
||||
select SND_SOC_GENERIC_DMAENGINE_PCM
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
Say Y if you want to enable ASoC-support for STM32
|
||||
6
sound/soc/stm/Makefile
Normal file
6
sound/soc/stm/Makefile
Normal file
@@ -0,0 +1,6 @@
|
||||
# SAI
|
||||
snd-soc-stm32-sai-sub-objs := stm32_sai_sub.o
|
||||
obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai-sub.o
|
||||
|
||||
snd-soc-stm32-sai-objs := stm32_sai.o
|
||||
obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai.o
|
||||
115
sound/soc/stm/stm32_sai.c
Normal file
115
sound/soc/stm/stm32_sai.c
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* STM32 ALSA SoC Digital Audio Interface (SAI) driver.
|
||||
*
|
||||
* Copyright (C) 2016, STMicroelectronics - All Rights Reserved
|
||||
* Author(s): Olivier Moysan <olivier.moysan@st.com> for STMicroelectronics.
|
||||
*
|
||||
* License terms: GPL V2.0.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
#include <sound/core.h>
|
||||
|
||||
#include "stm32_sai.h"
|
||||
|
||||
static const struct of_device_id stm32_sai_ids[] = {
|
||||
{ .compatible = "st,stm32f4-sai", .data = (void *)SAI_STM32F4 },
|
||||
{}
|
||||
};
|
||||
|
||||
static int stm32_sai_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct stm32_sai_data *sai;
|
||||
struct reset_control *rst;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
const struct of_device_id *of_id;
|
||||
|
||||
sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
|
||||
if (!sai)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
of_id = of_match_device(stm32_sai_ids, &pdev->dev);
|
||||
if (of_id)
|
||||
sai->version = (enum stm32_sai_version)of_id->data;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k");
|
||||
if (IS_ERR(sai->clk_x8k)) {
|
||||
dev_err(&pdev->dev, "missing x8k parent clock\n");
|
||||
return PTR_ERR(sai->clk_x8k);
|
||||
}
|
||||
|
||||
sai->clk_x11k = devm_clk_get(&pdev->dev, "x11k");
|
||||
if (IS_ERR(sai->clk_x11k)) {
|
||||
dev_err(&pdev->dev, "missing x11k parent clock\n");
|
||||
return PTR_ERR(sai->clk_x11k);
|
||||
}
|
||||
|
||||
/* init irqs */
|
||||
sai->irq = platform_get_irq(pdev, 0);
|
||||
if (sai->irq < 0) {
|
||||
dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
|
||||
return sai->irq;
|
||||
}
|
||||
|
||||
/* reset */
|
||||
rst = reset_control_get(&pdev->dev, NULL);
|
||||
if (!IS_ERR(rst)) {
|
||||
reset_control_assert(rst);
|
||||
udelay(2);
|
||||
reset_control_deassert(rst);
|
||||
}
|
||||
|
||||
sai->pdev = pdev;
|
||||
platform_set_drvdata(pdev, sai);
|
||||
|
||||
return of_platform_populate(np, NULL, NULL, &pdev->dev);
|
||||
}
|
||||
|
||||
static int stm32_sai_remove(struct platform_device *pdev)
|
||||
{
|
||||
of_platform_depopulate(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_DEVICE_TABLE(of, stm32_sai_ids);
|
||||
|
||||
static struct platform_driver stm32_sai_driver = {
|
||||
.driver = {
|
||||
.name = "st,stm32-sai",
|
||||
.of_match_table = stm32_sai_ids,
|
||||
},
|
||||
.probe = stm32_sai_probe,
|
||||
.remove = stm32_sai_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(stm32_sai_driver);
|
||||
|
||||
MODULE_DESCRIPTION("STM32 Soc SAI Interface");
|
||||
MODULE_AUTHOR("Olivier Moysan, <olivier.moysan@st.com>");
|
||||
MODULE_ALIAS("platform:st,stm32-sai");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
200
sound/soc/stm/stm32_sai.h
Normal file
200
sound/soc/stm/stm32_sai.h
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* STM32 ALSA SoC Digital Audio Interface (SAI) driver.
|
||||
*
|
||||
* Copyright (C) 2016, STMicroelectronics - All Rights Reserved
|
||||
* Author(s): Olivier Moysan <olivier.moysan@st.com> for STMicroelectronics.
|
||||
*
|
||||
* License terms: GPL V2.0.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/******************** SAI Register Map **************************************/
|
||||
|
||||
/* common register */
|
||||
#define STM_SAI_GCR 0x00
|
||||
|
||||
/* Sub-block A&B registers offsets, relative to A&B sub-block addresses */
|
||||
#define STM_SAI_CR1_REGX 0x00 /* A offset: 0x04. B offset: 0x24 */
|
||||
#define STM_SAI_CR2_REGX 0x04
|
||||
#define STM_SAI_FRCR_REGX 0x08
|
||||
#define STM_SAI_SLOTR_REGX 0x0C
|
||||
#define STM_SAI_IMR_REGX 0x10
|
||||
#define STM_SAI_SR_REGX 0x14
|
||||
#define STM_SAI_CLRFR_REGX 0x18
|
||||
#define STM_SAI_DR_REGX 0x1C
|
||||
|
||||
/******************** Bit definition for SAI_GCR register *******************/
|
||||
#define SAI_GCR_SYNCIN_SHIFT 0
|
||||
#define SAI_GCR_SYNCIN_MASK GENMASK(1, SAI_GCR_SYNCIN_SHIFT)
|
||||
#define SAI_GCR_SYNCIN_SET(x) ((x) << SAI_GCR_SYNCIN_SHIFT)
|
||||
|
||||
#define SAI_GCR_SYNCOUT_SHIFT 4
|
||||
#define SAI_GCR_SYNCOUT_MASK GENMASK(5, SAI_GCR_SYNCOUT_SHIFT)
|
||||
#define SAI_GCR_SYNCOUT_SET(x) ((x) << SAI_GCR_SYNCOUT_SHIFT)
|
||||
|
||||
/******************* Bit definition for SAI_XCR1 register *******************/
|
||||
#define SAI_XCR1_RX_TX_SHIFT 0
|
||||
#define SAI_XCR1_RX_TX BIT(SAI_XCR1_RX_TX_SHIFT)
|
||||
#define SAI_XCR1_SLAVE_SHIFT 1
|
||||
#define SAI_XCR1_SLAVE BIT(SAI_XCR1_SLAVE_SHIFT)
|
||||
|
||||
#define SAI_XCR1_PRTCFG_SHIFT 2
|
||||
#define SAI_XCR1_PRTCFG_MASK GENMASK(3, SAI_XCR1_PRTCFG_SHIFT)
|
||||
#define SAI_XCR1_PRTCFG_SET(x) ((x) << SAI_XCR1_PRTCFG_SHIFT)
|
||||
|
||||
#define SAI_XCR1_DS_SHIFT 5
|
||||
#define SAI_XCR1_DS_MASK GENMASK(7, SAI_XCR1_DS_SHIFT)
|
||||
#define SAI_XCR1_DS_SET(x) ((x) << SAI_XCR1_DS_SHIFT)
|
||||
|
||||
#define SAI_XCR1_LSBFIRST_SHIFT 8
|
||||
#define SAI_XCR1_LSBFIRST BIT(SAI_XCR1_LSBFIRST_SHIFT)
|
||||
#define SAI_XCR1_CKSTR_SHIFT 9
|
||||
#define SAI_XCR1_CKSTR BIT(SAI_XCR1_CKSTR_SHIFT)
|
||||
|
||||
#define SAI_XCR1_SYNCEN_SHIFT 10
|
||||
#define SAI_XCR1_SYNCEN_MASK GENMASK(11, SAI_XCR1_SYNCEN_SHIFT)
|
||||
#define SAI_XCR1_SYNCEN_SET(x) ((x) << SAI_XCR1_SYNCEN_SHIFT)
|
||||
|
||||
#define SAI_XCR1_MONO_SHIFT 12
|
||||
#define SAI_XCR1_MONO BIT(SAI_XCR1_MONO_SHIFT)
|
||||
#define SAI_XCR1_OUTDRIV_SHIFT 13
|
||||
#define SAI_XCR1_OUTDRIV BIT(SAI_XCR1_OUTDRIV_SHIFT)
|
||||
#define SAI_XCR1_SAIEN_SHIFT 16
|
||||
#define SAI_XCR1_SAIEN BIT(SAI_XCR1_SAIEN_SHIFT)
|
||||
#define SAI_XCR1_DMAEN_SHIFT 17
|
||||
#define SAI_XCR1_DMAEN BIT(SAI_XCR1_DMAEN_SHIFT)
|
||||
#define SAI_XCR1_NODIV_SHIFT 19
|
||||
#define SAI_XCR1_NODIV BIT(SAI_XCR1_NODIV_SHIFT)
|
||||
|
||||
#define SAI_XCR1_MCKDIV_SHIFT 20
|
||||
#define SAI_XCR1_MCKDIV_WIDTH 4
|
||||
#define SAI_XCR1_MCKDIV_MASK GENMASK(24, SAI_XCR1_MCKDIV_SHIFT)
|
||||
#define SAI_XCR1_MCKDIV_SET(x) ((x) << SAI_XCR1_MCKDIV_SHIFT)
|
||||
#define SAI_XCR1_MCKDIV_MAX ((1 << SAI_XCR1_MCKDIV_WIDTH) - 1)
|
||||
|
||||
#define SAI_XCR1_OSR_SHIFT 26
|
||||
#define SAI_XCR1_OSR BIT(SAI_XCR1_OSR_SHIFT)
|
||||
|
||||
/******************* Bit definition for SAI_XCR2 register *******************/
|
||||
#define SAI_XCR2_FTH_SHIFT 0
|
||||
#define SAI_XCR2_FTH_MASK GENMASK(2, SAI_XCR2_FTH_SHIFT)
|
||||
#define SAI_XCR2_FTH_SET(x) ((x) << SAI_XCR2_FTH_SHIFT)
|
||||
|
||||
#define SAI_XCR2_FFLUSH_SHIFT 3
|
||||
#define SAI_XCR2_FFLUSH BIT(SAI_XCR2_FFLUSH_SHIFT)
|
||||
#define SAI_XCR2_TRIS_SHIFT 4
|
||||
#define SAI_XCR2_TRIS BIT(SAI_XCR2_TRIS_SHIFT)
|
||||
#define SAI_XCR2_MUTE_SHIFT 5
|
||||
#define SAI_XCR2_MUTE BIT(SAI_XCR2_MUTE_SHIFT)
|
||||
#define SAI_XCR2_MUTEVAL_SHIFT 6
|
||||
#define SAI_XCR2_MUTEVAL BIT(SAI_XCR2_MUTEVAL_SHIFT)
|
||||
|
||||
#define SAI_XCR2_MUTECNT_SHIFT 7
|
||||
#define SAI_XCR2_MUTECNT_MASK GENMASK(12, SAI_XCR2_MUTECNT_SHIFT)
|
||||
#define SAI_XCR2_MUTECNT_SET(x) ((x) << SAI_XCR2_MUTECNT_SHIFT)
|
||||
|
||||
#define SAI_XCR2_CPL_SHIFT 13
|
||||
#define SAI_XCR2_CPL BIT(SAI_XCR2_CPL_SHIFT)
|
||||
|
||||
#define SAI_XCR2_COMP_SHIFT 14
|
||||
#define SAI_XCR2_COMP_MASK GENMASK(15, SAI_XCR2_COMP_SHIFT)
|
||||
#define SAI_XCR2_COMP_SET(x) ((x) << SAI_XCR2_COMP_SHIFT)
|
||||
|
||||
/****************** Bit definition for SAI_XFRCR register *******************/
|
||||
#define SAI_XFRCR_FRL_SHIFT 0
|
||||
#define SAI_XFRCR_FRL_MASK GENMASK(7, SAI_XFRCR_FRL_SHIFT)
|
||||
#define SAI_XFRCR_FRL_SET(x) ((x) << SAI_XFRCR_FRL_SHIFT)
|
||||
|
||||
#define SAI_XFRCR_FSALL_SHIFT 8
|
||||
#define SAI_XFRCR_FSALL_MASK GENMASK(14, SAI_XFRCR_FSALL_SHIFT)
|
||||
#define SAI_XFRCR_FSALL_SET(x) ((x) << SAI_XFRCR_FSALL_SHIFT)
|
||||
|
||||
#define SAI_XFRCR_FSDEF_SHIFT 16
|
||||
#define SAI_XFRCR_FSDEF BIT(SAI_XFRCR_FSDEF_SHIFT)
|
||||
#define SAI_XFRCR_FSPOL_SHIFT 17
|
||||
#define SAI_XFRCR_FSPOL BIT(SAI_XFRCR_FSPOL_SHIFT)
|
||||
#define SAI_XFRCR_FSOFF_SHIFT 18
|
||||
#define SAI_XFRCR_FSOFF BIT(SAI_XFRCR_FSOFF_SHIFT)
|
||||
|
||||
/****************** Bit definition for SAI_XSLOTR register ******************/
|
||||
|
||||
#define SAI_XSLOTR_FBOFF_SHIFT 0
|
||||
#define SAI_XSLOTR_FBOFF_MASK GENMASK(4, SAI_XSLOTR_FBOFF_SHIFT)
|
||||
#define SAI_XSLOTR_FBOFF_SET(x) ((x) << SAI_XSLOTR_FBOFF_SHIFT)
|
||||
|
||||
#define SAI_XSLOTR_SLOTSZ_SHIFT 6
|
||||
#define SAI_XSLOTR_SLOTSZ_MASK GENMASK(7, SAI_XSLOTR_SLOTSZ_SHIFT)
|
||||
#define SAI_XSLOTR_SLOTSZ_SET(x) ((x) << SAI_XSLOTR_SLOTSZ_SHIFT)
|
||||
|
||||
#define SAI_XSLOTR_NBSLOT_SHIFT 8
|
||||
#define SAI_XSLOTR_NBSLOT_MASK GENMASK(11, SAI_XSLOTR_NBSLOT_SHIFT)
|
||||
#define SAI_XSLOTR_NBSLOT_SET(x) ((x) << SAI_XSLOTR_NBSLOT_SHIFT)
|
||||
|
||||
#define SAI_XSLOTR_SLOTEN_SHIFT 16
|
||||
#define SAI_XSLOTR_SLOTEN_WIDTH 16
|
||||
#define SAI_XSLOTR_SLOTEN_MASK GENMASK(31, SAI_XSLOTR_SLOTEN_SHIFT)
|
||||
#define SAI_XSLOTR_SLOTEN_SET(x) ((x) << SAI_XSLOTR_SLOTEN_SHIFT)
|
||||
|
||||
/******************* Bit definition for SAI_XIMR register *******************/
|
||||
#define SAI_XIMR_OVRUDRIE BIT(0)
|
||||
#define SAI_XIMR_MUTEDETIE BIT(1)
|
||||
#define SAI_XIMR_WCKCFGIE BIT(2)
|
||||
#define SAI_XIMR_FREQIE BIT(3)
|
||||
#define SAI_XIMR_CNRDYIE BIT(4)
|
||||
#define SAI_XIMR_AFSDETIE BIT(5)
|
||||
#define SAI_XIMR_LFSDETIE BIT(6)
|
||||
|
||||
#define SAI_XIMR_SHIFT 0
|
||||
#define SAI_XIMR_MASK GENMASK(6, SAI_XIMR_SHIFT)
|
||||
|
||||
/******************** Bit definition for SAI_XSR register *******************/
|
||||
#define SAI_XSR_OVRUDR BIT(0)
|
||||
#define SAI_XSR_MUTEDET BIT(1)
|
||||
#define SAI_XSR_WCKCFG BIT(2)
|
||||
#define SAI_XSR_FREQ BIT(3)
|
||||
#define SAI_XSR_CNRDY BIT(4)
|
||||
#define SAI_XSR_AFSDET BIT(5)
|
||||
#define SAI_XSR_LFSDET BIT(6)
|
||||
|
||||
#define SAI_XSR_SHIFT 0
|
||||
#define SAI_XSR_MASK GENMASK(6, SAI_XSR_SHIFT)
|
||||
|
||||
/****************** Bit definition for SAI_XCLRFR register ******************/
|
||||
#define SAI_XCLRFR_COVRUDR BIT(0)
|
||||
#define SAI_XCLRFR_CMUTEDET BIT(1)
|
||||
#define SAI_XCLRFR_CWCKCFG BIT(2)
|
||||
#define SAI_XCLRFR_CFREQ BIT(3)
|
||||
#define SAI_XCLRFR_CCNRDY BIT(4)
|
||||
#define SAI_XCLRFR_CAFSDET BIT(5)
|
||||
#define SAI_XCLRFR_CLFSDET BIT(6)
|
||||
|
||||
#define SAI_XCLRFR_SHIFT 0
|
||||
#define SAI_XCLRFR_MASK GENMASK(6, SAI_XCLRFR_SHIFT)
|
||||
|
||||
enum stm32_sai_version {
|
||||
SAI_STM32F4
|
||||
};
|
||||
|
||||
/**
|
||||
* struct stm32_sai_data - private data of SAI instance driver
|
||||
* @pdev: device data pointer
|
||||
* @clk_x8k: SAI parent clock for sampling frequencies multiple of 8kHz
|
||||
* @clk_x11k: SAI parent clock for sampling frequencies multiple of 11kHz
|
||||
* @version: SOC version
|
||||
* @irq: SAI interrupt line
|
||||
*/
|
||||
struct stm32_sai_data {
|
||||
struct platform_device *pdev;
|
||||
struct clk *clk_x8k;
|
||||
struct clk *clk_x11k;
|
||||
int version;
|
||||
int irq;
|
||||
};
|
||||
884
sound/soc/stm/stm32_sai_sub.c
Normal file
884
sound/soc/stm/stm32_sai_sub.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user