mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 16:29:59 +00:00
Merge remote-tracking branch 'asoc/topic/intel' into asoc-next
This commit is contained in:
commit
b68cbc1d1d
44 changed files with 1071 additions and 1957 deletions
|
@ -737,16 +737,17 @@ bool acpi_dev_found(const char *hid)
|
|||
}
|
||||
EXPORT_SYMBOL(acpi_dev_found);
|
||||
|
||||
struct acpi_dev_present_info {
|
||||
struct acpi_dev_match_info {
|
||||
const char *dev_name;
|
||||
struct acpi_device_id hid[2];
|
||||
const char *uid;
|
||||
s64 hrv;
|
||||
};
|
||||
|
||||
static int acpi_dev_present_cb(struct device *dev, void *data)
|
||||
static int acpi_dev_match_cb(struct device *dev, void *data)
|
||||
{
|
||||
struct acpi_device *adev = to_acpi_device(dev);
|
||||
struct acpi_dev_present_info *match = data;
|
||||
struct acpi_dev_match_info *match = data;
|
||||
unsigned long long hrv;
|
||||
acpi_status status;
|
||||
|
||||
|
@ -757,6 +758,8 @@ static int acpi_dev_present_cb(struct device *dev, void *data)
|
|||
strcmp(adev->pnp.unique_id, match->uid)))
|
||||
return 0;
|
||||
|
||||
match->dev_name = acpi_dev_name(adev);
|
||||
|
||||
if (match->hrv == -1)
|
||||
return 1;
|
||||
|
||||
|
@ -789,20 +792,44 @@ static int acpi_dev_present_cb(struct device *dev, void *data)
|
|||
*/
|
||||
bool acpi_dev_present(const char *hid, const char *uid, s64 hrv)
|
||||
{
|
||||
struct acpi_dev_present_info match = {};
|
||||
struct acpi_dev_match_info match = {};
|
||||
struct device *dev;
|
||||
|
||||
strlcpy(match.hid[0].id, hid, sizeof(match.hid[0].id));
|
||||
match.uid = uid;
|
||||
match.hrv = hrv;
|
||||
|
||||
dev = bus_find_device(&acpi_bus_type, NULL, &match,
|
||||
acpi_dev_present_cb);
|
||||
|
||||
dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb);
|
||||
return !!dev;
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_dev_present);
|
||||
|
||||
/**
|
||||
* acpi_dev_get_first_match_name - Return name of first match of ACPI device
|
||||
* @hid: Hardware ID of the device.
|
||||
* @uid: Unique ID of the device, pass NULL to not check _UID
|
||||
* @hrv: Hardware Revision of the device, pass -1 to not check _HRV
|
||||
*
|
||||
* Return device name if a matching device was present
|
||||
* at the moment of invocation, or NULL otherwise.
|
||||
*
|
||||
* See additional information in acpi_dev_present() as well.
|
||||
*/
|
||||
const char *
|
||||
acpi_dev_get_first_match_name(const char *hid, const char *uid, s64 hrv)
|
||||
{
|
||||
struct acpi_dev_match_info match = {};
|
||||
struct device *dev;
|
||||
|
||||
strlcpy(match.hid[0].id, hid, sizeof(match.hid[0].id));
|
||||
match.uid = uid;
|
||||
match.hrv = hrv;
|
||||
|
||||
dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb);
|
||||
return dev ? match.dev_name : NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_dev_get_first_match_name);
|
||||
|
||||
/*
|
||||
* acpi_backlight= handling, this is done here rather then in video_detect.c
|
||||
* because __setup cannot be used in modules.
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -380,9 +381,16 @@ static void mrfld_irq_init_hw(struct mrfld_gpio *priv)
|
|||
}
|
||||
}
|
||||
|
||||
static const char *mrfld_gpio_get_pinctrl_dev_name(void)
|
||||
{
|
||||
const char *dev_name = acpi_dev_get_first_match_name("INTC1002", NULL, -1);
|
||||
return dev_name ? dev_name : "pinctrl-merrifield";
|
||||
}
|
||||
|
||||
static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
const struct mrfld_gpio_pinrange *range;
|
||||
const char *pinctrl_dev_name;
|
||||
struct mrfld_gpio *priv;
|
||||
u32 gpio_base, irq_base;
|
||||
void __iomem *base;
|
||||
|
@ -439,10 +447,11 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id
|
|||
return retval;
|
||||
}
|
||||
|
||||
pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name();
|
||||
for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) {
|
||||
range = &mrfld_gpio_ranges[i];
|
||||
retval = gpiochip_add_pin_range(&priv->chip,
|
||||
"pinctrl-merrifield",
|
||||
pinctrl_dev_name,
|
||||
range->gpio_base,
|
||||
range->pin_base,
|
||||
range->npins);
|
||||
|
|
|
@ -91,6 +91,9 @@ acpi_evaluate_dsm_typed(acpi_handle handle, const guid_t *guid, u64 rev,
|
|||
bool acpi_dev_found(const char *hid);
|
||||
bool acpi_dev_present(const char *hid, const char *uid, s64 hrv);
|
||||
|
||||
const char *
|
||||
acpi_dev_get_first_match_name(const char *hid, const char *uid, s64 hrv);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
||||
#include <linux/proc_fs.h>
|
||||
|
|
|
@ -640,6 +640,12 @@ static inline bool acpi_dev_present(const char *hid, const char *uid, s64 hrv)
|
|||
return false;
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
acpi_dev_get_first_match_name(const char *hid, const char *uid, s64 hrv)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool is_acpi_node(struct fwnode_handle *fwnode)
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -193,7 +193,7 @@ struct hda_dai_map {
|
|||
* @pvt_data - private data, for asoc contains asoc codec object
|
||||
*/
|
||||
struct hdac_ext_device {
|
||||
struct hdac_device hdac;
|
||||
struct hdac_device hdev;
|
||||
struct hdac_ext_bus *ebus;
|
||||
|
||||
/* soc-dai to nid map */
|
||||
|
@ -213,7 +213,7 @@ struct hdac_ext_dma_params {
|
|||
u8 stream_tag;
|
||||
};
|
||||
#define to_ehdac_device(dev) (container_of((dev), \
|
||||
struct hdac_ext_device, hdac))
|
||||
struct hdac_ext_device, hdev))
|
||||
/*
|
||||
* HD-audio codec base driver
|
||||
*/
|
||||
|
|
|
@ -27,17 +27,13 @@ struct snd_soc_acpi_package_context {
|
|||
bool data_valid;
|
||||
};
|
||||
|
||||
/* codec name is used in DAIs is i2c-<HID>:00 with HID being 8 chars */
|
||||
#define SND_ACPI_I2C_ID_LEN (4 + ACPI_ID_LEN + 3 + 1)
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
/* translation fron HID to I2C name, needed for DAI codec_name */
|
||||
const char *snd_soc_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]);
|
||||
bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
|
||||
struct snd_soc_acpi_package_context *ctx);
|
||||
#else
|
||||
static inline const char *
|
||||
snd_soc_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN])
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline bool
|
||||
snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
|
||||
struct snd_soc_acpi_package_context *ctx)
|
||||
|
@ -50,9 +46,6 @@ snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
|
|||
struct snd_soc_acpi_mach *
|
||||
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
|
||||
* related to the hardware, except for the firmware and topology file names.
|
||||
|
|
|
@ -222,6 +222,17 @@
|
|||
* %SKL_TKN_MM_U32_NUM_IN_FMT: Number of input 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
|
||||
* read from the DSP FW manifest
|
||||
*
|
||||
|
@ -309,7 +320,11 @@ enum SKL_TKNS {
|
|||
SKL_TKN_MM_U32_NUM_IN_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
|
||||
|
|
|
@ -146,7 +146,7 @@ int snd_hdac_ext_bus_device_init(struct hdac_ext_bus *ebus, int addr)
|
|||
edev = kzalloc(sizeof(*edev), GFP_KERNEL);
|
||||
if (!edev)
|
||||
return -ENOMEM;
|
||||
hdev = &edev->hdac;
|
||||
hdev = &edev->hdev;
|
||||
edev->ebus = ebus;
|
||||
|
||||
snprintf(name, sizeof(name), "ehdaudio%dD%d", ebus->idx, addr);
|
||||
|
|
|
@ -133,7 +133,6 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_SGTL5000 if I2C
|
||||
select SND_SOC_SI476X if MFD_SI476X_CORE
|
||||
select SND_SOC_SIRF_AUDIO_CODEC
|
||||
select SND_SOC_SN95031 if INTEL_SCU_IPC
|
||||
select SND_SOC_SPDIF
|
||||
select SND_SOC_SSM2518 if I2C
|
||||
select SND_SOC_SSM2602_SPI if SPI_MASTER
|
||||
|
@ -818,9 +817,6 @@ config SND_SOC_SIRF_AUDIO_CODEC
|
|||
tristate "SiRF SoC internal audio codec"
|
||||
select REGMAP_MMIO
|
||||
|
||||
config SND_SOC_SN95031
|
||||
tristate
|
||||
|
||||
config SND_SOC_SPDIF
|
||||
tristate "S/PDIF CODEC"
|
||||
|
||||
|
|
|
@ -140,7 +140,6 @@ snd-soc-sigmadsp-i2c-objs := sigmadsp-i2c.o
|
|||
snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o
|
||||
snd-soc-si476x-objs := si476x.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-rx-objs := spdif_receiver.o
|
||||
snd-soc-ssm2518-objs := ssm2518.o
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,936 +0,0 @@
|
|||
/*
|
||||
* 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");
|
|
@ -1,133 +0,0 @@
|
|||
/*
|
||||
* 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
|
|
@ -1,71 +1,122 @@
|
|||
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
|
||||
tristate
|
||||
# This option controls the IPC core for HiFi2 platforms
|
||||
|
||||
config SND_SST_IPC_PCI
|
||||
tristate
|
||||
select SND_SST_IPC
|
||||
# This option controls the PCI-based IPC for HiFi2 platforms
|
||||
# (Medfield, Merrifield).
|
||||
|
||||
config SND_SST_IPC_ACPI
|
||||
tristate
|
||||
select SND_SST_IPC
|
||||
select SND_SOC_INTEL_SST
|
||||
select IOSF_MBI
|
||||
# This option controls the ACPI-based IPC for HiFi2 platforms
|
||||
# (Baytrail, Cherrytrail)
|
||||
|
||||
config SND_SOC_INTEL_COMMON
|
||||
config SND_SOC_INTEL_SST_ACPI
|
||||
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
|
||||
tristate
|
||||
select SND_SOC_INTEL_SST_ACPI if ACPI
|
||||
|
||||
config SND_SOC_INTEL_SST_FIRMWARE
|
||||
tristate
|
||||
select DW_DMAC_CORE
|
||||
|
||||
config SND_SOC_INTEL_SST_ACPI
|
||||
tristate
|
||||
|
||||
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".
|
||||
# This option controls firmware download on
|
||||
# Haswell/Broadwell/Baytrail legacy and will be set
|
||||
# when these platforms are enabled
|
||||
|
||||
config SND_SOC_INTEL_HASWELL
|
||||
tristate "Intel ASoC SST driver for Haswell/Broadwell"
|
||||
depends on SND_SOC_INTEL_SST_TOPLEVEL && SND_DMA_SGBUF
|
||||
depends on DMADEVICES
|
||||
tristate "Haswell/Broadwell Platforms"
|
||||
depends on SND_DMA_SGBUF
|
||||
depends on DMADEVICES && ACPI
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SST_ACPI
|
||||
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
|
||||
tristate "Intel ASoC SST driver for Baytrail (legacy)"
|
||||
depends on SND_SOC_INTEL_SST_TOPLEVEL
|
||||
depends on DMADEVICES
|
||||
tristate "Baytrail (legacy) Platforms"
|
||||
depends on DMADEVICES && ACPI
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SST_ACPI
|
||||
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
|
||||
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
|
||||
tristate "Intel ASoC SST driver for HiFi2 platforms (*field, *trail)"
|
||||
depends on SND_SOC_INTEL_SST_TOPLEVEL && X86
|
||||
tristate "ACPI HiFi2 (Baytrail, Cherrytrail) Platforms"
|
||||
depends on X86 && ACPI
|
||||
select SND_SST_IPC_ACPI
|
||||
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
|
||||
tristate "Intel ASoC SST driver for SKL/BXT/KBL/GLK/CNL"
|
||||
depends on SND_SOC_INTEL_SST_TOPLEVEL && PCI && ACPI
|
||||
tristate "SKL/BXT/KBL/GLK/CNL... Platforms"
|
||||
depends on PCI && ACPI
|
||||
select SND_HDA_EXT_CORE
|
||||
select SND_HDA_DSP_LOADER
|
||||
select SND_SOC_TOPOLOGY
|
||||
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
|
||||
source "sound/soc/intel/boards/Kconfig"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Core support
|
||||
obj-$(CONFIG_SND_SOC_INTEL_COMMON) += common/
|
||||
obj-$(CONFIG_SND_SOC) += common/
|
||||
|
||||
# Platform Support
|
||||
obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/
|
||||
|
|
|
@ -236,6 +236,9 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
|
|||
/* Find the IRQ */
|
||||
ctx->irq_num = platform_get_irq(pdev,
|
||||
ctx->pdata->res_info->acpi_ipc_irq_index);
|
||||
if (ctx->irq_num <= 0)
|
||||
return ctx->irq_num < 0 ? ctx->irq_num : -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -220,10 +220,10 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
|
|||
sst_free_block(sst_drv_ctx, block);
|
||||
out:
|
||||
test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* sst_pause_stream - Send msg for a pausing stream
|
||||
* @str_id: stream ID
|
||||
*
|
||||
|
@ -261,7 +261,7 @@ int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
|
|||
}
|
||||
} else {
|
||||
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;
|
||||
|
@ -284,7 +284,7 @@ int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
|
|||
if (!str_info)
|
||||
return -EINVAL;
|
||||
if (str_info->status == STREAM_RUNNING)
|
||||
return 0;
|
||||
return 0;
|
||||
if (str_info->status == STREAM_PAUSED) {
|
||||
retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
|
||||
IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD,
|
||||
|
|
|
@ -1,183 +1,183 @@
|
|||
config SND_SOC_INTEL_MACH
|
||||
tristate "Intel Audio machine drivers"
|
||||
menuconfig SND_SOC_INTEL_MACH
|
||||
bool "Intel Machine drivers"
|
||||
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
|
||||
|
||||
config SND_MFLD_MACHINE
|
||||
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".
|
||||
if SND_SOC_INTEL_HASWELL
|
||||
|
||||
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 SND_SOC_INTEL_HASWELL
|
||||
select SND_SOC_RT5640
|
||||
help
|
||||
This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell
|
||||
Ultrabook platforms.
|
||||
Say Y if you have such a device.
|
||||
Ultrabook platforms. This is a recommended option.
|
||||
Say Y or m if you have such a device.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_INTEL_BDW_RT5677_MACH
|
||||
tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec"
|
||||
depends on X86_INTEL_LPSS && GPIOLIB && I2C
|
||||
depends on SND_SOC_INTEL_HASWELL
|
||||
tristate "Broadwell with RT5677 codec"
|
||||
depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM && GPIOLIB
|
||||
select SND_SOC_RT5677
|
||||
help
|
||||
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
|
||||
tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
|
||||
tristate "Broadwell Wildcatpoint"
|
||||
depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
|
||||
depends on SND_SOC_INTEL_HASWELL
|
||||
select SND_SOC_RT286
|
||||
help
|
||||
This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell
|
||||
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".
|
||||
endif ## SND_SOC_INTEL_HASWELL
|
||||
|
||||
if SND_SOC_INTEL_BAYTRAIL
|
||||
|
||||
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 SND_SST_IPC_ACPI = n
|
||||
depends on SND_SOC_INTEL_BAYTRAIL
|
||||
select SND_SOC_MAX98090
|
||||
help
|
||||
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
|
||||
tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
|
||||
tristate "Baytrail with RT5640 codec"
|
||||
depends on X86_INTEL_LPSS && I2C
|
||||
depends on SND_SST_IPC_ACPI = n
|
||||
depends on SND_SOC_INTEL_BAYTRAIL
|
||||
select SND_SOC_RT5640
|
||||
help
|
||||
This adds audio driver for Intel Baytrail platform based boards
|
||||
with the RT5640 audio codec. This driver is deprecated, use
|
||||
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
|
||||
tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec"
|
||||
depends on X86 && I2C && ACPI
|
||||
tristate "Baytrail and Baytrail-CR with RT5640 codec"
|
||||
depends on X86_INTEL_LPSS && I2C && ACPI
|
||||
select SND_SOC_ACPI
|
||||
select SND_SOC_RT5640
|
||||
depends on SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
help
|
||||
This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
|
||||
platforms with RT5640 audio codec.
|
||||
Say Y if you have such a device.
|
||||
If unsure select "N".
|
||||
This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
|
||||
platforms with RT5640 audio codec.
|
||||
Say Y or m if you have such a device. This is a recommended option.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_INTEL_BYTCR_RT5651_MACH
|
||||
tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec"
|
||||
depends on X86 && I2C && ACPI
|
||||
tristate "Baytrail and Baytrail-CR with RT5651 codec"
|
||||
depends on X86_INTEL_LPSS && I2C && ACPI
|
||||
select SND_SOC_ACPI
|
||||
select SND_SOC_RT5651
|
||||
depends on SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
help
|
||||
This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
|
||||
platforms with RT5651 audio codec.
|
||||
Say Y if you have such a device.
|
||||
If unsure select "N".
|
||||
This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
|
||||
platforms with RT5651 audio codec.
|
||||
Say Y or m if you have such a device. This is a recommended option.
|
||||
If unsure select "N".
|
||||
|
||||
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
|
||||
select SND_SOC_RT5670
|
||||
depends on SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
select SND_SOC_ACPI
|
||||
select SND_SOC_RT5670
|
||||
help
|
||||
This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
|
||||
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".
|
||||
|
||||
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
|
||||
select SND_SOC_ACPI
|
||||
select SND_SOC_RT5645
|
||||
depends on SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
help
|
||||
This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
|
||||
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".
|
||||
|
||||
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
|
||||
select SND_SOC_MAX98090
|
||||
select SND_SOC_TS3A227E
|
||||
depends on SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
help
|
||||
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.
|
||||
Say Y or m if you have such a device. This is a recommended option.
|
||||
If unsure select "N".
|
||||
|
||||
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
|
||||
select SND_SOC_ACPI
|
||||
select SND_SOC_DA7213
|
||||
depends on SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
help
|
||||
This adds support for ASoC machine driver for Intel(R) Baytrail & CherryTrail
|
||||
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".
|
||||
|
||||
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
|
||||
select SND_SOC_ACPI
|
||||
select SND_SOC_ES8316
|
||||
depends on SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
help
|
||||
This adds support for ASoC machine driver for Intel(R) Baytrail &
|
||||
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".
|
||||
|
||||
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 SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
help
|
||||
This adds support for ASoC machine driver for the MinnowBoard Max or
|
||||
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".
|
||||
|
||||
endif ## SND_SST_ATOM_HIFI2_PLATFORM
|
||||
|
||||
if SND_SOC_INTEL_SKYLAKE
|
||||
|
||||
config SND_SOC_INTEL_SKL_RT286_MACH
|
||||
tristate "ASoC Audio driver for SKL with RT286 I2S mode"
|
||||
depends on X86 && ACPI && I2C
|
||||
depends on SND_SOC_INTEL_SKYLAKE
|
||||
tristate "SKL with RT286 I2S mode"
|
||||
depends on MFD_INTEL_LPSS && I2C && ACPI
|
||||
select SND_SOC_RT286
|
||||
select SND_SOC_DMIC
|
||||
select SND_SOC_HDAC_HDMI
|
||||
help
|
||||
This adds support for ASoC machine driver for Skylake platforms
|
||||
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".
|
||||
|
||||
config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
|
||||
tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode"
|
||||
depends on X86_INTEL_LPSS && I2C
|
||||
depends on SND_SOC_INTEL_SKYLAKE
|
||||
tristate "SKL with NAU88L25 and SSM4567 in I2S Mode"
|
||||
depends on MFD_INTEL_LPSS && I2C && ACPI
|
||||
select SND_SOC_NAU8825
|
||||
select SND_SOC_SSM4567
|
||||
select SND_SOC_DMIC
|
||||
|
@ -185,13 +185,12 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
|
|||
help
|
||||
This adds support for ASoC Onboard Codec I2S machine driver. This will
|
||||
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".
|
||||
|
||||
config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
|
||||
tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode"
|
||||
depends on X86_INTEL_LPSS && I2C
|
||||
depends on SND_SOC_INTEL_SKYLAKE
|
||||
tristate "SKL with NAU88L25 and MAX98357A in I2S Mode"
|
||||
depends on MFD_INTEL_LPSS && I2C && ACPI
|
||||
select SND_SOC_NAU8825
|
||||
select SND_SOC_MAX98357A
|
||||
select SND_SOC_DMIC
|
||||
|
@ -199,13 +198,12 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
|
|||
help
|
||||
This adds support for ASoC Onboard Codec I2S machine driver. This will
|
||||
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".
|
||||
|
||||
config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
|
||||
tristate "ASoC Audio driver for Broxton with DA7219 and MAX98357A in I2S Mode"
|
||||
depends on X86 && ACPI && I2C
|
||||
depends on SND_SOC_INTEL_SKYLAKE
|
||||
tristate "Broxton with DA7219 and MAX98357A in I2S Mode"
|
||||
depends on MFD_INTEL_LPSS && I2C && ACPI
|
||||
select SND_SOC_DA7219
|
||||
select SND_SOC_MAX98357A
|
||||
select SND_SOC_DMIC
|
||||
|
@ -214,13 +212,12 @@ config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
|
|||
help
|
||||
This adds support for ASoC machine driver for Broxton-P platforms
|
||||
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".
|
||||
|
||||
config SND_SOC_INTEL_BXT_RT298_MACH
|
||||
tristate "ASoC Audio driver for Broxton with RT298 I2S mode"
|
||||
depends on X86 && ACPI && I2C
|
||||
depends on SND_SOC_INTEL_SKYLAKE
|
||||
tristate "Broxton with RT298 I2S mode"
|
||||
depends on MFD_INTEL_LPSS && I2C && ACPI
|
||||
select SND_SOC_RT298
|
||||
select SND_SOC_DMIC
|
||||
select SND_SOC_HDAC_HDMI
|
||||
|
@ -228,14 +225,12 @@ config SND_SOC_INTEL_BXT_RT298_MACH
|
|||
help
|
||||
This adds support for ASoC machine driver for Broxton platforms
|
||||
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".
|
||||
|
||||
config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
|
||||
tristate "ASoC Audio driver for KBL with RT5663 and MAX98927 in I2S Mode"
|
||||
depends on X86_INTEL_LPSS && I2C
|
||||
select SND_SOC_INTEL_SST
|
||||
depends on SND_SOC_INTEL_SKYLAKE
|
||||
tristate "KBL with RT5663 and MAX98927 in I2S Mode"
|
||||
depends on MFD_INTEL_LPSS && I2C && ACPI
|
||||
select SND_SOC_RT5663
|
||||
select SND_SOC_MAX98927
|
||||
select SND_SOC_DMIC
|
||||
|
@ -243,14 +238,13 @@ config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
|
|||
help
|
||||
This adds support for ASoC Onboard Codec I2S machine driver. This will
|
||||
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".
|
||||
|
||||
config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
|
||||
tristate "ASoC Audio driver for KBL with RT5663, RT5514 and MAX98927 in I2S Mode"
|
||||
depends on X86_INTEL_LPSS && I2C && SPI
|
||||
select SND_SOC_INTEL_SST
|
||||
depends on SND_SOC_INTEL_SKYLAKE
|
||||
tristate "KBL with RT5663, RT5514 and MAX98927 in I2S Mode"
|
||||
depends on MFD_INTEL_LPSS && I2C && ACPI
|
||||
depends on SPI
|
||||
select SND_SOC_RT5663
|
||||
select SND_SOC_RT5514
|
||||
select SND_SOC_RT5514_SPI
|
||||
|
@ -259,7 +253,8 @@ config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
|
|||
help
|
||||
This adds support for ASoC Onboard Codec I2S machine driver. This will
|
||||
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".
|
||||
endif ## SND_SOC_INTEL_SKYLAKE
|
||||
|
||||
endif
|
||||
endif ## SND_SOC_INTEL_MACH
|
||||
|
|
|
@ -219,7 +219,7 @@ static struct snd_soc_card bytcht_da7213_card = {
|
|||
.num_dapm_routes = ARRAY_SIZE(audio_map),
|
||||
};
|
||||
|
||||
static char codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
|
||||
static char codec_name[SND_ACPI_I2C_ID_LEN];
|
||||
|
||||
static int bytcht_da7213_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
@ -243,7 +243,7 @@ static int bytcht_da7213_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/* fixup codec name based on HID */
|
||||
i2c_name = snd_soc_acpi_find_name_from_hid(mach->id);
|
||||
i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1);
|
||||
if (i2c_name) {
|
||||
snprintf(codec_name, sizeof(codec_name),
|
||||
"%s%s", "i2c-", i2c_name);
|
||||
|
|
|
@ -232,15 +232,39 @@ static struct snd_soc_card byt_cht_es8316_card = {
|
|||
.fully_routed = true,
|
||||
};
|
||||
|
||||
static char codec_name[SND_ACPI_I2C_ID_LEN];
|
||||
|
||||
static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct byt_cht_es8316_private *priv;
|
||||
struct snd_soc_acpi_mach *mach;
|
||||
const char *i2c_name = NULL;
|
||||
int dai_index = 0;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
mach = (&pdev->dev)->platform_data;
|
||||
/* fix index of codec dai */
|
||||
for (i = 0; i < ARRAY_SIZE(byt_cht_es8316_dais); i++) {
|
||||
if (!strcmp(byt_cht_es8316_dais[i].codec_name,
|
||||
"i2c-ESSX8316:00")) {
|
||||
dai_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* fixup codec name based on HID */
|
||||
i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1);
|
||||
if (i2c_name) {
|
||||
snprintf(codec_name, sizeof(codec_name),
|
||||
"%s%s", "i2c-", i2c_name);
|
||||
byt_cht_es8316_dais[dai_index].codec_name = codec_name;
|
||||
}
|
||||
|
||||
/* register the soc card */
|
||||
byt_cht_es8316_card.dev = &pdev->dev;
|
||||
snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv);
|
||||
|
|
|
@ -713,7 +713,7 @@ static struct snd_soc_card byt_rt5640_card = {
|
|||
.fully_routed = true,
|
||||
};
|
||||
|
||||
static char byt_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
|
||||
static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN];
|
||||
static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */
|
||||
static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */
|
||||
|
||||
|
@ -762,7 +762,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/* fixup codec name based on HID */
|
||||
i2c_name = snd_soc_acpi_find_name_from_hid(mach->id);
|
||||
i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1);
|
||||
if (i2c_name) {
|
||||
snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name),
|
||||
"%s%s", "i2c-", i2c_name);
|
||||
|
|
|
@ -38,6 +38,8 @@ enum {
|
|||
BYT_RT5651_DMIC_MAP,
|
||||
BYT_RT5651_IN1_MAP,
|
||||
BYT_RT5651_IN2_MAP,
|
||||
BYT_RT5651_IN1_IN2_MAP,
|
||||
BYT_RT5651_IN3_MAP,
|
||||
};
|
||||
|
||||
#define BYT_RT5651_MAP(quirk) ((quirk) & GENMASK(7, 0))
|
||||
|
@ -62,6 +64,8 @@ static void log_quirks(struct device *dev)
|
|||
dev_info(dev, "quirk IN1_MAP enabled");
|
||||
if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN2_MAP)
|
||||
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)
|
||||
dev_info(dev, "quirk DMIC enabled");
|
||||
if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN)
|
||||
|
@ -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("Internal Mic", 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,
|
||||
platform_clock_control, SND_SOC_DAPM_PRE_PMU |
|
||||
SND_SOC_DAPM_POST_PMD),
|
||||
|
@ -138,6 +143,7 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = {
|
|||
{"Headset Mic", NULL, "Platform Clock"},
|
||||
{"Internal Mic", NULL, "Platform Clock"},
|
||||
{"Speaker", NULL, "Platform Clock"},
|
||||
{"Line In", NULL, "Platform Clock"},
|
||||
|
||||
{"AIF1 Playback", NULL, "ssp2 Tx"},
|
||||
{"ssp2 Tx", NULL, "codec_out0"},
|
||||
|
@ -151,6 +157,9 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = {
|
|||
{"Headphone", NULL, "HPOR"},
|
||||
{"Speaker", NULL, "LOUTL"},
|
||||
{"Speaker", NULL, "LOUTR"},
|
||||
{"IN2P", NULL, "Line In"},
|
||||
{"IN2N", NULL, "Line In"},
|
||||
|
||||
};
|
||||
|
||||
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[] = {
|
|||
{"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[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Headphone"),
|
||||
SOC_DAPM_PIN_SWITCH("Headset Mic"),
|
||||
SOC_DAPM_PIN_SWITCH("Internal Mic"),
|
||||
SOC_DAPM_PIN_SWITCH("Speaker"),
|
||||
SOC_DAPM_PIN_SWITCH("Line In"),
|
||||
};
|
||||
|
||||
static struct snd_soc_jack_pin bytcr_jack_pins[] = {
|
||||
|
@ -247,8 +270,16 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"),
|
||||
},
|
||||
.driver_data = (void *)(BYT_RT5651_DMIC_MAP |
|
||||
BYT_RT5651_DMIC_EN),
|
||||
.driver_data = (void *)(BYT_RT5651_IN3_MAP),
|
||||
},
|
||||
{
|
||||
.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,
|
||||
|
@ -256,7 +287,8 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "KIANO"),
|
||||
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)
|
|||
custom_map = byt_rt5651_intmic_in2_map;
|
||||
num_routes = ARRAY_SIZE(byt_rt5651_intmic_in2_map);
|
||||
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:
|
||||
custom_map = byt_rt5651_intmic_dmic_map;
|
||||
num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic_map);
|
||||
|
@ -469,7 +509,7 @@ static struct snd_soc_card byt_rt5651_card = {
|
|||
.fully_routed = true,
|
||||
};
|
||||
|
||||
static char byt_rt5651_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
|
||||
static char byt_rt5651_codec_name[SND_ACPI_I2C_ID_LEN];
|
||||
|
||||
static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
@ -499,7 +539,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/* fixup codec name based on HID */
|
||||
i2c_name = snd_soc_acpi_find_name_from_hid(mach->id);
|
||||
i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1);
|
||||
if (i2c_name) {
|
||||
snprintf(byt_rt5651_codec_name, sizeof(byt_rt5651_codec_name),
|
||||
"%s%s", "i2c-", i2c_name);
|
||||
|
|
|
@ -49,7 +49,7 @@ struct cht_acpi_card {
|
|||
struct cht_mc_private {
|
||||
struct snd_soc_jack jack;
|
||||
struct cht_acpi_card *acpi_card;
|
||||
char codec_name[16];
|
||||
char codec_name[SND_ACPI_I2C_ID_LEN];
|
||||
struct clk *mclk;
|
||||
};
|
||||
|
||||
|
@ -499,7 +499,7 @@ static struct cht_acpi_card snd_soc_cards[] = {
|
|||
{"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650},
|
||||
};
|
||||
|
||||
static char cht_rt5645_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
|
||||
static char cht_rt5645_codec_name[SND_ACPI_I2C_ID_LEN];
|
||||
static char cht_rt5645_codec_aif_name[12]; /* = "rt5645-aif[1|2]" */
|
||||
static char cht_rt5645_cpu_dai_name[10]; /* = "ssp[0|2]-port" */
|
||||
|
||||
|
@ -566,7 +566,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/* fixup codec name based on HID */
|
||||
i2c_name = snd_soc_acpi_find_name_from_hid(mach->id);
|
||||
i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1);
|
||||
if (i2c_name) {
|
||||
snprintf(cht_rt5645_codec_name, sizeof(cht_rt5645_codec_name),
|
||||
"%s%s", "i2c-", i2c_name);
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
struct cht_mc_private {
|
||||
struct snd_soc_jack headset;
|
||||
char codec_name[16];
|
||||
char codec_name[SND_ACPI_I2C_ID_LEN];
|
||||
struct clk *mclk;
|
||||
};
|
||||
|
||||
|
@ -396,7 +396,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
|||
|
||||
/* fixup codec name based on HID */
|
||||
if (mach) {
|
||||
i2c_name = snd_soc_acpi_find_name_from_hid(mach->id);
|
||||
i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1);
|
||||
if (i2c_name) {
|
||||
snprintf(drv->codec_name, sizeof(drv->codec_name),
|
||||
"i2c-%s", i2c_name);
|
||||
|
|
|
@ -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 */
|
||||
snd_soc_update_bits(rtd->codec, 0x83, 0xffff, 0x8000);
|
||||
snd_soc_component_update_bits(codec_dai->component, 0x83, 0xffff, 0x8000);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -225,7 +225,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
|
|||
}
|
||||
|
||||
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_2, KEY_VOLUMEUP);
|
||||
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)
|
|||
}
|
||||
|
||||
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_2, KEY_VOLUMEUP);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
|
||||
|
|
|
@ -1,428 +0,0 @@
|
|||
/*
|
||||
* 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,
|
|||
*/
|
||||
|
||||
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)) {
|
||||
k++;
|
||||
if (k > 10)
|
||||
|
@ -278,8 +278,6 @@ int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
|
|||
usleep_range(s, 2*s);
|
||||
}
|
||||
|
||||
reg = sst_dsp_shim_read_unlocked(ctx, offset);
|
||||
|
||||
if ((reg & mask) == target) {
|
||||
dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s successful\n",
|
||||
reg, operation);
|
||||
|
|
|
@ -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);
|
||||
skl->d0i3.state = SKL_DSP_D0I3_NONE;
|
||||
|
||||
return 0;
|
||||
return skl_dsp_acquire_irq(sst);
|
||||
}
|
||||
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,
|
|||
cnl->boot_complete = false;
|
||||
init_waitqueue_head(&cnl->boot_wait);
|
||||
|
||||
return 0;
|
||||
return skl_dsp_acquire_irq(sst);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cnl_sst_dsp_init);
|
||||
|
||||
|
|
64
sound/soc/intel/skylake/skl-i2s.h
Normal file
64
sound/soc/intel/skylake/skl-i2s.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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)
|
|||
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_MASK 0xf
|
||||
|
||||
|
@ -404,11 +417,20 @@ int skl_resume_dsp(struct skl *skl)
|
|||
if (skl->skl_sst->is_first_boot == true)
|
||||
return 0;
|
||||
|
||||
/* disable dynamic clock gating during fw and lib download */
|
||||
ctx->enable_miscbdcge(ctx->dev, false);
|
||||
|
||||
ret = skl_dsp_wake(ctx->dsp);
|
||||
ctx->enable_miscbdcge(ctx->dev, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
#include <linux/pci.h>
|
||||
#include "skl.h"
|
||||
#include "skl-i2s.h"
|
||||
|
||||
#define NHLT_ACPI_HEADER_SIG "NHLT"
|
||||
|
||||
|
@ -277,3 +278,157 @@ void skl_nhlt_remove_sysfs(struct skl *skl)
|
|||
|
||||
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,
|
|||
|
||||
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)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -620,7 +620,7 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
|
|||
|
||||
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)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -1343,7 +1343,11 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
|
|||
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);
|
||||
skl->skl_sst->enable_miscbdcge(platform->dev, true);
|
||||
if (ret < 0) {
|
||||
dev_err(platform->dev, "Failed to boot first fw: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -1351,6 +1355,12 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
|
|||
skl_populate_modules(skl);
|
||||
skl->skl_sst->update_d0i3c = skl_update_d0i3c;
|
||||
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_put_autosuspend(platform->dev);
|
||||
|
|
79
sound/soc/intel/skylake/skl-ssp-clk.h
Normal file
79
sound/soc/intel/skylake/skl-ssp-clk.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* 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,
|
|||
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 */
|
||||
ret = request_threaded_irq(sst->irq, sst->ops->irq_handler,
|
||||
sst_dev->thread, IRQF_SHARED, "AudioDSP", sst);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
dev_err(sst->dev, "unable to grab threaded IRQ %d, disabling device\n",
|
||||
sst->irq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sst;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void skl_dsp_free(struct sst_dsp *dsp)
|
||||
|
|
|
@ -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);
|
||||
struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
|
||||
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);
|
||||
|
||||
unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx);
|
||||
|
@ -251,6 +252,9 @@ void skl_freeup_uuid_list(struct skl_sst *ctx);
|
|||
|
||||
int skl_dsp_strip_extended_manifest(struct firmware *fw);
|
||||
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,
|
||||
struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp,
|
||||
struct sst_dsp_device *skl_dev);
|
||||
|
|
|
@ -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
|
||||
*
|
||||
* @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
|
||||
* module instance is unique
|
||||
|
@ -208,7 +209,8 @@ EXPORT_SYMBOL_GPL(skl_get_pvt_id);
|
|||
* skl_put_pvt_id: free up the private id allocated
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
|
|
|
@ -569,7 +569,7 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
|||
|
||||
sst->fw_ops = skl_fw_ops;
|
||||
|
||||
return 0;
|
||||
return skl_dsp_acquire_irq(sst);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
|
||||
|
||||
|
|
|
@ -190,7 +190,6 @@ skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig)
|
|||
u8 res_idx = mconfig->res_idx;
|
||||
struct skl_module_res *res = &mconfig->module->resources[res_idx];
|
||||
|
||||
res = &mconfig->module->resources[res_idx];
|
||||
skl->resource.mcps -= res->cps;
|
||||
}
|
||||
|
||||
|
@ -3056,11 +3055,13 @@ static int skl_tplg_get_int_tkn(struct device *dev,
|
|||
struct snd_soc_tplg_vendor_value_elem *tkn_elem,
|
||||
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;
|
||||
struct skl_module_res *res = NULL;
|
||||
struct skl_module_iface *fmt = NULL;
|
||||
struct skl_module *mod = NULL;
|
||||
static struct skl_astate_param *astate_table;
|
||||
static int astate_cfg_idx, count;
|
||||
int i;
|
||||
|
||||
if (skl->modules) {
|
||||
|
@ -3093,6 +3094,46 @@ static int skl_tplg_get_int_tkn(struct device *dev,
|
|||
mod_idx = tkn_elem->value;
|
||||
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_OUT_PIN_TYPE:
|
||||
case SKL_TKN_U8_IN_QUEUE_COUNT:
|
||||
|
|
|
@ -355,6 +355,7 @@ static int skl_resume(struct device *dev)
|
|||
|
||||
if (ebus->cmd_dma_state)
|
||||
snd_hdac_bus_init_cmd_io(&ebus->bus);
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = _skl_resume(ebus);
|
||||
|
||||
|
@ -435,19 +436,51 @@ static int skl_free(struct hdac_ext_bus *ebus)
|
|||
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;
|
||||
int ret;
|
||||
struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
|
||||
struct skl_machine_pdata *pdata;
|
||||
|
||||
mach = snd_soc_acpi_find_machine(mach);
|
||||
if (mach == NULL) {
|
||||
dev_err(bus->dev, "No matching machine driver found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
skl->mach = mach;
|
||||
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);
|
||||
if (pdev == NULL) {
|
||||
|
@ -462,11 +495,8 @@ static int skl_machine_device_register(struct skl *skl, void *driver_data)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
if (mach->pdata) {
|
||||
skl->use_tplg_pcm =
|
||||
((struct skl_machine_pdata *)mach->pdata)->use_tplg_pcm;
|
||||
if (mach->pdata)
|
||||
dev_set_drvdata(&pdev->dev, mach->pdata);
|
||||
}
|
||||
|
||||
skl->i2s_dev = pdev;
|
||||
|
||||
|
@ -509,6 +539,74 @@ static void skl_dmic_device_unregister(struct skl *skl)
|
|||
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
|
||||
*/
|
||||
|
@ -615,18 +713,30 @@ static void skl_probe_work(struct work_struct *work)
|
|||
/* create codec instances */
|
||||
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)) {
|
||||
err = snd_hdac_display_power(bus, false);
|
||||
if (err < 0) {
|
||||
dev_err(bus->dev, "Cannot turn off display power on i915\n");
|
||||
skl_machine_device_unregister(skl);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* register platform dai and controls */
|
||||
err = skl_platform_register(bus->dev);
|
||||
if (err < 0)
|
||||
return;
|
||||
/*
|
||||
* we are done probing so decrement link counts
|
||||
*/
|
||||
|
@ -791,18 +901,21 @@ static int skl_probe(struct pci_dev *pci,
|
|||
|
||||
/* check if dsp is there */
|
||||
if (bus->ppcap) {
|
||||
err = skl_machine_device_register(skl,
|
||||
(void *)pci_id->driver_data);
|
||||
/* create device for dsp clk */
|
||||
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)
|
||||
goto out_nhlt_free;
|
||||
|
||||
err = skl_init_dsp(skl);
|
||||
if (err < 0) {
|
||||
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;
|
||||
|
||||
}
|
||||
if (bus->mlcap)
|
||||
snd_hdac_ext_bus_get_ml_capabilities(ebus);
|
||||
|
@ -820,8 +933,8 @@ static int skl_probe(struct pci_dev *pci,
|
|||
|
||||
out_dsp_free:
|
||||
skl_free_dsp(skl);
|
||||
out_mach_free:
|
||||
skl_machine_device_unregister(skl);
|
||||
out_clk_free:
|
||||
skl_clock_device_unregister(skl);
|
||||
out_nhlt_free:
|
||||
skl_nhlt_free(skl->nhlt);
|
||||
out_free:
|
||||
|
@ -872,6 +985,7 @@ static void skl_remove(struct pci_dev *pci)
|
|||
skl_free_dsp(skl);
|
||||
skl_machine_device_unregister(skl);
|
||||
skl_dmic_device_unregister(skl);
|
||||
skl_clock_device_unregister(skl);
|
||||
skl_nhlt_remove_sysfs(skl);
|
||||
skl_nhlt_free(skl->nhlt);
|
||||
skl_free(ebus);
|
||||
|
|
|
@ -25,9 +25,12 @@
|
|||
#include <sound/hdaudio_ext.h>
|
||||
#include <sound/soc.h>
|
||||
#include "skl-nhlt.h"
|
||||
#include "skl-ssp-clk.h"
|
||||
|
||||
#define SKL_SUSPEND_DELAY 2000
|
||||
|
||||
#define SKL_MAX_ASTATE_CFG 3
|
||||
|
||||
#define AZX_PCIREG_PGCTL 0x44
|
||||
#define AZX_PGCTL_LSRMD_MASK (1 << 4)
|
||||
#define AZX_PCIREG_CGCTL 0x48
|
||||
|
@ -45,6 +48,20 @@ struct skl_dsp_resource {
|
|||
|
||||
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 hdac_ext_bus ebus;
|
||||
struct pci_dev *pci;
|
||||
|
@ -52,6 +69,7 @@ struct skl {
|
|||
unsigned int init_done:1; /* delayed init status */
|
||||
struct platform_device *dmic_dev;
|
||||
struct platform_device *i2s_dev;
|
||||
struct platform_device *clk_dev;
|
||||
struct snd_soc_platform *platform;
|
||||
struct snd_soc_dai_driver *dais;
|
||||
|
||||
|
@ -75,6 +93,8 @@ struct skl {
|
|||
u8 nr_modules;
|
||||
struct skl_module **modules;
|
||||
bool use_tplg_pcm;
|
||||
struct skl_fw_config cfg;
|
||||
struct snd_soc_acpi_mach *mach;
|
||||
};
|
||||
|
||||
#define skl_to_ebus(s) (&(s)->ebus)
|
||||
|
@ -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);
|
||||
int skl_nhlt_create_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;
|
||||
|
||||
|
|
|
@ -16,74 +16,13 @@
|
|||
|
||||
#include <sound/soc-acpi.h>
|
||||
|
||||
static acpi_status snd_soc_acpi_find_name(acpi_handle handle, u32 level,
|
||||
void *context, void **ret)
|
||||
{
|
||||
struct acpi_device *adev;
|
||||
const char *name = NULL;
|
||||
|
||||
if (acpi_bus_get_device(handle, &adev))
|
||||
return AE_OK;
|
||||
|
||||
if (adev->status.present && adev->status.functional) {
|
||||
name = acpi_dev_name(adev);
|
||||
*(const char **)ret = name;
|
||||
return AE_CTRL_TERMINATE;
|
||||
}
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
const char *snd_soc_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN])
|
||||
{
|
||||
const char *name = NULL;
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_get_devices(hid, snd_soc_acpi_find_name, NULL,
|
||||
(void **)&name);
|
||||
|
||||
if (ACPI_FAILURE(status) || name[0] == '\0')
|
||||
return NULL;
|
||||
|
||||
return name;
|
||||
}
|
||||
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 *
|
||||
snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines)
|
||||
{
|
||||
struct snd_soc_acpi_mach *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)
|
||||
mach = mach->machine_quirk(mach);
|
||||
return mach;
|
||||
|
@ -161,7 +100,7 @@ struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg)
|
|||
return mach;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue