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