Skip to content

Commit 7c2280e

Browse files
committed
Minor SDCA Fixes
Merge series from Charles Keepax <ckeepax@opensource.cirrus.com>: A bit of a mixed bag of minor misc fixes, improve handling of volatile SDCA Controls, make some minor bug fixes to jack detect, improve the cache syncing by adding some more defaults, and improve some FDL error messages.
2 parents 55137f5 + 812ff1b commit 7c2280e

6 files changed

Lines changed: 170 additions & 36 deletions

File tree

include/sound/sdca_function.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,7 @@ struct sdca_control_range {
798798
* @sel: Identifier used for addressing.
799799
* @nbits: Number of bits used in the Control.
800800
* @values: Holds the Control value for constants and defaults.
801+
* @reset: Defined reset value for the Control.
801802
* @cn_list: A bitmask showing the valid Control Numbers within this Control,
802803
* Control Numbers typically represent channels.
803804
* @interrupt_position: SCDA interrupt line that will alert to changes on this
@@ -808,6 +809,7 @@ struct sdca_control_range {
808809
* @layers: Bitmask of access layers of the Control.
809810
* @deferrable: Indicates if the access to the Control can be deferred.
810811
* @has_default: Indicates the Control has a default value to be written.
812+
* @has_reset: Indicates the Control has a defined reset value.
811813
* @has_fixed: Indicates the Control only supports a single value.
812814
*/
813815
struct sdca_control {
@@ -816,6 +818,7 @@ struct sdca_control {
816818

817819
int nbits;
818820
int *values;
821+
int reset;
819822
u64 cn_list;
820823
int interrupt_position;
821824

@@ -827,6 +830,7 @@ struct sdca_control {
827830
bool deferrable;
828831
bool is_volatile;
829832
bool has_default;
833+
bool has_reset;
830834
bool has_fixed;
831835
};
832836

sound/soc/sdca/sdca_asoc.c

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/minmax.h>
1717
#include <linux/module.h>
1818
#include <linux/overflow.h>
19+
#include <linux/pm_runtime.h>
1920
#include <linux/regmap.h>
2021
#include <linux/soundwire/sdw_registers.h>
2122
#include <linux/string_helpers.h>
@@ -115,6 +116,41 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun
115116
}
116117
EXPORT_SYMBOL_NS(sdca_asoc_count_component, "SND_SOC_SDCA");
117118

119+
static int ge_put_enum_double(struct snd_kcontrol *kcontrol,
120+
struct snd_ctl_elem_value *ucontrol)
121+
{
122+
struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
123+
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
124+
struct device *dev = component->dev;
125+
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
126+
unsigned int *item = ucontrol->value.enumerated.item;
127+
unsigned int reg = e->reg;
128+
int ret;
129+
130+
reg &= ~SDW_SDCA_CTL_CSEL(0x3F);
131+
reg |= SDW_SDCA_CTL_CSEL(SDCA_CTL_GE_DETECTED_MODE);
132+
133+
ret = pm_runtime_resume_and_get(dev);
134+
if (ret < 0) {
135+
dev_err(dev, "failed to resume writing %s: %d\n",
136+
kcontrol->id.name, ret);
137+
return ret;
138+
}
139+
140+
ret = snd_soc_component_read(component, reg);
141+
pm_runtime_put(dev);
142+
if (ret < 0)
143+
return ret;
144+
else if (ret <= SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS)
145+
return -EBUSY;
146+
147+
ret = snd_soc_enum_item_to_val(e, item[0]);
148+
if (ret <= SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS)
149+
return -EINVAL;
150+
151+
return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
152+
}
153+
118154
static int entity_early_parse_ge(struct device *dev,
119155
struct sdca_function_data *function,
120156
struct sdca_entity *entity)
@@ -191,7 +227,7 @@ static int entity_early_parse_ge(struct device *dev,
191227
kctl->name = control_name;
192228
kctl->info = snd_soc_info_enum_double;
193229
kctl->get = snd_soc_dapm_get_enum_double;
194-
kctl->put = snd_soc_dapm_put_enum_double;
230+
kctl->put = ge_put_enum_double;
195231
kctl->private_value = (unsigned long)soc_enum;
196232

197233
entity->ge.kctl = kctl;
@@ -792,6 +828,48 @@ static int control_limit_kctl(struct device *dev,
792828
return 0;
793829
}
794830

831+
static int volatile_get_volsw(struct snd_kcontrol *kcontrol,
832+
struct snd_ctl_elem_value *ucontrol)
833+
{
834+
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
835+
struct device *dev = component->dev;
836+
int ret;
837+
838+
ret = pm_runtime_resume_and_get(dev);
839+
if (ret < 0) {
840+
dev_err(dev, "failed to resume reading %s: %d\n",
841+
kcontrol->id.name, ret);
842+
return ret;
843+
}
844+
845+
ret = snd_soc_get_volsw(kcontrol, ucontrol);
846+
847+
pm_runtime_put(dev);
848+
849+
return ret;
850+
}
851+
852+
static int volatile_put_volsw(struct snd_kcontrol *kcontrol,
853+
struct snd_ctl_elem_value *ucontrol)
854+
{
855+
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
856+
struct device *dev = component->dev;
857+
int ret;
858+
859+
ret = pm_runtime_resume_and_get(dev);
860+
if (ret < 0) {
861+
dev_err(dev, "failed to resume writing %s: %d\n",
862+
kcontrol->id.name, ret);
863+
return ret;
864+
}
865+
866+
ret = snd_soc_put_volsw(kcontrol, ucontrol);
867+
868+
pm_runtime_put(dev);
869+
870+
return ret;
871+
}
872+
795873
static int populate_control(struct device *dev,
796874
struct sdca_function_data *function,
797875
struct sdca_entity *entity,
@@ -849,8 +927,13 @@ static int populate_control(struct device *dev,
849927
(*kctl)->private_value = (unsigned long)mc;
850928
(*kctl)->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
851929
(*kctl)->info = snd_soc_info_volsw;
852-
(*kctl)->get = snd_soc_get_volsw;
853-
(*kctl)->put = snd_soc_put_volsw;
930+
if (control->is_volatile) {
931+
(*kctl)->get = volatile_get_volsw;
932+
(*kctl)->put = volatile_put_volsw;
933+
} else {
934+
(*kctl)->get = snd_soc_get_volsw;
935+
(*kctl)->put = snd_soc_put_volsw;
936+
}
854937

855938
if (readonly_control(control))
856939
(*kctl)->access = SNDRV_CTL_ELEM_ACCESS_READ;

sound/soc/sdca/sdca_fdl.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,7 @@ static int fdl_load_file(struct sdca_interrupt *interrupt,
256256
tmp->file_length != firmware->size) {
257257
dev_err(dev, "bad disk SWF size\n");
258258
} else if (!swf || swf->file_version <= tmp->file_version) {
259-
dev_dbg(dev, "using SWF from disk: %x-%x-%x\n",
260-
tmp->vendor_id, tmp->file_id, tmp->file_version);
259+
dev_dbg(dev, "using SWF from disk\n");
261260
swf = tmp;
262261
}
263262
}
@@ -267,6 +266,9 @@ static int fdl_load_file(struct sdca_interrupt *interrupt,
267266
return -ENOENT;
268267
}
269268

269+
dev_info(dev, "loading SWF: %x-%x-%x\n",
270+
swf->vendor_id, swf->file_id, swf->file_version);
271+
270272
ret = sdca_ump_write_message(dev, interrupt->device_regmap,
271273
interrupt->function_regmap,
272274
interrupt->function, interrupt->entity,

sound/soc/sdca/sdca_functions.c

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -911,10 +911,38 @@ static int find_sdca_control_value(struct device *dev, struct sdca_entity *entit
911911
return 0;
912912
}
913913

914-
/*
915-
* TODO: Add support for -cn- properties, allowing different channels to have
916-
* different defaults etc.
917-
*/
914+
static int find_sdca_control_reset(const struct sdca_entity *entity,
915+
struct sdca_control *control)
916+
{
917+
switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
918+
case SDCA_CTL_TYPE_S(FU, AGC):
919+
case SDCA_CTL_TYPE_S(FU, BASS_BOOST):
920+
case SDCA_CTL_TYPE_S(FU, LOUDNESS):
921+
case SDCA_CTL_TYPE_S(SMPU, TRIGGER_ENABLE):
922+
case SDCA_CTL_TYPE_S(GE, SELECTED_MODE):
923+
case SDCA_CTL_TYPE_S(TG, TONE_DIVIDER):
924+
case SDCA_CTL_TYPE_S(ENTITY_0, COMMIT_GROUP_MASK):
925+
control->has_reset = true;
926+
control->reset = 0;
927+
break;
928+
case SDCA_CTL_TYPE_S(XU, BYPASS):
929+
case SDCA_CTL_TYPE_S(MFPU, BYPASS):
930+
case SDCA_CTL_TYPE_S(FU, MUTE):
931+
case SDCA_CTL_TYPE_S(CX, CLOCK_SELECT):
932+
control->has_reset = true;
933+
control->reset = 1;
934+
break;
935+
case SDCA_CTL_TYPE_S(PDE, REQUESTED_PS):
936+
control->has_reset = true;
937+
control->reset = 3;
938+
break;
939+
default:
940+
break;
941+
}
942+
943+
return 0;
944+
}
945+
918946
static int find_sdca_entity_control(struct device *dev, struct sdca_entity *entity,
919947
struct fwnode_handle *control_node,
920948
struct sdca_control *control)
@@ -990,6 +1018,10 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti
9901018

9911019
control->is_volatile = find_sdca_control_volatile(entity, control);
9921020

1021+
ret = find_sdca_control_reset(entity, control);
1022+
if (ret)
1023+
return ret;
1024+
9931025
ret = find_sdca_control_range(dev, control_node, &control->range);
9941026
if (ret) {
9951027
dev_err(dev, "%s: control %#x: range missing: %d\n",
@@ -2033,6 +2065,7 @@ static int find_sdca_filesets(struct device *dev, struct sdw_slave *sdw,
20332065
num_sets = fwnode_property_count_u32(function_node,
20342066
"mipi-sdca-file-set-id-list");
20352067
if (num_sets == 0 || num_sets == -EINVAL) {
2068+
dev_dbg(dev, "%pfwP: file set id list missing\n", function_node);
20362069
return 0;
20372070
} else if (num_sets < 0) {
20382071
dev_err(dev, "%pfwP: failed to read file set list: %d\n",

sound/soc/sdca/sdca_jack.c

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,11 @@ int sdca_jack_process(struct sdca_interrupt *interrupt)
4141
struct jack_state *state = interrupt->priv;
4242
struct snd_kcontrol *kctl = state->kctl;
4343
struct snd_ctl_elem_value *ucontrol __free(kfree) = NULL;
44-
struct soc_enum *soc_enum;
4544
unsigned int reg, val;
4645
int ret;
4746

47+
guard(rwsem_write)(rwsem);
48+
4849
if (!kctl) {
4950
const char *name __free(kfree) = kasprintf(GFP_KERNEL, "%s %s",
5051
interrupt->entity->label,
@@ -54,16 +55,12 @@ int sdca_jack_process(struct sdca_interrupt *interrupt)
5455
return -ENOMEM;
5556

5657
kctl = snd_soc_component_get_kcontrol(component, name);
57-
if (!kctl) {
58+
if (!kctl)
5859
dev_dbg(dev, "control not found: %s\n", name);
59-
return -ENOENT;
60-
}
61-
62-
state->kctl = kctl;
60+
else
61+
state->kctl = kctl;
6362
}
6463

65-
soc_enum = (struct soc_enum *)kctl->private_value;
66-
6764
reg = SDW_SDCA_CTL(interrupt->function->desc->adr, interrupt->entity->id,
6865
interrupt->control->sel, 0);
6966

@@ -73,13 +70,12 @@ int sdca_jack_process(struct sdca_interrupt *interrupt)
7370
return ret;
7471
}
7572

73+
reg = SDW_SDCA_CTL(interrupt->function->desc->adr, interrupt->entity->id,
74+
SDCA_CTL_GE_SELECTED_MODE, 0);
75+
7676
switch (val) {
7777
case SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS:
7878
case SDCA_DETECTED_MODE_JACK_UNKNOWN:
79-
reg = SDW_SDCA_CTL(interrupt->function->desc->adr,
80-
interrupt->entity->id,
81-
SDCA_CTL_GE_SELECTED_MODE, 0);
82-
8379
/*
8480
* Selected mode is not normally marked as volatile register
8581
* (RW), but here force a read from the hardware. If the
@@ -100,21 +96,29 @@ int sdca_jack_process(struct sdca_interrupt *interrupt)
10096

10197
dev_dbg(dev, "%s: %#x\n", interrupt->name, val);
10298

103-
ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL);
104-
if (!ucontrol)
105-
return -ENOMEM;
99+
if (kctl) {
100+
struct soc_enum *soc_enum = (struct soc_enum *)kctl->private_value;
101+
102+
ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL);
103+
if (!ucontrol)
104+
return -ENOMEM;
106105

107-
ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(soc_enum, val);
106+
ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(soc_enum, val);
108107

109-
down_write(rwsem);
110-
ret = kctl->put(kctl, ucontrol);
111-
up_write(rwsem);
112-
if (ret < 0) {
113-
dev_err(dev, "failed to update selected mode: %d\n", ret);
114-
return ret;
115-
}
108+
ret = snd_soc_dapm_put_enum_double(kctl, ucontrol);
109+
if (ret < 0) {
110+
dev_err(dev, "failed to update selected mode: %d\n", ret);
111+
return ret;
112+
}
116113

117-
snd_ctl_notify(card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
114+
snd_ctl_notify(card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
115+
} else {
116+
ret = regmap_write(interrupt->function_regmap, reg, val);
117+
if (ret) {
118+
dev_err(dev, "failed to write selected mode: %d\n", ret);
119+
return ret;
120+
}
121+
}
118122

119123
return sdca_jack_report(interrupt);
120124
}

sound/soc/sdca/sdca_regmap.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,8 @@ int sdca_regmap_count_constants(struct device *dev,
218218
struct sdca_entity *entity = &function->entities[i];
219219

220220
for (j = 0; j < entity->num_controls; j++) {
221-
if (entity->controls[j].mode == SDCA_ACCESS_MODE_DC)
221+
if (entity->controls[j].mode == SDCA_ACCESS_MODE_DC ||
222+
entity->controls[j].has_reset)
222223
nconsts += hweight64(entity->controls[j].cn_list);
223224
}
224225
}
@@ -255,7 +256,8 @@ int sdca_regmap_populate_constants(struct device *dev,
255256
struct sdca_control *control = &entity->controls[j];
256257
int cn;
257258

258-
if (control->mode != SDCA_ACCESS_MODE_DC)
259+
if (control->mode != SDCA_ACCESS_MODE_DC &&
260+
!control->has_reset)
259261
continue;
260262

261263
l = 0;
@@ -264,7 +266,10 @@ int sdca_regmap_populate_constants(struct device *dev,
264266
consts[k].reg = SDW_SDCA_CTL(function->desc->adr,
265267
entity->id,
266268
control->sel, cn);
267-
consts[k].def = control->values[l];
269+
if (control->mode == SDCA_ACCESS_MODE_DC)
270+
consts[k].def = control->values[l];
271+
else
272+
consts[k].def = control->reset;
268273
k++;
269274
l++;
270275
}
@@ -306,6 +311,9 @@ static int populate_control_defaults(struct device *dev, struct regmap *regmap,
306311

307312
i++;
308313
} else if (!control->is_volatile) {
314+
if (control->has_reset)
315+
regcache_drop_region(regmap, reg, reg);
316+
309317
ret = regmap_read(regmap, reg, &val);
310318
if (ret) {
311319
dev_err(dev, "Failed to read initial %#x: %d\n",

0 commit comments

Comments
 (0)