/*
* Greybus audio driver
* Copyright 2015-2016 Google Inc.
* Copyright 2015-2016 Linaro Ltd.
*
* Released under the GPLv2 only.
*/
#include "audio_codec.h"
#include "greybus_protocols.h"
#define GBAUDIO_INVALID_ID 0xFF
/* mixer control */
struct gb_mixer_control {
int min, max;
unsigned int reg, rreg, shift, rshift, invert;
};
struct gbaudio_ctl_pvt {
unsigned int ctl_id;
unsigned int data_cport;
unsigned int access;
unsigned int vcount;
struct gb_audio_ctl_elem_info *info;
};
static struct gbaudio_module_info *find_gb_module(
struct gbaudio_codec_info *codec,
char const *name)
{
int dev_id, ret;
char begin[NAME_SIZE];
struct gbaudio_module_info *module;
if (!name)
return NULL;
ret = sscanf(name, "%s %d", begin, &dev_id);
dev_dbg(codec->dev, "%s:Find module#%d\n", __func__, dev_id);
mutex_lock(&codec->lock);
list_for_each_entry(module, &codec->module_list, list) {
if (module->dev_id == dev_id) {
mutex_unlock(&codec->lock);
return module;
}
}
mutex_unlock(&codec->lock);
return NULL;
}
static const char *gbaudio_map_controlid(struct gbaudio_module_info *module,
__u8 control_id, __u8 index)
{
struct gbaudio_control *control;
if (control_id == GBAUDIO_INVALID_ID)
return NULL;
list_for_each_entry(control, &module->ctl_list, list) {
if (control->id == control_id) {
if (index == GBAUDIO_INVALID_ID)
return control->name;
return control->texts[index];
}
}
list_for_each_entry(control, &module->widget_ctl_list, list) {
if (control->id == control_id) {
if (index == GBAUDIO_INVALID_ID)
return control->name;
return control->texts[index];
}
}
return NULL;
}
static int gbaudio_map_widgetname(struct gbaudio_module_info *module,
const char *name)
{
struct gbaudio_widget *widget;
list_for_each_entry(widget, &module->widget_list, list) {
if (!strncmp(widget->name, name, NAME_SIZE))
return widget->id;
}
return -EINVAL;
}
static const char *gbaudio_map_widgetid(struct gbaudio_module_info *module,
__u8 widget_id)
{
struct gbaudio_widget *widget;
list_for_each_entry(widget, &module->widget_list, list) {
if (widget->id == widget_id)
return widget->name;
}
return NULL;
}
static int gbcodec_mixer_ctl_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
unsigned int max;
const char *name;
struct gbaudio_ctl_pvt *data;
struct gb_audio_ctl_elem_info *info;
struct gbaudio_module_info *module;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct gbaudio_codec_info *gbcodec = snd_soc_codec_get_drvdata(codec);
dev_dbg(codec->dev, "Entered %s:%s\n", __func__, kcontrol->id.name);
data = (struct gbaudio_ctl_pvt *)kcontrol->private_value;
info = (struct gb_audio_ctl_elem_info *)data->info;
if (!info) {
dev_err(module->dev, "NULL info for %s\n", uinfo->id.name);
return -EINVAL;
}
/* update uinfo */
uinfo->access = data->access;
uinfo->count = data->vcount;
uinfo->type = (