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

ASoC: Updates for v4.18

This is a very big update, mainly due to a huge set of new drivers some
of which are individually very large.  We also have a lot of fixes for
the topology stuff, several of the users have stepped up and fixed some
the serious issues there, and continued progress on the transition away
from CODEC specific drivers to generic component drivers.

 - Many fixes for the topology code, including fixes for the half done
   v4 ABI compatibility from Guenter Roeck and other ABI fixes from
   Kirill Marinushkin.
 - Lots of cleanup for Intel platforms based on Realtek CODECs from Hans
   de Goode.
 - More followups on removing legacy CODEC things and transitioning to
   components from Morimoto-san.
 - Conversion of OMAP DMA to the new, more standard SDMA-PCM driver.
 - A series of fixes and updates to the rather elderly Cirrus Logic SoC
   drivers from Alexander Sverdlin.
 - Qualcomm DSP support from Srinivas Kandagatla.
 - New drivers for Analog SSM2305, Atmel I2S controllers, Mediatek
   MT6351, MT6797 and MT7622, Qualcomm DSPs, Realtek RT1305, RT1306 and
   RT5668 and TI TSCS454
This commit is contained in:
Takashi Iwai
2018-06-05 16:51:55 +02:00
256 changed files with 29811 additions and 4011 deletions

View File

@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-utils.o
snd-soc-core-objs += soc-pcm.o soc-io.o soc-devres.o soc-ops.o
snd-soc-core-$(CONFIG_SND_SOC_COMPRESS) += soc-compress.o

View File

@@ -33,17 +33,19 @@
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/acpi.h>
#include "acp.h"
#include "../codecs/da7219.h"
#include "../codecs/da7219-aad.h"
#define CZ_PLAT_CLK 24000000
#define MCLK_RATE 24576000
#define CZ_PLAT_CLK 25000000
#define DUAL_CHANNEL 2
static struct snd_soc_jack cz_jack;
static struct clk *da7219_dai_clk;
extern int bt_uart_enable;
static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
{
@@ -62,7 +64,7 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
}
ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL,
CZ_PLAT_CLK, MCLK_RATE);
CZ_PLAT_CLK, DA7219_PLL_FREQ_OUT_98304);
if (ret < 0) {
dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
return ret;
@@ -80,13 +82,17 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
da7219_aad_jack_det(component, &cz_jack);
return 0;
}
static int cz_da7219_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
static int da7219_clk_enable(struct snd_pcm_substream *substream)
{
int ret = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -100,11 +106,9 @@ static int cz_da7219_hw_params(struct snd_pcm_substream *substream,
return ret;
}
static int cz_da7219_hw_free(struct snd_pcm_substream *substream)
static void da7219_clk_disable(void)
{
clk_disable_unprepare(da7219_dai_clk);
return 0;
}
static const unsigned int channels[] = {
@@ -127,9 +131,12 @@ static const struct snd_pcm_hw_constraint_list constraints_channels = {
.mask = 0,
};
static int cz_fe_startup(struct snd_pcm_substream *substream)
static int cz_da7219_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
/*
* On this platform for PCM device we support stereo
@@ -141,23 +148,58 @@ static int cz_fe_startup(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
return 0;
machine->i2s_instance = I2S_BT_INSTANCE;
return da7219_clk_enable(substream);
}
static struct snd_soc_ops cz_da7219_cap_ops = {
.hw_params = cz_da7219_hw_params,
.hw_free = cz_da7219_hw_free,
.startup = cz_fe_startup,
static void cz_da7219_shutdown(struct snd_pcm_substream *substream)
{
da7219_clk_disable();
}
static int cz_max_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
machine->i2s_instance = I2S_SP_INSTANCE;
return da7219_clk_enable(substream);
}
static void cz_max_shutdown(struct snd_pcm_substream *substream)
{
da7219_clk_disable();
}
static int cz_dmic_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
machine->i2s_instance = I2S_SP_INSTANCE;
return da7219_clk_enable(substream);
}
static void cz_dmic_shutdown(struct snd_pcm_substream *substream)
{
da7219_clk_disable();
}
static const struct snd_soc_ops cz_da7219_cap_ops = {
.startup = cz_da7219_startup,
.shutdown = cz_da7219_shutdown,
};
static struct snd_soc_ops cz_max_play_ops = {
.hw_params = cz_da7219_hw_params,
.hw_free = cz_da7219_hw_free,
static const struct snd_soc_ops cz_max_play_ops = {
.startup = cz_max_startup,
.shutdown = cz_max_shutdown,
};
static struct snd_soc_ops cz_dmic_cap_ops = {
.hw_params = cz_da7219_hw_params,
.hw_free = cz_da7219_hw_free,
static const struct snd_soc_ops cz_dmic_cap_ops = {
.startup = cz_dmic_startup,
.shutdown = cz_dmic_shutdown,
};
static struct snd_soc_dai_link cz_dai_7219_98357[] = {
@@ -240,10 +282,16 @@ static int cz_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card;
struct acp_platform_info *machine;
machine = devm_kzalloc(&pdev->dev, sizeof(struct acp_platform_info),
GFP_KERNEL);
if (!machine)
return -ENOMEM;
card = &cz_card;
cz_card.dev = &pdev->dev;
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
ret = devm_snd_soc_register_card(&pdev->dev, &cz_card);
if (ret) {
dev_err(&pdev->dev,
@@ -251,6 +299,8 @@ static int cz_probe(struct platform_device *pdev)
cz_card.name, ret);
return ret;
}
bt_uart_enable = !device_property_read_bool(&pdev->dev,
"bt-pad-enable");
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -10,17 +10,30 @@
#define ACP_PLAYBACK_PTE_OFFSET 10
#define ACP_CAPTURE_PTE_OFFSET 0
/* Playback and Capture Offset for Stoney */
#define ACP_ST_PLAYBACK_PTE_OFFSET 0x04
#define ACP_ST_CAPTURE_PTE_OFFSET 0x00
#define ACP_ST_BT_PLAYBACK_PTE_OFFSET 0x08
#define ACP_ST_BT_CAPTURE_PTE_OFFSET 0x0c
#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_SHARED_RAM_BANK_3_ADDRESS 0x4006000
/*
* In case of I2S SP controller instance, Stoney uses SRAM bank 1 for
* playback and SRAM Bank 2 for capture where as in case of BT I2S
* Instance, Stoney uses SRAM Bank 3 for playback & SRAM Bank 4 will
* be used for capture. Carrizo uses I2S SP controller instance. SRAM Banks
* 1, 2, 3, 4 will be used for playback & SRAM Banks 5, 6, 7, 8 will be used
* for capture scenario.
*/
#define ACP_SRAM_BANK_1_ADDRESS 0x4002000
#define ACP_SRAM_BANK_2_ADDRESS 0x4004000
#define ACP_SRAM_BANK_3_ADDRESS 0x4006000
#define ACP_SRAM_BANK_4_ADDRESS 0x4008000
#define ACP_SRAM_BANK_5_ADDRESS 0x400A000
#define ACP_DMA_RESET_TIME 10000
#define ACP_CLOCK_EN_TIME_OUT_VALUE 0x000000FF
@@ -35,8 +48,13 @@
#define TO_ACP_I2S_1 0x2
#define TO_ACP_I2S_2 0x4
#define TO_BLUETOOTH 0x3
#define FROM_ACP_I2S_1 0xa
#define FROM_ACP_I2S_2 0xb
#define FROM_BLUETOOTH 0xb
#define I2S_SP_INSTANCE 0x01
#define I2S_BT_INSTANCE 0x02
#define ACP_TILE_ON_MASK 0x03
#define ACP_TILE_OFF_MASK 0x02
@@ -57,6 +75,14 @@
#define ACP_TO_SYSRAM_CH_NUM 14
#define I2S_TO_ACP_DMA_CH_NUM 15
/* Playback DMA Channels for I2S BT instance */
#define SYSRAM_TO_ACP_BT_INSTANCE_CH_NUM 8
#define ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM 9
/* Capture DMA Channels for I2S BT Instance */
#define ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM 10
#define I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM 11
#define NUM_DSCRS_PER_CHANNEL 2
#define PLAYBACK_START_DMA_DESCR_CH12 0
@@ -69,9 +95,23 @@
#define CAPTURE_START_DMA_DESCR_CH15 6
#define CAPTURE_END_DMA_DESCR_CH15 7
/* I2S BT Instance DMA Descriptors */
#define PLAYBACK_START_DMA_DESCR_CH8 8
#define PLAYBACK_END_DMA_DESCR_CH8 9
#define PLAYBACK_START_DMA_DESCR_CH9 10
#define PLAYBACK_END_DMA_DESCR_CH9 11
#define CAPTURE_START_DMA_DESCR_CH10 12
#define CAPTURE_END_DMA_DESCR_CH10 13
#define CAPTURE_START_DMA_DESCR_CH11 14
#define CAPTURE_END_DMA_DESCR_CH11 15
#define mmACP_I2S_16BIT_RESOLUTION_EN 0x5209
#define ACP_I2S_MIC_16BIT_RESOLUTION_EN 0x01
#define ACP_I2S_SP_16BIT_RESOLUTION_EN 0x02
#define ACP_I2S_BT_16BIT_RESOLUTION_EN 0x04
#define ACP_BT_UART_PAD_SELECT_MASK 0x1
enum acp_dma_priority_level {
/* 0x0 Specifies the DMA channel is given normal priority */
ACP_DMA_PRIORITY_LEVEL_NORMAL = 0x0,
@@ -84,20 +124,39 @@ struct audio_substream_data {
struct page *pg;
unsigned int order;
u16 num_of_pages;
u16 i2s_instance;
u16 direction;
u16 ch1;
u16 ch2;
u16 destination;
u16 dma_dscr_idx_1;
u16 dma_dscr_idx_2;
u32 pte_offset;
u32 sram_bank;
u32 byte_cnt_high_reg_offset;
u32 byte_cnt_low_reg_offset;
uint64_t size;
u64 i2ssp_renderbytescount;
u64 i2ssp_capturebytescount;
u64 bytescount;
void __iomem *acp_mmio;
};
struct audio_drv_data {
struct snd_pcm_substream *play_i2ssp_stream;
struct snd_pcm_substream *capture_i2ssp_stream;
struct snd_pcm_substream *play_i2sbt_stream;
struct snd_pcm_substream *capture_i2sbt_stream;
void __iomem *acp_mmio;
u32 asic_type;
};
/*
* this structure used for platform data transfer between machine driver
* and dma driver
*/
struct acp_platform_info {
u16 i2s_instance;
};
union acp_dma_count {
struct {
u32 low;
@@ -115,23 +174,25 @@ enum {
};
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
ACP_DMA_ATTR_SHAREDMEM_TO_DAGB_ONION = 0x0,
ACP_DMA_ATTR_SHARED_MEM_TO_DAGB_GARLIC = 0x1,
ACP_DMA_ATTR_DAGB_ONION_TO_SHAREDMEM = 0x8,
ACP_DMA_ATTR_DAGB_GARLIC_TO_SHAREDMEM = 0x9,
ACP_DMA_ATTR_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
/*
* 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
*/
/*
* 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;

View File

@@ -88,4 +88,13 @@ config SND_ATMEL_SOC_TSE850_PCM5142
help
Say Y if you want to add support for the ASoC driver for the
Axentia TSE-850 with a PCM5142 codec.
config SND_ATMEL_SOC_I2S
tristate "Atmel ASoC driver for boards using I2S"
depends on OF && (ARCH_AT91 || COMPILE_TEST)
select SND_SOC_GENERIC_DMAENGINE_PCM
select REGMAP_MMIO
help
Say Y or M if you want to add support for Atmel ASoc driver for boards
using I2S.
endif

View File

@@ -3,10 +3,12 @@
snd-soc-atmel-pcm-pdc-objs := atmel-pcm-pdc.o
snd-soc-atmel-pcm-dma-objs := atmel-pcm-dma.o
snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o
snd-soc-atmel-i2s-objs := atmel-i2s.o
obj-$(CONFIG_SND_ATMEL_SOC_PDC) += snd-soc-atmel-pcm-pdc.o
obj-$(CONFIG_SND_ATMEL_SOC_DMA) += snd-soc-atmel-pcm-dma.o
obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
obj-$(CONFIG_SND_ATMEL_SOC_I2S) += snd-soc-atmel-i2s.o
# AT91 Machine Support
snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o

765
sound/soc/atmel/atmel-i2s.c Normal file
View File

@@ -0,0 +1,765 @@
/*
* Driver for Atmel I2S controller
*
* Copyright (C) 2015 Atmel Corporation
*
* Author: Cyrille Pitchen <cyrille.pitchen@atmel.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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 <linux/mfd/syscon.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>
#define ATMEL_I2SC_MAX_TDM_CHANNELS 8
/*
* ---- I2S Controller Register map ----
*/
#define ATMEL_I2SC_CR 0x0000 /* Control Register */
#define ATMEL_I2SC_MR 0x0004 /* Mode Register */
#define ATMEL_I2SC_SR 0x0008 /* Status Register */
#define ATMEL_I2SC_SCR 0x000c /* Status Clear Register */
#define ATMEL_I2SC_SSR 0x0010 /* Status Set Register */
#define ATMEL_I2SC_IER 0x0014 /* Interrupt Enable Register */
#define ATMEL_I2SC_IDR 0x0018 /* Interrupt Disable Register */
#define ATMEL_I2SC_IMR 0x001c /* Interrupt Mask Register */
#define ATMEL_I2SC_RHR 0x0020 /* Receiver Holding Register */
#define ATMEL_I2SC_THR 0x0024 /* Transmitter Holding Register */
#define ATMEL_I2SC_VERSION 0x0028 /* Version Register */
/*
* ---- Control Register (Write-only) ----
*/
#define ATMEL_I2SC_CR_RXEN BIT(0) /* Receiver Enable */
#define ATMEL_I2SC_CR_RXDIS BIT(1) /* Receiver Disable */
#define ATMEL_I2SC_CR_CKEN BIT(2) /* Clock Enable */
#define ATMEL_I2SC_CR_CKDIS BIT(3) /* Clock Disable */
#define ATMEL_I2SC_CR_TXEN BIT(4) /* Transmitter Enable */
#define ATMEL_I2SC_CR_TXDIS BIT(5) /* Transmitter Disable */
#define ATMEL_I2SC_CR_SWRST BIT(7) /* Software Reset */
/*
* ---- Mode Register (Read/Write) ----
*/
#define ATMEL_I2SC_MR_MODE_MASK GENMASK(0, 0)
#define ATMEL_I2SC_MR_MODE_SLAVE (0 << 0)
#define ATMEL_I2SC_MR_MODE_MASTER (1 << 0)
#define ATMEL_I2SC_MR_DATALENGTH_MASK GENMASK(4, 2)
#define ATMEL_I2SC_MR_DATALENGTH_32_BITS (0 << 2)
#define ATMEL_I2SC_MR_DATALENGTH_24_BITS (1 << 2)
#define ATMEL_I2SC_MR_DATALENGTH_20_BITS (2 << 2)
#define ATMEL_I2SC_MR_DATALENGTH_18_BITS (3 << 2)
#define ATMEL_I2SC_MR_DATALENGTH_16_BITS (4 << 2)
#define ATMEL_I2SC_MR_DATALENGTH_16_BITS_COMPACT (5 << 2)
#define ATMEL_I2SC_MR_DATALENGTH_8_BITS (6 << 2)
#define ATMEL_I2SC_MR_DATALENGTH_8_BITS_COMPACT (7 << 2)
#define ATMEL_I2SC_MR_FORMAT_MASK GENMASK(7, 6)
#define ATMEL_I2SC_MR_FORMAT_I2S (0 << 6)
#define ATMEL_I2SC_MR_FORMAT_LJ (1 << 6) /* Left Justified */
#define ATMEL_I2SC_MR_FORMAT_TDM (2 << 6)
#define ATMEL_I2SC_MR_FORMAT_TDMLJ (3 << 6)
/* Left audio samples duplicated to right audio channel */
#define ATMEL_I2SC_MR_RXMONO BIT(8)
/* Receiver uses one DMA channel ... */
#define ATMEL_I2SC_MR_RXDMA_MASK GENMASK(9, 9)
#define ATMEL_I2SC_MR_RXDMA_SINGLE (0 << 9) /* for all audio channels */
#define ATMEL_I2SC_MR_RXDMA_MULTIPLE (1 << 9) /* per audio channel */
/* I2SDO output of I2SC is internally connected to I2SDI input */
#define ATMEL_I2SC_MR_RXLOOP BIT(10)
/* Left audio samples duplicated to right audio channel */
#define ATMEL_I2SC_MR_TXMONO BIT(12)
/* Transmitter uses one DMA channel ... */
#define ATMEL_I2SC_MR_TXDMA_MASK GENMASK(13, 13)
#define ATMEL_I2SC_MR_TXDMA_SINGLE (0 << 13) /* for all audio channels */
#define ATMEL_I2SC_MR_TXDME_MULTIPLE (1 << 13) /* per audio channel */
/* x sample transmitted when underrun */
#define ATMEL_I2SC_MR_TXSAME_MASK GENMASK(14, 14)
#define ATMEL_I2SC_MR_TXSAME_ZERO (0 << 14) /* Zero sample */
#define ATMEL_I2SC_MR_TXSAME_PREVIOUS (1 << 14) /* Previous sample */
/* Audio Clock to I2SC Master Clock ratio */
#define ATMEL_I2SC_MR_IMCKDIV_MASK GENMASK(21, 16)
#define ATMEL_I2SC_MR_IMCKDIV(div) \
(((div) << 16) & ATMEL_I2SC_MR_IMCKDIV_MASK)
/* Master Clock to fs ratio */
#define ATMEL_I2SC_MR_IMCKFS_MASK GENMASK(29, 24)
#define ATMEL_I2SC_MR_IMCKFS(fs) \
(((fs) << 24) & ATMEL_I2SC_MR_IMCKFS_MASK)
/* Master Clock mode */
#define ATMEL_I2SC_MR_IMCKMODE_MASK GENMASK(30, 30)
/* 0: No master clock generated (selected clock drives I2SCK pin) */
#define ATMEL_I2SC_MR_IMCKMODE_I2SCK (0 << 30)
/* 1: master clock generated (internally generated clock drives I2SMCK pin) */
#define ATMEL_I2SC_MR_IMCKMODE_I2SMCK (1 << 30)
/* Slot Width */
/* 0: slot is 32 bits wide for DATALENGTH = 18/20/24 bits. */
/* 1: slot is 24 bits wide for DATALENGTH = 18/20/24 bits. */
#define ATMEL_I2SC_MR_IWS BIT(31)
/*
* ---- Status Registers ----
*/
#define ATMEL_I2SC_SR_RXEN BIT(0) /* Receiver Enabled */
#define ATMEL_I2SC_SR_RXRDY BIT(1) /* Receive Ready */
#define ATMEL_I2SC_SR_RXOR BIT(2) /* Receive Overrun */
#define ATMEL_I2SC_SR_TXEN BIT(4) /* Transmitter Enabled */
#define ATMEL_I2SC_SR_TXRDY BIT(5) /* Transmit Ready */
#define ATMEL_I2SC_SR_TXUR BIT(6) /* Transmit Underrun */
/* Receive Overrun Channel */
#define ATMEL_I2SC_SR_RXORCH_MASK GENMASK(15, 8)
#define ATMEL_I2SC_SR_RXORCH(ch) (1 << (((ch) & 0x7) + 8))
/* Transmit Underrun Channel */
#define ATMEL_I2SC_SR_TXURCH_MASK GENMASK(27, 20)
#define ATMEL_I2SC_SR_TXURCH(ch) (1 << (((ch) & 0x7) + 20))
/*
* ---- Interrupt Enable/Disable/Mask Registers ----
*/
#define ATMEL_I2SC_INT_RXRDY ATMEL_I2SC_SR_RXRDY
#define ATMEL_I2SC_INT_RXOR ATMEL_I2SC_SR_RXOR
#define ATMEL_I2SC_INT_TXRDY ATMEL_I2SC_SR_TXRDY
#define ATMEL_I2SC_INT_TXUR ATMEL_I2SC_SR_TXUR
static const struct regmap_config atmel_i2s_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = ATMEL_I2SC_VERSION,
};
struct atmel_i2s_gck_param {
int fs;
unsigned long mck;
int imckdiv;
int imckfs;
};
#define I2S_MCK_12M288 12288000UL
#define I2S_MCK_11M2896 11289600UL
/* mck = (32 * (imckfs+1) / (imckdiv+1)) * fs */
static const struct atmel_i2s_gck_param gck_params[] = {
/* mck = 12.288MHz */
{ 8000, I2S_MCK_12M288, 0, 47}, /* mck = 1536 fs */
{ 16000, I2S_MCK_12M288, 1, 47}, /* mck = 768 fs */
{ 24000, I2S_MCK_12M288, 3, 63}, /* mck = 512 fs */
{ 32000, I2S_MCK_12M288, 3, 47}, /* mck = 384 fs */
{ 48000, I2S_MCK_12M288, 7, 63}, /* mck = 256 fs */
{ 64000, I2S_MCK_12M288, 7, 47}, /* mck = 192 fs */
{ 96000, I2S_MCK_12M288, 7, 31}, /* mck = 128 fs */
{192000, I2S_MCK_12M288, 7, 15}, /* mck = 64 fs */
/* mck = 11.2896MHz */
{ 11025, I2S_MCK_11M2896, 1, 63}, /* mck = 1024 fs */
{ 22050, I2S_MCK_11M2896, 3, 63}, /* mck = 512 fs */
{ 44100, I2S_MCK_11M2896, 7, 63}, /* mck = 256 fs */
{ 88200, I2S_MCK_11M2896, 7, 31}, /* mck = 128 fs */
{176400, I2S_MCK_11M2896, 7, 15}, /* mck = 64 fs */
};
struct atmel_i2s_dev;
struct atmel_i2s_caps {
int (*mck_init)(struct atmel_i2s_dev *, struct device_node *np);
};
struct atmel_i2s_dev {
struct device *dev;
struct regmap *regmap;
struct clk *pclk;
struct clk *gclk;
struct clk *aclk;
struct snd_dmaengine_dai_dma_data playback;
struct snd_dmaengine_dai_dma_data capture;
unsigned int fmt;
const struct atmel_i2s_gck_param *gck_param;
const struct atmel_i2s_caps *caps;
};
static irqreturn_t atmel_i2s_interrupt(int irq, void *dev_id)
{
struct atmel_i2s_dev *dev = dev_id;
unsigned int sr, imr, pending, ch, mask;
irqreturn_t ret = IRQ_NONE;
regmap_read(dev->regmap, ATMEL_I2SC_SR, &sr);
regmap_read(dev->regmap, ATMEL_I2SC_IMR, &imr);
pending = sr & imr;
if (!pending)
return IRQ_NONE;
if (pending & ATMEL_I2SC_INT_RXOR) {
mask = ATMEL_I2SC_SR_RXOR;
for (ch = 0; ch < ATMEL_I2SC_MAX_TDM_CHANNELS; ++ch) {
if (sr & ATMEL_I2SC_SR_RXORCH(ch)) {
mask |= ATMEL_I2SC_SR_RXORCH(ch);
dev_err(dev->dev,
"RX overrun on channel %d\n", ch);
}
}
regmap_write(dev->regmap, ATMEL_I2SC_SCR, mask);
ret = IRQ_HANDLED;
}
if (pending & ATMEL_I2SC_INT_TXUR) {
mask = ATMEL_I2SC_SR_TXUR;
for (ch = 0; ch < ATMEL_I2SC_MAX_TDM_CHANNELS; ++ch) {
if (sr & ATMEL_I2SC_SR_TXURCH(ch)) {
mask |= ATMEL_I2SC_SR_TXURCH(ch);
dev_err(dev->dev,
"TX underrun on channel %d\n", ch);
}
}
regmap_write(dev->regmap, ATMEL_I2SC_SCR, mask);
ret = IRQ_HANDLED;
}
return ret;
}
#define ATMEL_I2S_RATES SNDRV_PCM_RATE_8000_192000
#define ATMEL_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S18_3LE | \
SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
static int atmel_i2s_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
dev->fmt = fmt;
return 0;
}
static int atmel_i2s_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
unsigned int rhr, sr = 0;
if (is_playback) {
regmap_read(dev->regmap, ATMEL_I2SC_SR, &sr);
if (sr & ATMEL_I2SC_SR_RXRDY) {
/*
* The RX Ready flag should not be set. However if here,
* we flush (read) the Receive Holding Register to start
* from a clean state.
*/
dev_dbg(dev->dev, "RXRDY is set\n");
regmap_read(dev->regmap, ATMEL_I2SC_RHR, &rhr);
}
}
return 0;
}
static int atmel_i2s_get_gck_param(struct atmel_i2s_dev *dev, int fs)
{
int i, best;
if (!dev->gclk || !dev->aclk) {
dev_err(dev->dev, "cannot generate the I2S Master Clock\n");
return -EINVAL;
}
/*
* Find the best possible settings to generate the I2S Master Clock
* from the PLL Audio.
*/
dev->gck_param = NULL;
best = INT_MAX;
for (i = 0; i < ARRAY_SIZE(gck_params); ++i) {
const struct atmel_i2s_gck_param *gck_param = &gck_params[i];
int val = abs(fs - gck_param->fs);
if (val < best) {
best = val;
dev->gck_param = gck_param;
}
}
return 0;
}
static int atmel_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
unsigned int mr = 0;
int ret;
switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
mr |= ATMEL_I2SC_MR_FORMAT_I2S;
break;
default:
dev_err(dev->dev, "unsupported bus format\n");
return -EINVAL;
}
switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
/* codec is slave, so cpu is master */
mr |= ATMEL_I2SC_MR_MODE_MASTER;
ret = atmel_i2s_get_gck_param(dev, params_rate(params));
if (ret)
return ret;
break;
case SND_SOC_DAIFMT_CBM_CFM:
/* codec is master, so cpu is slave */
mr |= ATMEL_I2SC_MR_MODE_SLAVE;
dev->gck_param = NULL;
break;
default:
dev_err(dev->dev, "unsupported master/slave mode\n");
return -EINVAL;
}
switch (params_channels(params)) {
case 1:
if (is_playback)
mr |= ATMEL_I2SC_MR_TXMONO;
else
mr |= ATMEL_I2SC_MR_RXMONO;
break;
case 2:
break;
default:
dev_err(dev->dev, "unsupported number of audio channels\n");
return -EINVAL;
}
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
mr |= ATMEL_I2SC_MR_DATALENGTH_8_BITS;
break;
case SNDRV_PCM_FORMAT_S16_LE:
mr |= ATMEL_I2SC_MR_DATALENGTH_16_BITS;
break;
case SNDRV_PCM_FORMAT_S18_3LE:
mr |= ATMEL_I2SC_MR_DATALENGTH_18_BITS | ATMEL_I2SC_MR_IWS;
break;
case SNDRV_PCM_FORMAT_S20_3LE:
mr |= ATMEL_I2SC_MR_DATALENGTH_20_BITS | ATMEL_I2SC_MR_IWS;
break;
case SNDRV_PCM_FORMAT_S24_3LE:
mr |= ATMEL_I2SC_MR_DATALENGTH_24_BITS | ATMEL_I2SC_MR_IWS;
break;
case SNDRV_PCM_FORMAT_S24_LE:
mr |= ATMEL_I2SC_MR_DATALENGTH_24_BITS;
break;
case SNDRV_PCM_FORMAT_S32_LE:
mr |= ATMEL_I2SC_MR_DATALENGTH_32_BITS;
break;
default:
dev_err(dev->dev, "unsupported size/endianness for audio samples\n");
return -EINVAL;
}
return regmap_write(dev->regmap, ATMEL_I2SC_MR, mr);
}
static int atmel_i2s_switch_mck_generator(struct atmel_i2s_dev *dev,
bool enabled)
{
unsigned int mr, mr_mask;
unsigned long aclk_rate;
int ret;
mr = 0;
mr_mask = (ATMEL_I2SC_MR_IMCKDIV_MASK |
ATMEL_I2SC_MR_IMCKFS_MASK |
ATMEL_I2SC_MR_IMCKMODE_MASK);
if (!enabled) {
/* Disable the I2S Master Clock generator. */
ret = regmap_write(dev->regmap, ATMEL_I2SC_CR,
ATMEL_I2SC_CR_CKDIS);
if (ret)
return ret;
/* Reset the I2S Master Clock generator settings. */
ret = regmap_update_bits(dev->regmap, ATMEL_I2SC_MR,
mr_mask, mr);
if (ret)
return ret;
/* Disable/unprepare the PMC generated clock. */
clk_disable_unprepare(dev->gclk);
/* Disable/unprepare the PLL audio clock. */
clk_disable_unprepare(dev->aclk);
return 0;
}
if (!dev->gck_param)
return -EINVAL;
aclk_rate = dev->gck_param->mck * (dev->gck_param->imckdiv + 1);
/* Fist change the PLL audio clock frequency ... */
ret = clk_set_rate(dev->aclk, aclk_rate);
if (ret)
return ret;
/*
* ... then set the PMC generated clock rate to the very same frequency
* to set the gclk parent to aclk.
*/
ret = clk_set_rate(dev->gclk, aclk_rate);
if (ret)
return ret;
/* Prepare and enable the PLL audio clock first ... */
ret = clk_prepare_enable(dev->aclk);
if (ret)
return ret;
/* ... then prepare and enable the PMC generated clock. */
ret = clk_prepare_enable(dev->gclk);
if (ret)
return ret;
/* Update the Mode Register to generate the I2S Master Clock. */
mr |= ATMEL_I2SC_MR_IMCKDIV(dev->gck_param->imckdiv);
mr |= ATMEL_I2SC_MR_IMCKFS(dev->gck_param->imckfs);
mr |= ATMEL_I2SC_MR_IMCKMODE_I2SMCK;
ret = regmap_update_bits(dev->regmap, ATMEL_I2SC_MR, mr_mask, mr);
if (ret)
return ret;
/* Finally enable the I2S Master Clock generator. */
return regmap_write(dev->regmap, ATMEL_I2SC_CR,
ATMEL_I2SC_CR_CKEN);
}
static int atmel_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
bool is_master, mck_enabled;
unsigned int cr, mr;
int err;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
cr = is_playback ? ATMEL_I2SC_CR_TXEN : ATMEL_I2SC_CR_RXEN;
mck_enabled = true;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
cr = is_playback ? ATMEL_I2SC_CR_TXDIS : ATMEL_I2SC_CR_RXDIS;
mck_enabled = false;
break;
default:
return -EINVAL;
}
/* Read the Mode Register to retrieve the master/slave state. */
err = regmap_read(dev->regmap, ATMEL_I2SC_MR, &mr);
if (err)
return err;
is_master = (mr & ATMEL_I2SC_MR_MODE_MASK) == ATMEL_I2SC_MR_MODE_MASTER;
/* If master starts, enable the audio clock. */
if (is_master && mck_enabled)
err = atmel_i2s_switch_mck_generator(dev, true);
if (err)
return err;
err = regmap_write(dev->regmap, ATMEL_I2SC_CR, cr);
if (err)
return err;
/* If master stops, disable the audio clock. */
if (is_master && !mck_enabled)
err = atmel_i2s_switch_mck_generator(dev, false);
return err;
}
static const struct snd_soc_dai_ops atmel_i2s_dai_ops = {
.prepare = atmel_i2s_prepare,
.trigger = atmel_i2s_trigger,
.hw_params = atmel_i2s_hw_params,
.set_fmt = atmel_i2s_set_dai_fmt,
};
static int atmel_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
snd_soc_dai_init_dma_data(dai, &dev->playback, &dev->capture);
return 0;
}
static struct snd_soc_dai_driver atmel_i2s_dai = {
.probe = atmel_i2s_dai_probe,
.playback = {
.channels_min = 1,
.channels_max = 2,
.rates = ATMEL_I2S_RATES,
.formats = ATMEL_I2S_FORMATS,
},
.capture = {
.channels_min = 1,
.channels_max = 2,
.rates = ATMEL_I2S_RATES,
.formats = ATMEL_I2S_FORMATS,
},
.ops = &atmel_i2s_dai_ops,
.symmetric_rates = 1,
};
static const struct snd_soc_component_driver atmel_i2s_component = {
.name = "atmel-i2s",
};
static int atmel_i2s_sama5d2_mck_init(struct atmel_i2s_dev *dev,
struct device_node *np)
{
struct clk *muxclk;
int err;
if (!dev->gclk)
return 0;
/* muxclk is optional, so we return error for probe defer only */
muxclk = devm_clk_get(dev->dev, "muxclk");
if (IS_ERR(muxclk)) {
err = PTR_ERR(muxclk);
if (err == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_warn(dev->dev,
"failed to get the I2S clock control: %d\n", err);
return 0;
}
return clk_set_parent(muxclk, dev->gclk);
}
static const struct atmel_i2s_caps atmel_i2s_sama5d2_caps = {
.mck_init = atmel_i2s_sama5d2_mck_init,
};
static const struct of_device_id atmel_i2s_dt_ids[] = {
{
.compatible = "atmel,sama5d2-i2s",
.data = (void *)&atmel_i2s_sama5d2_caps,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, atmel_i2s_dt_ids);
static int atmel_i2s_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match;
struct atmel_i2s_dev *dev;
struct resource *mem;
struct regmap *regmap;
void __iomem *base;
int irq;
int err = -ENXIO;
unsigned int pcm_flags = 0;
unsigned int version;
/* Get memory for driver data. */
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
/* Get hardware capabilities. */
match = of_match_node(atmel_i2s_dt_ids, np);
if (match)
dev->caps = match->data;
/* Map I/O registers. */
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(base))
return PTR_ERR(base);
regmap = devm_regmap_init_mmio(&pdev->dev, base,
&atmel_i2s_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
/* Request IRQ. */
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
err = devm_request_irq(&pdev->dev, irq, atmel_i2s_interrupt, 0,
dev_name(&pdev->dev), dev);
if (err)
return err;
/* Get the peripheral clock. */
dev->pclk = devm_clk_get(&pdev->dev, "pclk");
if (IS_ERR(dev->pclk)) {
err = PTR_ERR(dev->pclk);
dev_err(&pdev->dev,
"failed to get the peripheral clock: %d\n", err);
return err;
}
/* Get audio clocks to generate the I2S Master Clock (I2S_MCK) */
dev->aclk = devm_clk_get(&pdev->dev, "aclk");
dev->gclk = devm_clk_get(&pdev->dev, "gclk");
if (IS_ERR(dev->aclk) && IS_ERR(dev->gclk)) {
if (PTR_ERR(dev->aclk) == -EPROBE_DEFER ||
PTR_ERR(dev->gclk) == -EPROBE_DEFER)
return -EPROBE_DEFER;
/* Master Mode not supported */
dev->aclk = NULL;
dev->gclk = NULL;
} else if (IS_ERR(dev->gclk)) {
err = PTR_ERR(dev->gclk);
dev_err(&pdev->dev,
"failed to get the PMC generated clock: %d\n", err);
return err;
} else if (IS_ERR(dev->aclk)) {
err = PTR_ERR(dev->aclk);
dev_err(&pdev->dev,
"failed to get the PLL audio clock: %d\n", err);
return err;
}
dev->dev = &pdev->dev;
dev->regmap = regmap;
platform_set_drvdata(pdev, dev);
/* Do hardware specific settings to initialize I2S_MCK generator */
if (dev->caps && dev->caps->mck_init) {
err = dev->caps->mck_init(dev, np);
if (err)
return err;
}
/* Enable the peripheral clock. */
err = clk_prepare_enable(dev->pclk);
if (err)
return err;
/* Get IP version. */
regmap_read(dev->regmap, ATMEL_I2SC_VERSION, &version);
dev_info(&pdev->dev, "hw version: %#x\n", version);
/* Enable error interrupts. */
regmap_write(dev->regmap, ATMEL_I2SC_IER,
ATMEL_I2SC_INT_RXOR | ATMEL_I2SC_INT_TXUR);
err = devm_snd_soc_register_component(&pdev->dev,
&atmel_i2s_component,
&atmel_i2s_dai, 1);
if (err) {
dev_err(&pdev->dev, "failed to register DAI: %d\n", err);
clk_disable_unprepare(dev->pclk);
return err;
}
/* Prepare DMA config. */
dev->playback.addr = (dma_addr_t)mem->start + ATMEL_I2SC_THR;
dev->playback.maxburst = 1;
dev->capture.addr = (dma_addr_t)mem->start + ATMEL_I2SC_RHR;
dev->capture.maxburst = 1;
if (of_property_match_string(np, "dma-names", "rx-tx") == 0)
pcm_flags |= SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX;
err = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, pcm_flags);
if (err) {
dev_err(&pdev->dev, "failed to register PCM: %d\n", err);
clk_disable_unprepare(dev->pclk);
return err;
}
return 0;
}
static int atmel_i2s_remove(struct platform_device *pdev)
{
struct atmel_i2s_dev *dev = platform_get_drvdata(pdev);
clk_disable_unprepare(dev->pclk);
return 0;
}
static struct platform_driver atmel_i2s_driver = {
.driver = {
.name = "atmel_i2s",
.of_match_table = of_match_ptr(atmel_i2s_dt_ids),
},
.probe = atmel_i2s_probe,
.remove = atmel_i2s_remove,
};
module_platform_driver(atmel_i2s_driver);
MODULE_DESCRIPTION("Atmel I2S Controller driver");
MODULE_AUTHOR("Cyrille Pitchen <cyrille.pitchen@atmel.com>");
MODULE_LICENSE("GPL v2");

View File

@@ -820,7 +820,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
if (ret < 0) {
printk(KERN_WARNING
"atmel_ssc_dai: request_irq failure\n");
pr_debug("Atmel_ssc_dai: Stoping clock\n");
pr_debug("Atmel_ssc_dai: Stopping clock\n");
clk_disable(ssc_p->ssc->clk);
return ret;
}
@@ -1002,8 +1002,7 @@ static const struct snd_soc_component_driver atmel_ssc_component = {
static int asoc_ssc_init(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct ssc_device *ssc = platform_get_drvdata(pdev);
struct ssc_device *ssc = dev_get_drvdata(dev);
int ret;
ret = snd_soc_register_component(dev, &atmel_ssc_component,
@@ -1033,8 +1032,7 @@ err:
static void asoc_ssc_exit(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct ssc_device *ssc = platform_get_drvdata(pdev);
struct ssc_device *ssc = dev_get_drvdata(dev);
if (ssc->pdata->use_dma)
atmel_pcm_dma_platform_unregister(dev);

View File

@@ -11,9 +11,8 @@ config SND_BCM2835_SOC_I2S
config SND_SOC_CYGNUS
tristate "SoC platform audio for Broadcom Cygnus chips"
depends on ARCH_BCM_CYGNUS || COMPILE_TEST
depends on HAS_DMA
help
Say Y if you want to add support for ASoC audio on Broadcom
Cygnus chips (bcm958300, bcm958305, bcm911360)
If you don't know what to do here, say N.
If you don't know what to do here, say N.

View File

@@ -9,6 +9,23 @@ config SND_EP93XX_SOC
config SND_EP93XX_SOC_I2S
tristate
if SND_EP93XX_SOC_I2S
config SND_EP93XX_SOC_I2S_WATCHDOG
bool "IRQ based underflow watchdog workaround"
default y
help
I2S controller on EP93xx seems to have undocumented HW issue.
Underflow of internal I2S controller FIFO could confuse the
state machine and the whole stream can be shifted by one byte
until I2S is disabled. This option enables IRQ based watchdog
which disables and re-enables I2S in case of underflow and
fills FIFO with zeroes.
If you are unsure how to answer this question, answer Y.
endif # if SND_EP93XX_SOC_I2S
config SND_EP93XX_SOC_AC97
tristate
select AC97_BUS

View File

@@ -67,7 +67,7 @@ static struct snd_soc_dai_link edb93xx_dai = {
.cpu_dai_name = "ep93xx-i2s",
.codec_name = "spi0.0",
.codec_dai_name = "cs4271-hifi",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
.ops = &edb93xx_ops,
};

View File

@@ -35,8 +35,12 @@
#define EP93XX_I2S_TXCLKCFG 0x00
#define EP93XX_I2S_RXCLKCFG 0x04
#define EP93XX_I2S_GLSTS 0x08
#define EP93XX_I2S_GLCTRL 0x0C
#define EP93XX_I2S_I2STX0LFT 0x10
#define EP93XX_I2S_I2STX0RT 0x14
#define EP93XX_I2S_TXLINCTRLDATA 0x28
#define EP93XX_I2S_TXCTRL 0x2C
#define EP93XX_I2S_TXWRDLEN 0x30
@@ -51,7 +55,17 @@
#define EP93XX_I2S_WRDLEN_24 (1 << 0)
#define EP93XX_I2S_WRDLEN_32 (2 << 0)
#define EP93XX_I2S_LINCTRLDATA_R_JUST (1 << 2) /* Right justify */
#define EP93XX_I2S_RXLINCTRLDATA_R_JUST BIT(1) /* Right justify */
#define EP93XX_I2S_TXLINCTRLDATA_R_JUST BIT(2) /* Right justify */
/*
* Transmit empty interrupt level select:
* 0 - Generate interrupt when FIFO is half empty
* 1 - Generate interrupt when FIFO is empty
*/
#define EP93XX_I2S_TXCTRL_TXEMPTY_LVL BIT(0)
#define EP93XX_I2S_TXCTRL_TXUFIE BIT(1) /* Transmit interrupt enable */
#define EP93XX_I2S_CLKCFG_LRS (1 << 0) /* lrclk polarity */
#define EP93XX_I2S_CLKCFG_CKP (1 << 1) /* Bit clock polarity */
@@ -59,6 +73,8 @@
#define EP93XX_I2S_CLKCFG_MASTER (1 << 3) /* Master mode */
#define EP93XX_I2S_CLKCFG_NBCG (1 << 4) /* Not bit clock gating */
#define EP93XX_I2S_GLSTS_TX0_FIFO_FULL BIT(12)
struct ep93xx_i2s_info {
struct clk *mclk;
struct clk *sclk;
@@ -96,7 +112,6 @@ static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info,
static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
{
unsigned base_reg;
int i;
if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
(ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
@@ -109,27 +124,36 @@ static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1);
}
/* Enable fifos */
/* Enable fifo */
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
base_reg = EP93XX_I2S_TX0EN;
else
base_reg = EP93XX_I2S_RX0EN;
for (i = 0; i < 3; i++)
ep93xx_i2s_write_reg(info, base_reg + (i * 4), 1);
ep93xx_i2s_write_reg(info, base_reg, 1);
/* Enable TX IRQs (FIFO empty or underflow) */
if (IS_ENABLED(CONFIG_SND_EP93XX_SOC_I2S_WATCHDOG) &&
stream == SNDRV_PCM_STREAM_PLAYBACK)
ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCTRL,
EP93XX_I2S_TXCTRL_TXEMPTY_LVL |
EP93XX_I2S_TXCTRL_TXUFIE);
}
static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
{
unsigned base_reg;
int i;
/* Disable fifos */
/* Disable IRQs */
if (IS_ENABLED(CONFIG_SND_EP93XX_SOC_I2S_WATCHDOG) &&
stream == SNDRV_PCM_STREAM_PLAYBACK)
ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCTRL, 0);
/* Disable fifo */
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
base_reg = EP93XX_I2S_TX0EN;
else
base_reg = EP93XX_I2S_RX0EN;
for (i = 0; i < 3; i++)
ep93xx_i2s_write_reg(info, base_reg + (i * 4), 0);
ep93xx_i2s_write_reg(info, base_reg, 0);
if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
(ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
@@ -143,6 +167,37 @@ static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
}
}
/*
* According to documentation I2S controller can handle underflow conditions
* just fine, but in reality the state machine is sometimes confused so that
* the whole stream is shifted by one byte. The watchdog below disables the TX
* FIFO, fills the buffer with zeroes and re-enables the FIFO. State machine
* is being reset and by filling the buffer we get some time before next
* underflow happens.
*/
static irqreturn_t ep93xx_i2s_interrupt(int irq, void *dev_id)
{
struct ep93xx_i2s_info *info = dev_id;
/* Disable FIFO */
ep93xx_i2s_write_reg(info, EP93XX_I2S_TX0EN, 0);
/*
* Fill TX FIFO with zeroes, this way we can defer next IRQs as much as
* possible and get more time for DMA to catch up. Actually there are
* only 8 samples in this FIFO, so even on 8kHz maximum deferral here is
* 1ms.
*/
while (!(ep93xx_i2s_read_reg(info, EP93XX_I2S_GLSTS) &
EP93XX_I2S_GLSTS_TX0_FIFO_FULL)) {
ep93xx_i2s_write_reg(info, EP93XX_I2S_I2STX0LFT, 0);
ep93xx_i2s_write_reg(info, EP93XX_I2S_I2STX0RT, 0);
}
/* Re-enable FIFO */
ep93xx_i2s_write_reg(info, EP93XX_I2S_TX0EN, 1);
return IRQ_HANDLED;
}
static int ep93xx_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
@@ -170,25 +225,25 @@ static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(cpu_dai);
unsigned int clk_cfg, lin_ctrl;
unsigned int clk_cfg;
unsigned int txlin_ctrl = 0;
unsigned int rxlin_ctrl = 0;
clk_cfg = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXCLKCFG);
lin_ctrl = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXLINCTRLDATA);
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
clk_cfg |= EP93XX_I2S_CLKCFG_REL;
lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
break;
case SND_SOC_DAIFMT_LEFT_J:
clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
break;
case SND_SOC_DAIFMT_RIGHT_J:
clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
lin_ctrl |= EP93XX_I2S_LINCTRLDATA_R_JUST;
rxlin_ctrl |= EP93XX_I2S_RXLINCTRLDATA_R_JUST;
txlin_ctrl |= EP93XX_I2S_TXLINCTRLDATA_R_JUST;
break;
default:
@@ -213,32 +268,32 @@ static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
/* Negative bit clock, lrclk low on left word */
clk_cfg &= ~(EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL);
clk_cfg &= ~(EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_LRS);
break;
case SND_SOC_DAIFMT_NB_IF:
/* Negative bit clock, lrclk low on right word */
clk_cfg &= ~EP93XX_I2S_CLKCFG_CKP;
clk_cfg |= EP93XX_I2S_CLKCFG_REL;
clk_cfg |= EP93XX_I2S_CLKCFG_LRS;
break;
case SND_SOC_DAIFMT_IB_NF:
/* Positive bit clock, lrclk low on left word */
clk_cfg |= EP93XX_I2S_CLKCFG_CKP;
clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
clk_cfg &= ~EP93XX_I2S_CLKCFG_LRS;
break;
case SND_SOC_DAIFMT_IB_IF:
/* Positive bit clock, lrclk low on right word */
clk_cfg |= EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL;
clk_cfg |= EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_LRS;
break;
}
/* Write new register values */
ep93xx_i2s_write_reg(info, EP93XX_I2S_RXCLKCFG, clk_cfg);
ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCLKCFG, clk_cfg);
ep93xx_i2s_write_reg(info, EP93XX_I2S_RXLINCTRLDATA, lin_ctrl);
ep93xx_i2s_write_reg(info, EP93XX_I2S_TXLINCTRLDATA, lin_ctrl);
ep93xx_i2s_write_reg(info, EP93XX_I2S_RXLINCTRLDATA, rxlin_ctrl);
ep93xx_i2s_write_reg(info, EP93XX_I2S_TXLINCTRLDATA, txlin_ctrl);
return 0;
}
@@ -392,6 +447,17 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
if (IS_ERR(info->regs))
return PTR_ERR(info->regs);
if (IS_ENABLED(CONFIG_SND_EP93XX_SOC_I2S_WATCHDOG)) {
int irq = platform_get_irq(pdev, 0);
if (irq <= 0)
return irq < 0 ? irq : -ENODEV;
err = devm_request_irq(&pdev->dev, irq, ep93xx_i2s_interrupt, 0,
pdev->name, info);
if (err)
return err;
}
info->mclk = clk_get(&pdev->dev, "mclk");
if (IS_ERR(info->mclk)) {
err = PTR_ERR(info->mclk);

View File

@@ -72,7 +72,7 @@ static struct snd_soc_dai_link snappercl15_dai = {
.codec_dai_name = "tlv320aic23-hifi",
.codec_name = "tlv320aic23-codec.0-001a",
.platform_name = "ep93xx-i2s",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
.ops = &snappercl15_ops,
};

View File

@@ -106,6 +106,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_MAX9877 if I2C
select SND_SOC_MC13783 if MFD_MC13XXX
select SND_SOC_ML26124 if I2C
select SND_SOC_MT6351 if MTK_PMIC_WRAP
select SND_SOC_NAU8540 if I2C
select SND_SOC_NAU8810 if I2C
select SND_SOC_NAU8824 if I2C
@@ -126,6 +127,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_RT274 if I2C
select SND_SOC_RT286 if I2C
select SND_SOC_RT298 if I2C
select SND_SOC_RT1305 if I2C
select SND_SOC_RT5514 if I2C
select SND_SOC_RT5616 if I2C
select SND_SOC_RT5631 if I2C
@@ -136,12 +138,14 @@ config SND_SOC_ALL_CODECS
select SND_SOC_RT5660 if I2C
select SND_SOC_RT5663 if I2C
select SND_SOC_RT5665 if I2C
select SND_SOC_RT5668 if I2C
select SND_SOC_RT5670 if I2C
select SND_SOC_RT5677 if I2C && SPI_MASTER
select SND_SOC_SGTL5000 if I2C
select SND_SOC_SI476X if MFD_SI476X_CORE
select SND_SOC_SIRF_AUDIO_CODEC
select SND_SOC_SPDIF
select SND_SOC_SSM2305
select SND_SOC_SSM2518 if I2C
select SND_SOC_SSM2602_SPI if SPI_MASTER
select SND_SOC_SSM2602_I2C if I2C
@@ -168,6 +172,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_TPA6130A2 if I2C
select SND_SOC_TLV320DAC33 if I2C
select SND_SOC_TSCS42XX if I2C
select SND_SOC_TSCS454 if I2C
select SND_SOC_TS3A227E if I2C
select SND_SOC_TWL4030 if TWL4030_CORE
select SND_SOC_TWL6040 if TWL6040_CORE
@@ -770,8 +775,10 @@ config SND_SOC_RL6231
default y if SND_SOC_RT5660=y
default y if SND_SOC_RT5663=y
default y if SND_SOC_RT5665=y
default y if SND_SOC_RT5668=y
default y if SND_SOC_RT5670=y
default y if SND_SOC_RT5677=y
default y if SND_SOC_RT1305=y
default m if SND_SOC_RT5514=m
default m if SND_SOC_RT5616=m
default m if SND_SOC_RT5640=m
@@ -781,8 +788,10 @@ config SND_SOC_RL6231
default m if SND_SOC_RT5660=m
default m if SND_SOC_RT5663=m
default m if SND_SOC_RT5665=m
default m if SND_SOC_RT5668=m
default m if SND_SOC_RT5670=m
default m if SND_SOC_RT5677=m
default m if SND_SOC_RT1305=m
config SND_SOC_RL6347A
tristate
@@ -805,6 +814,9 @@ config SND_SOC_RT298
tristate
depends on I2C
config SND_SOC_RT1305
tristate
config SND_SOC_RT5514
tristate
@@ -844,6 +856,9 @@ config SND_SOC_RT5663
config SND_SOC_RT5665
tristate
config SND_SOC_RT5668
tristate
config SND_SOC_RT5670
tristate
@@ -883,6 +898,12 @@ config SND_SOC_SIRF_AUDIO_CODEC
config SND_SOC_SPDIF
tristate "S/PDIF CODEC"
config SND_SOC_SSM2305
tristate "Analog Devices SSM2305 Class-D Amplifier"
help
Enable support for Analog Devices SSM2305 filterless
high-efficiency mono Class-D audio power amplifiers.
config SND_SOC_SSM2518
tristate
@@ -1011,6 +1032,13 @@ config SND_SOC_TSCS42XX
help
Add support for Tempo Semiconductor's TSCS42xx audio CODEC.
config SND_SOC_TSCS454
tristate "Tempo Semiconductor TSCS454 CODEC"
depends on I2C
select REGMAP_I2C
help
Add support for Tempo Semiconductor's TSCS454 audio CODEC.
config SND_SOC_TWL4030
select MFD_TWL4030_AUDIO
tristate
@@ -1111,7 +1139,7 @@ config SND_SOC_WM8776
depends on SND_SOC_I2C_AND_SPI
config SND_SOC_WM8782
tristate
tristate "Wolfson Microelectronics WM8782 ADC"
config SND_SOC_WM8804
tristate
@@ -1247,6 +1275,9 @@ config SND_SOC_MC13783
config SND_SOC_ML26124
tristate
config SND_SOC_MT6351
tristate "MediaTek MT6351 Codec"
config SND_SOC_NAU8540
tristate "Nuvoton Technology Corporation NAU85L40 CODEC"
depends on I2C

View File

@@ -102,6 +102,7 @@ snd-soc-mc13783-objs := mc13783.o
snd-soc-ml26124-objs := ml26124.o
snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o
snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o
snd-soc-mt6351-objs := mt6351.o
snd-soc-nau8540-objs := nau8540.o
snd-soc-nau8810-objs := nau8810.o
snd-soc-nau8824-objs := nau8824.o
@@ -126,6 +127,7 @@ snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
snd-soc-pcm512x-spi-objs := pcm512x-spi.o
snd-soc-rl6231-objs := rl6231.o
snd-soc-rl6347a-objs := rl6347a.o
snd-soc-rt1305-objs := rt1305.o
snd-soc-rt274-objs := rt274.o
snd-soc-rt286-objs := rt286.o
snd-soc-rt298-objs := rt298.o
@@ -140,6 +142,7 @@ snd-soc-rt5659-objs := rt5659.o
snd-soc-rt5660-objs := rt5660.o
snd-soc-rt5663-objs := rt5663.o
snd-soc-rt5665-objs := rt5665.o
snd-soc-rt5668-objs := rt5668.o
snd-soc-rt5670-objs := rt5670.o
snd-soc-rt5677-objs := rt5677.o
snd-soc-rt5677-spi-objs := rt5677-spi.o
@@ -153,6 +156,7 @@ snd-soc-si476x-objs := si476x.o
snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o
snd-soc-spdif-tx-objs := spdif_transmitter.o
snd-soc-spdif-rx-objs := spdif_receiver.o
snd-soc-ssm2305-objs := ssm2305.o
snd-soc-ssm2518-objs := ssm2518.o
snd-soc-ssm2602-objs := ssm2602.o
snd-soc-ssm2602-spi-objs := ssm2602-spi.o
@@ -180,6 +184,7 @@ snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
snd-soc-tlv320dac33-objs := tlv320dac33.o
snd-soc-tscs42xx-objs := tscs42xx.o
snd-soc-tscs454-objs := tscs454.o
snd-soc-ts3a227e-objs := ts3a227e.o
snd-soc-twl4030-objs := twl4030.o
snd-soc-twl6040-objs := twl6040.o
@@ -355,6 +360,7 @@ obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o
obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o
obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o
obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o
obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o
obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o
obj-$(CONFIG_SND_SOC_NAU8824) += snd-soc-nau8824.o
@@ -379,6 +385,7 @@ obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o
obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o
obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o
obj-$(CONFIG_SND_SOC_RT274) += snd-soc-rt274.o
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
@@ -394,6 +401,7 @@ obj-$(CONFIG_SND_SOC_RT5659) += snd-soc-rt5659.o
obj-$(CONFIG_SND_SOC_RT5660) += snd-soc-rt5660.o
obj-$(CONFIG_SND_SOC_RT5663) += snd-soc-rt5663.o
obj-$(CONFIG_SND_SOC_RT5665) += snd-soc-rt5665.o
obj-$(CONFIG_SND_SOC_RT5668) += snd-soc-rt5668.o
obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o
obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o
obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o
@@ -404,6 +412,7 @@ obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP) += snd-soc-sigmadsp-regmap.o
obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o
obj-$(CONFIG_SND_SOC_SIRF_AUDIO_CODEC) += sirf-audio-codec.o
obj-$(CONFIG_SND_SOC_SSM2305) += snd-soc-ssm2305.o
obj-$(CONFIG_SND_SOC_SSM2518) += snd-soc-ssm2518.o
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
obj-$(CONFIG_SND_SOC_SSM2602_SPI) += snd-soc-ssm2602-spi.o
@@ -432,6 +441,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC32X4_SPI) += snd-soc-tlv320aic32x4-spi.o
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o
obj-$(CONFIG_SND_SOC_TSCS42XX) += snd-soc-tscs42xx.o
obj-$(CONFIG_SND_SOC_TSCS454) += snd-soc-tscs454.o
obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o
obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o

View File

@@ -843,6 +843,15 @@ int adau17x1_setup_firmware(struct snd_soc_component *component,
struct adau *adau = snd_soc_component_get_drvdata(component);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
/* Check if sample rate is the same as before. If it is there is no
* point in performing the below steps as the call to
* sigmadsp_setup(...) will return directly when it finds the sample
* rate to be the same as before. By checking this we can prevent an
* audiable popping noise which occours when toggling DSP_RUN.
*/
if (adau->sigmadsp->current_samplerate == rate)
return 0;
snd_soc_dapm_mutex_lock(dapm);
ret = regmap_read(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, &dspsr);

View File

@@ -1105,6 +1105,7 @@ static struct regmap_config cs35l35_regmap = {
.readable_reg = cs35l35_readable_register,
.precious_reg = cs35l35_precious_register,
.cache_type = REGCACHE_RBTREE,
.use_single_rw = true,
};
static irqreturn_t cs35l35_irq(int irq, void *data)

View File

@@ -1382,15 +1382,12 @@ static const char *eq_mode_name[] = {"EQ1 Mode", "EQ2 Mode"};
static int max98088_get_channel(struct snd_soc_component *component, const char *name)
{
int i;
int ret;
for (i = 0; i < ARRAY_SIZE(eq_mode_name); i++)
if (strcmp(name, eq_mode_name[i]) == 0)
return i;
/* Shouldn't happen */
dev_err(component->dev, "Bad EQ channel name '%s'\n", name);
return -EINVAL;
ret = match_string(eq_mode_name, ARRAY_SIZE(eq_mode_name), name);
if (ret < 0)
dev_err(component->dev, "Bad EQ channel name '%s'\n", name);
return ret;
}
static void max98088_setup_eq1(struct snd_soc_component *component)

View File

@@ -1634,15 +1634,12 @@ static const char *bq_mode_name[] = {"Biquad1 Mode", "Biquad2 Mode"};
static int max98095_get_bq_channel(struct snd_soc_component *component,
const char *name)
{
int i;
int ret;
for (i = 0; i < ARRAY_SIZE(bq_mode_name); i++)
if (strcmp(name, bq_mode_name[i]) == 0)
return i;
/* Shouldn't happen */
dev_err(component->dev, "Bad biquad channel name '%s'\n", name);
return -EINVAL;
ret = match_string(bq_mode_name, ARRAY_SIZE(bq_mode_name), name);
if (ret < 0)
dev_err(component->dev, "Bad biquad channel name '%s'\n", name);
return ret;
}
static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,

View File

@@ -1,23 +1,14 @@
/*
* Driver for the MAX9860 Mono Audio Voice Codec
*
* https://datasheets.maximintegrated.com/en/ds/MAX9860.pdf
*
* The driver does not support sidetone since the DVST register field is
* backwards with the mute near the maximum level instead of the minimum.
*
* Author: Peter Rosin <peda@axentia.s>
* Copyright 2016 Axentia Technologies
*
* 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.
*/
// SPDX-License-Identifier: GPL-2.0
//
// Driver for the MAX9860 Mono Audio Voice Codec
//
// https://datasheets.maximintegrated.com/en/ds/MAX9860.pdf
//
// The driver does not support sidetone since the DVST register field is
// backwards with the mute near the maximum level instead of the minimum.
//
// Author: Peter Rosin <peda@axentia.s>
// Copyright 2016 Axentia Technologies
#include <linux/init.h>
#include <linux/module.h>
@@ -443,7 +434,8 @@ static int max9860_hw_params(struct snd_pcm_substream *substream,
ret = regmap_update_bits(max9860->regmap, MAX9860_AUDIOCLKHIGH,
MAX9860_PLL, MAX9860_PLL);
if (ret) {
dev_err(component->dev, "Failed to enable PLL: %d\n", ret);
dev_err(component->dev, "Failed to enable PLL: %d\n",
ret);
return ret;
}
}
@@ -515,7 +507,8 @@ static int max9860_set_bias_level(struct snd_soc_component *component,
ret = regmap_update_bits(max9860->regmap, MAX9860_PWRMAN,
MAX9860_SHDN, MAX9860_SHDN);
if (ret) {
dev_err(component->dev, "Failed to remove SHDN: %d\n", ret);
dev_err(component->dev, "Failed to remove SHDN: %d\n",
ret);
return ret;
}
break;
@@ -598,8 +591,7 @@ static const struct dev_pm_ops max9860_pm_ops = {
SET_RUNTIME_PM_OPS(max9860_suspend, max9860_resume, NULL)
};
static int max9860_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
static int max9860_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
struct max9860_priv *max9860;
@@ -698,7 +690,7 @@ static int max9860_probe(struct i2c_client *i2c,
pm_runtime_idle(dev);
ret = devm_snd_soc_register_component(dev, &max9860_component_driver,
&max9860_dai, 1);
&max9860_dai, 1);
if (ret) {
dev_err(dev, "Failed to register CODEC: %d\n", ret);
goto err_pm;
@@ -736,7 +728,7 @@ static const struct of_device_id max9860_of_match[] = {
MODULE_DEVICE_TABLE(of, max9860_of_match);
static struct i2c_driver max9860_i2c_driver = {
.probe = max9860_probe,
.probe_new = max9860_probe,
.remove = max9860_remove,
.id_table = max9860_i2c_id,
.driver = {

View File

@@ -1,17 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Driver for the MAX9860 Mono Audio Voice Codec
*
* Author: Peter Rosin <peda@axentia.s>
* Copyright 2016 Axentia Technologies
*
* 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.
*/
#ifndef _SND_SOC_MAX9860

1505
sound/soc/codecs/mt6351.c Normal file

File diff suppressed because it is too large Load Diff

105
sound/soc/codecs/mt6351.h Normal file
View File

@@ -0,0 +1,105 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* mt6351.h -- mt6351 ALSA SoC audio codec driver
*
* Copyright (c) 2018 MediaTek Inc.
* Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
*/
#ifndef __MT6351_H__
#define __MT6351_H__
#define MT6351_AFE_UL_DL_CON0 (0x2000 + 0x0000)
#define MT6351_AFE_DL_SRC2_CON0_H (0x2000 + 0x0002)
#define MT6351_AFE_DL_SRC2_CON0_L (0x2000 + 0x0004)
#define MT6351_AFE_DL_SDM_CON0 (0x2000 + 0x0006)
#define MT6351_AFE_DL_SDM_CON1 (0x2000 + 0x0008)
#define MT6351_AFE_UL_SRC_CON0_H (0x2000 + 0x000a)
#define MT6351_AFE_UL_SRC_CON0_L (0x2000 + 0x000c)
#define MT6351_AFE_UL_SRC_CON1_H (0x2000 + 0x000e)
#define MT6351_AFE_UL_SRC_CON1_L (0x2000 + 0x0010)
#define MT6351_AFE_TOP_CON0 (0x2000 + 0x0012)
#define MT6351_AUDIO_TOP_CON0 (0x2000 + 0x0014)
#define MT6351_AFE_DL_SRC_MON0 (0x2000 + 0x0016)
#define MT6351_AFE_DL_SDM_TEST0 (0x2000 + 0x0018)
#define MT6351_AFE_MON_DEBUG0 (0x2000 + 0x001a)
#define MT6351_AFUNC_AUD_CON0 (0x2000 + 0x001c)
#define MT6351_AFUNC_AUD_CON1 (0x2000 + 0x001e)
#define MT6351_AFUNC_AUD_CON2 (0x2000 + 0x0020)
#define MT6351_AFUNC_AUD_CON3 (0x2000 + 0x0022)
#define MT6351_AFUNC_AUD_CON4 (0x2000 + 0x0024)
#define MT6351_AFUNC_AUD_MON0 (0x2000 + 0x0026)
#define MT6351_AFUNC_AUD_MON1 (0x2000 + 0x0028)
#define MT6351_AFE_UP8X_FIFO_CFG0 (0x2000 + 0x002c)
#define MT6351_AFE_UP8X_FIFO_LOG_MON0 (0x2000 + 0x002e)
#define MT6351_AFE_UP8X_FIFO_LOG_MON1 (0x2000 + 0x0030)
#define MT6351_AFE_DL_DC_COMP_CFG0 (0x2000 + 0x0032)
#define MT6351_AFE_DL_DC_COMP_CFG1 (0x2000 + 0x0034)
#define MT6351_AFE_DL_DC_COMP_CFG2 (0x2000 + 0x0036)
#define MT6351_AFE_PMIC_NEWIF_CFG0 (0x2000 + 0x0038)
#define MT6351_AFE_PMIC_NEWIF_CFG1 (0x2000 + 0x003a)
#define MT6351_AFE_PMIC_NEWIF_CFG2 (0x2000 + 0x003c)
#define MT6351_AFE_PMIC_NEWIF_CFG3 (0x2000 + 0x003e)
#define MT6351_AFE_SGEN_CFG0 (0x2000 + 0x0040)
#define MT6351_AFE_SGEN_CFG1 (0x2000 + 0x0042)
#define MT6351_AFE_ADDA2_UP8X_FIFO_LOG_MON0 (0x2000 + 0x004c)
#define MT6351_AFE_ADDA2_UP8X_FIFO_LOG_MON1 (0x2000 + 0x004e)
#define MT6351_AFE_ADDA2_PMIC_NEWIF_CFG0 (0x2000 + 0x0050)
#define MT6351_AFE_ADDA2_PMIC_NEWIF_CFG1 (0x2000 + 0x0052)
#define MT6351_AFE_ADDA2_PMIC_NEWIF_CFG2 (0x2000 + 0x0054)
#define MT6351_AFE_DCCLK_CFG0 (0x2000 + 0x0090)
#define MT6351_AFE_DCCLK_CFG1 (0x2000 + 0x0092)
#define MT6351_AFE_HPANC_CFG0 (0x2000 + 0x0094)
#define MT6351_AFE_NCP_CFG0 (0x2000 + 0x0096)
#define MT6351_AFE_NCP_CFG1 (0x2000 + 0x0098)
#define MT6351_TOP_CKPDN_CON0 0x023A
#define MT6351_TOP_CKPDN_CON0_SET 0x023C
#define MT6351_TOP_CKPDN_CON0_CLR 0x023E
#define MT6351_TOP_CLKSQ 0x029A
#define MT6351_TOP_CLKSQ_SET 0x029C
#define MT6351_TOP_CLKSQ_CLR 0x029E
#define MT6351_ZCD_CON0 0x0800
#define MT6351_ZCD_CON1 0x0802
#define MT6351_ZCD_CON2 0x0804
#define MT6351_ZCD_CON3 0x0806
#define MT6351_ZCD_CON4 0x0808
#define MT6351_ZCD_CON5 0x080A
#define MT6351_LDO_VA18_CON0 0x0A00
#define MT6351_LDO_VA18_CON1 0x0A02
#define MT6351_LDO_VUSB33_CON0 0x0A16
#define MT6351_LDO_VUSB33_CON1 0x0A18
#define MT6351_AUDDEC_ANA_CON0 0x0CF2
#define MT6351_AUDDEC_ANA_CON1 0x0CF4
#define MT6351_AUDDEC_ANA_CON2 0x0CF6
#define MT6351_AUDDEC_ANA_CON3 0x0CF8
#define MT6351_AUDDEC_ANA_CON4 0x0CFA
#define MT6351_AUDDEC_ANA_CON5 0x0CFC
#define MT6351_AUDDEC_ANA_CON6 0x0CFE
#define MT6351_AUDDEC_ANA_CON7 0x0D00
#define MT6351_AUDDEC_ANA_CON8 0x0D02
#define MT6351_AUDDEC_ANA_CON9 0x0D04
#define MT6351_AUDDEC_ANA_CON10 0x0D06
#define MT6351_AUDENC_ANA_CON0 0x0D08
#define MT6351_AUDENC_ANA_CON1 0x0D0A
#define MT6351_AUDENC_ANA_CON2 0x0D0C
#define MT6351_AUDENC_ANA_CON3 0x0D0E
#define MT6351_AUDENC_ANA_CON4 0x0D10
#define MT6351_AUDENC_ANA_CON5 0x0D12
#define MT6351_AUDENC_ANA_CON6 0x0D14
#define MT6351_AUDENC_ANA_CON7 0x0D16
#define MT6351_AUDENC_ANA_CON8 0x0D18
#define MT6351_AUDENC_ANA_CON9 0x0D1A
#define MT6351_AUDENC_ANA_CON10 0x0D1C
#define MT6351_AUDENC_ANA_CON11 0x0D1E
#define MT6351_AUDENC_ANA_CON12 0x0D20
#define MT6351_AUDENC_ANA_CON13 0x0D22
#define MT6351_AUDENC_ANA_CON14 0x0D24
#define MT6351_AUDENC_ANA_CON15 0x0D26
#define MT6351_AUDENC_ANA_CON16 0x0D28
#endif

View File

@@ -373,9 +373,11 @@ static const struct snd_kcontrol_new nau8810_mono_mixer_controls[] = {
};
/* PGA Mute */
static const struct snd_kcontrol_new nau8810_inpga_mute[] = {
static const struct snd_kcontrol_new nau8810_pgaboost_mixer_controls[] = {
SOC_DAPM_SINGLE("PGA Mute Switch", NAU8810_REG_PGAGAIN,
NAU8810_PGAMT_SFT, 1, 0),
NAU8810_PGAMT_SFT, 1, 1),
SOC_DAPM_SINGLE("PMIC PGA Switch", NAU8810_REG_ADCBOOST,
NAU8810_PMICBSTGAIN_SFT, 0x7, 0),
};
/* Input PGA */
@@ -386,11 +388,6 @@ static const struct snd_kcontrol_new nau8810_inpga[] = {
NAU8810_PMICPGA_SFT, 1, 0),
};
/* Mic Input boost vol */
static const struct snd_kcontrol_new nau8810_mic_boost_controls =
SOC_DAPM_SINGLE("Mic Volume", NAU8810_REG_ADCBOOST,
NAU8810_PMICBSTGAIN_SFT, 0x7, 0);
/* Loopback Switch */
static const struct snd_kcontrol_new nau8810_loopback =
SOC_DAPM_SINGLE("Switch", NAU8810_REG_COMP,
@@ -429,8 +426,8 @@ static const struct snd_soc_dapm_widget nau8810_dapm_widgets[] = {
NAU8810_PGA_EN_SFT, 0, nau8810_inpga,
ARRAY_SIZE(nau8810_inpga)),
SND_SOC_DAPM_MIXER("Input Boost Stage", NAU8810_REG_POWER2,
NAU8810_BST_EN_SFT, 0, nau8810_inpga_mute,
ARRAY_SIZE(nau8810_inpga_mute)),
NAU8810_BST_EN_SFT, 0, nau8810_pgaboost_mixer_controls,
ARRAY_SIZE(nau8810_pgaboost_mixer_controls)),
SND_SOC_DAPM_SUPPLY("Mic Bias", NAU8810_REG_POWER1,
NAU8810_MICBIAS_EN_SFT, 0, NULL, 0),
@@ -469,8 +466,8 @@ static const struct snd_soc_dapm_route nau8810_dapm_routes[] = {
/* Input Boost Stage */
{"ADC", NULL, "Input Boost Stage"},
{"ADC", NULL, "PLL", check_mclk_select_pll},
{"Input Boost Stage", NULL, "Input PGA"},
{"Input Boost Stage", NULL, "MICP"},
{"Input Boost Stage", "PGA Mute Switch", "Input PGA"},
{"Input Boost Stage", "PMIC PGA Switch", "MICP"},
/* Input PGA */
{"Input PGA", NULL, "Mic Bias"},

View File

@@ -205,11 +205,11 @@ static int nau8824_sema_acquire(struct nau8824 *nau8824, long timeout)
if (timeout) {
ret = down_timeout(&nau8824->jd_sem, timeout);
if (ret < 0)
dev_warn(nau8824->dev, "Acquire semaphone timeout\n");
dev_warn(nau8824->dev, "Acquire semaphore timeout\n");
} else {
ret = down_interruptible(&nau8824->jd_sem);
if (ret < 0)
dev_warn(nau8824->dev, "Acquire semaphone fail\n");
dev_warn(nau8824->dev, "Acquire semaphore fail\n");
}
return ret;
@@ -409,6 +409,15 @@ static const struct snd_kcontrol_new nau8824_snd_controls[] = {
SOC_SINGLE("DACL LR Mix", NAU8824_REG_DAC_MUTE_CTRL, 0, 1, 0),
SOC_SINGLE("DACR LR Mix", NAU8824_REG_DAC_MUTE_CTRL, 1, 1, 0),
SOC_SINGLE("THD for key media",
NAU8824_REG_VDET_THRESHOLD_1, 8, 0xff, 0),
SOC_SINGLE("THD for key voice command",
NAU8824_REG_VDET_THRESHOLD_1, 0, 0xff, 0),
SOC_SINGLE("THD for key volume up",
NAU8824_REG_VDET_THRESHOLD_2, 8, 0xff, 0),
SOC_SINGLE("THD for key volume down",
NAU8824_REG_VDET_THRESHOLD_2, 0, 0xff, 0),
};
static int nau8824_output_dac_event(struct snd_soc_dapm_widget *w,

View File

@@ -3,7 +3,7 @@
// Copyright (C) 2018 Bootlin
// Mylène Josserand <mylene.josserand@bootlin.com>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/workqueue.h>

View File

@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
#include "pcm512x.h"
@@ -52,6 +53,7 @@ static const struct i2c_device_id pcm512x_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id);
#if defined(CONFIG_OF)
static const struct of_device_id pcm512x_of_match[] = {
{ .compatible = "ti,pcm5121", },
{ .compatible = "ti,pcm5122", },
@@ -60,6 +62,18 @@ static const struct of_device_id pcm512x_of_match[] = {
{ }
};
MODULE_DEVICE_TABLE(of, pcm512x_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id pcm512x_acpi_match[] = {
{ "104C5121", 0 },
{ "104C5122", 0 },
{ "104C5141", 0 },
{ "104C5142", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, pcm512x_acpi_match);
#endif
static struct i2c_driver pcm512x_i2c_driver = {
.probe = pcm512x_i2c_probe,
@@ -67,7 +81,8 @@ static struct i2c_driver pcm512x_i2c_driver = {
.id_table = pcm512x_i2c_id,
.driver = {
.name = "pcm512x",
.of_match_table = pcm512x_of_match,
.of_match_table = of_match_ptr(pcm512x_of_match),
.acpi_match_table = ACPI_PTR(pcm512x_acpi_match),
.pm = &pcm512x_pm_ops,
},
};

1191
sound/soc/codecs/rt1305.c Normal file

File diff suppressed because it is too large Load Diff

276
sound/soc/codecs/rt1305.h Normal file
View File

@@ -0,0 +1,276 @@
/*
* RT1305.h -- RT1305 ALSA SoC amplifier component driver
*
* Copyright 2018 Realtek Semiconductor Corp.
* Author: Shuming Fan <shumingf@realtek.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.
*/
#ifndef _RT1305_H_
#define _RT1305_H_
#define RT1305_DEVICE_ID_NUM 0x6251
#define RT1305_RESET 0x00
#define RT1305_CLK_1 0x04
#define RT1305_CLK_2 0x05
#define RT1305_CLK_3 0x06
#define RT1305_DFLL_REG 0x07
#define RT1305_CAL_EFUSE_CLOCK 0x08
#define RT1305_PLL0_1 0x0a
#define RT1305_PLL0_2 0x0b
#define RT1305_PLL1_1 0x0c
#define RT1305_PLL1_2 0x0d
#define RT1305_MIXER_CTRL_1 0x10
#define RT1305_MIXER_CTRL_2 0x11
#define RT1305_DAC_SET_1 0x12
#define RT1305_DAC_SET_2 0x14
#define RT1305_ADC_SET_1 0x16
#define RT1305_ADC_SET_2 0x17
#define RT1305_ADC_SET_3 0x18
#define RT1305_PATH_SET 0x20
#define RT1305_SPDIF_IN_SET_1 0x22
#define RT1305_SPDIF_IN_SET_2 0x24
#define RT1305_SPDIF_IN_SET_3 0x26
#define RT1305_SPDIF_OUT_SET_1 0x28
#define RT1305_SPDIF_OUT_SET_2 0x2a
#define RT1305_SPDIF_OUT_SET_3 0x2b
#define RT1305_I2S_SET_1 0x2d
#define RT1305_I2S_SET_2 0x2e
#define RT1305_PBTL_MONO_MODE_SRC 0x2f
#define RT1305_MANUALLY_I2C_DEVICE 0x32
#define RT1305_POWER_STATUS 0x39
#define RT1305_POWER_CTRL_1 0x3a
#define RT1305_POWER_CTRL_2 0x3b
#define RT1305_POWER_CTRL_3 0x3c
#define RT1305_POWER_CTRL_4 0x3d
#define RT1305_POWER_CTRL_5 0x3e
#define RT1305_CLOCK_DETECT 0x3f
#define RT1305_BIQUAD_SET_1 0x40
#define RT1305_BIQUAD_SET_2 0x42
#define RT1305_ADJUSTED_HPF_1 0x46
#define RT1305_ADJUSTED_HPF_2 0x47
#define RT1305_EQ_SET_1 0x4b
#define RT1305_EQ_SET_2 0x4c
#define RT1305_SPK_TEMP_PROTECTION_0 0x4f
#define RT1305_SPK_TEMP_PROTECTION_1 0x50
#define RT1305_SPK_TEMP_PROTECTION_2 0x51
#define RT1305_SPK_TEMP_PROTECTION_3 0x52
#define RT1305_SPK_DC_DETECT_1 0x53
#define RT1305_SPK_DC_DETECT_2 0x54
#define RT1305_LOUDNESS 0x58
#define RT1305_THERMAL_FOLD_BACK_1 0x5e
#define RT1305_THERMAL_FOLD_BACK_2 0x5f
#define RT1305_SILENCE_DETECT 0x60
#define RT1305_ALC_DRC_1 0x62
#define RT1305_ALC_DRC_2 0x63
#define RT1305_ALC_DRC_3 0x64
#define RT1305_ALC_DRC_4 0x65
#define RT1305_PRIV_INDEX 0x6a
#define RT1305_PRIV_DATA 0x6c
#define RT1305_SPK_EXCURSION_LIMITER_7 0x76
#define RT1305_VERSION_ID 0x7a
#define RT1305_VENDOR_ID 0x7c
#define RT1305_DEVICE_ID 0x7e
#define RT1305_EFUSE_1 0x80
#define RT1305_EFUSE_2 0x81
#define RT1305_EFUSE_3 0x82
#define RT1305_DC_CALIB_1 0x90
#define RT1305_DC_CALIB_2 0x91
#define RT1305_DC_CALIB_3 0x92
#define RT1305_DAC_OFFSET_1 0x93
#define RT1305_DAC_OFFSET_2 0x94
#define RT1305_DAC_OFFSET_3 0x95
#define RT1305_DAC_OFFSET_4 0x96
#define RT1305_DAC_OFFSET_5 0x97
#define RT1305_DAC_OFFSET_6 0x98
#define RT1305_DAC_OFFSET_7 0x99
#define RT1305_DAC_OFFSET_8 0x9a
#define RT1305_DAC_OFFSET_9 0x9b
#define RT1305_DAC_OFFSET_10 0x9c
#define RT1305_DAC_OFFSET_11 0x9d
#define RT1305_DAC_OFFSET_12 0x9e
#define RT1305_DAC_OFFSET_13 0x9f
#define RT1305_DAC_OFFSET_14 0xa0
#define RT1305_TRIM_1 0xb0
#define RT1305_TRIM_2 0xb1
#define RT1305_TUNE_INTERNAL_OSC 0xb2
#define RT1305_BIQUAD1_H0_L_28_16 0xc0
#define RT1305_BIQUAD3_A2_R_15_0 0xfb
#define RT1305_MAX_REG 0xff
/* CLOCK-1 (0x04) */
#define RT1305_SEL_PLL_SRC_2_MASK (0x1 << 15)
#define RT1305_SEL_PLL_SRC_2_SFT 15
#define RT1305_SEL_PLL_SRC_2_MCLK (0x0 << 15)
#define RT1305_SEL_PLL_SRC_2_RCCLK (0x1 << 15)
#define RT1305_DIV_PLL_SRC_2_MASK (0x3 << 13)
#define RT1305_DIV_PLL_SRC_2_SFT 13
#define RT1305_SEL_PLL_SRC_1_MASK (0x3 << 10)
#define RT1305_SEL_PLL_SRC_1_SFT 10
#define RT1305_SEL_PLL_SRC_1_PLL2 (0x0 << 10)
#define RT1305_SEL_PLL_SRC_1_BCLK (0x1 << 10)
#define RT1305_SEL_PLL_SRC_1_DFLL (0x2 << 10)
#define RT1305_SEL_FS_SYS_PRE_MASK (0x3 << 8)
#define RT1305_SEL_FS_SYS_PRE_SFT 8
#define RT1305_SEL_FS_SYS_PRE_MCLK (0x0 << 8)
#define RT1305_SEL_FS_SYS_PRE_PLL (0x1 << 8)
#define RT1305_SEL_FS_SYS_PRE_RCCLK (0x2 << 8)
#define RT1305_DIV_FS_SYS_MASK (0x7 << 4)
#define RT1305_DIV_FS_SYS_SFT 4
/* PLL1M/N/K Code-1 (0x0c) */
#define RT1305_PLL_1_M_SFT 12
#define RT1305_PLL_1_M_BYPASS_MASK (0x1 << 11)
#define RT1305_PLL_1_M_BYPASS_SFT 11
#define RT1305_PLL_1_M_BYPASS (0x1 << 11)
#define RT1305_PLL_1_N_MASK (0x1ff << 0)
/* DAC Setting (0x14) */
#define RT1305_DVOL_MUTE_L_EN_SFT 15
#define RT1305_DVOL_MUTE_R_EN_SFT 14
/* I2S Setting-1 (0x2d) */
#define RT1305_SEL_I2S_OUT_MODE_MASK (0x1 << 15)
#define RT1305_SEL_I2S_OUT_MODE_SFT 15
#define RT1305_SEL_I2S_OUT_MODE_S (0x0 << 15)
#define RT1305_SEL_I2S_OUT_MODE_M (0x1 << 15)
/* I2S Setting-2 (0x2e) */
#define RT1305_I2S_DF_SEL_MASK (0x3 << 12)
#define RT1305_I2S_DF_SEL_SFT 12
#define RT1305_I2S_DF_SEL_I2S (0x0 << 12)
#define RT1305_I2S_DF_SEL_LEFT (0x1 << 12)
#define RT1305_I2S_DF_SEL_PCM_A (0x2 << 12)
#define RT1305_I2S_DF_SEL_PCM_B (0x3 << 12)
#define RT1305_I2S_DL_SEL_MASK (0x3 << 10)
#define RT1305_I2S_DL_SEL_SFT 10
#define RT1305_I2S_DL_SEL_16B (0x0 << 10)
#define RT1305_I2S_DL_SEL_20B (0x1 << 10)
#define RT1305_I2S_DL_SEL_24B (0x2 << 10)
#define RT1305_I2S_DL_SEL_8B (0x3 << 10)
#define RT1305_I2S_BCLK_MASK (0x1 << 9)
#define RT1305_I2S_BCLK_SFT 9
#define RT1305_I2S_BCLK_NORMAL (0x0 << 9)
#define RT1305_I2S_BCLK_INV (0x1 << 9)
/* Power Control-1 (0x3a) */
#define RT1305_POW_PDB_JD_MASK (0x1 << 12)
#define RT1305_POW_PDB_JD (0x1 << 12)
#define RT1305_POW_PDB_JD_BIT 12
#define RT1305_POW_PLL0_EN (0x1 << 11)
#define RT1305_POW_PLL0_EN_BIT 11
#define RT1305_POW_PLL1_EN (0x1 << 10)
#define RT1305_POW_PLL1_EN_BIT 10
#define RT1305_POW_PDB_JD_POLARITY (0x1 << 9)
#define RT1305_POW_PDB_JD_POLARITY_BIT 9
#define RT1305_POW_MBIAS_LV (0x1 << 8)
#define RT1305_POW_MBIAS_LV_BIT 8
#define RT1305_POW_BG_MBIAS_LV (0x1 << 7)
#define RT1305_POW_BG_MBIAS_LV_BIT 7
#define RT1305_POW_LDO2 (0x1 << 6)
#define RT1305_POW_LDO2_BIT 6
#define RT1305_POW_BG2 (0x1 << 5)
#define RT1305_POW_BG2_BIT 5
#define RT1305_POW_LDO2_IB2 (0x1 << 4)
#define RT1305_POW_LDO2_IB2_BIT 4
#define RT1305_POW_VREF (0x1 << 3)
#define RT1305_POW_VREF_BIT 3
#define RT1305_POW_VREF1 (0x1 << 2)
#define RT1305_POW_VREF1_BIT 2
#define RT1305_POW_VREF2 (0x1 << 1)
#define RT1305_POW_VREF2_BIT 1
/* Power Control-2 (0x3b) */
#define RT1305_POW_DISC_VREF (1 << 15)
#define RT1305_POW_DISC_VREF_BIT 15
#define RT1305_POW_FASTB_VREF (1 << 14)
#define RT1305_POW_FASTB_VREF_BIT 14
#define RT1305_POW_ULTRA_FAST_VREF (1 << 13)
#define RT1305_POW_ULTRA_FAST_VREF_BIT 13
#define RT1305_POW_CKXEN_DAC (1 << 12)
#define RT1305_POW_CKXEN_DAC_BIT 12
#define RT1305_POW_EN_CKGEN_DAC (1 << 11)
#define RT1305_POW_EN_CKGEN_DAC_BIT 11
#define RT1305_POW_DAC1_L (1 << 10)
#define RT1305_POW_DAC1_L_BIT 10
#define RT1305_POW_DAC1_R (1 << 9)
#define RT1305_POW_DAC1_R_BIT 9
#define RT1305_POW_CLAMP (1 << 8)
#define RT1305_POW_CLAMP_BIT 8
#define RT1305_POW_BUFL (1 << 7)
#define RT1305_POW_BUFL_BIT 7
#define RT1305_POW_BUFR (1 << 6)
#define RT1305_POW_BUFR_BIT 6
#define RT1305_POW_EN_CKGEN_ADC (1 << 5)
#define RT1305_POW_EN_CKGEN_ADC_BIT 5
#define RT1305_POW_ADC3_L (1 << 4)
#define RT1305_POW_ADC3_L_BIT 4
#define RT1305_POW_ADC3_R (1 << 3)
#define RT1305_POW_ADC3_R_BIT 3
#define RT1305_POW_TRIOSC (1 << 2)
#define RT1305_POW_TRIOSC_BIT 2
#define RT1305_POR_AVDD1 (1 << 1)
#define RT1305_POR_AVDD1_BIT 1
#define RT1305_POR_AVDD2 (1 << 0)
#define RT1305_POR_AVDD2_BIT 0
/* Power Control-3 (0x3c) */
#define RT1305_POW_VSENSE_RCH (1 << 15)
#define RT1305_POW_VSENSE_RCH_BIT 15
#define RT1305_POW_VSENSE_LCH (1 << 14)
#define RT1305_POW_VSENSE_LCH_BIT 14
#define RT1305_POW_ISENSE_RCH (1 << 13)
#define RT1305_POW_ISENSE_RCH_BIT 13
#define RT1305_POW_ISENSE_LCH (1 << 12)
#define RT1305_POW_ISENSE_LCH_BIT 12
#define RT1305_POW_POR_AVDD1 (1 << 11)
#define RT1305_POW_POR_AVDD1_BIT 11
#define RT1305_POW_POR_AVDD2 (1 << 10)
#define RT1305_POW_POR_AVDD2_BIT 10
#define RT1305_EN_K_HV (1 << 9)
#define RT1305_EN_K_HV_BIT 9
#define RT1305_EN_PRE_K_HV (1 << 8)
#define RT1305_EN_PRE_K_HV_BIT 8
#define RT1305_EN_EFUSE_1P8V (1 << 7)
#define RT1305_EN_EFUSE_1P8V_BIT 7
#define RT1305_EN_EFUSE_5V (1 << 6)
#define RT1305_EN_EFUSE_5V_BIT 6
#define RT1305_EN_VCM_6172 (1 << 5)
#define RT1305_EN_VCM_6172_BIT 5
#define RT1305_POR_EFUSE (1 << 4)
#define RT1305_POR_EFUSE_BIT 4
/* Clock Detect (0x3f) */
#define RT1305_SEL_CLK_DET_SRC_MASK (0x1 << 12)
#define RT1305_SEL_CLK_DET_SRC_SFT 12
#define RT1305_SEL_CLK_DET_SRC_MCLK (0x0 << 12)
#define RT1305_SEL_CLK_DET_SRC_BCLK (0x1 << 12)
/* System Clock Source */
enum {
RT1305_FS_SYS_PRE_S_MCLK,
RT1305_FS_SYS_PRE_S_PLL1,
RT1305_FS_SYS_PRE_S_RCCLK, /* 98.304M Hz */
};
/* PLL Source 1/2 */
enum {
RT1305_PLL1_S_BCLK,
RT1305_PLL2_S_MCLK,
RT1305_PLL2_S_RCCLK, /* 98.304M Hz */
};
enum {
RT1305_AIF1,
RT1305_AIFS
};
#define R0_UPPER 0x2E8BA2 //5.5 ohm
#define R0_LOWER 0x666666 //2.5 ohm
#endif /* end of _RT1305_H_ */

View File

@@ -24,6 +24,7 @@
#include <linux/spi/spi.h>
#include <linux/acpi.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -476,20 +477,6 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
return idx;
}
static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
unsigned int val;
val = snd_soc_component_read32(component, RT5640_GLB_CLK);
val &= RT5640_SCLK_SRC_MASK;
if (val == RT5640_SCLK_SRC_PLL1)
return 1;
else
return 0;
}
static int is_using_asrc(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
@@ -1071,9 +1058,6 @@ 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),
@@ -1427,22 +1411,18 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"Stereo ADC MIXL", "ADC1 Switch", "Stereo ADC L1 Mux"},
{"Stereo ADC MIXL", "ADC2 Switch", "Stereo ADC L2 Mux"},
{"Stereo ADC MIXL", NULL, "Stereo Filter"},
{"Stereo Filter", NULL, "PLL1", is_sys_clk_from_pll},
{"Stereo ADC MIXR", "ADC1 Switch", "Stereo ADC R1 Mux"},
{"Stereo ADC MIXR", "ADC2 Switch", "Stereo ADC R2 Mux"},
{"Stereo ADC MIXR", NULL, "Stereo Filter"},
{"Stereo Filter", NULL, "PLL1", is_sys_clk_from_pll},
{"Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux"},
{"Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux"},
{"Mono ADC MIXL", NULL, "Mono Left Filter"},
{"Mono Left Filter", NULL, "PLL1", is_sys_clk_from_pll},
{"Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux"},
{"Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux"},
{"Mono ADC MIXR", NULL, "Mono Right Filter"},
{"Mono Right Filter", NULL, "PLL1", is_sys_clk_from_pll},
{"IF2 ADC L", NULL, "Mono ADC MIXL"},
{"IF2 ADC R", NULL, "Mono ADC MIXR"},
@@ -1512,10 +1492,8 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"DIG MIXR", "DAC R1 Switch", "DAC MIXR"},
{"DAC L1", NULL, "Stereo DAC MIXL"},
{"DAC L1", NULL, "PLL1", is_sys_clk_from_pll},
{"DAC L1", NULL, "DAC L1 Power"},
{"DAC R1", NULL, "Stereo DAC MIXR"},
{"DAC R1", NULL, "PLL1", is_sys_clk_from_pll},
{"DAC R1", NULL, "DAC R1 Power"},
{"SPK MIXL", "REC MIXL Switch", "RECMIXL"},
@@ -1622,10 +1600,8 @@ static const struct snd_soc_dapm_route rt5640_specific_dapm_routes[] = {
{"DIG MIXL", "DAC L2 Switch", "DAC L2 Mux"},
{"DAC L2", NULL, "Mono DAC MIXL"},
{"DAC L2", NULL, "PLL1", is_sys_clk_from_pll},
{"DAC L2", NULL, "DAC L2 Power"},
{"DAC R2", NULL, "Mono DAC MIXR"},
{"DAC R2", NULL, "PLL1", is_sys_clk_from_pll},
{"DAC R2", NULL, "DAC R2 Power"},
{"SPK MIXL", "DAC L2 Switch", "DAC L2"},
@@ -1861,6 +1837,7 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
struct snd_soc_component *component = dai->component;
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
unsigned int reg_val = 0;
unsigned int pll_bit = 0;
if (freq == rt5640->sysclk && clk_id == rt5640->sysclk_src)
return 0;
@@ -1871,6 +1848,7 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
break;
case RT5640_SCLK_S_PLL1:
reg_val |= RT5640_SCLK_SRC_PLL1;
pll_bit |= RT5640_PWR_PLL;
break;
case RT5640_SCLK_S_RCCLK:
reg_val |= RT5640_SCLK_SRC_RCCLK;
@@ -1879,6 +1857,8 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
return -EINVAL;
}
snd_soc_component_update_bits(component, RT5640_PWR_ANLG2,
RT5640_PWR_PLL, pll_bit);
snd_soc_component_update_bits(component, RT5640_GLB_CLK,
RT5640_SCLK_SRC_MASK, reg_val);
rt5640->sysclk = freq;
@@ -2114,10 +2094,376 @@ int rt5640_sel_asrc_clk_src(struct snd_soc_component *component,
}
EXPORT_SYMBOL_GPL(rt5640_sel_asrc_clk_src);
static void rt5640_enable_micbias1_for_ovcd(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
snd_soc_dapm_mutex_lock(dapm);
snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO2");
snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS1");
/* OVCD is unreliable when used with RCCLK as sysclk-source */
snd_soc_dapm_force_enable_pin_unlocked(dapm, "Platform Clock");
snd_soc_dapm_sync_unlocked(dapm);
snd_soc_dapm_mutex_unlock(dapm);
}
static void rt5640_disable_micbias1_for_ovcd(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
snd_soc_dapm_mutex_lock(dapm);
snd_soc_dapm_disable_pin_unlocked(dapm, "Platform Clock");
snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS1");
snd_soc_dapm_disable_pin_unlocked(dapm, "LDO2");
snd_soc_dapm_sync_unlocked(dapm);
snd_soc_dapm_mutex_unlock(dapm);
}
static void rt5640_enable_micbias1_ovcd_irq(struct snd_soc_component *component)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2,
RT5640_IRQ_MB1_OC_MASK, RT5640_IRQ_MB1_OC_NOR);
rt5640->ovcd_irq_enabled = true;
}
static void rt5640_disable_micbias1_ovcd_irq(struct snd_soc_component *component)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2,
RT5640_IRQ_MB1_OC_MASK, RT5640_IRQ_MB1_OC_BP);
rt5640->ovcd_irq_enabled = false;
}
static void rt5640_clear_micbias1_ovcd(struct snd_soc_component *component)
{
snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2,
RT5640_MB1_OC_STATUS, 0);
}
static bool rt5640_micbias1_ovcd(struct snd_soc_component *component)
{
int val;
val = snd_soc_component_read32(component, RT5640_IRQ_CTRL2);
dev_dbg(component->dev, "irq ctrl2 %#04x\n", val);
return (val & RT5640_MB1_OC_STATUS);
}
static bool rt5640_jack_inserted(struct snd_soc_component *component)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
int val;
val = snd_soc_component_read32(component, RT5640_INT_IRQ_ST);
dev_dbg(component->dev, "irq status %#04x\n", val);
if (rt5640->jd_inverted)
return !(val & RT5640_JD_STATUS);
else
return (val & RT5640_JD_STATUS);
}
/* Jack detect and button-press timings */
#define JACK_SETTLE_TIME 100 /* milli seconds */
#define JACK_DETECT_COUNT 5
#define JACK_DETECT_MAXCOUNT 20 /* Aprox. 2 seconds worth of tries */
#define JACK_UNPLUG_TIME 80 /* milli seconds */
#define BP_POLL_TIME 10 /* milli seconds */
#define BP_POLL_MAXCOUNT 200 /* assume something is wrong after this */
#define BP_THRESHOLD 3
static void rt5640_start_button_press_work(struct snd_soc_component *component)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
rt5640->poll_count = 0;
rt5640->press_count = 0;
rt5640->release_count = 0;
rt5640->pressed = false;
rt5640->press_reported = false;
rt5640_clear_micbias1_ovcd(component);
schedule_delayed_work(&rt5640->bp_work, msecs_to_jiffies(BP_POLL_TIME));
}
static void rt5640_button_press_work(struct work_struct *work)
{
struct rt5640_priv *rt5640 =
container_of(work, struct rt5640_priv, bp_work.work);
struct snd_soc_component *component = rt5640->component;
/* Check the jack was not removed underneath us */
if (!rt5640_jack_inserted(component))
return;
if (rt5640_micbias1_ovcd(component)) {
rt5640->release_count = 0;
rt5640->press_count++;
/* Remember till after JACK_UNPLUG_TIME wait */
if (rt5640->press_count >= BP_THRESHOLD)
rt5640->pressed = true;
rt5640_clear_micbias1_ovcd(component);
} else {
rt5640->press_count = 0;
rt5640->release_count++;
}
/*
* The pins get temporarily shorted on jack unplug, so we poll for
* at least JACK_UNPLUG_TIME milli-seconds before reporting a press.
*/
rt5640->poll_count++;
if (rt5640->poll_count < (JACK_UNPLUG_TIME / BP_POLL_TIME)) {
schedule_delayed_work(&rt5640->bp_work,
msecs_to_jiffies(BP_POLL_TIME));
return;
}
if (rt5640->pressed && !rt5640->press_reported) {
dev_dbg(component->dev, "headset button press\n");
snd_soc_jack_report(rt5640->jack, SND_JACK_BTN_0,
SND_JACK_BTN_0);
rt5640->press_reported = true;
}
if (rt5640->release_count >= BP_THRESHOLD) {
if (rt5640->press_reported) {
dev_dbg(component->dev, "headset button release\n");
snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0);
}
/* Re-enable OVCD IRQ to detect next press */
rt5640_enable_micbias1_ovcd_irq(component);
return; /* Stop polling */
}
schedule_delayed_work(&rt5640->bp_work, msecs_to_jiffies(BP_POLL_TIME));
}
static int rt5640_detect_headset(struct snd_soc_component *component)
{
int i, headset_count = 0, headphone_count = 0;
/*
* We get the insertion event before the jack is fully inserted at which
* point the second ring on a TRRS connector may short the 2nd ring and
* sleeve contacts, also the overcurrent detection is not entirely
* reliable. So we try several times with a wait in between until we
* detect the same type JACK_DETECT_COUNT times in a row.
*/
for (i = 0; i < JACK_DETECT_MAXCOUNT; i++) {
/* Clear any previous over-current status flag */
rt5640_clear_micbias1_ovcd(component);
msleep(JACK_SETTLE_TIME);
/* Check the jack is still connected before checking ovcd */
if (!rt5640_jack_inserted(component))
return 0;
if (rt5640_micbias1_ovcd(component)) {
/*
* Over current detected, there is a short between the
* 2nd ring contact and the ground, so a TRS connector
* without a mic contact and thus plain headphones.
*/
dev_dbg(component->dev, "jack mic-gnd shorted\n");
headset_count = 0;
headphone_count++;
if (headphone_count == JACK_DETECT_COUNT)
return SND_JACK_HEADPHONE;
} else {
dev_dbg(component->dev, "jack mic-gnd open\n");
headphone_count = 0;
headset_count++;
if (headset_count == JACK_DETECT_COUNT)
return SND_JACK_HEADSET;
}
}
dev_err(component->dev, "Error detecting headset vs headphones, bad contact?, assuming headphones\n");
return SND_JACK_HEADPHONE;
}
static void rt5640_jack_work(struct work_struct *work)
{
struct rt5640_priv *rt5640 =
container_of(work, struct rt5640_priv, jack_work);
struct snd_soc_component *component = rt5640->component;
int status;
if (!rt5640_jack_inserted(component)) {
/* Jack removed, or spurious IRQ? */
if (rt5640->jack->status & SND_JACK_HEADPHONE) {
if (rt5640->jack->status & SND_JACK_MICROPHONE) {
cancel_delayed_work_sync(&rt5640->bp_work);
rt5640_disable_micbias1_ovcd_irq(component);
rt5640_disable_micbias1_for_ovcd(component);
}
snd_soc_jack_report(rt5640->jack, 0,
SND_JACK_HEADSET | SND_JACK_BTN_0);
dev_dbg(component->dev, "jack unplugged\n");
}
} else if (!(rt5640->jack->status & SND_JACK_HEADPHONE)) {
/* Jack inserted */
WARN_ON(rt5640->ovcd_irq_enabled);
rt5640_enable_micbias1_for_ovcd(component);
status = rt5640_detect_headset(component);
if (status == SND_JACK_HEADSET) {
/* Enable ovcd IRQ for button press detect. */
rt5640_enable_micbias1_ovcd_irq(component);
} else {
/* No more need for overcurrent detect. */
rt5640_disable_micbias1_for_ovcd(component);
}
dev_dbg(component->dev, "detect status %#02x\n", status);
snd_soc_jack_report(rt5640->jack, status, SND_JACK_HEADSET);
} else if (rt5640->ovcd_irq_enabled && rt5640_micbias1_ovcd(component)) {
dev_dbg(component->dev, "OVCD IRQ\n");
/*
* The ovcd IRQ keeps firing while the button is pressed, so
* we disable it and start polling the button until released.
*
* The disable will make the IRQ pin 0 again and since we get
* IRQs on both edges (so as to detect both jack plugin and
* unplug) this means we will immediately get another IRQ.
* The ovcd_irq_enabled check above makes the 2ND IRQ a NOP.
*/
rt5640_disable_micbias1_ovcd_irq(component);
rt5640_start_button_press_work(component);
/*
* If the jack-detect IRQ flag goes high (unplug) after our
* above rt5640_jack_inserted() check and before we have
* disabled the OVCD IRQ, the IRQ pin will stay high and as
* we react to edges, we miss the unplug event -> recheck.
*/
queue_work(system_long_wq, &rt5640->jack_work);
}
}
static irqreturn_t rt5640_irq(int irq, void *data)
{
struct rt5640_priv *rt5640 = data;
if (rt5640->jack)
queue_work(system_long_wq, &rt5640->jack_work);
return IRQ_HANDLED;
}
static void rt5640_cancel_work(void *data)
{
struct rt5640_priv *rt5640 = data;
cancel_work_sync(&rt5640->jack_work);
cancel_delayed_work_sync(&rt5640->bp_work);
}
static void rt5640_enable_jack_detect(struct snd_soc_component *component,
struct snd_soc_jack *jack)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
/* Select JD-source */
snd_soc_component_update_bits(component, RT5640_JD_CTRL,
RT5640_JD_MASK, rt5640->jd_src);
/* Selecting GPIO01 as an interrupt */
snd_soc_component_update_bits(component, RT5640_GPIO_CTRL1,
RT5640_GP1_PIN_MASK, RT5640_GP1_PIN_IRQ);
/* Set GPIO1 output */
snd_soc_component_update_bits(component, RT5640_GPIO_CTRL3,
RT5640_GP1_PF_MASK, RT5640_GP1_PF_OUT);
/* Enabling jd2 in general control 1 */
snd_soc_component_write(component, RT5640_DUMMY1, 0x3f41);
/* Enabling jd2 in general control 2 */
snd_soc_component_write(component, RT5640_DUMMY2, 0x4001);
snd_soc_component_write(component, RT5640_PR_BASE + RT5640_BIAS_CUR4,
0xa800 | rt5640->ovcd_sf);
snd_soc_component_update_bits(component, RT5640_MICBIAS,
RT5640_MIC1_OVTH_MASK | RT5640_MIC1_OVCD_MASK,
rt5640->ovcd_th | RT5640_MIC1_OVCD_EN);
/*
* The over-current-detect is only reliable in detecting the absence
* of over-current, when the mic-contact in the jack is short-circuited,
* the hardware periodically retries if it can apply the bias-current
* leading to the ovcd status flip-flopping 1-0-1 with it being 0 about
* 10% of the time, as we poll the ovcd status bit we might hit that
* 10%, so we enable sticky mode and when checking OVCD we clear the
* status, msleep() a bit and then check to get a reliable reading.
*/
snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2,
RT5640_MB1_OC_STKY_MASK, RT5640_MB1_OC_STKY_EN);
/*
* All IRQs get or-ed together, so we need the jack IRQ to report 0
* when a jack is inserted so that the OVCD IRQ then toggles the IRQ
* pin 0/1 instead of it being stuck to 1. So we invert the JD polarity
* on systems where the hardware does not already do this.
*/
if (rt5640->jd_inverted)
snd_soc_component_write(component, RT5640_IRQ_CTRL1,
RT5640_IRQ_JD_NOR);
else
snd_soc_component_write(component, RT5640_IRQ_CTRL1,
RT5640_IRQ_JD_NOR | RT5640_JD_P_INV);
rt5640->jack = jack;
if (rt5640->jack->status & SND_JACK_MICROPHONE) {
rt5640_enable_micbias1_for_ovcd(component);
rt5640_enable_micbias1_ovcd_irq(component);
}
enable_irq(rt5640->irq);
/* sync initial jack state */
queue_work(system_long_wq, &rt5640->jack_work);
}
static void rt5640_disable_jack_detect(struct snd_soc_component *component)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
disable_irq(rt5640->irq);
rt5640_cancel_work(rt5640);
if (rt5640->jack->status & SND_JACK_MICROPHONE) {
rt5640_disable_micbias1_ovcd_irq(component);
rt5640_disable_micbias1_for_ovcd(component);
snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0);
}
rt5640->jack = NULL;
}
static int rt5640_set_jack(struct snd_soc_component *component,
struct snd_soc_jack *jack, void *data)
{
if (jack)
rt5640_enable_jack_detect(component, jack);
else
rt5640_disable_jack_detect(component);
return 0;
}
static int rt5640_probe(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
u32 dmic1_data_pin = 0;
u32 dmic2_data_pin = 0;
bool dmic_en = false;
u32 val;
/* Check if MCLK provided */
rt5640->mclk = devm_clk_get(component->dev, "mclk");
@@ -2159,9 +2505,86 @@ static int rt5640_probe(struct snd_soc_component *component)
return -ENODEV;
}
if (rt5640->pdata.dmic_en)
rt5640_dmic_enable(component, rt5640->pdata.dmic1_data_pin,
rt5640->pdata.dmic2_data_pin);
/*
* Note on some platforms the platform code may need to add device-props
* rather then relying only on properties set by the firmware.
* Therefor the property parsing MUST be done here, rather then from
* rt5640_i2c_probe(), so that the platform-code can attach extra
* properties before calling snd_soc_register_card().
*/
if (device_property_read_bool(component->dev, "realtek,in1-differential"))
snd_soc_component_update_bits(component, RT5640_IN1_IN2,
RT5640_IN_DF1, RT5640_IN_DF1);
if (device_property_read_bool(component->dev, "realtek,in2-differential"))
snd_soc_component_update_bits(component, RT5640_IN3_IN4,
RT5640_IN_DF2, RT5640_IN_DF2);
if (device_property_read_bool(component->dev, "realtek,in3-differential"))
snd_soc_component_update_bits(component, RT5640_IN1_IN2,
RT5640_IN_DF2, RT5640_IN_DF2);
if (device_property_read_u32(component->dev, "realtek,dmic1-data-pin",
&val) == 0 && val) {
dmic1_data_pin = val - 1;
dmic_en = true;
}
if (device_property_read_u32(component->dev, "realtek,dmic2-data-pin",
&val) == 0 && val) {
dmic2_data_pin = val - 1;
dmic_en = true;
}
if (dmic_en)
rt5640_dmic_enable(component, dmic1_data_pin, dmic2_data_pin);
if (device_property_read_u32(component->dev,
"realtek,jack-detect-source", &val) == 0) {
if (val <= RT5640_JD_SRC_GPIO4)
rt5640->jd_src = val << RT5640_JD_SFT;
else
dev_warn(component->dev, "Warning: Invalid jack-detect-source value: %d, leaving jack-detect disabled\n",
val);
}
if (!device_property_read_bool(component->dev, "realtek,jack-detect-not-inverted"))
rt5640->jd_inverted = true;
/*
* Testing on various boards has shown that good defaults for the OVCD
* threshold and scale-factor are 2000µA and 0.75. For an effective
* limit of 1500µA, this seems to be more reliable then 1500µA and 1.0.
*/
rt5640->ovcd_th = RT5640_MIC1_OVTH_2000UA;
rt5640->ovcd_sf = RT5640_MIC_OVCD_SF_0P75;
if (device_property_read_u32(component->dev,
"realtek,over-current-threshold-microamp", &val) == 0) {
switch (val) {
case 600:
rt5640->ovcd_th = RT5640_MIC1_OVTH_600UA;
break;
case 1500:
rt5640->ovcd_th = RT5640_MIC1_OVTH_1500UA;
break;
case 2000:
rt5640->ovcd_th = RT5640_MIC1_OVTH_2000UA;
break;
default:
dev_warn(component->dev, "Warning: Invalid over-current-threshold-microamp value: %d, defaulting to 2000uA\n",
val);
}
}
if (device_property_read_u32(component->dev,
"realtek,over-current-scale-factor", &val) == 0) {
if (val <= RT5640_OVCD_SF_1P5)
rt5640->ovcd_sf = val << RT5640_MIC_OVCD_SF_SFT;
else
dev_warn(component->dev, "Warning: Invalid over-current-scale-factor value: %d, defaulting to 0.75\n",
val);
}
return 0;
}
@@ -2180,8 +2603,8 @@ static int rt5640_suspend(struct snd_soc_component *component)
rt5640_reset(component);
regcache_cache_only(rt5640->regmap, true);
regcache_mark_dirty(rt5640->regmap);
if (gpio_is_valid(rt5640->pdata.ldo1_en))
gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 0);
if (gpio_is_valid(rt5640->ldo1_en))
gpio_set_value_cansleep(rt5640->ldo1_en, 0);
return 0;
}
@@ -2190,8 +2613,8 @@ static int rt5640_resume(struct snd_soc_component *component)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
if (gpio_is_valid(rt5640->pdata.ldo1_en)) {
gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 1);
if (gpio_is_valid(rt5640->ldo1_en)) {
gpio_set_value_cansleep(rt5640->ldo1_en, 1);
msleep(400);
}
@@ -2263,6 +2686,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt5640 = {
.suspend = rt5640_suspend,
.resume = rt5640_resume,
.set_bias_level = rt5640_set_bias_level,
.set_jack = rt5640_set_jack,
.controls = rt5640_snd_controls,
.num_controls = ARRAY_SIZE(rt5640_snd_controls),
.dapm_widgets = rt5640_dapm_widgets,
@@ -2323,22 +2747,16 @@ MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);
static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np)
{
rt5640->pdata.in1_diff = of_property_read_bool(np,
"realtek,in1-differential");
rt5640->pdata.in2_diff = of_property_read_bool(np,
"realtek,in2-differential");
rt5640->pdata.ldo1_en = of_get_named_gpio(np,
"realtek,ldo1-en-gpios", 0);
rt5640->ldo1_en = of_get_named_gpio(np, "realtek,ldo1-en-gpios", 0);
/*
* LDO1_EN is optional (it may be statically tied on the board).
* -ENOENT means that the property doesn't exist, i.e. there is no
* GPIO, so is not an error. Any other error code means the property
* exists, but could not be parsed.
*/
if (!gpio_is_valid(rt5640->pdata.ldo1_en) &&
(rt5640->pdata.ldo1_en != -ENOENT))
return rt5640->pdata.ldo1_en;
if (!gpio_is_valid(rt5640->ldo1_en) &&
(rt5640->ldo1_en != -ENOENT))
return rt5640->ldo1_en;
return 0;
}
@@ -2346,7 +2764,6 @@ static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np)
static int rt5640_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct rt5640_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct rt5640_priv *rt5640;
int ret;
unsigned int val;
@@ -2358,22 +2775,12 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
return -ENOMEM;
i2c_set_clientdata(i2c, rt5640);
if (pdata) {
rt5640->pdata = *pdata;
/*
* Translate zero'd out (default) pdata value to an invalid
* GPIO ID. This makes the pdata and DT paths consistent in
* terms of the value left in this field when no GPIO is
* specified, but means we can't actually use GPIO 0.
*/
if (!rt5640->pdata.ldo1_en)
rt5640->pdata.ldo1_en = -EINVAL;
} else if (i2c->dev.of_node) {
if (i2c->dev.of_node) {
ret = rt5640_parse_dt(rt5640, i2c->dev.of_node);
if (ret)
return ret;
} else
rt5640->pdata.ldo1_en = -EINVAL;
rt5640->ldo1_en = -EINVAL;
rt5640->regmap = devm_regmap_init_i2c(i2c, &rt5640_regmap);
if (IS_ERR(rt5640->regmap)) {
@@ -2383,13 +2790,13 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
return ret;
}
if (gpio_is_valid(rt5640->pdata.ldo1_en)) {
ret = devm_gpio_request_one(&i2c->dev, rt5640->pdata.ldo1_en,
if (gpio_is_valid(rt5640->ldo1_en)) {
ret = devm_gpio_request_one(&i2c->dev, rt5640->ldo1_en,
GPIOF_OUT_INIT_HIGH,
"RT5640 LDO1_EN");
if (ret < 0) {
dev_err(&i2c->dev, "Failed to request LDO1_EN %d: %d\n",
rt5640->pdata.ldo1_en, ret);
rt5640->ldo1_en, ret);
return ret;
}
msleep(400);
@@ -2412,19 +2819,27 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
regmap_update_bits(rt5640->regmap, RT5640_DUMMY1,
RT5640_MCLK_DET, RT5640_MCLK_DET);
if (rt5640->pdata.in1_diff)
regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2,
RT5640_IN_DF1, RT5640_IN_DF1);
if (rt5640->pdata.in2_diff)
regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4,
RT5640_IN_DF2, RT5640_IN_DF2);
if (rt5640->pdata.in3_diff)
regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2,
RT5640_IN_DF2, RT5640_IN_DF2);
rt5640->hp_mute = 1;
rt5640->irq = i2c->irq;
INIT_DELAYED_WORK(&rt5640->bp_work, rt5640_button_press_work);
INIT_WORK(&rt5640->jack_work, rt5640_jack_work);
/* Make sure work is stopped on probe-error / remove */
ret = devm_add_action_or_reset(&i2c->dev, rt5640_cancel_work, rt5640);
if (ret)
return ret;
ret = devm_request_irq(&i2c->dev, rt5640->irq, rt5640_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
| IRQF_ONESHOT, "rt5640", rt5640);
if (ret == 0) {
/* Gets re-enabled by rt5640_set_jack() */
disable_irq(rt5640->irq);
} else {
dev_warn(&i2c->dev, "Failed to reguest IRQ %d: %d\n",
rt5640->irq, ret);
rt5640->irq = -ENXIO;
}
return devm_snd_soc_register_component(&i2c->dev,
&soc_component_dev_rt5640,

View File

@@ -13,7 +13,8 @@
#define _RT5640_H
#include <linux/clk.h>
#include <sound/rt5640.h>
#include <linux/workqueue.h>
#include <dt-bindings/sound/rt5640.h>
/* Info */
#define RT5640_RESET 0x00
@@ -146,6 +147,7 @@
/* Index of Codec Private Register definition */
#define RT5640_BIAS_CUR4 0x15
#define RT5640_CHPUMP_INT_REG1 0x24
#define RT5640_MAMP_INT_REG2 0x37
#define RT5640_3D_SPK 0x63
@@ -1607,10 +1609,17 @@
#define RT5640_MB2_OC_P_SFT 6
#define RT5640_MB2_OC_P_NOR (0x0 << 6)
#define RT5640_MB2_OC_P_INV (0x1 << 6)
#define RT5640_MB1_OC_CLR (0x1 << 3)
#define RT5640_MB1_OC_CLR_SFT 3
#define RT5640_MB2_OC_CLR (0x1 << 2)
#define RT5640_MB2_OC_CLR_SFT 2
#define RT5640_MB1_OC_STATUS (0x1 << 3)
#define RT5640_MB1_OC_STATUS_SFT 3
#define RT5640_MB2_OC_STATUS (0x1 << 2)
#define RT5640_MB2_OC_STATUS_SFT 2
/* GPIO and Internal Status (0xbf) */
#define RT5640_GPIO1_STATUS (0x1 << 8)
#define RT5640_GPIO2_STATUS (0x1 << 7)
#define RT5640_JD_STATUS (0x1 << 4)
#define RT5640_OVT_STATUS (0x1 << 3)
#define RT5640_CLS_D_OVCD_STATUS (0x1 << 0)
/* GPIO Control 1 (0xc0) */
#define RT5640_GP1_PIN_MASK (0x1 << 15)
@@ -1978,6 +1987,15 @@
#define RT5640_MCLK_DET (0x1 << 11)
/* Codec Private Register definition */
/* MIC Over current threshold scale factor (0x15) */
#define RT5640_MIC_OVCD_SF_MASK (0x3 << 8)
#define RT5640_MIC_OVCD_SF_SFT 8
#define RT5640_MIC_OVCD_SF_0P5 (0x0 << 8)
#define RT5640_MIC_OVCD_SF_0P75 (0x1 << 8)
#define RT5640_MIC_OVCD_SF_1P0 (0x2 << 8)
#define RT5640_MIC_OVCD_SF_1P5 (0x3 << 8)
/* 3D Speaker Control (0x63) */
#define RT5640_3D_SPK_MASK (0x1 << 15)
#define RT5640_3D_SPK_SFT 15
@@ -2103,10 +2121,11 @@ enum {
struct rt5640_priv {
struct snd_soc_component *component;
struct rt5640_platform_data pdata;
struct regmap *regmap;
struct clk *mclk;
int ldo1_en; /* GPIO for LDO1_EN */
int irq;
int sysclk;
int sysclk_src;
int lrck[RT5640_AIFS];
@@ -2119,6 +2138,21 @@ struct rt5640_priv {
bool hp_mute;
bool asrc_en;
/* Jack and button detect data */
bool ovcd_irq_enabled;
bool pressed;
bool press_reported;
int press_count;
int release_count;
int poll_count;
struct delayed_work bp_work;
struct work_struct jack_work;
struct snd_soc_jack *jack;
unsigned int jd_src;
bool jd_inverted;
unsigned int ovcd_th;
unsigned int ovcd_sf;
};
int rt5640_dmic_enable(struct snd_soc_component *component,

View File

@@ -3652,6 +3652,11 @@ static const struct rt5645_platform_data asus_t100ha_platform_data = {
.inv_jd1_1 = true,
};
static const struct rt5645_platform_data lenovo_ideapad_miix_310_pdata = {
.jd_mode = 3,
.in2_diff = true,
};
static const struct rt5645_platform_data jd_mode3_platform_data = {
.jd_mode = 3,
};
@@ -3735,6 +3740,24 @@ static const struct dmi_system_id dmi_platform_data[] = {
},
.driver_data = (void *)&jd_mode3_platform_data,
},
{
.ident = "Lenovo Ideapad Miix 310",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80SG"),
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "MIIX 310-10ICR"),
},
.driver_data = (void *)&lenovo_ideapad_miix_310_pdata,
},
{
.ident = "Lenovo Ideapad Miix 320",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80XF"),
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"),
},
.driver_data = (void *)&intel_braswell_platform_data,
},
{ }
};

View File

@@ -72,6 +72,8 @@ struct rt5663_priv {
static const struct reg_sequence rt5663_patch_list[] = {
{ 0x002a, 0x8020 },
{ 0x0086, 0x0028 },
{ 0x0117, 0x0f28 },
{ 0x02fb, 0x8089 },
};
static const struct reg_default rt5663_v2_reg[] = {
@@ -593,7 +595,7 @@ static const struct reg_default rt5663_reg[] = {
{ 0x0113, 0x2000 },
{ 0x0114, 0x0000 },
{ 0x0116, 0x0000 },
{ 0x0117, 0x0f00 },
{ 0x0117, 0x0f28 },
{ 0x0118, 0x0006 },
{ 0x0125, 0x2424 },
{ 0x0126, 0x5550 },
@@ -693,7 +695,7 @@ static const struct reg_default rt5663_reg[] = {
{ 0x0251, 0x0000 },
{ 0x0252, 0x028a },
{ 0x02fa, 0x0000 },
{ 0x02fb, 0x00a4 },
{ 0x02fb, 0x8089 },
{ 0x02fc, 0x0300 },
{ 0x0300, 0x0000 },
{ 0x03d0, 0x0000 },
@@ -1556,6 +1558,14 @@ static int rt5663_jack_detect(struct snd_soc_component *component, int jack_inse
RT5663_PWR_MB_MASK | RT5663_LDO1_DVO_MASK |
RT5663_AMP_HP_MASK, RT5663_PWR_MB |
RT5663_LDO1_DVO_0_9V | RT5663_AMP_HP_3X);
snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK |
RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK,
RT5663_PWR_VREF1 | RT5663_PWR_VREF2);
msleep(20);
snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK,
RT5663_PWR_FV1 | RT5663_PWR_FV2);
snd_soc_component_update_bits(component, RT5663_AUTO_1MRC_CLK,
RT5663_IRQ_POW_SAV_MASK, RT5663_IRQ_POW_SAV_EN);
snd_soc_component_update_bits(component, RT5663_IRQ_1,
@@ -1613,7 +1623,10 @@ static int rt5663_jack_detect(struct snd_soc_component *component, int jack_inse
break;
default:
rt5663->jack_type = SND_JACK_HEADPHONE;
snd_soc_component_update_bits(component,
RT5663_PWR_ANLG_1,
RT5663_PWR_MB_MASK | RT5663_PWR_VREF1_MASK |
RT5663_PWR_VREF2_MASK, 0);
if (rt5663->pdata.impedance_sensing_num)
break;
@@ -1638,6 +1651,9 @@ static int rt5663_jack_detect(struct snd_soc_component *component, int jack_inse
if (rt5663->jack_type == SND_JACK_HEADSET)
rt5663_enable_push_button_irq(component, false);
rt5663->jack_type = 0;
snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
RT5663_PWR_MB_MASK | RT5663_PWR_VREF1_MASK |
RT5663_PWR_VREF2_MASK, 0);
}
dev_dbg(component->dev, "jack_type = %d\n", rt5663->jack_type);
@@ -1840,8 +1856,8 @@ static irqreturn_t rt5663_irq(int irq, void *data)
return IRQ_HANDLED;
}
int rt5663_set_jack_detect(struct snd_soc_component *component,
struct snd_soc_jack *hs_jack)
static int rt5663_set_jack_detect(struct snd_soc_component *component,
struct snd_soc_jack *hs_jack, void *data)
{
struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
@@ -1851,7 +1867,6 @@ int rt5663_set_jack_detect(struct snd_soc_component *component,
return 0;
}
EXPORT_SYMBOL_GPL(rt5663_set_jack_detect);
static bool rt5663_check_jd_status(struct snd_soc_component *component)
{
@@ -2307,6 +2322,8 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w,
RT5663_HP_SIG_SRC1_MASK,
RT5663_HP_SIG_SRC1_SILENCE);
} else {
snd_soc_component_update_bits(component,
RT5663_DACREF_LDO, 0x3e0e, 0x3a0a);
snd_soc_component_write(component, RT5663_DEPOP_2, 0x3003);
snd_soc_component_update_bits(component, RT5663_HP_CHARGE_PUMP_1,
RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_DIS);
@@ -2332,6 +2349,8 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w,
snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x3000, 0x0);
snd_soc_component_update_bits(component, RT5663_HP_CHARGE_PUMP_1,
RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_EN);
snd_soc_component_update_bits(component,
RT5663_DACREF_LDO, 0x3e0e, 0);
}
break;
@@ -3086,9 +3105,17 @@ static int rt5663_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_OFF:
snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK |
RT5663_PWR_FV1 | RT5663_PWR_FV2, 0x0);
if (rt5663->jack_type != SND_JACK_HEADSET)
snd_soc_component_update_bits(component,
RT5663_PWR_ANLG_1,
RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK |
RT5663_PWR_FV1 | RT5663_PWR_FV2 |
RT5663_PWR_MB_MASK, 0);
else
snd_soc_component_update_bits(component,
RT5663_PWR_ANLG_1,
RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK,
RT5663_PWR_FV1 | RT5663_PWR_FV2);
break;
default:
@@ -3216,10 +3243,10 @@ static const struct snd_soc_component_driver soc_component_dev_rt5663 = {
.num_dapm_widgets = ARRAY_SIZE(rt5663_dapm_widgets),
.dapm_routes = rt5663_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(rt5663_dapm_routes),
.set_jack = rt5663_set_jack_detect,
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static const struct regmap_config rt5663_v2_regmap = {
@@ -3310,6 +3337,7 @@ static void rt5663_calibrate(struct rt5663_priv *rt5663)
regmap_write(rt5663->regmap, RT5663_HP_IMP_SEN_19, 0x000c);
regmap_write(rt5663->regmap, RT5663_DUMMY_1, 0x0324);
regmap_write(rt5663->regmap, RT5663_DIG_MISC, 0x8001);
regmap_write(rt5663->regmap, RT5663_VREFADJ_OP, 0x0f28);
regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa23b);
msleep(30);
regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf23b);
@@ -3344,6 +3372,7 @@ static void rt5663_calibrate(struct rt5663_priv *rt5663)
regmap_write(rt5663->regmap, RT5663_PWR_ANLG_2, 0x8003);
regmap_write(rt5663->regmap, RT5663_PWR_ANLG_3, 0x018c);
regmap_write(rt5663->regmap, RT5663_HP_CHARGE_PUMP_1, 0x1e32);
regmap_write(rt5663->regmap, RT5663_DUMMY_2, 0x8089);
regmap_write(rt5663->regmap, RT5663_DACREF_LDO, 0x3b0b);
msleep(40);
regmap_write(rt5663->regmap, RT5663_STO_DAC_MIXER, 0x0000);
@@ -3578,15 +3607,9 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
regmap_update_bits(rt5663->regmap, RT5663_GPIO_1,
RT5663_GPIO1_TYPE_MASK, RT5663_GPIO1_TYPE_EN);
regmap_write(rt5663->regmap, RT5663_VREF_RECMIX, 0x0032);
regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa2be);
msleep(20);
regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf2be);
regmap_update_bits(rt5663->regmap, RT5663_GPIO_2,
RT5663_GP1_PIN_CONF_MASK | RT5663_SEL_GPIO1_MASK,
RT5663_GP1_PIN_CONF_OUTPUT | RT5663_SEL_GPIO1_EN);
/* DACREF LDO control */
regmap_update_bits(rt5663->regmap, RT5663_DACREF_LDO, 0x3e0e,
0x3a0a);
regmap_update_bits(rt5663->regmap, RT5663_RECMIX,
RT5663_RECMIX1_BST1_MASK, RT5663_RECMIX1_BST1_ON);
regmap_update_bits(rt5663->regmap, RT5663_TDM_2,

View File

@@ -1125,8 +1125,6 @@ enum {
RT5663_AD_STEREO_FILTER = 0x2,
};
int rt5663_set_jack_detect(struct snd_soc_component *component,
struct snd_soc_jack *hs_jack);
int rt5663_sel_asrc_clk_src(struct snd_soc_component *component,
unsigned int filter_mask, unsigned int clk_src);

2639
sound/soc/codecs/rt5668.c Normal file

File diff suppressed because it is too large Load Diff

1318
sound/soc/codecs/rt5668.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -71,7 +71,7 @@ static const struct regmap_range_cfg rt5670_ranges[] = {
static const struct reg_sequence init_list[] = {
{ RT5670_PR_BASE + 0x14, 0x9a8a },
{ RT5670_PR_BASE + 0x38, 0x3ba1 },
{ RT5670_PR_BASE + 0x38, 0x1fe1 },
{ RT5670_PR_BASE + 0x3d, 0x3640 },
{ 0x8a, 0x0123 },
};

View File

@@ -5006,13 +5006,6 @@ static const struct regmap_config rt5677_regmap = {
.num_ranges = ARRAY_SIZE(rt5677_ranges),
};
static const struct i2c_device_id rt5677_i2c_id[] = {
{ "rt5677", RT5677 },
{ "rt5676", RT5676 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id);
static const struct of_device_id rt5677_of_match[] = {
{ .compatible = "realtek,rt5677", RT5677 },
{ }
@@ -5130,8 +5123,7 @@ static void rt5677_free_irq(struct i2c_client *i2c)
regmap_del_irq_chip(i2c->irq, rt5677->irq_data);
}
static int rt5677_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
static int rt5677_i2c_probe(struct i2c_client *i2c)
{
struct rt5677_priv *rt5677;
int ret;
@@ -5278,9 +5270,8 @@ static struct i2c_driver rt5677_i2c_driver = {
.of_match_table = rt5677_of_match,
.acpi_match_table = ACPI_PTR(rt5677_acpi_match),
},
.probe = rt5677_i2c_probe,
.probe_new = rt5677_i2c_probe,
.remove = rt5677_i2c_remove,
.id_table = rt5677_i2c_id,
};
module_i2c_driver(rt5677_i2c_driver);

View File

@@ -1,12 +1,8 @@
/*
* sgtl5000.c -- SGTL5000 ALSA SoC Audio driver
*
* Copyright 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
*
* 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.
*/
// SPDX-License-Identifier: GPL-2.0
//
// sgtl5000.c -- SGTL5000 ALSA SoC Audio driver
//
// Copyright 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -457,7 +453,7 @@ static int dac_put_volsw(struct snd_kcontrol *kcontrol,
* avc_put_threshold function: register_value = 10^(dB/20) * 0.636 * 2^15 ==>
* dB = ( fls(register_value) - 14.347 ) * 6.02
*
* As this calculation is expensive and the threshold dB values may not exeed
* As this calculation is expensive and the threshold dB values may not exceed
* 0 to 96 we use pre-calculated values.
*/
static int avc_get_threshold(struct snd_kcontrol *kcontrol,
@@ -490,7 +486,7 @@ static int avc_get_threshold(struct snd_kcontrol *kcontrol,
*
* The register value is calculated by following formula:
* register_value = 10^(dB/20) * 0.636 * 2^15
* As this calculation is expensive and the threshold dB values may not exeed
* As this calculation is expensive and the threshold dB values may not exceed
* 0 to 96 we use pre-calculated values.
*/
static int avc_put_threshold(struct snd_kcontrol *kcontrol,

View File

@@ -1,11 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* sgtl5000.h - SGTL5000 audio codec interface
*
* Copyright 2010-2011 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.
*/
#ifndef _SGTL5000_H

104
sound/soc/codecs/ssm2305.c Normal file
View File

@@ -0,0 +1,104 @@
// SPDX-License-Identifier: GPL-2.0
//
// Analog Devices SSM2305 Amplifier Driver
//
// Copyright (C) 2018 Pengutronix, Marco Felsch <kernel@pengutronix.de>
//
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <sound/soc.h>
#define DRV_NAME "ssm2305"
struct ssm2305 {
/* shutdown gpio */
struct gpio_desc *gpiod_shutdown;
};
static int ssm2305_power_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kctrl, int event)
{
struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
struct ssm2305 *data = snd_soc_component_get_drvdata(c);
gpiod_set_value_cansleep(data->gpiod_shutdown,
SND_SOC_DAPM_EVENT_ON(event));
return 0;
}
static const struct snd_soc_dapm_widget ssm2305_dapm_widgets[] = {
/* Stereo input/output */
SND_SOC_DAPM_INPUT("L_IN"),
SND_SOC_DAPM_INPUT("R_IN"),
SND_SOC_DAPM_OUTPUT("L_OUT"),
SND_SOC_DAPM_OUTPUT("R_OUT"),
SND_SOC_DAPM_SUPPLY("Power", SND_SOC_NOPM, 0, 0, ssm2305_power_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
};
static const struct snd_soc_dapm_route ssm2305_dapm_routes[] = {
{ "L_OUT", NULL, "L_IN" },
{ "R_OUT", NULL, "R_IN" },
{ "L_IN", NULL, "Power" },
{ "R_IN", NULL, "Power" },
};
static const struct snd_soc_component_driver ssm2305_component_driver = {
.dapm_widgets = ssm2305_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(ssm2305_dapm_widgets),
.dapm_routes = ssm2305_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(ssm2305_dapm_routes),
};
static int ssm2305_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ssm2305 *priv;
int err;
/* Allocate the private data */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
platform_set_drvdata(pdev, priv);
/* Get shutdown gpio */
priv->gpiod_shutdown = devm_gpiod_get(dev, "shutdown",
GPIOD_OUT_LOW);
if (IS_ERR(priv->gpiod_shutdown)) {
err = PTR_ERR(priv->gpiod_shutdown);
if (err != -EPROBE_DEFER)
dev_err(dev, "Failed to get 'shutdown' gpio: %d\n",
err);
return err;
}
return devm_snd_soc_register_component(dev, &ssm2305_component_driver,
NULL, 0);
}
#ifdef CONFIG_OF
static const struct of_device_id ssm2305_of_match[] = {
{ .compatible = "adi,ssm2305", },
{ }
};
MODULE_DEVICE_TABLE(of, ssm2305_of_match);
#endif
static struct platform_driver ssm2305_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = of_match_ptr(ssm2305_of_match),
},
.probe = ssm2305_probe,
};
module_platform_driver(ssm2305_driver);
MODULE_DESCRIPTION("ASoC SSM2305 amplifier driver");
MODULE_AUTHOR("Marco Felsch <m.felsch@pengutronix.de>");
MODULE_LICENSE("GPL v2");

View File

@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -43,6 +44,8 @@ struct tas6424_data {
unsigned int last_fault1;
unsigned int last_fault2;
unsigned int last_warn;
struct gpio_desc *standby_gpio;
struct gpio_desc *mute_gpio;
};
/*
@@ -61,6 +64,8 @@ static const struct snd_kcontrol_new tas6424_snd_controls[] = {
TAS6424_CH3_VOL_CTRL, 0, 0xff, 0, dac_tlv),
SOC_SINGLE_TLV("Speaker Driver CH4 Playback Volume",
TAS6424_CH4_VOL_CTRL, 0, 0xff, 0, dac_tlv),
SOC_SINGLE_STROBE("Auto Diagnostics Switch", TAS6424_DC_DIAG_CTRL1,
TAS6424_LDGBYPASS_SHIFT, 1),
};
static int tas6424_dac_event(struct snd_soc_dapm_widget *w,
@@ -249,10 +254,16 @@ static int tas6424_set_dai_tdm_slot(struct snd_soc_dai *dai,
static int tas6424_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_component *component = dai->component;
struct tas6424_data *tas6424 = snd_soc_component_get_drvdata(component);
unsigned int val;
dev_dbg(component->dev, "%s() mute=%d\n", __func__, mute);
if (tas6424->mute_gpio) {
gpiod_set_value_cansleep(tas6424->mute_gpio, mute);
return 0;
}
if (mute)
val = TAS6424_ALL_STATE_MUTE;
else
@@ -287,6 +298,12 @@ static int tas6424_power_on(struct snd_soc_component *component)
{
struct tas6424_data *tas6424 = snd_soc_component_get_drvdata(component);
int ret;
u8 chan_states;
int no_auto_diags = 0;
unsigned int reg_val;
if (!regmap_read(tas6424->regmap, TAS6424_DC_DIAG_CTRL1, &reg_val))
no_auto_diags = reg_val & TAS6424_LDGBYPASS_MASK;
ret = regulator_bulk_enable(ARRAY_SIZE(tas6424->supplies),
tas6424->supplies);
@@ -303,12 +320,25 @@ static int tas6424_power_on(struct snd_soc_component *component)
return ret;
}
snd_soc_component_write(component, TAS6424_CH_STATE_CTRL, TAS6424_ALL_STATE_MUTE);
if (tas6424->mute_gpio) {
gpiod_set_value_cansleep(tas6424->mute_gpio, 0);
/*
* channels are muted via the mute pin. Don't also mute
* them via the registers so that subsequent register
* access is not necessary to un-mute the channels
*/
chan_states = TAS6424_ALL_STATE_PLAY;
} else {
chan_states = TAS6424_ALL_STATE_MUTE;
}
snd_soc_component_write(component, TAS6424_CH_STATE_CTRL, chan_states);
/* any time we come out of HIZ, the output channels automatically run DC
* load diagnostics, wait here until this completes
* load diagnostics if autodiagnotics are enabled. wait here until this
* completes.
*/
msleep(230);
if (!no_auto_diags)
msleep(230);
return 0;
}
@@ -627,6 +657,38 @@ static int tas6424_i2c_probe(struct i2c_client *client,
return ret;
}
/*
* Get control of the standby pin and set it LOW to take the codec
* out of the stand-by mode.
* Note: The actual pin polarity is taken care of in the GPIO lib
* according the polarity specified in the DTS.
*/
tas6424->standby_gpio = devm_gpiod_get_optional(dev, "standby",
GPIOD_OUT_LOW);
if (IS_ERR(tas6424->standby_gpio)) {
if (PTR_ERR(tas6424->standby_gpio) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_info(dev, "failed to get standby GPIO: %ld\n",
PTR_ERR(tas6424->standby_gpio));
tas6424->standby_gpio = NULL;
}
/*
* Get control of the mute pin and set it HIGH in order to start with
* all the output muted.
* Note: The actual pin polarity is taken care of in the GPIO lib
* according the polarity specified in the DTS.
*/
tas6424->mute_gpio = devm_gpiod_get_optional(dev, "mute",
GPIOD_OUT_HIGH);
if (IS_ERR(tas6424->mute_gpio)) {
if (PTR_ERR(tas6424->mute_gpio) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_info(dev, "failed to get nmute GPIO: %ld\n",
PTR_ERR(tas6424->mute_gpio));
tas6424->mute_gpio = NULL;
}
for (i = 0; i < ARRAY_SIZE(tas6424->supplies); i++)
tas6424->supplies[i].supply = tas6424_supply_names[i];
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(tas6424->supplies),
@@ -671,6 +733,10 @@ static int tas6424_i2c_remove(struct i2c_client *client)
cancel_delayed_work_sync(&tas6424->fault_check_work);
/* put the codec in stand-by */
if (tas6424->standby_gpio)
gpiod_set_value_cansleep(tas6424->standby_gpio, 1);
ret = regulator_bulk_disable(ARRAY_SIZE(tas6424->supplies),
tas6424->supplies);
if (ret < 0) {

View File

@@ -111,6 +111,10 @@
TAS6424_CH3_STATE_DIAG | \
TAS6424_CH4_STATE_DIAG)
/* TAS6424_DC_DIAG_CTRL1 */
#define TAS6424_LDGBYPASS_SHIFT 0
#define TAS6424_LDGBYPASS_MASK BIT(TAS6424_LDGBYPASS_SHIFT)
/* TAS6424_GLOB_FAULT1_REG */
#define TAS6424_FAULT_CLOCK BIT(4)
#define TAS6424_FAULT_PVDD_OV BIT(3)

View File

@@ -1,15 +1,9 @@
/*
* tfa9879.c -- driver for NXP Semiconductors TFA9879
*
* Copyright (C) 2014 Axentia Technologies AB
* Author: Peter Rosin <peda@axentia.se>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
// SPDX-License-Identifier: GPL-2.0+
//
// tfa9879.c -- driver for NXP Semiconductors TFA9879
//
// Copyright (C) 2014 Axentia Technologies AB
// Author: Peter Rosin <peda@axentia.se>
#include <linux/module.h>
#include <linux/init.h>
@@ -88,13 +82,14 @@ static int tfa9879_hw_params(struct snd_pcm_substream *substream,
}
if (tfa9879->lsb_justified)
snd_soc_component_update_bits(component, TFA9879_SERIAL_INTERFACE_1,
TFA9879_I2S_SET_MASK,
i2s_set << TFA9879_I2S_SET_SHIFT);
snd_soc_component_update_bits(component,
TFA9879_SERIAL_INTERFACE_1,
TFA9879_I2S_SET_MASK,
i2s_set << TFA9879_I2S_SET_SHIFT);
snd_soc_component_update_bits(component, TFA9879_SERIAL_INTERFACE_1,
TFA9879_I2S_FS_MASK,
fs << TFA9879_I2S_FS_SHIFT);
TFA9879_I2S_FS_MASK,
fs << TFA9879_I2S_FS_SHIFT);
return 0;
}
@@ -103,8 +98,8 @@ static int tfa9879_digital_mute(struct snd_soc_dai *dai, int mute)
struct snd_soc_component *component = dai->component;
snd_soc_component_update_bits(component, TFA9879_MISC_CONTROL,
TFA9879_S_MUTE_MASK,
!!mute << TFA9879_S_MUTE_SHIFT);
TFA9879_S_MUTE_MASK,
!!mute << TFA9879_S_MUTE_SHIFT);
return 0;
}
@@ -152,11 +147,11 @@ static int tfa9879_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
}
snd_soc_component_update_bits(component, TFA9879_SERIAL_INTERFACE_1,
TFA9879_SCK_POL_MASK,
sck_pol << TFA9879_SCK_POL_SHIFT);
TFA9879_SCK_POL_MASK,
sck_pol << TFA9879_SCK_POL_SHIFT);
snd_soc_component_update_bits(component, TFA9879_SERIAL_INTERFACE_1,
TFA9879_I2S_SET_MASK,
i2s_set << TFA9879_I2S_SET_SHIFT);
TFA9879_I2S_SET_MASK,
i2s_set << TFA9879_I2S_SET_SHIFT);
return 0;
}
@@ -276,8 +271,7 @@ static struct snd_soc_dai_driver tfa9879_dai = {
.ops = &tfa9879_dai_ops,
};
static int tfa9879_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
static int tfa9879_i2c_probe(struct i2c_client *i2c)
{
struct tfa9879_priv *tfa9879;
int i;
@@ -298,7 +292,7 @@ static int tfa9879_i2c_probe(struct i2c_client *i2c,
tfa9879_regs[i].reg, tfa9879_regs[i].def);
return devm_snd_soc_register_component(&i2c->dev, &tfa9879_component,
&tfa9879_dai, 1);
&tfa9879_dai, 1);
}
static const struct i2c_device_id tfa9879_i2c_id[] = {
@@ -318,7 +312,7 @@ static struct i2c_driver tfa9879_i2c_driver = {
.name = "tfa9879",
.of_match_table = tfa9879_of_match,
},
.probe = tfa9879_i2c_probe,
.probe_new = tfa9879_i2c_probe,
.id_table = tfa9879_i2c_id,
};

View File

@@ -1,14 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* tfa9879.h -- driver for NXP Semiconductors TFA9879
*
* Copyright (C) 2014 Axentia Technologies AB
* Author: Peter Rosin <peda@axentia.se>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#ifndef _TFA9879_H

View File

@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/clk.h>
#include <sound/tlv.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -31,7 +32,6 @@ struct tscs42xx {
int bclk_ratio;
int samplerate;
unsigned int blrcm;
struct mutex audio_params_lock;
u8 coeff_ram[COEFF_RAM_SIZE];
@@ -42,7 +42,8 @@ struct tscs42xx {
struct regmap *regmap;
struct device *dev;
struct clk *sysclk;
int sysclk_src_id;
};
struct coeff_ram_ctl {
@@ -204,7 +205,8 @@ static int power_up_audio_plls(struct snd_soc_component *component)
break;
default:
ret = -EINVAL;
dev_err(component->dev, "Unrecognized PLL output freq (%d)\n", ret);
dev_err(component->dev,
"Unrecognized PLL output freq (%d)\n", ret);
return ret;
}
@@ -261,7 +263,8 @@ exit:
static int coeff_ram_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct snd_soc_component *component =
snd_soc_kcontrol_component(kcontrol);
struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
struct coeff_ram_ctl *ctl =
(struct coeff_ram_ctl *)kcontrol->private_value;
@@ -280,7 +283,8 @@ static int coeff_ram_get(struct snd_kcontrol *kcontrol,
static int coeff_ram_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct snd_soc_component *component =
snd_soc_kcontrol_component(kcontrol);
struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
struct coeff_ram_ctl *ctl =
(struct coeff_ram_ctl *)kcontrol->private_value;
@@ -363,7 +367,8 @@ static int dapm_micb_event(struct snd_soc_dapm_widget *w,
static int pll_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
int ret;
if (SND_SOC_DAPM_EVENT_ON(event))
@@ -377,7 +382,8 @@ static int pll_event(struct snd_soc_dapm_widget *w,
static int dac_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
int ret;
@@ -819,16 +825,19 @@ static int setup_sample_format(struct snd_soc_component *component,
dev_err(component->dev, "Unsupported format width (%d)\n", ret);
return ret;
}
ret = snd_soc_component_update_bits(component, R_AIC1, RM_AIC1_WL, width);
ret = snd_soc_component_update_bits(component,
R_AIC1, RM_AIC1_WL, width);
if (ret < 0) {
dev_err(component->dev, "Failed to set sample width (%d)\n", ret);
dev_err(component->dev,
"Failed to set sample width (%d)\n", ret);
return ret;
}
return 0;
}
static int setup_sample_rate(struct snd_soc_component *component, unsigned int rate)
static int setup_sample_rate(struct snd_soc_component *component,
unsigned int rate)
{
struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
unsigned int br, bm;
@@ -881,24 +890,32 @@ static int setup_sample_rate(struct snd_soc_component *component, unsigned int r
}
/* DAC and ADC share bit and frame clock */
ret = snd_soc_component_update_bits(component, R_DACSR, RM_DACSR_DBR, br);
ret = snd_soc_component_update_bits(component,
R_DACSR, RM_DACSR_DBR, br);
if (ret < 0) {
dev_err(component->dev, "Failed to update register (%d)\n", ret);
dev_err(component->dev,
"Failed to update register (%d)\n", ret);
return ret;
}
ret = snd_soc_component_update_bits(component, R_DACSR, RM_DACSR_DBM, bm);
ret = snd_soc_component_update_bits(component,
R_DACSR, RM_DACSR_DBM, bm);
if (ret < 0) {
dev_err(component->dev, "Failed to update register (%d)\n", ret);
dev_err(component->dev,
"Failed to update register (%d)\n", ret);
return ret;
}
ret = snd_soc_component_update_bits(component, R_ADCSR, RM_DACSR_DBR, br);
ret = snd_soc_component_update_bits(component,
R_ADCSR, RM_DACSR_DBR, br);
if (ret < 0) {
dev_err(component->dev, "Failed to update register (%d)\n", ret);
dev_err(component->dev,
"Failed to update register (%d)\n", ret);
return ret;
}
ret = snd_soc_component_update_bits(component, R_ADCSR, RM_DACSR_DBM, bm);
ret = snd_soc_component_update_bits(component,
R_ADCSR, RM_DACSR_DBM, bm);
if (ret < 0) {
dev_err(component->dev, "Failed to update register (%d)\n", ret);
dev_err(component->dev,
"Failed to update register (%d)\n", ret);
return ret;
}
@@ -1076,7 +1093,8 @@ static int tscs42xx_hw_params(struct snd_pcm_substream *substream,
ret = setup_sample_rate(component, params_rate(params));
if (ret < 0) {
dev_err(component->dev, "Failed to setup sample rate (%d)\n", ret);
dev_err(component->dev,
"Failed to setup sample rate (%d)\n", ret);
return ret;
}
@@ -1087,7 +1105,8 @@ static inline int dac_mute(struct snd_soc_component *component)
{
int ret;
ret = snd_soc_component_update_bits(component, R_CNVRTR1, RM_CNVRTR1_DACMU,
ret = snd_soc_component_update_bits(component,
R_CNVRTR1, RM_CNVRTR1_DACMU,
RV_CNVRTR1_DACMU_ENABLE);
if (ret < 0) {
dev_err(component->dev, "Failed to mute DAC (%d)\n",
@@ -1102,7 +1121,8 @@ static inline int dac_unmute(struct snd_soc_component *component)
{
int ret;
ret = snd_soc_component_update_bits(component, R_CNVRTR1, RM_CNVRTR1_DACMU,
ret = snd_soc_component_update_bits(component,
R_CNVRTR1, RM_CNVRTR1_DACMU,
RV_CNVRTR1_DACMU_DISABLE);
if (ret < 0) {
dev_err(component->dev, "Failed to unmute DAC (%d)\n",
@@ -1117,8 +1137,8 @@ static inline int adc_mute(struct snd_soc_component *component)
{
int ret;
ret = snd_soc_component_update_bits(component, R_CNVRTR0, RM_CNVRTR0_ADCMU,
RV_CNVRTR0_ADCMU_ENABLE);
ret = snd_soc_component_update_bits(component,
R_CNVRTR0, RM_CNVRTR0_ADCMU, RV_CNVRTR0_ADCMU_ENABLE);
if (ret < 0) {
dev_err(component->dev, "Failed to mute ADC (%d)\n",
ret);
@@ -1132,8 +1152,8 @@ static inline int adc_unmute(struct snd_soc_component *component)
{
int ret;
ret = snd_soc_component_update_bits(component, R_CNVRTR0, RM_CNVRTR0_ADCMU,
RV_CNVRTR0_ADCMU_DISABLE);
ret = snd_soc_component_update_bits(component,
R_CNVRTR0, RM_CNVRTR0_ADCMU, RV_CNVRTR0_ADCMU_DISABLE);
if (ret < 0) {
dev_err(component->dev, "Failed to unmute ADC (%d)\n",
ret);
@@ -1171,8 +1191,8 @@ static int tscs42xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* Slave mode not supported since it needs always-on frame clock */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
ret = snd_soc_component_update_bits(component, R_AIC1, RM_AIC1_MS,
RV_AIC1_MS_MASTER);
ret = snd_soc_component_update_bits(component,
R_AIC1, RM_AIC1_MS, RV_AIC1_MS_MASTER);
if (ret < 0) {
dev_err(component->dev,
"Failed to set codec DAI master (%d)\n", ret);
@@ -1211,14 +1231,18 @@ static int tscs42xx_set_dai_bclk_ratio(struct snd_soc_dai *codec_dai,
return -EINVAL;
}
ret = snd_soc_component_update_bits(component, R_DACSR, RM_DACSR_DBCM, value);
ret = snd_soc_component_update_bits(component,
R_DACSR, RM_DACSR_DBCM, value);
if (ret < 0) {
dev_err(component->dev, "Failed to set DAC BCLK ratio (%d)\n", ret);
dev_err(component->dev,
"Failed to set DAC BCLK ratio (%d)\n", ret);
return ret;
}
ret = snd_soc_component_update_bits(component, R_ADCSR, RM_ADCSR_ABCM, value);
ret = snd_soc_component_update_bits(component,
R_ADCSR, RM_ADCSR_ABCM, value);
if (ret < 0) {
dev_err(component->dev, "Failed to set ADC BCLK ratio (%d)\n", ret);
dev_err(component->dev,
"Failed to set ADC BCLK ratio (%d)\n", ret);
return ret;
}
@@ -1231,56 +1255,11 @@ static int tscs42xx_set_dai_bclk_ratio(struct snd_soc_dai *codec_dai,
return 0;
}
static int tscs42xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_component *component = codec_dai->component;
int ret;
switch (clk_id) {
case TSCS42XX_PLL_SRC_XTAL:
case TSCS42XX_PLL_SRC_MCLK1:
ret = snd_soc_component_write(component, R_PLLREFSEL,
RV_PLLREFSEL_PLL1_REF_SEL_XTAL_MCLK1 |
RV_PLLREFSEL_PLL2_REF_SEL_XTAL_MCLK1);
if (ret < 0) {
dev_err(component->dev,
"Failed to set pll reference input (%d)\n",
ret);
return ret;
}
break;
case TSCS42XX_PLL_SRC_MCLK2:
ret = snd_soc_component_write(component, R_PLLREFSEL,
RV_PLLREFSEL_PLL1_REF_SEL_MCLK2 |
RV_PLLREFSEL_PLL2_REF_SEL_MCLK2);
if (ret < 0) {
dev_err(component->dev,
"Failed to set PLL reference (%d)\n", ret);
return ret;
}
break;
default:
dev_err(component->dev, "pll src is unsupported\n");
return -EINVAL;
}
ret = set_pll_ctl_from_input_freq(component, freq);
if (ret < 0) {
dev_err(component->dev,
"Failed to setup PLL input freq (%d)\n", ret);
return ret;
}
return 0;
}
static const struct snd_soc_dai_ops tscs42xx_dai_ops = {
.hw_params = tscs42xx_hw_params,
.mute_stream = tscs42xx_mute_stream,
.set_fmt = tscs42xx_set_dai_fmt,
.set_bclk_ratio = tscs42xx_set_dai_bclk_ratio,
.set_sysclk = tscs42xx_set_dai_sysclk,
};
static int part_is_valid(struct tscs42xx *tscs42xx)
@@ -1309,7 +1288,58 @@ static int part_is_valid(struct tscs42xx *tscs42xx)
};
}
static struct snd_soc_component_driver soc_codec_dev_tscs42xx = {
static int set_sysclk(struct snd_soc_component *component)
{
struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
unsigned long freq;
int ret;
switch (tscs42xx->sysclk_src_id) {
case TSCS42XX_PLL_SRC_XTAL:
case TSCS42XX_PLL_SRC_MCLK1:
ret = snd_soc_component_write(component, R_PLLREFSEL,
RV_PLLREFSEL_PLL1_REF_SEL_XTAL_MCLK1 |
RV_PLLREFSEL_PLL2_REF_SEL_XTAL_MCLK1);
if (ret < 0) {
dev_err(component->dev,
"Failed to set pll reference input (%d)\n",
ret);
return ret;
}
break;
case TSCS42XX_PLL_SRC_MCLK2:
ret = snd_soc_component_write(component, R_PLLREFSEL,
RV_PLLREFSEL_PLL1_REF_SEL_MCLK2 |
RV_PLLREFSEL_PLL2_REF_SEL_MCLK2);
if (ret < 0) {
dev_err(component->dev,
"Failed to set PLL reference (%d)\n", ret);
return ret;
}
break;
default:
dev_err(component->dev, "pll src is unsupported\n");
return -EINVAL;
}
freq = clk_get_rate(tscs42xx->sysclk);
ret = set_pll_ctl_from_input_freq(component, freq);
if (ret < 0) {
dev_err(component->dev,
"Failed to setup PLL input freq (%d)\n", ret);
return ret;
}
return 0;
}
static int tscs42xx_probe(struct snd_soc_component *component)
{
return set_sysclk(component);
}
static const struct snd_soc_component_driver soc_codec_dev_tscs42xx = {
.probe = tscs42xx_probe,
.dapm_widgets = tscs42xx_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(tscs42xx_dapm_widgets),
.dapm_routes = tscs42xx_intercon,
@@ -1367,11 +1397,15 @@ static const struct reg_sequence tscs42xx_patch[] = {
{ R_AIC2, RV_AIC2_BLRCM_DAC_BCLK_LRCLK_SHARED },
};
static char const * const src_names[TSCS42XX_PLL_SRC_CNT] = {
"xtal", "mclk1", "mclk2"};
static int tscs42xx_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct tscs42xx *tscs42xx;
int ret = 0;
int src;
int ret;
tscs42xx = devm_kzalloc(&i2c->dev, sizeof(*tscs42xx), GFP_KERNEL);
if (!tscs42xx) {
@@ -1381,12 +1415,29 @@ static int tscs42xx_i2c_probe(struct i2c_client *i2c,
return ret;
}
i2c_set_clientdata(i2c, tscs42xx);
tscs42xx->dev = &i2c->dev;
for (src = TSCS42XX_PLL_SRC_XTAL; src < TSCS42XX_PLL_SRC_CNT; src++) {
tscs42xx->sysclk = devm_clk_get(&i2c->dev, src_names[src]);
if (!IS_ERR(tscs42xx->sysclk)) {
break;
} else if (PTR_ERR(tscs42xx->sysclk) != -ENOENT) {
ret = PTR_ERR(tscs42xx->sysclk);
dev_err(&i2c->dev, "Failed to get sysclk (%d)\n", ret);
return ret;
}
}
if (src == TSCS42XX_PLL_SRC_CNT) {
ret = -EINVAL;
dev_err(&i2c->dev, "Failed to get a valid clock name (%d)\n",
ret);
return ret;
}
tscs42xx->sysclk_src_id = src;
tscs42xx->regmap = devm_regmap_init_i2c(i2c, &tscs42xx_regmap);
if (IS_ERR(tscs42xx->regmap)) {
ret = PTR_ERR(tscs42xx->regmap);
dev_err(tscs42xx->dev, "Failed to allocate regmap (%d)\n", ret);
dev_err(&i2c->dev, "Failed to allocate regmap (%d)\n", ret);
return ret;
}
@@ -1394,21 +1445,21 @@ static int tscs42xx_i2c_probe(struct i2c_client *i2c,
ret = part_is_valid(tscs42xx);
if (ret <= 0) {
dev_err(tscs42xx->dev, "No valid part (%d)\n", ret);
dev_err(&i2c->dev, "No valid part (%d)\n", ret);
ret = -ENODEV;
return ret;
}
ret = regmap_write(tscs42xx->regmap, R_RESET, RV_RESET_ENABLE);
if (ret < 0) {
dev_err(tscs42xx->dev, "Failed to reset device (%d)\n", ret);
dev_err(&i2c->dev, "Failed to reset device (%d)\n", ret);
return ret;
}
ret = regmap_register_patch(tscs42xx->regmap, tscs42xx_patch,
ARRAY_SIZE(tscs42xx_patch));
if (ret < 0) {
dev_err(tscs42xx->dev, "Failed to apply patch (%d)\n", ret);
dev_err(&i2c->dev, "Failed to apply patch (%d)\n", ret);
return ret;
}
@@ -1416,10 +1467,10 @@ static int tscs42xx_i2c_probe(struct i2c_client *i2c,
mutex_init(&tscs42xx->coeff_ram_lock);
mutex_init(&tscs42xx->pll_lock);
ret = devm_snd_soc_register_component(tscs42xx->dev, &soc_codec_dev_tscs42xx,
&tscs42xx_dai, 1);
ret = devm_snd_soc_register_component(&i2c->dev,
&soc_codec_dev_tscs42xx, &tscs42xx_dai, 1);
if (ret) {
dev_err(tscs42xx->dev, "Failed to register codec (%d)\n", ret);
dev_err(&i2c->dev, "Failed to register codec (%d)\n", ret);
return ret;
}

View File

@@ -7,10 +7,10 @@
#define __WOOKIE_H__
enum {
TSCS42XX_PLL_SRC_NONE,
TSCS42XX_PLL_SRC_XTAL,
TSCS42XX_PLL_SRC_MCLK1,
TSCS42XX_PLL_SRC_MCLK2,
TSCS42XX_PLL_SRC_CNT,
};
#define R_HPVOLL 0x0

3497
sound/soc/codecs/tscs454.c Normal file

File diff suppressed because it is too large Load Diff

2323
sound/soc/codecs/tscs454.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1155,8 +1155,8 @@ SOC_DOUBLE_R_TLV("IN3 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_3L,
SND_SOC_BYTES_MASK("EQL Coefficients", WM2200_EQL_1, 20, WM2200_EQL_ENA),
SND_SOC_BYTES_MASK("EQR Coefficients", WM2200_EQR_1, 20, WM2200_EQR_ENA),
SND_SOC_BYTES("LHPF1 Coefficeints", WM2200_HPLPF1_2, 1),
SND_SOC_BYTES("LHPF2 Coefficeints", WM2200_HPLPF2_2, 1),
SND_SOC_BYTES("LHPF1 Coefficients", WM2200_HPLPF1_2, 1),
SND_SOC_BYTES("LHPF2 Coefficients", WM2200_HPLPF2_2, 1),
SOC_SINGLE("OUT1 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_1L,
WM2200_OUT1_OSR_SHIFT, 1, 0),

View File

@@ -573,10 +573,10 @@ SND_SOC_BYTES_MASK("EQ4 Coefficients", WM5100_EQ4_1, 20, WM5100_EQ4_ENA),
SND_SOC_BYTES_MASK("DRC Coefficients", WM5100_DRC1_CTRL1, 5,
WM5100_DRCL_ENA | WM5100_DRCR_ENA),
SND_SOC_BYTES("LHPF1 Coefficeints", WM5100_HPLPF1_2, 1),
SND_SOC_BYTES("LHPF2 Coefficeints", WM5100_HPLPF2_2, 1),
SND_SOC_BYTES("LHPF3 Coefficeints", WM5100_HPLPF3_2, 1),
SND_SOC_BYTES("LHPF4 Coefficeints", WM5100_HPLPF4_2, 1),
SND_SOC_BYTES("LHPF1 Coefficients", WM5100_HPLPF1_2, 1),
SND_SOC_BYTES("LHPF2 Coefficients", WM5100_HPLPF2_2, 1),
SND_SOC_BYTES("LHPF3 Coefficients", WM5100_HPLPF3_2, 1),
SND_SOC_BYTES("LHPF4 Coefficients", WM5100_HPLPF4_2, 1),
SOC_SINGLE("HPOUT1 High Performance Switch", WM5100_OUT_VOLUME_1L,
WM5100_OUT1_OSR_SHIFT, 1, 0),

View File

@@ -67,9 +67,18 @@ static int wm8782_probe(struct platform_device *pdev)
&soc_component_dev_wm8782, &wm8782_dai, 1);
}
#ifdef CONFIG_OF
static const struct of_device_id wm8782_of_match[] = {
{ .compatible = "wlf,wm8782", },
{ }
};
MODULE_DEVICE_TABLE(of, wm8782_of_match);
#endif
static struct platform_driver wm8782_codec_driver = {
.driver = {
.name = "wm8782",
.of_match_table = of_match_ptr(wm8782_of_match),
},
.probe = wm8782_probe,
};

View File

@@ -596,7 +596,7 @@ static const struct snd_kcontrol_new wm8904_adc_snd_controls[] = {
SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8904_ADC_DIGITAL_VOLUME_LEFT,
WM8904_ADC_DIGITAL_VOLUME_RIGHT, 1, 119, 0, digital_tlv),
SOC_ENUM("Left Caputure Mode", lin_mode),
SOC_ENUM("Left Capture Mode", lin_mode),
SOC_ENUM("Right Capture Mode", rin_mode),
/* No TLV since it depends on mode */

View File

@@ -2665,9 +2665,9 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
dsp->preloaded = ucontrol->value.integer.value[0];
if (ucontrol->value.integer.value[0])
snd_soc_dapm_force_enable_pin(dapm, preload);
snd_soc_component_force_enable_pin(component, preload);
else
snd_soc_dapm_disable_pin(dapm, preload);
snd_soc_component_disable_pin(component, preload);
snd_soc_dapm_sync(dapm);
@@ -2851,11 +2851,11 @@ EXPORT_SYMBOL_GPL(wm_adsp2_event);
int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
char preload[32];
snprintf(preload, ARRAY_SIZE(preload), "DSP%d Preload", dsp->num);
snd_soc_dapm_disable_pin(dapm, preload);
snd_soc_component_disable_pin(component, preload);
wm_adsp2_init_debugfs(dsp, component);

View File

@@ -24,7 +24,7 @@ config SND_DAVINCI_SOC_I2S
config SND_DAVINCI_SOC_MCASP
tristate "Multichannel Audio Serial Port (McASP) support"
depends on SND_OMAP_SOC || SND_EDMA_SOC
depends on SND_SDMA_SOC || SND_EDMA_SOC
help
Say Y or M here if you want to have support for McASP IP found in
various Texas Instruments SoCs like:

View File

@@ -36,9 +36,9 @@
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
#include <sound/omap-pcm.h>
#include "edma-pcm.h"
#include "../omap/sdma-pcm.h"
#include "davinci-mcasp.h"
#define MCASP_MAX_AFIFO_DEPTH 64
@@ -789,7 +789,7 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
rx_ser < max_active_serializers) {
mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i));
rx_ser++;
} else {
} else if (mcasp->serial_dir[i] == INACTIVE_MODE) {
mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
SRMOD_INACTIVE, SRMOD_MASK);
}
@@ -2048,10 +2048,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
#endif
break;
case PCM_SDMA:
#if IS_BUILTIN(CONFIG_SND_OMAP_SOC) || \
#if IS_BUILTIN(CONFIG_SND_SDMA_SOC) || \
(IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
IS_MODULE(CONFIG_SND_OMAP_SOC))
ret = omap_pcm_platform_register(&pdev->dev);
IS_MODULE(CONFIG_SND_SDMA_SOC))
ret = sdma_pcm_platform_register(&pdev->dev, NULL, NULL);
#else
dev_err(&pdev->dev, "Missing SND_SDMA_SOC\n");
ret = -EINVAL;

View File

@@ -1,12 +1,8 @@
/*
* Freescale ESAI ALSA SoC Digital Audio Interface (DAI) driver
*
* Copyright (C) 2014 Freescale Semiconductor, Inc.
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
// SPDX-License-Identifier: GPL-2.0
//
// Freescale ESAI ALSA SoC Digital Audio Interface (DAI) driver
//
// Copyright (C) 2014 Freescale Semiconductor, Inc.
#include <linux/clk.h>
#include <linux/dmaengine.h>
@@ -226,6 +222,12 @@ static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned long clk_rate;
int ret;
if (freq == 0) {
dev_err(dai->dev, "%sput freq of HCK%c should not be 0Hz\n",
in ? "in" : "out", tx ? 'T' : 'R');
return -EINVAL;
}
/* Bypass divider settings if the requirement doesn't change */
if (freq == esai_priv->hck_rate[tx] && dir == esai_priv->hck_dir[tx])
return 0;

View File

@@ -1,13 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* fsl_esai.h - ALSA ESAI interface for the Freescale i.MX SoC
*
* Copyright (C) 2014 Freescale Semiconductor, Inc.
*
* Author: Nicolin Chen <Guangyu.Chen@freescale.com>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#ifndef _FSL_ESAI_DAI_H

View File

@@ -1,14 +1,8 @@
/*
* Freescale ALSA SoC Digital Audio Interface (SAI) driver.
*
* Copyright 2012-2015 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 as published by the
* Free Software Foundation, either version 2 of the License, or(at your
* option) any later version.
*
*/
// SPDX-License-Identifier: GPL-2.0+
//
// Freescale ALSA SoC Digital Audio Interface (SAI) driver.
//
// Copyright 2012-2015 Freescale Semiconductor, Inc.
#include <linux/clk.h>
#include <linux/delay.h>

View File

@@ -1,9 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright 2012-2013 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.
*/
#ifndef __FSL_SAI_H

View File

@@ -1,17 +1,13 @@
/*
* Freescale S/PDIF ALSA SoC Digital Audio Interface (DAI) driver
*
* Copyright (C) 2013 Freescale Semiconductor, Inc.
*
* Based on stmp3xxx_spdif_dai.c
* Vladimir Barinov <vbarinov@embeddedalley.com>
* Copyright 2008 SigmaTel, Inc
* Copyright 2008 Embedded Alley Solutions, Inc
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
// SPDX-License-Identifier: GPL-2.0
//
// Freescale S/PDIF ALSA SoC Digital Audio Interface (DAI) driver
//
// Copyright (C) 2013 Freescale Semiconductor, Inc.
//
// Based on stmp3xxx_spdif_dai.c
// Vladimir Barinov <vbarinov@embeddedalley.com>
// Copyright 2008 SigmaTel, Inc
// Copyright 2008 Embedded Alley Solutions, Inc
#include <linux/bitrev.h>
#include <linux/clk.h>

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* fsl_spdif.h - ALSA S/PDIF interface for the Freescale i.MX SoC
*
@@ -8,10 +9,6 @@
* Based on fsl_ssi.h
* Author: Timur Tabi <timur@freescale.com>
* Copyright 2007-2008 Freescale Semiconductor, Inc.
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#ifndef _FSL_SPDIF_DAI_H

View File

@@ -1,34 +1,29 @@
/*
* Freescale SSI ALSA SoC Digital Audio Interface (DAI) driver
*
* Author: Timur Tabi <timur@freescale.com>
*
* Copyright 2007-2010 Freescale Semiconductor, Inc.
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*
*
* Some notes why imx-pcm-fiq is used instead of DMA on some boards:
*
* The i.MX SSI core has some nasty limitations in AC97 mode. While most
* sane processor vendors have a FIFO per AC97 slot, the i.MX has only
* one FIFO which combines all valid receive slots. We cannot even select
* which slots we want to receive. The WM9712 with which this driver
* was developed with always sends GPIO status data in slot 12 which
* we receive in our (PCM-) data stream. The only chance we have is to
* manually skip this data in the FIQ handler. With sampling rates different
* from 48000Hz not every frame has valid receive data, so the ratio
* between pcm data and GPIO status data changes. Our FIQ handler is not
* able to handle this, hence this driver only works with 48000Hz sampling
* rate.
* Reading and writing AC97 registers is another challenge. The core
* provides us status bits when the read register is updated with *another*
* value. When we read the same register two times (and the register still
* contains the same value) these status bits are not set. We work
* around this by not polling these bits but only wait a fixed delay.
*/
// SPDX-License-Identifier: GPL-2.0
//
// Freescale SSI ALSA SoC Digital Audio Interface (DAI) driver
//
// Author: Timur Tabi <timur@freescale.com>
//
// Copyright 2007-2010 Freescale Semiconductor, Inc.
//
// Some notes why imx-pcm-fiq is used instead of DMA on some boards:
//
// The i.MX SSI core has some nasty limitations in AC97 mode. While most
// sane processor vendors have a FIFO per AC97 slot, the i.MX has only
// one FIFO which combines all valid receive slots. We cannot even select
// which slots we want to receive. The WM9712 with which this driver
// was developed with always sends GPIO status data in slot 12 which
// we receive in our (PCM-) data stream. The only chance we have is to
// manually skip this data in the FIQ handler. With sampling rates different
// from 48000Hz not every frame has valid receive data, so the ratio
// between pcm data and GPIO status data changes. Our FIQ handler is not
// able to handle this, hence this driver only works with 48000Hz sampling
// rate.
// Reading and writing AC97 registers is another challenge. The core
// provides us status bits when the read register is updated with *another*
// value. When we read the same register two times (and the register still
// contains the same value) these status bits are not set. We work
// around this by not polling these bits but only wait a fixed delay.
#include <linux/init.h>
#include <linux/io.h>
@@ -385,8 +380,7 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
{
struct fsl_ssi *ssi = dev_id;
struct regmap *regs = ssi->regs;
__be32 sisr;
__be32 sisr2;
u32 sisr, sisr2;
regmap_read(regs, REG_SSI_SISR, &sisr);

View File

@@ -1,12 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* fsl_ssi.h - ALSA SSI interface for the Freescale MPC8610 and i.MX SoC
*
* Author: Timur Tabi <timur@freescale.com>
*
* Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed
* under the terms of the GNU General Public License version 2. This
* program is licensed "as is" without any warranty of any kind, whether
* express or implied.
* Copyright 2007-2008 Freescale Semiconductor, Inc.
*/
#ifndef _MPC8610_I2S_H

View File

@@ -1,14 +1,10 @@
/*
* Freescale SSI ALSA SoC Digital Audio Interface (DAI) debugging functions
*
* Copyright 2014 Markus Pargmann <mpa@pengutronix.de>, Pengutronix
*
* Splitted from fsl_ssi.c
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
// SPDX-License-Identifier: GPL-2.0
//
// Freescale SSI ALSA SoC Digital Audio Interface (DAI) debugging functions
//
// Copyright 2014 Markus Pargmann <mpa@pengutronix.de>, Pengutronix
//
// Split from fsl_ssi.c
#include <linux/debugfs.h>
#include <linux/device.h>

View File

@@ -135,6 +135,18 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
asoc_simple_card_clk_disable(&dai_props->codec_dai);
}
static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
unsigned long rate)
{
if (!simple_dai->clk)
return 0;
if (clk_get_rate(simple_dai->clk) == rate)
return 0;
return clk_set_rate(simple_dai->clk, rate);
}
static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -154,6 +166,15 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
if (mclk_fs) {
mclk = params_rate(params) * mclk_fs;
ret = asoc_simple_set_clk_rate(&dai_props->codec_dai, mclk);
if (ret < 0)
return ret;
ret = asoc_simple_set_clk_rate(&dai_props->cpu_dai, mclk);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
SND_SOC_CLOCK_IN);
if (ret && ret != -ENOTSUPP)

View File

@@ -498,7 +498,7 @@ static int hi6210_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
hi6210_i2s_txctrl(cpu_dai, 0);
break;
default:
dev_err(cpu_dai->dev, "uknown cmd\n");
dev_err(cpu_dai->dev, "unknown cmd\n");
return -EINVAL;
}
return 0;

View File

@@ -61,7 +61,7 @@ config SND_SOC_INTEL_HASWELL
config SND_SOC_INTEL_BAYTRAIL
tristate "Baytrail (legacy) Platforms"
depends on DMADEVICES && ACPI
depends on DMADEVICES && ACPI && SND_SST_ATOM_HIFI2_PLATFORM=n
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SST_ACPI
select SND_SOC_INTEL_SST_FIRMWARE

View File

@@ -571,7 +571,7 @@ static int broxton_audio_probe(struct platform_device *pdev)
{
struct bxt_card_private *ctx;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;

View File

@@ -593,7 +593,7 @@ static int broxton_audio_probe(struct platform_device *pdev)
}
}
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;

View File

@@ -151,7 +151,7 @@ static int byt_max98090_probe(struct platform_device *pdev)
struct byt_max98090_private *priv;
int ret_val;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) {
dev_err(&pdev->dev, "allocation failed\n");
return -ENOMEM;

View File

@@ -243,7 +243,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
int i;
int ret = 0;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;

View File

@@ -17,6 +17,7 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -25,6 +26,7 @@
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <asm/cpu_device_id.h>
#include <asm/platform_sst_audio.h>
@@ -33,6 +35,7 @@
#include <sound/soc.h>
#include <sound/jack.h>
#include <sound/soc-acpi.h>
#include <dt-bindings/sound/rt5640.h>
#include "../../codecs/rt5640.h"
#include "../atom/sst-atom-controls.h"
#include "../common/sst-dsp.h"
@@ -44,17 +47,53 @@ enum {
BYT_RT5640_IN3_MAP,
};
#define BYT_RT5640_MAP(quirk) ((quirk) & GENMASK(7, 0))
#define BYT_RT5640_DMIC_EN BIT(16)
#define BYT_RT5640_MONO_SPEAKER BIT(17)
#define BYT_RT5640_DIFF_MIC BIT(18) /* defaut is single-ended */
#define BYT_RT5640_SSP2_AIF2 BIT(19) /* default is using AIF1 */
#define BYT_RT5640_SSP0_AIF1 BIT(20)
#define BYT_RT5640_SSP0_AIF2 BIT(21)
#define BYT_RT5640_MCLK_EN BIT(22)
#define BYT_RT5640_MCLK_25MHZ BIT(23)
enum {
BYT_RT5640_JD_SRC_GPIO1 = (RT5640_JD_SRC_GPIO1 << 4),
BYT_RT5640_JD_SRC_JD1_IN4P = (RT5640_JD_SRC_JD1_IN4P << 4),
BYT_RT5640_JD_SRC_JD2_IN4N = (RT5640_JD_SRC_JD2_IN4N << 4),
BYT_RT5640_JD_SRC_GPIO2 = (RT5640_JD_SRC_GPIO2 << 4),
BYT_RT5640_JD_SRC_GPIO3 = (RT5640_JD_SRC_GPIO3 << 4),
BYT_RT5640_JD_SRC_GPIO4 = (RT5640_JD_SRC_GPIO4 << 4),
};
enum {
BYT_RT5640_OVCD_TH_600UA = (6 << 8),
BYT_RT5640_OVCD_TH_1500UA = (15 << 8),
BYT_RT5640_OVCD_TH_2000UA = (20 << 8),
};
enum {
BYT_RT5640_OVCD_SF_0P5 = (RT5640_OVCD_SF_0P5 << 13),
BYT_RT5640_OVCD_SF_0P75 = (RT5640_OVCD_SF_0P75 << 13),
BYT_RT5640_OVCD_SF_1P0 = (RT5640_OVCD_SF_1P0 << 13),
BYT_RT5640_OVCD_SF_1P5 = (RT5640_OVCD_SF_1P5 << 13),
};
#define BYT_RT5640_MAP(quirk) ((quirk) & GENMASK(3, 0))
#define BYT_RT5640_JDSRC(quirk) (((quirk) & GENMASK(7, 4)) >> 4)
#define BYT_RT5640_OVCD_TH(quirk) (((quirk) & GENMASK(12, 8)) >> 8)
#define BYT_RT5640_OVCD_SF(quirk) (((quirk) & GENMASK(14, 13)) >> 13)
#define BYT_RT5640_JD_NOT_INV BIT(16)
#define BYT_RT5640_MONO_SPEAKER BIT(17)
#define BYT_RT5640_DIFF_MIC BIT(18) /* default is single-ended */
#define BYT_RT5640_SSP2_AIF2 BIT(19) /* default is using AIF1 */
#define BYT_RT5640_SSP0_AIF1 BIT(20)
#define BYT_RT5640_SSP0_AIF2 BIT(21)
#define BYT_RT5640_MCLK_EN BIT(22)
#define BYT_RT5640_MCLK_25MHZ BIT(23)
#define BYTCR_INPUT_DEFAULTS \
(BYT_RT5640_IN3_MAP | \
BYT_RT5640_JD_SRC_JD1_IN4P | \
BYT_RT5640_OVCD_TH_2000UA | \
BYT_RT5640_OVCD_SF_0P75 | \
BYT_RT5640_DIFF_MIC)
/* in-diff or dmic-pin + jdsrc + ovcd-th + -sf + jd-inv + terminating entry */
#define MAX_NO_PROPS 6
struct byt_rt5640_private {
struct snd_soc_jack jack;
struct clk *mclk;
};
static bool is_bytcr;
@@ -67,7 +106,6 @@ MODULE_PARM_DESC(quirk, "Board-specific quirk override");
static void log_quirks(struct device *dev)
{
int map;
bool has_dmic = false;
bool has_mclk = false;
bool has_ssp0 = false;
bool has_ssp0_aif1 = false;
@@ -78,11 +116,9 @@ static void log_quirks(struct device *dev)
switch (map) {
case BYT_RT5640_DMIC1_MAP:
dev_info(dev, "quirk DMIC1_MAP enabled\n");
has_dmic = true;
break;
case BYT_RT5640_DMIC2_MAP:
dev_info(dev, "quirk DMIC2_MAP enabled\n");
has_dmic = true;
break;
case BYT_RT5640_IN1_MAP:
dev_info(dev, "quirk IN1_MAP enabled\n");
@@ -94,20 +130,20 @@ static void log_quirks(struct device *dev)
dev_err(dev, "quirk map 0x%x is not supported, microphone input will not work\n", map);
break;
}
if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) {
if (has_dmic)
dev_info(dev, "quirk DMIC enabled\n");
else
dev_err(dev, "quirk DMIC enabled but no DMIC input set, will be ignored\n");
if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) {
dev_info(dev, "quirk realtek,jack-detect-source %ld\n",
BYT_RT5640_JDSRC(byt_rt5640_quirk));
dev_info(dev, "quirk realtek,over-current-threshold-microamp %ld\n",
BYT_RT5640_OVCD_TH(byt_rt5640_quirk) * 100);
dev_info(dev, "quirk realtek,over-current-scale-factor %ld\n",
BYT_RT5640_OVCD_SF(byt_rt5640_quirk));
}
if (byt_rt5640_quirk & BYT_RT5640_JD_NOT_INV)
dev_info(dev, "quirk JD_NOT_INV enabled\n");
if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER)
dev_info(dev, "quirk MONO_SPEAKER enabled\n");
if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) {
if (!has_dmic)
dev_info(dev, "quirk DIFF_MIC enabled\n");
else
dev_info(dev, "quirk DIFF_MIC enabled but DMIC input selected, will be ignored\n");
}
if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC)
dev_info(dev, "quirk DIFF_MIC enabled\n");
if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) {
dev_info(dev, "quirk SSP0_AIF1 enabled\n");
has_ssp0 = true;
@@ -141,6 +177,52 @@ static void log_quirks(struct device *dev)
}
}
static int byt_rt5640_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai,
int rate)
{
int ret;
/* Configure the PLL before selecting it */
if (!(byt_rt5640_quirk & BYT_RT5640_MCLK_EN)) {
/* use bitclock as PLL input */
if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) ||
(byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) {
/* 2x16 bit slots on SSP0 */
ret = snd_soc_dai_set_pll(codec_dai, 0,
RT5640_PLL1_S_BCLK1,
rate * 32, rate * 512);
} else {
/* 2x15 bit slots on SSP2 */
ret = snd_soc_dai_set_pll(codec_dai, 0,
RT5640_PLL1_S_BCLK1,
rate * 50, rate * 512);
}
} else {
if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) {
ret = snd_soc_dai_set_pll(codec_dai, 0,
RT5640_PLL1_S_MCLK,
25000000, rate * 512);
} else {
ret = snd_soc_dai_set_pll(codec_dai, 0,
RT5640_PLL1_S_MCLK,
19200000, rate * 512);
}
}
if (ret < 0) {
dev_err(codec_dai->component->dev, "can't set pll: %d\n", ret);
return ret;
}
ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
rate * 512, SND_SOC_CLOCK_IN);
if (ret < 0) {
dev_err(codec_dai->component->dev, "can't set clock %d\n", ret);
return ret;
}
return 0;
}
#define BYT_CODEC_DAI1 "rt5640-aif1"
#define BYT_CODEC_DAI2 "rt5640-aif2"
@@ -173,9 +255,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
return ret;
}
}
ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
48000 * 512,
SND_SOC_CLOCK_IN);
ret = byt_rt5640_prepare_and_enable_pll1(codec_dai, 48000);
} else {
/*
* Set codec clock source to internal clock before
@@ -295,129 +375,41 @@ static const struct snd_kcontrol_new byt_rt5640_controls[] = {
SOC_DAPM_PIN_SWITCH("Speaker"),
};
static struct snd_soc_jack_pin rt5640_pins[] = {
{
.pin = "Headphone",
.mask = SND_JACK_HEADPHONE,
},
{
.pin = "Headset Mic",
.mask = SND_JACK_MICROPHONE,
},
};
static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
struct snd_soc_dai *dai = rtd->codec_dai;
ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
params_rate(params) * 512,
SND_SOC_CLOCK_IN);
if (ret < 0) {
dev_err(rtd->dev, "can't set codec clock %d\n", ret);
return ret;
}
if (!(byt_rt5640_quirk & BYT_RT5640_MCLK_EN)) {
/* use bitclock as PLL input */
if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) ||
(byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) {
/* 2x16 bit slots on SSP0 */
ret = snd_soc_dai_set_pll(codec_dai, 0,
RT5640_PLL1_S_BCLK1,
params_rate(params) * 32,
params_rate(params) * 512);
} else {
/* 2x15 bit slots on SSP2 */
ret = snd_soc_dai_set_pll(codec_dai, 0,
RT5640_PLL1_S_BCLK1,
params_rate(params) * 50,
params_rate(params) * 512);
}
} else {
if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) {
ret = snd_soc_dai_set_pll(codec_dai, 0,
RT5640_PLL1_S_MCLK,
25000000,
params_rate(params) * 512);
} else {
ret = snd_soc_dai_set_pll(codec_dai, 0,
RT5640_PLL1_S_MCLK,
19200000,
params_rate(params) * 512);
}
}
if (ret < 0) {
dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
return ret;
}
return 0;
}
static int byt_rt5640_quirk_cb(const struct dmi_system_id *id)
{
byt_rt5640_quirk = (unsigned long)id->driver_data;
return 1;
return byt_rt5640_prepare_and_enable_pll1(dai, params_rate(params));
}
/* Please keep this list alphabetically sorted */
static const struct dmi_system_id byt_rt5640_quirk_table[] = {
{
.callback = byt_rt5640_quirk_cb,
{ /* Acer Iconia Tab 8 W1-810 */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
},
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
BYT_RT5640_MCLK_EN),
},
{
.callback = byt_rt5640_quirk_cb,
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"),
},
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
BYT_RT5640_MONO_SPEAKER |
BYT_RT5640_DIFF_MIC |
BYT_RT5640_SSP0_AIF2 |
BYT_RT5640_MCLK_EN),
},
{
.callback = byt_rt5640_quirk_cb,
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "DellInc."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),
},
.driver_data = (void *)(BYT_RT5640_DMIC2_MAP |
BYT_RT5640_DMIC_EN |
BYT_RT5640_MCLK_EN),
},
{
.callback = byt_rt5640_quirk_cb,
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"),
},
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
BYT_RT5640_MCLK_EN),
},
{
.callback = byt_rt5640_quirk_cb,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"),
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Iconia W1-810"),
},
.driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
BYT_RT5640_DMIC_EN),
BYT_RT5640_JD_SRC_JD1_IN4P |
BYT_RT5640_OVCD_TH_2000UA |
BYT_RT5640_OVCD_SF_0P75 |
BYT_RT5640_SSP0_AIF1 |
BYT_RT5640_MCLK_EN),
},
{
.callback = byt_rt5640_quirk_cb,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),
DMI_MATCH(DMI_BOARD_NAME, "tPAD"),
},
.driver_data = (void *)(BYT_RT5640_IN3_MAP |
BYT_RT5640_MCLK_EN |
BYT_RT5640_SSP0_AIF1),
},
{
.callback = byt_rt5640_quirk_cb,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
@@ -428,11 +420,207 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
},
{
.callback = byt_rt5640_quirk_cb,
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ARCHOS 80 Cesium"),
},
.driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
BYT_RT5640_MONO_SPEAKER |
BYT_RT5640_SSP0_AIF1 |
BYT_RT5640_MCLK_EN),
},
{
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
},
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
BYT_RT5640_JD_SRC_JD2_IN4N |
BYT_RT5640_OVCD_TH_2000UA |
BYT_RT5640_OVCD_SF_0P75 |
BYT_RT5640_MCLK_EN),
},
{
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"),
},
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
BYT_RT5640_MONO_SPEAKER |
BYT_RT5640_DIFF_MIC |
BYT_RT5640_SSP0_AIF2 |
BYT_RT5640_MCLK_EN),
},
{ /* Chuwi Vi8 (CWI506) */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "i86"),
/* The above are too generic, also match BIOS info */
DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.D86JLBNR"),
},
.driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
BYT_RT5640_MONO_SPEAKER |
BYT_RT5640_SSP0_AIF1 |
BYT_RT5640_MCLK_EN),
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"),
},
.driver_data = (void *)(BYT_RT5640_DMIC1_MAP),
},
{
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),
},
.driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
BYT_RT5640_JD_SRC_JD2_IN4N |
BYT_RT5640_OVCD_TH_2000UA |
BYT_RT5640_OVCD_SF_0P75 |
BYT_RT5640_MONO_SPEAKER |
BYT_RT5640_MCLK_EN),
},
{
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"),
},
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
BYT_RT5640_MCLK_EN),
},
{ /* HP Pavilion x2 10-n000nd */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
},
.driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
BYT_RT5640_JD_SRC_JD2_IN4N |
BYT_RT5640_OVCD_TH_1500UA |
BYT_RT5640_OVCD_SF_0P75 |
BYT_RT5640_SSP0_AIF1 |
BYT_RT5640_MCLK_EN),
},
{ /* HP Stream 7 */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP Stream 7 Tablet"),
},
.driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
BYT_RT5640_MONO_SPEAKER |
BYT_RT5640_JD_NOT_INV |
BYT_RT5640_SSP0_AIF1 |
BYT_RT5640_MCLK_EN),
},
{ /* I.T.Works TW891 */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "TW891"),
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "To be filled by O.E.M."),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "TW891"),
},
.driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
BYT_RT5640_MONO_SPEAKER |
BYT_RT5640_SSP0_AIF1 |
BYT_RT5640_MCLK_EN),
},
{ /* Lamina I8270 / T701BR.SE */
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Lamina"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "T701BR.SE"),
},
.driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
BYT_RT5640_MONO_SPEAKER |
BYT_RT5640_JD_NOT_INV |
BYT_RT5640_SSP0_AIF1 |
BYT_RT5640_MCLK_EN),
},
{ /* MSI S100 tablet */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "S100"),
},
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
BYT_RT5640_JD_SRC_JD2_IN4N |
BYT_RT5640_OVCD_TH_2000UA |
BYT_RT5640_OVCD_SF_0P75 |
BYT_RT5640_MONO_SPEAKER |
BYT_RT5640_DIFF_MIC |
BYT_RT5640_MCLK_EN),
},
{ /* Pipo W4 */
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
/* The above are too generic, also match BIOS info */
DMI_MATCH(DMI_BIOS_VERSION, "V8L_WIN32_CHIPHD"),
},
.driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
BYT_RT5640_MONO_SPEAKER |
BYT_RT5640_SSP0_AIF1 |
BYT_RT5640_MCLK_EN),
},
{ /* Point of View Mobii TAB-P800W (V2.0) */
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
/* The above are too generic, also match BIOS info */
DMI_EXACT_MATCH(DMI_BIOS_VERSION, "3BAIR1014"),
DMI_EXACT_MATCH(DMI_BIOS_DATE, "10/24/2014"),
},
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
BYT_RT5640_JD_SRC_JD2_IN4N |
BYT_RT5640_OVCD_TH_2000UA |
BYT_RT5640_OVCD_SF_0P75 |
BYT_RT5640_MONO_SPEAKER |
BYT_RT5640_DIFF_MIC |
BYT_RT5640_SSP0_AIF2 |
BYT_RT5640_MCLK_EN),
},
{ /* Point of View Mobii TAB-P800W (V2.1) */
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
/* The above are too generic, also match BIOS info */
DMI_EXACT_MATCH(DMI_BIOS_VERSION, "3BAIR1013"),
DMI_EXACT_MATCH(DMI_BIOS_DATE, "08/22/2014"),
},
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
BYT_RT5640_JD_SRC_JD2_IN4N |
BYT_RT5640_OVCD_TH_2000UA |
BYT_RT5640_OVCD_SF_0P75 |
BYT_RT5640_MONO_SPEAKER |
BYT_RT5640_DIFF_MIC |
BYT_RT5640_SSP0_AIF2 |
BYT_RT5640_MCLK_EN),
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),
DMI_MATCH(DMI_BOARD_NAME, "tPAD"),
},
.driver_data = (void *)(BYT_RT5640_IN3_MAP |
BYT_RT5640_MCLK_EN |
BYT_RT5640_SSP0_AIF1),
},
{ /* Toshiba Satellite Click Mini L9W-B */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SATELLITE Click Mini L9W-B"),
},
.driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
BYT_RT5640_JD_SRC_JD2_IN4N |
BYT_RT5640_OVCD_TH_1500UA |
BYT_RT5640_OVCD_SF_0P75 |
BYT_RT5640_SSP0_AIF1 |
BYT_RT5640_MCLK_EN),
},
{ /* Catch-all for generic Insyde tablets, must be last */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
},
.driver_data = (void *)(BYT_RT5640_IN3_MAP |
.driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
BYT_RT5640_MCLK_EN |
BYT_RT5640_SSP0_AIF1),
@@ -440,6 +628,64 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
{}
};
/*
* Note this MUST be called before snd_soc_register_card(), so that the props
* are in place before the codec component driver's probe function parses them.
*/
static int byt_rt5640_add_codec_device_props(const char *i2c_dev_name)
{
struct property_entry props[MAX_NO_PROPS] = {};
struct device *i2c_dev;
int ret, cnt = 0;
i2c_dev = bus_find_device_by_name(&i2c_bus_type, NULL, i2c_dev_name);
if (!i2c_dev)
return -EPROBE_DEFER;
switch (BYT_RT5640_MAP(byt_rt5640_quirk)) {
case BYT_RT5640_DMIC1_MAP:
props[cnt++] = PROPERTY_ENTRY_U32("realtek,dmic1-data-pin",
RT5640_DMIC1_DATA_PIN_IN1P);
break;
case BYT_RT5640_DMIC2_MAP:
props[cnt++] = PROPERTY_ENTRY_U32("realtek,dmic2-data-pin",
RT5640_DMIC2_DATA_PIN_IN1N);
break;
case BYT_RT5640_IN1_MAP:
if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC)
props[cnt++] =
PROPERTY_ENTRY_BOOL("realtek,in1-differential");
break;
case BYT_RT5640_IN3_MAP:
if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC)
props[cnt++] =
PROPERTY_ENTRY_BOOL("realtek,in3-differential");
break;
}
if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) {
props[cnt++] = PROPERTY_ENTRY_U32(
"realtek,jack-detect-source",
BYT_RT5640_JDSRC(byt_rt5640_quirk));
props[cnt++] = PROPERTY_ENTRY_U32(
"realtek,over-current-threshold-microamp",
BYT_RT5640_OVCD_TH(byt_rt5640_quirk) * 100);
props[cnt++] = PROPERTY_ENTRY_U32(
"realtek,over-current-scale-factor",
BYT_RT5640_OVCD_SF(byt_rt5640_quirk));
}
if (byt_rt5640_quirk & BYT_RT5640_JD_NOT_INV)
props[cnt++] = PROPERTY_ENTRY_BOOL("realtek,jack-detect-not-inverted");
ret = device_add_properties(i2c_dev, props);
put_device(i2c_dev);
return ret;
}
static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
{
struct snd_soc_card *card = runtime->card;
@@ -451,6 +697,11 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
card->dapm.idle_bias_off = true;
/* Start with RC clk for jack-detect (we disable MCLK below) */
if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN)
snd_soc_component_update_bits(component, RT5640_GLB_CLK,
RT5640_SCLK_SRC_MASK, RT5640_SCLK_SRC_RCCLK);
rt5640_sel_asrc_clk_src(component,
RT5640_DA_STEREO_FILTER |
RT5640_DA_MONO_L_FILTER |
@@ -521,17 +772,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
if (ret)
return ret;
if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) {
snd_soc_component_update_bits(component, RT5640_IN1_IN2, RT5640_IN_DF1,
RT5640_IN_DF1);
}
if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) {
ret = rt5640_dmic_enable(component, 0, 0);
if (ret)
return ret;
}
snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
@@ -555,11 +795,27 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
else
ret = clk_set_rate(priv->mclk, 19200000);
if (ret)
if (ret) {
dev_err(card->dev, "unable to set MCLK rate\n");
return ret;
}
}
return ret;
if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) {
ret = snd_soc_card_jack_new(card, "Headset",
SND_JACK_HEADSET | SND_JACK_BTN_0,
&priv->jack, rt5640_pins,
ARRAY_SIZE(rt5640_pins));
if (ret) {
dev_err(card->dev, "Jack creation failed %d\n", ret);
return ret;
}
snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0,
KEY_PLAYPAUSE);
snd_soc_component_set_jack(component, &priv->jack, NULL);
}
return 0;
}
static const struct snd_soc_pcm_stream byt_rt5640_dai_params = {
@@ -701,6 +957,48 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = {
};
/* SoC card */
static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN];
static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */
static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */
static char byt_rt5640_long_name[40]; /* = "bytcr-rt5640-*-spk-*-mic" */
static int byt_rt5640_suspend(struct snd_soc_card *card)
{
struct snd_soc_component *component;
if (!BYT_RT5640_JDSRC(byt_rt5640_quirk))
return 0;
list_for_each_entry(component, &card->component_dev_list, card_list) {
if (!strcmp(component->name, byt_rt5640_codec_name)) {
dev_dbg(component->dev, "disabling jack detect before suspend\n");
snd_soc_component_set_jack(component, NULL, NULL);
break;
}
}
return 0;
}
static int byt_rt5640_resume(struct snd_soc_card *card)
{
struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card);
struct snd_soc_component *component;
if (!BYT_RT5640_JDSRC(byt_rt5640_quirk))
return 0;
list_for_each_entry(component, &card->component_dev_list, card_list) {
if (!strcmp(component->name, byt_rt5640_codec_name)) {
dev_dbg(component->dev, "re-enabling jack detect after resume\n");
snd_soc_component_set_jack(component, &priv->jack, NULL);
break;
}
}
return 0;
}
static struct snd_soc_card byt_rt5640_card = {
.name = "bytcr-rt5640",
.owner = THIS_MODULE,
@@ -711,12 +1009,10 @@ static struct snd_soc_card byt_rt5640_card = {
.dapm_routes = byt_rt5640_audio_map,
.num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
.fully_routed = true,
.suspend_pre = byt_rt5640_suspend,
.resume_post = byt_rt5640_resume,
};
static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN];
static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */
static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */
static bool is_valleyview(void)
{
static const struct x86_cpu_id cpu_ids[] = {
@@ -736,6 +1032,8 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */
static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
{
const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" };
const struct dmi_system_id *dmi_id;
struct byt_rt5640_private *priv;
struct snd_soc_acpi_mach *mach;
const char *i2c_name = NULL;
@@ -744,7 +1042,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
int i;
is_bytcr = false;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -829,20 +1127,29 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
}
/* change defaults for Baytrail-CR capture */
byt_rt5640_quirk |= BYT_RT5640_IN1_MAP;
byt_rt5640_quirk |= BYT_RT5640_DIFF_MIC;
byt_rt5640_quirk |= BYTCR_INPUT_DEFAULTS;
} else {
byt_rt5640_quirk |= (BYT_RT5640_DMIC1_MAP |
BYT_RT5640_DMIC_EN);
byt_rt5640_quirk |= BYT_RT5640_DMIC1_MAP |
BYT_RT5640_JD_SRC_JD2_IN4N |
BYT_RT5640_OVCD_TH_2000UA |
BYT_RT5640_OVCD_SF_0P75;
}
/* check quirks before creating card */
dmi_check_system(byt_rt5640_quirk_table);
dmi_id = dmi_first_match(byt_rt5640_quirk_table);
if (dmi_id)
byt_rt5640_quirk = (unsigned long)dmi_id->driver_data;
if (quirk_override) {
dev_info(&pdev->dev, "Overriding quirk 0x%x => 0x%x\n",
(unsigned int)byt_rt5640_quirk, quirk_override);
byt_rt5640_quirk = quirk_override;
}
/* Must be called before register_card, also see declaration comment. */
ret_val = byt_rt5640_add_codec_device_props(byt_rt5640_codec_name);
if (ret_val)
return ret_val;
log_quirks(&pdev->dev);
if ((byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) ||
@@ -889,6 +1196,13 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
}
}
snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name),
"bytcr-rt5640-%s-spk-%s-mic",
(byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ?
"mono" : "stereo",
map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]);
byt_rt5640_card.long_name = byt_rt5640_long_name;
ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card);
if (ret_val) {

View File

@@ -706,6 +706,7 @@ static struct snd_soc_card byt_rt5651_card = {
static char byt_rt5651_codec_name[SND_ACPI_I2C_ID_LEN];
static char byt_rt5651_codec_aif_name[12]; /* = "rt5651-aif[1|2]" */
static char byt_rt5651_cpu_dai_name[10]; /* = "ssp[0|2]-port" */
static char byt_rt5651_long_name[40]; /* = "bytcr-rt5651-*-spk-*-mic" */
static bool is_valleyview(void)
{
@@ -726,6 +727,10 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */
static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
{
const char * const intmic_name[] =
{ "dmic", "in1", "in2", "in12", "in1", "in2" };
const char * const hsmic_name[] =
{ "in2", "in2", "in1", "in3", "in3", "in3" };
struct byt_rt5651_private *priv;
struct snd_soc_acpi_mach *mach;
const char *i2c_name = NULL;
@@ -734,7 +739,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
int dai_index = 0;
int i;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -856,9 +861,10 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN) {
priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
if (IS_ERR(priv->mclk)) {
ret_val = PTR_ERR(priv->mclk);
dev_err(&pdev->dev,
"Failed to get MCLK from pmc_plt_clk_3: %ld\n",
PTR_ERR(priv->mclk));
"Failed to get MCLK from pmc_plt_clk_3: %d\n",
ret_val);
/*
* Fall back to bit clock usage for -ENOENT (clock not
* available likely due to missing dependencies), bail
@@ -870,6 +876,12 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
}
}
snprintf(byt_rt5651_long_name, sizeof(byt_rt5651_long_name),
"bytcr-rt5651-%s-intmic-%s-hsmic",
intmic_name[BYT_RT5651_MAP(byt_rt5651_quirk)],
hsmic_name[BYT_RT5651_MAP(byt_rt5651_quirk)]);
byt_rt5651_card.long_name = byt_rt5651_long_name;
ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card);
if (ret_val) {

View File

@@ -391,7 +391,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
int ret_val = 0;
struct cht_mc_private *drv;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
return -ENOMEM;

View File

@@ -120,7 +120,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
* KEY_VOLUMEUP
* KEY_VOLUMEDOWN
*/
jack_type = SND_JACK_HEADPHONE | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
jack_type = SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3;
ret = snd_soc_card_jack_new(runtime->card, "Headset", jack_type, jack,
cht_bsw_jack_pins, ARRAY_SIZE(cht_bsw_jack_pins));
@@ -248,7 +248,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
struct cht_mc_private *drv;
int ret_val;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
return -ENOMEM;
snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);

View File

@@ -539,7 +539,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
int ret_val = 0;
int i;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
return -ENOMEM;

View File

@@ -189,13 +189,6 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
if (devm_acpi_dev_add_driver_gpios(component->dev, cht_rt5672_gpios))
dev_warn(runtime->dev, "Unable to add GPIO mapping table\n");
/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
if (ret < 0) {
dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret);
return ret;
}
/* Select codec ASRC clock source to track I2S1 clock, because codec
* is in slave mode and 100fs I2S format (BCLK = 100 * LRCLK) cannot
* be supported by RT5672. Otherwise, ASRC will be disabled and cause
@@ -252,6 +245,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
int ret;
/* The DSP will covert the FE rate to 48k, stereo, 24bits */
rate->min = rate->max = 48000;
@@ -259,6 +253,26 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
/* set SSP2 to 24-bit */
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
/*
* Default mode for SSP configuration is TDM 4 slot
*/
ret = snd_soc_dai_set_fmt(rtd->codec_dai,
SND_SOC_DAIFMT_DSP_B |
SND_SOC_DAIFMT_IB_NF |
SND_SOC_DAIFMT_CBS_CFS);
if (ret < 0) {
dev_err(rtd->dev, "can't set format to TDM %d\n", ret);
return ret;
}
/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
ret = snd_soc_dai_set_tdm_slot(rtd->codec_dai, 0xF, 0xF, 4, 24);
if (ret < 0) {
dev_err(rtd->dev, "can't set codec TDM slot %d\n", ret);
return ret;
}
return 0;
}
@@ -315,8 +329,6 @@ static struct snd_soc_dai_link cht_dailink[] = {
.nonatomic = true,
.codec_dai_name = "rt5670-aif1",
.codec_name = "i2c-10EC5670:00",
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
| SND_SOC_DAIFMT_CBS_CFS,
.init = cht_codec_init,
.be_hw_params_fixup = cht_codec_fixup,
.dpcm_playback = 1,

View File

@@ -65,14 +65,6 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
return -EIO;
}
/* Configure sysclk for codec */
ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24576000,
SND_SOC_CLOCK_IN);
if (ret) {
dev_err(card->dev, "can't set codec sysclk configuration\n");
return ret;
}
if (SND_SOC_DAPM_EVENT_OFF(event)) {
ret = snd_soc_dai_set_pll(codec_dai, 0,
DA7219_SYSCLK_MCLK, 0, 0);
@@ -169,9 +161,18 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_component *component = rtd->codec_dai->component;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_jack *jack;
int ret;
/* Configure sysclk for codec */
ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24576000,
SND_SOC_CLOCK_IN);
if (ret) {
dev_err(rtd->dev, "can't set codec sysclk configuration\n");
return ret;
}
/*
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
@@ -572,7 +573,7 @@ static int kabylake_audio_probe(struct platform_device *pdev)
{
struct kbl_codec_private *ctx;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;

View File

@@ -299,7 +299,8 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
rt5663_set_jack_detect(component, &ctx->kabylake_headset);
snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL);
return ret;
}
@@ -972,7 +973,7 @@ static int kabylake_audio_probe(struct platform_device *pdev)
struct skl_machine_pdata *pdata;
int ret;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;

View File

@@ -200,7 +200,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
rt5663_set_jack_detect(component, &ctx->kabylake_headset);
snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL);
ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "DMIC");
if (ret)
@@ -651,7 +651,7 @@ static int kabylake_audio_probe(struct platform_device *pdev)
struct kbl_codec_private *ctx;
struct skl_machine_pdata *pdata;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;

View File

@@ -643,7 +643,7 @@ static int skylake_audio_probe(struct platform_device *pdev)
struct skl_nau8825_private *ctx;
struct skl_machine_pdata *pdata;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;

View File

@@ -696,7 +696,7 @@ static int skylake_audio_probe(struct platform_device *pdev)
struct skl_nau88125_private *ctx;
struct skl_machine_pdata *pdata;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;

View File

@@ -527,7 +527,7 @@ static int skylake_audio_probe(struct platform_device *pdev)
{
struct skl_rt286_private *ctx;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;

View File

@@ -15,10 +15,10 @@
#include <linux/pci.h>
#include <linux/debugfs.h>
#include <uapi/sound/skl-tplg-interface.h>
#include "skl.h"
#include "skl-sst-dsp.h"
#include "skl-sst-ipc.h"
#include "skl-tplg-interface.h"
#include "skl-topology.h"
#include "../common/sst-dsp.h"
#include "../common/sst-dsp-priv.h"
@@ -142,8 +142,8 @@ static ssize_t module_read(struct file *file, char __user *user_buf,
mconfig->max_out_queue, ret, false);
ret += snprintf(buf + ret, MOD_BUF - ret,
"Other:\n\tDomain %d\n\tHomogenous Input %s\n\t"
"Homogenous Output %s\n\tIn Queue Mask %d\n\t"
"Other:\n\tDomain %d\n\tHomogeneous Input %s\n\t"
"Homogeneous Output %s\n\tIn Queue Mask %d\n\t"
"Out Queue Mask %d\n\tDMA ID %d\n\tMem Pages %d\n\t"
"Module Type %d\n\tModule State %d\n",
mconfig->domain,

View File

@@ -21,6 +21,7 @@
#include <linux/pci.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <uapi/sound/skl-tplg-interface.h>
#include "skl-sst-dsp.h"
#include "cnl-sst-dsp.h"
#include "skl-sst-ipc.h"
@@ -28,7 +29,6 @@
#include "../common/sst-dsp.h"
#include "../common/sst-dsp-priv.h"
#include "skl-topology.h"
#include "skl-tplg-interface.h"
static int skl_alloc_dma_buf(struct device *dev,
struct snd_dma_buffer *dmab, size_t size)
@@ -225,7 +225,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
.id = 0x9d71,
.num_cores = 2,
.loader_ops = skl_get_loader_ops,
.init = kbl_sst_dsp_init,
.init = skl_sst_dsp_init,
.init_fw = skl_sst_init_fw,
.cleanup = skl_sst_dsp_cleanup
},

View File

@@ -268,15 +268,31 @@ static int skl_pcm_prepare(struct snd_pcm_substream *substream,
{
struct skl *skl = get_skl_ctx(dai->dev);
struct skl_module_cfg *mconfig;
int ret;
dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
/* In case of XRUN recovery, reset the FW pipe to clean state */
if (mconfig && (substream->runtime->status->state ==
SNDRV_PCM_STATE_XRUN))
skl_reset_pipe(skl->skl_sst, mconfig->pipe);
/*
* In case of XRUN recovery or in the case when the application
* calls prepare another time, reset the FW pipe to clean state
*/
if (mconfig &&
(substream->runtime->status->state == SNDRV_PCM_STATE_XRUN ||
mconfig->pipe->state == SKL_PIPE_CREATED ||
mconfig->pipe->state == SKL_PIPE_PAUSED)) {
ret = skl_reset_pipe(skl->skl_sst, mconfig->pipe);
if (ret < 0)
return ret;
ret = skl_pcm_host_dma_prepare(dai->dev,
mconfig->pipe->p_params);
if (ret < 0)
return ret;
}
return 0;
}
@@ -366,9 +382,21 @@ static int skl_pcm_hw_free(struct snd_pcm_substream *substream,
{
struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
struct skl *skl = get_skl_ctx(dai->dev);
struct skl_module_cfg *mconfig;
int ret;
dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
if (mconfig) {
ret = skl_reset_pipe(skl->skl_sst, mconfig->pipe);
if (ret < 0)
dev_err(dai->dev, "%s:Reset failed ret =%d",
__func__, ret);
}
snd_hdac_stream_cleanup(hdac_stream(stream));
hdac_stream(stream)->prepared = 0;

View File

@@ -231,9 +231,6 @@ int skl_dsp_boot(struct sst_dsp *ctx);
int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
struct skl_sst **dsp);
int kbl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
struct skl_sst **dsp);
int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
struct skl_sst **dsp);

View File

@@ -390,7 +390,7 @@ out:
}
static int
kbl_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count)
skl_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count)
{
struct skl_sst *skl = ctx->thread_context;
struct firmware stripped_fw;
@@ -508,16 +508,7 @@ static const struct skl_dsp_fw_ops skl_fw_ops = {
.set_state_D3 = skl_set_dsp_D3,
.load_fw = skl_load_base_firmware,
.get_fw_errcode = skl_get_errorcode,
.load_mod = skl_load_module,
.unload_mod = skl_unload_module,
};
static const struct skl_dsp_fw_ops kbl_fw_ops = {
.set_state_D0 = skl_set_dsp_D0,
.set_state_D3 = skl_set_dsp_D3,
.load_fw = skl_load_base_firmware,
.get_fw_errcode = skl_get_errorcode,
.load_library = kbl_load_library,
.load_library = skl_load_library,
.load_mod = skl_load_module,
.unload_mod = skl_unload_module,
};
@@ -573,27 +564,6 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
}
EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
int kbl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
struct skl_sst **dsp)
{
struct sst_dsp *sst;
int ret;
ret = skl_sst_dsp_init(dev, mmio_base, irq, fw_name, dsp_ops, dsp);
if (ret < 0) {
dev_err(dev, "%s: Init failed %d\n", __func__, ret);
return ret;
}
sst = (*dsp)->dsp;
sst->fw_ops = kbl_fw_ops;
return 0;
}
EXPORT_SYMBOL_GPL(kbl_sst_dsp_init);
int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx)
{
int ret;

View File

@@ -19,14 +19,15 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/firmware.h>
#include <linux/uuid.h>
#include <sound/soc.h>
#include <sound/soc-topology.h>
#include <uapi/sound/snd_sst_tokens.h>
#include <uapi/sound/skl-tplg-interface.h>
#include "skl-sst-dsp.h"
#include "skl-sst-ipc.h"
#include "skl-topology.h"
#include "skl.h"
#include "skl-tplg-interface.h"
#include "../common/sst-dsp.h"
#include "../common/sst-dsp-priv.h"
@@ -2724,6 +2725,167 @@ static int skl_tplg_get_desc_blocks(struct device *dev,
return -EINVAL;
}
/* Functions to parse private data from configuration file format v4 */
/*
* Add pipeline from topology binary into driver pipeline list
*
* If already added we return that instance
* Otherwise we create a new instance and add into driver list
*/
static int skl_tplg_add_pipe_v4(struct device *dev,
struct skl_module_cfg *mconfig, struct skl *skl,
struct skl_dfw_v4_pipe *dfw_pipe)
{
struct skl_pipeline *ppl;
struct skl_pipe *pipe;
struct skl_pipe_params *params;
list_for_each_entry(ppl, &skl->ppl_list, node) {
if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) {
mconfig->pipe = ppl->pipe;
return 0;
}
}
ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
if (!ppl)
return -ENOMEM;
pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
if (!pipe)
return -ENOMEM;
params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
if (!params)
return -ENOMEM;
pipe->ppl_id = dfw_pipe->pipe_id;
pipe->memory_pages = dfw_pipe->memory_pages;
pipe->pipe_priority = dfw_pipe->pipe_priority;
pipe->conn_type = dfw_pipe->conn_type;
pipe->state = SKL_PIPE_INVALID;
pipe->p_params = params;
INIT_LIST_HEAD(&pipe->w_list);
ppl->pipe = pipe;
list_add(&ppl->node, &skl->ppl_list);
mconfig->pipe = pipe;
return 0;
}
static void skl_fill_module_pin_info_v4(struct skl_dfw_v4_module_pin *dfw_pin,
struct skl_module_pin *m_pin,
bool is_dynamic, int max_pin)
{
int i;
for (i = 0; i < max_pin; i++) {
m_pin[i].id.module_id = dfw_pin[i].module_id;
m_pin[i].id.instance_id = dfw_pin[i].instance_id;
m_pin[i].in_use = false;
m_pin[i].is_dynamic = is_dynamic;
m_pin[i].pin_state = SKL_PIN_UNBIND;
}
}
static void skl_tplg_fill_fmt_v4(struct skl_module_pin_fmt *dst_fmt,
struct skl_dfw_v4_module_fmt *src_fmt,
int pins)
{
int i;
for (i = 0; i < pins; i++) {
dst_fmt[i].fmt.channels = src_fmt[i].channels;
dst_fmt[i].fmt.s_freq = src_fmt[i].freq;
dst_fmt[i].fmt.bit_depth = src_fmt[i].bit_depth;
dst_fmt[i].fmt.valid_bit_depth = src_fmt[i].valid_bit_depth;
dst_fmt[i].fmt.ch_cfg = src_fmt[i].ch_cfg;
dst_fmt[i].fmt.ch_map = src_fmt[i].ch_map;
dst_fmt[i].fmt.interleaving_style =
src_fmt[i].interleaving_style;
dst_fmt[i].fmt.sample_type = src_fmt[i].sample_type;
}
}
static int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w,
struct skl *skl, struct device *dev,
struct skl_module_cfg *mconfig)
{
struct skl_dfw_v4_module *dfw =
(struct skl_dfw_v4_module *)tplg_w->priv.data;
int ret;
dev_dbg(dev, "Parsing Skylake v4 widget topology data\n");
ret = guid_parse(dfw->uuid, (guid_t *)mconfig->guid);
if (ret)
return ret;
mconfig->id.module_id = -1;
mconfig->id.instance_id = dfw->instance_id;
mconfig->module->resources[0].cps = dfw->max_mcps;
mconfig->module->resources[0].ibs = dfw->ibs;
mconfig->module->resources[0].obs = dfw->obs;
mconfig->core_id = dfw->core_id;
mconfig->module->max_input_pins = dfw->max_in_queue;
mconfig->module->max_output_pins = dfw->max_out_queue;
mconfig->module->loadable = dfw->is_loadable;
skl_tplg_fill_fmt_v4(mconfig->module->formats[0].inputs, dfw->in_fmt,
MAX_IN_QUEUE);
skl_tplg_fill_fmt_v4(mconfig->module->formats[0].outputs, dfw->out_fmt,
MAX_OUT_QUEUE);
mconfig->params_fixup = dfw->params_fixup;
mconfig->converter = dfw->converter;
mconfig->m_type = dfw->module_type;
mconfig->vbus_id = dfw->vbus_id;
mconfig->module->resources[0].is_pages = dfw->mem_pages;
ret = skl_tplg_add_pipe_v4(dev, mconfig, skl, &dfw->pipe);
if (ret)
return ret;
mconfig->dev_type = dfw->dev_type;
mconfig->hw_conn_type = dfw->hw_conn_type;
mconfig->time_slot = dfw->time_slot;
mconfig->formats_config.caps_size = dfw->caps.caps_size;
mconfig->m_in_pin = devm_kzalloc(dev,
MAX_IN_QUEUE * sizeof(*mconfig->m_in_pin),
GFP_KERNEL);
if (!mconfig->m_in_pin)
return -ENOMEM;
mconfig->m_out_pin = devm_kzalloc(dev,
MAX_OUT_QUEUE * sizeof(*mconfig->m_out_pin),
GFP_KERNEL);
if (!mconfig->m_out_pin)
return -ENOMEM;
skl_fill_module_pin_info_v4(dfw->in_pin, mconfig->m_in_pin,
dfw->is_dynamic_in_pin,
mconfig->module->max_input_pins);
skl_fill_module_pin_info_v4(dfw->out_pin, mconfig->m_out_pin,
dfw->is_dynamic_out_pin,
mconfig->module->max_output_pins);
if (mconfig->formats_config.caps_size) {
mconfig->formats_config.set_params = dfw->caps.set_params;
mconfig->formats_config.param_id = dfw->caps.param_id;
mconfig->formats_config.caps =
devm_kzalloc(dev, mconfig->formats_config.caps_size,
GFP_KERNEL);
if (!mconfig->formats_config.caps)
return -ENOMEM;
memcpy(mconfig->formats_config.caps, dfw->caps.caps,
dfw->caps.caps_size);
}
return 0;
}
/*
* Parse the private data for the token and corresponding value.
* The private data can have multiple data blocks. So, a data block
@@ -2739,6 +2901,13 @@ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
char *data;
int ret;
/*
* v4 configuration files have a valid UUID at the start of
* the widget's private data.
*/
if (uuid_is_valid((char *)tplg_w->priv.data))
return skl_tplg_get_pvt_data_v4(tplg_w, skl, dev, mconfig);
/* Read the NUM_DATA_BLOCKS descriptor */
array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data;
ret = skl_tplg_get_desc_blocks(dev, array);

View File

@@ -25,8 +25,8 @@
#include <sound/hdaudio_ext.h>
#include <sound/soc.h>
#include <uapi/sound/skl-tplg-interface.h>
#include "skl.h"
#include "skl-tplg-interface.h"
#define BITS_PER_BYTE 8
#define MAX_TS_GROUPS 8

View File

@@ -1,172 +0,0 @@
/*
* skl-tplg-interface.h - Intel DSP FW private data interface
*
* Copyright (C) 2015 Intel Corp
* Author: Jeeja KP <jeeja.kp@intel.com>
* Nilofer, Samreen <samreen.nilofer@intel.com>
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as 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.
*/
#ifndef __HDA_TPLG_INTERFACE_H__
#define __HDA_TPLG_INTERFACE_H__
/*
* Default types range from 0~12. type can range from 0 to 0xff
* SST types start at higher to avoid any overlapping in future
*/
#define SKL_CONTROL_TYPE_BYTE_TLV 0x100
#define SKL_CONTROL_TYPE_MIC_SELECT 0x102
#define HDA_SST_CFG_MAX 900 /* size of copier cfg*/
#define MAX_IN_QUEUE 8
#define MAX_OUT_QUEUE 8
#define SKL_UUID_STR_SZ 40
/* Event types goes here */
/* Reserve event type 0 for no event handlers */
enum skl_event_types {
SKL_EVENT_NONE = 0,
SKL_MIXER_EVENT,
SKL_MUX_EVENT,
SKL_VMIXER_EVENT,
SKL_PGA_EVENT
};
/**
* enum skl_ch_cfg - channel configuration
*
* @SKL_CH_CFG_MONO: One channel only
* @SKL_CH_CFG_STEREO: L & R
* @SKL_CH_CFG_2_1: L, R & LFE
* @SKL_CH_CFG_3_0: L, C & R
* @SKL_CH_CFG_3_1: L, C, R & LFE
* @SKL_CH_CFG_QUATRO: L, R, Ls & Rs
* @SKL_CH_CFG_4_0: L, C, R & Cs
* @SKL_CH_CFG_5_0: L, C, R, Ls & Rs
* @SKL_CH_CFG_5_1: L, C, R, Ls, Rs & LFE
* @SKL_CH_CFG_DUAL_MONO: One channel replicated in two
* @SKL_CH_CFG_I2S_DUAL_STEREO_0: Stereo(L,R) in 4 slots, 1st stream:[ L, R, -, - ]
* @SKL_CH_CFG_I2S_DUAL_STEREO_1: Stereo(L,R) in 4 slots, 2nd stream:[ -, -, L, R ]
* @SKL_CH_CFG_INVALID: Invalid
*/
enum skl_ch_cfg {
SKL_CH_CFG_MONO = 0,
SKL_CH_CFG_STEREO = 1,
SKL_CH_CFG_2_1 = 2,
SKL_CH_CFG_3_0 = 3,
SKL_CH_CFG_3_1 = 4,
SKL_CH_CFG_QUATRO = 5,
SKL_CH_CFG_4_0 = 6,
SKL_CH_CFG_5_0 = 7,
SKL_CH_CFG_5_1 = 8,
SKL_CH_CFG_DUAL_MONO = 9,
SKL_CH_CFG_I2S_DUAL_STEREO_0 = 10,
SKL_CH_CFG_I2S_DUAL_STEREO_1 = 11,
SKL_CH_CFG_4_CHANNEL = 12,
SKL_CH_CFG_INVALID
};
enum skl_module_type {
SKL_MODULE_TYPE_MIXER = 0,
SKL_MODULE_TYPE_COPIER,
SKL_MODULE_TYPE_UPDWMIX,
SKL_MODULE_TYPE_SRCINT,
SKL_MODULE_TYPE_ALGO,
SKL_MODULE_TYPE_BASE_OUTFMT,
SKL_MODULE_TYPE_KPB,
SKL_MODULE_TYPE_MIC_SELECT,
};
enum skl_core_affinity {
SKL_AFFINITY_CORE_0 = 0,
SKL_AFFINITY_CORE_1,
SKL_AFFINITY_CORE_MAX
};
enum skl_pipe_conn_type {
SKL_PIPE_CONN_TYPE_NONE = 0,
SKL_PIPE_CONN_TYPE_FE,
SKL_PIPE_CONN_TYPE_BE
};
enum skl_hw_conn_type {
SKL_CONN_NONE = 0,
SKL_CONN_SOURCE = 1,
SKL_CONN_SINK = 2
};
enum skl_dev_type {
SKL_DEVICE_BT = 0x0,
SKL_DEVICE_DMIC = 0x1,
SKL_DEVICE_I2S = 0x2,
SKL_DEVICE_SLIMBUS = 0x3,
SKL_DEVICE_HDALINK = 0x4,
SKL_DEVICE_HDAHOST = 0x5,
SKL_DEVICE_NONE
};
/**
* enum skl_interleaving - interleaving style
*
* @SKL_INTERLEAVING_PER_CHANNEL: [s1_ch1...s1_chN,...,sM_ch1...sM_chN]
* @SKL_INTERLEAVING_PER_SAMPLE: [s1_ch1...sM_ch1,...,s1_chN...sM_chN]
*/
enum skl_interleaving {
SKL_INTERLEAVING_PER_CHANNEL = 0,
SKL_INTERLEAVING_PER_SAMPLE = 1,
};
enum skl_sample_type {
SKL_SAMPLE_TYPE_INT_MSB = 0,
SKL_SAMPLE_TYPE_INT_LSB = 1,
SKL_SAMPLE_TYPE_INT_SIGNED = 2,
SKL_SAMPLE_TYPE_INT_UNSIGNED = 3,
SKL_SAMPLE_TYPE_FLOAT = 4
};
enum module_pin_type {
/* All pins of the module takes same PCM inputs or outputs
* e.g. mixout
*/
SKL_PIN_TYPE_HOMOGENEOUS,
/* All pins of the module takes different PCM inputs or outputs
* e.g mux
*/
SKL_PIN_TYPE_HETEROGENEOUS,
};
enum skl_module_param_type {
SKL_PARAM_DEFAULT = 0,
SKL_PARAM_INIT,
SKL_PARAM_SET,
SKL_PARAM_BIND
};
struct skl_dfw_algo_data {
u32 set_params:2;
u32 rsvd:30;
u32 param_id;
u32 max;
char params[0];
} __packed;
enum skl_tkn_dir {
SKL_DIR_IN,
SKL_DIR_OUT
};
enum skl_tuple_type {
SKL_TYPE_TUPLE,
SKL_TYPE_DATA
};
#endif

View File

@@ -127,10 +127,17 @@ static void skl_clock_power_gating(struct device *dev, bool enable)
*/
static int skl_init_chip(struct hdac_bus *bus, bool full_reset)
{
struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
struct hdac_ext_link *hlink;
int ret;
skl_enable_miscbdcge(bus->dev, false);
ret = snd_hdac_bus_init_chip(bus, full_reset);
/* Reset stream-to-link mapping */
list_for_each_entry(hlink, &ebus->hlink_list, list)
bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
skl_enable_miscbdcge(bus->dev, true);
return ret;

View File

@@ -1,7 +1,6 @@
config SND_KIRKWOOD_SOC
tristate "SoC Audio for the Marvell Kirkwood and Dove chips"
depends on ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST
depends on HAS_DMA
help
Say Y or M if you want to add support for codecs attached to
the Kirkwood I2S interface. You will also need to select the

View File

@@ -32,6 +32,26 @@ config SND_SOC_MT2701_WM8960
Select Y if you have such device.
If unsure select "N".
config SND_SOC_MT6797
tristate "ASoC support for Mediatek MT6797 chip"
depends on ARCH_MEDIATEK
select SND_SOC_MEDIATEK
help
This adds ASoC driver for Mediatek MT6797 boards
that can be used with other codecs.
Select Y if you have such device.
If unsure select "N".
config SND_SOC_MT6797_MT6351
tristate "ASoc Audio driver for MT6797 with MT6351 codec"
depends on SND_SOC_MT6797 && MTK_PMIC_WRAP
select SND_SOC_MT6351
help
This adds ASoC driver for Mediatek MT6797 boards
with the MT6351 codecs.
Select Y if you have such device.
If unsure select "N".
config SND_SOC_MT8173
tristate "ASoC support for Mediatek MT8173 chip"
depends on ARCH_MEDIATEK

View File

@@ -1,3 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_SND_SOC_MEDIATEK) += common/
obj-$(CONFIG_SND_SOC_MT2701) += mt2701/
obj-$(CONFIG_SND_SOC_MT6797) += mt6797/
obj-$(CONFIG_SND_SOC_MT8173) += mt8173/

View File

@@ -1,16 +1,4 @@
#
# Copyright (C) 2015 MediaTek 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.
#
# SPDX-License-Identifier: GPL-2.0
# platform driver
snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o
obj-$(CONFIG_SND_SOC_MEDIATEK) += snd-soc-mtk-common.o

View File

@@ -1,17 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/*
* mtk-afe-fe-dais.c -- Mediatek afe fe dai operator
*
* Copyright (c) 2016 MediaTek Inc.
* Author: Garlic Tseng <garlic.tseng@mediatek.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 and
* only 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/module.h>
@@ -44,8 +36,7 @@ int mtk_afe_fe_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
struct snd_pcm_runtime *runtime = substream->runtime;
int memif_num = rtd->cpu_dai->id;
struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
@@ -107,8 +98,7 @@ void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
int irq_id;
@@ -131,8 +121,7 @@ int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
int msb_at_bit33 = 0;
int ret, fs = 0;
@@ -196,8 +185,7 @@ int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_pcm_runtime * const runtime = substream->runtime;
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage];
const struct mtk_base_irq_data *irq_data = irqs->irq_data;
@@ -260,8 +248,7 @@ int mtk_afe_fe_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
int hd_audio = 0;
@@ -333,7 +320,7 @@ EXPORT_SYMBOL_GPL(mtk_dynamic_irq_release);
int mtk_afe_dai_suspend(struct snd_soc_dai *dai)
{
struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
struct device *dev = afe->dev;
struct regmap *regmap = afe->regmap;
int i;
@@ -358,7 +345,7 @@ EXPORT_SYMBOL_GPL(mtk_afe_dai_suspend);
int mtk_afe_dai_resume(struct snd_soc_dai *dai)
{
struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
struct device *dev = afe->dev;
struct regmap *regmap = afe->regmap;
int i = 0;
@@ -383,4 +370,3 @@ EXPORT_SYMBOL_GPL(mtk_afe_dai_resume);
MODULE_DESCRIPTION("Mediatek simple fe dai operator");
MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
MODULE_LICENSE("GPL v2");

View File

@@ -1,17 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* mtk-afe-fe-dais.h -- Mediatek afe fe dai operator definition
*
* Copyright (c) 2016 MediaTek Inc.
* Author: Garlic Tseng <garlic.tseng@mediatek.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 and
* only 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.
*/
#ifndef _MTK_AFE_FE_DAI_H_

View File

@@ -1,17 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/*
* mtk-afe-platform-driver.c -- Mediatek afe platform driver
*
* Copyright (c) 2016 MediaTek Inc.
* Author: Garlic Tseng <garlic.tseng@mediatek.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 and
* only 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/module.h>
@@ -21,6 +13,86 @@
#include "mtk-afe-platform-driver.h"
#include "mtk-base-afe.h"
int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe)
{
struct snd_soc_dai_driver *sub_dai_drivers;
size_t num_dai_drivers = 0, dai_idx = 0;
int i;
if (!afe->sub_dais) {
dev_err(afe->dev, "%s(), sub_dais == NULL\n", __func__);
return -EINVAL;
}
/* calcualte total dai driver size */
for (i = 0; i < afe->num_sub_dais; i++) {
if (afe->sub_dais[i].dai_drivers &&
afe->sub_dais[i].num_dai_drivers != 0)
num_dai_drivers += afe->sub_dais[i].num_dai_drivers;
}
dev_info(afe->dev, "%s(), num of dai %zd\n", __func__, num_dai_drivers);
/* combine sub_dais */
afe->num_dai_drivers = num_dai_drivers;
afe->dai_drivers = devm_kcalloc(afe->dev,
num_dai_drivers,
sizeof(struct snd_soc_dai_driver),
GFP_KERNEL);
if (!afe->dai_drivers)
return -ENOMEM;
for (i = 0; i < afe->num_sub_dais; i++) {
if (afe->sub_dais[i].dai_drivers &&
afe->sub_dais[i].num_dai_drivers != 0) {
sub_dai_drivers = afe->sub_dais[i].dai_drivers;
/* dai driver */
memcpy(&afe->dai_drivers[dai_idx],
sub_dai_drivers,
afe->sub_dais[i].num_dai_drivers *
sizeof(struct snd_soc_dai_driver));
dai_idx += afe->sub_dais[i].num_dai_drivers;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(mtk_afe_combine_sub_dai);
int mtk_afe_add_sub_dai_control(struct snd_soc_component *component)
{
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
int i;
if (!afe->sub_dais) {
dev_err(afe->dev, "%s(), sub_dais == NULL\n", __func__);
return -EINVAL;
}
for (i = 0; i < afe->num_sub_dais; i++) {
if (afe->sub_dais[i].controls)
snd_soc_add_component_controls(component,
afe->sub_dais[i].controls,
afe->sub_dais[i].num_controls);
if (afe->sub_dais[i].dapm_widgets)
snd_soc_dapm_new_controls(&component->dapm,
afe->sub_dais[i].dapm_widgets,
afe->sub_dais[i].num_dapm_widgets);
if (afe->sub_dais[i].dapm_routes)
snd_soc_dapm_add_routes(&component->dapm,
afe->sub_dais[i].dapm_routes,
afe->sub_dais[i].num_dapm_routes);
}
snd_soc_dapm_new_widgets(component->dapm.card);
return 0;
}
EXPORT_SYMBOL_GPL(mtk_afe_add_sub_dai_control);
static snd_pcm_uframes_t mtk_afe_pcm_pointer
(struct snd_pcm_substream *substream)
{
@@ -56,28 +128,31 @@ POINTER_RETURN_FRAMES:
return bytes_to_frames(substream->runtime, pcm_ptr_bytes);
}
static const struct snd_pcm_ops mtk_afe_pcm_ops = {
const struct snd_pcm_ops mtk_afe_pcm_ops = {
.ioctl = snd_pcm_lib_ioctl,
.pointer = mtk_afe_pcm_pointer,
};
EXPORT_SYMBOL_GPL(mtk_afe_pcm_ops);
static int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd)
int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
size_t size;
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
size = afe->mtk_afe_hardware->buffer_bytes_max;
return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
card->dev, size, size);
afe->dev,
size, size);
}
EXPORT_SYMBOL_GPL(mtk_afe_pcm_new);
static void mtk_afe_pcm_free(struct snd_pcm *pcm)
void mtk_afe_pcm_free(struct snd_pcm *pcm)
{
snd_pcm_lib_preallocate_free_for_all(pcm);
}
EXPORT_SYMBOL_GPL(mtk_afe_pcm_free);
const struct snd_soc_component_driver mtk_afe_pcm_platform = {
.name = AFE_PCM_NAME,

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