Commit 815ad862 authored by Takashi Iwai's avatar Takashi Iwai

Merge tag 'asoc-v4.4-rc8' of...

Merge tag 'asoc-v4.4-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-next

ASoC: Last updates for v4.5

A bunch more updates for v4.5, mainly driver work:

 - More topology API enhancements from Mengdong Lin working towards
   making everything more component based and being able to specify PCM
   links via topology.
 - Large sets driver updates from Cirrus, Intel (mainly more Skylake
   support) and Renesas.
 - New driver for AMD ACP
 - Rename PCM1792a driver to be generic pcm179x
parents 56f27013 d0021d3b
Texas Instruments pcm1792a DT bindings
Texas Instruments pcm179x DT bindings
This driver supports the SPI bus.
......
RT5651 audio CODEC
This device supports I2C only.
Required properties:
- compatible : "realtek,rt5651".
- reg : The I2C address of the device.
Optional properties:
- realtek,in2-differential
Boolean. Indicate MIC2 input are differential, rather than single-ended.
- realtek,dmic-en
Boolean. true if dmic is used.
Pins on the device (for linking into audio routes) for RT5651:
* DMIC L1
* DMIC R1
* IN1P
* IN2P
* IN2N
* IN3P
* HPOL
* HPOR
* LOUTL
* LOUTR
* PDML
* PDMR
Example:
codec: rt5651@1a {
compatible = "realtek,rt5651";
reg = <0x1a>;
realtek,dmic-en = "true";
realtek,in2-diff = "false";
};
......@@ -46,6 +46,7 @@ struct i2s_platform_data {
u32 snd_rates;
#define DW_I2S_QUIRK_COMP_REG_OFFSET (1 << 0)
#define DW_I2S_QUIRK_COMP_PARAM1 (1 << 1)
unsigned int quirks;
unsigned int i2s_reg_comp1;
unsigned int i2s_reg_comp2;
......
......@@ -233,6 +233,15 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define AZX_MLCTL_SPA (1<<16)
#define AZX_MLCTL_CPA 23
/* registers for DMA Resume Capability Structure */
#define AZX_DRSM_CAP_ID 0x5
#define AZX_REG_DRSM_CTL 0x4
/* Base used to calculate the iterating register offset */
#define AZX_DRSM_BASE 0x08
/* Interval used to calculate the iterating register offset */
#define AZX_DRSM_INTERVAL 0x08
/*
* helpers to read the stream position
*/
......
......@@ -12,6 +12,7 @@
* @spbcap: SPIB capabilities pointer
* @mlcap: MultiLink capabilities pointer
* @gtscap: gts capabilities pointer
* @drsmcap: dma resume capabilities pointer
* @hlink_list: link list of HDA links
*/
struct hdac_ext_bus {
......@@ -23,6 +24,7 @@ struct hdac_ext_bus {
void __iomem *spbcap;
void __iomem *mlcap;
void __iomem *gtscap;
void __iomem *drsmcap;
struct list_head hlink_list;
};
......@@ -72,6 +74,9 @@ enum hdac_ext_stream_type {
* @pplc_addr: processing pipe link stream pointer
* @spib_addr: software position in buffers stream pointer
* @fifo_addr: software position Max fifos stream pointer
* @dpibr_addr: DMA position in buffer resume pointer
* @dpib: DMA position in buffer
* @lpib: Linear position in buffer
* @decoupled: stream host and link is decoupled
* @link_locked: link is locked
* @link_prepared: link is prepared
......@@ -86,6 +91,10 @@ struct hdac_ext_stream {
void __iomem *spib_addr;
void __iomem *fifo_addr;
void __iomem *dpibr_addr;
u32 dpib;
u32 lpib;
bool decoupled:1;
bool link_locked:1;
bool link_prepared;
......@@ -116,6 +125,11 @@ int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus,
struct hdac_ext_stream *stream, u32 value);
int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus,
struct hdac_ext_stream *stream);
void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus,
bool enable, int index);
int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus,
struct hdac_ext_stream *stream, u32 value);
int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value);
void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hstream);
void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hstream);
......@@ -133,6 +147,7 @@ struct hdac_ext_link {
int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link);
int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link);
int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus);
int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus);
void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link,
int stream);
......
......@@ -222,6 +222,7 @@ struct snd_soc_dai_driver {
const char *name;
unsigned int id;
unsigned int base;
struct snd_soc_dobj dobj;
/* DAI driver callbacks */
int (*probe)(struct snd_soc_dai *dai);
......
......@@ -798,6 +798,7 @@ struct snd_soc_component {
unsigned int registered_as_component:1;
struct list_head list;
struct list_head list_aux; /* for auxiliary component of the card */
struct snd_soc_dai_driver *dai_drv;
int num_dai;
......@@ -841,6 +842,9 @@ struct snd_soc_component {
int (*probe)(struct snd_soc_component *);
void (*remove)(struct snd_soc_component *);
/* machine specific init */
int (*init)(struct snd_soc_component *component);
#ifdef CONFIG_DEBUG_FS
void (*init_debugfs)(struct snd_soc_component *component);
const char *debugfs_prefix;
......@@ -1141,8 +1145,7 @@ struct snd_soc_card {
*/
struct snd_soc_aux_dev *aux_dev;
int num_aux_devs;
struct snd_soc_pcm_runtime *rtd_aux;
int num_aux_rtd;
struct list_head aux_comp_list;
const struct snd_kcontrol_new *controls;
int num_controls;
......@@ -1550,6 +1553,7 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
INIT_LIST_HEAD(&card->widgets);
INIT_LIST_HEAD(&card->paths);
INIT_LIST_HEAD(&card->dapm_list);
INIT_LIST_HEAD(&card->aux_comp_list);
}
static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)
......@@ -1676,6 +1680,9 @@ int snd_soc_add_dai_link(struct snd_soc_card *card,
void snd_soc_remove_dai_link(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_link);
int snd_soc_register_dai(struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv);
#include <sound/soc-dai.h>
#ifdef CONFIG_DEBUG_FS
......
......@@ -77,6 +77,12 @@ int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *ebus)
ebus->spbcap = bus->remap_addr + offset;
break;
case AZX_DRSM_CAP_ID:
/* DMA resume capability found, handler function */
dev_dbg(bus->dev, "Found DRSM capability\n");
ebus->drsmcap = bus->remap_addr + offset;
break;
default:
dev_dbg(bus->dev, "Unknown capability %d\n", cur_cap);
break;
......@@ -240,7 +246,7 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
int mask = (1 << AZX_MLCTL_CPA);
udelay(3);
timeout = 50;
timeout = 150;
do {
val = readl(link->ml_addr + AZX_REG_ML_LCTL);
......@@ -281,6 +287,27 @@ int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link)
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down);
/**
* snd_hdac_ext_bus_link_power_up_all -power up all hda link
* @ebus: HD-audio extended bus
*/
int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus)
{
struct hdac_ext_link *hlink = NULL;
int ret;
list_for_each_entry(hlink, &ebus->hlink_list, list) {
snd_hdac_updatel(hlink->ml_addr,
AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA);
ret = check_hdac_link_power_active(hlink, true);
if (ret < 0)
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up_all);
/**
* snd_hdac_ext_bus_link_power_down_all -power down all hda link
* @ebus: HD-audio extended bus
......
......@@ -59,6 +59,10 @@ void snd_hdac_ext_stream_init(struct hdac_ext_bus *ebus,
AZX_SPB_MAXFIFO;
}
if (ebus->drsmcap)
stream->dpibr_addr = ebus->drsmcap + AZX_DRSM_BASE +
AZX_DRSM_INTERVAL * idx;
stream->decoupled = false;
snd_hdac_stream_init(bus, &stream->hstream, idx, direction, tag);
}
......@@ -107,6 +111,7 @@ void snd_hdac_stream_free_all(struct hdac_ext_bus *ebus)
while (!list_empty(&bus->stream_list)) {
s = list_first_entry(&bus->stream_list, struct hdac_stream, list);
stream = stream_to_hdac_ext_stream(s);
snd_hdac_ext_stream_decouple(ebus, stream, false);
list_del(&s->list);
kfree(stream);
}
......@@ -497,3 +502,70 @@ void snd_hdac_ext_stop_streams(struct hdac_ext_bus *ebus)
}
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_stop_streams);
/**
* snd_hdac_ext_stream_drsm_enable - enable DMA resume for a stream
* @ebus: HD-audio ext core bus
* @enable: flag to enable/disable DRSM
* @index: stream index for which DRSM need to be enabled
*/
void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus,
bool enable, int index)
{
u32 mask = 0;
u32 register_mask = 0;
struct hdac_bus *bus = &ebus->bus;
if (!ebus->drsmcap) {
dev_err(bus->dev, "Address of DRSM capability is NULL");
return;
}
mask |= (1 << index);
register_mask = readl(ebus->drsmcap + AZX_REG_SPB_SPBFCCTL);
mask |= register_mask;
if (enable)
snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, 0, mask);
else
snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, mask, 0);
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable);
/**
* snd_hdac_ext_stream_set_dpibr - sets the dpibr value of a stream
* @ebus: HD-audio ext core bus
* @stream: hdac_ext_stream
* @value: dpib value to set
*/
int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus,
struct hdac_ext_stream *stream, u32 value)
{
struct hdac_bus *bus = &ebus->bus;
if (!ebus->drsmcap) {
dev_err(bus->dev, "Address of DRSM capability is NULL");
return -EINVAL;
}
writel(value, stream->dpibr_addr);
return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_dpibr);
/**
* snd_hdac_ext_stream_set_lpib - sets the lpib value of a stream
* @ebus: HD-audio ext core bus
* @stream: hdac_ext_stream
* @value: lpib value to set
*/
int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value)
{
snd_hdac_stream_writel(&stream->hstream, SD_LPIB, value);
return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_lpib);
......@@ -38,6 +38,7 @@ config SND_SOC_TOPOLOGY
# All the supported SoCs
source "sound/soc/adi/Kconfig"
source "sound/soc/amd/Kconfig"
source "sound/soc/atmel/Kconfig"
source "sound/soc/au1x/Kconfig"
source "sound/soc/bcm/Kconfig"
......
......@@ -18,6 +18,7 @@ obj-$(CONFIG_SND_SOC) += snd-soc-core.o
obj-$(CONFIG_SND_SOC) += codecs/
obj-$(CONFIG_SND_SOC) += generic/
obj-$(CONFIG_SND_SOC) += adi/
obj-$(CONFIG_SND_SOC) += amd/
obj-$(CONFIG_SND_SOC) += atmel/
obj-$(CONFIG_SND_SOC) += au1x/
obj-$(CONFIG_SND_SOC) += bcm/
......
config SND_SOC_AMD_ACP
tristate "AMD Audio Coprocessor support"
help
This option enables ACP DMA support on AMD platform.
snd-soc-acp-pcm-objs := acp-pcm-dma.o
obj-$(CONFIG_SND_SOC_AMD_ACP) += snd-soc-acp-pcm.o
This diff is collapsed.
#ifndef __ACP_HW_H
#define __ACP_HW_H
#include "include/acp_2_2_d.h"
#include "include/acp_2_2_sh_mask.h"
#define ACP_PAGE_SIZE_4K_ENABLE 0x02
#define ACP_PLAYBACK_PTE_OFFSET 10
#define ACP_CAPTURE_PTE_OFFSET 0
#define ACP_GARLIC_CNTL_DEFAULT 0x00000FB4
#define ACP_ONION_CNTL_DEFAULT 0x00000FB4
#define ACP_PHYSICAL_BASE 0x14000
/* Playback SRAM address (as a destination in dma descriptor) */
#define ACP_SHARED_RAM_BANK_1_ADDRESS 0x4002000
/* Capture SRAM address (as a source in dma descriptor) */
#define ACP_SHARED_RAM_BANK_5_ADDRESS 0x400A000
#define ACP_DMA_RESET_TIME 10000
#define ACP_CLOCK_EN_TIME_OUT_VALUE 0x000000FF
#define ACP_SOFT_RESET_DONE_TIME_OUT_VALUE 0x000000FF
#define ACP_DMA_COMPLETE_TIME_OUT_VALUE 0x000000FF
#define ACP_SRAM_BASE_ADDRESS 0x4000000
#define ACP_DAGB_GRP_SRAM_BASE_ADDRESS 0x4001000
#define ACP_DAGB_GRP_SRBM_SRAM_BASE_OFFSET 0x1000
#define ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS 0x00000000
#define ACP_INTERNAL_APERTURE_WINDOW_4_ADDRESS 0x01800000
#define TO_ACP_I2S_1 0x2
#define TO_ACP_I2S_2 0x4
#define FROM_ACP_I2S_1 0xa
#define FROM_ACP_I2S_2 0xb
#define ACP_TILE_ON_MASK 0x03
#define ACP_TILE_OFF_MASK 0x02
#define ACP_TILE_ON_RETAIN_REG_MASK 0x1f
#define ACP_TILE_OFF_RETAIN_REG_MASK 0x20
#define ACP_TILE_P1_MASK 0x3e
#define ACP_TILE_P2_MASK 0x3d
#define ACP_TILE_DSP0_MASK 0x3b
#define ACP_TILE_DSP1_MASK 0x37
#define ACP_TILE_DSP2_MASK 0x2f
/* Playback DMA channels */
#define SYSRAM_TO_ACP_CH_NUM 12
#define ACP_TO_I2S_DMA_CH_NUM 13
/* Capture DMA channels */
#define ACP_TO_SYSRAM_CH_NUM 14
#define I2S_TO_ACP_DMA_CH_NUM 15
#define NUM_DSCRS_PER_CHANNEL 2
#define PLAYBACK_START_DMA_DESCR_CH12 0
#define PLAYBACK_END_DMA_DESCR_CH12 1
#define PLAYBACK_START_DMA_DESCR_CH13 2
#define PLAYBACK_END_DMA_DESCR_CH13 3
#define CAPTURE_START_DMA_DESCR_CH14 4
#define CAPTURE_END_DMA_DESCR_CH14 5
#define CAPTURE_START_DMA_DESCR_CH15 6
#define CAPTURE_END_DMA_DESCR_CH15 7
enum acp_dma_priority_level {
/* 0x0 Specifies the DMA channel is given normal priority */
ACP_DMA_PRIORITY_LEVEL_NORMAL = 0x0,
/* 0x1 Specifies the DMA channel is given high priority */
ACP_DMA_PRIORITY_LEVEL_HIGH = 0x1,
ACP_DMA_PRIORITY_LEVEL_FORCESIZE = 0xFF
};
struct audio_substream_data {
struct page *pg;
unsigned int order;
u16 num_of_pages;
u16 direction;
uint64_t size;
void __iomem *acp_mmio;
};
enum {
ACP_TILE_P1 = 0,
ACP_TILE_P2,
ACP_TILE_DSP0,
ACP_TILE_DSP1,
ACP_TILE_DSP2,
};
enum {
ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION = 0x0,
ACP_DMA_ATTRIBUTES_SHARED_MEM_TO_DAGB_GARLIC = 0x1,
ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM = 0x8,
ACP_DMA_ATTRIBUTES_DAGB_GARLIC_TO_SHAREDMEM = 0x9,
ACP_DMA_ATTRIBUTES_FORCE_SIZE = 0xF
};
typedef struct acp_dma_dscr_transfer {
/* Specifies the source memory location for the DMA data transfer. */
u32 src;
/* Specifies the destination memory location to where the data will
* be transferred.
*/
u32 dest;
/* Specifies the number of bytes need to be transferred
* from source to destination memory.Transfer direction & IOC enable
*/
u32 xfer_val;
/* Reserved for future use */
u32 reserved;
} acp_dma_dscr_transfer_t;
#endif /*__ACP_HW_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -31,20 +31,20 @@
* General Public License for more details.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/io.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/dmaengine_pcm.h>
#include <sound/initval.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
......
......@@ -87,7 +87,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ML26124 if I2C
select SND_SOC_NAU8825 if I2C
select SND_SOC_PCM1681 if I2C
select SND_SOC_PCM1792A if SPI_MASTER
select SND_SOC_PCM179X if SPI_MASTER
select SND_SOC_PCM3008
select SND_SOC_PCM3168A_I2C if I2C
select SND_SOC_PCM3168A_SPI if SPI_MASTER
......@@ -526,8 +526,8 @@ config SND_SOC_PCM1681
tristate "Texas Instruments PCM1681 CODEC"
depends on I2C
config SND_SOC_PCM1792A
tristate "Texas Instruments PCM1792A CODEC"
config SND_SOC_PCM179X
tristate "Texas Instruments PCM179X CODEC"
depends on SPI_MASTER
config SND_SOC_PCM3008
......
......@@ -80,7 +80,7 @@ snd-soc-mc13783-objs := mc13783.o
snd-soc-ml26124-objs := ml26124.o
snd-soc-nau8825-objs := nau8825.o
snd-soc-pcm1681-objs := pcm1681.o
snd-soc-pcm1792a-codec-objs := pcm1792a.o
snd-soc-pcm179x-codec-objs := pcm179x.o
snd-soc-pcm3008-objs := pcm3008.o
snd-soc-pcm3168a-objs := pcm3168a.o
snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o
......@@ -284,7 +284,7 @@ obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o
obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o
obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o
obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o
obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o
obj-$(CONFIG_SND_SOC_PCM3168A_I2C) += snd-soc-pcm3168a-i2c.o
......
......@@ -1494,6 +1494,9 @@ static int arizona_startup(struct snd_pcm_substream *substream,
const struct snd_pcm_hw_constraint_list *constraint;
unsigned int base_rate;
if (!substream->runtime)
return 0;
switch (dai_priv->clk) {
case ARIZONA_CLK_SYSCLK:
base_rate = priv->sysclk;
......
......@@ -1954,17 +1954,44 @@ static int da7218_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
break;
case SND_SOC_DAIFMT_NB_IF:
dai_clk_mode |= DA7218_DAI_WCLK_POL_INV;
break;
case SND_SOC_DAIFMT_IB_NF:
dai_clk_mode |= DA7218_DAI_CLK_POL_INV;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
case SND_SOC_DAIFMT_LEFT_J:
case SND_SOC_DAIFMT_RIGHT_J:
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
break;
case SND_SOC_DAIFMT_NB_IF:
dai_clk_mode |= DA7218_DAI_WCLK_POL_INV;
break;
case SND_SOC_DAIFMT_IB_NF:
dai_clk_mode |= DA7218_DAI_CLK_POL_INV;
break;
case SND_SOC_DAIFMT_IB_IF:
dai_clk_mode |= DA7218_DAI_WCLK_POL_INV |
DA7218_DAI_CLK_POL_INV;
break;
default:
return -EINVAL;
}
break;
case SND_SOC_DAIFMT_IB_IF:
dai_clk_mode |= DA7218_DAI_WCLK_POL_INV | DA7218_DAI_CLK_POL_INV;
case SND_SOC_DAIFMT_DSP_B:
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
dai_clk_mode |= DA7218_DAI_CLK_POL_INV;
break;
case SND_SOC_DAIFMT_NB_IF:
dai_clk_mode |= DA7218_DAI_WCLK_POL_INV |
DA7218_DAI_CLK_POL_INV;
break;
case SND_SOC_DAIFMT_IB_NF:
break;
case SND_SOC_DAIFMT_IB_IF:
dai_clk_mode |= DA7218_DAI_WCLK_POL_INV;
break;
default:
return -EINVAL;
}
break;
default:
return -EINVAL;
......
......@@ -1156,18 +1156,44 @@ static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
break;
case SND_SOC_DAIFMT_NB_IF:
dai_clk_mode |= DA7219_DAI_WCLK_POL_INV;
break;
case SND_SOC_DAIFMT_IB_NF:
dai_clk_mode |= DA7219_DAI_CLK_POL_INV;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
case SND_SOC_DAIFMT_LEFT_J:
case SND_SOC_DAIFMT_RIGHT_J:
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
break;
case SND_SOC_DAIFMT_NB_IF:
dai_clk_mode |= DA7219_DAI_WCLK_POL_INV;
break;
case SND_SOC_DAIFMT_IB_NF:
dai_clk_mode |= DA7219_DAI_CLK_POL_INV;
break;
case SND_SOC_DAIFMT_IB_IF:
dai_clk_mode |= DA7219_DAI_WCLK_POL_INV |
DA7219_DAI_CLK_POL_INV;
break;
default:
return -EINVAL;
}
break;
case SND_SOC_DAIFMT_IB_IF:
dai_clk_mode |= DA7219_DAI_WCLK_POL_INV |
DA7219_DAI_CLK_POL_INV;
case SND_SOC_DAIFMT_DSP_B:
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
dai_clk_mode |= DA7219_DAI_CLK_POL_INV;
break;
case SND_SOC_DAIFMT_NB_IF:
dai_clk_mode |= DA7219_DAI_WCLK_POL_INV |
DA7219_DAI_CLK_POL_INV;
break;
case SND_SOC_DAIFMT_IB_NF:
break;
case SND_SOC_DAIFMT_IB_IF:
dai_clk_mode |= DA7219_DAI_WCLK_POL_INV;
break;
default:
return -EINVAL;
}
break;
default:
return -EINVAL;
......@@ -1592,9 +1618,14 @@ static void da7219_handle_pdata(struct snd_soc_codec *codec)
}
}
static struct reg_sequence da7219_rev_aa_patch[] = {
{ DA7219_REFERENCES, 0x08 },
};
static int da7219_probe(struct snd_soc_codec *codec)
{
struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
unsigned int rev;
int ret;
mutex_init(&da7219->lock);
......@@ -1604,6 +1635,26 @@ static int da7219_probe(struct snd_soc_codec *codec)
if (ret)
return ret;
ret = regmap_read(da7219->regmap, DA7219_CHIP_REVISION, &rev);
if (ret) {
dev_err(codec->dev, "Failed to read chip revision: %d\n", ret);
goto err_disable_reg;
}
switch (rev & DA7219_CHIP_MINOR_MASK) {
case 0:
ret = regmap_register_patch(da7219->regmap, da7219_rev_aa_patch,
ARRAY_SIZE(da7219_rev_aa_patch));
if (ret) {
dev_err(codec->dev, "Failed to register AA patch: %d\n",
ret);
goto err_disable_reg;
}
break;
default:
break;
}
/* Handle DT/Platform data */
if (codec->dev->of_node)
da7219->pdata = da7219_of_to_pdata(codec);
......@@ -1774,7 +1825,6 @@ static struct reg_default da7219_reg_defaults[] = {
{ DA7219_MIXOUT_R_CTRL, 0x10 },
{ DA7219_CHIP_ID1, 0x23 },
{ DA7219_CHIP_ID2, 0x93 },
{ DA7219_CHIP_REVISION, 0x00 },
{ DA7219_IO_CTRL, 0x00 },
{ DA7219_GAIN_RAMP_CTRL, 0x00 },
{ DA7219_PC_COUNT, 0x02 },
......
......@@ -43,11 +43,13 @@ struct hdac_hdmi_cvt_params {
};
struct hdac_hdmi_cvt {
struct list_head head;
hda_nid_t nid;
struct hdac_hdmi_cvt_params params;
};
struct hdac_hdmi_pin {
struct list_head head;
hda_nid_t nid;
int num_mux_nids;
hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
......@@ -55,21 +57,23 @@ struct hdac_hdmi_pin {
struct hdac_hdmi_dai_pin_map {
int dai_id;
struct hdac_hdmi_pin pin;
struct hdac_hdmi_cvt cvt;
struct hdac_hdmi_pin *pin;
struct hdac_hdmi_cvt *cvt;
};
struct hdac_hdmi_priv {
hda_nid_t pin_nid[3];
hda_nid_t cvt_nid[3];
struct hdac_hdmi_dai_pin_map dai_map[3];
struct list_head pin_list;
struct list_head cvt_list;
int num_pin;
int num_cvt;
};
static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
{
struct hdac_device *hdac = container_of(dev, struct hdac_device, dev);
struct hdac_device *hdac = dev_to_hdac_dev(dev);
return container_of(hdac, struct hdac_ext_device, hdac);
return to_ehdac_device(hdac);
}
static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac,
......@@ -149,13 +153,15 @@ static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev,
struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state)
{
/* Power up pin widget */
if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin.nid, pwr_state))
snd_hdac_codec_write(&edev->hdac, dai_map->pin.nid, 0,
if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin->nid,
pwr_state))
snd_hdac_codec_write(&edev->hdac, dai_map->pin->nid, 0,
AC_VERB_SET_POWER_STATE, pwr_state);
/* Power up converter */
if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt.nid, pwr_state))
snd_hdac_codec_write(&edev->hdac, dai_map->cvt.nid, 0,
if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt->nid,
pwr_state))
snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
AC_VERB_SET_POWER_STATE, pwr_state);
}
......@@ -179,13 +185,13 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream,
dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n",
dd->stream_tag, dd->format);
ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt.nid,
dai_map->pin.nid);
ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid,
dai_map->pin->nid);
if (ret < 0)
return ret;
return hdac_hdmi_setup_stream(hdac, dai_map->cvt.nid, dai_map->pin.nid,
dd->stream_tag, dd->format);
return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid,
dai_map->pin->nid, dd->stream_tag, dd->format);
}
static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
......@@ -221,9 +227,9 @@ static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream,
dai_map = &hdmi->dai_map[dai->id];
snd_hdac_codec_write(&edev->hdac, dai_map->cvt.nid, 0,
snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
AC_VERB_SET_CHANNEL_STREAMID, 0);
snd_hdac_codec_write(&edev->hdac, dai_map->cvt.nid, 0,
snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
AC_VERB_SET_STREAM_FORMAT, 0);
dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
......@@ -249,7 +255,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
dai_map = &hdmi->dai_map[dai->id];
val = snd_hdac_codec_read(&hdac->hdac, dai_map->pin.nid, 0,
val = snd_hdac_codec_read(&hdac->hdac, dai_map->pin->nid, 0,
AC_VERB_GET_PIN_SENSE, 0);
dev_info(&hdac->hdac.dev, "Val for AC_VERB_GET_PIN_SENSE: %x\n", val);
......@@ -260,7 +266,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0);
snd_hdac_codec_write(&hdac->hdac, dai_map->pin.nid, 0,
snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
snd_pcm_hw_constraint_step(substream->runtime, 0,
......@@ -280,7 +286,7 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3);
snd_hdac_codec_write(&hdac->hdac, dai_map->pin.nid, 0,
snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
}
......@@ -304,26 +310,6 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
return err;
}
static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac,
struct hdac_hdmi_pin *pin)
{
if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) {
dev_warn(&hdac->hdac.dev,
"HDMI: pin %d wcaps %#x does not support connection list\n",
pin->nid, get_wcaps(&hdac->hdac, pin->nid));
return -EINVAL;
}
pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid,
pin->mux_nids, HDA_MAX_CONNECTIONS);
if (pin->num_mux_nids == 0) {
dev_err(&hdac->hdac.dev, "No connections found\n");
return -ENODEV;
}
return pin->num_mux_nids;
}
static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w,
enum snd_soc_dapm_type id,
const char *wname, const char *stream)
......@@ -366,40 +352,79 @@ static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm,
snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route));
}
static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev,
struct hdac_hdmi_dai_pin_map *dai_map,
hda_nid_t pin_nid, hda_nid_t cvt_nid, int dai_id)
static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
{
int ret;
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_dai_pin_map *dai_map = &hdmi->dai_map[0];
struct hdac_hdmi_cvt *cvt;
struct hdac_hdmi_pin *pin;
dai_map->dai_id = dai_id;
dai_map->pin.nid = pin_nid;
if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list))
return -EINVAL;
ret = hdac_hdmi_query_pin_connlist(edev, &dai_map->pin);
if (ret < 0) {
dev_err(&edev->hdac.dev,
"Error querying connection list: %d\n", ret);
return ret;
}
/*
* Currently on board only 1 pin and 1 converter is enabled for
* simplification, more will be added eventually
* So using fixed map for dai_id:pin:cvt
*/
cvt = list_first_entry(&hdmi->cvt_list, struct hdac_hdmi_cvt, head);
pin = list_first_entry(&hdmi->pin_list, struct hdac_hdmi_pin, head);
dai_map->dai_id = 0;
dai_map->pin = pin;
dai_map->cvt.nid = cvt_nid;
dai_map->cvt = cvt;
/* Enable out path for this pin widget */
snd_hdac_codec_write(&edev->hdac, pin_nid, 0,
snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
/* Enable transmission */
snd_hdac_codec_write(&edev->hdac, cvt_nid, 0,
snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
AC_VERB_SET_DIGI_CONVERT_1, 1);
/* Category Code (CC) to zero */
snd_hdac_codec_write(&edev->hdac, cvt_nid, 0,
snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
AC_VERB_SET_DIGI_CONVERT_2, 0);
snd_hdac_codec_write(&edev->hdac, pin_nid, 0,
snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
AC_VERB_SET_CONNECT_SEL, 0);
return hdac_hdmi_query_cvt_params(&edev->hdac, &dai_map->cvt);
return 0;
}
static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
{
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_cvt *cvt;
cvt = kzalloc(sizeof(*cvt), GFP_KERNEL);
if (!cvt)
return -ENOMEM;
cvt->nid = nid;
list_add_tail(&cvt->head, &hdmi->cvt_list);
hdmi->num_cvt++;
return hdac_hdmi_query_cvt_params(&edev->hdac, cvt);
}
static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
{
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pin *pin;
pin = kzalloc(sizeof(*pin), GFP_KERNEL);
if (!pin)
return -ENOMEM;
pin->nid = nid;
list_add_tail(&pin->head, &hdmi->pin_list);
hdmi->num_pin++;
return 0;
}
/*
......@@ -412,10 +437,10 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev)
int i, num_nodes;
struct hdac_device *hdac = &edev->hdac;
struct hdac_hdmi_priv *hdmi = edev->private_data;
int cvt_nid = 0, pin_nid = 0;
int ret;
num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid);
if (!nid || num_nodes < 0) {
if (!nid || num_nodes <= 0) {
dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n");
return -EINVAL;
}
......@@ -436,29 +461,25 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev)
switch (type) {
case AC_WID_AUD_OUT:
hdmi->cvt_nid[cvt_nid] = nid;
cvt_nid++;
ret = hdac_hdmi_add_cvt(edev, nid);
if (ret < 0)
return ret;
break;
case AC_WID_PIN:
hdmi->pin_nid[pin_nid] = nid;
pin_nid++;
ret = hdac_hdmi_add_pin(edev, nid);
if (ret < 0)
return ret;
break;
}
}
hdac->end_nid = nid;
if (!pin_nid || !cvt_nid)
if (!hdmi->num_pin || !hdmi->num_cvt)
return -EIO;
/*
* Currently on board only 1 pin and 1 converter is enabled for
* simplification, more will be added eventually
* So using fixed map for dai_id:pin:cvt
*/
return hdac_hdmi_init_dai_map(edev, &hdmi->dai_map[0], hdmi->pin_nid[0],
hdmi->cvt_nid[0], 0);
return hdac_hdmi_init_dai_map(edev);
}
static int hdmi_codec_probe(struct snd_soc_codec *codec)
......@@ -542,6 +563,9 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
dev_set_drvdata(&codec->dev, edev);
INIT_LIST_HEAD(&hdmi_priv->pin_list);
INIT_LIST_HEAD(&hdmi_priv->cvt_list);
ret = hdac_hdmi_parse_and_map_nid(edev);
if (ret < 0)
return ret;
......@@ -553,8 +577,22 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
{
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pin *pin, *pin_next;
struct hdac_hdmi_cvt *cvt, *cvt_next;
snd_soc_unregister_codec(&edev->hdac.dev);
list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) {
list_del(&cvt->head);
kfree(cvt);
}
list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) {
list_del(&pin->head);
kfree(pin);
}
return 0;
}
......
/*
* PCM1792A ASoC codec driver
* PCM179X ASoC codec driver
*
* Copyright (c) Amarula Solutions B.V. 2013
*
......@@ -31,21 +31,21 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include "pcm1792a.h"
#include "pcm179x.h"
#define PCM1792A_DAC_VOL_LEFT 0x10
#define PCM1792A_DAC_VOL_RIGHT 0x11
#define PCM1792A_FMT_CONTROL 0x12
#define PCM1792A_MODE_CONTROL 0x13
#define PCM1792A_SOFT_MUTE PCM1792A_FMT_CONTROL
#define PCM179X_DAC_VOL_LEFT 0x10
#define PCM179X_DAC_VOL_RIGHT 0x11
#define PCM179X_FMT_CONTROL 0x12
#define PCM179X_MODE_CONTROL 0x13
#define PCM179X_SOFT_MUTE PCM179X_FMT_CONTROL
#define PCM1792A_FMT_MASK 0x70
#define PCM1792A_FMT_SHIFT 4
#define PCM1792A_MUTE_MASK 0x01
#define PCM1792A_MUTE_SHIFT 0
#define PCM1792A_ATLD_ENABLE (1 << 7)
#define PCM179X_FMT_MASK 0x70
#define PCM179X_FMT_SHIFT 4
#define PCM179X_MUTE_MASK 0x01
#define PCM179X_MUTE_SHIFT 0
#define PCM179X_ATLD_ENABLE (1 << 7)
static const struct reg_default pcm1792a_reg_defaults[] = {
static const struct reg_default pcm179x_reg_defaults[] = {
{ 0x10, 0xff },
{ 0x11, 0xff },
{ 0x12, 0x50 },
......@@ -56,57 +56,57 @@ static const struct reg_default pcm1792a_reg_defaults[] = {
{ 0x17, 0x00 },
};
static bool pcm1792a_accessible_reg(struct device *dev, unsigned int reg)
static bool pcm179x_accessible_reg(struct device *dev, unsigned int reg)
{
return reg >= 0x10 && reg <= 0x17;
}
static bool pcm1792a_writeable_reg(struct device *dev, unsigned register reg)
static bool pcm179x_writeable_reg(struct device *dev, unsigned register reg)
{
bool accessible;
accessible = pcm1792a_accessible_reg(dev, reg);
accessible = pcm179x_accessible_reg(dev, reg);
return accessible && reg != 0x16 && reg != 0x17;
}
struct pcm1792a_private {
struct pcm179x_private {
struct regmap *regmap;
unsigned int format;
unsigned int rate;
};
static int pcm1792a_set_dai_fmt(struct snd_soc_dai *codec_dai,
static int pcm179x_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int format)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec);
priv->format = format;
return 0;
}
static int pcm1792a_digital_mute(struct snd_soc_dai *dai, int mute)
static int pcm179x_digital_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec);
int ret;
ret = regmap_update_bits(priv->regmap, PCM1792A_SOFT_MUTE,
PCM1792A_MUTE_MASK, !!mute);
ret = regmap_update_bits(priv->regmap, PCM179X_SOFT_MUTE,
PCM179X_MUTE_MASK, !!mute);
if (ret < 0)
return ret;
return 0;
}
static int pcm1792a_hw_params(struct snd_pcm_substream *substream,
static int pcm179x_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec);
int val = 0, ret;
priv->rate = params_rate(params);
......@@ -143,129 +143,129 @@ static int pcm1792a_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
val = val << PCM1792A_FMT_SHIFT | PCM1792A_ATLD_ENABLE;
val = val << PCM179X_FMT_SHIFT | PCM179X_ATLD_ENABLE;
ret = regmap_update_bits(priv->regmap, PCM1792A_FMT_CONTROL,
PCM1792A_FMT_MASK | PCM1792A_ATLD_ENABLE, val);
ret = regmap_update_bits(priv->regmap, PCM179X_FMT_CONTROL,
PCM179X_FMT_MASK | PCM179X_ATLD_ENABLE, val);
if (ret < 0)
return ret;
return 0;
}
static const struct snd_soc_dai_ops pcm1792a_dai_ops = {
.set_fmt = pcm1792a_set_dai_fmt,
.hw_params = pcm1792a_hw_params,
.digital_mute = pcm1792a_digital_mute,
static const struct snd_soc_dai_ops pcm179x_dai_ops = {
.set_fmt = pcm179x_set_dai_fmt,
.hw_params = pcm179x_hw_params,
.digital_mute = pcm179x_digital_mute,
};
static const DECLARE_TLV_DB_SCALE(pcm1792a_dac_tlv, -12000, 50, 1);
static const DECLARE_TLV_DB_SCALE(pcm179x_dac_tlv, -12000, 50, 1);
static const struct snd_kcontrol_new pcm1792a_controls[] = {
SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM1792A_DAC_VOL_LEFT,
PCM1792A_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0,
pcm1792a_dac_tlv),
SOC_SINGLE("DAC Invert Output Switch", PCM1792A_MODE_CONTROL, 7, 1, 0),
SOC_SINGLE("DAC Rolloff Filter Switch", PCM1792A_MODE_CONTROL, 1, 1, 0),
static const struct snd_kcontrol_new pcm179x_controls[] = {
SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM179X_DAC_VOL_LEFT,
PCM179X_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0,
pcm179x_dac_tlv),
SOC_SINGLE("DAC Invert Output Switch", PCM179X_MODE_CONTROL, 7, 1, 0),
SOC_SINGLE("DAC Rolloff Filter Switch", PCM179X_MODE_CONTROL, 1, 1, 0),
};
static const struct snd_soc_dapm_widget pcm1792a_dapm_widgets[] = {
static const struct snd_soc_dapm_widget pcm179x_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("IOUTL+"),
SND_SOC_DAPM_OUTPUT("IOUTL-"),
SND_SOC_DAPM_OUTPUT("IOUTR+"),
SND_SOC_DAPM_OUTPUT("IOUTR-"),
};
static const struct snd_soc_dapm_route pcm1792a_dapm_routes[] = {
static const struct snd_soc_dapm_route pcm179x_dapm_routes[] = {
{ "IOUTL+", NULL, "Playback" },
{ "IOUTL-", NULL, "Playback" },
{ "IOUTR+", NULL, "Playback" },
{ "IOUTR-", NULL, "Playback" },
};
static struct snd_soc_dai_driver pcm1792a_dai = {
.name = "pcm1792a-hifi",
static struct snd_soc_dai_driver pcm179x_dai = {
.name = "pcm179x-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
.channels_max = 2,
.rates = PCM1792A_RATES,
.formats = PCM1792A_FORMATS, },
.ops = &pcm1792a_dai_ops,
.ops = &pcm179x_dai_ops,
};
static const struct of_device_id pcm1792a_of_match[] = {
static const struct of_device_id pcm179x_of_match[] = {
{ .compatible = "ti,pcm1792a", },
{ }
};
MODULE_DEVICE_TABLE(of, pcm1792a_of_match);
MODULE_DEVICE_TABLE(of, pcm179x_of_match);
static const struct regmap_config pcm1792a_regmap = {
static const struct regmap_config pcm179x_regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 23,
.reg_defaults = pcm1792a_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(pcm1792a_reg_defaults),
.writeable_reg = pcm1792a_writeable_reg,
.readable_reg = pcm1792a_accessible_reg,
.reg_defaults = pcm179x_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(pcm179x_reg_defaults),
.writeable_reg = pcm179x_writeable_reg,
.readable_reg = pcm179x_accessible_reg,
};
static struct snd_soc_codec_driver soc_codec_dev_pcm1792a = {
.controls = pcm1792a_controls,
.num_controls = ARRAY_SIZE(pcm1792a_controls),
.dapm_widgets = pcm1792a_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(pcm1792a_dapm_widgets),
.dapm_routes = pcm1792a_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(pcm1792a_dapm_routes),
static struct snd_soc_codec_driver soc_codec_dev_pcm179x = {
.controls = pcm179x_controls,
.num_controls = ARRAY_SIZE(pcm179x_controls),
.dapm_widgets = pcm179x_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(pcm179x_dapm_widgets),
.dapm_routes = pcm179x_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(pcm179x_dapm_routes),
};
static int pcm1792a_spi_probe(struct spi_device *spi)
static int pcm179x_spi_probe(struct spi_device *spi)
{
struct pcm1792a_private *pcm1792a;
struct pcm179x_private *pcm179x;
int ret;
pcm1792a = devm_kzalloc(&spi->dev, sizeof(struct pcm1792a_private),
pcm179x = devm_kzalloc(&spi->dev, sizeof(struct pcm179x_private),
GFP_KERNEL);
if (!pcm1792a)
if (!pcm179x)
return -ENOMEM;
spi_set_drvdata(spi, pcm1792a);
spi_set_drvdata(spi, pcm179x);
pcm1792a->regmap = devm_regmap_init_spi(spi, &pcm1792a_regmap);
if (IS_ERR(pcm1792a->regmap)) {
ret = PTR_ERR(pcm1792a->regmap);
pcm179x->regmap = devm_regmap_init_spi(spi, &pcm179x_regmap);
if (IS_ERR(pcm179x->regmap)) {
ret = PTR_ERR(pcm179x->regmap);
dev_err(&spi->dev, "Failed to register regmap: %d\n", ret);
return ret;
}
return snd_soc_register_codec(&spi->dev,
&soc_codec_dev_pcm1792a, &pcm1792a_dai, 1);
&soc_codec_dev_pcm179x, &pcm179x_dai, 1);
}
static int pcm1792a_spi_remove(struct spi_device *spi)
static int pcm179x_spi_remove(struct spi_device *spi)
{
snd_soc_unregister_codec(&spi->dev);
return 0;
}
static const struct spi_device_id pcm1792a_spi_ids[] = {
{ "pcm1792a", 0 },
static const struct spi_device_id pcm179x_spi_ids[] = {
{ "pcm179x", 0 },
{ },
};
MODULE_DEVICE_TABLE(spi, pcm1792a_spi_ids);
MODULE_DEVICE_TABLE(spi, pcm179x_spi_ids);
static struct spi_driver pcm1792a_codec_driver = {
static struct spi_driver pcm179x_codec_driver = {
.driver = {
.name = "pcm1792a",
.of_match_table = of_match_ptr(pcm1792a_of_match),
.name = "pcm179x",
.of_match_table = of_match_ptr(pcm179x_of_match),
},
.id_table = pcm1792a_spi_ids,
.probe = pcm1792a_spi_probe,
.remove = pcm1792a_spi_remove,
.id_table = pcm179x_spi_ids,
.probe = pcm179x_spi_probe,
.remove = pcm179x_spi_remove,
};
module_spi_driver(pcm1792a_codec_driver);
module_spi_driver(pcm179x_codec_driver);
MODULE_DESCRIPTION("ASoC PCM1792A driver");
MODULE_DESCRIPTION("ASoC PCM179X driver");
MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
MODULE_LICENSE("GPL");
/*
* definitions for PCM1792A
* definitions for PCM179X
*
* Copyright 2013 Amarula Solutions
*
......@@ -14,8 +14,8 @@
* GNU General Public License for more details.
*/
#ifndef __PCM1792A_H__
#define __PCM1792A_H__
#ifndef __PCM179X_H__
#define __PCM179X_H__
#define PCM1792A_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_8000_48000 | \
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
......
......@@ -488,6 +488,18 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
return 0;
}
static int is_using_asrc(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
if (!rt5640->asrc_en)
return 0;
return 1;
}
/* Digital Mixer */
static const struct snd_kcontrol_new rt5640_sto_adc_l_mix[] = {
SOC_DAPM_SINGLE("ADC1 Switch", RT5640_STO_ADC_MIXER,
......@@ -1059,6 +1071,20 @@ static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w,
static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2,
RT5640_PWR_PLL_BIT, 0, NULL, 0),
/* ASRC */
SND_SOC_DAPM_SUPPLY_S("Stereo Filter ASRC", 1, RT5640_ASRC_1,
15, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("I2S2 Filter ASRC", 1, RT5640_ASRC_1,
12, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5640_ASRC_1,
11, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("DMIC1 ASRC", 1, RT5640_ASRC_1,
9, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("DMIC2 ASRC", 1, RT5640_ASRC_1,
8, 0, NULL, 0),
/* Input Side */
/* micbias */
SND_SOC_DAPM_SUPPLY("LDO2", RT5640_PWR_ANLG1,
......@@ -1319,6 +1345,12 @@ static const struct snd_soc_dapm_widget rt5639_specific_dapm_widgets[] = {
};
static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{ "I2S1", NULL, "Stereo Filter ASRC", is_using_asrc },
{ "I2S2", NULL, "I2S2 ASRC", is_using_asrc },
{ "I2S2", NULL, "I2S2 Filter ASRC", is_using_asrc },
{ "DMIC1", NULL, "DMIC1 ASRC", is_using_asrc },
{ "DMIC2", NULL, "DMIC2 ASRC", is_using_asrc },
{"IN1P", NULL, "LDO2"},
{"IN2P", NULL, "LDO2"},
{"IN3P", NULL, "LDO2"},
......@@ -1981,6 +2013,76 @@ int rt5640_dmic_enable(struct snd_soc_codec *codec,
}
EXPORT_SYMBOL_GPL(rt5640_dmic_enable);
int rt5640_sel_asrc_clk_src(struct snd_soc_codec *codec,
unsigned int filter_mask, unsigned int clk_src)
{
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
unsigned int asrc2_mask = 0;
unsigned int asrc2_value = 0;
switch (clk_src) {
case RT5640_CLK_SEL_SYS:
case RT5640_CLK_SEL_ASRC:
break;
default:
return -EINVAL;
}
if (!filter_mask)
return -EINVAL;
if (filter_mask & RT5640_DA_STEREO_FILTER) {
asrc2_mask |= RT5640_STO_DAC_M_MASK;
asrc2_value = (asrc2_value & ~RT5640_STO_DAC_M_MASK)
| (clk_src << RT5640_STO_DAC_M_SFT);
}
if (filter_mask & RT5640_DA_MONO_L_FILTER) {
asrc2_mask |= RT5640_MDA_L_M_MASK;
asrc2_value = (asrc2_value & ~RT5640_MDA_L_M_MASK)
| (clk_src << RT5640_MDA_L_M_SFT);
}
if (filter_mask & RT5640_DA_MONO_R_FILTER) {
asrc2_mask |= RT5640_MDA_R_M_MASK;
asrc2_value = (asrc2_value & ~RT5640_MDA_R_M_MASK)
| (clk_src << RT5640_MDA_R_M_SFT);
}
if (filter_mask & RT5640_AD_STEREO_FILTER) {
asrc2_mask |= RT5640_ADC_M_MASK;
asrc2_value = (asrc2_value & ~RT5640_ADC_M_MASK)
| (clk_src << RT5640_ADC_M_SFT);
}
if (filter_mask & RT5640_AD_MONO_L_FILTER) {
asrc2_mask |= RT5640_MAD_L_M_MASK;
asrc2_value = (asrc2_value & ~RT5640_MAD_L_M_MASK)
| (clk_src << RT5640_MAD_L_M_SFT);
}
if (filter_mask & RT5640_AD_MONO_R_FILTER) {
asrc2_mask |= RT5640_MAD_R_M_MASK;
asrc2_value = (asrc2_value & ~RT5640_MAD_R_M_MASK)
| (clk_src << RT5640_MAD_R_M_SFT);
}
snd_soc_update_bits(codec, RT5640_ASRC_2,
asrc2_mask, asrc2_value);
if (snd_soc_read(codec, RT5640_ASRC_2)) {
rt5640->asrc_en = true;
snd_soc_update_bits(codec, RT5640_JD_CTRL, 0x3, 0x3);
} else {
rt5640->asrc_en = false;
snd_soc_update_bits(codec, RT5640_JD_CTRL, 0x3, 0x0);
}
return 0;
}
EXPORT_SYMBOL_GPL(rt5640_sel_asrc_clk_src);
static int rt5640_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
......@@ -2175,6 +2277,7 @@ static const struct acpi_device_id rt5640_acpi_match[] = {
{ "INT33CA", 0 },
{ "10EC5640", 0 },
{ "10EC5642", 0 },
{ "INTCCFFD", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);
......
......@@ -1033,6 +1033,10 @@
#define RT5640_DMIC_2_M_NOR (0x0 << 8)
#define RT5640_DMIC_2_M_ASYN (0x1 << 8)
/* ASRC clock source selection (0x84) */
#define RT5640_CLK_SEL_SYS (0x0)
#define RT5640_CLK_SEL_ASRC (0x1)
/* ASRC Control 2 (0x84) */
#define RT5640_MDA_L_M_MASK (0x1 << 15)
#define RT5640_MDA_L_M_SFT 15
......@@ -2079,6 +2083,16 @@ enum {
RT5640_DMIC2,
};
/* filter mask */
enum {
RT5640_DA_STEREO_FILTER = 0x1,
RT5640_DA_MONO_L_FILTER = (0x1 << 1),
RT5640_DA_MONO_R_FILTER = (0x1 << 2),
RT5640_AD_STEREO_FILTER = (0x1 << 3),
RT5640_AD_MONO_L_FILTER = (0x1 << 4),
RT5640_AD_MONO_R_FILTER = (0x1 << 5),
};
struct rt5640_priv {
struct snd_soc_codec *codec;
struct rt5640_platform_data pdata;
......@@ -2095,9 +2109,12 @@ struct rt5640_priv {
int pll_out;
bool hp_mute;
bool asrc_en;
};
int rt5640_dmic_enable(struct snd_soc_codec *codec,
bool dmic1_data_pin, bool dmic2_data_pin);
int rt5640_sel_asrc_clk_src(struct snd_soc_codec *codec,
unsigned int filter_mask, unsigned int clk_src);
#endif
......@@ -64,7 +64,6 @@ static const struct reg_sequence init_list[] = {
{RT5645_PR_BASE + 0x21, 0x4040},
{RT5645_PR_BASE + 0x23, 0x0004},
};
#define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list)
static const struct reg_sequence rt5650_init_list[] = {
{0xf6, 0x0100},
......@@ -405,6 +404,7 @@ struct rt5645_priv {
struct delayed_work jack_detect_work, rcclock_work;
struct regulator_bulk_data supplies[ARRAY_SIZE(rt5645_supply_names)];
struct rt5645_eq_param_s *eq_param;
struct timer_list btn_check_timer;
int codec_type;
int sysclk;
......@@ -3066,6 +3066,7 @@ static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec,
snd_soc_dapm_force_enable_pin(dapm, "ADC R power");
snd_soc_dapm_sync(dapm);
snd_soc_update_bits(codec, RT5650_4BTN_IL_CMD1, 0x3, 0x3);
snd_soc_update_bits(codec,
RT5645_INT_IRQ_ST, 0x8, 0x8);
snd_soc_update_bits(codec,
......@@ -3134,7 +3135,7 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
}
if (rt5645->pdata.jd_invert)
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR);
} else { /* jack out */
rt5645->jack_type = 0;
......@@ -3155,7 +3156,7 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
snd_soc_dapm_sync(dapm);
if (rt5645->pdata.jd_invert)
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR);
RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
}
return rt5645->jack_type;
......@@ -3279,6 +3280,12 @@ static void rt5645_jack_detect_work(struct work_struct *work)
}
if (btn_type == 0)/* button release */
report = rt5645->jack_type;
else {
if (rt5645->pdata.jd_invert) {
mod_timer(&rt5645->btn_check_timer,
msecs_to_jiffies(100));
}
}
break;
/* jack out */
......@@ -3321,6 +3328,14 @@ static irqreturn_t rt5645_irq(int irq, void *data)
return IRQ_HANDLED;
}
static void rt5645_btn_check_callback(unsigned long data)
{
struct rt5645_priv *rt5645 = (struct rt5645_priv *)data;
queue_delayed_work(system_power_efficient_wq,
&rt5645->jack_detect_work, msecs_to_jiffies(5));
}
static int rt5645_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
......@@ -3510,7 +3525,7 @@ static const struct i2c_device_id rt5645_i2c_id[] = {
MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
#ifdef CONFIG_ACPI
static struct acpi_device_id rt5645_acpi_match[] = {
static const struct acpi_device_id rt5645_acpi_match[] = {
{ "10EC5645", 0 },
{ "10EC5650", 0 },
{},
......@@ -3787,6 +3802,13 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
}
}
if (rt5645->pdata.jd_invert) {
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
setup_timer(&rt5645->btn_check_timer,
rt5645_btn_check_callback, (unsigned long)rt5645);
}
INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work);
INIT_DELAYED_WORK(&rt5645->rcclock_work, rt5645_rcclock_work);
......
......@@ -18,6 +18,7 @@
#include <linux/regmap.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
......@@ -1735,12 +1736,38 @@ static const struct regmap_config rt5651_regmap = {
.num_ranges = ARRAY_SIZE(rt5651_ranges),
};
#if defined(CONFIG_OF)
static const struct of_device_id rt5651_of_match[] = {
{ .compatible = "realtek,rt5651", },
{},
};
MODULE_DEVICE_TABLE(of, rt5651_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt5651_acpi_match[] = {
{ "10EC5651", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, rt5651_acpi_match);
#endif
static const struct i2c_device_id rt5651_i2c_id[] = {
{ "rt5651", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt5651_i2c_id);
static int rt5651_parse_dt(struct rt5651_priv *rt5651, struct device_node *np)
{
rt5651->pdata.in2_diff = of_property_read_bool(np,
"realtek,in2-differential");
rt5651->pdata.dmic_en = of_property_read_bool(np,
"realtek,dmic-en");
return 0;
}
static int rt5651_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
......@@ -1757,6 +1784,8 @@ static int rt5651_i2c_probe(struct i2c_client *i2c,
if (pdata)
rt5651->pdata = *pdata;
else if (i2c->dev.of_node)
rt5651_parse_dt(rt5651, i2c->dev.of_node);
rt5651->regmap = devm_regmap_init_i2c(i2c, &rt5651_regmap);
if (IS_ERR(rt5651->regmap)) {
......@@ -1806,6 +1835,8 @@ static int rt5651_i2c_remove(struct i2c_client *i2c)
static struct i2c_driver rt5651_i2c_driver = {
.driver = {
.name = "rt5651",
.acpi_match_table = ACPI_PTR(rt5651_acpi_match),
.of_match_table = of_match_ptr(rt5651_of_match),
},
.probe = rt5651_i2c_probe,
.remove = rt5651_i2c_remove,
......
......@@ -1097,8 +1097,7 @@ static int twl6040_probe(struct snd_soc_codec *codec)
{
struct twl6040_data *priv;
struct twl6040 *twl6040 = dev_get_drvdata(codec->dev->parent);
struct platform_device *pdev = container_of(codec->dev,
struct platform_device, dev);
struct platform_device *pdev = to_platform_device(codec->dev);
int ret = 0;
priv = devm_kzalloc(codec->dev, sizeof(*priv), GFP_KERNEL);
......
......@@ -360,15 +360,13 @@ static int wm5110_hp_ev(struct snd_soc_dapm_widget *w,
static int wm5110_clear_pga_volume(struct arizona *arizona, int output)
{
struct reg_sequence clear_pga = {
ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4, 0x80
};
unsigned int reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4;
int ret;
ret = regmap_multi_reg_write_bypassed(arizona->regmap, &clear_pga, 1);
ret = regmap_write(arizona->regmap, reg, 0x80);
if (ret)
dev_err(arizona->dev, "Failed to clear PGA (0x%x): %d\n",
clear_pga.reg, ret);
reg, ret);
return ret;
}
......@@ -439,18 +437,17 @@ static int wm5110_in_pga_get(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct snd_soc_card *card = dapm->card;
int ret;
/*
* PGA Volume is also used as part of the enable sequence, so
* usage of it should be avoided whilst that is running.
*/
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
snd_soc_dapm_mutex_lock(dapm);
ret = snd_soc_get_volsw_range(kcontrol, ucontrol);
mutex_unlock(&card->dapm_mutex);
snd_soc_dapm_mutex_unlock(dapm);
return ret;
}
......@@ -460,18 +457,17 @@ static int wm5110_in_pga_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct snd_soc_card *card = dapm->card;
int ret;
/*
* PGA Volume is also used as part of the enable sequence, so
* usage of it should be avoided whilst that is running.
*/
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
snd_soc_dapm_mutex_lock(dapm);
ret = snd_soc_put_volsw_range(kcontrol, ucontrol);
mutex_unlock(&card->dapm_mutex);
snd_soc_dapm_mutex_unlock(dapm);
return ret;
}
......@@ -2177,10 +2173,23 @@ static int wm5110_open(struct snd_compr_stream *stream)
return wm_adsp_compr_open(&priv->core.adsp[n_adsp], stream);
}
static irqreturn_t wm5110_adsp2_irq(int irq, void *data)
{
struct wm5110_priv *florida = data;
int ret;
ret = wm_adsp_compr_handle_irq(&florida->core.adsp[2]);
if (ret == -ENODEV)
return IRQ_NONE;
return IRQ_HANDLED;
}
static int wm5110_codec_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->core.arizona;
int i, ret;
priv->core.arizona->dapm = dapm;
......@@ -2189,6 +2198,14 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
arizona_init_gpio(codec);
arizona_init_mono(codec);
ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
"ADSP2 Compressed IRQ", wm5110_adsp2_irq,
priv);
if (ret != 0) {
dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret);
return ret;
}
for (i = 0; i < WM5110_NUM_ADSP; ++i) {
ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec);
if (ret)
......@@ -2209,12 +2226,15 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
for (--i; i >= 0; --i)
wm_adsp2_codec_remove(&priv->core.adsp[i], codec);
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
return ret;
}
static int wm5110_codec_remove(struct snd_soc_codec *codec)
{
struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->core.arizona;
int i;
for (i = 0; i < WM5110_NUM_ADSP; ++i)
......@@ -2222,6 +2242,8 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec)
priv->core.arizona->dapm = NULL;
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
return 0;
}
......@@ -2273,6 +2295,8 @@ static struct snd_compr_ops wm5110_compr_ops = {
.set_params = wm_adsp_compr_set_params,
.get_caps = wm_adsp_compr_get_caps,
.trigger = wm_adsp_compr_trigger,
.pointer = wm_adsp_compr_pointer,
.copy = wm_adsp_compr_copy,
};
static struct snd_soc_platform_driver wm5110_compr_platform = {
......
......@@ -147,6 +147,13 @@ static const char *wm8960_3d_upper_cutoff[] = {"High", "Low"};
static const char *wm8960_3d_lower_cutoff[] = {"Low", "High"};
static const char *wm8960_alcfunc[] = {"Off", "Right", "Left", "Stereo"};
static const char *wm8960_alcmode[] = {"ALC", "Limiter"};
static const char *wm8960_adc_data_output_sel[] = {
"Left Data = Left ADC; Right Data = Right ADC",
"Left Data = Left ADC; Right Data = Left ADC",
"Left Data = Right ADC; Right Data = Right ADC",
"Left Data = Right ADC; Right Data = Left ADC",
};
static const char *wm8960_dmonomix[] = {"Stereo", "Mono"};
static const struct soc_enum wm8960_enum[] = {
SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity),
......@@ -155,6 +162,8 @@ static const struct soc_enum wm8960_enum[] = {
SOC_ENUM_SINGLE(WM8960_3D, 5, 2, wm8960_3d_lower_cutoff),
SOC_ENUM_SINGLE(WM8960_ALC1, 7, 4, wm8960_alcfunc),
SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode),
SOC_ENUM_SINGLE(WM8960_ADDCTL1, 2, 4, wm8960_adc_data_output_sel),
SOC_ENUM_SINGLE(WM8960_ADDCTL1, 4, 2, wm8960_dmonomix),
};
static const int deemph_settings[] = { 0, 32000, 44100, 48000 };
......@@ -295,6 +304,9 @@ SOC_SINGLE_TLV("Right Output Mixer Boost Bypass Volume",
WM8960_BYPASS2, 4, 7, 1, bypass_tlv),
SOC_SINGLE_TLV("Right Output Mixer RINPUT3 Volume",
WM8960_ROUTMIX, 4, 7, 1, bypass_tlv),
SOC_ENUM("ADC Data Output Select", wm8960_enum[6]),
SOC_ENUM("DAC Mono Mix", wm8960_enum[7]),
};
static const struct snd_kcontrol_new wm8960_lin_boost[] = {
......@@ -401,8 +413,8 @@ static const struct snd_soc_dapm_route audio_paths[] = {
{ "Left Boost Mixer", "LINPUT2 Switch", "LINPUT2" },
{ "Left Boost Mixer", "LINPUT3 Switch", "LINPUT3" },
{ "Left Input Mixer", "Boost Switch", "Left Boost Mixer", },
{ "Left Input Mixer", NULL, "LINPUT1", }, /* Really Boost Switch */
{ "Left Input Mixer", "Boost Switch", "Left Boost Mixer" },
{ "Left Input Mixer", "Boost Switch", "LINPUT1" }, /* Really Boost Switch */
{ "Left Input Mixer", NULL, "LINPUT2" },
{ "Left Input Mixer", NULL, "LINPUT3" },
......@@ -410,8 +422,8 @@ static const struct snd_soc_dapm_route audio_paths[] = {
{ "Right Boost Mixer", "RINPUT2 Switch", "RINPUT2" },
{ "Right Boost Mixer", "RINPUT3 Switch", "RINPUT3" },
{ "Right Input Mixer", "Boost Switch", "Right Boost Mixer", },
{ "Right Input Mixer", NULL, "RINPUT1", }, /* Really Boost Switch */
{ "Right Input Mixer", "Boost Switch", "Right Boost Mixer" },
{ "Right Input Mixer", "Boost Switch", "RINPUT1" }, /* Really Boost Switch */
{ "Right Input Mixer", NULL, "RINPUT2" },
{ "Right Input Mixer", NULL, "RINPUT3" },
......@@ -419,11 +431,11 @@ static const struct snd_soc_dapm_route audio_paths[] = {
{ "Right ADC", NULL, "Right Input Mixer" },
{ "Left Output Mixer", "LINPUT3 Switch", "LINPUT3" },
{ "Left Output Mixer", "Boost Bypass Switch", "Left Boost Mixer"} ,
{ "Left Output Mixer", "Boost Bypass Switch", "Left Boost Mixer" },
{ "Left Output Mixer", "PCM Playback Switch", "Left DAC" },
{ "Right Output Mixer", "RINPUT3 Switch", "RINPUT3" },
{ "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" } ,
{ "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" },
{ "Right Output Mixer", "PCM Playback Switch", "Right DAC" },
{ "LOUT1 PGA", NULL, "Left Output Mixer" },
......
......@@ -279,6 +279,11 @@ struct wm_adsp_compr_buf {
struct wm_adsp_buffer_region *regions;
u32 host_buf_ptr;
u32 error;
u32 irq_count;
int read_index;
int avail;
};
struct wm_adsp_compr {
......@@ -287,6 +292,9 @@ struct wm_adsp_compr {
struct snd_compr_stream *stream;
struct snd_compressed_buffer size;
u32 *raw_buf;
unsigned int copied_total;
};
#define WM_ADSP_DATA_WORD_SIZE 3
......@@ -2378,6 +2386,7 @@ int wm_adsp_compr_free(struct snd_compr_stream *stream)
dsp->compr = NULL;
kfree(compr->raw_buf);
kfree(compr);
mutex_unlock(&dsp->pwr_lock);
......@@ -2436,10 +2445,16 @@ static int wm_adsp_compr_check_params(struct snd_compr_stream *stream,
return -EINVAL;
}
static inline unsigned int wm_adsp_compr_frag_words(struct wm_adsp_compr *compr)
{
return compr->size.fragment_size / WM_ADSP_DATA_WORD_SIZE;
}
int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
struct snd_compr_params *params)
{
struct wm_adsp_compr *compr = stream->runtime->private_data;
unsigned int size;
int ret;
ret = wm_adsp_compr_check_params(stream, params);
......@@ -2451,6 +2466,11 @@ int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
adsp_dbg(compr->dsp, "fragment_size=%d fragments=%d\n",
compr->size.fragment_size, compr->size.fragments);
size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf);
compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL);
if (!compr->raw_buf)
return -ENOMEM;
return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params);
......@@ -2622,6 +2642,8 @@ static int wm_adsp_buffer_init(struct wm_adsp *dsp)
return -ENOMEM;
buf->dsp = dsp;
buf->read_index = -1;
buf->irq_count = 0xFFFFFFFF;
ret = wm_adsp_buffer_locate(buf);
if (ret < 0) {
......@@ -2705,6 +2727,16 @@ int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd)
ret);
break;
}
/* Trigger the IRQ at one fragment of data */
ret = wm_adsp_buffer_write(compr->buf,
HOST_BUFFER_FIELD(high_water_mark),
wm_adsp_compr_frag_words(compr));
if (ret < 0) {
adsp_err(dsp, "Failed to set high water mark: %d\n",
ret);
break;
}
break;
case SNDRV_PCM_TRIGGER_STOP:
break;
......@@ -2719,4 +2751,298 @@ int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd)
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger);
static inline int wm_adsp_buffer_size(struct wm_adsp_compr_buf *buf)
{
int last_region = wm_adsp_fw[buf->dsp->fw].caps->num_regions - 1;
return buf->regions[last_region].cumulative_size;
}
static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf)
{
u32 next_read_index, next_write_index;
int write_index, read_index, avail;
int ret;
/* Only sync read index if we haven't already read a valid index */
if (buf->read_index < 0) {
ret = wm_adsp_buffer_read(buf,
HOST_BUFFER_FIELD(next_read_index),
&next_read_index);
if (ret < 0)
return ret;
read_index = sign_extend32(next_read_index, 23);
if (read_index < 0) {
adsp_dbg(buf->dsp, "Avail check on unstarted stream\n");
return 0;
}
buf->read_index = read_index;
}
ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(next_write_index),
&next_write_index);
if (ret < 0)
return ret;
write_index = sign_extend32(next_write_index, 23);
avail = write_index - buf->read_index;
if (avail < 0)
avail += wm_adsp_buffer_size(buf);
adsp_dbg(buf->dsp, "readindex=0x%x, writeindex=0x%x, avail=%d\n",
buf->read_index, write_index, avail);
buf->avail = avail;
return 0;
}
int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
{
struct wm_adsp_compr_buf *buf = dsp->buffer;
struct wm_adsp_compr *compr = dsp->compr;
int ret = 0;
mutex_lock(&dsp->pwr_lock);
if (!buf) {
adsp_err(dsp, "Spurious buffer IRQ\n");
ret = -ENODEV;
goto out;
}
adsp_dbg(dsp, "Handling buffer IRQ\n");
ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error);
if (ret < 0) {
adsp_err(dsp, "Failed to check buffer error: %d\n", ret);
goto out;
}
if (buf->error != 0) {
adsp_err(dsp, "Buffer error occurred: %d\n", buf->error);
ret = -EIO;
goto out;
}
ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count),
&buf->irq_count);
if (ret < 0) {
adsp_err(dsp, "Failed to get irq_count: %d\n", ret);
goto out;
}
ret = wm_adsp_buffer_update_avail(buf);
if (ret < 0) {
adsp_err(dsp, "Error reading avail: %d\n", ret);
goto out;
}
if (compr->stream)
snd_compr_fragment_elapsed(compr->stream);
out:
mutex_unlock(&dsp->pwr_lock);
return ret;
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_handle_irq);
static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf)
{
if (buf->irq_count & 0x01)
return 0;
adsp_dbg(buf->dsp, "Enable IRQ(0x%x) for next fragment\n",
buf->irq_count);
buf->irq_count |= 0x01;
return wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(irq_ack),
buf->irq_count);
}
int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
struct snd_compr_tstamp *tstamp)
{
struct wm_adsp_compr *compr = stream->runtime->private_data;
struct wm_adsp_compr_buf *buf = compr->buf;
struct wm_adsp *dsp = compr->dsp;
int ret = 0;
adsp_dbg(dsp, "Pointer request\n");
mutex_lock(&dsp->pwr_lock);
if (!compr->buf) {
ret = -ENXIO;
goto out;
}
if (compr->buf->error) {
ret = -EIO;
goto out;
}
if (buf->avail < wm_adsp_compr_frag_words(compr)) {
ret = wm_adsp_buffer_update_avail(buf);
if (ret < 0) {
adsp_err(dsp, "Error reading avail: %d\n", ret);
goto out;
}
/*
* If we really have less than 1 fragment available tell the
* DSP to inform us once a whole fragment is available.
*/
if (buf->avail < wm_adsp_compr_frag_words(compr)) {
ret = wm_adsp_buffer_reenable_irq(buf);
if (ret < 0) {
adsp_err(dsp,
"Failed to re-enable buffer IRQ: %d\n",
ret);
goto out;
}
}
}
tstamp->copied_total = compr->copied_total;
tstamp->copied_total += buf->avail * WM_ADSP_DATA_WORD_SIZE;
out:
mutex_unlock(&dsp->pwr_lock);
return ret;
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer);
static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
{
struct wm_adsp_compr_buf *buf = compr->buf;
u8 *pack_in = (u8 *)compr->raw_buf;
u8 *pack_out = (u8 *)compr->raw_buf;
unsigned int adsp_addr;
int mem_type, nwords, max_read;
int i, j, ret;
/* Calculate read parameters */
for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i)
if (buf->read_index < buf->regions[i].cumulative_size)
break;
if (i == wm_adsp_fw[buf->dsp->fw].caps->num_regions)
return -EINVAL;
mem_type = buf->regions[i].mem_type;
adsp_addr = buf->regions[i].base_addr +
(buf->read_index - buf->regions[i].offset);
max_read = wm_adsp_compr_frag_words(compr);
nwords = buf->regions[i].cumulative_size - buf->read_index;
if (nwords > target)
nwords = target;
if (nwords > buf->avail)
nwords = buf->avail;
if (nwords > max_read)
nwords = max_read;
if (!nwords)
return 0;
/* Read data from DSP */
ret = wm_adsp_read_data_block(buf->dsp, mem_type, adsp_addr,
nwords, compr->raw_buf);
if (ret < 0)
return ret;
/* Remove the padding bytes from the data read from the DSP */
for (i = 0; i < nwords; i++) {
for (j = 0; j < WM_ADSP_DATA_WORD_SIZE; j++)
*pack_out++ = *pack_in++;
pack_in += sizeof(*(compr->raw_buf)) - WM_ADSP_DATA_WORD_SIZE;
}
/* update read index to account for words read */
buf->read_index += nwords;
if (buf->read_index == wm_adsp_buffer_size(buf))
buf->read_index = 0;
ret = wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(next_read_index),
buf->read_index);
if (ret < 0)
return ret;
/* update avail to account for words read */
buf->avail -= nwords;
return nwords;
}
static int wm_adsp_compr_read(struct wm_adsp_compr *compr,
char __user *buf, size_t count)
{
struct wm_adsp *dsp = compr->dsp;
int ntotal = 0;
int nwords, nbytes;
adsp_dbg(dsp, "Requested read of %zu bytes\n", count);
if (!compr->buf)
return -ENXIO;
if (compr->buf->error)
return -EIO;
count /= WM_ADSP_DATA_WORD_SIZE;
do {
nwords = wm_adsp_buffer_capture_block(compr, count);
if (nwords < 0) {
adsp_err(dsp, "Failed to capture block: %d\n", nwords);
return nwords;
}
nbytes = nwords * WM_ADSP_DATA_WORD_SIZE;
adsp_dbg(dsp, "Read %d bytes\n", nbytes);
if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) {
adsp_err(dsp, "Failed to copy data to user: %d, %d\n",
ntotal, nbytes);
return -EFAULT;
}
count -= nwords;
ntotal += nbytes;
} while (nwords > 0 && count > 0);
compr->copied_total += ntotal;
return ntotal;
}
int wm_adsp_compr_copy(struct snd_compr_stream *stream, char __user *buf,
size_t count)
{
struct wm_adsp_compr *compr = stream->runtime->private_data;
struct wm_adsp *dsp = compr->dsp;
int ret;
mutex_lock(&dsp->pwr_lock);
if (stream->direction == SND_COMPRESS_CAPTURE)
ret = wm_adsp_compr_read(compr, buf, count);
else
ret = -ENOTSUPP;
mutex_unlock(&dsp->pwr_lock);
return ret;
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_copy);
MODULE_LICENSE("GPL v2");
......@@ -112,5 +112,10 @@ extern int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
extern int wm_adsp_compr_get_caps(struct snd_compr_stream *stream,
struct snd_compr_caps *caps);
extern int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd);
extern int wm_adsp_compr_handle_irq(struct wm_adsp *dsp);
extern int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
struct snd_compr_tstamp *tstamp);
extern int wm_adsp_compr_copy(struct snd_compr_stream *stream,
char __user *buf, size_t count);
#endif
......@@ -500,6 +500,10 @@ static int dw_configure_dai(struct dw_i2s_dev *dev,
u32 comp2 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp2);
u32 idx;
if (dev->capability & DWC_I2S_RECORD &&
dev->quirks & DW_I2S_QUIRK_COMP_PARAM1)
comp1 = comp1 & ~BIT(5);
if (COMP1_TX_ENABLED(comp1)) {
dev_dbg(dev->dev, " designware: play supported\n");
idx = COMP1_TX_WORDSIZE_0(comp1);
......
......@@ -996,6 +996,9 @@ static int fsl_asrc_suspend(struct device *dev)
{
struct fsl_asrc *asrc_priv = dev_get_drvdata(dev);
regmap_read(asrc_priv->regmap, REG_ASRCFG,
&asrc_priv->regcache_cfg);
regcache_cache_only(asrc_priv->regmap, true);
regcache_mark_dirty(asrc_priv->regmap);
......@@ -1016,6 +1019,10 @@ static int fsl_asrc_resume(struct device *dev)
regcache_cache_only(asrc_priv->regmap, false);
regcache_sync(asrc_priv->regmap);
regmap_update_bits(asrc_priv->regmap, REG_ASRCFG,
ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK |
ASRCFG_PREMODi_ALL_MASK, asrc_priv->regcache_cfg);
/* Restart enabled pairs */
regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
ASRCTR_ASRCEi_ALL_MASK, asrctr);
......
......@@ -132,10 +132,13 @@
#define ASRCFG_INIRQi (1 << ASRCFG_INIRQi_SHIFT(i))
#define ASRCFG_NDPRi_SHIFT(i) (18 + i)
#define ASRCFG_NDPRi_MASK(i) (1 << ASRCFG_NDPRi_SHIFT(i))
#define ASRCFG_NDPRi_ALL_SHIFT 18
#define ASRCFG_NDPRi_ALL_MASK (7 << ASRCFG_NDPRi_ALL_SHIFT)
#define ASRCFG_NDPRi (1 << ASRCFG_NDPRi_SHIFT(i))
#define ASRCFG_POSTMODi_SHIFT(i) (8 + (i << 2))
#define ASRCFG_POSTMODi_WIDTH 2
#define ASRCFG_POSTMODi_MASK(i) (((1 << ASRCFG_POSTMODi_WIDTH) - 1) << ASRCFG_POSTMODi_SHIFT(i))
#define ASRCFG_POSTMODi_ALL_MASK (ASRCFG_POSTMODi_MASK(0) | ASRCFG_POSTMODi_MASK(1) | ASRCFG_POSTMODi_MASK(2))
#define ASRCFG_POSTMOD(i, v) ((v) << ASRCFG_POSTMODi_SHIFT(i))
#define ASRCFG_POSTMODi_UP(i) (0 << ASRCFG_POSTMODi_SHIFT(i))
#define ASRCFG_POSTMODi_DCON(i) (1 << ASRCFG_POSTMODi_SHIFT(i))
......@@ -143,6 +146,7 @@
#define ASRCFG_PREMODi_SHIFT(i) (6 + (i << 2))
#define ASRCFG_PREMODi_WIDTH 2
#define ASRCFG_PREMODi_MASK(i) (((1 << ASRCFG_PREMODi_WIDTH) - 1) << ASRCFG_PREMODi_SHIFT(i))
#define ASRCFG_PREMODi_ALL_MASK (ASRCFG_PREMODi_MASK(0) | ASRCFG_PREMODi_MASK(1) | ASRCFG_PREMODi_MASK(2))
#define ASRCFG_PREMOD(i, v) ((v) << ASRCFG_PREMODi_SHIFT(i))
#define ASRCFG_PREMODi_UP(i) (0 << ASRCFG_PREMODi_SHIFT(i))
#define ASRCFG_PREMODi_DCON(i) (1 << ASRCFG_PREMODi_SHIFT(i))
......@@ -434,6 +438,7 @@ struct fsl_asrc_pair {
* @channel_avail: non-occupied channel numbers
* @asrc_rate: default sample rate for ASoC Back-Ends
* @asrc_width: default sample width for ASoC Back-Ends
* @regcache_cfg: store register value of REG_ASRCFG
*/
struct fsl_asrc {
struct snd_dmaengine_dai_dma_data dma_params_rx;
......@@ -453,6 +458,8 @@ struct fsl_asrc {
int asrc_rate;
int asrc_width;
u32 regcache_cfg;
};
extern struct snd_soc_platform_driver fsl_asrc_platform;
......
This diff is collapsed.
......@@ -189,8 +189,7 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
{
struct device *dev = pdev->dev.parent;
/* ssi_pdev is the platform device for the SSI node that probed us */
struct platform_device *ssi_pdev =
container_of(dev, struct platform_device, dev);
struct platform_device *ssi_pdev = to_platform_device(dev);
struct device_node *np = ssi_pdev->dev.of_node;
struct device_node *codec_np = NULL;
struct mpc8610_hpcd_data *machine_data;
......
......@@ -199,8 +199,7 @@ static int p1022_ds_probe(struct platform_device *pdev)
{
struct device *dev = pdev->dev.parent;
/* ssi_pdev is the platform device for the SSI node that probed us */
struct platform_device *ssi_pdev =
container_of(dev, struct platform_device, dev);
struct platform_device *ssi_pdev = to_platform_device(dev);
struct device_node *np = ssi_pdev->dev.of_node;
struct device_node *codec_np = NULL;
struct machine_data *mdata;
......
......@@ -203,8 +203,7 @@ static int p1022_rdk_probe(struct platform_device *pdev)
{
struct device *dev = pdev->dev.parent;
/* ssi_pdev is the platform device for the SSI node that probed us */
struct platform_device *ssi_pdev =
container_of(dev, struct platform_device, dev);
struct platform_device *ssi_pdev = to_platform_device(dev);
struct device_node *np = ssi_pdev->dev.of_node;
struct device_node *codec_np = NULL;
struct machine_data *mdata;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment