Merge remote-tracking branches 'asoc/topic/ad1836', 'asoc/topic/ad193x', 'asoc/topic/adav80x', 'asoc/topic/adsp', 'asoc/topic/ak4641', 'asoc/topic/ak4642', 'asoc/topic/arizona', 'asoc/topic/atmel', 'asoc/topic/au1x', 'asoc/topic/axi', 'asoc/topic/bcm2835', 'asoc/topic/blackfin', 'asoc/topic/cs4271', 'asoc/topic/cs42l52', 'asoc/topic/da7210', 'asoc/topic/davinci', 'asoc/topic/ep93xx', 'asoc/topic/fsl', 'asoc/topic/fsl-mxs', 'asoc/topic/generic', 'asoc/topic/hdmi', 'asoc/topic/jack', 'asoc/topic/jz4740', 'asoc/topic/max98090', 'asoc/topic/mxs', 'asoc/topic/omap', 'asoc/topic/pxa', 'asoc/topic/rcar', 'asoc/topic/s6000', 'asoc/topic/sai', 'asoc/topic/samsung', 'asoc/topic/sgtl5000', 'asoc/topic/spear', 'asoc/topic/ssm2518', 'asoc/topic/ssm2602', 'asoc/topic/tegra', 'asoc/topic/tlv320aic3x', 'asoc/topic/twl6040', 'asoc/topic/txx9', 'asoc/topic/uda1380', 'asoc/topic/width', 'asoc/topic/wm8510', 'asoc/topic/wm8523', 'asoc/topic/wm8580', 'asoc/topic/wm8711', 'asoc/topic/wm8728', 'asoc/topic/wm8731', 'asoc/topic/wm8741', 'asoc/topic/wm8750', 'asoc/topic/wm8753', 'asoc/topic/wm8776', 'asoc/topic/wm8804', 'asoc/topic/wm8900', 'asoc/topic/wm8901', 'asoc/topic/wm8940', 'asoc/topic/wm8962', 'asoc/topic/wm8974', 'asoc/topic/wm8985', 'asoc/topic/wm8988', 'asoc/topic/wm8990', 'asoc/topic/wm8991', 'asoc/topic/wm8994', 'asoc/topic/wm8995', 'asoc/topic/wm9081' and 'asoc/topic/x86' into asoc-next

This commit is contained in:
167 changed files with 6676 additions and 3712 deletions

View File

@ -0,0 +1,31 @@
ADI AXI-I2S controller
Required properties:
- compatible : Must be "adi,axi-i2s-1.00.a"
- reg : Must contain I2S core's registers location and length
- clocks : Pairs of phandle and specifier referencing the controller's clocks.
The controller expects two clocks, the clock used for the AXI interface and
the clock used as the sampling rate reference clock sample.
- clock-names : "axi" for the clock to the AXI interface, "ref" for the sample
rate reference clock.
- dmas: Pairs of phandle and specifier for the DMA channels that are used by
the core. The core expects two dma channels, one for transmit and one for
receive.
- dma-names : "tx" for the transmit channel, "rx" for the receive channel.
For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties
please check:
* resource-names.txt
* clock/clock-bindings.txt
* dma/dma.txt
Example:
i2s: i2s@0x77600000 {
compatible = "adi,axi-i2s-1.00.a";
reg = <0x77600000 0x1000>;
clocks = <&clk 15>, <&audio_clock>;
clock-names = "axi", "ref";
dmas = <&ps7_dma 0>, <&ps7_dma 1>;
dma-names = "tx", "rx";
};

View File

@ -0,0 +1,30 @@
ADI AXI-SPDIF controller
Required properties:
- compatible : Must be "adi,axi-spdif-1.00.a"
- reg : Must contain SPDIF core's registers location and length
- clocks : Pairs of phandle and specifier referencing the controller's clocks.
The controller expects two clocks, the clock used for the AXI interface and
the clock used as the sampling rate reference clock sample.
- clock-names: "axi" for the clock to the AXI interface, "ref" for the sample
rate reference clock.
- dmas: Pairs of phandle and specifier for the DMA channel that is used by
the core. The core expects one dma channel for transmit.
- dma-names : Must be "tx"
For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties
please check:
* resource-names.txt
* clock/clock-bindings.txt
* dma/dma.txt
Example:
spdif: spdif@0x77400000 {
compatible = "adi,axi-spdif-tx-1.00.a";
reg = <0x77600000 0x1000>;
clocks = <&clk 15>, <&audio_clock>;
clock-names = "axi", "ref";
dmas = <&ps7_dma 0>;
dma-names = "tx";
};

View File

@ -0,0 +1,25 @@
* Broadcom BCM2835 SoC I2S/PCM module
Required properties:
- compatible: "brcm,bcm2835-i2s"
- reg: A list of base address and size entries:
* The first entry should cover the PCM registers
* The second entry should cover the PCM clock registers
- dmas: List of DMA controller phandle and DMA request line ordered pairs.
- dma-names: Identifier string for each DMA request line in the dmas property.
These strings correspond 1:1 with the ordered pairs in dmas.
One of the DMA channels will be responsible for transmission (should be
named "tx") and one for reception (should be named "rx").
Example:
bcm2835_i2s: i2s@7e203000 {
compatible = "brcm,bcm2835-i2s";
reg = <0x7e203000 0x20>,
<0x7e101098 0x02>;
dmas = <&dma 2>,
<&dma 3>;
dma-names = "tx", "rx";
};

View File

@ -0,0 +1,46 @@
CS42L52 audio CODEC
Required properties:
- compatible : "cirrus,cs42l52"
- reg : the I2C address of the device for I2C
Optional properties:
- cirrus,reset-gpio : GPIO controller's phandle and the number
of the GPIO used to reset the codec.
- cirrus,chgfreq-divisor : Values used to set the Charge Pump Frequency.
Allowable values of 0x00 through 0x0F. These are raw values written to the
register, not the actual frequency. The frequency is determined by the following.
Frequency = (64xFs)/(N+2)
N = chgfreq_val
Fs = Sample Rate (variable)
- cirrus,mica-differential-cfg : boolean, If present, then the MICA input is configured
as a differential input. If not present then the MICA input is configured as
Single-ended input. Single-ended mode allows for MIC1 or MIC2 muxing for input.
- cirrus,micb-differential-cfg : boolean, If present, then the MICB input is configured
as a differential input. If not present then the MICB input is configured as
Single-ended input. Single-ended mode allows for MIC1 or MIC2 muxing for input.
- cirrus,micbias-lvl: Set the output voltage level on the MICBIAS Pin
0 = 0.5 x VA
1 = 0.6 x VA
2 = 0.7 x VA
3 = 0.8 x VA
4 = 0.83 x VA
5 = 0.91 x VA
Example:
codec: codec@4a {
compatible = "cirrus,cs42l52";
reg = <0x4a>;
reset-gpio = <&gpio 10 0>;
cirrus,chgfreq-divisor = <0x05>;
cirrus.mica-differential-cfg;
cirrus,micbias-lvl = <5>;
};

View File

@ -4,7 +4,8 @@ Required properties:
- compatible : - compatible :
"ti,dm646x-mcasp-audio" : for DM646x platforms "ti,dm646x-mcasp-audio" : for DM646x platforms
"ti,da830-mcasp-audio" : for both DA830 & DA850 platforms "ti,da830-mcasp-audio" : for both DA830 & DA850 platforms
"ti,am33xx-mcasp-audio" : for AM33xx platforms (AM33xx, TI81xx) "ti,am33xx-mcasp-audio" : for AM33xx platforms (AM33xx, AM43xx, TI81xx)
"ti,dra7-mcasp-audio" : for DRA7xx platforms
- reg : Should contain reg specifiers for the entries in the reg-names property. - reg : Should contain reg specifiers for the entries in the reg-names property.
- reg-names : Should contain: - reg-names : Should contain:
@ -36,7 +37,8 @@ Optional properties:
- pinctrl-0: Should specify pin control group used for this controller. - pinctrl-0: Should specify pin control group used for this controller.
- pinctrl-names: Should contain only one value - "default", for more details - pinctrl-names: Should contain only one value - "default", for more details
please refer to pinctrl-bindings.txt please refer to pinctrl-bindings.txt
- fck_parent : Should contain a valid clock name which will be used as parent
for the McASP fck
Example: Example:

View File

@ -0,0 +1,40 @@
Freescale Synchronous Audio Interface (SAI).
The SAI is based on I2S module that used communicating with audio codecs,
which provides a synchronous audio interface that supports fullduplex
serial interfaces with frame synchronization such as I2S, AC97, TDM, and
codec/DSP interfaces.
Required properties:
- compatible: Compatible list, contains "fsl,vf610-sai".
- reg: Offset and length of the register set for the device.
- clocks: Must contain an entry for each entry in clock-names.
- clock-names : Must include the "sai" entry.
- dmas : Generic dma devicetree binding as described in
Documentation/devicetree/bindings/dma/dma.txt.
- dma-names : Two dmas have to be defined, "tx" and "rx".
- pinctrl-names: Must contain a "default" entry.
- pinctrl-NNN: One property must exist for each entry in pinctrl-names.
See ../pinctrl/pinctrl-bindings.txt for details of the property values.
- big-endian-regs: If this property is absent, the little endian mode will
be in use as default, or the big endian mode will be in use for all the
device registers.
- big-endian-data: If this property is absent, the little endian mode will
be in use as default, or the big endian mode will be in use for all the
fifo data.
Example:
sai2: sai@40031000 {
compatible = "fsl,vf610-sai";
reg = <0x40031000 0x1000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_sai2_1>;
clocks = <&clks VF610_CLK_SAI2>;
clock-names = "sai";
dma-names = "tx", "rx";
dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>,
<&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>;
big-endian-regs;
big-endian-data;
};

View File

@ -0,0 +1,17 @@
Device-Tree bindings for dummy HDMI codec
Required properties:
- compatible: should be "linux,hdmi-audio".
CODEC output pins:
* TX
CODEC input pins:
* RX
Example node:
hdmi_audio: hdmi_audio@0 {
compatible = "linux,hdmi-audio";
status = "okay";
};

View File

@ -0,0 +1,43 @@
MAX98090 audio CODEC
This device supports I2C only.
Required properties:
- compatible : "maxim,max98090".
- reg : The I2C address of the device.
- interrupts : The CODEC's interrupt output.
Pins on the device (for linking into audio routes):
* MIC1
* MIC2
* DMICL
* DMICR
* IN1
* IN2
* IN3
* IN4
* IN5
* IN6
* IN12
* IN34
* IN56
* HPL
* HPR
* SPKL
* SPKR
* RCVL
* RCVR
* MICBIAS
Example:
audio-codec@10 {
compatible = "maxim,max98090";
reg = <0x10>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(H, 4) GPIO_ACTIVE_HIGH>;
};

View File

@ -0,0 +1,51 @@
NVIDIA Tegra audio complex, with MAX98090 CODEC
Required properties:
- compatible : "nvidia,tegra-audio-max98090"
- clocks : Must contain an entry for each entry in clock-names.
See ../clocks/clock-bindings.txt for details.
- clock-names : Must include the following entries:
- pll_a
- pll_a_out0
- mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk)
- nvidia,model : The user-visible name of this sound complex.
- nvidia,audio-routing : A list of the connections between audio components.
Each entry is a pair of strings, the first being the connection's sink,
the second being the connection's source. Valid names for sources and
sinks are the MAX98090's pins (as documented in its binding), and the jacks
on the board:
* Headphones
* Speakers
* Mic Jack
- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
connected to the CODEC.
- nvidia,audio-codec : The phandle of the MAX98090 audio codec.
Optional properties:
- nvidia,hp-det-gpios : The GPIO that detect headphones are plugged in
Example:
sound {
compatible = "nvidia,tegra-audio-max98090-venice2",
"nvidia,tegra-audio-max98090";
nvidia,model = "NVIDIA Tegra Venice2";
nvidia,audio-routing =
"Headphones", "HPR",
"Headphones", "HPL",
"Speakers", "SPKR",
"Speakers", "SPKL",
"Mic Jack", "MICBIAS",
"IN34", "Mic Jack";
nvidia,i2s-controller = <&tegra_i2s1>;
nvidia,audio-codec = <&acodec>;
clocks = <&tegra_car TEGRA124_CLK_PLL_A>,
<&tegra_car TEGRA124_CLK_PLL_A_OUT0>,
<&tegra_car TEGRA124_CLK_EXTERN1>;
clock-names = "pll_a", "pll_a_out0", "mclk";
};

View File

@ -9,8 +9,13 @@ Required properties:
Optional properties: Optional properties:
- simple-audio-card,format : CPU/CODEC common audio format. - simple-audio-card,format : CPU/CODEC common audio format.
"i2s", "right_j", "left_j" , "dsp_a" "i2s", "right_j", "left_j" , "dsp_a"
"dsp_b", "ac97", "pdm", "msb", "lsb" "dsp_b", "ac97", "pdm", "msb", "lsb"
- simple-audio-routing : A list of the connections between audio components.
Each entry is a pair of strings, the first being the
connection's sink, the second being the connection's
source.
Required subnodes: Required subnodes:
- simple-audio-card,cpu : CPU sub-node - simple-audio-card,cpu : CPU sub-node
@ -38,6 +43,10 @@ Example:
sound { sound {
compatible = "simple-audio-card"; compatible = "simple-audio-card";
simple-audio-card,format = "left_j"; simple-audio-card,format = "left_j";
simple-audio-routing =
"MIC_IN", "Mic Jack",
"Headphone Jack", "HP_OUT",
"Ext Spk", "LINE_OUT";
simple-audio-card,cpu { simple-audio-card,cpu {
sound-dai = <&sh_fsi2 0>; sound-dai = <&sh_fsi2 0>;

View File

@ -723,6 +723,7 @@ config ARCH_S3C64XX
bool "Samsung S3C64XX" bool "Samsung S3C64XX"
select ARCH_HAS_CPUFREQ select ARCH_HAS_CPUFREQ
select ARCH_REQUIRE_GPIOLIB select ARCH_REQUIRE_GPIOLIB
select ARM_AMBA
select ARM_VIC select ARM_VIC
select CLKDEV_LOOKUP select CLKDEV_LOOKUP
select CLKSRC_SAMSUNG_PWM select CLKSRC_SAMSUNG_PWM

View File

@ -17,9 +17,10 @@ config CPU_S3C6410
help help
Enable S3C6410 CPU support Enable S3C6410 CPU support
config S3C64XX_DMA config S3C64XX_PL080
bool "S3C64XX DMA" bool "S3C64XX DMA using generic PL08x driver"
select S3C_DMA select AMBA_PL08X
select SAMSUNG_DMADEV
config S3C64XX_SETUP_SDHCI config S3C64XX_SETUP_SDHCI
bool bool

View File

@ -26,7 +26,7 @@ obj-$(CONFIG_CPU_IDLE) += cpuidle.o
# DMA support # DMA support
obj-$(CONFIG_S3C64XX_DMA) += dma.o obj-$(CONFIG_S3C64XX_PL080) += pl080.o
# Device support # Device support

View File

@ -58,4 +58,9 @@ int __init s3c64xx_pm_late_initcall(void);
static inline int s3c64xx_pm_late_initcall(void) { return 0; } static inline int s3c64xx_pm_late_initcall(void) { return 0; }
#endif #endif
#ifdef CONFIG_S3C64XX_PL080
extern struct pl08x_platform_data s3c64xx_dma0_plat_data;
extern struct pl08x_platform_data s3c64xx_dma1_plat_data;
#endif
#endif /* __ARCH_ARM_MACH_S3C64XX_COMMON_H */ #endif /* __ARCH_ARM_MACH_S3C64XX_COMMON_H */

View File

@ -1,762 +0,0 @@
/* linux/arch/arm/plat-s3c64xx/dma.c
*
* Copyright 2009 Openmoko, Inc.
* Copyright 2009 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
* http://armlinux.simtec.co.uk/
*
* S3C64XX DMA core
*
* 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.
*/
/*
* NOTE: Code in this file is not used when booting with Device Tree support.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/dmapool.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/amba/pl080.h>
#include <linux/of.h>
#include <mach/dma.h>
#include <mach/map.h>
#include <mach/irqs.h>
#include "regs-sys.h"
/* dma channel state information */
struct s3c64xx_dmac {
struct device dev;
struct clk *clk;
void __iomem *regs;
struct s3c2410_dma_chan *channels;
enum dma_ch chanbase;
};
/* pool to provide LLI buffers */
static struct dma_pool *dma_pool;
/* Debug configuration and code */
static unsigned char debug_show_buffs = 0;
static void dbg_showchan(struct s3c2410_dma_chan *chan)
{
pr_debug("DMA%d: %08x->%08x L %08x C %08x,%08x S %08x\n",
chan->number,
readl(chan->regs + PL080_CH_SRC_ADDR),
readl(chan->regs + PL080_CH_DST_ADDR),
readl(chan->regs + PL080_CH_LLI),
readl(chan->regs + PL080_CH_CONTROL),
readl(chan->regs + PL080S_CH_CONTROL2),
readl(chan->regs + PL080S_CH_CONFIG));
}
static void show_lli(struct pl080s_lli *lli)
{
pr_debug("LLI[%p] %08x->%08x, NL %08x C %08x,%08x\n",
lli, lli->src_addr, lli->dst_addr, lli->next_lli,
lli->control0, lli->control1);
}
static void dbg_showbuffs(struct s3c2410_dma_chan *chan)
{
struct s3c64xx_dma_buff *ptr;
struct s3c64xx_dma_buff *end;
pr_debug("DMA%d: buffs next %p, curr %p, end %p\n",
chan->number, chan->next, chan->curr, chan->end);
ptr = chan->next;
end = chan->end;
if (debug_show_buffs) {
for (; ptr != NULL; ptr = ptr->next) {
pr_debug("DMA%d: %08x ",
chan->number, ptr->lli_dma);
show_lli(ptr->lli);
}
}
}
/* End of Debug */
static struct s3c2410_dma_chan *s3c64xx_dma_map_channel(unsigned int channel)
{
struct s3c2410_dma_chan *chan;
unsigned int start, offs;
start = 0;
if (channel >= DMACH_PCM1_TX)
start = 8;
for (offs = 0; offs < 8; offs++) {
chan = &s3c2410_chans[start + offs];
if (!chan->in_use)
goto found;
}
return NULL;
found:
s3c_dma_chan_map[channel] = chan;
return chan;
}
int s3c2410_dma_config(enum dma_ch channel, int xferunit)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
if (chan == NULL)
return -EINVAL;
switch (xferunit) {
case 1:
chan->hw_width = 0;
break;
case 2:
chan->hw_width = 1;
break;
case 4:
chan->hw_width = 2;
break;
default:
printk(KERN_ERR "%s: illegal width %d\n", __func__, xferunit);
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL(s3c2410_dma_config);
static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan,
struct pl080s_lli *lli,
dma_addr_t data, int size)
{
dma_addr_t src, dst;
u32 control0, control1;
switch (chan->source) {
case DMA_FROM_DEVICE:
src = chan->dev_addr;
dst = data;
control0 = PL080_CONTROL_SRC_AHB2;
control0 |= PL080_CONTROL_DST_INCR;
break;
case DMA_TO_DEVICE:
src = data;
dst = chan->dev_addr;
control0 = PL080_CONTROL_DST_AHB2;
control0 |= PL080_CONTROL_SRC_INCR;
break;
default:
BUG();
}
/* note, we do not currently setup any of the burst controls */
control1 = size >> chan->hw_width; /* size in no of xfers */
control0 |= PL080_CONTROL_PROT_SYS; /* always in priv. mode */
control0 |= PL080_CONTROL_TC_IRQ_EN; /* always fire IRQ */
control0 |= (u32)chan->hw_width << PL080_CONTROL_DWIDTH_SHIFT;
control0 |= (u32)chan->hw_width << PL080_CONTROL_SWIDTH_SHIFT;
lli->src_addr = src;
lli->dst_addr = dst;
lli->next_lli = 0;
lli->control0 = control0;
lli->control1 = control1;
}
static void s3c64xx_lli_to_regs(struct s3c2410_dma_chan *chan,
struct pl080s_lli *lli)
{
void __iomem *regs = chan->regs;
pr_debug("%s: LLI %p => regs\n", __func__, lli);
show_lli(lli);
writel(lli->src_addr, regs + PL080_CH_SRC_ADDR);
writel(lli->dst_addr, regs + PL080_CH_DST_ADDR);
writel(lli->next_lli, regs + PL080_CH_LLI);
writel(lli->control0, regs + PL080_CH_CONTROL);
writel(lli->control1, regs + PL080S_CH_CONTROL2);
}
static int s3c64xx_dma_start(struct s3c2410_dma_chan *chan)
{
struct s3c64xx_dmac *dmac = chan->dmac;
u32 config;
u32 bit = chan->bit;
dbg_showchan(chan);
pr_debug("%s: clearing interrupts\n", __func__);
/* clear interrupts */
writel(bit, dmac->regs + PL080_TC_CLEAR);
writel(bit, dmac->regs + PL080_ERR_CLEAR);
pr_debug("%s: starting channel\n", __func__);
config = readl(chan->regs + PL080S_CH_CONFIG);
config |= PL080_CONFIG_ENABLE;
config &= ~PL080_CONFIG_HALT;
pr_debug("%s: writing config %08x\n", __func__, config);
writel(config, chan->regs + PL080S_CH_CONFIG);
return 0;
}
static int s3c64xx_dma_stop(struct s3c2410_dma_chan *chan)
{
u32 config;
int timeout;
pr_debug("%s: stopping channel\n", __func__);
dbg_showchan(chan);
config = readl(chan->regs + PL080S_CH_CONFIG);
config |= PL080_CONFIG_HALT;
writel(config, chan->regs + PL080S_CH_CONFIG);
timeout = 1000;
do {
config = readl(chan->regs + PL080S_CH_CONFIG);
pr_debug("%s: %d - config %08x\n", __func__, timeout, config);
if (config & PL080_CONFIG_ACTIVE)
udelay(10);
else
break;
} while (--timeout > 0);
if (config & PL080_CONFIG_ACTIVE) {
printk(KERN_ERR "%s: channel still active\n", __func__);
return -EFAULT;
}
config = readl(chan->regs + PL080S_CH_CONFIG);
config &= ~PL080_CONFIG_ENABLE;
writel(config, chan->regs + PL080S_CH_CONFIG);
return 0;
}
static inline void s3c64xx_dma_bufffdone(struct s3c2410_dma_chan *chan,
struct s3c64xx_dma_buff *buf,
enum s3c2410_dma_buffresult result)
{
if (chan->callback_fn != NULL)
(chan->callback_fn)(chan, buf->pw, 0, result);
}
static void s3c64xx_dma_freebuff(struct s3c64xx_dma_buff *buff)
{
dma_pool_free(dma_pool, buff->lli, buff->lli_dma);
kfree(buff);
}
static int s3c64xx_dma_flush(struct s3c2410_dma_chan *chan)
{
struct s3c64xx_dma_buff *buff, *next;
u32 config;
dbg_showchan(chan);
pr_debug("%s: flushing channel\n", __func__);
config = readl(chan->regs + PL080S_CH_CONFIG);
config &= ~PL080_CONFIG_ENABLE;
writel(config, chan->regs + PL080S_CH_CONFIG);
/* dump all the buffers associated with this channel */
for (buff = chan->curr; buff != NULL; buff = next) {
next = buff->next;
pr_debug("%s: buff %p (next %p)\n", __func__, buff, buff->next);
s3c64xx_dma_bufffdone(chan, buff, S3C2410_RES_ABORT);
s3c64xx_dma_freebuff(buff);
}
chan->curr = chan->next = chan->end = NULL;
return 0;
}
int s3c2410_dma_ctrl(enum dma_ch channel, enum s3c2410_chan_op op)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
WARN_ON(!chan);
if (!chan)
return -EINVAL;
switch (op) {
case S3C2410_DMAOP_START:
return s3c64xx_dma_start(chan);
case S3C2410_DMAOP_STOP:
return s3c64xx_dma_stop(chan);
case S3C2410_DMAOP_FLUSH:
return s3c64xx_dma_flush(chan);
/* believe PAUSE/RESUME are no-ops */
case S3C2410_DMAOP_PAUSE:
case S3C2410_DMAOP_RESUME:
case S3C2410_DMAOP_STARTED:
case S3C2410_DMAOP_TIMEOUT:
return 0;
}
return -ENOENT;
}
EXPORT_SYMBOL(s3c2410_dma_ctrl);
/* s3c2410_dma_enque
*
*/
int s3c2410_dma_enqueue(enum dma_ch channel, void *id,
dma_addr_t data, int size)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
struct s3c64xx_dma_buff *next;
struct s3c64xx_dma_buff *buff;
struct pl080s_lli *lli;
unsigned long flags;
int ret;
WARN_ON(!chan);
if (!chan)
return -EINVAL;
buff = kzalloc(sizeof(struct s3c64xx_dma_buff), GFP_ATOMIC);
if (!buff) {
printk(KERN_ERR "%s: no memory for buffer\n", __func__);
return -ENOMEM;
}
lli = dma_pool_alloc(dma_pool, GFP_ATOMIC, &buff->lli_dma);
if (!lli) {
printk(KERN_ERR "%s: no memory for lli\n", __func__);
ret = -ENOMEM;
goto err_buff;
}
pr_debug("%s: buff %p, dp %08x lli (%p, %08x) %d\n",
__func__, buff, data, lli, (u32)buff->lli_dma, size);
buff->lli = lli;
buff->pw = id;
s3c64xx_dma_fill_lli(chan, lli, data, size);
local_irq_save(flags);
if ((next = chan->next) != NULL) {
struct s3c64xx_dma_buff *end = chan->end;
struct pl080s_lli *endlli = end->lli;
pr_debug("enquing onto channel\n");
end->next = buff;
endlli->next_lli = buff->lli_dma;
if (chan->flags & S3C2410_DMAF_CIRCULAR) {
struct s3c64xx_dma_buff *curr = chan->curr;
lli->next_lli = curr->lli_dma;
}
if (next == chan->curr) {
writel(buff->lli_dma, chan->regs + PL080_CH_LLI);
chan->next = buff;
}
show_lli(endlli);
chan->end = buff;
} else {
pr_debug("enquing onto empty channel\n");
chan->curr = buff;
chan->next = buff;
chan->end = buff;
s3c64xx_lli_to_regs(chan, lli);
}
local_irq_restore(flags);
show_lli(lli);
dbg_showchan(chan);
dbg_showbuffs(chan);
return 0;
err_buff:
kfree(buff);
return ret;
}
EXPORT_SYMBOL(s3c2410_dma_enqueue);
int s3c2410_dma_devconfig(enum dma_ch channel,
enum dma_data_direction source,
unsigned long devaddr)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
u32 peripheral;
u32 config = 0;
pr_debug("%s: channel %d, source %d, dev %08lx, chan %p\n",
__func__, channel, source, devaddr, chan);
WARN_ON(!chan);
if (!chan)
return -EINVAL;
peripheral = (chan->peripheral & 0xf);
chan->source = source;
chan->dev_addr = devaddr;
pr_debug("%s: peripheral %d\n", __func__, peripheral);
switch (source) {
case DMA_FROM_DEVICE:
config = 2 << PL080_CONFIG_FLOW_CONTROL_SHIFT;
config |= peripheral << PL080_CONFIG_SRC_SEL_SHIFT;
break;
case DMA_TO_DEVICE:
config = 1 << PL080_CONFIG_FLOW_CONTROL_SHIFT;
config |= peripheral << PL080_CONFIG_DST_SEL_SHIFT;
break;
default:
printk(KERN_ERR "%s: bad source\n", __func__);
return -EINVAL;
}
/* allow TC and ERR interrupts */
config |= PL080_CONFIG_TC_IRQ_MASK;
config |= PL080_CONFIG_ERR_IRQ_MASK;
pr_debug("%s: config %08x\n", __func__, config);
writel(config, chan->regs + PL080S_CH_CONFIG);
return 0;
}
EXPORT_SYMBOL(s3c2410_dma_devconfig);
int s3c2410_dma_getposition(enum dma_ch channel,
dma_addr_t *src, dma_addr_t *dst)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
WARN_ON(!chan);
if (!chan)
return -EINVAL;
if (src != NULL)
*src = readl(chan->regs + PL080_CH_SRC_ADDR);
if (dst != NULL)
*dst = readl(chan->regs + PL080_CH_DST_ADDR);
return 0;
}
EXPORT_SYMBOL(s3c2410_dma_getposition);
/* s3c2410_request_dma
*
* get control of an dma channel
*/
int s3c2410_dma_request(enum dma_ch channel,
struct s3c2410_dma_client *client,
void *dev)
{
struct s3c2410_dma_chan *chan;
unsigned long flags;
pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
channel, client->name, dev);
local_irq_save(flags);
chan = s3c64xx_dma_map_channel(channel);
if (chan == NULL) {
local_irq_restore(flags);
return -EBUSY;
}
dbg_showchan(chan);
chan->client = client;
chan->in_use = 1;
chan->peripheral = channel;
chan->flags = 0;
local_irq_restore(flags);
/* need to setup */
pr_debug("%s: channel initialised, %p\n", __func__, chan);
return chan->number | DMACH_LOW_LEVEL;
}
EXPORT_SYMBOL(s3c2410_dma_request);
/* s3c2410_dma_free
*
* release the given channel back to the system, will stop and flush
* any outstanding transfers, and ensure the channel is ready for the
* next claimant.
*
* Note, although a warning is currently printed if the freeing client
* info is not the same as the registrant's client info, the free is still
* allowed to go through.
*/
int s3c2410_dma_free(enum dma_ch channel, struct s3c2410_dma_client *client)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
unsigned long flags;
if (chan == NULL)
return -EINVAL;
local_irq_save(flags);
if (chan->client != client) {
printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
channel, chan->client, client);
}
/* sort out stopping and freeing the channel */
chan->client = NULL;
chan->in_use = 0;
if (!(channel & DMACH_LOW_LEVEL))
s3c_dma_chan_map[channel] = NULL;
local_irq_restore(flags);
return 0;
}
EXPORT_SYMBOL(s3c2410_dma_free);
static irqreturn_t s3c64xx_dma_irq(int irq, void *pw)
{
struct s3c64xx_dmac *dmac = pw;
struct s3c2410_dma_chan *chan;
enum s3c2410_dma_buffresult res;
u32 tcstat, errstat;
u32 bit;
int offs;
tcstat = readl(dmac->regs + PL080_TC_STATUS);
errstat = readl(dmac->regs + PL080_ERR_STATUS);
for (offs = 0, bit = 1; offs < 8; offs++, bit <<= 1) {
struct s3c64xx_dma_buff *buff;
if (!(errstat & bit) && !(tcstat & bit))
continue;
chan = dmac->channels + offs;
res = S3C2410_RES_ERR;
if (tcstat & bit) {
writel(bit, dmac->regs + PL080_TC_CLEAR);
res = S3C2410_RES_OK;
}
if (errstat & bit)
writel(bit, dmac->regs + PL080_ERR_CLEAR);
/* 'next' points to the buffer that is next to the
* currently active buffer.
* For CIRCULAR queues, 'next' will be same as 'curr'
* when 'end' is the active buffer.
*/
buff = chan->curr;
while (buff && buff != chan->next
&& buff->next != chan->next)
buff = buff->next;
if (!buff)
BUG();
if (buff == chan->next)
buff = chan->end;
s3c64xx_dma_bufffdone(chan, buff, res);
/* Free the node and update curr, if non-circular queue */
if (!(chan->flags & S3C2410_DMAF_CIRCULAR)) {
chan->curr = buff->next;
s3c64xx_dma_freebuff(buff);
}
/* Update 'next' */
buff = chan->next;
if (chan->next == chan->end) {
chan->next = chan->curr;
if (!(chan->flags & S3C2410_DMAF_CIRCULAR))
chan->end = NULL;
} else {
chan->next = buff->next;
}
}
return IRQ_HANDLED;
}
static struct bus_type dma_subsys = {
.name = "s3c64xx-dma",
.dev_name = "s3c64xx-dma",
};
static int s3c64xx_dma_init1(int chno, enum dma_ch chbase,
int irq, unsigned int base)
{
struct s3c2410_dma_chan *chptr = &s3c2410_chans[chno];
struct s3c64xx_dmac *dmac;
char clkname[16];
void __iomem *regs;
void __iomem *regptr;
int err, ch;
dmac = kzalloc(sizeof(struct s3c64xx_dmac), GFP_KERNEL);
if (!dmac) {
printk(KERN_ERR "%s: failed to alloc mem\n", __func__);
return -ENOMEM;
}
dmac->dev.id = chno / 8;
dmac->dev.bus = &dma_subsys;
err = device_register(&dmac->dev);
if (err) {
printk(KERN_ERR "%s: failed to register device\n", __func__);
goto err_alloc;
}
regs = ioremap(base, 0x200);
if (!regs) {
printk(KERN_ERR "%s: failed to ioremap()\n", __func__);
err = -ENXIO;
goto err_dev;
}
snprintf(clkname, sizeof(clkname), "dma%d", dmac->dev.id);
dmac->clk = clk_get(NULL, clkname);
if (IS_ERR(dmac->clk)) {
printk(KERN_ERR "%s: failed to get clock %s\n", __func__, clkname);
err = PTR_ERR(dmac->clk);
goto err_map;
}
clk_prepare_enable(dmac->clk);
dmac->regs = regs;
dmac->chanbase = chbase;
dmac->channels = chptr;
err = request_irq(irq, s3c64xx_dma_irq, 0, "DMA", dmac);
if (err < 0) {
printk(KERN_ERR "%s: failed to get irq\n", __func__);
goto err_clk;
}
regptr = regs + PL080_Cx_BASE(0);
for (ch = 0; ch < 8; ch++, chptr++) {
pr_debug("%s: registering DMA %d (%p)\n",
__func__, chno + ch, regptr);
chptr->bit = 1 << ch;
chptr->number = chno + ch;
chptr->dmac = dmac;
chptr->regs = regptr;
regptr += PL080_Cx_STRIDE;
}
/* for the moment, permanently enable the controller */
writel(PL080_CONFIG_ENABLE, regs + PL080_CONFIG);
printk(KERN_INFO "PL080: IRQ %d, at %p, channels %d..%d\n",
irq, regs, chno, chno+8);
return 0;
err_clk:
clk_disable_unprepare(dmac->clk);
clk_put(dmac->clk);
err_map:
iounmap(regs);
err_dev:
device_unregister(&dmac->dev);
err_alloc:
kfree(dmac);
return err;
}
static int __init s3c64xx_dma_init(void)
{
int ret;
/* This driver is not supported when booting with device tree. */
if (of_have_populated_dt())
return -ENODEV;
printk(KERN_INFO "%s: Registering DMA channels\n", __func__);
dma_pool = dma_pool_create("DMA-LLI", NULL, sizeof(struct pl080s_lli), 16, 0);
if (!dma_pool) {
printk(KERN_ERR "%s: failed to create pool\n", __func__);
return -ENOMEM;
}
ret = subsys_system_register(&dma_subsys, NULL);
if (ret) {
printk(KERN_ERR "%s: failed to create subsys\n", __func__);
return -ENOMEM;
}
/* Set all DMA configuration to be DMA, not SDMA */
writel(0xffffff, S3C64XX_SDMA_SEL);
/* Register standard DMA controllers */
s3c64xx_dma_init1(0, DMACH_UART0, IRQ_DMA0, 0x75000000);
s3c64xx_dma_init1(8, DMACH_PCM1_TX, IRQ_DMA1, 0x75100000);
return 0;
}
arch_initcall(s3c64xx_dma_init);

View File

@ -11,51 +11,48 @@
#ifndef __ASM_ARCH_DMA_H #ifndef __ASM_ARCH_DMA_H
#define __ASM_ARCH_DMA_H __FILE__ #define __ASM_ARCH_DMA_H __FILE__
#define S3C_DMA_CHANNELS (16) #define S3C64XX_DMA_CHAN(name) ((unsigned long)(name))
/* see mach-s3c2410/dma.h for notes on dma channel numbers */ /* DMA0/SDMA0 */
#define DMACH_UART0 S3C64XX_DMA_CHAN("uart0_tx")
#define DMACH_UART0_SRC2 S3C64XX_DMA_CHAN("uart0_rx")
#define DMACH_UART1 S3C64XX_DMA_CHAN("uart1_tx")
#define DMACH_UART1_SRC2 S3C64XX_DMA_CHAN("uart1_rx")
#define DMACH_UART2 S3C64XX_DMA_CHAN("uart2_tx")
#define DMACH_UART2_SRC2 S3C64XX_DMA_CHAN("uart2_rx")
#define DMACH_UART3 S3C64XX_DMA_CHAN("uart3_tx")
#define DMACH_UART3_SRC2 S3C64XX_DMA_CHAN("uart3_rx")
#define DMACH_PCM0_TX S3C64XX_DMA_CHAN("pcm0_tx")
#define DMACH_PCM0_RX S3C64XX_DMA_CHAN("pcm0_rx")
#define DMACH_I2S0_OUT S3C64XX_DMA_CHAN("i2s0_tx")
#define DMACH_I2S0_IN S3C64XX_DMA_CHAN("i2s0_rx")
#define DMACH_SPI0_TX S3C64XX_DMA_CHAN("spi0_tx")
#define DMACH_SPI0_RX S3C64XX_DMA_CHAN("spi0_rx")
#define DMACH_HSI_I2SV40_TX S3C64XX_DMA_CHAN("i2s2_tx")
#define DMACH_HSI_I2SV40_RX S3C64XX_DMA_CHAN("i2s2_rx")
/* DMA1/SDMA1 */
#define DMACH_PCM1_TX S3C64XX_DMA_CHAN("pcm1_tx")
#define DMACH_PCM1_RX S3C64XX_DMA_CHAN("pcm1_rx")
#define DMACH_I2S1_OUT S3C64XX_DMA_CHAN("i2s1_tx")
#define DMACH_I2S1_IN S3C64XX_DMA_CHAN("i2s1_rx")
#define DMACH_SPI1_TX S3C64XX_DMA_CHAN("spi1_tx")
#define DMACH_SPI1_RX S3C64XX_DMA_CHAN("spi1_rx")
#define DMACH_AC97_PCMOUT S3C64XX_DMA_CHAN("ac97_out")
#define DMACH_AC97_PCMIN S3C64XX_DMA_CHAN("ac97_in")
#define DMACH_AC97_MICIN S3C64XX_DMA_CHAN("ac97_mic")
#define DMACH_PWM S3C64XX_DMA_CHAN("pwm")
#define DMACH_IRDA S3C64XX_DMA_CHAN("irda")
#define DMACH_EXTERNAL S3C64XX_DMA_CHAN("external")
#define DMACH_SECURITY_RX S3C64XX_DMA_CHAN("sec_rx")
#define DMACH_SECURITY_TX S3C64XX_DMA_CHAN("sec_tx")
/* Note, for the S3C64XX architecture we keep the DMACH_
* defines in the order they are allocated to [S]DMA0/[S]DMA1
* so that is easy to do DHACH_ -> DMA controller conversion
*/
enum dma_ch { enum dma_ch {
/* DMA0/SDMA0 */ DMACH_MAX = 32
DMACH_UART0 = 0, };
DMACH_UART0_SRC2,
DMACH_UART1,
DMACH_UART1_SRC2,
DMACH_UART2,
DMACH_UART2_SRC2,
DMACH_UART3,
DMACH_UART3_SRC2,
DMACH_PCM0_TX,
DMACH_PCM0_RX,
DMACH_I2S0_OUT,
DMACH_I2S0_IN,
DMACH_SPI0_TX,
DMACH_SPI0_RX,
DMACH_HSI_I2SV40_TX,
DMACH_HSI_I2SV40_RX,
/* DMA1/SDMA1 */ struct s3c2410_dma_client {
DMACH_PCM1_TX = 16, char *name;
DMACH_PCM1_RX,
DMACH_I2S1_OUT,
DMACH_I2S1_IN,
DMACH_SPI1_TX,
DMACH_SPI1_RX,
DMACH_AC97_PCMOUT,
DMACH_AC97_PCMIN,
DMACH_AC97_MICIN,
DMACH_PWM,
DMACH_IRDA,
DMACH_EXTERNAL,
DMACH_RES1,
DMACH_RES2,
DMACH_SECURITY_RX, /* SDMA1 only */
DMACH_SECURITY_TX, /* SDMA1 only */
DMACH_MAX /* the end */
}; };
static inline bool samsung_dma_has_circular(void) static inline bool samsung_dma_has_circular(void)
@ -65,67 +62,10 @@ static inline bool samsung_dma_has_circular(void)
static inline bool samsung_dma_is_dmadev(void) static inline bool samsung_dma_is_dmadev(void)
{ {
return false; return true;
} }
#define S3C2410_DMAF_CIRCULAR (1 << 0)
#include <plat/dma.h> #include <linux/amba/pl08x.h>
#include <plat/dma-ops.h>
#define DMACH_LOW_LEVEL (1<<28) /* use this to specifiy hardware ch no */
struct s3c64xx_dma_buff;
/** s3c64xx_dma_buff - S3C64XX DMA buffer descriptor
* @next: Pointer to next buffer in queue or ring.
* @pw: Client provided identifier
* @lli: Pointer to hardware descriptor this buffer is associated with.
* @lli_dma: Hardare address of the descriptor.
*/
struct s3c64xx_dma_buff {
struct s3c64xx_dma_buff *next;
void *pw;
struct pl080s_lli *lli;
dma_addr_t lli_dma;
};
struct s3c64xx_dmac;
struct s3c2410_dma_chan {
unsigned char number; /* number of this dma channel */
unsigned char in_use; /* channel allocated */
unsigned char bit; /* bit for enable/disable/etc */
unsigned char hw_width;
unsigned char peripheral;
unsigned int flags;
enum dma_data_direction source;
dma_addr_t dev_addr;
struct s3c2410_dma_client *client;
struct s3c64xx_dmac *dmac; /* pointer to controller */
void __iomem *regs;
/* cdriver callbacks */
s3c2410_dma_cbfn_t callback_fn; /* buffer done callback */
s3c2410_dma_opfn_t op_fn; /* channel op callback */
/* buffer list and information */
struct s3c64xx_dma_buff *curr; /* current dma buffer */
struct s3c64xx_dma_buff *next; /* next buffer to load */
struct s3c64xx_dma_buff *end; /* end of queue */
/* note, when channel is running in circular mode, curr is the
* first buffer enqueued, end is the last and curr is where the
* last buffer-done event is set-at. The buffers are not freed
* and the last buffer hardware descriptor points back to the
* first.
*/
};
#include <plat/dma-core.h>
#endif /* __ASM_ARCH_IRQ_H */ #endif /* __ASM_ARCH_IRQ_H */

View File

@ -0,0 +1,244 @@
/*
* Samsung's S3C64XX generic DMA support using amba-pl08x driver.
*
* Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.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.
*/
#include <linux/kernel.h>
#include <linux/amba/bus.h>
#include <linux/amba/pl080.h>
#include <linux/amba/pl08x.h>
#include <linux/of.h>
#include <mach/irqs.h>
#include <mach/map.h>
#include "regs-sys.h"
static int pl08x_get_xfer_signal(const struct pl08x_channel_data *cd)
{
return cd->min_signal;
}
static void pl08x_put_xfer_signal(const struct pl08x_channel_data *cd, int ch)
{
}
/*
* DMA0
*/
static struct pl08x_channel_data s3c64xx_dma0_info[] = {
{
.bus_id = "uart0_tx",
.min_signal = 0,
.max_signal = 0,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "uart0_rx",
.min_signal = 1,
.max_signal = 1,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "uart1_tx",
.min_signal = 2,
.max_signal = 2,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "uart1_rx",
.min_signal = 3,
.max_signal = 3,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "uart2_tx",
.min_signal = 4,
.max_signal = 4,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "uart2_rx",
.min_signal = 5,
.max_signal = 5,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "uart3_tx",
.min_signal = 6,
.max_signal = 6,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "uart3_rx",
.min_signal = 7,
.max_signal = 7,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "pcm0_tx",
.min_signal = 8,
.max_signal = 8,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "pcm0_rx",
.min_signal = 9,
.max_signal = 9,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "i2s0_tx",
.min_signal = 10,
.max_signal = 10,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "i2s0_rx",
.min_signal = 11,
.max_signal = 11,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "spi0_tx",
.min_signal = 12,
.max_signal = 12,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "spi0_rx",
.min_signal = 13,
.max_signal = 13,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "i2s2_tx",
.min_signal = 14,
.max_signal = 14,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "i2s2_rx",
.min_signal = 15,
.max_signal = 15,
.periph_buses = PL08X_AHB2,
}
};
struct pl08x_platform_data s3c64xx_dma0_plat_data = {
.memcpy_channel = {
.bus_id = "memcpy",
.cctl_memcpy =
(PL080_BSIZE_4 << PL080_CONTROL_SB_SIZE_SHIFT |
PL080_BSIZE_4 << PL080_CONTROL_DB_SIZE_SHIFT |
PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT |
PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT |
PL080_CONTROL_PROT_BUFF | PL080_CONTROL_PROT_CACHE |
PL080_CONTROL_PROT_SYS),
},
.lli_buses = PL08X_AHB1,
.mem_buses = PL08X_AHB1,
.get_xfer_signal = pl08x_get_xfer_signal,
.put_xfer_signal = pl08x_put_xfer_signal,
.slave_channels = s3c64xx_dma0_info,
.num_slave_channels = ARRAY_SIZE(s3c64xx_dma0_info),
};
static AMBA_AHB_DEVICE(s3c64xx_dma0, "dma-pl080s.0", 0,
0x75000000, {IRQ_DMA0}, &s3c64xx_dma0_plat_data);
/*
* DMA1
*/
static struct pl08x_channel_data s3c64xx_dma1_info[] = {
{
.bus_id = "pcm1_tx",
.min_signal = 0,
.max_signal = 0,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "pcm1_rx",
.min_signal = 1,
.max_signal = 1,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "i2s1_tx",
.min_signal = 2,
.max_signal = 2,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "i2s1_rx",
.min_signal = 3,
.max_signal = 3,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "spi1_tx",
.min_signal = 4,
.max_signal = 4,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "spi1_rx",
.min_signal = 5,
.max_signal = 5,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "ac97_out",
.min_signal = 6,
.max_signal = 6,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "ac97_in",
.min_signal = 7,
.max_signal = 7,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "ac97_mic",
.min_signal = 8,
.max_signal = 8,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "pwm",
.min_signal = 9,
.max_signal = 9,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "irda",
.min_signal = 10,
.max_signal = 10,
.periph_buses = PL08X_AHB2,
}, {
.bus_id = "external",
.min_signal = 11,
.max_signal = 11,
.periph_buses = PL08X_AHB2,
},
};
struct pl08x_platform_data s3c64xx_dma1_plat_data = {
.memcpy_channel = {
.bus_id = "memcpy",
.cctl_memcpy =
(PL080_BSIZE_4 << PL080_CONTROL_SB_SIZE_SHIFT |
PL080_BSIZE_4 << PL080_CONTROL_DB_SIZE_SHIFT |
PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT |
PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT |
PL080_CONTROL_PROT_BUFF | PL080_CONTROL_PROT_CACHE |
PL080_CONTROL_PROT_SYS),
},
.lli_buses = PL08X_AHB1,
.mem_buses = PL08X_AHB1,
.get_xfer_signal = pl08x_get_xfer_signal,
.put_xfer_signal = pl08x_put_xfer_signal,
.slave_channels = s3c64xx_dma1_info,
.num_slave_channels = ARRAY_SIZE(s3c64xx_dma1_info),
};
static AMBA_AHB_DEVICE(s3c64xx_dma1, "dma-pl080s.1", 0,
0x75100000, {IRQ_DMA1}, &s3c64xx_dma1_plat_data);
static int __init s3c64xx_pl080_init(void)
{
/* Set all DMA configuration to be DMA, not SDMA */
writel(0xffffff, S3C64XX_SDMA_SEL);
if (of_have_populated_dt())
return 0;
amba_device_register(&s3c64xx_dma0_device, &iomem_resource);
amba_device_register(&s3c64xx_dma1_device, &iomem_resource);
return 0;
}
arch_initcall(s3c64xx_pl080_init);

View File

@ -1468,6 +1468,8 @@ void __init s3c64xx_spi0_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi0_cfg_gpio; pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi0_cfg_gpio;
#if defined(CONFIG_PL330_DMA) #if defined(CONFIG_PL330_DMA)
pd.filter = pl330_filter; pd.filter = pl330_filter;
#elif defined(CONFIG_S3C64XX_PL080)
pd.filter = pl08x_filter_id;
#elif defined(CONFIG_S3C24XX_DMAC) #elif defined(CONFIG_S3C24XX_DMAC)
pd.filter = s3c24xx_dma_filter; pd.filter = s3c24xx_dma_filter;
#endif #endif
@ -1509,8 +1511,10 @@ void __init s3c64xx_spi1_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
pd.num_cs = num_cs; pd.num_cs = num_cs;
pd.src_clk_nr = src_clk_nr; pd.src_clk_nr = src_clk_nr;
pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi1_cfg_gpio; pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi1_cfg_gpio;
#ifdef CONFIG_PL330_DMA #if defined(CONFIG_PL330_DMA)
pd.filter = pl330_filter; pd.filter = pl330_filter;
#elif defined(CONFIG_S3C64XX_PL080)
pd.filter = pl08x_filter_id;
#endif #endif
s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi1); s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi1);
@ -1550,8 +1554,10 @@ void __init s3c64xx_spi2_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
pd.num_cs = num_cs; pd.num_cs = num_cs;
pd.src_clk_nr = src_clk_nr; pd.src_clk_nr = src_clk_nr;
pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi2_cfg_gpio; pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi2_cfg_gpio;
#ifdef CONFIG_PL330_DMA #if defined(CONFIG_PL330_DMA)
pd.filter = pl330_filter; pd.filter = pl330_filter;
#elif defined(CONFIG_S3C64XX_PL080)
pd.filter = pl08x_filter_id;
#endif #endif
s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi2); s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi2);

View File

@ -18,6 +18,12 @@
#include <mach/dma.h> #include <mach/dma.h>
#if defined(CONFIG_PL330_DMA)
#define dma_filter pl330_filter
#elif defined(CONFIG_S3C64XX_PL080)
#define dma_filter pl08x_filter_id
#endif
static unsigned samsung_dmadev_request(enum dma_ch dma_ch, static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
struct samsung_dma_req *param, struct samsung_dma_req *param,
struct device *dev, char *ch_name) struct device *dev, char *ch_name)
@ -30,7 +36,7 @@ static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
if (dev->of_node) if (dev->of_node)
return (unsigned)dma_request_slave_channel(dev, ch_name); return (unsigned)dma_request_slave_channel(dev, ch_name);
else else
return (unsigned)dma_request_channel(mask, pl330_filter, return (unsigned)dma_request_channel(mask, dma_filter,
(void *)dma_ch); (void *)dma_ch);
} }

View File

@ -331,8 +331,8 @@ static struct samsung_clock_alias s3c64xx_clock_aliases[] = {
ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.0"), ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.0"),
ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"), ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"),
ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "mmc_busclk.0"), ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "mmc_busclk.0"),
ALIAS(HCLK_DMA1, NULL, "dma1"), ALIAS(HCLK_DMA1, "dma-pl080s.1", "apb_pclk"),
ALIAS(HCLK_DMA0, NULL, "dma0"), ALIAS(HCLK_DMA0, "dma-pl080s.0", "apb_pclk"),
ALIAS(HCLK_CAMIF, "s3c-camif", "camif"), ALIAS(HCLK_CAMIF, "s3c-camif", "camif"),
ALIAS(HCLK_LCD, "s3c-fb", "lcd"), ALIAS(HCLK_LCD, "s3c-fb", "lcd"),
ALIAS(PCLK_SPI1, "s3c6410-spi.1", "spi"), ALIAS(PCLK_SPI1, "s3c6410-spi.1", "spi"),

View File

@ -44,6 +44,54 @@
#define VIBRACTRL_MEMBER(reg) ((reg == TWL6040_REG_VIBCTLL) ? 0 : 1) #define VIBRACTRL_MEMBER(reg) ((reg == TWL6040_REG_VIBCTLL) ? 0 : 1)
#define TWL6040_NUM_SUPPLIES (2) #define TWL6040_NUM_SUPPLIES (2)
static struct reg_default twl6040_defaults[] = {
{ 0x01, 0x4B }, /* REG_ASICID (ro) */
{ 0x02, 0x00 }, /* REG_ASICREV (ro) */
{ 0x03, 0x00 }, /* REG_INTID */
{ 0x04, 0x00 }, /* REG_INTMR */
{ 0x05, 0x00 }, /* REG_NCPCTRL */
{ 0x06, 0x00 }, /* REG_LDOCTL */
{ 0x07, 0x60 }, /* REG_HPPLLCTL */
{ 0x08, 0x00 }, /* REG_LPPLLCTL */
{ 0x09, 0x4A }, /* REG_LPPLLDIV */
{ 0x0A, 0x00 }, /* REG_AMICBCTL */
{ 0x0B, 0x00 }, /* REG_DMICBCTL */
{ 0x0C, 0x00 }, /* REG_MICLCTL */
{ 0x0D, 0x00 }, /* REG_MICRCTL */
{ 0x0E, 0x00 }, /* REG_MICGAIN */
{ 0x0F, 0x1B }, /* REG_LINEGAIN */
{ 0x10, 0x00 }, /* REG_HSLCTL */
{ 0x11, 0x00 }, /* REG_HSRCTL */
{ 0x12, 0x00 }, /* REG_HSGAIN */
{ 0x13, 0x00 }, /* REG_EARCTL */
{ 0x14, 0x00 }, /* REG_HFLCTL */
{ 0x15, 0x00 }, /* REG_HFLGAIN */
{ 0x16, 0x00 }, /* REG_HFRCTL */
{ 0x17, 0x00 }, /* REG_HFRGAIN */
{ 0x18, 0x00 }, /* REG_VIBCTLL */
{ 0x19, 0x00 }, /* REG_VIBDATL */
{ 0x1A, 0x00 }, /* REG_VIBCTLR */
{ 0x1B, 0x00 }, /* REG_VIBDATR */
{ 0x1C, 0x00 }, /* REG_HKCTL1 */
{ 0x1D, 0x00 }, /* REG_HKCTL2 */
{ 0x1E, 0x00 }, /* REG_GPOCTL */
{ 0x1F, 0x00 }, /* REG_ALB */
{ 0x20, 0x00 }, /* REG_DLB */
/* 0x28, REG_TRIM1 */
/* 0x29, REG_TRIM2 */
/* 0x2A, REG_TRIM3 */
/* 0x2B, REG_HSOTRIM */
/* 0x2C, REG_HFOTRIM */
{ 0x2D, 0x08 }, /* REG_ACCCTL */
{ 0x2E, 0x00 }, /* REG_STATUS (ro) */
};
struct reg_default twl6040_patch[] = {
/* Select I2C bus access to dual access registers */
{ TWL6040_REG_ACCCTL, 0x09 },
};
static bool twl6040_has_vibra(struct device_node *node) static bool twl6040_has_vibra(struct device_node *node)
{ {
#ifdef CONFIG_OF #ifdef CONFIG_OF
@ -238,6 +286,9 @@ int twl6040_power(struct twl6040 *twl6040, int on)
if (twl6040->power_count++) if (twl6040->power_count++)
goto out; goto out;
/* Allow writes to the chip */
regcache_cache_only(twl6040->regmap, false);
if (gpio_is_valid(twl6040->audpwron)) { if (gpio_is_valid(twl6040->audpwron)) {
/* use automatic power-up sequence */ /* use automatic power-up sequence */
ret = twl6040_power_up_automatic(twl6040); ret = twl6040_power_up_automatic(twl6040);
@ -253,6 +304,10 @@ int twl6040_power(struct twl6040 *twl6040, int on)
goto out; goto out;
} }
} }
/* Sync with the HW */
regcache_sync(twl6040->regmap);
/* Default PLL configuration after power up */ /* Default PLL configuration after power up */
twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL; twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL;
twl6040->sysclk = 19200000; twl6040->sysclk = 19200000;
@ -279,6 +334,11 @@ int twl6040_power(struct twl6040 *twl6040, int on)
/* use manual power-down sequence */ /* use manual power-down sequence */
twl6040_power_down_manual(twl6040); twl6040_power_down_manual(twl6040);
} }
/* Set regmap to cache only and mark it as dirty */
regcache_cache_only(twl6040->regmap, true);
regcache_mark_dirty(twl6040->regmap);
twl6040->sysclk = 0; twl6040->sysclk = 0;
twl6040->mclk = 0; twl6040->mclk = 0;
} }
@ -490,9 +550,24 @@ static bool twl6040_readable_reg(struct device *dev, unsigned int reg)
static bool twl6040_volatile_reg(struct device *dev, unsigned int reg) static bool twl6040_volatile_reg(struct device *dev, unsigned int reg)
{ {
switch (reg) { switch (reg) {
case TWL6040_REG_VIBCTLL: case TWL6040_REG_ASICID:
case TWL6040_REG_VIBCTLR: case TWL6040_REG_ASICREV:
case TWL6040_REG_INTMR: case TWL6040_REG_INTID:
case TWL6040_REG_LPPLLCTL:
case TWL6040_REG_HPPLLCTL:
case TWL6040_REG_STATUS:
return true;
default:
return false;
}
}
static bool twl6040_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case TWL6040_REG_ASICID:
case TWL6040_REG_ASICREV:
case TWL6040_REG_STATUS:
return false; return false;
default: default:
return true; return true;
@ -502,10 +577,15 @@ static bool twl6040_volatile_reg(struct device *dev, unsigned int reg)
static struct regmap_config twl6040_regmap_config = { static struct regmap_config twl6040_regmap_config = {
.reg_bits = 8, .reg_bits = 8,
.val_bits = 8, .val_bits = 8,
.reg_defaults = twl6040_defaults,
.num_reg_defaults = ARRAY_SIZE(twl6040_defaults),
.max_register = TWL6040_REG_STATUS, /* 0x2e */ .max_register = TWL6040_REG_STATUS, /* 0x2e */
.readable_reg = twl6040_readable_reg, .readable_reg = twl6040_readable_reg,
.volatile_reg = twl6040_volatile_reg, .volatile_reg = twl6040_volatile_reg,
.writeable_reg = twl6040_writeable_reg,
.cache_type = REGCACHE_RBTREE, .cache_type = REGCACHE_RBTREE,
}; };
@ -624,6 +704,8 @@ static int twl6040_probe(struct i2c_client *client,
/* dual-access registers controlled by I2C only */ /* dual-access registers controlled by I2C only */
twl6040_set_bits(twl6040, TWL6040_REG_ACCCTL, TWL6040_I2CSEL); twl6040_set_bits(twl6040, TWL6040_REG_ACCCTL, TWL6040_I2CSEL);
regmap_register_patch(twl6040->regmap, twl6040_patch,
ARRAY_SIZE(twl6040_patch));
/* /*
* The main functionality of twl6040 to provide audio on OMAP4+ systems. * The main functionality of twl6040 to provide audio on OMAP4+ systems.
@ -656,6 +738,10 @@ static int twl6040_probe(struct i2c_client *client,
cell->name = "twl6040-gpo"; cell->name = "twl6040-gpo";
children++; children++;
/* The chip is powered down so mark regmap to cache only and dirty */
regcache_cache_only(twl6040->regmap, true);
regcache_mark_dirty(twl6040->regmap);
ret = mfd_add_devices(&client->dev, -1, twl6040->cells, children, ret = mfd_add_devices(&client->dev, -1, twl6040->cells, children,
NULL, 0, NULL); NULL, 0, NULL);
if (ret) if (ret)

View File

@ -14,6 +14,7 @@
#include <linux/mfd/arizona/core.h> #include <linux/mfd/arizona/core.h>
#include <linux/mfd/arizona/registers.h> #include <linux/mfd/arizona/registers.h>
#include <linux/device.h>
#include "arizona.h" #include "arizona.h"
@ -524,6 +525,7 @@ static const struct reg_default wm5110_reg_default[] = {
{ 0x00000300, 0x0000 }, /* R768 - Input Enables */ { 0x00000300, 0x0000 }, /* R768 - Input Enables */
{ 0x00000308, 0x0000 }, /* R776 - Input Rate */ { 0x00000308, 0x0000 }, /* R776 - Input Rate */
{ 0x00000309, 0x0022 }, /* R777 - Input Volume Ramp */ { 0x00000309, 0x0022 }, /* R777 - Input Volume Ramp */
{ 0x0000030C, 0x0002 }, /* R780 - HPF Control */
{ 0x00000310, 0x2080 }, /* R784 - IN1L Control */ { 0x00000310, 0x2080 }, /* R784 - IN1L Control */
{ 0x00000311, 0x0180 }, /* R785 - ADC Digital Volume 1L */ { 0x00000311, 0x0180 }, /* R785 - ADC Digital Volume 1L */
{ 0x00000312, 0x0000 }, /* R786 - DMIC1L Control */ { 0x00000312, 0x0000 }, /* R786 - DMIC1L Control */
@ -545,6 +547,7 @@ static const struct reg_default wm5110_reg_default[] = {
{ 0x00000328, 0x2000 }, /* R808 - IN4L Control */ { 0x00000328, 0x2000 }, /* R808 - IN4L Control */
{ 0x00000329, 0x0180 }, /* R809 - ADC Digital Volume 4L */ { 0x00000329, 0x0180 }, /* R809 - ADC Digital Volume 4L */
{ 0x0000032A, 0x0000 }, /* R810 - DMIC4L Control */ { 0x0000032A, 0x0000 }, /* R810 - DMIC4L Control */
{ 0x0000032C, 0x0000 }, /* R812 - IN4R Control */
{ 0x0000032D, 0x0180 }, /* R813 - ADC Digital Volume 4R */ { 0x0000032D, 0x0180 }, /* R813 - ADC Digital Volume 4R */
{ 0x0000032E, 0x0000 }, /* R814 - DMIC4R Control */ { 0x0000032E, 0x0000 }, /* R814 - DMIC4R Control */
{ 0x00000400, 0x0000 }, /* R1024 - Output Enables 1 */ { 0x00000400, 0x0000 }, /* R1024 - Output Enables 1 */
@ -598,6 +601,7 @@ static const struct reg_default wm5110_reg_default[] = {
{ 0x0000043D, 0x0180 }, /* R1085 - DAC Digital Volume 6R */ { 0x0000043D, 0x0180 }, /* R1085 - DAC Digital Volume 6R */
{ 0x0000043E, 0x0080 }, /* R1086 - DAC Volume Limit 6R */ { 0x0000043E, 0x0080 }, /* R1086 - DAC Volume Limit 6R */
{ 0x0000043F, 0x0800 }, /* R1087 - Noise Gate Select 6R */ { 0x0000043F, 0x0800 }, /* R1087 - Noise Gate Select 6R */
{ 0x00000440, 0x8FFF }, /* R1088 - DRE Enable */
{ 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */ { 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */
{ 0x00000458, 0x0000 }, /* R1112 - Noise Gate Control */ { 0x00000458, 0x0000 }, /* R1112 - Noise Gate Control */
{ 0x00000480, 0x0040 }, /* R1152 - Class W ANC Threshold 1 */ { 0x00000480, 0x0040 }, /* R1152 - Class W ANC Threshold 1 */
@ -882,6 +886,38 @@ static const struct reg_default wm5110_reg_default[] = {
{ 0x0000074D, 0x0080 }, /* R1869 - AIF2TX2MIX Input 3 Volume */ { 0x0000074D, 0x0080 }, /* R1869 - AIF2TX2MIX Input 3 Volume */
{ 0x0000074E, 0x0000 }, /* R1870 - AIF2TX2MIX Input 4 Source */ { 0x0000074E, 0x0000 }, /* R1870 - AIF2TX2MIX Input 4 Source */
{ 0x0000074F, 0x0080 }, /* R1871 - AIF2TX2MIX Input 4 Volume */ { 0x0000074F, 0x0080 }, /* R1871 - AIF2TX2MIX Input 4 Volume */
{ 0x00000750, 0x0000 }, /* R1872 - AIF2TX3MIX Input 1 Source */
{ 0x00000751, 0x0080 }, /* R1873 - AIF2TX3MIX Input 1 Volume */
{ 0x00000752, 0x0000 }, /* R1874 - AIF2TX3MIX Input 2 Source */
{ 0x00000753, 0x0080 }, /* R1875 - AIF2TX3MIX Input 2 Volume */
{ 0x00000754, 0x0000 }, /* R1876 - AIF2TX3MIX Input 3 Source */
{ 0x00000755, 0x0080 }, /* R1877 - AIF2TX3MIX Input 3 Volume */
{ 0x00000756, 0x0000 }, /* R1878 - AIF2TX3MIX Input 4 Source */
{ 0x00000757, 0x0080 }, /* R1879 - AIF2TX3MIX Input 4 Volume */
{ 0x00000758, 0x0000 }, /* R1880 - AIF2TX4MIX Input 1 Source */
{ 0x00000759, 0x0080 }, /* R1881 - AIF2TX4MIX Input 1 Volume */
{ 0x0000075A, 0x0000 }, /* R1882 - AIF2TX4MIX Input 2 Source */
{ 0x0000075B, 0x0080 }, /* R1883 - AIF2TX4MIX Input 2 Volume */
{ 0x0000075C, 0x0000 }, /* R1884 - AIF2TX4MIX Input 3 Source */
{ 0x0000075D, 0x0080 }, /* R1885 - AIF2TX4MIX Input 3 Volume */
{ 0x0000075E, 0x0000 }, /* R1886 - AIF2TX4MIX Input 4 Source */
{ 0x0000075F, 0x0080 }, /* R1887 - AIF2TX4MIX Input 4 Volume */
{ 0x00000760, 0x0000 }, /* R1888 - AIF2TX5MIX Input 1 Source */
{ 0x00000761, 0x0080 }, /* R1889 - AIF2TX5MIX Input 1 Volume */
{ 0x00000762, 0x0000 }, /* R1890 - AIF2TX5MIX Input 2 Source */
{ 0x00000763, 0x0080 }, /* R1891 - AIF2TX5MIX Input 2 Volume */
{ 0x00000764, 0x0000 }, /* R1892 - AIF2TX5MIX Input 3 Source */
{ 0x00000765, 0x0080 }, /* R1893 - AIF2TX5MIX Input 3 Volume */
{ 0x00000766, 0x0000 }, /* R1894 - AIF2TX5MIX Input 4 Source */
{ 0x00000767, 0x0080 }, /* R1895 - AIF2TX5MIX Input 4 Volume */
{ 0x00000768, 0x0000 }, /* R1896 - AIF2TX6MIX Input 1 Source */
{ 0x00000769, 0x0080 }, /* R1897 - AIF2TX6MIX Input 1 Volume */
{ 0x0000076A, 0x0000 }, /* R1898 - AIF2TX6MIX Input 2 Source */
{ 0x0000076B, 0x0080 }, /* R1899 - AIF2TX6MIX Input 2 Volume */
{ 0x0000076C, 0x0000 }, /* R1900 - AIF2TX6MIX Input 3 Source */
{ 0x0000076D, 0x0080 }, /* R1901 - AIF2TX6MIX Input 3 Volume */
{ 0x0000076E, 0x0000 }, /* R1902 - AIF2TX6MIX Input 4 Source */
{ 0x0000076F, 0x0080 }, /* R1903 - AIF2TX6MIX Input 4 Volume */
{ 0x00000780, 0x0000 }, /* R1920 - AIF3TX1MIX Input 1 Source */ { 0x00000780, 0x0000 }, /* R1920 - AIF3TX1MIX Input 1 Source */
{ 0x00000781, 0x0080 }, /* R1921 - AIF3TX1MIX Input 1 Volume */ { 0x00000781, 0x0080 }, /* R1921 - AIF3TX1MIX Input 1 Volume */
{ 0x00000782, 0x0000 }, /* R1922 - AIF3TX1MIX Input 2 Source */ { 0x00000782, 0x0000 }, /* R1922 - AIF3TX1MIX Input 2 Source */
@ -1342,6 +1378,64 @@ static const struct reg_default wm5110_reg_default[] = {
{ 0x00001404, 0x0000 }, /* R5124 - DSP4 Status 1 */ { 0x00001404, 0x0000 }, /* R5124 - DSP4 Status 1 */
}; };
static bool wm5110_is_rev_b_adsp_memory(unsigned int reg)
{
if ((reg >= 0x100000 && reg < 0x103000) ||
(reg >= 0x180000 && reg < 0x181000) ||
(reg >= 0x190000 && reg < 0x192000) ||
(reg >= 0x1a8000 && reg < 0x1a9000) ||
(reg >= 0x200000 && reg < 0x209000) ||
(reg >= 0x280000 && reg < 0x281000) ||
(reg >= 0x290000 && reg < 0x29a000) ||
(reg >= 0x2a8000 && reg < 0x2aa000) ||
(reg >= 0x300000 && reg < 0x30f000) ||
(reg >= 0x380000 && reg < 0x382000) ||
(reg >= 0x390000 && reg < 0x39e000) ||
(reg >= 0x3a8000 && reg < 0x3b6000) ||
(reg >= 0x400000 && reg < 0x403000) ||
(reg >= 0x480000 && reg < 0x481000) ||
(reg >= 0x490000 && reg < 0x492000) ||
(reg >= 0x4a8000 && reg < 0x4a9000))
return true;
else
return false;
}
static bool wm5110_is_rev_d_adsp_memory(unsigned int reg)
{
if ((reg >= 0x100000 && reg < 0x106000) ||
(reg >= 0x180000 && reg < 0x182000) ||
(reg >= 0x190000 && reg < 0x198000) ||
(reg >= 0x1a8000 && reg < 0x1aa000) ||
(reg >= 0x200000 && reg < 0x20f000) ||
(reg >= 0x280000 && reg < 0x282000) ||
(reg >= 0x290000 && reg < 0x29c000) ||
(reg >= 0x2a6000 && reg < 0x2b4000) ||
(reg >= 0x300000 && reg < 0x30f000) ||
(reg >= 0x380000 && reg < 0x382000) ||
(reg >= 0x390000 && reg < 0x3a2000) ||
(reg >= 0x3a6000 && reg < 0x3b4000) ||
(reg >= 0x400000 && reg < 0x406000) ||
(reg >= 0x480000 && reg < 0x482000) ||
(reg >= 0x490000 && reg < 0x498000) ||
(reg >= 0x4a8000 && reg < 0x4aa000))
return true;
else
return false;
}
static bool wm5110_is_adsp_memory(struct device *dev, unsigned int reg)
{
struct arizona *arizona = dev_get_drvdata(dev);
switch (arizona->rev) {
case 0 ... 2:
return wm5110_is_rev_b_adsp_memory(reg);
default:
return wm5110_is_rev_d_adsp_memory(reg);
}
}
static bool wm5110_readable_register(struct device *dev, unsigned int reg) static bool wm5110_readable_register(struct device *dev, unsigned int reg)
{ {
switch (reg) { switch (reg) {
@ -1460,6 +1554,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_INPUT_ENABLES_STATUS: case ARIZONA_INPUT_ENABLES_STATUS:
case ARIZONA_INPUT_RATE: case ARIZONA_INPUT_RATE:
case ARIZONA_INPUT_VOLUME_RAMP: case ARIZONA_INPUT_VOLUME_RAMP:
case ARIZONA_HPF_CONTROL:
case ARIZONA_IN1L_CONTROL: case ARIZONA_IN1L_CONTROL:
case ARIZONA_ADC_DIGITAL_VOLUME_1L: case ARIZONA_ADC_DIGITAL_VOLUME_1L:
case ARIZONA_DMIC1L_CONTROL: case ARIZONA_DMIC1L_CONTROL:
@ -1481,6 +1576,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_IN4L_CONTROL: case ARIZONA_IN4L_CONTROL:
case ARIZONA_ADC_DIGITAL_VOLUME_4L: case ARIZONA_ADC_DIGITAL_VOLUME_4L:
case ARIZONA_DMIC4L_CONTROL: case ARIZONA_DMIC4L_CONTROL:
case ARIZONA_IN4R_CONTROL:
case ARIZONA_ADC_DIGITAL_VOLUME_4R: case ARIZONA_ADC_DIGITAL_VOLUME_4R:
case ARIZONA_DMIC4R_CONTROL: case ARIZONA_DMIC4R_CONTROL:
case ARIZONA_OUTPUT_ENABLES_1: case ARIZONA_OUTPUT_ENABLES_1:
@ -1536,6 +1632,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_DAC_DIGITAL_VOLUME_6R: case ARIZONA_DAC_DIGITAL_VOLUME_6R:
case ARIZONA_DAC_VOLUME_LIMIT_6R: case ARIZONA_DAC_VOLUME_LIMIT_6R:
case ARIZONA_NOISE_GATE_SELECT_6R: case ARIZONA_NOISE_GATE_SELECT_6R:
case ARIZONA_DRE_ENABLE:
case ARIZONA_DAC_AEC_CONTROL_1: case ARIZONA_DAC_AEC_CONTROL_1:
case ARIZONA_NOISE_GATE_CONTROL: case ARIZONA_NOISE_GATE_CONTROL:
case ARIZONA_PDM_SPK1_CTRL_1: case ARIZONA_PDM_SPK1_CTRL_1:
@ -1820,6 +1917,38 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_AIF2TX2MIX_INPUT_3_VOLUME: case ARIZONA_AIF2TX2MIX_INPUT_3_VOLUME:
case ARIZONA_AIF2TX2MIX_INPUT_4_SOURCE: case ARIZONA_AIF2TX2MIX_INPUT_4_SOURCE:
case ARIZONA_AIF2TX2MIX_INPUT_4_VOLUME: case ARIZONA_AIF2TX2MIX_INPUT_4_VOLUME:
case ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE:
case ARIZONA_AIF2TX3MIX_INPUT_1_VOLUME:
case ARIZONA_AIF2TX3MIX_INPUT_2_SOURCE:
case ARIZONA_AIF2TX3MIX_INPUT_2_VOLUME:
case ARIZONA_AIF2TX3MIX_INPUT_3_SOURCE:
case ARIZONA_AIF2TX3MIX_INPUT_3_VOLUME:
case ARIZONA_AIF2TX3MIX_INPUT_4_SOURCE:
case ARIZONA_AIF2TX3MIX_INPUT_4_VOLUME:
case ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE:
case ARIZONA_AIF2TX4MIX_INPUT_1_VOLUME:
case ARIZONA_AIF2TX4MIX_INPUT_2_SOURCE:
case ARIZONA_AIF2TX4MIX_INPUT_2_VOLUME:
case ARIZONA_AIF2TX4MIX_INPUT_3_SOURCE:
case ARIZONA_AIF2TX4MIX_INPUT_3_VOLUME:
case ARIZONA_AIF2TX4MIX_INPUT_4_SOURCE:
case ARIZONA_AIF2TX4MIX_INPUT_4_VOLUME:
case ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE:
case ARIZONA_AIF2TX5MIX_INPUT_1_VOLUME:
case ARIZONA_AIF2TX5MIX_INPUT_2_SOURCE:
case ARIZONA_AIF2TX5MIX_INPUT_2_VOLUME:
case ARIZONA_AIF2TX5MIX_INPUT_3_SOURCE:
case ARIZONA_AIF2TX5MIX_INPUT_3_VOLUME:
case ARIZONA_AIF2TX5MIX_INPUT_4_SOURCE:
case ARIZONA_AIF2TX5MIX_INPUT_4_VOLUME:
case ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE:
case ARIZONA_AIF2TX6MIX_INPUT_1_VOLUME:
case ARIZONA_AIF2TX6MIX_INPUT_2_SOURCE:
case ARIZONA_AIF2TX6MIX_INPUT_2_VOLUME:
case ARIZONA_AIF2TX6MIX_INPUT_3_SOURCE:
case ARIZONA_AIF2TX6MIX_INPUT_3_VOLUME:
case ARIZONA_AIF2TX6MIX_INPUT_4_SOURCE:
case ARIZONA_AIF2TX6MIX_INPUT_4_VOLUME:
case ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE: case ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE:
case ARIZONA_AIF3TX1MIX_INPUT_1_VOLUME: case ARIZONA_AIF3TX1MIX_INPUT_1_VOLUME:
case ARIZONA_AIF3TX1MIX_INPUT_2_SOURCE: case ARIZONA_AIF3TX1MIX_INPUT_2_SOURCE:
@ -2331,7 +2460,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_DSP4_SCRATCH_3: case ARIZONA_DSP4_SCRATCH_3:
return true; return true;
default: default:
return false; return wm5110_is_adsp_memory(dev, reg);
} }
} }
@ -2407,16 +2536,18 @@ static bool wm5110_volatile_register(struct device *dev, unsigned int reg)
case ARIZONA_DSP4_SCRATCH_3: case ARIZONA_DSP4_SCRATCH_3:
return true; return true;
default: default:
return false; return wm5110_is_adsp_memory(dev, reg);
} }
} }
#define WM5110_MAX_REGISTER 0x4a9fff
const struct regmap_config wm5110_spi_regmap = { const struct regmap_config wm5110_spi_regmap = {
.reg_bits = 32, .reg_bits = 32,
.pad_bits = 16, .pad_bits = 16,
.val_bits = 16, .val_bits = 16,
.max_register = ARIZONA_DSP1_STATUS_2, .max_register = WM5110_MAX_REGISTER,
.readable_reg = wm5110_readable_register, .readable_reg = wm5110_readable_register,
.volatile_reg = wm5110_volatile_register, .volatile_reg = wm5110_volatile_register,
@ -2430,7 +2561,7 @@ const struct regmap_config wm5110_i2c_regmap = {
.reg_bits = 32, .reg_bits = 32,
.val_bits = 16, .val_bits = 16,
.max_register = ARIZONA_DSP1_STATUS_2, .max_register = WM5110_MAX_REGISTER,
.readable_reg = wm5110_readable_register, .readable_reg = wm5110_readable_register,
.volatile_reg = wm5110_volatile_register, .volatile_reg = wm5110_volatile_register,

View File

@ -395,7 +395,7 @@ config SPI_S3C24XX_FIQ
config SPI_S3C64XX config SPI_S3C64XX
tristate "Samsung S3C64XX series type SPI" tristate "Samsung S3C64XX series type SPI"
depends on PLAT_SAMSUNG depends on PLAT_SAMSUNG
select S3C64XX_DMA if ARCH_S3C64XX select S3C64XX_PL080 if ARCH_S3C64XX
help help
SPI driver for Samsung S3C64XX and newer SoCs. SPI driver for Samsung S3C64XX and newer SoCs.

View File

@ -139,6 +139,7 @@
#define ARIZONA_INPUT_ENABLES_STATUS 0x301 #define ARIZONA_INPUT_ENABLES_STATUS 0x301
#define ARIZONA_INPUT_RATE 0x308 #define ARIZONA_INPUT_RATE 0x308
#define ARIZONA_INPUT_VOLUME_RAMP 0x309 #define ARIZONA_INPUT_VOLUME_RAMP 0x309
#define ARIZONA_HPF_CONTROL 0x30C
#define ARIZONA_IN1L_CONTROL 0x310 #define ARIZONA_IN1L_CONTROL 0x310
#define ARIZONA_ADC_DIGITAL_VOLUME_1L 0x311 #define ARIZONA_ADC_DIGITAL_VOLUME_1L 0x311
#define ARIZONA_DMIC1L_CONTROL 0x312 #define ARIZONA_DMIC1L_CONTROL 0x312
@ -160,6 +161,7 @@
#define ARIZONA_IN4L_CONTROL 0x328 #define ARIZONA_IN4L_CONTROL 0x328
#define ARIZONA_ADC_DIGITAL_VOLUME_4L 0x329 #define ARIZONA_ADC_DIGITAL_VOLUME_4L 0x329
#define ARIZONA_DMIC4L_CONTROL 0x32A #define ARIZONA_DMIC4L_CONTROL 0x32A
#define ARIZONA_IN4R_CONTROL 0x32C
#define ARIZONA_ADC_DIGITAL_VOLUME_4R 0x32D #define ARIZONA_ADC_DIGITAL_VOLUME_4R 0x32D
#define ARIZONA_DMIC4R_CONTROL 0x32E #define ARIZONA_DMIC4R_CONTROL 0x32E
#define ARIZONA_OUTPUT_ENABLES_1 0x400 #define ARIZONA_OUTPUT_ENABLES_1 0x400
@ -511,6 +513,38 @@
#define ARIZONA_AIF2TX2MIX_INPUT_3_VOLUME 0x74D #define ARIZONA_AIF2TX2MIX_INPUT_3_VOLUME 0x74D
#define ARIZONA_AIF2TX2MIX_INPUT_4_SOURCE 0x74E #define ARIZONA_AIF2TX2MIX_INPUT_4_SOURCE 0x74E
#define ARIZONA_AIF2TX2MIX_INPUT_4_VOLUME 0x74F #define ARIZONA_AIF2TX2MIX_INPUT_4_VOLUME 0x74F
#define ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE 0x750
#define ARIZONA_AIF2TX3MIX_INPUT_1_VOLUME 0x751
#define ARIZONA_AIF2TX3MIX_INPUT_2_SOURCE 0x752
#define ARIZONA_AIF2TX3MIX_INPUT_2_VOLUME 0x753
#define ARIZONA_AIF2TX3MIX_INPUT_3_SOURCE 0x754
#define ARIZONA_AIF2TX3MIX_INPUT_3_VOLUME 0x755
#define ARIZONA_AIF2TX3MIX_INPUT_4_SOURCE 0x756
#define ARIZONA_AIF2TX3MIX_INPUT_4_VOLUME 0x757
#define ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE 0x758
#define ARIZONA_AIF2TX4MIX_INPUT_1_VOLUME 0x759
#define ARIZONA_AIF2TX4MIX_INPUT_2_SOURCE 0x75A
#define ARIZONA_AIF2TX4MIX_INPUT_2_VOLUME 0x75B
#define ARIZONA_AIF2TX4MIX_INPUT_3_SOURCE 0x75C
#define ARIZONA_AIF2TX4MIX_INPUT_3_VOLUME 0x75D
#define ARIZONA_AIF2TX4MIX_INPUT_4_SOURCE 0x75E
#define ARIZONA_AIF2TX4MIX_INPUT_4_VOLUME 0x75F
#define ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE 0x760
#define ARIZONA_AIF2TX5MIX_INPUT_1_VOLUME 0x761
#define ARIZONA_AIF2TX5MIX_INPUT_2_SOURCE 0x762
#define ARIZONA_AIF2TX5MIX_INPUT_2_VOLUME 0x763
#define ARIZONA_AIF2TX5MIX_INPUT_3_SOURCE 0x764
#define ARIZONA_AIF2TX5MIX_INPUT_3_VOLUME 0x765
#define ARIZONA_AIF2TX5MIX_INPUT_4_SOURCE 0x766
#define ARIZONA_AIF2TX5MIX_INPUT_4_VOLUME 0x767
#define ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE 0x768
#define ARIZONA_AIF2TX6MIX_INPUT_1_VOLUME 0x769
#define ARIZONA_AIF2TX6MIX_INPUT_2_SOURCE 0x76A
#define ARIZONA_AIF2TX6MIX_INPUT_2_VOLUME 0x76B
#define ARIZONA_AIF2TX6MIX_INPUT_3_SOURCE 0x76C
#define ARIZONA_AIF2TX6MIX_INPUT_3_VOLUME 0x76D
#define ARIZONA_AIF2TX6MIX_INPUT_4_SOURCE 0x76E
#define ARIZONA_AIF2TX6MIX_INPUT_4_VOLUME 0x76F
#define ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE 0x780 #define ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE 0x780
#define ARIZONA_AIF3TX1MIX_INPUT_1_VOLUME 0x781 #define ARIZONA_AIF3TX1MIX_INPUT_1_VOLUME 0x781
#define ARIZONA_AIF3TX1MIX_INPUT_2_SOURCE 0x782 #define ARIZONA_AIF3TX1MIX_INPUT_2_SOURCE 0x782
@ -2292,9 +2326,19 @@
#define ARIZONA_IN_VI_RAMP_SHIFT 0 /* IN_VI_RAMP - [2:0] */ #define ARIZONA_IN_VI_RAMP_SHIFT 0 /* IN_VI_RAMP - [2:0] */
#define ARIZONA_IN_VI_RAMP_WIDTH 3 /* IN_VI_RAMP - [2:0] */ #define ARIZONA_IN_VI_RAMP_WIDTH 3 /* IN_VI_RAMP - [2:0] */
/*
* R780 (0x30C) - HPF Control
*/
#define ARIZONA_IN_HPF_CUT_MASK 0x0007 /* IN_HPF_CUT [2:0] */
#define ARIZONA_IN_HPF_CUT_SHIFT 0 /* IN_HPF_CUT [2:0] */
#define ARIZONA_IN_HPF_CUT_WIDTH 3 /* IN_HPF_CUT [2:0] */
/* /*
* R784 (0x310) - IN1L Control * R784 (0x310) - IN1L Control
*/ */
#define ARIZONA_IN1L_HPF_MASK 0x8000 /* IN1L_HPF - [15] */
#define ARIZONA_IN1L_HPF_SHIFT 15 /* IN1L_HPF - [15] */
#define ARIZONA_IN1L_HPF_WIDTH 1 /* IN1L_HPF - [15] */
#define ARIZONA_IN1_OSR_MASK 0x6000 /* IN1_OSR - [14:13] */ #define ARIZONA_IN1_OSR_MASK 0x6000 /* IN1_OSR - [14:13] */
#define ARIZONA_IN1_OSR_SHIFT 13 /* IN1_OSR - [14:13] */ #define ARIZONA_IN1_OSR_SHIFT 13 /* IN1_OSR - [14:13] */
#define ARIZONA_IN1_OSR_WIDTH 2 /* IN1_OSR - [14:13] */ #define ARIZONA_IN1_OSR_WIDTH 2 /* IN1_OSR - [14:13] */
@ -2333,6 +2377,9 @@
/* /*
* R788 (0x314) - IN1R Control * R788 (0x314) - IN1R Control
*/ */
#define ARIZONA_IN1R_HPF_MASK 0x8000 /* IN1R_HPF - [15] */
#define ARIZONA_IN1R_HPF_SHIFT 15 /* IN1R_HPF - [15] */
#define ARIZONA_IN1R_HPF_WIDTH 1 /* IN1R_HPF - [15] */
#define ARIZONA_IN1R_PGA_VOL_MASK 0x00FE /* IN1R_PGA_VOL - [7:1] */ #define ARIZONA_IN1R_PGA_VOL_MASK 0x00FE /* IN1R_PGA_VOL - [7:1] */
#define ARIZONA_IN1R_PGA_VOL_SHIFT 1 /* IN1R_PGA_VOL - [7:1] */ #define ARIZONA_IN1R_PGA_VOL_SHIFT 1 /* IN1R_PGA_VOL - [7:1] */
#define ARIZONA_IN1R_PGA_VOL_WIDTH 7 /* IN1R_PGA_VOL - [7:1] */ #define ARIZONA_IN1R_PGA_VOL_WIDTH 7 /* IN1R_PGA_VOL - [7:1] */
@ -2362,6 +2409,9 @@
/* /*
* R792 (0x318) - IN2L Control * R792 (0x318) - IN2L Control
*/ */
#define ARIZONA_IN2L_HPF_MASK 0x8000 /* IN2L_HPF - [15] */
#define ARIZONA_IN2L_HPF_SHIFT 15 /* IN2L_HPF - [15] */
#define ARIZONA_IN2L_HPF_WIDTH 1 /* IN2L_HPF - [15] */
#define ARIZONA_IN2_OSR_MASK 0x6000 /* IN2_OSR - [14:13] */ #define ARIZONA_IN2_OSR_MASK 0x6000 /* IN2_OSR - [14:13] */
#define ARIZONA_IN2_OSR_SHIFT 13 /* IN2_OSR - [14:13] */ #define ARIZONA_IN2_OSR_SHIFT 13 /* IN2_OSR - [14:13] */
#define ARIZONA_IN2_OSR_WIDTH 2 /* IN2_OSR - [14:13] */ #define ARIZONA_IN2_OSR_WIDTH 2 /* IN2_OSR - [14:13] */
@ -2400,6 +2450,9 @@
/* /*
* R796 (0x31C) - IN2R Control * R796 (0x31C) - IN2R Control
*/ */
#define ARIZONA_IN2R_HPF_MASK 0x8000 /* IN2R_HPF - [15] */
#define ARIZONA_IN2R_HPF_SHIFT 15 /* IN2R_HPF - [15] */
#define ARIZONA_IN2R_HPF_WIDTH 1 /* IN2R_HPF - [15] */
#define ARIZONA_IN2R_PGA_VOL_MASK 0x00FE /* IN2R_PGA_VOL - [7:1] */ #define ARIZONA_IN2R_PGA_VOL_MASK 0x00FE /* IN2R_PGA_VOL - [7:1] */
#define ARIZONA_IN2R_PGA_VOL_SHIFT 1 /* IN2R_PGA_VOL - [7:1] */ #define ARIZONA_IN2R_PGA_VOL_SHIFT 1 /* IN2R_PGA_VOL - [7:1] */
#define ARIZONA_IN2R_PGA_VOL_WIDTH 7 /* IN2R_PGA_VOL - [7:1] */ #define ARIZONA_IN2R_PGA_VOL_WIDTH 7 /* IN2R_PGA_VOL - [7:1] */
@ -2429,6 +2482,9 @@
/* /*
* R800 (0x320) - IN3L Control * R800 (0x320) - IN3L Control
*/ */
#define ARIZONA_IN3L_HPF_MASK 0x8000 /* IN3L_HPF - [15] */
#define ARIZONA_IN3L_HPF_SHIFT 15 /* IN3L_HPF - [15] */
#define ARIZONA_IN3L_HPF_WIDTH 1 /* IN3L_HPF - [15] */
#define ARIZONA_IN3_OSR_MASK 0x6000 /* IN3_OSR - [14:13] */ #define ARIZONA_IN3_OSR_MASK 0x6000 /* IN3_OSR - [14:13] */
#define ARIZONA_IN3_OSR_SHIFT 13 /* IN3_OSR - [14:13] */ #define ARIZONA_IN3_OSR_SHIFT 13 /* IN3_OSR - [14:13] */
#define ARIZONA_IN3_OSR_WIDTH 2 /* IN3_OSR - [14:13] */ #define ARIZONA_IN3_OSR_WIDTH 2 /* IN3_OSR - [14:13] */
@ -2467,6 +2523,9 @@
/* /*
* R804 (0x324) - IN3R Control * R804 (0x324) - IN3R Control
*/ */
#define ARIZONA_IN3R_HPF_MASK 0x8000 /* IN3R_HPF - [15] */
#define ARIZONA_IN3R_HPF_SHIFT 15 /* IN3R_HPF - [15] */
#define ARIZONA_IN3R_HPF_WIDTH 1 /* IN3R_HPF - [15] */
#define ARIZONA_IN3R_PGA_VOL_MASK 0x00FE /* IN3R_PGA_VOL - [7:1] */ #define ARIZONA_IN3R_PGA_VOL_MASK 0x00FE /* IN3R_PGA_VOL - [7:1] */
#define ARIZONA_IN3R_PGA_VOL_SHIFT 1 /* IN3R_PGA_VOL - [7:1] */ #define ARIZONA_IN3R_PGA_VOL_SHIFT 1 /* IN3R_PGA_VOL - [7:1] */
#define ARIZONA_IN3R_PGA_VOL_WIDTH 7 /* IN3R_PGA_VOL - [7:1] */ #define ARIZONA_IN3R_PGA_VOL_WIDTH 7 /* IN3R_PGA_VOL - [7:1] */
@ -2496,6 +2555,9 @@
/* /*
* R808 (0x328) - IN4 Control * R808 (0x328) - IN4 Control
*/ */
#define ARIZONA_IN4L_HPF_MASK 0x8000 /* IN4L_HPF - [15] */
#define ARIZONA_IN4L_HPF_SHIFT 15 /* IN4L_HPF - [15] */
#define ARIZONA_IN4L_HPF_WIDTH 1 /* IN4L_HPF - [15] */
#define ARIZONA_IN4_OSR_MASK 0x6000 /* IN4_OSR - [14:13] */ #define ARIZONA_IN4_OSR_MASK 0x6000 /* IN4_OSR - [14:13] */
#define ARIZONA_IN4_OSR_SHIFT 13 /* IN4_OSR - [14:13] */ #define ARIZONA_IN4_OSR_SHIFT 13 /* IN4_OSR - [14:13] */
#define ARIZONA_IN4_OSR_WIDTH 2 /* IN4_OSR - [14:13] */ #define ARIZONA_IN4_OSR_WIDTH 2 /* IN4_OSR - [14:13] */
@ -2525,6 +2587,13 @@
#define ARIZONA_IN4L_DMIC_DLY_SHIFT 0 /* IN4L_DMIC_DLY - [5:0] */ #define ARIZONA_IN4L_DMIC_DLY_SHIFT 0 /* IN4L_DMIC_DLY - [5:0] */
#define ARIZONA_IN4L_DMIC_DLY_WIDTH 6 /* IN4L_DMIC_DLY - [5:0] */ #define ARIZONA_IN4L_DMIC_DLY_WIDTH 6 /* IN4L_DMIC_DLY - [5:0] */
/*
* R812 (0x32C) - IN4R Control
*/
#define ARIZONA_IN4R_HPF_MASK 0x8000 /* IN4R_HPF - [15] */
#define ARIZONA_IN4R_HPF_SHIFT 15 /* IN4R_HPF - [15] */
#define ARIZONA_IN4R_HPF_WIDTH 1 /* IN4R_HPF - [15] */
/* /*
* R813 (0x32D) - ADC Digital Volume 4R * R813 (0x32D) - ADC Digital Volume 4R
*/ */
@ -3138,6 +3207,10 @@
/* /*
* R1088 (0x440) - DRE Enable * R1088 (0x440) - DRE Enable
*/ */
#define ARIZONA_DRE3R_ENA 0x0020 /* DRE3R_ENA */
#define ARIZONA_DRE3R_ENA_MASK 0x0020 /* DRE3R_ENA */
#define ARIZONA_DRE3R_ENA_SHIFT 5 /* DRE3R_ENA */
#define ARIZONA_DRE3R_ENA_WIDTH 1 /* DRE3R_ENA */
#define ARIZONA_DRE3L_ENA 0x0010 /* DRE3L_ENA */ #define ARIZONA_DRE3L_ENA 0x0010 /* DRE3L_ENA */
#define ARIZONA_DRE3L_ENA_MASK 0x0010 /* DRE3L_ENA */ #define ARIZONA_DRE3L_ENA_MASK 0x0010 /* DRE3L_ENA */
#define ARIZONA_DRE3L_ENA_SHIFT 4 /* DRE3L_ENA */ #define ARIZONA_DRE3L_ENA_SHIFT 4 /* DRE3L_ENA */
@ -3725,6 +3798,35 @@
#define ARIZONA_AIF2TX2_SLOT_SHIFT 0 /* AIF2TX2_SLOT - [5:0] */ #define ARIZONA_AIF2TX2_SLOT_SHIFT 0 /* AIF2TX2_SLOT - [5:0] */
#define ARIZONA_AIF2TX2_SLOT_WIDTH 6 /* AIF2TX2_SLOT - [5:0] */ #define ARIZONA_AIF2TX2_SLOT_WIDTH 6 /* AIF2TX2_SLOT - [5:0] */
/*
* R1355 (0x54B) - AIF2 Frame Ctrl 5
*/
#define ARIZONA_AIF2TX3_SLOT_MASK 0x003F /* AIF2TX3_SLOT - [5:0] */
#define ARIZONA_AIF2TX3_SLOT_SHIFT 0 /* AIF2TX3_SLOT - [5:0] */
#define ARIZONA_AIF2TX3_SLOT_WIDTH 6 /* AIF2TX3_SLOT - [5:0] */
/*
* R1356 (0x54C) - AIF2 Frame Ctrl 6
*/
#define ARIZONA_AIF2TX4_SLOT_MASK 0x003F /* AIF2TX4_SLOT - [5:0] */
#define ARIZONA_AIF2TX4_SLOT_SHIFT 0 /* AIF2TX4_SLOT - [5:0] */
#define ARIZONA_AIF2TX4_SLOT_WIDTH 6 /* AIF2TX4_SLOT - [5:0] */
/*
* R1357 (0x54D) - AIF2 Frame Ctrl 7
*/
#define ARIZONA_AIF2TX5_SLOT_MASK 0x003F /* AIF2TX5_SLOT - [5:0] */
#define ARIZONA_AIF2TX5_SLOT_SHIFT 0 /* AIF2TX5_SLOT - [5:0] */
#define ARIZONA_AIF2TX5_SLOT_WIDTH 6 /* AIF2TX5_SLOT - [5:0] */
/*
* R1358 (0x54E) - AIF2 Frame Ctrl 8
*/
#define ARIZONA_AIF2TX6_SLOT_MASK 0x003F /* AIF2TX6_SLOT - [5:0] */
#define ARIZONA_AIF2TX6_SLOT_SHIFT 0 /* AIF2TX6_SLOT - [5:0] */
#define ARIZONA_AIF2TX6_SLOT_WIDTH 6 /* AIF2TX6_SLOT - [5:0] */
/* /*
* R1361 (0x551) - AIF2 Frame Ctrl 11 * R1361 (0x551) - AIF2 Frame Ctrl 11
*/ */
@ -3739,9 +3841,53 @@
#define ARIZONA_AIF2RX2_SLOT_SHIFT 0 /* AIF2RX2_SLOT - [5:0] */ #define ARIZONA_AIF2RX2_SLOT_SHIFT 0 /* AIF2RX2_SLOT - [5:0] */
#define ARIZONA_AIF2RX2_SLOT_WIDTH 6 /* AIF2RX2_SLOT - [5:0] */ #define ARIZONA_AIF2RX2_SLOT_WIDTH 6 /* AIF2RX2_SLOT - [5:0] */
/*
* R1363 (0x553) - AIF2 Frame Ctrl 13
*/
#define ARIZONA_AIF2RX3_SLOT_MASK 0x003F /* AIF2RX3_SLOT - [5:0] */
#define ARIZONA_AIF2RX3_SLOT_SHIFT 0 /* AIF2RX3_SLOT - [5:0] */
#define ARIZONA_AIF2RX3_SLOT_WIDTH 6 /* AIF2RX3_SLOT - [5:0] */
/*
* R1364 (0x554) - AIF2 Frame Ctrl 14
*/
#define ARIZONA_AIF2RX4_SLOT_MASK 0x003F /* AIF2RX4_SLOT - [5:0] */
#define ARIZONA_AIF2RX4_SLOT_SHIFT 0 /* AIF2RX4_SLOT - [5:0] */
#define ARIZONA_AIF2RX4_SLOT_WIDTH 6 /* AIF2RX4_SLOT - [5:0] */
/*
* R1365 (0x555) - AIF2 Frame Ctrl 15
*/
#define ARIZONA_AIF2RX5_SLOT_MASK 0x003F /* AIF2RX5_SLOT - [5:0] */
#define ARIZONA_AIF2RX5_SLOT_SHIFT 0 /* AIF2RX5_SLOT - [5:0] */
#define ARIZONA_AIF2RX5_SLOT_WIDTH 6 /* AIF2RX5_SLOT - [5:0] */
/*
* R1366 (0x556) - AIF2 Frame Ctrl 16
*/
#define ARIZONA_AIF2RX6_SLOT_MASK 0x003F /* AIF2RX6_SLOT - [5:0] */
#define ARIZONA_AIF2RX6_SLOT_SHIFT 0 /* AIF2RX6_SLOT - [5:0] */
#define ARIZONA_AIF2RX6_SLOT_WIDTH 6 /* AIF2RX6_SLOT - [5:0] */
/* /*
* R1369 (0x559) - AIF2 Tx Enables * R1369 (0x559) - AIF2 Tx Enables
*/ */
#define ARIZONA_AIF2TX6_ENA 0x0020 /* AIF2TX6_ENA */
#define ARIZONA_AIF2TX6_ENA_MASK 0x0020 /* AIF2TX6_ENA */
#define ARIZONA_AIF2TX6_ENA_SHIFT 5 /* AIF2TX6_ENA */
#define ARIZONA_AIF2TX6_ENA_WIDTH 1 /* AIF2TX6_ENA */
#define ARIZONA_AIF2TX5_ENA 0x0010 /* AIF2TX5_ENA */
#define ARIZONA_AIF2TX5_ENA_MASK 0x0010 /* AIF2TX5_ENA */
#define ARIZONA_AIF2TX5_ENA_SHIFT 4 /* AIF2TX5_ENA */
#define ARIZONA_AIF2TX5_ENA_WIDTH 1 /* AIF2TX5_ENA */
#define ARIZONA_AIF2TX4_ENA 0x0008 /* AIF2TX4_ENA */
#define ARIZONA_AIF2TX4_ENA_MASK 0x0008 /* AIF2TX4_ENA */
#define ARIZONA_AIF2TX4_ENA_SHIFT 3 /* AIF2TX4_ENA */
#define ARIZONA_AIF2TX4_ENA_WIDTH 1 /* AIF2TX4_ENA */
#define ARIZONA_AIF2TX3_ENA 0x0004 /* AIF2TX3_ENA */
#define ARIZONA_AIF2TX3_ENA_MASK 0x0004 /* AIF2TX3_ENA */
#define ARIZONA_AIF2TX3_ENA_SHIFT 2 /* AIF2TX3_ENA */
#define ARIZONA_AIF2TX3_ENA_WIDTH 1 /* AIF2TX3_ENA */
#define ARIZONA_AIF2TX2_ENA 0x0002 /* AIF2TX2_ENA */ #define ARIZONA_AIF2TX2_ENA 0x0002 /* AIF2TX2_ENA */
#define ARIZONA_AIF2TX2_ENA_MASK 0x0002 /* AIF2TX2_ENA */ #define ARIZONA_AIF2TX2_ENA_MASK 0x0002 /* AIF2TX2_ENA */
#define ARIZONA_AIF2TX2_ENA_SHIFT 1 /* AIF2TX2_ENA */ #define ARIZONA_AIF2TX2_ENA_SHIFT 1 /* AIF2TX2_ENA */
@ -3754,6 +3900,22 @@
/* /*
* R1370 (0x55A) - AIF2 Rx Enables * R1370 (0x55A) - AIF2 Rx Enables
*/ */
#define ARIZONA_AIF2RX6_ENA 0x0020 /* AIF2RX6_ENA */
#define ARIZONA_AIF2RX6_ENA_MASK 0x0020 /* AIF2RX6_ENA */
#define ARIZONA_AIF2RX6_ENA_SHIFT 5 /* AIF2RX6_ENA */
#define ARIZONA_AIF2RX6_ENA_WIDTH 1 /* AIF2RX6_ENA */
#define ARIZONA_AIF2RX5_ENA 0x0010 /* AIF2RX5_ENA */
#define ARIZONA_AIF2RX5_ENA_MASK 0x0010 /* AIF2RX5_ENA */
#define ARIZONA_AIF2RX5_ENA_SHIFT 4 /* AIF2RX5_ENA */
#define ARIZONA_AIF2RX5_ENA_WIDTH 1 /* AIF2RX5_ENA */
#define ARIZONA_AIF2RX4_ENA 0x0008 /* AIF2RX4_ENA */
#define ARIZONA_AIF2RX4_ENA_MASK 0x0008 /* AIF2RX4_ENA */
#define ARIZONA_AIF2RX4_ENA_SHIFT 3 /* AIF2RX4_ENA */
#define ARIZONA_AIF2RX4_ENA_WIDTH 1 /* AIF2RX4_ENA */
#define ARIZONA_AIF2RX3_ENA 0x0004 /* AIF2RX3_ENA */
#define ARIZONA_AIF2RX3_ENA_MASK 0x0004 /* AIF2RX3_ENA */
#define ARIZONA_AIF2RX3_ENA_SHIFT 2 /* AIF2RX3_ENA */
#define ARIZONA_AIF2RX3_ENA_WIDTH 1 /* AIF2RX3_ENA */
#define ARIZONA_AIF2RX2_ENA 0x0002 /* AIF2RX2_ENA */ #define ARIZONA_AIF2RX2_ENA 0x0002 /* AIF2RX2_ENA */
#define ARIZONA_AIF2RX2_ENA_MASK 0x0002 /* AIF2RX2_ENA */ #define ARIZONA_AIF2RX2_ENA_MASK 0x0002 /* AIF2RX2_ENA */
#define ARIZONA_AIF2RX2_ENA_SHIFT 1 /* AIF2RX2_ENA */ #define ARIZONA_AIF2RX2_ENA_SHIFT 1 /* AIF2RX2_ENA */

View File

@ -1,6 +1,4 @@
/* /*
* arch/arm/plat-omap/include/mach/mcbsp.h
*
* Defines for Multi-Channel Buffered Serial Port * Defines for Multi-Channel Buffered Serial Port
* *
* Copyright (C) 2002 RidgeRun, Inc. * Copyright (C) 2002 RidgeRun, Inc.
@ -21,8 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
*/ */
#ifndef __ASM_ARCH_OMAP_MCBSP_H #ifndef __ASOC_TI_MCBSP_H
#define __ASM_ARCH_OMAP_MCBSP_H #define __ASOC_TI_MCBSP_H
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/clk.h> #include <linux/clk.h>

View File

@ -92,6 +92,7 @@ enum {
MCASP_VERSION_1 = 0, /* DM646x */ MCASP_VERSION_1 = 0, /* DM646x */
MCASP_VERSION_2, /* DA8xx/OMAPL1x */ MCASP_VERSION_2, /* DA8xx/OMAPL1x */
MCASP_VERSION_3, /* TI81xx/AM33xx */ MCASP_VERSION_3, /* TI81xx/AM33xx */
MCASP_VERSION_4, /* DRA7xxx */
}; };
enum mcbsp_clk_input_pin { enum mcbsp_clk_input_pin {

View File

@ -16,17 +16,11 @@ struct cs42l52_platform_data {
/* MICBIAS Level. Check datasheet Pg48 */ /* MICBIAS Level. Check datasheet Pg48 */
unsigned int micbias_lvl; unsigned int micbias_lvl;
/* MICA mode selection 0=Single 1=Differential */ /* MICA mode selection Differential or Single-ended */
unsigned int mica_cfg; bool mica_diff_cfg;
/* MICB mode selection 0=Single 1=Differential */ /* MICB mode selection Differential or Single-ended */
unsigned int micb_cfg; bool micb_diff_cfg;
/* MICA Select 0=MIC1A 1=MIC2A */
unsigned int mica_sel;
/* MICB Select 0=MIC2A 1=MIC2B */
unsigned int micb_sel;
/* Charge Pump Freq. Check datasheet Pg73 */ /* Charge Pump Freq. Check datasheet Pg73 */
unsigned int chgfreq; unsigned int chgfreq;

View File

@ -354,4 +354,16 @@ params_period_bytes(const struct snd_pcm_hw_params *p)
params_channels(p)) / 8; params_channels(p)) / 8;
} }
static inline int
params_width(const struct snd_pcm_hw_params *p)
{
return snd_pcm_format_width(params_format(p));
}
static inline int
params_physical_width(const struct snd_pcm_hw_params *p)
{
return snd_pcm_format_physical_width(params_format(p));
}
#endif /* __SOUND_PCM_PARAMS_H */ #endif /* __SOUND_PCM_PARAMS_H */

View File

@ -18,7 +18,7 @@
#define RSND_GEN1_ADG 1 #define RSND_GEN1_ADG 1
#define RSND_GEN1_SSI 2 #define RSND_GEN1_SSI 2
#define RSND_GEN2_SRU 0 #define RSND_GEN2_SCU 0
#define RSND_GEN2_ADG 1 #define RSND_GEN2_ADG 1
#define RSND_GEN2_SSIU 2 #define RSND_GEN2_SSIU 2
#define RSND_GEN2_SSI 3 #define RSND_GEN2_SSI 3
@ -58,6 +58,7 @@ struct rsnd_ssi_platform_info {
struct rsnd_scu_platform_info { struct rsnd_scu_platform_info {
u32 flags; u32 flags;
u32 convert_rate; /* sampling rate convert */
}; };
/* /*

View File

@ -334,9 +334,7 @@ struct snd_soc_jack_pin;
#include <sound/soc-dapm.h> #include <sound/soc-dapm.h>
#include <sound/soc-dpcm.h> #include <sound/soc-dpcm.h>
#ifdef CONFIG_GPIOLIB
struct snd_soc_jack_gpio; struct snd_soc_jack_gpio;
#endif
typedef int (*hw_write_t)(void *,const char* ,int); typedef int (*hw_write_t)(void *,const char* ,int);
@ -446,6 +444,17 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
struct snd_soc_jack_gpio *gpios); struct snd_soc_jack_gpio *gpios);
void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
struct snd_soc_jack_gpio *gpios); struct snd_soc_jack_gpio *gpios);
#else
static inline int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
struct snd_soc_jack_gpio *gpios)
{
return 0;
}
static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
struct snd_soc_jack_gpio *gpios)
{
}
#endif #endif
/* codec register bit access */ /* codec register bit access */
@ -580,7 +589,6 @@ struct snd_soc_jack_zone {
* to provide more complex checks (eg, reading an * to provide more complex checks (eg, reading an
* ADC). * ADC).
*/ */
#ifdef CONFIG_GPIOLIB
struct snd_soc_jack_gpio { struct snd_soc_jack_gpio {
unsigned int gpio; unsigned int gpio;
const char *name; const char *name;
@ -594,7 +602,6 @@ struct snd_soc_jack_gpio {
int (*jack_status_check)(void); int (*jack_status_check)(void);
}; };
#endif
struct snd_soc_jack { struct snd_soc_jack {
struct mutex mutex; struct mutex mutex;

View File

@ -29,7 +29,6 @@ struct spear_dma_data {
dma_addr_t addr; dma_addr_t addr;
u32 max_burst; u32 max_burst;
enum dma_slave_buswidth addr_width; enum dma_slave_buswidth addr_width;
bool (*filter)(struct dma_chan *chan, void *slave);
}; };
#endif /* SPEAR_DMA_H */ #endif /* SPEAR_DMA_H */

View File

@ -31,8 +31,10 @@ config SND_SOC_GENERIC_DMAENGINE_PCM
select SND_DMAENGINE_PCM select SND_DMAENGINE_PCM
# All the supported SoCs # All the supported SoCs
source "sound/soc/adi/Kconfig"
source "sound/soc/atmel/Kconfig" source "sound/soc/atmel/Kconfig"
source "sound/soc/au1x/Kconfig" source "sound/soc/au1x/Kconfig"
source "sound/soc/bcm/Kconfig"
source "sound/soc/blackfin/Kconfig" source "sound/soc/blackfin/Kconfig"
source "sound/soc/cirrus/Kconfig" source "sound/soc/cirrus/Kconfig"
source "sound/soc/davinci/Kconfig" source "sound/soc/davinci/Kconfig"
@ -42,7 +44,7 @@ source "sound/soc/jz4740/Kconfig"
source "sound/soc/nuc900/Kconfig" source "sound/soc/nuc900/Kconfig"
source "sound/soc/omap/Kconfig" source "sound/soc/omap/Kconfig"
source "sound/soc/kirkwood/Kconfig" source "sound/soc/kirkwood/Kconfig"
source "sound/soc/mid-x86/Kconfig" source "sound/soc/intel/Kconfig"
source "sound/soc/mxs/Kconfig" source "sound/soc/mxs/Kconfig"
source "sound/soc/pxa/Kconfig" source "sound/soc/pxa/Kconfig"
source "sound/soc/samsung/Kconfig" source "sound/soc/samsung/Kconfig"

View File

@ -8,15 +8,17 @@ endif
obj-$(CONFIG_SND_SOC) += snd-soc-core.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o
obj-$(CONFIG_SND_SOC) += codecs/ obj-$(CONFIG_SND_SOC) += codecs/
obj-$(CONFIG_SND_SOC) += generic/ obj-$(CONFIG_SND_SOC) += generic/
obj-$(CONFIG_SND_SOC) += adi/
obj-$(CONFIG_SND_SOC) += atmel/ obj-$(CONFIG_SND_SOC) += atmel/
obj-$(CONFIG_SND_SOC) += au1x/ obj-$(CONFIG_SND_SOC) += au1x/
obj-$(CONFIG_SND_SOC) += bcm/
obj-$(CONFIG_SND_SOC) += blackfin/ obj-$(CONFIG_SND_SOC) += blackfin/
obj-$(CONFIG_SND_SOC) += cirrus/ obj-$(CONFIG_SND_SOC) += cirrus/
obj-$(CONFIG_SND_SOC) += davinci/ obj-$(CONFIG_SND_SOC) += davinci/
obj-$(CONFIG_SND_SOC) += dwc/ obj-$(CONFIG_SND_SOC) += dwc/
obj-$(CONFIG_SND_SOC) += fsl/ obj-$(CONFIG_SND_SOC) += fsl/
obj-$(CONFIG_SND_SOC) += jz4740/ obj-$(CONFIG_SND_SOC) += jz4740/
obj-$(CONFIG_SND_SOC) += mid-x86/ obj-$(CONFIG_SND_SOC) += intel/
obj-$(CONFIG_SND_SOC) += mxs/ obj-$(CONFIG_SND_SOC) += mxs/
obj-$(CONFIG_SND_SOC) += nuc900/ obj-$(CONFIG_SND_SOC) += nuc900/
obj-$(CONFIG_SND_SOC) += omap/ obj-$(CONFIG_SND_SOC) += omap/

21
sound/soc/adi/Kconfig Normal file
View File

@ -0,0 +1,21 @@
config SND_SOC_ADI
tristate "Audio support for Analog Devices reference designs"
depends on MICROBLAZE || ARCH_ZYNQ || COMPILE_TEST
help
Audio support for various reference designs by Analog Devices.
config SND_SOC_ADI_AXI_I2S
tristate "AXI-I2S support"
depends on SND_SOC_ADI
select SND_SOC_GENERIC_DMAENGINE_PCM
select REGMAP_MMIO
help
ASoC driver for the Analog Devices AXI-I2S softcore peripheral.
config SND_SOC_ADI_AXI_SPDIF
tristate "AXI-SPDIF support"
depends on SND_SOC_ADI
select SND_SOC_GENERIC_DMAENGINE_PCM
select REGMAP_MMIO
help
ASoC driver for the Analog Devices AXI-SPDIF softcore peripheral.

5
sound/soc/adi/Makefile Normal file
View File

@ -0,0 +1,5 @@
snd-soc-adi-axi-i2s-objs := axi-i2s.o
snd-soc-adi-axi-spdif-objs := axi-spdif.o
obj-$(CONFIG_SND_SOC_ADI_AXI_I2S) += snd-soc-adi-axi-i2s.o
obj-$(CONFIG_SND_SOC_ADI_AXI_SPDIF) += snd-soc-adi-axi-spdif.o

277
sound/soc/adi/axi-i2s.c Normal file
View File

@ -0,0 +1,277 @@
/*
* Copyright (C) 2012-2013, Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* Licensed under the GPL-2.
*/
#include <linux/clk.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
#define AXI_I2S_REG_RESET 0x00
#define AXI_I2S_REG_CTRL 0x04
#define AXI_I2S_REG_CLK_CTRL 0x08
#define AXI_I2S_REG_STATUS 0x10
#define AXI_I2S_REG_RX_FIFO 0x28
#define AXI_I2S_REG_TX_FIFO 0x2C
#define AXI_I2S_RESET_GLOBAL BIT(0)
#define AXI_I2S_RESET_TX_FIFO BIT(1)
#define AXI_I2S_RESET_RX_FIFO BIT(2)
#define AXI_I2S_CTRL_TX_EN BIT(0)
#define AXI_I2S_CTRL_RX_EN BIT(1)
/* The frame size is configurable, but for now we always set it 64 bit */
#define AXI_I2S_BITS_PER_FRAME 64
struct axi_i2s {
struct regmap *regmap;
struct clk *clk;
struct clk *clk_ref;
struct snd_soc_dai_driver dai_driver;
struct snd_dmaengine_dai_dma_data capture_dma_data;
struct snd_dmaengine_dai_dma_data playback_dma_data;
struct snd_ratnum ratnum;
struct snd_pcm_hw_constraint_ratnums rate_constraints;
};
static int axi_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai);
unsigned int mask, val;
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
mask = AXI_I2S_CTRL_RX_EN;
else
mask = AXI_I2S_CTRL_TX_EN;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
val = mask;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
val = 0;
break;
default:
return -EINVAL;
}
regmap_update_bits(i2s->regmap, AXI_I2S_REG_CTRL, mask, val);
return 0;
}
static int axi_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai);
unsigned int bclk_div, word_size;
unsigned int bclk_rate;
bclk_rate = params_rate(params) * AXI_I2S_BITS_PER_FRAME;
word_size = AXI_I2S_BITS_PER_FRAME / 2 - 1;
bclk_div = DIV_ROUND_UP(clk_get_rate(i2s->clk_ref), bclk_rate) / 2 - 1;
regmap_write(i2s->regmap, AXI_I2S_REG_CLK_CTRL, (word_size << 16) |
bclk_div);
return 0;
}
static int axi_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai);
uint32_t mask;
int ret;
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
mask = AXI_I2S_RESET_RX_FIFO;
else
mask = AXI_I2S_RESET_TX_FIFO;
regmap_write(i2s->regmap, AXI_I2S_REG_RESET, mask);
ret = snd_pcm_hw_constraint_ratnums(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
&i2s->rate_constraints);
if (ret)
return ret;
return clk_prepare_enable(i2s->clk_ref);
}
static void axi_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai);
clk_disable_unprepare(i2s->clk_ref);
}
static int axi_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai);
snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data,
&i2s->capture_dma_data);
return 0;
}
static const struct snd_soc_dai_ops axi_i2s_dai_ops = {
.startup = axi_i2s_startup,
.shutdown = axi_i2s_shutdown,
.trigger = axi_i2s_trigger,
.hw_params = axi_i2s_hw_params,
};
static struct snd_soc_dai_driver axi_i2s_dai = {
.probe = axi_i2s_dai_probe,
.playback = {
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE,
},
.capture = {
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE,
},
.ops = &axi_i2s_dai_ops,
.symmetric_rates = 1,
};
static const struct snd_soc_component_driver axi_i2s_component = {
.name = "axi-i2s",
};
static const struct regmap_config axi_i2s_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = AXI_I2S_REG_STATUS,
};
static int axi_i2s_probe(struct platform_device *pdev)
{
struct resource *res;
struct axi_i2s *i2s;
void __iomem *base;
int ret;
i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
if (!i2s)
return -ENOMEM;
platform_set_drvdata(pdev, i2s);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
i2s->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&axi_i2s_regmap_config);
if (IS_ERR(i2s->regmap))
return PTR_ERR(i2s->regmap);
i2s->clk = devm_clk_get(&pdev->dev, "axi");
if (IS_ERR(i2s->clk))
return PTR_ERR(i2s->clk);
i2s->clk_ref = devm_clk_get(&pdev->dev, "ref");
if (IS_ERR(i2s->clk_ref))
return PTR_ERR(i2s->clk_ref);
ret = clk_prepare_enable(i2s->clk);
if (ret)
return ret;
i2s->playback_dma_data.addr = res->start + AXI_I2S_REG_TX_FIFO;
i2s->playback_dma_data.addr_width = 4;
i2s->playback_dma_data.maxburst = 1;
i2s->capture_dma_data.addr = res->start + AXI_I2S_REG_RX_FIFO;
i2s->capture_dma_data.addr_width = 4;
i2s->capture_dma_data.maxburst = 1;
i2s->ratnum.num = clk_get_rate(i2s->clk_ref) / 2 / AXI_I2S_BITS_PER_FRAME;
i2s->ratnum.den_step = 1;
i2s->ratnum.den_min = 1;
i2s->ratnum.den_max = 64;
i2s->rate_constraints.rats = &i2s->ratnum;
i2s->rate_constraints.nrats = 1;
regmap_write(i2s->regmap, AXI_I2S_REG_RESET, AXI_I2S_RESET_GLOBAL);
ret = devm_snd_soc_register_component(&pdev->dev, &axi_i2s_component,
&axi_i2s_dai, 1);
if (ret)
goto err_clk_disable;
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
if (ret)
goto err_clk_disable;
err_clk_disable:
clk_disable_unprepare(i2s->clk);
return ret;
}
static int axi_i2s_dev_remove(struct platform_device *pdev)
{
struct axi_i2s *i2s = platform_get_drvdata(pdev);
clk_disable_unprepare(i2s->clk);
return 0;
}
static const struct of_device_id axi_i2s_of_match[] = {
{ .compatible = "adi,axi-i2s-1.00.a", },
{},
};
MODULE_DEVICE_TABLE(of, axi_i2s_of_match);
static struct platform_driver axi_i2s_driver = {
.driver = {
.name = "axi-i2s",
.owner = THIS_MODULE,
.of_match_table = axi_i2s_of_match,
},
.probe = axi_i2s_probe,
.remove = axi_i2s_dev_remove,
};
module_platform_driver(axi_i2s_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("AXI I2S driver");
MODULE_LICENSE("GPL");

272
sound/soc/adi/axi-spdif.c Normal file
View File

@ -0,0 +1,272 @@
/*
* Copyright (C) 2012-2013, Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* Licensed under the GPL-2.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/clk.h>
#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/dmaengine_pcm.h>
#define AXI_SPDIF_REG_CTRL 0x0
#define AXI_SPDIF_REG_STAT 0x4
#define AXI_SPDIF_REG_TX_FIFO 0xc
#define AXI_SPDIF_CTRL_TXDATA BIT(1)
#define AXI_SPDIF_CTRL_TXEN BIT(0)
#define AXI_SPDIF_CTRL_CLKDIV_OFFSET 8
#define AXI_SPDIF_CTRL_CLKDIV_MASK (0xff << 8)
#define AXI_SPDIF_FREQ_44100 (0x0 << 6)
#define AXI_SPDIF_FREQ_48000 (0x1 << 6)
#define AXI_SPDIF_FREQ_32000 (0x2 << 6)
#define AXI_SPDIF_FREQ_NA (0x3 << 6)
struct axi_spdif {
struct regmap *regmap;
struct clk *clk;
struct clk *clk_ref;
struct snd_dmaengine_dai_dma_data dma_data;
struct snd_ratnum ratnum;
struct snd_pcm_hw_constraint_ratnums rate_constraints;
};
static int axi_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct axi_spdif *spdif = snd_soc_dai_get_drvdata(dai);
unsigned int val;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
val = AXI_SPDIF_CTRL_TXDATA;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
val = 0;
break;
default:
return -EINVAL;
}
regmap_update_bits(spdif->regmap, AXI_SPDIF_REG_CTRL,
AXI_SPDIF_CTRL_TXDATA, val);
return 0;
}
static int axi_spdif_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
struct axi_spdif *spdif = snd_soc_dai_get_drvdata(dai);
unsigned int rate = params_rate(params);
unsigned int clkdiv, stat;
switch (params_rate(params)) {
case 32000:
stat = AXI_SPDIF_FREQ_32000;
break;
case 44100:
stat = AXI_SPDIF_FREQ_44100;
break;
case 48000:
stat = AXI_SPDIF_FREQ_48000;
break;
default:
stat = AXI_SPDIF_FREQ_NA;
break;
}
clkdiv = DIV_ROUND_CLOSEST(clk_get_rate(spdif->clk_ref),
rate * 64 * 2) - 1;
clkdiv <<= AXI_SPDIF_CTRL_CLKDIV_OFFSET;
regmap_write(spdif->regmap, AXI_SPDIF_REG_STAT, stat);
regmap_update_bits(spdif->regmap, AXI_SPDIF_REG_CTRL,
AXI_SPDIF_CTRL_CLKDIV_MASK, clkdiv);
return 0;
}
static int axi_spdif_dai_probe(struct snd_soc_dai *dai)
{
struct axi_spdif *spdif = snd_soc_dai_get_drvdata(dai);
snd_soc_dai_init_dma_data(dai, &spdif->dma_data, NULL);
return 0;
}
static int axi_spdif_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct axi_spdif *spdif = snd_soc_dai_get_drvdata(dai);
int ret;
ret = snd_pcm_hw_constraint_ratnums(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
&spdif->rate_constraints);
if (ret)
return ret;
ret = clk_prepare_enable(spdif->clk_ref);
if (ret)
return ret;
regmap_update_bits(spdif->regmap, AXI_SPDIF_REG_CTRL,
AXI_SPDIF_CTRL_TXEN, AXI_SPDIF_CTRL_TXEN);
return 0;
}
static void axi_spdif_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct axi_spdif *spdif = snd_soc_dai_get_drvdata(dai);
regmap_update_bits(spdif->regmap, AXI_SPDIF_REG_CTRL,
AXI_SPDIF_CTRL_TXEN, 0);
clk_disable_unprepare(spdif->clk_ref);
}
static const struct snd_soc_dai_ops axi_spdif_dai_ops = {
.startup = axi_spdif_startup,
.shutdown = axi_spdif_shutdown,
.trigger = axi_spdif_trigger,
.hw_params = axi_spdif_hw_params,
};
static struct snd_soc_dai_driver axi_spdif_dai = {
.probe = axi_spdif_dai_probe,
.playback = {
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.ops = &axi_spdif_dai_ops,
};
static const struct snd_soc_component_driver axi_spdif_component = {
.name = "axi-spdif",
};
static const struct regmap_config axi_spdif_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = AXI_SPDIF_REG_STAT,
};
static int axi_spdif_probe(struct platform_device *pdev)
{
struct axi_spdif *spdif;
struct resource *res;
void __iomem *base;
int ret;
spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL);
if (!spdif)
return -ENOMEM;
platform_set_drvdata(pdev, spdif);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
spdif->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&axi_spdif_regmap_config);
if (IS_ERR(spdif->regmap))
return PTR_ERR(spdif->regmap);
spdif->clk = devm_clk_get(&pdev->dev, "axi");
if (IS_ERR(spdif->clk))
return PTR_ERR(spdif->clk);
spdif->clk_ref = devm_clk_get(&pdev->dev, "ref");
if (IS_ERR(spdif->clk_ref))
return PTR_ERR(spdif->clk_ref);
ret = clk_prepare_enable(spdif->clk);
if (ret)
return ret;
spdif->dma_data.addr = res->start + AXI_SPDIF_REG_TX_FIFO;
spdif->dma_data.addr_width = 4;
spdif->dma_data.maxburst = 1;
spdif->ratnum.num = clk_get_rate(spdif->clk_ref) / 128;
spdif->ratnum.den_step = 1;
spdif->ratnum.den_min = 1;
spdif->ratnum.den_max = 64;
spdif->rate_constraints.rats = &spdif->ratnum;
spdif->rate_constraints.nrats = 1;
ret = devm_snd_soc_register_component(&pdev->dev, &axi_spdif_component,
&axi_spdif_dai, 1);
if (ret)
goto err_clk_disable;
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
if (ret)
goto err_clk_disable;
return 0;
err_clk_disable:
clk_disable_unprepare(spdif->clk);
return ret;
}
static int axi_spdif_dev_remove(struct platform_device *pdev)
{
struct axi_spdif *spdif = platform_get_drvdata(pdev);
clk_disable_unprepare(spdif->clk);
return 0;
}
static const struct of_device_id axi_spdif_of_match[] = {
{ .compatible = "adi,axi-spdif-tx-1.00.a", },
{},
};
MODULE_DEVICE_TABLE(of, axi_spdif_of_match);
static struct platform_driver axi_spdif_driver = {
.driver = {
.name = "axi-spdif",
.owner = THIS_MODULE,
.of_match_table = axi_spdif_of_match,
},
.probe = axi_spdif_probe,
.remove = axi_spdif_dev_remove,
};
module_platform_driver(axi_spdif_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("AXI SPDIF driver");
MODULE_LICENSE("GPL");

View File

@ -155,8 +155,6 @@ static int sam9x5_wm8731_driver_probe(struct platform_device *pdev)
of_node_put(codec_np); of_node_put(codec_np);
of_node_put(cpu_np); of_node_put(cpu_np);
platform_set_drvdata(pdev, card);
ret = snd_soc_register_card(card); ret = snd_soc_register_card(card);
if (ret) { if (ret) {
dev_err(&pdev->dev, dev_err(&pdev->dev,

View File

@ -65,19 +65,10 @@ struct au1xpsc_audio_dmadata {
#define AU1XPSC_PERIOD_MIN_BYTES 1024 #define AU1XPSC_PERIOD_MIN_BYTES 1024
#define AU1XPSC_BUFFER_MIN_BYTES 65536 #define AU1XPSC_BUFFER_MIN_BYTES 65536
#define AU1XPSC_PCM_FMTS \
(SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | \
SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE | \
0)
/* PCM hardware DMA capabilities - platform specific */ /* PCM hardware DMA capabilities - platform specific */
static const struct snd_pcm_hardware au1xpsc_pcm_hardware = { static const struct snd_pcm_hardware au1xpsc_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BATCH, SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BATCH,
.formats = AU1XPSC_PCM_FMTS,
.period_bytes_min = AU1XPSC_PERIOD_MIN_BYTES, .period_bytes_min = AU1XPSC_PERIOD_MIN_BYTES,
.period_bytes_max = 4096 * 1024 - 1, .period_bytes_max = 4096 * 1024 - 1,
.periods_min = 2, .periods_min = 2,

View File

@ -21,14 +21,6 @@
#include "psc.h" #include "psc.h"
#define ALCHEMY_PCM_FMTS \
(SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | \
SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE | \
0)
struct pcm_period { struct pcm_period {
u32 start; u32 start;
u32 relative_end; /* relative to start of buffer */ u32 relative_end; /* relative to start of buffer */
@ -171,12 +163,6 @@ static irqreturn_t au1000_dma_interrupt(int irq, void *ptr)
static const struct snd_pcm_hardware alchemy_pcm_hardware = { static const struct snd_pcm_hardware alchemy_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BATCH, SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BATCH,
.formats = ALCHEMY_PCM_FMTS,
.rates = SNDRV_PCM_RATE_8000_192000,
.rate_min = SNDRV_PCM_RATE_8000,
.rate_max = SNDRV_PCM_RATE_192000,
.channels_min = 2,
.channels_max = 2,
.period_bytes_min = 1024, .period_bytes_min = 1024,
.period_bytes_max = 16 * 1024 - 1, .period_bytes_max = 16 * 1024 - 1,
.periods_min = 4, .periods_min = 4,

10
sound/soc/bcm/Kconfig Normal file
View File

@ -0,0 +1,10 @@
config SND_BCM2835_SOC_I2S
tristate "SoC Audio support for the Broadcom BCM2835 I2S module"
depends on ARCH_BCM2835 || COMPILE_TEST
select SND_SOC_DMAENGINE_PCM
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.

5
sound/soc/bcm/Makefile Normal file
View File

@ -0,0 +1,5 @@
# BCM2835 Platform Support
snd-soc-bcm2835-i2s-objs := bcm2835-i2s.o
obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd-soc-bcm2835-i2s.o

879
sound/soc/bcm/bcm2835-i2s.c Normal file
View File

@ -0,0 +1,879 @@
/*
* ALSA SoC I2S Audio Layer for Broadcom BCM2835 SoC
*
* Author: Florian Meier <florian.meier@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@embeddedalley.com>
* Copyright (C) 2007 MontaVista Software, Inc., <source@mvista.com>
*
* OMAP ALSA SoC DAI driver using McBSP port
* Copyright (C) 2008 Nokia Corporation
* Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
* Peter Ujfalusi <peter.ujfalusi@ti.com>
*
* Freescale SSI ALSA SoC Digital Audio Interface (DAI) driver
* Author: Timur Tabi <timur@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.
*/
#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>
/* 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 BIT(8)
#define BCM2835_CLK_BUSY BIT(7)
#define BCM2835_CLK_KILL BIT(5)
#define BCM2835_CLK_ENAB BIT(4)
#define BCM2835_CLK_SRC(v) (v)
#define BCM2835_CLK_SHIFT (12)
#define BCM2835_CLK_DIVI(v) ((v) << BCM2835_CLK_SHIFT)
#define BCM2835_CLK_DIVF(v) (v)
#define BCM2835_CLK_DIVF_MASK (0xFFF)
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 BIT(25)
#define BCM2835_I2S_SYNC BIT(24)
#define BCM2835_I2S_RXSEX BIT(23)
#define BCM2835_I2S_RXF BIT(22)
#define BCM2835_I2S_TXE BIT(21)
#define BCM2835_I2S_RXD BIT(20)
#define BCM2835_I2S_TXD BIT(19)
#define BCM2835_I2S_RXR BIT(18)
#define BCM2835_I2S_TXW BIT(17)
#define BCM2835_I2S_CS_RXERR BIT(16)
#define BCM2835_I2S_CS_TXERR BIT(15)
#define BCM2835_I2S_RXSYNC BIT(14)
#define BCM2835_I2S_TXSYNC BIT(13)
#define BCM2835_I2S_DMAEN BIT(9)
#define BCM2835_I2S_RXTHR(v) ((v) << 7)
#define BCM2835_I2S_TXTHR(v) ((v) << 5)
#define BCM2835_I2S_RXCLR BIT(4)
#define BCM2835_I2S_TXCLR BIT(3)
#define BCM2835_I2S_TXON BIT(2)
#define BCM2835_I2S_RXON BIT(1)
#define BCM2835_I2S_EN (1)
#define BCM2835_I2S_CLKDIS BIT(28)
#define BCM2835_I2S_PDMN BIT(27)
#define BCM2835_I2S_PDME BIT(26)
#define BCM2835_I2S_FRXP BIT(25)
#define BCM2835_I2S_FTXP BIT(24)
#define BCM2835_I2S_CLKM BIT(23)
#define BCM2835_I2S_CLKI BIT(22)
#define BCM2835_I2S_FSM BIT(21)
#define BCM2835_I2S_FSI BIT(20)
#define BCM2835_I2S_FLEN(v) ((v) << 10)
#define BCM2835_I2S_FSLEN(v) (v)
#define BCM2835_I2S_CHWEX BIT(15)
#define BCM2835_I2S_CHEN BIT(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 BIT(3)
#define BCM2835_I2S_INT_TXERR BIT(2)
#define BCM2835_I2S_INT_RXR BIT(1)
#define BCM2835_I2S_INT_TXW BIT(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;
unsigned int bclk_ratio;
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) {
regmap_read(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, &clkreg);
if (!(clkreg & BCM2835_CLK_BUSY))
break;
}
if (!timeout) {
/* 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, clr);
/* 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) {
regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg);
if ((csreg & BCM2835_I2S_SYNC) != syncval)
break;
}
if (!timeout)
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_set_dai_bclk_ratio(struct snd_soc_dai *dai,
unsigned int ratio)
{
struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
dev->bclk_ratio = ratio;
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, bclk_ratio;
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;
bool bit_master = (master == SND_SOC_DAIFMT_CBS_CFS
|| master == SND_SOC_DAIFMT_CBS_CFM);
bool 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;
bclk_ratio = 40;
break;
case SNDRV_PCM_FORMAT_S32_LE:
data_length = 32;
bclk_ratio = 80;
break;
default:
return -EINVAL;
}
/* If bclk_ratio already set, use that one. */
if (dev->bclk_ratio)
bclk_ratio = dev->bclk_ratio;
/*
* 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 * bclk_ratio;
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;
if (!dev->bclk_ratio) {
/*
* Overwrite bclk_ratio, because the
* above trick is not needed or can
* not be used.
*/
bclk_ratio = 2 * data_length;
}
target_frequency = sampling_rate * bclk_ratio;
clk_src = BCM2835_CLK_SRC_PLLD;
mash = BCM2835_CLK_MASH_1;
dividend = bcm2835_clk_freq[clk_src];
dividend <<= BCM2835_CLK_SHIFT;
do_div(dividend, target_frequency);
divi = dividend >> BCM2835_CLK_SHIFT;
divf = dividend & BCM2835_CLK_DIVF_MASK;
}
/* 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 = bclk_ratio / 2 + 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(bclk_ratio - 1);
mode |= BCM2835_I2S_FSLEN(bclk_ratio / 2);
/* 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, 0xffffffff);
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), 0xffffffff);
/* 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)
return 0;
/* 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, BCM2835_I2S_EN);
/*
* 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, BCM2835_I2S_STBY);
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)
return;
/* 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,
.set_bclk_ratio = bcm2835_i2s_set_dai_bclk_ratio
};
static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
snd_soc_dai_init_dma_data(dai,
&dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
&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);
base = devm_ioremap_resource(&pdev->dev, mem[i]);
if (IS_ERR(base))
return PTR_ERR(base);
regmap[i] = devm_regmap_init_mmio(&pdev->dev, base,
&bcm2835_regmap_config[i]);
if (IS_ERR(regmap[i]))
return PTR_ERR(regmap[i]);
}
dev = devm_kzalloc(&pdev->dev, sizeof(*dev),
GFP_KERNEL);
if (!dev)
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;
/* Set the bus width */
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;
/* Set burst */
dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].maxburst = 2;
dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].maxburst = 2;
/* BCLK ratio - use default */
dev->bclk_ratio = 0;
/* Store the pdev */
dev->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, dev);
ret = devm_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);
return ret;
}
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
if (ret) {
dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
return ret;
}
return 0;
}
static const struct of_device_id bcm2835_i2s_of_match[] = {
{ .compatible = "brcm,bcm2835-i2s", },
{},
};
static struct platform_driver bcm2835_i2s_driver = {
.probe = bcm2835_i2s_probe,
.driver = {
.name = "bcm2835-i2s",
.owner = THIS_MODULE,
.of_match_table = bcm2835_i2s_of_match,
},
};
module_platform_driver(bcm2835_i2s_driver);
MODULE_ALIAS("platform:bcm2835-i2s");
MODULE_DESCRIPTION("BCM2835 I2S interface");
MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
MODULE_LICENSE("GPL v2");

View File

@ -107,7 +107,6 @@ static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
#endif #endif
SNDRV_PCM_INFO_BLOCK_TRANSFER, SNDRV_PCM_INFO_BLOCK_TRANSFER,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.period_bytes_min = 32, .period_bytes_min = 32,
.period_bytes_max = 0x10000, .period_bytes_max = 0x10000,
.periods_min = 1, .periods_min = 1,

View File

@ -52,9 +52,6 @@ static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED | .info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_BLOCK_TRANSFER, SNDRV_PCM_INFO_BLOCK_TRANSFER,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.period_bytes_min = 32, .period_bytes_min = 32,
.period_bytes_max = 0x10000, .period_bytes_max = 0x10000,
.periods_min = 1, .periods_min = 1,

View File

@ -63,7 +63,7 @@ static struct snd_soc_ops edb93xx_ops = {
static struct snd_soc_dai_link edb93xx_dai = { static struct snd_soc_dai_link edb93xx_dai = {
.name = "CS4271", .name = "CS4271",
.stream_name = "CS4271 HiFi", .stream_name = "CS4271 HiFi",
.platform_name = "ep93xx-pcm-audio", .platform_name = "ep93xx-i2s",
.cpu_dai_name = "ep93xx-i2s", .cpu_dai_name = "ep93xx-i2s",
.codec_name = "spi0.0", .codec_name = "spi0.0",
.codec_dai_name = "cs4271-hifi", .codec_dai_name = "cs4271-hifi",

View File

@ -19,11 +19,14 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/dmaengine_pcm.h>
#include <sound/ac97_codec.h> #include <sound/ac97_codec.h>
#include <sound/soc.h> #include <sound/soc.h>
#include <linux/platform_data/dma-ep93xx.h> #include <linux/platform_data/dma-ep93xx.h>
#include "ep93xx-pcm.h"
/* /*
* Per channel (1-4) registers. * Per channel (1-4) registers.
*/ */
@ -95,6 +98,8 @@ struct ep93xx_ac97_info {
struct device *dev; struct device *dev;
void __iomem *regs; void __iomem *regs;
struct completion done; struct completion done;
struct snd_dmaengine_dai_dma_data dma_params_rx;
struct snd_dmaengine_dai_dma_data dma_params_tx;
}; };
/* currently ALSA only supports a single AC97 device */ /* currently ALSA only supports a single AC97 device */
@ -315,8 +320,13 @@ static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
static int ep93xx_ac97_dai_probe(struct snd_soc_dai *dai) static int ep93xx_ac97_dai_probe(struct snd_soc_dai *dai)
{ {
dai->playback_dma_data = &ep93xx_ac97_pcm_out; struct ep93xx_ac97_info *info = snd_soc_dai_get_drvdata(dai);
dai->capture_dma_data = &ep93xx_ac97_pcm_in;
info->dma_params_tx.filter_data = &ep93xx_ac97_pcm_out;
info->dma_params_rx.filter_data = &ep93xx_ac97_pcm_in;
dai->playback_dma_data = &info->dma_params_tx;
dai->capture_dma_data = &info->dma_params_rx;
return 0; return 0;
} }
@ -394,8 +404,14 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
if (ret) if (ret)
goto fail; goto fail;
ret = devm_ep93xx_pcm_platform_register(&pdev->dev);
if (ret)
goto fail_unregister;
return 0; return 0;
fail_unregister:
snd_soc_unregister_component(&pdev->dev);
fail: fail:
ep93xx_ac97_info = NULL; ep93xx_ac97_info = NULL;
snd_soc_set_ac97_ops(NULL); snd_soc_set_ac97_ops(NULL);

View File

@ -21,6 +21,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/dmaengine_pcm.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <sound/initval.h> #include <sound/initval.h>
@ -30,6 +31,8 @@
#include <mach/ep93xx-regs.h> #include <mach/ep93xx-regs.h>
#include <linux/platform_data/dma-ep93xx.h> #include <linux/platform_data/dma-ep93xx.h>
#include "ep93xx-pcm.h"
#define EP93XX_I2S_TXCLKCFG 0x00 #define EP93XX_I2S_TXCLKCFG 0x00
#define EP93XX_I2S_RXCLKCFG 0x04 #define EP93XX_I2S_RXCLKCFG 0x04
#define EP93XX_I2S_GLCTRL 0x0C #define EP93XX_I2S_GLCTRL 0x0C
@ -61,6 +64,8 @@ struct ep93xx_i2s_info {
struct clk *sclk; struct clk *sclk;
struct clk *lrclk; struct clk *lrclk;
void __iomem *regs; void __iomem *regs;
struct snd_dmaengine_dai_dma_data dma_params_rx;
struct snd_dmaengine_dai_dma_data dma_params_tx;
}; };
static struct ep93xx_dma_data ep93xx_i2s_dma_data[] = { static struct ep93xx_dma_data ep93xx_i2s_dma_data[] = {
@ -140,8 +145,15 @@ static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
static int ep93xx_i2s_dai_probe(struct snd_soc_dai *dai) static int ep93xx_i2s_dai_probe(struct snd_soc_dai *dai)
{ {
dai->playback_dma_data = &ep93xx_i2s_dma_data[SNDRV_PCM_STREAM_PLAYBACK]; struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
dai->capture_dma_data = &ep93xx_i2s_dma_data[SNDRV_PCM_STREAM_CAPTURE];
info->dma_params_tx.filter_data =
&ep93xx_i2s_dma_data[SNDRV_PCM_STREAM_PLAYBACK];
info->dma_params_rx.filter_data =
&ep93xx_i2s_dma_data[SNDRV_PCM_STREAM_CAPTURE];
dai->playback_dma_data = &info->dma_params_tx;
dai->capture_dma_data = &info->dma_params_rx;
return 0; return 0;
} }
@ -405,8 +417,14 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
if (err) if (err)
goto fail_put_lrclk; goto fail_put_lrclk;
err = devm_ep93xx_pcm_platform_register(&pdev->dev);
if (err)
goto fail_unregister;
return 0; return 0;
fail_unregister:
snd_soc_unregister_component(&pdev->dev);
fail_put_lrclk: fail_put_lrclk:
clk_put(info->lrclk); clk_put(info->lrclk);
fail_put_sclk: fail_put_sclk:

View File

@ -23,20 +23,13 @@
#include <linux/platform_data/dma-ep93xx.h> #include <linux/platform_data/dma-ep93xx.h>
#include "ep93xx-pcm.h"
static const struct snd_pcm_hardware ep93xx_pcm_hardware = { static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
.info = (SNDRV_PCM_INFO_MMAP | .info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER), SNDRV_PCM_INFO_BLOCK_TRANSFER),
.rates = SNDRV_PCM_RATE_8000_192000,
.rate_min = SNDRV_PCM_RATE_8000,
.rate_max = SNDRV_PCM_RATE_192000,
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE),
.buffer_bytes_max = 131072, .buffer_bytes_max = 131072,
.period_bytes_min = 32, .period_bytes_min = 32,
.period_bytes_max = 32768, .period_bytes_max = 32768,
@ -57,53 +50,22 @@ static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param)
return false; return false;
} }
static struct dma_chan *ep93xx_compat_request_channel(
struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_substream *substream)
{
struct snd_dmaengine_dai_dma_data *dma_data;
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
return snd_dmaengine_pcm_request_channel(ep93xx_pcm_dma_filter,
dma_data);
}
static const struct snd_dmaengine_pcm_config ep93xx_dmaengine_pcm_config = { static const struct snd_dmaengine_pcm_config ep93xx_dmaengine_pcm_config = {
.pcm_hardware = &ep93xx_pcm_hardware, .pcm_hardware = &ep93xx_pcm_hardware,
.compat_filter_fn = ep93xx_pcm_dma_filter, .compat_filter_fn = ep93xx_pcm_dma_filter,
.compat_request_channel = ep93xx_compat_request_channel,
.prealloc_buffer_size = 131072, .prealloc_buffer_size = 131072,
}; };
static int ep93xx_soc_platform_probe(struct platform_device *pdev) int devm_ep93xx_pcm_platform_register(struct device *dev)
{ {
return snd_dmaengine_pcm_register(&pdev->dev, return devm_snd_dmaengine_pcm_register(dev,
&ep93xx_dmaengine_pcm_config, &ep93xx_dmaengine_pcm_config,
SND_DMAENGINE_PCM_FLAG_NO_RESIDUE | SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
SND_DMAENGINE_PCM_FLAG_NO_DT | SND_DMAENGINE_PCM_FLAG_NO_DT |
SND_DMAENGINE_PCM_FLAG_COMPAT); SND_DMAENGINE_PCM_FLAG_COMPAT);
} }
EXPORT_SYMBOL_GPL(devm_ep93xx_pcm_platform_register);
static int ep93xx_soc_platform_remove(struct platform_device *pdev)
{
snd_dmaengine_pcm_unregister(&pdev->dev);
return 0;
}
static struct platform_driver ep93xx_pcm_driver = {
.driver = {
.name = "ep93xx-pcm-audio",
.owner = THIS_MODULE,
},
.probe = ep93xx_soc_platform_probe,
.remove = ep93xx_soc_platform_remove,
};
module_platform_driver(ep93xx_pcm_driver);
MODULE_AUTHOR("Ryan Mallon"); MODULE_AUTHOR("Ryan Mallon");
MODULE_DESCRIPTION("EP93xx ALSA PCM interface"); MODULE_DESCRIPTION("EP93xx ALSA PCM interface");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:ep93xx-pcm-audio");

View File

@ -0,0 +1,22 @@
/*
* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __EP93XX_PCM_H__
#define __EP93XX_PCM_H__
int devm_ep93xx_pcm_platform_register(struct device *dev);
#endif

View File

@ -27,7 +27,7 @@ static struct snd_soc_dai_link simone_dai = {
.cpu_dai_name = "ep93xx-ac97", .cpu_dai_name = "ep93xx-ac97",
.codec_dai_name = "ac97-hifi", .codec_dai_name = "ac97-hifi",
.codec_name = "ac97-codec", .codec_name = "ac97-codec",
.platform_name = "ep93xx-pcm-audio", .platform_name = "ep93xx-ac97",
}; };
static struct snd_soc_card snd_soc_simone = { static struct snd_soc_card snd_soc_simone = {

View File

@ -83,7 +83,7 @@ static struct snd_soc_dai_link snappercl15_dai = {
.cpu_dai_name = "ep93xx-i2s", .cpu_dai_name = "ep93xx-i2s",
.codec_dai_name = "tlv320aic23-hifi", .codec_dai_name = "tlv320aic23-hifi",
.codec_name = "tlv320aic23-codec.0-001a", .codec_name = "tlv320aic23-codec.0-001a",
.platform_name = "ep93xx-pcm-audio", .platform_name = "ep93xx-i2s",
.init = snappercl15_tlv320aic23_init, .init = snappercl15_tlv320aic23_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAIFMT_CBS_CFS,

View File

@ -163,8 +163,10 @@ config SND_SOC_WM_HUBS
config SND_SOC_WM_ADSP config SND_SOC_WM_ADSP
tristate tristate
default y if SND_SOC_WM5102=y default y if SND_SOC_WM5102=y
default y if SND_SOC_WM5110=y
default y if SND_SOC_WM2200=y default y if SND_SOC_WM2200=y
default m if SND_SOC_WM5102=m default m if SND_SOC_WM5102=m
default m if SND_SOC_WM5110=m
default m if SND_SOC_WM2200=m default m if SND_SOC_WM2200=m
config SND_SOC_AB8500_CODEC config SND_SOC_AB8500_CODEC

View File

@ -179,6 +179,8 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
case SNDRV_PCM_FORMAT_S32_LE: case SNDRV_PCM_FORMAT_S32_LE:
word_len = AD1836_WORD_LEN_24; word_len = AD1836_WORD_LEN_24;
break; break;
default:
return -EINVAL;
} }
regmap_update_bits(ad1836->regmap, AD1836_DAC_CTRL1, regmap_update_bits(ad1836->regmap, AD1836_DAC_CTRL1,

View File

@ -413,7 +413,7 @@ static struct spi_driver ad193x_spi_driver = {
}; };
#endif #endif
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static const struct regmap_config ad193x_i2c_regmap_config = { static const struct regmap_config ad193x_i2c_regmap_config = {
.val_bits = 8, .val_bits = 8,
@ -470,7 +470,7 @@ static int __init ad193x_modinit(void)
{ {
int ret; int ret;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&ad193x_i2c_driver); ret = i2c_add_driver(&ad193x_i2c_driver);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR "Failed to register AD193X I2C driver: %d\n", printk(KERN_ERR "Failed to register AD193X I2C driver: %d\n",
@ -495,7 +495,7 @@ static void __exit ad193x_modexit(void)
spi_unregister_driver(&ad193x_spi_driver); spi_unregister_driver(&ad193x_spi_driver);
#endif #endif
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&ad193x_i2c_driver); i2c_del_driver(&ad193x_i2c_driver);
#endif #endif
} }

View File

@ -939,7 +939,7 @@ static struct spi_driver adav80x_spi_driver = {
}; };
#endif #endif
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static const struct regmap_config adav80x_i2c_regmap_config = { static const struct regmap_config adav80x_i2c_regmap_config = {
.val_bits = 8, .val_bits = 8,
.pad_bits = 1, .pad_bits = 1,
@ -985,7 +985,7 @@ static int __init adav80x_init(void)
{ {
int ret = 0; int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&adav80x_i2c_driver); ret = i2c_add_driver(&adav80x_i2c_driver);
if (ret) if (ret)
return ret; return ret;
@ -1001,7 +1001,7 @@ module_init(adav80x_init);
static void __exit adav80x_exit(void) static void __exit adav80x_exit(void)
{ {
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&adav80x_i2c_driver); i2c_del_driver(&adav80x_i2c_driver);
#endif #endif
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)

View File

@ -17,6 +17,7 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
@ -30,6 +31,7 @@
/* codec private data */ /* codec private data */
struct ak4641_priv { struct ak4641_priv {
struct regmap *regmap;
unsigned int sysclk; unsigned int sysclk;
int deemph; int deemph;
int playback_fs; int playback_fs;
@ -38,12 +40,12 @@ struct ak4641_priv {
/* /*
* ak4641 register cache * ak4641 register cache
*/ */
static const u8 ak4641_reg[AK4641_CACHEREGNUM] = { static const struct reg_default ak4641_reg_defaults[] = {
0x00, 0x80, 0x00, 0x80, { 0, 0x00 }, { 1, 0x80 }, { 2, 0x00 }, { 3, 0x80 },
0x02, 0x00, 0x11, 0x05, { 4, 0x02 }, { 5, 0x00 }, { 6, 0x11 }, { 7, 0x05 },
0x00, 0x00, 0x36, 0x10, { 8, 0x00 }, { 9, 0x00 }, { 10, 0x36 }, { 11, 0x10 },
0x00, 0x00, 0x57, 0x00, { 12, 0x00 }, { 13, 0x00 }, { 14, 0x57 }, { 15, 0x00 },
0x88, 0x88, 0x08, 0x08 { 16, 0x88 }, { 17, 0x88 }, { 18, 0x08 }, { 19, 0x08 }
}; };
static const int deemph_settings[] = {44100, 0, 48000, 32000}; static const int deemph_settings[] = {44100, 0, 48000, 32000};
@ -396,6 +398,7 @@ static int ak4641_mute(struct snd_soc_dai *dai, int mute)
static int ak4641_set_bias_level(struct snd_soc_codec *codec, static int ak4641_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
struct ak4641_platform_data *pdata = codec->dev->platform_data; struct ak4641_platform_data *pdata = codec->dev->platform_data;
int ret; int ret;
@ -417,7 +420,7 @@ static int ak4641_set_bias_level(struct snd_soc_codec *codec,
gpio_set_value(pdata->gpio_npdn, 1); gpio_set_value(pdata->gpio_npdn, 1);
mdelay(1); mdelay(1);
ret = snd_soc_cache_sync(codec); ret = regcache_sync(ak4641->regmap);
if (ret) { if (ret) {
dev_err(codec->dev, dev_err(codec->dev,
"Failed to sync cache: %d\n", ret); "Failed to sync cache: %d\n", ret);
@ -433,7 +436,7 @@ static int ak4641_set_bias_level(struct snd_soc_codec *codec,
gpio_set_value(pdata->gpio_npdn, 0); gpio_set_value(pdata->gpio_npdn, 0);
if (pdata && gpio_is_valid(pdata->gpio_power)) if (pdata && gpio_is_valid(pdata->gpio_power))
gpio_set_value(pdata->gpio_power, 0); gpio_set_value(pdata->gpio_power, 0);
codec->cache_sync = 1; regcache_mark_dirty(ak4641->regmap);
break; break;
} }
codec->dapm.bias_level = level; codec->dapm.bias_level = level;
@ -518,7 +521,7 @@ static int ak4641_probe(struct snd_soc_codec *codec)
{ {
int ret; int ret;
ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
if (ret != 0) { if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret; return ret;
@ -550,12 +553,17 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
.dapm_routes = ak4641_audio_map, .dapm_routes = ak4641_audio_map,
.num_dapm_routes = ARRAY_SIZE(ak4641_audio_map), .num_dapm_routes = ARRAY_SIZE(ak4641_audio_map),
.set_bias_level = ak4641_set_bias_level, .set_bias_level = ak4641_set_bias_level,
.reg_cache_size = ARRAY_SIZE(ak4641_reg),
.reg_word_size = sizeof(u8),
.reg_cache_default = ak4641_reg,
.reg_cache_step = 1,
}; };
static const struct regmap_config ak4641_regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = AK4641_BTIF,
.reg_defaults = ak4641_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(ak4641_reg_defaults),
.cache_type = REGCACHE_RBTREE,
};
static int ak4641_i2c_probe(struct i2c_client *i2c, static int ak4641_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
@ -569,6 +577,10 @@ static int ak4641_i2c_probe(struct i2c_client *i2c,
if (!ak4641) if (!ak4641)
return -ENOMEM; return -ENOMEM;
ak4641->regmap = devm_regmap_init_i2c(i2c, &ak4641_regmap);
if (IS_ERR(ak4641->regmap))
return PTR_ERR(ak4641->regmap);
if (pdata) { if (pdata) {
if (gpio_is_valid(pdata->gpio_power)) { if (gpio_is_valid(pdata->gpio_power)) {
ret = gpio_request_one(pdata->gpio_power, ret = gpio_request_one(pdata->gpio_power,

View File

@ -28,6 +28,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/regmap.h>
#include <sound/soc.h> #include <sound/soc.h>
#include <sound/initval.h> #include <sound/initval.h>
#include <sound/tlv.h> #include <sound/tlv.h>
@ -198,30 +199,30 @@ static const struct snd_soc_dapm_route ak4642_intercon[] = {
/* /*
* ak4642 register cache * ak4642 register cache
*/ */
static const u8 ak4642_reg[] = { static const struct reg_default ak4642_reg[] = {
0x00, 0x00, 0x01, 0x00, { 0, 0x00 }, { 1, 0x00 }, { 2, 0x01 }, { 3, 0x00 },
0x02, 0x00, 0x00, 0x00, { 4, 0x02 }, { 5, 0x00 }, { 6, 0x00 }, { 7, 0x00 },
0xe1, 0xe1, 0x18, 0x00, { 8, 0xe1 }, { 9, 0xe1 }, { 10, 0x18 }, { 11, 0x00 },
0xe1, 0x18, 0x11, 0x08, { 12, 0xe1 }, { 13, 0x18 }, { 14, 0x11 }, { 15, 0x08 },
0x00, 0x00, 0x00, 0x00, { 16, 0x00 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x00 },
0x00, 0x00, 0x00, 0x00, { 20, 0x00 }, { 21, 0x00 }, { 22, 0x00 }, { 23, 0x00 },
0x00, 0x00, 0x00, 0x00, { 24, 0x00 }, { 25, 0x00 }, { 26, 0x00 }, { 27, 0x00 },
0x00, 0x00, 0x00, 0x00, { 28, 0x00 }, { 29, 0x00 }, { 30, 0x00 }, { 31, 0x00 },
0x00, 0x00, 0x00, 0x00, { 32, 0x00 }, { 33, 0x00 }, { 34, 0x00 }, { 35, 0x00 },
0x00, { 36, 0x00 },
}; };
static const u8 ak4648_reg[] = { static const struct reg_default ak4648_reg[] = {
0x00, 0x00, 0x01, 0x00, { 0, 0x00 }, { 1, 0x00 }, { 2, 0x01 }, { 3, 0x00 },
0x02, 0x00, 0x00, 0x00, { 4, 0x02 }, { 5, 0x00 }, { 6, 0x00 }, { 7, 0x00 },
0xe1, 0xe1, 0x18, 0x00, { 8, 0xe1 }, { 9, 0xe1 }, { 10, 0x18 }, { 11, 0x00 },
0xe1, 0x18, 0x11, 0xb8, { 12, 0xe1 }, { 13, 0x18 }, { 14, 0x11 }, { 15, 0xb8 },
0x00, 0x00, 0x00, 0x00, { 16, 0x00 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x00 },
0x00, 0x00, 0x00, 0x00, { 20, 0x00 }, { 21, 0x00 }, { 22, 0x00 }, { 23, 0x00 },
0x00, 0x00, 0x00, 0x00, { 24, 0x00 }, { 25, 0x00 }, { 26, 0x00 }, { 27, 0x00 },
0x00, 0x00, 0x00, 0x00, { 28, 0x00 }, { 29, 0x00 }, { 30, 0x00 }, { 31, 0x00 },
0x00, 0x00, 0x00, 0x00, { 32, 0x00 }, { 33, 0x00 }, { 34, 0x00 }, { 35, 0x00 },
0x00, 0x88, 0x88, 0x08, { 36, 0x00 }, { 37, 0x88 }, { 38, 0x88 }, { 39, 0x08 },
}; };
static int ak4642_dai_startup(struct snd_pcm_substream *substream, static int ak4642_dai_startup(struct snd_pcm_substream *substream,
@ -454,7 +455,10 @@ static struct snd_soc_dai_driver ak4642_dai = {
static int ak4642_resume(struct snd_soc_codec *codec) static int ak4642_resume(struct snd_soc_codec *codec)
{ {
snd_soc_cache_sync(codec); struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
regcache_mark_dirty(regmap);
regcache_sync(regmap);
return 0; return 0;
} }
@ -463,15 +467,12 @@ static int ak4642_probe(struct snd_soc_codec *codec)
{ {
int ret; int ret;
ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
if (ret < 0) { if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret; return ret;
} }
snd_soc_add_codec_controls(codec, ak4642_snd_controls,
ARRAY_SIZE(ak4642_snd_controls));
ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY); ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0; return 0;
@ -488,55 +489,59 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
.remove = ak4642_remove, .remove = ak4642_remove,
.resume = ak4642_resume, .resume = ak4642_resume,
.set_bias_level = ak4642_set_bias_level, .set_bias_level = ak4642_set_bias_level,
.reg_cache_default = ak4642_reg, /* ak4642 reg */ .controls = ak4642_snd_controls,
.reg_cache_size = ARRAY_SIZE(ak4642_reg), /* ak4642 reg */ .num_controls = ARRAY_SIZE(ak4642_snd_controls),
.reg_word_size = sizeof(u8),
.dapm_widgets = ak4642_dapm_widgets, .dapm_widgets = ak4642_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(ak4642_dapm_widgets), .num_dapm_widgets = ARRAY_SIZE(ak4642_dapm_widgets),
.dapm_routes = ak4642_intercon, .dapm_routes = ak4642_intercon,
.num_dapm_routes = ARRAY_SIZE(ak4642_intercon), .num_dapm_routes = ARRAY_SIZE(ak4642_intercon),
}; };
static struct snd_soc_codec_driver soc_codec_dev_ak4648 = { static const struct regmap_config ak4642_regmap = {
.probe = ak4642_probe, .reg_bits = 8,
.remove = ak4642_remove, .val_bits = 8,
.resume = ak4642_resume, .max_register = ARRAY_SIZE(ak4642_reg) + 1,
.set_bias_level = ak4642_set_bias_level, .reg_defaults = ak4642_reg,
.reg_cache_default = ak4648_reg, /* ak4648 reg */ .num_reg_defaults = ARRAY_SIZE(ak4642_reg),
.reg_cache_size = ARRAY_SIZE(ak4648_reg), /* ak4648 reg */ };
.reg_word_size = sizeof(u8),
.dapm_widgets = ak4642_dapm_widgets, static const struct regmap_config ak4648_regmap = {
.num_dapm_widgets = ARRAY_SIZE(ak4642_dapm_widgets), .reg_bits = 8,
.dapm_routes = ak4642_intercon, .val_bits = 8,
.num_dapm_routes = ARRAY_SIZE(ak4642_intercon), .max_register = ARRAY_SIZE(ak4648_reg) + 1,
.reg_defaults = ak4648_reg,
.num_reg_defaults = ARRAY_SIZE(ak4648_reg),
}; };
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static struct of_device_id ak4642_of_match[]; static struct of_device_id ak4642_of_match[];
static int ak4642_i2c_probe(struct i2c_client *i2c, static int ak4642_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct device_node *np = i2c->dev.of_node; struct device_node *np = i2c->dev.of_node;
const struct snd_soc_codec_driver *driver; const struct regmap_config *regmap_config = NULL;
struct regmap *regmap;
driver = NULL;
if (np) { if (np) {
const struct of_device_id *of_id; const struct of_device_id *of_id;
of_id = of_match_device(ak4642_of_match, &i2c->dev); of_id = of_match_device(ak4642_of_match, &i2c->dev);
if (of_id) if (of_id)
driver = of_id->data; regmap_config = of_id->data;
} else { } else {
driver = (struct snd_soc_codec_driver *)id->driver_data; regmap_config = (const struct regmap_config *)id->driver_data;
} }
if (!driver) { if (!regmap_config) {
dev_err(&i2c->dev, "no driver\n"); dev_err(&i2c->dev, "Unknown device type\n");
return -EINVAL; return -EINVAL;
} }
regmap = devm_regmap_init_i2c(i2c, regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
return snd_soc_register_codec(&i2c->dev, return snd_soc_register_codec(&i2c->dev,
driver, &ak4642_dai, 1); &soc_codec_dev_ak4642, &ak4642_dai, 1);
} }
static int ak4642_i2c_remove(struct i2c_client *client) static int ak4642_i2c_remove(struct i2c_client *client)
@ -546,17 +551,17 @@ static int ak4642_i2c_remove(struct i2c_client *client)
} }
static struct of_device_id ak4642_of_match[] = { static struct of_device_id ak4642_of_match[] = {
{ .compatible = "asahi-kasei,ak4642", .data = &soc_codec_dev_ak4642}, { .compatible = "asahi-kasei,ak4642", .data = &ak4642_regmap},
{ .compatible = "asahi-kasei,ak4643", .data = &soc_codec_dev_ak4642}, { .compatible = "asahi-kasei,ak4643", .data = &ak4642_regmap},
{ .compatible = "asahi-kasei,ak4648", .data = &soc_codec_dev_ak4648}, { .compatible = "asahi-kasei,ak4648", .data = &ak4648_regmap},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, ak4642_of_match); MODULE_DEVICE_TABLE(of, ak4642_of_match);
static const struct i2c_device_id ak4642_i2c_id[] = { static const struct i2c_device_id ak4642_i2c_id[] = {
{ "ak4642", (kernel_ulong_t)&soc_codec_dev_ak4642 }, { "ak4642", (kernel_ulong_t)&ak4642_regmap },
{ "ak4643", (kernel_ulong_t)&soc_codec_dev_ak4642 }, { "ak4643", (kernel_ulong_t)&ak4642_regmap },
{ "ak4648", (kernel_ulong_t)&soc_codec_dev_ak4648 }, { "ak4648", (kernel_ulong_t)&ak4648_regmap },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id); MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
@ -571,27 +576,8 @@ static struct i2c_driver ak4642_i2c_driver = {
.remove = ak4642_i2c_remove, .remove = ak4642_i2c_remove,
.id_table = ak4642_i2c_id, .id_table = ak4642_i2c_id,
}; };
#endif
static int __init ak4642_modinit(void) module_i2c_driver(ak4642_i2c_driver);
{
int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&ak4642_i2c_driver);
#endif
return ret;
}
module_init(ak4642_modinit);
static void __exit ak4642_exit(void)
{
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&ak4642_i2c_driver);
#endif
}
module_exit(ak4642_exit);
MODULE_DESCRIPTION("Soc AK4642 driver"); MODULE_DESCRIPTION("Soc AK4642 driver");
MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>"); MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");

View File

@ -93,7 +93,7 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
switch (event) { switch (event) {
case SND_SOC_DAPM_PRE_PMU: case SND_SOC_DAPM_PRE_PMU:
if (!priv->spk_ena && manual_ena) { if (!priv->spk_ena && manual_ena) {
snd_soc_write(codec, 0x4f5, 0x25a); regmap_write_async(arizona->regmap, 0x4f5, 0x25a);
priv->spk_ena_pending = true; priv->spk_ena_pending = true;
} }
break; break;
@ -105,12 +105,13 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
return -EBUSY; return -EBUSY;
} }
snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1, regmap_update_bits_async(arizona->regmap,
1 << w->shift, 1 << w->shift); ARIZONA_OUTPUT_ENABLES_1,
1 << w->shift, 1 << w->shift);
if (priv->spk_ena_pending) { if (priv->spk_ena_pending) {
msleep(75); msleep(75);
snd_soc_write(codec, 0x4f5, 0xda); regmap_write_async(arizona->regmap, 0x4f5, 0xda);
priv->spk_ena_pending = false; priv->spk_ena_pending = false;
priv->spk_ena++; priv->spk_ena++;
} }
@ -119,16 +120,19 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
if (manual_ena) { if (manual_ena) {
priv->spk_ena--; priv->spk_ena--;
if (!priv->spk_ena) if (!priv->spk_ena)
snd_soc_write(codec, 0x4f5, 0x25a); regmap_write_async(arizona->regmap,
0x4f5, 0x25a);
} }
snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1, regmap_update_bits_async(arizona->regmap,
1 << w->shift, 0); ARIZONA_OUTPUT_ENABLES_1,
1 << w->shift, 0);
break; break;
case SND_SOC_DAPM_POST_PMD: case SND_SOC_DAPM_POST_PMD:
if (manual_ena) { if (manual_ena) {
if (!priv->spk_ena) if (!priv->spk_ena)
snd_soc_write(codec, 0x4f5, 0x0da); regmap_write_async(arizona->regmap,
0x4f5, 0x0da);
} }
break; break;
} }
@ -292,6 +296,10 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
"AIF1RX8", "AIF1RX8",
"AIF2RX1", "AIF2RX1",
"AIF2RX2", "AIF2RX2",
"AIF2RX3",
"AIF2RX4",
"AIF2RX5",
"AIF2RX6",
"AIF3RX1", "AIF3RX1",
"AIF3RX2", "AIF3RX2",
"SLIMRX1", "SLIMRX1",
@ -395,6 +403,10 @@ int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
0x27, 0x27,
0x28, /* AIF2RX1 */ 0x28, /* AIF2RX1 */
0x29, 0x29,
0x2a,
0x2b,
0x2c,
0x2d,
0x30, /* AIF3RX1 */ 0x30, /* AIF3RX1 */
0x31, 0x31,
0x38, /* SLIMRX1 */ 0x38, /* SLIMRX1 */
@ -486,6 +498,22 @@ const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
EXPORT_SYMBOL_GPL(arizona_rate_val); EXPORT_SYMBOL_GPL(arizona_rate_val);
const struct soc_enum arizona_isrc_fsh[] = {
SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
ARIZONA_ISRC1_FSH_SHIFT, 0xf,
ARIZONA_RATE_ENUM_SIZE,
arizona_rate_text, arizona_rate_val),
SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1,
ARIZONA_ISRC2_FSH_SHIFT, 0xf,
ARIZONA_RATE_ENUM_SIZE,
arizona_rate_text, arizona_rate_val),
SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1,
ARIZONA_ISRC3_FSH_SHIFT, 0xf,
ARIZONA_RATE_ENUM_SIZE,
arizona_rate_text, arizona_rate_val),
};
EXPORT_SYMBOL_GPL(arizona_isrc_fsh);
const struct soc_enum arizona_isrc_fsl[] = { const struct soc_enum arizona_isrc_fsl[] = {
SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2, SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
ARIZONA_ISRC1_FSL_SHIFT, 0xf, ARIZONA_ISRC1_FSL_SHIFT, 0xf,
@ -502,6 +530,13 @@ const struct soc_enum arizona_isrc_fsl[] = {
}; };
EXPORT_SYMBOL_GPL(arizona_isrc_fsl); EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
const struct soc_enum arizona_asrc_rate1 =
SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1,
ARIZONA_ASRC_RATE1_SHIFT, 0xf,
ARIZONA_RATE_ENUM_SIZE - 1,
arizona_rate_text, arizona_rate_val);
EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
static const char *arizona_vol_ramp_text[] = { static const char *arizona_vol_ramp_text[] = {
"0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB", "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
"15ms/6dB", "30ms/6dB", "15ms/6dB", "30ms/6dB",
@ -560,6 +595,16 @@ const struct soc_enum arizona_ng_hold =
4, arizona_ng_hold_text); 4, arizona_ng_hold_text);
EXPORT_SYMBOL_GPL(arizona_ng_hold); EXPORT_SYMBOL_GPL(arizona_ng_hold);
static const char * const arizona_in_hpf_cut_text[] = {
"2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
};
const struct soc_enum arizona_in_hpf_cut_enum =
SOC_ENUM_SINGLE(ARIZONA_HPF_CONTROL, ARIZONA_IN_HPF_CUT_SHIFT,
ARRAY_SIZE(arizona_in_hpf_cut_text),
arizona_in_hpf_cut_text);
EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
static const char * const arizona_in_dmic_osr_text[] = { static const char * const arizona_in_dmic_osr_text[] = {
"1.536MHz", "3.072MHz", "6.144MHz", "1.536MHz", "3.072MHz", "6.144MHz",
}; };
@ -669,6 +714,7 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,
int event) int event)
{ {
struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec); struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
struct arizona *arizona = priv->arizona;
unsigned int mask = 1 << w->shift; unsigned int mask = 1 << w->shift;
unsigned int val; unsigned int val;
@ -691,7 +737,8 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,
if (priv->arizona->hpdet_magic) if (priv->arizona->hpdet_magic)
val = 0; val = 0;
snd_soc_update_bits(w->codec, ARIZONA_OUTPUT_ENABLES_1, mask, val); regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
mask, val);
return arizona_out_ev(w, kcontrol, event); return arizona_out_ev(w, kcontrol, event);
} }
@ -846,6 +893,8 @@ EXPORT_SYMBOL_GPL(arizona_set_sysclk);
static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->arizona;
int lrclk, bclk, mode, base; int lrclk, bclk, mode, base;
base = dai->driver->base; base = dai->driver->base;
@ -902,17 +951,19 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL; return -EINVAL;
} }
snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL, regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR, ARIZONA_AIF1_BCLK_INV |
bclk); ARIZONA_AIF1_BCLK_MSTR,
snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL, bclk);
ARIZONA_AIF1TX_LRCLK_INV | regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
ARIZONA_AIF1TX_LRCLK_MSTR, lrclk); ARIZONA_AIF1TX_LRCLK_INV |
snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL, ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
ARIZONA_AIF1RX_LRCLK_INV | regmap_update_bits_async(arizona->regmap,
ARIZONA_AIF1RX_LRCLK_MSTR, lrclk); base + ARIZONA_AIF_RX_PIN_CTRL,
snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT, ARIZONA_AIF1RX_LRCLK_INV |
ARIZONA_AIF1_FMT_MASK, mode); ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
ARIZONA_AIF1_FMT_MASK, mode);
return 0; return 0;
} }
@ -1164,18 +1215,22 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
if (ret != 0) if (ret != 0)
return ret; return ret;
snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL, regmap_update_bits_async(arizona->regmap,
ARIZONA_AIF1_BCLK_FREQ_MASK, bclk); base + ARIZONA_AIF_BCLK_CTRL,
snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE, ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
ARIZONA_AIF1TX_BCPF_MASK, lrclk); regmap_update_bits_async(arizona->regmap,
snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE, base + ARIZONA_AIF_TX_BCLK_RATE,
ARIZONA_AIF1RX_BCPF_MASK, lrclk); ARIZONA_AIF1TX_BCPF_MASK, lrclk);
snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1, regmap_update_bits_async(arizona->regmap,
ARIZONA_AIF1TX_WL_MASK | base + ARIZONA_AIF_RX_BCLK_RATE,
ARIZONA_AIF1TX_SLOT_LEN_MASK, frame); ARIZONA_AIF1RX_BCPF_MASK, lrclk);
snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2, regmap_update_bits_async(arizona->regmap,
ARIZONA_AIF1RX_WL_MASK | base + ARIZONA_AIF_FRAME_CTRL_1,
ARIZONA_AIF1RX_SLOT_LEN_MASK, frame); ARIZONA_AIF1TX_WL_MASK |
ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FRAME_CTRL_2,
ARIZONA_AIF1RX_WL_MASK |
ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
return 0; return 0;
} }
@ -1428,31 +1483,31 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
struct arizona_fll_cfg *cfg, int source, struct arizona_fll_cfg *cfg, int source,
bool sync) bool sync)
{ {
regmap_update_bits(arizona->regmap, base + 3, regmap_update_bits_async(arizona->regmap, base + 3,
ARIZONA_FLL1_THETA_MASK, cfg->theta); ARIZONA_FLL1_THETA_MASK, cfg->theta);
regmap_update_bits(arizona->regmap, base + 4, regmap_update_bits_async(arizona->regmap, base + 4,
ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda); ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
regmap_update_bits(arizona->regmap, base + 5, regmap_update_bits_async(arizona->regmap, base + 5,
ARIZONA_FLL1_FRATIO_MASK, ARIZONA_FLL1_FRATIO_MASK,
cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT); cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
regmap_update_bits(arizona->regmap, base + 6, regmap_update_bits_async(arizona->regmap, base + 6,
ARIZONA_FLL1_CLK_REF_DIV_MASK | ARIZONA_FLL1_CLK_REF_DIV_MASK |
ARIZONA_FLL1_CLK_REF_SRC_MASK, ARIZONA_FLL1_CLK_REF_SRC_MASK,
cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT | cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT); source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
if (sync) if (sync)
regmap_update_bits(arizona->regmap, base + 0x7, regmap_update_bits_async(arizona->regmap, base + 0x7,
ARIZONA_FLL1_GAIN_MASK, ARIZONA_FLL1_GAIN_MASK,
cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
else else
regmap_update_bits(arizona->regmap, base + 0x9, regmap_update_bits_async(arizona->regmap, base + 0x9,
ARIZONA_FLL1_GAIN_MASK, ARIZONA_FLL1_GAIN_MASK,
cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
regmap_update_bits(arizona->regmap, base + 2, regmap_update_bits_async(arizona->regmap, base + 2,
ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK, ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
ARIZONA_FLL1_CTRL_UPD | cfg->n); ARIZONA_FLL1_CTRL_UPD | cfg->n);
} }
static bool arizona_is_enabled_fll(struct arizona_fll *fll) static bool arizona_is_enabled_fll(struct arizona_fll *fll)
@ -1485,9 +1540,9 @@ static void arizona_enable_fll(struct arizona_fll *fll,
*/ */
if (fll->ref_src >= 0 && fll->ref_freq && if (fll->ref_src >= 0 && fll->ref_freq &&
fll->ref_src != fll->sync_src) { fll->ref_src != fll->sync_src) {
regmap_update_bits(arizona->regmap, fll->base + 5, regmap_update_bits_async(arizona->regmap, fll->base + 5,
ARIZONA_FLL1_OUTDIV_MASK, ARIZONA_FLL1_OUTDIV_MASK,
ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
arizona_apply_fll(arizona, fll->base, ref, fll->ref_src, arizona_apply_fll(arizona, fll->base, ref, fll->ref_src,
false); false);
@ -1497,15 +1552,15 @@ static void arizona_enable_fll(struct arizona_fll *fll,
use_sync = true; use_sync = true;
} }
} else if (fll->sync_src >= 0) { } else if (fll->sync_src >= 0) {
regmap_update_bits(arizona->regmap, fll->base + 5, regmap_update_bits_async(arizona->regmap, fll->base + 5,
ARIZONA_FLL1_OUTDIV_MASK, ARIZONA_FLL1_OUTDIV_MASK,
sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
arizona_apply_fll(arizona, fll->base, sync, arizona_apply_fll(arizona, fll->base, sync,
fll->sync_src, false); fll->sync_src, false);
regmap_update_bits(arizona->regmap, fll->base + 0x11, regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
ARIZONA_FLL1_SYNC_ENA, 0); ARIZONA_FLL1_SYNC_ENA, 0);
} else { } else {
arizona_fll_err(fll, "No clocks provided\n"); arizona_fll_err(fll, "No clocks provided\n");
return; return;
@ -1516,11 +1571,12 @@ static void arizona_enable_fll(struct arizona_fll *fll,
* sync source. * sync source.
*/ */
if (use_sync && fll->sync_freq > 100000) if (use_sync && fll->sync_freq > 100000)
regmap_update_bits(arizona->regmap, fll->base + 0x17, regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
ARIZONA_FLL1_SYNC_BW, 0); ARIZONA_FLL1_SYNC_BW, 0);
else else
regmap_update_bits(arizona->regmap, fll->base + 0x17, regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
ARIZONA_FLL1_SYNC_BW, ARIZONA_FLL1_SYNC_BW); ARIZONA_FLL1_SYNC_BW,
ARIZONA_FLL1_SYNC_BW);
if (!arizona_is_enabled_fll(fll)) if (!arizona_is_enabled_fll(fll))
pm_runtime_get(arizona->dev); pm_runtime_get(arizona->dev);
@ -1528,14 +1584,14 @@ static void arizona_enable_fll(struct arizona_fll *fll,
/* Clear any pending completions */ /* Clear any pending completions */
try_wait_for_completion(&fll->ok); try_wait_for_completion(&fll->ok);
regmap_update_bits(arizona->regmap, fll->base + 1, regmap_update_bits_async(arizona->regmap, fll->base + 1,
ARIZONA_FLL1_FREERUN, 0); ARIZONA_FLL1_FREERUN, 0);
regmap_update_bits(arizona->regmap, fll->base + 1, regmap_update_bits_async(arizona->regmap, fll->base + 1,
ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
if (use_sync) if (use_sync)
regmap_update_bits(arizona->regmap, fll->base + 0x11, regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
ARIZONA_FLL1_SYNC_ENA, ARIZONA_FLL1_SYNC_ENA,
ARIZONA_FLL1_SYNC_ENA); ARIZONA_FLL1_SYNC_ENA);
ret = wait_for_completion_timeout(&fll->ok, ret = wait_for_completion_timeout(&fll->ok,
msecs_to_jiffies(250)); msecs_to_jiffies(250));
@ -1548,8 +1604,8 @@ static void arizona_disable_fll(struct arizona_fll *fll)
struct arizona *arizona = fll->arizona; struct arizona *arizona = fll->arizona;
bool change; bool change;
regmap_update_bits(arizona->regmap, fll->base + 1, regmap_update_bits_async(arizona->regmap, fll->base + 1,
ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN); ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
regmap_update_bits_check(arizona->regmap, fll->base + 1, regmap_update_bits_check(arizona->regmap, fll->base + 1,
ARIZONA_FLL1_ENA, 0, &change); ARIZONA_FLL1_ENA, 0, &change);
regmap_update_bits(arizona->regmap, fll->base + 0x11, regmap_update_bits(arizona->regmap, fll->base + 0x11,

View File

@ -81,7 +81,7 @@ struct arizona_priv {
unsigned int spk_ena_pending:1; unsigned int spk_ena_pending:1;
}; };
#define ARIZONA_NUM_MIXER_INPUTS 99 #define ARIZONA_NUM_MIXER_INPUTS 103
extern const unsigned int arizona_mixer_tlv[]; extern const unsigned int arizona_mixer_tlv[];
extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS]; extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];
@ -186,6 +186,8 @@ extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE]; extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
extern const struct soc_enum arizona_isrc_fsl[]; extern const struct soc_enum arizona_isrc_fsl[];
extern const struct soc_enum arizona_isrc_fsh[];
extern const struct soc_enum arizona_asrc_rate1;
extern const struct soc_enum arizona_in_vi_ramp; extern const struct soc_enum arizona_in_vi_ramp;
extern const struct soc_enum arizona_in_vd_ramp; extern const struct soc_enum arizona_in_vd_ramp;
@ -199,6 +201,7 @@ extern const struct soc_enum arizona_lhpf3_mode;
extern const struct soc_enum arizona_lhpf4_mode; extern const struct soc_enum arizona_lhpf4_mode;
extern const struct soc_enum arizona_ng_hold; extern const struct soc_enum arizona_ng_hold;
extern const struct soc_enum arizona_in_hpf_cut_enum;
extern const struct soc_enum arizona_in_dmic_osr[]; extern const struct soc_enum arizona_in_dmic_osr[];
extern int arizona_in_ev(struct snd_soc_dapm_widget *w, extern int arizona_in_ev(struct snd_soc_dapm_widget *w,

View File

@ -675,7 +675,7 @@ static struct spi_driver cs4271_spi_driver = {
}; };
#endif /* defined(CONFIG_SPI_MASTER) */ #endif /* defined(CONFIG_SPI_MASTER) */
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static const struct i2c_device_id cs4271_i2c_id[] = { static const struct i2c_device_id cs4271_i2c_id[] = {
{"cs4271", 0}, {"cs4271", 0},
{} {}
@ -728,7 +728,7 @@ static struct i2c_driver cs4271_i2c_driver = {
.probe = cs4271_i2c_probe, .probe = cs4271_i2c_probe,
.remove = cs4271_i2c_remove, .remove = cs4271_i2c_remove,
}; };
#endif /* defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) */ #endif /* IS_ENABLED(CONFIG_I2C) */
/* /*
* We only register our serial bus driver here without * We only register our serial bus driver here without
@ -741,7 +741,7 @@ static int __init cs4271_modinit(void)
{ {
int ret; int ret;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&cs4271_i2c_driver); ret = i2c_add_driver(&cs4271_i2c_driver);
if (ret) { if (ret) {
pr_err("Failed to register CS4271 I2C driver: %d\n", ret); pr_err("Failed to register CS4271 I2C driver: %d\n", ret);
@ -767,7 +767,7 @@ static void __exit cs4271_modexit(void)
spi_unregister_driver(&cs4271_spi_driver); spi_unregister_driver(&cs4271_spi_driver);
#endif #endif
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&cs4271_i2c_driver); i2c_del_driver(&cs4271_i2c_driver);
#endif #endif
} }

View File

@ -17,7 +17,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gpio.h> #include <linux/of_gpio.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/input.h> #include <linux/input.h>
@ -50,7 +50,7 @@ struct cs42l52_private {
u8 mclksel; u8 mclksel;
u32 mclk; u32 mclk;
u8 flags; u8 flags;
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) #if IS_ENABLED(CONFIG_INPUT)
struct input_dev *beep; struct input_dev *beep;
struct work_struct beep_work; struct work_struct beep_work;
int beep_rate; int beep_rate;
@ -233,7 +233,7 @@ static const struct soc_enum mic_bias_level_enum =
SOC_ENUM_SINGLE(CS42L52_IFACE_CTL2, 0, SOC_ENUM_SINGLE(CS42L52_IFACE_CTL2, 0,
ARRAY_SIZE(mic_bias_level_text), mic_bias_level_text); ARRAY_SIZE(mic_bias_level_text), mic_bias_level_text);
static const char * const cs42l52_mic_text[] = { "Single", "Differential" }; static const char * const cs42l52_mic_text[] = { "MIC1", "MIC2" };
static const struct soc_enum mica_enum = static const struct soc_enum mica_enum =
SOC_ENUM_SINGLE(CS42L52_MICA_CTL, 5, SOC_ENUM_SINGLE(CS42L52_MICA_CTL, 5,
@ -243,12 +243,6 @@ static const struct soc_enum micb_enum =
SOC_ENUM_SINGLE(CS42L52_MICB_CTL, 5, SOC_ENUM_SINGLE(CS42L52_MICB_CTL, 5,
ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text); ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text);
static const struct snd_kcontrol_new mica_mux =
SOC_DAPM_ENUM("Left Mic Input Capture Mux", mica_enum);
static const struct snd_kcontrol_new micb_mux =
SOC_DAPM_ENUM("Right Mic Input Capture Mux", micb_enum);
static const char * const digital_output_mux_text[] = {"ADC", "DSP"}; static const char * const digital_output_mux_text[] = {"ADC", "DSP"};
static const struct soc_enum digital_output_mux_enum = static const struct soc_enum digital_output_mux_enum =
@ -531,6 +525,30 @@ static const struct snd_kcontrol_new cs42l52_snd_controls[] = {
}; };
static const struct snd_kcontrol_new cs42l52_mica_controls[] = {
SOC_ENUM("MICA Select", mica_enum),
};
static const struct snd_kcontrol_new cs42l52_micb_controls[] = {
SOC_ENUM("MICB Select", micb_enum),
};
static int cs42l52_add_mic_controls(struct snd_soc_codec *codec)
{
struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
struct cs42l52_platform_data *pdata = &cs42l52->pdata;
if (!pdata->mica_diff_cfg)
snd_soc_add_codec_controls(codec, cs42l52_mica_controls,
ARRAY_SIZE(cs42l52_mica_controls));
if (!pdata->micb_diff_cfg)
snd_soc_add_codec_controls(codec, cs42l52_micb_controls,
ARRAY_SIZE(cs42l52_micb_controls));
return 0;
}
static const struct snd_soc_dapm_widget cs42l52_dapm_widgets[] = { static const struct snd_soc_dapm_widget cs42l52_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("AIN1L"), SND_SOC_DAPM_INPUT("AIN1L"),
@ -550,9 +568,6 @@ static const struct snd_soc_dapm_widget cs42l52_dapm_widgets[] = {
SND_SOC_DAPM_AIF_OUT("AIFOUTR", NULL, 0, SND_SOC_DAPM_AIF_OUT("AIFOUTR", NULL, 0,
SND_SOC_NOPM, 0, 0), SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_MUX("MICA Mux", SND_SOC_NOPM, 0, 0, &mica_mux),
SND_SOC_DAPM_MUX("MICB Mux", SND_SOC_NOPM, 0, 0, &micb_mux),
SND_SOC_DAPM_ADC("ADC Left", NULL, CS42L52_PWRCTL1, 1, 1), SND_SOC_DAPM_ADC("ADC Left", NULL, CS42L52_PWRCTL1, 1, 1),
SND_SOC_DAPM_ADC("ADC Right", NULL, CS42L52_PWRCTL1, 2, 1), SND_SOC_DAPM_ADC("ADC Right", NULL, CS42L52_PWRCTL1, 2, 1),
SND_SOC_DAPM_PGA("PGA Left", CS42L52_PWRCTL1, 3, 1, NULL, 0), SND_SOC_DAPM_PGA("PGA Left", CS42L52_PWRCTL1, 3, 1, NULL, 0),
@ -953,7 +968,7 @@ static int cs42l52_resume(struct snd_soc_codec *codec)
return 0; return 0;
} }
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) #if IS_ENABLED(CONFIG_INPUT)
static int beep_rates[] = { static int beep_rates[] = {
261, 522, 585, 667, 706, 774, 889, 1000, 261, 522, 585, 667, 706, 774, 889, 1000,
1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182 1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
@ -1110,6 +1125,8 @@ static int cs42l52_probe(struct snd_soc_codec *codec)
} }
regcache_cache_only(cs42l52->regmap, true); regcache_cache_only(cs42l52->regmap, true);
cs42l52_add_mic_controls(codec);
cs42l52_init_beep(codec); cs42l52_init_beep(codec);
cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY); cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@ -1176,6 +1193,7 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
int ret; int ret;
unsigned int devid = 0; unsigned int devid = 0;
unsigned int reg; unsigned int reg;
u32 val32;
cs42l52 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l52_private), cs42l52 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l52_private),
GFP_KERNEL); GFP_KERNEL);
@ -1189,9 +1207,39 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
return ret; return ret;
} }
if (pdata) {
if (pdata)
cs42l52->pdata = *pdata; cs42l52->pdata = *pdata;
} else {
pdata = devm_kzalloc(&i2c_client->dev,
sizeof(struct cs42l52_platform_data),
GFP_KERNEL);
if (!pdata) {
dev_err(&i2c_client->dev, "could not allocate pdata\n");
return -ENOMEM;
}
if (i2c_client->dev.of_node) {
if (of_property_read_bool(i2c_client->dev.of_node,
"cirrus,mica-differential-cfg"))
pdata->mica_diff_cfg = true;
if (of_property_read_bool(i2c_client->dev.of_node,
"cirrus,micb-differential-cfg"))
pdata->micb_diff_cfg = true;
if (of_property_read_u32(i2c_client->dev.of_node,
"cirrus,micbias-lvl", &val32) >= 0)
pdata->micbias_lvl = val32;
if (of_property_read_u32(i2c_client->dev.of_node,
"cirrus,chgfreq-divisor", &val32) >= 0)
pdata->chgfreq = val32;
pdata->reset_gpio =
of_get_named_gpio(i2c_client->dev.of_node,
"cirrus,reset-gpio", 0);
}
cs42l52->pdata = *pdata;
}
if (cs42l52->pdata.reset_gpio) { if (cs42l52->pdata.reset_gpio) {
ret = gpio_request_one(cs42l52->pdata.reset_gpio, ret = gpio_request_one(cs42l52->pdata.reset_gpio,
@ -1227,29 +1275,18 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
reg & 0xFF); reg & 0xFF);
/* Set Platform Data */ /* Set Platform Data */
if (cs42l52->pdata.mica_cfg) if (cs42l52->pdata.mica_diff_cfg)
regmap_update_bits(cs42l52->regmap, CS42L52_MICA_CTL, regmap_update_bits(cs42l52->regmap, CS42L52_MICA_CTL,
CS42L52_MIC_CTL_TYPE_MASK, CS42L52_MIC_CTL_TYPE_MASK,
cs42l52->pdata.mica_cfg << cs42l52->pdata.mica_diff_cfg <<
CS42L52_MIC_CTL_TYPE_SHIFT); CS42L52_MIC_CTL_TYPE_SHIFT);
if (cs42l52->pdata.micb_cfg) if (cs42l52->pdata.micb_diff_cfg)
regmap_update_bits(cs42l52->regmap, CS42L52_MICB_CTL, regmap_update_bits(cs42l52->regmap, CS42L52_MICB_CTL,
CS42L52_MIC_CTL_TYPE_MASK, CS42L52_MIC_CTL_TYPE_MASK,
cs42l52->pdata.micb_cfg << cs42l52->pdata.micb_diff_cfg <<
CS42L52_MIC_CTL_TYPE_SHIFT); CS42L52_MIC_CTL_TYPE_SHIFT);
if (cs42l52->pdata.mica_sel)
regmap_update_bits(cs42l52->regmap, CS42L52_MICA_CTL,
CS42L52_MIC_CTL_MIC_SEL_MASK,
cs42l52->pdata.mica_sel <<
CS42L52_MIC_CTL_MIC_SEL_SHIFT);
if (cs42l52->pdata.micb_sel)
regmap_update_bits(cs42l52->regmap, CS42L52_MICB_CTL,
CS42L52_MIC_CTL_MIC_SEL_MASK,
cs42l52->pdata.micb_sel <<
CS42L52_MIC_CTL_MIC_SEL_SHIFT);
if (cs42l52->pdata.chgfreq) if (cs42l52->pdata.chgfreq)
regmap_update_bits(cs42l52->regmap, CS42L52_CHARGE_PUMP, regmap_update_bits(cs42l52->regmap, CS42L52_CHARGE_PUMP,
CS42L52_CHARGE_PUMP_MASK, CS42L52_CHARGE_PUMP_MASK,
@ -1274,6 +1311,13 @@ static int cs42l52_i2c_remove(struct i2c_client *client)
return 0; return 0;
} }
static const struct of_device_id cs42l52_of_match[] = {
{ .compatible = "cirrus,cs42l52", },
{},
};
MODULE_DEVICE_TABLE(of, cs42l52_of_match);
static const struct i2c_device_id cs42l52_id[] = { static const struct i2c_device_id cs42l52_id[] = {
{ "cs42l52", 0 }, { "cs42l52", 0 },
{ } { }
@ -1284,6 +1328,7 @@ static struct i2c_driver cs42l52_i2c_driver = {
.driver = { .driver = {
.name = "cs42l52", .name = "cs42l52",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = cs42l52_of_match,
}, },
.id_table = cs42l52_id, .id_table = cs42l52_id,
.probe = cs42l52_i2c_probe, .probe = cs42l52_i2c_probe,

View File

@ -1188,7 +1188,7 @@ static struct snd_soc_codec_driver soc_codec_dev_da7210 = {
.num_dapm_routes = ARRAY_SIZE(da7210_audio_map), .num_dapm_routes = ARRAY_SIZE(da7210_audio_map),
}; };
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static struct reg_default da7210_regmap_i2c_patch[] = { static struct reg_default da7210_regmap_i2c_patch[] = {
@ -1362,7 +1362,7 @@ static struct spi_driver da7210_spi_driver = {
static int __init da7210_modinit(void) static int __init da7210_modinit(void)
{ {
int ret = 0; int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&da7210_i2c_driver); ret = i2c_add_driver(&da7210_i2c_driver);
#endif #endif
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)
@ -1378,7 +1378,7 @@ module_init(da7210_modinit);
static void __exit da7210_exit(void) static void __exit da7210_exit(void)
{ {
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&da7210_i2c_driver); i2c_del_driver(&da7210_i2c_driver);
#endif #endif
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)

View File

@ -20,6 +20,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <sound/soc.h> #include <sound/soc.h>
#include <linux/of_device.h>
#define DRV_NAME "hdmi-audio-codec" #define DRV_NAME "hdmi-audio-codec"
@ -44,7 +45,7 @@ static struct snd_soc_dai_driver hdmi_codec_dai = {
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | .formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE, SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
}, },
.capture = { .capture = {
.stream_name = "Capture", .stream_name = "Capture",
@ -60,6 +61,14 @@ static struct snd_soc_dai_driver hdmi_codec_dai = {
}; };
#ifdef CONFIG_OF
static const struct of_device_id hdmi_audio_codec_ids[] = {
{ .compatible = "linux,hdmi-audio", },
{ }
};
MODULE_DEVICE_TABLE(of, hdmi_audio_codec_ids);
#endif
static struct snd_soc_codec_driver hdmi_codec = { static struct snd_soc_codec_driver hdmi_codec = {
.dapm_widgets = hdmi_widgets, .dapm_widgets = hdmi_widgets,
.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
@ -83,6 +92,7 @@ static struct platform_driver hdmi_codec_driver = {
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(hdmi_audio_codec_ids),
}, },
.probe = hdmi_codec_probe, .probe = hdmi_codec_probe,

View File

@ -115,6 +115,7 @@ struct sgtl5000_priv {
struct ldo_regulator *ldo; struct ldo_regulator *ldo;
struct regmap *regmap; struct regmap *regmap;
struct clk *mclk; struct clk *mclk;
int revision;
}; };
/* /*
@ -1285,41 +1286,45 @@ static int sgtl5000_replace_vddd_with_ldo(struct snd_soc_codec *codec)
sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME; sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME;
ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies),
sgtl5000->supplies);
if (ret) {
ldo_regulator_remove(codec);
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
return ret;
}
dev_info(codec->dev, "Using internal LDO instead of VDDD\n"); dev_info(codec->dev, "Using internal LDO instead of VDDD\n");
return 0; return 0;
} }
static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
{ {
int reg;
int ret; int ret;
int rev;
int i; int i;
int external_vddd = 0; int external_vddd = 0;
struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
struct regulator *vddd;
for (i = 0; i < ARRAY_SIZE(sgtl5000->supplies); i++) for (i = 0; i < ARRAY_SIZE(sgtl5000->supplies); i++)
sgtl5000->supplies[i].supply = supply_names[i]; sgtl5000->supplies[i].supply = supply_names[i];
ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies), /* External VDDD only works before revision 0x11 */
sgtl5000->supplies); if (sgtl5000->revision < 0x11) {
if (!ret) vddd = regulator_get_optional(codec->dev, "VDDD");
external_vddd = 1; if (IS_ERR(vddd)) {
else { /* See if it's just not registered yet */
if (PTR_ERR(vddd) == -EPROBE_DEFER)
return -EPROBE_DEFER;
} else {
external_vddd = 1;
regulator_put(vddd);
}
}
if (!external_vddd) {
ret = sgtl5000_replace_vddd_with_ldo(codec); ret = sgtl5000_replace_vddd_with_ldo(codec);
if (ret) if (ret)
return ret; return ret;
} }
ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies),
sgtl5000->supplies);
if (ret)
goto err_ldo_remove;
ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies), ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies),
sgtl5000->supplies); sgtl5000->supplies);
if (ret) if (ret)
@ -1328,47 +1333,13 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
/* wait for all power rails bring up */ /* wait for all power rails bring up */
udelay(10); udelay(10);
/*
* workaround for revision 0x11 and later,
* roll back to use internal LDO
*/
ret = regmap_read(sgtl5000->regmap, SGTL5000_CHIP_ID, &reg);
if (ret)
goto err_regulator_disable;
rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT;
if (external_vddd && rev >= 0x11) {
/* disable all regulator first */
regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
sgtl5000->supplies);
/* free VDDD regulator */
regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
sgtl5000->supplies);
ret = sgtl5000_replace_vddd_with_ldo(codec);
if (ret)
return ret;
ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies),
sgtl5000->supplies);
if (ret)
goto err_regulator_free;
/* wait for all power rails bring up */
udelay(10);
}
return 0; return 0;
err_regulator_disable:
regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
sgtl5000->supplies);
err_regulator_free: err_regulator_free:
regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
sgtl5000->supplies); sgtl5000->supplies);
if (external_vddd) err_ldo_remove:
if (!external_vddd)
ldo_regulator_remove(codec); ldo_regulator_remove(codec);
return ret; return ret;
@ -1566,6 +1537,7 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT; rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT;
dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev); dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev);
sgtl5000->revision = rev;
i2c_set_clientdata(client, sgtl5000); i2c_set_clientdata(client, sgtl5000);

View File

@ -549,13 +549,13 @@ static int ssm2518_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
right_slot = 0; right_slot = 0;
} else { } else {
/* We assume the left channel < right channel */ /* We assume the left channel < right channel */
left_slot = ffs(tx_mask); left_slot = __ffs(tx_mask);
tx_mask &= ~(1 << tx_mask); tx_mask &= ~(1 << left_slot);
if (tx_mask == 0) { if (tx_mask == 0) {
right_slot = left_slot; right_slot = left_slot;
} else { } else {
right_slot = ffs(tx_mask); right_slot = __ffs(tx_mask);
tx_mask &= ~(1 << tx_mask); tx_mask &= ~(1 << right_slot);
} }
} }

View File

@ -53,8 +53,6 @@ enum ssm2602_type {
struct ssm2602_priv { struct ssm2602_priv {
unsigned int sysclk; unsigned int sysclk;
struct snd_pcm_hw_constraint_list *sysclk_constraints; struct snd_pcm_hw_constraint_list *sysclk_constraints;
struct snd_pcm_substream *master_substream;
struct snd_pcm_substream *slave_substream;
struct regmap *regmap; struct regmap *regmap;
@ -277,11 +275,6 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params)); int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params));
unsigned int iface; unsigned int iface;
if (substream == ssm2602->slave_substream) {
dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n");
return 0;
}
if (srate < 0) if (srate < 0)
return srate; return srate;
@ -314,33 +307,6 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
struct snd_pcm_runtime *master_runtime;
/* The DAI has shared clocks so if we already have a playback or
* capture going then constrain this substream to match it.
* TODO: the ssm2602 allows pairs of non-matching PB/REC rates
*/
if (ssm2602->master_substream) {
master_runtime = ssm2602->master_substream->runtime;
dev_dbg(codec->dev, "Constraining to %d bits at %dHz\n",
master_runtime->sample_bits,
master_runtime->rate);
if (master_runtime->rate != 0)
snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_RATE,
master_runtime->rate,
master_runtime->rate);
if (master_runtime->sample_bits != 0)
snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
master_runtime->sample_bits,
master_runtime->sample_bits);
ssm2602->slave_substream = substream;
} else
ssm2602->master_substream = substream;
if (ssm2602->sysclk_constraints) { if (ssm2602->sysclk_constraints) {
snd_pcm_hw_constraint_list(substream->runtime, 0, snd_pcm_hw_constraint_list(substream->runtime, 0,
@ -351,19 +317,6 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
return 0; return 0;
} }
static void ssm2602_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
if (ssm2602->master_substream == substream)
ssm2602->master_substream = ssm2602->slave_substream;
ssm2602->slave_substream = NULL;
}
static int ssm2602_mute(struct snd_soc_dai *dai, int mute) static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
{ {
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(dai->codec); struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(dai->codec);
@ -530,7 +483,6 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
static const struct snd_soc_dai_ops ssm2602_dai_ops = { static const struct snd_soc_dai_ops ssm2602_dai_ops = {
.startup = ssm2602_startup, .startup = ssm2602_startup,
.hw_params = ssm2602_hw_params, .hw_params = ssm2602_hw_params,
.shutdown = ssm2602_shutdown,
.digital_mute = ssm2602_mute, .digital_mute = ssm2602_mute,
.set_sysclk = ssm2602_set_dai_sysclk, .set_sysclk = ssm2602_set_dai_sysclk,
.set_fmt = ssm2602_set_dai_fmt, .set_fmt = ssm2602_set_dai_fmt,
@ -551,6 +503,8 @@ static struct snd_soc_dai_driver ssm2602_dai = {
.rates = SSM2602_RATES, .rates = SSM2602_RATES,
.formats = SSM2602_FORMATS,}, .formats = SSM2602_FORMATS,},
.ops = &ssm2602_dai_ops, .ops = &ssm2602_dai_ops,
.symmetric_rates = 1,
.symmetric_samplebits = 1,
}; };
static int ssm2602_suspend(struct snd_soc_codec *codec) static int ssm2602_suspend(struct snd_soc_codec *codec)
@ -730,7 +684,7 @@ static struct spi_driver ssm2602_spi_driver = {
}; };
#endif #endif
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
/* /*
* ssm2602 2 wire address is determined by GPIO5 * ssm2602 2 wire address is determined by GPIO5
* state during powerup. * state during powerup.
@ -797,7 +751,7 @@ static int __init ssm2602_modinit(void)
return ret; return ret;
#endif #endif
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&ssm2602_i2c_driver); ret = i2c_add_driver(&ssm2602_i2c_driver);
if (ret) if (ret)
return ret; return ret;
@ -813,7 +767,7 @@ static void __exit ssm2602_exit(void)
spi_unregister_driver(&ssm2602_spi_driver); spi_unregister_driver(&ssm2602_spi_driver);
#endif #endif
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&ssm2602_i2c_driver); i2c_del_driver(&ssm2602_i2c_driver);
#endif #endif
} }

View File

@ -350,16 +350,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL, DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL,
0, 118, 1, output_stage_tlv), 0, 118, 1, output_stage_tlv),
SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume",
LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
0, 118, 1, output_stage_tlv),
SOC_DOUBLE_R_TLV("Mono PGA Bypass Volume",
PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
0, 118, 1, output_stage_tlv),
SOC_DOUBLE_R_TLV("Mono DAC Playback Volume",
DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL,
0, 118, 1, output_stage_tlv),
SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume", SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume",
LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL, LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
0, 118, 1, output_stage_tlv), 0, 118, 1, output_stage_tlv),
@ -383,7 +373,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
/* Output pin mute controls */ /* Output pin mute controls */
SOC_DOUBLE_R("Line Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3, SOC_DOUBLE_R("Line Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3,
0x01, 0), 0x01, 0),
SOC_SINGLE("Mono Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
SOC_DOUBLE_R("HP Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3, SOC_DOUBLE_R("HP Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
0x01, 0), 0x01, 0),
SOC_DOUBLE_R("HPCOM Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3, SOC_DOUBLE_R("HPCOM Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
@ -412,6 +401,20 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]),
}; };
static const struct snd_kcontrol_new aic3x_mono_controls[] = {
SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume",
LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
0, 118, 1, output_stage_tlv),
SOC_DOUBLE_R_TLV("Mono PGA Bypass Volume",
PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
0, 118, 1, output_stage_tlv),
SOC_DOUBLE_R_TLV("Mono DAC Playback Volume",
DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL,
0, 118, 1, output_stage_tlv),
SOC_SINGLE("Mono Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
};
/* /*
* Class-D amplifier gain. From 0 to 18 dB in 6 dB steps * Class-D amplifier gain. From 0 to 18 dB in 6 dB steps
*/ */
@ -565,9 +568,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
SND_SOC_DAPM_PGA("Right HP Out", HPROUT_CTRL, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("Right HP Out", HPROUT_CTRL, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("Right HP Com", HPRCOM_CTRL, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("Right HP Com", HPRCOM_CTRL, 0, 0, NULL, 0),
/* Mono Output */
SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0),
/* Inputs to Left ADC */ /* Inputs to Left ADC */
SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0), SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0),
SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0, SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
@ -626,9 +626,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
SND_SOC_DAPM_MIXER("Right Line Mixer", SND_SOC_NOPM, 0, 0, SND_SOC_DAPM_MIXER("Right Line Mixer", SND_SOC_NOPM, 0, 0,
&aic3x_right_line_mixer_controls[0], &aic3x_right_line_mixer_controls[0],
ARRAY_SIZE(aic3x_right_line_mixer_controls)), ARRAY_SIZE(aic3x_right_line_mixer_controls)),
SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0,
&aic3x_mono_mixer_controls[0],
ARRAY_SIZE(aic3x_mono_mixer_controls)),
SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0, SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
&aic3x_left_hp_mixer_controls[0], &aic3x_left_hp_mixer_controls[0],
ARRAY_SIZE(aic3x_left_hp_mixer_controls)), ARRAY_SIZE(aic3x_left_hp_mixer_controls)),
@ -644,7 +641,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("LLOUT"), SND_SOC_DAPM_OUTPUT("LLOUT"),
SND_SOC_DAPM_OUTPUT("RLOUT"), SND_SOC_DAPM_OUTPUT("RLOUT"),
SND_SOC_DAPM_OUTPUT("MONO_LOUT"),
SND_SOC_DAPM_OUTPUT("HPLOUT"), SND_SOC_DAPM_OUTPUT("HPLOUT"),
SND_SOC_DAPM_OUTPUT("HPROUT"), SND_SOC_DAPM_OUTPUT("HPROUT"),
SND_SOC_DAPM_OUTPUT("HPLCOM"), SND_SOC_DAPM_OUTPUT("HPLCOM"),
@ -666,6 +662,17 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("Detection"), SND_SOC_DAPM_OUTPUT("Detection"),
}; };
static const struct snd_soc_dapm_widget aic3x_dapm_mono_widgets[] = {
/* Mono Output */
SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0,
&aic3x_mono_mixer_controls[0],
ARRAY_SIZE(aic3x_mono_mixer_controls)),
SND_SOC_DAPM_OUTPUT("MONO_LOUT"),
};
static const struct snd_soc_dapm_widget aic3007_dapm_widgets[] = { static const struct snd_soc_dapm_widget aic3007_dapm_widgets[] = {
/* Class-D outputs */ /* Class-D outputs */
SND_SOC_DAPM_PGA("Left Class-D Out", CLASSD_CTRL, 3, 0, NULL, 0), SND_SOC_DAPM_PGA("Left Class-D Out", CLASSD_CTRL, 3, 0, NULL, 0),
@ -754,17 +761,6 @@ static const struct snd_soc_dapm_route intercon[] = {
{"Right Line Out", NULL, "Right DAC Mux"}, {"Right Line Out", NULL, "Right DAC Mux"},
{"RLOUT", NULL, "Right Line Out"}, {"RLOUT", NULL, "Right Line Out"},
/* Mono Output */
{"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
{"Mono Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
{"Mono Mixer", "DACL1 Switch", "Left DAC Mux"},
{"Mono Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
{"Mono Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
{"Mono Mixer", "DACR1 Switch", "Right DAC Mux"},
{"Mono Out", NULL, "Mono Mixer"},
{"MONO_LOUT", NULL, "Mono Out"},
/* Left HP Output */ /* Left HP Output */
{"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, {"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
{"Left HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, {"Left HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
@ -820,6 +816,18 @@ static const struct snd_soc_dapm_route intercon[] = {
{"HPRCOM", NULL, "Right HP Com"}, {"HPRCOM", NULL, "Right HP Com"},
}; };
static const struct snd_soc_dapm_route intercon_mono[] = {
/* Mono Output */
{"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
{"Mono Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
{"Mono Mixer", "DACL1 Switch", "Left DAC Mux"},
{"Mono Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
{"Mono Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
{"Mono Mixer", "DACR1 Switch", "Right DAC Mux"},
{"Mono Out", NULL, "Mono Mixer"},
{"MONO_LOUT", NULL, "Mono Out"},
};
static const struct snd_soc_dapm_route intercon_3007[] = { static const struct snd_soc_dapm_route intercon_3007[] = {
/* Class-D outputs */ /* Class-D outputs */
{"Left Class-D Out", NULL, "Left Line Out"}, {"Left Class-D Out", NULL, "Left Line Out"},
@ -833,11 +841,20 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec)
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_dapm_context *dapm = &codec->dapm;
if (aic3x->model == AIC3X_MODEL_3007) { switch (aic3x->model) {
case AIC3X_MODEL_3X:
case AIC3X_MODEL_33:
snd_soc_dapm_new_controls(dapm, aic3x_dapm_mono_widgets,
ARRAY_SIZE(aic3x_dapm_mono_widgets));
snd_soc_dapm_add_routes(dapm, intercon_mono,
ARRAY_SIZE(intercon_mono));
break;
case AIC3X_MODEL_3007:
snd_soc_dapm_new_controls(dapm, aic3007_dapm_widgets, snd_soc_dapm_new_controls(dapm, aic3007_dapm_widgets,
ARRAY_SIZE(aic3007_dapm_widgets)); ARRAY_SIZE(aic3007_dapm_widgets));
snd_soc_dapm_add_routes(dapm, intercon_3007, snd_soc_dapm_add_routes(dapm, intercon_3007,
ARRAY_SIZE(intercon_3007)); ARRAY_SIZE(intercon_3007));
break;
} }
return 0; return 0;
@ -1218,6 +1235,24 @@ static int aic3x_resume(struct snd_soc_codec *codec)
return 0; return 0;
} }
static void aic3x_mono_init(struct snd_soc_codec *codec)
{
/* DAC to Mono Line Out default volume and route to Output mixer */
snd_soc_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
snd_soc_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
/* unmute all outputs */
snd_soc_update_bits(codec, MONOLOPM_CTRL, UNMUTE, UNMUTE);
/* PGA to Mono Line Out default volume, disconnect from Output Mixer */
snd_soc_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
snd_soc_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
/* Line2 to Mono Out default volume, disconnect from Output Mixer */
snd_soc_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
}
/* /*
* initialise the AIC3X driver * initialise the AIC3X driver
* register the mixer and dsp interfaces with the kernel * register the mixer and dsp interfaces with the kernel
@ -1241,14 +1276,10 @@ static int aic3x_init(struct snd_soc_codec *codec)
/* DAC to Line Out default volume and route to Output mixer */ /* DAC to Line Out default volume and route to Output mixer */
snd_soc_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON); snd_soc_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
snd_soc_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON); snd_soc_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
/* DAC to Mono Line Out default volume and route to Output mixer */
snd_soc_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
snd_soc_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
/* unmute all outputs */ /* unmute all outputs */
snd_soc_update_bits(codec, LLOPM_CTRL, UNMUTE, UNMUTE); snd_soc_update_bits(codec, LLOPM_CTRL, UNMUTE, UNMUTE);
snd_soc_update_bits(codec, RLOPM_CTRL, UNMUTE, UNMUTE); snd_soc_update_bits(codec, RLOPM_CTRL, UNMUTE, UNMUTE);
snd_soc_update_bits(codec, MONOLOPM_CTRL, UNMUTE, UNMUTE);
snd_soc_update_bits(codec, HPLOUT_CTRL, UNMUTE, UNMUTE); snd_soc_update_bits(codec, HPLOUT_CTRL, UNMUTE, UNMUTE);
snd_soc_update_bits(codec, HPROUT_CTRL, UNMUTE, UNMUTE); snd_soc_update_bits(codec, HPROUT_CTRL, UNMUTE, UNMUTE);
snd_soc_update_bits(codec, HPLCOM_CTRL, UNMUTE, UNMUTE); snd_soc_update_bits(codec, HPLCOM_CTRL, UNMUTE, UNMUTE);
@ -1269,9 +1300,6 @@ static int aic3x_init(struct snd_soc_codec *codec)
/* PGA to Line Out default volume, disconnect from Output Mixer */ /* PGA to Line Out default volume, disconnect from Output Mixer */
snd_soc_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL);
snd_soc_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL);
/* PGA to Mono Line Out default volume, disconnect from Output Mixer */
snd_soc_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
snd_soc_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
/* Line2 to HP Bypass default volume, disconnect from Output Mixer */ /* Line2 to HP Bypass default volume, disconnect from Output Mixer */
snd_soc_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL); snd_soc_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL);
@ -1281,12 +1309,15 @@ static int aic3x_init(struct snd_soc_codec *codec)
/* Line2 Line Out default volume, disconnect from Output Mixer */ /* Line2 Line Out default volume, disconnect from Output Mixer */
snd_soc_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL);
snd_soc_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL);
/* Line2 to Mono Out default volume, disconnect from Output Mixer */
snd_soc_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
if (aic3x->model == AIC3X_MODEL_3007) { switch (aic3x->model) {
case AIC3X_MODEL_3X:
case AIC3X_MODEL_33:
aic3x_mono_init(codec);
break;
case AIC3X_MODEL_3007:
snd_soc_write(codec, CLASSD_CTRL, 0); snd_soc_write(codec, CLASSD_CTRL, 0);
break;
} }
return 0; return 0;
@ -1343,8 +1374,17 @@ static int aic3x_probe(struct snd_soc_codec *codec)
(aic3x->setup->gpio_func[1] & 0xf) << 4); (aic3x->setup->gpio_func[1] & 0xf) << 4);
} }
if (aic3x->model == AIC3X_MODEL_3007) switch (aic3x->model) {
snd_soc_add_codec_controls(codec, &aic3x_classd_amp_gain_ctrl, 1); case AIC3X_MODEL_3X:
case AIC3X_MODEL_33:
snd_soc_add_codec_controls(codec, aic3x_mono_controls,
ARRAY_SIZE(aic3x_mono_controls));
break;
case AIC3X_MODEL_3007:
snd_soc_add_codec_controls(codec,
&aic3x_classd_amp_gain_ctrl, 1);
break;
}
/* set mic bias voltage */ /* set mic bias voltage */
switch (aic3x->micbias_vg) { switch (aic3x->micbias_vg) {

View File

@ -72,6 +72,7 @@ struct twl6040_data {
int hs_power_mode_locked; int hs_power_mode_locked;
bool dl1_unmuted; bool dl1_unmuted;
bool dl2_unmuted; bool dl2_unmuted;
u8 dl12_cache[TWL6040_REG_HFRCTL - TWL6040_REG_HSLCTL + 1];
unsigned int clk_in; unsigned int clk_in;
unsigned int sysclk; unsigned int sysclk;
struct twl6040_jack_data hs_jack; struct twl6040_jack_data hs_jack;
@ -79,75 +80,6 @@ struct twl6040_data {
struct mutex mutex; struct mutex mutex;
}; };
/*
* twl6040 register cache & default register settings
*/
static const u8 twl6040_reg[TWL6040_CACHEREGNUM] = {
0x00, /* not used 0x00 */
0x4B, /* REG_ASICID 0x01 (ro) */
0x00, /* REG_ASICREV 0x02 (ro) */
0x00, /* REG_INTID 0x03 */
0x00, /* REG_INTMR 0x04 */
0x00, /* REG_NCPCTRL 0x05 */
0x00, /* REG_LDOCTL 0x06 */
0x60, /* REG_HPPLLCTL 0x07 */
0x00, /* REG_LPPLLCTL 0x08 */
0x4A, /* REG_LPPLLDIV 0x09 */
0x00, /* REG_AMICBCTL 0x0A */
0x00, /* REG_DMICBCTL 0x0B */
0x00, /* REG_MICLCTL 0x0C */
0x00, /* REG_MICRCTL 0x0D */
0x00, /* REG_MICGAIN 0x0E */
0x1B, /* REG_LINEGAIN 0x0F */
0x00, /* REG_HSLCTL 0x10 */
0x00, /* REG_HSRCTL 0x11 */
0x00, /* REG_HSGAIN 0x12 */
0x00, /* REG_EARCTL 0x13 */
0x00, /* REG_HFLCTL 0x14 */
0x00, /* REG_HFLGAIN 0x15 */
0x00, /* REG_HFRCTL 0x16 */
0x00, /* REG_HFRGAIN 0x17 */
0x00, /* REG_VIBCTLL 0x18 */
0x00, /* REG_VIBDATL 0x19 */
0x00, /* REG_VIBCTLR 0x1A */
0x00, /* REG_VIBDATR 0x1B */
0x00, /* REG_HKCTL1 0x1C */
0x00, /* REG_HKCTL2 0x1D */
0x00, /* REG_GPOCTL 0x1E */
0x00, /* REG_ALB 0x1F */
0x00, /* REG_DLB 0x20 */
0x00, /* not used 0x21 */
0x00, /* not used 0x22 */
0x00, /* not used 0x23 */
0x00, /* not used 0x24 */
0x00, /* not used 0x25 */
0x00, /* not used 0x26 */
0x00, /* not used 0x27 */
0x00, /* REG_TRIM1 0x28 */
0x00, /* REG_TRIM2 0x29 */
0x00, /* REG_TRIM3 0x2A */
0x00, /* REG_HSOTRIM 0x2B */
0x00, /* REG_HFOTRIM 0x2C */
0x09, /* REG_ACCCTL 0x2D */
0x00, /* REG_STATUS 0x2E (ro) */
};
/* List of registers to be restored after power up */
static const int twl6040_restore_list[] = {
TWL6040_REG_MICLCTL,
TWL6040_REG_MICRCTL,
TWL6040_REG_MICGAIN,
TWL6040_REG_LINEGAIN,
TWL6040_REG_HSLCTL,
TWL6040_REG_HSRCTL,
TWL6040_REG_HSGAIN,
TWL6040_REG_EARCTL,
TWL6040_REG_HFLCTL,
TWL6040_REG_HFLGAIN,
TWL6040_REG_HFRCTL,
TWL6040_REG_HFRGAIN,
};
/* set of rates for each pll: low-power and high-performance */ /* set of rates for each pll: low-power and high-performance */
static unsigned int lp_rates[] = { static unsigned int lp_rates[] = {
8000, 8000,
@ -174,53 +106,33 @@ static struct snd_pcm_hw_constraint_list sysclk_constraints[] = {
{ .count = ARRAY_SIZE(hp_rates), .list = hp_rates, }, { .count = ARRAY_SIZE(hp_rates), .list = hp_rates, },
}; };
/* static unsigned int twl6040_read(struct snd_soc_codec *codec, unsigned int reg)
* read twl6040 register cache
*/
static inline unsigned int twl6040_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u8 *cache = codec->reg_cache;
if (reg >= TWL6040_CACHEREGNUM)
return -EIO;
return cache[reg];
}
/*
* write twl6040 register cache
*/
static inline void twl6040_write_reg_cache(struct snd_soc_codec *codec,
u8 reg, u8 value)
{
u8 *cache = codec->reg_cache;
if (reg >= TWL6040_CACHEREGNUM)
return;
cache[reg] = value;
}
/*
* read from twl6040 hardware register
*/
static int twl6040_read_reg_volatile(struct snd_soc_codec *codec,
unsigned int reg)
{ {
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct twl6040 *twl6040 = codec->control_data; struct twl6040 *twl6040 = codec->control_data;
u8 value; u8 value;
if (reg >= TWL6040_CACHEREGNUM) if (reg >= TWL6040_CACHEREGNUM)
return -EIO; return -EIO;
value = twl6040_reg_read(twl6040, reg); switch (reg) {
twl6040_write_reg_cache(codec, reg, value); case TWL6040_REG_HSLCTL:
case TWL6040_REG_HSRCTL:
case TWL6040_REG_EARCTL:
case TWL6040_REG_HFLCTL:
case TWL6040_REG_HFRCTL:
value = priv->dl12_cache[reg - TWL6040_REG_HSLCTL];
break;
default:
value = twl6040_reg_read(twl6040, reg);
break;
}
return value; return value;
} }
static bool twl6040_is_path_unmuted(struct snd_soc_codec *codec, static bool twl6040_can_write_to_chip(struct snd_soc_codec *codec,
unsigned int reg) unsigned int reg)
{ {
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
@ -238,9 +150,24 @@ static bool twl6040_is_path_unmuted(struct snd_soc_codec *codec,
} }
} }
/* static inline void twl6040_update_dl12_cache(struct snd_soc_codec *codec,
* write to the twl6040 register space u8 reg, u8 value)
*/ {
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
switch (reg) {
case TWL6040_REG_HSLCTL:
case TWL6040_REG_HSRCTL:
case TWL6040_REG_EARCTL:
case TWL6040_REG_HFLCTL:
case TWL6040_REG_HFRCTL:
priv->dl12_cache[reg - TWL6040_REG_HSLCTL] = value;
break;
default:
break;
}
}
static int twl6040_write(struct snd_soc_codec *codec, static int twl6040_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value) unsigned int reg, unsigned int value)
{ {
@ -249,8 +176,8 @@ static int twl6040_write(struct snd_soc_codec *codec,
if (reg >= TWL6040_CACHEREGNUM) if (reg >= TWL6040_CACHEREGNUM)
return -EIO; return -EIO;
twl6040_write_reg_cache(codec, reg, value); twl6040_update_dl12_cache(codec, reg, value);
if (twl6040_is_path_unmuted(codec, reg)) if (twl6040_can_write_to_chip(codec, reg))
return twl6040_reg_write(twl6040, reg, value); return twl6040_reg_write(twl6040, reg, value);
else else
return 0; return 0;
@ -258,45 +185,27 @@ static int twl6040_write(struct snd_soc_codec *codec,
static void twl6040_init_chip(struct snd_soc_codec *codec) static void twl6040_init_chip(struct snd_soc_codec *codec)
{ {
struct twl6040 *twl6040 = codec->control_data; twl6040_read(codec, TWL6040_REG_TRIM1);
u8 val; twl6040_read(codec, TWL6040_REG_TRIM2);
twl6040_read(codec, TWL6040_REG_TRIM3);
/* Update reg_cache: ASICREV, and TRIM values */ twl6040_read(codec, TWL6040_REG_HSOTRIM);
val = twl6040_get_revid(twl6040); twl6040_read(codec, TWL6040_REG_HFOTRIM);
twl6040_write_reg_cache(codec, TWL6040_REG_ASICREV, val);
twl6040_read_reg_volatile(codec, TWL6040_REG_TRIM1);
twl6040_read_reg_volatile(codec, TWL6040_REG_TRIM2);
twl6040_read_reg_volatile(codec, TWL6040_REG_TRIM3);
twl6040_read_reg_volatile(codec, TWL6040_REG_HSOTRIM);
twl6040_read_reg_volatile(codec, TWL6040_REG_HFOTRIM);
/* Change chip defaults */ /* Change chip defaults */
/* No imput selected for microphone amplifiers */ /* No imput selected for microphone amplifiers */
twl6040_write_reg_cache(codec, TWL6040_REG_MICLCTL, 0x18); twl6040_write(codec, TWL6040_REG_MICLCTL, 0x18);
twl6040_write_reg_cache(codec, TWL6040_REG_MICRCTL, 0x18); twl6040_write(codec, TWL6040_REG_MICRCTL, 0x18);
/* /*
* We need to lower the default gain values, so the ramp code * We need to lower the default gain values, so the ramp code
* can work correctly for the first playback. * can work correctly for the first playback.
* This reduces the pop noise heard at the first playback. * This reduces the pop noise heard at the first playback.
*/ */
twl6040_write_reg_cache(codec, TWL6040_REG_HSGAIN, 0xff); twl6040_write(codec, TWL6040_REG_HSGAIN, 0xff);
twl6040_write_reg_cache(codec, TWL6040_REG_EARCTL, 0x1e); twl6040_write(codec, TWL6040_REG_EARCTL, 0x1e);
twl6040_write_reg_cache(codec, TWL6040_REG_HFLGAIN, 0x1d); twl6040_write(codec, TWL6040_REG_HFLGAIN, 0x1d);
twl6040_write_reg_cache(codec, TWL6040_REG_HFRGAIN, 0x1d); twl6040_write(codec, TWL6040_REG_HFRGAIN, 0x1d);
twl6040_write_reg_cache(codec, TWL6040_REG_LINEGAIN, 0); twl6040_write(codec, TWL6040_REG_LINEGAIN, 0);
}
static void twl6040_restore_regs(struct snd_soc_codec *codec)
{
u8 *cache = codec->reg_cache;
int reg, i;
for (i = 0; i < ARRAY_SIZE(twl6040_restore_list); i++) {
reg = twl6040_restore_list[i];
twl6040_write(codec, reg, cache[reg]);
}
} }
/* set headset dac and driver power mode */ /* set headset dac and driver power mode */
@ -305,8 +214,8 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
int hslctl, hsrctl; int hslctl, hsrctl;
int mask = TWL6040_HSDRVMODE | TWL6040_HSDACMODE; int mask = TWL6040_HSDRVMODE | TWL6040_HSDACMODE;
hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL); hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL);
hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL); hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);
if (high_perf) { if (high_perf) {
hslctl &= ~mask; hslctl &= ~mask;
@ -333,8 +242,8 @@ static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
* Both HS DAC need to be turned on (before the HS driver) and off at * Both HS DAC need to be turned on (before the HS driver) and off at
* the same time. * the same time.
*/ */
hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL); hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL);
hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL); hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);
if (SND_SOC_DAPM_EVENT_ON(event)) { if (SND_SOC_DAPM_EVENT_ON(event)) {
hslctl |= TWL6040_HSDACENA; hslctl |= TWL6040_HSDACENA;
hsrctl |= TWL6040_HSDACENA; hsrctl |= TWL6040_HSDACENA;
@ -379,7 +288,7 @@ static void twl6040_hs_jack_report(struct snd_soc_codec *codec,
mutex_lock(&priv->mutex); mutex_lock(&priv->mutex);
/* Sync status */ /* Sync status */
status = twl6040_read_reg_volatile(codec, TWL6040_REG_STATUS); status = twl6040_read(codec, TWL6040_REG_STATUS);
if (status & TWL6040_PLUGCOMP) if (status & TWL6040_PLUGCOMP)
snd_soc_jack_report(jack, report, report); snd_soc_jack_report(jack, report, report);
else else
@ -431,7 +340,7 @@ static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol,
unsigned int val; unsigned int val;
/* Do not allow changes while Input/FF efect is running */ /* Do not allow changes while Input/FF efect is running */
val = twl6040_read_reg_volatile(codec, e->reg); val = twl6040_read(codec, e->reg);
if (val & TWL6040_VIBENA && !(val & TWL6040_VIBSEL)) if (val & TWL6040_VIBENA && !(val & TWL6040_VIBSEL))
return -EBUSY; return -EBUSY;
@ -656,7 +565,7 @@ int twl6040_get_trim_value(struct snd_soc_codec *codec, enum twl6040_trim trim)
if (unlikely(trim >= TWL6040_TRIM_INVAL)) if (unlikely(trim >= TWL6040_TRIM_INVAL))
return -EINVAL; return -EINVAL;
return twl6040_read_reg_cache(codec, TWL6040_REG_TRIM1 + trim); return twl6040_read(codec, TWL6040_REG_TRIM1 + trim);
} }
EXPORT_SYMBOL_GPL(twl6040_get_trim_value); EXPORT_SYMBOL_GPL(twl6040_get_trim_value);
@ -931,8 +840,6 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
priv->codec_powered = 1; priv->codec_powered = 1;
twl6040_restore_regs(codec);
/* Set external boost GPO */ /* Set external boost GPO */
twl6040_write(codec, TWL6040_REG_GPOCTL, 0x02); twl6040_write(codec, TWL6040_REG_GPOCTL, 0x02);
break; break;
@ -1053,9 +960,9 @@ static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id i
switch (id) { switch (id) {
case TWL6040_DAI_DL1: case TWL6040_DAI_DL1:
hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL); hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL);
hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL); hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);
earctl = twl6040_read_reg_cache(codec, TWL6040_REG_EARCTL); earctl = twl6040_read(codec, TWL6040_REG_EARCTL);
if (mute) { if (mute) {
/* Power down drivers and DACs */ /* Power down drivers and DACs */
@ -1071,8 +978,8 @@ static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id i
priv->dl1_unmuted = !mute; priv->dl1_unmuted = !mute;
break; break;
case TWL6040_DAI_DL2: case TWL6040_DAI_DL2:
hflctl = twl6040_read_reg_cache(codec, TWL6040_REG_HFLCTL); hflctl = twl6040_read(codec, TWL6040_REG_HFLCTL);
hfrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HFRCTL); hfrctl = twl6040_read(codec, TWL6040_REG_HFRCTL);
if (mute) { if (mute) {
/* Power down drivers and DACs */ /* Power down drivers and DACs */
@ -1209,6 +1116,7 @@ static int twl6040_resume(struct snd_soc_codec *codec)
static int twl6040_probe(struct snd_soc_codec *codec) static int twl6040_probe(struct snd_soc_codec *codec)
{ {
struct twl6040_data *priv; struct twl6040_data *priv;
struct twl6040 *twl6040 = dev_get_drvdata(codec->dev->parent);
struct platform_device *pdev = container_of(codec->dev, struct platform_device *pdev = container_of(codec->dev,
struct platform_device, dev); struct platform_device, dev);
int ret = 0; int ret = 0;
@ -1220,7 +1128,7 @@ static int twl6040_probe(struct snd_soc_codec *codec)
snd_soc_codec_set_drvdata(codec, priv); snd_soc_codec_set_drvdata(codec, priv);
priv->codec = codec; priv->codec = codec;
codec->control_data = dev_get_drvdata(codec->dev->parent); codec->control_data = twl6040;
priv->plug_irq = platform_get_irq(pdev, 0); priv->plug_irq = platform_get_irq(pdev, 0);
if (priv->plug_irq < 0) { if (priv->plug_irq < 0) {
@ -1240,10 +1148,10 @@ static int twl6040_probe(struct snd_soc_codec *codec)
return ret; return ret;
} }
twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
twl6040_init_chip(codec); twl6040_init_chip(codec);
/* power on device */ return 0;
return twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
} }
static int twl6040_remove(struct snd_soc_codec *codec) static int twl6040_remove(struct snd_soc_codec *codec)
@ -1261,12 +1169,9 @@ static struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
.remove = twl6040_remove, .remove = twl6040_remove,
.suspend = twl6040_suspend, .suspend = twl6040_suspend,
.resume = twl6040_resume, .resume = twl6040_resume,
.read = twl6040_read_reg_cache, .read = twl6040_read,
.write = twl6040_write, .write = twl6040_write,
.set_bias_level = twl6040_set_bias_level, .set_bias_level = twl6040_set_bias_level,
.reg_cache_size = ARRAY_SIZE(twl6040_reg),
.reg_word_size = sizeof(u8),
.reg_cache_default = twl6040_reg,
.ignore_pmdown_time = true, .ignore_pmdown_time = true,
.controls = twl6040_snd_controls, .controls = twl6040_snd_controls,

View File

@ -794,7 +794,7 @@ static struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
.num_dapm_routes = ARRAY_SIZE(uda1380_dapm_routes), .num_dapm_routes = ARRAY_SIZE(uda1380_dapm_routes),
}; };
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static int uda1380_i2c_probe(struct i2c_client *i2c, static int uda1380_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -840,7 +840,7 @@ static struct i2c_driver uda1380_i2c_driver = {
static int __init uda1380_modinit(void) static int __init uda1380_modinit(void)
{ {
int ret = 0; int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&uda1380_i2c_driver); ret = i2c_add_driver(&uda1380_i2c_driver);
if (ret != 0) if (ret != 0)
pr_err("Failed to register UDA1380 I2C driver: %d\n", ret); pr_err("Failed to register UDA1380 I2C driver: %d\n", ret);
@ -851,7 +851,7 @@ module_init(uda1380_modinit);
static void __exit uda1380_exit(void) static void __exit uda1380_exit(void)
{ {
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&uda1380_i2c_driver); i2c_del_driver(&uda1380_i2c_driver);
#endif #endif
} }

View File

@ -601,8 +601,8 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU: case SND_SOC_DAPM_POST_PMU:
if (patch) if (patch)
for (i = 0; i < patch_size; i++) for (i = 0; i < patch_size; i++)
regmap_write(regmap, patch[i].reg, regmap_write_async(regmap, patch[i].reg,
patch[i].def); patch[i].def);
break; break;
default: default:

View File

@ -30,13 +30,51 @@
#include <linux/mfd/arizona/registers.h> #include <linux/mfd/arizona/registers.h>
#include "arizona.h" #include "arizona.h"
#include "wm_adsp.h"
#include "wm5110.h" #include "wm5110.h"
#define WM5110_NUM_ADSP 4
struct wm5110_priv { struct wm5110_priv {
struct arizona_priv core; struct arizona_priv core;
struct arizona_fll fll[2]; struct arizona_fll fll[2];
}; };
static const struct wm_adsp_region wm5110_dsp1_regions[] = {
{ .type = WMFW_ADSP2_PM, .base = 0x100000 },
{ .type = WMFW_ADSP2_ZM, .base = 0x180000 },
{ .type = WMFW_ADSP2_XM, .base = 0x190000 },
{ .type = WMFW_ADSP2_YM, .base = 0x1a8000 },
};
static const struct wm_adsp_region wm5110_dsp2_regions[] = {
{ .type = WMFW_ADSP2_PM, .base = 0x200000 },
{ .type = WMFW_ADSP2_ZM, .base = 0x280000 },
{ .type = WMFW_ADSP2_XM, .base = 0x290000 },
{ .type = WMFW_ADSP2_YM, .base = 0x2a8000 },
};
static const struct wm_adsp_region wm5110_dsp3_regions[] = {
{ .type = WMFW_ADSP2_PM, .base = 0x300000 },
{ .type = WMFW_ADSP2_ZM, .base = 0x380000 },
{ .type = WMFW_ADSP2_XM, .base = 0x390000 },
{ .type = WMFW_ADSP2_YM, .base = 0x3a8000 },
};
static const struct wm_adsp_region wm5110_dsp4_regions[] = {
{ .type = WMFW_ADSP2_PM, .base = 0x400000 },
{ .type = WMFW_ADSP2_ZM, .base = 0x480000 },
{ .type = WMFW_ADSP2_XM, .base = 0x490000 },
{ .type = WMFW_ADSP2_YM, .base = 0x4a8000 },
};
static const struct wm_adsp_region *wm5110_dsp_regions[] = {
wm5110_dsp1_regions,
wm5110_dsp2_regions,
wm5110_dsp3_regions,
wm5110_dsp4_regions,
};
static const struct reg_default wm5110_sysclk_revd_patch[] = { static const struct reg_default wm5110_sysclk_revd_patch[] = {
{ 0x3093, 0x1001 }, { 0x3093, 0x1001 },
{ 0x30E3, 0x1301 }, { 0x30E3, 0x1301 },
@ -67,8 +105,8 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU: case SND_SOC_DAPM_POST_PMU:
if (patch) if (patch)
for (i = 0; i < patch_size; i++) for (i = 0; i < patch_size; i++)
regmap_write(regmap, patch[i].reg, regmap_write_async(regmap, patch[i].reg,
patch[i].def); patch[i].def);
break; break;
default: default:
@ -117,6 +155,25 @@ SOC_SINGLE_RANGE_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL,
SOC_SINGLE_RANGE_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL, SOC_SINGLE_RANGE_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL,
ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
SOC_ENUM("IN HPF Cutoff Frequency", arizona_in_hpf_cut_enum),
SOC_SINGLE("IN1L HPF Switch", ARIZONA_IN1L_CONTROL,
ARIZONA_IN1L_HPF_SHIFT, 1, 0),
SOC_SINGLE("IN1R HPF Switch", ARIZONA_IN1R_CONTROL,
ARIZONA_IN1R_HPF_SHIFT, 1, 0),
SOC_SINGLE("IN2L HPF Switch", ARIZONA_IN2L_CONTROL,
ARIZONA_IN2L_HPF_SHIFT, 1, 0),
SOC_SINGLE("IN2R HPF Switch", ARIZONA_IN2R_CONTROL,
ARIZONA_IN2R_HPF_SHIFT, 1, 0),
SOC_SINGLE("IN3L HPF Switch", ARIZONA_IN3L_CONTROL,
ARIZONA_IN3L_HPF_SHIFT, 1, 0),
SOC_SINGLE("IN3R HPF Switch", ARIZONA_IN3R_CONTROL,
ARIZONA_IN3R_HPF_SHIFT, 1, 0),
SOC_SINGLE("IN4L HPF Switch", ARIZONA_IN4L_CONTROL,
ARIZONA_IN4L_HPF_SHIFT, 1, 0),
SOC_SINGLE("IN4R HPF Switch", ARIZONA_IN4R_CONTROL,
ARIZONA_IN4R_HPF_SHIFT, 1, 0),
SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L, SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R, SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R,
@ -220,6 +277,14 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode), SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
SOC_VALUE_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]),
SOC_VALUE_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]),
SOC_VALUE_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
SOC_VALUE_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
SOC_VALUE_ENUM("ASRC RATE 1", arizona_asrc_rate1),
ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE),
@ -285,6 +350,13 @@ SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,
SOC_DOUBLE("SPKDAT2 Switch", ARIZONA_PDM_SPK2_CTRL_1, ARIZONA_SPK2L_MUTE_SHIFT, SOC_DOUBLE("SPKDAT2 Switch", ARIZONA_PDM_SPK2_CTRL_1, ARIZONA_SPK2L_MUTE_SHIFT,
ARIZONA_SPK2R_MUTE_SHIFT, 1, 1), ARIZONA_SPK2R_MUTE_SHIFT, 1, 1),
SOC_DOUBLE("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE,
ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0),
SOC_DOUBLE("HPOUT2 DRE Switch", ARIZONA_DRE_ENABLE,
ARIZONA_DRE2L_ENA_SHIFT, ARIZONA_DRE2R_ENA_SHIFT, 1, 0),
SOC_DOUBLE("HPOUT3 DRE Switch", ARIZONA_DRE_ENABLE,
ARIZONA_DRE3L_ENA_SHIFT, ARIZONA_DRE3R_ENA_SHIFT, 1, 0),
SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp), SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp), SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
@ -318,6 +390,10 @@ ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF2TX3", ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF2TX4", ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF2TX5", ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF2TX6", ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
@ -347,6 +423,22 @@ ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(DSP1L, ARIZONA_DSP1LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(DSP1R, ARIZONA_DSP1RMIX_INPUT_1_SOURCE);
ARIZONA_DSP_AUX_ENUMS(DSP1, ARIZONA_DSP1AUX1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(DSP2L, ARIZONA_DSP2LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(DSP2R, ARIZONA_DSP2RMIX_INPUT_1_SOURCE);
ARIZONA_DSP_AUX_ENUMS(DSP2, ARIZONA_DSP2AUX1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(DSP3L, ARIZONA_DSP3LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(DSP3R, ARIZONA_DSP3RMIX_INPUT_1_SOURCE);
ARIZONA_DSP_AUX_ENUMS(DSP3, ARIZONA_DSP3AUX1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(DSP4L, ARIZONA_DSP4LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(DSP4R, ARIZONA_DSP4RMIX_INPUT_1_SOURCE);
ARIZONA_DSP_AUX_ENUMS(DSP4, ARIZONA_DSP4AUX1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(Mic, ARIZONA_MICMIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(Mic, ARIZONA_MICMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(Noise, ARIZONA_NOISEMIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(Noise, ARIZONA_NOISEMIX_INPUT_1_SOURCE);
@ -377,6 +469,10 @@ ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF2TX3, ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF2TX4, ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF2TX5, ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF2TX6, ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE);
@ -395,6 +491,36 @@ ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE); ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE); ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC1INT3, ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC1INT4, ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC1DEC3, ARIZONA_ISRC1DEC3MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC1DEC4, ARIZONA_ISRC1DEC4MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC2INT3, ARIZONA_ISRC2INT3MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC2INT4, ARIZONA_ISRC2INT4MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC2DEC3, ARIZONA_ISRC2DEC3MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC2DEC4, ARIZONA_ISRC2DEC4MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC3INT1, ARIZONA_ISRC3INT1MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC3INT2, ARIZONA_ISRC3INT2MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC3INT3, ARIZONA_ISRC3INT3MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC3INT4, ARIZONA_ISRC3INT4MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC3DEC1, ARIZONA_ISRC3DEC1MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC3DEC2, ARIZONA_ISRC3DEC2MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC3DEC3, ARIZONA_ISRC3DEC3MIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ISRC3DEC4, ARIZONA_ISRC3DEC4MIX_INPUT_1_SOURCE);
static const char *wm5110_aec_loopback_texts[] = { static const char *wm5110_aec_loopback_texts[] = {
"HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "HPOUT3L", "HPOUT3R", "HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "HPOUT3L", "HPOUT3R",
"SPKOUTL", "SPKOUTR", "SPKDAT1L", "SPKDAT1R", "SPKDAT2L", "SPKDAT2R", "SPKOUTL", "SPKOUTR", "SPKDAT1L", "SPKDAT1R", "SPKDAT2L", "SPKDAT2R",
@ -535,6 +661,65 @@ SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0, SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
NULL, 0), NULL, 0),
WM_ADSP2("DSP1", 0),
WM_ADSP2("DSP2", 1),
WM_ADSP2("DSP3", 2),
WM_ADSP2("DSP4", 3),
SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3,
ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC1INT3", ARIZONA_ISRC_1_CTRL_3,
ARIZONA_ISRC1_INT2_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC1INT4", ARIZONA_ISRC_1_CTRL_3,
ARIZONA_ISRC1_INT3_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3,
ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3,
ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC1DEC3", ARIZONA_ISRC_1_CTRL_3,
ARIZONA_ISRC1_DEC2_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC1DEC4", ARIZONA_ISRC_1_CTRL_3,
ARIZONA_ISRC1_DEC3_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3,
ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3,
ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC2INT3", ARIZONA_ISRC_2_CTRL_3,
ARIZONA_ISRC2_INT2_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC2INT4", ARIZONA_ISRC_2_CTRL_3,
ARIZONA_ISRC2_INT3_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3,
ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3,
ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC2DEC3", ARIZONA_ISRC_2_CTRL_3,
ARIZONA_ISRC2_DEC2_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC2DEC4", ARIZONA_ISRC_2_CTRL_3,
ARIZONA_ISRC2_DEC3_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC3INT1", ARIZONA_ISRC_3_CTRL_3,
ARIZONA_ISRC3_INT0_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC3INT2", ARIZONA_ISRC_3_CTRL_3,
ARIZONA_ISRC3_INT1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC3INT3", ARIZONA_ISRC_3_CTRL_3,
ARIZONA_ISRC3_INT2_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC3INT4", ARIZONA_ISRC_3_CTRL_3,
ARIZONA_ISRC3_INT3_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC3DEC1", ARIZONA_ISRC_3_CTRL_3,
ARIZONA_ISRC3_DEC0_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC3DEC2", ARIZONA_ISRC_3_CTRL_3,
ARIZONA_ISRC3_DEC1_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC3DEC3", ARIZONA_ISRC_3_CTRL_3,
ARIZONA_ISRC3_DEC2_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC3DEC4", ARIZONA_ISRC_3_CTRL_3,
ARIZONA_ISRC3_DEC3_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
&wm5110_aec_loopback_mux), &wm5110_aec_loopback_mux),
@ -577,11 +762,27 @@ SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0,
ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0), ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0,
ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0), ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0,
ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0,
ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0,
ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0,
ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,
ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0), ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,
ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0), ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0,
ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0,
ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0,
ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0,
ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0, SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0,
ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
@ -719,6 +920,10 @@ ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),
ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"), ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"), ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
ARIZONA_MIXER_WIDGETS(AIF2TX3, "AIF2TX3"),
ARIZONA_MIXER_WIDGETS(AIF2TX4, "AIF2TX4"),
ARIZONA_MIXER_WIDGETS(AIF2TX5, "AIF2TX5"),
ARIZONA_MIXER_WIDGETS(AIF2TX6, "AIF2TX6"),
ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"), ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"), ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
@ -737,6 +942,41 @@ ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"),
ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"), ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"),
ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"), ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"),
ARIZONA_DSP_WIDGETS(DSP1, "DSP1"),
ARIZONA_DSP_WIDGETS(DSP2, "DSP2"),
ARIZONA_DSP_WIDGETS(DSP3, "DSP3"),
ARIZONA_DSP_WIDGETS(DSP4, "DSP4"),
ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"),
ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"),
ARIZONA_MUX_WIDGETS(ISRC1DEC3, "ISRC1DEC3"),
ARIZONA_MUX_WIDGETS(ISRC1DEC4, "ISRC1DEC4"),
ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"),
ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"),
ARIZONA_MUX_WIDGETS(ISRC1INT3, "ISRC1INT3"),
ARIZONA_MUX_WIDGETS(ISRC1INT4, "ISRC1INT4"),
ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"),
ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
ARIZONA_MUX_WIDGETS(ISRC2DEC3, "ISRC2DEC3"),
ARIZONA_MUX_WIDGETS(ISRC2DEC4, "ISRC2DEC4"),
ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
ARIZONA_MUX_WIDGETS(ISRC2INT3, "ISRC2INT3"),
ARIZONA_MUX_WIDGETS(ISRC2INT4, "ISRC2INT4"),
ARIZONA_MUX_WIDGETS(ISRC3DEC1, "ISRC3DEC1"),
ARIZONA_MUX_WIDGETS(ISRC3DEC2, "ISRC3DEC2"),
ARIZONA_MUX_WIDGETS(ISRC3DEC3, "ISRC3DEC3"),
ARIZONA_MUX_WIDGETS(ISRC3DEC4, "ISRC3DEC4"),
ARIZONA_MUX_WIDGETS(ISRC3INT1, "ISRC3INT1"),
ARIZONA_MUX_WIDGETS(ISRC3INT2, "ISRC3INT2"),
ARIZONA_MUX_WIDGETS(ISRC3INT3, "ISRC3INT3"),
ARIZONA_MUX_WIDGETS(ISRC3INT4, "ISRC3INT4"),
SND_SOC_DAPM_OUTPUT("HPOUT1L"), SND_SOC_DAPM_OUTPUT("HPOUT1L"),
SND_SOC_DAPM_OUTPUT("HPOUT1R"), SND_SOC_DAPM_OUTPUT("HPOUT1R"),
SND_SOC_DAPM_OUTPUT("HPOUT2L"), SND_SOC_DAPM_OUTPUT("HPOUT2L"),
@ -780,6 +1020,10 @@ SND_SOC_DAPM_OUTPUT("MICSUPP"),
{ name, "AIF1RX8", "AIF1RX8" }, \ { name, "AIF1RX8", "AIF1RX8" }, \
{ name, "AIF2RX1", "AIF2RX1" }, \ { name, "AIF2RX1", "AIF2RX1" }, \
{ name, "AIF2RX2", "AIF2RX2" }, \ { name, "AIF2RX2", "AIF2RX2" }, \
{ name, "AIF2RX3", "AIF2RX3" }, \
{ name, "AIF2RX4", "AIF2RX4" }, \
{ name, "AIF2RX5", "AIF2RX5" }, \
{ name, "AIF2RX6", "AIF2RX6" }, \
{ name, "AIF3RX1", "AIF3RX1" }, \ { name, "AIF3RX1", "AIF3RX1" }, \
{ name, "AIF3RX2", "AIF3RX2" }, \ { name, "AIF3RX2", "AIF3RX2" }, \
{ name, "SLIMRX1", "SLIMRX1" }, \ { name, "SLIMRX1", "SLIMRX1" }, \
@ -805,7 +1049,55 @@ SND_SOC_DAPM_OUTPUT("MICSUPP"),
{ name, "ASRC1L", "ASRC1L" }, \ { name, "ASRC1L", "ASRC1L" }, \
{ name, "ASRC1R", "ASRC1R" }, \ { name, "ASRC1R", "ASRC1R" }, \
{ name, "ASRC2L", "ASRC2L" }, \ { name, "ASRC2L", "ASRC2L" }, \
{ name, "ASRC2R", "ASRC2R" } { name, "ASRC2R", "ASRC2R" }, \
{ name, "ISRC1DEC1", "ISRC1DEC1" }, \
{ name, "ISRC1DEC2", "ISRC1DEC2" }, \
{ name, "ISRC1DEC3", "ISRC1DEC3" }, \
{ name, "ISRC1DEC4", "ISRC1DEC4" }, \
{ name, "ISRC1INT1", "ISRC1INT1" }, \
{ name, "ISRC1INT2", "ISRC1INT2" }, \
{ name, "ISRC1INT3", "ISRC1INT3" }, \
{ name, "ISRC1INT4", "ISRC1INT4" }, \
{ name, "ISRC2DEC1", "ISRC2DEC1" }, \
{ name, "ISRC2DEC2", "ISRC2DEC2" }, \
{ name, "ISRC2DEC3", "ISRC2DEC3" }, \
{ name, "ISRC2DEC4", "ISRC2DEC4" }, \
{ name, "ISRC2INT1", "ISRC2INT1" }, \
{ name, "ISRC2INT2", "ISRC2INT2" }, \
{ name, "ISRC2INT3", "ISRC2INT3" }, \
{ name, "ISRC2INT4", "ISRC2INT4" }, \
{ name, "ISRC3DEC1", "ISRC3DEC1" }, \
{ name, "ISRC3DEC2", "ISRC3DEC2" }, \
{ name, "ISRC3DEC3", "ISRC3DEC3" }, \
{ name, "ISRC3DEC4", "ISRC3DEC4" }, \
{ name, "ISRC3INT1", "ISRC3INT1" }, \
{ name, "ISRC3INT2", "ISRC3INT2" }, \
{ name, "ISRC3INT3", "ISRC3INT3" }, \
{ name, "ISRC3INT4", "ISRC3INT4" }, \
{ name, "DSP1.1", "DSP1" }, \
{ name, "DSP1.2", "DSP1" }, \
{ name, "DSP1.3", "DSP1" }, \
{ name, "DSP1.4", "DSP1" }, \
{ name, "DSP1.5", "DSP1" }, \
{ name, "DSP1.6", "DSP1" }, \
{ name, "DSP2.1", "DSP2" }, \
{ name, "DSP2.2", "DSP2" }, \
{ name, "DSP2.3", "DSP2" }, \
{ name, "DSP2.4", "DSP2" }, \
{ name, "DSP2.5", "DSP2" }, \
{ name, "DSP2.6", "DSP2" }, \
{ name, "DSP3.1", "DSP3" }, \
{ name, "DSP3.2", "DSP3" }, \
{ name, "DSP3.3", "DSP3" }, \
{ name, "DSP3.4", "DSP3" }, \
{ name, "DSP3.5", "DSP3" }, \
{ name, "DSP3.6", "DSP3" }, \
{ name, "DSP4.1", "DSP4" }, \
{ name, "DSP4.2", "DSP4" }, \
{ name, "DSP4.3", "DSP4" }, \
{ name, "DSP4.4", "DSP4" }, \
{ name, "DSP4.5", "DSP4" }, \
{ name, "DSP4.6", "DSP4" }
static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
{ "AIF2 Capture", NULL, "DBVDD2" }, { "AIF2 Capture", NULL, "DBVDD2" },
@ -877,9 +1169,17 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
{ "AIF2 Capture", NULL, "AIF2TX1" }, { "AIF2 Capture", NULL, "AIF2TX1" },
{ "AIF2 Capture", NULL, "AIF2TX2" }, { "AIF2 Capture", NULL, "AIF2TX2" },
{ "AIF2 Capture", NULL, "AIF2TX3" },
{ "AIF2 Capture", NULL, "AIF2TX4" },
{ "AIF2 Capture", NULL, "AIF2TX5" },
{ "AIF2 Capture", NULL, "AIF2TX6" },
{ "AIF2RX1", NULL, "AIF2 Playback" }, { "AIF2RX1", NULL, "AIF2 Playback" },
{ "AIF2RX2", NULL, "AIF2 Playback" }, { "AIF2RX2", NULL, "AIF2 Playback" },
{ "AIF2RX3", NULL, "AIF2 Playback" },
{ "AIF2RX4", NULL, "AIF2 Playback" },
{ "AIF2RX5", NULL, "AIF2 Playback" },
{ "AIF2RX6", NULL, "AIF2 Playback" },
{ "AIF3 Capture", NULL, "AIF3TX1" }, { "AIF3 Capture", NULL, "AIF3TX1" },
{ "AIF3 Capture", NULL, "AIF3TX2" }, { "AIF3 Capture", NULL, "AIF3TX2" },
@ -963,6 +1263,10 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"), ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"), ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
ARIZONA_MIXER_ROUTES("AIF2TX3", "AIF2TX3"),
ARIZONA_MIXER_ROUTES("AIF2TX4", "AIF2TX4"),
ARIZONA_MIXER_ROUTES("AIF2TX5", "AIF2TX5"),
ARIZONA_MIXER_ROUTES("AIF2TX6", "AIF2TX6"),
ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"), ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"), ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
@ -999,6 +1303,41 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"), ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"),
ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"), ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"),
ARIZONA_DSP_ROUTES("DSP1"),
ARIZONA_DSP_ROUTES("DSP2"),
ARIZONA_DSP_ROUTES("DSP3"),
ARIZONA_DSP_ROUTES("DSP4"),
ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
ARIZONA_MUX_ROUTES("ISRC1INT3", "ISRC1INT3"),
ARIZONA_MUX_ROUTES("ISRC1INT4", "ISRC1INT4"),
ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
ARIZONA_MUX_ROUTES("ISRC1DEC3", "ISRC1DEC3"),
ARIZONA_MUX_ROUTES("ISRC1DEC4", "ISRC1DEC4"),
ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
ARIZONA_MUX_ROUTES("ISRC2INT3", "ISRC2INT3"),
ARIZONA_MUX_ROUTES("ISRC2INT4", "ISRC2INT4"),
ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
ARIZONA_MUX_ROUTES("ISRC2DEC3", "ISRC2DEC3"),
ARIZONA_MUX_ROUTES("ISRC2DEC4", "ISRC2DEC4"),
ARIZONA_MUX_ROUTES("ISRC3INT1", "ISRC3INT1"),
ARIZONA_MUX_ROUTES("ISRC3INT2", "ISRC3INT2"),
ARIZONA_MUX_ROUTES("ISRC3INT3", "ISRC3INT3"),
ARIZONA_MUX_ROUTES("ISRC3INT4", "ISRC3INT4"),
ARIZONA_MUX_ROUTES("ISRC3DEC1", "ISRC3DEC1"),
ARIZONA_MUX_ROUTES("ISRC3DEC2", "ISRC3DEC2"),
ARIZONA_MUX_ROUTES("ISRC3DEC3", "ISRC3DEC3"),
ARIZONA_MUX_ROUTES("ISRC3DEC4", "ISRC3DEC4"),
{ "AEC Loopback", "HPOUT1L", "OUT1L" }, { "AEC Loopback", "HPOUT1L", "OUT1L" },
{ "AEC Loopback", "HPOUT1R", "OUT1R" }, { "AEC Loopback", "HPOUT1R", "OUT1R" },
{ "HPOUT1L", NULL, "OUT1L" }, { "HPOUT1L", NULL, "OUT1L" },
@ -1095,14 +1434,14 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
.playback = { .playback = {
.stream_name = "AIF2 Playback", .stream_name = "AIF2 Playback",
.channels_min = 1, .channels_min = 1,
.channels_max = 2, .channels_max = 6,
.rates = WM5110_RATES, .rates = WM5110_RATES,
.formats = WM5110_FORMATS, .formats = WM5110_FORMATS,
}, },
.capture = { .capture = {
.stream_name = "AIF2 Capture", .stream_name = "AIF2 Capture",
.channels_min = 1, .channels_min = 1,
.channels_max = 2, .channels_max = 6,
.rates = WM5110_RATES, .rates = WM5110_RATES,
.formats = WM5110_FORMATS, .formats = WM5110_FORMATS,
}, },
@ -1204,6 +1543,10 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
arizona_init_spk(codec); arizona_init_spk(codec);
arizona_init_gpio(codec); arizona_init_gpio(codec);
ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 8);
if (ret != 0)
return ret;
snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS"); snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
priv->core.arizona->dapm = &codec->dapm; priv->core.arizona->dapm = &codec->dapm;
@ -1258,7 +1601,7 @@ static int wm5110_probe(struct platform_device *pdev)
{ {
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
struct wm5110_priv *wm5110; struct wm5110_priv *wm5110;
int i; int i, ret;
wm5110 = devm_kzalloc(&pdev->dev, sizeof(struct wm5110_priv), wm5110 = devm_kzalloc(&pdev->dev, sizeof(struct wm5110_priv),
GFP_KERNEL); GFP_KERNEL);
@ -1269,6 +1612,24 @@ static int wm5110_probe(struct platform_device *pdev)
wm5110->core.arizona = arizona; wm5110->core.arizona = arizona;
wm5110->core.num_inputs = 8; wm5110->core.num_inputs = 8;
for (i = 0; i < WM5110_NUM_ADSP; i++) {
wm5110->core.adsp[i].part = "wm5110";
wm5110->core.adsp[i].num = i + 1;
wm5110->core.adsp[i].type = WMFW_ADSP2;
wm5110->core.adsp[i].dev = arizona->dev;
wm5110->core.adsp[i].regmap = arizona->regmap;
wm5110->core.adsp[i].base = ARIZONA_DSP1_CONTROL_1
+ (0x100 * i);
wm5110->core.adsp[i].mem = wm5110_dsp_regions[i];
wm5110->core.adsp[i].num_mems
= ARRAY_SIZE(wm5110_dsp1_regions);
ret = wm_adsp2_init(&wm5110->core.adsp[i], false);
if (ret != 0)
return ret;
}
for (i = 0; i < ARRAY_SIZE(wm5110->fll); i++) for (i = 0; i < ARRAY_SIZE(wm5110->fll); i++)
wm5110->fll[i].vco_mult = 3; wm5110->fll[i].vco_mult = 3;
@ -1279,6 +1640,12 @@ static int wm5110_probe(struct platform_device *pdev)
ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK, ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
&wm5110->fll[1]); &wm5110->fll[1]);
/* SR2 fixed at 8kHz, SR3 fixed at 16kHz */
regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2,
ARIZONA_SAMPLE_RATE_2_MASK, 0x11);
regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3,
ARIZONA_SAMPLE_RATE_3_MASK, 0x12);
for (i = 0; i < ARRAY_SIZE(wm5110_dai); i++) for (i = 0; i < ARRAY_SIZE(wm5110_dai); i++)
arizona_init_dai(&wm5110->core, i); arizona_init_dai(&wm5110->core, i);

View File

@ -684,7 +684,7 @@ static struct spi_driver wm8510_spi_driver = {
}; };
#endif /* CONFIG_SPI_MASTER */ #endif /* CONFIG_SPI_MASTER */
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static int wm8510_i2c_probe(struct i2c_client *i2c, static int wm8510_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -735,7 +735,7 @@ static struct i2c_driver wm8510_i2c_driver = {
static int __init wm8510_modinit(void) static int __init wm8510_modinit(void)
{ {
int ret = 0; int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8510_i2c_driver); ret = i2c_add_driver(&wm8510_i2c_driver);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR "Failed to register WM8510 I2C driver: %d\n", printk(KERN_ERR "Failed to register WM8510 I2C driver: %d\n",
@ -755,7 +755,7 @@ module_init(wm8510_modinit);
static void __exit wm8510_exit(void) static void __exit wm8510_exit(void)
{ {
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8510_i2c_driver); i2c_del_driver(&wm8510_i2c_driver);
#endif #endif
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)

View File

@ -452,7 +452,7 @@ static const struct regmap_config wm8523_regmap = {
.volatile_reg = wm8523_volatile_register, .volatile_reg = wm8523_volatile_register,
}; };
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static int wm8523_i2c_probe(struct i2c_client *i2c, static int wm8523_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -555,7 +555,7 @@ static struct i2c_driver wm8523_i2c_driver = {
static int __init wm8523_modinit(void) static int __init wm8523_modinit(void)
{ {
int ret; int ret;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8523_i2c_driver); ret = i2c_add_driver(&wm8523_i2c_driver);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR "Failed to register WM8523 I2C driver: %d\n", printk(KERN_ERR "Failed to register WM8523 I2C driver: %d\n",
@ -568,7 +568,7 @@ module_init(wm8523_modinit);
static void __exit wm8523_exit(void) static void __exit wm8523_exit(void)
{ {
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8523_i2c_driver); i2c_del_driver(&wm8523_i2c_driver);
#endif #endif
} }

View File

@ -941,7 +941,7 @@ static const struct regmap_config wm8580_regmap = {
.volatile_reg = wm8580_volatile, .volatile_reg = wm8580_volatile,
}; };
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static int wm8580_i2c_probe(struct i2c_client *i2c, static int wm8580_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -1003,7 +1003,7 @@ static int __init wm8580_modinit(void)
{ {
int ret = 0; int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8580_i2c_driver); ret = i2c_add_driver(&wm8580_i2c_driver);
if (ret != 0) { if (ret != 0) {
pr_err("Failed to register WM8580 I2C driver: %d\n", ret); pr_err("Failed to register WM8580 I2C driver: %d\n", ret);
@ -1016,7 +1016,7 @@ module_init(wm8580_modinit);
static void __exit wm8580_exit(void) static void __exit wm8580_exit(void)
{ {
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8580_i2c_driver); i2c_del_driver(&wm8580_i2c_driver);
#endif #endif
} }

View File

@ -469,7 +469,7 @@ static struct spi_driver wm8711_spi_driver = {
}; };
#endif /* CONFIG_SPI_MASTER */ #endif /* CONFIG_SPI_MASTER */
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static int wm8711_i2c_probe(struct i2c_client *client, static int wm8711_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -520,7 +520,7 @@ static struct i2c_driver wm8711_i2c_driver = {
static int __init wm8711_modinit(void) static int __init wm8711_modinit(void)
{ {
int ret; int ret;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8711_i2c_driver); ret = i2c_add_driver(&wm8711_i2c_driver);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR "Failed to register WM8711 I2C driver: %d\n", printk(KERN_ERR "Failed to register WM8711 I2C driver: %d\n",
@ -540,7 +540,7 @@ module_init(wm8711_modinit);
static void __exit wm8711_exit(void) static void __exit wm8711_exit(void)
{ {
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8711_i2c_driver); i2c_del_driver(&wm8711_i2c_driver);
#endif #endif
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)

View File

@ -320,7 +320,7 @@ static struct spi_driver wm8728_spi_driver = {
}; };
#endif /* CONFIG_SPI_MASTER */ #endif /* CONFIG_SPI_MASTER */
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static int wm8728_i2c_probe(struct i2c_client *i2c, static int wm8728_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -371,7 +371,7 @@ static struct i2c_driver wm8728_i2c_driver = {
static int __init wm8728_modinit(void) static int __init wm8728_modinit(void)
{ {
int ret = 0; int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8728_i2c_driver); ret = i2c_add_driver(&wm8728_i2c_driver);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR "Failed to register wm8728 I2C driver: %d\n", printk(KERN_ERR "Failed to register wm8728 I2C driver: %d\n",
@ -391,7 +391,7 @@ module_init(wm8728_modinit);
static void __exit wm8728_exit(void) static void __exit wm8728_exit(void)
{ {
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8728_i2c_driver); i2c_del_driver(&wm8728_i2c_driver);
#endif #endif
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)

View File

@ -732,7 +732,7 @@ static struct spi_driver wm8731_spi_driver = {
}; };
#endif /* CONFIG_SPI_MASTER */ #endif /* CONFIG_SPI_MASTER */
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static int wm8731_i2c_probe(struct i2c_client *i2c, static int wm8731_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -791,7 +791,7 @@ static struct i2c_driver wm8731_i2c_driver = {
static int __init wm8731_modinit(void) static int __init wm8731_modinit(void)
{ {
int ret = 0; int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8731_i2c_driver); ret = i2c_add_driver(&wm8731_i2c_driver);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR "Failed to register WM8731 I2C driver: %d\n", printk(KERN_ERR "Failed to register WM8731 I2C driver: %d\n",
@ -811,7 +811,7 @@ module_init(wm8731_modinit);
static void __exit wm8731_exit(void) static void __exit wm8731_exit(void)
{ {
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8731_i2c_driver); i2c_del_driver(&wm8731_i2c_driver);
#endif #endif
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)

View File

@ -500,7 +500,7 @@ static const struct regmap_config wm8741_regmap = {
.readable_reg = wm8741_readable, .readable_reg = wm8741_readable,
}; };
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static int wm8741_i2c_probe(struct i2c_client *i2c, static int wm8741_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -617,7 +617,7 @@ static int __init wm8741_modinit(void)
{ {
int ret = 0; int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8741_i2c_driver); ret = i2c_add_driver(&wm8741_i2c_driver);
if (ret != 0) if (ret != 0)
pr_err("Failed to register WM8741 I2C driver: %d\n", ret); pr_err("Failed to register WM8741 I2C driver: %d\n", ret);
@ -639,7 +639,7 @@ static void __exit wm8741_exit(void)
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)
spi_unregister_driver(&wm8741_spi_driver); spi_unregister_driver(&wm8741_spi_driver);
#endif #endif
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8741_i2c_driver); i2c_del_driver(&wm8741_i2c_driver);
#endif #endif
} }

View File

@ -816,7 +816,7 @@ static struct spi_driver wm8750_spi_driver = {
}; };
#endif /* CONFIG_SPI_MASTER */ #endif /* CONFIG_SPI_MASTER */
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static int wm8750_i2c_probe(struct i2c_client *i2c, static int wm8750_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -868,7 +868,7 @@ static struct i2c_driver wm8750_i2c_driver = {
static int __init wm8750_modinit(void) static int __init wm8750_modinit(void)
{ {
int ret = 0; int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8750_i2c_driver); ret = i2c_add_driver(&wm8750_i2c_driver);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR "Failed to register wm8750 I2C driver: %d\n", printk(KERN_ERR "Failed to register wm8750 I2C driver: %d\n",
@ -888,7 +888,7 @@ module_init(wm8750_modinit);
static void __exit wm8750_exit(void) static void __exit wm8750_exit(void)
{ {
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8750_i2c_driver); i2c_del_driver(&wm8750_i2c_driver);
#endif #endif
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)

View File

@ -1596,7 +1596,7 @@ static struct spi_driver wm8753_spi_driver = {
}; };
#endif /* CONFIG_SPI_MASTER */ #endif /* CONFIG_SPI_MASTER */
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static int wm8753_i2c_probe(struct i2c_client *i2c, static int wm8753_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -1653,7 +1653,7 @@ static struct i2c_driver wm8753_i2c_driver = {
static int __init wm8753_modinit(void) static int __init wm8753_modinit(void)
{ {
int ret = 0; int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8753_i2c_driver); ret = i2c_add_driver(&wm8753_i2c_driver);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR "Failed to register wm8753 I2C driver: %d\n", printk(KERN_ERR "Failed to register wm8753 I2C driver: %d\n",
@ -1673,7 +1673,7 @@ module_init(wm8753_modinit);
static void __exit wm8753_exit(void) static void __exit wm8753_exit(void)
{ {
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8753_i2c_driver); i2c_del_driver(&wm8753_i2c_driver);
#endif #endif
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)

View File

@ -532,7 +532,7 @@ static struct spi_driver wm8776_spi_driver = {
}; };
#endif /* CONFIG_SPI_MASTER */ #endif /* CONFIG_SPI_MASTER */
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static int wm8776_i2c_probe(struct i2c_client *i2c, static int wm8776_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -584,7 +584,7 @@ static struct i2c_driver wm8776_i2c_driver = {
static int __init wm8776_modinit(void) static int __init wm8776_modinit(void)
{ {
int ret = 0; int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8776_i2c_driver); ret = i2c_add_driver(&wm8776_i2c_driver);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR "Failed to register wm8776 I2C driver: %d\n", printk(KERN_ERR "Failed to register wm8776 I2C driver: %d\n",
@ -604,7 +604,7 @@ module_init(wm8776_modinit);
static void __exit wm8776_exit(void) static void __exit wm8776_exit(void)
{ {
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8776_i2c_driver); i2c_del_driver(&wm8776_i2c_driver);
#endif #endif
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)

View File

@ -739,7 +739,7 @@ static struct spi_driver wm8804_spi_driver = {
}; };
#endif #endif
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static int wm8804_i2c_probe(struct i2c_client *i2c, static int wm8804_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -791,7 +791,7 @@ static int __init wm8804_modinit(void)
{ {
int ret = 0; int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8804_i2c_driver); ret = i2c_add_driver(&wm8804_i2c_driver);
if (ret) { if (ret) {
printk(KERN_ERR "Failed to register wm8804 I2C driver: %d\n", printk(KERN_ERR "Failed to register wm8804 I2C driver: %d\n",
@ -811,7 +811,7 @@ module_init(wm8804_modinit);
static void __exit wm8804_exit(void) static void __exit wm8804_exit(void)
{ {
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8804_i2c_driver); i2c_del_driver(&wm8804_i2c_driver);
#endif #endif
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)

View File

@ -1288,7 +1288,7 @@ static struct spi_driver wm8900_spi_driver = {
}; };
#endif /* CONFIG_SPI_MASTER */ #endif /* CONFIG_SPI_MASTER */
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static int wm8900_i2c_probe(struct i2c_client *i2c, static int wm8900_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -1338,7 +1338,7 @@ static struct i2c_driver wm8900_i2c_driver = {
static int __init wm8900_modinit(void) static int __init wm8900_modinit(void)
{ {
int ret = 0; int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8900_i2c_driver); ret = i2c_add_driver(&wm8900_i2c_driver);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR "Failed to register wm8900 I2C driver: %d\n", printk(KERN_ERR "Failed to register wm8900 I2C driver: %d\n",
@ -1358,7 +1358,7 @@ module_init(wm8900_modinit);
static void __exit wm8900_exit(void) static void __exit wm8900_exit(void)
{ {
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8900_i2c_driver); i2c_del_driver(&wm8900_i2c_driver);
#endif #endif
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)

View File

@ -28,7 +28,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/spi/spi.h> #include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
@ -41,78 +41,116 @@
struct wm8940_priv { struct wm8940_priv {
unsigned int sysclk; unsigned int sysclk;
enum snd_soc_control_type control_type; struct regmap *regmap;
}; };
static int wm8940_volatile_register(struct snd_soc_codec *codec, static bool wm8940_volatile_register(struct device *dev, unsigned int reg)
unsigned int reg)
{ {
switch (reg) { switch (reg) {
case WM8940_SOFTRESET: case WM8940_SOFTRESET:
return 1; return true;
default: default:
return 0; return false;
} }
} }
static u16 wm8940_reg_defaults[] = { static bool wm8940_readable_register(struct device *dev, unsigned int reg)
0x8940, /* Soft Reset */ {
0x0000, /* Power 1 */ switch (reg) {
0x0000, /* Power 2 */ case WM8940_SOFTRESET:
0x0000, /* Power 3 */ case WM8940_POWER1:
0x0010, /* Interface Control */ case WM8940_POWER2:
0x0000, /* Companding Control */ case WM8940_POWER3:
0x0140, /* Clock Control */ case WM8940_IFACE:
0x0000, /* Additional Controls */ case WM8940_COMPANDINGCTL:
0x0000, /* GPIO Control */ case WM8940_CLOCK:
0x0002, /* Auto Increment Control */ case WM8940_ADDCNTRL:
0x0000, /* DAC Control */ case WM8940_GPIO:
0x00FF, /* DAC Volume */ case WM8940_CTLINT:
0, case WM8940_DAC:
0, case WM8940_DACVOL:
0x0100, /* ADC Control */ case WM8940_ADC:
0x00FF, /* ADC Volume */ case WM8940_ADCVOL:
0x0000, /* Notch Filter 1 Control 1 */ case WM8940_NOTCH1:
0x0000, /* Notch Filter 1 Control 2 */ case WM8940_NOTCH2:
0x0000, /* Notch Filter 2 Control 1 */ case WM8940_NOTCH3:
0x0000, /* Notch Filter 2 Control 2 */ case WM8940_NOTCH4:
0x0000, /* Notch Filter 3 Control 1 */ case WM8940_NOTCH5:
0x0000, /* Notch Filter 3 Control 2 */ case WM8940_NOTCH6:
0x0000, /* Notch Filter 4 Control 1 */ case WM8940_NOTCH7:
0x0000, /* Notch Filter 4 Control 2 */ case WM8940_NOTCH8:
0x0032, /* DAC Limit Control 1 */ case WM8940_DACLIM1:
0x0000, /* DAC Limit Control 2 */ case WM8940_DACLIM2:
0, case WM8940_ALC1:
0, case WM8940_ALC2:
0, case WM8940_ALC3:
0, case WM8940_NOISEGATE:
0, case WM8940_PLLN:
0, case WM8940_PLLK1:
0x0038, /* ALC Control 1 */ case WM8940_PLLK2:
0x000B, /* ALC Control 2 */ case WM8940_PLLK3:
0x0032, /* ALC Control 3 */ case WM8940_ALC4:
0x0000, /* Noise Gate */ case WM8940_INPUTCTL:
0x0041, /* PLLN */ case WM8940_PGAGAIN:
0x000C, /* PLLK1 */ case WM8940_ADCBOOST:
0x0093, /* PLLK2 */ case WM8940_OUTPUTCTL:
0x00E9, /* PLLK3 */ case WM8940_SPKMIX:
0, case WM8940_SPKVOL:
0, case WM8940_MONOMIX:
0x0030, /* ALC Control 4 */ return true;
0, default:
0x0002, /* Input Control */ return false;
0x0050, /* PGA Gain */ }
0, }
0x0002, /* ADC Boost Control */
0, static const struct reg_default wm8940_reg_defaults[] = {
0x0002, /* Output Control */ { 0x1, 0x0000 }, /* Power 1 */
0x0000, /* Speaker Mixer Control */ { 0x2, 0x0000 }, /* Power 2 */
0, { 0x3, 0x0000 }, /* Power 3 */
0, { 0x4, 0x0010 }, /* Interface Control */
0, { 0x5, 0x0000 }, /* Companding Control */
0x0079, /* Speaker Volume */ { 0x6, 0x0140 }, /* Clock Control */
0, { 0x7, 0x0000 }, /* Additional Controls */
0x0000, /* Mono Mixer Control */ { 0x8, 0x0000 }, /* GPIO Control */
{ 0x9, 0x0002 }, /* Auto Increment Control */
{ 0xa, 0x0000 }, /* DAC Control */
{ 0xb, 0x00FF }, /* DAC Volume */
{ 0xe, 0x0100 }, /* ADC Control */
{ 0xf, 0x00FF }, /* ADC Volume */
{ 0x10, 0x0000 }, /* Notch Filter 1 Control 1 */
{ 0x11, 0x0000 }, /* Notch Filter 1 Control 2 */
{ 0x12, 0x0000 }, /* Notch Filter 2 Control 1 */
{ 0x13, 0x0000 }, /* Notch Filter 2 Control 2 */
{ 0x14, 0x0000 }, /* Notch Filter 3 Control 1 */
{ 0x15, 0x0000 }, /* Notch Filter 3 Control 2 */
{ 0x16, 0x0000 }, /* Notch Filter 4 Control 1 */
{ 0x17, 0x0000 }, /* Notch Filter 4 Control 2 */
{ 0x18, 0x0032 }, /* DAC Limit Control 1 */
{ 0x19, 0x0000 }, /* DAC Limit Control 2 */
{ 0x20, 0x0038 }, /* ALC Control 1 */
{ 0x21, 0x000B }, /* ALC Control 2 */
{ 0x22, 0x0032 }, /* ALC Control 3 */
{ 0x23, 0x0000 }, /* Noise Gate */
{ 0x24, 0x0041 }, /* PLLN */
{ 0x25, 0x000C }, /* PLLK1 */
{ 0x26, 0x0093 }, /* PLLK2 */
{ 0x27, 0x00E9 }, /* PLLK3 */
{ 0x2a, 0x0030 }, /* ALC Control 4 */
{ 0x2c, 0x0002 }, /* Input Control */
{ 0x2d, 0x0050 }, /* PGA Gain */
{ 0x2f, 0x0002 }, /* ADC Boost Control */
{ 0x31, 0x0002 }, /* Output Control */
{ 0x32, 0x0000 }, /* Speaker Mixer Control */
{ 0x36, 0x0079 }, /* Speaker Volume */
{ 0x38, 0x0000 }, /* Mono Mixer Control */
}; };
static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" }; static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" };
@ -264,7 +302,7 @@ static const struct snd_soc_dapm_widget wm8940_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("AUX"), 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 output mixer */
{"Mono Mixer", "PCM Playback Switch", "DAC"}, {"Mono Mixer", "PCM Playback Switch", "DAC"},
{"Mono Mixer", "Aux Playback Switch", "Aux Input"}, {"Mono Mixer", "Aux Playback Switch", "Aux Input"},
@ -296,21 +334,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"ADC", NULL, "Boost Mixer"}, {"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); #define wm8940_reset(c) snd_soc_write(c, WM8940_SOFTRESET, 0);
static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai, static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
@ -446,6 +469,7 @@ static int wm8940_mute(struct snd_soc_dai *dai, int mute)
static int wm8940_set_bias_level(struct snd_soc_codec *codec, static int wm8940_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);
u16 val; u16 val;
u16 pwr_reg = snd_soc_read(codec, WM8940_POWER1) & 0x1F0; u16 pwr_reg = snd_soc_read(codec, WM8940_POWER1) & 0x1F0;
int ret = 0; int ret = 0;
@ -469,7 +493,7 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec,
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
ret = snd_soc_cache_sync(codec); ret = regcache_sync(wm8940->regmap);
if (ret < 0) { if (ret < 0) {
dev_err(codec->dev, "Failed to sync cache: %d\n", ret); dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
return ret; return ret;
@ -684,12 +708,11 @@ static int wm8940_resume(struct snd_soc_codec *codec)
static int wm8940_probe(struct snd_soc_codec *codec) static int wm8940_probe(struct snd_soc_codec *codec)
{ {
struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);
struct wm8940_setup_data *pdata = codec->dev->platform_data; struct wm8940_setup_data *pdata = codec->dev->platform_data;
int ret; int ret;
u16 reg; u16 reg;
ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8940->control_type); ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
if (ret < 0) { if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret; return ret;
@ -716,11 +739,6 @@ static int wm8940_probe(struct snd_soc_codec *codec)
return ret; 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; return ret;
} }
@ -736,10 +754,24 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8940 = {
.suspend = wm8940_suspend, .suspend = wm8940_suspend,
.resume = wm8940_resume, .resume = wm8940_resume,
.set_bias_level = wm8940_set_bias_level, .set_bias_level = wm8940_set_bias_level,
.reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults), .controls = wm8940_snd_controls,
.reg_word_size = sizeof(u16), .num_controls = ARRAY_SIZE(wm8940_snd_controls),
.reg_cache_default = wm8940_reg_defaults, .dapm_widgets = wm8940_dapm_widgets,
.volatile_register = wm8940_volatile_register, .num_dapm_widgets = ARRAY_SIZE(wm8940_dapm_widgets),
.dapm_routes = wm8940_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(wm8940_dapm_routes),
};
static const struct regmap_config wm8940_regmap = {
.reg_bits = 8,
.val_bits = 16,
.max_register = WM8940_MONOMIX,
.reg_defaults = wm8940_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8940_reg_defaults),
.readable_reg = wm8940_readable_register,
.volatile_reg = wm8940_volatile_register,
}; };
static int wm8940_i2c_probe(struct i2c_client *i2c, static int wm8940_i2c_probe(struct i2c_client *i2c,
@ -753,8 +785,11 @@ static int wm8940_i2c_probe(struct i2c_client *i2c,
if (wm8940 == NULL) if (wm8940 == NULL)
return -ENOMEM; return -ENOMEM;
wm8940->regmap = devm_regmap_init_i2c(i2c, &wm8940_regmap);
if (IS_ERR(wm8940->regmap))
return PTR_ERR(wm8940->regmap);
i2c_set_clientdata(i2c, wm8940); i2c_set_clientdata(i2c, wm8940);
wm8940->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c->dev, ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8940, &wm8940_dai, 1); &soc_codec_dev_wm8940, &wm8940_dai, 1);

View File

@ -74,7 +74,7 @@ struct wm8962_priv {
struct regulator_bulk_data supplies[WM8962_NUM_SUPPLIES]; struct regulator_bulk_data supplies[WM8962_NUM_SUPPLIES];
struct notifier_block disable_nb[WM8962_NUM_SUPPLIES]; struct notifier_block disable_nb[WM8962_NUM_SUPPLIES];
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) #if IS_ENABLED(CONFIG_INPUT)
struct input_dev *beep; struct input_dev *beep;
struct work_struct beep_work; struct work_struct beep_work;
int beep_rate; int beep_rate;
@ -3121,7 +3121,7 @@ int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
} }
EXPORT_SYMBOL_GPL(wm8962_mic_detect); EXPORT_SYMBOL_GPL(wm8962_mic_detect);
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) #if IS_ENABLED(CONFIG_INPUT)
static int beep_rates[] = { static int beep_rates[] = {
500, 1000, 2000, 4000, 500, 1000, 2000, 4000,
}; };

View File

@ -17,6 +17,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
@ -27,22 +28,22 @@
#include "wm8974.h" #include "wm8974.h"
static const u16 wm8974_reg[WM8974_CACHEREGNUM] = { static const struct reg_default wm8974_reg_defaults[] = {
0x0000, 0x0000, 0x0000, 0x0000, { 0, 0x0000 }, { 1, 0x0000 }, { 2, 0x0000 }, { 3, 0x0000 },
0x0050, 0x0000, 0x0140, 0x0000, { 4, 0x0050 }, { 5, 0x0000 }, { 6, 0x0140 }, { 7, 0x0000 },
0x0000, 0x0000, 0x0000, 0x00ff, { 8, 0x0000 }, { 9, 0x0000 }, { 10, 0x0000 }, { 11, 0x00ff },
0x0000, 0x0000, 0x0100, 0x00ff, { 12, 0x0000 }, { 13, 0x0000 }, { 14, 0x0100 }, { 15, 0x00ff },
0x0000, 0x0000, 0x012c, 0x002c, { 16, 0x0000 }, { 17, 0x0000 }, { 18, 0x012c }, { 19, 0x002c },
0x002c, 0x002c, 0x002c, 0x0000, { 20, 0x002c }, { 21, 0x002c }, { 22, 0x002c }, { 23, 0x0000 },
0x0032, 0x0000, 0x0000, 0x0000, { 24, 0x0032 }, { 25, 0x0000 }, { 26, 0x0000 }, { 27, 0x0000 },
0x0000, 0x0000, 0x0000, 0x0000, { 28, 0x0000 }, { 29, 0x0000 }, { 30, 0x0000 }, { 31, 0x0000 },
0x0038, 0x000b, 0x0032, 0x0000, { 32, 0x0038 }, { 33, 0x000b }, { 34, 0x0032 }, { 35, 0x0000 },
0x0008, 0x000c, 0x0093, 0x00e9, { 36, 0x0008 }, { 37, 0x000c }, { 38, 0x0093 }, { 39, 0x00e9 },
0x0000, 0x0000, 0x0000, 0x0000, { 40, 0x0000 }, { 41, 0x0000 }, { 42, 0x0000 }, { 43, 0x0000 },
0x0003, 0x0010, 0x0000, 0x0000, { 44, 0x0003 }, { 45, 0x0010 }, { 46, 0x0000 }, { 47, 0x0000 },
0x0000, 0x0002, 0x0000, 0x0000, { 48, 0x0000 }, { 49, 0x0002 }, { 50, 0x0000 }, { 51, 0x0000 },
0x0000, 0x0000, 0x0039, 0x0000, { 52, 0x0000 }, { 53, 0x0000 }, { 54, 0x0039 }, { 55, 0x0000 },
0x0000, { 56, 0x0000 },
}; };
#define WM8974_POWER1_BIASEN 0x08 #define WM8974_POWER1_BIASEN 0x08
@ -514,7 +515,7 @@ static int wm8974_set_bias_level(struct snd_soc_codec *codec,
power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN; power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN;
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
snd_soc_cache_sync(codec); regcache_sync(dev_get_regmap(codec->dev, NULL));
/* Initial cap charge at VMID 5k */ /* Initial cap charge at VMID 5k */
snd_soc_write(codec, WM8974_POWER1, power1 | 0x3); snd_soc_write(codec, WM8974_POWER1, power1 | 0x3);
@ -579,11 +580,20 @@ static int wm8974_resume(struct snd_soc_codec *codec)
return 0; return 0;
} }
static const struct regmap_config wm8974_regmap = {
.reg_bits = 7,
.val_bits = 9,
.max_register = WM8974_MONOMIX,
.reg_defaults = wm8974_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8974_reg_defaults),
};
static int wm8974_probe(struct snd_soc_codec *codec) static int wm8974_probe(struct snd_soc_codec *codec)
{ {
int ret = 0; int ret = 0;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C); ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
if (ret < 0) { if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret; return ret;
@ -613,9 +623,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8974 = {
.suspend = wm8974_suspend, .suspend = wm8974_suspend,
.resume = wm8974_resume, .resume = wm8974_resume,
.set_bias_level = wm8974_set_bias_level, .set_bias_level = wm8974_set_bias_level,
.reg_cache_size = ARRAY_SIZE(wm8974_reg),
.reg_word_size = sizeof(u16),
.reg_cache_default = wm8974_reg,
.controls = wm8974_snd_controls, .controls = wm8974_snd_controls,
.num_controls = ARRAY_SIZE(wm8974_snd_controls), .num_controls = ARRAY_SIZE(wm8974_snd_controls),
@ -628,8 +635,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8974 = {
static int wm8974_i2c_probe(struct i2c_client *i2c, static int wm8974_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct regmap *regmap;
int ret; int ret;
regmap = devm_regmap_init_i2c(i2c, &wm8974_regmap);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
ret = snd_soc_register_codec(&i2c->dev, ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8974, &wm8974_dai, 1); &soc_codec_dev_wm8974, &wm8974_dai, 1);

View File

@ -1148,7 +1148,7 @@ static struct spi_driver wm8985_spi_driver = {
}; };
#endif #endif
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static int wm8985_i2c_probe(struct i2c_client *i2c, static int wm8985_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -1201,7 +1201,7 @@ static int __init wm8985_modinit(void)
{ {
int ret = 0; int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8985_i2c_driver); ret = i2c_add_driver(&wm8985_i2c_driver);
if (ret) { if (ret) {
printk(KERN_ERR "Failed to register wm8985 I2C driver: %d\n", printk(KERN_ERR "Failed to register wm8985 I2C driver: %d\n",
@ -1221,7 +1221,7 @@ module_init(wm8985_modinit);
static void __exit wm8985_exit(void) static void __exit wm8985_exit(void)
{ {
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8985_i2c_driver); i2c_del_driver(&wm8985_i2c_driver);
#endif #endif
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)

View File

@ -912,7 +912,7 @@ static struct spi_driver wm8988_spi_driver = {
}; };
#endif /* CONFIG_SPI_MASTER */ #endif /* CONFIG_SPI_MASTER */
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static int wm8988_i2c_probe(struct i2c_client *i2c, static int wm8988_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -964,7 +964,7 @@ static struct i2c_driver wm8988_i2c_driver = {
static int __init wm8988_modinit(void) static int __init wm8988_modinit(void)
{ {
int ret = 0; int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8988_i2c_driver); ret = i2c_add_driver(&wm8988_i2c_driver);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR "Failed to register WM8988 I2C driver: %d\n", printk(KERN_ERR "Failed to register WM8988 I2C driver: %d\n",
@ -984,7 +984,7 @@ module_init(wm8988_modinit);
static void __exit wm8988_exit(void) static void __exit wm8988_exit(void)
{ {
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8988_i2c_driver); i2c_del_driver(&wm8988_i2c_driver);
#endif #endif
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)

View File

@ -17,6 +17,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
@ -30,13 +31,12 @@
/* codec private data */ /* codec private data */
struct wm8990_priv { struct wm8990_priv {
enum snd_soc_control_type control_type; struct regmap *regmap;
unsigned int sysclk; unsigned int sysclk;
unsigned int pcmclk; unsigned int pcmclk;
}; };
static int wm8990_volatile_register(struct snd_soc_codec *codec, static bool wm8990_volatile_register(struct device *dev, unsigned int reg)
unsigned int reg)
{ {
switch (reg) { switch (reg) {
case WM8990_RESET: case WM8990_RESET:
@ -46,71 +46,69 @@ static int wm8990_volatile_register(struct snd_soc_codec *codec,
} }
} }
static const u16 wm8990_reg[] = { static const struct reg_default wm8990_reg_defaults[] = {
0x8990, /* R0 - Reset */ { 1, 0x0000 }, /* R1 - Power Management (1) */
0x0000, /* R1 - Power Management (1) */ { 2, 0x6000 }, /* R2 - Power Management (2) */
0x6000, /* R2 - Power Management (2) */ { 3, 0x0000 }, /* R3 - Power Management (3) */
0x0000, /* R3 - Power Management (3) */ { 4, 0x4050 }, /* R4 - Audio Interface (1) */
0x4050, /* R4 - Audio Interface (1) */ { 5, 0x4000 }, /* R5 - Audio Interface (2) */
0x4000, /* R5 - Audio Interface (2) */ { 6, 0x01C8 }, /* R6 - Clocking (1) */
0x01C8, /* R6 - Clocking (1) */ { 7, 0x0000 }, /* R7 - Clocking (2) */
0x0000, /* R7 - Clocking (2) */ { 8, 0x0040 }, /* R8 - Audio Interface (3) */
0x0040, /* R8 - Audio Interface (3) */ { 9, 0x0040 }, /* R9 - Audio Interface (4) */
0x0040, /* R9 - Audio Interface (4) */ { 10, 0x0004 }, /* R10 - DAC CTRL */
0x0004, /* R10 - DAC CTRL */ { 11, 0x00C0 }, /* R11 - Left DAC Digital Volume */
0x00C0, /* R11 - Left DAC Digital Volume */ { 12, 0x00C0 }, /* R12 - Right DAC Digital Volume */
0x00C0, /* R12 - Right DAC Digital Volume */ { 13, 0x0000 }, /* R13 - Digital Side Tone */
0x0000, /* R13 - Digital Side Tone */ { 14, 0x0100 }, /* R14 - ADC CTRL */
0x0100, /* R14 - ADC CTRL */ { 15, 0x00C0 }, /* R15 - Left ADC Digital Volume */
0x00C0, /* R15 - Left ADC Digital Volume */ { 16, 0x00C0 }, /* R16 - Right ADC Digital Volume */
0x00C0, /* R16 - Right ADC Digital Volume */
0x0000, /* R17 */ { 18, 0x0000 }, /* R18 - GPIO CTRL 1 */
0x0000, /* R18 - GPIO CTRL 1 */ { 19, 0x1000 }, /* R19 - GPIO1 & GPIO2 */
0x1000, /* R19 - GPIO1 & GPIO2 */ { 20, 0x1010 }, /* R20 - GPIO3 & GPIO4 */
0x1010, /* R20 - GPIO3 & GPIO4 */ { 21, 0x1010 }, /* R21 - GPIO5 & GPIO6 */
0x1010, /* R21 - GPIO5 & GPIO6 */ { 22, 0x8000 }, /* R22 - GPIOCTRL 2 */
0x8000, /* R22 - GPIOCTRL 2 */ { 23, 0x0800 }, /* R23 - GPIO_POL */
0x0800, /* R23 - GPIO_POL */ { 24, 0x008B }, /* R24 - Left Line Input 1&2 Volume */
0x008B, /* R24 - Left Line Input 1&2 Volume */ { 25, 0x008B }, /* R25 - Left Line Input 3&4 Volume */
0x008B, /* R25 - Left Line Input 3&4 Volume */ { 26, 0x008B }, /* R26 - Right Line Input 1&2 Volume */
0x008B, /* R26 - Right Line Input 1&2 Volume */ { 27, 0x008B }, /* R27 - Right Line Input 3&4 Volume */
0x008B, /* R27 - Right Line Input 3&4 Volume */ { 28, 0x0000 }, /* R28 - Left Output Volume */
0x0000, /* R28 - Left Output Volume */ { 29, 0x0000 }, /* R29 - Right Output Volume */
0x0000, /* R29 - Right Output Volume */ { 30, 0x0066 }, /* R30 - Line Outputs Volume */
0x0066, /* R30 - Line Outputs Volume */ { 31, 0x0022 }, /* R31 - Out3/4 Volume */
0x0022, /* R31 - Out3/4 Volume */ { 32, 0x0079 }, /* R32 - Left OPGA Volume */
0x0079, /* R32 - Left OPGA Volume */ { 33, 0x0079 }, /* R33 - Right OPGA Volume */
0x0079, /* R33 - Right OPGA Volume */ { 34, 0x0003 }, /* R34 - Speaker Volume */
0x0003, /* R34 - Speaker Volume */ { 35, 0x0003 }, /* R35 - ClassD1 */
0x0003, /* R35 - ClassD1 */
0x0000, /* R36 */ { 37, 0x0100 }, /* R37 - ClassD3 */
0x0100, /* R37 - ClassD3 */ { 38, 0x0079 }, /* R38 - ClassD4 */
0x0079, /* R38 - ClassD4 */ { 39, 0x0000 }, /* R39 - Input Mixer1 */
0x0000, /* R39 - Input Mixer1 */ { 40, 0x0000 }, /* R40 - Input Mixer2 */
0x0000, /* R40 - Input Mixer2 */ { 41, 0x0000 }, /* R41 - Input Mixer3 */
0x0000, /* R41 - Input Mixer3 */ { 42, 0x0000 }, /* R42 - Input Mixer4 */
0x0000, /* R42 - Input Mixer4 */ { 43, 0x0000 }, /* R43 - Input Mixer5 */
0x0000, /* R43 - Input Mixer5 */ { 44, 0x0000 }, /* R44 - Input Mixer6 */
0x0000, /* R44 - Input Mixer6 */ { 45, 0x0000 }, /* R45 - Output Mixer1 */
0x0000, /* R45 - Output Mixer1 */ { 46, 0x0000 }, /* R46 - Output Mixer2 */
0x0000, /* R46 - Output Mixer2 */ { 47, 0x0000 }, /* R47 - Output Mixer3 */
0x0000, /* R47 - Output Mixer3 */ { 48, 0x0000 }, /* R48 - Output Mixer4 */
0x0000, /* R48 - Output Mixer4 */ { 49, 0x0000 }, /* R49 - Output Mixer5 */
0x0000, /* R49 - Output Mixer5 */ { 50, 0x0000 }, /* R50 - Output Mixer6 */
0x0000, /* R50 - Output Mixer6 */ { 51, 0x0180 }, /* R51 - Out3/4 Mixer */
0x0180, /* R51 - Out3/4 Mixer */ { 52, 0x0000 }, /* R52 - Line Mixer1 */
0x0000, /* R52 - Line Mixer1 */ { 53, 0x0000 }, /* R53 - Line Mixer2 */
0x0000, /* R53 - Line Mixer2 */ { 54, 0x0000 }, /* R54 - Speaker Mixer */
0x0000, /* R54 - Speaker Mixer */ { 55, 0x0000 }, /* R55 - Additional Control */
0x0000, /* R55 - Additional Control */ { 56, 0x0000 }, /* R56 - AntiPOP1 */
0x0000, /* R56 - AntiPOP1 */ { 57, 0x0000 }, /* R57 - AntiPOP2 */
0x0000, /* R57 - AntiPOP2 */ { 58, 0x0000 }, /* R58 - MICBIAS */
0x0000, /* R58 - MICBIAS */
0x0000, /* R59 */ { 60, 0x0008 }, /* R60 - PLL1 */
0x0008, /* R60 - PLL1 */ { 61, 0x0031 }, /* R61 - PLL2 */
0x0031, /* R61 - PLL2 */ { 62, 0x0026 }, /* R62 - PLL3 */
0x0026, /* R62 - PLL3 */
0x0000, /* R63 - Driver internal */
}; };
#define wm8990_reset(c) snd_soc_write(c, WM8990_RESET, 0) #define wm8990_reset(c) snd_soc_write(c, WM8990_RESET, 0)
@ -376,32 +374,6 @@ SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME,
* _DAPM_ Controls * _DAPM_ Controls
*/ */
static int inmixer_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
u16 reg, fakepower;
reg = snd_soc_read(w->codec, WM8990_POWER_MANAGEMENT_2);
fakepower = snd_soc_read(w->codec, WM8990_INTDRIVBITS);
if (fakepower & ((1 << WM8990_INMIXL_PWR_BIT) |
(1 << WM8990_AINLMUX_PWR_BIT))) {
reg |= WM8990_AINL_ENA;
} else {
reg &= ~WM8990_AINL_ENA;
}
if (fakepower & ((1 << WM8990_INMIXR_PWR_BIT) |
(1 << WM8990_AINRMUX_PWR_BIT))) {
reg |= WM8990_AINR_ENA;
} else {
reg &= ~WM8990_AINR_ENA;
}
snd_soc_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg);
return 0;
}
static int outmixer_event(struct snd_soc_dapm_widget *w, static int outmixer_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event) struct snd_kcontrol *kcontrol, int event)
{ {
@ -656,6 +628,11 @@ SND_SOC_DAPM_INPUT("RIN1"),
SND_SOC_DAPM_INPUT("RIN2"), SND_SOC_DAPM_INPUT("RIN2"),
SND_SOC_DAPM_INPUT("Internal ADC Source"), SND_SOC_DAPM_INPUT("Internal ADC Source"),
SND_SOC_DAPM_SUPPLY("INL", WM8990_POWER_MANAGEMENT_2, WM8990_AINL_ENA_BIT, 0,
NULL, 0),
SND_SOC_DAPM_SUPPLY("INR", WM8990_POWER_MANAGEMENT_2, WM8990_AINR_ENA_BIT, 0,
NULL, 0),
/* DACs */ /* DACs */
SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8990_POWER_MANAGEMENT_2, SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8990_POWER_MANAGEMENT_2,
WM8990_ADCL_ENA_BIT, 0), WM8990_ADCL_ENA_BIT, 0),
@ -677,26 +654,20 @@ SND_SOC_DAPM_MIXER("RIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN34_ENA_BIT,
ARRAY_SIZE(wm8990_dapm_rin34_pga_controls)), ARRAY_SIZE(wm8990_dapm_rin34_pga_controls)),
/* INMIXL */ /* INMIXL */
SND_SOC_DAPM_MIXER_E("INMIXL", WM8990_INTDRIVBITS, WM8990_INMIXL_PWR_BIT, 0, SND_SOC_DAPM_MIXER("INMIXL", SND_SOC_NOPM, 0, 0,
&wm8990_dapm_inmixl_controls[0], &wm8990_dapm_inmixl_controls[0],
ARRAY_SIZE(wm8990_dapm_inmixl_controls), ARRAY_SIZE(wm8990_dapm_inmixl_controls)),
inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
/* AINLMUX */ /* AINLMUX */
SND_SOC_DAPM_MUX_E("AINLMUX", WM8990_INTDRIVBITS, WM8990_AINLMUX_PWR_BIT, 0, SND_SOC_DAPM_MUX("AINLMUX", SND_SOC_NOPM, 0, 0, &wm8990_dapm_ainlmux_controls),
&wm8990_dapm_ainlmux_controls, inmixer_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
/* INMIXR */ /* INMIXR */
SND_SOC_DAPM_MIXER_E("INMIXR", WM8990_INTDRIVBITS, WM8990_INMIXR_PWR_BIT, 0, SND_SOC_DAPM_MIXER("INMIXR", SND_SOC_NOPM, 0, 0,
&wm8990_dapm_inmixr_controls[0], &wm8990_dapm_inmixr_controls[0],
ARRAY_SIZE(wm8990_dapm_inmixr_controls), ARRAY_SIZE(wm8990_dapm_inmixr_controls)),
inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
/* AINRMUX */ /* AINRMUX */
SND_SOC_DAPM_MUX_E("AINRMUX", WM8990_INTDRIVBITS, WM8990_AINRMUX_PWR_BIT, 0, SND_SOC_DAPM_MUX("AINRMUX", SND_SOC_NOPM, 0, 0, &wm8990_dapm_ainrmux_controls),
&wm8990_dapm_ainrmux_controls, inmixer_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
/* Output Side */ /* Output Side */
/* DACs */ /* DACs */
@ -787,7 +758,7 @@ SND_SOC_DAPM_OUTPUT("RON"),
SND_SOC_DAPM_OUTPUT("Internal DAC Sink"), SND_SOC_DAPM_OUTPUT("Internal DAC Sink"),
}; };
static const struct snd_soc_dapm_route audio_map[] = { static const struct snd_soc_dapm_route wm8990_dapm_routes[] = {
/* Make DACs turn on when playing even if not mixed into any outputs */ /* Make DACs turn on when playing even if not mixed into any outputs */
{"Internal DAC Sink", NULL, "Left DAC"}, {"Internal DAC Sink", NULL, "Left DAC"},
{"Internal DAC Sink", NULL, "Right DAC"}, {"Internal DAC Sink", NULL, "Right DAC"},
@ -796,6 +767,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Left ADC", NULL, "Internal ADC Source"}, {"Left ADC", NULL, "Internal ADC Source"},
{"Right ADC", NULL, "Internal ADC Source"}, {"Right ADC", NULL, "Internal ADC Source"},
{"AINLMUX", NULL, "INL"},
{"INMIXL", NULL, "INL"},
{"AINRMUX", NULL, "INR"},
{"INMIXR", NULL, "INR"},
/* Input Side */ /* Input Side */
/* LIN12 PGA */ /* LIN12 PGA */
{"LIN12 PGA", "LIN1 Switch", "LIN1"}, {"LIN12 PGA", "LIN1 Switch", "LIN1"},
@ -912,18 +888,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"RON", NULL, "RONMIX"}, {"RON", NULL, "RONMIX"},
}; };
static int wm8990_add_widgets(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_new_controls(dapm, wm8990_dapm_widgets,
ARRAY_SIZE(wm8990_dapm_widgets));
/* set up the WM8990 audio map */
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
return 0;
}
/* PLL divisors */ /* PLL divisors */
struct _pll_div { struct _pll_div {
u32 div2; u32 div2;
@ -1148,6 +1112,7 @@ static int wm8990_mute(struct snd_soc_dai *dai, int mute)
static int wm8990_set_bias_level(struct snd_soc_codec *codec, static int wm8990_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
struct wm8990_priv *wm8990 = snd_soc_codec_get_drvdata(codec);
int ret; int ret;
switch (level) { switch (level) {
@ -1162,7 +1127,7 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
ret = snd_soc_cache_sync(codec); ret = regcache_sync(wm8990->regmap);
if (ret < 0) { if (ret < 0) {
dev_err(codec->dev, "Failed to sync cache: %d\n", ret); dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
return ret; return ret;
@ -1260,7 +1225,7 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
/* disable POBCTRL, SOFT_ST and BUFDCOPEN */ /* disable POBCTRL, SOFT_ST and BUFDCOPEN */
snd_soc_write(codec, WM8990_ANTIPOP2, 0x0); snd_soc_write(codec, WM8990_ANTIPOP2, 0x0);
codec->cache_sync = 1; regcache_mark_dirty(wm8990->regmap);
break; break;
} }
@ -1329,7 +1294,7 @@ static int wm8990_probe(struct snd_soc_codec *codec)
{ {
int ret; int ret;
ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
if (ret < 0) { if (ret < 0) {
printk(KERN_ERR "wm8990: failed to set cache I/O: %d\n", ret); printk(KERN_ERR "wm8990: failed to set cache I/O: %d\n", ret);
return ret; return ret;
@ -1352,10 +1317,6 @@ static int wm8990_probe(struct snd_soc_codec *codec)
snd_soc_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); snd_soc_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
snd_soc_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); snd_soc_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
snd_soc_add_codec_controls(codec, wm8990_snd_controls,
ARRAY_SIZE(wm8990_snd_controls));
wm8990_add_widgets(codec);
return 0; return 0;
} }
@ -1372,13 +1333,25 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8990 = {
.suspend = wm8990_suspend, .suspend = wm8990_suspend,
.resume = wm8990_resume, .resume = wm8990_resume,
.set_bias_level = wm8990_set_bias_level, .set_bias_level = wm8990_set_bias_level,
.reg_cache_size = ARRAY_SIZE(wm8990_reg), .controls = wm8990_snd_controls,
.reg_word_size = sizeof(u16), .num_controls = ARRAY_SIZE(wm8990_snd_controls),
.reg_cache_default = wm8990_reg, .dapm_widgets = wm8990_dapm_widgets,
.volatile_register = wm8990_volatile_register, .num_dapm_widgets = ARRAY_SIZE(wm8990_dapm_widgets),
.dapm_routes = wm8990_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(wm8990_dapm_routes),
};
static const struct regmap_config wm8990_regmap = {
.reg_bits = 8,
.val_bits = 16,
.max_register = WM8990_PLL3,
.volatile_reg = wm8990_volatile_register,
.reg_defaults = wm8990_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8990_reg_defaults),
.cache_type = REGCACHE_RBTREE,
}; };
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static int wm8990_i2c_probe(struct i2c_client *i2c, static int wm8990_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -1420,29 +1393,8 @@ static struct i2c_driver wm8990_i2c_driver = {
.remove = wm8990_i2c_remove, .remove = wm8990_i2c_remove,
.id_table = wm8990_i2c_id, .id_table = wm8990_i2c_id,
}; };
#endif
static int __init wm8990_modinit(void) module_i2c_driver(wm8990_i2c_driver);
{
int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8990_i2c_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register wm8990 I2C driver: %d\n",
ret);
}
#endif
return ret;
}
module_init(wm8990_modinit);
static void __exit wm8990_exit(void)
{
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8990_i2c_driver);
#endif
}
module_exit(wm8990_exit);
MODULE_DESCRIPTION("ASoC WM8990 driver"); MODULE_DESCRIPTION("ASoC WM8990 driver");
MODULE_AUTHOR("Liam Girdwood"); MODULE_AUTHOR("Liam Girdwood");

View File

@ -78,7 +78,6 @@
#define WM8990_PLL1 0x3C #define WM8990_PLL1 0x3C
#define WM8990_PLL2 0x3D #define WM8990_PLL2 0x3D
#define WM8990_PLL3 0x3E #define WM8990_PLL3 0x3E
#define WM8990_INTDRIVBITS 0x3F
#define WM8990_EXT_ACCESS_ENA 0x75 #define WM8990_EXT_ACCESS_ENA 0x75
#define WM8990_EXT_CTL1 0x7a #define WM8990_EXT_CTL1 0x7a
@ -818,14 +817,6 @@
*/ */
#define WM8990_PLLK2_MASK 0x00FF /* PLLK2 - [7:0] */ #define WM8990_PLLK2_MASK 0x00FF /* PLLK2 - [7:0] */
/*
* R63 (0x3F) - Internal Driver Bits
*/
#define WM8990_INMIXL_PWR_BIT 0
#define WM8990_AINLMUX_PWR_BIT 1
#define WM8990_INMIXR_PWR_BIT 2
#define WM8990_AINRMUX_PWR_BIT 3
#define WM8990_MCLK_DIV 0 #define WM8990_MCLK_DIV 0
#define WM8990_DACCLK_DIV 1 #define WM8990_DACCLK_DIV 1
#define WM8990_ADCCLK_DIV 2 #define WM8990_ADCCLK_DIV 2

View File

@ -18,6 +18,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
@ -31,77 +32,84 @@
#include "wm8991.h" #include "wm8991.h"
struct wm8991_priv { struct wm8991_priv {
enum snd_soc_control_type control_type; struct regmap *regmap;
unsigned int pcmclk; unsigned int pcmclk;
}; };
static const u16 wm8991_reg_defs[] = { static const struct reg_default wm8991_reg_defaults[] = {
0x8991, /* R0 - Reset */ { 1, 0x0000 }, /* R1 - Power Management (1) */
0x0000, /* R1 - Power Management (1) */ { 2, 0x6000 }, /* R2 - Power Management (2) */
0x6000, /* R2 - Power Management (2) */ { 3, 0x0000 }, /* R3 - Power Management (3) */
0x0000, /* R3 - Power Management (3) */ { 4, 0x4050 }, /* R4 - Audio Interface (1) */
0x4050, /* R4 - Audio Interface (1) */ { 5, 0x4000 }, /* R5 - Audio Interface (2) */
0x4000, /* R5 - Audio Interface (2) */ { 6, 0x01C8 }, /* R6 - Clocking (1) */
0x01C8, /* R6 - Clocking (1) */ { 7, 0x0000 }, /* R7 - Clocking (2) */
0x0000, /* R7 - Clocking (2) */ { 8, 0x0040 }, /* R8 - Audio Interface (3) */
0x0040, /* R8 - Audio Interface (3) */ { 9, 0x0040 }, /* R9 - Audio Interface (4) */
0x0040, /* R9 - Audio Interface (4) */ { 10, 0x0004 }, /* R10 - DAC CTRL */
0x0004, /* R10 - DAC CTRL */ { 11, 0x00C0 }, /* R11 - Left DAC Digital Volume */
0x00C0, /* R11 - Left DAC Digital Volume */ { 12, 0x00C0 }, /* R12 - Right DAC Digital Volume */
0x00C0, /* R12 - Right DAC Digital Volume */ { 13, 0x0000 }, /* R13 - Digital Side Tone */
0x0000, /* R13 - Digital Side Tone */ { 14, 0x0100 }, /* R14 - ADC CTRL */
0x0100, /* R14 - ADC CTRL */ { 15, 0x00C0 }, /* R15 - Left ADC Digital Volume */
0x00C0, /* R15 - Left ADC Digital Volume */ { 16, 0x00C0 }, /* R16 - Right ADC Digital Volume */
0x00C0, /* R16 - Right ADC Digital Volume */
0x0000, /* R17 */ { 18, 0x0000 }, /* R18 - GPIO CTRL 1 */
0x0000, /* R18 - GPIO CTRL 1 */ { 19, 0x1000 }, /* R19 - GPIO1 & GPIO2 */
0x1000, /* R19 - GPIO1 & GPIO2 */ { 20, 0x1010 }, /* R20 - GPIO3 & GPIO4 */
0x1010, /* R20 - GPIO3 & GPIO4 */ { 21, 0x1010 }, /* R21 - GPIO5 & GPIO6 */
0x1010, /* R21 - GPIO5 & GPIO6 */ { 22, 0x8000 }, /* R22 - GPIOCTRL 2 */
0x8000, /* R22 - GPIOCTRL 2 */ { 23, 0x0800 }, /* R23 - GPIO_POL */
0x0800, /* R23 - GPIO_POL */ { 24, 0x008B }, /* R24 - Left Line Input 1&2 Volume */
0x008B, /* R24 - Left Line Input 1&2 Volume */ { 25, 0x008B }, /* R25 - Left Line Input 3&4 Volume */
0x008B, /* R25 - Left Line Input 3&4 Volume */ { 26, 0x008B }, /* R26 - Right Line Input 1&2 Volume */
0x008B, /* R26 - Right Line Input 1&2 Volume */ { 27, 0x008B }, /* R27 - Right Line Input 3&4 Volume */
0x008B, /* R27 - Right Line Input 3&4 Volume */ { 28, 0x0000 }, /* R28 - Left Output Volume */
0x0000, /* R28 - Left Output Volume */ { 29, 0x0000 }, /* R29 - Right Output Volume */
0x0000, /* R29 - Right Output Volume */ { 30, 0x0066 }, /* R30 - Line Outputs Volume */
0x0066, /* R30 - Line Outputs Volume */ { 31, 0x0022 }, /* R31 - Out3/4 Volume */
0x0022, /* R31 - Out3/4 Volume */ { 32, 0x0079 }, /* R32 - Left OPGA Volume */
0x0079, /* R32 - Left OPGA Volume */ { 33, 0x0079 }, /* R33 - Right OPGA Volume */
0x0079, /* R33 - Right OPGA Volume */ { 34, 0x0003 }, /* R34 - Speaker Volume */
0x0003, /* R34 - Speaker Volume */ { 35, 0x0003 }, /* R35 - ClassD1 */
0x0003, /* R35 - ClassD1 */
0x0000, /* R36 */ { 37, 0x0100 }, /* R37 - ClassD3 */
0x0100, /* R37 - ClassD3 */
0x0000, /* R38 */ { 39, 0x0000 }, /* R39 - Input Mixer1 */
0x0000, /* R39 - Input Mixer1 */ { 40, 0x0000 }, /* R40 - Input Mixer2 */
0x0000, /* R40 - Input Mixer2 */ { 41, 0x0000 }, /* R41 - Input Mixer3 */
0x0000, /* R41 - Input Mixer3 */ { 42, 0x0000 }, /* R42 - Input Mixer4 */
0x0000, /* R42 - Input Mixer4 */ { 43, 0x0000 }, /* R43 - Input Mixer5 */
0x0000, /* R43 - Input Mixer5 */ { 44, 0x0000 }, /* R44 - Input Mixer6 */
0x0000, /* R44 - Input Mixer6 */ { 45, 0x0000 }, /* R45 - Output Mixer1 */
0x0000, /* R45 - Output Mixer1 */ { 46, 0x0000 }, /* R46 - Output Mixer2 */
0x0000, /* R46 - Output Mixer2 */ { 47, 0x0000 }, /* R47 - Output Mixer3 */
0x0000, /* R47 - Output Mixer3 */ { 48, 0x0000 }, /* R48 - Output Mixer4 */
0x0000, /* R48 - Output Mixer4 */ { 49, 0x0000 }, /* R49 - Output Mixer5 */
0x0000, /* R49 - Output Mixer5 */ { 50, 0x0000 }, /* R50 - Output Mixer6 */
0x0000, /* R50 - Output Mixer6 */ { 51, 0x0180 }, /* R51 - Out3/4 Mixer */
0x0180, /* R51 - Out3/4 Mixer */ { 52, 0x0000 }, /* R52 - Line Mixer1 */
0x0000, /* R52 - Line Mixer1 */ { 53, 0x0000 }, /* R53 - Line Mixer2 */
0x0000, /* R53 - Line Mixer2 */ { 54, 0x0000 }, /* R54 - Speaker Mixer */
0x0000, /* R54 - Speaker Mixer */ { 55, 0x0000 }, /* R55 - Additional Control */
0x0000, /* R55 - Additional Control */ { 56, 0x0000 }, /* R56 - AntiPOP1 */
0x0000, /* R56 - AntiPOP1 */ { 57, 0x0000 }, /* R57 - AntiPOP2 */
0x0000, /* R57 - AntiPOP2 */ { 58, 0x0000 }, /* R58 - MICBIAS */
0x0000, /* R58 - MICBIAS */
0x0000, /* R59 */ { 60, 0x0008 }, /* R60 - PLL1 */
0x0008, /* R60 - PLL1 */ { 61, 0x0031 }, /* R61 - PLL2 */
0x0031, /* R61 - PLL2 */ { 62, 0x0026 }, /* R62 - PLL3 */
0x0026, /* R62 - PLL3 */
}; };
#define wm8991_reset(c) snd_soc_write(c, WM8991_RESET, 0) static bool wm8991_volatile(struct device *dev, unsigned int reg)
{
switch (reg) {
case WM8991_RESET:
return true;
default:
return false;
}
}
static const unsigned int rec_mix_tlv[] = { static const unsigned int rec_mix_tlv[] = {
TLV_DB_RANGE_HEAD(1), TLV_DB_RANGE_HEAD(1),
@ -374,30 +382,6 @@ static const struct snd_kcontrol_new wm8991_snd_controls[] = {
/* /*
* _DAPM_ Controls * _DAPM_ Controls
*/ */
static int inmixer_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
u16 reg, fakepower;
reg = snd_soc_read(w->codec, WM8991_POWER_MANAGEMENT_2);
fakepower = snd_soc_read(w->codec, WM8991_INTDRIVBITS);
if (fakepower & ((1 << WM8991_INMIXL_PWR_BIT) |
(1 << WM8991_AINLMUX_PWR_BIT)))
reg |= WM8991_AINL_ENA;
else
reg &= ~WM8991_AINL_ENA;
if (fakepower & ((1 << WM8991_INMIXR_PWR_BIT) |
(1 << WM8991_AINRMUX_PWR_BIT)))
reg |= WM8991_AINR_ENA;
else
reg &= ~WM8991_AINR_ENA;
snd_soc_write(w->codec, WM8991_POWER_MANAGEMENT_2, reg);
return 0;
}
static int outmixer_event(struct snd_soc_dapm_widget *w, static int outmixer_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event) struct snd_kcontrol *kcontrol, int event)
{ {
@ -655,6 +639,11 @@ static const struct snd_soc_dapm_widget wm8991_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("RIN2"), SND_SOC_DAPM_INPUT("RIN2"),
SND_SOC_DAPM_INPUT("Internal ADC Source"), SND_SOC_DAPM_INPUT("Internal ADC Source"),
SND_SOC_DAPM_SUPPLY("INL", WM8991_POWER_MANAGEMENT_2,
WM8991_AINL_ENA_BIT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("INR", WM8991_POWER_MANAGEMENT_2,
WM8991_AINR_ENA_BIT, 0, NULL, 0),
/* DACs */ /* DACs */
SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8991_POWER_MANAGEMENT_2, SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8991_POWER_MANAGEMENT_2,
WM8991_ADCL_ENA_BIT, 0), WM8991_ADCL_ENA_BIT, 0),
@ -676,26 +665,22 @@ static const struct snd_soc_dapm_widget wm8991_dapm_widgets[] = {
ARRAY_SIZE(wm8991_dapm_rin34_pga_controls)), ARRAY_SIZE(wm8991_dapm_rin34_pga_controls)),
/* INMIXL */ /* INMIXL */
SND_SOC_DAPM_MIXER_E("INMIXL", WM8991_INTDRIVBITS, WM8991_INMIXL_PWR_BIT, 0, SND_SOC_DAPM_MIXER("INMIXL", SND_SOC_NOPM, 0, 0,
&wm8991_dapm_inmixl_controls[0], &wm8991_dapm_inmixl_controls[0],
ARRAY_SIZE(wm8991_dapm_inmixl_controls), ARRAY_SIZE(wm8991_dapm_inmixl_controls)),
inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
/* AINLMUX */ /* AINLMUX */
SND_SOC_DAPM_MUX_E("AINLMUX", WM8991_INTDRIVBITS, WM8991_AINLMUX_PWR_BIT, 0, SND_SOC_DAPM_MUX("AINLMUX", SND_SOC_NOPM, 0, 0,
&wm8991_dapm_ainlmux_controls, inmixer_event, &wm8991_dapm_ainlmux_controls),
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
/* INMIXR */ /* INMIXR */
SND_SOC_DAPM_MIXER_E("INMIXR", WM8991_INTDRIVBITS, WM8991_INMIXR_PWR_BIT, 0, SND_SOC_DAPM_MIXER("INMIXR", SND_SOC_NOPM, 0, 0,
&wm8991_dapm_inmixr_controls[0], &wm8991_dapm_inmixr_controls[0],
ARRAY_SIZE(wm8991_dapm_inmixr_controls), ARRAY_SIZE(wm8991_dapm_inmixr_controls)),
inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
/* AINRMUX */ /* AINRMUX */
SND_SOC_DAPM_MUX_E("AINRMUX", WM8991_INTDRIVBITS, WM8991_AINRMUX_PWR_BIT, 0, SND_SOC_DAPM_MUX("AINRMUX", SND_SOC_NOPM, 0, 0,
&wm8991_dapm_ainrmux_controls, inmixer_event, &wm8991_dapm_ainrmux_controls),
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
/* Output Side */ /* Output Side */
/* DACs */ /* DACs */
@ -787,7 +772,7 @@ static const struct snd_soc_dapm_widget wm8991_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("Internal DAC Sink"), SND_SOC_DAPM_OUTPUT("Internal DAC Sink"),
}; };
static const struct snd_soc_dapm_route audio_map[] = { static const struct snd_soc_dapm_route wm8991_dapm_routes[] = {
/* Make DACs turn on when playing even if not mixed into any outputs */ /* Make DACs turn on when playing even if not mixed into any outputs */
{"Internal DAC Sink", NULL, "Left DAC"}, {"Internal DAC Sink", NULL, "Left DAC"},
{"Internal DAC Sink", NULL, "Right DAC"}, {"Internal DAC Sink", NULL, "Right DAC"},
@ -797,6 +782,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Right ADC", NULL, "Internal ADC Source"}, {"Right ADC", NULL, "Internal ADC Source"},
/* Input Side */ /* Input Side */
{"INMIXL", NULL, "INL"},
{"AINLMUX", NULL, "INL"},
{"INMIXR", NULL, "INR"},
{"AINRMUX", NULL, "INR"},
/* LIN12 PGA */ /* LIN12 PGA */
{"LIN12 PGA", "LIN1 Switch", "LIN1"}, {"LIN12 PGA", "LIN1 Switch", "LIN1"},
{"LIN12 PGA", "LIN2 Switch", "LIN2"}, {"LIN12 PGA", "LIN2 Switch", "LIN2"},
@ -1129,6 +1118,7 @@ static int wm8991_mute(struct snd_soc_dai *dai, int mute)
static int wm8991_set_bias_level(struct snd_soc_codec *codec, static int wm8991_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
struct wm8991_priv *wm8991 = snd_soc_codec_get_drvdata(codec);
u16 val; u16 val;
switch (level) { switch (level) {
@ -1144,7 +1134,7 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
snd_soc_cache_sync(codec); regcache_sync(wm8991->regmap);
/* Enable all output discharge bits */ /* Enable all output discharge bits */
snd_soc_write(codec, WM8991_ANTIPOP1, WM8991_DIS_LLINE | snd_soc_write(codec, WM8991_ANTIPOP1, WM8991_DIS_LLINE |
WM8991_DIS_RLINE | WM8991_DIS_OUT3 | WM8991_DIS_RLINE | WM8991_DIS_OUT3 |
@ -1232,7 +1222,7 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec,
/* disable POBCTRL, SOFT_ST and BUFDCOPEN */ /* disable POBCTRL, SOFT_ST and BUFDCOPEN */
snd_soc_write(codec, WM8991_ANTIPOP2, 0x0); snd_soc_write(codec, WM8991_ANTIPOP2, 0x0);
codec->cache_sync = 1; regcache_mark_dirty(wm8991->regmap);
break; break;
} }
@ -1266,44 +1256,14 @@ static int wm8991_probe(struct snd_soc_codec *codec)
wm8991 = snd_soc_codec_get_drvdata(codec); wm8991 = snd_soc_codec_get_drvdata(codec);
ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8991->control_type); ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
if (ret < 0) { if (ret < 0) {
dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret); dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
return ret; return ret;
} }
ret = wm8991_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
return ret;
}
wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
snd_soc_update_bits(codec, WM8991_AUDIO_INTERFACE_4,
WM8991_ALRCGPIO1, WM8991_ALRCGPIO1);
snd_soc_update_bits(codec, WM8991_GPIO1_GPIO2,
WM8991_GPIO1_SEL_MASK, 1);
snd_soc_update_bits(codec, WM8991_POWER_MANAGEMENT_1,
WM8991_VREF_ENA | WM8991_VMID_MODE_MASK,
WM8991_VREF_ENA | WM8991_VMID_MODE_MASK);
snd_soc_update_bits(codec, WM8991_POWER_MANAGEMENT_2,
WM8991_OPCLK_ENA, WM8991_OPCLK_ENA);
snd_soc_write(codec, WM8991_DAC_CTRL, 0);
snd_soc_write(codec, WM8991_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
snd_soc_write(codec, WM8991_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
snd_soc_add_codec_controls(codec, wm8991_snd_controls,
ARRAY_SIZE(wm8991_snd_controls));
snd_soc_dapm_new_controls(&codec->dapm, wm8991_dapm_widgets,
ARRAY_SIZE(wm8991_dapm_widgets));
snd_soc_dapm_add_routes(&codec->dapm, audio_map,
ARRAY_SIZE(audio_map));
return 0; return 0;
} }
@ -1352,24 +1312,77 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8991 = {
.suspend = wm8991_suspend, .suspend = wm8991_suspend,
.resume = wm8991_resume, .resume = wm8991_resume,
.set_bias_level = wm8991_set_bias_level, .set_bias_level = wm8991_set_bias_level,
.reg_cache_size = WM8991_MAX_REGISTER + 1, .controls = wm8991_snd_controls,
.reg_word_size = sizeof(u16), .num_controls = ARRAY_SIZE(wm8991_snd_controls),
.reg_cache_default = wm8991_reg_defs .dapm_widgets = wm8991_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm8991_dapm_widgets),
.dapm_routes = wm8991_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(wm8991_dapm_routes),
};
static const struct regmap_config wm8991_regmap = {
.reg_bits = 8,
.val_bits = 16,
.max_register = WM8991_PLL3,
.volatile_reg = wm8991_volatile,
.reg_defaults = wm8991_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8991_reg_defaults),
.cache_type = REGCACHE_RBTREE,
}; };
static int wm8991_i2c_probe(struct i2c_client *i2c, static int wm8991_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct wm8991_priv *wm8991; struct wm8991_priv *wm8991;
unsigned int val;
int ret; int ret;
wm8991 = devm_kzalloc(&i2c->dev, sizeof(*wm8991), GFP_KERNEL); wm8991 = devm_kzalloc(&i2c->dev, sizeof(*wm8991), GFP_KERNEL);
if (!wm8991) if (!wm8991)
return -ENOMEM; return -ENOMEM;
wm8991->control_type = SND_SOC_I2C; wm8991->regmap = devm_regmap_init_i2c(i2c, &wm8991_regmap);
if (IS_ERR(wm8991->regmap))
return PTR_ERR(wm8991->regmap);
i2c_set_clientdata(i2c, wm8991); i2c_set_clientdata(i2c, wm8991);
ret = regmap_read(wm8991->regmap, WM8991_RESET, &val);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to read device ID: %d\n", ret);
return ret;
}
if (val != 0x8991) {
dev_err(&i2c->dev, "Device with ID %x is not a WM8991\n", val);
return -EINVAL;
}
ret = regmap_write(wm8991->regmap, WM8991_RESET, 0);
if (ret < 0) {
dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret);
return ret;
}
regmap_update_bits(wm8991->regmap, WM8991_AUDIO_INTERFACE_4,
WM8991_ALRCGPIO1, WM8991_ALRCGPIO1);
regmap_update_bits(wm8991->regmap, WM8991_GPIO1_GPIO2,
WM8991_GPIO1_SEL_MASK, 1);
regmap_update_bits(wm8991->regmap, WM8991_POWER_MANAGEMENT_1,
WM8991_VREF_ENA | WM8991_VMID_MODE_MASK,
WM8991_VREF_ENA | WM8991_VMID_MODE_MASK);
regmap_update_bits(wm8991->regmap, WM8991_POWER_MANAGEMENT_2,
WM8991_OPCLK_ENA, WM8991_OPCLK_ENA);
regmap_write(wm8991->regmap, WM8991_DAC_CTRL, 0);
regmap_write(wm8991->regmap, WM8991_LEFT_OUTPUT_VOLUME,
0x50 | (1<<8));
regmap_write(wm8991->regmap, WM8991_RIGHT_OUTPUT_VOLUME,
0x50 | (1<<8));
ret = snd_soc_register_codec(&i2c->dev, ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8991, &wm8991_dai, 1); &soc_codec_dev_wm8991, &wm8991_dai, 1);

View File

@ -76,7 +76,6 @@
#define WM8991_PLL1 0x3C #define WM8991_PLL1 0x3C
#define WM8991_PLL2 0x3D #define WM8991_PLL2 0x3D
#define WM8991_PLL3 0x3E #define WM8991_PLL3 0x3E
#define WM8991_INTDRIVBITS 0x3F
#define WM8991_REGISTER_COUNT 60 #define WM8991_REGISTER_COUNT 60
#define WM8991_MAX_REGISTER 0x3F #define WM8991_MAX_REGISTER 0x3F
@ -807,14 +806,6 @@
*/ */
#define WM8991_PLLK2_MASK 0x00FF /* PLLK2 - [7:0] */ #define WM8991_PLLK2_MASK 0x00FF /* PLLK2 - [7:0] */
/*
* R63 (0x3F) - Internal Driver Bits
*/
#define WM8991_INMIXL_PWR_BIT 0
#define WM8991_AINLMUX_PWR_BIT 1
#define WM8991_INMIXR_PWR_BIT 2
#define WM8991_AINRMUX_PWR_BIT 3
#define WM8991_MCLK_DIV 0 #define WM8991_MCLK_DIV 0
#define WM8991_DACCLK_DIV 1 #define WM8991_DACCLK_DIV 1
#define WM8991_ADCCLK_DIV 2 #define WM8991_ADCCLK_DIV 2

View File

@ -4077,12 +4077,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_TEMP_SHUT, wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_TEMP_SHUT,
wm8994_temp_shut, "Thermal shutdown", codec); wm8994_temp_shut, "Thermal shutdown", codec);
ret = wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_DCS_DONE,
wm_hubs_dcs_done, "DC servo done",
&wm8994->hubs);
if (ret == 0)
wm8994->hubs.dcs_done_irq = true;
switch (control->type) { switch (control->type) {
case WM8994: case WM8994:
if (wm8994->micdet_irq) { if (wm8994->micdet_irq) {
@ -4313,6 +4307,11 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
} }
wm_hubs_add_analogue_routes(codec, 0, 0); wm_hubs_add_analogue_routes(codec, 0, 0);
ret = wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_DCS_DONE,
wm_hubs_dcs_done, "DC servo done",
&wm8994->hubs);
if (ret == 0)
wm8994->hubs.dcs_done_irq = true;
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
switch (control->type) { switch (control->type) {

View File

@ -2293,7 +2293,7 @@ static struct spi_driver wm8995_spi_driver = {
}; };
#endif #endif
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static int wm8995_i2c_probe(struct i2c_client *i2c, static int wm8995_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
@ -2350,7 +2350,7 @@ static int __init wm8995_modinit(void)
{ {
int ret = 0; int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8995_i2c_driver); ret = i2c_add_driver(&wm8995_i2c_driver);
if (ret) { if (ret) {
printk(KERN_ERR "Failed to register wm8995 I2C driver: %d\n", printk(KERN_ERR "Failed to register wm8995 I2C driver: %d\n",
@ -2371,7 +2371,7 @@ module_init(wm8995_modinit);
static void __exit wm8995_exit(void) static void __exit wm8995_exit(void)
{ {
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8995_i2c_driver); i2c_del_driver(&wm8995_i2c_driver);
#endif #endif
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)

View File

@ -103,8 +103,8 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU: case SND_SOC_DAPM_POST_PMU:
if (patch) if (patch)
for (i = 0; i < patch_size; i++) for (i = 0; i < patch_size; i++)
regmap_write(regmap, patch[i].reg, regmap_write_async(regmap, patch[i].reg,
patch[i].def); patch[i].def);
break; break;
default: default:
break; break;

View File

@ -1326,7 +1326,7 @@ static const struct regmap_config wm9081_regmap = {
.cache_type = REGCACHE_RBTREE, .cache_type = REGCACHE_RBTREE,
}; };
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
static int wm9081_i2c_probe(struct i2c_client *i2c, static int wm9081_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {

View File

@ -1286,6 +1286,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
reg = wm_adsp_region_to_reg(mem, reg = wm_adsp_region_to_reg(mem,
reg); reg);
reg += offset; reg += offset;
break;
} }
} }
@ -1468,8 +1469,8 @@ static int wm_adsp2_ena(struct wm_adsp *dsp)
unsigned int val; unsigned int val;
int ret, count; int ret, count;
ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL,
ADSP2_SYS_ENA, ADSP2_SYS_ENA); ADSP2_SYS_ENA, ADSP2_SYS_ENA);
if (ret != 0) if (ret != 0)
return ret; return ret;
@ -1492,7 +1493,6 @@ static int wm_adsp2_ena(struct wm_adsp *dsp)
} }
adsp_dbg(dsp, "RAM ready after %d polls\n", count); adsp_dbg(dsp, "RAM ready after %d polls\n", count);
adsp_info(dsp, "RAM ready after %d polls\n", count);
return 0; return 0;
} }
@ -1525,9 +1525,9 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
val = (val & ARIZONA_SYSCLK_FREQ_MASK) val = (val & ARIZONA_SYSCLK_FREQ_MASK)
>> ARIZONA_SYSCLK_FREQ_SHIFT; >> ARIZONA_SYSCLK_FREQ_SHIFT;
ret = regmap_update_bits(dsp->regmap, ret = regmap_update_bits_async(dsp->regmap,
dsp->base + ADSP2_CLOCKING, dsp->base + ADSP2_CLOCKING,
ADSP2_CLK_SEL_MASK, val); ADSP2_CLK_SEL_MASK, val);
if (ret != 0) { if (ret != 0) {
adsp_err(dsp, "Failed to set clock rate: %d\n", adsp_err(dsp, "Failed to set clock rate: %d\n",
ret); ret);
@ -1590,10 +1590,10 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
if (ret != 0) if (ret != 0)
goto err; goto err;
ret = regmap_update_bits(dsp->regmap, ret = regmap_update_bits_async(dsp->regmap,
dsp->base + ADSP2_CONTROL, dsp->base + ADSP2_CONTROL,
ADSP2_CORE_ENA | ADSP2_START, ADSP2_CORE_ENA | ADSP2_START,
ADSP2_CORE_ENA | ADSP2_START); ADSP2_CORE_ENA | ADSP2_START);
if (ret != 0) if (ret != 0)
goto err; goto err;

View File

@ -1,11 +1,6 @@
config SND_DAVINCI_SOC config SND_DAVINCI_SOC
tristate "SoC Audio for the TI DAVINCI or AM33XX chip" tristate "SoC Audio for TI DAVINCI or AM33XX/AM43XX chips"
depends on ARCH_DAVINCI || SOC_AM33XX depends on ARCH_DAVINCI || SOC_AM33XX || SOC_AM43XX
help
Platform driver for daVinci or AM33xx
Say Y or M if you want to add support for codecs attached to
the DAVINCI AC97, I2S, or McASP interface. You will also need
to select the audio interfaces to support below.
config SND_DAVINCI_SOC_I2S config SND_DAVINCI_SOC_I2S
tristate tristate
@ -16,11 +11,15 @@ config SND_DAVINCI_SOC_MCASP
config SND_DAVINCI_SOC_VCIF config SND_DAVINCI_SOC_VCIF
tristate tristate
config SND_DAVINCI_SOC_GENERIC_EVM
tristate
select SND_SOC_TLV320AIC3X
select SND_DAVINCI_SOC_MCASP
config SND_AM33XX_SOC_EVM config SND_AM33XX_SOC_EVM
tristate "SoC Audio for the AM33XX chip based boards" tristate "SoC Audio for the AM33XX chip based boards"
depends on SND_DAVINCI_SOC && SOC_AM33XX depends on SND_DAVINCI_SOC && SOC_AM33XX
select SND_SOC_TLV320AIC3X select SND_DAVINCI_SOC_GENERIC_EVM
select SND_DAVINCI_SOC_MCASP
help help
Say Y or M if you want to add support for SoC audio on AM33XX Say Y or M if you want to add support for SoC audio on AM33XX
boards using McASP and TLV320AIC3X codec. For example AM335X-EVM, boards using McASP and TLV320AIC3X codec. For example AM335X-EVM,
@ -31,8 +30,7 @@ config SND_DAVINCI_SOC_EVM
tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM" tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
depends on SND_DAVINCI_SOC depends on SND_DAVINCI_SOC
depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM
select SND_DAVINCI_SOC_I2S select SND_DAVINCI_SOC_GENERIC_EVM
select SND_SOC_TLV320AIC3X
help help
Say Y if you want to add support for SoC audio on TI Say Y if you want to add support for SoC audio on TI
DaVinci DM6446, DM355 or DM365 EVM platforms. DaVinci DM6446, DM355 or DM365 EVM platforms.
@ -59,8 +57,7 @@ endchoice
config SND_DM6467_SOC_EVM config SND_DM6467_SOC_EVM
tristate "SoC Audio support for DaVinci DM6467 EVM" tristate "SoC Audio support for DaVinci DM6467 EVM"
depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM
select SND_DAVINCI_SOC_MCASP select SND_DAVINCI_SOC_GENERIC_EVM
select SND_SOC_TLV320AIC3X
select SND_SOC_SPDIF select SND_SOC_SPDIF
help help
@ -69,8 +66,7 @@ config SND_DM6467_SOC_EVM
config SND_DA830_SOC_EVM config SND_DA830_SOC_EVM
tristate "SoC Audio support for DA830/OMAP-L137 EVM" tristate "SoC Audio support for DA830/OMAP-L137 EVM"
depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM
select SND_DAVINCI_SOC_MCASP select SND_DAVINCI_SOC_GENERIC_EVM
select SND_SOC_TLV320AIC3X
help help
Say Y if you want to add support for SoC audio on TI Say Y if you want to add support for SoC audio on TI
@ -79,8 +75,7 @@ config SND_DA830_SOC_EVM
config SND_DA850_SOC_EVM config SND_DA850_SOC_EVM
tristate "SoC Audio support for DA850/OMAP-L138 EVM" tristate "SoC Audio support for DA850/OMAP-L138 EVM"
depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM
select SND_DAVINCI_SOC_MCASP select SND_DAVINCI_SOC_GENERIC_EVM
select SND_SOC_TLV320AIC3X
help help
Say Y if you want to add support for SoC audio on TI Say Y if you want to add support for SoC audio on TI
DA850/OMAP-L138 EVM DA850/OMAP-L138 EVM

View File

@ -9,11 +9,7 @@ obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o
obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o
obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o
# DAVINCI Machine Support # Generic DAVINCI/AM33xx Machine Support
snd-soc-evm-objs := davinci-evm.o snd-soc-evm-objs := davinci-evm.o
obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o obj-$(CONFIG_SND_DAVINCI_SOC_GENERIC_EVM) += snd-soc-evm.o
obj-$(CONFIG_SND_AM33XX_SOC_EVM) += snd-soc-evm.o
obj-$(CONFIG_SND_DM6467_SOC_EVM) += snd-soc-evm.o
obj-$(CONFIG_SND_DA830_SOC_EVM) += snd-soc-evm.o
obj-$(CONFIG_SND_DA850_SOC_EVM) += snd-soc-evm.o

Some files were not shown because too many files have changed in this diff Show More