Commit 515511a7 authored by Mark Brown's avatar Mark Brown

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

parents 180bc41a 8f658815
/*
* hdmi-codec.h - HDMI Codec driver API
*
* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
*
* Author: Jyri Sarha <jsarha@ti.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#ifndef __HDMI_CODEC_H__
#define __HDMI_CODEC_H__
#include <linux/hdmi.h>
#include <drm/drm_edid.h>
#include <sound/asoundef.h>
#include <uapi/sound/asound.h>
/*
* Protocol between ASoC cpu-dai and HDMI-encoder
*/
struct hdmi_codec_daifmt {
enum {
HDMI_I2S,
HDMI_RIGHT_J,
HDMI_LEFT_J,
HDMI_DSP_A,
HDMI_DSP_B,
HDMI_AC97,
HDMI_SPDIF,
} fmt;
int bit_clk_inv:1;
int frame_clk_inv:1;
int bit_clk_master:1;
int frame_clk_master:1;
};
/*
* HDMI audio parameters
*/
struct hdmi_codec_params {
struct hdmi_audio_infoframe cea;
struct snd_aes_iec958 iec;
int sample_rate;
int sample_width;
int channels;
};
struct hdmi_codec_ops {
/*
* Called when ASoC starts an audio stream setup.
* Optional
*/
int (*audio_startup)(struct device *dev);
/*
* Configures HDMI-encoder for audio stream.
* Mandatory
*/
int (*hw_params)(struct device *dev,
struct hdmi_codec_daifmt *fmt,
struct hdmi_codec_params *hparms);
/*
* Shuts down the audio stream.
* Mandatory
*/
void (*audio_shutdown)(struct device *dev);
/*
* Mute/unmute HDMI audio stream.
* Optional
*/
int (*digital_mute)(struct device *dev, bool enable);
/*
* Provides EDID-Like-Data from connected HDMI device.
* Optional
*/
int (*get_eld)(struct device *dev, uint8_t *buf, size_t len);
};
/* HDMI codec initalization data */
struct hdmi_codec_pdata {
const struct hdmi_codec_ops *ops;
uint i2s:1;
uint spdif:1;
int max_i2s_channels;
};
#define HDMI_CODEC_DRV_NAME "hdmi-audio-codec"
#endif /* __HDMI_CODEC_H__ */
...@@ -6,4 +6,6 @@ ...@@ -6,4 +6,6 @@
int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,
size_t len); size_t len);
int snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params,
u8 *cs, size_t len);
#endif #endif
...@@ -9,30 +9,18 @@ ...@@ -9,30 +9,18 @@
#include <linux/types.h> #include <linux/types.h>
#include <sound/asoundef.h> #include <sound/asoundef.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/pcm_iec958.h> #include <sound/pcm_iec958.h>
/** static int create_iec958_consumer(uint rate, uint sample_width,
* snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status u8 *cs, size_t len)
* @runtime: pcm runtime structure with ->rate filled in
* @cs: channel status buffer, at least four bytes
* @len: length of channel status buffer
*
* Create the consumer format channel status data in @cs of maximum size
* @len corresponding to the parameters of the PCM runtime @runtime.
*
* Drivers may wish to tweak the contents of the buffer after creation.
*
* Returns: length of buffer, or negative error code if something failed.
*/
int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,
size_t len)
{ {
unsigned int fs, ws; unsigned int fs, ws;
if (len < 4) if (len < 4)
return -EINVAL; return -EINVAL;
switch (runtime->rate) { switch (rate) {
case 32000: case 32000:
fs = IEC958_AES3_CON_FS_32000; fs = IEC958_AES3_CON_FS_32000;
break; break;
...@@ -59,7 +47,7 @@ int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, ...@@ -59,7 +47,7 @@ int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,
} }
if (len > 4) { if (len > 4) {
switch (snd_pcm_format_width(runtime->format)) { switch (sample_width) {
case 16: case 16:
ws = IEC958_AES4_CON_WORDLEN_20_16; ws = IEC958_AES4_CON_WORDLEN_20_16;
break; break;
...@@ -71,6 +59,7 @@ int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, ...@@ -71,6 +59,7 @@ int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,
IEC958_AES4_CON_MAX_WORDLEN_24; IEC958_AES4_CON_MAX_WORDLEN_24;
break; break;
case 24: case 24:
case 32: /* Assume 24-bit width for 32-bit samples. */
ws = IEC958_AES4_CON_WORDLEN_24_20 | ws = IEC958_AES4_CON_WORDLEN_24_20 |
IEC958_AES4_CON_MAX_WORDLEN_24; IEC958_AES4_CON_MAX_WORDLEN_24;
break; break;
...@@ -92,4 +81,46 @@ int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, ...@@ -92,4 +81,46 @@ int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,
return len; return len;
} }
/**
* snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status
* @runtime: pcm runtime structure with ->rate filled in
* @cs: channel status buffer, at least four bytes
* @len: length of channel status buffer
*
* Create the consumer format channel status data in @cs of maximum size
* @len corresponding to the parameters of the PCM runtime @runtime.
*
* Drivers may wish to tweak the contents of the buffer after creation.
*
* Returns: length of buffer, or negative error code if something failed.
*/
int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,
size_t len)
{
return create_iec958_consumer(runtime->rate,
snd_pcm_format_width(runtime->format),
cs, len);
}
EXPORT_SYMBOL(snd_pcm_create_iec958_consumer); EXPORT_SYMBOL(snd_pcm_create_iec958_consumer);
/**
* snd_pcm_create_iec958_consumer_hw_params - create IEC958 channel status
* @hw_params: the hw_params instance for extracting rate and sample format
* @cs: channel status buffer, at least four bytes
* @len: length of channel status buffer
*
* Create the consumer format channel status data in @cs of maximum size
* @len corresponding to the parameters of the PCM runtime @runtime.
*
* Drivers may wish to tweak the contents of the buffer after creation.
*
* Returns: length of buffer, or negative error code if something failed.
*/
int snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params,
u8 *cs, size_t len)
{
return create_iec958_consumer(params_rate(params), params_width(params),
cs, len);
}
EXPORT_SYMBOL(snd_pcm_create_iec958_consumer_hw_params);
...@@ -16,6 +16,16 @@ static inline int get_wcaps_type(unsigned int wcaps) ...@@ -16,6 +16,16 @@ static inline int get_wcaps_type(unsigned int wcaps)
return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
} }
static inline unsigned int get_wcaps_channels(u32 wcaps)
{
unsigned int chans;
chans = (wcaps & AC_WCAP_CHAN_CNT_EXT) >> 13;
chans = (chans + 1) * 2;
return chans;
}
extern const struct attribute_group *hdac_dev_attr_groups[]; extern const struct attribute_group *hdac_dev_attr_groups[];
int hda_widget_sysfs_init(struct hdac_device *codec); int hda_widget_sysfs_init(struct hdac_device *codec);
void hda_widget_sysfs_exit(struct hdac_device *codec); void hda_widget_sysfs_exit(struct hdac_device *codec);
......
...@@ -88,6 +88,7 @@ config SND_SOC_ALL_CODECS ...@@ -88,6 +88,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_MC13783 if MFD_MC13XXX select SND_SOC_MC13783 if MFD_MC13XXX
select SND_SOC_ML26124 if I2C select SND_SOC_ML26124 if I2C
select SND_SOC_NAU8825 if I2C select SND_SOC_NAU8825 if I2C
select SND_SOC_HDMI_CODEC
select SND_SOC_PCM1681 if I2C select SND_SOC_PCM1681 if I2C
select SND_SOC_PCM179X_I2C if I2C select SND_SOC_PCM179X_I2C if I2C
select SND_SOC_PCM179X_SPI if SPI_MASTER select SND_SOC_PCM179X_SPI if SPI_MASTER
...@@ -478,6 +479,11 @@ config SND_SOC_BT_SCO ...@@ -478,6 +479,11 @@ config SND_SOC_BT_SCO
config SND_SOC_DMIC config SND_SOC_DMIC
tristate tristate
config SND_SOC_HDMI_CODEC
tristate
select SND_PCM_ELD
select SND_PCM_IEC958
config SND_SOC_ES8328 config SND_SOC_ES8328
tristate "Everest Semi ES8328 CODEC" tristate "Everest Semi ES8328 CODEC"
......
...@@ -81,6 +81,7 @@ snd-soc-max9850-objs := max9850.o ...@@ -81,6 +81,7 @@ snd-soc-max9850-objs := max9850.o
snd-soc-mc13783-objs := mc13783.o snd-soc-mc13783-objs := mc13783.o
snd-soc-ml26124-objs := ml26124.o snd-soc-ml26124-objs := ml26124.o
snd-soc-nau8825-objs := nau8825.o snd-soc-nau8825-objs := nau8825.o
snd-soc-hdmi-codec-objs := hdmi-codec.o
snd-soc-pcm1681-objs := pcm1681.o snd-soc-pcm1681-objs := pcm1681.o
snd-soc-pcm179x-codec-objs := pcm179x.o snd-soc-pcm179x-codec-objs := pcm179x.o
snd-soc-pcm179x-i2c-objs := pcm179x-i2c.o snd-soc-pcm179x-i2c-objs := pcm179x-i2c.o
...@@ -291,6 +292,7 @@ obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o ...@@ -291,6 +292,7 @@ obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o
obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o
obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o
obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o
obj-$(CONFIG_SND_SOC_PCM179X_I2C) += snd-soc-pcm179x-i2c.o obj-$(CONFIG_SND_SOC_PCM179X_I2C) += snd-soc-pcm179x-i2c.o
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <sound/hdaudio_ext.h> #include <sound/hdaudio_ext.h>
#include <sound/hda_i915.h> #include <sound/hda_i915.h>
#include <sound/pcm_drm_eld.h> #include <sound/pcm_drm_eld.h>
#include <sound/hda_chmap.h>
#include "../../hda/local.h" #include "../../hda/local.h"
#include "hdac_hdmi.h" #include "hdac_hdmi.h"
...@@ -60,11 +61,17 @@ struct hdac_hdmi_cvt { ...@@ -60,11 +61,17 @@ struct hdac_hdmi_cvt {
struct hdac_hdmi_cvt_params params; struct hdac_hdmi_cvt_params params;
}; };
/* Currently only spk_alloc, more to be added */
struct hdac_hdmi_parsed_eld {
u8 spk_alloc;
};
struct hdac_hdmi_eld { struct hdac_hdmi_eld {
bool monitor_present; bool monitor_present;
bool eld_valid; bool eld_valid;
int eld_size; int eld_size;
char eld_buffer[ELD_MAX_SIZE]; char eld_buffer[ELD_MAX_SIZE];
struct hdac_hdmi_parsed_eld info;
}; };
struct hdac_hdmi_pin { struct hdac_hdmi_pin {
...@@ -76,6 +83,10 @@ struct hdac_hdmi_pin { ...@@ -76,6 +83,10 @@ struct hdac_hdmi_pin {
struct hdac_ext_device *edev; struct hdac_ext_device *edev;
int repoll_count; int repoll_count;
struct delayed_work work; struct delayed_work work;
struct mutex lock;
bool chmap_set;
unsigned char chmap[8]; /* ALSA API channel-map */
int channels; /* current number of channels */
}; };
struct hdac_hdmi_pcm { struct hdac_hdmi_pcm {
...@@ -100,8 +111,22 @@ struct hdac_hdmi_priv { ...@@ -100,8 +111,22 @@ struct hdac_hdmi_priv {
int num_pin; int num_pin;
int num_cvt; int num_cvt;
struct mutex pin_mutex; struct mutex pin_mutex;
struct hdac_chmap chmap;
}; };
static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi,
int pcm_idx)
{
struct hdac_hdmi_pcm *pcm;
list_for_each_entry(pcm, &hdmi->pcm_list, head) {
if (pcm->pcm_id == pcm_idx)
return pcm;
}
return NULL;
}
static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
{ {
struct hdac_device *hdac = dev_to_hdac_dev(dev); struct hdac_device *hdac = dev_to_hdac_dev(dev);
...@@ -278,26 +303,31 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, ...@@ -278,26 +303,31 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
int i; int i;
const u8 *eld_buf; const u8 *eld_buf;
u8 conn_type; u8 conn_type;
int channels = 2; int channels, ca;
list_for_each_entry(pin, &hdmi->pin_list, head) { list_for_each_entry(pin, &hdmi->pin_list, head) {
if (pin->nid == pin_nid) if (pin->nid == pin_nid)
break; break;
} }
ca = snd_hdac_channel_allocation(&hdac->hdac, pin->eld.info.spk_alloc,
pin->channels, pin->chmap_set, true, pin->chmap);
channels = snd_hdac_get_active_channels(ca);
hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt_nid, channels);
snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca,
pin->channels, pin->chmap, pin->chmap_set);
eld_buf = pin->eld.eld_buffer; eld_buf = pin->eld.eld_buffer;
conn_type = drm_eld_get_conn_type(eld_buf); conn_type = drm_eld_get_conn_type(eld_buf);
/* setup channel count */
snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
AC_VERB_SET_CVT_CHAN_COUNT, channels - 1);
switch (conn_type) { switch (conn_type) {
case DRM_ELD_CONN_TYPE_HDMI: case DRM_ELD_CONN_TYPE_HDMI:
hdmi_audio_infoframe_init(&frame); hdmi_audio_infoframe_init(&frame);
/* Default stereo for now */
frame.channels = channels; frame.channels = channels;
frame.channel_allocation = ca;
ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
if (ret < 0) if (ret < 0)
...@@ -311,7 +341,7 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, ...@@ -311,7 +341,7 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
dp_ai.len = 0x1b; dp_ai.len = 0x1b;
dp_ai.ver = 0x11 << 2; dp_ai.ver = 0x11 << 2;
dp_ai.CC02_CT47 = channels - 1; dp_ai.CC02_CT47 = channels - 1;
dp_ai.CA = 0; dp_ai.CA = ca;
dip = (u8 *)&dp_ai; dip = (u8 *)&dp_ai;
break; break;
...@@ -370,17 +400,23 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, ...@@ -370,17 +400,23 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream,
struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
struct hdac_hdmi_priv *hdmi = hdac->private_data; struct hdac_hdmi_priv *hdmi = hdac->private_data;
struct hdac_hdmi_dai_pin_map *dai_map; struct hdac_hdmi_dai_pin_map *dai_map;
struct hdac_hdmi_pin *pin;
struct hdac_ext_dma_params *dd; struct hdac_ext_dma_params *dd;
int ret; int ret;
dai_map = &hdmi->dai_map[dai->id]; dai_map = &hdmi->dai_map[dai->id];
pin = dai_map->pin;
dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n", dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n",
dd->stream_tag, dd->format); dd->stream_tag, dd->format);
mutex_lock(&pin->lock);
pin->channels = substream->runtime->channels;
ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid, ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid,
dai_map->pin->nid); dai_map->pin->nid);
mutex_unlock(&pin->lock);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -640,6 +676,12 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, ...@@ -640,6 +676,12 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
mutex_lock(&dai_map->pin->lock);
dai_map->pin->chmap_set = false;
memset(dai_map->pin->chmap, 0, sizeof(dai_map->pin->chmap));
dai_map->pin->channels = 0;
mutex_unlock(&dai_map->pin->lock);
dai_map->pin = NULL; dai_map->pin = NULL;
} }
} }
...@@ -647,10 +689,19 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, ...@@ -647,10 +689,19 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
static int static int
hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
{ {
unsigned int chans;
struct hdac_ext_device *edev = to_ehdac_device(hdac);
struct hdac_hdmi_priv *hdmi = edev->private_data;
int err; int err;
/* Only stereo supported as of now */ chans = get_wcaps(hdac, cvt->nid);
cvt->params.channels_min = cvt->params.channels_max = 2; chans = get_wcaps_channels(chans);
cvt->params.channels_min = 2;
cvt->params.channels_max = chans;
if (chans > hdmi->chmap.channels_max)
hdmi->chmap.channels_max = chans;
err = snd_hdac_query_supported_pcm(hdac, cvt->nid, err = snd_hdac_query_supported_pcm(hdac, cvt->nid,
&cvt->params.rates, &cvt->params.rates,
...@@ -1008,6 +1059,12 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) ...@@ -1008,6 +1059,12 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
return hdac_hdmi_query_cvt_params(&edev->hdac, cvt); return hdac_hdmi_query_cvt_params(&edev->hdac, cvt);
} }
static void hdac_hdmi_parse_eld(struct hdac_ext_device *edev,
struct hdac_hdmi_pin *pin)
{
pin->eld.info.spk_alloc = pin->eld.eld_buffer[DRM_ELD_SPEAKER];
}
static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll)
{ {
struct hdac_ext_device *edev = pin->edev; struct hdac_ext_device *edev = pin->edev;
...@@ -1065,6 +1122,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) ...@@ -1065,6 +1122,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll)
snd_jack_report(pcm->jack, SND_JACK_AVOUT); snd_jack_report(pcm->jack, SND_JACK_AVOUT);
} }
hdac_hdmi_parse_eld(edev, pin);
print_hex_dump_bytes("ELD: ", DUMP_PREFIX_OFFSET, print_hex_dump_bytes("ELD: ", DUMP_PREFIX_OFFSET,
pin->eld.eld_buffer, pin->eld.eld_size); pin->eld.eld_buffer, pin->eld.eld_size);
...@@ -1123,6 +1181,7 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) ...@@ -1123,6 +1181,7 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
hdmi->num_pin++; hdmi->num_pin++;
pin->edev = edev; pin->edev = edev;
mutex_init(&pin->lock);
INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld); INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld);
return 0; return 0;
...@@ -1342,6 +1401,19 @@ static struct i915_audio_component_audio_ops aops = { ...@@ -1342,6 +1401,19 @@ static struct i915_audio_component_audio_ops aops = {
.pin_eld_notify = hdac_hdmi_eld_notify_cb, .pin_eld_notify = hdac_hdmi_eld_notify_cb,
}; };
static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card,
int device)
{
struct snd_soc_pcm_runtime *rtd;
list_for_each_entry(rtd, &card->rtd_list, list) {
if (rtd->pcm && (rtd->pcm->device == device))
return rtd->pcm;
}
return NULL;
}
int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device)
{ {
char jack_name[NAME_SIZE]; char jack_name[NAME_SIZE];
...@@ -1351,6 +1423,8 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) ...@@ -1351,6 +1423,8 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device)
snd_soc_component_get_dapm(&codec->component); snd_soc_component_get_dapm(&codec->component);
struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pcm *pcm; struct hdac_hdmi_pcm *pcm;
struct snd_pcm *snd_pcm;
int err;
/* /*
* this is a new PCM device, create new pcm and * this is a new PCM device, create new pcm and
...@@ -1362,6 +1436,18 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) ...@@ -1362,6 +1436,18 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device)
pcm->pcm_id = device; pcm->pcm_id = device;
pcm->cvt = hdmi->dai_map[dai->id].cvt; pcm->cvt = hdmi->dai_map[dai->id].cvt;
snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device);
if (snd_pcm) {
err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap);
if (err < 0) {
dev_err(&edev->hdac.dev,
"chmap control add failed with err: %d for pcm: %d\n",
err, device);
kfree(pcm);
return err;
}
}
list_add_tail(&pcm->head, &hdmi->pcm_list); list_add_tail(&pcm->head, &hdmi->pcm_list);
sprintf(jack_name, "HDMI/DP, pcm=%d Jack", device); sprintf(jack_name, "HDMI/DP, pcm=%d Jack", device);
...@@ -1483,6 +1569,60 @@ static struct snd_soc_codec_driver hdmi_hda_codec = { ...@@ -1483,6 +1569,60 @@ static struct snd_soc_codec_driver hdmi_hda_codec = {
.idle_bias_off = true, .idle_bias_off = true,
}; };
static void hdac_hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx,
unsigned char *chmap)
{
struct hdac_ext_device *edev = to_ehdac_device(hdac);
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
struct hdac_hdmi_pin *pin = pcm->pin;
/* chmap is already set to 0 in caller */
if (!pin)
return;
memcpy(chmap, pin->chmap, ARRAY_SIZE(pin->chmap));
}
static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx,
unsigned char *chmap, int prepared)
{
struct hdac_ext_device *edev = to_ehdac_device(hdac);
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
struct hdac_hdmi_pin *pin = pcm->pin;
mutex_lock(&pin->lock);
pin->chmap_set = true;
memcpy(pin->chmap, chmap, ARRAY_SIZE(pin->chmap));
if (prepared)
hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, pin->nid);
mutex_unlock(&pin->lock);
}
static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
{
struct hdac_ext_device *edev = to_ehdac_device(hdac);
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
struct hdac_hdmi_pin *pin = pcm->pin;
return pin ? true:false;
}
static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
{
struct hdac_ext_device *edev = to_ehdac_device(hdac);
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
struct hdac_hdmi_pin *pin = pcm->pin;
if (!pin || !pin->eld.eld_valid)
return 0;
return pin->eld.info.spk_alloc;
}
static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
{ {
struct hdac_device *codec = &edev->hdac; struct hdac_device *codec = &edev->hdac;
...@@ -1501,6 +1641,11 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) ...@@ -1501,6 +1641,11 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
return -ENOMEM; return -ENOMEM;
edev->private_data = hdmi_priv; edev->private_data = hdmi_priv;
snd_hdac_register_chmap_ops(codec, &hdmi_priv->chmap);
hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap;
hdmi_priv->chmap.ops.set_chmap = hdac_hdmi_set_chmap;
hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached;
hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc;
dev_set_drvdata(&codec->dev, edev); dev_set_drvdata(&codec->dev, edev);
......
This diff is collapsed.
...@@ -30,6 +30,16 @@ ...@@ -30,6 +30,16 @@
static struct snd_soc_jack skylake_headset; static struct snd_soc_jack skylake_headset;
static struct snd_soc_card skylake_audio_card; static struct snd_soc_card skylake_audio_card;
struct skl_hdmi_pcm {
struct list_head head;
struct snd_soc_dai *codec_dai;
int device;
};
struct skl_nau8825_private {
struct list_head hdmi_pcm_list;
};
enum { enum {
SKL_DPCM_AUDIO_PB = 0, SKL_DPCM_AUDIO_PB = 0,
SKL_DPCM_AUDIO_CP, SKL_DPCM_AUDIO_CP,
...@@ -192,23 +202,56 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) ...@@ -192,23 +202,56 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
{ {
struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai = rtd->codec_dai; struct snd_soc_dai *dai = rtd->codec_dai;
struct skl_hdmi_pcm *pcm;
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
if (!pcm)
return -ENOMEM;
pcm->device = SKL_DPCM_AUDIO_HDMI1_PB;
pcm->codec_dai = dai;
return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI1_PB); list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
return 0;
} }
static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
{ {
struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai = rtd->codec_dai; struct snd_soc_dai *dai = rtd->codec_dai;
struct skl_hdmi_pcm *pcm;
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
if (!pcm)
return -ENOMEM;
return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI2_PB); pcm->device = SKL_DPCM_AUDIO_HDMI2_PB;
pcm->codec_dai = dai;
list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
return 0;
} }
static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
{ {
struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai = rtd->codec_dai; struct snd_soc_dai *dai = rtd->codec_dai;
struct skl_hdmi_pcm *pcm;
return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI3_PB); pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
if (!pcm)
return -ENOMEM;
pcm->device = SKL_DPCM_AUDIO_HDMI3_PB;
pcm->codec_dai = dai;
list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
return 0;
} }
static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd)
...@@ -533,6 +576,21 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -533,6 +576,21 @@ static struct snd_soc_dai_link skylake_dais[] = {
}, },
}; };
static int skylake_card_late_probe(struct snd_soc_card *card)
{
struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(card);
struct skl_hdmi_pcm *pcm;
int err;
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device);
if (err < 0)
return err;
}
return 0;
}
/* skylake audio machine driver for SPT + NAU88L25 */ /* skylake audio machine driver for SPT + NAU88L25 */
static struct snd_soc_card skylake_audio_card = { static struct snd_soc_card skylake_audio_card = {
.name = "sklnau8825max", .name = "sklnau8825max",
...@@ -546,11 +604,21 @@ static struct snd_soc_card skylake_audio_card = { ...@@ -546,11 +604,21 @@ static struct snd_soc_card skylake_audio_card = {
.dapm_routes = skylake_map, .dapm_routes = skylake_map,
.num_dapm_routes = ARRAY_SIZE(skylake_map), .num_dapm_routes = ARRAY_SIZE(skylake_map),
.fully_routed = true, .fully_routed = true,
.late_probe = skylake_card_late_probe,
}; };
static int skylake_audio_probe(struct platform_device *pdev) static int skylake_audio_probe(struct platform_device *pdev)
{ {
struct skl_nau8825_private *ctx;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
if (!ctx)
return -ENOMEM;
INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
skylake_audio_card.dev = &pdev->dev; skylake_audio_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&skylake_audio_card, ctx);
return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
} }
......
...@@ -34,6 +34,15 @@ ...@@ -34,6 +34,15 @@
static struct snd_soc_jack skylake_headset; static struct snd_soc_jack skylake_headset;
static struct snd_soc_card skylake_audio_card; static struct snd_soc_card skylake_audio_card;
struct skl_hdmi_pcm {
struct list_head head;
struct snd_soc_dai *codec_dai;
int device;
};
struct skl_nau88125_private {
struct list_head hdmi_pcm_list;
};
enum { enum {
SKL_DPCM_AUDIO_PB = 0, SKL_DPCM_AUDIO_PB = 0,
SKL_DPCM_AUDIO_CP, SKL_DPCM_AUDIO_CP,
...@@ -222,24 +231,57 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) ...@@ -222,24 +231,57 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
{ {
struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai = rtd->codec_dai; struct snd_soc_dai *dai = rtd->codec_dai;
struct skl_hdmi_pcm *pcm;
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
if (!pcm)
return -ENOMEM;
pcm->device = SKL_DPCM_AUDIO_HDMI1_PB;
pcm->codec_dai = dai;
list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI1_PB); return 0;
} }
static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
{ {
struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai = rtd->codec_dai; struct snd_soc_dai *dai = rtd->codec_dai;
struct skl_hdmi_pcm *pcm;
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
if (!pcm)
return -ENOMEM;
pcm->device = SKL_DPCM_AUDIO_HDMI2_PB;
pcm->codec_dai = dai;
return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI2_PB); list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
return 0;
} }
static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
{ {
struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai = rtd->codec_dai; struct snd_soc_dai *dai = rtd->codec_dai;
struct skl_hdmi_pcm *pcm;
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
if (!pcm)
return -ENOMEM;
return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI3_PB); pcm->device = SKL_DPCM_AUDIO_HDMI3_PB;
pcm->codec_dai = dai;
list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
return 0;
} }
static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd)
...@@ -584,6 +626,21 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -584,6 +626,21 @@ static struct snd_soc_dai_link skylake_dais[] = {
}, },
}; };
static int skylake_card_late_probe(struct snd_soc_card *card)
{
struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card);
struct skl_hdmi_pcm *pcm;
int err;
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device);
if (err < 0)
return err;
}
return 0;
}
/* skylake audio machine driver for SPT + NAU88L25 */ /* skylake audio machine driver for SPT + NAU88L25 */
static struct snd_soc_card skylake_audio_card = { static struct snd_soc_card skylake_audio_card = {
.name = "sklnau8825adi", .name = "sklnau8825adi",
...@@ -599,11 +656,21 @@ static struct snd_soc_card skylake_audio_card = { ...@@ -599,11 +656,21 @@ static struct snd_soc_card skylake_audio_card = {
.codec_conf = ssm4567_codec_conf, .codec_conf = ssm4567_codec_conf,
.num_configs = ARRAY_SIZE(ssm4567_codec_conf), .num_configs = ARRAY_SIZE(ssm4567_codec_conf),
.fully_routed = true, .fully_routed = true,
.late_probe = skylake_card_late_probe,
}; };
static int skylake_audio_probe(struct platform_device *pdev) static int skylake_audio_probe(struct platform_device *pdev)
{ {
struct skl_nau88125_private *ctx;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
if (!ctx)
return -ENOMEM;
INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
skylake_audio_card.dev = &pdev->dev; skylake_audio_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&skylake_audio_card, ctx);
return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
} }
......
...@@ -30,6 +30,16 @@ ...@@ -30,6 +30,16 @@
static struct snd_soc_jack skylake_headset; static struct snd_soc_jack skylake_headset;
struct skl_hdmi_pcm {
struct list_head head;
struct snd_soc_dai *codec_dai;
int device;
};
struct skl_rt286_private {
struct list_head hdmi_pcm_list;
};
enum { enum {
SKL_DPCM_AUDIO_PB = 0, SKL_DPCM_AUDIO_PB = 0,
SKL_DPCM_AUDIO_CP, SKL_DPCM_AUDIO_CP,
...@@ -142,9 +152,20 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) ...@@ -142,9 +152,20 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
static int skylake_hdmi_init(struct snd_soc_pcm_runtime *rtd) static int skylake_hdmi_init(struct snd_soc_pcm_runtime *rtd)
{ {
struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai = rtd->codec_dai; struct snd_soc_dai *dai = rtd->codec_dai;
struct skl_hdmi_pcm *pcm;
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
if (!pcm)
return -ENOMEM;
return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI1_PB + dai->id); pcm->device = SKL_DPCM_AUDIO_HDMI1_PB + dai->id;
pcm->codec_dai = dai;
list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
return 0;
} }
static unsigned int rates[] = { static unsigned int rates[] = {
...@@ -437,6 +458,21 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { ...@@ -437,6 +458,21 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
}, },
}; };
static int skylake_card_late_probe(struct snd_soc_card *card)
{
struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(card);
struct skl_hdmi_pcm *pcm;
int err;
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device);
if (err < 0)
return err;
}
return 0;
}
/* skylake audio machine driver for SPT + RT286S */ /* skylake audio machine driver for SPT + RT286S */
static struct snd_soc_card skylake_rt286 = { static struct snd_soc_card skylake_rt286 = {
.name = "skylake-rt286", .name = "skylake-rt286",
...@@ -450,11 +486,21 @@ static struct snd_soc_card skylake_rt286 = { ...@@ -450,11 +486,21 @@ static struct snd_soc_card skylake_rt286 = {
.dapm_routes = skylake_rt286_map, .dapm_routes = skylake_rt286_map,
.num_dapm_routes = ARRAY_SIZE(skylake_rt286_map), .num_dapm_routes = ARRAY_SIZE(skylake_rt286_map),
.fully_routed = true, .fully_routed = true,
.late_probe = skylake_card_late_probe,
}; };
static int skylake_audio_probe(struct platform_device *pdev) static int skylake_audio_probe(struct platform_device *pdev)
{ {
struct skl_rt286_private *ctx;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
if (!ctx)
return -ENOMEM;
INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
skylake_rt286.dev = &pdev->dev; skylake_rt286.dev = &pdev->dev;
snd_soc_card_set_drvdata(&skylake_rt286, ctx);
return devm_snd_soc_register_card(&pdev->dev, &skylake_rt286); return devm_snd_soc_register_card(&pdev->dev, &skylake_rt286);
} }
......
...@@ -51,7 +51,7 @@ static struct snd_pcm_hardware azx_pcm_hw = { ...@@ -51,7 +51,7 @@ static struct snd_pcm_hardware azx_pcm_hw = {
.rate_min = 8000, .rate_min = 8000,
.rate_max = 48000, .rate_max = 48000,
.channels_min = 1, .channels_min = 1,
.channels_max = HDA_QUAD, .channels_max = 8,
.buffer_bytes_max = AZX_MAX_BUF_SIZE, .buffer_bytes_max = AZX_MAX_BUF_SIZE,
.period_bytes_min = 128, .period_bytes_min = 128,
.period_bytes_max = AZX_MAX_BUF_SIZE / 2, .period_bytes_max = AZX_MAX_BUF_SIZE / 2,
...@@ -691,7 +691,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { ...@@ -691,7 +691,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.playback = { .playback = {
.stream_name = "HDMI1 Playback", .stream_name = "HDMI1 Playback",
.channels_min = HDA_STEREO, .channels_min = HDA_STEREO,
.channels_max = HDA_STEREO, .channels_max = 8,
.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
...@@ -706,7 +706,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { ...@@ -706,7 +706,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.playback = { .playback = {
.stream_name = "HDMI2 Playback", .stream_name = "HDMI2 Playback",
.channels_min = HDA_STEREO, .channels_min = HDA_STEREO,
.channels_max = HDA_STEREO, .channels_max = 8,
.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
...@@ -721,7 +721,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { ...@@ -721,7 +721,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.playback = { .playback = {
.stream_name = "HDMI3 Playback", .stream_name = "HDMI3 Playback",
.channels_min = HDA_STEREO, .channels_min = HDA_STEREO,
.channels_max = HDA_STEREO, .channels_max = 8,
.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
...@@ -846,7 +846,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { ...@@ -846,7 +846,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.playback = { .playback = {
.stream_name = "iDisp1 Tx", .stream_name = "iDisp1 Tx",
.channels_min = HDA_STEREO, .channels_min = HDA_STEREO,
.channels_max = HDA_STEREO, .channels_max = 8,
.rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE |
SNDRV_PCM_FMTBIT_S24_LE, SNDRV_PCM_FMTBIT_S24_LE,
...@@ -858,7 +858,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { ...@@ -858,7 +858,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.playback = { .playback = {
.stream_name = "iDisp2 Tx", .stream_name = "iDisp2 Tx",
.channels_min = HDA_STEREO, .channels_min = HDA_STEREO,
.channels_max = HDA_STEREO, .channels_max = 8,
.rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|
SNDRV_PCM_RATE_48000, SNDRV_PCM_RATE_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE |
...@@ -871,7 +871,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { ...@@ -871,7 +871,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.playback = { .playback = {
.stream_name = "iDisp3 Tx", .stream_name = "iDisp3 Tx",
.channels_min = HDA_STEREO, .channels_min = HDA_STEREO,
.channels_max = HDA_STEREO, .channels_max = 8,
.rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|
SNDRV_PCM_RATE_48000, SNDRV_PCM_RATE_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE |
......
...@@ -154,13 +154,32 @@ static void skl_dump_mconfig(struct skl_sst *ctx, ...@@ -154,13 +154,32 @@ static void skl_dump_mconfig(struct skl_sst *ctx,
dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg); dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg);
} }
static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs)
{
int slot_map = 0xFFFFFFFF;
int start_slot = 0;
int i;
for (i = 0; i < chs; i++) {
/*
* For 2 channels with starting slot as 0, slot map will
* look like 0xFFFFFF10.
*/
slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i)));
start_slot++;
}
fmt->ch_map = slot_map;
}
static void skl_tplg_update_params(struct skl_module_fmt *fmt, static void skl_tplg_update_params(struct skl_module_fmt *fmt,
struct skl_pipe_params *params, int fixup) struct skl_pipe_params *params, int fixup)
{ {
if (fixup & SKL_RATE_FIXUP_MASK) if (fixup & SKL_RATE_FIXUP_MASK)
fmt->s_freq = params->s_freq; fmt->s_freq = params->s_freq;
if (fixup & SKL_CH_FIXUP_MASK) if (fixup & SKL_CH_FIXUP_MASK) {
fmt->channels = params->ch; fmt->channels = params->ch;
skl_tplg_update_chmap(fmt, fmt->channels);
}
if (fixup & SKL_FMT_FIXUP_MASK) { if (fixup & SKL_FMT_FIXUP_MASK) {
fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt); fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment