root/drivers/media/rc/sunxi-cir.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sunxi_ir_irq
  2. sunxi_ir_probe
  3. sunxi_ir_remove

   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");

/* [<][>][^][v][top][bottom][index][help] */