From d9ea55a79c651cd168d600e119ba2ff5d2938ccc Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sun, 10 Jan 2021 11:43:21 +0100 Subject: [PATCH] Allwinner: linux: add CIR PM patches --- ...r-allow-timeout-to-be-set-at-runtime.patch | 104 ++++++++ ...r-Skip-register-writes-during-remove.patch | 43 ++++ ...unxi-cir-Remove-unnecessary-spinlock.patch | 74 ++++++ ...r-Factor-out-hardware-initialization.patch | 228 ++++++++++++++++++ ...Implement-suspend-resume-shutdown-ca.patch | 66 +++++ 5 files changed, 515 insertions(+) create mode 100644 projects/Allwinner/patches/linux/0008-media-sunxi-cir-allow-timeout-to-be-set-at-runtime.patch create mode 100644 projects/Allwinner/patches/linux/crust/0032-media-sunxi-cir-Skip-register-writes-during-remove.patch create mode 100644 projects/Allwinner/patches/linux/crust/0033-media-sunxi-cir-Remove-unnecessary-spinlock.patch create mode 100644 projects/Allwinner/patches/linux/crust/0034-media-sunxi-cir-Factor-out-hardware-initialization.patch create mode 100644 projects/Allwinner/patches/linux/crust/0035-media-sunxi-cir-Implement-suspend-resume-shutdown-ca.patch diff --git a/projects/Allwinner/patches/linux/0008-media-sunxi-cir-allow-timeout-to-be-set-at-runtime.patch b/projects/Allwinner/patches/linux/0008-media-sunxi-cir-allow-timeout-to-be-set-at-runtime.patch new file mode 100644 index 0000000000..c161c9a81c --- /dev/null +++ b/projects/Allwinner/patches/linux/0008-media-sunxi-cir-allow-timeout-to-be-set-at-runtime.patch @@ -0,0 +1,104 @@ +From 371443de3c991f7b025d5203754a3497b7ea7c32 Mon Sep 17 00:00:00 2001 +From: Sean Young +Date: Tue, 10 Nov 2020 09:30:38 +0100 +Subject: [PATCH] media: sunxi-cir: allow timeout to be set at runtime + +This allows the timeout to be set with the LIRC_SET_REC_TIMEOUT ioctl. + +The timeout was hardcoded at just over 20ms, but returned 120ms when +queried with the LIRC_GET_REC_TIMEOUT ioctl. + +This also ensures the idle threshold is set correctly with a base clock +other than 8Mhz. + +Acked-by: Maxime Ripard +Signed-off-by: Sean Young +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/rc/sunxi-cir.c | 48 ++++++++++++++++++++++++++++++------ + 1 file changed, 40 insertions(+), 8 deletions(-) + +diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c +index 4afc5895bee7..8555c7798706 100644 +--- a/drivers/media/rc/sunxi-cir.c ++++ b/drivers/media/rc/sunxi-cir.c +@@ -73,10 +73,6 @@ + #define SUNXI_IR_BASE_CLK 8000000 + /* Noise threshold in samples */ + #define SUNXI_IR_RXNOISE 1 +-/* Idle Threshold in samples */ +-#define SUNXI_IR_RXIDLE 20 +-/* Time after which device stops sending data in ms */ +-#define SUNXI_IR_TIMEOUT 120 + + /** + * struct sunxi_ir_quirks - Differences between SoC variants. +@@ -146,6 +142,41 @@ static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id) + return IRQ_HANDLED; + } + ++/* Convert idle threshold to usec */ ++static unsigned int sunxi_ithr_to_usec(unsigned int base_clk, unsigned int ithr) ++{ ++ return DIV_ROUND_CLOSEST(USEC_PER_SEC * (ithr + 1), ++ base_clk / (128 * 64)); ++} ++ ++/* Convert usec to idle threshold */ ++static unsigned int sunxi_usec_to_ithr(unsigned int base_clk, unsigned int usec) ++{ ++ /* make sure we don't end up with a timeout less than requested */ ++ return DIV_ROUND_UP((base_clk / (128 * 64)) * usec, USEC_PER_SEC) - 1; ++} ++ ++static int sunxi_ir_set_timeout(struct rc_dev *rc_dev, unsigned int timeout) ++{ ++ struct sunxi_ir *ir = rc_dev->priv; ++ unsigned int base_clk = clk_get_rate(ir->clk); ++ unsigned long flags; ++ ++ unsigned int ithr = sunxi_usec_to_ithr(base_clk, timeout); ++ ++ dev_dbg(rc_dev->dev.parent, "setting idle threshold to %u\n", ithr); ++ ++ spin_lock_irqsave(&ir->ir_lock, flags); ++ /* Set noise threshold and idle threshold */ ++ writel(REG_CIR_NTHR(SUNXI_IR_RXNOISE) | REG_CIR_ITHR(ithr), ++ ir->base + SUNXI_IR_CIR_REG); ++ spin_unlock_irqrestore(&ir->ir_lock, flags); ++ ++ rc_dev->timeout = sunxi_ithr_to_usec(base_clk, ithr); ++ ++ return 0; ++} ++ + static int sunxi_ir_probe(struct platform_device *pdev) + { + int ret = 0; +@@ -242,9 +273,11 @@ static int sunxi_ir_probe(struct platform_device *pdev) + ir->rc->map_name = ir->map_name ?: RC_MAP_EMPTY; + ir->rc->dev.parent = dev; + ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; +- /* Frequency after IR internal divider with sample period in ns */ ++ /* Frequency after IR internal divider with sample period in us */ + ir->rc->rx_resolution = (USEC_PER_SEC / (b_clk_freq / 64)); +- ir->rc->timeout = MS_TO_US(SUNXI_IR_TIMEOUT); ++ ir->rc->min_timeout = sunxi_ithr_to_usec(b_clk_freq, 0); ++ ir->rc->max_timeout = sunxi_ithr_to_usec(b_clk_freq, 255); ++ ir->rc->s_timeout = sunxi_ir_set_timeout; + ir->rc->driver_name = SUNXI_IR_DEV; + + ret = rc_register_device(ir->rc); +@@ -272,8 +305,7 @@ static int sunxi_ir_probe(struct platform_device *pdev) + writel(REG_CTL_MD, ir->base+SUNXI_IR_CTL_REG); + + /* Set noise threshold and idle threshold */ +- writel(REG_CIR_NTHR(SUNXI_IR_RXNOISE)|REG_CIR_ITHR(SUNXI_IR_RXIDLE), +- ir->base + SUNXI_IR_CIR_REG); ++ sunxi_ir_set_timeout(ir->rc, IR_DEFAULT_TIMEOUT); + + /* Invert Input Signal */ + writel(REG_RXCTL_RPPI, ir->base + SUNXI_IR_RXCTL_REG); +-- +2.30.0 + diff --git a/projects/Allwinner/patches/linux/crust/0032-media-sunxi-cir-Skip-register-writes-during-remove.patch b/projects/Allwinner/patches/linux/crust/0032-media-sunxi-cir-Skip-register-writes-during-remove.patch new file mode 100644 index 0000000000..a868045460 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0032-media-sunxi-cir-Skip-register-writes-during-remove.patch @@ -0,0 +1,43 @@ +From 0d476c62bcc132f66dc69342c2a90bba6d7128fe Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 10 Jan 2021 00:41:23 -0600 +Subject: [PATCH 1/4] media: sunxi-cir: Skip register writes during remove + +These writes occur after the device is already put back in reset, so +they never had any effect. + +Signed-off-by: Samuel Holland +--- + drivers/media/rc/sunxi-cir.c | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c +index 8555c7798706..0a7f7eab3cc3 100644 +--- a/drivers/media/rc/sunxi-cir.c ++++ b/drivers/media/rc/sunxi-cir.c +@@ -342,22 +342,12 @@ static int sunxi_ir_probe(struct platform_device *pdev) + + static int sunxi_ir_remove(struct platform_device *pdev) + { +- unsigned long flags; + struct sunxi_ir *ir = platform_get_drvdata(pdev); + + clk_disable_unprepare(ir->clk); + clk_disable_unprepare(ir->apb_clk); + reset_control_assert(ir->rst); + +- spin_lock_irqsave(&ir->ir_lock, flags); +- /* disable IR IRQ */ +- writel(0, ir->base + SUNXI_IR_RXINT_REG); +- /* clear All Rx Interrupt Status */ +- writel(REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG); +- /* disable IR */ +- writel(0, ir->base + SUNXI_IR_CTL_REG); +- spin_unlock_irqrestore(&ir->ir_lock, flags); +- + rc_unregister_device(ir->rc); + return 0; + } +-- +2.30.0 + diff --git a/projects/Allwinner/patches/linux/crust/0033-media-sunxi-cir-Remove-unnecessary-spinlock.patch b/projects/Allwinner/patches/linux/crust/0033-media-sunxi-cir-Remove-unnecessary-spinlock.patch new file mode 100644 index 0000000000..bf7513703a --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0033-media-sunxi-cir-Remove-unnecessary-spinlock.patch @@ -0,0 +1,74 @@ +From c7bc741a2aec36d9f87a99ef098db88825d5ef79 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 10 Jan 2021 00:43:19 -0600 +Subject: [PATCH 2/4] media: sunxi-cir: Remove unnecessary spinlock + +Only one register, SUNXI_IR_CIR_REG, is written from outside the +interrupt handler, and that register is not written from inside it. +There is no overlap between different contexts, so no lock is needed. + +Signed-off-by: Samuel Holland +--- + drivers/media/rc/sunxi-cir.c | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c +index 0a7f7eab3cc3..48be400421cd 100644 +--- a/drivers/media/rc/sunxi-cir.c ++++ b/drivers/media/rc/sunxi-cir.c +@@ -86,7 +86,6 @@ struct sunxi_ir_quirks { + }; + + struct sunxi_ir { +- spinlock_t ir_lock; + struct rc_dev *rc; + void __iomem *base; + int irq; +@@ -105,8 +104,6 @@ static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id) + struct sunxi_ir *ir = dev_id; + struct ir_raw_event rawir = {}; + +- spin_lock(&ir->ir_lock); +- + status = readl(ir->base + SUNXI_IR_RXSTA_REG); + + /* clean all pending statuses */ +@@ -137,8 +134,6 @@ static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id) + ir_raw_event_handle(ir->rc); + } + +- spin_unlock(&ir->ir_lock); +- + return IRQ_HANDLED; + } + +@@ -160,17 +155,14 @@ static int sunxi_ir_set_timeout(struct rc_dev *rc_dev, unsigned int timeout) + { + struct sunxi_ir *ir = rc_dev->priv; + unsigned int base_clk = clk_get_rate(ir->clk); +- unsigned long flags; + + unsigned int ithr = sunxi_usec_to_ithr(base_clk, timeout); + + dev_dbg(rc_dev->dev.parent, "setting idle threshold to %u\n", ithr); + +- spin_lock_irqsave(&ir->ir_lock, flags); + /* Set noise threshold and idle threshold */ + writel(REG_CIR_NTHR(SUNXI_IR_RXNOISE) | REG_CIR_ITHR(ithr), + ir->base + SUNXI_IR_CIR_REG); +- spin_unlock_irqrestore(&ir->ir_lock, flags); + + rc_dev->timeout = sunxi_ithr_to_usec(base_clk, ithr); + +@@ -199,8 +191,6 @@ static int sunxi_ir_probe(struct platform_device *pdev) + return -ENODEV; + } + +- spin_lock_init(&ir->ir_lock); +- + ir->fifo_size = quirks->fifo_size; + + /* Clock */ +-- +2.30.0 + diff --git a/projects/Allwinner/patches/linux/crust/0034-media-sunxi-cir-Factor-out-hardware-initialization.patch b/projects/Allwinner/patches/linux/crust/0034-media-sunxi-cir-Factor-out-hardware-initialization.patch new file mode 100644 index 0000000000..5241b44254 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0034-media-sunxi-cir-Factor-out-hardware-initialization.patch @@ -0,0 +1,228 @@ +From c0009aa415ef085c8f31ddd68b873f195a77f3c4 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 10 Jan 2021 00:50:32 -0600 +Subject: [PATCH 3/4] media: sunxi-cir: Factor out hardware initialization + +Signed-off-by: Samuel Holland +--- + drivers/media/rc/sunxi-cir.c | 142 ++++++++++++++++++++--------------- + 1 file changed, 82 insertions(+), 60 deletions(-) + +diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c +index 48be400421cd..1047654e601b 100644 +--- a/drivers/media/rc/sunxi-cir.c ++++ b/drivers/media/rc/sunxi-cir.c +@@ -90,6 +90,7 @@ struct sunxi_ir { + void __iomem *base; + int irq; + int fifo_size; ++ u32 base_clk_freq; + struct clk *clk; + struct clk *apb_clk; + struct reset_control *rst; +@@ -169,10 +170,81 @@ static int sunxi_ir_set_timeout(struct rc_dev *rc_dev, unsigned int timeout) + return 0; + } + ++static int sunxi_ir_hw_init(struct device *dev) ++{ ++ struct sunxi_ir *ir = dev_get_drvdata(dev); ++ unsigned long tmp; ++ int ret; ++ ++ ret = reset_control_deassert(ir->rst); ++ if (ret) ++ return ret; ++ ++ ret = clk_set_rate(ir->clk, ir->base_clk_freq); ++ if (ret) { ++ dev_err(dev, "set ir base clock failed!\n"); ++ goto exit_reset_assert; ++ } ++ dev_dbg(dev, "set base clock frequency to %d Hz.\n", ir->base_clk_freq); ++ ++ if (clk_prepare_enable(ir->apb_clk)) { ++ dev_err(dev, "try to enable apb_ir_clk failed\n"); ++ ret = -EINVAL; ++ goto exit_reset_assert; ++ } ++ ++ if (clk_prepare_enable(ir->clk)) { ++ dev_err(dev, "try to enable ir_clk failed\n"); ++ ret = -EINVAL; ++ goto exit_apb_clk_disable; ++ } ++ ++ /* Enable CIR Mode */ ++ writel(REG_CTL_MD, ir->base + SUNXI_IR_CTL_REG); ++ ++ /* Set noise threshold and idle threshold */ ++ sunxi_ir_set_timeout(ir->rc, ir->rc->timeout); ++ ++ /* Invert Input Signal */ ++ writel(REG_RXCTL_RPPI, ir->base + SUNXI_IR_RXCTL_REG); ++ ++ /* Clear All Rx Interrupt Status */ ++ writel(REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG); ++ ++ /* ++ * Enable IRQ on overflow, packet end, FIFO available with trigger ++ * level ++ */ ++ writel(REG_RXINT_ROI_EN | REG_RXINT_RPEI_EN | ++ REG_RXINT_RAI_EN | REG_RXINT_RAL(ir->fifo_size / 2 - 1), ++ ir->base + SUNXI_IR_RXINT_REG); ++ ++ /* Enable IR Module */ ++ tmp = readl(ir->base + SUNXI_IR_CTL_REG); ++ writel(tmp | REG_CTL_GEN | REG_CTL_RXEN, ir->base + SUNXI_IR_CTL_REG); ++ ++ return 0; ++ ++exit_apb_clk_disable: ++ clk_disable_unprepare(ir->apb_clk); ++exit_reset_assert: ++ reset_control_assert(ir->rst); ++ ++ return ret; ++} ++ ++static void sunxi_ir_hw_exit(struct device *dev) ++{ ++ struct sunxi_ir *ir = dev_get_drvdata(dev); ++ ++ clk_disable_unprepare(ir->clk); ++ clk_disable_unprepare(ir->apb_clk); ++ reset_control_assert(ir->rst); ++} ++ + static int sunxi_ir_probe(struct platform_device *pdev) + { + int ret = 0; +- unsigned long tmp = 0; + + struct device *dev = &pdev->dev; + struct device_node *dn = dev->of_node; +@@ -207,49 +279,26 @@ static int sunxi_ir_probe(struct platform_device *pdev) + + /* Base clock frequency (optional) */ + of_property_read_u32(dn, "clock-frequency", &b_clk_freq); ++ ir->base_clk_freq = b_clk_freq; + + /* Reset */ + if (quirks->has_reset) { + ir->rst = devm_reset_control_get_exclusive(dev, NULL); + if (IS_ERR(ir->rst)) + return PTR_ERR(ir->rst); +- ret = reset_control_deassert(ir->rst); +- if (ret) +- return ret; +- } +- +- ret = clk_set_rate(ir->clk, b_clk_freq); +- if (ret) { +- dev_err(dev, "set ir base clock failed!\n"); +- goto exit_reset_assert; +- } +- dev_dbg(dev, "set base clock frequency to %d Hz.\n", b_clk_freq); +- +- if (clk_prepare_enable(ir->apb_clk)) { +- dev_err(dev, "try to enable apb_ir_clk failed\n"); +- ret = -EINVAL; +- goto exit_reset_assert; +- } +- +- if (clk_prepare_enable(ir->clk)) { +- dev_err(dev, "try to enable ir_clk failed\n"); +- ret = -EINVAL; +- goto exit_clkdisable_apb_clk; + } + + /* IO */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ir->base = devm_ioremap_resource(dev, res); + if (IS_ERR(ir->base)) { +- ret = PTR_ERR(ir->base); +- goto exit_clkdisable_clk; ++ return PTR_ERR(ir->base); + } + + ir->rc = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!ir->rc) { + dev_err(dev, "failed to allocate device\n"); +- ret = -ENOMEM; +- goto exit_clkdisable_clk; ++ return -ENOMEM; + } + + ir->rc->priv = ir; +@@ -265,6 +314,7 @@ static int sunxi_ir_probe(struct platform_device *pdev) + ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; + /* Frequency after IR internal divider with sample period in us */ + ir->rc->rx_resolution = (USEC_PER_SEC / (b_clk_freq / 64)); ++ ir->rc->timeout = IR_DEFAULT_TIMEOUT; + ir->rc->min_timeout = sunxi_ithr_to_usec(b_clk_freq, 0); + ir->rc->max_timeout = sunxi_ithr_to_usec(b_clk_freq, 255); + ir->rc->s_timeout = sunxi_ir_set_timeout; +@@ -291,41 +341,15 @@ static int sunxi_ir_probe(struct platform_device *pdev) + goto exit_free_dev; + } + +- /* Enable CIR Mode */ +- writel(REG_CTL_MD, ir->base+SUNXI_IR_CTL_REG); +- +- /* Set noise threshold and idle threshold */ +- sunxi_ir_set_timeout(ir->rc, IR_DEFAULT_TIMEOUT); +- +- /* Invert Input Signal */ +- writel(REG_RXCTL_RPPI, ir->base + SUNXI_IR_RXCTL_REG); +- +- /* Clear All Rx Interrupt Status */ +- writel(REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG); +- +- /* +- * Enable IRQ on overflow, packet end, FIFO available with trigger +- * level +- */ +- writel(REG_RXINT_ROI_EN | REG_RXINT_RPEI_EN | +- REG_RXINT_RAI_EN | REG_RXINT_RAL(ir->fifo_size / 2 - 1), +- ir->base + SUNXI_IR_RXINT_REG); +- +- /* Enable IR Module */ +- tmp = readl(ir->base + SUNXI_IR_CTL_REG); +- writel(tmp | REG_CTL_GEN | REG_CTL_RXEN, ir->base + SUNXI_IR_CTL_REG); ++ ret = sunxi_ir_hw_init(dev); ++ if (ret) ++ goto exit_free_dev; + + dev_info(dev, "initialized sunXi IR driver\n"); + return 0; + + exit_free_dev: + rc_free_device(ir->rc); +-exit_clkdisable_clk: +- clk_disable_unprepare(ir->clk); +-exit_clkdisable_apb_clk: +- clk_disable_unprepare(ir->apb_clk); +-exit_reset_assert: +- reset_control_assert(ir->rst); + + return ret; + } +@@ -334,11 +358,9 @@ static int sunxi_ir_remove(struct platform_device *pdev) + { + struct sunxi_ir *ir = platform_get_drvdata(pdev); + +- clk_disable_unprepare(ir->clk); +- clk_disable_unprepare(ir->apb_clk); +- reset_control_assert(ir->rst); +- ++ sunxi_ir_hw_exit(&pdev->dev); + rc_unregister_device(ir->rc); ++ + return 0; + } + +-- +2.30.0 + diff --git a/projects/Allwinner/patches/linux/crust/0035-media-sunxi-cir-Implement-suspend-resume-shutdown-ca.patch b/projects/Allwinner/patches/linux/crust/0035-media-sunxi-cir-Implement-suspend-resume-shutdown-ca.patch new file mode 100644 index 0000000000..b747b772c7 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0035-media-sunxi-cir-Implement-suspend-resume-shutdown-ca.patch @@ -0,0 +1,66 @@ +From 2f76dd45fb1faf046aaaaddb6021312622002a3d Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 10 Jan 2021 00:51:31 -0600 +Subject: [PATCH 4/4] media: sunxi-cir: Implement suspend/resume/shutdown + callbacks + +Signed-off-by: Samuel Holland +--- + drivers/media/rc/sunxi-cir.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c +index 1047654e601b..4e025f3980f4 100644 +--- a/drivers/media/rc/sunxi-cir.c ++++ b/drivers/media/rc/sunxi-cir.c +@@ -242,6 +242,18 @@ static void sunxi_ir_hw_exit(struct device *dev) + reset_control_assert(ir->rst); + } + ++static int __maybe_unused sunxi_ir_suspend(struct device *dev) ++{ ++ sunxi_ir_hw_exit(dev); ++ ++ return 0; ++} ++ ++static int __maybe_unused sunxi_ir_resume(struct device *dev) ++{ ++ return sunxi_ir_hw_init(dev); ++} ++ + static int sunxi_ir_probe(struct platform_device *pdev) + { + int ret = 0; +@@ -364,6 +376,11 @@ static int sunxi_ir_remove(struct platform_device *pdev) + return 0; + } + ++static void sunxi_ir_shutdown(struct platform_device *pdev) ++{ ++ sunxi_ir_hw_exit(&pdev->dev); ++} ++ + static const struct sunxi_ir_quirks sun4i_a10_ir_quirks = { + .has_reset = false, + .fifo_size = 16, +@@ -396,12 +413,16 @@ static const struct of_device_id sunxi_ir_match[] = { + }; + MODULE_DEVICE_TABLE(of, sunxi_ir_match); + ++static SIMPLE_DEV_PM_OPS(sunxi_ir_pm_ops, sunxi_ir_suspend, sunxi_ir_resume); ++ + static struct platform_driver sunxi_ir_driver = { + .probe = sunxi_ir_probe, + .remove = sunxi_ir_remove, ++ .shutdown = sunxi_ir_shutdown, + .driver = { + .name = SUNXI_IR_DEV, + .of_match_table = sunxi_ir_match, ++ .pm = &sunxi_ir_pm_ops, + }, + }; + +-- +2.30.0 +