Commit 535b218a authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/ak4613', 'asoc/topic/core',...

Merge remote-tracking branches 'asoc/topic/ak4613', 'asoc/topic/core', 'asoc/topic/dmic' and 'asoc/topic/intel' into asoc-next
...@@ -737,16 +737,17 @@ bool acpi_dev_found(const char *hid) ...@@ -737,16 +737,17 @@ bool acpi_dev_found(const char *hid)
} }
EXPORT_SYMBOL(acpi_dev_found); 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]; struct acpi_device_id hid[2];
const char *uid; const char *uid;
s64 hrv; 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_device *adev = to_acpi_device(dev);
struct acpi_dev_present_info *match = data; struct acpi_dev_match_info *match = data;
unsigned long long hrv; unsigned long long hrv;
acpi_status status; acpi_status status;
...@@ -757,6 +758,8 @@ static int acpi_dev_present_cb(struct device *dev, void *data) ...@@ -757,6 +758,8 @@ static int acpi_dev_present_cb(struct device *dev, void *data)
strcmp(adev->pnp.unique_id, match->uid))) strcmp(adev->pnp.unique_id, match->uid)))
return 0; return 0;
match->dev_name = acpi_dev_name(adev);
if (match->hrv == -1) if (match->hrv == -1)
return 1; return 1;
...@@ -789,20 +792,44 @@ static int acpi_dev_present_cb(struct device *dev, void *data) ...@@ -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) 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; struct device *dev;
strlcpy(match.hid[0].id, hid, sizeof(match.hid[0].id)); strlcpy(match.hid[0].id, hid, sizeof(match.hid[0].id));
match.uid = uid; match.uid = uid;
match.hrv = hrv; match.hrv = hrv;
dev = bus_find_device(&acpi_bus_type, NULL, &match, dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb);
acpi_dev_present_cb);
return !!dev; return !!dev;
} }
EXPORT_SYMBOL(acpi_dev_present); 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 * acpi_backlight= handling, this is done here rather then in video_detect.c
* because __setup cannot be used in modules. * because __setup cannot be used in modules.
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/acpi.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -380,9 +381,16 @@ static void mrfld_irq_init_hw(struct mrfld_gpio *priv) ...@@ -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) static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{ {
const struct mrfld_gpio_pinrange *range; const struct mrfld_gpio_pinrange *range;
const char *pinctrl_dev_name;
struct mrfld_gpio *priv; struct mrfld_gpio *priv;
u32 gpio_base, irq_base; u32 gpio_base, irq_base;
void __iomem *base; void __iomem *base;
...@@ -439,10 +447,11 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id ...@@ -439,10 +447,11 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id
return retval; return retval;
} }
pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name();
for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) { for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) {
range = &mrfld_gpio_ranges[i]; range = &mrfld_gpio_ranges[i];
retval = gpiochip_add_pin_range(&priv->chip, retval = gpiochip_add_pin_range(&priv->chip,
"pinctrl-merrifield", pinctrl_dev_name,
range->gpio_base, range->gpio_base,
range->pin_base, range->pin_base,
range->npins); range->npins);
......
...@@ -91,6 +91,9 @@ acpi_evaluate_dsm_typed(acpi_handle handle, const guid_t *guid, u64 rev, ...@@ -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_found(const char *hid);
bool acpi_dev_present(const char *hid, const char *uid, s64 hrv); 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 #ifdef CONFIG_ACPI
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
......
...@@ -640,6 +640,12 @@ static inline bool acpi_dev_present(const char *hid, const char *uid, s64 hrv) ...@@ -640,6 +640,12 @@ static inline bool acpi_dev_present(const char *hid, const char *uid, s64 hrv)
return false; 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) static inline bool is_acpi_node(struct fwnode_handle *fwnode)
{ {
return false; return false;
......
...@@ -27,17 +27,13 @@ struct snd_soc_acpi_package_context { ...@@ -27,17 +27,13 @@ struct snd_soc_acpi_package_context {
bool data_valid; 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) #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], bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
struct snd_soc_acpi_package_context *ctx); struct snd_soc_acpi_package_context *ctx);
#else #else
static inline const char *
snd_soc_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN])
{
return NULL;
}
static inline bool static inline bool
snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
struct snd_soc_acpi_package_context *ctx) struct snd_soc_acpi_package_context *ctx)
......
...@@ -804,6 +804,9 @@ struct snd_soc_component_driver { ...@@ -804,6 +804,9 @@ struct snd_soc_component_driver {
int (*suspend)(struct snd_soc_component *); int (*suspend)(struct snd_soc_component *);
int (*resume)(struct snd_soc_component *); int (*resume)(struct snd_soc_component *);
unsigned int (*read)(struct snd_soc_component *, unsigned int);
int (*write)(struct snd_soc_component *, unsigned int, unsigned int);
/* pcm creation and destruction */ /* pcm creation and destruction */
int (*pcm_new)(struct snd_soc_pcm_runtime *); int (*pcm_new)(struct snd_soc_pcm_runtime *);
void (*pcm_free)(struct snd_pcm *); void (*pcm_free)(struct snd_pcm *);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of_device.h> #include <linux/of_device.h>
...@@ -95,6 +96,9 @@ struct ak4613_priv { ...@@ -95,6 +96,9 @@ struct ak4613_priv {
struct mutex lock; struct mutex lock;
const struct ak4613_interface *iface; const struct ak4613_interface *iface;
struct snd_pcm_hw_constraint_list constraint; struct snd_pcm_hw_constraint_list constraint;
struct work_struct dummy_write_work;
struct snd_soc_component *component;
unsigned int rate;
unsigned int sysclk; unsigned int sysclk;
unsigned int fmt; unsigned int fmt;
...@@ -392,6 +396,7 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, ...@@ -392,6 +396,7 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
default: default:
return -EINVAL; return -EINVAL;
} }
priv->rate = rate;
/* /*
* FIXME * FIXME
...@@ -467,11 +472,83 @@ static int ak4613_set_bias_level(struct snd_soc_codec *codec, ...@@ -467,11 +472,83 @@ static int ak4613_set_bias_level(struct snd_soc_codec *codec,
return 0; return 0;
} }
static void ak4613_dummy_write(struct work_struct *work)
{
struct ak4613_priv *priv = container_of(work,
struct ak4613_priv,
dummy_write_work);
struct snd_soc_component *component = priv->component;
unsigned int mgmt1;
unsigned int mgmt3;
/*
* PW_MGMT1 / PW_MGMT3 needs dummy write at least after 5 LR clocks
*
* Note
*
* To avoid extra delay, we want to avoid preemption here,
* but we can't. Because it uses I2C access which is using IRQ
* and sleep. Thus, delay might be more than 5 LR clocks
* see also
* ak4613_dai_trigger()
*/
udelay(5000000 / priv->rate);
snd_soc_component_read(component, PW_MGMT1, &mgmt1);
snd_soc_component_read(component, PW_MGMT3, &mgmt3);
snd_soc_component_write(component, PW_MGMT1, mgmt1);
snd_soc_component_write(component, PW_MGMT3, mgmt3);
}
static int ak4613_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
/*
* FIXME
*
* PW_MGMT1 / PW_MGMT3 needs dummy write at least after 5 LR clocks
* from Power Down Release. Otherwise, Playback volume will be 0dB.
* To avoid complex multiple delay/dummy_write method from
* ak4613_set_bias_level() / SND_SOC_DAPM_DAC_E("DACx", ...),
* call it once here.
*
* But, unfortunately, we can't "write" here because here is atomic
* context (It uses I2C access for writing).
* Thus, use schedule_work() to switching to normal context
* immediately.
*
* Note
*
* Calling ak4613_dummy_write() function might be delayed.
* In such case, ak4613 volume might be temporarily 0dB when
* beggining of playback.
* see also
* ak4613_dummy_write()
*/
if ((cmd != SNDRV_PCM_TRIGGER_START) &&
(cmd != SNDRV_PCM_TRIGGER_RESUME))
return 0;
if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
return 0;
priv->component = &codec->component;
schedule_work(&priv->dummy_write_work);
return 0;
}
static const struct snd_soc_dai_ops ak4613_dai_ops = { static const struct snd_soc_dai_ops ak4613_dai_ops = {
.startup = ak4613_dai_startup, .startup = ak4613_dai_startup,
.shutdown = ak4613_dai_shutdown, .shutdown = ak4613_dai_shutdown,
.set_sysclk = ak4613_dai_set_sysclk, .set_sysclk = ak4613_dai_set_sysclk,
.set_fmt = ak4613_dai_set_fmt, .set_fmt = ak4613_dai_set_fmt,
.trigger = ak4613_dai_trigger,
.hw_params = ak4613_dai_hw_params, .hw_params = ak4613_dai_hw_params,
}; };
...@@ -590,6 +667,7 @@ static int ak4613_i2c_probe(struct i2c_client *i2c, ...@@ -590,6 +667,7 @@ static int ak4613_i2c_probe(struct i2c_client *i2c,
priv->iface = NULL; priv->iface = NULL;
priv->cnt = 0; priv->cnt = 0;
priv->sysclk = 0; priv->sysclk = 0;
INIT_WORK(&priv->dummy_write_work, ak4613_dummy_write);
mutex_init(&priv->lock); mutex_init(&priv->lock);
......
...@@ -113,7 +113,7 @@ static int dmic_dev_probe(struct platform_device *pdev) ...@@ -113,7 +113,7 @@ static int dmic_dev_probe(struct platform_device *pdev)
if (pdev->dev.of_node) { if (pdev->dev.of_node) {
err = of_property_read_u32(pdev->dev.of_node, "num-channels", &chans); err = of_property_read_u32(pdev->dev.of_node, "num-channels", &chans);
if (err && (err != -ENOENT)) if (err && (err != -EINVAL))
return err; return err;
if (!err) { if (!err) {
......
...@@ -77,7 +77,6 @@ config SND_SST_ATOM_HIFI2_PLATFORM_PCI ...@@ -77,7 +77,6 @@ config SND_SST_ATOM_HIFI2_PLATFORM_PCI
depends on X86 && PCI depends on X86 && PCI
select SND_SST_IPC_PCI select SND_SST_IPC_PCI
select SND_SOC_COMPRESS select SND_SOC_COMPRESS
select SND_SOC_INTEL_COMMON
help help
If you have a Intel Medfield or Merrifield/Edison platform, then 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 by saying Y or m. Distros will typically not
...@@ -98,6 +97,9 @@ config SND_SST_ATOM_HIFI2_PLATFORM ...@@ -98,6 +97,9 @@ config SND_SST_ATOM_HIFI2_PLATFORM
codec, then enable this option by saying Y or m. This is a codec, then enable this option by saying Y or m. This is a
recommended option recommended option
config SND_SOC_INTEL_SKYLAKE_SSP_CLK
tristate
config SND_SOC_INTEL_SKYLAKE config SND_SOC_INTEL_SKYLAKE
tristate "SKL/BXT/KBL/GLK/CNL... Platforms" tristate "SKL/BXT/KBL/GLK/CNL... Platforms"
depends on PCI && ACPI depends on PCI && ACPI
......
...@@ -139,6 +139,7 @@ config SND_SOC_INTEL_BYT_CHT_DA7213_MACH ...@@ -139,6 +139,7 @@ config SND_SOC_INTEL_BYT_CHT_DA7213_MACH
config SND_SOC_INTEL_BYT_CHT_ES8316_MACH config SND_SOC_INTEL_BYT_CHT_ES8316_MACH
tristate "Baytrail & Cherrytrail with ES8316 codec" tristate "Baytrail & Cherrytrail with ES8316 codec"
depends on X86_INTEL_LPSS && I2C && ACPI depends on X86_INTEL_LPSS && I2C && ACPI
select SND_SOC_ACPI
select SND_SOC_ES8316 select SND_SOC_ES8316
help help
This adds support for ASoC machine driver for Intel(R) Baytrail & This adds support for ASoC machine driver for Intel(R) Baytrail &
...@@ -234,6 +235,7 @@ config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH ...@@ -234,6 +235,7 @@ config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
select SND_SOC_MAX98927 select SND_SOC_MAX98927
select SND_SOC_DMIC select SND_SOC_DMIC
select SND_SOC_HDAC_HDMI select SND_SOC_HDAC_HDMI
select SND_SOC_INTEL_SKYLAKE_SSP_CLK
help help
This adds support for ASoC Onboard Codec I2S machine driver. This will This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for RT5663 + MAX98927. create an alsa sound card for RT5663 + MAX98927.
......
...@@ -219,7 +219,7 @@ static struct snd_soc_card bytcht_da7213_card = { ...@@ -219,7 +219,7 @@ static struct snd_soc_card bytcht_da7213_card = {
.num_dapm_routes = ARRAY_SIZE(audio_map), .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) static int bytcht_da7213_probe(struct platform_device *pdev)
{ {
...@@ -243,7 +243,7 @@ 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 */ /* 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) { if (i2c_name) {
snprintf(codec_name, sizeof(codec_name), snprintf(codec_name, sizeof(codec_name),
"%s%s", "i2c-", i2c_name); "%s%s", "i2c-", i2c_name);
......
...@@ -232,15 +232,39 @@ static struct snd_soc_card byt_cht_es8316_card = { ...@@ -232,15 +232,39 @@ static struct snd_soc_card byt_cht_es8316_card = {
.fully_routed = true, .fully_routed = true,
}; };
static char codec_name[SND_ACPI_I2C_ID_LEN];
static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
{ {
int ret = 0;
struct byt_cht_es8316_private *priv; 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); priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
if (!priv) if (!priv)
return -ENOMEM; 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 */ /* register the soc card */
byt_cht_es8316_card.dev = &pdev->dev; byt_cht_es8316_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv);
......
...@@ -713,7 +713,7 @@ static struct snd_soc_card byt_rt5640_card = { ...@@ -713,7 +713,7 @@ static struct snd_soc_card byt_rt5640_card = {
.fully_routed = true, .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_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */
static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ 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) ...@@ -762,7 +762,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
} }
/* fixup codec name based on HID */ /* 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) { if (i2c_name) {
snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name), snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name),
"%s%s", "i2c-", i2c_name); "%s%s", "i2c-", i2c_name);
......
...@@ -509,7 +509,7 @@ static struct snd_soc_card byt_rt5651_card = { ...@@ -509,7 +509,7 @@ static struct snd_soc_card byt_rt5651_card = {
.fully_routed = true, .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) static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
{ {
...@@ -539,7 +539,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) ...@@ -539,7 +539,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
} }
/* fixup codec name based on HID */ /* 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) { if (i2c_name) {
snprintf(byt_rt5651_codec_name, sizeof(byt_rt5651_codec_name), snprintf(byt_rt5651_codec_name, sizeof(byt_rt5651_codec_name),
"%s%s", "i2c-", i2c_name); "%s%s", "i2c-", i2c_name);
......
...@@ -49,7 +49,7 @@ struct cht_acpi_card { ...@@ -49,7 +49,7 @@ struct cht_acpi_card {
struct cht_mc_private { struct cht_mc_private {
struct snd_soc_jack jack; struct snd_soc_jack jack;
struct cht_acpi_card *acpi_card; struct cht_acpi_card *acpi_card;
char codec_name[16]; char codec_name[SND_ACPI_I2C_ID_LEN];
struct clk *mclk; struct clk *mclk;
}; };
...@@ -506,7 +506,7 @@ static struct cht_acpi_card snd_soc_cards[] = { ...@@ -506,7 +506,7 @@ static struct cht_acpi_card snd_soc_cards[] = {
{"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650}, {"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_codec_aif_name[12]; /* = "rt5645-aif[1|2]" */
static char cht_rt5645_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ static char cht_rt5645_cpu_dai_name[10]; /* = "ssp[0|2]-port" */
...@@ -573,7 +573,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) ...@@ -573,7 +573,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
} }
/* fixup codec name based on HID */ /* 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) { if (i2c_name) {
snprintf(cht_rt5645_codec_name, sizeof(cht_rt5645_codec_name), snprintf(cht_rt5645_codec_name, sizeof(cht_rt5645_codec_name),
"%s%s", "i2c-", i2c_name); "%s%s", "i2c-", i2c_name);
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
struct cht_mc_private { struct cht_mc_private {
struct snd_soc_jack headset; struct snd_soc_jack headset;
char codec_name[16]; char codec_name[SND_ACPI_I2C_ID_LEN];
struct clk *mclk; struct clk *mclk;
}; };
...@@ -396,7 +396,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) ...@@ -396,7 +396,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
/* fixup codec name based on HID */ /* fixup codec name based on HID */
if (mach) { 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) { if (i2c_name) {
snprintf(drv->codec_name, sizeof(drv->codec_name), snprintf(drv->codec_name, sizeof(drv->codec_name),
"i2c-%s", i2c_name); "i2c-%s", i2c_name);
......
...@@ -28,6 +28,9 @@ ...@@ -28,6 +28,9 @@
#include "../../codecs/rt5663.h" #include "../../codecs/rt5663.h"
#include "../../codecs/hdac_hdmi.h" #include "../../codecs/hdac_hdmi.h"
#include "../skylake/skl.h" #include "../skylake/skl.h"
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#define KBL_REALTEK_CODEC_DAI "rt5663-aif" #define KBL_REALTEK_CODEC_DAI "rt5663-aif"
#define KBL_MAXIM_CODEC_DAI "max98927-aif1" #define KBL_MAXIM_CODEC_DAI "max98927-aif1"
...@@ -48,6 +51,8 @@ struct kbl_hdmi_pcm { ...@@ -48,6 +51,8 @@ struct kbl_hdmi_pcm {
struct kbl_rt5663_private { struct kbl_rt5663_private {
struct snd_soc_jack kabylake_headset; struct snd_soc_jack kabylake_headset;
struct list_head hdmi_pcm_list; struct list_head hdmi_pcm_list;
struct clk *mclk;
struct clk *sclk;
}; };
enum { enum {
...@@ -69,6 +74,61 @@ static const struct snd_kcontrol_new kabylake_controls[] = { ...@@ -69,6 +74,61 @@ static const struct snd_kcontrol_new kabylake_controls[] = {
SOC_DAPM_PIN_SWITCH("Right Spk"), SOC_DAPM_PIN_SWITCH("Right Spk"),
}; };
static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
struct snd_soc_dapm_context *dapm = w->dapm;
struct snd_soc_card *card = dapm->card;
struct kbl_rt5663_private *priv = snd_soc_card_get_drvdata(card);
int ret = 0;
/*
* MCLK/SCLK need to be ON early for a successful synchronization of
* codec internal clock. And the clocks are turned off during
* POST_PMD after the stream is stopped.
*/
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
/* Enable MCLK */
ret = clk_set_rate(priv->mclk, 24000000);
if (ret < 0) {
dev_err(card->dev, "Can't set rate for mclk, err: %d\n",
ret);
return ret;
}
ret = clk_prepare_enable(priv->mclk);
if (ret < 0) {
dev_err(card->dev, "Can't enable mclk, err: %d\n", ret);
return ret;
}
/* Enable SCLK */
ret = clk_set_rate(priv->sclk, 3072000);
if (ret < 0) {
dev_err(card->dev, "Can't set rate for sclk, err: %d\n",
ret);
clk_disable_unprepare(priv->mclk);
return ret;
}
ret = clk_prepare_enable(priv->sclk);
if (ret < 0) {
dev_err(card->dev, "Can't enable sclk, err: %d\n", ret);
clk_disable_unprepare(priv->mclk);
}
break;
case SND_SOC_DAPM_POST_PMD:
clk_disable_unprepare(priv->mclk);
clk_disable_unprepare(priv->sclk);
break;
default:
return 0;
}
return 0;
}
static const struct snd_soc_dapm_widget kabylake_widgets[] = { static const struct snd_soc_dapm_widget kabylake_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL),
...@@ -78,11 +138,14 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = { ...@@ -78,11 +138,14 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
SND_SOC_DAPM_SPK("HDMI1", NULL), SND_SOC_DAPM_SPK("HDMI1", NULL),
SND_SOC_DAPM_SPK("HDMI2", NULL), SND_SOC_DAPM_SPK("HDMI2", NULL),
SND_SOC_DAPM_SPK("HDMI3", NULL), SND_SOC_DAPM_SPK("HDMI3", 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),
}; };
static const struct snd_soc_dapm_route kabylake_map[] = { static const struct snd_soc_dapm_route kabylake_map[] = {
/* HP jack connectors - unknown if we have jack detection */ /* HP jack connectors - unknown if we have jack detection */
{ "Headphone Jack", NULL, "Platform Clock" },
{ "Headphone Jack", NULL, "HPOL" }, { "Headphone Jack", NULL, "HPOL" },
{ "Headphone Jack", NULL, "HPOR" }, { "Headphone Jack", NULL, "HPOR" },
...@@ -91,6 +154,7 @@ static const struct snd_soc_dapm_route kabylake_map[] = { ...@@ -91,6 +154,7 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
{ "Right Spk", NULL, "Right BE_OUT" }, { "Right Spk", NULL, "Right BE_OUT" },
/* other jacks */ /* other jacks */
{ "Headset Mic", NULL, "Platform Clock" },
{ "IN1P", NULL, "Headset Mic" }, { "IN1P", NULL, "Headset Mic" },
{ "IN1N", NULL, "Headset Mic" }, { "IN1N", NULL, "Headset Mic" },
{ "DMic", NULL, "SoC DMIC" }, { "DMic", NULL, "SoC DMIC" },
...@@ -901,6 +965,7 @@ static int kabylake_audio_probe(struct platform_device *pdev) ...@@ -901,6 +965,7 @@ static int kabylake_audio_probe(struct platform_device *pdev)
{ {
struct kbl_rt5663_private *ctx; struct kbl_rt5663_private *ctx;
struct skl_machine_pdata *pdata; struct skl_machine_pdata *pdata;
int ret;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
if (!ctx) if (!ctx)
...@@ -919,6 +984,34 @@ static int kabylake_audio_probe(struct platform_device *pdev) ...@@ -919,6 +984,34 @@ static int kabylake_audio_probe(struct platform_device *pdev)
dmic_constraints = pdata->dmic_num == 2 ? dmic_constraints = pdata->dmic_num == 2 ?
&constraints_dmic_2ch : &constraints_dmic_channels; &constraints_dmic_2ch : &constraints_dmic_channels;
ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk");
if (IS_ERR(ctx->mclk)) {
ret = PTR_ERR(ctx->mclk);
if (ret == -ENOENT) {
dev_info(&pdev->dev,
"Failed to get ssp1_sclk, defer probe\n");
return -EPROBE_DEFER;
}
dev_err(&pdev->dev, "Failed to get ssp1_mclk with err:%d\n",
ret);
return ret;
}
ctx->sclk = devm_clk_get(&pdev->dev, "ssp1_sclk");
if (IS_ERR(ctx->sclk)) {
ret = PTR_ERR(ctx->sclk);
if (ret == -ENOENT) {
dev_info(&pdev->dev,
"Failed to get ssp1_sclk, defer probe\n");
return -EPROBE_DEFER;
}
dev_err(&pdev->dev, "Failed to get ssp1_sclk with err:%d\n",
ret);
return ret;
}
return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card); return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card);
} }
......
...@@ -14,3 +14,8 @@ snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o cnl-sst-dsp.o \ ...@@ -14,3 +14,8 @@ snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o cnl-sst-dsp.o \
skl-sst-utils.o skl-sst-utils.o
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o
#Skylake Clock device support
snd-soc-skl-ssp-clk-objs := skl-ssp-clk.o
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE_SSP_CLK) += snd-soc-skl-ssp-clk.o
...@@ -27,6 +27,12 @@ ...@@ -27,6 +27,12 @@
#define SKL_SHIFT(x) (ffs(x) - 1) #define SKL_SHIFT(x) (ffs(x) - 1)
#define SKL_MCLK_DIV_RATIO_MASK GENMASK(11, 0) #define SKL_MCLK_DIV_RATIO_MASK GENMASK(11, 0)
#define is_legacy_blob(x) (x.signature != 0xEE)
#define ext_to_legacy_blob(i2s_config_blob_ext) \
((struct skl_i2s_config_blob_legacy *) i2s_config_blob_ext)
#define get_clk_src(mclk, mask) \
((mclk.mdivctrl & mask) >> SKL_SHIFT(mask))
struct skl_i2s_config { struct skl_i2s_config {
u32 ssc0; u32 ssc0;
u32 ssc1; u32 ssc1;
...@@ -45,6 +51,24 @@ struct skl_i2s_config_mclk { ...@@ -45,6 +51,24 @@ struct skl_i2s_config_mclk {
u32 mdivr; u32 mdivr;
}; };
struct skl_i2s_config_mclk_ext {
u32 mdivctrl;
u32 mdivr_count;
u32 mdivr[0];
} __packed;
struct skl_i2s_config_blob_signature {
u32 minor_ver : 8;
u32 major_ver : 8;
u32 resvdz : 8;
u32 signature : 8;
} __packed;
struct skl_i2s_config_blob_header {
struct skl_i2s_config_blob_signature sig;
u32 size;
};
/** /**
* struct skl_i2s_config_blob_legacy - Structure defines I2S Gateway * struct skl_i2s_config_blob_legacy - Structure defines I2S Gateway
* configuration legacy blob * configuration legacy blob
...@@ -61,4 +85,11 @@ struct skl_i2s_config_blob_legacy { ...@@ -61,4 +85,11 @@ struct skl_i2s_config_blob_legacy {
struct skl_i2s_config_mclk mclk; struct skl_i2s_config_mclk mclk;
}; };
struct skl_i2s_config_blob_ext {
u32 gtw_attr;
struct skl_i2s_config_blob_header hdr;
u32 tdm_ts_group[SKL_I2S_MAX_TIME_SLOTS];
struct skl_i2s_config i2s_cfg;
struct skl_i2s_config_mclk_ext mclk;
} __packed;
#endif /* __SOUND_SOC_SKL_I2S_H */ #endif /* __SOUND_SOC_SKL_I2S_H */
...@@ -675,6 +675,7 @@ int skl_dsp_set_dma_control(struct skl_sst *ctx, u32 *caps, ...@@ -675,6 +675,7 @@ int skl_dsp_set_dma_control(struct skl_sst *ctx, u32 *caps,
kfree(dma_ctrl); kfree(dma_ctrl);
return err; return err;
} }
EXPORT_SYMBOL_GPL(skl_dsp_set_dma_control);
static void skl_setup_out_format(struct skl_sst *ctx, static void skl_setup_out_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig, struct skl_module_cfg *mconfig,
......
...@@ -28,6 +28,7 @@ static guid_t osc_guid = ...@@ -28,6 +28,7 @@ static guid_t osc_guid =
GUID_INIT(0xA69F886E, 0x6CEB, 0x4594, GUID_INIT(0xA69F886E, 0x6CEB, 0x4594,
0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53); 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53);
struct nhlt_acpi_table *skl_nhlt_init(struct device *dev) struct nhlt_acpi_table *skl_nhlt_init(struct device *dev)
{ {
acpi_handle handle; acpi_handle handle;
...@@ -287,6 +288,7 @@ void skl_nhlt_remove_sysfs(struct skl *skl) ...@@ -287,6 +288,7 @@ void skl_nhlt_remove_sysfs(struct skl *skl)
static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks, static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks,
struct nhlt_fmt *fmt, u8 id) struct nhlt_fmt *fmt, u8 id)
{ {
struct skl_i2s_config_blob_ext *i2s_config_ext;
struct skl_i2s_config_blob_legacy *i2s_config; struct skl_i2s_config_blob_legacy *i2s_config;
struct skl_clk_parent_src *parent; struct skl_clk_parent_src *parent;
struct skl_ssp_clk *sclk, *sclkfs; struct skl_ssp_clk *sclk, *sclkfs;
...@@ -347,12 +349,18 @@ static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks, ...@@ -347,12 +349,18 @@ static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks,
/* Fill rate and parent for sclk/sclkfs */ /* Fill rate and parent for sclk/sclkfs */
if (!present) { if (!present) {
/* MCLK Divider Source Select */ i2s_config_ext = (struct skl_i2s_config_blob_ext *)
i2s_config = (struct skl_i2s_config_blob_legacy *)
fmt->fmt_config[0].config.caps; fmt->fmt_config[0].config.caps;
clk_src = ((i2s_config->mclk.mdivctrl)
& SKL_MNDSS_DIV_CLK_SRC_MASK) >> /* MCLK Divider Source Select */
SKL_SHIFT(SKL_MNDSS_DIV_CLK_SRC_MASK); if (is_legacy_blob(i2s_config_ext->hdr.sig)) {
i2s_config = ext_to_legacy_blob(i2s_config_ext);
clk_src = get_clk_src(i2s_config->mclk,
SKL_MNDSS_DIV_CLK_SRC_MASK);
} else {
clk_src = get_clk_src(i2s_config_ext->mclk,
SKL_MNDSS_DIV_CLK_SRC_MASK);
}
parent = skl_get_parent_clk(clk_src); parent = skl_get_parent_clk(clk_src);
...@@ -378,6 +386,7 @@ static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks, ...@@ -378,6 +386,7 @@ static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks,
static void skl_get_mclk(struct skl *skl, struct skl_ssp_clk *mclk, static void skl_get_mclk(struct skl *skl, struct skl_ssp_clk *mclk,
struct nhlt_fmt *fmt, u8 id) struct nhlt_fmt *fmt, u8 id)
{ {
struct skl_i2s_config_blob_ext *i2s_config_ext;
struct skl_i2s_config_blob_legacy *i2s_config; struct skl_i2s_config_blob_legacy *i2s_config;
struct nhlt_specific_cfg *fmt_cfg; struct nhlt_specific_cfg *fmt_cfg;
struct skl_clk_parent_src *parent; struct skl_clk_parent_src *parent;
...@@ -385,13 +394,21 @@ static void skl_get_mclk(struct skl *skl, struct skl_ssp_clk *mclk, ...@@ -385,13 +394,21 @@ static void skl_get_mclk(struct skl *skl, struct skl_ssp_clk *mclk,
u8 clk_src; u8 clk_src;
fmt_cfg = &fmt->fmt_config[0].config; fmt_cfg = &fmt->fmt_config[0].config;
i2s_config = (struct skl_i2s_config_blob_legacy *)fmt_cfg->caps; i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->caps;
/* MCLK Divider Source Select */ /* MCLK Divider Source Select and divider */
clk_src = ((i2s_config->mclk.mdivctrl) & SKL_MCLK_DIV_CLK_SRC_MASK) >> if (is_legacy_blob(i2s_config_ext->hdr.sig)) {
SKL_SHIFT(SKL_MCLK_DIV_CLK_SRC_MASK); i2s_config = ext_to_legacy_blob(i2s_config_ext);
clk_src = get_clk_src(i2s_config->mclk,
clkdiv = i2s_config->mclk.mdivr & SKL_MCLK_DIV_RATIO_MASK; SKL_MCLK_DIV_CLK_SRC_MASK);
clkdiv = i2s_config->mclk.mdivr &
SKL_MCLK_DIV_RATIO_MASK;
} else {
clk_src = get_clk_src(i2s_config_ext->mclk,
SKL_MCLK_DIV_CLK_SRC_MASK);
clkdiv = i2s_config_ext->mclk.mdivr[0] &
SKL_MCLK_DIV_RATIO_MASK;
}
/* bypass divider */ /* bypass divider */
div_ratio = 1; div_ratio = 1;
......
// SPDX-License-Identifier: GPL-2.0
// Copyright(c) 2015-17 Intel Corporation
/*
* skl-ssp-clk.c - ASoC skylake ssp clock driver
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include "skl.h"
#include "skl-ssp-clk.h"
#include "skl-topology.h"
#define to_skl_clk(_hw) container_of(_hw, struct skl_clk, hw)
struct skl_clk_parent {
struct clk_hw *hw;
struct clk_lookup *lookup;
};
struct skl_clk {
struct clk_hw hw;
struct clk_lookup *lookup;
unsigned long rate;
struct skl_clk_pdata *pdata;
u32 id;
};
struct skl_clk_data {
struct skl_clk_parent parent[SKL_MAX_CLK_SRC];
struct skl_clk *clk[SKL_MAX_CLK_CNT];
u8 avail_clk_cnt;
};
static int skl_get_clk_type(u32 index)
{
switch (index) {
case 0 ... (SKL_SCLK_OFS - 1):
return SKL_MCLK;
case SKL_SCLK_OFS ... (SKL_SCLKFS_OFS - 1):
return SKL_SCLK;
case SKL_SCLKFS_OFS ... (SKL_MAX_CLK_CNT - 1):
return SKL_SCLK_FS;
default:
return -EINVAL;
}
}
static int skl_get_vbus_id(u32 index, u8 clk_type)
{
switch (clk_type) {
case SKL_MCLK:
return index;
case SKL_SCLK:
return index - SKL_SCLK_OFS;
case SKL_SCLK_FS:
return index - SKL_SCLKFS_OFS;
default:
return -EINVAL;
}
}
static void skl_fill_clk_ipc(struct skl_clk_rate_cfg_table *rcfg, u8 clk_type)
{
struct nhlt_fmt_cfg *fmt_cfg;
union skl_clk_ctrl_ipc *ipc;
struct wav_fmt *wfmt;
if (!rcfg)
return;
ipc = &rcfg->dma_ctl_ipc;
if (clk_type == SKL_SCLK_FS) {
fmt_cfg = (struct nhlt_fmt_cfg *)rcfg->config;
wfmt = &fmt_cfg->fmt_ext.fmt;
/* Remove TLV Header size */
ipc->sclk_fs.hdr.size = sizeof(struct skl_dmactrl_sclkfs_cfg) -
sizeof(struct skl_tlv_hdr);
ipc->sclk_fs.sampling_frequency = wfmt->samples_per_sec;
ipc->sclk_fs.bit_depth = wfmt->bits_per_sample;
ipc->sclk_fs.valid_bit_depth =
fmt_cfg->fmt_ext.sample.valid_bits_per_sample;
ipc->sclk_fs.number_of_channels = wfmt->channels;
} else {
ipc->mclk.hdr.type = DMA_CLK_CONTROLS;
/* Remove TLV Header size */
ipc->mclk.hdr.size = sizeof(struct skl_dmactrl_mclk_cfg) -
sizeof(struct skl_tlv_hdr);
}
}
/* Sends dma control IPC to turn the clock ON/OFF */
static int skl_send_clk_dma_control(struct skl *skl,
struct skl_clk_rate_cfg_table *rcfg,
u32 vbus_id, u8 clk_type,
bool enable)
{
struct nhlt_specific_cfg *sp_cfg;
u32 i2s_config_size, node_id = 0;
struct nhlt_fmt_cfg *fmt_cfg;
union skl_clk_ctrl_ipc *ipc;
void *i2s_config = NULL;
u8 *data, size;
int ret;
if (!rcfg)
return -EIO;
ipc = &rcfg->dma_ctl_ipc;
fmt_cfg = (struct nhlt_fmt_cfg *)rcfg->config;
sp_cfg = &fmt_cfg->config;
if (clk_type == SKL_SCLK_FS) {
ipc->sclk_fs.hdr.type =
enable ? DMA_TRANSMITION_START : DMA_TRANSMITION_STOP;
data = (u8 *)&ipc->sclk_fs;
size = sizeof(struct skl_dmactrl_sclkfs_cfg);
} else {
/* 1 to enable mclk, 0 to enable sclk */
if (clk_type == SKL_SCLK)
ipc->mclk.mclk = 0;
else
ipc->mclk.mclk = 1;
ipc->mclk.keep_running = enable;
ipc->mclk.warm_up_over = enable;
ipc->mclk.clk_stop_over = !enable;
data = (u8 *)&ipc->mclk;
size = sizeof(struct skl_dmactrl_mclk_cfg);
}
i2s_config_size = sp_cfg->size + size;
i2s_config = kzalloc(i2s_config_size, GFP_KERNEL);
if (!i2s_config)
return -ENOMEM;
/* copy blob */
memcpy(i2s_config, sp_cfg->caps, sp_cfg->size);
/* copy additional dma controls information */
memcpy(i2s_config + sp_cfg->size, data, size);
node_id = ((SKL_DMA_I2S_LINK_INPUT_CLASS << 8) | (vbus_id << 4));
ret = skl_dsp_set_dma_control(skl->skl_sst, (u32 *)i2s_config,
i2s_config_size, node_id);
kfree(i2s_config);
return ret;
}
static struct skl_clk_rate_cfg_table *skl_get_rate_cfg(
struct skl_clk_rate_cfg_table *rcfg,
unsigned long rate)
{
int i;
for (i = 0; (i < SKL_MAX_CLK_RATES) && rcfg[i].rate; i++) {
if (rcfg[i].rate == rate)
return &rcfg[i];
}
return NULL;
}
static int skl_clk_change_status(struct skl_clk *clkdev,
bool enable)
{
struct skl_clk_rate_cfg_table *rcfg;
int vbus_id, clk_type;
clk_type = skl_get_clk_type(clkdev->id);
if (clk_type < 0)
return clk_type;
vbus_id = skl_get_vbus_id(clkdev->id, clk_type);
if (vbus_id < 0)
return vbus_id;
rcfg = skl_get_rate_cfg(clkdev->pdata->ssp_clks[clkdev->id].rate_cfg,
clkdev->rate);
if (!rcfg)
return -EINVAL;
return skl_send_clk_dma_control(clkdev->pdata->pvt_data, rcfg,
vbus_id, clk_type, enable);
}
static int skl_clk_prepare(struct clk_hw *hw)
{
struct skl_clk *clkdev = to_skl_clk(hw);
return skl_clk_change_status(clkdev, true);
}
static void skl_clk_unprepare(struct clk_hw *hw)
{
struct skl_clk *clkdev = to_skl_clk(hw);
skl_clk_change_status(clkdev, false);
}
static int skl_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct skl_clk *clkdev = to_skl_clk(hw);
struct skl_clk_rate_cfg_table *rcfg;
int clk_type;
if (!rate)
return -EINVAL;
rcfg = skl_get_rate_cfg(clkdev->pdata->ssp_clks[clkdev->id].rate_cfg,
rate);
if (!rcfg)
return -EINVAL;
clk_type = skl_get_clk_type(clkdev->id);
if (clk_type < 0)
return clk_type;
skl_fill_clk_ipc(rcfg, clk_type);
clkdev->rate = rate;
return 0;
}
static unsigned long skl_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct skl_clk *clkdev = to_skl_clk(hw);
if (clkdev->rate)
return clkdev->rate;
return 0;
}
/* Not supported by clk driver. Implemented to satisfy clk fw */
long skl_clk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
return rate;
}
/*
* prepare/unprepare are used instead of enable/disable as IPC will be sent
* in non-atomic context.
*/
static const struct clk_ops skl_clk_ops = {
.prepare = skl_clk_prepare,
.unprepare = skl_clk_unprepare,
.set_rate = skl_clk_set_rate,
.round_rate = skl_clk_round_rate,
.recalc_rate = skl_clk_recalc_rate,
};
static void unregister_parent_src_clk(struct skl_clk_parent *pclk,
unsigned int id)
{
while (id--) {
clkdev_drop(pclk[id].lookup);
clk_hw_unregister_fixed_rate(pclk[id].hw);
}
}
static void unregister_src_clk(struct skl_clk_data *dclk)
{
u8 cnt = dclk->avail_clk_cnt;
while (cnt--)
clkdev_drop(dclk->clk[cnt]->lookup);
}
static int skl_register_parent_clks(struct device *dev,
struct skl_clk_parent *parent,
struct skl_clk_parent_src *pclk)
{
int i, ret;
for (i = 0; i < SKL_MAX_CLK_SRC; i++) {
/* Register Parent clock */
parent[i].hw = clk_hw_register_fixed_rate(dev, pclk[i].name,
pclk[i].parent_name, 0, pclk[i].rate);
if (IS_ERR(parent[i].hw)) {
ret = PTR_ERR(parent[i].hw);
goto err;
}
parent[i].lookup = clkdev_hw_create(parent[i].hw, pclk[i].name,
NULL);
if (!parent[i].lookup) {
clk_hw_unregister_fixed_rate(parent[i].hw);
ret = -ENOMEM;
goto err;
}
}
return 0;
err:
unregister_parent_src_clk(parent, i);
return ret;
}
/* Assign fmt_config to clk_data */
static struct skl_clk *register_skl_clk(struct device *dev,
struct skl_ssp_clk *clk,
struct skl_clk_pdata *clk_pdata, int id)
{
struct clk_init_data init;
struct skl_clk *clkdev;
int ret;
clkdev = devm_kzalloc(dev, sizeof(*clkdev), GFP_KERNEL);
if (!clkdev)
return ERR_PTR(-ENOMEM);
init.name = clk->name;
init.ops = &skl_clk_ops;
init.flags = CLK_SET_RATE_GATE;
init.parent_names = &clk->parent_name;
init.num_parents = 1;
clkdev->hw.init = &init;
clkdev->pdata = clk_pdata;
clkdev->id = id;
ret = devm_clk_hw_register(dev, &clkdev->hw);
if (ret) {
clkdev = ERR_PTR(ret);
return clkdev;
}
clkdev->lookup = clkdev_hw_create(&clkdev->hw, init.name, NULL);
if (!clkdev->lookup)
clkdev = ERR_PTR(-ENOMEM);
return clkdev;
}
static int skl_clk_dev_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device *parent_dev = dev->parent;
struct skl_clk_parent_src *parent_clks;
struct skl_clk_pdata *clk_pdata;
struct skl_clk_data *data;
struct skl_ssp_clk *clks;
int ret, i;
clk_pdata = dev_get_platdata(&pdev->dev);
parent_clks = clk_pdata->parent_clks;
clks = clk_pdata->ssp_clks;
if (!parent_clks || !clks)
return -EIO;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
/* Register Parent clock */
ret = skl_register_parent_clks(parent_dev, data->parent, parent_clks);
if (ret < 0)
return ret;
for (i = 0; i < clk_pdata->num_clks; i++) {
/*
* Only register valid clocks
* i.e. for which nhlt entry is present.
*/
if (clks[i].rate_cfg[0].rate == 0)
continue;
data->clk[i] = register_skl_clk(dev, &clks[i], clk_pdata, i);
if (IS_ERR(data->clk[i])) {
ret = PTR_ERR(data->clk[i]);
goto err_unreg_skl_clk;
}
data->avail_clk_cnt++;
}
platform_set_drvdata(pdev, data);
return 0;
err_unreg_skl_clk:
unregister_src_clk(data);
unregister_parent_src_clk(data->parent, SKL_MAX_CLK_SRC);
return ret;
}
static int skl_clk_dev_remove(struct platform_device *pdev)
{
struct skl_clk_data *data;
data = platform_get_drvdata(pdev);
unregister_src_clk(data);
unregister_parent_src_clk(data->parent, SKL_MAX_CLK_SRC);
return 0;
}
static struct platform_driver skl_clk_driver = {
.driver = {
.name = "skl-ssp-clk",
},
.probe = skl_clk_dev_probe,
.remove = skl_clk_dev_remove,
};
module_platform_driver(skl_clk_driver);
MODULE_DESCRIPTION("Skylake clock driver");
MODULE_AUTHOR("Jaikrishna Nemallapudi <jaikrishnax.nemallapudi@intel.com>");
MODULE_AUTHOR("Subhransu S. Prusty <subhransu.s.prusty@intel.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:skl-ssp-clk");
...@@ -54,8 +54,46 @@ struct skl_clk_parent_src { ...@@ -54,8 +54,46 @@ struct skl_clk_parent_src {
const char *parent_name; const char *parent_name;
}; };
struct skl_tlv_hdr {
u32 type;
u32 size;
};
struct skl_dmactrl_mclk_cfg {
struct skl_tlv_hdr hdr;
/* DMA Clk TLV params */
u32 clk_warm_up:16;
u32 mclk:1;
u32 warm_up_over:1;
u32 rsvd0:14;
u32 clk_stop_delay:16;
u32 keep_running:1;
u32 clk_stop_over:1;
u32 rsvd1:14;
};
struct skl_dmactrl_sclkfs_cfg {
struct skl_tlv_hdr hdr;
/* DMA SClk&FS TLV params */
u32 sampling_frequency;
u32 bit_depth;
u32 channel_map;
u32 channel_config;
u32 interleaving_style;
u32 number_of_channels : 8;
u32 valid_bit_depth : 8;
u32 sample_type : 8;
u32 reserved : 8;
};
union skl_clk_ctrl_ipc {
struct skl_dmactrl_mclk_cfg mclk;
struct skl_dmactrl_sclkfs_cfg sclk_fs;
};
struct skl_clk_rate_cfg_table { struct skl_clk_rate_cfg_table {
unsigned long rate; unsigned long rate;
union skl_clk_ctrl_ipc dma_ctl_ipc;
void *config; void *config;
}; };
......
...@@ -190,7 +190,6 @@ skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig) ...@@ -190,7 +190,6 @@ skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig)
u8 res_idx = mconfig->res_idx; u8 res_idx = mconfig->res_idx;
struct skl_module_res *res = &mconfig->module->resources[res_idx]; struct skl_module_res *res = &mconfig->module->resources[res_idx];
res = &mconfig->module->resources[res_idx];
skl->resource.mcps -= res->cps; skl->resource.mcps -= res->cps;
} }
......
...@@ -38,6 +38,10 @@ ...@@ -38,6 +38,10 @@
/* D0I3C Register fields */ /* D0I3C Register fields */
#define AZX_REG_VS_D0I3C_CIP 0x1 /* Command in progress */ #define AZX_REG_VS_D0I3C_CIP 0x1 /* Command in progress */
#define AZX_REG_VS_D0I3C_I3 0x4 /* D0i3 enable */ #define AZX_REG_VS_D0I3C_I3 0x4 /* D0i3 enable */
#define SKL_MAX_DMACTRL_CFG 18
#define DMA_CLK_CONTROLS 1
#define DMA_TRANSMITION_START 2
#define DMA_TRANSMITION_STOP 3
struct skl_dsp_resource { struct skl_dsp_resource {
u32 max_mcps; u32 max_mcps;
...@@ -147,6 +151,8 @@ int skl_nhlt_create_sysfs(struct skl *skl); ...@@ -147,6 +151,8 @@ int skl_nhlt_create_sysfs(struct skl *skl);
void skl_nhlt_remove_sysfs(struct skl *skl); void skl_nhlt_remove_sysfs(struct skl *skl);
void skl_get_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks); 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_clk_parent_src *skl_get_parent_clk(u8 clk_id);
int skl_dsp_set_dma_control(struct skl_sst *ctx, u32 *caps,
u32 caps_size, u32 node_id);
struct skl_module_cfg; struct skl_module_cfg;
......
...@@ -16,39 +16,6 @@ ...@@ -16,39 +16,6 @@
#include <sound/soc-acpi.h> #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);
struct snd_soc_acpi_mach * struct snd_soc_acpi_mach *
snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines) snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines)
{ {
......
...@@ -590,14 +590,23 @@ struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, ...@@ -590,14 +590,23 @@ struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd,
{ {
struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_rtdcom_list *rtdcom;
if (!driver_name)
return NULL;
for_each_rtdcom(rtd, rtdcom) { for_each_rtdcom(rtd, rtdcom) {
if ((rtdcom->component->driver->name == driver_name) || const char *component_name = rtdcom->component->driver->name;
strcmp(rtdcom->component->driver->name, driver_name) == 0)
if (!component_name)
continue;
if ((component_name == driver_name) ||
strcmp(component_name, driver_name) == 0)
return rtdcom->component; return rtdcom->component;
} }
return NULL; return NULL;
} }
EXPORT_SYMBOL_GPL(snd_soc_rtdcom_lookup);
struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
const char *dai_link, int stream) const char *dai_link, int stream)
......
...@@ -34,6 +34,10 @@ int snd_soc_component_read(struct snd_soc_component *component, ...@@ -34,6 +34,10 @@ int snd_soc_component_read(struct snd_soc_component *component,
ret = regmap_read(component->regmap, reg, val); ret = regmap_read(component->regmap, reg, val);
else if (component->read) else if (component->read)
ret = component->read(component, reg, val); ret = component->read(component, reg, val);
else if (component->driver->read) {
*val = component->driver->read(component, reg);
ret = 0;
}
else else
ret = -EIO; ret = -EIO;
...@@ -70,6 +74,8 @@ int snd_soc_component_write(struct snd_soc_component *component, ...@@ -70,6 +74,8 @@ int snd_soc_component_write(struct snd_soc_component *component,
return regmap_write(component->regmap, reg, val); return regmap_write(component->regmap, reg, val);
else if (component->write) else if (component->write)
return component->write(component, reg, val); return component->write(component, reg, val);
else if (component->driver->write)
return component->driver->write(component, reg, val);
else else
return -EIO; return -EIO;
} }
......
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