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 @@
int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,
size_t len);
int snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params,
u8 *cs, size_t len);
#endif
......@@ -9,30 +9,18 @@
#include <linux/types.h>
#include <sound/asoundef.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/pcm_iec958.h>
/**
* 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)
static int create_iec958_consumer(uint rate, uint sample_width,
u8 *cs, size_t len)
{
unsigned int fs, ws;
if (len < 4)
return -EINVAL;
switch (runtime->rate) {
switch (rate) {
case 32000:
fs = IEC958_AES3_CON_FS_32000;
break;
......@@ -59,7 +47,7 @@ int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,
}
if (len > 4) {
switch (snd_pcm_format_width(runtime->format)) {
switch (sample_width) {
case 16:
ws = IEC958_AES4_CON_WORDLEN_20_16;
break;
......@@ -71,6 +59,7 @@ int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,
IEC958_AES4_CON_MAX_WORDLEN_24;
break;
case 24:
case 32: /* Assume 24-bit width for 32-bit samples. */
ws = IEC958_AES4_CON_WORDLEN_24_20 |
IEC958_AES4_CON_MAX_WORDLEN_24;
break;
......@@ -92,4 +81,46 @@ int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,
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);
/**
* 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)
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[];
int hda_widget_sysfs_init(struct hdac_device *codec);
void hda_widget_sysfs_exit(struct hdac_device *codec);
......
......@@ -88,6 +88,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_MC13783 if MFD_MC13XXX
select SND_SOC_ML26124 if I2C
select SND_SOC_NAU8825 if I2C
select SND_SOC_HDMI_CODEC
select SND_SOC_PCM1681 if I2C
select SND_SOC_PCM179X_I2C if I2C
select SND_SOC_PCM179X_SPI if SPI_MASTER
......@@ -478,6 +479,11 @@ config SND_SOC_BT_SCO
config SND_SOC_DMIC
tristate
config SND_SOC_HDMI_CODEC
tristate
select SND_PCM_ELD
select SND_PCM_IEC958
config SND_SOC_ES8328
tristate "Everest Semi ES8328 CODEC"
......
......@@ -81,6 +81,7 @@ snd-soc-max9850-objs := max9850.o
snd-soc-mc13783-objs := mc13783.o
snd-soc-ml26124-objs := ml26124.o
snd-soc-nau8825-objs := nau8825.o
snd-soc-hdmi-codec-objs := hdmi-codec.o
snd-soc-pcm1681-objs := pcm1681.o
snd-soc-pcm179x-codec-objs := pcm179x.o
snd-soc-pcm179x-i2c-objs := pcm179x-i2c.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_ML26124) += snd-soc-ml26124.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_PCM179X) += snd-soc-pcm179x-codec.o
obj-$(CONFIG_SND_SOC_PCM179X_I2C) += snd-soc-pcm179x-i2c.o
......
......@@ -29,6 +29,7 @@
#include <sound/hdaudio_ext.h>
#include <sound/hda_i915.h>
#include <sound/pcm_drm_eld.h>
#include <sound/hda_chmap.h>
#include "../../hda/local.h"
#include "hdac_hdmi.h"
......@@ -60,11 +61,17 @@ struct hdac_hdmi_cvt {
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 {
bool monitor_present;
bool eld_valid;
int eld_size;
char eld_buffer[ELD_MAX_SIZE];
struct hdac_hdmi_parsed_eld info;
};
struct hdac_hdmi_pin {
......@@ -76,6 +83,10 @@ struct hdac_hdmi_pin {
struct hdac_ext_device *edev;
int repoll_count;
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 {
......@@ -100,8 +111,22 @@ struct hdac_hdmi_priv {
int num_pin;
int num_cvt;
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)
{
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,
int i;
const u8 *eld_buf;
u8 conn_type;
int channels = 2;
int channels, ca;
list_for_each_entry(pin, &hdmi->pin_list, head) {
if (pin->nid == pin_nid)
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;
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) {
case DRM_ELD_CONN_TYPE_HDMI:
hdmi_audio_infoframe_init(&frame);
/* Default stereo for now */
frame.channels = channels;
frame.channel_allocation = ca;
ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
if (ret < 0)
......@@ -311,7 +341,7 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
dp_ai.len = 0x1b;
dp_ai.ver = 0x11 << 2;
dp_ai.CC02_CT47 = channels - 1;
dp_ai.CA = 0;
dp_ai.CA = ca;
dip = (u8 *)&dp_ai;
break;
......@@ -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_hdmi_priv *hdmi = hdac->private_data;
struct hdac_hdmi_dai_pin_map *dai_map;
struct hdac_hdmi_pin *pin;
struct hdac_ext_dma_params *dd;
int ret;
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);
dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n",
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,
dai_map->pin->nid);
mutex_unlock(&pin->lock);
if (ret < 0)
return ret;
......@@ -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,
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;
}
}
......@@ -647,10 +689,19 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
static int
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;
/* Only stereo supported as of now */
cvt->params.channels_min = cvt->params.channels_max = 2;
chans = get_wcaps(hdac, cvt->nid);
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,
&cvt->params.rates,
......@@ -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);
}
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)
{
struct hdac_ext_device *edev = pin->edev;
......@@ -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);
}
hdac_hdmi_parse_eld(edev, pin);
print_hex_dump_bytes("ELD: ", DUMP_PREFIX_OFFSET,
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)
hdmi->num_pin++;
pin->edev = edev;
mutex_init(&pin->lock);
INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld);
return 0;
......@@ -1342,6 +1401,19 @@ static struct i915_audio_component_audio_ops aops = {
.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)
{
char jack_name[NAME_SIZE];
......@@ -1351,6 +1423,8 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device)
snd_soc_component_get_dapm(&codec->component);
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pcm *pcm;
struct snd_pcm *snd_pcm;
int err;
/*
* 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)
pcm->pcm_id = device;
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);
sprintf(jack_name, "HDMI/DP, pcm=%d Jack", device);
......@@ -1483,6 +1569,60 @@ static struct snd_soc_codec_driver hdmi_hda_codec = {
.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)
{
struct hdac_device *codec = &edev->hdac;
......@@ -1501,6 +1641,11 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
return -ENOMEM;
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);
......
This diff is collapsed.
......@@ -30,6 +30,16 @@
static struct snd_soc_jack skylake_headset;
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 {
SKL_DPCM_AUDIO_PB = 0,
SKL_DPCM_AUDIO_CP,
......@@ -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)
{
struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card);
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)
{
struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card);
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)
{
struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card);
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)
......@@ -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 */
static struct snd_soc_card skylake_audio_card = {
.name = "sklnau8825max",
......@@ -546,11 +604,21 @@ static struct snd_soc_card skylake_audio_card = {
.dapm_routes = skylake_map,
.num_dapm_routes = ARRAY_SIZE(skylake_map),
.fully_routed = true,
.late_probe = skylake_card_late_probe,
};
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;
snd_soc_card_set_drvdata(&skylake_audio_card, ctx);
return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
}
......
......@@ -34,6 +34,15 @@
static struct snd_soc_jack skylake_headset;
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 {
SKL_DPCM_AUDIO_PB = 0,
SKL_DPCM_AUDIO_CP,
......@@ -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)
{
struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card);
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)
{
struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card);
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)
{
struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card);
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)
......@@ -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 */
static struct snd_soc_card skylake_audio_card = {
.name = "sklnau8825adi",
......@@ -599,11 +656,21 @@ static struct snd_soc_card skylake_audio_card = {
.codec_conf = ssm4567_codec_conf,
.num_configs = ARRAY_SIZE(ssm4567_codec_conf),
.fully_routed = true,
.late_probe = skylake_card_late_probe,
};
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;
snd_soc_card_set_drvdata(&skylake_audio_card, ctx);
return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
}
......
......@@ -30,6 +30,16 @@
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 {
SKL_DPCM_AUDIO_PB = 0,
SKL_DPCM_AUDIO_CP,
......@@ -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)
{
struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(rtd->card);
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[] = {
......@@ -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 */
static struct snd_soc_card skylake_rt286 = {
.name = "skylake-rt286",
......@@ -450,11 +486,21 @@ static struct snd_soc_card skylake_rt286 = {
.dapm_routes = skylake_rt286_map,
.num_dapm_routes = ARRAY_SIZE(skylake_rt286_map),
.fully_routed = true,
.late_probe = skylake_card_late_probe,
};
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;
snd_soc_card_set_drvdata(&skylake_rt286, ctx);
return devm_snd_soc_register_card(&pdev->dev, &skylake_rt286);
}
......
......@@ -51,7 +51,7 @@ static struct snd_pcm_hardware azx_pcm_hw = {
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,
.channels_max = HDA_QUAD,
.channels_max = 8,
.buffer_bytes_max = AZX_MAX_BUF_SIZE,
.period_bytes_min = 128,
.period_bytes_max = AZX_MAX_BUF_SIZE / 2,
......@@ -691,7 +691,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.playback = {
.stream_name = "HDMI1 Playback",
.channels_min = HDA_STEREO,
.channels_max = HDA_STEREO,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
......@@ -706,7 +706,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.playback = {
.stream_name = "HDMI2 Playback",
.channels_min = HDA_STEREO,
.channels_max = HDA_STEREO,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
......@@ -721,7 +721,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.playback = {
.stream_name = "HDMI3 Playback",
.channels_min = HDA_STEREO,
.channels_max = HDA_STEREO,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
......@@ -846,7 +846,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.playback = {
.stream_name = "iDisp1 Tx",
.channels_min = HDA_STEREO,
.channels_max = HDA_STEREO,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE |
SNDRV_PCM_FMTBIT_S24_LE,
......@@ -858,7 +858,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.playback = {
.stream_name = "iDisp2 Tx",
.channels_min = HDA_STEREO,
.channels_max = HDA_STEREO,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|
SNDRV_PCM_RATE_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE |
......@@ -871,7 +871,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.playback = {
.stream_name = "iDisp3 Tx",
.channels_min = HDA_STEREO,
.channels_max = HDA_STEREO,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|
SNDRV_PCM_RATE_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE |
......
......@@ -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);
}
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,
struct skl_pipe_params *params, int fixup)
{
if (fixup & SKL_RATE_FIXUP_MASK)
fmt->s_freq = params->s_freq;
if (fixup & SKL_CH_FIXUP_MASK)
if (fixup & SKL_CH_FIXUP_MASK) {
fmt->channels = params->ch;
skl_tplg_update_chmap(fmt, fmt->channels);
}
if (fixup & SKL_FMT_FIXUP_MASK) {
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