diff --git a/01_git_sync.sh b/01_git_sync.sh index b28efeb..211513a 100755 --- a/01_git_sync.sh +++ b/01_git_sync.sh @@ -13,11 +13,11 @@ UBOOT_BRANCH="v2023.02-BeagleV-Fire" UBOOT_REPO="https://openbeagle.org/beaglev-fire/beaglev-fire-u-boot.git" #UBOOT_REPO="git@openbeagle.org:beaglev-fire/beaglev-fire-u-boot.git" -DT_BRANCH="v6.1.x-Beagle" +DT_BRANCH="v6.6.x-Beagle" DT_REPO="https://openbeagle.org/beagleboard/BeagleBoard-DeviceTrees.git" #DT_REPO="git@openbeagle.org:beagleboard/BeagleBoard-DeviceTrees.git" -LINUX_BRANCH="linux4microchip+fpga-2023.06" +LINUX_BRANCH="linux4microchip+fpga-2024.09" LINUX_REPO="https://github.com/linux4microchip/linux.git" #LINUX_REPO="https://openbeagle.org/beaglev-fire/beaglev-fire-linux.git" #LINUX_REPO="git@openbeagle.org:beaglev-fire/beaglev-fire-linux.git" diff --git a/04_build_linux.sh b/04_build_linux.sh index 7274d6e..e0de379 100755 --- a/04_build_linux.sh +++ b/04_build_linux.sh @@ -8,23 +8,19 @@ cd ./linux/ if [ ! -f ./.patched ] ; then if [ -f arch/riscv/configs/mpfs_defconfig ] ; then - git am ../patches/linux/0002-PCIe-Change-controller-and-bridge-base-address.patch - git am ../patches/linux/0003-GPIO-Add-Microchip-CoreGPIO-driver.patch - git am ../patches/linux/0004-ADC-Add-Microchip-MCP356X-driver.patch - git am ../patches/linux/0005-Microchip-QSPI-Add-regular-transfers.patch - git am ../patches/linux/0006-BeagleV-Fire-Add-printk-to-IM219-driver-for-board-te.patch - git am ../patches/linux/0007-MMC-SPI-Hack-to-support-non-DMA-capable-SPI-ctrl.patch + git am ../patches/linux/linux-6.6.y/0002-PCIe-Change-controller-and-bridge-base-address.patch git am ../patches/linux/0008-Add-wireless-regdb-regulatory-database-file.patch - git am ../patches/linux/0009-Makefile-build-mpfs-beaglev-fire.dtb.patch - git am ../patches/linux/0010-BeagleV-Fire-Add-MPFS-TVS-auxiliary-driver.patch + git am ../patches/linux/linux-6.6.y/0011-can-mpfs_can-add-registration-string.patch + git am ../patches/linux/linux-6.6.y/0012-gpio-gpio-mpfs-add-registration-string.patch fi touch .patched fi if [ -f arch/riscv/configs/mpfs_defconfig ] ; then # cp -v ../patches/linux/Makefile arch/riscv/boot/dts/microchip/Makefile - cp -v ../device-tree/src/microchip/mpfs-beaglev-fire.dts arch/riscv/boot/dts/microchip/ - cp -v ../device-tree/src/microchip/mpfs-beaglev-fire-fabric.dtsi arch/riscv/boot/dts/microchip/ + cp -v ../device-tree/src/riscv/microchip/mpfs-beaglev-fire.dts arch/riscv/boot/dts/microchip/ + cp -v ../device-tree/src/riscv/microchip/mpfs-beaglev-fire-fabric.dtsi arch/riscv/boot/dts/microchip/ + cp -v ../device-tree/src/riscv/microchip/mpfs-beaglev-fire-pinmux.dtsi arch/riscv/boot/dts/microchip/ #echo "************************************" #git diff arch/riscv/boot/dts/microchip/ > log.txt ; cat log.txt ; rm log.txt #echo "************************************" @@ -47,6 +43,17 @@ if [ -f arch/riscv/configs/mpfs_defconfig ] ; then ./scripts/config --set-str CONFIG_LOCALVERSION "-$(date +%Y%m%d)" + #6.1 to 6.6 switches + ./scripts/config --disable CONFIG_FW_LOADER_DEBUG + ./scripts/config --disable CONFIG_FW_CACHE + ./scripts/config --enable CONFIG_MFD_SYSCON + ./scripts/config --enable CONFIG_POLARFIRE_SOC_SYS_CTRL + ./scripts/config --enable CONFIG_POLARFIRE_SOC_GENERIC_SERVICE + ./scripts/config --enable CONFIG_POLARFIRE_SOC_MAILBOX + ./scripts/config --enable CONFIG_POLARFIRE_SOC_AUTO_UPDATE + ./scripts/config --enable CONFIG_HW_RANDOM_POLARFIRE_SOC + + ./scripts/config --enable CONFIG_OF_OVERLAY ./scripts/config --disable CONFIG_MODULE_DECOMPRESS @@ -73,7 +80,12 @@ if [ -f arch/riscv/configs/mpfs_defconfig ] ; then ./scripts/config --enable CONFIG_CRYPTO_SHA512 ./scripts/config --enable CONFIG_CRYPTO_SHA1 - ./scripts/config --enable CONFIG_SENSORS_TVS_MPFS + ./scripts/config --enable CONFIG_SENSORS_POLARFIRE_SOC_TVS + ./scripts/config --module CONFIG_CAN + ./scripts/config --module CONFIG_CAN_POLARFIRE_SOC + + #non-workable on RevA + ./scripts/config --disable CONFIG_VIDEO_IMX219 echo "make -j${CORES} ARCH=riscv CROSS_COMPILE=${CC} olddefconfig" make -j${CORES} ARCH=riscv CROSS_COMPILE=${CC} olddefconfig @@ -160,8 +172,8 @@ else make -j${CORES} ARCH=riscv CROSS_COMPILE=${CC} olddefconfig fi -echo "make -j${CORES} ARCH=riscv CROSS_COMPILE=${CC} Image modules dtbs" -make -j${CORES} ARCH=riscv CROSS_COMPILE="ccache ${CC}" Image modules dtbs +echo "make -j${CORES} ARCH=riscv CROSS_COMPILE=${CC} DTC_FLAGS=\"-@\" Image modules dtbs" +make -j${CORES} ARCH=riscv CROSS_COMPILE="ccache ${CC}" DTC_FLAGS="-@" Image modules dtbs if [ ! -f ./arch/riscv/boot/Image ] ; then echo "Build Failed" diff --git a/patches/linux/0003-GPIO-Add-Microchip-CoreGPIO-driver.patch b/patches/linux/0003-GPIO-Add-Microchip-CoreGPIO-driver.patch deleted file mode 100644 index eccc9a5..0000000 --- a/patches/linux/0003-GPIO-Add-Microchip-CoreGPIO-driver.patch +++ /dev/null @@ -1,371 +0,0 @@ -From 37ff4eff8ff033c48aa73526fec7291127326dcb Mon Sep 17 00:00:00 2001 -From: vauban353 -Date: Fri, 21 Jul 2023 19:33:28 +0100 -Subject: [PATCH 3/8] GPIO: Add Microchip CoreGPIO driver. - ---- - drivers/gpio/Kconfig | 8 + - drivers/gpio/Makefile | 1 + - drivers/gpio/gpio-microchip-core.c | 319 +++++++++++++++++++++++++++++ - 3 files changed, 328 insertions(+) - create mode 100644 drivers/gpio/gpio-microchip-core.c - -diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig -index d71f5bd6f..8e3858e34 100644 ---- a/drivers/gpio/Kconfig -+++ b/drivers/gpio/Kconfig -@@ -501,6 +501,14 @@ config GPIO_POLARFIRE_SOC - help - Say yes here to support the GPIO device on Microchip FPGAs. - -+config GPIO_MICROCHIP_CORE -+ bool "Microchip FPGA soft-IP GPIO support" -+ depends on OF_GPIO -+ select GPIOLIB_IRQCHIP -+ help -+ Say yes here to support the soft-IP GPIO device on Microchip FPGAs -+ -+ - config GPIO_PXA - bool "PXA GPIO support" - depends on ARCH_PXA || ARCH_MMP || COMPILE_TEST -diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile -index 9be0691d9..05a65ff04 100644 ---- a/drivers/gpio/Makefile -+++ b/drivers/gpio/Makefile -@@ -121,6 +121,7 @@ obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o - obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o - obj-$(CONFIG_GPIO_PMIC_EIC_SPRD) += gpio-pmic-eic-sprd.o - obj-$(CONFIG_GPIO_POLARFIRE_SOC) += gpio-mpfs.o -+obj-$(CONFIG_GPIO_MICROCHIP_CORE) += gpio-microchip-core.o - obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o - obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o - obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o -diff --git a/drivers/gpio/gpio-microchip-core.c b/drivers/gpio/gpio-microchip-core.c -new file mode 100644 -index 000000000..fd630cac4 ---- /dev/null -+++ b/drivers/gpio/gpio-microchip-core.c -@@ -0,0 +1,319 @@ -+// SPDX-License-Identifier: (GPL-2.0) -+/* -+ * Microchip CoreGPIO FPGA soft-IP GPIO controller driver -+ * -+ * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries -+ * -+ * Author: Lewis Hanly -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define MPFS_GPIO_CTRL(i) (0x4 * (i)) -+#define MAX_NUM_GPIO 32 -+#define MPFS_GPIO_EN_INT 3 -+#define MPFS_GPIO_EN_OUT_BUF BIT(2) -+#define MPFS_GPIO_EN_IN BIT(1) -+#define MPFS_GPIO_EN_OUT BIT(0) -+ -+#define MPFS_GPIO_TYPE_INT_EDGE_BOTH 0x80 -+#define MPFS_GPIO_TYPE_INT_EDGE_NEG 0x60 -+#define MPFS_GPIO_TYPE_INT_EDGE_POS 0x40 -+#define MPFS_GPIO_TYPE_INT_LEVEL_LOW 0x20 -+#define MPFS_GPIO_TYPE_INT_LEVEL_HIGH 0x00 -+#define MPFS_GPIO_TYPE_INT_MASK GENMASK(7, 5) -+#define MPFS_IRQ_REG 0x80 -+#define MPFS_INP_REG 0x90 -+#define MPFS_OUTP_REG 0xA0 -+ -+struct mpfs_gpio_chip { -+ void __iomem *base; -+ struct clk *clk; -+ raw_spinlock_t lock; -+ struct gpio_chip gc; -+}; -+ -+static void mpfs_gpio_assign_bit(void __iomem *addr, unsigned int bit_offset, bool value) -+{ -+ unsigned long reg = readl(addr); -+ -+ __assign_bit(bit_offset, ®, value); -+ writel(reg, addr); -+} -+ -+static int mpfs_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio_index) -+{ -+ struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); -+ u32 gpio_cfg; -+ unsigned long flags; -+ -+ raw_spin_lock_irqsave(&mpfs_gpio->lock, flags); -+ -+ gpio_cfg = readl(mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index)); -+ gpio_cfg |= MPFS_GPIO_EN_IN; -+ gpio_cfg &= ~(MPFS_GPIO_EN_OUT | MPFS_GPIO_EN_OUT_BUF); -+ writel(gpio_cfg, mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index)); -+ -+ raw_spin_unlock_irqrestore(&mpfs_gpio->lock, flags); -+ -+ return 0; -+} -+ -+static int mpfs_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio_index, int value) -+{ -+ struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); -+ u32 gpio_cfg; -+ unsigned long flags; -+ -+ raw_spin_lock_irqsave(&mpfs_gpio->lock, flags); -+ -+ gpio_cfg = readl(mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index)); -+ gpio_cfg |= MPFS_GPIO_EN_OUT | MPFS_GPIO_EN_OUT_BUF; -+ gpio_cfg &= ~MPFS_GPIO_EN_IN; -+ writel(gpio_cfg, mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index)); -+ -+ mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_OUTP_REG, gpio_index, value); -+ -+ raw_spin_unlock_irqrestore(&mpfs_gpio->lock, flags); -+ -+ return 0; -+} -+ -+static int mpfs_gpio_get_direction(struct gpio_chip *gc, -+ unsigned int gpio_index) -+{ -+ struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); -+ u32 gpio_cfg; -+ -+ gpio_cfg = readl(mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index)); -+ if (gpio_cfg & MPFS_GPIO_EN_IN) -+ return GPIO_LINE_DIRECTION_IN; -+ -+ return GPIO_LINE_DIRECTION_OUT; -+} -+ -+static int mpfs_gpio_get(struct gpio_chip *gc, -+ unsigned int gpio_index) -+{ -+ struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); -+ -+ return !!(readl(mpfs_gpio->base + MPFS_INP_REG) & BIT(gpio_index)); -+} -+ -+static void mpfs_gpio_set(struct gpio_chip *gc, unsigned int gpio_index, int value) -+{ -+ struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); -+ unsigned long flags; -+ -+ raw_spin_lock_irqsave(&mpfs_gpio->lock, flags); -+ -+ mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_OUTP_REG, -+ gpio_index, value); -+ -+ raw_spin_unlock_irqrestore(&mpfs_gpio->lock, flags); -+} -+ -+static int mpfs_gpio_irq_set_type(struct irq_data *data, unsigned int type) -+{ -+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data); -+ struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); -+ int gpio_index = irqd_to_hwirq(data); -+ u32 interrupt_type; -+ u32 gpio_cfg; -+ unsigned long flags; -+ -+ switch (type) { -+ case IRQ_TYPE_EDGE_BOTH: -+ interrupt_type = MPFS_GPIO_TYPE_INT_EDGE_BOTH; -+ break; -+ case IRQ_TYPE_EDGE_FALLING: -+ interrupt_type = MPFS_GPIO_TYPE_INT_EDGE_NEG; -+ break; -+ case IRQ_TYPE_EDGE_RISING: -+ interrupt_type = MPFS_GPIO_TYPE_INT_EDGE_POS; -+ break; -+ case IRQ_TYPE_LEVEL_HIGH: -+ interrupt_type = MPFS_GPIO_TYPE_INT_LEVEL_HIGH; -+ break; -+ case IRQ_TYPE_LEVEL_LOW: -+ interrupt_type = MPFS_GPIO_TYPE_INT_LEVEL_LOW; -+ break; -+ } -+ -+ raw_spin_lock_irqsave(&mpfs_gpio->lock, flags); -+ -+ gpio_cfg = readl(mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index)); -+ gpio_cfg &= ~MPFS_GPIO_TYPE_INT_MASK; -+ gpio_cfg |= interrupt_type; -+ writel(gpio_cfg, mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index)); -+ -+ raw_spin_unlock_irqrestore(&mpfs_gpio->lock, flags); -+ -+ return 0; -+} -+ -+static void mpfs_gpio_irq_unmask(struct irq_data *data) -+{ -+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data); -+ struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); -+ int gpio_index = irqd_to_hwirq(data) % MAX_NUM_GPIO; -+ -+ mpfs_gpio_direction_input(gc, gpio_index); -+ mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_IRQ_REG, gpio_index, 1); -+ mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index), -+ MPFS_GPIO_EN_INT, 1); -+} -+ -+static void mpfs_gpio_irq_mask(struct irq_data *data) -+{ -+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data); -+ struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); -+ int gpio_index = irqd_to_hwirq(data) % MAX_NUM_GPIO; -+ -+ mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_IRQ_REG, gpio_index, 1); -+ mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_GPIO_CTRL(gpio_index), -+ MPFS_GPIO_EN_INT, 0); -+} -+ -+static struct irq_chip mpfs_gpio_irqchip = { -+ .name = "mpfs", -+ .irq_set_type = mpfs_gpio_irq_set_type, -+ .irq_mask = mpfs_gpio_irq_mask, -+ .irq_unmask = mpfs_gpio_irq_unmask, -+ .flags = IRQCHIP_MASK_ON_SUSPEND, -+}; -+ -+static void mpfs_gpio_irq_handler(struct irq_desc *desc) -+{ -+ struct irq_chip *irqchip = irq_desc_get_chip(desc); -+ struct mpfs_gpio_chip *mpfs_gpio = -+ gpiochip_get_data(irq_desc_get_handler_data(desc)); -+ unsigned long status; -+ int offset; -+ -+ chained_irq_enter(irqchip, desc); -+ -+ status = readl(mpfs_gpio->base + MPFS_IRQ_REG); -+ for_each_set_bit(offset, &status, mpfs_gpio->gc.ngpio) { -+ mpfs_gpio_assign_bit(mpfs_gpio->base + MPFS_IRQ_REG, offset, 1); -+ generic_handle_irq(irq_find_mapping(mpfs_gpio->gc.irq.domain, offset)); -+ } -+ -+ chained_irq_exit(irqchip, desc); -+} -+ -+static int mpfs_gpio_probe(struct platform_device *pdev) -+{ -+ struct clk *clk; -+ struct device *dev = &pdev->dev; -+ struct device_node *node = pdev->dev.of_node; -+ struct mpfs_gpio_chip *mpfs_gpio; -+ struct gpio_irq_chip *girq; -+ int i, ret, ngpios, nirqs; -+ -+ mpfs_gpio = devm_kzalloc(dev, sizeof(*mpfs_gpio), GFP_KERNEL); -+ if (!mpfs_gpio) -+ return -ENOMEM; -+ -+ mpfs_gpio->base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(mpfs_gpio->base)) -+ return dev_err_probe(dev, PTR_ERR(mpfs_gpio->base), "memory allocation failure\n"); -+ -+ clk = devm_clk_get(dev, NULL); -+ if (IS_ERR(clk)) -+ return dev_err_probe(dev, PTR_ERR(clk), "devm_clk_get failed\n"); -+ -+ ret = clk_prepare_enable(clk); -+ if (ret) -+ return dev_err_probe(dev, ret, "failed to enable clock\n"); -+ -+ mpfs_gpio->clk = clk; -+ -+ raw_spin_lock_init(&mpfs_gpio->lock); -+ -+ ngpios = MAX_NUM_GPIO; -+ device_property_read_u32(dev, "ngpios", &ngpios); -+ if (ngpios > MAX_NUM_GPIO) -+ ngpios = MAX_NUM_GPIO; -+ -+ mpfs_gpio->gc.direction_input = mpfs_gpio_direction_input; -+ mpfs_gpio->gc.direction_output = mpfs_gpio_direction_output; -+ mpfs_gpio->gc.get_direction = mpfs_gpio_get_direction; -+ mpfs_gpio->gc.get = mpfs_gpio_get; -+ mpfs_gpio->gc.set = mpfs_gpio_set; -+ mpfs_gpio->gc.base = -1; -+ mpfs_gpio->gc.ngpio = ngpios; -+ mpfs_gpio->gc.label = dev_name(dev); -+ mpfs_gpio->gc.parent = dev; -+ mpfs_gpio->gc.owner = THIS_MODULE; -+ -+ nirqs = of_irq_count(node); -+ if (nirqs > MAX_NUM_GPIO) { -+ ret = -ENXIO; -+ goto cleanup_clock; -+ } -+ girq = &mpfs_gpio->gc.irq; -+ girq->chip = &mpfs_gpio_irqchip; -+ girq->handler = handle_simple_irq; -+ girq->parent_handler = mpfs_gpio_irq_handler; -+ girq->default_type = IRQ_TYPE_NONE; -+ girq->num_parents = nirqs; -+ girq->parents = devm_kcalloc(&pdev->dev, nirqs, -+ sizeof(*girq->parents), GFP_KERNEL); -+ if (!girq->parents) { -+ ret = -ENOMEM; -+ goto cleanup_clock; -+ } -+ for (i = 0; i < nirqs; i++) -+ girq->parents[i] = platform_get_irq(pdev, i); -+ -+ ret = gpiochip_add_data(&mpfs_gpio->gc, mpfs_gpio); -+ if (ret) -+ goto cleanup_clock; -+ -+ platform_set_drvdata(pdev, mpfs_gpio); -+ -+ return 0; -+ -+cleanup_clock: -+ clk_disable_unprepare(mpfs_gpio->clk); -+ return ret; -+} -+ -+static int mpfs_gpio_remove(struct platform_device *pdev) -+{ -+ struct mpfs_gpio_chip *mpfs_gpio = platform_get_drvdata(pdev); -+ -+ gpiochip_remove(&mpfs_gpio->gc); -+ clk_disable_unprepare(mpfs_gpio->clk); -+ -+ return 0; -+} -+ -+static const struct of_device_id mpfs_of_ids[] = { -+ { .compatible = "microchip,core-gpio", }, -+ { /* end of list */ } -+}; -+ -+static struct platform_driver mchp_core_gpio_driver = { -+ .probe = mpfs_gpio_probe, -+ .driver = { -+ .name = "microchip,core-gpio", -+ .of_match_table = mpfs_of_ids, -+ }, -+ .remove = mpfs_gpio_remove, -+}; -+builtin_platform_driver(mchp_core_gpio_driver); --- -2.39.2 - diff --git a/patches/linux/0004-ADC-Add-Microchip-MCP356X-driver.patch b/patches/linux/0004-ADC-Add-Microchip-MCP356X-driver.patch deleted file mode 100644 index 32fa0f1..0000000 --- a/patches/linux/0004-ADC-Add-Microchip-MCP356X-driver.patch +++ /dev/null @@ -1,1450 +0,0 @@ -From deadef387eed1bc60c8d2570e86a9bd0b4b196b4 Mon Sep 17 00:00:00 2001 -From: vauban353 -Date: Fri, 16 Jun 2023 16:05:01 +0100 -Subject: [PATCH 4/8] ADC: Add Microchip MCP356X driver. - ---- - drivers/iio/adc/Kconfig | 10 + - drivers/iio/adc/Makefile | 1 + - drivers/iio/adc/mcp356x.c | 1396 +++++++++++++++++++++++++++++++++++++ - 3 files changed, 1407 insertions(+) - create mode 100644 drivers/iio/adc/mcp356x.c - -diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig -index 48763d6a8..6c6b62a7f 100644 ---- a/drivers/iio/adc/Kconfig -+++ b/drivers/iio/adc/Kconfig -@@ -741,6 +741,16 @@ config MCP3911 - This driver can also be built as a module. If so, the module will be - called mcp3911. - -+config MCP356X -+ tristate "Microchip Technology MCP356X driver" -+ depends on SPI -+ help -+ Say yes here to build support for Microchip Technology's MCP356X -+ analog to digital converter. -+ -+ This driver can also be built as a module. If so, the module will be -+ called mcp356x. -+ - config MEDIATEK_MT6360_ADC - tristate "Mediatek MT6360 ADC driver" - depends on MFD_MT6360 -diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile -index d5ca37205..5b3f027ac 100644 ---- a/drivers/iio/adc/Makefile -+++ b/drivers/iio/adc/Makefile -@@ -68,6 +68,7 @@ obj-$(CONFIG_MAX9611) += max9611.o - obj-$(CONFIG_MCP320X) += mcp320x.o - obj-$(CONFIG_MCP3422) += mcp3422.o - obj-$(CONFIG_MCP3911) += mcp3911.o -+obj-$(CONFIG_MCP356X) += mcp356x.o - obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o - obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o - obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o -diff --git a/drivers/iio/adc/mcp356x.c b/drivers/iio/adc/mcp356x.c -new file mode 100644 -index 000000000..22d59413d ---- /dev/null -+++ b/drivers/iio/adc/mcp356x.c -@@ -0,0 +1,1396 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * IIO driver for MCP356X/MCP356XR and MCP346X/MCP346XR series ADC chip family -+ * -+ * Copyright (C) 2022-2023 Microchip Technology Inc. and its subsidiaries -+ * -+ * Author: Marius Cristea -+ * -+ * Datasheet for MCP3561, MCP3562, MCP3564 can be found here: -+ * https://ww1.microchip.com/downloads/aemDocuments/documents/MSLD/ProductDocuments/DataSheets/MCP3561-2-4-Family-Data-Sheet-DS20006181C.pdf -+ * Datasheet for MCP3561R, MCP3562R, MCP3564R can be found here: -+ * https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3561_2_4R-Data-Sheet-DS200006391C.pdf -+ * Datasheet for MCP3461, MCP3462, MCP3464 can be found here: -+ * https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3461-2-4-Two-Four-Eight-Channel-153.6-ksps-Low-Noise-16-Bit-Delta-Sigma-ADC-Data-Sheet-20006180D.pdf -+ * Datasheet for MCP3461R, MCP3462R, MCP3464R can be found here: -+ * https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3461-2-4R-Family-Data-Sheet-DS20006404C.pdf -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define MCP356X_ADCDATA 0x00 -+#define MCP356X_CONFIG0 0x01 -+#define MCP356X_CONFIG1 0x02 -+#define MCP356X_CONFIG2 0x03 -+#define MCP356X_CONFIG3 0x04 -+#define MCP356X_IRQ 0x05 -+#define MCP356X_MUX 0x06 -+#define MCP356X_SCAN 0x07 -+#define MCP356X_TIMER 0x08 -+#define MCP356X_OFFSETCAL 0x09 -+#define MCP356X_GAINCAL 0x0A -+#define MCP356X_RESERVED_B 0x0B -+#define MCP356X_RESERVED_C 0x0C -+#define MCP356X_LOCK 0x0D -+#define MCP356X_RESERVED_E 0x0E -+#define MCP356X_CRCCFG 0x0F -+ -+#define MCP356X_FAST_CMD_CTRL 0 -+#define MCP356X_RD_CTRL BIT(0) -+#define MCP356X_WRT_CTRL BIT(1) -+ -+#define MCP356X_FULL_RESET_CMD GENMASK(3, 1) -+ -+#define MCP3461_HW_ID BIT(3) -+#define MCP3462_HW_ID 0x0009 -+#define MCP3464_HW_ID 0x000B -+ -+#define MCP3561_HW_ID GENMASK(3, 2) -+#define MCP3562_HW_ID 0x000D -+#define MCP3564_HW_ID GENMASK(3, 0) -+#define MCP356X_HW_ID_MASK GENMASK(3, 0) -+ -+#define MCP356XR_INT_VREF_MV 2400 -+ -+/* MUX_VIN Input Selection -+ */ -+#define MCP356X_INTERNAL_VCM GENMASK(3, 0) -+#define MCP356X_TEMP_DIODE_M GENMASK(3, 1) -+#define MCP356X_TEMP_DIODE_P 0b1101 -+#define MCP356X_REFIN_NEG GENMASK(3, 2) -+#define MCP356X_REFIN_POZ 0b1011 -+#define MCP356X_RESERVED 0b1010 /* do not use */ -+#define MCP356X_AVDD 0b1001 -+#define MCP356X_AGND BIT(3) -+#define MCP356X_CH7 GENMASK(2, 0) -+#define MCP356X_CH6 GENMASK(2, 1) -+#define MCP356X_CH5 0b0101 -+#define MCP356X_CH4 BIT(2) -+#define MCP356X_CH3 GENMASK(1, 0) -+#define MCP356X_CH2 BIT(1) -+#define MCP356X_CH1 BIT(0) -+#define MCP356X_CH0 0 -+ -+#define MCP356X_ADC_MODE_MASK GENMASK(1, 0) -+ -+#define MCP356X_ADC_DEFAULT_MODE 0 -+#define MCP356X_ADC_SHUTDOWN_MODE BIT(0) -+#define MCP356X_ADC_STANDBY BIT(1) -+#define MCP356X_ADC_CONVERSION_MODE GENMASK(1, 0) -+ -+#define MCP356X_DATA_READY_MASK BIT(6) -+ -+#define MCP356X_OVERSAMPLING_RATIO_32 0 -+#define MCP356X_OVERSAMPLING_RATIO_64 BIT(0) -+#define MCP356X_OVERSAMPLING_RATIO_128 BIT(1) -+#define MCP356X_OVERSAMPLING_RATIO_256 GENMASK(1, 0) -+#define MCP356X_OVERSAMPLING_RATIO_512 BIT(2) -+#define MCP356X_OVERSAMPLING_RATIO_1024 0x05 -+#define MCP356X_OVERSAMPLING_RATIO_2048 GENMASK(2, 1) -+#define MCP356X_OVERSAMPLING_RATIO_4096 GENMASK(2, 0) -+#define MCP356X_OVERSAMPLING_RATIO_8192 BIT(3) -+#define MCP356X_OVERSAMPLING_RATIO_16384 0x09 -+#define MCP356X_OVERSAMPLING_RATIO_20480 0x0A -+#define MCP356X_OVERSAMPLING_RATIO_24576 0x0B -+#define MCP356X_OVERSAMPLING_RATIO_40960 0x0C -+#define MCP356X_OVERSAMPLING_RATIO_49152 0x0D -+#define MCP356X_OVERSAMPLING_RATIO_81920 GENMASK(3, 1) -+#define MCP356X_OVERSAMPLING_RATIO_98304 GENMASK(3, 0) -+ -+#define MCP356X_OVERSAMPLING_RATIO_MASK GENMASK(5, 2) -+#define MCP356X_OVERSAMPLING_RATIO_SHIFT 0x02 -+ -+#define MCP356X_HARDWARE_GAIN_MASK GENMASK(5, 3) -+#define MCP356X_HARDWARE_GAIN_SHIFT 0x03 -+#define MCP356X_DEFAULT_HARDWARE_GAIN BIT(1) -+ -+#define MCP356X_CS_SEL_0_0_uA 0x0 -+#define MCP356X_CS_SEL_0_9_uA BIT(0) -+#define MCP356X_CS_SEL_3_7_uA BIT(1) -+#define MCP356X_CS_SEL_15_uA GENMASK(1, 0) -+ -+#define MCP356X_CS_SEL_MASK GENMASK(3, 2) -+ -+#define MCP356X_BOOST_CURRENT_x0_50 0 -+#define MCP356X_BOOST_CURRENT_x0_66 BIT(0) -+#define MCP356X_BOOST_CURRENT_x1_00 BIT(1) -+#define MCP356X_BOOST_CURRENT_x2_00 GENMASK(1, 0) -+ -+#define MCP356X_BOOST_CURRENT_MASK GENMASK(7, 6) -+ -+/* Auto-Zeroing MUX Setting */ -+#define MCP356X_AZ_MUX_MASK BIT(2) -+/* Auto-Zeroing REF Setting */ -+#define MCP356X_AZ_REF_MASK BIT(1) -+ -+#define MCP356X_SHARED_DEVATTRS_COUNT 1 -+#define MCP356X_PARTICULAR_DEVATTRS_COUNT 1 -+ -+#define MAX_HWGAIN 64000 -+ -+#define MCP356X_DATA_READY_TIMEOUT_MS 2000 -+ -+enum mcp356x_ids { -+ mcp3461, -+ mcp3462, -+ mcp3464, -+ mcp3461r, -+ mcp3462r, -+ mcp3464r, -+ mcp3561, -+ mcp3562, -+ mcp3564, -+ mcp3561r, -+ mcp3562r, -+ mcp3564r, -+}; -+ -+static const unsigned int mcp356x_oversampling_avail[16] = { -+ [MCP356X_OVERSAMPLING_RATIO_32] = 32, -+ [MCP356X_OVERSAMPLING_RATIO_64] = 64, -+ [MCP356X_OVERSAMPLING_RATIO_128] = 128, -+ [MCP356X_OVERSAMPLING_RATIO_256] = 256, -+ [MCP356X_OVERSAMPLING_RATIO_512] = 512, -+ [MCP356X_OVERSAMPLING_RATIO_1024] = 1024, -+ [MCP356X_OVERSAMPLING_RATIO_2048] = 2048, -+ [MCP356X_OVERSAMPLING_RATIO_4096] = 4096, -+ [MCP356X_OVERSAMPLING_RATIO_8192] = 8192, -+ [MCP356X_OVERSAMPLING_RATIO_16384] = 16384, -+ [MCP356X_OVERSAMPLING_RATIO_20480] = 20480, -+ [MCP356X_OVERSAMPLING_RATIO_24576] = 24576, -+ [MCP356X_OVERSAMPLING_RATIO_40960] = 40960, -+ [MCP356X_OVERSAMPLING_RATIO_49152] = 49152, -+ [MCP356X_OVERSAMPLING_RATIO_81920] = 81920, -+ [MCP356X_OVERSAMPLING_RATIO_98304] = 98304 -+}; -+ -+/* -+ * Current Source/Sink Selection Bits for Sensor Bias (source on VIN+/sink on VIN-) -+ */ -+static const char * const mcp356x_current_bias_avail[] = { -+ [MCP356X_CS_SEL_0_0_uA] = "no_current(default)", -+ [MCP356X_CS_SEL_0_9_uA] = "0.9_uA", -+ [MCP356X_CS_SEL_3_7_uA] = "3.7_uA", -+ [MCP356X_CS_SEL_15_uA] = "15_uA", -+}; -+ -+/* -+ * BOOST[1:0]: ADC Bias Current Selection -+ */ -+static const char * const mcp356x_boost_current_avail[] = { -+ [MCP356X_BOOST_CURRENT_x0_50] = "x0.5", -+ [MCP356X_BOOST_CURRENT_x0_66] = "x0.66", -+ [MCP356X_BOOST_CURRENT_x1_00] = "x1_(default)", -+ [MCP356X_BOOST_CURRENT_x2_00] = "x2", -+}; -+ -+/* -+ * Calibration bias values -+ */ -+static const int mcp356x_calib_bias[] = { -+ -8388608, /* min: -2^23 */ -+ 1, /* step: 1 */ -+ 8388607 /* max: 2^23 - 1 */ -+}; -+ -+/* -+ * Calibration scale values -+ * The Gain Error Calibration register (GAINCAL) is an -+ * unsigned 24-bit register that holds the digital gain error -+ * calibration value, GAINCAL which could be calculated by -+ * GAINCAL (V/V) = (GAINCAL[23:0])/8388608 -+ * The gain error calibration value range in equivalent voltage is [0; 2-2^(-23)] -+ */ -+static const unsigned int mcp356x_calib_scale[] = { -+ 0, /* min: 0 */ -+ 1, /* step: 1/8388608 */ -+ 16777215 /* max: 2 - 2^(-23) */ -+}; -+ -+/* Programmable hardware gain x1/3, x1, x2, x4, x8, x16, x32, x64 */ -+static const int mcp356x_hwgain_frac[] = { -+ 3, -+ 10, -+ 1, -+ 1, -+ 2, -+ 1, -+ 4, -+ 1, -+ 8, -+ 1, -+ 16, -+ 1, -+ 32, -+ 1, -+ 64, -+ 1 -+}; -+ -+static const int mcp356x_hwgain[] = { -+ 300, -+ 1000, -+ 2000, -+ 4000, -+ 8000, -+ 16000, -+ 32000, -+ 64000 -+}; -+ -+/** -+ * struct mcp356x_chip_info - chip specific data -+ * @channels: struct iio_chan_spec matching the device's capabilities -+ * @num_channels: number of channels -+ * @int_vref_uv: internal voltage reference value in microVolts -+ * @has_vref: Does the ADC has an internal voltage reference? -+ */ -+struct mcp356x_chip_info { -+ const struct iio_chan_spec *channels; -+ unsigned int num_channels; -+ unsigned int int_vref_uv; -+ bool has_vref; -+}; -+ -+/** -+ * struct mcp356x_state - working data for a ADC device -+ * @chip_info: chip specific data -+ * @mcp356x_info: information about iio device -+ * @spi: SPI device structure -+ * @vref: The regulator device used as a voltage reference in case -+ * external voltage reference is used -+ * @vref_mv: voltage reference value in miliVolts -+ * @lock: mutex to prevent concurrent reads/writes -+ * @dev_addr: hardware device address -+ * @oversampling: the index inside oversampling list of the ADC -+ * @hwgain: the index inside hardware gain list of the ADC -+ * @calib_bias: calibration bias value -+ * @calib_scale: calibration scale value -+ * @current_boost_mode: the index inside current boost list of the ADC -+ * @current_bias_mode: the index inside current bias list of the ADC -+ * @auto_zeroing_mux: set if ADC auto-zeroing algorithm is enabled -+ * @auto_zeroing_ref: set if ADC auto-Zeroing Reference Buffer Setting is enabled -+ */ -+struct mcp356x_state { -+ const struct mcp356x_chip_info *chip_info; -+ struct iio_info mcp356x_info; -+ struct spi_device *spi; -+ struct regulator *vref; -+ unsigned short vref_mv; -+ struct mutex lock; /*lock to prevent concurrent reads/writes */ -+ u8 dev_addr; -+ unsigned int oversampling; -+ unsigned int hwgain; -+ int calib_bias; -+ int calib_scale; -+ unsigned int current_boost_mode; -+ unsigned int current_bias_mode; -+ bool auto_zeroing_mux; -+ bool auto_zeroing_ref; -+}; -+ -+static inline u8 mcp356x_reg_write(u8 chip_addr, u8 reg) -+{ -+ return ((chip_addr << 6) | (reg << 2) | MCP356X_WRT_CTRL); -+} -+ -+static inline u8 mcp356x_reg_read(u8 chip_addr, u8 reg) -+{ -+ return ((chip_addr << 6) | (reg << 2) | MCP356X_RD_CTRL); -+} -+ -+static inline u8 mcp356x_reg_fast_cmd(u8 chip_addr, u8 cmd) -+{ -+ return ((chip_addr << 6) | (cmd << 2)); -+} -+ -+static int mcp356x_read(struct mcp356x_state *adc, u8 reg, u32 *val, u8 len) -+{ -+ int ret; -+ u8 tmp_reg; -+ -+ tmp_reg = mcp356x_reg_read(adc->dev_addr, reg); -+ -+ ret = spi_write_then_read(adc->spi, &tmp_reg, 1, val, len); -+ -+ be32_to_cpus(val); -+ *val >>= ((4 - len) * 8); -+ -+ return ret; -+} -+ -+static int mcp356x_write(struct mcp356x_state *adc, u8 reg, u32 val, u8 len) -+{ -+ val |= (mcp356x_reg_write(adc->dev_addr, reg) << (len * 8)); -+ val <<= (3 - len) * 8; -+ cpu_to_be32s(&val); -+ -+ return spi_write(adc->spi, &val, len + 1); -+} -+ -+static int mcp356x_fast_cmd(struct mcp356x_state *adc, u8 fast_cmd) -+{ -+ u8 val; -+ -+ val = mcp356x_reg_fast_cmd(adc->dev_addr, fast_cmd); -+ -+ return spi_write(adc->spi, &val, 1); -+} -+ -+static int mcp356x_update(struct mcp356x_state *adc, u8 reg, u32 mask, u32 val, -+ u8 len) -+{ -+ u32 tmp; -+ int ret; -+ -+ ret = mcp356x_read(adc, reg, &tmp, len); -+ -+ if (ret == 0) { -+ val &= mask; -+ val |= tmp & ~mask; -+ ret = mcp356x_write(adc, reg, val, len); -+ } -+ -+ return ret; -+} -+ -+/* Custom IIO Device Attributes */ -+static int mcp356x_set_current_boost_mode(struct iio_dev *indio_dev, -+ const struct iio_chan_spec *chan, -+ unsigned int mode) -+{ -+ struct mcp356x_state *adc = iio_priv(indio_dev); -+ int ret; -+ -+ dev_dbg(&indio_dev->dev, "%s: %d\n", __func__, mode); -+ -+ mutex_lock(&adc->lock); -+ ret = mcp356x_update(adc, MCP356X_CONFIG2, MCP356X_BOOST_CURRENT_MASK, -+ mode, 1); -+ -+ if (ret) -+ dev_err(&indio_dev->dev, "Failed to configure CONFIG2 register\n"); -+ else -+ adc->current_boost_mode = mode; -+ -+ mutex_unlock(&adc->lock); -+ -+ return ret; -+} -+ -+static int mcp356x_get_current_boost_mode(struct iio_dev *indio_dev, -+ const struct iio_chan_spec *chan) -+{ -+ struct mcp356x_state *adc = iio_priv(indio_dev); -+ -+ return adc->current_boost_mode; -+} -+ -+static int mcp356x_set_current_bias_mode(struct iio_dev *indio_dev, -+ const struct iio_chan_spec *chan, -+ unsigned int mode) -+{ -+ struct mcp356x_state *adc = iio_priv(indio_dev); -+ int ret; -+ -+ dev_dbg(&indio_dev->dev, "%s: %d\n", __func__, mode); -+ -+ mutex_lock(&adc->lock); -+ ret = mcp356x_update(adc, MCP356X_CONFIG0, MCP356X_CS_SEL_MASK, mode, 1); -+ -+ if (ret) -+ dev_err(&indio_dev->dev, "Failed to configure CONFIG0 register\n"); -+ else -+ adc->current_bias_mode = mode; -+ -+ mutex_unlock(&adc->lock); -+ -+ return ret; -+} -+ -+static int mcp356x_get_current_bias_mode(struct iio_dev *indio_dev, -+ const struct iio_chan_spec *chan) -+{ -+ struct mcp356x_state *adc = iio_priv(indio_dev); -+ -+ return adc->current_bias_mode; -+} -+ -+static const struct iio_enum mcp356x_current_boost_mode_enum = { -+ .items = mcp356x_boost_current_avail, -+ .num_items = ARRAY_SIZE(mcp356x_boost_current_avail), -+ .set = mcp356x_set_current_boost_mode, -+ .get = mcp356x_get_current_boost_mode, -+}; -+ -+static const struct iio_enum mcp356x_current_bias_mode_enum = { -+ .items = mcp356x_current_bias_avail, -+ .num_items = ARRAY_SIZE(mcp356x_current_bias_avail), -+ .set = mcp356x_set_current_bias_mode, -+ .get = mcp356x_get_current_bias_mode, -+}; -+ -+static const struct iio_chan_spec_ext_info mcp356x_ext_info[] = { -+ IIO_ENUM("boost_current", IIO_SHARED_BY_ALL, &mcp356x_current_boost_mode_enum), -+ { -+ .name = "boost_current_available", -+ .shared = IIO_SHARED_BY_ALL, -+ .read = iio_enum_available_read, -+ .private = (uintptr_t)&mcp356x_current_boost_mode_enum, -+ }, -+ IIO_ENUM("current_bias", IIO_SHARED_BY_ALL, &mcp356x_current_bias_mode_enum), -+ { -+ .name = "current_bias_available", -+ .shared = IIO_SHARED_BY_ALL, -+ .read = iio_enum_available_read, -+ .private = (uintptr_t)&mcp356x_current_bias_mode_enum, -+ }, -+ {} -+}; -+ -+static ssize_t mcp356x_auto_zeroing_mux_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct iio_dev *indio_dev = dev_to_iio_dev(dev); -+ struct mcp356x_state *adc = iio_priv(indio_dev); -+ -+ return sysfs_emit(buf, "%d\n", adc->auto_zeroing_mux); -+} -+ -+static ssize_t mcp356x_auto_zeroing_mux_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ struct iio_dev *indio_dev = dev_to_iio_dev(dev); -+ struct mcp356x_state *adc = iio_priv(indio_dev); -+ bool auto_zero; -+ int ret; -+ -+ ret = kstrtobool(buf, &auto_zero); -+ if (ret) -+ return ret; -+ -+ mutex_lock(&adc->lock); -+ ret = mcp356x_update(adc, MCP356X_CONFIG2, MCP356X_AZ_MUX_MASK, -+ (u32)auto_zero, 1); -+ -+ if (ret) -+ dev_err(&indio_dev->dev, "Failed to update CONFIG2 register\n"); -+ else -+ adc->auto_zeroing_mux = auto_zero; -+ -+ mutex_unlock(&adc->lock); -+ -+ return ret ? ret : len; -+} -+ -+static ssize_t mcp356x_auto_zeroing_ref_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct iio_dev *indio_dev = dev_to_iio_dev(dev); -+ struct mcp356x_state *adc = iio_priv(indio_dev); -+ -+ return sysfs_emit(buf, "%d\n", adc->auto_zeroing_ref); -+} -+ -+static ssize_t mcp356x_auto_zeroing_ref_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ struct iio_dev *indio_dev = dev_to_iio_dev(dev); -+ struct mcp356x_state *adc = iio_priv(indio_dev); -+ bool auto_zero; -+ int ret; -+ -+ ret = kstrtobool(buf, &auto_zero); -+ if (ret) -+ return ret; -+ -+ mutex_lock(&adc->lock); -+ ret = mcp356x_update(adc, MCP356X_CONFIG2, MCP356X_AZ_REF_MASK, -+ (u32)auto_zero, 1); -+ -+ if (ret) -+ dev_err(&indio_dev->dev, "Failed to update CONFIG2 register\n"); -+ else -+ adc->auto_zeroing_ref = auto_zero; -+ -+ mutex_unlock(&adc->lock); -+ -+ return ret ? ret : len; -+} -+ -+#define MCP356X_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr) -+ -+static IIO_DEVICE_ATTR(enable_auto_zeroing_ref, 0644, -+ mcp356x_auto_zeroing_ref_show, -+ mcp356x_auto_zeroing_ref_store, 0); -+ -+static struct attribute *mcp356x_particular_attributes[] = { -+ MCP356X_DEV_ATTR(enable_auto_zeroing_ref), -+ NULL -+}; -+ -+static IIO_DEVICE_ATTR(enable_auto_zeroing_mux, 0644, -+ mcp356x_auto_zeroing_mux_show, -+ mcp356x_auto_zeroing_mux_store, 0); -+ -+static struct attribute *mcp356x_shared_attributes[] = { -+ MCP356X_DEV_ATTR(enable_auto_zeroing_mux), -+ NULL, -+}; -+ -+static int mcp356x_prep_custom_attributes(struct mcp356x_state *adc, -+ struct iio_dev *indio_dev) -+{ -+ int i; -+ struct attribute **mcp356x_custom_attr; -+ struct attribute_group *mcp356x_group; -+ -+ mcp356x_group = devm_kzalloc(&adc->spi->dev, sizeof(*mcp356x_group), GFP_KERNEL); -+ -+ if (!mcp356x_group) -+ return (-ENOMEM); -+ -+ mcp356x_custom_attr = devm_kzalloc(&adc->spi->dev, (MCP356X_SHARED_DEVATTRS_COUNT + -+ MCP356X_PARTICULAR_DEVATTRS_COUNT + 1) * sizeof(struct attribute *), -+ GFP_KERNEL); -+ -+ if (!mcp356x_custom_attr) -+ return (-ENOMEM); -+ -+ for (i = 0; i < MCP356X_SHARED_DEVATTRS_COUNT; i++) -+ mcp356x_custom_attr[i] = mcp356x_shared_attributes[i]; -+ -+ if (adc->chip_info->has_vref) { -+ dev_dbg(&indio_dev->dev, "Setup custom attr for R variant\n"); -+ for (i = 0; i < MCP356X_PARTICULAR_DEVATTRS_COUNT; i++) -+ mcp356x_custom_attr[MCP356X_SHARED_DEVATTRS_COUNT + i] = -+ mcp356x_particular_attributes[i]; -+ } -+ -+ mcp356x_group->attrs = mcp356x_custom_attr; -+ adc->mcp356x_info.attrs = mcp356x_group; -+ -+ return 0; -+} -+ -+#define MCP356X_V_CHANNEL(index, addr, depth) { \ -+ .type = IIO_VOLTAGE, \ -+ .indexed = 1, \ -+ .channel = (index), \ -+ .address = (((addr) << 4) | MCP356X_AGND), \ -+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ -+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ -+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \ -+ BIT(IIO_CHAN_INFO_CALIBBIAS) | \ -+ BIT(IIO_CHAN_INFO_CALIBSCALE) | \ -+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ -+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_CALIBSCALE) | \ -+ BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \ -+ BIT(IIO_CHAN_INFO_CALIBBIAS) | \ -+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ -+ .ext_info = mcp356x_ext_info, \ -+ .scan_index = 0, \ -+ .scan_type = { \ -+ .sign = 's', \ -+ .realbits = depth, \ -+ .storagebits = 32, \ -+ .endianness = IIO_BE, \ -+ }, \ -+} -+ -+#define MCP356X_T_CHAN(depth) { \ -+ .type = IIO_TEMP, \ -+ .channel = 0, \ -+ .address = ((MCP356X_TEMP_DIODE_P << 4) | MCP356X_TEMP_DIODE_M), \ -+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ -+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ -+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \ -+ BIT(IIO_CHAN_INFO_CALIBBIAS) | \ -+ BIT(IIO_CHAN_INFO_CALIBSCALE) | \ -+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ -+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_CALIBSCALE) | \ -+ BIT(IIO_CHAN_INFO_CALIBBIAS) | \ -+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ -+ .ext_info = mcp356x_ext_info, \ -+ .scan_index = 0, \ -+ .scan_type = { \ -+ .sign = 'u', \ -+ .realbits = depth, \ -+ .storagebits = 32, \ -+ .endianness = IIO_BE, \ -+ }, \ -+} -+ -+#define MCP356X_V_CHANNEL_DIFF(chan1, chan2, addr, depth) { \ -+ .type = IIO_VOLTAGE, \ -+ .indexed = 1, \ -+ .channel = (chan1), \ -+ .channel2 = (chan2), \ -+ .address = (addr), \ -+ .differential = 1, \ -+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ -+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ -+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \ -+ BIT(IIO_CHAN_INFO_CALIBBIAS) | \ -+ BIT(IIO_CHAN_INFO_CALIBSCALE) | \ -+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ -+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_CALIBSCALE) | \ -+ BIT(IIO_CHAN_INFO_CALIBBIAS) | \ -+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ -+ .ext_info = mcp356x_ext_info, \ -+ .scan_index = 0, \ -+ .scan_type = { \ -+ .sign = 's', \ -+ .realbits = depth, \ -+ .storagebits = 32, \ -+ .endianness = IIO_BE, \ -+ }, \ -+} -+ -+#define MCP3561_CHANNELS(depth) { \ -+ MCP356X_V_CHANNEL(0, 0, depth), \ -+ MCP356X_V_CHANNEL(1, 1, depth), \ -+ MCP356X_V_CHANNEL_DIFF(0, 1, 0x01, depth), \ -+ MCP356X_V_CHANNEL_DIFF(1, 0, 0x10, depth), \ -+ MCP356X_T_CHAN(depth) \ -+} -+ -+#define MCP3562_CHANNELS(depth) { \ -+ MCP356X_V_CHANNEL(0, 0, depth), \ -+ MCP356X_V_CHANNEL(1, 1, depth), \ -+ MCP356X_V_CHANNEL(2, 2, depth), \ -+ MCP356X_V_CHANNEL(3, 3, depth), \ -+ MCP356X_T_CHAN(depth), \ -+ MCP356X_V_CHANNEL_DIFF(0, 1, 0x01, depth), \ -+ MCP356X_V_CHANNEL_DIFF(1, 0, 0x10, depth), \ -+ MCP356X_V_CHANNEL_DIFF(0, 2, 0x02, depth), \ -+ MCP356X_V_CHANNEL_DIFF(0, 3, 0x03, depth), \ -+ MCP356X_V_CHANNEL_DIFF(1, 2, 0x12, depth), \ -+ MCP356X_V_CHANNEL_DIFF(1, 3, 0x13, depth), \ -+ MCP356X_V_CHANNEL_DIFF(2, 3, 0x23, depth), \ -+ MCP356X_V_CHANNEL_DIFF(2, 0, 0x20, depth), \ -+ MCP356X_V_CHANNEL_DIFF(3, 0, 0x30, depth), \ -+ MCP356X_V_CHANNEL_DIFF(2, 1, 0x21, depth), \ -+ MCP356X_V_CHANNEL_DIFF(3, 1, 0x31, depth), \ -+ MCP356X_V_CHANNEL_DIFF(3, 2, 0x32, depth), \ -+} -+ -+#define MCP3564_CHANNELS(depth) { \ -+ MCP356X_V_CHANNEL(0, 0, depth), \ -+ MCP356X_V_CHANNEL(1, 1, depth), \ -+ MCP356X_V_CHANNEL(2, 2, depth), \ -+ MCP356X_V_CHANNEL(3, 3, depth), \ -+ MCP356X_V_CHANNEL(4, 4, depth), \ -+ MCP356X_V_CHANNEL(5, 5, depth), \ -+ MCP356X_V_CHANNEL(6, 6, depth), \ -+ MCP356X_V_CHANNEL(7, 7, depth), \ -+ MCP356X_T_CHAN(depth), \ -+ MCP356X_V_CHANNEL_DIFF(0, 1, 0x01, depth), \ -+ MCP356X_V_CHANNEL_DIFF(1, 0, 0x10, depth), \ -+ MCP356X_V_CHANNEL_DIFF(0, 2, 0x02, depth), \ -+ MCP356X_V_CHANNEL_DIFF(0, 3, 0x03, depth), \ -+ MCP356X_V_CHANNEL_DIFF(1, 2, 0x12, depth), \ -+ MCP356X_V_CHANNEL_DIFF(1, 3, 0x13, depth), \ -+ MCP356X_V_CHANNEL_DIFF(2, 3, 0x23, depth), \ -+ MCP356X_V_CHANNEL_DIFF(2, 0, 0x20, depth), \ -+ MCP356X_V_CHANNEL_DIFF(3, 0, 0x30, depth), \ -+ MCP356X_V_CHANNEL_DIFF(2, 1, 0x21, depth), \ -+ MCP356X_V_CHANNEL_DIFF(3, 1, 0x31, depth), \ -+ MCP356X_V_CHANNEL_DIFF(3, 2, 0x32, depth), \ -+ MCP356X_V_CHANNEL_DIFF(0, 4, 0x04, depth), \ -+ MCP356X_V_CHANNEL_DIFF(0, 5, 0x05, depth), \ -+ MCP356X_V_CHANNEL_DIFF(0, 6, 0x06, depth), \ -+ MCP356X_V_CHANNEL_DIFF(0, 7, 0x07, depth), \ -+ MCP356X_V_CHANNEL_DIFF(1, 4, 0x14, depth), \ -+ MCP356X_V_CHANNEL_DIFF(1, 5, 0x15, depth), \ -+ MCP356X_V_CHANNEL_DIFF(1, 6, 0x16, depth), \ -+ MCP356X_V_CHANNEL_DIFF(1, 7, 0x17, depth), \ -+ MCP356X_V_CHANNEL_DIFF(2, 4, 0x24, depth), \ -+ MCP356X_V_CHANNEL_DIFF(2, 5, 0x25, depth), \ -+ MCP356X_V_CHANNEL_DIFF(2, 6, 0x26, depth), \ -+ MCP356X_V_CHANNEL_DIFF(2, 7, 0x27, depth), \ -+ MCP356X_V_CHANNEL_DIFF(3, 4, 0x34, depth), \ -+ MCP356X_V_CHANNEL_DIFF(3, 5, 0x35, depth), \ -+ MCP356X_V_CHANNEL_DIFF(3, 6, 0x36, depth), \ -+ MCP356X_V_CHANNEL_DIFF(3, 7, 0x37, depth), \ -+ MCP356X_V_CHANNEL_DIFF(4, 5, 0x45, depth), \ -+ MCP356X_V_CHANNEL_DIFF(4, 6, 0x46, depth), \ -+ MCP356X_V_CHANNEL_DIFF(4, 7, 0x47, depth), \ -+ MCP356X_V_CHANNEL_DIFF(5, 6, 0x56, depth), \ -+ MCP356X_V_CHANNEL_DIFF(5, 7, 0x57, depth), \ -+ MCP356X_V_CHANNEL_DIFF(6, 7, 0x67, depth), \ -+ MCP356X_V_CHANNEL_DIFF(4, 0, 0x40, depth), \ -+ MCP356X_V_CHANNEL_DIFF(5, 0, 0x50, depth), \ -+ MCP356X_V_CHANNEL_DIFF(6, 0, 0x60, depth), \ -+ MCP356X_V_CHANNEL_DIFF(7, 0, 0x70, depth), \ -+ MCP356X_V_CHANNEL_DIFF(4, 1, 0x41, depth), \ -+ MCP356X_V_CHANNEL_DIFF(5, 1, 0x51, depth), \ -+ MCP356X_V_CHANNEL_DIFF(6, 1, 0x61, depth), \ -+ MCP356X_V_CHANNEL_DIFF(7, 1, 0x71, depth), \ -+ MCP356X_V_CHANNEL_DIFF(4, 2, 0x42, depth), \ -+ MCP356X_V_CHANNEL_DIFF(5, 2, 0x52, depth), \ -+ MCP356X_V_CHANNEL_DIFF(6, 2, 0x62, depth), \ -+ MCP356X_V_CHANNEL_DIFF(7, 2, 0x72, depth), \ -+ MCP356X_V_CHANNEL_DIFF(4, 3, 0x43, depth), \ -+ MCP356X_V_CHANNEL_DIFF(5, 3, 0x53, depth), \ -+ MCP356X_V_CHANNEL_DIFF(6, 3, 0x63, depth), \ -+ MCP356X_V_CHANNEL_DIFF(7, 3, 0x73, depth), \ -+ MCP356X_V_CHANNEL_DIFF(5, 4, 0x54, depth), \ -+ MCP356X_V_CHANNEL_DIFF(6, 4, 0x64, depth), \ -+ MCP356X_V_CHANNEL_DIFF(7, 4, 0x74, depth), \ -+ MCP356X_V_CHANNEL_DIFF(6, 5, 0x65, depth), \ -+ MCP356X_V_CHANNEL_DIFF(7, 5, 0x75, depth), \ -+ MCP356X_V_CHANNEL_DIFF(7, 6, 0x76, depth) \ -+} -+ -+static const struct iio_chan_spec mcp3461_channels[] = MCP3561_CHANNELS(16); -+static const struct iio_chan_spec mcp3462_channels[] = MCP3562_CHANNELS(16); -+static const struct iio_chan_spec mcp3464_channels[] = MCP3564_CHANNELS(16); -+static const struct iio_chan_spec mcp3561_channels[] = MCP3561_CHANNELS(24); -+static const struct iio_chan_spec mcp3562_channels[] = MCP3562_CHANNELS(24); -+static const struct iio_chan_spec mcp3564_channels[] = MCP3564_CHANNELS(24); -+ -+static const struct mcp356x_chip_info mcp356x_chip_infos_tbl[] = { -+ [mcp3461] = { -+ .channels = mcp3461_channels, -+ .num_channels = ARRAY_SIZE(mcp3461_channels), -+ .int_vref_uv = 0, -+ .has_vref = false -+ }, -+ [mcp3462] = { -+ .channels = mcp3462_channels, -+ .num_channels = ARRAY_SIZE(mcp3462_channels), -+ .int_vref_uv = 0, -+ .has_vref = false -+ }, -+ [mcp3464] = { -+ .channels = mcp3464_channels, -+ .num_channels = ARRAY_SIZE(mcp3464_channels), -+ .int_vref_uv = 0, -+ .has_vref = false -+ }, -+ [mcp3461r] = { -+ .channels = mcp3461_channels, -+ .num_channels = ARRAY_SIZE(mcp3461_channels), -+ .int_vref_uv = MCP356XR_INT_VREF_MV, -+ .has_vref = true -+ }, -+ [mcp3462r] = { -+ .channels = mcp3462_channels, -+ .num_channels = ARRAY_SIZE(mcp3462_channels), -+ .int_vref_uv = MCP356XR_INT_VREF_MV, -+ .has_vref = true -+ }, -+ [mcp3464r] = { -+ .channels = mcp3464_channels, -+ .num_channels = ARRAY_SIZE(mcp3464_channels), -+ .int_vref_uv = MCP356XR_INT_VREF_MV, -+ .has_vref = true -+ }, -+ [mcp3561] = { -+ .channels = mcp3561_channels, -+ .num_channels = ARRAY_SIZE(mcp3561_channels), -+ .int_vref_uv = 0, -+ .has_vref = false -+ }, -+ [mcp3562] = { -+ .channels = mcp3562_channels, -+ .num_channels = ARRAY_SIZE(mcp3562_channels), -+ .int_vref_uv = 0, -+ .has_vref = false -+ }, -+ [mcp3564] = { -+ .channels = mcp3564_channels, -+ .num_channels = ARRAY_SIZE(mcp3564_channels), -+ .int_vref_uv = 0, -+ .has_vref = false -+ }, -+ [mcp3561r] = { -+ .channels = mcp3561_channels, -+ .num_channels = ARRAY_SIZE(mcp3561_channels), -+ .int_vref_uv = MCP356XR_INT_VREF_MV, -+ .has_vref = true -+ }, -+ [mcp3562r] = { -+ .channels = mcp3562_channels, -+ .num_channels = ARRAY_SIZE(mcp3562_channels), -+ .int_vref_uv = MCP356XR_INT_VREF_MV, -+ .has_vref = true -+ }, -+ [mcp3564r] = { -+ .channels = mcp3564_channels, -+ .num_channels = ARRAY_SIZE(mcp3564_channels), -+ .int_vref_uv = MCP356XR_INT_VREF_MV, -+ .has_vref = true -+ }, -+}; -+ -+static int mcp356x_read_single_value(struct iio_dev *indio_dev, -+ struct iio_chan_spec const *channel, -+ int *val) -+{ -+ struct mcp356x_state *adc = iio_priv(indio_dev); -+ int ret, tmp, ret_read = 0; -+ -+ /* Configure MUX register with the requested channel */ -+ ret = mcp356x_write(adc, MCP356X_MUX, channel->address, 1); -+ if (ret) { -+ dev_err(&indio_dev->dev, "Failed to configure MUX register\n"); -+ return ret; -+ } -+ -+ /* ADC Conversion starts by writing ADC_MODE[1:0] = 11 to CONFIG0[1:0] = */ -+ ret = mcp356x_update(adc, MCP356X_CONFIG0, MCP356X_ADC_MODE_MASK, -+ MCP356X_ADC_CONVERSION_MODE, 1); -+ if (ret) { -+ dev_err(&indio_dev->dev, -+ "Failed to configure CONFIG0 register\n"); -+ return ret; -+ } -+ -+ /* -+ * Check if the conversion is ready. If not, wait a little bit, and -+ * in case of timeout exit with an error. -+ */ -+ -+ ret = read_poll_timeout(mcp356x_read, ret_read, -+ ret_read || !(tmp & MCP356X_DATA_READY_MASK), -+ 1000, MCP356X_DATA_READY_TIMEOUT_MS * 1000, true, -+ adc, MCP356X_IRQ, &tmp, 1); -+ -+ /* failed to read status register */ -+ if (ret_read) -+ return ret; -+ -+ if (ret) -+ return -ETIMEDOUT; -+ -+ if (tmp & MCP356X_DATA_READY_MASK) -+ /* failing to finish conversion */ -+ return -EBUSY; -+ -+ ret = mcp356x_read(adc, MCP356X_ADCDATA, &tmp, 4); -+ if (ret) -+ return ret; -+ -+ *val = tmp; -+ -+ return ret; -+} -+ -+static int mcp356x_read_avail(struct iio_dev *indio_dev, -+ struct iio_chan_spec const *channel, -+ const int **vals, int *type, -+ int *length, long mask) -+{ -+ switch (mask) { -+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO: -+ *type = IIO_VAL_INT; -+ *vals = mcp356x_oversampling_avail; -+ *length = ARRAY_SIZE(mcp356x_oversampling_avail); -+ return IIO_AVAIL_LIST; -+ case IIO_CHAN_INFO_HARDWAREGAIN: -+ *type = IIO_VAL_FRACTIONAL; -+ *length = ARRAY_SIZE(mcp356x_hwgain_frac); -+ *vals = mcp356x_hwgain_frac; -+ return IIO_AVAIL_LIST; -+ case IIO_CHAN_INFO_CALIBBIAS: -+ *vals = mcp356x_calib_bias; -+ *type = IIO_VAL_INT; -+ return IIO_AVAIL_RANGE; -+ case IIO_CHAN_INFO_CALIBSCALE: -+ *vals = mcp356x_calib_scale; -+ *type = IIO_VAL_INT; -+ return IIO_AVAIL_RANGE; -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int mcp356x_read_raw(struct iio_dev *indio_dev, -+ struct iio_chan_spec const *channel, -+ int *val, int *val2, long mask) -+{ -+ struct mcp356x_state *adc = iio_priv(indio_dev); -+ int ret; -+ -+ mutex_lock(&adc->lock); -+ -+ switch (mask) { -+ case IIO_CHAN_INFO_RAW: -+ ret = mcp356x_read_single_value(indio_dev, channel, val); -+ if (ret) -+ ret = -EINVAL; -+ else -+ ret = IIO_VAL_INT; -+ break; -+ case IIO_CHAN_INFO_SCALE: -+ *val = adc->vref_mv; -+ *val2 = channel->scan_type.realbits - 1; -+ ret = IIO_VAL_FRACTIONAL_LOG2; -+ break; -+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO: -+ *val = mcp356x_oversampling_avail[adc->oversampling]; -+ ret = IIO_VAL_INT; -+ break; -+ case IIO_CHAN_INFO_HARDWAREGAIN: -+ *val = mcp356x_hwgain_frac[2 * adc->hwgain]; -+ *val2 = mcp356x_hwgain_frac[(2 * adc->hwgain) + 1]; -+ ret = IIO_VAL_FRACTIONAL; -+ break; -+ case IIO_CHAN_INFO_CALIBBIAS: -+ *val = adc->calib_bias; -+ ret = IIO_VAL_INT; -+ break; -+ case IIO_CHAN_INFO_CALIBSCALE: -+ *val = adc->calib_scale; -+ ret = IIO_VAL_INT; -+ break; -+ default: -+ ret = -EINVAL; -+ } -+ -+ mutex_unlock(&adc->lock); -+ -+ return ret; -+} -+ -+static int mcp356x_write_raw(struct iio_dev *indio_dev, -+ struct iio_chan_spec const *channel, int val, -+ int val2, long mask) -+{ -+ struct mcp356x_state *adc = iio_priv(indio_dev); -+ int tmp; -+ int ret = -EINVAL; -+ -+ mutex_lock(&adc->lock); -+ switch (mask) { -+ case IIO_CHAN_INFO_CALIBBIAS: -+ if (val < mcp356x_calib_bias[0] && val > mcp356x_calib_bias[2]) -+ goto out; -+ -+ adc->calib_bias = val; -+ ret = mcp356x_write(adc, MCP356X_OFFSETCAL, val, 3); -+ break; -+ case IIO_CHAN_INFO_CALIBSCALE: -+ if (val < mcp356x_calib_bias[0] && val > mcp356x_calib_bias[2]) -+ goto out; -+ -+ adc->calib_scale = val; -+ ret = mcp356x_write(adc, MCP356X_GAINCAL, val, 3); -+ break; -+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO: -+ if (val < 0) -+ goto out; -+ -+ adc->oversampling = find_closest(val, mcp356x_oversampling_avail, -+ ARRAY_SIZE(mcp356x_oversampling_avail)); -+ -+ dev_dbg(&adc->spi->dev, -+ "IIO_CHAN_INFO_OVERSAMPLING_RATIO index %d\n", -+ adc->oversampling); -+ -+ ret = mcp356x_update(adc, MCP356X_CONFIG1, MCP356X_OVERSAMPLING_RATIO_MASK, -+ (adc->oversampling << MCP356X_OVERSAMPLING_RATIO_SHIFT), -+ 1); -+ if (ret) -+ dev_err(&indio_dev->dev, -+ "Failed to configure CONFIG1 register\n"); -+ -+ break; -+ case IIO_CHAN_INFO_HARDWAREGAIN: -+ /* -+ * calculate gain from read values. -+ * avoid using fractional numbers so -+ * multiply the value with 1000. In case of x1/3 gain -+ * the tmp will be 300 -+ */ -+ tmp = ((val * 1000000) + val2) / 1000; -+ if (tmp < 1 || tmp > MAX_HWGAIN) -+ goto out; -+ -+ adc->hwgain = find_closest(tmp, mcp356x_hwgain, -+ ARRAY_SIZE(mcp356x_hwgain)); -+ -+ dev_dbg(&adc->spi->dev, -+ "IIO_CHAN_INFO_HARDWAREGAIN Gain:%d; index %d\n", -+ tmp, adc->hwgain); -+ -+ /* Update GAIN in CONFIG2[5:3] -> GAIN[2:0]*/ -+ ret = mcp356x_update(adc, MCP356X_CONFIG2, MCP356X_HARDWARE_GAIN_MASK, -+ (adc->hwgain << MCP356X_HARDWARE_GAIN_SHIFT), 1); -+ if (ret) -+ dev_err(&indio_dev->dev, -+ "Failed to configure CONFIG0 register\n"); -+ break; -+ } -+ -+out: -+ mutex_unlock(&adc->lock); -+ -+ return ret; -+} -+ -+static int mcp356x_config(struct mcp356x_state *adc) -+{ -+ int ret = 0; -+ unsigned int tmp; -+ -+ dev_dbg(&adc->spi->dev, "%s: Start config...\n", __func__); -+ -+ /* -+ * The address is set on a per-device basis by fuses in the factory, -+ * configured on request. If not requested, the fuses are set for 0x1. -+ * The device address is part of the device markings to avoid -+ * potential confusion. This address is coded on two bits, so four possible -+ * addresses are available when multiple devices are present on the same -+ * SPI bus with only one Chip Select line for all devices. -+ */ -+ device_property_read_u32(&adc->spi->dev, "microchip,hw-device-address", &tmp); -+ -+ if (tmp > 3) { -+ dev_err_probe(&adc->spi->dev, tmp, -+ "invalid device address. Must be in range 0-3.\n"); -+ return -EINVAL; -+ } -+ -+ adc->dev_addr = 0xff & tmp; -+ -+ dev_dbg(&adc->spi->dev, "use device address %i\n", adc->dev_addr); -+ -+ ret = mcp356x_read(adc, MCP356X_RESERVED_E, &tmp, 2); -+ -+ if (ret == 0) { -+ switch (tmp & MCP356X_HW_ID_MASK) { -+ case MCP3461_HW_ID: -+ dev_dbg(&adc->spi->dev, "Found MCP3461 chip\n"); -+ break; -+ case MCP3462_HW_ID: -+ dev_dbg(&adc->spi->dev, "Found MCP3462 chip\n"); -+ break; -+ case MCP3464_HW_ID: -+ dev_dbg(&adc->spi->dev, "Found MCP3464 chip\n"); -+ break; -+ case MCP3561_HW_ID: -+ dev_dbg(&adc->spi->dev, "Found MCP3561 chip\n"); -+ break; -+ case MCP3562_HW_ID: -+ dev_dbg(&adc->spi->dev, "Found MCP3562 chip\n"); -+ break; -+ case MCP3564_HW_ID: -+ dev_dbg(&adc->spi->dev, "Found MCP3564 chip\n"); -+ break; -+ default: -+ dev_err_probe(&adc->spi->dev, tmp, -+ "Unknown chip found\n"); -+ return -EINVAL; -+ } -+ } else { -+ return ret; -+ } -+ -+ /* Command sequence that ensures a recovery with -+ * the desired settings in any cases of loss-of-power scenario. -+ */ -+ -+ /* Write LOCK register to 0xA5 (Write Access Password) -+ * Write access is allowed on the full register map. -+ */ -+ ret = mcp356x_write(adc, MCP356X_LOCK, 0x000000A5, 1); -+ if (ret) -+ return ret; -+ -+ /* Write IRQ register to 0x03 */ -+ /* IRQ --> IRQ Mode = Hi-Z IRQ Output --> (0b00000011). -+ * IRQ = 0x00000003 -+ */ -+ ret = mcp356x_write(adc, MCP356X_IRQ, 0x00000003, 1); -+ if (ret) -+ return ret; -+ -+ /* Device Full Reset Fast Command */ -+ ret = mcp356x_fast_cmd(adc, MCP356X_FULL_RESET_CMD); -+ -+ /* wait 1ms for the chip to restart after a full reset */ -+ mdelay(1); -+ -+ /* Reconfigure the ADC chip */ -+ -+ /* GAINCAL --> Disabled. -+ * Default value is GAINCAL = 0x00800000; which provides a gain of 1x -+ */ -+ ret = mcp356x_write(adc, MCP356X_GAINCAL, 0x00800000, 3); -+ if (ret) -+ return ret; -+ -+ adc->calib_scale = 0x00800000; -+ -+ /* OFFSETCAL --> 0 Counts of Offset Cancellation -+ * (Measured offset is negative). -+ * OFFSETCAL = 0x0 -+ */ -+ ret = mcp356x_write(adc, MCP356X_OFFSETCAL, 0x00000000, 3); -+ if (ret) -+ return ret; -+ -+ /* TIMER --> Disabled. -+ * TIMER = 0x00000000 -+ */ -+ ret = mcp356x_write(adc, MCP356X_TIMER, 0x00000000, 3); -+ if (ret) -+ return ret; -+ -+ /* SCAN --> Disabled. -+ * SCAN = 0x00000000 -+ */ -+ ret = mcp356x_write(adc, MCP356X_SCAN, 0x00000000, 3); -+ if (ret) -+ return ret; -+ -+ /* MUX --> VIN+ = CH0, VIN- = CH1 --> (0b00000001). -+ * MUX = 0x00000001 -+ */ -+ ret = mcp356x_write(adc, MCP356X_MUX, 0x00000001, 1); -+ if (ret) -+ return ret; -+ -+ /* IRQ --> IRQ Mode = Hi-Z IRQ Output --> (0b00000011). -+ * IRQ = 0x00000003 -+ */ -+ ret = mcp356x_write(adc, MCP356X_IRQ, 0x00000003, 1); -+ if (ret) -+ return ret; -+ -+ /* CONFIG3 -+ * Conv. Mod = One-Shot/Standby, -+ * FORMAT = 32-bit (right justified data): SGN extension + ADC data, -+ * CRC_FORMAT = 16b, CRC-COM = Disabled, -+ * OFFSETCAL = Enabled, GAINCAL = Enabled --> (10100011). -+ * CONFIG3 = 0x000000A3 -+ * -+ */ -+ ret = mcp356x_write(adc, MCP356X_CONFIG3, 0x000000A3, 1); -+ if (ret) -+ return ret; -+ -+ /* CONFIG2 --> BOOST = 1x, GAIN = 1x, AZ_MUX = 1 --> (0b10001101). -+ * CONFIG2 = 0x0000008D -+ */ -+ ret = mcp356x_write(adc, MCP356X_CONFIG2, 0x0000008D, 1); -+ if (ret) -+ return ret; -+ -+ adc->hwgain = 0x01; -+ adc->auto_zeroing_mux = true; -+ adc->auto_zeroing_ref = false; -+ adc->current_boost_mode = MCP356X_BOOST_CURRENT_x1_00; -+ -+ /* CONFIG1 --> AMCLK = MCLK, OSR = 98304 --> (0b00111100). -+ * CONFIG1 = 0x0000003C -+ */ -+ ret = mcp356x_write(adc, MCP356X_CONFIG1, 0x0000003C, 1); -+ if (ret) -+ return ret; -+ -+ adc->oversampling = 0x0F; -+ -+ if (!adc->vref) { -+ /* CONFIG0 --> VREF_SEL = Internal Voltage Reference 2.4v -+ * CLK_SEL = INTOSC w/o CLKOUT, CS_SEL = No Bias, -+ * ADC_MODE = Standby Mode --> (0b11100010). -+ * CONFIG0 = 0x000000E2 -+ */ -+ ret = mcp356x_write(adc, MCP356X_CONFIG0, 0x000000E2, 1); -+ -+ dev_dbg(&adc->spi->dev, "%s: Using internal Vref\n", -+ __func__); -+ adc->vref_mv = MCP356XR_INT_VREF_MV; -+ -+ } else { -+ /* CONFIG0 --> CLK_SEL = INTOSC w/o CLKOUT, CS_SEL = No Bias, -+ * ADC_MODE = Standby Mode --> (0b01100010). -+ * CONFIG0 = 0x000000E2 -+ */ -+ ret = mcp356x_write(adc, MCP356X_CONFIG0, 0x00000062, 1); -+ } -+ adc->current_bias_mode = MCP356X_CS_SEL_0_0_uA; -+ -+ return ret; -+} -+ -+static int mcp356x_probe(struct spi_device *spi) -+{ -+ int ret, device_index; -+ struct iio_dev *indio_dev; -+ struct mcp356x_state *adc; -+ -+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); -+ if (!indio_dev) { -+ dev_err_probe(&indio_dev->dev, PTR_ERR(indio_dev), -+ "Can't allocate iio device\n"); -+ return -ENOMEM; -+ } -+ -+ adc = iio_priv(indio_dev); -+ adc->spi = spi; -+ -+ dev_dbg(&adc->spi->dev, "%s: probe(spi = 0x%p)\n", __func__, spi); -+ -+ adc->vref = devm_regulator_get_optional(&adc->spi->dev, "vref"); -+ if (IS_ERR(adc->vref)) { -+ if (PTR_ERR(adc->vref) == -ENODEV) { -+ adc->vref = NULL; -+ dev_dbg(&adc->spi->dev, "%s: Using internal Vref\n", -+ __func__); -+ } else { -+ dev_err_probe(&adc->spi->dev, PTR_ERR(adc->vref), -+ "failed to get regulator\n"); -+ return PTR_ERR(adc->vref); -+ } -+ } else { -+ ret = regulator_enable(adc->vref); -+ if (ret) -+ return ret; -+ -+ dev_dbg(&adc->spi->dev, "%s: Using External Vref\n", -+ __func__); -+ -+ ret = regulator_get_voltage(adc->vref); -+ if (ret < 0) { -+ dev_err_probe(&adc->spi->dev, ret, -+ "Failed to read vref regulator\n"); -+ goto error_disable_reg; -+ } -+ -+ adc->vref_mv = ret / 1000; -+ } -+ -+ spi_set_drvdata(spi, indio_dev); -+ device_index = spi_get_device_id(spi)->driver_data; -+ adc->chip_info = &mcp356x_chip_infos_tbl[device_index]; -+ -+ adc->mcp356x_info.read_raw = mcp356x_read_raw; -+ adc->mcp356x_info.write_raw = mcp356x_write_raw; -+ adc->mcp356x_info.read_avail = mcp356x_read_avail; -+ -+ ret = mcp356x_prep_custom_attributes(adc, indio_dev); -+ if (ret) { -+ dev_err_probe(&adc->spi->dev, ret, -+ "Can't configure custom attributes for MCP356X device\n"); -+ goto error_disable_reg; -+ } -+ -+ indio_dev->name = spi_get_device_id(spi)->name; -+ indio_dev->modes = INDIO_DIRECT_MODE; -+ indio_dev->info = &adc->mcp356x_info; -+ -+ indio_dev->channels = adc->chip_info->channels; -+ indio_dev->num_channels = adc->chip_info->num_channels; -+ indio_dev->masklength = adc->chip_info->num_channels - 1; -+ -+ /* initialize the chip access mutex */ -+ mutex_init(&adc->lock); -+ -+ /* Do any chip specific initialization, e.g: -+ * read/write some registers -+ * enable/disable certain channels -+ * change the sampling rate to the requested value -+ */ -+ ret = mcp356x_config(adc); -+ if (ret) { -+ dev_err_probe(&adc->spi->dev, ret, -+ "Can't configure MCP356X device\n"); -+ goto error_disable_reg; -+ } -+ -+ dev_dbg(&adc->spi->dev, "%s: Vref (mV): %d\n", __func__, adc->vref_mv); -+ -+ ret = devm_iio_device_register(&spi->dev, indio_dev); -+ if (ret) { -+ dev_err_probe(&adc->spi->dev, ret, -+ "Can't register IIO device\n"); -+ goto error_disable_reg; -+ } -+ -+ return 0; -+ -+error_disable_reg: -+ if (adc->vref) -+ regulator_disable(adc->vref); -+ -+ return ret; -+} -+ -+static void mcp356x_remove(struct spi_device *spi) -+{ -+ struct iio_dev *indio_dev = spi_get_drvdata(spi); -+ struct mcp356x_state *adc = iio_priv(indio_dev); -+ -+ if (adc->vref) -+ regulator_disable(adc->vref); -+} -+ -+static const struct of_device_id mcp356x_dt_ids[] = { -+ { .compatible = "microchip,mcp3461" }, -+ { .compatible = "microchip,mcp3462" }, -+ { .compatible = "microchip,mcp3464" }, -+ { .compatible = "microchip,mcp3461r" }, -+ { .compatible = "microchip,mcp3462r" }, -+ { .compatible = "microchip,mcp3464r" }, -+ { .compatible = "microchip,mcp3561" }, -+ { .compatible = "microchip,mcp3562" }, -+ { .compatible = "microchip,mcp3564" }, -+ { .compatible = "microchip,mcp3561r" }, -+ { .compatible = "microchip,mcp3562r" }, -+ { .compatible = "microchip,mcp3564r" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, mcp356x_dt_ids); -+ -+static const struct spi_device_id mcp356x_id[] = { -+ { "mcp3461", mcp3461 }, -+ { "mcp3462", mcp3462 }, -+ { "mcp3464", mcp3464 }, -+ { "mcp3461r", mcp3461r }, -+ { "mcp3462r", mcp3462r }, -+ { "mcp3464r", mcp3464r }, -+ { "mcp3561", mcp3561 }, -+ { "mcp3562", mcp3562 }, -+ { "mcp3564", mcp3564 }, -+ { "mcp3561r", mcp3561r }, -+ { "mcp3562r", mcp3562r }, -+ { "mcp3564r", mcp3564r }, -+ { } -+}; -+MODULE_DEVICE_TABLE(spi, mcp356x_id); -+ -+static struct spi_driver mcp356x_driver = { -+ .driver = { -+ .name = "mcp3564", -+ .of_match_table = mcp356x_dt_ids, -+ }, -+ .probe = mcp356x_probe, -+ .remove = mcp356x_remove, -+ .id_table = mcp356x_id, -+}; -+ -+module_spi_driver(mcp356x_driver); -+ -+MODULE_AUTHOR("Marius Cristea "); -+MODULE_DESCRIPTION("Microchip MCP346x/MCP346xR and MCP356x/MCP346xR ADCs"); -+MODULE_LICENSE("GPL v2"); -+MODULE_VERSION("0.1.2"); --- -2.39.2 - diff --git a/patches/linux/0005-Microchip-QSPI-Add-regular-transfers.patch b/patches/linux/0005-Microchip-QSPI-Add-regular-transfers.patch deleted file mode 100644 index b691b57..0000000 --- a/patches/linux/0005-Microchip-QSPI-Add-regular-transfers.patch +++ /dev/null @@ -1,275 +0,0 @@ -From 0eeed461b7b86e3b822984b1c266316ac70ccf69 Mon Sep 17 00:00:00 2001 -From: vauban353 -Date: Sun, 6 Aug 2023 09:37:40 +0100 -Subject: [PATCH 5/8] Microchip QSPI: Add regular transfers. - ---- - drivers/spi/spi-microchip-core-qspi.c | 226 +++++++++++++++++++++++++- - 1 file changed, 223 insertions(+), 3 deletions(-) - -diff --git a/drivers/spi/spi-microchip-core-qspi.c b/drivers/spi/spi-microchip-core-qspi.c -index 33c19b98b..5f1623ac4 100644 ---- a/drivers/spi/spi-microchip-core-qspi.c -+++ b/drivers/spi/spi-microchip-core-qspi.c -@@ -1,3 +1,4 @@ -+ - // SPDX-License-Identifier: (GPL-2.0) - /* - * Microchip coreQSPI QSPI controller driver -@@ -117,10 +118,10 @@ struct mchp_coreqspi { - struct completion data_completion; - struct mutex op_lock; /* lock access to the device */ - u8 *txbuf; -- u8 *rxbuf; -+ volatile u8 *rxbuf; - int irq; -- int tx_len; -- int rx_len; -+ volatile int tx_len; -+ volatile int rx_len; - }; - - static int mchp_coreqspi_set_mode(struct mchp_coreqspi *qspi, const struct spi_mem_op *op) -@@ -222,6 +223,68 @@ static inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi, bool word) - } - } - -+static inline void mchp_coreqspi_write_read_op(struct mchp_coreqspi *qspi, bool last) -+{ -+ u32 frames, control, data; -+ qspi->rx_len = qspi->tx_len; -+ -+ control = readl_relaxed(qspi->regs + REG_CONTROL); -+ control |= CONTROL_FLAGSX4; -+ writel_relaxed(control, qspi->regs + REG_CONTROL); -+ -+ while (qspi->tx_len >= 4) { -+ while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL) -+ ; -+ -+ data = *(u32 *)qspi->txbuf; -+ qspi->txbuf += 4; -+ qspi->tx_len -= 4; -+ writel_relaxed(data, qspi->regs + REG_X4_TX_DATA); -+ -+ if (qspi->rx_len >= 8) { -+ if (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_RXAVAILABLE) { -+ data = readl_relaxed(qspi->regs + REG_X4_RX_DATA); -+ *(u32 *)qspi->rxbuf = data; -+ qspi->rxbuf += 4; -+ qspi->rx_len -= 4; -+ } -+ } -+ } -+ -+ if (!last ) { -+ while (qspi->rx_len >= 4) { -+ while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_RXFIFOEMPTY) -+ ; -+ data = readl_relaxed(qspi->regs + REG_X4_RX_DATA); -+ *(u32 *)qspi->rxbuf = data; -+ qspi->rxbuf += 4; -+ qspi->rx_len -= 4; -+ } -+ } -+ -+ if (qspi->tx_len) { -+ control &= ~CONTROL_FLAGSX4; -+ writel_relaxed(control, qspi->regs + REG_CONTROL); -+ -+ -+ while (qspi->tx_len--) { -+ while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL) -+ ; -+ data = *qspi->txbuf++; -+ writel_relaxed(data, qspi->regs + REG_TX_DATA); -+ } -+ if (!last) { -+ while (qspi->rx_len--) { -+ while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_RXFIFOEMPTY) -+ ; -+ data = readl_relaxed(qspi->regs + REG_RX_DATA); -+ *qspi->rxbuf++ = (data & 0xFF); -+ } -+ } -+ } -+} -+ -+ - static void mchp_coreqspi_enable_ints(struct mchp_coreqspi *qspi) - { - u32 mask = IEN_TXDONE | -@@ -497,6 +560,160 @@ static const struct spi_controller_mem_ops mchp_coreqspi_mem_ops = { - .exec_op = mchp_coreqspi_exec_op, - }; - -+static int mchp_coreqspi_transfer_one_message(struct spi_controller *ctlr, -+ struct spi_message *m) -+{ -+ struct mchp_coreqspi *qspi = spi_controller_get_devdata(ctlr); -+ struct spi_transfer *t = NULL; -+ u32 control, frames, status; -+ u32 total_bytes, cmd_bytes = 0, idle_cycles = 0; -+ int ret; -+ bool quad = false, dual = false; -+ bool keep_cs = false; -+ -+ mutex_lock(&qspi->op_lock); -+ ret = readl_poll_timeout(qspi->regs + REG_STATUS, status, -+ (status & STATUS_READY), 0, -+ TIMEOUT_MS); -+ if (ret) { -+ dev_err(&ctlr->dev, -+ "Timeout waiting on QSPI ready.\n"); -+ return -ETIMEDOUT; -+ } -+ -+ ret = mchp_coreqspi_setup_clock(qspi, m->spi); -+ if (ret) -+ goto error; -+ -+ if (m->spi->cs_gpiod) { -+ if (m->spi->mode & SPI_CS_HIGH) { -+ gpiod_set_value(m->spi->cs_gpiod, 0); -+ } else { -+ gpiod_set_value(m->spi->cs_gpiod, 1); -+ } -+ } -+ -+ control = readl_relaxed(qspi->regs + REG_CONTROL); -+ control &= ~(CONTROL_MODE12_MASK | -+ CONTROL_MODE0); -+ writel_relaxed(control, qspi->regs + REG_CONTROL); -+ -+ reinit_completion(&qspi->data_completion); -+ -+ /* Check the total bytes and command bytes */ -+ list_for_each_entry(t, &m->transfers, transfer_list) { -+ total_bytes += t->len; -+ if ((!cmd_bytes) && !(t->tx_buf && t->rx_buf)) -+ cmd_bytes = t->len; -+ if (!t->rx_buf) -+ cmd_bytes = total_bytes; -+ if (t->tx_nbits == SPI_NBITS_QUAD || t->rx_nbits == SPI_NBITS_QUAD) -+ quad = true; -+ else if (t->tx_nbits == SPI_NBITS_DUAL || t->rx_nbits == SPI_NBITS_DUAL) -+ dual = true; -+ } -+ -+ control = readl_relaxed(qspi->regs + REG_CONTROL); -+ if (quad) { -+ control |= (CONTROL_MODE0 | CONTROL_MODE12_EX_RW); -+ } else if (dual) { -+ control &= ~CONTROL_MODE0; -+ control |= CONTROL_MODE12_FULL; -+ } else { -+ control &= ~(CONTROL_MODE12_MASK | -+ CONTROL_MODE0); -+ } -+ -+ writel_relaxed(control, qspi->regs + REG_CONTROL); -+ frames = total_bytes & BYTESUPPER_MASK; -+ writel_relaxed(frames, qspi->regs + REG_FRAMESUP); -+ frames = total_bytes & BYTESLOWER_MASK; -+ frames |= cmd_bytes << FRAMES_CMDBYTES_SHIFT; -+ frames |= idle_cycles << FRAMES_IDLE_SHIFT; -+ control = readl_relaxed(qspi->regs + REG_CONTROL); -+ if (control & CONTROL_MODE12_MASK) -+ frames |= (1 << FRAMES_SHIFT); -+ -+ frames |= FRAMES_FLAGWORD; -+ writel_relaxed(frames, qspi->regs + REG_FRAMES); -+ -+ list_for_each_entry(t, &m->transfers, transfer_list) { -+ -+ if ((t->tx_buf) && (t->rx_buf)){ -+ bool last = false; -+ qspi->txbuf = (u8 *)t->tx_buf; -+ qspi->rxbuf = (u8 *)t->rx_buf; -+ qspi->tx_len = t->len; -+ if (list_is_last(&t->transfer_list, &m->transfers)) -+ last = true; -+ mchp_coreqspi_write_read_op(qspi, last); -+ } else if (t->tx_buf) { -+ qspi->txbuf = (u8 *)t->tx_buf; -+ qspi->tx_len = t->len; -+ mchp_coreqspi_write_op(qspi, true); -+ } else { -+ qspi->rxbuf = (u8 *)t->rx_buf; -+ qspi->rx_len = t->len; -+ } -+ -+ if (t->cs_change) { -+ if (list_is_last(&t->transfer_list, -+ &m->transfers)) { -+ keep_cs = true; -+ } else { -+ if (!t->cs_off) { -+// gpiod_set_value(m->spi->cs_gpiod, 0); -+ if (m->spi->mode & SPI_CS_HIGH) { -+ gpiod_set_value(m->spi->cs_gpiod, 0); -+ } else { -+ gpiod_set_value(m->spi->cs_gpiod, 1); -+ } -+ } -+// _spi_transfer_cs_change_delay(m, t); -+ if (!list_next_entry(t, transfer_list)->cs_off) { -+// spi_set_cs(m->spi, true, false); -+ if (m->spi->mode & SPI_CS_HIGH) { -+// gpiod_set_value(m->spi->cs_gpiod, 0); -+ gpiod_set_value(m->spi->cs_gpiod, 1); -+ } else { -+// gpiod_set_value(m->spi->cs_gpiod, 1); -+ gpiod_set_value(m->spi->cs_gpiod, 0); -+ } -+// gpiod_set_value(m->spi->cs_gpiod, 1); -+ } -+ } -+ } else if (!list_is_last(&t->transfer_list, &m->transfers) && -+ t->cs_off != list_next_entry(t, transfer_list)->cs_off) { -+// spi_set_cs(m->spi, t->cs_off, false); -+ if (m->spi->mode & SPI_CS_HIGH) { -+ gpiod_set_value(m->spi->cs_gpiod, !t->cs_off); -+ } else { -+ gpiod_set_value(m->spi->cs_gpiod, !t->cs_off); -+ } -+ } -+ -+ -+ -+ } -+ -+ mchp_coreqspi_enable_ints(qspi); -+ -+ if (!wait_for_completion_timeout(&qspi->data_completion, msecs_to_jiffies(1000))) -+ ret = -ETIMEDOUT; -+ -+ m->actual_length = total_bytes; -+ -+error: -+ if (ret != 0 || !keep_cs) -+ gpiod_set_value(m->spi->cs_gpiod, 0); -+ -+ m->status = ret; -+ spi_finalize_current_message(ctlr); -+ mutex_unlock(&qspi->op_lock); -+ mchp_coreqspi_disable_ints(qspi); -+ return ret; -+} -+ - static int mchp_coreqspi_probe(struct platform_device *pdev) - { - struct spi_controller *ctlr; -@@ -550,6 +767,9 @@ static int mchp_coreqspi_probe(struct platform_device *pdev) - ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD | - SPI_TX_DUAL | SPI_TX_QUAD; - ctlr->dev.of_node = np; -+ ctlr->transfer_one_message = mchp_coreqspi_transfer_one_message; -+ ctlr->num_chipselect = 2; -+ ctlr->use_gpio_descriptors = true; - - ret = devm_spi_register_controller(&pdev->dev, ctlr); - if (ret) { --- -2.39.2 - diff --git a/patches/linux/0006-BeagleV-Fire-Add-printk-to-IM219-driver-for-board-te.patch b/patches/linux/0006-BeagleV-Fire-Add-printk-to-IM219-driver-for-board-te.patch deleted file mode 100644 index b2aad86..0000000 --- a/patches/linux/0006-BeagleV-Fire-Add-printk-to-IM219-driver-for-board-te.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 747c6d5984cccf7c3e48c2cdb4dd1d626889096e Mon Sep 17 00:00:00 2001 -From: vauban353 -Date: Sat, 12 Aug 2023 18:14:01 +0100 -Subject: [PATCH 6/8] BeagleV-Fire: Add printk to IM219 driver for board tests. - ---- - drivers/media/i2c/imx219.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c -index 7a14688f8..effb399b1 100644 ---- a/drivers/media/i2c/imx219.c -+++ b/drivers/media/i2c/imx219.c -@@ -1181,6 +1181,9 @@ static int imx219_identify_module(struct imx219 *imx219) - int ret; - u32 val; - -+ printk(KERN_INFO "imx219_identify_module()\n"); -+ -+ - ret = imx219_read_reg(imx219, IMX219_REG_CHIP_ID, - IMX219_REG_VALUE_16BIT, &val); - if (ret) { -@@ -1195,6 +1198,9 @@ static int imx219_identify_module(struct imx219 *imx219) - return -EIO; - } - -+ printk(KERN_INFO "imx219_identify_module() - Success\n"); -+ -+ - return 0; - } - -@@ -1402,6 +1408,8 @@ static int imx219_probe(struct i2c_client *client) - struct imx219 *imx219; - int ret; - -+ printk(KERN_INFO "imx219_probe()\n"); -+ - imx219 = devm_kzalloc(&client->dev, sizeof(*imx219), GFP_KERNEL); - if (!imx219) - return -ENOMEM; --- -2.39.2 - diff --git a/patches/linux/0007-MMC-SPI-Hack-to-support-non-DMA-capable-SPI-ctrl.patch b/patches/linux/0007-MMC-SPI-Hack-to-support-non-DMA-capable-SPI-ctrl.patch deleted file mode 100644 index 7953390..0000000 --- a/patches/linux/0007-MMC-SPI-Hack-to-support-non-DMA-capable-SPI-ctrl.patch +++ /dev/null @@ -1,66 +0,0 @@ -From e9aea028119afd0858e77989dd1a4ecc21d30dc1 Mon Sep 17 00:00:00 2001 -From: vauban353 -Date: Sun, 6 Aug 2023 11:13:27 +0100 -Subject: [PATCH 7/8] MMC SPI: Hack to support non DMA capable SPI ctrl. - ---- - drivers/mmc/host/mmc_spi.c | 6 +++++- - drivers/spi/internals.h | 3 +++ - drivers/spi/spi.c | 3 +++ - 3 files changed, 11 insertions(+), 1 deletion(-) - -diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c -index cc333ad67..fb45c7fa4 100644 ---- a/drivers/mmc/host/mmc_spi.c -+++ b/drivers/mmc/host/mmc_spi.c -@@ -29,6 +29,9 @@ - - #include - -+//: -+#undef CONFIG_HAS_DMA -+//#define DEBUG 1 - - /* NOTES: - * -@@ -1375,7 +1378,8 @@ static int mmc_spi_probe(struct spi_device *spi) - * that's the only reason not to use a few MHz for f_min (until - * the upper layer reads the target frequency from the CSD). - */ -- mmc->f_min = 400000; -+// mmc->f_min = 400000; -+ mmc->f_min = 5000000; - mmc->f_max = spi->max_speed_hz; - - host = mmc_priv(mmc); -diff --git a/drivers/spi/internals.h b/drivers/spi/internals.h -index 4a28a8395..c49350240 100644 ---- a/drivers/spi/internals.h -+++ b/drivers/spi/internals.h -@@ -12,6 +12,9 @@ - #ifndef __LINUX_SPI_INTERNALS_H - #define __LINUX_SPI_INTERNALS_H - -+//: -+#undef CONFIG_HAS_DMA -+ - #include - #include - #include -diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c -index a221478e5..e198049cc 100644 ---- a/drivers/spi/spi.c -+++ b/drivers/spi/spi.c -@@ -42,6 +42,9 @@ EXPORT_TRACEPOINT_SYMBOL(spi_transfer_stop); - - #include "internals.h" - -+//: -+#undef CONFIG_HAS_DMA -+ - static DEFINE_IDR(spi_master_idr); - - static void spidev_release(struct device *dev) --- -2.39.2 - diff --git a/patches/linux/0009-Makefile-build-mpfs-beaglev-fire.dtb.patch b/patches/linux/0009-Makefile-build-mpfs-beaglev-fire.dtb.patch deleted file mode 100644 index 0ef92e0..0000000 --- a/patches/linux/0009-Makefile-build-mpfs-beaglev-fire.dtb.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 09e2d12d8ade10bb2d8ab1d42e9a1bd8442a74c8 Mon Sep 17 00:00:00 2001 -From: Robert Nelson -Date: Tue, 10 Oct 2023 10:01:45 -0500 -Subject: [PATCH 9/9] Makefile: build mpfs-beaglev-fire.dtb - -Signed-off-by: Robert Nelson ---- - arch/riscv/boot/dts/microchip/Makefile | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/riscv/boot/dts/microchip/Makefile b/arch/riscv/boot/dts/microchip/Makefile -index 48c9d3d071f3..4e3529217d9a 100644 ---- a/arch/riscv/boot/dts/microchip/Makefile -+++ b/arch/riscv/boot/dts/microchip/Makefile -@@ -5,4 +5,5 @@ dtb-$(CONFIG_SOC_MICROCHIP_POLARFIRE) += mpfs-m100pfsevp.dtb - dtb-$(CONFIG_SOC_MICROCHIP_POLARFIRE) += mpfs-polarberry.dtb - dtb-$(CONFIG_SOC_MICROCHIP_POLARFIRE) += mpfs-video-kit.dtb - dtb-$(CONFIG_SOC_MICROCHIP_POLARFIRE) += mpfs-tysom-m.dtb -+dtb-$(CONFIG_SOC_MICROCHIP_POLARFIRE) += mpfs-beaglev-fire.dtb - obj-$(CONFIG_BUILTIN_DTB) += $(addsuffix .o, $(dtb-y)) --- -2.39.2 - diff --git a/patches/linux/0010-BeagleV-Fire-Add-MPFS-TVS-auxiliary-driver.patch b/patches/linux/0010-BeagleV-Fire-Add-MPFS-TVS-auxiliary-driver.patch deleted file mode 100644 index 6a42b7d..0000000 --- a/patches/linux/0010-BeagleV-Fire-Add-MPFS-TVS-auxiliary-driver.patch +++ /dev/null @@ -1,516 +0,0 @@ -From 413071dc2f13f581eb844a0009d571dfa0bb2f02 Mon Sep 17 00:00:00 2001 -From: Lars Randers -Date: Thu, 20 Jun 2024 13:55:40 +0000 -Subject: [PATCH] BeagleV-Fire: Add MPFS TVS auxiliary driver - -Signed-off-by: Lars Randers ---- - drivers/hwmon/Kconfig | 11 + - drivers/hwmon/Makefile | 1 + - drivers/hwmon/tvs-mpfs.c | 371 +++++++++++++++++++++++++++++++++ - drivers/mailbox/mailbox-mpfs.c | 62 ++++++ - 4 files changed, 445 insertions(+) - create mode 100644 drivers/hwmon/tvs-mpfs.c - -diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index a5143d01b..e3564df18 100644 ---- a/drivers/hwmon/Kconfig -+++ b/drivers/hwmon/Kconfig -@@ -2108,6 +2108,17 @@ config SENSORS_TMP513 - This driver can also be built as a module. If so, the module - will be called tmp513. - -+config SENSORS_TVS_MPFS -+ tristate "PolarFire SoC (MPFS) TVS" -+ depends on POLARFIRE_SOC_MAILBOX -+ help -+ This driver adds support for the PolarFire SoC (MPFS) Temperature Voltage Sensor. -+ -+ To compile this driver as a module, choose M here. the -+ module will be called tvs-mpfs. -+ -+ If unsure, say N. -+ - config SENSORS_VEXPRESS - tristate "Versatile Express" - depends on VEXPRESS_CONFIG -diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile -index 11d076cad..1cebd0e73 100644 ---- a/drivers/hwmon/Makefile -+++ b/drivers/hwmon/Makefile -@@ -203,6 +203,7 @@ obj-$(CONFIG_SENSORS_TMP401) += tmp401.o - obj-$(CONFIG_SENSORS_TMP421) += tmp421.o - obj-$(CONFIG_SENSORS_TMP464) += tmp464.o - obj-$(CONFIG_SENSORS_TMP513) += tmp513.o -+obj-$(CONFIG_SENSORS_TVS_MPFS) += tvs-mpfs.o - obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress-hwmon.o - obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o - obj-$(CONFIG_SENSORS_VIA686A) += via686a.o -diff --git a/drivers/hwmon/tvs-mpfs.c b/drivers/hwmon/tvs-mpfs.c -new file mode 100644 -index 000000000..087a8b33f ---- /dev/null -+++ b/drivers/hwmon/tvs-mpfs.c -@@ -0,0 +1,371 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * -+ * Author: Lars Randers -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define PFSOC_CONTROL_SCB_TVS_CONTROL 0x08 -+#define PFSOC_CONTROL_SCB_TVS_OUTPUT0 0x24 -+#define PFSOC_CONTROL_SCB_TVS_OUTPUT1 0x28 -+ -+#define CTRL_POWEROFF BIT(5) -+#define CTRL_ABORT BIT(4) -+#define CTRL_TEMP BIT(3) -+#define CTRL_2P5 BIT(2) -+#define CTRL_1P8 BIT(1) -+#define CTRL_1P05 BIT(0) -+ -+#define OUTPUT0_U1P8_MASK 0x7FFF0000 -+#define OUTPUT0_U1P8_OFF 16 -+#define OUTPUT0_U1P0_MASK 0x00007FFF -+#define OUTPUT0_U1P0_OFF 0 -+#define OUTPUT1_TEMP_MASK 0xFFFF0000 -+#define OUTPUT1_TEMP_OFF 16 -+#define OUTPUT1_U2P5_MASK 0x00007FFF -+#define OUTPUT1_U2P5_OFF 0 -+ -+/* -+ * Poll intervals (in milliseconds) -+ */ -+#define MPFS_TVS_MIN_POLL_INTERVAL 2000 -+ -+// The following constant is 273.5 in (16.4) fixedpoint notation -+#define MPFS_TVS_MIN_TEMP_IN_K 0x1112 -+ -+typedef struct { -+ long min; -+ long actual; -+ long max; -+} mpfs_tvs_sensor_t; -+ -+typedef enum { -+ SN_V1P05 = 0, -+ SN_V1P8, -+ SN_V2P5, -+ SN_TEMP, -+ -+ SN_MAX -+} mpfs_tvs_sn_t; -+ -+static const char *mpfs_tvs_voltage_labels[] = { "U1P05", "U1P8", "U2P5" }; -+ -+struct mpfs_tvs { -+ struct device *dev; -+ struct device *hwmon_dev; -+ struct task_struct *poll_task; -+ bool kthread_running; -+ long update_interval; /* in milli-seconds */ -+ mpfs_tvs_sensor_t sensors[SN_MAX]; -+ void __iomem *ctrl_base; -+}; -+ -+static int mpfs_tvs_update_sensors(struct mpfs_tvs *data) { -+ u32 temp; -+ u32 work; -+ -+ /* read measurement */ -+ temp = readl(data->ctrl_base + PFSOC_CONTROL_SCB_TVS_OUTPUT1); -+ work = temp; -+ -+ /* compute temperature */ -+ temp = (temp & OUTPUT1_TEMP_MASK) >> OUTPUT1_TEMP_OFF; -+ temp = clamp_val(temp, MPFS_TVS_MIN_TEMP_IN_K, INT_MAX); -+ temp = temp - MPFS_TVS_MIN_TEMP_IN_K; /* Kelvin to Celsius */ -+ temp = (temp * 1000) >> 4; -+ data->sensors[SN_TEMP].actual = temp; -+ data->sensors[SN_TEMP].max = -+ max(data->sensors[SN_TEMP].actual, data->sensors[SN_TEMP].max); -+ data->sensors[SN_TEMP].min = -+ min(data->sensors[SN_TEMP].min, data->sensors[SN_TEMP].actual); -+ -+ /* compute voltage */ -+ work &= OUTPUT1_U2P5_MASK; -+ work = (1 * work) >> 3; -+ data->sensors[SN_V2P5].actual = work; -+ data->sensors[SN_V2P5].max = -+ max(data->sensors[SN_V2P5].actual, data->sensors[SN_V2P5].max); -+ data->sensors[SN_V2P5].min = -+ min(data->sensors[SN_V2P5].min, data->sensors[SN_V2P5].actual); -+ -+ temp = readl(data->ctrl_base + PFSOC_CONTROL_SCB_TVS_OUTPUT0); -+ work = temp; -+ temp = (OUTPUT0_U1P8_MASK & temp) >> OUTPUT0_U1P8_OFF; -+ temp = (1 * temp) >> 3; -+ data->sensors[SN_V1P8].actual = temp; -+ data->sensors[SN_V1P8].max = -+ max(data->sensors[SN_V1P8].actual, data->sensors[SN_V1P8].max); -+ data->sensors[SN_V2P5].min = -+ min(data->sensors[SN_V1P8].min, data->sensors[SN_V1P8].actual); -+ -+ work &= OUTPUT0_U1P0_MASK; -+ work = (1 * work) >> 3; -+ data->sensors[SN_V1P05].actual = work; -+ data->sensors[SN_V1P05].max = -+ max(data->sensors[SN_V1P05].actual, data->sensors[SN_V1P05].max); -+ data->sensors[SN_V1P05].min = -+ min(data->sensors[SN_V1P05].min, data->sensors[SN_V1P05].actual); -+ -+ return 0; -+} -+ -+ -+static int mpfs_tvs_chip_read(struct mpfs_tvs *data, long *val) -+{ -+ *val = data->update_interval; -+ return 0; -+} -+ -+static int mpfs_tvs_temp_read(struct mpfs_tvs *data, u32 attr, -+ int channel, long *val) -+{ -+ switch(attr) { -+ case hwmon_temp_input: -+ *val = data->sensors[SN_TEMP].actual; -+ break; -+ -+ case hwmon_temp_max: -+ *val = data->sensors[SN_TEMP].max; -+ break; -+ -+ default: -+ return -EOPNOTSUPP; -+ } -+ return 0; -+} -+ -+static int mpfs_tvs_voltage_read(struct mpfs_tvs *data, u32 attr, -+ int channel, long *val) -+{ -+ dev_dbg(data->dev, "read voltage chan %d\n", channel); -+ switch(attr) { -+ case hwmon_in_input: -+ *val = data->sensors[channel].actual; -+ break; -+ -+ case hwmon_in_max: -+ *val = data->sensors[channel].max; -+ break; -+ -+ default: -+ return -EOPNOTSUPP; -+ } -+ return 0; -+} -+ -+ -+static ssize_t mpfs_tvs_interval_write(struct mpfs_tvs *data, long val) -+{ -+ data->update_interval = clamp_val(val, -+ MPFS_TVS_MIN_POLL_INTERVAL, INT_MAX); -+ return 0; -+} -+ -+ -+static umode_t mpfs_tvs_is_visible(const void *data, -+ enum hwmon_sensor_types type, -+ u32 attr, int channel) -+{ -+ if(type == hwmon_chip && attr == hwmon_chip_update_interval) -+ return 0644; -+ -+ if(type == hwmon_temp) { -+ switch(attr) { -+ case hwmon_temp_input: -+ case hwmon_temp_max: -+ case hwmon_temp_label: -+ return 0444; -+ -+ default: -+ return 0; -+ } -+ } else if (type == hwmon_in) { -+ switch (attr) { -+ case hwmon_in_input: -+ case hwmon_in_label: -+ return 0444; -+ -+ default: -+ return 0; -+ } -+ } -+ return 0; -+} -+ -+static int mpfs_tvs_read(struct device *dev, enum hwmon_sensor_types type, -+ u32 attr, int channel, long *val) -+{ -+ struct mpfs_tvs *data = dev_get_drvdata(dev); -+ -+ switch(type) { -+ case hwmon_temp: -+ return mpfs_tvs_temp_read(data, attr, channel, val); -+ case hwmon_in: -+ return mpfs_tvs_voltage_read(data, attr, channel, val); -+ case hwmon_chip: -+ return mpfs_tvs_chip_read(data, val); -+ -+ default: -+ return -EOPNOTSUPP; -+ } -+} -+ -+static int mpfs_tvs_write(struct device *dev, enum hwmon_sensor_types type, -+ u32 attr, int channel, long val) -+{ -+ struct mpfs_tvs *data = dev_get_drvdata(dev); -+ -+ switch(type) { -+ case hwmon_chip: -+ return mpfs_tvs_interval_write(data, val); -+ default: -+ return -EOPNOTSUPP; -+ } -+} -+ -+static int mpfs_tvs_read_labels(struct device *dev, -+ enum hwmon_sensor_types type, -+ u32 attr, int channel, -+ const char **str) -+{ -+ switch(type) { -+ case hwmon_temp: -+ *str = "CPU Temp"; -+ return 0; -+ case hwmon_in: -+ *str = mpfs_tvs_voltage_labels[channel]; -+ return 0; -+ default: -+ return -ENOTSUPP; -+ } -+} -+ -+ -+static const struct hwmon_ops mpfs_tvs_ops = { -+ .is_visible = mpfs_tvs_is_visible, -+ .read_string = mpfs_tvs_read_labels, -+ .read = mpfs_tvs_read, -+ .write = mpfs_tvs_write, -+}; -+ -+static const struct hwmon_channel_info *mpfs_tvs_info[] = { -+ HWMON_CHANNEL_INFO(chip, -+ HWMON_C_REGISTER_TZ|HWMON_C_UPDATE_INTERVAL), -+ HWMON_CHANNEL_INFO(temp, -+ HWMON_T_INPUT|HWMON_T_MIN|HWMON_T_MAX|HWMON_T_LABEL), -+ HWMON_CHANNEL_INFO(in, -+ HWMON_I_INPUT|HWMON_I_LABEL, -+ HWMON_I_INPUT|HWMON_I_LABEL, -+ HWMON_I_INPUT|HWMON_I_LABEL), -+ NULL -+}; -+ -+static const struct hwmon_chip_info mpfs_tvs_chip_info = { -+ .ops = &mpfs_tvs_ops, -+ .info = mpfs_tvs_info, -+}; -+ -+ -+static int mpfs_tvs_poll_task(void *ptr) -+{ -+ struct mpfs_tvs *data = ptr; -+ int ret = 0; -+ -+ data->kthread_running = true; -+ -+ set_freezable(); -+ -+ while(!kthread_should_stop()) { -+ schedule_timeout_interruptible(data->update_interval); -+ try_to_freeze(); -+ ret = mpfs_tvs_update_sensors(data); -+ if(ret) -+ break; -+ } -+ -+ data->kthread_running = false; -+ return ret; -+} -+ -+static int mpfs_tvs_probe(struct auxiliary_device *auxdev, -+ const struct auxiliary_device_id *id) -+{ -+ struct device *dev = &auxdev->dev; -+ struct device *hwmon_dev; -+ struct mpfs_tvs *data; -+ struct task_struct *task; -+ int err; -+ -+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); -+ if(!data) -+ return -ENOMEM; -+ -+ data->ctrl_base = (void __iomem *)auxdev->dev.platform_data; -+ -+ data->dev = dev; -+ data->kthread_running = false; -+ -+ hwmon_dev = devm_hwmon_device_register_with_info(dev, "mpfs_tvs", -+ data, -+ &mpfs_tvs_chip_info, -+ NULL); -+ -+ if(IS_ERR(hwmon_dev)) { -+ err = PTR_ERR(hwmon_dev); -+ dev_err(dev, "Class registration failed (%d)\n", err); -+ return err; -+ } -+ -+ /* enable HW sensor */ -+ writel(CTRL_1P05 | CTRL_1P8 | CTRL_2P5 | CTRL_TEMP, -+ data->ctrl_base + PFSOC_CONTROL_SCB_TVS_CONTROL); -+ -+ data->hwmon_dev = hwmon_dev; -+ data->sensors[SN_TEMP].max = 0; -+ data->sensors[SN_V1P05].min = -+ data->sensors[SN_V1P8].min = -+ data->sensors[SN_V2P5].min = 20000; -+ data->sensors[SN_V1P05].max = -+ data->sensors[SN_V1P8].max = -+ data->sensors[SN_V2P5].max = 0; -+ data->update_interval = MPFS_TVS_MIN_POLL_INTERVAL; -+ mpfs_tvs_update_sensors(data); -+ -+ task = kthread_run(mpfs_tvs_poll_task, data, "tvs-mpfs-kthread"); -+ if (IS_ERR(task)) { -+ err = PTR_ERR(task); -+ dev_err(dev, "Unable to run kthread err %d\n", err); -+ return err; -+ } -+ -+ data->poll_task = task; -+ -+ dev_info(dev, "Registered MPFS TVS auxiliary driver\n"); -+ return 0; -+} -+ -+static const struct auxiliary_device_id mpfs_tvs_ids[] = { -+ { -+ .name = "mailbox_mpfs.tvs-mpfs", -+ }, -+ { } -+}; -+MODULE_DEVICE_TABLE(auxiliary, mpfs_reset_ids); -+ -+static struct auxiliary_driver mpfs_tvs_driver = { -+ .probe = mpfs_tvs_probe, -+ .id_table = mpfs_tvs_ids, -+}; -+module_auxiliary_driver(mpfs_tvs_driver); -+ -+MODULE_AUTHOR("Lars Randers "); -+MODULE_DESCRIPTION("MPFS temperature voltage sensor driver"); -+MODULE_LICENSE("GPL"); -\ No newline at end of file -diff --git a/drivers/mailbox/mailbox-mpfs.c b/drivers/mailbox/mailbox-mpfs.c -index 162df4965..198e6b37d 100644 ---- a/drivers/mailbox/mailbox-mpfs.c -+++ b/drivers/mailbox/mailbox-mpfs.c -@@ -8,6 +8,7 @@ - * - */ - -+#include - #include - #include - #include -@@ -220,6 +221,64 @@ static const struct mbox_chan_ops mpfs_mbox_ops = { - .last_tx_done = mpfs_mbox_last_tx_done, - }; - -+static void mpfs_mbox_auxdev_release(struct device *dev) -+{ -+ struct auxiliary_device *auxdev = to_auxiliary_dev(dev); -+ -+ kfree(auxdev); -+} -+ -+static struct auxiliary_device *mpfs_mbox_adev_alloc(struct device *parent_dev) -+{ -+ struct auxiliary_device *auxdev; -+ int ret; -+ -+ auxdev = kzalloc(sizeof(*auxdev), GFP_KERNEL); -+ if(!auxdev) -+ return ERR_PTR(-ENOMEM); -+ -+ auxdev->name = "tvs-mpfs"; -+ auxdev->dev.parent = parent_dev; -+ auxdev->dev.release = mpfs_mbox_auxdev_release; -+ auxdev->id = 10u; -+ -+ ret = auxiliary_device_init(auxdev); -+ if(ret) { -+ kfree(auxdev); -+ return ERR_PTR(ret); -+ } -+ -+ return auxdev; -+} -+ -+static void mpfs_mbox_unregister_auxdev(void *dev) -+{ -+ struct auxiliary_device *auxdev = dev; -+ -+ auxiliary_device_delete(auxdev); -+ auxiliary_device_uninit(auxdev); -+} -+ -+int mpfs_mbox_auxdev_register(struct device *parent_dev, void __iomem *base) -+{ -+ struct auxiliary_device *auxdev; -+ int ret; -+ -+ auxdev = mpfs_mbox_adev_alloc(parent_dev); -+ if(IS_ERR(auxdev)) -+ return PTR_ERR(auxdev); -+ -+ auxdev->dev.platform_data = base; -+ -+ ret = auxiliary_device_add(auxdev); -+ if(ret) { -+ auxiliary_device_uninit(auxdev); -+ return ret; -+ } -+ -+ return devm_add_action_or_reset(parent_dev, mpfs_mbox_unregister_auxdev, auxdev); -+} -+ - static int mpfs_mbox_probe(struct platform_device *pdev) - { - struct mpfs_mbox *mbox; -@@ -261,6 +320,9 @@ static int mpfs_mbox_probe(struct platform_device *pdev) - dev_err(&pdev->dev, "Registering MPFS mailbox controller failed\n"); - return ret; - } -+ -+ mpfs_mbox_auxdev_register(&pdev->dev, mbox->ctrl_base); -+ - dev_info(&pdev->dev, "Registered MPFS mailbox controller driver\n"); - - return 0; --- -2.39.2 - diff --git a/patches/linux/0002-PCIe-Change-controller-and-bridge-base-address.patch b/patches/linux/linux-6.6.y/0002-PCIe-Change-controller-and-bridge-base-address.patch similarity index 66% rename from patches/linux/0002-PCIe-Change-controller-and-bridge-base-address.patch rename to patches/linux/linux-6.6.y/0002-PCIe-Change-controller-and-bridge-base-address.patch index 9fb4752..3d3f793 100644 --- a/patches/linux/0002-PCIe-Change-controller-and-bridge-base-address.patch +++ b/patches/linux/linux-6.6.y/0002-PCIe-Change-controller-and-bridge-base-address.patch @@ -1,17 +1,17 @@ -From 8911855f7b07ba7f592f73850e551802ae40601d Mon Sep 17 00:00:00 2001 +From 4c14a137c399cbdb29d121b6dcdc395976e38579 Mon Sep 17 00:00:00 2001 From: vauban353 -Date: Sat, 5 Nov 2022 17:47:50 +0000 -Subject: [PATCH 2/8] PCIe: Change controller and bridge base address. +Date: Fri, 25 Oct 2024 09:17:26 +0000 +Subject: [PATCH] PCIe: Change controller and bridge base address. --- drivers/pci/controller/pcie-microchip-host.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/pcie-microchip-host.c b/drivers/pci/controller/pcie-microchip-host.c -index 56306f514..b1b3b7820 100644 +index 4030a2bb0..1aa8aca7e 100644 --- a/drivers/pci/controller/pcie-microchip-host.c +++ b/drivers/pci/controller/pcie-microchip-host.c -@@ -26,8 +26,8 @@ +@@ -27,8 +27,8 @@ #define MC_ATT_MASK GENMASK_ULL(63, 31) /* PCIe Bridge Phy and Controller Phy offsets */ @@ -20,8 +20,8 @@ index 56306f514..b1b3b7820 100644 +#define MC_PCIE1_BRIDGE_ADDR 0x00004000u +#define MC_PCIE1_CTRL_ADDR 0x00006000u - #define MC_PCIE_BRIDGE_ADDR (MC_PCIE1_BRIDGE_ADDR) - #define MC_PCIE_CTRL_ADDR (MC_PCIE1_CTRL_ADDR) + /* PCIe Bridge Phy Regs */ + #define PCIE_PCI_IRQ_DW0 0xa8 -- 2.39.2 diff --git a/patches/linux/linux-6.6.y/0011-can-mpfs_can-add-registration-string.patch b/patches/linux/linux-6.6.y/0011-can-mpfs_can-add-registration-string.patch new file mode 100644 index 0000000..4d8c435 --- /dev/null +++ b/patches/linux/linux-6.6.y/0011-can-mpfs_can-add-registration-string.patch @@ -0,0 +1,25 @@ +From ff3af0236730758e918a3d6c090bb78ce03aedcf Mon Sep 17 00:00:00 2001 +From: Lars Randers +Date: Mon, 28 Oct 2024 11:46:26 +0000 +Subject: [PATCH] can: mpfs_can: add registration string + +Signed-off-by: Lars Randers +--- + drivers/net/can/mpfs_can.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/can/mpfs_can.c b/drivers/net/can/mpfs_can.c +index f741af2c0..0e0aa2384 100644 +--- a/drivers/net/can/mpfs_can.c ++++ b/drivers/net/can/mpfs_can.c +@@ -913,6 +913,7 @@ static int mpfs_can_probe(struct platform_device *pdev) + priv->reg, ndev->irq, priv->can.clock.freq, + priv->tx_max); + ++ dev_info(&pdev->dev, "Registered MPFS CAN controller %s\n", ndev->name); + return 0; + + err: +-- +2.39.2 + diff --git a/patches/linux/linux-6.6.y/0012-gpio-gpio-mpfs-add-registration-string.patch b/patches/linux/linux-6.6.y/0012-gpio-gpio-mpfs-add-registration-string.patch new file mode 100644 index 0000000..c653d2f --- /dev/null +++ b/patches/linux/linux-6.6.y/0012-gpio-gpio-mpfs-add-registration-string.patch @@ -0,0 +1,25 @@ +From 6759b8dc43985a2d6083835931257f3229b240f4 Mon Sep 17 00:00:00 2001 +From: Lars Randers +Date: Mon, 28 Oct 2024 11:55:28 +0000 +Subject: [PATCH] gpio: gpio-mpfs: add registration string + +Signed-off-by: Lars Randers +--- + drivers/gpio/gpio-mpfs.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpio/gpio-mpfs.c b/drivers/gpio/gpio-mpfs.c +index d7168aa04..abf3e4151 100644 +--- a/drivers/gpio/gpio-mpfs.c ++++ b/drivers/gpio/gpio-mpfs.c +@@ -332,6 +332,7 @@ static int mpfs_gpio_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, mpfs_gpio); + ++ dev_info(&pdev->dev, "Registered MPFS GPIO controller\n"); + return 0; + + cleanup_clock: +-- +2.39.2 +