// 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>
#include <linux/bitops.h>
#define soc_component_ret(dai, ret) _soc_component_ret(dai, __func__, ret, -1)
#define soc_component_ret_reg_rw(dai, ret, reg) _soc_component_ret(dai, __func__, ret, reg)
static inline int _soc_component_ret(struct snd_soc_component *component,
const char *func, int ret, int reg)
{
/* 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:
if (reg == -1)
dev_err(component->dev,
"ASoC: error at %s on %s: %d\n",
func, component->name, ret);
else
dev_err(component->dev,
"ASoC: error at %s on %s for register: [0x%08x] %d\n",
func, component->name, reg, ret);
}
return ret;
}
static inline int soc_component_field_shift(struct snd_soc_component *component,
unsigned int mask)
{
if (!mask) {
dev_err(component->dev, "ASoC: error field mask is zero for %s\n",
component->name);
return 0;
}
return (ffs(mask) - 1);
}
/*
* 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.
*/