/*
* 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 const char *gbaudio_map_controlid(struct gbaudio_codec_info *gbcodec,
__u8 control_id, __u8 index)
{
struct gbaudio_control *control;
if (control_id == GBAUDIO_INVALID_ID)
return NULL;
list_for_each_entry(control, &gbcodec->codec_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, &gbcodec->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_codec_info *gbcodec,
const char *name)
{
struct gbaudio_widget *widget;
char widget_name[NAME_SIZE];
char prefix_name[NAME_SIZE];
snprintf(prefix_name, NAME_SIZE, "GB %d ", gbcodec->dev_id);
if (strncmp(name, prefix_name, strlen(prefix_name)))
return -EINVAL;
strlcpy(widget_name, name+strlen(prefix_name), NAME_SIZE);
dev_dbg(gbcodec->dev, "widget_name:%s, truncated widget_name:%s\n",
name, widget_name);
list_for_each_entry(widget, &gbcodec->widget_list, list) {
if (!strncmp(widget->name, widget_name, NAME_SIZE))
return widget->id;
}
return -EINVAL;
}
static const char *gbaudio_map_widgetid(struct gbaudio_codec_info *gbcodec,
__u8 widget_id)
{
struct gbaudio_widget *widget;
list_for_each_entry(widget, &gbcodec->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 snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct gbaudio_codec_info *gbcodec = snd_soc_codec_get_drvdata(codec);
data = (struct gbaudio_ctl_pvt *)kcontrol->private_value;
info = (struct gb_audio_ctl_elem_info *)data->info;
if (!info) {
dev_err(gbcodec->dev, "NULL info for %s\n", uinfo->id.name);
return -EINVAL;
}
/* update uinfo */
uinfo->access = data->access;
uinfo->count = data->vcount;
uinfo->type = (snd_ctl_elem_type_t)info->type;
switch (info->type) {
case GB_AUDIO_CTL_ELEM_TYPE_BOOLEAN:
case GB_AUDIO_CTL_ELEM_TYPE_INTEGER:
uinfo->value.integer.min = info->value.integer.min;
uinfo->value.integer.max = info->value.integer.max;
break;
case GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED:
max = info->value.enumerated.<