From 068973996b53eb65f305d0d0c1efa6ca502405c5 Mon Sep 17 00:00:00 2001 From: dianjixz <18637716021@163.com> Date: Thu, 5 Nov 2026 10:41:19 +0800 Subject: [PATCH] aw882xx: support building against Linux 4.19 through 7.x kernels The vendored driver only built on the kernel it shipped with. Make the sources compile and load across 4.19 up to the current 7.x Raspberry Pi kernels by guarding each API change with version checks. - aw882xx.c: wrap snd_soc_kcontrol_component() and snd_soc_(un)register_component() in helpers, since they are macros or removed on newer kernels and cannot be used as function pointers - aw882xx.c: accept SND_SOC_DAIFMT_CBC_CFC in place of the removed SND_SOC_DAIFMT_CBS_CFS, and GPIOF_IN in place of GPIOF_DIR_IN - aw882xx.c: open code of_get_named_gpio() with the gpio_device API for 7.1+, and drop the includes that no longer exist - aw882xx.c: use the single-argument i2c probe/remove signatures from 6.3 on and skip the devm_gpio_free() calls that are gone since 6.0 - aw882xx.h: use the string literal form of MODULE_IMPORT_NS() needed by 6.13+ - aw882xx*.c: replace the removed strlcpy() with strscpy() - Makefile: drop the duplicated aw882xx.o entry, apply the commented out aw882xx_calib.o filter, and make KDIR overridable so cross builds work - README.md: document native and cross compilation --- modules/aw882xx/README.md | 23 +++++ modules/aw882xx/src/Makefile | 13 +-- modules/aw882xx/src/aw882xx.c | 112 +++++++++++++++++++++--- modules/aw882xx/src/aw882xx.h | 5 ++ modules/aw882xx/src/aw882xx_bin_parse.c | 3 +- modules/aw882xx/src/aw882xx_device.c | 1 - modules/aw882xx/src/aw882xx_init.c | 1 - modules/aw882xx/src/aw882xx_monitor.c | 1 - modules/aw882xx/src/aw882xx_spin.c | 1 - 9 files changed, 137 insertions(+), 23 deletions(-) diff --git a/modules/aw882xx/README.md b/modules/aw882xx/README.md index 40026e5..05242d5 100644 --- a/modules/aw882xx/README.md +++ b/modules/aw882xx/README.md @@ -1,6 +1,29 @@ Note that the aw882xx_drv.ko file was compiled on 32-bit systems and can only be loaded on 32-bit systems. This file cannot be loaded using the `sudo depmod - a&&sudo modprobe aw882xx_drv` command. Only the `insmod aw882xx_drv.ko` command can be loaded. Otherwise, an irreversible error will be generated. This makefile only provides an installer, not a launcher. Please use the boot file to load. +## Building from source + +The prebuilt `bin/aw882xx_drv.ko` only loads on the kernel and architecture it +was built for, so rebuild it against the headers of the target kernel: + +``` bash +# on the device, for a 64-bit kernel +sudo apt install linux-headers-$(uname -r) +cd modules/aw882xx/src +make + +# cross compiling, e.g. for a 64-bit kernel on an x86 host +make KDIR=/path/to/raspberrypi/linux ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- + +# clean +make clean KDIR=/path/to/raspberrypi/linux +``` + +`KDIR` defaults to `/lib/modules/$(uname -r)/build`. The driver sources build +against Linux 4.19 through the current 7.x Raspberry Pi kernels; the ASoC, +GPIO and i2c API changes in between are handled with version checks in +`aw882xx.c` / `aw882xx.h`. + Please use the boot script to load the kernel file. Please refer to the following to write the boot script: # systemd Starts the system and runs rc.local diff --git a/modules/aw882xx/src/Makefile b/modules/aw882xx/src/Makefile index 5773c7d..e91fcf2 100644 --- a/modules/aw882xx/src/Makefile +++ b/modules/aw882xx/src/Makefile @@ -1,15 +1,14 @@ CONFIG_AW882XX_DRV:=m aw882xx_drv-y:= \ - aw882xx.o \ aw882xx.o \ aw882xx_monitor.o \ aw882xx_init.o \ aw882xx_dsp.o \ aw882xx_device.o \ aw882xx_bin_parse.o \ - aw882xx_spin.o \ -# aw882xx_calib.o + aw882xx_spin.o +# aw882xx_calib.o is intentionally left out: it needs the private VFS namespace #ccflags-y += -DDEBUG @@ -17,9 +16,11 @@ aw882xx_drv-y:= \ obj-$(CONFIG_AW882XX_DRV) += aw882xx_drv.o -LINUX_DIR=KDIR=/lib/modules/$(shell uname -r)/build +# Point KDIR at the kernel you are building for, e.g. +# make KDIR=/path/to/linux ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- +KDIR ?= /lib/modules/$(shell uname -r)/build all: - make -C ${LINUX_DIR} M=$(PWD) modules + $(MAKE) -C $(KDIR) M=$(CURDIR) modules clean: - make -C ${LINUX_DIR} M=$(PWD) clean + $(MAKE) -C $(KDIR) M=$(CURDIR) clean diff --git a/modules/aw882xx/src/aw882xx.c b/modules/aw882xx/src/aw882xx.c index a91e7e8..9afeafb 100755 --- a/modules/aw882xx/src/aw882xx.c +++ b/modules/aw882xx/src/aw882xx.c @@ -20,12 +20,18 @@ #include #include #include -#include #include #include #include #include #include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(7, 1, 0) +#include +#else +/* gpio_device_find_by_fwnode()/gpio_device_get_desc()/gpio_device_put() */ +#include +#endif #include #include #include @@ -63,12 +69,36 @@ static const char *const aw882xx_spin[] = {"spin_0", "spin_90", * ******************************************************/ #ifdef AW_KERNEL_VER_OVER_4_19_1 +/* + * snd_soc_kcontrol_component() (removed in 6.19) is a plain alias of + * snd_kcontrol_chip(), and snd_soc_(un)register_component() became macros + * on newer kernels. None of them can be used as function pointers in those + * cases, so hand the ops table small wrappers. + */ +static aw_snd_soc_codec_t *aw882xx_kcontrol_component( + struct snd_kcontrol *kcontrol) +{ + return snd_kcontrol_chip(kcontrol); +} + +static int aw882xx_register_component(struct device *dev, + const aw_snd_soc_codec_driver_t *codec_drv, + struct snd_soc_dai_driver *dai_drv, int num_dai) +{ + return snd_soc_register_component(dev, codec_drv, dai_drv, num_dai); +} + +static void aw882xx_unregister_component(struct device *dev) +{ + snd_soc_unregister_component(dev); +} + static struct aw_componet_codec_ops aw_componet_codec_ops = { - .kcontrol_codec = snd_soc_kcontrol_component, + .kcontrol_codec = aw882xx_kcontrol_component, .codec_get_drvdata = snd_soc_component_get_drvdata, .add_codec_controls = snd_soc_add_component_controls, - .unregister_codec = snd_soc_unregister_component, - .register_codec = snd_soc_register_component, + .unregister_codec = aw882xx_unregister_component, + .register_codec = aw882xx_register_component, }; #else static struct aw_componet_codec_ops aw_componet_codec_ops = { @@ -282,8 +312,16 @@ static int aw882xx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) /* Supported mode: regular I2S, slave, or PDM */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: +#ifdef SND_SOC_DAIFMT_CBC_CFC + /* codec consumes both bit clock and frame clock + * (the old SND_SOC_DAIFMT_CBS_CFS spelling, dropped in 6.15) + */ + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != + SND_SOC_DAIFMT_CBC_CFC) { +#else if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { +#endif aw_dev_err(codec->dev, "invalid codec master mode"); return -EINVAL; } @@ -475,7 +513,7 @@ static int aw882xx_profile_info(struct snd_kcontrol *kcontrol, count = uinfo->value.enumerated.item; ret = aw88xx_dev_get_profile_name(aw882xx->aw_pa, name, count); if (ret) { - strlcpy(uinfo->value.enumerated.name, "null", strlen("null") + 1); + strscpy(uinfo->value.enumerated.name, "null", strlen("null") + 1); return 0; } @@ -550,7 +588,7 @@ static int aw882xx_switch_info(struct snd_kcontrol *kcontrol, if (uinfo->value.enumerated.item >= count) uinfo->value.enumerated.item = count - 1; - strlcpy(uinfo->value.enumerated.name, + strscpy(uinfo->value.enumerated.name, aw882xx_switch[uinfo->value.enumerated.item], strlen(aw882xx_switch[uinfo->value.enumerated.item]) + 1); @@ -624,7 +662,7 @@ static int aw882xx_monitor_info(struct snd_kcontrol *kcontrol, if (uinfo->value.enumerated.item >= count) uinfo->value.enumerated.item = count - 1; - strlcpy(uinfo->value.enumerated.name, + strscpy(uinfo->value.enumerated.name, aw882xx_switch[uinfo->value.enumerated.item], strlen(aw882xx_switch[uinfo->value.enumerated.item]) + 1); @@ -1530,6 +1568,47 @@ int aw_componet_codec_register(struct aw882xx *aw882xx) * device tree * *****************************************************/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) +/* + * of_get_named_gpio() and were removed in Linux 7.1. + * Resolve the legacy "-gpio" property into a legacy GPIO number + * so the rest of the driver keeps working unchanged. + */ +static int aw882xx_of_get_named_gpio(struct device_node *np, + const char *propname, int index) +{ + struct of_phandle_args gpiospec; + struct gpio_device *gdev; + struct gpio_desc *desc; + int ret; + + if (!np) + return -ENOENT; + + ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", + index, &gpiospec); + if (ret) + return ret; + + gdev = gpio_device_find_by_fwnode(of_fwnode_handle(gpiospec.np)); + of_node_put(gpiospec.np); + if (!gdev) + return -EPROBE_DEFER; + + desc = gpio_device_get_desc(gdev, gpiospec.args[0]); + if (IS_ERR(desc)) + ret = PTR_ERR(desc); + else + ret = desc_to_gpio(desc); + + gpio_device_put(gdev); + return ret; +} +#else +#define aw882xx_of_get_named_gpio(np, propname, index) \ + of_get_named_gpio(np, propname, index) +#endif + static int aw882xx_parse_gpio_dt(struct aw882xx *aw882xx, struct device_node *np) { @@ -1539,13 +1618,13 @@ static int aw882xx_parse_gpio_dt(struct aw882xx *aw882xx, return -EINVAL; } - aw882xx->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); + aw882xx->reset_gpio = aw882xx_of_get_named_gpio(np, "reset-gpio", 0); if (aw882xx->reset_gpio < 0) { aw_dev_info(aw882xx->dev, "no reset gpio provided, will not HW reset device"); } else { aw_dev_info(aw882xx->dev, "reset gpio provided ok"); } - aw882xx->irq_gpio = of_get_named_gpio(np, "irq-gpio", 0); + aw882xx->irq_gpio = aw882xx_of_get_named_gpio(np, "irq-gpio", 0); if (aw882xx->irq_gpio < 0) { aw_dev_info(aw882xx->dev, "no irq gpio provided."); } else { @@ -1597,7 +1676,7 @@ static int aw882xx_gpio_request(struct aw882xx *aw882xx) if (gpio_is_valid(aw882xx->irq_gpio)) { ret = devm_gpio_request_one(aw882xx->dev, aw882xx->irq_gpio, - GPIOF_DIR_IN, "aw882xx_int"); + GPIOF_IN, "aw882xx_int"); if (ret) { aw_dev_err(aw882xx->dev, "int request failed"); return ret; @@ -2220,8 +2299,12 @@ static struct attribute_group aw882xx_attribute_group = { .attrs = aw882xx_attributes, }; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0) +static int aw882xx_i2c_probe(struct i2c_client *i2c) +#else static int aw882xx_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +#endif { int ret; struct aw882xx *aw882xx = NULL; @@ -2308,7 +2391,11 @@ static int aw882xx_i2c_probe(struct i2c_client *i2c, return ret; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0) +static void aw882xx_i2c_remove(struct i2c_client *i2c) +#else static int aw882xx_i2c_remove(struct i2c_client *i2c) +#endif { struct aw882xx *aw882xx = i2c_get_clientdata(i2c); @@ -2321,10 +2408,12 @@ static int aw882xx_i2c_remove(struct i2c_client *i2c) aw882xx); /*free gpio*/ +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0) if (gpio_is_valid(aw882xx->irq_gpio)) devm_gpio_free(&i2c->dev, aw882xx->irq_gpio); if (gpio_is_valid(aw882xx->reset_gpio)) devm_gpio_free(&i2c->dev, aw882xx->reset_gpio); +#endif /*rm attr node*/ sysfs_remove_group(&i2c->dev.kobj, &aw882xx_attribute_group); @@ -2346,8 +2435,9 @@ static int aw882xx_i2c_remove(struct i2c_client *i2c) } mutex_unlock(&g_aw882xx_lock); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0) return 0; - +#endif } static void aw882xx_i2c_shutdown(struct i2c_client *i2c) diff --git a/modules/aw882xx/src/aw882xx.h b/modules/aw882xx/src/aw882xx.h index 38ea672..85559fe 100755 --- a/modules/aw882xx/src/aw882xx.h +++ b/modules/aw882xx/src/aw882xx.h @@ -61,8 +61,13 @@ enum aw882xx_int_type { #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) #define AW_KERNEL_VER_OVER_5_4_0 +/* Linux 6.13 requires the namespace name to be a string literal */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0) +MODULE_IMPORT_NS("VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver"); +#else MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); #endif +#endif #ifdef AW_KERNEL_VER_OVER_4_19_1 diff --git a/modules/aw882xx/src/aw882xx_bin_parse.c b/modules/aw882xx/src/aw882xx_bin_parse.c index 83f6183..96ef1ca 100755 --- a/modules/aw882xx/src/aw882xx_bin_parse.c +++ b/modules/aw882xx/src/aw882xx_bin_parse.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -1361,7 +1360,7 @@ int aw88xx_dev_get_profile_name(struct aw_device *aw_dev, char *name, int index) dev_profile_id = prof_info->prof_desc[index].id; - strlcpy(name, prof_info->prof_name_list[dev_profile_id], + strscpy(name, prof_info->prof_name_list[dev_profile_id], strlen(prof_info->prof_name_list[dev_profile_id]) + 1); return 0; } diff --git a/modules/aw882xx/src/aw882xx_device.c b/modules/aw882xx/src/aw882xx_device.c index 350a9dc..6da2d8f 100755 --- a/modules/aw882xx/src/aw882xx_device.c +++ b/modules/aw882xx/src/aw882xx_device.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/modules/aw882xx/src/aw882xx_init.c b/modules/aw882xx/src/aw882xx_init.c index c0f0471..cb18500 100755 --- a/modules/aw882xx/src/aw882xx_init.c +++ b/modules/aw882xx/src/aw882xx_init.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/modules/aw882xx/src/aw882xx_monitor.c b/modules/aw882xx/src/aw882xx_monitor.c index 174a3af..06e87c7 100755 --- a/modules/aw882xx/src/aw882xx_monitor.c +++ b/modules/aw882xx/src/aw882xx_monitor.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/modules/aw882xx/src/aw882xx_spin.c b/modules/aw882xx/src/aw882xx_spin.c index 03b3dd9..f5b18cb 100755 --- a/modules/aw882xx/src/aw882xx_spin.c +++ b/modules/aw882xx/src/aw882xx_spin.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include