Commit 3e4555ab authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'asoc/topic/intel' into asoc-next

parents 7c310f16 987da3fe
...@@ -50,9 +50,6 @@ snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], ...@@ -50,9 +50,6 @@ snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
struct snd_soc_acpi_mach * struct snd_soc_acpi_mach *
snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines); snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines);
/* acpi check hid */
bool snd_soc_acpi_check_hid(const u8 hid[ACPI_ID_LEN]);
/** /**
* snd_soc_acpi_mach: ACPI-based machine descriptor. Most of the fields are * snd_soc_acpi_mach: ACPI-based machine descriptor. Most of the fields are
* related to the hardware, except for the firmware and topology file names. * related to the hardware, except for the firmware and topology file names.
......
...@@ -222,6 +222,17 @@ ...@@ -222,6 +222,17 @@
* %SKL_TKN_MM_U32_NUM_IN_FMT: Number of input formats * %SKL_TKN_MM_U32_NUM_IN_FMT: Number of input formats
* %SKL_TKN_MM_U32_NUM_OUT_FMT: Number of output formats * %SKL_TKN_MM_U32_NUM_OUT_FMT: Number of output formats
* *
* %SKL_TKN_U32_ASTATE_IDX: Table Index for the A-State entry to be filled
* with kcps and clock source
*
* %SKL_TKN_U32_ASTATE_COUNT: Number of valid entries in A-State table
*
* %SKL_TKN_U32_ASTATE_KCPS: Specifies the core load threshold (in kilo
* cycles per second) below which DSP is clocked
* from source specified by clock source.
*
* %SKL_TKN_U32_ASTATE_CLK_SRC: Clock source for A-State entry
*
* module_id and loadable flags dont have tokens as these values will be * module_id and loadable flags dont have tokens as these values will be
* read from the DSP FW manifest * read from the DSP FW manifest
* *
...@@ -309,7 +320,11 @@ enum SKL_TKNS { ...@@ -309,7 +320,11 @@ enum SKL_TKNS {
SKL_TKN_MM_U32_NUM_IN_FMT, SKL_TKN_MM_U32_NUM_IN_FMT,
SKL_TKN_MM_U32_NUM_OUT_FMT, SKL_TKN_MM_U32_NUM_OUT_FMT,
SKL_TKN_MAX = SKL_TKN_MM_U32_NUM_OUT_FMT, SKL_TKN_U32_ASTATE_IDX,
SKL_TKN_U32_ASTATE_COUNT,
SKL_TKN_U32_ASTATE_KCPS,
SKL_TKN_U32_ASTATE_CLK_SRC,
SKL_TKN_MAX = SKL_TKN_U32_ASTATE_CLK_SRC,
}; };
#endif #endif
...@@ -133,7 +133,6 @@ config SND_SOC_ALL_CODECS ...@@ -133,7 +133,6 @@ config SND_SOC_ALL_CODECS
select SND_SOC_SGTL5000 if I2C select SND_SOC_SGTL5000 if I2C
select SND_SOC_SI476X if MFD_SI476X_CORE select SND_SOC_SI476X if MFD_SI476X_CORE
select SND_SOC_SIRF_AUDIO_CODEC select SND_SOC_SIRF_AUDIO_CODEC
select SND_SOC_SN95031 if INTEL_SCU_IPC
select SND_SOC_SPDIF select SND_SOC_SPDIF
select SND_SOC_SSM2518 if I2C select SND_SOC_SSM2518 if I2C
select SND_SOC_SSM2602_SPI if SPI_MASTER select SND_SOC_SSM2602_SPI if SPI_MASTER
...@@ -818,9 +817,6 @@ config SND_SOC_SIRF_AUDIO_CODEC ...@@ -818,9 +817,6 @@ config SND_SOC_SIRF_AUDIO_CODEC
tristate "SiRF SoC internal audio codec" tristate "SiRF SoC internal audio codec"
select REGMAP_MMIO select REGMAP_MMIO
config SND_SOC_SN95031
tristate
config SND_SOC_SPDIF config SND_SOC_SPDIF
tristate "S/PDIF CODEC" tristate "S/PDIF CODEC"
......
...@@ -140,7 +140,6 @@ snd-soc-sigmadsp-i2c-objs := sigmadsp-i2c.o ...@@ -140,7 +140,6 @@ snd-soc-sigmadsp-i2c-objs := sigmadsp-i2c.o
snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o
snd-soc-si476x-objs := si476x.o snd-soc-si476x-objs := si476x.o
snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o
snd-soc-sn95031-objs := sn95031.o
snd-soc-spdif-tx-objs := spdif_transmitter.o snd-soc-spdif-tx-objs := spdif_transmitter.o
snd-soc-spdif-rx-objs := spdif_receiver.o snd-soc-spdif-rx-objs := spdif_receiver.o
snd-soc-ssm2518-objs := ssm2518.o snd-soc-ssm2518-objs := ssm2518.o
......
/*
* sn95031.c - TI sn95031 Codec driver
*
* Copyright (C) 2010 Intel Corp
* Author: Vinod Koul <vinod.koul@intel.com>
* Author: Harsha Priya <priya.harsha@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 published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <asm/intel_scu_ipc.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/jack.h>
#include "sn95031.h"
#define SN95031_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100)
#define SN95031_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
/* adc helper functions */
/* enables mic bias voltage */
static void sn95031_enable_mic_bias(struct snd_soc_codec *codec)
{
snd_soc_write(codec, SN95031_VAUD, BIT(2)|BIT(1)|BIT(0));
snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(2), BIT(2));
}
/* Enable/Disable the ADC depending on the argument */
static void configure_adc(struct snd_soc_codec *sn95031_codec, int val)
{
int value = snd_soc_read(sn95031_codec, SN95031_ADC1CNTL1);
if (val) {
/* Enable and start the ADC */
value |= (SN95031_ADC_ENBL | SN95031_ADC_START);
value &= (~SN95031_ADC_NO_LOOP);
} else {
/* Just stop the ADC */
value &= (~SN95031_ADC_START);
}
snd_soc_write(sn95031_codec, SN95031_ADC1CNTL1, value);
}
/*
* finds an empty channel for conversion
* If the ADC is not enabled then start using 0th channel
* itself. Otherwise find an empty channel by looking for a
* channel in which the stopbit is set to 1. returns the index
* of the first free channel if succeeds or an error code.
*
* Context: can sleep
*
*/
static int find_free_channel(struct snd_soc_codec *sn95031_codec)
{
int i, value;
/* check whether ADC is enabled */
value = snd_soc_read(sn95031_codec, SN95031_ADC1CNTL1);
if ((value & SN95031_ADC_ENBL) == 0)
return 0;
/* ADC is already enabled; Looking for an empty channel */
for (i = 0; i < SN95031_ADC_CHANLS_MAX; i++) {
value = snd_soc_read(sn95031_codec,
SN95031_ADC_CHNL_START_ADDR + i);
if (value & SN95031_STOPBIT_MASK)
break;
}
return (i == SN95031_ADC_CHANLS_MAX) ? (-EINVAL) : i;
}
/* Initialize the ADC for reading micbias values. Can sleep. */
static int sn95031_initialize_adc(struct snd_soc_codec *sn95031_codec)
{
int base_addr, chnl_addr;
int value;
int channel_index;
/* Index of the first channel in which the stop bit is set */
channel_index = find_free_channel(sn95031_codec);
if (channel_index < 0) {
pr_err("No free ADC channels");
return channel_index;
}
base_addr = SN95031_ADC_CHNL_START_ADDR + channel_index;
if (!(channel_index == 0 || channel_index == SN95031_ADC_LOOP_MAX)) {
/* Reset stop bit for channels other than 0 and 12 */
value = snd_soc_read(sn95031_codec, base_addr);
/* Set the stop bit to zero */
snd_soc_write(sn95031_codec, base_addr, value & 0xEF);
/* Index of the first free channel */
base_addr++;
channel_index++;
}
/* Since this is the last channel, set the stop bit
to 1 by ORing the DIE_SENSOR_CODE with 0x10 */
snd_soc_write(sn95031_codec, base_addr,
SN95031_AUDIO_DETECT_CODE | 0x10);
chnl_addr = SN95031_ADC_DATA_START_ADDR + 2 * channel_index;
pr_debug("mid_initialize : %x", chnl_addr);
configure_adc(sn95031_codec, 1);
return chnl_addr;
}
/* reads the ADC registers and gets the mic bias value in mV. */
static unsigned int sn95031_get_mic_bias(struct snd_soc_codec *codec)
{
u16 adc_adr = sn95031_initialize_adc(codec);
u16 adc_val1, adc_val2;
unsigned int mic_bias;
sn95031_enable_mic_bias(codec);
/* Enable the sound card for conversion before reading */
snd_soc_write(codec, SN95031_ADC1CNTL3, 0x05);
/* Re-toggle the RRDATARD bit */
snd_soc_write(codec, SN95031_ADC1CNTL3, 0x04);
/* Read the higher bits of data */
msleep(1000);
adc_val1 = snd_soc_read(codec, adc_adr);
adc_adr++;
adc_val2 = snd_soc_read(codec, adc_adr);
/* Adding lower two bits to the higher bits */
mic_bias = (adc_val1 << 2) + (adc_val2 & 3);
mic_bias = (mic_bias * SN95031_ADC_ONE_LSB_MULTIPLIER) / 1000;
pr_debug("mic bias = %dmV\n", mic_bias);
return mic_bias;
}
/*end - adc helper functions */
static int sn95031_read(void *ctx, unsigned int reg, unsigned int *val)
{
u8 value = 0;
int ret;
ret = intel_scu_ipc_ioread8(reg, &value);
if (ret == 0)
*val = value;
return ret;
}
static int sn95031_write(void *ctx, unsigned int reg, unsigned int value)
{
return intel_scu_ipc_iowrite8(reg, value);
}
static const struct regmap_config sn95031_regmap = {
.reg_read = sn95031_read,
.reg_write = sn95031_write,
};
static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
switch (level) {
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
pr_debug("vaud_bias powering up pll\n");
/* power up the pll */
snd_soc_write(codec, SN95031_AUDPLLCTRL, BIT(5));
/* enable pcm 2 */
snd_soc_update_bits(codec, SN95031_PCM2C2,
BIT(0), BIT(0));
}
break;
case SND_SOC_BIAS_STANDBY:
switch (snd_soc_codec_get_bias_level(codec)) {
case SND_SOC_BIAS_OFF:
pr_debug("vaud_bias power up rail\n");
/* power up the rail */
snd_soc_write(codec, SN95031_VAUD,
BIT(2)|BIT(1)|BIT(0));
msleep(1);
break;
case SND_SOC_BIAS_PREPARE:
/* turn off pcm */
pr_debug("vaud_bias power dn pcm\n");
snd_soc_update_bits(codec, SN95031_PCM2C2, BIT(0), 0);
snd_soc_write(codec, SN95031_AUDPLLCTRL, 0);
break;
default:
break;
}
break;
case SND_SOC_BIAS_OFF:
pr_debug("vaud_bias _OFF doing rail shutdown\n");
snd_soc_write(codec, SN95031_VAUD, BIT(3));
break;
}
return 0;
}
static int sn95031_vhs_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
if (SND_SOC_DAPM_EVENT_ON(event)) {
pr_debug("VHS SND_SOC_DAPM_EVENT_ON doing rail startup now\n");
/* power up the rail */
snd_soc_write(codec, SN95031_VHSP, 0x3D);
snd_soc_write(codec, SN95031_VHSN, 0x3F);
msleep(1);
} else if (SND_SOC_DAPM_EVENT_OFF(event)) {
pr_debug("VHS SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n");
snd_soc_write(codec, SN95031_VHSP, 0xC4);
snd_soc_write(codec, SN95031_VHSN, 0x04);
}
return 0;
}
static int sn95031_vihf_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
if (SND_SOC_DAPM_EVENT_ON(event)) {
pr_debug("VIHF SND_SOC_DAPM_EVENT_ON doing rail startup now\n");
/* power up the rail */
snd_soc_write(codec, SN95031_VIHF, 0x27);
msleep(1);
} else if (SND_SOC_DAPM_EVENT_OFF(event)) {
pr_debug("VIHF SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n");
snd_soc_write(codec, SN95031_VIHF, 0x24);
}
return 0;
}
static int sn95031_dmic12_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
unsigned int ldo = 0, clk_dir = 0, data_dir = 0;
if (SND_SOC_DAPM_EVENT_ON(event)) {
ldo = BIT(5)|BIT(4);
clk_dir = BIT(0);
data_dir = BIT(7);
}
/* program DMIC LDO, clock and set clock */
snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo);
snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(0), clk_dir);
snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(7), data_dir);
return 0;
}
static int sn95031_dmic34_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
unsigned int ldo = 0, clk_dir = 0, data_dir = 0;
if (SND_SOC_DAPM_EVENT_ON(event)) {
ldo = BIT(5)|BIT(4);
clk_dir = BIT(2);
data_dir = BIT(1);
}
/* program DMIC LDO, clock and set clock */
snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo);
snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(2), clk_dir);
snd_soc_update_bits(codec, SN95031_DMICBUF45, BIT(1), data_dir);
return 0;
}
static int sn95031_dmic56_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
unsigned int ldo = 0;
if (SND_SOC_DAPM_EVENT_ON(event))
ldo = BIT(7)|BIT(6);
/* program DMIC LDO */
snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(7)|BIT(6), ldo);
return 0;
}
/* mux controls */
static const char *sn95031_mic_texts[] = { "AMIC", "LineIn" };
static SOC_ENUM_SINGLE_DECL(sn95031_micl_enum,
SN95031_ADCCONFIG, 1, sn95031_mic_texts);
static const struct snd_kcontrol_new sn95031_micl_mux_control =
SOC_DAPM_ENUM("Route", sn95031_micl_enum);
static SOC_ENUM_SINGLE_DECL(sn95031_micr_enum,
SN95031_ADCCONFIG, 3, sn95031_mic_texts);
static const struct snd_kcontrol_new sn95031_micr_mux_control =
SOC_DAPM_ENUM("Route", sn95031_micr_enum);
static const char *sn95031_input_texts[] = { "DMIC1", "DMIC2", "DMIC3",
"DMIC4", "DMIC5", "DMIC6",
"ADC Left", "ADC Right" };
static SOC_ENUM_SINGLE_DECL(sn95031_input1_enum,
SN95031_AUDIOMUX12, 0, sn95031_input_texts);
static const struct snd_kcontrol_new sn95031_input1_mux_control =
SOC_DAPM_ENUM("Route", sn95031_input1_enum);
static SOC_ENUM_SINGLE_DECL(sn95031_input2_enum,
SN95031_AUDIOMUX12, 4, sn95031_input_texts);
static const struct snd_kcontrol_new sn95031_input2_mux_control =
SOC_DAPM_ENUM("Route", sn95031_input2_enum);
static SOC_ENUM_SINGLE_DECL(sn95031_input3_enum,
SN95031_AUDIOMUX34, 0, sn95031_input_texts);
static const struct snd_kcontrol_new sn95031_input3_mux_control =
SOC_DAPM_ENUM("Route", sn95031_input3_enum);
static SOC_ENUM_SINGLE_DECL(sn95031_input4_enum,
SN95031_AUDIOMUX34, 4, sn95031_input_texts);
static const struct snd_kcontrol_new sn95031_input4_mux_control =
SOC_DAPM_ENUM("Route", sn95031_input4_enum);
/* capture path controls */
static const char *sn95031_micmode_text[] = {"Single Ended", "Differential"};
/* 0dB to 30dB in 10dB steps */
static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 10, 0);
static SOC_ENUM_SINGLE_DECL(sn95031_micmode1_enum,
SN95031_MICAMP1, 1, sn95031_micmode_text);
static SOC_ENUM_SINGLE_DECL(sn95031_micmode2_enum,
SN95031_MICAMP2, 1, sn95031_micmode_text);
static const char *sn95031_dmic_cfg_text[] = {"GPO", "DMIC"};
static SOC_ENUM_SINGLE_DECL(sn95031_dmic12_cfg_enum,
SN95031_DMICMUX, 0, sn95031_dmic_cfg_text);
static SOC_ENUM_SINGLE_DECL(sn95031_dmic34_cfg_enum,
SN95031_DMICMUX, 1, sn95031_dmic_cfg_text);
static SOC_ENUM_SINGLE_DECL(sn95031_dmic56_cfg_enum,
SN95031_DMICMUX, 2, sn95031_dmic_cfg_text);
static const struct snd_kcontrol_new sn95031_snd_controls[] = {
SOC_ENUM("Mic1Mode Capture Route", sn95031_micmode1_enum),
SOC_ENUM("Mic2Mode Capture Route", sn95031_micmode2_enum),
SOC_ENUM("DMIC12 Capture Route", sn95031_dmic12_cfg_enum),
SOC_ENUM("DMIC34 Capture Route", sn95031_dmic34_cfg_enum),
SOC_ENUM("DMIC56 Capture Route", sn95031_dmic56_cfg_enum),
SOC_SINGLE_TLV("Mic1 Capture Volume", SN95031_MICAMP1,
2, 4, 0, mic_tlv),
SOC_SINGLE_TLV("Mic2 Capture Volume", SN95031_MICAMP2,
2, 4, 0, mic_tlv),
};
/* DAPM widgets */
static const struct snd_soc_dapm_widget sn95031_dapm_widgets[] = {
/* all end points mic, hs etc */
SND_SOC_DAPM_OUTPUT("HPOUTL"),
SND_SOC_DAPM_OUTPUT("HPOUTR"),
SND_SOC_DAPM_OUTPUT("EPOUT"),
SND_SOC_DAPM_OUTPUT("IHFOUTL"),
SND_SOC_DAPM_OUTPUT("IHFOUTR"),
SND_SOC_DAPM_OUTPUT("LINEOUTL"),
SND_SOC_DAPM_OUTPUT("LINEOUTR"),
SND_SOC_DAPM_OUTPUT("VIB1OUT"),
SND_SOC_DAPM_OUTPUT("VIB2OUT"),
SND_SOC_DAPM_INPUT("AMIC1"), /* headset mic */
SND_SOC_DAPM_INPUT("AMIC2"),
SND_SOC_DAPM_INPUT("DMIC1"),
SND_SOC_DAPM_INPUT("DMIC2"),
SND_SOC_DAPM_INPUT("DMIC3"),
SND_SOC_DAPM_INPUT("DMIC4"),
SND_SOC_DAPM_INPUT("DMIC5"),
SND_SOC_DAPM_INPUT("DMIC6"),
SND_SOC_DAPM_INPUT("LINEINL"),
SND_SOC_DAPM_INPUT("LINEINR"),
SND_SOC_DAPM_MICBIAS("AMIC1Bias", SN95031_MICBIAS, 2, 0),
SND_SOC_DAPM_MICBIAS("AMIC2Bias", SN95031_MICBIAS, 3, 0),
SND_SOC_DAPM_MICBIAS("DMIC12Bias", SN95031_DMICMUX, 3, 0),
SND_SOC_DAPM_MICBIAS("DMIC34Bias", SN95031_DMICMUX, 4, 0),
SND_SOC_DAPM_MICBIAS("DMIC56Bias", SN95031_DMICMUX, 5, 0),
SND_SOC_DAPM_SUPPLY("DMIC12supply", SN95031_DMICLK, 0, 0,
sn95031_dmic12_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("DMIC34supply", SN95031_DMICLK, 1, 0,
sn95031_dmic34_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("DMIC56supply", SN95031_DMICLK, 2, 0,
sn95031_dmic56_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_AIF_OUT("PCM_Out", "Capture", 0,
SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_SUPPLY("Headset Rail", SND_SOC_NOPM, 0, 0,
sn95031_vhs_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("Speaker Rail", SND_SOC_NOPM, 0, 0,
sn95031_vihf_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
/* playback path driver enables */
SND_SOC_DAPM_PGA("Headset Left Playback",
SN95031_DRIVEREN, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("Headset Right Playback",
SN95031_DRIVEREN, 1, 0, NULL, 0),
SND_SOC_DAPM_PGA("Speaker Left Playback",
SN95031_DRIVEREN, 2, 0, NULL, 0),
SND_SOC_DAPM_PGA("Speaker Right Playback",
SN95031_DRIVEREN, 3, 0, NULL, 0),
SND_SOC_DAPM_PGA("Vibra1 Playback",
SN95031_DRIVEREN, 4, 0, NULL, 0),
SND_SOC_DAPM_PGA("Vibra2 Playback",
SN95031_DRIVEREN, 5, 0, NULL, 0),
SND_SOC_DAPM_PGA("Earpiece Playback",
SN95031_DRIVEREN, 6, 0, NULL, 0),
SND_SOC_DAPM_PGA("Lineout Left Playback",
SN95031_LOCTL, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("Lineout Right Playback",
SN95031_LOCTL, 4, 0, NULL, 0),
/* playback path filter enable */
SND_SOC_DAPM_PGA("Headset Left Filter",
SN95031_HSEPRXCTRL, 4, 0, NULL, 0),
SND_SOC_DAPM_PGA("Headset Right Filter",
SN95031_HSEPRXCTRL, 5, 0, NULL, 0),
SND_SOC_DAPM_PGA("Speaker Left Filter",
SN95031_IHFRXCTRL, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("Speaker Right Filter",
SN95031_IHFRXCTRL, 1, 0, NULL, 0),
/* DACs */
SND_SOC_DAPM_DAC("HSDAC Left", "Headset",
SN95031_DACCONFIG, 0, 0),
SND_SOC_DAPM_DAC("HSDAC Right", "Headset",
SN95031_DACCONFIG, 1, 0),
SND_SOC_DAPM_DAC("IHFDAC Left", "Speaker",
SN95031_DACCONFIG, 2, 0),
SND_SOC_DAPM_DAC("IHFDAC Right", "Speaker",
SN95031_DACCONFIG, 3, 0),
SND_SOC_DAPM_DAC("Vibra1 DAC", "Vibra1",
SN95031_VIB1C5, 1, 0),
SND_SOC_DAPM_DAC("Vibra2 DAC", "Vibra2",
SN95031_VIB2C5, 1, 0),
/* capture widgets */
SND_SOC_DAPM_PGA("LineIn Enable Left", SN95031_MICAMP1,
7, 0, NULL, 0),
SND_SOC_DAPM_PGA("LineIn Enable Right", SN95031_MICAMP2,
7, 0, NULL, 0),
SND_SOC_DAPM_PGA("MIC1 Enable", SN95031_MICAMP1, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("MIC2 Enable", SN95031_MICAMP2, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("TX1 Enable", SN95031_AUDIOTXEN, 2, 0, NULL, 0),
SND_SOC_DAPM_PGA("TX2 Enable", SN95031_AUDIOTXEN, 3, 0, NULL, 0),
SND_SOC_DAPM_PGA("TX3 Enable", SN95031_AUDIOTXEN, 4, 0, NULL, 0),
SND_SOC_DAPM_PGA("TX4 Enable", SN95031_AUDIOTXEN, 5, 0, NULL, 0),
/* ADC have null stream as they will be turned ON by TX path */
SND_SOC_DAPM_ADC("ADC Left", NULL,
SN95031_ADCCONFIG, 0, 0),
SND_SOC_DAPM_ADC("ADC Right", NULL,
SN95031_ADCCONFIG, 2, 0),
SND_SOC_DAPM_MUX("Mic_InputL Capture Route",
SND_SOC_NOPM, 0, 0, &sn95031_micl_mux_control),
SND_SOC_DAPM_MUX("Mic_InputR Capture Route",
SND_SOC_NOPM, 0, 0, &sn95031_micr_mux_control),
SND_SOC_DAPM_MUX("Txpath1 Capture Route",
SND_SOC_NOPM, 0, 0, &sn95031_input1_mux_control),
SND_SOC_DAPM_MUX("Txpath2 Capture Route",
SND_SOC_NOPM, 0, 0, &sn95031_input2_mux_control),
SND_SOC_DAPM_MUX("Txpath3 Capture Route",
SND_SOC_NOPM, 0, 0, &sn95031_input3_mux_control),
SND_SOC_DAPM_MUX("Txpath4 Capture Route",
SND_SOC_NOPM, 0, 0, &sn95031_input4_mux_control),
};
static const struct snd_soc_dapm_route sn95031_audio_map[] = {
/* headset and earpiece map */
{ "HPOUTL", NULL, "Headset Rail"},
{ "HPOUTR", NULL, "Headset Rail"},
{ "HPOUTL", NULL, "Headset Left Playback" },
{ "HPOUTR", NULL, "Headset Right Playback" },
{ "EPOUT", NULL, "Earpiece Playback" },
{ "Headset Left Playback", NULL, "Headset Left Filter"},
{ "Headset Right Playback", NULL, "Headset Right Filter"},
{ "Earpiece Playback", NULL, "Headset Left Filter"},
{ "Headset Left Filter", NULL, "HSDAC Left"},
{ "Headset Right Filter", NULL, "HSDAC Right"},
/* speaker map */
{ "IHFOUTL", NULL, "Speaker Rail"},
{ "IHFOUTR", NULL, "Speaker Rail"},
{ "IHFOUTL", NULL, "Speaker Left Playback"},
{ "IHFOUTR", NULL, "Speaker Right Playback"},
{ "Speaker Left Playback", NULL, "Speaker Left Filter"},
{ "Speaker Right Playback", NULL, "Speaker Right Filter"},
{ "Speaker Left Filter", NULL, "IHFDAC Left"},
{ "Speaker Right Filter", NULL, "IHFDAC Right"},
/* vibra map */
{ "VIB1OUT", NULL, "Vibra1 Playback"},
{ "Vibra1 Playback", NULL, "Vibra1 DAC"},
{ "VIB2OUT", NULL, "Vibra2 Playback"},
{ "Vibra2 Playback", NULL, "Vibra2 DAC"},
/* lineout */
{ "LINEOUTL", NULL, "Lineout Left Playback"},
{ "LINEOUTR", NULL, "Lineout Right Playback"},
{ "Lineout Left Playback", NULL, "Headset Left Filter"},
{ "Lineout Left Playback", NULL, "Speaker Left Filter"},
{ "Lineout Left Playback", NULL, "Vibra1 DAC"},
{ "Lineout Right Playback", NULL, "Headset Right Filter"},
{ "Lineout Right Playback", NULL, "Speaker Right Filter"},
{ "Lineout Right Playback", NULL, "Vibra2 DAC"},
/* Headset (AMIC1) mic */
{ "AMIC1Bias", NULL, "AMIC1"},
{ "MIC1 Enable", NULL, "AMIC1Bias"},
{ "Mic_InputL Capture Route", "AMIC", "MIC1 Enable"},
/* AMIC2 */
{ "AMIC2Bias", NULL, "AMIC2"},
{ "MIC2 Enable", NULL, "AMIC2Bias"},
{ "Mic_InputR Capture Route", "AMIC", "MIC2 Enable"},
/* Linein */
{ "LineIn Enable Left", NULL, "LINEINL"},
{ "LineIn Enable Right", NULL, "LINEINR"},
{ "Mic_InputL Capture Route", "LineIn", "LineIn Enable Left"},
{ "Mic_InputR Capture Route", "LineIn", "LineIn Enable Right"},
/* ADC connection */
{ "ADC Left", NULL, "Mic_InputL Capture Route"},
{ "ADC Right", NULL, "Mic_InputR Capture Route"},
/*DMIC connections */
{ "DMIC1", NULL, "DMIC12supply"},
{ "DMIC2", NULL, "DMIC12supply"},
{ "DMIC3", NULL, "DMIC34supply"},
{ "DMIC4", NULL, "DMIC34supply"},
{ "DMIC5", NULL, "DMIC56supply"},
{ "DMIC6", NULL, "DMIC56supply"},
{ "DMIC12Bias", NULL, "DMIC1"},
{ "DMIC12Bias", NULL, "DMIC2"},
{ "DMIC34Bias", NULL, "DMIC3"},
{ "DMIC34Bias", NULL, "DMIC4"},
{ "DMIC56Bias", NULL, "DMIC5"},
{ "DMIC56Bias", NULL, "DMIC6"},
/*TX path inputs*/
{ "Txpath1 Capture Route", "ADC Left", "ADC Left"},
{ "Txpath2 Capture Route", "ADC Left", "ADC Left"},
{ "Txpath3 Capture Route", "ADC Left", "ADC Left"},
{ "Txpath4 Capture Route", "ADC Left", "ADC Left"},
{ "Txpath1 Capture Route", "ADC Right", "ADC Right"},
{ "Txpath2 Capture Route", "ADC Right", "ADC Right"},
{ "Txpath3 Capture Route", "ADC Right", "ADC Right"},
{ "Txpath4 Capture Route", "ADC Right", "ADC Right"},
{ "Txpath1 Capture Route", "DMIC1", "DMIC1"},
{ "Txpath2 Capture Route", "DMIC1", "DMIC1"},
{ "Txpath3 Capture Route", "DMIC1", "DMIC1"},
{ "Txpath4 Capture Route", "DMIC1", "DMIC1"},
{ "Txpath1 Capture Route", "DMIC2", "DMIC2"},
{ "Txpath2 Capture Route", "DMIC2", "DMIC2"},
{ "Txpath3 Capture Route", "DMIC2", "DMIC2"},
{ "Txpath4 Capture Route", "DMIC2", "DMIC2"},
{ "Txpath1 Capture Route", "DMIC3", "DMIC3"},
{ "Txpath2 Capture Route", "DMIC3", "DMIC3"},
{ "Txpath3 Capture Route", "DMIC3", "DMIC3"},
{ "Txpath4 Capture Route", "DMIC3", "DMIC3"},
{ "Txpath1 Capture Route", "DMIC4", "DMIC4"},
{ "Txpath2 Capture Route", "DMIC4", "DMIC4"},
{ "Txpath3 Capture Route", "DMIC4", "DMIC4"},
{ "Txpath4 Capture Route", "DMIC4", "DMIC4"},
{ "Txpath1 Capture Route", "DMIC5", "DMIC5"},
{ "Txpath2 Capture Route", "DMIC5", "DMIC5"},
{ "Txpath3 Capture Route", "DMIC5", "DMIC5"},
{ "Txpath4 Capture Route", "DMIC5", "DMIC5"},
{ "Txpath1 Capture Route", "DMIC6", "DMIC6"},
{ "Txpath2 Capture Route", "DMIC6", "DMIC6"},
{ "Txpath3 Capture Route", "DMIC6", "DMIC6"},
{ "Txpath4 Capture Route", "DMIC6", "DMIC6"},
/* tx path */
{ "TX1 Enable", NULL, "Txpath1 Capture Route"},
{ "TX2 Enable", NULL, "Txpath2 Capture Route"},
{ "TX3 Enable", NULL, "Txpath3 Capture Route"},
{ "TX4 Enable", NULL, "Txpath4 Capture Route"},
{ "PCM_Out", NULL, "TX1 Enable"},
{ "PCM_Out", NULL, "TX2 Enable"},
{ "PCM_Out", NULL, "TX3 Enable"},
{ "PCM_Out", NULL, "TX4 Enable"},
};
/* speaker and headset mutes, for audio pops and clicks */
static int sn95031_pcm_hs_mute(struct snd_soc_dai *dai, int mute)
{
snd_soc_update_bits(dai->codec,
SN95031_HSLVOLCTRL, BIT(7), (!mute << 7));
snd_soc_update_bits(dai->codec,
SN95031_HSRVOLCTRL, BIT(7), (!mute << 7));
return 0;
}
static int sn95031_pcm_spkr_mute(struct snd_soc_dai *dai, int mute)
{
snd_soc_update_bits(dai->codec,
SN95031_IHFLVOLCTRL, BIT(7), (!mute << 7));
snd_soc_update_bits(dai->codec,
SN95031_IHFRVOLCTRL, BIT(7), (!mute << 7));
return 0;
}
static int sn95031_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
unsigned int format, rate;
switch (params_width(params)) {
case 16:
format = BIT(4)|BIT(5);
break;
case 24:
format = 0;
break;
default:
return -EINVAL;
}
snd_soc_update_bits(dai->codec, SN95031_PCM2C2,
BIT(4)|BIT(5), format);
switch (params_rate(params)) {
case 48000:
pr_debug("RATE_48000\n");
rate = 0;
break;
case 44100:
pr_debug("RATE_44100\n");
rate = BIT(7);
break;
default:
pr_err("ERR rate %d\n", params_rate(params));
return -EINVAL;
}
snd_soc_update_bits(dai->codec, SN95031_PCM1C1, BIT(7), rate);
return 0;
}
/* Codec DAI section */
static const struct snd_soc_dai_ops sn95031_headset_dai_ops = {
.digital_mute = sn95031_pcm_hs_mute,
.hw_params = sn95031_pcm_hw_params,
};
static const struct snd_soc_dai_ops sn95031_speaker_dai_ops = {
.digital_mute = sn95031_pcm_spkr_mute,
.hw_params = sn95031_pcm_hw_params,
};
static const struct snd_soc_dai_ops sn95031_vib1_dai_ops = {
.hw_params = sn95031_pcm_hw_params,
};
static const struct snd_soc_dai_ops sn95031_vib2_dai_ops = {
.hw_params = sn95031_pcm_hw_params,
};
static struct snd_soc_dai_driver sn95031_dais[] = {
{
.name = "SN95031 Headset",
.playback = {
.stream_name = "Headset",
.channels_min = 2,
.channels_max = 2,
.rates = SN95031_RATES,
.formats = SN95031_FORMATS,
},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 5,
.rates = SN95031_RATES,
.formats = SN95031_FORMATS,
},
.ops = &sn95031_headset_dai_ops,
},
{ .name = "SN95031 Speaker",
.playback = {
.stream_name = "Speaker",
.channels_min = 2,
.channels_max = 2,
.rates = SN95031_RATES,
.formats = SN95031_FORMATS,
},
.ops = &sn95031_speaker_dai_ops,
},
{ .name = "SN95031 Vibra1",
.playback = {
.stream_name = "Vibra1",
.channels_min = 1,
.channels_max = 1,
.rates = SN95031_RATES,
.formats = SN95031_FORMATS,
},
.ops = &sn95031_vib1_dai_ops,
},
{ .name = "SN95031 Vibra2",
.playback = {
.stream_name = "Vibra2",
.channels_min = 1,
.channels_max = 1,
.rates = SN95031_RATES,
.formats = SN95031_FORMATS,
},
.ops = &sn95031_vib2_dai_ops,
},
};
static inline void sn95031_disable_jack_btn(struct snd_soc_codec *codec)
{
snd_soc_write(codec, SN95031_BTNCTRL2, 0x00);
}
static inline void sn95031_enable_jack_btn(struct snd_soc_codec *codec)
{
snd_soc_write(codec, SN95031_BTNCTRL1, 0x77);
snd_soc_write(codec, SN95031_BTNCTRL2, 0x01);
}
static int sn95031_get_headset_state(struct snd_soc_codec *codec,
struct snd_soc_jack *mfld_jack)
{
int micbias = sn95031_get_mic_bias(codec);
int jack_type = snd_soc_jack_get_type(mfld_jack, micbias);
pr_debug("jack type detected = %d\n", jack_type);
if (jack_type == SND_JACK_HEADSET)
sn95031_enable_jack_btn(codec);
return jack_type;
}
void sn95031_jack_detection(struct snd_soc_codec *codec,
struct mfld_jack_data *jack_data)
{
unsigned int status;
unsigned int mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_HEADSET;
pr_debug("interrupt id read in sram = 0x%x\n", jack_data->intr_id);
if (jack_data->intr_id & 0x1) {
pr_debug("short_push detected\n");
status = SND_JACK_HEADSET | SND_JACK_BTN_0;
} else if (jack_data->intr_id & 0x2) {
pr_debug("long_push detected\n");
status = SND_JACK_HEADSET | SND_JACK_BTN_1;
} else if (jack_data->intr_id & 0x4) {
pr_debug("headset or headphones inserted\n");
status = sn95031_get_headset_state(codec, jack_data->mfld_jack);
} else if (jack_data->intr_id & 0x8) {
pr_debug("headset or headphones removed\n");
status = 0;
sn95031_disable_jack_btn(codec);
} else {
pr_err("unidentified interrupt\n");
return;
}
snd_soc_jack_report(jack_data->mfld_jack, status, mask);
/*button pressed and released so we send explicit button release */
if ((status & SND_JACK_BTN_0) | (status & SND_JACK_BTN_1))
snd_soc_jack_report(jack_data->mfld_jack,
SND_JACK_HEADSET, mask);
}
EXPORT_SYMBOL_GPL(sn95031_jack_detection);
/* codec registration */
static int sn95031_codec_probe(struct snd_soc_codec *codec)
{
pr_debug("codec_probe called\n");
/* PCM interface config
* This sets the pcm rx slot conguration to max 6 slots
* for max 4 dais (2 stereo and 2 mono)
*/
snd_soc_write(codec, SN95031_PCM2RXSLOT01, 0x10);
snd_soc_write(codec, SN95031_PCM2RXSLOT23, 0x32);
snd_soc_write(codec, SN95031_PCM2RXSLOT45, 0x54);
snd_soc_write(codec, SN95031_PCM2TXSLOT01, 0x10);
snd_soc_write(codec, SN95031_PCM2TXSLOT23, 0x32);
/* pcm port setting
* This sets the pcm port to slave and clock at 19.2Mhz which
* can support 6slots, sampling rate set per stream in hw-params
*/
snd_soc_write(codec, SN95031_PCM1C1, 0x00);
snd_soc_write(codec, SN95031_PCM2C1, 0x01);
snd_soc_write(codec, SN95031_PCM2C2, 0x0A);
snd_soc_write(codec, SN95031_HSMIXER, BIT(0)|BIT(4));
/* vendor vibra workround, the vibras are muted by
* custom register so unmute them
*/
snd_soc_write(codec, SN95031_SSR5, 0x80);
snd_soc_write(codec, SN95031_SSR6, 0x80);
snd_soc_write(codec, SN95031_VIB1C5, 0x00);
snd_soc_write(codec, SN95031_VIB2C5, 0x00);
/* configure vibras for pcm port */
snd_soc_write(codec, SN95031_VIB1C3, 0x00);
snd_soc_write(codec, SN95031_VIB2C3, 0x00);
/* soft mute ramp time */
snd_soc_write(codec, SN95031_SOFTMUTE, 0x3);
/* fix the initial volume at 1dB,
* default in +9dB,
* 1dB give optimal swing on DAC, amps
*/
snd_soc_write(codec, SN95031_HSLVOLCTRL, 0x08);
snd_soc_write(codec, SN95031_HSRVOLCTRL, 0x08);
snd_soc_write(codec, SN95031_IHFLVOLCTRL, 0x08);
snd_soc_write(codec, SN95031_IHFRVOLCTRL, 0x08);
/* dac mode and lineout workaround */
snd_soc_write(codec, SN95031_SSR2, 0x10);
snd_soc_write(codec, SN95031_SSR3, 0x40);
return 0;
}
static const struct snd_soc_codec_driver sn95031_codec = {
.probe = sn95031_codec_probe,
.set_bias_level = sn95031_set_vaud_bias,
.idle_bias_off = true,
.component_driver = {
.controls = sn95031_snd_controls,
.num_controls = ARRAY_SIZE(sn95031_snd_controls),
.dapm_widgets = sn95031_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(sn95031_dapm_widgets),
.dapm_routes = sn95031_audio_map,
.num_dapm_routes = ARRAY_SIZE(sn95031_audio_map),
},
};
static int sn95031_device_probe(struct platform_device *pdev)
{
struct regmap *regmap;
pr_debug("codec device probe called for %s\n", dev_name(&pdev->dev));
regmap = devm_regmap_init(&pdev->dev, NULL, NULL, &sn95031_regmap);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
return snd_soc_register_codec(&pdev->dev, &sn95031_codec,
sn95031_dais, ARRAY_SIZE(sn95031_dais));
}
static int sn95031_device_remove(struct platform_device *pdev)
{
pr_debug("codec device remove called\n");
snd_soc_unregister_codec(&pdev->dev);
return 0;
}
static struct platform_driver sn95031_codec_driver = {
.driver = {
.name = "sn95031",
},
.probe = sn95031_device_probe,
.remove = sn95031_device_remove,
};
module_platform_driver(sn95031_codec_driver);
MODULE_DESCRIPTION("ASoC TI SN95031 codec driver");
MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:sn95031");
/*
* sn95031.h - TI sn95031 Codec driver
*
* Copyright (C) 2010 Intel Corp
* Author: Vinod Koul <vinod.koul@intel.com>
* Author: Harsha Priya <priya.harsha@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 published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
*
*/
#ifndef _SN95031_H
#define _SN95031_H
/*register map*/
#define SN95031_VAUD 0xDB
#define SN95031_VHSP 0xDC
#define SN95031_VHSN 0xDD
#define SN95031_VIHF 0xC9
#define SN95031_AUDPLLCTRL 0x240
#define SN95031_DMICBUF0123 0x241
#define SN95031_DMICBUF45 0x242
#define SN95031_DMICGPO 0x244
#define SN95031_DMICMUX 0x245
#define SN95031_DMICLK 0x246
#define SN95031_MICBIAS 0x247
#define SN95031_ADCCONFIG 0x248
#define SN95031_MICAMP1 0x249
#define SN95031_MICAMP2 0x24A
#define SN95031_NOISEMUX 0x24B
#define SN95031_AUDIOMUX12 0x24C
#define SN95031_AUDIOMUX34 0x24D
#define SN95031_AUDIOSINC 0x24E
#define SN95031_AUDIOTXEN 0x24F
#define SN95031_HSEPRXCTRL 0x250
#define SN95031_IHFRXCTRL 0x251
#define SN95031_HSMIXER 0x256
#define SN95031_DACCONFIG 0x257
#define SN95031_SOFTMUTE 0x258
#define SN95031_HSLVOLCTRL 0x259
#define SN95031_HSRVOLCTRL 0x25A
#define SN95031_IHFLVOLCTRL 0x25B
#define SN95031_IHFRVOLCTRL 0x25C
#define SN95031_DRIVEREN 0x25D
#define SN95031_LOCTL 0x25E
#define SN95031_VIB1C1 0x25F
#define SN95031_VIB1C2 0x260
#define SN95031_VIB1C3 0x261
#define SN95031_VIB1SPIPCM1 0x262
#define SN95031_VIB1SPIPCM2 0x263
#define SN95031_VIB1C5 0x264
#define SN95031_VIB2C1 0x265
#define SN95031_VIB2C2 0x266
#define SN95031_VIB2C3 0x267
#define SN95031_VIB2SPIPCM1 0x268
#define SN95031_VIB2SPIPCM2 0x269
#define SN95031_VIB2C5 0x26A
#define SN95031_BTNCTRL1 0x26B
#define SN95031_BTNCTRL2 0x26C
#define SN95031_PCM1TXSLOT01 0x26D
#define SN95031_PCM1TXSLOT23 0x26E
#define SN95031_PCM1TXSLOT45 0x26F
#define SN95031_PCM1RXSLOT0_3 0x270
#define SN95031_PCM1RXSLOT45 0x271
#define SN95031_PCM2TXSLOT01 0x272
#define SN95031_PCM2TXSLOT23 0x273
#define SN95031_PCM2TXSLOT45 0x274
#define SN95031_PCM2RXSLOT01 0x275
#define SN95031_PCM2RXSLOT23 0x276
#define SN95031_PCM2RXSLOT45 0x277
#define SN95031_PCM1C1 0x278
#define SN95031_PCM1C2 0x279
#define SN95031_PCM1C3 0x27A
#define SN95031_PCM2C1 0x27B
#define SN95031_PCM2C2 0x27C
/*end codec register defn*/
/*vendor defn these are not part of avp*/
#define SN95031_SSR2 0x381
#define SN95031_SSR3 0x382
#define SN95031_SSR5 0x384
#define SN95031_SSR6 0x385
/* ADC registers */
#define SN95031_ADC1CNTL1 0x1C0
#define SN95031_ADC_ENBL 0x10
#define SN95031_ADC_START 0x08
#define SN95031_ADC1CNTL3 0x1C2
#define SN95031_ADCTHERM_ENBL 0x04
#define SN95031_ADCRRDATA_ENBL 0x05
#define SN95031_STOPBIT_MASK 16
#define SN95031_ADCTHERM_MASK 4
#define SN95031_ADC_CHANLS_MAX 15 /* Number of ADC channels */
#define SN95031_ADC_LOOP_MAX (SN95031_ADC_CHANLS_MAX - 1)
#define SN95031_ADC_NO_LOOP 0x07
#define SN95031_AUDIO_GPIO_CTRL 0x070
/* ADC channel code values */
#define SN95031_AUDIO_DETECT_CODE 0x06
/* ADC base addresses */
#define SN95031_ADC_CHNL_START_ADDR 0x1C5 /* increments by 1 */
#define SN95031_ADC_DATA_START_ADDR 0x1D4 /* increments by 2 */
/* multipier to convert to mV */
#define SN95031_ADC_ONE_LSB_MULTIPLIER 2346
struct mfld_jack_data {
int intr_id;
int micbias_vol;
struct snd_soc_jack *mfld_jack;
};
extern void sn95031_jack_detection(struct snd_soc_codec *codec,
struct mfld_jack_data *jack_data);
#endif
config SND_SOC_INTEL_SST_TOPLEVEL
bool "Intel ASoC SST drivers"
default y
depends on X86 || COMPILE_TEST
select SND_SOC_INTEL_MACH
help
Intel ASoC SST Platform Drivers. If you have a Intel machine that
has an audio controller with a DSP and I2S or DMIC port, then
enable this option by saying Y
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about Intel SST drivers.
if SND_SOC_INTEL_SST_TOPLEVEL
config SND_SST_IPC config SND_SST_IPC
tristate tristate
# This option controls the IPC core for HiFi2 platforms
config SND_SST_IPC_PCI config SND_SST_IPC_PCI
tristate tristate
select SND_SST_IPC select SND_SST_IPC
# This option controls the PCI-based IPC for HiFi2 platforms
# (Medfield, Merrifield).
config SND_SST_IPC_ACPI config SND_SST_IPC_ACPI
tristate tristate
select SND_SST_IPC select SND_SST_IPC
select SND_SOC_INTEL_SST # This option controls the ACPI-based IPC for HiFi2 platforms
select IOSF_MBI # (Baytrail, Cherrytrail)
config SND_SOC_INTEL_COMMON config SND_SOC_INTEL_SST_ACPI
tristate tristate
# This option controls ACPI-based probing on
# Haswell/Broadwell/Baytrail legacy and will be set
# when these platforms are enabled
config SND_SOC_INTEL_SST config SND_SOC_INTEL_SST
tristate tristate
select SND_SOC_INTEL_SST_ACPI if ACPI
config SND_SOC_INTEL_SST_FIRMWARE config SND_SOC_INTEL_SST_FIRMWARE
tristate tristate
select DW_DMAC_CORE select DW_DMAC_CORE
# This option controls firmware download on
config SND_SOC_INTEL_SST_ACPI # Haswell/Broadwell/Baytrail legacy and will be set
tristate # when these platforms are enabled
config SND_SOC_ACPI_INTEL_MATCH
tristate
select SND_SOC_ACPI if ACPI
config SND_SOC_INTEL_SST_TOPLEVEL
tristate "Intel ASoC SST drivers"
depends on X86 || COMPILE_TEST
select SND_SOC_INTEL_MACH
select SND_SOC_INTEL_COMMON
help
Intel ASoC Audio Drivers. If you have a Intel machine that
has audio controller with a DSP and I2S or DMIC port, then
enable this option by saying Y or M
If unsure select "N".
config SND_SOC_INTEL_HASWELL config SND_SOC_INTEL_HASWELL
tristate "Intel ASoC SST driver for Haswell/Broadwell" tristate "Haswell/Broadwell Platforms"
depends on SND_SOC_INTEL_SST_TOPLEVEL && SND_DMA_SGBUF depends on SND_DMA_SGBUF
depends on DMADEVICES depends on DMADEVICES && ACPI
select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SST_ACPI
select SND_SOC_INTEL_SST_FIRMWARE select SND_SOC_INTEL_SST_FIRMWARE
select SND_SOC_ACPI_INTEL_MATCH
help
If you have a Intel Haswell or Broadwell platform connected to
an I2S codec, then enable this option by saying Y or m. This is
typically used for Chromebooks. This is a recommended option.
config SND_SOC_INTEL_BAYTRAIL config SND_SOC_INTEL_BAYTRAIL
tristate "Intel ASoC SST driver for Baytrail (legacy)" tristate "Baytrail (legacy) Platforms"
depends on SND_SOC_INTEL_SST_TOPLEVEL depends on DMADEVICES && ACPI
depends on DMADEVICES
select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SST_ACPI
select SND_SOC_INTEL_SST_FIRMWARE select SND_SOC_INTEL_SST_FIRMWARE
select SND_SOC_ACPI_INTEL_MATCH
help
If you have a Intel Baytrail platform connected to an I2S codec,
then enable this option by saying Y or m. This was typically used
for Baytrail Chromebooks but this option is now deprecated and is
not recommended, use SND_SST_ATOM_HIFI2_PLATFORM instead.
config SND_SST_ATOM_HIFI2_PLATFORM_PCI
tristate "PCI HiFi2 (Medfield, Merrifield) Platforms"
depends on X86 && PCI
select SND_SST_IPC_PCI
select SND_SOC_COMPRESS
select SND_SOC_INTEL_COMMON
help
If you have a Intel Medfield or Merrifield/Edison platform, then
enable this option by saying Y or m. Distros will typically not
enable this option: Medfield devices are not available to
developers and while Merrifield/Edison can run a mainline kernel with
limited functionality it will require a firmware file which
is not in the standard firmware tree
config SND_SST_ATOM_HIFI2_PLATFORM config SND_SST_ATOM_HIFI2_PLATFORM
tristate "Intel ASoC SST driver for HiFi2 platforms (*field, *trail)" tristate "ACPI HiFi2 (Baytrail, Cherrytrail) Platforms"
depends on SND_SOC_INTEL_SST_TOPLEVEL && X86 depends on X86 && ACPI
select SND_SST_IPC_ACPI
select SND_SOC_COMPRESS select SND_SOC_COMPRESS
select SND_SOC_ACPI_INTEL_MATCH
select IOSF_MBI
help
If you have a Intel Baytrail or Cherrytrail platform with an I2S
codec, then enable this option by saying Y or m. This is a
recommended option
config SND_SOC_INTEL_SKYLAKE config SND_SOC_INTEL_SKYLAKE
tristate "Intel ASoC SST driver for SKL/BXT/KBL/GLK/CNL" tristate "SKL/BXT/KBL/GLK/CNL... Platforms"
depends on SND_SOC_INTEL_SST_TOPLEVEL && PCI && ACPI depends on PCI && ACPI
select SND_HDA_EXT_CORE select SND_HDA_EXT_CORE
select SND_HDA_DSP_LOADER select SND_HDA_DSP_LOADER
select SND_SOC_TOPOLOGY select SND_SOC_TOPOLOGY
select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST
select SND_SOC_ACPI_INTEL_MATCH
help
If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/
GeminiLake or CannonLake platform with the DSP enabled in the BIOS
then enable this option by saying Y or m.
config SND_SOC_ACPI_INTEL_MATCH
tristate
select SND_SOC_ACPI if ACPI
# this option controls the compilation of ACPI matching tables and
# helpers and is not meant to be selected by the user.
endif ## SND_SOC_INTEL_SST_TOPLEVEL
# ASoC codec drivers # ASoC codec drivers
source "sound/soc/intel/boards/Kconfig" source "sound/soc/intel/boards/Kconfig"
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
# Core support # Core support
obj-$(CONFIG_SND_SOC_INTEL_COMMON) += common/ obj-$(CONFIG_SND_SOC) += common/
# Platform Support # Platform Support
obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/ obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/
......
...@@ -236,6 +236,9 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) ...@@ -236,6 +236,9 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
/* Find the IRQ */ /* Find the IRQ */
ctx->irq_num = platform_get_irq(pdev, ctx->irq_num = platform_get_irq(pdev,
ctx->pdata->res_info->acpi_ipc_irq_index); ctx->pdata->res_info->acpi_ipc_irq_index);
if (ctx->irq_num <= 0)
return ctx->irq_num < 0 ? ctx->irq_num : -EIO;
return 0; return 0;
} }
......
...@@ -220,10 +220,10 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, ...@@ -220,10 +220,10 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
sst_free_block(sst_drv_ctx, block); sst_free_block(sst_drv_ctx, block);
out: out:
test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id); test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id);
return 0; return ret;
} }
/* /**
* sst_pause_stream - Send msg for a pausing stream * sst_pause_stream - Send msg for a pausing stream
* @str_id: stream ID * @str_id: stream ID
* *
...@@ -261,7 +261,7 @@ int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) ...@@ -261,7 +261,7 @@ int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
} }
} else { } else {
retval = -EBADRQC; retval = -EBADRQC;
dev_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n "); dev_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n");
} }
return retval; return retval;
...@@ -284,7 +284,7 @@ int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) ...@@ -284,7 +284,7 @@ int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
if (!str_info) if (!str_info)
return -EINVAL; return -EINVAL;
if (str_info->status == STREAM_RUNNING) if (str_info->status == STREAM_RUNNING)
return 0; return 0;
if (str_info->status == STREAM_PAUSED) { if (str_info->status == STREAM_PAUSED) {
retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD, IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD,
......
config SND_SOC_INTEL_MACH menuconfig SND_SOC_INTEL_MACH
tristate "Intel Audio machine drivers" bool "Intel Machine drivers"
depends on SND_SOC_INTEL_SST_TOPLEVEL depends on SND_SOC_INTEL_SST_TOPLEVEL
select SND_SOC_ACPI_INTEL_MATCH if ACPI help
Intel ASoC Machine Drivers. If you have a Intel machine that
has an audio controller with a DSP and I2S or DMIC port, then
enable this option by saying Y
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about Intel ASoC machine drivers.
if SND_SOC_INTEL_MACH if SND_SOC_INTEL_MACH
config SND_MFLD_MACHINE if SND_SOC_INTEL_HASWELL
tristate "SOC Machine Audio driver for Intel Medfield MID platform"
depends on INTEL_SCU_IPC
select SND_SOC_SN95031
depends on SND_SST_ATOM_HIFI2_PLATFORM
select SND_SST_IPC_PCI
help
This adds support for ASoC machine driver for Intel(R) MID Medfield platform
used as alsa device in audio substem in Intel(R) MID devices
Say Y if you have such a device.
If unsure select "N".
config SND_SOC_INTEL_HASWELL_MACH config SND_SOC_INTEL_HASWELL_MACH
tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" tristate "Haswell Lynxpoint"
depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
depends on SND_SOC_INTEL_HASWELL
select SND_SOC_RT5640 select SND_SOC_RT5640
help help
This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell
Ultrabook platforms. Ultrabook platforms. This is a recommended option.
Say Y if you have such a device. Say Y or m if you have such a device.
If unsure select "N". If unsure select "N".
config SND_SOC_INTEL_BDW_RT5677_MACH config SND_SOC_INTEL_BDW_RT5677_MACH
tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec" tristate "Broadwell with RT5677 codec"
depends on X86_INTEL_LPSS && GPIOLIB && I2C depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM && GPIOLIB
depends on SND_SOC_INTEL_HASWELL
select SND_SOC_RT5677 select SND_SOC_RT5677
help help
This adds support for Intel Broadwell platform based boards with This adds support for Intel Broadwell platform based boards with
the RT5677 audio codec. the RT5677 audio codec. This is a recommended option.
Say Y or m if you have such a device.
If unsure select "N".
config SND_SOC_INTEL_BROADWELL_MACH config SND_SOC_INTEL_BROADWELL_MACH
tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" tristate "Broadwell Wildcatpoint"
depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
depends on SND_SOC_INTEL_HASWELL
select SND_SOC_RT286 select SND_SOC_RT286
help help
This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell
Ultrabook platforms. Ultrabook platforms.
Say Y if you have such a device. Say Y or m if you have such a device. This is a recommended option.
If unsure select "N". If unsure select "N".
endif ## SND_SOC_INTEL_HASWELL
if SND_SOC_INTEL_BAYTRAIL
config SND_SOC_INTEL_BYT_MAX98090_MACH config SND_SOC_INTEL_BYT_MAX98090_MACH
tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" tristate "Baytrail with MAX98090 codec"
depends on X86_INTEL_LPSS && I2C depends on X86_INTEL_LPSS && I2C
depends on SND_SST_IPC_ACPI = n
depends on SND_SOC_INTEL_BAYTRAIL
select SND_SOC_MAX98090 select SND_SOC_MAX98090
help help
This adds audio driver for Intel Baytrail platform based boards This adds audio driver for Intel Baytrail platform based boards
with the MAX98090 audio codec. with the MAX98090 audio codec. This driver is deprecated, use
SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH instead for better
functionality.
config SND_SOC_INTEL_BYT_RT5640_MACH config SND_SOC_INTEL_BYT_RT5640_MACH
tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" tristate "Baytrail with RT5640 codec"
depends on X86_INTEL_LPSS && I2C depends on X86_INTEL_LPSS && I2C
depends on SND_SST_IPC_ACPI = n
depends on SND_SOC_INTEL_BAYTRAIL
select SND_SOC_RT5640 select SND_SOC_RT5640
help help
This adds audio driver for Intel Baytrail platform based boards This adds audio driver for Intel Baytrail platform based boards
with the RT5640 audio codec. This driver is deprecated, use with the RT5640 audio codec. This driver is deprecated, use
SND_SOC_INTEL_BYTCR_RT5640_MACH instead for better functionality. SND_SOC_INTEL_BYTCR_RT5640_MACH instead for better functionality.
endif ## SND_SOC_INTEL_BAYTRAIL
if SND_SST_ATOM_HIFI2_PLATFORM
config SND_SOC_INTEL_BYTCR_RT5640_MACH config SND_SOC_INTEL_BYTCR_RT5640_MACH
tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec" tristate "Baytrail and Baytrail-CR with RT5640 codec"
depends on X86 && I2C && ACPI depends on X86_INTEL_LPSS && I2C && ACPI
select SND_SOC_ACPI
select SND_SOC_RT5640 select SND_SOC_RT5640
depends on SND_SST_ATOM_HIFI2_PLATFORM
select SND_SST_IPC_ACPI
help help
This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
platforms with RT5640 audio codec. platforms with RT5640 audio codec.
Say Y if you have such a device. Say Y or m if you have such a device. This is a recommended option.
If unsure select "N". If unsure select "N".
config SND_SOC_INTEL_BYTCR_RT5651_MACH config SND_SOC_INTEL_BYTCR_RT5651_MACH
tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec" tristate "Baytrail and Baytrail-CR with RT5651 codec"
depends on X86 && I2C && ACPI depends on X86_INTEL_LPSS && I2C && ACPI
select SND_SOC_ACPI
select SND_SOC_RT5651 select SND_SOC_RT5651
depends on SND_SST_ATOM_HIFI2_PLATFORM
select SND_SST_IPC_ACPI
help help
This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
platforms with RT5651 audio codec. platforms with RT5651 audio codec.
Say Y if you have such a device. Say Y or m if you have such a device. This is a recommended option.
If unsure select "N". If unsure select "N".
config SND_SOC_INTEL_CHT_BSW_RT5672_MACH config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" tristate "Cherrytrail & Braswell with RT5672 codec"
depends on X86_INTEL_LPSS && I2C && ACPI depends on X86_INTEL_LPSS && I2C && ACPI
select SND_SOC_RT5670 select SND_SOC_ACPI
depends on SND_SST_ATOM_HIFI2_PLATFORM select SND_SOC_RT5670
select SND_SST_IPC_ACPI
help help
This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
platforms with RT5672 audio codec. platforms with RT5672 audio codec.
Say Y if you have such a device. Say Y or m if you have such a device. This is a recommended option.
If unsure select "N". If unsure select "N".
config SND_SOC_INTEL_CHT_BSW_RT5645_MACH config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec" tristate "Cherrytrail & Braswell with RT5645/5650 codec"
depends on X86_INTEL_LPSS && I2C && ACPI depends on X86_INTEL_LPSS && I2C && ACPI
select SND_SOC_ACPI
select SND_SOC_RT5645 select SND_SOC_RT5645
depends on SND_SST_ATOM_HIFI2_PLATFORM
select SND_SST_IPC_ACPI
help help
This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
platforms with RT5645/5650 audio codec. platforms with RT5645/5650 audio codec.
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N". If unsure select "N".
config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with MAX98090 & TI codec" tristate "Cherrytrail & Braswell with MAX98090 & TI codec"
depends on X86_INTEL_LPSS && I2C && ACPI depends on X86_INTEL_LPSS && I2C && ACPI
select SND_SOC_MAX98090 select SND_SOC_MAX98090
select SND_SOC_TS3A227E select SND_SOC_TS3A227E
depends on SND_SST_ATOM_HIFI2_PLATFORM
select SND_SST_IPC_ACPI
help help
This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
platforms with MAX98090 audio codec it also can support TI jack chip as aux device. platforms with MAX98090 audio codec it also can support TI jack chip as aux device.
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N". If unsure select "N".
config SND_SOC_INTEL_BYT_CHT_DA7213_MACH config SND_SOC_INTEL_BYT_CHT_DA7213_MACH
tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with DA7212/7213 codec" tristate "Baytrail & Cherrytrail with DA7212/7213 codec"
depends on X86_INTEL_LPSS && I2C && ACPI depends on X86_INTEL_LPSS && I2C && ACPI
select SND_SOC_ACPI
select SND_SOC_DA7213 select SND_SOC_DA7213
depends on SND_SST_ATOM_HIFI2_PLATFORM
select SND_SST_IPC_ACPI
help help
This adds support for ASoC machine driver for Intel(R) Baytrail & CherryTrail This adds support for ASoC machine driver for Intel(R) Baytrail & CherryTrail
platforms with DA7212/7213 audio codec. platforms with DA7212/7213 audio codec.
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N". If unsure select "N".
config SND_SOC_INTEL_BYT_CHT_ES8316_MACH config SND_SOC_INTEL_BYT_CHT_ES8316_MACH
tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with ES8316 codec" tristate "Baytrail & Cherrytrail with ES8316 codec"
depends on X86_INTEL_LPSS && I2C && ACPI depends on X86_INTEL_LPSS && I2C && ACPI
select SND_SOC_ES8316 select SND_SOC_ES8316
depends on SND_SST_ATOM_HIFI2_PLATFORM
select SND_SST_IPC_ACPI
help help
This adds support for ASoC machine driver for Intel(R) Baytrail & This adds support for ASoC machine driver for Intel(R) Baytrail &
Cherrytrail platforms with ES8316 audio codec. Cherrytrail platforms with ES8316 audio codec.
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N". If unsure select "N".
config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH
tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)" tristate "Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)"
depends on X86_INTEL_LPSS && I2C && ACPI depends on X86_INTEL_LPSS && I2C && ACPI
depends on SND_SST_ATOM_HIFI2_PLATFORM
select SND_SST_IPC_ACPI
help help
This adds support for ASoC machine driver for the MinnowBoard Max or This adds support for ASoC machine driver for the MinnowBoard Max or
Up boards and provides access to I2S signals on the Low-Speed Up boards and provides access to I2S signals on the Low-Speed
connector connector. This is not a recommended option outside of these cases.
It is not intended to be enabled by distros by default.
Say Y or m if you have such a device.
If unsure select "N". If unsure select "N".
endif ## SND_SST_ATOM_HIFI2_PLATFORM
if SND_SOC_INTEL_SKYLAKE
config SND_SOC_INTEL_SKL_RT286_MACH config SND_SOC_INTEL_SKL_RT286_MACH
tristate "ASoC Audio driver for SKL with RT286 I2S mode" tristate "SKL with RT286 I2S mode"
depends on X86 && ACPI && I2C depends on MFD_INTEL_LPSS && I2C && ACPI
depends on SND_SOC_INTEL_SKYLAKE
select SND_SOC_RT286 select SND_SOC_RT286
select SND_SOC_DMIC select SND_SOC_DMIC
select SND_SOC_HDAC_HDMI select SND_SOC_HDAC_HDMI
help help
This adds support for ASoC machine driver for Skylake platforms This adds support for ASoC machine driver for Skylake platforms
with RT286 I2S audio codec. with RT286 I2S audio codec.
Say Y if you have such a device. Say Y or m if you have such a device.
If unsure select "N". If unsure select "N".
config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode" tristate "SKL with NAU88L25 and SSM4567 in I2S Mode"
depends on X86_INTEL_LPSS && I2C depends on MFD_INTEL_LPSS && I2C && ACPI
depends on SND_SOC_INTEL_SKYLAKE
select SND_SOC_NAU8825 select SND_SOC_NAU8825
select SND_SOC_SSM4567 select SND_SOC_SSM4567
select SND_SOC_DMIC select SND_SOC_DMIC
...@@ -185,13 +184,12 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH ...@@ -185,13 +184,12 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
help help
This adds support for ASoC Onboard Codec I2S machine driver. This will This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for NAU88L25 + SSM4567. create an alsa sound card for NAU88L25 + SSM4567.
Say Y if you have such a device. Say Y or m if you have such a device. This is a recommended option.
If unsure select "N". If unsure select "N".
config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode" tristate "SKL with NAU88L25 and MAX98357A in I2S Mode"
depends on X86_INTEL_LPSS && I2C depends on MFD_INTEL_LPSS && I2C && ACPI
depends on SND_SOC_INTEL_SKYLAKE
select SND_SOC_NAU8825 select SND_SOC_NAU8825
select SND_SOC_MAX98357A select SND_SOC_MAX98357A
select SND_SOC_DMIC select SND_SOC_DMIC
...@@ -199,13 +197,12 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH ...@@ -199,13 +197,12 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
help help
This adds support for ASoC Onboard Codec I2S machine driver. This will This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for NAU88L25 + MAX98357A. create an alsa sound card for NAU88L25 + MAX98357A.
Say Y if you have such a device. Say Y or m if you have such a device. This is a recommended option.
If unsure select "N". If unsure select "N".
config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
tristate "ASoC Audio driver for Broxton with DA7219 and MAX98357A in I2S Mode" tristate "Broxton with DA7219 and MAX98357A in I2S Mode"
depends on X86 && ACPI && I2C depends on MFD_INTEL_LPSS && I2C && ACPI
depends on SND_SOC_INTEL_SKYLAKE
select SND_SOC_DA7219 select SND_SOC_DA7219
select SND_SOC_MAX98357A select SND_SOC_MAX98357A
select SND_SOC_DMIC select SND_SOC_DMIC
...@@ -214,13 +211,12 @@ config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH ...@@ -214,13 +211,12 @@ config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
help help
This adds support for ASoC machine driver for Broxton-P platforms This adds support for ASoC machine driver for Broxton-P platforms
with DA7219 + MAX98357A I2S audio codec. with DA7219 + MAX98357A I2S audio codec.
Say Y if you have such a device. Say Y or m if you have such a device. This is a recommended option.
If unsure select "N". If unsure select "N".
config SND_SOC_INTEL_BXT_RT298_MACH config SND_SOC_INTEL_BXT_RT298_MACH
tristate "ASoC Audio driver for Broxton with RT298 I2S mode" tristate "Broxton with RT298 I2S mode"
depends on X86 && ACPI && I2C depends on MFD_INTEL_LPSS && I2C && ACPI
depends on SND_SOC_INTEL_SKYLAKE
select SND_SOC_RT298 select SND_SOC_RT298
select SND_SOC_DMIC select SND_SOC_DMIC
select SND_SOC_HDAC_HDMI select SND_SOC_HDAC_HDMI
...@@ -228,14 +224,12 @@ config SND_SOC_INTEL_BXT_RT298_MACH ...@@ -228,14 +224,12 @@ config SND_SOC_INTEL_BXT_RT298_MACH
help help
This adds support for ASoC machine driver for Broxton platforms This adds support for ASoC machine driver for Broxton platforms
with RT286 I2S audio codec. with RT286 I2S audio codec.
Say Y if you have such a device. Say Y or m if you have such a device. This is a recommended option.
If unsure select "N". If unsure select "N".
config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
tristate "ASoC Audio driver for KBL with RT5663 and MAX98927 in I2S Mode" tristate "KBL with RT5663 and MAX98927 in I2S Mode"
depends on X86_INTEL_LPSS && I2C depends on MFD_INTEL_LPSS && I2C && ACPI
select SND_SOC_INTEL_SST
depends on SND_SOC_INTEL_SKYLAKE
select SND_SOC_RT5663 select SND_SOC_RT5663
select SND_SOC_MAX98927 select SND_SOC_MAX98927
select SND_SOC_DMIC select SND_SOC_DMIC
...@@ -243,14 +237,13 @@ config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH ...@@ -243,14 +237,13 @@ config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
help help
This adds support for ASoC Onboard Codec I2S machine driver. This will This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for RT5663 + MAX98927. create an alsa sound card for RT5663 + MAX98927.
Say Y if you have such a device. Say Y or m if you have such a device. This is a recommended option.
If unsure select "N". If unsure select "N".
config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
tristate "ASoC Audio driver for KBL with RT5663, RT5514 and MAX98927 in I2S Mode" tristate "KBL with RT5663, RT5514 and MAX98927 in I2S Mode"
depends on X86_INTEL_LPSS && I2C && SPI depends on MFD_INTEL_LPSS && I2C && ACPI
select SND_SOC_INTEL_SST depends on SPI
depends on SND_SOC_INTEL_SKYLAKE
select SND_SOC_RT5663 select SND_SOC_RT5663
select SND_SOC_RT5514 select SND_SOC_RT5514
select SND_SOC_RT5514_SPI select SND_SOC_RT5514_SPI
...@@ -259,7 +252,8 @@ config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH ...@@ -259,7 +252,8 @@ config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
help help
This adds support for ASoC Onboard Codec I2S machine driver. This will This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for RT5663 + RT5514 + MAX98927. create an alsa sound card for RT5663 + RT5514 + MAX98927.
Say Y if you have such a device. Say Y or m if you have such a device. This is a recommended option.
If unsure select "N". If unsure select "N".
endif ## SND_SOC_INTEL_SKYLAKE
endif endif ## SND_SOC_INTEL_MACH
...@@ -38,6 +38,8 @@ enum { ...@@ -38,6 +38,8 @@ enum {
BYT_RT5651_DMIC_MAP, BYT_RT5651_DMIC_MAP,
BYT_RT5651_IN1_MAP, BYT_RT5651_IN1_MAP,
BYT_RT5651_IN2_MAP, BYT_RT5651_IN2_MAP,
BYT_RT5651_IN1_IN2_MAP,
BYT_RT5651_IN3_MAP,
}; };
#define BYT_RT5651_MAP(quirk) ((quirk) & GENMASK(7, 0)) #define BYT_RT5651_MAP(quirk) ((quirk) & GENMASK(7, 0))
...@@ -62,6 +64,8 @@ static void log_quirks(struct device *dev) ...@@ -62,6 +64,8 @@ static void log_quirks(struct device *dev)
dev_info(dev, "quirk IN1_MAP enabled"); dev_info(dev, "quirk IN1_MAP enabled");
if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN2_MAP) if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN2_MAP)
dev_info(dev, "quirk IN2_MAP enabled"); dev_info(dev, "quirk IN2_MAP enabled");
if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN3_MAP)
dev_info(dev, "quirk IN3_MAP enabled");
if (byt_rt5651_quirk & BYT_RT5651_DMIC_EN) if (byt_rt5651_quirk & BYT_RT5651_DMIC_EN)
dev_info(dev, "quirk DMIC enabled"); dev_info(dev, "quirk DMIC enabled");
if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN) if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN)
...@@ -127,6 +131,7 @@ static const struct snd_soc_dapm_widget byt_rt5651_widgets[] = { ...@@ -127,6 +131,7 @@ static const struct snd_soc_dapm_widget byt_rt5651_widgets[] = {
SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Internal Mic", NULL), SND_SOC_DAPM_MIC("Internal Mic", NULL),
SND_SOC_DAPM_SPK("Speaker", NULL), SND_SOC_DAPM_SPK("Speaker", NULL),
SND_SOC_DAPM_LINE("Line In", NULL),
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
platform_clock_control, SND_SOC_DAPM_PRE_PMU | platform_clock_control, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_POST_PMD),
...@@ -138,6 +143,7 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = { ...@@ -138,6 +143,7 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = {
{"Headset Mic", NULL, "Platform Clock"}, {"Headset Mic", NULL, "Platform Clock"},
{"Internal Mic", NULL, "Platform Clock"}, {"Internal Mic", NULL, "Platform Clock"},
{"Speaker", NULL, "Platform Clock"}, {"Speaker", NULL, "Platform Clock"},
{"Line In", NULL, "Platform Clock"},
{"AIF1 Playback", NULL, "ssp2 Tx"}, {"AIF1 Playback", NULL, "ssp2 Tx"},
{"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out0"},
...@@ -151,6 +157,9 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = { ...@@ -151,6 +157,9 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = {
{"Headphone", NULL, "HPOR"}, {"Headphone", NULL, "HPOR"},
{"Speaker", NULL, "LOUTL"}, {"Speaker", NULL, "LOUTL"},
{"Speaker", NULL, "LOUTR"}, {"Speaker", NULL, "LOUTR"},
{"IN2P", NULL, "Line In"},
{"IN2N", NULL, "Line In"},
}; };
static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic_map[] = { static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic_map[] = {
...@@ -171,11 +180,25 @@ static const struct snd_soc_dapm_route byt_rt5651_intmic_in2_map[] = { ...@@ -171,11 +180,25 @@ static const struct snd_soc_dapm_route byt_rt5651_intmic_in2_map[] = {
{"IN2P", NULL, "Internal Mic"}, {"IN2P", NULL, "Internal Mic"},
}; };
static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_in2_map[] = {
{"Internal Mic", NULL, "micbias1"},
{"IN1P", NULL, "Internal Mic"},
{"IN2P", NULL, "Internal Mic"},
{"IN3P", NULL, "Headset Mic"},
};
static const struct snd_soc_dapm_route byt_rt5651_intmic_in3_map[] = {
{"Internal Mic", NULL, "micbias1"},
{"IN3P", NULL, "Headset Mic"},
{"IN1P", NULL, "Internal Mic"},
};
static const struct snd_kcontrol_new byt_rt5651_controls[] = { static const struct snd_kcontrol_new byt_rt5651_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headphone"),
SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Internal Mic"), SOC_DAPM_PIN_SWITCH("Internal Mic"),
SOC_DAPM_PIN_SWITCH("Speaker"), SOC_DAPM_PIN_SWITCH("Speaker"),
SOC_DAPM_PIN_SWITCH("Line In"),
}; };
static struct snd_soc_jack_pin bytcr_jack_pins[] = { static struct snd_soc_jack_pin bytcr_jack_pins[] = {
...@@ -247,8 +270,16 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = { ...@@ -247,8 +270,16 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"), DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"),
}, },
.driver_data = (void *)(BYT_RT5651_DMIC_MAP | .driver_data = (void *)(BYT_RT5651_IN3_MAP),
BYT_RT5651_DMIC_EN), },
{
.callback = byt_rt5651_quirk_cb,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ADI"),
DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Turbot"),
},
.driver_data = (void *)(BYT_RT5651_MCLK_EN |
BYT_RT5651_IN3_MAP),
}, },
{ {
.callback = byt_rt5651_quirk_cb, .callback = byt_rt5651_quirk_cb,
...@@ -256,7 +287,8 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = { ...@@ -256,7 +287,8 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "KIANO"), DMI_MATCH(DMI_SYS_VENDOR, "KIANO"),
DMI_MATCH(DMI_PRODUCT_NAME, "KIANO SlimNote 14.2"), DMI_MATCH(DMI_PRODUCT_NAME, "KIANO SlimNote 14.2"),
}, },
.driver_data = (void *)(BYT_RT5651_IN2_MAP), .driver_data = (void *)(BYT_RT5651_MCLK_EN |
BYT_RT5651_IN1_IN2_MAP),
}, },
{} {}
}; };
...@@ -281,6 +313,14 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) ...@@ -281,6 +313,14 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
custom_map = byt_rt5651_intmic_in2_map; custom_map = byt_rt5651_intmic_in2_map;
num_routes = ARRAY_SIZE(byt_rt5651_intmic_in2_map); num_routes = ARRAY_SIZE(byt_rt5651_intmic_in2_map);
break; break;
case BYT_RT5651_IN1_IN2_MAP:
custom_map = byt_rt5651_intmic_in1_in2_map;
num_routes = ARRAY_SIZE(byt_rt5651_intmic_in1_in2_map);
break;
case BYT_RT5651_IN3_MAP:
custom_map = byt_rt5651_intmic_in3_map;
num_routes = ARRAY_SIZE(byt_rt5651_intmic_in3_map);
break;
default: default:
custom_map = byt_rt5651_intmic_dmic_map; custom_map = byt_rt5651_intmic_dmic_map;
num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic_map); num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic_map);
......
...@@ -76,7 +76,7 @@ static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream, ...@@ -76,7 +76,7 @@ static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream,
} }
/* set correct codec filter for DAI format and clock config */ /* set correct codec filter for DAI format and clock config */
snd_soc_update_bits(rtd->codec, 0x83, 0xffff, 0x8000); snd_soc_component_update_bits(codec_dai->component, 0x83, 0xffff, 0x8000);
return ret; return ret;
} }
......
...@@ -225,7 +225,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd) ...@@ -225,7 +225,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
} }
jack = &ctx->kabylake_headset; jack = &ctx->kabylake_headset;
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA); snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
......
...@@ -195,7 +195,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd) ...@@ -195,7 +195,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
} }
jack = &ctx->kabylake_headset; jack = &ctx->kabylake_headset;
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA); snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
......
/*
* mfld_machine.c - ASoc Machine driver for Intel Medfield MID platform
*
* Copyright (C) 2010 Intel Corp
* Author: Vinod Koul <vinod.koul@intel.com>
* Author: Harsha Priya <priya.harsha@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 published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/init.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/module.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include "../codecs/sn95031.h"
#define MID_MONO 1
#define MID_STEREO 2
#define MID_MAX_CAP 5
#define MFLD_JACK_INSERT 0x04
enum soc_mic_bias_zones {
MFLD_MV_START = 0,
/* mic bias volutage range for Headphones*/
MFLD_MV_HP = 400,
/* mic bias volutage range for American Headset*/
MFLD_MV_AM_HS = 650,
/* mic bias volutage range for Headset*/
MFLD_MV_HS = 2000,
MFLD_MV_UNDEFINED,
};
static unsigned int hs_switch;
static unsigned int lo_dac;
static struct snd_soc_codec *mfld_codec;
struct mfld_mc_private {
void __iomem *int_base;
u8 interrupt_status;
};
struct snd_soc_jack mfld_jack;
/*Headset jack detection DAPM pins */
static struct snd_soc_jack_pin mfld_jack_pins[] = {
{
.pin = "Headphones",
.mask = SND_JACK_HEADPHONE,
},
{
.pin = "AMIC1",
.mask = SND_JACK_MICROPHONE,
},
};
/* jack detection voltage zones */
static struct snd_soc_jack_zone mfld_zones[] = {
{MFLD_MV_START, MFLD_MV_AM_HS, SND_JACK_HEADPHONE},
{MFLD_MV_AM_HS, MFLD_MV_HS, SND_JACK_HEADSET},
};
/* sound card controls */
static const char * const headset_switch_text[] = {"Earpiece", "Headset"};
static const char * const lo_text[] = {"Vibra", "Headset", "IHF", "None"};
static const struct soc_enum headset_enum =
SOC_ENUM_SINGLE_EXT(2, headset_switch_text);
static const struct soc_enum lo_enum =
SOC_ENUM_SINGLE_EXT(4, lo_text);
static int headset_get_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.enumerated.item[0] = hs_switch;
return 0;
}
static int headset_set_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_context *dapm = &card->dapm;
if (ucontrol->value.enumerated.item[0] == hs_switch)
return 0;
snd_soc_dapm_mutex_lock(dapm);
if (ucontrol->value.enumerated.item[0]) {
pr_debug("hs_set HS path\n");
snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones");
snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
} else {
pr_debug("hs_set EP path\n");
snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT");
}
snd_soc_dapm_sync_unlocked(dapm);
snd_soc_dapm_mutex_unlock(dapm);
hs_switch = ucontrol->value.enumerated.item[0];
return 0;
}
static void lo_enable_out_pins(struct snd_soc_dapm_context *dapm)
{
snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTL");
snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTR");
snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTL");
snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTR");
snd_soc_dapm_enable_pin_unlocked(dapm, "VIB1OUT");
snd_soc_dapm_enable_pin_unlocked(dapm, "VIB2OUT");
if (hs_switch) {
snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones");
snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
} else {
snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT");
}
}
static int lo_get_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.enumerated.item[0] = lo_dac;
return 0;
}
static int lo_set_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_context *dapm = &card->dapm;
if (ucontrol->value.enumerated.item[0] == lo_dac)
return 0;
snd_soc_dapm_mutex_lock(dapm);
/* we dont want to work with last state of lineout so just enable all
* pins and then disable pins not required
*/
lo_enable_out_pins(dapm);
switch (ucontrol->value.enumerated.item[0]) {
case 0:
pr_debug("set vibra path\n");
snd_soc_dapm_disable_pin_unlocked(dapm, "VIB1OUT");
snd_soc_dapm_disable_pin_unlocked(dapm, "VIB2OUT");
snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0);
break;
case 1:
pr_debug("set hs path\n");
snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x22);
break;
case 2:
pr_debug("set spkr path\n");
snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTL");
snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTR");
snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x44);
break;
case 3:
pr_debug("set null path\n");
snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTL");
snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTR");
snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x66);
break;
}
snd_soc_dapm_sync_unlocked(dapm);
snd_soc_dapm_mutex_unlock(dapm);
lo_dac = ucontrol->value.enumerated.item[0];
return 0;
}
static const struct snd_kcontrol_new mfld_snd_controls[] = {
SOC_ENUM_EXT("Playback Switch", headset_enum,
headset_get_switch, headset_set_switch),
SOC_ENUM_EXT("Lineout Mux", lo_enum,
lo_get_switch, lo_set_switch),
};
static const struct snd_soc_dapm_widget mfld_widgets[] = {
SND_SOC_DAPM_HP("Headphones", NULL),
SND_SOC_DAPM_MIC("Mic", NULL),
};
static const struct snd_soc_dapm_route mfld_map[] = {
{"Headphones", NULL, "HPOUTR"},
{"Headphones", NULL, "HPOUTL"},
{"Mic", NULL, "AMIC1"},
};
static void mfld_jack_check(unsigned int intr_status)
{
struct mfld_jack_data jack_data;
if (!mfld_codec)
return;
jack_data.mfld_jack = &mfld_jack;
jack_data.intr_id = intr_status;
sn95031_jack_detection(mfld_codec, &jack_data);
/* TODO: add american headset detection post gpiolib support */
}
static int mfld_init(struct snd_soc_pcm_runtime *runtime)
{
struct snd_soc_dapm_context *dapm = &runtime->card->dapm;
int ret_val;
/* default is earpiece pin, userspace sets it explcitly */
snd_soc_dapm_disable_pin(dapm, "Headphones");
/* default is lineout NC, userspace sets it explcitly */
snd_soc_dapm_disable_pin(dapm, "LINEOUTL");
snd_soc_dapm_disable_pin(dapm, "LINEOUTR");
lo_dac = 3;
hs_switch = 0;
/* we dont use linein in this so set to NC */
snd_soc_dapm_disable_pin(dapm, "LINEINL");
snd_soc_dapm_disable_pin(dapm, "LINEINR");
/* Headset and button jack detection */
ret_val = snd_soc_card_jack_new(runtime->card,
"Intel(R) MID Audio Jack", SND_JACK_HEADSET |
SND_JACK_BTN_0 | SND_JACK_BTN_1, &mfld_jack,
mfld_jack_pins, ARRAY_SIZE(mfld_jack_pins));
if (ret_val) {
pr_err("jack creation failed\n");
return ret_val;
}
ret_val = snd_soc_jack_add_zones(&mfld_jack,
ARRAY_SIZE(mfld_zones), mfld_zones);
if (ret_val) {
pr_err("adding jack zones failed\n");
return ret_val;
}
mfld_codec = runtime->codec;
/* we want to check if anything is inserted at boot,
* so send a fake event to codec and it will read adc
* to find if anything is there or not */
mfld_jack_check(MFLD_JACK_INSERT);
return ret_val;
}
static struct snd_soc_dai_link mfld_msic_dailink[] = {
{
.name = "Medfield Headset",
.stream_name = "Headset",
.cpu_dai_name = "Headset-cpu-dai",
.codec_dai_name = "SN95031 Headset",
.codec_name = "sn95031",
.platform_name = "sst-platform",
.init = mfld_init,
},
{
.name = "Medfield Speaker",
.stream_name = "Speaker",
.cpu_dai_name = "Speaker-cpu-dai",
.codec_dai_name = "SN95031 Speaker",
.codec_name = "sn95031",
.platform_name = "sst-platform",
.init = NULL,
},
{
.name = "Medfield Vibra",
.stream_name = "Vibra1",
.cpu_dai_name = "Vibra1-cpu-dai",
.codec_dai_name = "SN95031 Vibra1",
.codec_name = "sn95031",
.platform_name = "sst-platform",
.init = NULL,
},
{
.name = "Medfield Haptics",
.stream_name = "Vibra2",
.cpu_dai_name = "Vibra2-cpu-dai",
.codec_dai_name = "SN95031 Vibra2",
.codec_name = "sn95031",
.platform_name = "sst-platform",
.init = NULL,
},
{
.name = "Medfield Compress",
.stream_name = "Speaker",
.cpu_dai_name = "Compress-cpu-dai",
.codec_dai_name = "SN95031 Speaker",
.codec_name = "sn95031",
.platform_name = "sst-platform",
.init = NULL,
},
};
/* SoC card */
static struct snd_soc_card snd_soc_card_mfld = {
.name = "medfield_audio",
.owner = THIS_MODULE,
.dai_link = mfld_msic_dailink,
.num_links = ARRAY_SIZE(mfld_msic_dailink),
.controls = mfld_snd_controls,
.num_controls = ARRAY_SIZE(mfld_snd_controls),
.dapm_widgets = mfld_widgets,
.num_dapm_widgets = ARRAY_SIZE(mfld_widgets),
.dapm_routes = mfld_map,
.num_dapm_routes = ARRAY_SIZE(mfld_map),
};
static irqreturn_t snd_mfld_jack_intr_handler(int irq, void *dev)
{
struct mfld_mc_private *mc_private = (struct mfld_mc_private *) dev;
memcpy_fromio(&mc_private->interrupt_status,
((void *)(mc_private->int_base)),
sizeof(u8));
return IRQ_WAKE_THREAD;
}
static irqreturn_t snd_mfld_jack_detection(int irq, void *data)
{
struct mfld_mc_private *mc_drv_ctx = (struct mfld_mc_private *) data;
mfld_jack_check(mc_drv_ctx->interrupt_status);
return IRQ_HANDLED;
}
static int snd_mfld_mc_probe(struct platform_device *pdev)
{
int ret_val = 0, irq;
struct mfld_mc_private *mc_drv_ctx;
struct resource *irq_mem;
pr_debug("snd_mfld_mc_probe called\n");
/* retrive the irq number */
irq = platform_get_irq(pdev, 0);
/* audio interrupt base of SRAM location where
* interrupts are stored by System FW */
mc_drv_ctx = devm_kzalloc(&pdev->dev, sizeof(*mc_drv_ctx), GFP_ATOMIC);
if (!mc_drv_ctx)
return -ENOMEM;
irq_mem = platform_get_resource_byname(
pdev, IORESOURCE_MEM, "IRQ_BASE");
if (!irq_mem) {
pr_err("no mem resource given\n");
return -ENODEV;
}
mc_drv_ctx->int_base = devm_ioremap_nocache(&pdev->dev, irq_mem->start,
resource_size(irq_mem));
if (!mc_drv_ctx->int_base) {
pr_err("Mapping of cache failed\n");
return -ENOMEM;
}
/* register for interrupt */
ret_val = devm_request_threaded_irq(&pdev->dev, irq,
snd_mfld_jack_intr_handler,
snd_mfld_jack_detection,
IRQF_SHARED, pdev->dev.driver->name, mc_drv_ctx);
if (ret_val) {
pr_err("cannot register IRQ\n");
return ret_val;
}
/* register the soc card */
snd_soc_card_mfld.dev = &pdev->dev;
ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_mfld);
if (ret_val) {
pr_debug("snd_soc_register_card failed %d\n", ret_val);
return ret_val;
}
platform_set_drvdata(pdev, mc_drv_ctx);
pr_debug("successfully exited probe\n");
return 0;
}
static struct platform_driver snd_mfld_mc_driver = {
.driver = {
.name = "msic_audio",
},
.probe = snd_mfld_mc_probe,
};
module_platform_driver(snd_mfld_mc_driver);
MODULE_DESCRIPTION("ASoC Intel(R) MID Machine driver");
MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:msic-audio");
...@@ -269,7 +269,7 @@ int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, ...@@ -269,7 +269,7 @@ int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
*/ */
timeout = jiffies + msecs_to_jiffies(time); timeout = jiffies + msecs_to_jiffies(time);
while (((sst_dsp_shim_read_unlocked(ctx, offset) & mask) != target) while ((((reg = sst_dsp_shim_read_unlocked(ctx, offset)) & mask) != target)
&& time_before(jiffies, timeout)) { && time_before(jiffies, timeout)) {
k++; k++;
if (k > 10) if (k > 10)
...@@ -278,8 +278,6 @@ int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, ...@@ -278,8 +278,6 @@ int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
usleep_range(s, 2*s); usleep_range(s, 2*s);
} }
reg = sst_dsp_shim_read_unlocked(ctx, offset);
if ((reg & mask) == target) { if ((reg & mask) == target) {
dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s successful\n", dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s successful\n",
reg, operation); reg, operation);
......
...@@ -595,7 +595,7 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, ...@@ -595,7 +595,7 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3); INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3);
skl->d0i3.state = SKL_DSP_D0I3_NONE; skl->d0i3.state = SKL_DSP_D0I3_NONE;
return 0; return skl_dsp_acquire_irq(sst);
} }
EXPORT_SYMBOL_GPL(bxt_sst_dsp_init); EXPORT_SYMBOL_GPL(bxt_sst_dsp_init);
......
...@@ -458,7 +458,7 @@ int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, ...@@ -458,7 +458,7 @@ int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
cnl->boot_complete = false; cnl->boot_complete = false;
init_waitqueue_head(&cnl->boot_wait); init_waitqueue_head(&cnl->boot_wait);
return 0; return skl_dsp_acquire_irq(sst);
} }
EXPORT_SYMBOL_GPL(cnl_sst_dsp_init); EXPORT_SYMBOL_GPL(cnl_sst_dsp_init);
......
/*
* skl-i2s.h - i2s blob mapping
*
* Copyright (C) 2017 Intel Corp
* Author: Subhransu S. Prusty < subhransu.s.prusty@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 published by
* the Free Software Foundation; version 2 of the License.
*
* 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 __SOUND_SOC_SKL_I2S_H
#define __SOUND_SOC_SKL_I2S_H
#define SKL_I2S_MAX_TIME_SLOTS 8
#define SKL_MCLK_DIV_CLK_SRC_MASK GENMASK(17, 16)
#define SKL_MNDSS_DIV_CLK_SRC_MASK GENMASK(21, 20)
#define SKL_SHIFT(x) (ffs(x) - 1)
#define SKL_MCLK_DIV_RATIO_MASK GENMASK(11, 0)
struct skl_i2s_config {
u32 ssc0;
u32 ssc1;
u32 sscto;
u32 sspsp;
u32 sstsa;
u32 ssrsa;
u32 ssc2;
u32 sspsp2;
u32 ssc3;
u32 ssioc;
} __packed;
struct skl_i2s_config_mclk {
u32 mdivctrl;
u32 mdivr;
};
/**
* struct skl_i2s_config_blob_legacy - Structure defines I2S Gateway
* configuration legacy blob
*
* @gtw_attr: Gateway attribute for the I2S Gateway
* @tdm_ts_group: TDM slot mapping against channels in the Gateway.
* @i2s_cfg: I2S HW registers
* @mclk: MCLK clock source and divider values
*/
struct skl_i2s_config_blob_legacy {
u32 gtw_attr;
u32 tdm_ts_group[SKL_I2S_MAX_TIME_SLOTS];
struct skl_i2s_config i2s_cfg;
struct skl_i2s_config_mclk mclk;
};
#endif /* __SOUND_SOC_SKL_I2S_H */
...@@ -55,6 +55,19 @@ static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab) ...@@ -55,6 +55,19 @@ static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab)
return 0; return 0;
} }
#define SKL_ASTATE_PARAM_ID 4
void skl_dsp_set_astate_cfg(struct skl_sst *ctx, u32 cnt, void *data)
{
struct skl_ipc_large_config_msg msg = {0};
msg.large_param_id = SKL_ASTATE_PARAM_ID;
msg.param_data_size = (cnt * sizeof(struct skl_astate_param) +
sizeof(cnt));
skl_ipc_set_large_config(&ctx->ipc, &msg, data);
}
#define NOTIFICATION_PARAM_ID 3 #define NOTIFICATION_PARAM_ID 3
#define NOTIFICATION_MASK 0xf #define NOTIFICATION_MASK 0xf
...@@ -404,11 +417,20 @@ int skl_resume_dsp(struct skl *skl) ...@@ -404,11 +417,20 @@ int skl_resume_dsp(struct skl *skl)
if (skl->skl_sst->is_first_boot == true) if (skl->skl_sst->is_first_boot == true)
return 0; return 0;
/* disable dynamic clock gating during fw and lib download */
ctx->enable_miscbdcge(ctx->dev, false);
ret = skl_dsp_wake(ctx->dsp); ret = skl_dsp_wake(ctx->dsp);
ctx->enable_miscbdcge(ctx->dev, true);
if (ret < 0) if (ret < 0)
return ret; return ret;
skl_dsp_enable_notification(skl->skl_sst, false); skl_dsp_enable_notification(skl->skl_sst, false);
if (skl->cfg.astate_cfg != NULL) {
skl_dsp_set_astate_cfg(skl->skl_sst, skl->cfg.astate_cfg->count,
skl->cfg.astate_cfg);
}
return ret; return ret;
} }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
*/ */
#include <linux/pci.h> #include <linux/pci.h>
#include "skl.h" #include "skl.h"
#include "skl-i2s.h"
#define NHLT_ACPI_HEADER_SIG "NHLT" #define NHLT_ACPI_HEADER_SIG "NHLT"
...@@ -277,3 +278,157 @@ void skl_nhlt_remove_sysfs(struct skl *skl) ...@@ -277,3 +278,157 @@ void skl_nhlt_remove_sysfs(struct skl *skl)
sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr); sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr);
} }
/*
* Queries NHLT for all the fmt configuration for a particular endpoint and
* stores all possible rates supported in a rate table for the corresponding
* sclk/sclkfs.
*/
static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks,
struct nhlt_fmt *fmt, u8 id)
{
struct skl_i2s_config_blob_legacy *i2s_config;
struct skl_clk_parent_src *parent;
struct skl_ssp_clk *sclk, *sclkfs;
struct nhlt_fmt_cfg *fmt_cfg;
struct wav_fmt_ext *wav_fmt;
unsigned long rate = 0;
bool present = false;
int rate_index = 0;
u16 channels, bps;
u8 clk_src;
int i, j;
u32 fs;
sclk = &ssp_clks[SKL_SCLK_OFS];
sclkfs = &ssp_clks[SKL_SCLKFS_OFS];
if (fmt->fmt_count == 0)
return;
for (i = 0; i < fmt->fmt_count; i++) {
fmt_cfg = &fmt->fmt_config[i];
wav_fmt = &fmt_cfg->fmt_ext;
channels = wav_fmt->fmt.channels;
bps = wav_fmt->fmt.bits_per_sample;
fs = wav_fmt->fmt.samples_per_sec;
/*
* In case of TDM configuration on a ssp, there can
* be more than one blob in which channel masks are
* different for each usecase for a specific rate and bps.
* But the sclk rate will be generated for the total
* number of channels used for that endpoint.
*
* So for the given fs and bps, choose blob which has
* the superset of all channels for that endpoint and
* derive the rate.
*/
for (j = i; j < fmt->fmt_count; j++) {
fmt_cfg = &fmt->fmt_config[j];
wav_fmt = &fmt_cfg->fmt_ext;
if ((fs == wav_fmt->fmt.samples_per_sec) &&
(bps == wav_fmt->fmt.bits_per_sample))
channels = max_t(u16, channels,
wav_fmt->fmt.channels);
}
rate = channels * bps * fs;
/* check if the rate is added already to the given SSP's sclk */
for (j = 0; (j < SKL_MAX_CLK_RATES) &&
(sclk[id].rate_cfg[j].rate != 0); j++) {
if (sclk[id].rate_cfg[j].rate == rate) {
present = true;
break;
}
}
/* Fill rate and parent for sclk/sclkfs */
if (!present) {
/* MCLK Divider Source Select */
i2s_config = (struct skl_i2s_config_blob_legacy *)
fmt->fmt_config[0].config.caps;
clk_src = ((i2s_config->mclk.mdivctrl)
& SKL_MNDSS_DIV_CLK_SRC_MASK) >>
SKL_SHIFT(SKL_MNDSS_DIV_CLK_SRC_MASK);
parent = skl_get_parent_clk(clk_src);
/*
* Do not copy the config data if there is no parent
* clock available for this clock source select
*/
if (!parent)
continue;
sclk[id].rate_cfg[rate_index].rate = rate;
sclk[id].rate_cfg[rate_index].config = fmt_cfg;
sclkfs[id].rate_cfg[rate_index].rate = rate;
sclkfs[id].rate_cfg[rate_index].config = fmt_cfg;
sclk[id].parent_name = parent->name;
sclkfs[id].parent_name = parent->name;
rate_index++;
}
}
}
static void skl_get_mclk(struct skl *skl, struct skl_ssp_clk *mclk,
struct nhlt_fmt *fmt, u8 id)
{
struct skl_i2s_config_blob_legacy *i2s_config;
struct nhlt_specific_cfg *fmt_cfg;
struct skl_clk_parent_src *parent;
u32 clkdiv, div_ratio;
u8 clk_src;
fmt_cfg = &fmt->fmt_config[0].config;
i2s_config = (struct skl_i2s_config_blob_legacy *)fmt_cfg->caps;
/* MCLK Divider Source Select */
clk_src = ((i2s_config->mclk.mdivctrl) & SKL_MCLK_DIV_CLK_SRC_MASK) >>
SKL_SHIFT(SKL_MCLK_DIV_CLK_SRC_MASK);
clkdiv = i2s_config->mclk.mdivr & SKL_MCLK_DIV_RATIO_MASK;
/* bypass divider */
div_ratio = 1;
if (clkdiv != SKL_MCLK_DIV_RATIO_MASK)
/* Divider is 2 + clkdiv */
div_ratio = clkdiv + 2;
/* Calculate MCLK rate from source using div value */
parent = skl_get_parent_clk(clk_src);
if (!parent)
return;
mclk[id].rate_cfg[0].rate = parent->rate/div_ratio;
mclk[id].rate_cfg[0].config = &fmt->fmt_config[0];
mclk[id].parent_name = parent->name;
}
void skl_get_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks)
{
struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
struct nhlt_endpoint *epnt;
struct nhlt_fmt *fmt;
int i;
u8 id;
epnt = (struct nhlt_endpoint *)nhlt->desc;
for (i = 0; i < nhlt->endpoint_count; i++) {
if (epnt->linktype == NHLT_LINK_SSP) {
id = epnt->virtual_bus_id;
fmt = (struct nhlt_fmt *)(epnt->config.caps
+ epnt->config.size);
skl_get_ssp_clks(skl, ssp_clks, fmt, id);
skl_get_mclk(skl, ssp_clks, fmt, id);
}
epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
}
}
...@@ -537,7 +537,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, ...@@ -537,7 +537,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); link = snd_hdac_ext_bus_get_link(ebus, codec_dai->component->name);
if (!link) if (!link)
return -EINVAL; return -EINVAL;
...@@ -620,7 +620,7 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream, ...@@ -620,7 +620,7 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
link_dev->link_prepared = 0; link_dev->link_prepared = 0;
link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); link = snd_hdac_ext_bus_get_link(ebus, rtd->codec_dai->component->name);
if (!link) if (!link)
return -EINVAL; return -EINVAL;
...@@ -1343,7 +1343,11 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform) ...@@ -1343,7 +1343,11 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
return -EIO; return -EIO;
} }
/* disable dynamic clock gating during fw and lib download */
skl->skl_sst->enable_miscbdcge(platform->dev, false);
ret = ops->init_fw(platform->dev, skl->skl_sst); ret = ops->init_fw(platform->dev, skl->skl_sst);
skl->skl_sst->enable_miscbdcge(platform->dev, true);
if (ret < 0) { if (ret < 0) {
dev_err(platform->dev, "Failed to boot first fw: %d\n", ret); dev_err(platform->dev, "Failed to boot first fw: %d\n", ret);
return ret; return ret;
...@@ -1351,6 +1355,12 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform) ...@@ -1351,6 +1355,12 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
skl_populate_modules(skl); skl_populate_modules(skl);
skl->skl_sst->update_d0i3c = skl_update_d0i3c; skl->skl_sst->update_d0i3c = skl_update_d0i3c;
skl_dsp_enable_notification(skl->skl_sst, false); skl_dsp_enable_notification(skl->skl_sst, false);
if (skl->cfg.astate_cfg != NULL) {
skl_dsp_set_astate_cfg(skl->skl_sst,
skl->cfg.astate_cfg->count,
skl->cfg.astate_cfg);
}
} }
pm_runtime_mark_last_busy(platform->dev); pm_runtime_mark_last_busy(platform->dev);
pm_runtime_put_autosuspend(platform->dev); pm_runtime_put_autosuspend(platform->dev);
......
/*
* skl-ssp-clk.h - Skylake ssp clock information and ipc structure
*
* Copyright (C) 2017 Intel Corp
* Author: Jaikrishna Nemallapudi <jaikrishnax.nemallapudi@intel.com>
* Author: Subhransu S. Prusty <subhransu.s.prusty@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 published by
* the Free Software Foundation; version 2 of the License.
*
* 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 SOUND_SOC_SKL_SSP_CLK_H
#define SOUND_SOC_SKL_SSP_CLK_H
#define SKL_MAX_SSP 6
/* xtal/cardinal/pll, parent of ssp clocks and mclk */
#define SKL_MAX_CLK_SRC 3
#define SKL_MAX_SSP_CLK_TYPES 3 /* mclk, sclk, sclkfs */
#define SKL_MAX_CLK_CNT (SKL_MAX_SSP * SKL_MAX_SSP_CLK_TYPES)
/* Max number of configurations supported for each clock */
#define SKL_MAX_CLK_RATES 10
#define SKL_SCLK_OFS SKL_MAX_SSP
#define SKL_SCLKFS_OFS (SKL_SCLK_OFS + SKL_MAX_SSP)
enum skl_clk_type {
SKL_MCLK,
SKL_SCLK,
SKL_SCLK_FS,
};
enum skl_clk_src_type {
SKL_XTAL,
SKL_CARDINAL,
SKL_PLL,
};
struct skl_clk_parent_src {
u8 clk_id;
const char *name;
unsigned long rate;
const char *parent_name;
};
struct skl_clk_rate_cfg_table {
unsigned long rate;
void *config;
};
/*
* rate for mclk will be in rates[0]. For sclk and sclkfs, rates[] store
* all possible clocks ssp can generate for that platform.
*/
struct skl_ssp_clk {
const char *name;
const char *parent_name;
struct skl_clk_rate_cfg_table rate_cfg[SKL_MAX_CLK_RATES];
};
struct skl_clk_pdata {
struct skl_clk_parent_src *parent_clks;
int num_clks;
struct skl_ssp_clk *ssp_clks;
void *pvt_data;
};
#endif /* SOUND_SOC_SKL_SSP_CLK_H */
...@@ -435,16 +435,22 @@ struct sst_dsp *skl_dsp_ctx_init(struct device *dev, ...@@ -435,16 +435,22 @@ struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
return NULL; return NULL;
} }
return sst;
}
int skl_dsp_acquire_irq(struct sst_dsp *sst)
{
struct sst_dsp_device *sst_dev = sst->sst_dev;
int ret;
/* Register the ISR */ /* Register the ISR */
ret = request_threaded_irq(sst->irq, sst->ops->irq_handler, ret = request_threaded_irq(sst->irq, sst->ops->irq_handler,
sst_dev->thread, IRQF_SHARED, "AudioDSP", sst); sst_dev->thread, IRQF_SHARED, "AudioDSP", sst);
if (ret) { if (ret)
dev_err(sst->dev, "unable to grab threaded IRQ %d, disabling device\n", dev_err(sst->dev, "unable to grab threaded IRQ %d, disabling device\n",
sst->irq); sst->irq);
return NULL;
}
return sst; return ret;
} }
void skl_dsp_free(struct sst_dsp *dsp) void skl_dsp_free(struct sst_dsp *dsp)
......
...@@ -206,6 +206,7 @@ int skl_cldma_wait_interruptible(struct sst_dsp *ctx); ...@@ -206,6 +206,7 @@ int skl_cldma_wait_interruptible(struct sst_dsp *ctx);
void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state);
struct sst_dsp *skl_dsp_ctx_init(struct device *dev, struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
struct sst_dsp_device *sst_dev, int irq); struct sst_dsp_device *sst_dev, int irq);
int skl_dsp_acquire_irq(struct sst_dsp *sst);
bool is_skl_dsp_running(struct sst_dsp *ctx); bool is_skl_dsp_running(struct sst_dsp *ctx);
unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx); unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx);
...@@ -251,6 +252,9 @@ void skl_freeup_uuid_list(struct skl_sst *ctx); ...@@ -251,6 +252,9 @@ void skl_freeup_uuid_list(struct skl_sst *ctx);
int skl_dsp_strip_extended_manifest(struct firmware *fw); int skl_dsp_strip_extended_manifest(struct firmware *fw);
void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable); void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable);
void skl_dsp_set_astate_cfg(struct skl_sst *ctx, u32 cnt, void *data);
int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name, int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp, struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp,
struct sst_dsp_device *skl_dev); struct sst_dsp_device *skl_dev);
......
...@@ -178,7 +178,8 @@ static inline int skl_pvtid_128(struct uuid_module *module) ...@@ -178,7 +178,8 @@ static inline int skl_pvtid_128(struct uuid_module *module)
* skl_get_pvt_id: generate a private id for use as module id * skl_get_pvt_id: generate a private id for use as module id
* *
* @ctx: driver context * @ctx: driver context
* @mconfig: module configuration data * @uuid_mod: module's uuid
* @instance_id: module's instance id
* *
* This generates a 128 bit private unique id for a module TYPE so that * This generates a 128 bit private unique id for a module TYPE so that
* module instance is unique * module instance is unique
...@@ -208,7 +209,8 @@ EXPORT_SYMBOL_GPL(skl_get_pvt_id); ...@@ -208,7 +209,8 @@ EXPORT_SYMBOL_GPL(skl_get_pvt_id);
* skl_put_pvt_id: free up the private id allocated * skl_put_pvt_id: free up the private id allocated
* *
* @ctx: driver context * @ctx: driver context
* @mconfig: module configuration data * @uuid_mod: module's uuid
* @pvt_id: module pvt id
* *
* This frees a 128 bit private unique id previously generated * This frees a 128 bit private unique id previously generated
*/ */
......
...@@ -569,7 +569,7 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, ...@@ -569,7 +569,7 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
sst->fw_ops = skl_fw_ops; sst->fw_ops = skl_fw_ops;
return 0; return skl_dsp_acquire_irq(sst);
} }
EXPORT_SYMBOL_GPL(skl_sst_dsp_init); EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
......
...@@ -3056,11 +3056,13 @@ static int skl_tplg_get_int_tkn(struct device *dev, ...@@ -3056,11 +3056,13 @@ static int skl_tplg_get_int_tkn(struct device *dev,
struct snd_soc_tplg_vendor_value_elem *tkn_elem, struct snd_soc_tplg_vendor_value_elem *tkn_elem,
struct skl *skl) struct skl *skl)
{ {
int tkn_count = 0, ret; int tkn_count = 0, ret, size;
static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx; static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx;
struct skl_module_res *res = NULL; struct skl_module_res *res = NULL;
struct skl_module_iface *fmt = NULL; struct skl_module_iface *fmt = NULL;
struct skl_module *mod = NULL; struct skl_module *mod = NULL;
static struct skl_astate_param *astate_table;
static int astate_cfg_idx, count;
int i; int i;
if (skl->modules) { if (skl->modules) {
...@@ -3093,6 +3095,46 @@ static int skl_tplg_get_int_tkn(struct device *dev, ...@@ -3093,6 +3095,46 @@ static int skl_tplg_get_int_tkn(struct device *dev,
mod_idx = tkn_elem->value; mod_idx = tkn_elem->value;
break; break;
case SKL_TKN_U32_ASTATE_COUNT:
if (astate_table != NULL) {
dev_err(dev, "More than one entry for A-State count");
return -EINVAL;
}
if (tkn_elem->value > SKL_MAX_ASTATE_CFG) {
dev_err(dev, "Invalid A-State count %d\n",
tkn_elem->value);
return -EINVAL;
}
size = tkn_elem->value * sizeof(struct skl_astate_param) +
sizeof(count);
skl->cfg.astate_cfg = devm_kzalloc(dev, size, GFP_KERNEL);
if (!skl->cfg.astate_cfg)
return -ENOMEM;
astate_table = skl->cfg.astate_cfg->astate_table;
count = skl->cfg.astate_cfg->count = tkn_elem->value;
break;
case SKL_TKN_U32_ASTATE_IDX:
if (tkn_elem->value >= count) {
dev_err(dev, "Invalid A-State index %d\n",
tkn_elem->value);
return -EINVAL;
}
astate_cfg_idx = tkn_elem->value;
break;
case SKL_TKN_U32_ASTATE_KCPS:
astate_table[astate_cfg_idx].kcps = tkn_elem->value;
break;
case SKL_TKN_U32_ASTATE_CLK_SRC:
astate_table[astate_cfg_idx].clk_src = tkn_elem->value;
break;
case SKL_TKN_U8_IN_PIN_TYPE: case SKL_TKN_U8_IN_PIN_TYPE:
case SKL_TKN_U8_OUT_PIN_TYPE: case SKL_TKN_U8_OUT_PIN_TYPE:
case SKL_TKN_U8_IN_QUEUE_COUNT: case SKL_TKN_U8_IN_QUEUE_COUNT:
......
...@@ -355,6 +355,7 @@ static int skl_resume(struct device *dev) ...@@ -355,6 +355,7 @@ static int skl_resume(struct device *dev)
if (ebus->cmd_dma_state) if (ebus->cmd_dma_state)
snd_hdac_bus_init_cmd_io(&ebus->bus); snd_hdac_bus_init_cmd_io(&ebus->bus);
ret = 0;
} else { } else {
ret = _skl_resume(ebus); ret = _skl_resume(ebus);
...@@ -435,19 +436,51 @@ static int skl_free(struct hdac_ext_bus *ebus) ...@@ -435,19 +436,51 @@ static int skl_free(struct hdac_ext_bus *ebus)
return 0; return 0;
} }
static int skl_machine_device_register(struct skl *skl, void *driver_data) /*
* For each ssp there are 3 clocks (mclk/sclk/sclkfs).
* e.g. for ssp0, clocks will be named as
* "ssp0_mclk", "ssp0_sclk", "ssp0_sclkfs"
* So for skl+, there are 6 ssps, so 18 clocks will be created.
*/
static struct skl_ssp_clk skl_ssp_clks[] = {
{.name = "ssp0_mclk"}, {.name = "ssp1_mclk"}, {.name = "ssp2_mclk"},
{.name = "ssp3_mclk"}, {.name = "ssp4_mclk"}, {.name = "ssp5_mclk"},
{.name = "ssp0_sclk"}, {.name = "ssp1_sclk"}, {.name = "ssp2_sclk"},
{.name = "ssp3_sclk"}, {.name = "ssp4_sclk"}, {.name = "ssp5_sclk"},
{.name = "ssp0_sclkfs"}, {.name = "ssp1_sclkfs"},
{.name = "ssp2_sclkfs"},
{.name = "ssp3_sclkfs"}, {.name = "ssp4_sclkfs"},
{.name = "ssp5_sclkfs"},
};
static int skl_find_machine(struct skl *skl, void *driver_data)
{ {
struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
struct platform_device *pdev;
struct snd_soc_acpi_mach *mach = driver_data; struct snd_soc_acpi_mach *mach = driver_data;
int ret; struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
struct skl_machine_pdata *pdata;
mach = snd_soc_acpi_find_machine(mach); mach = snd_soc_acpi_find_machine(mach);
if (mach == NULL) { if (mach == NULL) {
dev_err(bus->dev, "No matching machine driver found\n"); dev_err(bus->dev, "No matching machine driver found\n");
return -ENODEV; return -ENODEV;
} }
skl->mach = mach;
skl->fw_name = mach->fw_filename; skl->fw_name = mach->fw_filename;
pdata = skl->mach->pdata;
if (mach->pdata)
skl->use_tplg_pcm = pdata->use_tplg_pcm;
return 0;
}
static int skl_machine_device_register(struct skl *skl)
{
struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
struct snd_soc_acpi_mach *mach = skl->mach;
struct platform_device *pdev;
int ret;
pdev = platform_device_alloc(mach->drv_name, -1); pdev = platform_device_alloc(mach->drv_name, -1);
if (pdev == NULL) { if (pdev == NULL) {
...@@ -462,11 +495,8 @@ static int skl_machine_device_register(struct skl *skl, void *driver_data) ...@@ -462,11 +495,8 @@ static int skl_machine_device_register(struct skl *skl, void *driver_data)
return -EIO; return -EIO;
} }
if (mach->pdata) { if (mach->pdata)
skl->use_tplg_pcm =
((struct skl_machine_pdata *)mach->pdata)->use_tplg_pcm;
dev_set_drvdata(&pdev->dev, mach->pdata); dev_set_drvdata(&pdev->dev, mach->pdata);
}
skl->i2s_dev = pdev; skl->i2s_dev = pdev;
...@@ -509,6 +539,74 @@ static void skl_dmic_device_unregister(struct skl *skl) ...@@ -509,6 +539,74 @@ static void skl_dmic_device_unregister(struct skl *skl)
platform_device_unregister(skl->dmic_dev); platform_device_unregister(skl->dmic_dev);
} }
static struct skl_clk_parent_src skl_clk_src[] = {
{ .clk_id = SKL_XTAL, .name = "xtal" },
{ .clk_id = SKL_CARDINAL, .name = "cardinal", .rate = 24576000 },
{ .clk_id = SKL_PLL, .name = "pll", .rate = 96000000 },
};
struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(skl_clk_src); i++) {
if (skl_clk_src[i].clk_id == clk_id)
return &skl_clk_src[i];
}
return NULL;
}
static void init_skl_xtal_rate(int pci_id)
{
switch (pci_id) {
case 0x9d70:
case 0x9d71:
skl_clk_src[0].rate = 24000000;
return;
default:
skl_clk_src[0].rate = 19200000;
return;
}
}
static int skl_clock_device_register(struct skl *skl)
{
struct platform_device_info pdevinfo = {NULL};
struct skl_clk_pdata *clk_pdata;
clk_pdata = devm_kzalloc(&skl->pci->dev, sizeof(*clk_pdata),
GFP_KERNEL);
if (!clk_pdata)
return -ENOMEM;
init_skl_xtal_rate(skl->pci->device);
clk_pdata->parent_clks = skl_clk_src;
clk_pdata->ssp_clks = skl_ssp_clks;
clk_pdata->num_clks = ARRAY_SIZE(skl_ssp_clks);
/* Query NHLT to fill the rates and parent */
skl_get_clks(skl, clk_pdata->ssp_clks);
clk_pdata->pvt_data = skl;
/* Register Platform device */
pdevinfo.parent = &skl->pci->dev;
pdevinfo.id = -1;
pdevinfo.name = "skl-ssp-clk";
pdevinfo.data = clk_pdata;
pdevinfo.size_data = sizeof(*clk_pdata);
skl->clk_dev = platform_device_register_full(&pdevinfo);
return PTR_ERR_OR_ZERO(skl->clk_dev);
}
static void skl_clock_device_unregister(struct skl *skl)
{
if (skl->clk_dev)
platform_device_unregister(skl->clk_dev);
}
/* /*
* Probe the given codec address * Probe the given codec address
*/ */
...@@ -615,18 +713,30 @@ static void skl_probe_work(struct work_struct *work) ...@@ -615,18 +713,30 @@ static void skl_probe_work(struct work_struct *work)
/* create codec instances */ /* create codec instances */
skl_codec_create(ebus); skl_codec_create(ebus);
/* register platform dai and controls */
err = skl_platform_register(bus->dev);
if (err < 0) {
dev_err(bus->dev, "platform register failed: %d\n", err);
return;
}
if (bus->ppcap) {
err = skl_machine_device_register(skl);
if (err < 0) {
dev_err(bus->dev, "machine register failed: %d\n", err);
goto out_err;
}
}
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
err = snd_hdac_display_power(bus, false); err = snd_hdac_display_power(bus, false);
if (err < 0) { if (err < 0) {
dev_err(bus->dev, "Cannot turn off display power on i915\n"); dev_err(bus->dev, "Cannot turn off display power on i915\n");
skl_machine_device_unregister(skl);
return; return;
} }
} }
/* register platform dai and controls */
err = skl_platform_register(bus->dev);
if (err < 0)
return;
/* /*
* we are done probing so decrement link counts * we are done probing so decrement link counts
*/ */
...@@ -791,18 +901,21 @@ static int skl_probe(struct pci_dev *pci, ...@@ -791,18 +901,21 @@ static int skl_probe(struct pci_dev *pci,
/* check if dsp is there */ /* check if dsp is there */
if (bus->ppcap) { if (bus->ppcap) {
err = skl_machine_device_register(skl, /* create device for dsp clk */
(void *)pci_id->driver_data); err = skl_clock_device_register(skl);
if (err < 0)
goto out_clk_free;
err = skl_find_machine(skl, (void *)pci_id->driver_data);
if (err < 0) if (err < 0)
goto out_nhlt_free; goto out_nhlt_free;
err = skl_init_dsp(skl); err = skl_init_dsp(skl);
if (err < 0) { if (err < 0) {
dev_dbg(bus->dev, "error failed to register dsp\n"); dev_dbg(bus->dev, "error failed to register dsp\n");
goto out_mach_free; goto out_nhlt_free;
} }
skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge; skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge;
} }
if (bus->mlcap) if (bus->mlcap)
snd_hdac_ext_bus_get_ml_capabilities(ebus); snd_hdac_ext_bus_get_ml_capabilities(ebus);
...@@ -820,8 +933,8 @@ static int skl_probe(struct pci_dev *pci, ...@@ -820,8 +933,8 @@ static int skl_probe(struct pci_dev *pci,
out_dsp_free: out_dsp_free:
skl_free_dsp(skl); skl_free_dsp(skl);
out_mach_free: out_clk_free:
skl_machine_device_unregister(skl); skl_clock_device_unregister(skl);
out_nhlt_free: out_nhlt_free:
skl_nhlt_free(skl->nhlt); skl_nhlt_free(skl->nhlt);
out_free: out_free:
...@@ -872,6 +985,7 @@ static void skl_remove(struct pci_dev *pci) ...@@ -872,6 +985,7 @@ static void skl_remove(struct pci_dev *pci)
skl_free_dsp(skl); skl_free_dsp(skl);
skl_machine_device_unregister(skl); skl_machine_device_unregister(skl);
skl_dmic_device_unregister(skl); skl_dmic_device_unregister(skl);
skl_clock_device_unregister(skl);
skl_nhlt_remove_sysfs(skl); skl_nhlt_remove_sysfs(skl);
skl_nhlt_free(skl->nhlt); skl_nhlt_free(skl->nhlt);
skl_free(ebus); skl_free(ebus);
......
...@@ -25,9 +25,12 @@ ...@@ -25,9 +25,12 @@
#include <sound/hdaudio_ext.h> #include <sound/hdaudio_ext.h>
#include <sound/soc.h> #include <sound/soc.h>
#include "skl-nhlt.h" #include "skl-nhlt.h"
#include "skl-ssp-clk.h"
#define SKL_SUSPEND_DELAY 2000 #define SKL_SUSPEND_DELAY 2000
#define SKL_MAX_ASTATE_CFG 3
#define AZX_PCIREG_PGCTL 0x44 #define AZX_PCIREG_PGCTL 0x44
#define AZX_PGCTL_LSRMD_MASK (1 << 4) #define AZX_PGCTL_LSRMD_MASK (1 << 4)
#define AZX_PCIREG_CGCTL 0x48 #define AZX_PCIREG_CGCTL 0x48
...@@ -45,6 +48,20 @@ struct skl_dsp_resource { ...@@ -45,6 +48,20 @@ struct skl_dsp_resource {
struct skl_debug; struct skl_debug;
struct skl_astate_param {
u32 kcps;
u32 clk_src;
};
struct skl_astate_config {
u32 count;
struct skl_astate_param astate_table[0];
};
struct skl_fw_config {
struct skl_astate_config *astate_cfg;
};
struct skl { struct skl {
struct hdac_ext_bus ebus; struct hdac_ext_bus ebus;
struct pci_dev *pci; struct pci_dev *pci;
...@@ -52,6 +69,7 @@ struct skl { ...@@ -52,6 +69,7 @@ struct skl {
unsigned int init_done:1; /* delayed init status */ unsigned int init_done:1; /* delayed init status */
struct platform_device *dmic_dev; struct platform_device *dmic_dev;
struct platform_device *i2s_dev; struct platform_device *i2s_dev;
struct platform_device *clk_dev;
struct snd_soc_platform *platform; struct snd_soc_platform *platform;
struct snd_soc_dai_driver *dais; struct snd_soc_dai_driver *dais;
...@@ -75,6 +93,8 @@ struct skl { ...@@ -75,6 +93,8 @@ struct skl {
u8 nr_modules; u8 nr_modules;
struct skl_module **modules; struct skl_module **modules;
bool use_tplg_pcm; bool use_tplg_pcm;
struct skl_fw_config cfg;
struct snd_soc_acpi_mach *mach;
}; };
#define skl_to_ebus(s) (&(s)->ebus) #define skl_to_ebus(s) (&(s)->ebus)
...@@ -125,6 +145,8 @@ const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id); ...@@ -125,6 +145,8 @@ const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id);
void skl_update_d0i3c(struct device *dev, bool enable); void skl_update_d0i3c(struct device *dev, bool enable);
int skl_nhlt_create_sysfs(struct skl *skl); int skl_nhlt_create_sysfs(struct skl *skl);
void skl_nhlt_remove_sysfs(struct skl *skl); void skl_nhlt_remove_sysfs(struct skl *skl);
void skl_get_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks);
struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id);
struct skl_module_cfg; struct skl_module_cfg;
......
...@@ -49,41 +49,13 @@ const char *snd_soc_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]) ...@@ -49,41 +49,13 @@ const char *snd_soc_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN])
} }
EXPORT_SYMBOL_GPL(snd_soc_acpi_find_name_from_hid); EXPORT_SYMBOL_GPL(snd_soc_acpi_find_name_from_hid);
static acpi_status snd_soc_acpi_mach_match(acpi_handle handle, u32 level,
void *context, void **ret)
{
unsigned long long sta;
acpi_status status;
*(bool *)context = true;
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT))
*(bool *)context = false;
return AE_OK;
}
bool snd_soc_acpi_check_hid(const u8 hid[ACPI_ID_LEN])
{
acpi_status status;
bool found = false;
status = acpi_get_devices(hid, snd_soc_acpi_mach_match, &found, NULL);
if (ACPI_FAILURE(status))
return false;
return found;
}
EXPORT_SYMBOL_GPL(snd_soc_acpi_check_hid);
struct snd_soc_acpi_mach * struct snd_soc_acpi_mach *
snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines) snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines)
{ {
struct snd_soc_acpi_mach *mach; struct snd_soc_acpi_mach *mach;
for (mach = machines; mach->id[0]; mach++) { for (mach = machines; mach->id[0]; mach++) {
if (snd_soc_acpi_check_hid(mach->id) == true) { if (acpi_dev_present(mach->id, NULL, -1)) {
if (mach->machine_quirk) if (mach->machine_quirk)
mach = mach->machine_quirk(mach); mach = mach->machine_quirk(mach);
return mach; return mach;
...@@ -161,7 +133,7 @@ struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) ...@@ -161,7 +133,7 @@ struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg)
return mach; return mach;
for (i = 0; i < codec_list->num_codecs; i++) { for (i = 0; i < codec_list->num_codecs; i++) {
if (snd_soc_acpi_check_hid(codec_list->codecs[i]) != true) if (!acpi_dev_present(codec_list->codecs[i], NULL, -1))
return NULL; return NULL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment