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