| @@ -60,6 +60,7 @@ Note:If the text contains special characters, please escape them according to th | |||
| 60 | <policylist> | 60 | <policylist> |
| 61 | <policy name="projectPolicy" desc=""> | 61 | <policy name="projectPolicy" desc=""> |
| 62 | <policyitem type="license" name="GPL" path=".*" desc="linux kernel adapter codes"/> | 62 | <policyitem type="license" name="GPL" path=".*" desc="linux kernel adapter codes"/> |
| 63 | + <policyitem type="copyright" name="HiSilicon (Shanghai) Technologies Co., Ltd." path=".*" desc="HiSilicon copyright"/> | ||
| 63 | </policy> | 64 | </policy> |
| 64 | </policylist> | 65 | </policylist> |
| 65 | </oatconfig> | 66 | </oatconfig> |
| @@ -0,0 +1,26 @@ | |||
| 1 | +diff --git a/arch/arm64/boot/dts/vendor/ss928v100-demb.dts b/arch/arm64/boot/dts/vendor/ss928v100-demb.dts | ||
| 2 | +index d90c5d5cf..a39158451 100644 | ||
| 3 | +--- a/arch/arm64/boot/dts/vendor/ss928v100-demb.dts | ||
| 4 | ++++ b/arch/arm64/boot/dts/vendor/ss928v100-demb.dts | ||
| 5 | + &gmac { | ||
| 6 | + | ||
| 7 | + &gmac1 { | ||
| 8 | + phy-handle = <ðphy1>; | ||
| 9 | +- phy-mode = "rgmii-id"; | ||
| 10 | ++ phy-mode = "rgmii"; | ||
| 11 | + }; | ||
| 12 | + | ||
| 13 | + &pcie0 { | ||
| 14 | +diff --git a/drivers/net/ethernet/vendor/gmac/gmac.c b/drivers/net/ethernet/vendor/gmac/gmac.c | ||
| 15 | +index 30247bd46..40bfe2386 100644 | ||
| 16 | +--- a/drivers/net/ethernet/vendor/gmac/gmac.c | ||
| 17 | ++++ b/drivers/net/ethernet/vendor/gmac/gmac.c | ||
| 18 | + static int gmac_netdev_preinit(struct gmac_netdev_local *priv) | ||
| 19 | + priv->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); | ||
| 20 | + | ||
| 21 | + #if defined(CONFIG_GMAC_DDR_64BIT) | ||
| 22 | +- ret = dma_set_mask_and_coherent(priv->dev, DMA_BIT_MASK(64)); /* 64: mask length */ | ||
| 23 | ++ ret = dma_set_mask_and_coherent(priv->dev, DMA_BIT_MASK(32)); /* 32: mask length */ | ||
| 24 | + if (ret) { | ||
| 25 | + pr_err("dma set mask bit 64 failed! ret=%d", ret); | ||
| 26 | + gmac_destroy_napi(priv); | ||
| @@ -0,0 +1,13 @@ | |||
| 1 | +diff --git a/arch/arm64/boot/dts/vendor/ss928v100.dtsi b/arch/arm64/boot/dts/vendor/ss928v100.dtsi | ||
| 2 | +index 80f4dcfb2..d285dd0a8 100644 | ||
| 3 | +--- a/arch/arm64/boot/dts/vendor/ss928v100.dtsi | ||
| 4 | ++++ b/arch/arm64/boot/dts/vendor/ss928v100.dtsi | ||
| 5 | + gpio_chip13: gpio_chip@1109D000 { | ||
| 6 | + clocks = <&clock SS928V100_FIXED_50M>; | ||
| 7 | + clock-names = "apb_pclk"; | ||
| 8 | + status = "disabled"; | ||
| 9 | ++ interrupt-controller; | ||
| 10 | ++ #interrupt-cells = <2>; | ||
| 11 | + }; | ||
| 12 | + | ||
| 13 | + gpio_chip14: gpio_chip@1109E000 { | ||
| @@ -0,0 +1,518 @@ | |||
| 1 | +diff --git a/arch/arm64/boot/dts/vendor/ss928v100-demb.dts b/arch/arm64/boot/dts/vendor/ss928v100-demb.dts | ||
| 2 | +index d90c5d5cf..b488894f5 100644 | ||
| 3 | +--- a/arch/arm64/boot/dts/vendor/ss928v100-demb.dts | ||
| 4 | ++++ b/arch/arm64/boot/dts/vendor/ss928v100-demb.dts | ||
| 5 | + &i2c_bus2 { | ||
| 6 | + | ||
| 7 | + &i2c_bus3 { | ||
| 8 | + status = "okay"; | ||
| 9 | ++ nca9555: ioexpander@20 { | ||
| 10 | ++ compatible = "nca9555"; | ||
[linux-6.6/hispark_aifly_patch/0007-kernel-nca9555.patch:10] DTS 节点缩进使用了空格,但内核 DTS 文件约定使用制表符(tab)缩进。请将 nca9555: ioexpander@20 节点内的缩进改为制表符以保持与文件其余部分一致。 ![]() ![]() | |||
| 11 | ++ reg = <0x20>; | ||
| 12 | ++ status = "okay"; | ||
| 13 | ++ }; | ||
| 14 | + }; | ||
| 15 | + | ||
| 16 | + &i2c_bus4 { | ||
| 17 | +diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig | ||
| 18 | +index ebd4e113d..7fbce8891 100644 | ||
| 19 | +--- a/drivers/gpio/Kconfig | ||
| 20 | ++++ b/drivers/gpio/Kconfig | ||
| 21 | + config GPIO_SIM | ||
| 22 | + endmenu | ||
| 23 | + | ||
| 24 | + endif | ||
| 25 | ++ | ||
| 26 | ++config GPIO_NCA9555 | ||
[linux-6.6/hispark_aifly_patch/0007-kernel-nca9555.patch:26] config GPIO_NCA9555 放在了 endif 之后,位于 if GPIOLIB 条件块之外,这意味着即使未启用 GPIOLIB 也会出现此配置选项。应将其移至 endmenu 之前、endif 之内。 ![]() ![]() | |||
| 27 | ++ tristate "NCA9555" | ||
| 28 | ++ default n | ||
| 29 | +diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile | ||
| 30 | +index f1f998da4..69407b9c5 100644 | ||
| 31 | +--- a/drivers/gpio/Makefile | ||
| 32 | ++++ b/drivers/gpio/Makefile | ||
| 33 | + obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o | ||
| 34 | + obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o | ||
| 35 | + obj-$(CONFIG_GPIO_ZYNQMP_MODEPIN) += gpio-zynqmp-modepin.o | ||
| 36 | + obj-$(CONFIG_ARCH_HISILICON) += vendor/ | ||
| 37 | ++obj-$(CONFIG_GPIO_NCA9555) += gpio-nca9555.o | ||
| 38 | + | ||
[linux-6.6/hispark_aifly_patch/0007-kernel-nca9555.patch:38] Makefile 末尾缺少换行符("No newline at end of file")。请在 obj-$(CONFIG_GPIO_NCA9555) 行末添加换行符,符合 POSIX 文本文件规范。 ![]() ![]() | |||
| 39 | +diff --git a/drivers/gpio/gpio-nca9555.c b/drivers/gpio/gpio-nca9555.c | ||
| 40 | +new file mode 100644 | ||
| 41 | +index 000000000..075c580da | ||
| 42 | +--- /dev/null | ||
| 43 | ++++ b/drivers/gpio/gpio-nca9555.c | ||
| 44 | + | ||
| 45 | ++// SPDX-License-Identifier: GPL-2.0-or-later | ||
| 46 | ++/* | ||
| 47 | ++ * GPIO driver for NCA9555 MFD | ||
| 48 | ++ * | ||
| 49 | ++ */ | ||
| 50 | ++ | ||
| 51 | ++#include <linux/module.h> | ||
| 52 | ++#include <linux/slab.h> | ||
| 53 | ++#include <linux/kernel.h> | ||
| 54 | ++#include <linux/init.h> | ||
| 55 | ++#include <linux/platform_device.h> | ||
| 56 | ++#include <linux/mfd/nca9555.h> | ||
| 57 | ++#include <linux/gpio/driver.h> | ||
| 58 | ++ | ||
| 59 | ++#define NCA9555_GPIO_MAX 16 | ||
| 60 | ++ | ||
| 61 | ++struct nca9555_gpio_dev { | ||
| 62 | ++ struct device *parent; | ||
| 63 | ++ struct gpio_chip gpio_chip; | ||
| 64 | ++ struct mutex lock; | ||
| 65 | ++ u8 dat_out[2]; | ||
| 66 | ++ u8 dir[2]; | ||
| 67 | ++}; | ||
| 68 | ++ | ||
| 69 | ++static int nca9555_gpio_reg_read(struct nca9555_gpio_dev *nca9555_gpio, u8 reg, u8 *val) | ||
| 70 | ++{ | ||
| 71 | ++ struct nca9555_dev *nca9555; | ||
| 72 | ++ nca9555 = dev_get_drvdata(nca9555_gpio->parent); | ||
| 73 | ++ | ||
| 74 | ++ return nca9555->read_reg(nca9555, reg, val); | ||
| 75 | ++} | ||
| 76 | ++ | ||
| 77 | ++static int nca9555_gpio_reg_write(struct nca9555_gpio_dev *nca9555_gpio, u8 reg, u8 val) | ||
| 78 | ++{ | ||
| 79 | ++ struct nca9555_dev *nca9555; | ||
| 80 | ++ nca9555 = dev_get_drvdata(nca9555_gpio->parent); | ||
| 81 | ++ | ||
| 82 | ++ return nca9555->write_reg(nca9555, reg, val); | ||
| 83 | ++} | ||
| 84 | ++ | ||
| 85 | ++static int nca9555_gpio_get_value(struct gpio_chip *chip, unsigned int off) | ||
| 86 | ++{ | ||
| 87 | ++ struct nca9555_gpio_dev *nca9555_gpio; | ||
| 88 | ++ unsigned int bank, bit; | ||
| 89 | ++ u8 val; | ||
| 90 | ++ | ||
| 91 | ++ nca9555_gpio = gpiochip_get_data(chip); | ||
| 92 | ++ bank = NCA9555_BANK(off); | ||
| 93 | ++ bit = NCA9555_BIT(off); | ||
| 94 | ++ | ||
| 95 | ++ mutex_lock(&nca9555_gpio->lock); | ||
| 96 | ++ /* There are dedicated registers for GPIO IN/OUT. */ | ||
| 97 | ++ if (nca9555_gpio->dir[bank] & bit) | ||
[linux-6.6/hispark_aifly_patch/0007-kernel-nca9555.patch:97] nca9555_gpio_get_value 中输入/输出方向判断逻辑反了:当 dir[bank] & bit 为真时(对应 CONFIG 寄存器 bit=1,即输入模式),代码返回 dat_out(输出缓存值);当 bit 为假时(CONFIG bit=0,即输出模式),代码读取输入寄存器。应交换两个分支:输入模式读输入寄存器,输出模式返回 dat_out 缓存值。 ![]() ![]() | |||
| 98 | ++ val = nca9555_gpio->dat_out[bank]; | ||
| 99 | ++ else | ||
| 100 | ++ nca9555_gpio_reg_read(nca9555_gpio, GPIO_PORT0_INPUT_REG + bank, &val); | ||
| 101 | ++ | ||
| 102 | ++ mutex_unlock(&nca9555_gpio->lock); | ||
| 103 | ++ | ||
| 104 | ++ return !!(val & bit); | ||
| 105 | ++} | ||
| 106 | ++ | ||
| 107 | ++static void nca9555_gpio_set_value(struct gpio_chip *chip, unsigned int off, int val) | ||
| 108 | ++{ | ||
| 109 | ++ struct nca9555_gpio_dev *nca9555_gpio; | ||
| 110 | ++ unsigned int bank, bit; | ||
| 111 | ++ | ||
| 112 | ++ nca9555_gpio = gpiochip_get_data(chip); | ||
| 113 | ++ bank = NCA9555_BANK(off); | ||
| 114 | ++ bit = NCA9555_BIT(off); | ||
| 115 | ++ | ||
| 116 | ++ mutex_lock(&nca9555_gpio->lock); | ||
| 117 | ++ if (val) | ||
| 118 | ++ nca9555_gpio->dat_out[bank] |= bit; | ||
| 119 | ++ else | ||
| 120 | ++ nca9555_gpio->dat_out[bank] &= ~bit; | ||
| 121 | ++ | ||
| 122 | ++ nca9555_gpio_reg_write(nca9555_gpio, GPIO_PORT0_OUTPUT_REG + bank, | ||
| 123 | ++ nca9555_gpio->dat_out[bank]); | ||
| 124 | ++ mutex_unlock(&nca9555_gpio->lock); | ||
| 125 | ++} | ||
| 126 | ++ | ||
| 127 | ++static int nca9555_gpio_direction_input(struct gpio_chip *chip, unsigned int off) | ||
| 128 | ++{ | ||
| 129 | ++ struct nca9555_gpio_dev *nca9555_gpio; | ||
| 130 | ++ unsigned int bank, bit; | ||
| 131 | ++ int ret; | ||
| 132 | ++ | ||
| 133 | ++ nca9555_gpio = gpiochip_get_data(chip); | ||
| 134 | ++ bank = NCA9555_BANK(off); | ||
| 135 | ++ bit = NCA9555_BIT(off); | ||
| 136 | ++ | ||
| 137 | ++ mutex_lock(&nca9555_gpio->lock); | ||
| 138 | ++ nca9555_gpio->dir[bank] |= bit; | ||
| 139 | ++ ret = nca9555_gpio_reg_write(nca9555_gpio, GPIO_PORT0_CONFIG_REG + bank, | ||
| 140 | ++ nca9555_gpio->dir[bank]); | ||
| 141 | ++ mutex_unlock(&nca9555_gpio->lock); | ||
| 142 | ++ return ret; | ||
| 143 | ++} | ||
| 144 | ++ | ||
| 145 | ++static int nca9555_gpio_direction_output(struct gpio_chip *chip, unsigned int off, int val) | ||
| 146 | ++{ | ||
| 147 | ++ struct nca9555_gpio_dev *nca9555_gpio; | ||
| 148 | ++ unsigned int bank, bit; | ||
| 149 | ++ int ret; | ||
| 150 | ++ | ||
| 151 | ++ nca9555_gpio = gpiochip_get_data(chip); | ||
| 152 | ++ | ||
| 153 | ++ bank = NCA9555_BANK(off); | ||
| 154 | ++ bit = NCA9555_BIT(off); | ||
| 155 | ++ | ||
| 156 | ++ mutex_lock(&nca9555_gpio->lock); | ||
| 157 | ++ // 配置为输出:先更新输出电平寄存器,再设置方向寄存器 | ||
| 158 | ++ // 设计目的:防止先切输出方向时引脚出现未知电平毛刺 | ||
| 159 | ++ nca9555_gpio->dir[bank] &= ~bit; | ||
| 160 | ++ | ||
| 161 | ++ if (val) | ||
| 162 | ++ nca9555_gpio->dat_out[bank] |= bit; | ||
| 163 | ++ else | ||
| 164 | ++ nca9555_gpio->dat_out[bank] &= ~bit; | ||
| 165 | ++ | ||
| 166 | ++ // 1. 先写入目标输出电平 | ||
| 167 | ++ ret = nca9555_gpio_reg_write(nca9555_gpio, GPIO_PORT0_OUTPUT_REG + bank, | ||
| 168 | ++ nca9555_gpio->dat_out[bank]); | ||
| 169 | ++ // 2. 再配置引脚为输出模式 | ||
| 170 | ++ ret |= nca9555_gpio_reg_write(nca9555_gpio, GPIO_PORT0_CONFIG_REG + bank, | ||
[linux-6.6/hispark_aifly_patch/0007-kernel-nca9555.patch:170] 使用 ret |= 合并两次 reg_write 的返回值是错误的错误处理方式。若第一次写入成功(返回 0),第二次失败(返回 -EIO),0 | -EIO 的结果并非有效的错误码。建议对每次 reg_write 分别检查返回值,第一次失败时直接返回错误。 ![]() ![]() | |||
| 171 | ++ nca9555_gpio->dir[bank]); | ||
| 172 | ++ | ||
| 173 | ++ mutex_unlock(&nca9555_gpio->lock); | ||
| 174 | ++ | ||
| 175 | ++ return ret; | ||
| 176 | ++} | ||
| 177 | ++ | ||
| 178 | ++static int nca9555_gpio_probe(struct platform_device *pdev) | ||
| 179 | ++{ | ||
| 180 | ++ struct nca9555_gpio_dev *nca9555_gpio; | ||
| 181 | ++ struct device *dev = &pdev->dev; | ||
| 182 | ++ struct device_node *np = dev->of_node; | ||
| 183 | ++ struct gpio_chip *gc; | ||
| 184 | ++ int i; | ||
| 185 | ++ int ret; | ||
| 186 | ++ | ||
| 187 | ++ dev_info(dev, "gpio-nca9555 probe start \n"); | ||
| 188 | ++ | ||
| 189 | ++ nca9555_gpio = devm_kzalloc(&pdev->dev, sizeof(struct nca9555_gpio_dev), GFP_KERNEL); | ||
| 190 | ++ if (!nca9555_gpio) | ||
| 191 | ++ return -ENOMEM; | ||
| 192 | ++ | ||
| 193 | ++ nca9555_gpio->parent = pdev->dev.parent; | ||
| 194 | ++ | ||
| 195 | ++ gc = &nca9555_gpio->gpio_chip; | ||
| 196 | ++ gc->fwnode = dev_fwnode(dev); | ||
| 197 | ++ gc->parent = dev; | ||
| 198 | ++ gc->direction_input = nca9555_gpio_direction_input; | ||
| 199 | ++ gc->direction_output = nca9555_gpio_direction_output; | ||
| 200 | ++ gc->get = nca9555_gpio_get_value; | ||
| 201 | ++ gc->set = nca9555_gpio_set_value; | ||
| 202 | ++ gc->can_sleep = true; | ||
| 203 | ++ | ||
| 204 | ++ gc->base = -1; | ||
| 205 | ++ gc->ngpio = NCA9555_GPIO_MAX; | ||
| 206 | ++ gc->label = pdev->name; | ||
| 207 | ++ gc->owner = THIS_MODULE; | ||
| 208 | ++ | ||
| 209 | ++ mutex_init(&nca9555_gpio->lock); | ||
| 210 | ++ | ||
| 211 | ++ for (i = 0; i < 2; i++) { | ||
| 212 | ++ u8 *dat_out, *dir; | ||
| 213 | ++ dat_out = nca9555_gpio->dat_out; | ||
| 214 | ++ dir = nca9555_gpio->dir; | ||
| 215 | ++ ret = nca9555_gpio_reg_read(nca9555_gpio, | ||
| 216 | ++ GPIO_PORT0_OUTPUT_REG + i, dat_out + i); | ||
| 217 | ++ if (ret) { | ||
| 218 | ++ dev_err(dev, "read output port%d reg fail, ret=%d\n", i, ret); | ||
| 219 | ++ return ret; | ||
| 220 | ++ } | ||
| 221 | ++ ret = nca9555_gpio_reg_read(nca9555_gpio, | ||
| 222 | ++ GPIO_PORT0_CONFIG_REG + i, dir + i); | ||
| 223 | ++ if (ret) { | ||
| 224 | ++ dev_err(dev, "read config port%d reg fail, ret=%d\n", i, ret); | ||
| 225 | ++ return ret; | ||
| 226 | ++ } | ||
| 227 | ++ } | ||
| 228 | ++ | ||
| 229 | ++ dev_info(dev, "gpio-nca9555 probe succes \n"); | ||
| 230 | ++ | ||
| 231 | ++ return devm_gpiochip_add_data(&pdev->dev, &nca9555_gpio->gpio_chip, nca9555_gpio); | ||
| 232 | ++} | ||
| 233 | ++ | ||
| 234 | ++static const struct of_device_id nca9555_of_match[] = { | ||
| 235 | ++ {.compatible = "nca9555-gpio", }, | ||
| 236 | ++ { /* sentinel */ } | ||
| 237 | ++}; | ||
| 238 | ++MODULE_DEVICE_TABLE(of, nca9555_of_match); | ||
| 239 | ++ | ||
| 240 | ++static struct platform_driver nca9555_gpio_driver = { | ||
| 241 | ++ .driver = { | ||
| 242 | ++ .name = "nca9555-gpio", | ||
| 243 | ++ .of_match_table = nca9555_of_match, | ||
| 244 | ++ }, | ||
| 245 | ++ .probe = nca9555_gpio_probe, | ||
| 246 | ++}; | ||
| 247 | ++ | ||
| 248 | ++module_platform_driver(nca9555_gpio_driver); | ||
| 249 | ++ | ||
| 250 | ++MODULE_DESCRIPTION("GPIO NCA9555 Driver"); | ||
| 251 | ++MODULE_LICENSE("GPL"); | ||
| 252 | +diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig | ||
| 253 | +index 459e737c5..3f6687e8f 100644 | ||
| 254 | +--- a/drivers/mfd/Kconfig | ||
| 255 | ++++ b/drivers/mfd/Kconfig | ||
| 256 | + config MFD_RSMU_SPI | ||
| 257 | + | ||
| 258 | + endmenu | ||
| 259 | + endif | ||
| 260 | ++ | ||
| 261 | ++config MFD_NCA9555 | ||
[linux-6.6/hispark_aifly_patch/0007-kernel-nca9555.patch:261] config MFD_NCA9555 缺少 depends on I2C 依赖。MFD 核心驱动 nca9555.c 使用 I2C 通信,若未启用 I2C 子系统,编译将失败。同时该配置也位于 endmenu 和 endif 之外,应移入条件块内。 ![]() ![]() | |||
| 262 | ++ tristate "NCA9555" | ||
| 263 | ++ select MFD_CORE | ||
| 264 | ++ default n | ||
| 265 | +diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile | ||
| 266 | +index 7e57a4983..f1ac14598 100644 | ||
| 267 | +--- a/drivers/mfd/Makefile | ||
| 268 | ++++ b/drivers/mfd/Makefile | ||
| 269 | + obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o | ||
| 270 | + | ||
| 271 | + obj-$(CONFIG_MFD_RSMU_I2C) += rsmu_i2c.o rsmu_core.o | ||
| 272 | + obj-$(CONFIG_MFD_RSMU_SPI) += rsmu_spi.o rsmu_core.o | ||
| 273 | ++obj-$(CONFIG_MFD_NCA9555) += nca9555.o | ||
| 274 | +diff --git a/drivers/mfd/nca9555.c b/drivers/mfd/nca9555.c | ||
| 275 | +new file mode 100644 | ||
| 276 | +index 000000000..30f6de079 | ||
| 277 | +--- /dev/null | ||
| 278 | ++++ b/drivers/mfd/nca9555.c | ||
| 279 | + | ||
| 280 | ++/* SPDX-License-Identifier: GPL-2.0-or-later */ | ||
| 281 | ++/* NCA9555 IO Expander, Key controller core driver. | ||
| 282 | ++ * | ||
| 283 | ++ * Copyright 2023 RPDZKJ | ||
| 284 | ++ */ | ||
| 285 | ++ | ||
| 286 | ++#include <linux/module.h> | ||
| 287 | ++#include <linux/moduleparam.h> | ||
| 288 | ++#include <linux/init.h> | ||
| 289 | ++#include <linux/slab.h> | ||
| 290 | ++#include <linux/i2c.h> | ||
| 291 | ++#include <linux/of.h> | ||
| 292 | ++#include <linux/mfd/core.h> | ||
| 293 | ++#include <linux/mfd/nca9555.h> | ||
| 294 | ++#include <linux/io.h> | ||
| 295 | ++static const struct mfd_cell nca9555_devs[] = { | ||
| 296 | ++ { | ||
| 297 | ++ .name = "nca9555-gpio", | ||
| 298 | ++ .of_compatible = "nca9555-gpio", | ||
| 299 | ++ } | ||
| 300 | ++}; | ||
| 301 | ++ | ||
| 302 | ++static int nca9555_i2c_read_reg(struct nca9555_dev *nca9555, u8 reg, u8 *val) | ||
| 303 | ++{ | ||
| 304 | ++ struct i2c_client *i2c = nca9555->i2c_client; | ||
| 305 | ++ struct i2c_msg xfer[2]; | ||
| 306 | ++ int ret; | ||
| 307 | ++ | ||
| 308 | ++ /* Write register */ | ||
| 309 | ++ xfer[0].addr = i2c->addr; | ||
| 310 | ++ xfer[0].flags = 0; | ||
| 311 | ++ xfer[0].len = 1; | ||
| 312 | ++ xfer[0].buf = ® | ||
| 313 | ++ | ||
| 314 | ++ /* Read data */ | ||
| 315 | ++ xfer[1].addr = i2c->addr; | ||
| 316 | ++ xfer[1].flags = I2C_M_RD; | ||
| 317 | ++ xfer[1].len = 1; | ||
| 318 | ++ xfer[1].buf = val; | ||
| 319 | ++ | ||
| 320 | ++ ret = i2c_transfer(i2c->adapter, xfer, 2); | ||
| 321 | ++ if (ret == 2) { | ||
| 322 | ++ return 0; | ||
| 323 | ++ } else { | ||
| 324 | ++ dev_err(&i2c->dev, | ||
| 325 | ++ "Failed to read reg 0x%02x, ret is %d\n", | ||
| 326 | ++ reg, ret); | ||
| 327 | ++ if ( ret >=0) | ||
| 328 | ++ return -EIO; | ||
| 329 | ++ else | ||
| 330 | ++ return ret; | ||
| 331 | ++ } | ||
| 332 | ++} | ||
| 333 | ++ | ||
| 334 | ++static int nca9555_i2c_write_reg(struct nca9555_dev *nca9555, u8 reg, u8 val) | ||
| 335 | ++{ | ||
| 336 | ++ struct i2c_client *i2c = nca9555->i2c_client; | ||
| 337 | ++ u8 msg[2]; | ||
| 338 | ++ int ret; | ||
| 339 | ++ | ||
| 340 | ++ msg[0] = reg; | ||
| 341 | ++ msg[1] = val; | ||
| 342 | ++ ret = i2c_master_send(i2c, msg, 2); | ||
| 343 | ++ if (ret == 2) { | ||
| 344 | ++ return 0; | ||
| 345 | ++ } else { | ||
| 346 | ++ dev_err(&i2c->dev, | ||
| 347 | ++ "Failed to write reg 0x%02x, ret is %d\n", | ||
| 348 | ++ reg, ret); | ||
| 349 | ++ if ( ret >=0) | ||
| 350 | ++ return -EIO; | ||
| 351 | ++ else | ||
| 352 | ++ return ret; | ||
| 353 | ++ } | ||
| 354 | ++} | ||
| 355 | ++ | ||
| 356 | ++static int nca9555_i2c_probe(struct i2c_client *i2c) | ||
| 357 | ++{ | ||
| 358 | ++ struct nca9555_dev *nca9555; | ||
| 359 | ++ int ret; | ||
| 360 | ++ struct device *dev = &i2c->dev; | ||
| 361 | ++ | ||
| 362 | ++ dev_info(dev, "Enter probe, i2c addr:0x%02x\n", i2c->addr); | ||
| 363 | ++ | ||
| 364 | ++ nca9555 = devm_kzalloc(dev, sizeof(struct nca9555_dev), GFP_KERNEL); | ||
| 365 | ++ if (!nca9555) { | ||
| 366 | ++ dev_err(dev, "devm_kzalloc failed\n"); | ||
| 367 | ++ return -ENOMEM; | ||
| 368 | ++ } | ||
| 369 | ++ dev_info(dev, "alloc nca9555 dev struct ok\n"); | ||
| 370 | ++ | ||
| 371 | ++ i2c_set_clientdata(i2c, nca9555); | ||
| 372 | ++ nca9555->dev = dev; | ||
| 373 | ++ nca9555->i2c_client = i2c; | ||
| 374 | ++ nca9555->read_reg = nca9555_i2c_read_reg; | ||
| 375 | ++ nca9555->write_reg = nca9555_i2c_write_reg; | ||
| 376 | ++ dev_info(dev, "bind reg ops complete\n"); | ||
| 377 | ++ | ||
| 378 | ++ if (!dev->of_node) { | ||
| 379 | ++ dev_err(dev, "no device tree node, reject probe\n"); | ||
| 380 | ++ return -ENODEV; | ||
| 381 | ++ } | ||
| 382 | ++ u32 dts_addr; | ||
[linux-6.6/hispark_aifly_patch/0007-kernel-nca9555.patch:382] u32 dts_addr 变量声明位于 dev_err 语句之后,违反内核代码风格(C89 要求变量声明在块开头)。请将 u32 dts_addr 声明移至 nca9555_i2c_probe 函数开头的变量声明区域。 ![]() ![]() | |||
| 383 | ++ ret = of_property_read_u32(dev->of_node, "reg", &dts_addr); | ||
| 384 | ++ if (ret || dts_addr != i2c->addr) { | ||
| 385 | ++ dev_err(dev, "reg mismatch: dts=0x%x client=0x%02x, ret=%d\n", | ||
| 386 | ++ dts_addr, i2c->addr, ret); | ||
| 387 | ++ return -ENODEV; | ||
| 388 | ++ } | ||
| 389 | ++ | ||
| 390 | ++ ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, | ||
| 391 | ++ nca9555_devs, ARRAY_SIZE(nca9555_devs), | ||
| 392 | ++ NULL, 0, NULL); | ||
| 393 | ++ if (ret) { | ||
| 394 | ++ dev_err(dev, "devm_mfd_add_devices failed, ret=%d, err=%pE\n", ret, ERR_PTR(ret)); | ||
| 395 | ++ return ret; | ||
| 396 | ++ } | ||
| 397 | ++ dev_info(dev, "probe finished successfully\n"); | ||
| 398 | ++ | ||
| 399 | ++ return 0; | ||
| 400 | ++} | ||
| 401 | ++ | ||
| 402 | ++static const struct i2c_device_id nca9555_i2c_id[] = { | ||
| 403 | ++ { "nca9555", 0 }, | ||
| 404 | ++ { /* sentinel */ } | ||
| 405 | ++}; | ||
| 406 | ++MODULE_DEVICE_TABLE(i2c, nca9555_i2c_id); | ||
| 407 | ++ | ||
| 408 | ++static const struct of_device_id nca9555_of_match[] = { | ||
| 409 | ++ {.compatible = "nca9555", }, | ||
| 410 | ++ { /* sentinel */ } | ||
| 411 | ++}; | ||
| 412 | ++MODULE_DEVICE_TABLE(of, nca9555_of_match); | ||
| 413 | ++ | ||
| 414 | ++static struct i2c_driver nca9555_i2c_driver = { | ||
| 415 | ++ .driver = { | ||
| 416 | ++ .name = "nca9555", | ||
| 417 | ++ .of_match_table = of_match_ptr(nca9555_of_match), | ||
| 418 | ++ }, | ||
| 419 | ++ .probe = nca9555_i2c_probe, | ||
| 420 | ++ .id_table = nca9555_i2c_id, | ||
| 421 | ++}; | ||
| 422 | ++ | ||
| 423 | ++static int __init nca9555_i2c_init(void) | ||
| 424 | ++{ | ||
| 425 | ++ return i2c_add_driver(&nca9555_i2c_driver); | ||
| 426 | ++} | ||
| 427 | ++/* init early so consumer devices can complete system boot */ | ||
| 428 | ++subsys_initcall(nca9555_i2c_init); | ||
[linux-6.6/hispark_aifly_patch/0007-kernel-nca9555.patch:428] 使用 subsys_initcall 而非标准的 module_i2c_driver() 宏。I2C 驱动通常使用 module_i2c_driver() 注册,它能正确处理模块加载/卸载逻辑。若确实需要早期初始化,请添加注释说明原因;否则建议改用 module_i2c_driver(nca9555_i2c_driver) 并删除手动定义的 init/exit 函数。 ![]() ![]() | |||
| 429 | ++ | ||
| 430 | ++static void __exit nca9555_i2c_exit(void) | ||
| 431 | ++{ | ||
| 432 | ++ i2c_del_driver(&nca9555_i2c_driver); | ||
| 433 | ++} | ||
| 434 | ++module_exit(nca9555_i2c_exit); | ||
| 435 | ++ | ||
| 436 | ++MODULE_DESCRIPTION("NCA9555 core driver"); | ||
| 437 | ++MODULE_LICENSE("GPL"); | ||
| 438 | +diff --git a/include/dt-bindings/gpio/nca9555-gpio.h b/include/dt-bindings/gpio/nca9555-gpio.h | ||
| 439 | +new file mode 100644 | ||
| 440 | +index 000000000..62fead2db | ||
| 441 | +--- /dev/null | ||
| 442 | ++++ b/include/dt-bindings/gpio/nca9555-gpio.h | ||
| 443 | + | ||
| 444 | ++/* SPDX-License-Identifier: GPL-2.0-only */ | ||
| 445 | ++/* | ||
| 446 | ++ * GPIO definitions for NCA9555 | ||
| 447 | ++ * | ||
| 448 | ++ * Copyright (C) 2023 RPDZKJ | ||
| 449 | ++ */ | ||
| 450 | ++ | ||
| 451 | ++#ifndef _DT_BINDINGS_NCA9555_GPIO_H | ||
| 452 | ++#define _DT_BINDINGS_NCA9555_GPIO_H | ||
| 453 | ++ | ||
| 454 | ++#define IO_00 0 | ||
| 455 | ++#define IO_01 1 | ||
| 456 | ++#define IO_02 2 | ||
| 457 | ++#define IO_03 3 | ||
| 458 | ++#define IO_04 4 | ||
| 459 | ++#define IO_05 5 | ||
| 460 | ++#define IO_06 6 | ||
| 461 | ++#define IO_07 7 | ||
| 462 | ++ | ||
| 463 | ++#define IO_10 8 | ||
| 464 | ++#define IO_11 9 | ||
| 465 | ++#define IO_12 10 | ||
| 466 | ++#define IO_13 11 | ||
| 467 | ++#define IO_14 12 | ||
| 468 | ++#define IO_15 13 | ||
| 469 | ++#define IO_16 14 | ||
| 470 | ++#define IO_17 15 | ||
| 471 | ++ | ||
| 472 | ++#endif /* _DT_BINDINGS_NCA9555_GPIO_H */ | ||
| 473 | +diff --git a/include/linux/mfd/nca9555.h b/include/linux/mfd/nca9555.h | ||
| 474 | +new file mode 100644 | ||
| 475 | +index 000000000..321aea2bf | ||
| 476 | +--- /dev/null | ||
| 477 | ++++ b/include/linux/mfd/nca9555.h | ||
| 478 | + | ||
| 479 | ++/* SPDX-License-Identifier: GPL-2.0-or-later */ | ||
| 480 | ++/* | ||
| 481 | ++ * Analog Devices NCA9555 I/O Expander, keypad controller, | ||
| 482 | ++ * PWM contorller. | ||
| 483 | ++ */ | ||
| 484 | ++ | ||
| 485 | ++#ifndef __NCA9555_H_ | ||
| 486 | ++#define __NCA9555_H_ | ||
| 487 | ++ | ||
| 488 | ++ | ||
| 489 | ++#define GPIO_PORT0 0 | ||
| 490 | ++#define GPIO_PORT1 1 | ||
| 491 | ++ | ||
| 492 | ++#define GPIO_PORT0_INPUT_REG 0x00 | ||
| 493 | ++#define GPIO_PORT1_INPUT_REG 0x01 | ||
| 494 | ++ | ||
| 495 | ++#define GPIO_PORT0_OUTPUT_REG 0x02 | ||
| 496 | ++#define GPIO_PORT1_OUTPUT_REG 0x03 | ||
| 497 | ++ | ||
| 498 | ++#define GPIO_PORT0_POLAR_REG 0x04 | ||
| 499 | ++#define GPIO_PORT1_POLAR_REG 0x05 | ||
| 500 | ++ | ||
| 501 | ++#define GPIO_PORT0_CONFIG_REG 0x06 | ||
| 502 | ++#define GPIO_PORT1_CONFIG_REG 0x07 | ||
| 503 | ++ | ||
| 504 | ++#define NCA9555_ID 0x00 | ||
| 505 | ++ | ||
| 506 | ++#define NCA9555_BANK(offs) ((offs) >= 8) | ||
| 507 | ++#define NCA9555_BIT(offs) ((offs) >= 8 ? \ | ||
| 508 | ++ 1u << (offs - 8) : 1u << (offs)) | ||
| 509 | ++ | ||
| 510 | ++struct nca9555_dev { | ||
| 511 | ++ struct device *dev; | ||
| 512 | ++ struct i2c_client *i2c_client; | ||
| 513 | ++ | ||
| 514 | ++ int (*read_reg)(struct nca9555_dev *nca9555, u8 reg, u8 *val); | ||
| 515 | ++ int (*write_reg)(struct nca9555_dev *nca9555, u8 reg, u8 val); | ||
| 516 | ++}; | ||
| 517 | ++ | ||
| 518 | ++#endif | ||
| @@ -0,0 +1,51 @@ | |||
| 1 | +diff --git a/arch/arm64/boot/dts/vendor/ss928v100-demb.dts b/arch/arm64/boot/dts/vendor/ss928v100-demb.dts | ||
| 2 | +index 529e33fe0..bdffb0627 100644 | ||
| 3 | +--- a/arch/arm64/boot/dts/vendor/ss928v100-demb.dts | ||
| 4 | ++++ b/arch/arm64/boot/dts/vendor/ss928v100-demb.dts | ||
| 5 | + | ||
| 6 | + /* Modify this configuration according to the system framework */ | ||
| 7 | + /memreserve/ 0x52fff000 0x01a02000; | ||
| 8 | + #include "ss928v100.dtsi" | ||
| 9 | ++#include <dt-bindings/input/input.h> | ||
| 10 | + | ||
| 11 | + / { | ||
| 12 | + model = "Vendor SS928V100 DEMO Board"; | ||
| 13 | + memory { | ||
| 14 | + device_type = "memory"; | ||
| 15 | + reg = <0x0 0x50000000 0x1 0xf0000000>; /* system memory base */ | ||
| 16 | + }; | ||
| 17 | ++ | ||
| 18 | ++ gpio-keys { | ||
| 19 | ++ compatible = "gpio-keys"; | ||
| 20 | ++ label = "board_gpio_key"; | ||
| 21 | ++ status = "okay"; | ||
| 22 | ++ | ||
| 23 | ++ power-key { | ||
| 24 | ++ label = "Power Key"; | ||
| 25 | ++ linux,code = <KEY_POWER>; | ||
| 26 | ++ gpios = <&gpio_chip11 2 GPIO_ACTIVE_HIGH>; | ||
[linux-6.6/hispark_aifly_patch/0008-power-key-dts.patch:26] 电源按键使用 GPIO_ACTIVE_HIGH,但大多数硬件设计中电源按键按下时将 GPIO 拉低,通常使用 GPIO_ACTIVE_LOW。请确认 HiSpark AiFly 开发板的电源按键硬件设计:若按键按下为低电平,应改为 GPIO_ACTIVE_LOW。 ![]() ![]() | |||
| 27 | ++ debounce-interval = <50>; | ||
| 28 | ++ }; | ||
| 29 | ++ | ||
| 30 | ++ backlight-key { | ||
| 31 | ++ label = "BackLight Key"; | ||
| 32 | ++ linux,code = <KEY_BRIGHTNESSDOWN>; | ||
| 33 | ++ gpios = <&gpio_chip11 3 GPIO_ACTIVE_HIGH>; | ||
| 34 | ++ debounce-interval = <50>; | ||
| 35 | ++ }; | ||
| 36 | ++ }; | ||
| 37 | + }; | ||
| 38 | + | ||
| 39 | + &ipcm { | ||
| 40 | +diff --git a/arch/arm64/boot/dts/vendor/ss928v100.dtsi b/arch/arm64/boot/dts/vendor/ss928v100.dtsi | ||
| 41 | +index d285dd0a8..376dac2ac 100644 | ||
| 42 | +--- a/arch/arm64/boot/dts/vendor/ss928v100.dtsi | ||
| 43 | ++++ b/arch/arm64/boot/dts/vendor/ss928v100.dtsi | ||
| 44 | + | ||
| 45 | + #include <dt-bindings/interrupt-controller/irq.h> | ||
| 46 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 47 | + #include "ss928v100_family_usb.dtsi" | ||
| 48 | ++#include <dt-bindings/gpio/gpio.h> | ||
| 49 | + | ||
| 50 | + / { | ||
| 51 | + #address-cells = <2>; | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | +diff --git a/drivers/Makefile b/drivers/Makefile | ||
| 2 | +--- a/drivers/Makefile | ||
| 3 | ++++ b/drivers/Makefile | ||
| 4 | + | ||
| 5 | + | ||
| 6 | + obj-$(CONFIG_ACCESS_TOKENID) += accesstokenid/ | ||
| 7 | + obj-$(CONFIG_HCK_VENDOR_HOOKS) += hck/ | ||
| 8 | ++obj-$(CONFIG_ARCH_SS928V100) += hdf/soc_driver/ | ||
| @@ -0,0 +1,412 @@ | |||
| 1 | +diff --git a/arch/arm64/boot/dts/vendor/ss928v100-demb.dts b/arch/arm64/boot/dts/vendor/ss928v100-demb.dts | ||
| 2 | +index c202cdb08..de6f1d0d0 100644 | ||
| 3 | +--- a/arch/arm64/boot/dts/vendor/ss928v100-demb.dts | ||
| 4 | ++++ b/arch/arm64/boot/dts/vendor/ss928v100-demb.dts | ||
| 5 | + backlight-key { | ||
| 6 | + debounce-interval = <50>; | ||
| 7 | + }; | ||
| 8 | + }; | ||
| 9 | ++ | ||
| 10 | ++ /* | ||
| 11 | ++ * Quectel EC20 board PERST: idle/run level is low (legacy gpio-hog | ||
| 12 | ++ * used output-low). Driver pulses high >= 150ms then returns low. | ||
| 13 | ++ */ | ||
| 14 | ++ ec20_4g { | ||
[linux-6.6/hispark_aifly_patch/0010-kernel-quectel-4g.patch:14] DTS ![]() ![]() | |||
| 15 | ++ compatible = "quectel,ec20-4g"; | ||
| 16 | ++ reset-gpios = <&gpio_chip1 5 GPIO_ACTIVE_HIGH>; | ||
| 17 | ++ status = "okay"; | ||
| 18 | ++ }; | ||
| 19 | + }; | ||
| 20 | + | ||
| 21 | + &ipcm { | ||
| 22 | +diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig | ||
| 23 | +index ef8d1c73c..615dd8726 100644 | ||
| 24 | +--- a/drivers/usb/serial/Kconfig | ||
| 25 | ++++ b/drivers/usb/serial/Kconfig | ||
| 26 | + config USB_SERIAL_OPTION | ||
| 27 | + If this driver doesn't recognize your device, | ||
| 28 | + it might be accessible via the FTDI_SIO driver. | ||
| 29 | + | ||
| 30 | ++config USB_SERIAL_QUECTEL_SUPPORT | ||
| 31 | ++ bool "Quectel USB serial modem extensions" | ||
[linux-6.6/hispark_aifly_patch/0010-kernel-quectel-4g.patch:31] ![]() ![]() | |||
| 32 | ++ depends on USB_SERIAL_OPTION | ||
| 33 | ++ help | ||
| 34 | ++ Enable Quectel-specific extensions for option, usb_wwan and | ||
| 35 | ++ qcserial: extra device IDs, zero-length packet, probe quirks, | ||
| 36 | ++ termios init, and EC20 PERST reset sequence. | ||
| 37 | ++ | ||
| 38 | ++ Say Y if your board uses a Quectel modem such as EC20. | ||
| 39 | ++ | ||
| 40 | + config USB_SERIAL_OMNINET | ||
| 41 | + tristate "USB ZyXEL omni.net LCD Plus Driver" | ||
| 42 | + help | ||
| 43 | +diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c | ||
| 44 | +index 6c6387d39..410f82e91 100644 | ||
| 45 | +--- a/drivers/usb/serial/option.c | ||
| 46 | ++++ b/drivers/usb/serial/option.c | ||
| 47 | + static void option_instat_callback(struct urb *urb); | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + static const struct usb_device_id option_ids[] = { | ||
| 51 | ++#ifdef CONFIG_USB_SERIAL_QUECTEL_SUPPORT | ||
| 52 | ++ { USB_DEVICE(0x05C6, 0x9090) }, /* Quectel UC15 */ | ||
[linux-6.6/hispark_aifly_patch/0010-kernel-quectel-4g.patch:52] 新增的 Quectel USB 设备 ID 列表中有部分 ID 可能已存在于上游 ![]() ![]() | |||
| 53 | ++ { USB_DEVICE(0x05C6, 0x9003) }, /* Quectel UC20 */ | ||
| 54 | ++ { USB_DEVICE(0x05C6, 0x9215) }, /* Quectel EC20(MDM9215) */ | ||
| 55 | ++ { USB_DEVICE(0x05C6, 0x9091) }, /* Quectel QCM6125 */ | ||
| 56 | ++ { USB_DEVICE(0x05C6, 0x90DB) }, /* Quectel QCM6490 */ | ||
| 57 | ++ { USB_DEVICE(0x2C7C, 0x0125) }, /* Quectel EC20(MDM9x07)/EC25/EG25 */ | ||
| 58 | ++ { USB_DEVICE(0x2C7C, 0x0121) }, /* Quectel EC21 */ | ||
| 59 | ++ { USB_DEVICE(0x2C7C, 0x0122) }, /* Quectel RG650V / RG650 SDX7X */ | ||
| 60 | ++ { USB_DEVICE(0x2C7C, 0x030E) }, /* Quectel EM05G */ | ||
| 61 | ++ { USB_DEVICE(0x2C7C, 0x0191) }, /* Quectel EG91 */ | ||
| 62 | ++ { USB_DEVICE(0x2C7C, 0x0195) }, /* Quectel EG95 */ | ||
| 63 | ++ { USB_DEVICE(0x2C7C, 0x0306) }, /* Quectel EG06/EP06/EM06 */ | ||
| 64 | ++ { USB_DEVICE(0x2C7C, 0x030B) }, /* Quectel EG065K/EG060K */ | ||
| 65 | ++ { USB_DEVICE(0x2C7C, 0x0514) }, /* Quectel BL EG060K RNDIS Only */ | ||
| 66 | ++ { USB_DEVICE(0x2C7C, 0x0512) }, /* Quectel EG12/EP12/EM12/EG16/EG18 */ | ||
| 67 | ++ { USB_DEVICE(0x2C7C, 0x0296) }, /* Quectel BG96 */ | ||
| 68 | ++ { USB_DEVICE(0x2C7C, 0x0700) }, /* Quectel BG95/BG77/BG600L-M3/BC69 */ | ||
| 69 | ++ { USB_DEVICE(0x2C7C, 0x0435) }, /* Quectel AG35 */ | ||
| 70 | ++ { USB_DEVICE(0x2C7C, 0x0415) }, /* Quectel AG15 */ | ||
| 71 | ++ { USB_DEVICE(0x2C7C, 0x0452) }, /* Quectel AG520/AG529 */ | ||
| 72 | ++ { USB_DEVICE(0x2C7C, 0x0455) }, /* Quectel AG550 */ | ||
| 73 | ++ { USB_DEVICE(0x2C7C, 0x0620) }, /* Quectel EG20 */ | ||
| 74 | ++ { USB_DEVICE(0x2C7C, 0x0800) }, /* Quectel RG500/RM500/RG510/RM510 */ | ||
| 75 | ++ { USB_DEVICE(0x2C7C, 0x0801) }, /* Quectel RG520/RM520/SG520 */ | ||
| 76 | ++ { USB_DEVICE(0x2C7C, 0x0133) }, /* Quectel RG650 SDX7X RNDIS / RM551E */ | ||
| 77 | ++ { USB_DEVICE(0x2C7C, 0x0134) }, /* Quectel SDX35 AG531C */ | ||
| 78 | ++ { USB_DEVICE(0x2C7C, 0x0316) }, /* Quectel RG255 SDX35 */ | ||
| 79 | ++ { USB_DEVICE(0x2C7C, 0x6026) }, /* Quectel EC200 */ | ||
| 80 | ++ { USB_DEVICE(0x2C7C, 0x6120) }, /* Quectel UC200 */ | ||
| 81 | ++ { USB_DEVICE(0x2C7C, 0x600B) }, /* Quectel ASR1903S */ | ||
| 82 | ++ { USB_DEVICE(0x2C7C, 0x600C) }, /* Quectel RG255A ASR1903L */ | ||
| 83 | ++ { USB_DEVICE(0x2C7C, 0x6000) }, /* Quectel EC200/UC200 */ | ||
| 84 | ++ { USB_DEVICE(0x2C7C, 0x7003) }, /* Quectel T750(META) */ | ||
| 85 | ++ { USB_DEVICE(0x2C7C, 0x7008) }, /* Quectel T750 */ | ||
| 86 | ++ { USB_DEVICE(0x2C7C, 0x7005) }, /* Quectel T830(META) */ | ||
| 87 | ++ { USB_DEVICE(0x2C7C, 0x7006) }, /* Quectel T830 */ | ||
| 88 | ++ { USB_DEVICE(0x3763, 0x3C93) }, /* Quectel GW */ | ||
| 89 | ++ { USB_DEVICE(0x3C93, 0xFFFF) }, /* Quectel GW */ | ||
| 90 | ++#endif | ||
| 91 | + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, | ||
| 92 | + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, | ||
| 93 | + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) }, | ||
| 94 | + static int option_probe(struct usb_serial *serial, | ||
| 95 | + &serial->interface->cur_altsetting->desc; | ||
| 96 | + unsigned long device_flags = id->driver_info; | ||
| 97 | + | ||
| 98 | ++#ifdef CONFIG_USB_SERIAL_QUECTEL_SUPPORT | ||
| 99 | ++ /* Quectel UC20: interface 4 is USB network */ | ||
| 100 | ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && | ||
[linux-6.6/hispark_aifly_patch/0010-kernel-quectel-4g.patch:100] ![]() ![]() | |||
| 101 | ++ serial->dev->descriptor.idProduct == cpu_to_le16(0x9003) && | ||
| 102 | ++ serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4) | ||
| 103 | ++ return -ENODEV; | ||
| 104 | ++ | ||
| 105 | ++ /* Quectel EC20(MDM9215): interface 4 is USB network */ | ||
| 106 | ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && | ||
| 107 | ++ serial->dev->descriptor.idProduct == cpu_to_le16(0x9215) && | ||
| 108 | ++ serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4) | ||
| 109 | ++ return -ENODEV; | ||
| 110 | ++ | ||
| 111 | ++ /* Quectel QCM6125/QCM6490: interface 2+ is USB network */ | ||
| 112 | ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && | ||
| 113 | ++ (serial->dev->descriptor.idProduct == cpu_to_le16(0x9091) || | ||
| 114 | ++ serial->dev->descriptor.idProduct == cpu_to_le16(0x90DB)) && | ||
| 115 | ++ serial->interface->cur_altsetting->desc.bInterfaceNumber >= 2) | ||
| 116 | ++ return -ENODEV; | ||
| 117 | ++ | ||
| 118 | ++ /* Netprisma PCUL11-LD(MDM9205): interface 3+ is USB network */ | ||
| 119 | ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x3731) && | ||
| 120 | ++ serial->dev->descriptor.idProduct == cpu_to_le16(0x0102) && | ||
| 121 | ++ serial->interface->cur_altsetting->desc.bInterfaceNumber >= 3) | ||
| 122 | ++ return -ENODEV; | ||
| 123 | ++ | ||
| 124 | ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C)) { | ||
| 125 | ++ __u16 idProduct = le16_to_cpu(serial->dev->descriptor.idProduct); | ||
| 126 | ++ struct usb_interface_descriptor *intf = | ||
| 127 | ++ &serial->interface->cur_altsetting->desc; | ||
| 128 | ++ | ||
| 129 | ++ if (intf->bInterfaceClass != 0xFF || intf->bInterfaceSubClass == 0x42) | ||
| 130 | ++ return -ENODEV; | ||
| 131 | ++ | ||
| 132 | ++ if ((idProduct & 0xF000) == 0x0000) { | ||
| 133 | ++ /* MDM interface 4 is QMI; SDX35 uses interface 3 */ | ||
| 134 | ++ if (idProduct == 0x0316 && intf->bInterfaceNumber == 3) | ||
| 135 | ++ return -ENODEV; | ||
| 136 | ++ | ||
| 137 | ++ if (idProduct == 0x0121 && intf->bInterfaceNumber == 4) | ||
| 138 | ++ return -ENODEV; | ||
| 139 | ++ | ||
| 140 | ++ if (intf->bInterfaceNumber == 4 && intf->bNumEndpoints == 3 && | ||
| 141 | ++ intf->bInterfaceSubClass == 0xFF && | ||
| 142 | ++ intf->bInterfaceProtocol == 0xFF) | ||
| 143 | ++ return -ENODEV; | ||
| 144 | ++ } | ||
| 145 | ++ } | ||
| 146 | ++#endif | ||
| 147 | ++ | ||
| 148 | + /* Never bind to the CD-Rom emulation interface */ | ||
| 149 | + if (iface_desc->bInterfaceClass == USB_CLASS_MASS_STORAGE) | ||
| 150 | + return -ENODEV; | ||
| 151 | + static int option_probe(struct usb_serial *serial, | ||
| 152 | + if (device_flags & NUMEP2 && iface_desc->bNumEndpoints != 2) | ||
| 153 | + return -ENODEV; | ||
| 154 | + | ||
| 155 | ++#ifdef CONFIG_USB_SERIAL_QUECTEL_SUPPORT | ||
| 156 | ++ /* Fold Quectel ZLP quirk into the generic use_zlp path. */ | ||
| 157 | ++ if (usb_wwan_quectel_use_zlp(serial->dev)) | ||
| 158 | ++ device_flags |= ZLP; | ||
| 159 | ++#endif | ||
| 160 | ++ | ||
| 161 | + /* Store the device flags so we can use them during attach. */ | ||
| 162 | + usb_set_serial_data(serial, (void *)device_flags); | ||
| 163 | + | ||
| 164 | +diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c | ||
| 165 | +index 061ff754b..d90e93291 100644 | ||
| 166 | +--- a/drivers/usb/serial/qcserial.c | ||
| 167 | ++++ b/drivers/usb/serial/qcserial.c | ||
| 168 | + static const struct usb_device_id id_table[] = { | ||
| 169 | + {DEVICE_G1K(0x05c6, 0x9202)}, /* Generic Gobi Modem device */ | ||
| 170 | + {DEVICE_G1K(0x05c6, 0x9203)}, /* Generic Gobi Modem device */ | ||
| 171 | + {DEVICE_G1K(0x05c6, 0x9222)}, /* Generic Gobi Modem device */ | ||
| 172 | ++#ifndef CONFIG_USB_SERIAL_QUECTEL_SUPPORT | ||
| 173 | + {DEVICE_G1K(0x05c6, 0x9008)}, /* Generic Gobi QDL device */ | ||
| 174 | ++#endif | ||
| 175 | + {DEVICE_G1K(0x05c6, 0x9009)}, /* Generic Gobi Modem device */ | ||
| 176 | + {DEVICE_G1K(0x05c6, 0x9201)}, /* Generic Gobi QDL device */ | ||
| 177 | + {DEVICE_G1K(0x05c6, 0x9221)}, /* Generic Gobi QDL device */ | ||
| 178 | + static int qc_attach(struct usb_serial *serial) | ||
| 179 | + if (sendsetup) | ||
| 180 | + data->use_send_setup = 1; | ||
| 181 | + | ||
| 182 | ++#ifdef CONFIG_USB_SERIAL_QUECTEL_SUPPORT | ||
| 183 | ++ if (usb_wwan_quectel_use_zlp(serial->dev)) | ||
| 184 | ++ data->use_zlp = 1; | ||
| 185 | ++#endif | ||
| 186 | ++ | ||
| 187 | + spin_lock_init(&data->susp_lock); | ||
| 188 | + | ||
| 189 | + usb_set_serial_data(serial, data); | ||
| 190 | +diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h | ||
| 191 | +index 519101945..91dff5a51 100644 | ||
| 192 | +--- a/drivers/usb/serial/usb-wwan.h | ||
| 193 | ++++ b/drivers/usb/serial/usb-wwan.h | ||
| 194 | + | ||
| 195 | + #ifndef __LINUX_USB_USB_WWAN | ||
| 196 | + #define __LINUX_USB_USB_WWAN | ||
| 197 | + | ||
| 198 | ++/* Quectel extensions are gated by CONFIG_USB_SERIAL_QUECTEL_SUPPORT. */ | ||
| 199 | ++ | ||
| 200 | + extern void usb_wwan_dtr_rts(struct usb_serial_port *port, int on); | ||
| 201 | + extern int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port); | ||
| 202 | + extern void usb_wwan_close(struct usb_serial_port *port); | ||
| 203 | + extern unsigned int usb_wwan_chars_in_buffer(struct tty_struct *tty); | ||
| 204 | + extern int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message); | ||
| 205 | + extern int usb_wwan_resume(struct usb_serial *serial); | ||
| 206 | + #endif | ||
| 207 | ++#ifdef CONFIG_USB_SERIAL_QUECTEL_SUPPORT | ||
| 208 | ++extern bool usb_wwan_quectel_use_zlp(struct usb_device *udev); | ||
| 209 | ++#endif | ||
| 210 | + | ||
| 211 | + /* per port private data */ | ||
| 212 | + | ||
| 213 | +diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c | ||
| 214 | +index fc87c4307..679a7c73d 100644 | ||
| 215 | +--- a/drivers/usb/serial/usb_wwan.c | ||
| 216 | ++++ b/drivers/usb/serial/usb_wwan.c | ||
| 217 | + static void usb_wwan_indat_callback(struct urb *urb) | ||
| 218 | + __func__, status, endpoint); | ||
| 219 | + | ||
| 220 | + /* don't resubmit on fatal errors */ | ||
| 221 | +-#ifdef CONFIG_ARCH_HISILICON | ||
| 222 | +- if (status == -ESHUTDOWN || status == -ENOENT || status == -EPROTO) | ||
| 223 | +-#else | ||
| 224 | + if (status == -ESHUTDOWN || status == -ENOENT) | ||
[linux-6.6/hispark_aifly_patch/0010-kernel-quectel-4g.patch:224] 移除 ![]() ![]() | |||
| 225 | +-#endif | ||
| 226 | + return; | ||
| 227 | + } else { | ||
| 228 | + if (urb->actual_length) { | ||
| 229 | + int usb_wwan_resume(struct usb_serial *serial) | ||
| 230 | + EXPORT_SYMBOL(usb_wwan_resume); | ||
| 231 | + #endif | ||
| 232 | + | ||
| 233 | ++#ifdef CONFIG_USB_SERIAL_QUECTEL_SUPPORT | ||
| 234 | ++/* | ||
| 235 | ++ * Quectel (and related) modems need URB_ZERO_PACKET on bulk OUT. | ||
| 236 | ++ * Callers set intfdata->use_zlp so usb_wwan_setup_urb applies it once. | ||
| 237 | ++ */ | ||
| 238 | ++bool usb_wwan_quectel_use_zlp(struct usb_device *udev) | ||
| 239 | ++{ | ||
| 240 | ++ u16 vid = le16_to_cpu(udev->descriptor.idVendor); | ||
| 241 | ++ u16 pid = le16_to_cpu(udev->descriptor.idProduct); | ||
| 242 | ++ | ||
| 243 | ++ if (vid == 0x2c7c) | ||
| 244 | ++ return true; | ||
| 245 | ++ | ||
| 246 | ++ if (vid == 0x05c6 && | ||
| 247 | ++ (pid == 0x9090 || pid == 0x9003 || pid == 0x9215 || | ||
| 248 | ++ pid == 0x9091 || pid == 0x90db)) | ||
| 249 | ++ return true; | ||
| 250 | ++ | ||
| 251 | ++ if (vid == 0x3731 && (pid == 0x0102 || pid == 0x0103)) | ||
| 252 | ++ return true; | ||
| 253 | ++ | ||
| 254 | ++ return false; | ||
| 255 | ++} | ||
| 256 | ++EXPORT_SYMBOL_GPL(usb_wwan_quectel_use_zlp); | ||
| 257 | ++#endif | ||
| 258 | ++ | ||
| 259 | + MODULE_AUTHOR(DRIVER_AUTHOR); | ||
| 260 | + MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 261 | + MODULE_LICENSE("GPL v2"); | ||
| 262 | +diff --git a/drivers/vendor/basedrv_clk/ss928v100/clk_ups.c b/drivers/vendor/basedrv_clk/ss928v100/clk_ups.c | ||
| 263 | +index 45052a687..0f1186cc4 100644 | ||
| 264 | +--- a/drivers/vendor/basedrv_clk/ss928v100/clk_ups.c | ||
| 265 | ++++ b/drivers/vendor/basedrv_clk/ss928v100/clk_ups.c | ||
| 266 | + | ||
| 267 | + #include <dt-bindings/clock/basedrv-clock.h> | ||
| 268 | + #include <asm/io.h> | ||
| 269 | + #include <linux/delay.h> | ||
| 270 | ++#include <linux/gpio.h> | ||
| 271 | ++#include <linux/of.h> | ||
| 272 | ++#include <linux/of_gpio.h> | ||
| 273 | + | ||
| 274 | + #include "../basedrv_clk.h" | ||
| 275 | + | ||
| 276 | + | ||
| 277 | + #define PITOUT_CTRL1_PWREN_OFFSET 0X3C | ||
| 278 | + #define PITOUT_CTRL1_VBUS_OFFSET 0x38 | ||
| 279 | + #define PINOUT_USB_VAL 0x1201 | ||
| 280 | ++#ifdef CONFIG_USB_SERIAL_QUECTEL_SUPPORT | ||
| 281 | ++#define IO_CFG_REG13_OFFSET 0x34 | ||
| 282 | ++#define IO_CFG_REG13_MUX_MASK 0xf | ||
| 283 | ++#define IO_CFG_REG13_GPIO1_5_MUX 0x2 | ||
| 284 | ++/* | ||
| 285 | ++ * Board "4g-perst" idle/run level is low (see former gpio-hog output-low). | ||
| 286 | ++ * Assert reset by driving high for >= 150ms, then return low to run. | ||
| 287 | ++ */ | ||
| 288 | ++#define EC20_PERST_HOLD_MS 150 | ||
| 289 | ++#define GPIO1_REG_BASE 0x11091000 | ||
| 290 | ++#define PL061_GPIODIR 0x400 | ||
| 291 | ++#define EC20_PERST_PIN 5 | ||
| 292 | ++#endif | ||
| 293 | + | ||
| 294 | + static unsigned int basedrv_clk_readl(const void __iomem *addr) | ||
| 295 | + { | ||
| 296 | + typedef enum mode { | ||
| 297 | + UNKOWN_MODE | ||
| 298 | + } combphy_mode; | ||
| 299 | + | ||
| 300 | ++#ifdef CONFIG_USB_SERIAL_QUECTEL_SUPPORT | ||
| 301 | ++/* | ||
| 302 | ++ * Step 1 of PERST bring-up: mux GPIO1_5 to GPIO mode only. | ||
| 303 | ++ * Direction and level are set in ec20_4g_perst_reset_seq() / _mmio_seq(). | ||
| 304 | ++ */ | ||
| 305 | ++static void ec20_4g_perst_pinmux_cfg(void __iomem *pinout_base) | ||
| 306 | ++{ | ||
| 307 | ++ u32 val; | ||
| 308 | ++ | ||
| 309 | ++ val = basedrv_clk_readl(pinout_base + IO_CFG_REG13_OFFSET); | ||
| 310 | ++ val = (val & ~IO_CFG_REG13_MUX_MASK) | IO_CFG_REG13_GPIO1_5_MUX; | ||
| 311 | ++ basedrv_clk_writel(val, pinout_base + IO_CFG_REG13_OFFSET); | ||
| 312 | ++} | ||
| 313 | ++ | ||
| 314 | ++/* | ||
| 315 | ++ * Step 2 (MMIO fallback): set GPIO1_5 as output and pulse PERST. | ||
| 316 | ++ * | ||
| 317 | ++ * Note: Quectel RESET_N datasheet is active-low (high = run). This board's | ||
| 318 | ++ * "4g-perst" line matches the former gpio-hog idle level: low = run, | ||
| 319 | ++ * high = reset. Verified with EC20F USB enumeration. | ||
| 320 | ++ */ | ||
| 321 | ++static void ec20_4g_perst_mmio_seq(void) | ||
| 322 | ++{ | ||
| 323 | ++ void __iomem *gpio; | ||
| 324 | ++ u32 dir; | ||
| 325 | ++ | ||
| 326 | ++ gpio = ioremap(GPIO1_REG_BASE, 0x1000); | ||
| 327 | ++ if (!gpio) { | ||
| 328 | ++ basedrv_clk_info("map GPIO1 for EC20 PERST failed\n"); | ||
| 329 | ++ return; | ||
| 330 | ++ } | ||
| 331 | ++ | ||
| 332 | ++ /* Output direction for GPIO1_5 */ | ||
| 333 | ++ dir = basedrv_clk_readl(gpio + PL061_GPIODIR); | ||
| 334 | ++ basedrv_clk_writel(dir | BIT(EC20_PERST_PIN), gpio + PL061_GPIODIR); | ||
| 335 | ++ | ||
| 336 | ++ /* Assert reset (high), hold, then release to run (low). */ | ||
| 337 | ++ basedrv_clk_writel(BIT(EC20_PERST_PIN), gpio + (BIT(EC20_PERST_PIN) << 2)); | ||
[linux-6.6/hispark_aifly_patch/0010-kernel-quectel-4g.patch:337] ![]() ![]() | |||
| 338 | ++ msleep(EC20_PERST_HOLD_MS); | ||
| 339 | ++ basedrv_clk_writel(0, gpio + (BIT(EC20_PERST_PIN) << 2)); | ||
| 340 | ++ | ||
| 341 | ++ iounmap(gpio); | ||
| 342 | ++ basedrv_clk_info("EC20 PERST reset done via MMIO (high %u ms then low)\n", | ||
| 343 | ++ EC20_PERST_HOLD_MS); | ||
| 344 | ++} | ||
| 345 | ++ | ||
| 346 | ++/* | ||
| 347 | ++ * Full EC20 PERST after VBUS is enabled: | ||
| 348 | ++ * 1) pinmux GPIO1_5 | ||
| 349 | ++ * 2) request GPIO (or MMIO), set output | ||
| 350 | ++ * 3) pulse high >= 150ms, hold low to run | ||
| 351 | ++ */ | ||
| 352 | ++static void ec20_4g_perst_reset_seq(void __iomem *pinout_base) | ||
| 353 | ++{ | ||
| 354 | ++ static bool done; | ||
[linux-6.6/hispark_aifly_patch/0010-kernel-quectel-4g.patch:354] ![]() ![]() | |||
| 355 | ++ struct device_node *np; | ||
| 356 | ++ int gpio; | ||
| 357 | ++ int ret; | ||
| 358 | ++ | ||
| 359 | ++ if (done) | ||
| 360 | ++ return; | ||
| 361 | ++ | ||
| 362 | ++ ec20_4g_perst_pinmux_cfg(pinout_base); | ||
| 363 | ++ | ||
| 364 | ++ np = of_find_compatible_node(NULL, NULL, "quectel,ec20-4g"); | ||
| 365 | ++ if (!np) { | ||
| 366 | ++ basedrv_clk_info("EC20 DT node missing, use MMIO PERST\n"); | ||
| 367 | ++ ec20_4g_perst_mmio_seq(); | ||
| 368 | ++ done = true; | ||
| 369 | ++ return; | ||
| 370 | ++ } | ||
| 371 | ++ | ||
| 372 | ++ gpio = of_get_named_gpio(np, "reset-gpios", 0); | ||
| 373 | ++ of_node_put(np); | ||
| 374 | ++ if (!gpio_is_valid(gpio)) { | ||
| 375 | ++ basedrv_clk_info("EC20 PERST gpio invalid, use MMIO\n"); | ||
| 376 | ++ ec20_4g_perst_mmio_seq(); | ||
| 377 | ++ done = true; | ||
| 378 | ++ return; | ||
| 379 | ++ } | ||
| 380 | ++ | ||
| 381 | ++ ret = gpio_request(gpio, "ec20-perst"); | ||
[linux-6.6/hispark_aifly_patch/0010-kernel-quectel-4g.patch:381] ![]() ![]() | |||
| 382 | ++ if (ret) { | ||
| 383 | ++ basedrv_clk_info("EC20 PERST gpio_request %d, use MMIO\n", ret); | ||
| 384 | ++ ec20_4g_perst_mmio_seq(); | ||
| 385 | ++ done = true; | ||
| 386 | ++ return; | ||
| 387 | ++ } | ||
| 388 | ++ | ||
| 389 | ++ /* Output + reset pulse: high (assert) then low (run). */ | ||
| 390 | ++ gpio_direction_output(gpio, 1); | ||
| 391 | ++ msleep(EC20_PERST_HOLD_MS); | ||
| 392 | ++ gpio_set_value(gpio, 0); | ||
| 393 | ++ /* Keep ownership so line stays driven low (run). */ | ||
| 394 | ++ done = true; | ||
| 395 | ++ basedrv_clk_info("EC20 PERST reset done (high %u ms then low)\n", | ||
| 396 | ++ EC20_PERST_HOLD_MS); | ||
| 397 | ++} | ||
| 398 | ++#endif | ||
| 399 | ++ | ||
| 400 | + static void usb_pinout_cfg(void) | ||
| 401 | + { | ||
| 402 | + void __iomem *addr = NULL; | ||
| 403 | + static void usb_pinout_cfg(void) | ||
| 404 | + basedrv_clk_writel(PINOUT_USB_VAL, addr + PITOUT_CTRL1_PWREN_OFFSET); | ||
| 405 | + basedrv_clk_writel(PINOUT_USB_VAL, addr + PITOUT_CTRL1_VBUS_OFFSET); | ||
| 406 | + udelay(200); /* delay 200 us to wait vbus stable */ | ||
| 407 | ++#ifdef CONFIG_USB_SERIAL_QUECTEL_SUPPORT | ||
| 408 | ++ ec20_4g_perst_reset_seq(addr); | ||
| 409 | ++#endif | ||
| 410 | + | ||
| 411 | + iounmap(addr); | ||
| 412 | + addr = NULL; | ||
| @@ -0,0 +1,67 @@ | |||
| 1 | +#!/bin/sh | ||
| 2 | +# Copyright (c) 2026 HiSilicon (Shanghai) Technologies Co., Ltd. | ||
| 3 | +# This program is free software; you can redistribute it and/or | ||
| 4 | +# modify it under the terms of the GNU General Public License | ||
| 5 | +# as published by the Free Software Foundation; either version 2 | ||
| 6 | +# of the License, or (at your option) any later version. | ||
| 7 | +# | ||
| 8 | +# This program is distributed in the hope that it will be useful, | ||
| 9 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | +# GNU General Public License for more details. | ||
| 12 | +# | ||
| 13 | +# You should have received a copy of the GNU General Public License | ||
| 14 | +# along with this program; if not, see | ||
| 15 | +# <https://www.gnu.org/licenses/>. | ||
| 16 | + | ||
| 17 | +patch_dir=${1} | ||
| 18 | +echo "${patch_dir}: ${1}" | ||
| 19 | +echo "Current directory $(pwd)" | ||
| 20 | +echo "patching aifly begin..." | ||
| 21 | + | ||
| 22 | +# Apply patch idempotently: skip if already applied, fail on real conflicts. | ||
| 23 | +apply_patch() { | ||
| 24 | + patch_file="$1" | ||
| 25 | + name=$(basename "${patch_file}") | ||
| 26 | + | ||
| 27 | + if patch -p1 --dry-run < "${patch_file}" >/dev/null 2>&1; then | ||
| 28 | + patch -p1 < "${patch_file}" || exit 1 | ||
| 29 | + echo "Applied: ${name}" | ||
| 30 | + elif patch -p1 --dry-run -R < "${patch_file}" >/dev/null 2>&1; then | ||
| 31 | + echo "Already applied, skipping: ${name}" | ||
| 32 | + else | ||
| 33 | + echo "Failed to apply patch: ${name}" >&2 | ||
| 34 | + exit 1 | ||
| 35 | + fi | ||
| 36 | +} | ||
| 37 | + | ||
| 38 | +# DTC resolves <dt-bindings/...> only under scripts/dtc/include-prefixes. | ||
| 39 | +# Vendor patches add new headers under include/dt-bindings; hardlink any | ||
| 40 | +# missing files into the DTC include tree. | ||
| 41 | +sync_dt_bindings() { | ||
| 42 | + src_root="include/dt-bindings" | ||
| 43 | + dtc_root="scripts/dtc/include-prefixes/dt-bindings" | ||
| 44 | + | ||
| 45 | + [ -d "${src_root}" ] || return 0 | ||
| 46 | + | ||
| 47 | + find "${src_root}" -type f | while read -r src; do | ||
| 48 | + rel="${src#${src_root}/}" | ||
| 49 | + dst="${dtc_root}/${rel}" | ||
| 50 | + [ -e "${dst}" ] && continue | ||
| 51 | + mkdir -p "$(dirname "${dst}")" | ||
| 52 | + ln "${src}" "${dst}" | ||
[linux-6.6/hispark_aifly_patch/patch_hispark_aifly.sh:52] 使用硬链接 ln 而非符号链接 ln -s。若 include/dt-bindings 和 scripts/dtc/include-prefixes 位于不同文件系统,硬链接将失败。建议改用 ln -s 或 cp 以增强兼容性。 ![]() ![]() | |||
| 53 | + done | ||
| 54 | +} | ||
| 55 | + | ||
| 56 | +apply_patch "${patch_dir}/0001-kernel-hispark_aifly.patch" | ||
| 57 | +apply_patch "${patch_dir}/0002-kernel-compile-support.patch" | ||
| 58 | +apply_patch "${patch_dir}/0003-kernel-drm.patch" | ||
| 59 | +apply_patch "${patch_dir}/0004-kernel-vo.patch" | ||
| 60 | +apply_patch "${patch_dir}/0005-kernel-dhcp-support.patch" | ||
| 61 | +apply_patch "${patch_dir}/0006-kernel-mipi-support.patch" | ||
| 62 | +apply_patch "${patch_dir}/0007-kernel-nca9555.patch" | ||
| 63 | +apply_patch "${patch_dir}/0008-power-key-dts.patch" | ||
| 64 | +apply_patch "${patch_dir}/0009-hdf-soc-path.patch" | ||
| 65 | +apply_patch "${patch_dir}/0010-kernel-quectel-4g.patch" | ||
| 66 | +sync_dt_bindings | ||
| 67 | +echo "patching aifly finished..." | ||


[linux-6.6/hispark_aifly_patch/0005-kernel-dhcp-support.patch:25] 错误消息与代码不一致:此处将 DMA_BIT_MASK(64) 改为 DMA_BIT_MASK(32),但下方的 pr_err 仍输出 "dma set mask bit 64 failed",应修改为 "dma set mask bit 32 failed" 以保持一致。