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