summaryrefslogtreecommitdiff
path: root/sound/soc/sdca/sdca_functions.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sdca/sdca_functions.c')
-rw-r--r--sound/soc/sdca/sdca_functions.c310
1 files changed, 275 insertions, 35 deletions
diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c
index 0ccb6775f4de..5a1f120487ef 100644
--- a/sound/soc/sdca/sdca_functions.c
+++ b/sound/soc/sdca/sdca_functions.c
@@ -6,8 +6,6 @@
* https://www.mipi.org/mipi-sdca-v1-0-download
*/
-#define dev_fmt(fmt) "%s: " fmt, __func__
-
#include <linux/acpi.h>
#include <linux/byteorder/generic.h>
#include <linux/cleanup.h>
@@ -16,6 +14,7 @@
#include <linux/module.h>
#include <linux/property.h>
#include <linux/soundwire/sdw.h>
+#include <linux/string.h>
#include <linux/types.h>
#include <sound/sdca.h>
#include <sound/sdca_function.h>
@@ -79,6 +78,8 @@ static const char *get_sdca_function_name(u32 function_type)
return SDCA_FUNCTION_TYPE_SPEAKER_MIC_NAME;
case SDCA_FUNCTION_TYPE_RJ:
return SDCA_FUNCTION_TYPE_RJ_NAME;
+ case SDCA_FUNCTION_TYPE_COMPANION_AMP:
+ return SDCA_FUNCTION_TYPE_COMPANION_AMP_NAME;
case SDCA_FUNCTION_TYPE_IMP_DEF:
return SDCA_FUNCTION_TYPE_IMP_DEF_NAME;
default:
@@ -179,11 +180,11 @@ static int find_sdca_function(struct acpi_device *adev, void *data)
*/
void sdca_lookup_functions(struct sdw_slave *slave)
{
- struct device *dev = &slave->dev;
- struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
+ struct device *sdev = &slave->dev;
+ struct acpi_device *adev = to_acpi_device_node(sdev->fwnode);
if (!adev) {
- dev_info(dev, "no matching ACPI device found, ignoring peripheral\n");
+ dev_info(sdev, "no matching ACPI device found, ignoring peripheral\n");
return;
}
@@ -779,6 +780,62 @@ find_sdca_control_datatype(const struct sdca_entity *entity,
}
}
+static bool find_sdca_control_volatile(const struct sdca_entity *entity,
+ const struct sdca_control *control)
+{
+ switch (control->mode) {
+ case SDCA_ACCESS_MODE_DC:
+ return false;
+ case SDCA_ACCESS_MODE_RO:
+ case SDCA_ACCESS_MODE_RW1S:
+ case SDCA_ACCESS_MODE_RW1C:
+ return true;
+ default:
+ break;
+ }
+
+ switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
+ case SDCA_CTL_TYPE_S(XU, FDL_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(XU, FDL_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(XU, FDL_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(XU, FDL_STATUS):
+ case SDCA_CTL_TYPE_S(XU, FDL_HOST_REQUEST):
+ case SDCA_CTL_TYPE_S(SPE, AUTHTX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SPE, AUTHRX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(MFPU, AE_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SMPU, HIST_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SMPU, DTODTX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SMPU, DTODRX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SAPU, DTODTX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SAPU, DTODRX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(HIDE, HIDRX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGELENGTH):
+ return true;
+ default:
+ return false;
+ }
+}
+
static int find_sdca_control_range(struct device *dev,
struct fwnode_handle *control_node,
struct sdca_control_range *range)
@@ -931,6 +988,8 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti
break;
}
+ control->is_volatile = find_sdca_control_volatile(entity, control);
+
ret = find_sdca_control_range(dev, control_node, &control->range);
if (ret) {
dev_err(dev, "%s: control %#x: range missing: %d\n",
@@ -953,10 +1012,10 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti
control->type = find_sdca_control_datatype(entity, control);
control->nbits = find_sdca_control_bits(entity, control);
- dev_info(dev, "%s: %s: control %#x mode %#x layers %#x cn %#llx int %d %s\n",
- entity->label, control->label, control->sel,
- control->mode, control->layers, control->cn_list,
- control->interrupt_position, control->deferrable ? "deferrable" : "");
+ dev_dbg(dev, "%s: %s: control %#x mode %#x layers %#x cn %#llx int %d %s\n",
+ entity->label, control->label, control->sel,
+ control->mode, control->layers, control->cn_list,
+ control->interrupt_position, control->deferrable ? "deferrable" : "");
return 0;
}
@@ -1062,6 +1121,14 @@ static int find_sdca_entity_iot(struct device *dev,
terminal->type = tmp;
terminal->is_dataport = find_sdca_iot_dataport(terminal);
+ if (!terminal->is_dataport) {
+ const char *type_name = sdca_find_terminal_name(terminal->type);
+
+ if (type_name)
+ entity->label = devm_kasprintf(dev, GFP_KERNEL, "%s %s",
+ entity->label, type_name);
+ }
+
ret = fwnode_property_read_u32(entity_node,
"mipi-sdca-terminal-reference-number", &tmp);
if (!ret)
@@ -1077,9 +1144,9 @@ static int find_sdca_entity_iot(struct device *dev,
if (!ret)
terminal->num_transducer = tmp;
- dev_info(dev, "%s: terminal type %#x ref %#x conn %#x count %d\n",
- entity->label, terminal->type, terminal->reference,
- terminal->connector, terminal->num_transducer);
+ dev_dbg(dev, "%s: terminal type %#x ref %#x conn %#x count %d\n",
+ entity->label, terminal->type, terminal->reference,
+ terminal->connector, terminal->num_transducer);
return 0;
}
@@ -1105,8 +1172,8 @@ static int find_sdca_entity_cs(struct device *dev,
if (!ret)
clock->max_delay = tmp;
- dev_info(dev, "%s: clock type %#x delay %d\n", entity->label,
- clock->type, clock->max_delay);
+ dev_dbg(dev, "%s: clock type %#x delay %d\n", entity->label,
+ clock->type, clock->max_delay);
return 0;
}
@@ -1157,8 +1224,8 @@ static int find_sdca_entity_pde(struct device *dev,
delays[i].to_ps = delay_list[j++];
delays[i].us = delay_list[j++];
- dev_info(dev, "%s: from %#x to %#x delay %dus\n", entity->label,
- delays[i].from_ps, delays[i].to_ps, delays[i].us);
+ dev_dbg(dev, "%s: from %#x to %#x delay %dus\n", entity->label,
+ delays[i].from_ps, delays[i].to_ps, delays[i].us);
}
power->num_max_delay = num_delays;
@@ -1254,7 +1321,8 @@ bad_list:
}
static int
-find_sdca_entity_hide(struct device *dev, struct fwnode_handle *function_node,
+find_sdca_entity_hide(struct device *dev, struct sdw_slave *sdw,
+ struct fwnode_handle *function_node,
struct fwnode_handle *entity_node, struct sdca_entity *entity)
{
struct sdca_entity_hide *hide = &entity->hide;
@@ -1263,7 +1331,7 @@ find_sdca_entity_hide(struct device *dev, struct fwnode_handle *function_node,
unsigned char *report_desc = NULL;
ret = fwnode_property_read_u32(entity_node,
- "mipi-sdca-RxUMP-ownership-transition-maxdelay", &delay);
+ "mipi-sdca-RxUMP-ownership-transition-max-delay", &delay);
if (!ret)
hide->max_delay = delay;
@@ -1329,7 +1397,7 @@ find_sdca_entity_hide(struct device *dev, struct fwnode_handle *function_node,
report_desc, nval);
/* add HID device */
- ret = sdca_add_hid_device(dev, entity);
+ ret = sdca_add_hid_device(dev, sdw, entity);
if (ret) {
dev_err(dev, "%pfwP: failed to add HID device: %d\n", entity_node, ret);
return ret;
@@ -1340,7 +1408,29 @@ find_sdca_entity_hide(struct device *dev, struct fwnode_handle *function_node,
return 0;
}
-static int find_sdca_entity(struct device *dev,
+static int find_sdca_entity_xu(struct device *dev,
+ struct fwnode_handle *entity_node,
+ struct sdca_entity *entity)
+{
+ struct sdca_entity_xu *xu = &entity->xu;
+ u32 tmp;
+ int ret;
+
+ ret = fwnode_property_read_u32(entity_node,
+ "mipi-sdca-RxUMP-ownership-transition-max-delay",
+ &tmp);
+ if (!ret)
+ xu->max_delay = tmp;
+
+ ret = fwnode_property_read_u32(entity_node, "mipi-sdca-FDL-reset-mechanism",
+ &tmp);
+ if (!ret)
+ xu->reset_mechanism = tmp;
+
+ return 0;
+}
+
+static int find_sdca_entity(struct device *dev, struct sdw_slave *sdw,
struct fwnode_handle *function_node,
struct fwnode_handle *entity_node,
struct sdca_entity *entity)
@@ -1364,14 +1454,17 @@ static int find_sdca_entity(struct device *dev,
entity->type = tmp;
- dev_info(dev, "%s: entity %#x type %#x\n",
- entity->label, entity->id, entity->type);
+ dev_dbg(dev, "%s: entity %#x type %#x\n",
+ entity->label, entity->id, entity->type);
switch (entity->type) {
case SDCA_ENTITY_TYPE_IT:
case SDCA_ENTITY_TYPE_OT:
ret = find_sdca_entity_iot(dev, entity_node, entity);
break;
+ case SDCA_ENTITY_TYPE_XU:
+ ret = find_sdca_entity_xu(dev, entity_node, entity);
+ break;
case SDCA_ENTITY_TYPE_CS:
ret = find_sdca_entity_cs(dev, entity_node, entity);
break;
@@ -1382,7 +1475,8 @@ static int find_sdca_entity(struct device *dev,
ret = find_sdca_entity_ge(dev, entity_node, entity);
break;
case SDCA_ENTITY_TYPE_HIDE:
- ret = find_sdca_entity_hide(dev, function_node, entity_node, entity);
+ ret = find_sdca_entity_hide(dev, sdw, function_node,
+ entity_node, entity);
break;
default:
break;
@@ -1397,7 +1491,7 @@ static int find_sdca_entity(struct device *dev,
return 0;
}
-static int find_sdca_entities(struct device *dev,
+static int find_sdca_entities(struct device *dev, struct sdw_slave *sdw,
struct fwnode_handle *function_node,
struct sdca_function_data *function)
{
@@ -1449,7 +1543,8 @@ static int find_sdca_entities(struct device *dev,
return -EINVAL;
}
- ret = find_sdca_entity(dev, function_node, entity_node, &entities[i]);
+ ret = find_sdca_entity(dev, sdw, function_node,
+ entity_node, &entities[i]);
fwnode_handle_put(entity_node);
if (ret)
return ret;
@@ -1479,7 +1574,7 @@ static struct sdca_entity *find_sdca_entity_by_label(struct sdca_function_data *
for (i = 0; i < function->num_entities; i++) {
struct sdca_entity *entity = &function->entities[i];
- if (!strcmp(entity->label, entity_label))
+ if (!strncmp(entity->label, entity_label, strlen(entity_label)))
return entity;
}
@@ -1535,7 +1630,7 @@ static int find_sdca_entity_connection_iot(struct device *dev,
terminal->clock = clock_entity;
- dev_info(dev, "%s -> %s\n", clock_entity->label, entity->label);
+ dev_dbg(dev, "%s -> %s\n", clock_entity->label, entity->label);
fwnode_handle_put(clock_node);
return 0;
@@ -1585,7 +1680,7 @@ static int find_sdca_entity_connection_pde(struct device *dev,
return -EINVAL;
}
- dev_info(dev, "%s -> %s\n", managed[i]->label, entity->label);
+ dev_dbg(dev, "%s -> %s\n", managed[i]->label, entity->label);
}
power->num_managed = num_managed;
@@ -1720,7 +1815,7 @@ static int find_sdca_entity_connection(struct device *dev,
pins[i] = connected_entity;
- dev_info(dev, "%s -> %s\n", connected_entity->label, entity->label);
+ dev_dbg(dev, "%s -> %s\n", connected_entity->label, entity->label);
i++;
fwnode_handle_put(connected_node);
@@ -1805,8 +1900,8 @@ static int find_sdca_cluster_channel(struct device *dev,
channel->relationship = tmp;
- dev_info(dev, "cluster %#x: channel id %#x purpose %#x relationship %#x\n",
- cluster->id, channel->id, channel->purpose, channel->relationship);
+ dev_dbg(dev, "cluster %#x: channel id %#x purpose %#x relationship %#x\n",
+ cluster->id, channel->id, channel->purpose, channel->relationship);
return 0;
}
@@ -1925,15 +2020,105 @@ static int find_sdca_clusters(struct device *dev,
return 0;
}
+static int find_sdca_filesets(struct device *dev, struct sdw_slave *sdw,
+ struct fwnode_handle *function_node,
+ struct sdca_function_data *function)
+{
+ static const int mult_fileset = 3;
+ char fileset_name[SDCA_PROPERTY_LENGTH];
+ u32 *filesets_list __free(kfree) = NULL;
+ struct sdca_fdl_set *sets;
+ int num_sets;
+ int i, j;
+
+ num_sets = fwnode_property_count_u32(function_node,
+ "mipi-sdca-file-set-id-list");
+ if (num_sets == 0 || num_sets == -EINVAL) {
+ return 0;
+ } else if (num_sets < 0) {
+ dev_err(dev, "%pfwP: failed to read file set list: %d\n",
+ function_node, num_sets);
+ return num_sets;
+ }
+
+ filesets_list = kcalloc(num_sets, sizeof(u32), GFP_KERNEL);
+ if (!filesets_list)
+ return -ENOMEM;
+
+ fwnode_property_read_u32_array(function_node, "mipi-sdca-file-set-id-list",
+ filesets_list, num_sets);
+
+ sets = devm_kcalloc(dev, num_sets, sizeof(struct sdca_fdl_set), GFP_KERNEL);
+ if (!sets)
+ return -ENOMEM;
+
+ for (i = 0; i < num_sets; i++) {
+ u32 *fileset_entries __free(kfree) = NULL;
+ struct sdca_fdl_set *set = &sets[i];
+ struct sdca_fdl_file *files;
+ int num_files, num_entries;
+
+ snprintf(fileset_name, sizeof(fileset_name),
+ "mipi-sdca-file-set-id-0x%X", filesets_list[i]);
+
+ num_entries = fwnode_property_count_u32(function_node, fileset_name);
+ if (num_entries <= 0) {
+ dev_err(dev, "%pfwP: file set %d missing entries: %d\n",
+ function_node, filesets_list[i], num_entries);
+ return -EINVAL;
+ } else if (num_entries % mult_fileset != 0) {
+ dev_err(dev, "%pfwP: file set %d files not multiple of %d\n",
+ function_node, filesets_list[i], mult_fileset);
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "fileset: %#x\n", filesets_list[i]);
+
+ files = devm_kcalloc(dev, num_entries / mult_fileset,
+ sizeof(struct sdca_fdl_file), GFP_KERNEL);
+ if (!files)
+ return -ENOMEM;
+
+ fileset_entries = kcalloc(num_entries, sizeof(u32), GFP_KERNEL);
+ if (!fileset_entries)
+ return -ENOMEM;
+
+ fwnode_property_read_u32_array(function_node, fileset_name,
+ fileset_entries, num_entries);
+
+ for (j = 0, num_files = 0; j < num_entries; num_files++) {
+ struct sdca_fdl_file *file = &files[num_files];
+
+ file->vendor_id = fileset_entries[j++];
+ file->file_id = fileset_entries[j++];
+ file->fdl_offset = fileset_entries[j++];
+
+ dev_dbg(dev, "file: %#x, vendor: %#x, offset: %#x\n",
+ file->file_id, file->vendor_id, file->fdl_offset);
+ }
+
+ set->id = filesets_list[i];
+ set->num_files = num_files;
+ set->files = files;
+ }
+
+ function->fdl_data.swft = sdw->sdca_data.swft;
+ function->fdl_data.num_sets = num_sets;
+ function->fdl_data.sets = sets;
+
+ return 0;
+}
+
/**
* sdca_parse_function - parse ACPI DisCo for a Function
* @dev: Pointer to device against which function data will be allocated.
+ * @sdw: SoundWire slave device to be processed.
* @function_desc: Pointer to the Function short descriptor.
* @function: Pointer to the Function information, to be populated.
*
* Return: Returns 0 for success.
*/
-int sdca_parse_function(struct device *dev,
+int sdca_parse_function(struct device *dev, struct sdw_slave *sdw,
struct sdca_function_desc *function_desc,
struct sdca_function_data *function)
{
@@ -1947,14 +2132,20 @@ int sdca_parse_function(struct device *dev,
if (!ret)
function->busy_max_delay = tmp;
- dev_info(dev, "%pfwP: name %s delay %dus\n", function->desc->node,
- function->desc->name, function->busy_max_delay);
+ ret = fwnode_property_read_u32(function_desc->node,
+ "mipi-sdca-function-reset-max-delay", &tmp);
+ if (!ret)
+ function->reset_max_delay = tmp;
+
+ dev_dbg(dev, "%pfwP: name %s busy delay %dus reset delay %dus\n",
+ function->desc->node, function->desc->name,
+ function->busy_max_delay, function->reset_max_delay);
ret = find_sdca_init_table(dev, function_desc->node, function);
if (ret)
return ret;
- ret = find_sdca_entities(dev, function_desc->node, function);
+ ret = find_sdca_entities(dev, sdw, function_desc->node, function);
if (ret)
return ret;
@@ -1966,10 +2157,59 @@ int sdca_parse_function(struct device *dev,
if (ret < 0)
return ret;
+ ret = find_sdca_filesets(dev, sdw, function_desc->node, function);
+ if (ret)
+ return ret;
+
return 0;
}
EXPORT_SYMBOL_NS(sdca_parse_function, "SND_SOC_SDCA");
+const char *sdca_find_terminal_name(enum sdca_terminal_type type)
+{
+ switch (type) {
+ case SDCA_TERM_TYPE_LINEIN_STEREO:
+ return SDCA_TERM_TYPE_LINEIN_STEREO_NAME;
+ case SDCA_TERM_TYPE_LINEIN_FRONT_LR:
+ return SDCA_TERM_TYPE_LINEIN_FRONT_LR_NAME;
+ case SDCA_TERM_TYPE_LINEIN_CENTER_LFE:
+ return SDCA_TERM_TYPE_LINEIN_CENTER_LFE_NAME;
+ case SDCA_TERM_TYPE_LINEIN_SURROUND_LR:
+ return SDCA_TERM_TYPE_LINEIN_SURROUND_LR_NAME;
+ case SDCA_TERM_TYPE_LINEIN_REAR_LR:
+ return SDCA_TERM_TYPE_LINEIN_REAR_LR_NAME;
+ case SDCA_TERM_TYPE_LINEOUT_STEREO:
+ return SDCA_TERM_TYPE_LINEOUT_STEREO_NAME;
+ case SDCA_TERM_TYPE_LINEOUT_FRONT_LR:
+ return SDCA_TERM_TYPE_LINEOUT_FRONT_LR_NAME;
+ case SDCA_TERM_TYPE_LINEOUT_CENTER_LFE:
+ return SDCA_TERM_TYPE_LINEOUT_CENTER_LFE_NAME;
+ case SDCA_TERM_TYPE_LINEOUT_SURROUND_LR:
+ return SDCA_TERM_TYPE_LINEOUT_SURROUND_LR_NAME;
+ case SDCA_TERM_TYPE_LINEOUT_REAR_LR:
+ return SDCA_TERM_TYPE_LINEOUT_REAR_LR_NAME;
+ case SDCA_TERM_TYPE_MIC_JACK:
+ return SDCA_TERM_TYPE_MIC_JACK_NAME;
+ case SDCA_TERM_TYPE_STEREO_JACK:
+ return SDCA_TERM_TYPE_STEREO_JACK_NAME;
+ case SDCA_TERM_TYPE_FRONT_LR_JACK:
+ return SDCA_TERM_TYPE_FRONT_LR_JACK_NAME;
+ case SDCA_TERM_TYPE_CENTER_LFE_JACK:
+ return SDCA_TERM_TYPE_CENTER_LFE_JACK_NAME;
+ case SDCA_TERM_TYPE_SURROUND_LR_JACK:
+ return SDCA_TERM_TYPE_SURROUND_LR_JACK_NAME;
+ case SDCA_TERM_TYPE_REAR_LR_JACK:
+ return SDCA_TERM_TYPE_REAR_LR_JACK_NAME;
+ case SDCA_TERM_TYPE_HEADPHONE_JACK:
+ return SDCA_TERM_TYPE_HEADPHONE_JACK_NAME;
+ case SDCA_TERM_TYPE_HEADSET_JACK:
+ return SDCA_TERM_TYPE_HEADSET_JACK_NAME;
+ default:
+ return NULL;
+ }
+}
+EXPORT_SYMBOL_NS(sdca_find_terminal_name, "SND_SOC_SDCA");
+
struct sdca_control *sdca_selector_find_control(struct device *dev,
struct sdca_entity *entity,
const int sel)