{"id":2230087,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2230087/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-gpio/patch/20260429074356.118420-16-herve.codina@bootlin.com/","project":{"id":42,"url":"http://patchwork.ozlabs.org/api/1.1/projects/42/?format=json","name":"Linux GPIO development","link_name":"linux-gpio","list_id":"linux-gpio.vger.kernel.org","list_email":"linux-gpio@vger.kernel.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20260429074356.118420-16-herve.codina@bootlin.com>","date":"2026-04-29T07:43:51","name":"[v2,15/17] ASoC: simple-amplifier: gpio-audio-amp: Add support for gain-labels","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"6808964f559ba5c2514dadda46813f684dbe6105","submitter":{"id":81983,"url":"http://patchwork.ozlabs.org/api/1.1/people/81983/?format=json","name":"Herve Codina","email":"herve.codina@bootlin.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-gpio/patch/20260429074356.118420-16-herve.codina@bootlin.com/mbox/","series":[{"id":502009,"url":"http://patchwork.ozlabs.org/api/1.1/series/502009/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-gpio/list/?series=502009","date":"2026-04-29T07:43:41","name":"ASoC: Add support for GPIOs driven amplifiers","version":2,"mbox":"http://patchwork.ozlabs.org/series/502009/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2230087/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2230087/checks/","tags":{},"headers":{"Return-Path":"\n <linux-gpio+bounces-35772-incoming=patchwork.ozlabs.org@vger.kernel.org>","X-Original-To":["incoming@patchwork.ozlabs.org","linux-gpio@vger.kernel.org"],"Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=bootlin.com header.i=@bootlin.com header.a=rsa-sha256\n header.s=dkim header.b=WjCwr/0L;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c09:e001:a7::12fc:5321; helo=sto.lore.kernel.org;\n envelope-from=linux-gpio+bounces-35772-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com\n header.b=\"WjCwr/0L\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=185.246.85.4","smtp.subspace.kernel.org;\n dmarc=pass (p=reject dis=none) header.from=bootlin.com","smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=bootlin.com"],"Received":["from sto.lore.kernel.org (sto.lore.kernel.org\n [IPv6:2600:3c09:e001:a7::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g58Y36lQsz1yHv\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 29 Apr 2026 17:47:51 +1000 (AEST)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sto.lore.kernel.org (Postfix) with ESMTP id DC9343015F9E\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 29 Apr 2026 07:46:09 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 3C72D3BBA15;\n\tWed, 29 Apr 2026 07:44:54 +0000 (UTC)","from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 5371F3AC0F9;\n\tWed, 29 Apr 2026 07:44:52 +0000 (UTC)","from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233])\n\tby smtpout-03.galae.net (Postfix) with ESMTPS id 0B26E4E42ADE;\n\tWed, 29 Apr 2026 07:44:51 +0000 (UTC)","from mail.galae.net (mail.galae.net [212.83.136.155])\n\tby smtpout-01.galae.net (Postfix) with ESMTPS id CF5BA601DF;\n\tWed, 29 Apr 2026 07:44:50 +0000 (UTC)","from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon)\n with ESMTPSA id C59911072989E;\n\tWed, 29 Apr 2026 09:44:47 +0200 (CEST)"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1777448694; cv=none;\n b=txzrCSTMHERzf7Cte/TWdWEJHVv2rZM9niUOi+7M6z9INDTXn4SWHotT/LthkydfMQ5qc1z7aWRXzVNARv8ckGluAZ2m0uodf/fzBtoO2NFlFUXwS2iXxn1DmH7qnxDClte36X4mY8dGhx8/kBBpbGvUY7oq9QeMbT3WxXAjwgk=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1777448694; c=relaxed/simple;\n\tbh=iKc3QYrFOcmY1MCPB4FxrTH+D7zAdtAOJ4RcBhuIqH4=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=mR6rSNgo+9G79u2NCRTrpPKdEkf9TkYahBZ3p2aSlrdsfgSGaGgYmsXc3RKVeBZk9ido00gtKHXkh0hJYkJej3MnPmk1WNGUTS2NQWCsgyQVJS7W4wZeuivMRqrJ50HVir1yiI/O7c+14bu5PjD1JzVcJuSHlRFE8oV6Y8CjpfM=","ARC-Authentication-Results":"i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=reject dis=none) header.from=bootlin.com;\n spf=pass smtp.mailfrom=bootlin.com;\n dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com\n header.b=WjCwr/0L; arc=none smtp.client-ip=185.246.85.4","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim;\n\tt=1777448689; h=from:subject:date:message-id:to:cc:mime-version:\n\t content-transfer-encoding:in-reply-to:references;\n\tbh=pcpQ7WpaW4lGxE92Wx2KSCv7DhOVSwNrRADnBFLqbNw=;\n\tb=WjCwr/0LnWUZZTL5k5bAYml9YJxUC4039wCuyoN1ASIaSwv0XBuFVqnN05FCvzLcbyYMmZ\n\tStjiDSBnj5y//dSMMOhkWebV+/7Uvt0pGloG/kFHzCv8j1ZEwM3in6oI47se9FBGTGRfa0\n\tfENuXSYV3AIWTs4wLShDvTsDBUYISYOv7NJtChk1vwHGlAt1HyLaNi1RftoZHcVvmT17ee\n\tqWoynWSF/4T9G6mGVe+6PKTy/Xm8hTPJddKw06vO2skfhKPp9LXAEcHAdpraMti2cqSgK6\n\tnCaSU9ikhDt7Eh0RdLk4RN5rg6pVNRB0F02TFtKbpAKXhmTKptqCOmQy9CEgaQ==","From":"Herve Codina <herve.codina@bootlin.com>","To":"Herve Codina <herve.codina@bootlin.com>,\n\tBartosz Golaszewski <brgl@kernel.org>,\n\tLinus Walleij <linusw@kernel.org>,\n\tLiam Girdwood <lgirdwood@gmail.com>,\n\tMark Brown <broonie@kernel.org>,\n\tRob Herring <robh@kernel.org>,\n\tKrzysztof Kozlowski <krzk+dt@kernel.org>,\n\tConor Dooley <conor+dt@kernel.org>,\n\tSaravana Kannan <saravanak@kernel.org>,\n\tJaroslav Kysela <perex@perex.cz>,\n\tTakashi Iwai <tiwai@suse.com>","Cc":"linux-sound@vger.kernel.org,\n\tlinux-gpio@vger.kernel.org,\n\tdevicetree@vger.kernel.org,\n\tlinux-kernel@vger.kernel.org,\n\tChristophe Leroy <christophe.leroy@csgroup.eu>,\n\tThomas Petazzoni <thomas.petazzoni@bootlin.com>","Subject":"[PATCH v2 15/17] ASoC: simple-amplifier: gpio-audio-amp: Add support\n for gain-labels","Date":"Wed, 29 Apr 2026 09:43:51 +0200","Message-ID":"<20260429074356.118420-16-herve.codina@bootlin.com>","X-Mailer":"git-send-email 2.53.0","In-Reply-To":"<20260429074356.118420-1-herve.codina@bootlin.com>","References":"<20260429074356.118420-1-herve.codina@bootlin.com>","Precedence":"bulk","X-Mailing-List":"linux-gpio@vger.kernel.org","List-Id":"<linux-gpio.vger.kernel.org>","List-Subscribe":"<mailto:linux-gpio+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:linux-gpio+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-Last-TLS-Session-Version":"TLSv1.3"},"content":"The possible gain values can be described using labels instead of gain\nvalues in dB.\n\nThose different labels are attached to a gpio values using the\ngain-labels property.\n\nUsing the gain-labels description is mutually exclusive with gain-ranges\ndescription used to describe the relationship between gpios values and\ngain values.\n\nHandle the gain-labels description and the related kcontrol.\n\nSigned-off-by: Herve Codina <herve.codina@bootlin.com>\n---\n sound/soc/codecs/simple-amplifier.c | 112 +++++++++++++++++++++++++++-\n 1 file changed, 109 insertions(+), 3 deletions(-)","diff":"diff --git a/sound/soc/codecs/simple-amplifier.c b/sound/soc/codecs/simple-amplifier.c\nindex b25332a76549..a7fbfcc4ec0d 100644\n--- a/sound/soc/codecs/simple-amplifier.c\n+++ b/sound/soc/codecs/simple-amplifier.c\n@@ -41,9 +41,15 @@ struct simple_amp_ranges {\n \tstruct simple_amp_range *tab_ranges;\n };\n \n+struct simple_amp_labels {\n+\tunsigned int nb_labels;\n+\tconst char **tab_labels;\n+};\n+\n enum simple_amp_mode {\n \tSIMPLE_AMP_MODE_NONE,\n \tSIMPLE_AMP_MODE_RANGES,\n+\tSIMPLE_AMP_MODE_LABELS,\n };\n \n struct simple_amp_multi {\n@@ -53,7 +59,10 @@ struct simple_amp_multi {\n \tconst char *control_name;\n \tunsigned int *tlv_array;\n \tenum simple_amp_mode mode;\n-\tstruct simple_amp_ranges ranges;\n+\tunion {\n+\t\tstruct simple_amp_ranges ranges;\n+\t\tstruct simple_amp_labels labels;\n+\t};\n };\n \n struct simple_amp_data {\n@@ -312,6 +321,45 @@ static int simple_amp_multi_kctrl_int_put(struct snd_kcontrol *kcontrol,\n \treturn 1; /* The value changed */\n }\n \n+static int simple_amp_multi_kctrl_enum_info(struct snd_kcontrol *kcontrol,\n+\t\t\t\t\t    struct snd_ctl_elem_info *uinfo)\n+{\n+\tstruct simple_amp_multi *multi = (struct simple_amp_multi *)kcontrol->private_value;\n+\n+\treturn snd_ctl_enum_info(uinfo, 1, multi->labels.nb_labels,\n+\t\t\t\t multi->labels.tab_labels);\n+}\n+\n+static int simple_amp_multi_kctrl_enum_get(struct snd_kcontrol *kcontrol,\n+\t\t\t\t\t   struct snd_ctl_elem_value *ucontrol)\n+{\n+\tstruct simple_amp_multi *multi = (struct simple_amp_multi *)kcontrol->private_value;\n+\n+\tucontrol->value.enumerated.item[0] = multi->kctrl_val;\n+\treturn 0;\n+}\n+\n+static int simple_amp_multi_kctrl_enum_put(struct snd_kcontrol *kcontrol,\n+\t\t\t\t\t   struct snd_ctl_elem_value *ucontrol)\n+{\n+\tstruct simple_amp_multi *multi = (struct simple_amp_multi *)kcontrol->private_value;\n+\tu32 kctrl_val;\n+\tint ret;\n+\n+\tkctrl_val = ucontrol->value.enumerated.item[0];\n+\n+\tif (kctrl_val == multi->kctrl_val)\n+\t\treturn 0;\n+\n+\tret = simple_amp_multi_kctrl_write_gpios(multi, kctrl_val);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tmulti->kctrl_val = kctrl_val;\n+\n+\treturn 1; /* The value changed */\n+}\n+\n static int *simple_amp_alloc_tlv_ranges(const struct simple_amp_ranges *ranges)\n {\n \tunsigned int index;\n@@ -368,6 +416,13 @@ static int simple_amp_multi_add_kcontrol(struct snd_soc_component *component,\n \t\tcontrol.tlv.p = multi->tlv_array;\n \t\tbreak;\n \n+\tcase SIMPLE_AMP_MODE_LABELS:\n+\t\t/* Use enumerated values */\n+\t\tcontrol.info = simple_amp_multi_kctrl_enum_info;\n+\t\tcontrol.get = simple_amp_multi_kctrl_enum_get;\n+\t\tcontrol.put = simple_amp_multi_kctrl_enum_put;\n+\t\tbreak;\n+\n \tcase SIMPLE_AMP_MODE_NONE:\n \t\t/* Already set control configuration is enough */\n \t\tbreak;\n@@ -712,10 +767,40 @@ static int simple_amp_parse_ranges(struct device *dev,\n \treturn 0;\n }\n \n+static int simple_amp_parse_labels(struct device *dev,\n+\t\t\t\t   struct simple_amp_multi *multi,\n+\t\t\t\t   const char *labels_property)\n+{\n+\tstruct simple_amp_labels *labels = &multi->labels;\n+\tstruct device_node *np = dev->of_node;\n+\tint ret;\n+\n+\tret = of_property_count_strings(np, labels_property);\n+\tif (ret <= 0)\n+\t\treturn ret;\n+\n+\tlabels->nb_labels = ret;\n+\tif (labels->nb_labels > (1 << multi->gpios->ndescs))\n+\t\treturn -EINVAL;\n+\n+\tlabels->tab_labels = devm_kcalloc(dev, labels->nb_labels,\n+\t\t\t\t\t  sizeof(*labels->tab_labels),\n+\t\t\t\t\t  GFP_KERNEL);\n+\tif (!labels->tab_labels)\n+\t\treturn -ENOMEM;\n+\n+\tmulti->kctrl_max = labels->nb_labels - 1;\n+\tmulti->kctrl_val = 0;\n+\n+\treturn of_property_read_string_array(np, labels_property, labels->tab_labels,\n+\t\t\t\t\t     labels->nb_labels);\n+}\n+\n static int simple_amp_parse_multi_gpio(struct device *dev,\n \t\t\t\t       struct simple_amp_multi *multi,\n \t\t\t\t       const char *gpios_property,\n-\t\t\t\t       const char *ranges_property)\n+\t\t\t\t       const char *ranges_property,\n+\t\t\t\t       const char *labels_property)\n {\n \tstruct device_node *np = dev->of_node;\n \tint ret;\n@@ -745,6 +830,13 @@ static int simple_amp_parse_multi_gpio(struct device *dev,\n \t\t\treturn dev_err_probe(dev, ret, \"Failed to parse '%s'\\n\",\n \t\t\t\t\t     ranges_property);\n \t\tmulti->mode = SIMPLE_AMP_MODE_RANGES;\n+\t} else if (of_property_present(np, labels_property)) {\n+\t\tret = simple_amp_parse_labels(dev, multi, labels_property);\n+\t\tif (ret < 0)\n+\t\t\treturn dev_err_probe(dev, ret, \"Failed to parse '%s'\\n\",\n+\t\t\t\t\t     labels_property);\n+\n+\t\tmulti->mode = SIMPLE_AMP_MODE_LABELS;\n \t}\n \n \treturn 0;\n@@ -785,7 +877,7 @@ static int simple_amp_probe(struct platform_device *pdev)\n \n \tif (simple_amp->data->supports & SIMPLE_AUDIO_SUPPORT_PGA) {\n \t\tret = simple_amp_parse_multi_gpio(dev, &simple_amp->gain, \"gain\",\n-\t\t\t\t\t\t  \"gain-ranges\");\n+\t\t\t\t\t\t  \"gain-ranges\", \"gain-labels\");\n \t\tif (ret)\n \t\t\treturn ret;\n \t}\n@@ -795,6 +887,20 @@ static int simple_amp_probe(struct platform_device *pdev)\n \tsimple_amp->mute.control_name = \"Switch\";\n \tsimple_amp->bypass.control_name = \"Bypass Switch\";\n \n+\tif (simple_amp->gain.mode == SIMPLE_AMP_MODE_LABELS) {\n+\t\t/*\n+\t\t * The gain widget control will use enumerated values.\n+\t\t *\n+\t\t * Having just \"Voltage\" and \"Switch\" widget names with\n+\t\t * enumerated values and boolean value can confuse ALSA in terms\n+\t\t * of possible values (strings).\n+\t\t *\n+\t\t * Make things clear and avoid the just \"Switch\" name in that\n+\t\t * case.\n+\t\t */\n+\t\tsimple_amp->mute.control_name = \"Out Switch\";\n+\t}\n+\n \treturn devm_snd_soc_register_component(dev,\n \t\t\t\t\t       &simple_amp_component_driver,\n \t\t\t\t\t       NULL, 0);\n","prefixes":["v2","15/17"]}