^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Driver for Allwinner sunXi IR controller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2014 Alexsey Shestacov <wingrime@linux-sunxi.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2014 Alexander Bersenev <bay@hackerdom.ru>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Based on sun5i-ir.c:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Copyright (C) 2007-2012 Daniel Wang
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/reset.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <media/rc-core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define SUNXI_IR_DEV "sunxi-ir"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) /* Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) /* IR Control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define SUNXI_IR_CTL_REG 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) /* Global Enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define REG_CTL_GEN BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) /* RX block enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define REG_CTL_RXEN BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) /* CIR mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define REG_CTL_MD (BIT(4) | BIT(5))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) /* Rx Config */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define SUNXI_IR_RXCTL_REG 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) /* Pulse Polarity Invert flag */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define REG_RXCTL_RPPI BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /* Rx Data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define SUNXI_IR_RXFIFO_REG 0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) /* Rx Interrupt Enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define SUNXI_IR_RXINT_REG 0x2C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) /* Rx FIFO Overflow Interrupt Enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define REG_RXINT_ROI_EN BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /* Rx Packet End Interrupt Enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define REG_RXINT_RPEI_EN BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /* Rx FIFO Data Available Interrupt Enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define REG_RXINT_RAI_EN BIT(4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) /* Rx FIFO available byte level */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define REG_RXINT_RAL(val) ((val) << 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /* Rx Interrupt Status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define SUNXI_IR_RXSTA_REG 0x30
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /* Rx FIFO Overflow */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define REG_RXSTA_ROI REG_RXINT_ROI_EN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) /* Rx Packet End */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define REG_RXSTA_RPE REG_RXINT_RPEI_EN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /* Rx FIFO Data Available */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define REG_RXSTA_RA REG_RXINT_RAI_EN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) /* RX FIFO Get Available Counter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define REG_RXSTA_GET_AC(val) (((val) >> 8) & (ir->fifo_size * 2 - 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /* Clear all interrupt status value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define REG_RXSTA_CLEARALL 0xff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /* IR Sample Config */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define SUNXI_IR_CIR_REG 0x34
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) /* CIR_REG register noise threshold */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define REG_CIR_NTHR(val) (((val) << 2) & (GENMASK(7, 2)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /* CIR_REG register idle threshold */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define REG_CIR_ITHR(val) (((val) << 8) & (GENMASK(15, 8)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) /* Required frequency for IR0 or IR1 clock in CIR mode (default) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define SUNXI_IR_BASE_CLK 8000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) /* Noise threshold in samples */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) #define SUNXI_IR_RXNOISE 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) /* Idle Threshold in samples */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #define SUNXI_IR_RXIDLE 20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /* Time after which device stops sending data in ms */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #define SUNXI_IR_TIMEOUT 120
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * struct sunxi_ir_quirks - Differences between SoC variants.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * @has_reset: SoC needs reset deasserted.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * @fifo_size: size of the fifo.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct sunxi_ir_quirks {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) bool has_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) int fifo_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct sunxi_ir {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) spinlock_t ir_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct rc_dev *rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) int fifo_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) struct clk *apb_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) struct reset_control *rst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) const char *map_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) unsigned long status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) unsigned char dt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) unsigned int cnt, rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) struct sunxi_ir *ir = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct ir_raw_event rawir = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) spin_lock(&ir->ir_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) status = readl(ir->base + SUNXI_IR_RXSTA_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* clean all pending statuses */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) writel(status | REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (status & (REG_RXSTA_RA | REG_RXSTA_RPE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /* How many messages in fifo */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) rc = REG_RXSTA_GET_AC(status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) /* Sanity check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) rc = rc > ir->fifo_size ? ir->fifo_size : rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) /* If we have data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) for (cnt = 0; cnt < rc; cnt++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) /* for each bit in fifo */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) dt = readb(ir->base + SUNXI_IR_RXFIFO_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) rawir.pulse = (dt & 0x80) != 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) rawir.duration = ((dt & 0x7f) + 1) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) ir->rc->rx_resolution;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) ir_raw_event_store_with_filter(ir->rc, &rawir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (status & REG_RXSTA_ROI) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) ir_raw_event_reset(ir->rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) } else if (status & REG_RXSTA_RPE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) ir_raw_event_set_idle(ir->rc, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) ir_raw_event_handle(ir->rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) ir_raw_event_handle(ir->rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) spin_unlock(&ir->ir_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) static int sunxi_ir_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) unsigned long tmp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) struct device_node *dn = dev->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) const struct sunxi_ir_quirks *quirks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) struct sunxi_ir *ir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) u32 b_clk_freq = SUNXI_IR_BASE_CLK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) ir = devm_kzalloc(dev, sizeof(struct sunxi_ir), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) if (!ir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) quirks = of_device_get_match_data(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (!quirks) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) spin_lock_init(&ir->ir_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) ir->fifo_size = quirks->fifo_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) /* Clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) ir->apb_clk = devm_clk_get(dev, "apb");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (IS_ERR(ir->apb_clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) dev_err(dev, "failed to get a apb clock.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return PTR_ERR(ir->apb_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) ir->clk = devm_clk_get(dev, "ir");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) if (IS_ERR(ir->clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) dev_err(dev, "failed to get a ir clock.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) return PTR_ERR(ir->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) /* Base clock frequency (optional) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) of_property_read_u32(dn, "clock-frequency", &b_clk_freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) /* Reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (quirks->has_reset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) ir->rst = devm_reset_control_get_exclusive(dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) if (IS_ERR(ir->rst))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return PTR_ERR(ir->rst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) ret = reset_control_deassert(ir->rst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) ret = clk_set_rate(ir->clk, b_clk_freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) dev_err(dev, "set ir base clock failed!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) goto exit_reset_assert;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) dev_dbg(dev, "set base clock frequency to %d Hz.\n", b_clk_freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (clk_prepare_enable(ir->apb_clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) dev_err(dev, "try to enable apb_ir_clk failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) goto exit_reset_assert;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (clk_prepare_enable(ir->clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) dev_err(dev, "try to enable ir_clk failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) goto exit_clkdisable_apb_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) /* IO */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) ir->base = devm_ioremap_resource(dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) if (IS_ERR(ir->base)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) ret = PTR_ERR(ir->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) goto exit_clkdisable_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) ir->rc = rc_allocate_device(RC_DRIVER_IR_RAW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (!ir->rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) dev_err(dev, "failed to allocate device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) goto exit_clkdisable_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) ir->rc->priv = ir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) ir->rc->device_name = SUNXI_IR_DEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) ir->rc->input_phys = "sunxi-ir/input0";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) ir->rc->input_id.bustype = BUS_HOST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) ir->rc->input_id.vendor = 0x0001;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) ir->rc->input_id.product = 0x0001;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) ir->rc->input_id.version = 0x0100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) ir->map_name = of_get_property(dn, "linux,rc-map-name", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) ir->rc->map_name = ir->map_name ?: RC_MAP_EMPTY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) ir->rc->dev.parent = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) /* Frequency after IR internal divider with sample period in ns */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) ir->rc->rx_resolution = (USEC_PER_SEC / (b_clk_freq / 64));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) ir->rc->timeout = MS_TO_US(SUNXI_IR_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) ir->rc->driver_name = SUNXI_IR_DEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) ret = rc_register_device(ir->rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) dev_err(dev, "failed to register rc device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) goto exit_free_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) platform_set_drvdata(pdev, ir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) /* IRQ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) ir->irq = platform_get_irq(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (ir->irq < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) ret = ir->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) goto exit_free_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) ret = devm_request_irq(dev, ir->irq, sunxi_ir_irq, 0, SUNXI_IR_DEV, ir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) dev_err(dev, "failed request irq\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) goto exit_free_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) /* Enable CIR Mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) writel(REG_CTL_MD, ir->base+SUNXI_IR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) /* Set noise threshold and idle threshold */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) writel(REG_CIR_NTHR(SUNXI_IR_RXNOISE)|REG_CIR_ITHR(SUNXI_IR_RXIDLE),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) ir->base + SUNXI_IR_CIR_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) /* Invert Input Signal */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) writel(REG_RXCTL_RPPI, ir->base + SUNXI_IR_RXCTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) /* Clear All Rx Interrupt Status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) writel(REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) * Enable IRQ on overflow, packet end, FIFO available with trigger
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) * level
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) writel(REG_RXINT_ROI_EN | REG_RXINT_RPEI_EN |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) REG_RXINT_RAI_EN | REG_RXINT_RAL(ir->fifo_size / 2 - 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) ir->base + SUNXI_IR_RXINT_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) /* Enable IR Module */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) tmp = readl(ir->base + SUNXI_IR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) writel(tmp | REG_CTL_GEN | REG_CTL_RXEN, ir->base + SUNXI_IR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) dev_info(dev, "initialized sunXi IR driver\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) exit_free_dev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) rc_free_device(ir->rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) exit_clkdisable_clk:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) clk_disable_unprepare(ir->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) exit_clkdisable_apb_clk:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) clk_disable_unprepare(ir->apb_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) exit_reset_assert:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) reset_control_assert(ir->rst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) static int sunxi_ir_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) struct sunxi_ir *ir = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) clk_disable_unprepare(ir->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) clk_disable_unprepare(ir->apb_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) reset_control_assert(ir->rst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) spin_lock_irqsave(&ir->ir_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) /* disable IR IRQ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) writel(0, ir->base + SUNXI_IR_RXINT_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) /* clear All Rx Interrupt Status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) writel(REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) /* disable IR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) writel(0, ir->base + SUNXI_IR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) spin_unlock_irqrestore(&ir->ir_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) rc_unregister_device(ir->rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) static const struct sunxi_ir_quirks sun4i_a10_ir_quirks = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) .has_reset = false,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) .fifo_size = 16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) static const struct sunxi_ir_quirks sun5i_a13_ir_quirks = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) .has_reset = false,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) .fifo_size = 64,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) static const struct sunxi_ir_quirks sun6i_a31_ir_quirks = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) .has_reset = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) .fifo_size = 64,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) static const struct of_device_id sunxi_ir_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) .compatible = "allwinner,sun4i-a10-ir",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) .data = &sun4i_a10_ir_quirks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) .compatible = "allwinner,sun5i-a13-ir",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) .data = &sun5i_a13_ir_quirks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) .compatible = "allwinner,sun6i-a31-ir",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) .data = &sun6i_a31_ir_quirks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) MODULE_DEVICE_TABLE(of, sunxi_ir_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) static struct platform_driver sunxi_ir_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) .probe = sunxi_ir_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) .remove = sunxi_ir_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) .name = SUNXI_IR_DEV,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) .of_match_table = sunxi_ir_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) module_platform_driver(sunxi_ir_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) MODULE_DESCRIPTION("Allwinner sunXi IR controller driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) MODULE_AUTHOR("Alexsey Shestacov <wingrime@linux-sunxi.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) MODULE_LICENSE("GPL");