From: Christian Marangi Date: Mon, 28 Oct 2024 13:01:52 +0000 (+0100) Subject: airoha: an7581: replace TRNG patch with upstream version X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=bcd95cb9c43aeb706ee03cb30f104ec8d171c91b;p=openwrt%2Fstaging%2Fwigyori.git airoha: an7581: replace TRNG patch with upstream version Replace TRNG patch with upstream version. Signed-off-by: Christian Marangi --- diff --git a/target/linux/airoha/patches-6.6/030-v6.13-hwrng-airoha-add-support-for-Airoha-EN7581-TRNG.patch b/target/linux/airoha/patches-6.6/030-v6.13-hwrng-airoha-add-support-for-Airoha-EN7581-TRNG.patch new file mode 100644 index 0000000000..e21fb5649e --- /dev/null +++ b/target/linux/airoha/patches-6.6/030-v6.13-hwrng-airoha-add-support-for-Airoha-EN7581-TRNG.patch @@ -0,0 +1,306 @@ +From 5c5db81bff81a0fcd9ad998543d4241cbfe4742f Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 17 Oct 2024 14:44:38 +0200 +Subject: [PATCH 2/2] hwrng: airoha - add support for Airoha EN7581 TRNG + +Add support for Airoha TRNG. The Airoha SoC provide a True RNG module +that can output 4 bytes of raw data at times. + +The module makes use of various noise source to provide True Random +Number Generation. + +On probe the module is reset to operate Health Test and verify correct +execution of it. + +The module can also provide DRBG function but the execution mode is +mutually exclusive, running as TRNG doesn't permit to also run it as +DRBG. + +Signed-off-by: Christian Marangi +Reviewed-by: Martin Kaiser +Signed-off-by: Herbert Xu +--- + drivers/char/hw_random/Kconfig | 13 ++ + drivers/char/hw_random/Makefile | 1 + + drivers/char/hw_random/airoha-trng.c | 243 +++++++++++++++++++++++++++ + 3 files changed, 257 insertions(+) + create mode 100644 drivers/char/hw_random/airoha-trng.c + +--- a/drivers/char/hw_random/Kconfig ++++ b/drivers/char/hw_random/Kconfig +@@ -62,6 +62,19 @@ config HW_RANDOM_AMD + + If unsure, say Y. + ++config HW_RANDOM_AIROHA ++ tristate "Airoha True HW Random Number Generator support" ++ depends on ARCH_AIROHA || COMPILE_TEST ++ default HW_RANDOM ++ help ++ This driver provides kernel-side support for the True Random Number ++ Generator hardware found on Airoha SoC. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called airoha-rng. ++ ++ If unsure, say Y. ++ + config HW_RANDOM_ATMEL + tristate "Atmel Random Number Generator support" + depends on (ARCH_AT91 || COMPILE_TEST) +--- a/drivers/char/hw_random/Makefile ++++ b/drivers/char/hw_random/Makefile +@@ -8,6 +8,7 @@ rng-core-y := core.o + obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o + obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o + obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o ++obj-$(CONFIG_HW_RANDOM_AIROHA) += airoha-trng.o + obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o + obj-$(CONFIG_HW_RANDOM_BA431) += ba431-rng.o + obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o +--- /dev/null ++++ b/drivers/char/hw_random/airoha-trng.c +@@ -0,0 +1,243 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright (C) 2024 Christian Marangi */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define TRNG_IP_RDY 0x800 ++#define CNT_TRANS GENMASK(15, 8) ++#define SAMPLE_RDY BIT(0) ++#define TRNG_NS_SEK_AND_DAT_EN 0x804 ++#define RNG_EN BIT(31) /* referenced as ring_en */ ++#define RAW_DATA_EN BIT(16) ++#define TRNG_HEALTH_TEST_SW_RST 0x808 ++#define SW_RST BIT(0) /* Active High */ ++#define TRNG_INTR_EN 0x818 ++#define INTR_MASK BIT(16) ++#define CONTINUOUS_HEALTH_INITR_EN BIT(2) ++#define SW_STARTUP_INITR_EN BIT(1) ++#define RST_STARTUP_INITR_EN BIT(0) ++/* Notice that Health Test are done only out of Reset and with RNG_EN */ ++#define TRNG_HEALTH_TEST_STATUS 0x824 ++#define CONTINUOUS_HEALTH_AP_TEST_FAIL BIT(23) ++#define CONTINUOUS_HEALTH_RC_TEST_FAIL BIT(22) ++#define SW_STARTUP_TEST_DONE BIT(21) ++#define SW_STARTUP_AP_TEST_FAIL BIT(20) ++#define SW_STARTUP_RC_TEST_FAIL BIT(19) ++#define RST_STARTUP_TEST_DONE BIT(18) ++#define RST_STARTUP_AP_TEST_FAIL BIT(17) ++#define RST_STARTUP_RC_TEST_FAIL BIT(16) ++#define RAW_DATA_VALID BIT(7) ++ ++#define TRNG_RAW_DATA_OUT 0x828 ++ ++#define TRNG_CNT_TRANS_VALID 0x80 ++#define BUSY_LOOP_SLEEP 10 ++#define BUSY_LOOP_TIMEOUT (BUSY_LOOP_SLEEP * 10000) ++ ++struct airoha_trng { ++ void __iomem *base; ++ struct hwrng rng; ++ struct device *dev; ++ ++ struct completion rng_op_done; ++}; ++ ++static int airoha_trng_irq_mask(struct airoha_trng *trng) ++{ ++ u32 val; ++ ++ val = readl(trng->base + TRNG_INTR_EN); ++ val |= INTR_MASK; ++ writel(val, trng->base + TRNG_INTR_EN); ++ ++ return 0; ++} ++ ++static int airoha_trng_irq_unmask(struct airoha_trng *trng) ++{ ++ u32 val; ++ ++ val = readl(trng->base + TRNG_INTR_EN); ++ val &= ~INTR_MASK; ++ writel(val, trng->base + TRNG_INTR_EN); ++ ++ return 0; ++} ++ ++static int airoha_trng_init(struct hwrng *rng) ++{ ++ struct airoha_trng *trng = container_of(rng, struct airoha_trng, rng); ++ int ret; ++ u32 val; ++ ++ val = readl(trng->base + TRNG_NS_SEK_AND_DAT_EN); ++ val |= RNG_EN; ++ writel(val, trng->base + TRNG_NS_SEK_AND_DAT_EN); ++ ++ /* Set out of SW Reset */ ++ airoha_trng_irq_unmask(trng); ++ writel(0, trng->base + TRNG_HEALTH_TEST_SW_RST); ++ ++ ret = wait_for_completion_timeout(&trng->rng_op_done, BUSY_LOOP_TIMEOUT); ++ if (ret <= 0) { ++ dev_err(trng->dev, "Timeout waiting for Health Check\n"); ++ airoha_trng_irq_mask(trng); ++ return -ENODEV; ++ } ++ ++ /* Check if Health Test Failed */ ++ val = readl(trng->base + TRNG_HEALTH_TEST_STATUS); ++ if (val & (RST_STARTUP_AP_TEST_FAIL | RST_STARTUP_RC_TEST_FAIL)) { ++ dev_err(trng->dev, "Health Check fail: %s test fail\n", ++ val & RST_STARTUP_AP_TEST_FAIL ? "AP" : "RC"); ++ return -ENODEV; ++ } ++ ++ /* Check if IP is ready */ ++ ret = readl_poll_timeout(trng->base + TRNG_IP_RDY, val, ++ val & SAMPLE_RDY, 10, 1000); ++ if (ret < 0) { ++ dev_err(trng->dev, "Timeout waiting for IP ready"); ++ return -ENODEV; ++ } ++ ++ /* CNT_TRANS must be 0x80 for IP to be considered ready */ ++ ret = readl_poll_timeout(trng->base + TRNG_IP_RDY, val, ++ FIELD_GET(CNT_TRANS, val) == TRNG_CNT_TRANS_VALID, ++ 10, 1000); ++ if (ret < 0) { ++ dev_err(trng->dev, "Timeout waiting for IP ready"); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static void airoha_trng_cleanup(struct hwrng *rng) ++{ ++ struct airoha_trng *trng = container_of(rng, struct airoha_trng, rng); ++ u32 val; ++ ++ val = readl(trng->base + TRNG_NS_SEK_AND_DAT_EN); ++ val &= ~RNG_EN; ++ writel(val, trng->base + TRNG_NS_SEK_AND_DAT_EN); ++ ++ /* Put it in SW Reset */ ++ writel(SW_RST, trng->base + TRNG_HEALTH_TEST_SW_RST); ++} ++ ++static int airoha_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait) ++{ ++ struct airoha_trng *trng = container_of(rng, struct airoha_trng, rng); ++ u32 *data = buf; ++ u32 status; ++ int ret; ++ ++ ret = readl_poll_timeout(trng->base + TRNG_HEALTH_TEST_STATUS, status, ++ status & RAW_DATA_VALID, 10, 1000); ++ if (ret < 0) { ++ dev_err(trng->dev, "Timeout waiting for TRNG RAW Data valid\n"); ++ return ret; ++ } ++ ++ *data = readl(trng->base + TRNG_RAW_DATA_OUT); ++ ++ return 4; ++} ++ ++static irqreturn_t airoha_trng_irq(int irq, void *priv) ++{ ++ struct airoha_trng *trng = (struct airoha_trng *)priv; ++ ++ airoha_trng_irq_mask(trng); ++ /* Just complete the task, we will read the value later */ ++ complete(&trng->rng_op_done); ++ ++ return IRQ_HANDLED; ++} ++ ++static int airoha_trng_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct airoha_trng *trng; ++ int irq, ret; ++ u32 val; ++ ++ trng = devm_kzalloc(dev, sizeof(*trng), GFP_KERNEL); ++ if (!trng) ++ return -ENOMEM; ++ ++ trng->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(trng->base)) ++ return PTR_ERR(trng->base); ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return irq; ++ ++ airoha_trng_irq_mask(trng); ++ ret = devm_request_irq(&pdev->dev, irq, airoha_trng_irq, 0, ++ pdev->name, (void *)trng); ++ if (ret) { ++ dev_err(dev, "Can't get interrupt working.\n"); ++ return ret; ++ } ++ ++ init_completion(&trng->rng_op_done); ++ ++ /* Enable interrupt for SW reset Health Check */ ++ val = readl(trng->base + TRNG_INTR_EN); ++ val |= RST_STARTUP_INITR_EN; ++ writel(val, trng->base + TRNG_INTR_EN); ++ ++ /* Set output to raw data */ ++ val = readl(trng->base + TRNG_NS_SEK_AND_DAT_EN); ++ val |= RAW_DATA_EN; ++ writel(val, trng->base + TRNG_NS_SEK_AND_DAT_EN); ++ ++ /* Put it in SW Reset */ ++ writel(SW_RST, trng->base + TRNG_HEALTH_TEST_SW_RST); ++ ++ trng->dev = dev; ++ trng->rng.name = pdev->name; ++ trng->rng.init = airoha_trng_init; ++ trng->rng.cleanup = airoha_trng_cleanup; ++ trng->rng.read = airoha_trng_read; ++ ++ ret = devm_hwrng_register(dev, &trng->rng); ++ if (ret) { ++ dev_err(dev, "failed to register rng device: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id airoha_trng_of_match[] = { ++ { .compatible = "airoha,en7581-trng", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, airoha_trng_of_match); ++ ++static struct platform_driver airoha_trng_driver = { ++ .driver = { ++ .name = "airoha-trng", ++ .of_match_table = airoha_trng_of_match, ++ }, ++ .probe = airoha_trng_probe, ++}; ++ ++module_platform_driver(airoha_trng_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Christian Marangi "); ++MODULE_DESCRIPTION("Airoha True Random Number Generator driver"); diff --git a/target/linux/airoha/patches-6.6/102-hwrng-add-support-for-Airoha-EN7581-TRNG.patch b/target/linux/airoha/patches-6.6/102-hwrng-add-support-for-Airoha-EN7581-TRNG.patch deleted file mode 100644 index 1c99369fcb..0000000000 --- a/target/linux/airoha/patches-6.6/102-hwrng-add-support-for-Airoha-EN7581-TRNG.patch +++ /dev/null @@ -1,304 +0,0 @@ -From 9dbd16ac89e00bd8640ecac3971b0943410b5cec Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Sat, 6 Jul 2024 01:15:24 +0200 -Subject: [PATCH 2/2] hwrng: add support for Airoha EN7581 TRNG - -Add support for Airoha TRNG. The Airoha SoC provide a True RNG module -that can output 4 bytes of raw data at times. - -The module makes use of various noise source to provide True Random -Number Generation. - -On probe the module is reset to operate Health Test and verify correct -execution of it. - -The module can also provide DRBG function but the execution mode is -mutually exclusive, running as TRNG doesn't permit to also run it as -DRBG. - -Signed-off-by: Christian Marangi ---- - drivers/char/hw_random/Kconfig | 13 ++ - drivers/char/hw_random/Makefile | 1 + - drivers/char/hw_random/airoha-trng.c | 243 +++++++++++++++++++++++++++ - 3 files changed, 257 insertions(+) - create mode 100644 drivers/char/hw_random/airoha-trng.c - ---- a/drivers/char/hw_random/Kconfig -+++ b/drivers/char/hw_random/Kconfig -@@ -62,6 +62,19 @@ config HW_RANDOM_AMD - - If unsure, say Y. - -+config HW_RANDOM_AIROHA -+ tristate "Airoha True HW Random Number Generator support" -+ depends on ARCH_AIROHA || COMPILE_TEST -+ default HW_RANDOM -+ help -+ This driver provides kernel-side support for the True Random Number -+ Generator hardware found on Airoha SoC. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called airoha-rng. -+ -+ If unsure, say Y. -+ - config HW_RANDOM_ATMEL - tristate "Atmel Random Number Generator support" - depends on (ARCH_AT91 || COMPILE_TEST) ---- a/drivers/char/hw_random/Makefile -+++ b/drivers/char/hw_random/Makefile -@@ -8,6 +8,7 @@ rng-core-y := core.o - obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o - obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o - obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o -+obj-$(CONFIG_HW_RANDOM_AIROHA) += airoha-trng.o - obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o - obj-$(CONFIG_HW_RANDOM_BA431) += ba431-rng.o - obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o ---- /dev/null -+++ b/drivers/char/hw_random/airoha-trng.c -@@ -0,0 +1,243 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* Copyright (C) 2024 Christian Marangi */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define TRNG_IP_RDY 0x800 -+#define CNT_TRANS GENMASK(15, 8) -+#define SAMPLE_RDY BIT(0) -+#define TRNG_NS_SEK_AND_DAT_EN 0x804 -+#define RNG_EN BIT(31) /* referenced as ring_en */ -+#define RAW_DATA_EN BIT(16) -+#define TRNG_HEALTH_TEST_SW_RST 0x808 -+#define SW_RST BIT(0) /* Active High */ -+#define TRNG_INTR_EN 0x818 -+#define INTR_MASK BIT(16) -+#define CONTINUOUS_HEALTH_INITR_EN BIT(2) -+#define SW_STARTUP_INITR_EN BIT(1) -+#define RST_STARTUP_INITR_EN BIT(0) -+/* Notice that Health Test are done only out of Reset and with RNG_EN */ -+#define TRNG_HEALTH_TEST_STATUS 0x824 -+#define CONTINUOUS_HEALTH_AP_TEST_FAIL BIT(23) -+#define CONTINUOUS_HEALTH_RC_TEST_FAIL BIT(22) -+#define SW_STARTUP_TEST_DONE BIT(21) -+#define SW_STARTUP_AP_TEST_FAIL BIT(20) -+#define SW_STARTUP_RC_TEST_FAIL BIT(19) -+#define RST_STARTUP_TEST_DONE BIT(18) -+#define RST_STARTUP_AP_TEST_FAIL BIT(17) -+#define RST_STARTUP_RC_TEST_FAIL BIT(16) -+#define RAW_DATA_VALID BIT(7) -+ -+#define TRNG_RAW_DATA_OUT 0x828 -+ -+#define TRNG_CNT_TRANS_VALID 0x80 -+#define BUSY_LOOP_SLEEP 10 -+#define BUSY_LOOP_TIMEOUT (BUSY_LOOP_SLEEP * 10000) -+ -+struct airoha_trng { -+ void __iomem *base; -+ struct hwrng rng; -+ struct device *dev; -+ -+ struct completion rng_op_done; -+}; -+ -+static int airoha_trng_irq_mask(struct airoha_trng *trng) -+{ -+ u32 val; -+ -+ val = readl(trng->base + TRNG_INTR_EN); -+ val |= INTR_MASK; -+ writel(val, trng->base + TRNG_INTR_EN); -+ -+ return 0; -+} -+ -+static int airoha_trng_irq_unmask(struct airoha_trng *trng) -+{ -+ u32 val; -+ -+ val = readl(trng->base + TRNG_INTR_EN); -+ val &= ~INTR_MASK; -+ writel(val, trng->base + TRNG_INTR_EN); -+ -+ return 0; -+} -+ -+static int airoha_trng_init(struct hwrng *rng) -+{ -+ struct airoha_trng *trng = container_of(rng, struct airoha_trng, rng); -+ int ret; -+ u32 val; -+ -+ val = readl(trng->base + TRNG_NS_SEK_AND_DAT_EN); -+ val |= RNG_EN; -+ writel(val, trng->base + TRNG_NS_SEK_AND_DAT_EN); -+ -+ /* Set out of SW Reset */ -+ airoha_trng_irq_unmask(trng); -+ writel(0, trng->base + TRNG_HEALTH_TEST_SW_RST); -+ -+ ret = wait_for_completion_timeout(&trng->rng_op_done, BUSY_LOOP_TIMEOUT); -+ if (ret <= 0) { -+ dev_err(trng->dev, "Timeout waiting for Health Check\n"); -+ airoha_trng_irq_mask(trng); -+ return -ENODEV; -+ } -+ -+ /* Check if Health Test Failed */ -+ val = readl(trng->base + TRNG_HEALTH_TEST_STATUS); -+ if (val & (RST_STARTUP_AP_TEST_FAIL | RST_STARTUP_RC_TEST_FAIL)) { -+ dev_err(trng->dev, "Health Check fail: %s test fail\n", -+ val & RST_STARTUP_AP_TEST_FAIL ? "AP" : "RC"); -+ return -ENODEV; -+ } -+ -+ /* Check if IP is ready */ -+ ret = readl_poll_timeout(trng->base + TRNG_IP_RDY, val, -+ val & SAMPLE_RDY, 10, 1000); -+ if (ret < 0) { -+ dev_err(trng->dev, "Timeout waiting for IP ready"); -+ return -ENODEV; -+ } -+ -+ /* CNT_TRANS must be 0x80 for IP to be considered ready */ -+ ret = readl_poll_timeout(trng->base + TRNG_IP_RDY, val, -+ FIELD_GET(CNT_TRANS, val) == TRNG_CNT_TRANS_VALID, -+ 10, 1000); -+ if (ret < 0) { -+ dev_err(trng->dev, "Timeout waiting for IP ready"); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+static void airoha_trng_cleanup(struct hwrng *rng) -+{ -+ struct airoha_trng *trng = container_of(rng, struct airoha_trng, rng); -+ u32 val; -+ -+ val = readl(trng->base + TRNG_NS_SEK_AND_DAT_EN); -+ val &= ~RNG_EN; -+ writel(val, trng->base + TRNG_NS_SEK_AND_DAT_EN); -+ -+ /* Put it in SW Reset */ -+ writel(SW_RST, trng->base + TRNG_HEALTH_TEST_SW_RST); -+} -+ -+static int airoha_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait) -+{ -+ struct airoha_trng *trng = container_of(rng, struct airoha_trng, rng); -+ u32 *data = buf; -+ u32 status; -+ int ret; -+ -+ ret = readl_poll_timeout(trng->base + TRNG_HEALTH_TEST_STATUS, status, -+ status & RAW_DATA_VALID, 10, 1000); -+ if (ret < 0) { -+ dev_err(trng->dev, "Timeout waiting for TRNG RAW Data valid\n"); -+ return ret; -+ } -+ -+ *data = readl(trng->base + TRNG_RAW_DATA_OUT); -+ -+ return 4; -+} -+ -+static irqreturn_t airoha_trng_irq(int irq, void *priv) -+{ -+ struct airoha_trng *trng = (struct airoha_trng *)priv; -+ -+ airoha_trng_irq_mask(trng); -+ /* Just complete the task, we will read the value later */ -+ complete(&trng->rng_op_done); -+ -+ return IRQ_HANDLED; -+} -+ -+static int airoha_trng_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct airoha_trng *trng; -+ int irq, ret; -+ u32 val; -+ -+ trng = devm_kzalloc(dev, sizeof(*trng), GFP_KERNEL); -+ if (!trng) -+ return -ENOMEM; -+ -+ trng->base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(trng->base)) -+ return PTR_ERR(trng->base); -+ -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) -+ return irq; -+ -+ airoha_trng_irq_mask(trng); -+ ret = devm_request_irq(&pdev->dev, irq, airoha_trng_irq, 0, -+ pdev->name, (void *)trng); -+ if (ret) { -+ dev_err(dev, "Can't get interrupt working.\n"); -+ return ret; -+ } -+ -+ init_completion(&trng->rng_op_done); -+ -+ /* Enable interrupt for SW reset Health Check */ -+ val = readl(trng->base + TRNG_INTR_EN); -+ val |= RST_STARTUP_INITR_EN; -+ writel(val, trng->base + TRNG_INTR_EN); -+ -+ /* Set output to raw data */ -+ val = readl(trng->base + TRNG_NS_SEK_AND_DAT_EN); -+ val |= RAW_DATA_EN; -+ writel(val, trng->base + TRNG_NS_SEK_AND_DAT_EN); -+ -+ /* Put it in SW Reset */ -+ writel(SW_RST, trng->base + TRNG_HEALTH_TEST_SW_RST); -+ -+ trng->dev = dev; -+ trng->rng.name = pdev->name; -+ trng->rng.init = airoha_trng_init; -+ trng->rng.cleanup = airoha_trng_cleanup; -+ trng->rng.read = airoha_trng_read; -+ -+ ret = devm_hwrng_register(dev, &trng->rng); -+ if (ret) { -+ dev_err(dev, "failed to register rng device: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static const struct of_device_id airoha_trng_of_match[] = { -+ { .compatible = "airoha,en7581-trng", }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, airoha_trng_of_match); -+ -+static struct platform_driver airoha_trng_driver = { -+ .driver = { -+ .name = "airoha-trng", -+ .of_match_table = airoha_trng_of_match, -+ }, -+ .probe = airoha_trng_probe, -+}; -+ -+module_platform_driver(airoha_trng_driver); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Christian Marangi "); -+MODULE_DESCRIPTION("Airoha True Random Number Generator driver");