diff mbox series

[v2] ASoC: rt-sdw-common: Common functions for Realtek soundwire driver

Message ID 959e8dcb075948459be4463f6a4ca6ee@realtek.com (mailing list archive)
State Accepted
Commit bbca8e7050e0769d46eb775082d1926db05e7dac
Headers show
Series [v2] ASoC: rt-sdw-common: Common functions for Realtek soundwire driver | expand

Commit Message

Jack Yu Oct. 1, 2024, 9:16 a.m. UTC
This is the first version of common functions for Realtek
soundwire codec driver.

Signed-off-by: Jack Yu <jack.yu@realtek.com>
---
 sound/soc/codecs/Kconfig         |   5 +
 sound/soc/codecs/Makefile        |   2 +
 sound/soc/codecs/rt-sdw-common.c | 238 +++++++++++++++++++++++++++++++
 sound/soc/codecs/rt-sdw-common.h |  66 +++++++++
 4 files changed, 311 insertions(+)
 create mode 100644 sound/soc/codecs/rt-sdw-common.c
 create mode 100644 sound/soc/codecs/rt-sdw-common.h

Comments

Mark Brown Oct. 7, 2024, 2:08 p.m. UTC | #1
On Tue, Oct 01, 2024 at 09:16:27AM +0000, Jack Yu wrote:

> +config SND_SOC_RT_SDW_COMMON
> +	tristate
> +	default y if SND_SOC_RT721_SDCA_SDW=y
> +	default m if SND_SOC_RT721_SDCA_SDW=m
> +

This should really be posted in a series with the patch adding the
driver, I guess the driver won't build without this.
Mark Brown Oct. 7, 2024, 7:34 p.m. UTC | #2
On Tue, 01 Oct 2024 09:16:27 +0000, Jack Yu wrote:
> This is the first version of common functions for Realtek
> soundwire codec driver.
> 
> 

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next

Thanks!

[1/1] ASoC: rt-sdw-common: Common functions for Realtek soundwire driver
      commit: bbca8e7050e0769d46eb775082d1926db05e7dac

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark
Kees Bakker Oct. 8, 2024, 8:43 p.m. UTC | #3
Op 01-10-2024 om 11:16 schreef Jack Yu:
> This is the first version of common functions for Realtek
> soundwire codec driver.
>
> Signed-off-by: Jack Yu <jack.yu@realtek.com>
> ---
>   sound/soc/codecs/Kconfig         |   5 +
>   sound/soc/codecs/Makefile        |   2 +
>   sound/soc/codecs/rt-sdw-common.c | 238 +++++++++++++++++++++++++++++++
>   sound/soc/codecs/rt-sdw-common.h |  66 +++++++++
>   4 files changed, 311 insertions(+)
>   create mode 100644 sound/soc/codecs/rt-sdw-common.c
>   create mode 100644 sound/soc/codecs/rt-sdw-common.h
>
> [...]
> +/**
> + * rt_sdca_btn_type - Decision of button type.
> + *
> + * @buffer: UMP message buffer.
> + *
> + * A button type will be returned regarding to buffer,
> + * it returns zero if buffer cannot be recognized.
> + */
> +int rt_sdca_btn_type(unsigned char *buffer)
> +{
> +	u8 btn_type = 0;
> +	int ret;
No initializer ?? You probably want to set it to zero here.
> +
> +	btn_type |= buffer[0] & 0xf;
> +	btn_type |= (buffer[0] >> 4) & 0xf;
> +	btn_type |= buffer[1] & 0xf;
> +	btn_type |= (buffer[1] >> 4) & 0xf;
> +
> +	if (btn_type & BIT(0))
Variable "ret" is not initialized yet.
> +		ret |= SND_JACK_BTN_2;
> +	if (btn_type & BIT(1))
> +		ret |= SND_JACK_BTN_3;
> +	if (btn_type & BIT(2))
> +		ret |= SND_JACK_BTN_0;
> +	if (btn_type & BIT(3))
> +		ret |= SND_JACK_BTN_1;
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(rt_sdca_btn_type);
>
Kees Bakker Oct. 8, 2024, 8:59 p.m. UTC | #4
Op 01-10-2024 om 11:16 schreef Jack Yu:
> This is the first version of common functions for Realtek
> soundwire codec driver.
>
> Signed-off-by: Jack Yu <jack.yu@realtek.com>
> ---
>   sound/soc/codecs/Kconfig         |   5 +
>   sound/soc/codecs/Makefile        |   2 +
>   sound/soc/codecs/rt-sdw-common.c | 238 +++++++++++++++++++++++++++++++
>   sound/soc/codecs/rt-sdw-common.h |  66 +++++++++
>   4 files changed, 311 insertions(+)
>   create mode 100644 sound/soc/codecs/rt-sdw-common.c
>   create mode 100644 sound/soc/codecs/rt-sdw-common.h
>
> [...]
> +/**
> + * rt_sdca_headset_detect - Headset jack type detection.
> + *
> + * @map: map for setting.
> + * @entity_id: SDCA entity ID.
> + *
> + * A headset jack type will be returned, a negative errno will
> + * be returned in error cases.
> + */
> +int rt_sdca_headset_detect(struct regmap *map, unsigned int entity_id)
> +{
> +	unsigned int det_mode, jack_type;
> +	int ret;
> +
> +	/* get detected_mode */
> +	ret = regmap_read(map, SDW_SDCA_CTL(SDCA_NUM_JACK_CODEC, entity_id,
> +			RT_SDCA_CTL_DETECTED_MODE, 0), &det_mode);
> +
> +	if (ret < 0)
> +		goto io_error;
> +
> +	switch (det_mode) {
> +	case 0x00:
> +		jack_type = 0;
> +		break;
> +	case 0x03:
> +		jack_type = SND_JACK_HEADPHONE;
> +		break;
> +	case 0x05:
> +		jack_type = SND_JACK_HEADSET;
> +		break;
There is no default case. So, variable jack_type can remain 
uninitialized and then used for the return value.
Perhaps you can combine "case 0x00" with "default".
> +	}
> +
> +	/* write selected_mode */
> +	if (det_mode) {
> +		ret = regmap_write(map, SDW_SDCA_CTL(SDCA_NUM_JACK_CODEC, entity_id,
> +				RT_SDCA_CTL_SELECTED_MODE, 0), det_mode);
> +		if (ret < 0)
> +			goto io_error;
> +	}
> +
> +	return jack_type;
>
Kees Bakker Oct. 12, 2024, 9 p.m. UTC | #5
Op 08-10-2024 om 22:59 schreef Kees Bakker:
> Op 01-10-2024 om 11:16 schreef Jack Yu:
>> This is the first version of common functions for Realtek
>> soundwire codec driver.
>>
>> Signed-off-by: Jack Yu <jack.yu@realtek.com>
>> ---
>>   sound/soc/codecs/Kconfig         |   5 +
>>   sound/soc/codecs/Makefile        |   2 +
>>   sound/soc/codecs/rt-sdw-common.c | 238 +++++++++++++++++++++++++++++++
>>   sound/soc/codecs/rt-sdw-common.h |  66 +++++++++
>>   4 files changed, 311 insertions(+)
>>   create mode 100644 sound/soc/codecs/rt-sdw-common.c
>>   create mode 100644 sound/soc/codecs/rt-sdw-common.h
>>
>> [...]
>> +/**
>> + * rt_sdca_headset_detect - Headset jack type detection.
>> + *
>> + * @map: map for setting.
>> + * @entity_id: SDCA entity ID.
>> + *
>> + * A headset jack type will be returned, a negative errno will
>> + * be returned in error cases.
>> + */
>> +int rt_sdca_headset_detect(struct regmap *map, unsigned int entity_id)
>> +{
>> +    unsigned int det_mode, jack_type;
>> +    int ret;
>> +
>> +    /* get detected_mode */
>> +    ret = regmap_read(map, SDW_SDCA_CTL(SDCA_NUM_JACK_CODEC, entity_id,
>> +            RT_SDCA_CTL_DETECTED_MODE, 0), &det_mode);
>> +
>> +    if (ret < 0)
>> +        goto io_error;
>> +
>> +    switch (det_mode) {
>> +    case 0x00:
>> +        jack_type = 0;
>> +        break;
>> +    case 0x03:
>> +        jack_type = SND_JACK_HEADPHONE;
>> +        break;
>> +    case 0x05:
>> +        jack_type = SND_JACK_HEADSET;
>> +        break;
> There is no default case. So, variable jack_type can remain 
> uninitialized and then used for the return value.
> Perhaps you can combine "case 0x00" with "default".
>> +    }
>> +
>> +    /* write selected_mode */
>> +    if (det_mode) {
>> +        ret = regmap_write(map, SDW_SDCA_CTL(SDCA_NUM_JACK_CODEC, 
>> entity_id,
>> +                RT_SDCA_CTL_SELECTED_MODE, 0), det_mode);
>> +        if (ret < 0)
>> +            goto io_error;
>> +    }
>> +
>> +    return jack_type;
>>
Please have a look at my comment again.
If regmap_read returns a `det_mode` not 0, 3 or 5 then the function will 
return jack_type
with an uninitialzed value.
diff mbox series

Patch

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 7092842480ef..b095eba9d634 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -1545,6 +1545,11 @@  config SND_SOC_RL6231
 	default m if SND_SOC_RT1305=m
 	default m if SND_SOC_RT1308=m
 
+config SND_SOC_RT_SDW_COMMON
+	tristate
+	default y if SND_SOC_RT721_SDCA_SDW=y
+	default m if SND_SOC_RT721_SDCA_SDW=m
+
 config SND_SOC_RL6347A
 	tristate
 	default y if SND_SOC_RT274=y
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 54cbc3feae32..4497b2e30cd3 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -216,6 +216,7 @@  snd-soc-rk3308-y := rk3308_codec.o
 snd-soc-rk3328-y := rk3328_codec.o
 snd-soc-rk817-y := rk817_codec.o
 snd-soc-rl6231-y := rl6231.o
+snd-soc-rt-sdw-common-y := rt-sdw-common.o
 snd-soc-rl6347a-y := rl6347a.o
 snd-soc-rt1011-y := rt1011.o
 snd-soc-rt1015-y := rt1015.o
@@ -618,6 +619,7 @@  obj-$(CONFIG_SND_SOC_RK3308)	+= snd-soc-rk3308.o
 obj-$(CONFIG_SND_SOC_RK3328)	+= snd-soc-rk3328.o
 obj-$(CONFIG_SND_SOC_RK817)	+= snd-soc-rk817.o
 obj-$(CONFIG_SND_SOC_RL6231)	+= snd-soc-rl6231.o
+obj-$(CONFIG_SND_SOC_RT_SDW_COMMON)	+= snd-soc-rt-sdw-common.o
 obj-$(CONFIG_SND_SOC_RL6347A)	+= snd-soc-rl6347a.o
 obj-$(CONFIG_SND_SOC_RT1011)	+= snd-soc-rt1011.o
 obj-$(CONFIG_SND_SOC_RT1015)	+= snd-soc-rt1015.o
diff --git a/sound/soc/codecs/rt-sdw-common.c b/sound/soc/codecs/rt-sdw-common.c
new file mode 100644
index 000000000000..9ed0e9855699
--- /dev/null
+++ b/sound/soc/codecs/rt-sdw-common.c
@@ -0,0 +1,238 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt-sdw-common.c
+//
+// Copyright(c) 2024 Realtek Semiconductor Corp.
+//
+
+/*
+ * This file defines common functions used with Realtek soundwire codecs.
+ */
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/bitops.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/jack.h>
+
+#include "rt-sdw-common.h"
+
+/**
+ * rt_sdca_index_write - Write a value to Realtek defined register.
+ *
+ * @map: map for setting.
+ * @nid: Realtek-defined ID.
+ * @reg: register.
+ * @value: value.
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+int rt_sdca_index_write(struct regmap *map, unsigned int nid,
+	unsigned int reg, unsigned int value)
+{
+	unsigned int addr = (nid << 20) | reg;
+	int ret;
+
+	ret = regmap_write(map, addr, value);
+	if (ret < 0)
+		pr_err("Failed to set value: %06x <= %04x ret=%d\n",
+			addr, value, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rt_sdca_index_write);
+
+/**
+ * rt_sdca_index_read - Read value from Realtek defined register.
+ *
+ * @map: map for setting.
+ * @nid: Realtek-defined ID.
+ * @reg: register.
+ * @value: value.
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+int rt_sdca_index_read(struct regmap *map, unsigned int nid,
+	unsigned int reg, unsigned int *value)
+{
+	unsigned int addr = (nid << 20) | reg;
+	int ret;
+
+	ret = regmap_read(map, addr, value);
+	if (ret < 0)
+		pr_err("Failed to get value: %06x => %04x ret=%d\n",
+			addr, *value, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rt_sdca_index_read);
+
+/**
+ * rt_sdca_index_update_bits - Update value on Realtek defined register.
+ *
+ * @map: map for setting.
+ * @nid: Realtek-defined ID.
+ * @reg: register.
+ * @mask: Bitmask to change
+ * @value: New value for bitmask
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+
+int rt_sdca_index_update_bits(struct regmap *map,
+	unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val)
+{
+	unsigned int tmp;
+	int ret;
+
+	ret = rt_sdca_index_read(map, nid, reg, &tmp);
+	if (ret < 0)
+		return ret;
+
+	set_mask_bits(&tmp, mask, val);
+	return rt_sdca_index_write(map, nid, reg, tmp);
+}
+EXPORT_SYMBOL_GPL(rt_sdca_index_update_bits);
+
+/**
+ * rt_sdca_btn_type - Decision of button type.
+ *
+ * @buffer: UMP message buffer.
+ *
+ * A button type will be returned regarding to buffer,
+ * it returns zero if buffer cannot be recognized.
+ */
+int rt_sdca_btn_type(unsigned char *buffer)
+{
+	u8 btn_type = 0;
+	int ret;
+
+	btn_type |= buffer[0] & 0xf;
+	btn_type |= (buffer[0] >> 4) & 0xf;
+	btn_type |= buffer[1] & 0xf;
+	btn_type |= (buffer[1] >> 4) & 0xf;
+
+	if (btn_type & BIT(0))
+		ret |= SND_JACK_BTN_2;
+	if (btn_type & BIT(1))
+		ret |= SND_JACK_BTN_3;
+	if (btn_type & BIT(2))
+		ret |= SND_JACK_BTN_0;
+	if (btn_type & BIT(3))
+		ret |= SND_JACK_BTN_1;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rt_sdca_btn_type);
+
+/**
+ * rt_sdca_headset_detect - Headset jack type detection.
+ *
+ * @map: map for setting.
+ * @entity_id: SDCA entity ID.
+ *
+ * A headset jack type will be returned, a negative errno will
+ * be returned in error cases.
+ */
+int rt_sdca_headset_detect(struct regmap *map, unsigned int entity_id)
+{
+	unsigned int det_mode, jack_type;
+	int ret;
+
+	/* get detected_mode */
+	ret = regmap_read(map, SDW_SDCA_CTL(SDCA_NUM_JACK_CODEC, entity_id,
+			RT_SDCA_CTL_DETECTED_MODE, 0), &det_mode);
+
+	if (ret < 0)
+		goto io_error;
+
+	switch (det_mode) {
+	case 0x00:
+		jack_type = 0;
+		break;
+	case 0x03:
+		jack_type = SND_JACK_HEADPHONE;
+		break;
+	case 0x05:
+		jack_type = SND_JACK_HEADSET;
+		break;
+	}
+
+	/* write selected_mode */
+	if (det_mode) {
+		ret = regmap_write(map, SDW_SDCA_CTL(SDCA_NUM_JACK_CODEC, entity_id,
+				RT_SDCA_CTL_SELECTED_MODE, 0), det_mode);
+		if (ret < 0)
+			goto io_error;
+	}
+
+	return jack_type;
+
+io_error:
+	pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rt_sdca_headset_detect);
+
+/**
+ * rt_sdca_button_detect - Read UMP message and decide button type.
+ *
+ * @map: map for setting.
+ * @entity_id: SDCA entity ID.
+ * @hid_buf_addr: HID buffer address.
+ * @hid_id: Report ID for HID.
+ *
+ * A button type will be returned regarding to buffer,
+ * it returns zero if buffer cannot be recognized.
+ */
+int rt_sdca_button_detect(struct regmap *map, unsigned int entity_id,
+	unsigned int hid_buf_addr, unsigned int hid_id)
+{
+	unsigned int btn_type = 0, offset, idx, val, owner;
+	unsigned char buf[3];
+	int ret;
+
+	/* get current UMP message owner */
+	ret = regmap_read(map, SDW_SDCA_CTL(SDCA_NUM_HID, entity_id,
+			RT_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), &owner);
+	if (ret < 0)
+		return 0;
+
+	/* if owner is device then there is no button event from device */
+	if (owner == 1)
+		return 0;
+
+	/* read UMP message offset */
+	ret = regmap_read(map, SDW_SDCA_CTL(SDCA_NUM_HID, entity_id,
+			RT_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0), &offset);
+	if (ret < 0)
+		goto _end_btn_det_;
+
+	for (idx = 0; idx < sizeof(buf); idx++) {
+		ret = regmap_read(map, hid_buf_addr + offset + idx, &val);
+		if (ret < 0)
+			goto _end_btn_det_;
+		buf[idx] = val & 0xff;
+	}
+	/* Report ID for HID */
+	if (buf[0] == hid_id)
+		btn_type = rt_sdca_btn_type(&buf[1]);
+
+_end_btn_det_:
+	/* Host is owner, so set back to device */
+	if (owner == 0)
+		/* set owner to device */
+		regmap_write(map,
+			SDW_SDCA_CTL(SDCA_NUM_HID, entity_id,
+				RT_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), 0x01);
+
+	return btn_type;
+}
+EXPORT_SYMBOL_GPL(rt_sdca_button_detect);
+
+MODULE_DESCRIPTION("Realtek soundwire common functions");
+MODULE_AUTHOR("jack yu <jack.yu@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt-sdw-common.h b/sound/soc/codecs/rt-sdw-common.h
new file mode 100644
index 000000000000..4759516feb38
--- /dev/null
+++ b/sound/soc/codecs/rt-sdw-common.h
@@ -0,0 +1,66 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+//
+// rt-sdw-common.h
+//
+// Copyright(c) 2024 Realtek Semiconductor Corp.
+//
+
+/*
+ * This file defines common functions used with Realtek soundwire codecs.
+ */
+
+#ifndef __RT_SDW_COMMON_H__
+#define __RT_SDW_COMMON_H__
+
+#define SDCA_NUM_JACK_CODEC			0x01
+#define SDCA_NUM_MIC_ARRAY			0x02
+#define SDCA_NUM_HID				0x03
+#define SDCA_NUM_AMP				0x04
+#define RT_SDCA_CTL_SELECTED_MODE		0x01
+#define RT_SDCA_CTL_DETECTED_MODE		0x02
+#define RT_SDCA_CTL_HIDTX_CURRENT_OWNER		0x10
+#define RT_SDCA_CTL_HIDTX_MESSAGE_OFFSET	0x12
+
+struct rt_sdca_dmic_kctrl_priv {
+	unsigned int reg_base;
+	unsigned int count;
+	unsigned int max;
+	unsigned int invert;
+};
+
+#define RT_SDCA_PR_VALUE(xreg_base, xcount, xmax, xinvert) \
+	((unsigned long)&(struct rt_sdca_dmic_kctrl_priv) \
+		{.reg_base = xreg_base, .count = xcount, .max = xmax, \
+		.invert = xinvert})
+
+#define RT_SDCA_FU_CTRL(xname, reg_base, xmax, xinvert, xcount, \
+	xinfo, xget, xput) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.info = xinfo, \
+	.get = xget, \
+	.put = xput, \
+	.private_value = RT_SDCA_PR_VALUE(reg_base, xcount, xmax, xinvert)}
+
+#define RT_SDCA_EXT_TLV(xname, reg_base, xhandler_get,\
+	 xhandler_put, xcount, xmax, tlv_array, xinfo) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+		 SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	.tlv.p = (tlv_array), \
+	.info = xinfo, \
+	.get = xhandler_get, .put = xhandler_put, \
+	.private_value = RT_SDCA_PR_VALUE(reg_base, xcount, xmax, 0) }
+
+
+int rt_sdca_index_write(struct regmap *map, unsigned int nid,
+	unsigned int reg, unsigned int value);
+int rt_sdca_index_read(struct regmap *map, unsigned int nid,
+	unsigned int reg, unsigned int *value);
+int rt_sdca_index_update_bits(struct regmap *map,
+	unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val);
+int rt_sdca_btn_type(unsigned char *buffer);
+int rt_sdca_headset_detect(struct regmap *map, unsigned int entity_id);
+int rt_sdca_button_detect(struct regmap *map, unsigned int entity_id,
+	unsigned int hid_buf_addr, unsigned int hid_id);
+
+#endif /* __RT_SDW_COMMON_H__ */