// SPDX-License-Identifier: GPL-2.0
//
// soc-component.c
//
// Copyright 2009-2011 Wolfson Microelectronics PLC.
// Copyright (C) 2019 Renesas Electronics Corp.
//
// Mark Brown <broonie@opensource.wolfsonmicro.com>
// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
//
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <sound/soc.h>
#define soc_component_ret(dai, ret) _soc_component_ret(dai, __func__, ret)
static inline int _soc_component_ret(struct snd_soc_component *component,
const char *func, int ret)
{
/* Positive/Zero values are not errors */
if (ret >= 0)
return ret;
/* Negative values might be errors */
switch (ret) {
case -EPROBE_DEFER:
case -ENOTSUPP:
break;
default:
dev_err(component->dev,
"ASoC: error at %s on %s: %d\n",
func, component->name, ret);
}
return ret;
}
/*
* We might want to check substream by using list.
* In such case, we can update these macros.
*/
#define soc_component_mark_push(component, substream, tgt) ((component)->mark_##tgt = substream)
#define soc_component_mark_pop(component, substream, tgt) ((component)->mark_##tgt = NULL)
#define soc_component_mark_match(component, substream, tgt) ((component)->mark_##tgt == substream)
void snd_soc_component_set_aux(struct snd_soc_component *component,
struct snd_soc_aux_dev *aux)
{
component->init = (aux) ? aux->init : NULL;
}
int snd_soc_component_init(struct snd_soc_component *component)
{
int ret = 0;
if (component->init)
ret = component->init(component);
return soc_component_ret(component, ret);
}
/**
* snd_soc_component_set_sysclk - configure COMPONENT system or master clock.
* @component: COMPONENT
* @clk_id: DAI specific clock ID
* @source: Source for the clock
* @freq: new clock frequency in Hz
* @dir: new clock direction - input/output.
*
* Configures the CODEC master (MCLK) or system (SYSCLK) clocking.
*/
int snd_soc_component_set_sysclk(struct snd_soc_component *component,
int clk_id, int source, unsigned int freq,
int dir)
{
int ret = -ENOTSUPP;
if (component->driver->set_sysclk)
ret = component->driver->set_sysclk(component, clk_id, source,
freq, dir);
return soc_component_ret(component, ret);
}
EXPORT_SYMBOL_GPL(snd_soc_component_set_sysclk);
/*
* snd_soc_component_set_pll - configure component PLL.
* @component: COMPONENT
* @pll_id: DAI specific PLL ID
* @source: DAI specific source for the PLL
* @freq_in: PLL input clock frequency in Hz
* @freq_out: requested PLL output clock frequency in Hz
*
* Configures and enables PLL to generate output clock based on input clock.
*/
int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id,
int source, unsigned int freq_in,
unsigned int freq_out)
{
int ret = -EINVAL;
if (component->driver->set_pll)
ret = component->driver->set_pll(component, pll_id, source,
freq_in, freq_out);
return soc_component_ret(component, ret);
}
EXPORT_SYMBOL_GPL(snd_soc_component_set_pll);
void snd_soc_component_seq_notifier(struct snd_soc_component *component,
enum snd_soc_dapm_type type, int subseq)
{
if (component->driver->seq_notifier)
component->driver->seq_notifier(component, type, subseq);
}
int snd_soc_component_stream_event(struct snd_soc_component *component,
int event)
{
int ret = 0;
if (component->driver->stream_event)
ret = component->driver->stream_event(component, event);
return soc_component_ret(component, ret);
}
int snd_soc_component_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
int ret = 0;