* [PATCH] ASoC: rt712: add GPIOs for LED control
@ 2026-09-16 9:05 shumingf
2026-09-16 21:39 ` Mark Brown
0 siblings, 1 reply; 4+ messages in thread
From: shumingf @ 2026-09-16 9:05 UTC (permalink / raw)
To: broonie, lgirdwood
Cc: linux-sound, lars, flove, oder_chiou, jack.yu, derek.fang,
Shuming Fan
From: Shuming Fan <shumingf@realtek.com>
Certain platforms use the RT712 GPIOs to control the microphone mute LED and speaker mute LED.
This patch lets the LED subsystem to handle the GPIO control.
Signed-off-by: Shuming Fan <shumingf@realtek.com>
---
sound/soc/codecs/rt712-sdca-sdw.h | 3 +
sound/soc/codecs/rt712-sdca.c | 106 ++++++++++++++++++++++++++++++
sound/soc/codecs/rt712-sdca.h | 6 +-
3 files changed, 114 insertions(+), 1 deletion(-)
diff --git a/sound/soc/codecs/rt712-sdca-sdw.h b/sound/soc/codecs/rt712-sdca-sdw.h
index 7ad25cc27f62..162d62234b68 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.h
+++ b/sound/soc/codecs/rt712-sdca-sdw.h
@@ -46,6 +46,9 @@ static const struct reg_default rt712_sdca_mbq_defaults[] = {
{ 0x5b00029, 0x3fff },
{ 0x5b0002a, 0xf000 },
{ 0x6100000, 0x04e4 },
+ { 0x6100009, 0x0000 },
+ { 0x610000a, 0x0000 },
+ { 0x610000b, 0x0020 },
{ 0x610000e, 0x0007 },
{ 0x6100045, 0x0860 },
{ 0x6100046, 0x0029 },
diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c
index 38052cb19790..20889c614e47 100644
--- a/sound/soc/codecs/rt712-sdca.c
+++ b/sound/soc/codecs/rt712-sdca.c
@@ -113,6 +113,109 @@ static void rt712_sdca_clk_patch2(struct rt712_sdca_priv *rt712)
rt712_sdca_index_write(rt712, RT712_VENDOR_REG, 0x65, 0x0000);
}
+static int rt712_sdca_gpio_request(struct gpio_chip *chip, unsigned int offset)
+{
+ struct rt712_sdca_priv *rt712 = gpiochip_get_data(chip);
+ unsigned int gpio_pin = offset + 3;
+ int ret;
+
+ dev_dbg(&rt712->slave->dev, "%s: gpio_pin=%d\n", __func__, gpio_pin);
+
+ ret = pm_runtime_resume(rt712->component->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
+ /*
+ * Only support GPIO3 and GPIO4 for now
+ */
+ switch (gpio_pin) {
+ case 3:
+ break;
+ case 4:
+ rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL,
+ RT712_HDA_LEGACY_CONFIG_CTL0, 0x000c, 0x0004);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL,
+ RT712_HDA_GPIO_EN_CTL, (1 << gpio_pin), (1 << gpio_pin));
+ rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL,
+ RT712_HDA_GPIO_DIRECTION_CTL, (1 << gpio_pin), (1 << gpio_pin));
+
+ return 0;
+}
+
+static int rt712_sdca_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ struct rt712_sdca_priv *rt712 = gpiochip_get_data(chip);
+ unsigned int gpio_pin = offset + 3;
+ int ret;
+
+ dev_dbg(&rt712->slave->dev, "%s: gpio_pin=%d, value=%d\n", __func__, gpio_pin, value);
+
+ ret = pm_runtime_resume(rt712->component->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
+ return rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL,
+ RT712_HDA_GPIO_SET_CTL, (1 << gpio_pin), (!!value << gpio_pin));
+}
+
+static int rt712_sdca_gpio_direction_out(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct rt712_sdca_priv *rt712 = gpiochip_get_data(chip);
+ unsigned int gpio_pin = offset + 3;
+ int ret;
+
+ dev_dbg(&rt712->slave->dev, "%s: gpio_pin=%d, value=%d\n", __func__, gpio_pin, value);
+
+ ret = pm_runtime_resume(rt712->component->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
+ switch (gpio_pin) {
+ case 3:
+ case 4:
+ rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL,
+ RT712_HDA_GPIO_DIRECTION_CTL, (1 << gpio_pin), (1 << gpio_pin));
+ rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL,
+ RT712_HDA_GPIO_SET_CTL, (1 << gpio_pin), (!!value << gpio_pin));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct gpio_chip rt712_sdca_template_chip = {
+ .label = "rt712-sdca",
+ .owner = THIS_MODULE,
+ .request = rt712_sdca_gpio_request,
+ .direction_output = rt712_sdca_gpio_direction_out,
+ .set = rt712_sdca_gpio_set,
+ .ngpio = 2,
+ .can_sleep = true,
+ .base = -1,
+};
+
+static void rt712_sdca_gpio_init(struct rt712_sdca_priv *rt712)
+{
+ int ret;
+
+ rt712->gpio_chip = rt712_sdca_template_chip;
+ rt712->gpio_chip.parent = &rt712->slave->dev;
+ rt712->gpio_chip.fwnode = dev_fwnode(&rt712->slave->dev);
+
+ ret = devm_gpiochip_add_data(&rt712->slave->dev, &rt712->gpio_chip, rt712);
+ if (ret != 0)
+ dev_err(&rt712->slave->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
static int rt712_sdca_calibration(struct rt712_sdca_priv *rt712)
{
unsigned int val, loop_rc = 0, loop_dc = 0;
@@ -1101,6 +1204,9 @@ static int rt712_sdca_probe(struct snd_soc_component *component)
rt712_sdca_spk_dapm_routes, ARRAY_SIZE(rt712_sdca_spk_dapm_routes));
}
+ /* initialize GPIOs */
+ rt712_sdca_gpio_init(rt712);
+
if (!rt712->first_hw_init)
return 0;
diff --git a/sound/soc/codecs/rt712-sdca.h b/sound/soc/codecs/rt712-sdca.h
index 6229fe341bb5..362e6226982a 100644
--- a/sound/soc/codecs/rt712-sdca.h
+++ b/sound/soc/codecs/rt712-sdca.h
@@ -14,6 +14,7 @@
#include <linux/soundwire/sdw_type.h>
#include <sound/soc.h>
#include <linux/workqueue.h>
+#include <linux/gpio/driver.h>
struct rt712_sdca_priv {
struct regmap *regmap;
@@ -45,6 +46,7 @@ struct rt712_sdca_priv {
bool fu05_dapm_mute;
bool fu05_mixer_l_mute;
bool fu05_mixer_r_mute;
+ struct gpio_chip gpio_chip;
};
struct rt712_dmic_kctrl_priv {
@@ -114,6 +116,9 @@ struct rt712_dmic_kctrl_priv {
#define RT712_HDA_LEGACY_MUX_CTL0 0x00
#define RT712_HDA_LEGACY_CONFIG_CTL0 0x06
#define RT712_HDA_LEGACY_RESET_CTL 0x08
+#define RT712_HDA_GPIO_EN_CTL 0x09
+#define RT712_HDA_GPIO_DIRECTION_CTL 0x0a
+#define RT712_HDA_GPIO_SET_CTL 0x0b
#define RT712_HDA_LEGACY_GPIO_WAKE_EN_CTL 0x0e
#define RT712_DMIC_ENT_FLOAT_CTL 0x10
#define RT712_DMIC_GAIN_ENT_FLOAT_CTL0 0x11
@@ -271,7 +276,6 @@ enum {
RT712_CLK_FREQ_22_5792MHZ = 4,
};
-
int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave);
int rt712_sdca_init(struct device *dev, struct regmap *regmap,
struct regmap *mbq_regmap, struct sdw_slave *slave);
--
2.54.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] ASoC: rt712: add GPIOs for LED control
2026-09-16 9:05 [PATCH] ASoC: rt712: add GPIOs for LED control shumingf
@ 2026-09-16 21:39 ` Mark Brown
2026-09-17 6:24 ` Shuming [范書銘]
0 siblings, 1 reply; 4+ messages in thread
From: Mark Brown @ 2026-09-16 21:39 UTC (permalink / raw)
To: shumingf
Cc: lgirdwood, linux-sound, lars, flove, oder_chiou, jack.yu,
derek.fang
[-- Attachment #1: Type: text/plain, Size: 2797 bytes --]
On Wed, Sep 16, 2026 at 05:05:13PM +0800, shumingf@realtek.com wrote:
> From: Shuming Fan <shumingf@realtek.com>
>
> Certain platforms use the RT712 GPIOs to control the microphone mute LED and speaker mute LED.
> This patch lets the LED subsystem to handle the GPIO control.
> +static int rt712_sdca_gpio_request(struct gpio_chip *chip, unsigned int offset)
> +{
> + struct rt712_sdca_priv *rt712 = gpiochip_get_data(chip);
> + unsigned int gpio_pin = offset + 3;
> + int ret;
> +
> + dev_dbg(&rt712->slave->dev, "%s: gpio_pin=%d\n", __func__, gpio_pin);
> +
> + ret = pm_runtime_resume(rt712->component->dev);
> + if (ret < 0 && ret != -EACCES)
> + return ret;
This pm_runtime_resume() usage can race with autosuspend, if the
autosuspend timer is about to expire it could do so before we actually
update the register values so the writes won't actually happen. It's
very unlikely to actually happen but the risk is there.
> + /*
> + * Only support GPIO3 and GPIO4 for now
> + */
> + switch (gpio_pin) {
> + case 3:
> + break;
> + case 4:
> + rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL,
> + RT712_HDA_LEGACY_CONFIG_CTL0, 0x000c, 0x0004);
This doesn't do any locking with other regmap users and gpiolib won't
hold a lock for us - since rt712_sdca_index_update_bits() is a
read/modify/write cycle this could lead to corruption.
> +static void rt712_sdca_gpio_init(struct rt712_sdca_priv *rt712)
> +{
> + int ret;
> +
> + rt712->gpio_chip = rt712_sdca_template_chip;
> + rt712->gpio_chip.parent = &rt712->slave->dev;
> + rt712->gpio_chip.fwnode = dev_fwnode(&rt712->slave->dev);
> +
> + ret = devm_gpiochip_add_data(&rt712->slave->dev, &rt712->gpio_chip, rt712);
> + if (ret != 0)
> + dev_err(&rt712->slave->dev, "Failed to add GPIOs: %d\n", ret);
> +}
The gpiolib usage either needs to be conditional on gpiolib or we need
the driver to depend on it. Either is fine.
> @@ -1101,6 +1204,9 @@ static int rt712_sdca_probe(struct snd_soc_component *component)
> rt712_sdca_spk_dapm_routes, ARRAY_SIZE(rt712_sdca_spk_dapm_routes));
> }
>
> + /* initialize GPIOs */
> + rt712_sdca_gpio_init(rt712);
> +
> if (!rt712->first_hw_init)
> return 0;
>
This will happen every time the card binds and uses devm, I'd expect it
to happen when the SoundWire device binds rather than during ASoC level
initialisation. We don't want to continually register and unregister
the GPIOs.
> @@ -271,7 +276,6 @@ enum {
> RT712_CLK_FREQ_22_5792MHZ = 4,
> };
>
> -
> int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave);
> int rt712_sdca_init(struct device *dev, struct regmap *regmap,
> struct regmap *mbq_regmap, struct sdw_slave *slave);
Unrelated whitespace change.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 4+ messages in thread
* RE: [PATCH] ASoC: rt712: add GPIOs for LED control
2026-09-16 21:39 ` Mark Brown
@ 2026-09-17 6:24 ` Shuming [范書銘]
2026-09-17 11:05 ` Mark Brown
0 siblings, 1 reply; 4+ messages in thread
From: Shuming [范書銘] @ 2026-09-17 6:24 UTC (permalink / raw)
To: Mark Brown
Cc: lgirdwood@gmail.com, linux-sound@vger.kernel.org, lars@metafoo.de,
Flove(HsinFu), Oder Chiou, Jack Yu,
Derek [方德義]
> > + dev_dbg(&rt712->slave->dev, "%s: gpio_pin=%d\n", __func__,
> > +gpio_pin);
> > +
> > + ret = pm_runtime_resume(rt712->component->dev);
> > + if (ret < 0 && ret != -EACCES)
> > + return ret;
>
> This pm_runtime_resume() usage can race with autosuspend, if the
> autosuspend timer is about to expire it could do so before we actually update
> the register values so the writes won't actually happen. It's very unlikely to
> actually happen but the risk is there.
Thanks for review.
I will use pm_runtime_resume_and_get() instead.
> > + switch (gpio_pin) {
> > + case 3:
> > + break;
> > + case 4:
> > + rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL,
> > + RT712_HDA_LEGACY_CONFIG_CTL0, 0x000c, 0x0004);
>
> This doesn't do any locking with other regmap users and gpiolib won't hold a
> lock for us - since rt712_sdca_index_update_bits() is a read/modify/write
> cycle this could lead to corruption.
Sure. May I add a lock in the callback instead of only locking rt712_sdca_index_update_bits()?
I will send v2 afterward.
> > +static void rt712_sdca_gpio_init(struct rt712_sdca_priv *rt712) {
> > + int ret;
> > +
> > + rt712->gpio_chip = rt712_sdca_template_chip;
> > + rt712->gpio_chip.parent = &rt712->slave->dev;
> > + rt712->gpio_chip.fwnode = dev_fwnode(&rt712->slave->dev);
> > +
> > + ret = devm_gpiochip_add_data(&rt712->slave->dev, &rt712->gpio_chip,
> rt712);
> > + if (ret != 0)
> > + dev_err(&rt712->slave->dev, "Failed to add GPIOs: %d\n", ret); }
>
> The gpiolib usage either needs to be conditional on gpiolib or we need the
> driver to depend on it. Either is fine.
Add the 'IS_ENABLED(CONFIG_GPIOLIB)' check before calling rt712_sdca_gpio_init().
> >
> > + /* initialize GPIOs */
> > + rt712_sdca_gpio_init(rt712);
> > +
> > if (!rt712->first_hw_init)
> > return 0;
> >
>
> This will happen every time the card binds and uses devm, I'd expect it to
> happen when the SoundWire device binds rather than during ASoC level
> initialisation. We don't want to continually register and unregister the GPIOs.
Will move to sdw_driver.probe().
> > @@ -271,7 +276,6 @@ enum {
> > RT712_CLK_FREQ_22_5792MHZ = 4,
> > };
> >
> > -
> > int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave);
> > int rt712_sdca_init(struct device *dev, struct regmap *regmap,
> > struct regmap *mbq_regmap, struct sdw_slave *slave);
>
> Unrelated whitespace change.
Wil fix
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] ASoC: rt712: add GPIOs for LED control
2026-09-17 6:24 ` Shuming [范書銘]
@ 2026-09-17 11:05 ` Mark Brown
0 siblings, 0 replies; 4+ messages in thread
From: Mark Brown @ 2026-09-17 11:05 UTC (permalink / raw)
To: Shuming [范書銘]
Cc: lgirdwood@gmail.com, linux-sound@vger.kernel.org, lars@metafoo.de,
Flove(HsinFu), Oder Chiou, Jack Yu,
Derek [方德義]
[-- Attachment #1: Type: text/plain, Size: 529 bytes --]
On Thu, Sep 17, 2026 at 06:24:06AM +0000, Shuming [范書銘] wrote:
> > > + rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL,
> > > + RT712_HDA_LEGACY_CONFIG_CTL0, 0x000c, 0x0004);
> > This doesn't do any locking with other regmap users and gpiolib won't hold a
> > lock for us - since rt712_sdca_index_update_bits() is a read/modify/write
> > cycle this could lead to corruption.
> Sure. May I add a lock in the callback instead of only locking rt712_sdca_index_update_bits()?
That sounds pluasible.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-17 11:06 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-16 9:05 [PATCH] ASoC: rt712: add GPIOs for LED control shumingf
2026-09-16 21:39 ` Mark Brown
2026-09-17 6:24 ` Shuming [范書銘]
2026-09-17 11:05 ` Mark Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox