Merge branch 'devel' into 'main'
Move to linux4microchip+fpga-2024.09 See merge request beaglev-fire/BeagleV-Fire-ubuntu!6main
commit
0fefceeb31
@ -1,371 +0,0 @@
|
|||||||
From 37ff4eff8ff033c48aa73526fec7291127326dcb Mon Sep 17 00:00:00 2001
|
|
||||||
From: vauban353 <vauban353@gmail.com>
|
|
||||||
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 <lewis.hanly@microchip.com>
|
|
||||||
+ *
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include <linux/bitops.h>
|
|
||||||
+#include <linux/clk.h>
|
|
||||||
+#include <linux/device.h>
|
|
||||||
+#include <linux/errno.h>
|
|
||||||
+#include <linux/gpio/driver.h>
|
|
||||||
+#include <linux/init.h>
|
|
||||||
+#include <linux/irq.h>
|
|
||||||
+#include <linux/irqchip/chained_irq.h>
|
|
||||||
+#include <linux/of.h>
|
|
||||||
+#include <linux/of_irq.h>
|
|
||||||
+#include <linux/mod_devicetable.h>
|
|
||||||
+#include <linux/platform_device.h>
|
|
||||||
+#include <linux/spinlock.h>
|
|
||||||
+
|
|
||||||
+#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
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -1,275 +0,0 @@
|
|||||||
From 0eeed461b7b86e3b822984b1c266316ac70ccf69 Mon Sep 17 00:00:00 2001
|
|
||||||
From: vauban353 <vauban353@gmail.com>
|
|
||||||
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
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
|||||||
From 747c6d5984cccf7c3e48c2cdb4dd1d626889096e Mon Sep 17 00:00:00 2001
|
|
||||||
From: vauban353 <vauban353@gmail.com>
|
|
||||||
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
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
|||||||
From e9aea028119afd0858e77989dd1a4ecc21d30dc1 Mon Sep 17 00:00:00 2001
|
|
||||||
From: vauban353 <vauban353@gmail.com>
|
|
||||||
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 <asm/unaligned.h>
|
|
||||||
|
|
||||||
+//<CJ>:
|
|
||||||
+#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;
|
|
||||||
+//<CJ> 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
|
|
||||||
|
|
||||||
+//<CJ>:
|
|
||||||
+#undef CONFIG_HAS_DMA
|
|
||||||
+
|
|
||||||
#include <linux/device.h>
|
|
||||||
#include <linux/dma-direction.h>
|
|
||||||
#include <linux/scatterlist.h>
|
|
||||||
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"
|
|
||||||
|
|
||||||
+//<CJ>:
|
|
||||||
+#undef CONFIG_HAS_DMA
|
|
||||||
+
|
|
||||||
static DEFINE_IDR(spi_master_idr);
|
|
||||||
|
|
||||||
static void spidev_release(struct device *dev)
|
|
||||||
--
|
|
||||||
2.39.2
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
|||||||
From 09e2d12d8ade10bb2d8ab1d42e9a1bd8442a74c8 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Robert Nelson <robertcnelson@gmail.com>
|
|
||||||
Date: Tue, 10 Oct 2023 10:01:45 -0500
|
|
||||||
Subject: [PATCH 9/9] Makefile: build mpfs-beaglev-fire.dtb
|
|
||||||
|
|
||||||
Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
|
|
||||||
---
|
|
||||||
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
|
|
||||||
|
|
@ -1,516 +0,0 @@
|
|||||||
From 413071dc2f13f581eb844a0009d571dfa0bb2f02 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Lars Randers <lranders@mail.dk>
|
|
||||||
Date: Thu, 20 Jun 2024 13:55:40 +0000
|
|
||||||
Subject: [PATCH] BeagleV-Fire: Add MPFS TVS auxiliary driver
|
|
||||||
|
|
||||||
Signed-off-by: Lars Randers <lranders@mail.dk>
|
|
||||||
---
|
|
||||||
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 <lranders@mail.dk>
|
|
||||||
+ *
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include <linux/auxiliary_bus.h>
|
|
||||||
+#include <linux/err.h>
|
|
||||||
+#include <linux/freezer.h>
|
|
||||||
+#include <linux/kthread.h>
|
|
||||||
+#include <linux/hwmon.h>
|
|
||||||
+#include <linux/io.h>
|
|
||||||
+#include <linux/module.h>
|
|
||||||
+
|
|
||||||
+#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 <lranders@mail.dk>");
|
|
||||||
+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 <linux/auxiliary_bus.h>
|
|
||||||
#include <linux/io.h>
|
|
||||||
#include <linux/err.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
@@ -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
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
|||||||
|
From ff3af0236730758e918a3d6c090bb78ce03aedcf Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lars Randers <lranders@mail.dk>
|
||||||
|
Date: Mon, 28 Oct 2024 11:46:26 +0000
|
||||||
|
Subject: [PATCH] can: mpfs_can: add registration string
|
||||||
|
|
||||||
|
Signed-off-by: Lars Randers <lranders@mail.dk>
|
||||||
|
---
|
||||||
|
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
|
||||||
|
|
@ -0,0 +1,25 @@
|
|||||||
|
From 6759b8dc43985a2d6083835931257f3229b240f4 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lars Randers <lranders@mail.dk>
|
||||||
|
Date: Mon, 28 Oct 2024 11:55:28 +0000
|
||||||
|
Subject: [PATCH] gpio: gpio-mpfs: add registration string
|
||||||
|
|
||||||
|
Signed-off-by: Lars Randers <lranders@mail.dk>
|
||||||
|
---
|
||||||
|
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
|
||||||
|
|
Loading…
Reference in New Issue