Alsa-devel
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
November 2013
- 132 participants
- 322 discussions
Hello all,
i have two laptops with internal dmic, each of them has 3 step mic
boost. One step 12 dB. The third step seems to me useless, since it give
more noise then sound.
I know there is code in patch_reatek.c to disable two steps.
But before i provide some patch, it will be interesting to know, how
much noise is too much? What is the best way to measure it?
Do i need some tools like this?
http://www.conrad.de/ce/de/product/100804/VOLTCRAFT-SL-100-Schallpegel-Mess…
--
Regards,
Oleksij
1
0
[alsa-devel] [RFC 0/9] ASoC: fsl-ssi: offline/online configuration and cleanups
by Markus Pargmann 18 Nov '13
by Markus Pargmann 18 Nov '13
18 Nov '13
Hi,
This patch series fixes some fsl-ssi code that does not act exactly as it is
described in the reference manuals.
The reference manuals before imx50 do mention that some register bits,
including TDMAE/RDMAE, should not be changed while the SSI unit is enabled
(SSIEN). At the same time the SDMA unit has a undefined request handling if
there are DMA requests before the SDMA engine and its channel is configured.
The reference manual states that SSI DMA requests are sent as soon as the FIFO
and the DMAE bits are enabled. It does not mention a dependency to SCR's TE/RE
bit.
To avoid sending DMA requests before a channel is configured, we have to
seperate the fsl-ssi behavior into offline and online configuration. SoCs
before imx50 have to use offline configuration while later SoC versions can use
online reconfiguration.
This series adds support for online configuration and cleans up the
configuration register code especially in fsl_ssi_trigger. At the end we have a
seperation between enable/disable logic and the actual configuration register
values used to enable/disable TX/RX.
I tested this series on mx53.
Regards,
Markus
Markus Pargmann (9):
ASoC: fsl-ssi: Drop AC97 debug register usage
ASoC: fsl-ssi: Move ac97 specific setup to seperate function
ASoC: fsl-ssi: Move sysfs stats to debugfs
ASoC: fsl-ssi: Add imx50-ssi and of_device_id matching
ASoC: fsl-ssi: Add offline_config flag
ASoC: fsl-ssi: Add configuration helper functions
ASoC: fsl-ssi: Move RX/TX configuration to seperate functions
ASoC: fsl-ssi: Drop ac97 specific trigger function
ARM: DTS: imx5* imx6*, use imx50-ssi
arch/arm/boot/dts/imx51.dtsi | 6 +-
arch/arm/boot/dts/imx53.dtsi | 6 +-
arch/arm/boot/dts/imx6qdl.dtsi | 6 +-
arch/arm/boot/dts/imx6sl.dtsi | 6 +-
sound/soc/fsl/fsl_ssi.c | 580 ++++++++++++++++++++++++++---------------
5 files changed, 389 insertions(+), 215 deletions(-)
--
1.8.4.2
2
12
[alsa-devel] [RFC 16/23] ASoC: omap: mcbsp, mcpdm, dmic: raw read and write endian fix
by Taras Kondratiuk 18 Nov '13
by Taras Kondratiuk 18 Nov '13
18 Nov '13
From: Victor Kamensky <victor.kamensky(a)linaro.org>
All OMAP IP blocks expect LE data, but CPU may operate in BE mode.
Need to use endian neutral functions to read/write h/w registers.
I.e instead of __raw_read[lw] and __raw_write[lw] functions code
need to use read[lw]_relaxed and write[lw]_relaxed functions.
If the first simply reads/writes register, the second will byteswap
it if host operates in BE mode.
Changes are trivial sed like replacement of __raw_xxx functions
with xxx_relaxed variant.
Signed-off-by: Victor Kamensky <victor.kamensky(a)linaro.org>
Signed-off-by: Taras Kondratiuk <taras.kondratiuk(a)linaro.org>
---
sound/soc/omap/mcbsp.c | 12 ++++++------
sound/soc/omap/omap-dmic.c | 4 ++--
sound/soc/omap/omap-mcpdm.c | 4 ++--
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c
index 83433fd..86c7538 100644
--- a/sound/soc/omap/mcbsp.c
+++ b/sound/soc/omap/mcbsp.c
@@ -36,10 +36,10 @@ static void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
if (mcbsp->pdata->reg_size == 2) {
((u16 *)mcbsp->reg_cache)[reg] = (u16)val;
- __raw_writew((u16)val, addr);
+ writew_relaxed((u16)val, addr);
} else {
((u32 *)mcbsp->reg_cache)[reg] = val;
- __raw_writel(val, addr);
+ writel_relaxed(val, addr);
}
}
@@ -48,22 +48,22 @@ static int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
if (mcbsp->pdata->reg_size == 2) {
- return !from_cache ? __raw_readw(addr) :
+ return !from_cache ? readw_relaxed(addr) :
((u16 *)mcbsp->reg_cache)[reg];
} else {
- return !from_cache ? __raw_readl(addr) :
+ return !from_cache ? readl_relaxed(addr) :
((u32 *)mcbsp->reg_cache)[reg];
}
}
static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
{
- __raw_writel(val, mcbsp->st_data->io_base_st + reg);
+ writel_relaxed(val, mcbsp->st_data->io_base_st + reg);
}
static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
{
- return __raw_readl(mcbsp->st_data->io_base_st + reg);
+ return readl_relaxed(mcbsp->st_data->io_base_st + reg);
}
#define MCBSP_READ(mcbsp, reg) \
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c
index 12e566b..1bd531d 100644
--- a/sound/soc/omap/omap-dmic.c
+++ b/sound/soc/omap/omap-dmic.c
@@ -61,12 +61,12 @@ struct omap_dmic {
static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val)
{
- __raw_writel(val, dmic->io_base + reg);
+ writel_relaxed(val, dmic->io_base + reg);
}
static inline int omap_dmic_read(struct omap_dmic *dmic, u16 reg)
{
- return __raw_readl(dmic->io_base + reg);
+ return readl_relaxed(dmic->io_base + reg);
}
static inline void omap_dmic_start(struct omap_dmic *dmic)
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index 90d2a7c..653ba1c 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -74,12 +74,12 @@ struct omap_mcpdm {
static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val)
{
- __raw_writel(val, mcpdm->io_base + reg);
+ writel_relaxed(val, mcpdm->io_base + reg);
}
static inline int omap_mcpdm_read(struct omap_mcpdm *mcpdm, u16 reg)
{
- return __raw_readl(mcpdm->io_base + reg);
+ return readl_relaxed(mcpdm->io_base + reg);
}
#ifdef DEBUG
--
1.7.9.5
5
4
Hi,
This short patch series contains three independent changes in pcm file plugin.
The first two of them are trivial fixes and should not cause any behavior changes and regressions.
The third one contains changes to make pcm_file.c access input/output files only when needed and thus to make its behavior more intuitive (from my point of view) (i.e., write to output file only on playback and read from input file only on capture).
The patches should apply cleanly against current HEAD (ae035b7fe5620fcaf4f5ea33ecabcf93b8e056cd).
2
8
[alsa-devel] [PATCH 1/2] ASoC: wm8940: Convert to table based control and DAPM init
by Mark Brown 17 Nov '13
by Mark Brown 17 Nov '13
17 Nov '13
From: Mark Brown <broonie(a)linaro.org>
Signed-off-by: Mark Brown <broonie(a)linaro.org>
---
sound/soc/codecs/wm8940.c | 28 +++++++---------------------
1 file changed, 7 insertions(+), 21 deletions(-)
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index b1591c6..4858b5c 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -264,7 +264,7 @@ static const struct snd_soc_dapm_widget wm8940_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("AUX"),
};
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8940_dapm_routes[] = {
/* Mono output mixer */
{"Mono Mixer", "PCM Playback Switch", "DAC"},
{"Mono Mixer", "Aux Playback Switch", "Aux Input"},
@@ -296,21 +296,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"ADC", NULL, "Boost Mixer"},
};
-static int wm8940_add_widgets(struct snd_soc_codec *codec)
-{
- struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret;
-
- ret = snd_soc_dapm_new_controls(dapm, wm8940_dapm_widgets,
- ARRAY_SIZE(wm8940_dapm_widgets));
- if (ret)
- goto error_ret;
- ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-error_ret:
- return ret;
-}
-
#define wm8940_reset(c) snd_soc_write(c, WM8940_SOFTRESET, 0);
static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
@@ -716,11 +701,6 @@ static int wm8940_probe(struct snd_soc_codec *codec)
return ret;
}
- ret = snd_soc_add_codec_controls(codec, wm8940_snd_controls,
- ARRAY_SIZE(wm8940_snd_controls));
- if (ret)
- return ret;
- ret = wm8940_add_widgets(codec);
return ret;
}
@@ -736,6 +716,12 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8940 = {
.suspend = wm8940_suspend,
.resume = wm8940_resume,
.set_bias_level = wm8940_set_bias_level,
+ .controls = wm8940_snd_controls,
+ .num_controls = ARRAY_SIZE(wm8940_snd_controls),
+ .dapm_widgets = wm8940_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wm8940_dapm_widgets),
+ .dapm_routes = wm8940_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(wm8940_dapm_routes),
.reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults),
.reg_word_size = sizeof(u16),
.reg_cache_default = wm8940_reg_defaults,
--
1.8.4.2
3
4
Hello,
the default prefix for alsa-utils is /usr however the udev rules directory
is /lib/udev/rules.d thus on setups with separate partition for /usr the
binaries, from /usr/bin and /usr/sbin, will likely not be available during
the boot process and the udev rule will fail to restore the state.
I suggest that the udev rules directory follows the prefix or append /usr
to it to resolve this.
Cheers!
4
12
This driver adds support for digital audio (I2S)
for the BCM2835 SoC that is used by the
Raspberry Pi. External audio codecs can be
connected to the Raspberry Pi via P5 header.
It relies on cyclic DMA engine support for BCM2835.
Signed-off-by: Florian Meier <florian.meier(a)koalo.de>
---
Second version.
- snd_pcm_hardware struct was removed - now calculated by core.
- FIFO address is now calculated from the device tree parameters.
- In a case of over- or underrun, only the associated FIFO is cleared.
According to the datasheet this might induce problems with
channel swapping, but testing has shown no evidence.
- dai->active is used instead of requesting state from hardware
or building up own method.
- Some minor fixes
arch/arm/boot/dts/bcm2835.dtsi | 12 +
sound/soc/Kconfig | 1 +
sound/soc/Makefile | 1 +
sound/soc/bcm/Kconfig | 15 +
sound/soc/bcm/Makefile | 7 +
sound/soc/bcm/bcm2835-i2s.c | 892 ++++++++++++++++++++++++++++++++++++++++
sound/soc/bcm/bcm2835-pcm.c | 52 +++
sound/soc/bcm/bcm2835-pcm.h | 29 ++
8 files changed, 1009 insertions(+)
create mode 100644 sound/soc/bcm/Kconfig
create mode 100644 sound/soc/bcm/Makefile
create mode 100644 sound/soc/bcm/bcm2835-i2s.c
create mode 100644 sound/soc/bcm/bcm2835-pcm.c
create mode 100644 sound/soc/bcm/bcm2835-pcm.h
diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi
index 7389405..facba9e 100644
--- a/arch/arm/boot/dts/bcm2835.dtsi
+++ b/arch/arm/boot/dts/bcm2835.dtsi
@@ -126,6 +126,18 @@
dma-requests = <32>;
dma-channel-mask = <0x7f35>;
};
+
+ bcm2835_i2s: i2s@7e203000 {
+ compatible = "brcm,bcm2835-i2s";
+ reg = < 0x7e203000 0x20
+ 0x7e101098 0x02>;
+
+ dmas = <&dma 2
+ &dma 3>;
+ dma-names = "tx", "rx";
+
+ status = "disabled";
+ };
};
clocks {
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 5138b84..a5e3a70 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -33,6 +33,7 @@ config SND_SOC_GENERIC_DMAENGINE_PCM
# All the supported SoCs
source "sound/soc/atmel/Kconfig"
source "sound/soc/au1x/Kconfig"
+source "sound/soc/bcm/Kconfig"
source "sound/soc/blackfin/Kconfig"
source "sound/soc/cirrus/Kconfig"
source "sound/soc/davinci/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 8b9e701..b52d4aa 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_SND_SOC) += codecs/
obj-$(CONFIG_SND_SOC) += generic/
obj-$(CONFIG_SND_SOC) += atmel/
obj-$(CONFIG_SND_SOC) += au1x/
+obj-$(CONFIG_SND_SOC) += bcm/
obj-$(CONFIG_SND_SOC) += blackfin/
obj-$(CONFIG_SND_SOC) += cirrus/
obj-$(CONFIG_SND_SOC) += davinci/
diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig
new file mode 100644
index 0000000..93619ec
--- /dev/null
+++ b/sound/soc/bcm/Kconfig
@@ -0,0 +1,15 @@
+config SND_BCM2835_SOC_I2S
+ tristate
+
+config SND_BCM2835_SOC
+ tristate "SoC Audio support for the Broadcom BCM2835 I2S module"
+ depends on ARCH_BCM2835
+ select SND_SOC_DMAENGINE_PCM
+ select DMADEVICES
+ select DMA_BCM2835
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ select REGMAP_MMIO
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the BCM2835 I2S interface. You will also need
+ to select the audio interfaces to support below.
diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile
new file mode 100644
index 0000000..46d8cfb
--- /dev/null
+++ b/sound/soc/bcm/Makefile
@@ -0,0 +1,7 @@
+# BCM2835 Platform Support
+snd-soc-bcm2835-objs := bcm2835-pcm.o
+snd-soc-bcm2835-i2s-objs := bcm2835-i2s.o
+
+obj-$(CONFIG_SND_BCM2835_SOC) += snd-soc-bcm2835.o
+obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd-soc-bcm2835-i2s.o
+
diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c
new file mode 100644
index 0000000..5aae315
--- /dev/null
+++ b/sound/soc/bcm/bcm2835-i2s.c
@@ -0,0 +1,892 @@
+/*
+ * ALSA SoC I2S Audio Layer for Broadcom BCM2835 SoC
+ *
+ * Author: Florian Meier <florian.meier(a)koalo.de>
+ * Copyright 2013
+ *
+ * based on
+ * Raspberry Pi PCM I2S ALSA Driver
+ * Copyright (c) by Phil Poole 2013
+ *
+ * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor
+ * Vladimir Barinov, <vbarinov(a)embeddedalley.com>
+ * Copyright (C) 2007 MontaVista Software, Inc., <source(a)mvista.com>
+ *
+ * OMAP ALSA SoC DAI driver using McBSP port
+ * Copyright (C) 2008 Nokia Corporation
+ * Contact: Jarkko Nikula <jarkko.nikula(a)bitmer.com>
+ * Peter Ujfalusi <peter.ujfalusi(a)ti.com>
+ *
+ * Freescale SSI ALSA SoC Digital Audio Interface (DAI) driver
+ * Author: Timur Tabi <timur(a)freescale.com>
+ * Copyright 2007-2010 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "bcm2835-pcm.h"
+
+/* Clock registers */
+#define BCM2835_CLK_PCMCTL_REG 0x00
+#define BCM2835_CLK_PCMDIV_REG 0x04
+
+/* Clock register settings */
+#define BCM2835_CLK_PASSWD (0x5a000000)
+#define BCM2835_CLK_PASSWD_MASK (0xff000000)
+#define BCM2835_CLK_MASH(v) ((v) << 9)
+#define BCM2835_CLK_FLIP (1 << 8)
+#define BCM2835_CLK_BUSY (1 << 7)
+#define BCM2835_CLK_KILL (1 << 5)
+#define BCM2835_CLK_ENAB (1 << 4)
+#define BCM2835_CLK_SRC(v) (v)
+
+#define BCM2835_CLK_DIVI(v) ((v) << 12)
+#define BCM2835_CLK_DIVF(v) (v)
+
+enum {
+ BCM2835_CLK_MASH_0 = 0,
+ BCM2835_CLK_MASH_1,
+ BCM2835_CLK_MASH_2,
+ BCM2835_CLK_MASH_3,
+};
+
+enum {
+ BCM2835_CLK_SRC_GND = 0,
+ BCM2835_CLK_SRC_OSC,
+ BCM2835_CLK_SRC_DBG0,
+ BCM2835_CLK_SRC_DBG1,
+ BCM2835_CLK_SRC_PLLA,
+ BCM2835_CLK_SRC_PLLC,
+ BCM2835_CLK_SRC_PLLD,
+ BCM2835_CLK_SRC_HDMI,
+};
+
+/* Most clocks are not useable (freq = 0) */
+static const unsigned int bcm2835_clk_freq[BCM2835_CLK_SRC_HDMI+1] = {
+ [BCM2835_CLK_SRC_GND] = 0,
+ [BCM2835_CLK_SRC_OSC] = 19200000,
+ [BCM2835_CLK_SRC_DBG0] = 0,
+ [BCM2835_CLK_SRC_DBG1] = 0,
+ [BCM2835_CLK_SRC_PLLA] = 0,
+ [BCM2835_CLK_SRC_PLLC] = 0,
+ [BCM2835_CLK_SRC_PLLD] = 500000000,
+ [BCM2835_CLK_SRC_HDMI] = 0,
+};
+
+/* I2S registers */
+#define BCM2835_I2S_CS_A_REG 0x00
+#define BCM2835_I2S_FIFO_A_REG 0x04
+#define BCM2835_I2S_MODE_A_REG 0x08
+#define BCM2835_I2S_RXC_A_REG 0x0c
+#define BCM2835_I2S_TXC_A_REG 0x10
+#define BCM2835_I2S_DREQ_A_REG 0x14
+#define BCM2835_I2S_INTEN_A_REG 0x18
+#define BCM2835_I2S_INTSTC_A_REG 0x1c
+#define BCM2835_I2S_GRAY_REG 0x20
+
+/* I2S register settings */
+#define BCM2835_I2S_STBY (1 << 25)
+#define BCM2835_I2S_SYNC (1 << 24)
+#define BCM2835_I2S_RXSEX (1 << 23)
+#define BCM2835_I2S_RXF (1 << 22)
+#define BCM2835_I2S_TXE (1 << 21)
+#define BCM2835_I2S_RXD (1 << 20)
+#define BCM2835_I2S_TXD (1 << 19)
+#define BCM2835_I2S_RXR (1 << 18)
+#define BCM2835_I2S_TXW (1 << 17)
+#define BCM2835_I2S_CS_RXERR (1 << 16)
+#define BCM2835_I2S_CS_TXERR (1 << 15)
+#define BCM2835_I2S_RXSYNC (1 << 14)
+#define BCM2835_I2S_TXSYNC (1 << 13)
+#define BCM2835_I2S_DMAEN (1 << 9)
+#define BCM2835_I2S_RXTHR(v) ((v) << 7)
+#define BCM2835_I2S_TXTHR(v) ((v) << 5)
+#define BCM2835_I2S_RXCLR (1 << 4)
+#define BCM2835_I2S_TXCLR (1 << 3)
+#define BCM2835_I2S_TXON (1 << 2)
+#define BCM2835_I2S_RXON (1 << 1)
+#define BCM2835_I2S_EN (1)
+
+#define BCM2835_I2S_CLKDIS (1 << 28)
+#define BCM2835_I2S_PDMN (1 << 27)
+#define BCM2835_I2S_PDME (1 << 26)
+#define BCM2835_I2S_FRXP (1 << 25)
+#define BCM2835_I2S_FTXP (1 << 24)
+#define BCM2835_I2S_CLKM (1 << 23)
+#define BCM2835_I2S_CLKI (1 << 22)
+#define BCM2835_I2S_FSM (1 << 21)
+#define BCM2835_I2S_FSI (1 << 20)
+#define BCM2835_I2S_FLEN(v) ((v) << 10)
+#define BCM2835_I2S_FSLEN(v) (v)
+
+#define BCM2835_I2S_CHWEX (1 << 15)
+#define BCM2835_I2S_CHEN (1 << 14)
+#define BCM2835_I2S_CHPOS(v) ((v) << 4)
+#define BCM2835_I2S_CHWID(v) (v)
+#define BCM2835_I2S_CH1(v) ((v) << 16)
+#define BCM2835_I2S_CH2(v) (v)
+
+#define BCM2835_I2S_TX_PANIC(v) ((v) << 24)
+#define BCM2835_I2S_RX_PANIC(v) ((v) << 16)
+#define BCM2835_I2S_TX(v) ((v) << 8)
+#define BCM2835_I2S_RX(v) (v)
+
+#define BCM2835_I2S_INT_RXERR (1 << 3)
+#define BCM2835_I2S_INT_TXERR (1 << 2)
+#define BCM2835_I2S_INT_RXR (1 << 1)
+#define BCM2835_I2S_INT_TXW (1 << 0)
+
+/* I2S DMA interface */
+/* FIXME: Needs IOMMU support */
+#define BCM2835_VCMMU_SHIFT (0x7E000000 - 0x20000000)
+
+/* General device struct */
+struct bcm2835_i2s_dev {
+ struct device *dev;
+ struct snd_dmaengine_dai_dma_data dma_data[2];
+ unsigned int fmt;
+
+ struct regmap *i2s_regmap;
+ struct regmap *clk_regmap;
+};
+
+static void bcm2835_i2s_start_clock(struct bcm2835_i2s_dev *dev)
+{
+ /*
+ * Start the clock if in master mode.
+ */
+ unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK;
+
+ switch (master) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBS_CFM:
+ regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG,
+ BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB,
+ BCM2835_CLK_PASSWD | BCM2835_CLK_ENAB);
+ break;
+ default:
+ break;
+ }
+}
+
+static void bcm2835_i2s_stop_clock(struct bcm2835_i2s_dev *dev)
+{
+ uint32_t clkreg;
+ int timeout = 1000;
+
+ /* stop clock */
+ regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG,
+ BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB,
+ BCM2835_CLK_PASSWD);
+
+ /* wait for the BUSY flag going down */
+ while (timeout > 0) {
+ timeout--;
+
+ regmap_read(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, &clkreg);
+ if (!(clkreg & BCM2835_CLK_BUSY))
+ break;
+ }
+
+ if (timeout <= 0) {
+ /* KILL the clock */
+ dev_err(dev->dev, "I2S clock didn't stop. Kill the clock!\n");
+ regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG,
+ BCM2835_CLK_KILL | BCM2835_CLK_PASSWD_MASK,
+ BCM2835_CLK_KILL | BCM2835_CLK_PASSWD);
+ }
+}
+
+static void bcm2835_i2s_clear_fifos(struct bcm2835_i2s_dev *dev,
+ bool tx, bool rx)
+{
+ int timeout = 1000;
+ uint32_t syncval;
+ uint32_t csreg;
+ uint32_t i2s_active_state;
+ uint32_t clkreg;
+ uint32_t clk_active_state;
+ uint32_t off;
+ uint32_t clr;
+
+ off = tx ? BCM2835_I2S_TXON : 0;
+ off |= rx ? BCM2835_I2S_RXON : 0;
+
+ clr = tx ? BCM2835_I2S_TXCLR : 0;
+ clr |= rx ? BCM2835_I2S_RXCLR : 0;
+
+ /* Backup the current state */
+ regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg);
+ i2s_active_state = csreg & (BCM2835_I2S_RXON | BCM2835_I2S_TXON);
+
+ regmap_read(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, &clkreg);
+ clk_active_state = clkreg & BCM2835_CLK_ENAB;
+
+ /* Start clock if not running */
+ if (!clk_active_state) {
+ regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG,
+ BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB,
+ BCM2835_CLK_PASSWD | BCM2835_CLK_ENAB);
+ }
+
+ /* Stop I2S module */
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, off, 0);
+
+ /*
+ * Clear the FIFOs
+ * Requires at least 2 PCM clock cycles to take effect
+ */
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, clr, -1);
+
+ /* Wait for 2 PCM clock cycles */
+
+ /*
+ * Toggle the SYNC flag - after 2 PCM clock cycles it can be read back
+ * FIXME: This does not seem to work for slave mode!
+ */
+ regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &syncval);
+ syncval &= BCM2835_I2S_SYNC;
+
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+ BCM2835_I2S_SYNC, ~syncval);
+
+ /* Wait for the SYNC flag changing it's state */
+ while (timeout > 0) {
+ timeout--;
+
+ regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg);
+ if ((csreg & BCM2835_I2S_SYNC) != syncval)
+ break;
+ }
+
+ if (timeout <= 0)
+ dev_err(dev->dev, "I2S SYNC error!\n");
+
+ /* Stop clock if it was not running before */
+ if (!clk_active_state)
+ bcm2835_i2s_stop_clock(dev);
+
+ /* Restore I2S state */
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+ BCM2835_I2S_RXON | BCM2835_I2S_TXON, i2s_active_state);
+}
+
+static int bcm2835_i2s_set_dai_fmt(struct snd_soc_dai *dai,
+ unsigned int fmt)
+{
+ struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+ dev->fmt = fmt;
+ return 0;
+}
+
+static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ unsigned int sampling_rate = params_rate(params);
+ unsigned int data_length, data_delay, half_frame;
+ unsigned int ch1pos, ch2pos, mode, format;
+ unsigned int mash = BCM2835_CLK_MASH_1;
+ unsigned int divi, divf, target_frequency;
+ int clk_src = -1;
+ unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK;
+ uint32_t bit_master = (master == SND_SOC_DAIFMT_CBS_CFS
+ || master == SND_SOC_DAIFMT_CBS_CFM);
+
+ uint32_t frame_master = (master == SND_SOC_DAIFMT_CBS_CFS
+ || master == SND_SOC_DAIFMT_CBM_CFS);
+ uint32_t csreg;
+
+ /*
+ * If a stream is already enabled,
+ * the registers are already set properly.
+ */
+ regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg);
+
+ if (csreg & (BCM2835_I2S_TXON | BCM2835_I2S_RXON))
+ return 0;
+
+ /*
+ * Adjust the data length according to the format.
+ * We prefill the half frame length with an integer
+ * divider of 2400 as explained at the clock settings.
+ * Maybe it is overwritten there, if the Integer mode
+ * does not apply.
+ */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ data_length = 16;
+ half_frame = 20;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ data_length = 32;
+ half_frame = 40;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * Clock Settings
+ *
+ * The target frequency of the bit clock is
+ * sampling rate * frame length
+ *
+ * Integer mode:
+ * Sampling rates that are multiples of 8000 kHz
+ * can be driven by the oscillator of 19.2 MHz
+ * with an integer divider as long as the frame length
+ * is an integer divider of 19200000/8000=2400 as set up above.
+ * This is no longer possible if the sampling rate
+ * is too high (e.g. 192 kHz), because the oscillator is too slow.
+ *
+ * MASH mode:
+ * For all other sampling rates, it is not possible to
+ * have an integer divider. Approximate the clock
+ * with the MASH module that induces a slight frequency
+ * variance. To minimize that it is best to have the fastest
+ * clock here. That is PLLD with 500 MHz.
+ */
+ target_frequency = sampling_rate*half_frame*2;
+ clk_src = BCM2835_CLK_SRC_OSC;
+ mash = BCM2835_CLK_MASH_0;
+
+ if (bcm2835_clk_freq[clk_src] % target_frequency == 0
+ && bit_master && frame_master) {
+ divi = bcm2835_clk_freq[clk_src]/target_frequency;
+ divf = 0;
+ } else {
+ uint64_t dividend;
+
+ /*
+ * Overwrite half frame length, because the
+ * above trick is not needed.
+ * This is fixed, because a bit clock of 64*fs
+ * seems to be what most codecs want.
+ * Is it necessary to have this dynamic?
+ */
+ half_frame = 32;
+ target_frequency = sampling_rate*half_frame*2;
+
+ clk_src = BCM2835_CLK_SRC_PLLD;
+ mash = BCM2835_CLK_MASH_1;
+
+ dividend = bcm2835_clk_freq[clk_src];
+ dividend *= 1024;
+ do_div(dividend, target_frequency);
+ divi = dividend / 1024;
+ divf = dividend % 1024;
+ }
+
+ /* Set clock divider */
+ regmap_write(dev->clk_regmap, BCM2835_CLK_PCMDIV_REG, BCM2835_CLK_PASSWD
+ | BCM2835_CLK_DIVI(divi)
+ | BCM2835_CLK_DIVF(divf));
+
+ /* Setup clock, but don't start it yet */
+ regmap_write(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, BCM2835_CLK_PASSWD
+ | BCM2835_CLK_MASH(mash)
+ | BCM2835_CLK_SRC(clk_src));
+
+ /* Setup the frame format */
+ format = BCM2835_I2S_CHEN;
+
+ if (data_length > 24)
+ format |= BCM2835_I2S_CHWEX;
+
+ format |= BCM2835_I2S_CHWID((data_length-8)&0xf);
+
+ switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ data_delay = 1;
+ break;
+ default:
+ /* TODO
+ * Others are possible but are not implemented at the moment.
+ */
+ dev_err(dev->dev, "%s:bad format\n", __func__);
+ return -EINVAL;
+ }
+
+ ch1pos = data_delay;
+ ch2pos = half_frame+data_delay;
+
+ switch (params_channels(params)) {
+ case 2:
+ format = BCM2835_I2S_CH1(format) | BCM2835_I2S_CH2(format);
+ format |= BCM2835_I2S_CH1(BCM2835_I2S_CHPOS(ch1pos));
+ format |= BCM2835_I2S_CH2(BCM2835_I2S_CHPOS(ch2pos));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * Set format for both streams.
+ * We cannot set another frame length
+ * (and therefore word length) anyway,
+ * so the format will be the same.
+ */
+ regmap_write(dev->i2s_regmap, BCM2835_I2S_RXC_A_REG, format);
+ regmap_write(dev->i2s_regmap, BCM2835_I2S_TXC_A_REG, format);
+
+ /* Setup the I2S mode */
+ mode = 0;
+
+ if (data_length <= 16) {
+ /*
+ * Use frame packed mode (2 channels per 32 bit word)
+ * We cannot set another frame length in the second stream
+ * (and therefore word length) anyway,
+ * so the format will be the same.
+ */
+ mode |= BCM2835_I2S_FTXP | BCM2835_I2S_FRXP;
+ }
+
+ mode |= BCM2835_I2S_FLEN(half_frame*2-1);
+ mode |= BCM2835_I2S_FSLEN(half_frame);
+
+ /* master or slave? */
+ switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* cpu is master */
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ /*
+ * codec is bit clock master
+ * cpu is frame master
+ */
+ mode |= BCM2835_I2S_CLKM;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ /*
+ * codec is frame master
+ * cpu is bit clock master
+ */
+ mode |= BCM2835_I2S_FSM;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* codec is master */
+ mode |= BCM2835_I2S_CLKM;
+ mode |= BCM2835_I2S_FSM;
+ break;
+ default:
+ dev_err(dev->dev, "%s:bad master\n", __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * Invert clocks?
+ *
+ * The BCM approach seems to be inverted to the classical I2S approach.
+ */
+ switch (dev->fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ /* none - therefore, both for BCM */
+ mode |= BCM2835_I2S_CLKI;
+ mode |= BCM2835_I2S_FSI;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ /* both - therefore, none for BCM*/
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ /*
+ * invert only frame sync - therefore,
+ * invert only bit clock for BCM
+ */
+ mode |= BCM2835_I2S_CLKI;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ /*
+ * invert only bit clock - therefore,
+ * invert only frame sync for BCM
+ */
+ mode |= BCM2835_I2S_FSI;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_write(dev->i2s_regmap, BCM2835_I2S_MODE_A_REG, mode);
+
+
+ /* Setup the DMA parameters */
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+ BCM2835_I2S_RXTHR(1)
+ | BCM2835_I2S_TXTHR(1)
+ | BCM2835_I2S_DMAEN, -1);
+
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_DREQ_A_REG,
+ BCM2835_I2S_TX_PANIC(0x10)
+ | BCM2835_I2S_RX_PANIC(0x30)
+ | BCM2835_I2S_TX(0x30)
+ | BCM2835_I2S_RX(0x20), -1);
+
+ /* Clear FIFOs */
+ bcm2835_i2s_clear_fifos(dev, true, true);
+
+ return 0;
+}
+
+
+static int bcm2835_i2s_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+ uint32_t cs_reg;
+
+ bcm2835_i2s_start_clock(dev);
+
+ /*
+ * Clear both FIFOs if the one that should be started
+ * is not empty at the moment. This should only happen
+ * after overrun. Otherwise, hw_params would have cleared
+ * the FIFO.
+ */
+ regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &cs_reg);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK
+ && !(cs_reg & BCM2835_I2S_TXE))
+ bcm2835_i2s_clear_fifos(dev, true, false);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE
+ && (cs_reg & BCM2835_I2S_RXD))
+ bcm2835_i2s_clear_fifos(dev, false, true);
+
+ return 0;
+}
+
+static void bcm2835_i2s_stop(struct bcm2835_i2s_dev *dev,
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ uint32_t mask;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ mask = BCM2835_I2S_RXON;
+ else
+ mask = BCM2835_I2S_TXON;
+
+ regmap_update_bits(dev->i2s_regmap,
+ BCM2835_I2S_CS_A_REG, mask, 0);
+
+ /* Stop also the clock when not SND_SOC_DAIFMT_CONT */
+ if (!dai->active && !(dev->fmt & SND_SOC_DAIFMT_CONT))
+ bcm2835_i2s_stop_clock(dev);
+
+}
+
+static int bcm2835_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+ uint32_t mask;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ bcm2835_i2s_start_clock(dev);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ mask = BCM2835_I2S_RXON;
+ else
+ mask = BCM2835_I2S_TXON;
+
+ regmap_update_bits(dev->i2s_regmap,
+ BCM2835_I2S_CS_A_REG, mask, mask);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ bcm2835_i2s_stop(dev, substream, dai);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int bcm2835_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ if (!dai->active) {
+ /* should this still be running stop it */
+ bcm2835_i2s_stop_clock(dev);
+
+ /* enable PCM block */
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+ BCM2835_I2S_EN, -1);
+
+ /*
+ * Disable STBY
+ * Requires at least 4 PCM clock cycles to take effect
+ */
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+ BCM2835_I2S_STBY, -1);
+ }
+
+ return 0;
+}
+
+static void bcm2835_i2s_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ bcm2835_i2s_stop(dev, substream, dai);
+
+ /* If both streams are stopped, disable module and clock */
+ if (!dai->active) {
+ /* Disable the module */
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+ BCM2835_I2S_EN, 0);
+
+ /*
+ * Stopping clock is necessary, because stop does
+ * not stop the clock when SND_SOC_DAIFMT_CONT
+ */
+ bcm2835_i2s_stop_clock(dev);
+ }
+}
+
+static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = {
+ .startup = bcm2835_i2s_startup,
+ .shutdown = bcm2835_i2s_shutdown,
+ .prepare = bcm2835_i2s_prepare,
+ .trigger = bcm2835_i2s_trigger,
+ .hw_params = bcm2835_i2s_hw_params,
+ .set_fmt = bcm2835_i2s_set_dai_fmt,
+};
+
+static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+ struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr_width =
+ DMA_SLAVE_BUSWIDTH_4_BYTES;
+ dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr_width =
+ DMA_SLAVE_BUSWIDTH_4_BYTES;
+
+ /* TODO other burst parameters possible? */
+ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].maxburst = 2;
+ dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].maxburst = 2;
+
+ dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+ dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver bcm2835_i2s_dai = {
+ .name = "bcm2835-i2s",
+ .probe = bcm2835_i2s_dai_probe,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE
+ | SNDRV_PCM_FMTBIT_S32_LE
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE
+ | SNDRV_PCM_FMTBIT_S32_LE
+ },
+ .ops = &bcm2835_i2s_dai_ops,
+ .symmetric_rates = 1
+};
+
+static bool bcm2835_i2s_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case BCM2835_I2S_CS_A_REG:
+ case BCM2835_I2S_FIFO_A_REG:
+ case BCM2835_I2S_INTSTC_A_REG:
+ case BCM2835_I2S_GRAY_REG:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static bool bcm2835_i2s_precious_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case BCM2835_I2S_FIFO_A_REG:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static bool bcm2835_clk_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case BCM2835_CLK_PCMCTL_REG:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static const struct regmap_config bcm2835_regmap_config[] = {
+ {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = BCM2835_I2S_GRAY_REG,
+ .precious_reg = bcm2835_i2s_precious_reg,
+ .volatile_reg = bcm2835_i2s_volatile_reg,
+ .cache_type = REGCACHE_RBTREE,
+ },
+ {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = BCM2835_CLK_PCMDIV_REG,
+ .volatile_reg = bcm2835_clk_volatile_reg,
+ .cache_type = REGCACHE_RBTREE,
+ },
+};
+
+static const struct snd_soc_component_driver bcm2835_i2s_component = {
+ .name = "bcm2835-i2s-comp",
+};
+
+static int bcm2835_i2s_probe(struct platform_device *pdev)
+{
+ struct bcm2835_i2s_dev *dev;
+ int i;
+ int ret;
+ struct regmap *regmap[2];
+ struct resource *mem[2];
+
+ /* request both ioareas */
+ for (i = 0; i <= 1; i++) {
+ void __iomem *base;
+
+ mem[i] = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (!mem[i]) {
+ dev_err(&pdev->dev, "I2S probe: Memory resource could not be found.\n");
+ return -ENODEV;
+ }
+
+ base = devm_ioremap_resource(&pdev->dev, mem[i]);
+ if (!base) {
+ dev_err(&pdev->dev, "I2S probe: ioremap failed.\n");
+ return -ENOMEM;
+ }
+
+ regmap[i] = devm_regmap_init_mmio(&pdev->dev, base,
+ &bcm2835_regmap_config[i]);
+ if (IS_ERR(regmap[i])) {
+ dev_err(&pdev->dev, "I2S probe: regmap init failed\n");
+ return PTR_ERR(regmap[i]);
+ }
+ }
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(struct bcm2835_i2s_dev),
+ GFP_KERNEL);
+ if (!dev) {
+ dev_err(&pdev->dev, "I2S probe: kzalloc failed.\n");
+ return -ENOMEM;
+ }
+
+ dev->i2s_regmap = regmap[0];
+ dev->clk_regmap = regmap[1];
+
+ /* Set the DMA address */
+ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
+ (dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG
+ + BCM2835_VCMMU_SHIFT;
+
+ dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
+ (dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG
+ + BCM2835_VCMMU_SHIFT;
+
+ /* Store the pdev */
+ dev->dev = &pdev->dev;
+ dev_set_drvdata(&pdev->dev, dev);
+
+ ret = snd_soc_register_component(&pdev->dev,
+ &bcm2835_i2s_component, &bcm2835_i2s_dai, 1);
+
+ if (ret) {
+ dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ ret = bcm2835_pcm_platform_register(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
+ snd_soc_unregister_component(&pdev->dev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id bcm2835_i2s_of_match[] = {
+ { .compatible = "brcm,bcm2835-i2s", },
+ {},
+};
+
+static int bcm2835_i2s_remove(struct platform_device *pdev)
+{
+ bcm2835_pcm_platform_unregister(&pdev->dev);
+ snd_soc_unregister_component(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver bcm2835_i2s_driver = {
+ .probe = bcm2835_i2s_probe,
+ .remove = bcm2835_i2s_remove,
+ .driver = {
+ .name = "bcm2835-i2s",
+ .owner = THIS_MODULE,
+ .of_match_table = bcm2835_i2s_of_match,
+ },
+};
+
+module_platform_driver(bcm2835_i2s_driver);
+
+MODULE_AUTHOR("Florian Meier");
+MODULE_DESCRIPTION("BCM2835 I2S Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/bcm/bcm2835-pcm.c b/sound/soc/bcm/bcm2835-pcm.c
new file mode 100644
index 0000000..c4dc12ea
--- /dev/null
+++ b/sound/soc/bcm/bcm2835-pcm.c
@@ -0,0 +1,52 @@
+/*
+ * ALSA PCM interface for Broadcom BCM2835 SoC
+ *
+ * Author: Florian Meier <florian.meier(a)koalo.de>
+ * Copyright 2013
+ *
+ * based on
+ * ALSA PCM interface for the OMAP SoC
+ * Copyright (C) 2008 Nokia Corporation
+ * Contact: Jarkko Nikula <jarkko.nikula(a)bitmer.com>
+ * Peter Ujfalusi <peter.ujfalusi(a)ti.com>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "bcm2835-pcm.h"
+
+int bcm2835_pcm_platform_register(struct device *dev)
+{
+ return snd_dmaengine_pcm_register(dev, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(bcm2835_pcm_platform_register);
+
+void bcm2835_pcm_platform_unregister(struct device *dev)
+{
+ snd_dmaengine_pcm_unregister(dev);
+}
+EXPORT_SYMBOL_GPL(bcm2835_pcm_platform_unregister);
+
+MODULE_AUTHOR("Florian Meier");
+MODULE_DESCRIPTION("BCM2835 PCM ASoC driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/bcm/bcm2835-pcm.h b/sound/soc/bcm/bcm2835-pcm.h
new file mode 100644
index 0000000..07a70ca
--- /dev/null
+++ b/sound/soc/bcm/bcm2835-pcm.h
@@ -0,0 +1,29 @@
+/*
+ * ALSA PCM interface for Broadcom BCM2835 SoC
+ *
+ * Author: Florian Meier <florian.meier(a)koalo.de>
+ * Copyright 2013
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __BCM2835_PCM_H__
+#define __BCM2835_PCM_H__
+
+int bcm2835_pcm_platform_register(struct device *dev);
+void bcm2835_pcm_platform_unregister(struct device *dev);
+
+#endif
--
1.7.9.5
2
1
The following changes since commit a894bd7fb539d671149fea9420c94c0fbe6baf7a:
ASoC: generic-dmaengine-pcm: Clear slave_config memory (2013-11-07 11:35:30 +0000)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git tags/asoc-v3.13-4
for you to fetch changes up to a190f7867e1830a2d4c890c00b27465b863f5f59:
Merge remote-tracking branch 'asoc/fix/wm8962' into asoc-linus (2013-11-15 10:20:16 +0000)
The diffstat is inflated by some of the branches being based on v3.12.
For the next release cycle I think I'm going to start basing most things
on -rc1 to cut down on this.
----------------------------------------------------------------
ASoC: Fixes for v3.13
A few fixes in drivers, the i.MX and wm8962 fixes are for a pretty nasty
issues for users of those drivers if they run into them.
----------------------------------------------------------------
Brian Austin (1):
ASoC: cs42l52: Correct MIC CTL mask
Charles Keepax (1):
ASoC: wm8997: Correct typo in ISRC mux routes
Mark Brown (6):
Merge remote-tracking branch 'asoc/fix/arizona' into asoc-linus
Merge remote-tracking branch 'asoc/fix/blackfin' into asoc-linus
Merge remote-tracking branch 'asoc/fix/cs42l52' into asoc-linus
Merge remote-tracking branch 'asoc/fix/dma' into asoc-linus
Merge remote-tracking branch 'asoc/fix/fsl' into asoc-linus
Merge remote-tracking branch 'asoc/fix/wm8962' into asoc-linus
Nicolin Chen (1):
ASoC: wm8962: Turn on regcache_cache_only before disabling regulator
Oskar Schirmer (1):
ASoC: fsl: imx-pcm-fiq: omit fiq counter to avoid harm in unbalanced situations
Richard Fitzgerald (1):
ASoC: arizona: Fix typo in name of EQ coefficient controls
Takashi Iwai (1):
ASoC: blackfin: Fix missing break
Documentation/ABI/stable/sysfs-bus-usb | 8 +-
Documentation/ABI/testing/sysfs-devices-power | 32 +-
Documentation/ABI/testing/sysfs-power | 22 +-
Documentation/acpi/dsdt-override.txt | 2 +-
Documentation/connector/ucon.c | 2 +-
Documentation/devicetree/bindings/memory.txt | 168 ------
.../devicetree/bindings/sound/cs42l73.txt | 22 +
.../bindings/sound/davinci-evm-audio.txt | 42 ++
.../bindings/sound/davinci-mcasp-audio.txt | 41 +-
.../devicetree/bindings/sound/tlv320aic3x.txt | 26 +
.../devicetree/bindings/sound/tpa6130a2.txt | 27 +
Documentation/sound/alsa/soc/DPCM.txt | 380 +++++++++++++
Documentation/sound/alsa/soc/codec.txt | 46 +-
Documentation/sound/alsa/soc/dapm.txt | 71 ++-
Documentation/sound/alsa/soc/machine.txt | 6 +-
Documentation/sound/alsa/soc/platform.txt | 19 +-
MAINTAINERS | 171 +++---
Makefile | 2 +-
arch/arc/mm/fault.c | 6 +-
arch/arm/boot/dts/integratorcp.dts | 9 +-
arch/arm/common/mcpm_entry.c | 6 +-
arch/arm/common/sharpsl_param.c | 5 +-
arch/arm/include/asm/Kbuild | 1 -
arch/arm/include/asm/mcpm.h | 14 +-
arch/arm/include/asm/syscall.h | 6 +
arch/arm/kernel/head.S | 21 +-
arch/arm/mm/dma-mapping.c | 43 +-
arch/arm/mm/init.c | 3 -
arch/arm/net/bpf_jit_32.c | 1 +
arch/mips/kernel/perf_event_mipsxx.c | 4 +-
arch/mips/mti-malta/malta-int.c | 9 +-
arch/mips/ralink/timer.c | 2 +-
arch/parisc/configs/712_defconfig | 2 +
arch/parisc/configs/a500_defconfig | 2 +
arch/parisc/configs/b180_defconfig | 3 +
arch/parisc/configs/c3000_defconfig | 3 +
arch/parisc/configs/c8000_defconfig | 2 +
arch/parisc/configs/default_defconfig | 2 +
arch/parisc/kernel/cache.c | 1 -
arch/parisc/kernel/head.S | 4 +
arch/powerpc/net/bpf_jit_comp.c | 1 +
arch/s390/include/asm/pgtable.h | 4 +-
arch/s390/include/asm/timex.h | 28 +-
arch/s390/kernel/compat_signal.c | 4 +-
arch/s390/kernel/debug.c | 2 +-
arch/s390/kvm/interrupt.c | 6 +-
arch/s390/lib/delay.c | 14 +-
arch/s390/net/bpf_jit_comp.c | 4 +-
arch/sparc/net/bpf_jit_comp.c | 1 +
arch/um/kernel/exitcode.c | 4 +-
arch/x86/Kconfig | 1 +
arch/x86/include/asm/percpu.h | 3 +-
arch/x86/kernel/apic/x2apic_uv_x.c | 2 +-
arch/x86/kernel/cpu/perf_event.c | 6 +-
arch/x86/kernel/kvm.c | 19 +-
arch/x86/kernel/nmi.c | 4 +-
arch/x86/net/bpf_jit_comp.c | 18 +-
arch/x86/xen/smp.c | 9 +
arch/xtensa/kernel/entry.S | 49 +-
arch/xtensa/kernel/signal.c | 2 +-
arch/xtensa/platforms/iss/network.c | 3 +-
block/partitions/efi.c | 7 +-
drivers/acpi/Kconfig | 8 +-
drivers/acpi/device_pm.c | 56 --
drivers/acpi/power.c | 104 +---
drivers/acpi/scan.c | 1 -
drivers/ata/ahci.c | 2 +-
drivers/ata/ahci_platform.c | 2 +-
drivers/ata/libahci.c | 10 +-
drivers/ata/libata-acpi.c | 14 -
drivers/ata/libata-eh.c | 6 +-
drivers/ata/libata-scsi.c | 3 -
drivers/ata/libata.h | 4 -
drivers/ata/pata_isapnp.c | 2 +-
drivers/base/memory.c | 7 +-
drivers/base/regmap/internal.h | 8 +-
drivers/base/regmap/regcache.c | 3 +-
drivers/base/regmap/regmap.c | 294 ++++++++--
drivers/char/tpm/xen-tpmfront.c | 1 +
drivers/clk/clk-nomadik.c | 21 +
drivers/clk/mvebu/armada-370.c | 4 +-
drivers/clk/socfpga/clk.c | 2 +-
drivers/clk/versatile/clk-icst.c | 2 +-
drivers/connector/cn_proc.c | 18 +
drivers/connector/connector.c | 9 +-
drivers/cpufreq/acpi-cpufreq.c | 8 +-
drivers/cpufreq/intel_pstate.c | 52 +-
drivers/cpufreq/s3c64xx-cpufreq.c | 2 +-
drivers/dma/edma.c | 2 +
drivers/gpio/gpio-lynxpoint.c | 5 +-
drivers/gpio/gpiolib.c | 6 +-
drivers/gpu/drm/drm_drv.c | 11 +-
drivers/gpu/drm/i915/i915_drv.c | 5 +-
drivers/gpu/drm/i915/i915_drv.h | 8 +-
drivers/gpu/drm/i915/i915_gem_gtt.c | 109 +++-
drivers/gpu/drm/i915/i915_reg.h | 6 +
drivers/gpu/drm/i915/intel_crt.c | 28 +-
drivers/gpu/drm/i915/intel_ddi.c | 21 +-
drivers/gpu/drm/i915/intel_display.c | 131 +++--
drivers/gpu/drm/i915/intel_dp.c | 20 +
drivers/gpu/drm/i915/intel_drv.h | 2 +
drivers/gpu/drm/i915/intel_lvds.c | 16 +
drivers/gpu/drm/i915/intel_pm.c | 4 +-
drivers/gpu/drm/radeon/atombios_encoders.c | 54 +-
drivers/gpu/drm/radeon/cik.c | 4 +
drivers/gpu/drm/radeon/dce6_afmt.c | 3 +
drivers/gpu/drm/radeon/evergreen_hdmi.c | 4 +
drivers/gpu/drm/radeon/kv_dpm.c | 2 +-
drivers/gpu/drm/radeon/ni.c | 1 +
drivers/gpu/drm/radeon/r600.c | 1 +
drivers/gpu/drm/radeon/r600_hdmi.c | 3 +
drivers/gpu/drm/radeon/radeon.h | 4 +-
drivers/gpu/drm/radeon/radeon_connectors.c | 33 +-
drivers/gpu/drm/radeon/radeon_cs.c | 3 +-
drivers/gpu/drm/radeon/radeon_drv.c | 4 +-
drivers/gpu/drm/radeon/radeon_uvd.c | 3 +-
drivers/gpu/drm/radeon/si.c | 1 +
drivers/gpu/drm/radeon/uvd_v1_0.c | 4 +-
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 17 +-
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 2 +-
drivers/hid/hid-core.c | 12 +-
drivers/hid/hid-ids.h | 6 +
drivers/hid/hid-input.c | 13 +-
drivers/hid/hid-wiimote-core.c | 5 +-
drivers/hid/usbhid/hid-quirks.c | 3 +
drivers/iio/frequency/adf4350.c | 6 +-
drivers/iio/industrialio-buffer.c | 3 +
drivers/infiniband/Kconfig | 11 +
drivers/infiniband/core/uverbs.h | 2 +
drivers/infiniband/core/uverbs_cmd.c | 4 +
drivers/infiniband/core/uverbs_main.c | 6 +
drivers/infiniband/hw/amso1100/c2_ae.c | 2 +-
drivers/infiniband/hw/mlx4/main.c | 2 +
drivers/infiniband/hw/mlx5/main.c | 16 +-
drivers/infiniband/hw/mlx5/mr.c | 70 ++-
drivers/infiniband/hw/mlx5/qp.c | 80 +--
drivers/infiniband/hw/mlx5/srq.c | 4 +-
drivers/infiniband/hw/mthca/mthca_eq.c | 2 +-
drivers/infiniband/hw/ocrdma/ocrdma_hw.c | 6 +-
drivers/infiniband/hw/ocrdma/ocrdma_main.c | 2 +-
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c | 6 +-
drivers/infiniband/ulp/isert/ib_isert.c | 2 +-
drivers/input/input.c | 10 +-
drivers/input/keyboard/pxa27x_keypad.c | 11 +-
drivers/input/misc/cm109.c | 14 +-
drivers/input/mouse/alps.c | 1 +
drivers/input/serio/i8042.c | 23 +-
drivers/input/tablet/wacom_sys.c | 4 +
drivers/input/tablet/wacom_wac.c | 8 +
drivers/md/bcache/request.c | 2 +-
drivers/md/dm-snap-persistent.c | 18 +-
drivers/md/md.c | 5 +-
drivers/md/raid1.c | 1 +
drivers/md/raid10.c | 1 +
drivers/md/raid5.c | 20 +
drivers/media/dvb-frontends/tda10071.c | 9 +-
drivers/media/i2c/ad9389b.c | 15 +-
drivers/media/i2c/adv7511.c | 18 +-
drivers/media/i2c/adv7842.c | 30 +-
drivers/media/i2c/ths8200.c | 12 +-
drivers/media/pci/saa7134/saa7134-video.c | 1 +
drivers/media/platform/s5p-jpeg/jpeg-core.c | 1 +
drivers/media/platform/sh_vou.c | 2 +-
drivers/media/platform/soc_camera/mx3_camera.c | 5 +-
drivers/media/tuners/e4000.c | 3 +-
drivers/media/usb/stkwebcam/stk-webcam.c | 7 +
drivers/media/usb/uvc/uvc_driver.c | 18 +
drivers/media/v4l2-core/videobuf2-core.c | 4 +-
drivers/media/v4l2-core/videobuf2-dma-contig.c | 87 ++-
drivers/mfd/mc13xxx-core.c | 5 -
drivers/mfd/mc13xxx-spi.c | 5 +
drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 2 +-
drivers/mtd/nand/pxa3xx_nand.c | 7 +-
drivers/net/can/at91_can.c | 4 +-
drivers/net/can/dev.c | 10 +-
drivers/net/can/flexcan.c | 14 +-
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 15 +-
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 1 +
.../net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 40 +-
drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h | 38 +-
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 388 +++++++------
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | 29 +-
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c | 2 +-
drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c | 2 +-
drivers/net/ethernet/calxeda/xgmac.c | 23 +-
drivers/net/ethernet/davicom/dm9000.c | 56 +-
drivers/net/ethernet/emulex/benet/be_cmds.c | 3 +-
drivers/net/ethernet/freescale/gianfar.c | 38 +-
drivers/net/ethernet/intel/igb/igb_ethtool.c | 2 +
drivers/net/ethernet/marvell/mv643xx_eth.c | 7 +-
drivers/net/ethernet/mellanox/mlx4/en_rx.c | 41 +-
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 4 +-
drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 28 +-
drivers/net/ethernet/mellanox/mlx5/core/eq.c | 4 +-
drivers/net/ethernet/mellanox/mlx5/core/main.c | 21 +-
.../net/ethernet/mellanox/mlx5/core/pagealloc.c | 16 +-
drivers/net/ethernet/moxa/moxart_ether.c | 22 +-
.../net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c | 2 +-
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 13 +-
drivers/net/ethernet/renesas/sh_eth.c | 4 +
drivers/net/ethernet/sfc/ef10.c | 87 ++-
drivers/net/ethernet/sfc/mcdi.c | 18 +-
drivers/net/ethernet/sfc/mcdi_pcol.h | 56 +-
drivers/net/ethernet/sfc/nic.c | 9 +-
drivers/net/ethernet/sfc/nic.h | 12 +
drivers/net/ethernet/smsc/smc91x.h | 6 +-
drivers/net/ethernet/ti/cpsw.c | 19 +-
drivers/net/ethernet/ti/davinci_emac.c | 3 +-
drivers/net/hamradio/yam.c | 1 -
drivers/net/ieee802154/mrf24j40.c | 31 +-
drivers/net/tun.c | 8 +-
drivers/net/usb/ax88179_178a.c | 23 +-
drivers/net/usb/qmi_wwan.c | 1 +
drivers/net/usb/usbnet.c | 4 +-
drivers/net/virtio_net.c | 14 +-
drivers/net/wan/farsync.c | 1 +
drivers/net/wan/wanxl.c | 1 +
drivers/net/wireless/ath/ath9k/main.c | 23 +-
drivers/net/wireless/ath/ath9k/xmit.c | 9 +-
drivers/net/wireless/cw1200/cw1200_spi.c | 2 +
drivers/net/wireless/iwlwifi/iwl-6000.c | 6 +
drivers/net/wireless/iwlwifi/iwl-config.h | 1 +
drivers/net/wireless/iwlwifi/iwl-trans.h | 6 +-
drivers/net/wireless/iwlwifi/mvm/power.c | 5 +-
drivers/net/wireless/iwlwifi/mvm/scan.c | 12 +-
drivers/net/wireless/iwlwifi/pcie/drv.c | 42 ++
drivers/net/wireless/iwlwifi/pcie/trans.c | 8 +-
drivers/net/wireless/iwlwifi/pcie/tx.c | 2 +
drivers/net/wireless/mwifiex/join.c | 10 +-
drivers/net/wireless/mwifiex/main.c | 6 +-
drivers/net/wireless/mwifiex/sta_event.c | 3 +-
drivers/net/wireless/rt2x00/rt2x00pci.c | 9 +-
drivers/net/wireless/rtlwifi/rtl8192cu/trx.c | 3 +-
drivers/net/xen-netback/xenbus.c | 4 +
drivers/of/Kconfig | 6 -
drivers/of/Makefile | 1 -
drivers/of/base.c | 4 +-
drivers/of/fdt.c | 12 -
drivers/of/of_reserved_mem.c | 173 ------
drivers/of/platform.c | 4 -
drivers/pci/hotplug/acpiphp_glue.c | 14 +-
drivers/platform/x86/Kconfig | 1 +
drivers/platform/x86/sony-laptop.c | 26 +-
drivers/s390/block/dasd_eckd.c | 98 +++-
drivers/s390/char/sclp.c | 4 +-
drivers/s390/char/vmlogrdr.c | 2 +-
drivers/s390/cio/cio.c | 4 +-
drivers/s390/cio/qdio_main.c | 10 +-
drivers/scsi/BusLogic.c | 16 +-
drivers/scsi/aacraid/linit.c | 2 +
drivers/scsi/qla2xxx/qla_dbg.c | 2 +-
drivers/scsi/qla2xxx/qla_isr.c | 9 +
drivers/scsi/sd.c | 2 +-
drivers/scsi/sg.c | 176 +++---
drivers/staging/bcm/Bcmchar.c | 1 +
drivers/staging/media/msi3101/Kconfig | 1 +
drivers/staging/media/msi3101/sdr-msi3101.c | 10 +-
drivers/staging/ozwpan/ozcdev.c | 3 +
drivers/staging/sb105x/sb_pci_mp.c | 2 +-
drivers/staging/wlags49_h2/wl_priv.c | 9 +-
drivers/target/target_core_pscsi.c | 8 +-
drivers/target/target_core_sbc.c | 5 +
drivers/target/target_core_xcopy.c | 53 +-
drivers/thermal/samsung/exynos_thermal_common.c | 2 -
drivers/thermal/samsung/exynos_tmu.c | 12 +-
drivers/thermal/samsung/exynos_tmu.h | 7 +-
drivers/thermal/samsung/exynos_tmu_data.c | 30 +-
drivers/thermal/samsung/exynos_tmu_data.h | 13 +-
drivers/thermal/thermal_hwmon.c | 2 +-
drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 1 +
drivers/thermal/x86_pkg_temp_thermal.c | 14 +-
drivers/tty/serial/atmel_serial.c | 9 +-
drivers/tty/serial/imx.c | 3 -
drivers/tty/serial/vt8500_serial.c | 5 +-
drivers/uio/uio.c | 17 +-
drivers/usb/chipidea/host.c | 6 +-
drivers/usb/core/quirks.c | 6 +
drivers/usb/host/pci-quirks.c | 4 +-
drivers/usb/host/xhci-hub.c | 26 -
drivers/usb/host/xhci-pci.c | 25 +
drivers/usb/host/xhci.c | 14 +-
drivers/usb/host/xhci.h | 2 +
drivers/usb/misc/Kconfig | 2 +-
drivers/usb/musb/musb_core.c | 46 ++
drivers/usb/musb/musb_core.h | 1 +
drivers/usb/musb/musb_gadget.c | 3 +
drivers/usb/musb/musb_virthub.c | 46 --
drivers/usb/serial/ftdi_sio.c | 1 +
drivers/usb/serial/ftdi_sio_ids.h | 6 +
drivers/usb/serial/option.c | 225 +++++++-
drivers/usb/serial/pl2303.c | 274 ++-------
drivers/usb/serial/ti_usb_3410_5052.c | 1 +
drivers/usb/storage/scsiglue.c | 5 +-
drivers/usb/storage/unusual_devs.h | 7 +
drivers/vfio/vfio_iommu_type1.c | 40 +-
drivers/vhost/scsi.c | 2 +-
drivers/video/au1100fb.c | 26 +-
drivers/video/au1200fb.c | 23 +-
drivers/w1/w1.c | 6 +
fs/btrfs/inode.c | 1 +
fs/buffer.c | 14 +-
fs/cifs/cifsfs.c | 6 +-
fs/cifs/cifspdu.h | 31 +-
fs/cifs/cifssmb.c | 40 +-
fs/cifs/netmisc.c | 4 +-
fs/cifs/sess.c | 4 +-
fs/cifs/smb2pdu.c | 6 +
fs/cifs/smbfsctl.h | 14 +
fs/cifs/transport.c | 9 +-
fs/dcache.c | 20 +-
fs/ecryptfs/crypto.c | 2 +-
fs/ecryptfs/keystore.c | 3 +-
fs/eventpoll.c | 4 +-
fs/ext3/namei.c | 5 +-
fs/ext4/namei.c | 5 +-
fs/file_table.c | 4 +-
fs/jfs/jfs_inode.c | 3 +-
fs/namei.c | 3 +-
fs/proc/inode.c | 10 +-
fs/proc/task_mmu.c | 4 +-
fs/select.c | 3 +-
fs/seq_file.c | 2 +
include/acpi/acpi_bus.h | 7 -
include/linux/filter.h | 15 +-
include/linux/ipc_namespace.h | 6 +-
include/linux/memcontrol.h | 50 +-
include/linux/mfd/mc13xxx.h | 7 +
include/linux/mlx5/device.h | 4 +-
include/linux/mlx5/driver.h | 6 +-
include/linux/netdevice.h | 5 +-
include/linux/of_reserved_mem.h | 14 -
include/linux/percpu.h | 8 +-
include/linux/platform_data/davinci_asp.h | 2 +
include/linux/regmap.h | 44 ++
include/linux/sched.h | 7 +-
include/linux/usb/usb_phy_gen_xceiv.h | 2 +-
include/linux/usb_usual.h | 4 +-
include/linux/yam.h | 2 +-
include/net/cipso_ipv4.h | 6 +-
include/net/dst.h | 12 +
include/net/ip6_route.h | 6 +-
include/net/mac802154.h | 2 +-
include/net/sock.h | 6 +-
include/sound/cs42l52.h | 2 +
include/sound/cs42l73.h | 22 +
include/sound/rcar_snd.h | 2 +-
include/sound/soc-dai.h | 10 +
include/sound/soc-dapm.h | 4 +
include/sound/soc.h | 100 ++--
include/trace/events/asoc.h | 1 +
include/trace/events/target.h | 4 +-
include/uapi/drm/drm_mode.h | 2 +
include/uapi/linux/perf_event.h | 12 +-
include/uapi/linux/tc_act/Kbuild | 1 +
include/{ => uapi}/linux/tc_act/tc_defact.h | 2 +-
include/uapi/rdma/ib_user_verbs.h | 6 +
ipc/ipc_sysctl.c | 20 +-
ipc/sem.c | 42 +-
ipc/util.c | 27 +-
kernel/cgroup.c | 14 +-
kernel/events/core.c | 4 +
kernel/events/ring_buffer.c | 31 +-
kernel/mutex.c | 32 +-
kernel/power/hibernate.c | 2 +-
kernel/time/clockevents.c | 65 ++-
lib/Kconfig.debug | 2 +-
lib/percpu-refcount.c | 3 +
lib/scatterlist.c | 3 +-
mm/filemap.c | 11 +-
mm/huge_memory.c | 80 ++-
mm/hugetlb.c | 17 +-
mm/list_lru.c | 3 +-
mm/memcontrol.c | 196 +++----
mm/memory.c | 73 ++-
mm/migrate.c | 21 +-
mm/mprotect.c | 9 +-
mm/mremap.c | 5 +-
mm/oom_kill.c | 2 +-
mm/page-writeback.c | 10 +-
mm/pagewalk.c | 2 +-
mm/slab_common.c | 2 +
mm/swapfile.c | 4 +-
mm/vmscan.c | 1 +
mm/zswap.c | 4 +
net/8021q/vlan_netlink.c | 2 +-
net/batman-adv/main.c | 5 +-
net/batman-adv/network-coding.c | 28 +-
net/batman-adv/network-coding.h | 14 +-
net/bridge/br_fdb.c | 4 +-
net/bridge/br_mdb.c | 2 +-
net/bridge/br_multicast.c | 38 +-
net/bridge/br_netlink.c | 2 +-
net/bridge/br_private.h | 5 +-
net/bridge/br_stp_if.c | 2 +-
net/bridge/br_vlan.c | 125 +++--
net/compat.c | 2 +
net/core/dev.c | 3 +-
net/core/filter.c | 8 +-
net/core/secure_seq.c | 2 +
net/core/sock.c | 1 +
net/ieee802154/6lowpan.c | 5 +
net/ipv4/inet_hashtables.c | 2 +-
net/ipv4/ip_output.c | 13 +-
net/ipv4/ip_vti.c | 14 +-
net/ipv4/route.c | 2 +-
net/ipv4/tcp_input.c | 9 +-
net/ipv4/tcp_output.c | 14 +-
net/ipv4/xfrm4_policy.c | 1 +
net/ipv6/ah6.c | 3 +-
net/ipv6/esp6.c | 3 +-
net/ipv6/inet6_hashtables.c | 2 +-
net/ipv6/ip6_gre.c | 6 +-
net/ipv6/ip6_output.c | 29 +-
net/ipv6/ip6_tunnel.c | 12 +-
net/ipv6/ipcomp6.c | 3 +-
net/ipv6/route.c | 46 +-
net/ipv6/udp.c | 5 +-
net/ipv6/xfrm6_policy.c | 1 +
net/key/af_key.c | 3 +-
net/l2tp/l2tp_core.c | 36 +-
net/l2tp/l2tp_core.h | 3 +
net/l2tp/l2tp_ppp.c | 4 +
net/mac80211/cfg.c | 2 +-
net/mac80211/ieee80211_i.h | 3 +
net/mac80211/offchannel.c | 2 +
net/mac80211/rx.c | 3 +
net/mac80211/scan.c | 19 +
net/mac80211/status.c | 3 +
net/mac80211/tx.c | 3 +-
net/mac80211/util.c | 9 +-
net/netfilter/nf_conntrack_h323_main.c | 4 +-
net/sched/sch_fq.c | 22 +-
net/sched/sch_netem.c | 17 +
net/sctp/output.c | 3 +-
net/socket.c | 24 +-
net/unix/af_unix.c | 10 +
net/unix/diag.c | 1 +
net/wireless/core.c | 23 +-
net/wireless/core.h | 3 +
net/wireless/ibss.c | 3 +
net/wireless/nl80211.c | 4 +-
net/wireless/radiotap.c | 7 +-
net/xfrm/xfrm_policy.c | 28 +-
net/xfrm/xfrm_replay.c | 54 +-
net/xfrm/xfrm_user.c | 5 +-
scripts/kallsyms.c | 12 +-
scripts/link-vmlinux.sh | 2 +
security/apparmor/apparmorfs.c | 4 +-
security/apparmor/policy.c | 1 +
sound/arm/pxa2xx-ac97-lib.c | 27 +-
sound/core/pcm.c | 4 +
sound/pci/hda/hda_codec.c | 4 +-
sound/pci/hda/hda_generic.c | 6 +-
sound/pci/hda/patch_analog.c | 18 +-
sound/pci/hda/patch_realtek.c | 1 +
sound/pci/rme9652/hdsp.c | 1 +
sound/soc/Makefile | 2 +-
sound/soc/atmel/atmel-pcm.c | 2 +-
sound/soc/atmel/atmel_wm8904.c | 8 -
sound/soc/atmel/sam9g20_wm8731.c | 1 +
sound/soc/blackfin/bf5xx-i2s.c | 1 +
sound/soc/cirrus/Kconfig | 2 +-
sound/soc/codecs/88pm860x-codec.c | 75 +--
sound/soc/codecs/88pm860x-codec.h | 117 ++--
sound/soc/codecs/ab8500-codec.c | 92 ++-
sound/soc/codecs/adau1373.c | 298 ++++++++--
sound/soc/codecs/adav80x.c | 147 +++--
sound/soc/codecs/ak4104.c | 11 +-
sound/soc/codecs/ak4642.c | 4 +-
sound/soc/codecs/arizona.c | 23 +-
sound/soc/codecs/cq93vc.c | 46 +-
sound/soc/codecs/cs4271.c | 1 +
sound/soc/codecs/cs42l52.c | 93 +--
sound/soc/codecs/cs42l52.h | 4 +-
sound/soc/codecs/cs42l73.c | 114 ++--
sound/soc/codecs/cs42l73.h | 105 ++--
sound/soc/codecs/max98088.c | 624 +++++++++------------
sound/soc/codecs/max98095.c | 466 ++++++---------
sound/soc/codecs/max9850.c | 39 +-
sound/soc/codecs/mc13783.c | 135 +++--
sound/soc/codecs/ml26124.c | 2 +
sound/soc/codecs/pcm1681.c | 3 +-
sound/soc/codecs/pcm1792a.c | 3 +-
sound/soc/codecs/rt5640.c | 31 +-
sound/soc/codecs/si476x.c | 64 +--
sound/soc/codecs/sn95031.c | 35 +-
sound/soc/codecs/tas5086.c | 171 ++++--
sound/soc/codecs/tlv320aic23.c | 84 ++-
sound/soc/codecs/tlv320aic26.c | 139 +----
sound/soc/codecs/tlv320aic26.h | 5 +-
sound/soc/codecs/tlv320aic32x4.c | 101 +---
sound/soc/codecs/tlv320aic3x.c | 238 ++++----
sound/soc/codecs/tpa6130a2.c | 32 +-
sound/soc/codecs/twl4030.c | 80 ++-
sound/soc/codecs/twl6040.c | 26 +-
sound/soc/codecs/wm0010.c | 8 +-
sound/soc/codecs/wm5102.c | 8 +-
sound/soc/codecs/wm5110.c | 20 +-
sound/soc/codecs/wm8400.c | 95 +---
sound/soc/codecs/wm8962.c | 228 ++++----
sound/soc/codecs/wm8996.c | 2 +
sound/soc/codecs/wm8997.c | 10 +-
sound/soc/codecs/wm_adsp.c | 27 +-
sound/soc/codecs/wm_hubs.c | 1 +
sound/soc/davinci/Kconfig | 18 +-
sound/soc/davinci/Makefile | 1 +
sound/soc/davinci/davinci-evm.c | 188 ++++++-
sound/soc/davinci/davinci-mcasp.c | 169 ++++--
sound/soc/davinci/davinci-mcasp.h | 12 +
sound/soc/fsl/eukrea-tlv320.c | 15 +-
sound/soc/fsl/fsl_spdif.c | 22 +-
sound/soc/fsl/fsl_ssi.c | 22 +-
sound/soc/fsl/imx-audmux.c | 9 +-
sound/soc/fsl/imx-mc13783.c | 3 +-
sound/soc/fsl/imx-pcm-fiq.c | 29 +-
sound/soc/fsl/imx-sgtl5000.c | 4 +-
sound/soc/fsl/imx-spdif.c | 4 +-
sound/soc/fsl/imx-ssi.c | 26 +-
sound/soc/fsl/imx-ssi.h | 2 +
sound/soc/fsl/imx-wm8962.c | 4 +-
sound/soc/generic/simple-card.c | 5 +
sound/soc/kirkwood/kirkwood-dma.c | 6 +-
sound/soc/kirkwood/kirkwood-i2s.c | 108 +++-
sound/soc/kirkwood/kirkwood-openrd.c | 2 +-
sound/soc/kirkwood/kirkwood-t5325.c | 2 +-
sound/soc/kirkwood/kirkwood.h | 4 +-
sound/soc/mid-x86/mfld_machine.c | 10 +-
sound/soc/mxs/mxs-saif.c | 42 +-
sound/soc/mxs/mxs-saif.h | 5 +
sound/soc/mxs/mxs-sgtl5000.c | 20 +-
sound/soc/omap/Kconfig | 4 +-
sound/soc/omap/omap-mcpdm.c | 12 +-
sound/soc/omap/omap-twl4030.c | 5 +-
sound/soc/pxa/brownstone.c | 1 +
sound/soc/pxa/corgi.c | 1 +
sound/soc/pxa/e740_wm9705.c | 1 +
sound/soc/pxa/e750_wm9705.c | 1 +
sound/soc/pxa/e800_wm9712.c | 1 +
sound/soc/pxa/imote2.c | 1 +
sound/soc/pxa/mioa701_wm9713.c | 1 +
sound/soc/pxa/mmp-sspa.c | 5 +-
sound/soc/pxa/palm27x.c | 1 +
sound/soc/pxa/poodle.c | 1 +
sound/soc/pxa/pxa2xx-ac97.c | 56 +-
sound/soc/pxa/tosa.c | 1 +
sound/soc/pxa/ttc-dkb.c | 1 +
sound/soc/samsung/bells.c | 1 +
sound/soc/samsung/i2s.c | 16 +-
sound/soc/samsung/smdk_wm8994.c | 14 +-
sound/soc/sh/rcar/adg.c | 11 +-
sound/soc/sh/rcar/core.c | 81 +--
sound/soc/sh/rcar/gen.c | 261 +++++----
sound/soc/sh/rcar/rsnd.h | 9 +-
sound/soc/sh/rcar/scu.c | 12 +-
sound/soc/sh/rcar/ssi.c | 52 +-
sound/soc/soc-cache.c | 263 ++-------
sound/soc/soc-core.c | 343 ++++++-----
sound/soc/soc-dapm.c | 124 ++--
sound/soc/soc-devres.c | 86 +++
sound/soc/soc-io.c | 26 -
sound/soc/soc-jack.c | 7 +-
sound/soc/soc-pcm.c | 60 +-
sound/soc/soc-utils.c | 6 +-
sound/soc/spear/spdif_in.c | 12 +-
sound/soc/spear/spdif_out.c | 14 +-
sound/soc/tegra/tegra30_ahub.c | 115 +++-
sound/soc/tegra/tegra30_ahub.h | 38 +-
sound/soc/tegra/tegra30_i2s.c | 51 +-
sound/soc/tegra/tegra30_i2s.h | 7 +
sound/soc/tegra/tegra_asoc_utils.c | 2 +
sound/soc/tegra/tegra_asoc_utils.h | 1 +
sound/usb/usx2y/us122l.c | 4 +-
tools/perf/Documentation/perf-record.txt | 14 +-
tools/perf/Documentation/perf-top.txt | 18 +-
tools/perf/builtin-kvm.c | 7 +
tools/perf/builtin-record.c | 73 ++-
tools/perf/builtin-top.c | 33 +-
tools/perf/builtin-trace.c | 8 +-
tools/perf/tests/code-reading.c | 1 +
tools/perf/tests/keep-tracking.c | 1 +
tools/perf/tests/mmap-basic.c | 1 +
tools/perf/tests/open-syscall-tp-fields.c | 4 +-
tools/perf/tests/perf-record.c | 2 +
tools/perf/tests/perf-time-to-tsc.c | 4 +-
tools/perf/tests/sw-clock.c | 4 +-
tools/perf/tests/task-exit.c | 6 +-
tools/perf/ui/stdio/hist.c | 9 +-
tools/perf/util/callchain.h | 3 +
tools/perf/util/event.c | 32 +-
tools/perf/util/evlist.c | 13 +-
tools/perf/util/evlist.h | 2 +
tools/perf/util/evsel.c | 1 -
tools/perf/util/hist.h | 13 +
tools/perf/util/probe-finder.c | 2 +-
tools/perf/util/python.c | 2 +
.../perf/util/scripting-engines/trace-event-perl.c | 2 +-
.../util/scripting-engines/trace-event-python.c | 37 +-
tools/testing/selftests/timers/posix_timers.c | 2 +-
virt/kvm/kvm_main.c | 2 +-
599 files changed, 8499 insertions(+), 6158 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/memory.txt
create mode 100644 Documentation/devicetree/bindings/sound/cs42l73.txt
create mode 100644 Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
create mode 100644 Documentation/devicetree/bindings/sound/tpa6130a2.txt
create mode 100644 Documentation/sound/alsa/soc/DPCM.txt
delete mode 100644 drivers/of/of_reserved_mem.c
delete mode 100644 include/linux/of_reserved_mem.h
create mode 100644 include/sound/cs42l73.h
rename include/{ => uapi}/linux/tc_act/tc_defact.h (75%)
create mode 100644 sound/soc/soc-devres.c
2
1
[alsa-devel] [RFC 0/2] I2C and SPI dev_name change for ACPI enumerated slaves
by Jarkko Nikula 16 Nov '13
by Jarkko Nikula 16 Nov '13
16 Nov '13
Hi
We've run into problem of changing I2C device names while developing
ALSA SoC drivers for x86 based systems. Changing device names makes
more difficult to match devices by their name. Which is what we use
within ASoC subsystem.
These changing names comes from changing adapter/bus numbering which
could occur due variable amount of bus controllers, probe order, add-on
cards or different BIOS settings.
Patches here try to solve the problem on ACPI 5 based systems by
using stable ACPI device name with a "i2c-"/"spi-" prefix for I2C/SPI
slave device names.
Both patches are independent from each other and can go through their
own subsystems.
Jarkko Nikula (2):
i2c: Use stable dev_name for ACPI enumerated I2C slaves
spi: Use stable dev_name for ACPI enumerated SPI slaves
drivers/i2c/i2c-core.c | 24 ++++++++++++++++++++----
drivers/spi/spi.c | 21 ++++++++++++++++++---
2 files changed, 38 insertions(+), 7 deletions(-)
--
1.8.4.rc3
5
41
Add support for DMA controller of BCM2835 as used in the Raspberry Pi.
Currently it only supports cyclic DMA.
Signed-off-by: Florian Meier <florian.meier(a)koalo.de>
---
Fifth version with better error handling in probe.
.../devicetree/bindings/dma/bcm2835-dma.txt | 56 ++
drivers/dma/Kconfig | 6 +
drivers/dma/Makefile | 1 +
drivers/dma/bcm2835-dma.c | 749 +++++++++++++++++++++
4 files changed, 812 insertions(+)
create mode 100644 Documentation/devicetree/bindings/dma/bcm2835-dma.txt
create mode 100644 drivers/dma/bcm2835-dma.c
diff --git a/Documentation/devicetree/bindings/dma/bcm2835-dma.txt b/Documentation/devicetree/bindings/dma/bcm2835-dma.txt
new file mode 100644
index 0000000..7d91019
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/bcm2835-dma.txt
@@ -0,0 +1,56 @@
+* BCM2835 DMA controller
+
+Required properties:
+- compatible: Should be "brcm,bcm2835-dma".
+- reg: Should contain DMA registers location and length.
+- interrupts: Should contain the DMA interrupts associated
+ to the DMA channels in ascending order.
+ First cell is the IRQ bank.
+ Second cell is the IRQ number.
+- #dma-cells: Must be <1>, used to represent the number of integer cells in
+ the dmas property of client devices.
+- brcm,dma-channel-mask: Bit mask representing the channels
+ not used by the firmware.
+
+Example:
+
+dma: dma@7e007000 {
+ compatible = "brcm,bcm2835-dma";
+ reg = <0x7e007000 0xf00>;
+ interrupts = <1 16
+ 1 17
+ 1 18
+ 1 19
+ 1 20
+ 1 21
+ 1 22
+ 1 23
+ 1 24
+ 1 25
+ 1 26
+ 1 27
+ 1 28>;
+
+ #dma-cells = <1>;
+ brcm,dma-channel-mask = <0x7f35>;
+};
+
+DMA clients connected to the BCM2835 DMA controller must use the format
+described in the dma.txt file, using a two-cell specifier for each channel:
+a phandle plus one integer cells.
+The two cells in order are:
+
+1. A phandle pointing to the DMA controller.
+2. The DREQ number.
+
+Example:
+
+bcm2835_i2s: i2s@7e203000 {
+ compatible = "brcm,bcm2835-i2s";
+ reg = < 0x7e203000 0x20
+ 0x7e101098 0x02>;
+
+ dmas = <&dma 2
+ &dma 3>;
+ dma-names = "tx", "rx";
+};
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index c61a6ec..880e723 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -300,6 +300,12 @@ config DMA_OMAP
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
+config DMA_BCM2835
+ tristate "BCM2835 DMA engine support"
+ depends on (ARCH_BCM2835 || MACH_BCM2708)
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+
config TI_CPPI41
tristate "AM33xx CPPI41 DMA support"
depends on ARCH_OMAP
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 0ce2da9..0a6f08e 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o
obj-$(CONFIG_DMA_OMAP) += omap-dma.o
+obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o
obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
obj-$(CONFIG_TI_CPPI41) += cppi41.o
diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
new file mode 100644
index 0000000..bc26398
--- /dev/null
+++ b/drivers/dma/bcm2835-dma.c
@@ -0,0 +1,749 @@
+/*
+ * BCM2835 DMA engine support
+ *
+ * This driver only supports cyclic DMA transfers
+ * as needed for the I2S module.
+ *
+ * Author: Florian Meier, <florian.meier(a)koalo.de>
+ * Copyright 2013
+ *
+ * based on
+ * OMAP DMAengine support by Russell King
+ *
+ * BCM2708 DMA Driver
+ * Copyright (C) 2010 Broadcom
+ *
+ * Raspberry Pi PCM I2S ALSA Driver
+ * Copyright (c) by Phil Poole 2013
+ *
+ * MARVELL MMP Peripheral DMA Driver
+ * Copyright 2012 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_dma.h>
+
+#include "virt-dma.h"
+
+struct bcm2835_dmadev {
+ struct dma_device ddev;
+ spinlock_t lock;
+ void __iomem *dma_base;
+ struct device_dma_parameters dma_parms;
+};
+
+struct bcm2835_dma_cb {
+ uint32_t info;
+ uint32_t src;
+ uint32_t dst;
+ uint32_t length;
+ uint32_t stride;
+ uint32_t next;
+ uint32_t pad[2];
+};
+
+struct bcm2835_chan {
+ struct virt_dma_chan vc;
+ struct list_head node;
+
+ struct dma_slave_config cfg;
+ bool cyclic;
+ unsigned dreq;
+
+ int dma_ch;
+ struct bcm2835_desc *desc;
+
+ void __iomem *dma_chan_base;
+ int dma_irq_number;
+};
+
+struct bcm2835_desc {
+ struct virt_dma_desc vd;
+ enum dma_transfer_direction dir;
+
+ unsigned int control_block_size;
+ struct bcm2835_dma_cb *control_block_base;
+ dma_addr_t control_block_base_phys;
+
+ unsigned frames;
+ size_t size;
+};
+
+#define BCM2835_DMA_CS 0x00
+#define BCM2835_DMA_ADDR 0x04
+#define BCM2835_DMA_SOURCE_AD 0x0c
+#define BCM2835_DMA_DEST_AD 0x10
+#define BCM2835_DMA_NEXTCB 0x1C
+
+/* DMA CS Control and Status bits */
+#define BCM2835_DMA_ACTIVE (1 << 0)
+#define BCM2835_DMA_INT (1 << 2)
+#define BCM2835_DMA_ISPAUSED (1 << 4) /* Pause requested or not active */
+#define BCM2835_DMA_ISHELD (1 << 5) /* Is held by DREQ flow control */
+#define BCM2835_DMA_ERR (1 << 8)
+#define BCM2835_DMA_ABORT (1 << 30) /* stop current CB, go to next, WO */
+#define BCM2835_DMA_RESET (1 << 31) /* WO, self clearing */
+
+#define BCM2835_DMA_INT_EN (1 << 0)
+#define BCM2835_DMA_D_INC (1 << 4)
+#define BCM2835_DMA_D_DREQ (1 << 6)
+#define BCM2835_DMA_S_INC (1 << 8)
+#define BCM2835_DMA_S_DREQ (1 << 6)
+
+#define BCM2835_DMA_PER_MAP(x) ((x) << 16)
+
+#define BCM2835_DMA_DATA_TYPE_S8 1
+#define BCM2835_DMA_DATA_TYPE_S16 2
+#define BCM2835_DMA_DATA_TYPE_S32 4
+#define BCM2835_DMA_DATA_TYPE_S128 16
+
+/* valid only for channels 0 - 14, 15 has its own base address */
+#define BCM2835_DMA_CHAN(n) ((n) << 8) /* base address */
+#define BCM2835_DMA_CHANIO(dma_base, n) ((dma_base) + BCM2835_DMA_CHAN(n))
+
+static inline struct bcm2835_dmadev *to_bcm2835_dma_dev(struct dma_device *d)
+{
+ return container_of(d, struct bcm2835_dmadev, ddev);
+}
+
+static inline struct bcm2835_chan *to_bcm2835_dma_chan(struct dma_chan *c)
+{
+ return container_of(c, struct bcm2835_chan, vc.chan);
+}
+
+static inline struct bcm2835_desc *to_bcm2835_dma_desc(
+ struct dma_async_tx_descriptor *t)
+{
+ return container_of(t, struct bcm2835_desc, vd.tx);
+}
+
+static void bcm2835_dma_desc_free(struct virt_dma_desc *vd)
+{
+ struct bcm2835_desc *desc = container_of(vd, struct bcm2835_desc, vd);
+ dma_free_coherent(desc->vd.tx.chan->device->dev,
+ desc->control_block_size,
+ desc->control_block_base,
+ desc->control_block_base_phys);
+ kfree(desc);
+}
+
+static int bcm2835_dma_abort(void __iomem *dma_chan_base)
+{
+ unsigned long int cs;
+ int rc = 0;
+
+ cs = readl(dma_chan_base + BCM2835_DMA_CS);
+
+ if (BCM2835_DMA_ACTIVE & cs) {
+ long int timeout = 10000;
+
+ /* write 0 to the active bit - pause the DMA */
+ writel(0, dma_chan_base + BCM2835_DMA_CS);
+
+ /* wait for any current AXI transfer to complete */
+ while ((cs & BCM2835_DMA_ISPAUSED) && --timeout >= 0)
+ cs = readl(dma_chan_base + BCM2835_DMA_CS);
+
+ if (cs & BCM2835_DMA_ISPAUSED) {
+ /* we'll un-pause when we set of our next DMA */
+ rc = -ETIMEDOUT;
+
+ } else if (BCM2835_DMA_ACTIVE & cs) {
+ /* terminate the control block chain */
+ writel(0, dma_chan_base + BCM2835_DMA_NEXTCB);
+
+ /* abort the whole DMA */
+ writel(BCM2835_DMA_ABORT | BCM2835_DMA_ACTIVE,
+ dma_chan_base + BCM2835_DMA_CS);
+ }
+ }
+
+ return rc;
+}
+
+static void bcm2835_dma_start_desc(struct bcm2835_chan *c)
+{
+ struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
+ struct bcm2835_desc *d;
+
+ if (!vd) {
+ c->desc = NULL;
+ return;
+ }
+
+ list_del(&vd->node);
+
+ c->desc = d = to_bcm2835_dma_desc(&vd->tx);
+
+ dsb(); /* ARM data synchronization (push) operation */
+
+ writel(d->control_block_base_phys, c->dma_chan_base + BCM2835_DMA_ADDR);
+ writel(BCM2835_DMA_ACTIVE, c->dma_chan_base + BCM2835_DMA_CS);
+}
+
+static irqreturn_t bcm2835_dma_callback(int irq, void *data)
+{
+ struct bcm2835_chan *c = data;
+ struct bcm2835_desc *d;
+ unsigned long flags;
+
+ spin_lock_irqsave(&c->vc.lock, flags);
+
+ /* acknowledge interrupt */
+ writel(BCM2835_DMA_INT, c->dma_chan_base + BCM2835_DMA_CS);
+
+ d = c->desc;
+
+ if (d) {
+ /* TODO Only works for cyclic DMA */
+ vchan_cyclic_callback(&d->vd);
+ }
+
+ /* keep the DMA engine running */
+ dsb(); /* ARM synchronization barrier */
+ writel(BCM2835_DMA_ACTIVE, c->dma_chan_base + BCM2835_DMA_CS);
+
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static int bcm2835_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+
+ dev_dbg(c->vc.chan.device->dev,
+ "Allocating DMA channel %i\n", c->dma_ch);
+
+ return request_irq(c->dma_irq_number,
+ bcm2835_dma_callback, 0, "DMA IRQ", c);
+}
+
+static void bcm2835_dma_free_chan_resources(struct dma_chan *chan)
+{
+ struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+
+ vchan_free_chan_resources(&c->vc);
+ free_irq(c->dma_irq_number, c);
+
+ dev_dbg(c->vc.chan.device->dev, "Freeing DMA channel %u\n", c->dma_ch);
+}
+
+static size_t bcm2835_dma_desc_size(struct bcm2835_desc *d)
+{
+ return d->size;
+}
+
+static size_t bcm2835_dma_desc_size_pos(struct bcm2835_desc *d, dma_addr_t addr)
+{
+ unsigned i;
+ size_t size;
+
+ for (size = i = 0; i < d->frames; i++) {
+ struct bcm2835_dma_cb *control_block =
+ &d->control_block_base[i];
+ size_t this_size = control_block->length;
+ dma_addr_t dma;
+
+ if (d->dir == DMA_DEV_TO_MEM)
+ dma = control_block->dst;
+ else
+ dma = control_block->src;
+
+ if (size)
+ size += this_size;
+ else if (addr >= dma && addr < dma + this_size)
+ size += dma + this_size - addr;
+ }
+
+ return size;
+}
+
+static enum dma_status bcm2835_dma_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+ struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+ struct virt_dma_desc *vd;
+ enum dma_status ret;
+ unsigned long flags;
+
+ ret = dma_cookie_status(chan, cookie, txstate);
+ if (ret == DMA_SUCCESS || !txstate)
+ return ret;
+
+ spin_lock_irqsave(&c->vc.lock, flags);
+ vd = vchan_find_desc(&c->vc, cookie);
+ if (vd) {
+ txstate->residue =
+ bcm2835_dma_desc_size(to_bcm2835_dma_desc(&vd->tx));
+ } else if (c->desc && c->desc->vd.tx.cookie == cookie) {
+ struct bcm2835_desc *d = c->desc;
+ dma_addr_t pos;
+
+ if (d->dir == DMA_MEM_TO_DEV)
+ pos = readl(c->dma_chan_base + BCM2835_DMA_SOURCE_AD);
+ else if (d->dir == DMA_DEV_TO_MEM)
+ pos = readl(c->dma_chan_base + BCM2835_DMA_DEST_AD);
+ else
+ pos = 0;
+
+ txstate->residue = bcm2835_dma_desc_size_pos(d, pos);
+ } else {
+ txstate->residue = 0;
+ }
+
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+
+ return ret;
+}
+
+static void bcm2835_dma_issue_pending(struct dma_chan *chan)
+{
+ struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+ unsigned long flags;
+
+ c->cyclic = true; /* nothing else is implemented */
+
+ spin_lock_irqsave(&c->vc.lock, flags);
+ if (vchan_issue_pending(&c->vc) && !c->desc)
+ bcm2835_dma_start_desc(c);
+
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+}
+
+
+static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
+ struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
+ size_t period_len, enum dma_transfer_direction direction,
+ unsigned long flags, void *context)
+{
+ struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+ enum dma_slave_buswidth dev_width;
+ struct bcm2835_desc *d;
+ dma_addr_t dev_addr;
+ unsigned es, sync_type;
+ unsigned frame;
+
+ /* Grab configuration */
+ if (direction == DMA_DEV_TO_MEM) {
+ dev_addr = c->cfg.src_addr;
+ dev_width = c->cfg.src_addr_width;
+ sync_type = BCM2835_DMA_S_DREQ;
+ } else if (direction == DMA_MEM_TO_DEV) {
+ dev_addr = c->cfg.dst_addr;
+ dev_width = c->cfg.dst_addr_width;
+ sync_type = BCM2835_DMA_D_DREQ;
+ } else {
+ dev_err(chan->device->dev, "%s: bad direction?\n", __func__);
+ return NULL;
+ }
+
+ /* Bus width translates to the element size (ES) */
+ switch (dev_width) {
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
+ es = BCM2835_DMA_DATA_TYPE_S32;
+ break;
+ default:
+ return NULL;
+ }
+
+ /* Now allocate and setup the descriptor. */
+ d = kzalloc(sizeof(*d), GFP_NOWAIT);
+ if (!d)
+ return NULL;
+
+ d->dir = direction;
+ d->frames = buf_len / period_len;
+
+ /* Allocate memory for control blocks */
+ d->control_block_size = d->frames * sizeof(struct bcm2835_dma_cb);
+ d->control_block_base = dma_alloc_coherent(chan->device->dev,
+ d->control_block_size, &d->control_block_base_phys,
+ GFP_NOWAIT);
+
+ if (!d->control_block_base) {
+ kfree(d);
+ dev_err(chan->device->dev,
+ "%s: Memory allocation error\n", __func__);
+ return NULL;
+ }
+
+ memset(d->control_block_base, 0, d->control_block_size);
+
+ /*
+ * Iterate over all frames, create a control block
+ * for each frame and link them together.
+ */
+ for (frame = 0; frame < d->frames; frame++) {
+ struct bcm2835_dma_cb *control_block =
+ &d->control_block_base[frame];
+
+ /* Setup adresses */
+ if (d->dir == DMA_DEV_TO_MEM) {
+ control_block->info = BCM2835_DMA_D_INC;
+ control_block->src = dev_addr;
+ control_block->dst = buf_addr + frame * period_len;
+ } else {
+ control_block->info = BCM2835_DMA_S_INC;
+ control_block->src = buf_addr + frame * period_len;
+ control_block->dst = dev_addr;
+ }
+
+ /* Enable interrupt */
+ control_block->info |= BCM2835_DMA_INT_EN;
+
+ /* Setup synchronization */
+ if (sync_type != 0)
+ control_block->info |= sync_type;
+
+ /* Setup DREQ channel */
+ if (c->dreq != 0)
+ control_block->info |=
+ BCM2835_DMA_PER_MAP(c->dreq);
+
+ /* Length of a frame */
+ control_block->length = period_len;
+ d->size += control_block->length;
+
+ /*
+ * Next block is the next frame.
+ * This DMA engine driver currently only supports cyclic DMA.
+ * Therefore, wrap around at number of frames.
+ */
+ control_block->next = d->control_block_base_phys +
+ sizeof(struct bcm2835_dma_cb)
+ * ((frame + 1) % d->frames);
+
+ /* The following fields are not used here */
+ control_block->stride = 0;
+ control_block->pad[0] = 0;
+ control_block->pad[1] = 0;
+ }
+
+ return vchan_tx_prep(&c->vc, &d->vd, flags);
+}
+
+static int bcm2835_dma_slave_config(struct bcm2835_chan *c,
+ struct dma_slave_config *cfg)
+{
+ if ((cfg->direction == DMA_DEV_TO_MEM &&
+ cfg->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) ||
+ (cfg->direction == DMA_MEM_TO_DEV &&
+ cfg->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) ||
+ (cfg->direction != DMA_DEV_TO_MEM &&
+ cfg->direction != DMA_MEM_TO_DEV)) {
+ return -EINVAL;
+ }
+
+ c->cfg = *cfg;
+
+ return 0;
+}
+
+static int bcm2835_dma_terminate_all(struct bcm2835_chan *c)
+{
+ struct bcm2835_dmadev *d = to_bcm2835_dma_dev(c->vc.chan.device);
+ unsigned long flags;
+ int timeout = 1000;
+ LIST_HEAD(head);
+
+ spin_lock_irqsave(&c->vc.lock, flags);
+
+ /* Prevent this channel being scheduled */
+ spin_lock(&d->lock);
+ list_del_init(&c->node);
+ spin_unlock(&d->lock);
+
+ /*
+ * Stop DMA activity: we assume the callback will not be called
+ * after bcm_dma_abort() returns (even if it does, it will see
+ * c->desc is NULL and exit.)
+ */
+ if (c->desc) {
+ c->desc = NULL;
+ bcm2835_dma_abort(c->dma_chan_base);
+
+ /* Wait for stopping */
+ while (timeout > 0) {
+ timeout--;
+ if (!(readl(c->dma_chan_base + BCM2835_DMA_CS) &
+ BCM2835_DMA_ACTIVE))
+ break;
+
+ cpu_relax();
+ }
+
+ if (timeout <= 0)
+ dev_err(d->ddev.dev, "DMA transfer could not be terminated\n");
+ }
+
+ vchan_get_all_descriptors(&c->vc, &head);
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+ vchan_dma_desc_free_list(&c->vc, &head);
+
+ return 0;
+}
+
+static int bcm2835_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+{
+ struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+ int ret;
+
+ switch (cmd) {
+ case DMA_SLAVE_CONFIG:
+ return bcm2835_dma_slave_config(c,
+ (struct dma_slave_config *)arg);
+
+ case DMA_TERMINATE_ALL:
+ bcm2835_dma_terminate_all(c);
+ break;
+
+ default:
+ ret = -ENXIO;
+ break;
+ }
+
+ return ret;
+}
+
+static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, int irq)
+{
+ struct bcm2835_chan *c;
+
+ c = kzalloc(sizeof(*c), GFP_KERNEL);
+ if (!c)
+ return -ENOMEM;
+
+ c->vc.desc_free = bcm2835_dma_desc_free;
+ vchan_init(&c->vc, &d->ddev);
+ INIT_LIST_HEAD(&c->node);
+
+ d->ddev.chancnt++;
+
+ c->dma_chan_base = BCM2835_DMA_CHANIO(d->dma_base, chan_id);
+ c->dma_ch = chan_id;
+ c->dma_irq_number = irq;
+
+ return 0;
+}
+
+static void bcm2835_dma_free(struct bcm2835_dmadev *od)
+{
+ while (!list_empty(&od->ddev.channels)) {
+ struct bcm2835_chan *c = list_first_entry(&od->ddev.channels,
+ struct bcm2835_chan, vc.chan.device_node);
+
+ list_del(&c->vc.chan.device_node);
+ tasklet_kill(&c->vc.task);
+ kfree(c);
+ }
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id bcm2835_dma_of_match[] = {
+ { .compatible = "brcm,bcm2835-dma", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bcm2835_dma_of_match);
+#endif
+
+static struct dma_chan *bcm2835_dma_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct bcm2835_dmadev *d = ofdma->of_dma_data;
+ struct dma_chan *chan, *candidate;
+
+retry:
+ candidate = NULL;
+
+ /* walk the list of channels registered with the current instance and
+ * find one that is currently unused */
+ list_for_each_entry(chan, &d->ddev.channels, device_node)
+ if (chan->client_count == 0) {
+ candidate = chan;
+ break;
+ }
+
+ if (!candidate)
+ return NULL;
+
+ /* dma_get_slave_channel will return NULL if we lost a race between
+ * the lookup and the reservation */
+ chan = dma_get_slave_channel(candidate);
+
+ if (chan) {
+ struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+
+ /* Set DREQ from param */
+ c->dreq = dma_spec->args[0];
+
+ return chan;
+ }
+
+ goto retry;
+}
+
+static int bcm2835_dma_device_slave_caps(struct dma_chan *dchan,
+ struct dma_slave_caps *caps)
+{
+ caps->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+ caps->dstn_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+ caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+ caps->cmd_pause = false;
+ caps->cmd_terminate = true;
+
+ return 0;
+}
+
+static int bcm2835_dma_probe(struct platform_device *pdev)
+{
+ struct bcm2835_dmadev *od;
+ struct resource *dma_res = NULL;
+ void __iomem *dma_base = NULL;
+ int rc = 0;
+ int i = 0;
+ int irq;
+ uint32_t chans_available;
+
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+
+ rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+ if (rc)
+ return rc;
+ dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+
+ od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL);
+ if (!od)
+ return -ENOMEM;
+
+ pdev->dev.dma_parms = &od->dma_parms;
+ dma_set_max_seg_size(&pdev->dev, 0x3FFFFFFF);
+
+ dma_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dma_base = devm_ioremap_resource(&pdev->dev, dma_res);
+ if (IS_ERR(dma_base))
+ return PTR_ERR(dma_base);
+
+ od->dma_base = dma_base;
+
+ dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
+ dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask);
+ od->ddev.device_alloc_chan_resources = bcm2835_dma_alloc_chan_resources;
+ od->ddev.device_free_chan_resources = bcm2835_dma_free_chan_resources;
+ od->ddev.device_tx_status = bcm2835_dma_tx_status;
+ od->ddev.device_issue_pending = bcm2835_dma_issue_pending;
+ od->ddev.device_slave_caps = bcm2835_dma_device_slave_caps;
+ od->ddev.device_prep_dma_cyclic = bcm2835_dma_prep_dma_cyclic;
+ od->ddev.device_control = bcm2835_dma_control;
+ od->ddev.dev = &pdev->dev;
+ INIT_LIST_HEAD(&od->ddev.channels);
+ spin_lock_init(&od->lock);
+
+ platform_set_drvdata(pdev, od);
+
+ if (pdev->dev.of_node) {
+ /* Request DMA channel mask from device tree */
+ if (of_property_read_u32(pdev->dev.of_node,
+ "brcm,dma-channel-mask",
+ &chans_available)) {
+ dev_err(&pdev->dev, "Failed to get channel mask\n");
+ bcm2835_dma_free(od);
+ return -EINVAL;
+ }
+ } else {
+ dev_err(&pdev->dev, "Failed to get channel mask. No device tree.\n");
+ bcm2835_dma_free(od);
+ return -EINVAL;
+ }
+
+ /* do not use the FIQ and BULK channels */
+ chans_available &= ~0xD;
+
+ for (i = 0; i < pdev->num_resources; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq < 0)
+ break;
+
+ if (chans_available & (1 << i)) {
+ rc = bcm2835_dma_chan_init(od, i, irq);
+ if (rc) {
+ bcm2835_dma_free(od);
+ return rc;
+ }
+ }
+ }
+
+ dev_dbg(&pdev->dev, "Initialized %i DMA channels\n", i);
+
+ if (pdev->dev.of_node) {
+ /* Device-tree DMA controller registration */
+ rc = of_dma_controller_register(pdev->dev.of_node,
+ bcm2835_dma_xlate, od);
+ if (rc) {
+ dev_err(&pdev->dev, "Failed to register DMA controller\n");
+ bcm2835_dma_free(od);
+ return rc;
+ }
+ }
+
+ rc = dma_async_device_register(&od->ddev);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "Failed to register slave DMA engine device: %d\n", rc);
+ bcm2835_dma_free(od);
+ return rc;
+ }
+
+ dev_dbg(&pdev->dev, "Load BCM2835 DMA engine driver\n");
+
+ return rc;
+}
+
+static int bcm2835_dma_remove(struct platform_device *pdev)
+{
+ struct bcm2835_dmadev *od = platform_get_drvdata(pdev);
+
+ dma_async_device_unregister(&od->ddev);
+ bcm2835_dma_free(od);
+
+ return 0;
+}
+
+static struct platform_driver bcm2835_dma_driver = {
+ .probe = bcm2835_dma_probe,
+ .remove = bcm2835_dma_remove,
+ .driver = {
+ .name = "bcm2835-dma",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(bcm2835_dma_of_match),
+ },
+};
+
+module_platform_driver(bcm2835_dma_driver);
+
+MODULE_ALIAS("platform:bcm2835-dma");
+MODULE_DESCRIPTION("BCM2835 DMA engine driver");
+MODULE_AUTHOR("Florian Meier <florian.meier(a)koalo.de>");
+MODULE_LICENSE("GPL v2");
--
1.8.1.2
3
3