Commit 166729f3 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/rt5665', 'asoc/topic/rt5677',...

Merge remote-tracking branches 'asoc/topic/rt5665', 'asoc/topic/rt5677', 'asoc/topic/samsung', 'asoc/topic/simple' and 'asoc/topic/sunxi' into asoc-next
...@@ -7,6 +7,7 @@ Required properties: ...@@ -7,6 +7,7 @@ Required properties:
- compatible: should be one of the followings - compatible: should be one of the followings
- "allwinner,sun4i-a10-i2s" - "allwinner,sun4i-a10-i2s"
- "allwinner,sun6i-a31-i2s"
- reg: physical base address of the controller and length of memory mapped - reg: physical base address of the controller and length of memory mapped
region. region.
- interrupts: should contain the I2S interrupt. - interrupts: should contain the I2S interrupt.
...@@ -19,6 +20,10 @@ Required properties: ...@@ -19,6 +20,10 @@ Required properties:
- "mod" : module clock for the I2S controller - "mod" : module clock for the I2S controller
- #sound-dai-cells : Must be equal to 0 - #sound-dai-cells : Must be equal to 0
Required properties for the following compatibles:
- "allwinner,sun6i-a31-i2s"
- resets: phandle to the reset line for this codec
Example: Example:
i2s0: i2s@01c22400 { i2s0: i2s@01c22400 {
......
Allwinner SUN8I audio codec
------------------------------------
On Sun8i-A33 SoCs, the audio is separated in different parts:
- A DAI driver. It uses the "sun4i-i2s" driver which is
documented here:
Documentation/devicetree/bindings/sound/sun4i-i2s.txt
- An analog part of the codec which is handled as PRCM registers.
See Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt
- An digital part of the codec which is documented in this current
binding documentation.
- And finally, an audio card which links all the above components.
The simple-audio card will be used.
See Documentation/devicetree/bindings/sound/simple-card.txt
This bindings documentation exposes Sun8i codec (digital part).
Required properties:
- compatible: must be "allwinner,sun8i-a33-codec"
- reg: must contain the registers location and length
- interrupts: must contain the codec interrupt
- clocks: a list of phandle + clock-specifer pairs, one for each entry
in clock-names.
- clock-names: should contain followings:
- "bus": the parent APB clock for this controller
- "mod": the parent module clock
Here is an example to add a sound card and the codec binding on sun8i SoCs that
are similar to A33 using simple-card:
sound {
compatible = "simple-audio-card";
simple-audio-card,name = "sun8i-a33-audio";
simple-audio-card,format = "i2s";
simple-audio-card,frame-master = <&link_codec>;
simple-audio-card,bitclock-master = <&link_codec>;
simple-audio-card,mclk-fs = <512>;
simple-audio-card,aux-devs = <&codec_analog>;
simple-audio-card,routing =
"Left DAC", "Digital Left DAC",
"Right DAC", "Digital Right DAC";
simple-audio-card,cpu {
sound-dai = <&dai>;
};
link_codec: simple-audio-card,codec {
sound-dai = <&codec>;
};
soc@01c00000 {
[...]
audio-codec@1c22e00 {
#sound-dai-cells = <0>;
compatible = "allwinner,sun8i-a33-codec";
reg = <0x01c22e00 0x400>;
interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>;
clock-names = "bus", "mod";
};
};
...@@ -10,6 +10,7 @@ Required properties: ...@@ -10,6 +10,7 @@ Required properties:
- compatible : should be one of the following: - compatible : should be one of the following:
- "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC - "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC
- "allwinner,sun6i-a31-spdif": for the Allwinner A31 SoC - "allwinner,sun6i-a31-spdif": for the Allwinner A31 SoC
- "allwinner,sun8i-h3-spdif": for the Allwinner H3 SoC
- reg : Offset and length of the register set for the device. - reg : Offset and length of the register set for the device.
......
...@@ -106,9 +106,7 @@ static struct s3c_audio_pdata i2sv4_pdata = { ...@@ -106,9 +106,7 @@ static struct s3c_audio_pdata i2sv4_pdata = {
.dma_playback = DMACH_HSI_I2SV40_TX, .dma_playback = DMACH_HSI_I2SV40_TX,
.dma_capture = DMACH_HSI_I2SV40_RX, .dma_capture = DMACH_HSI_I2SV40_RX,
.type = { .type = {
.i2s = { .quirks = QUIRK_PRI_6CHAN,
.quirks = QUIRK_PRI_6CHAN,
},
}, },
}; };
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
extern void s3c64xx_ac97_setup_gpio(int); extern void s3c64xx_ac97_setup_gpio(int);
struct samsung_i2s { struct samsung_i2s_type {
/* If the Primary DAI has 5.1 Channels */ /* If the Primary DAI has 5.1 Channels */
#define QUIRK_PRI_6CHAN (1 << 0) #define QUIRK_PRI_6CHAN (1 << 0)
/* If the I2S block has a Stereo Overlay Channel */ /* If the I2S block has a Stereo Overlay Channel */
...@@ -47,7 +47,5 @@ struct s3c_audio_pdata { ...@@ -47,7 +47,5 @@ struct s3c_audio_pdata {
void *dma_capture; void *dma_capture;
void *dma_play_sec; void *dma_play_sec;
void *dma_capture_mic; void *dma_capture_mic;
union { struct samsung_i2s_type type;
struct samsung_i2s i2s;
} type;
}; };
...@@ -34,11 +34,12 @@ int asoc_simple_card_set_dailink_name(struct device *dev, ...@@ -34,11 +34,12 @@ int asoc_simple_card_set_dailink_name(struct device *dev,
int asoc_simple_card_parse_card_name(struct snd_soc_card *card, int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
char *prefix); char *prefix);
#define asoc_simple_card_parse_clk_cpu(node, dai_link, simple_dai) \ #define asoc_simple_card_parse_clk_cpu(dev, node, dai_link, simple_dai) \
asoc_simple_card_parse_clk(node, dai_link->cpu_of_node, simple_dai) asoc_simple_card_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai)
#define asoc_simple_card_parse_clk_codec(node, dai_link, simple_dai) \ #define asoc_simple_card_parse_clk_codec(dev, node, dai_link, simple_dai) \
asoc_simple_card_parse_clk(node, dai_link->codec_of_node, simple_dai) asoc_simple_card_parse_clk(dev, node, dai_link->codec_of_node, simple_dai)
int asoc_simple_card_parse_clk(struct device_node *node, int asoc_simple_card_parse_clk(struct device *dev,
struct device_node *node,
struct device_node *dai_of_node, struct device_node *dai_of_node,
struct asoc_simple_dai *simple_dai); struct asoc_simple_dai *simple_dai);
......
...@@ -118,8 +118,8 @@ config SND_SOC_ALL_CODECS ...@@ -118,8 +118,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_RT5651 if I2C select SND_SOC_RT5651 if I2C
select SND_SOC_RT5659 if I2C select SND_SOC_RT5659 if I2C
select SND_SOC_RT5660 if I2C select SND_SOC_RT5660 if I2C
select SND_SOC_RT5665 if I2C
select SND_SOC_RT5663 if I2C select SND_SOC_RT5663 if I2C
select SND_SOC_RT5665 if I2C
select SND_SOC_RT5670 if I2C select SND_SOC_RT5670 if I2C
select SND_SOC_RT5677 if I2C && SPI_MASTER select SND_SOC_RT5677 if I2C && SPI_MASTER
select SND_SOC_SGTL5000 if I2C select SND_SOC_SGTL5000 if I2C
...@@ -671,8 +671,8 @@ config SND_SOC_RL6231 ...@@ -671,8 +671,8 @@ config SND_SOC_RL6231
default y if SND_SOC_RT5651=y default y if SND_SOC_RT5651=y
default y if SND_SOC_RT5659=y default y if SND_SOC_RT5659=y
default y if SND_SOC_RT5660=y default y if SND_SOC_RT5660=y
default y if SND_SOC_RT5665=y
default y if SND_SOC_RT5663=y default y if SND_SOC_RT5663=y
default y if SND_SOC_RT5665=y
default y if SND_SOC_RT5670=y default y if SND_SOC_RT5670=y
default y if SND_SOC_RT5677=y default y if SND_SOC_RT5677=y
default m if SND_SOC_RT5514=m default m if SND_SOC_RT5514=m
...@@ -682,8 +682,8 @@ config SND_SOC_RL6231 ...@@ -682,8 +682,8 @@ config SND_SOC_RL6231
default m if SND_SOC_RT5651=m default m if SND_SOC_RT5651=m
default m if SND_SOC_RT5659=m default m if SND_SOC_RT5659=m
default m if SND_SOC_RT5660=m default m if SND_SOC_RT5660=m
default m if SND_SOC_RT5665=m
default m if SND_SOC_RT5663=m default m if SND_SOC_RT5663=m
default m if SND_SOC_RT5665=m
default m if SND_SOC_RT5670=m default m if SND_SOC_RT5670=m
default m if SND_SOC_RT5677=m default m if SND_SOC_RT5677=m
...@@ -731,10 +731,10 @@ config SND_SOC_RT5659 ...@@ -731,10 +731,10 @@ config SND_SOC_RT5659
config SND_SOC_RT5660 config SND_SOC_RT5660
tristate tristate
config SND_SOC_RT5665 config SND_SOC_RT5663
tristate tristate
config SND_SOC_RT5663 config SND_SOC_RT5665
tristate tristate
config SND_SOC_RT5670 config SND_SOC_RT5670
......
...@@ -119,8 +119,8 @@ snd-soc-rt5645-objs := rt5645.o ...@@ -119,8 +119,8 @@ snd-soc-rt5645-objs := rt5645.o
snd-soc-rt5651-objs := rt5651.o snd-soc-rt5651-objs := rt5651.o
snd-soc-rt5659-objs := rt5659.o snd-soc-rt5659-objs := rt5659.o
snd-soc-rt5660-objs := rt5660.o snd-soc-rt5660-objs := rt5660.o
snd-soc-rt5665-objs := rt5665.o
snd-soc-rt5663-objs := rt5663.o snd-soc-rt5663-objs := rt5663.o
snd-soc-rt5665-objs := rt5665.o
snd-soc-rt5670-objs := rt5670.o snd-soc-rt5670-objs := rt5670.o
snd-soc-rt5677-objs := rt5677.o snd-soc-rt5677-objs := rt5677.o
snd-soc-rt5677-spi-objs := rt5677-spi.o snd-soc-rt5677-spi-objs := rt5677-spi.o
...@@ -348,8 +348,8 @@ obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o ...@@ -348,8 +348,8 @@ obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o
obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o
obj-$(CONFIG_SND_SOC_RT5659) += snd-soc-rt5659.o obj-$(CONFIG_SND_SOC_RT5659) += snd-soc-rt5659.o
obj-$(CONFIG_SND_SOC_RT5660) += snd-soc-rt5660.o obj-$(CONFIG_SND_SOC_RT5660) += snd-soc-rt5660.o
obj-$(CONFIG_SND_SOC_RT5665) += snd-soc-rt5665.o
obj-$(CONFIG_SND_SOC_RT5663) += snd-soc-rt5663.o obj-$(CONFIG_SND_SOC_RT5663) += snd-soc-rt5663.o
obj-$(CONFIG_SND_SOC_RT5665) += snd-soc-rt5665.o
obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o
obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o
obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/pm_qos.h> #include <linux/pm_qos.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
......
...@@ -98,7 +98,8 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card, ...@@ -98,7 +98,8 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
} }
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name); EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name);
int asoc_simple_card_parse_clk(struct device_node *node, int asoc_simple_card_parse_clk(struct device *dev,
struct device_node *node,
struct device_node *dai_of_node, struct device_node *dai_of_node,
struct asoc_simple_dai *simple_dai) struct asoc_simple_dai *simple_dai)
{ {
...@@ -111,14 +112,13 @@ int asoc_simple_card_parse_clk(struct device_node *node, ...@@ -111,14 +112,13 @@ int asoc_simple_card_parse_clk(struct device_node *node,
* or "system-clock-frequency = <xxx>" * or "system-clock-frequency = <xxx>"
* or device's module clock. * or device's module clock.
*/ */
clk = of_clk_get(node, 0); clk = devm_get_clk_from_child(dev, node, NULL);
if (!IS_ERR(clk)) { if (!IS_ERR(clk)) {
simple_dai->sysclk = clk_get_rate(clk); simple_dai->sysclk = clk_get_rate(clk);
simple_dai->clk = clk;
} else if (!of_property_read_u32(node, "system-clock-frequency", &val)) { } else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
simple_dai->sysclk = val; simple_dai->sysclk = val;
} else { } else {
clk = of_clk_get(dai_of_node, 0); clk = devm_get_clk_from_child(dev, dai_of_node, NULL);
if (!IS_ERR(clk)) if (!IS_ERR(clk))
simple_dai->sysclk = clk_get_rate(clk); simple_dai->sysclk = clk_get_rate(clk);
} }
......
...@@ -278,11 +278,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, ...@@ -278,11 +278,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
if (ret < 0) if (ret < 0)
goto dai_link_of_err; goto dai_link_of_err;
ret = asoc_simple_card_parse_clk_cpu(cpu, dai_link, cpu_dai); ret = asoc_simple_card_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
if (ret < 0) if (ret < 0)
goto dai_link_of_err; goto dai_link_of_err;
ret = asoc_simple_card_parse_clk_codec(codec, dai_link, codec_dai); ret = asoc_simple_card_parse_clk_codec(dev, codec, dai_link, codec_dai);
if (ret < 0) if (ret < 0)
goto dai_link_of_err; goto dai_link_of_err;
......
...@@ -128,7 +128,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, ...@@ -128,7 +128,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
if (ret) if (ret)
return ret; return ret;
ret = asoc_simple_card_parse_clk_cpu(np, dai_link, dai_props); ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai_props);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -153,7 +153,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, ...@@ -153,7 +153,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = asoc_simple_card_parse_clk_codec(np, dai_link, dai_props); ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai_props);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -111,6 +111,7 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380 ...@@ -111,6 +111,7 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380
config SND_SOC_SMARTQ config SND_SOC_SMARTQ
tristate "SoC I2S Audio support for SmartQ board" tristate "SoC I2S Audio support for SmartQ board"
depends on MACH_SMARTQ || COMPILE_TEST depends on MACH_SMARTQ || COMPILE_TEST
depends on GPIOLIB || COMPILE_TEST
depends on I2C depends on I2C
select SND_SAMSUNG_I2S select SND_SAMSUNG_I2S
select SND_SOC_WM8750 select SND_SOC_WM8750
...@@ -193,6 +194,7 @@ config SND_SOC_ARNDALE_RT5631_ALC5631 ...@@ -193,6 +194,7 @@ config SND_SOC_ARNDALE_RT5631_ALC5631
config SND_SOC_SAMSUNG_TM2_WM5110 config SND_SOC_SAMSUNG_TM2_WM5110
tristate "SoC I2S Audio support for WM5110 on TM2 board" tristate "SoC I2S Audio support for WM5110 on TM2 board"
depends on SND_SOC_SAMSUNG && MFD_ARIZONA && I2C && SPI_MASTER depends on SND_SOC_SAMSUNG && MFD_ARIZONA && I2C && SPI_MASTER
depends on GPIOLIB || COMPILE_TEST
select SND_SOC_MAX98504 select SND_SOC_MAX98504
select SND_SOC_WM5110 select SND_SOC_WM5110
select SND_SAMSUNG_I2S select SND_SAMSUNG_I2S
......
This diff is collapsed.
...@@ -32,14 +32,11 @@ static int smdk_hw_params(struct snd_pcm_substream *substream, ...@@ -32,14 +32,11 @@ static int smdk_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai;
unsigned int pll_out; unsigned int pll_out;
int bfs, rfs, ret; int rfs, ret;
switch (params_width(params)) { switch (params_width(params)) {
case 8: case 8:
bfs = 16;
break;
case 16: case 16:
bfs = 32;
break; break;
default: default:
return -EINVAL; return -EINVAL;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
......
...@@ -9,9 +9,20 @@ config SND_SUN4I_CODEC ...@@ -9,9 +9,20 @@ config SND_SUN4I_CODEC
Select Y or M to add support for the Codec embedded in the Allwinner Select Y or M to add support for the Codec embedded in the Allwinner
A10 and affiliated SoCs. A10 and affiliated SoCs.
config SND_SUN8I_CODEC
tristate "Allwinner SUN8I audio codec"
depends on OF
depends on MACH_SUN8I || COMPILE_TEST
select REGMAP_MMIO
help
This option enables the digital part of the internal audio codec for
Allwinner sun8i SoC (and particularly A33).
Say Y or M if you want to add sun8i digital audio codec support.
config SND_SUN8I_CODEC_ANALOG config SND_SUN8I_CODEC_ANALOG
tristate "Allwinner sun8i Codec Analog Controls Support" tristate "Allwinner sun8i Codec Analog Controls Support"
depends on MACH_SUN8I || COMPILE_TEST depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST
select REGMAP select REGMAP
help help
Say Y or M if you want to add support for the analog controls for Say Y or M if you want to add support for the analog controls for
......
...@@ -2,3 +2,4 @@ obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o ...@@ -2,3 +2,4 @@ obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o
obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o
obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o
obj-$(CONFIG_SND_SUN8I_CODEC) += sun8i-codec.o
...@@ -1058,6 +1058,7 @@ static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = { ...@@ -1058,6 +1058,7 @@ static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
{ "Line Out Source Playback Route", "Stereo", "Left Mixer" }, { "Line Out Source Playback Route", "Stereo", "Left Mixer" },
{ "Line Out Source Playback Route", "Stereo", "Right Mixer" }, { "Line Out Source Playback Route", "Stereo", "Right Mixer" },
{ "Line Out Source Playback Route", "Mono Differential", "Left Mixer" }, { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
{ "Line Out Source Playback Route", "Mono Differential", "Right Mixer" },
{ "LINEOUT", NULL, "Line Out Source Playback Route" }, { "LINEOUT", NULL, "Line Out Source Playback Route" },
/* ADC Routes */ /* ADC Routes */
......
...@@ -14,9 +14,11 @@ ...@@ -14,9 +14,11 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/reset.h>
#include <sound/dmaengine_pcm.h> #include <sound/dmaengine_pcm.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
...@@ -92,6 +94,7 @@ struct sun4i_i2s { ...@@ -92,6 +94,7 @@ struct sun4i_i2s {
struct clk *bus_clk; struct clk *bus_clk;
struct clk *mod_clk; struct clk *mod_clk;
struct regmap *regmap; struct regmap *regmap;
struct reset_control *rst;
unsigned int mclk_freq; unsigned int mclk_freq;
...@@ -651,9 +654,22 @@ static int sun4i_i2s_runtime_suspend(struct device *dev) ...@@ -651,9 +654,22 @@ static int sun4i_i2s_runtime_suspend(struct device *dev)
return 0; return 0;
} }
struct sun4i_i2s_quirks {
bool has_reset;
};
static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
.has_reset = false,
};
static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
.has_reset = true,
};
static int sun4i_i2s_probe(struct platform_device *pdev) static int sun4i_i2s_probe(struct platform_device *pdev)
{ {
struct sun4i_i2s *i2s; struct sun4i_i2s *i2s;
const struct sun4i_i2s_quirks *quirks;
struct resource *res; struct resource *res;
void __iomem *regs; void __iomem *regs;
int irq, ret; int irq, ret;
...@@ -674,6 +690,12 @@ static int sun4i_i2s_probe(struct platform_device *pdev) ...@@ -674,6 +690,12 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
return irq; return irq;
} }
quirks = of_device_get_match_data(&pdev->dev);
if (!quirks) {
dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
return -ENODEV;
}
i2s->bus_clk = devm_clk_get(&pdev->dev, "apb"); i2s->bus_clk = devm_clk_get(&pdev->dev, "apb");
if (IS_ERR(i2s->bus_clk)) { if (IS_ERR(i2s->bus_clk)) {
dev_err(&pdev->dev, "Can't get our bus clock\n"); dev_err(&pdev->dev, "Can't get our bus clock\n");
...@@ -692,7 +714,24 @@ static int sun4i_i2s_probe(struct platform_device *pdev) ...@@ -692,7 +714,24 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Can't get our mod clock\n"); dev_err(&pdev->dev, "Can't get our mod clock\n");
return PTR_ERR(i2s->mod_clk); return PTR_ERR(i2s->mod_clk);
} }
if (quirks->has_reset) {
i2s->rst = devm_reset_control_get(&pdev->dev, NULL);
if (IS_ERR(i2s->rst)) {
dev_err(&pdev->dev, "Failed to get reset control\n");
return PTR_ERR(i2s->rst);
}
}
if (!IS_ERR(i2s->rst)) {
ret = reset_control_deassert(i2s->rst);
if (ret) {
dev_err(&pdev->dev,
"Failed to deassert the reset control\n");
return -EINVAL;
}
}
i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG; i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG;
i2s->playback_dma_data.maxburst = 8; i2s->playback_dma_data.maxburst = 8;
...@@ -727,23 +766,37 @@ static int sun4i_i2s_probe(struct platform_device *pdev) ...@@ -727,23 +766,37 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
sun4i_i2s_runtime_suspend(&pdev->dev); sun4i_i2s_runtime_suspend(&pdev->dev);
err_pm_disable: err_pm_disable:
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
if (!IS_ERR(i2s->rst))
reset_control_assert(i2s->rst);
return ret; return ret;
} }
static int sun4i_i2s_remove(struct platform_device *pdev) static int sun4i_i2s_remove(struct platform_device *pdev)
{ {
struct sun4i_i2s *i2s = dev_get_drvdata(&pdev->dev);
snd_dmaengine_pcm_unregister(&pdev->dev); snd_dmaengine_pcm_unregister(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
if (!pm_runtime_status_suspended(&pdev->dev)) if (!pm_runtime_status_suspended(&pdev->dev))
sun4i_i2s_runtime_suspend(&pdev->dev); sun4i_i2s_runtime_suspend(&pdev->dev);
if (!IS_ERR(i2s->rst))
reset_control_assert(i2s->rst);
return 0; return 0;
} }
static const struct of_device_id sun4i_i2s_match[] = { static const struct of_device_id sun4i_i2s_match[] = {
{ .compatible = "allwinner,sun4i-a10-i2s", }, {
.compatible = "allwinner,sun4i-a10-i2s",
.data = &sun4i_a10_i2s_quirks,
},
{
.compatible = "allwinner,sun6i-a31-i2s",
.data = &sun6i_a31_i2s_quirks,
},
{} {}
}; };
MODULE_DEVICE_TABLE(of, sun4i_i2s_match); MODULE_DEVICE_TABLE(of, sun4i_i2s_match);
......
...@@ -103,6 +103,8 @@ ...@@ -103,6 +103,8 @@
#define SUN4I_SPDIF_ISTA_RXOSTA BIT(1) #define SUN4I_SPDIF_ISTA_RXOSTA BIT(1)
#define SUN4I_SPDIF_ISTA_RXASTA BIT(0) #define SUN4I_SPDIF_ISTA_RXASTA BIT(0)
#define SUN8I_SPDIF_TXFIFO (0x20)
#define SUN4I_SPDIF_TXCNT (0x24) #define SUN4I_SPDIF_TXCNT (0x24)
#define SUN4I_SPDIF_RXCNT (0x28) #define SUN4I_SPDIF_RXCNT (0x28)
...@@ -403,17 +405,38 @@ static struct snd_soc_dai_driver sun4i_spdif_dai = { ...@@ -403,17 +405,38 @@ static struct snd_soc_dai_driver sun4i_spdif_dai = {
.name = "spdif", .name = "spdif",
}; };
static const struct snd_soc_dapm_widget dit_widgets[] = { struct sun4i_spdif_quirks {
SND_SOC_DAPM_OUTPUT("spdif-out"), unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */
bool has_reset;
};
static const struct sun4i_spdif_quirks sun4i_a10_spdif_quirks = {
.reg_dac_txdata = SUN4I_SPDIF_TXFIFO,
}; };
static const struct snd_soc_dapm_route dit_routes[] = { static const struct sun4i_spdif_quirks sun6i_a31_spdif_quirks = {
{ "spdif-out", NULL, "Playback" }, .reg_dac_txdata = SUN4I_SPDIF_TXFIFO,
.has_reset = true,
};
static const struct sun4i_spdif_quirks sun8i_h3_spdif_quirks = {
.reg_dac_txdata = SUN8I_SPDIF_TXFIFO,
.has_reset = true,
}; };
static const struct of_device_id sun4i_spdif_of_match[] = { static const struct of_device_id sun4i_spdif_of_match[] = {
{ .compatible = "allwinner,sun4i-a10-spdif", }, {
{ .compatible = "allwinner,sun6i-a31-spdif", }, .compatible = "allwinner,sun4i-a10-spdif",
.data = &sun4i_a10_spdif_quirks,
},
{
.compatible = "allwinner,sun6i-a31-spdif",
.data = &sun6i_a31_spdif_quirks,
},
{
.compatible = "allwinner,sun8i-h3-spdif",
.data = &sun8i_h3_spdif_quirks,
},
{ /* sentinel */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, sun4i_spdif_of_match); MODULE_DEVICE_TABLE(of, sun4i_spdif_of_match);
...@@ -446,6 +469,7 @@ static int sun4i_spdif_probe(struct platform_device *pdev) ...@@ -446,6 +469,7 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
{ {
struct sun4i_spdif_dev *host; struct sun4i_spdif_dev *host;
struct resource *res; struct resource *res;
const struct sun4i_spdif_quirks *quirks;
int ret; int ret;
void __iomem *base; void __iomem *base;
...@@ -467,6 +491,12 @@ static int sun4i_spdif_probe(struct platform_device *pdev) ...@@ -467,6 +491,12 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
if (IS_ERR(base)) if (IS_ERR(base))
return PTR_ERR(base); return PTR_ERR(base);
quirks = of_device_get_match_data(&pdev->dev);
if (quirks == NULL) {
dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
return -ENODEV;
}
host->regmap = devm_regmap_init_mmio(&pdev->dev, base, host->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&sun4i_spdif_regmap_config); &sun4i_spdif_regmap_config);
...@@ -480,23 +510,21 @@ static int sun4i_spdif_probe(struct platform_device *pdev) ...@@ -480,23 +510,21 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
host->spdif_clk = devm_clk_get(&pdev->dev, "spdif"); host->spdif_clk = devm_clk_get(&pdev->dev, "spdif");
if (IS_ERR(host->spdif_clk)) { if (IS_ERR(host->spdif_clk)) {
dev_err(&pdev->dev, "failed to get a spdif clock.\n"); dev_err(&pdev->dev, "failed to get a spdif clock.\n");
ret = PTR_ERR(host->spdif_clk); return PTR_ERR(host->spdif_clk);
goto err_disable_apb_clk;
} }
host->dma_params_tx.addr = res->start + SUN4I_SPDIF_TXFIFO; host->dma_params_tx.addr = res->start + quirks->reg_dac_txdata;
host->dma_params_tx.maxburst = 8; host->dma_params_tx.maxburst = 8;
host->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; host->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
platform_set_drvdata(pdev, host); platform_set_drvdata(pdev, host);
if (of_device_is_compatible(pdev->dev.of_node, if (quirks->has_reset) {
"allwinner,sun6i-a31-spdif")) {
host->rst = devm_reset_control_get_optional(&pdev->dev, NULL); host->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
if (IS_ERR(host->rst) && PTR_ERR(host->rst) == -EPROBE_DEFER) { if (IS_ERR(host->rst) && PTR_ERR(host->rst) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER; ret = -EPROBE_DEFER;
dev_err(&pdev->dev, "Failed to get reset: %d\n", ret); dev_err(&pdev->dev, "Failed to get reset: %d\n", ret);
goto err_disable_apb_clk; return ret;
} }
if (!IS_ERR(host->rst)) if (!IS_ERR(host->rst))
reset_control_deassert(host->rst); reset_control_deassert(host->rst);
...@@ -505,7 +533,7 @@ static int sun4i_spdif_probe(struct platform_device *pdev) ...@@ -505,7 +533,7 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_component(&pdev->dev, ret = devm_snd_soc_register_component(&pdev->dev,
&sun4i_spdif_component, &sun4i_spdif_dai, 1); &sun4i_spdif_component, &sun4i_spdif_dai, 1);
if (ret) if (ret)
goto err_disable_apb_clk; return ret;
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev)) { if (!pm_runtime_enabled(&pdev->dev)) {
...@@ -523,9 +551,6 @@ static int sun4i_spdif_probe(struct platform_device *pdev) ...@@ -523,9 +551,6 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
sun4i_spdif_runtime_suspend(&pdev->dev); sun4i_spdif_runtime_suspend(&pdev->dev);
err_unregister: err_unregister:
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
snd_soc_unregister_component(&pdev->dev);
err_disable_apb_clk:
clk_disable_unprepare(host->apb_clk);
return ret; return ret;
} }
...@@ -535,9 +560,6 @@ static int sun4i_spdif_remove(struct platform_device *pdev) ...@@ -535,9 +560,6 @@ static int sun4i_spdif_remove(struct platform_device *pdev)
if (!pm_runtime_status_suspended(&pdev->dev)) if (!pm_runtime_status_suspended(&pdev->dev))
sun4i_spdif_runtime_suspend(&pdev->dev); sun4i_spdif_runtime_suspend(&pdev->dev);
snd_soc_unregister_platform(&pdev->dev);
snd_soc_unregister_component(&pdev->dev);
return 0; return 0;
} }
......
...@@ -398,11 +398,37 @@ static const struct snd_kcontrol_new sun8i_codec_hp_src[] = { ...@@ -398,11 +398,37 @@ static const struct snd_kcontrol_new sun8i_codec_hp_src[] = {
sun8i_codec_hp_src_enum), sun8i_codec_hp_src_enum),
}; };
static int sun8i_headphone_amp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
if (SND_SOC_DAPM_EVENT_ON(event)) {
snd_soc_component_update_bits(component, SUN8I_ADDA_PAEN_HP_CTRL,
BIT(SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN),
BIT(SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN));
/*
* Need a delay to have the amplifier up. 700ms seems the best
* compromise between the time to let the amplifier up and the
* time not to feel this delay while playing a sound.
*/
msleep(700);
} else if (SND_SOC_DAPM_EVENT_OFF(event)) {
snd_soc_component_update_bits(component, SUN8I_ADDA_PAEN_HP_CTRL,
BIT(SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN),
0x0);
}
return 0;
}
static const struct snd_soc_dapm_widget sun8i_codec_headphone_widgets[] = { static const struct snd_soc_dapm_widget sun8i_codec_headphone_widgets[] = {
SND_SOC_DAPM_MUX("Headphone Source Playback Route", SND_SOC_DAPM_MUX("Headphone Source Playback Route",
SND_SOC_NOPM, 0, 0, sun8i_codec_hp_src), SND_SOC_NOPM, 0, 0, sun8i_codec_hp_src),
SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN8I_ADDA_PAEN_HP_CTRL, SND_SOC_DAPM_OUT_DRV_E("Headphone Amp", SUN8I_ADDA_PAEN_HP_CTRL,
SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN, 0, NULL, 0), SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN, 0, NULL, 0,
sun8i_headphone_amp_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN8I_ADDA_PAEN_HP_CTRL, SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN8I_ADDA_PAEN_HP_CTRL,
SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN, 0, NULL, 0), SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN, 0, NULL, 0),
SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN8I_ADDA_PAEN_HP_CTRL, SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN8I_ADDA_PAEN_HP_CTRL,
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment