root/drivers/media/rc/ir-hix5hd2.c

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

DEFINITIONS

This source file includes following definitions.
  1. hix5hd2_ir_enable
  2. hix5hd2_ir_config
  3. hix5hd2_ir_open
  4. hix5hd2_ir_close
  5. hix5hd2_ir_rx_interrupt
  6. hix5hd2_ir_probe
  7. hix5hd2_ir_remove
  8. hix5hd2_ir_suspend
  9. hix5hd2_ir_resume

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (c) 2014 Linaro Ltd.
   4  * Copyright (c) 2014 Hisilicon Limited.
   5  */
   6 
   7 #include <linux/clk.h>
   8 #include <linux/delay.h>
   9 #include <linux/interrupt.h>
  10 #include <linux/mfd/syscon.h>
  11 #include <linux/module.h>
  12 #include <linux/of_device.h>
  13 #include <linux/regmap.h>
  14 #include <media/rc-core.h>
  15 
  16 #define IR_ENABLE               0x00
  17 #define IR_CONFIG               0x04
  18 #define CNT_LEADS               0x08
  19 #define CNT_LEADE               0x0c
  20 #define CNT_SLEADE              0x10
  21 #define CNT0_B                  0x14
  22 #define CNT1_B                  0x18
  23 #define IR_BUSY                 0x1c
  24 #define IR_DATAH                0x20
  25 #define IR_DATAL                0x24
  26 #define IR_INTM                 0x28
  27 #define IR_INTS                 0x2c
  28 #define IR_INTC                 0x30
  29 #define IR_START                0x34
  30 
  31 /* interrupt mask */
  32 #define INTMS_SYMBRCV           (BIT(24) | BIT(8))
  33 #define INTMS_TIMEOUT           (BIT(25) | BIT(9))
  34 #define INTMS_OVERFLOW          (BIT(26) | BIT(10))
  35 #define INT_CLR_OVERFLOW        BIT(18)
  36 #define INT_CLR_TIMEOUT         BIT(17)
  37 #define INT_CLR_RCV             BIT(16)
  38 #define INT_CLR_RCVTIMEOUT      (BIT(16) | BIT(17))
  39 
  40 #define IR_CLK                  0x48
  41 #define IR_CLK_ENABLE           BIT(4)
  42 #define IR_CLK_RESET            BIT(5)
  43 
  44 #define IR_CFG_WIDTH_MASK       0xffff
  45 #define IR_CFG_WIDTH_SHIFT      16
  46 #define IR_CFG_FORMAT_MASK      0x3
  47 #define IR_CFG_FORMAT_SHIFT     14
  48 #define IR_CFG_INT_LEVEL_MASK   0x3f
  49 #define IR_CFG_INT_LEVEL_SHIFT  8
  50 /* only support raw mode */
  51 #define IR_CFG_MODE_RAW         BIT(7)
  52 #define IR_CFG_FREQ_MASK        0x7f
  53 #define IR_CFG_FREQ_SHIFT       0
  54 #define IR_CFG_INT_THRESHOLD    1
  55 /* symbol start from low to high, symbol stream end at high*/
  56 #define IR_CFG_SYMBOL_FMT       0
  57 #define IR_CFG_SYMBOL_MAXWIDTH  0x3e80
  58 
  59 #define IR_HIX5HD2_NAME         "hix5hd2-ir"
  60 
  61 struct hix5hd2_ir_priv {
  62         int                     irq;
  63         void __iomem            *base;
  64         struct device           *dev;
  65         struct rc_dev           *rdev;
  66         struct regmap           *regmap;
  67         struct clk              *clock;
  68         unsigned long           rate;
  69 };
  70 
  71 static int hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on)
  72 {
  73         u32 val;
  74         int ret = 0;
  75 
  76         if (dev->regmap) {
  77                 regmap_read(dev->regmap, IR_CLK, &val);
  78                 if (on) {
  79                         val &= ~IR_CLK_RESET;
  80                         val |= IR_CLK_ENABLE;
  81                 } else {
  82                         val &= ~IR_CLK_ENABLE;
  83                         val |= IR_CLK_RESET;
  84                 }
  85                 regmap_write(dev->regmap, IR_CLK, val);
  86         } else {
  87                 if (on)
  88                         ret = clk_prepare_enable(dev->clock);
  89                 else
  90                         clk_disable_unprepare(dev->clock);
  91         }
  92         return ret;
  93 }
  94 
  95 static int hix5hd2_ir_config(struct hix5hd2_ir_priv *priv)
  96 {
  97         int timeout = 10000;
  98         u32 val, rate;
  99 
 100         writel_relaxed(0x01, priv->base + IR_ENABLE);
 101         while (readl_relaxed(priv->base + IR_BUSY)) {
 102                 if (timeout--) {
 103                         udelay(1);
 104                 } else {
 105                         dev_err(priv->dev, "IR_BUSY timeout\n");
 106                         return -ETIMEDOUT;
 107                 }
 108         }
 109 
 110         /* Now only support raw mode, with symbol start from low to high */
 111         rate = DIV_ROUND_CLOSEST(priv->rate, 1000000);
 112         val = IR_CFG_SYMBOL_MAXWIDTH & IR_CFG_WIDTH_MASK << IR_CFG_WIDTH_SHIFT;
 113         val |= IR_CFG_SYMBOL_FMT & IR_CFG_FORMAT_MASK << IR_CFG_FORMAT_SHIFT;
 114         val |= (IR_CFG_INT_THRESHOLD - 1) & IR_CFG_INT_LEVEL_MASK
 115                << IR_CFG_INT_LEVEL_SHIFT;
 116         val |= IR_CFG_MODE_RAW;
 117         val |= (rate - 1) & IR_CFG_FREQ_MASK << IR_CFG_FREQ_SHIFT;
 118         writel_relaxed(val, priv->base + IR_CONFIG);
 119 
 120         writel_relaxed(0x00, priv->base + IR_INTM);
 121         /* write arbitrary value to start  */
 122         writel_relaxed(0x01, priv->base + IR_START);
 123         return 0;
 124 }
 125 
 126 static int hix5hd2_ir_open(struct rc_dev *rdev)
 127 {
 128         struct hix5hd2_ir_priv *priv = rdev->priv;
 129         int ret;
 130 
 131         ret = hix5hd2_ir_enable(priv, true);
 132         if (ret)
 133                 return ret;
 134 
 135         ret = hix5hd2_ir_config(priv);
 136         if (ret) {
 137                 hix5hd2_ir_enable(priv, false);
 138                 return ret;
 139         }
 140         return 0;
 141 }
 142 
 143 static void hix5hd2_ir_close(struct rc_dev *rdev)
 144 {
 145         struct hix5hd2_ir_priv *priv = rdev->priv;
 146 
 147         hix5hd2_ir_enable(priv, false);
 148 }
 149 
 150 static irqreturn_t hix5hd2_ir_rx_interrupt(int irq, void *data)
 151 {
 152         u32 symb_num, symb_val, symb_time;
 153         u32 data_l, data_h;
 154         u32 irq_sr, i;
 155         struct hix5hd2_ir_priv *priv = data;
 156 
 157         irq_sr = readl_relaxed(priv->base + IR_INTS);
 158         if (irq_sr & INTMS_OVERFLOW) {
 159                 /*
 160                  * we must read IR_DATAL first, then we can clean up
 161                  * IR_INTS availably since logic would not clear
 162                  * fifo when overflow, drv do the job
 163                  */
 164                 ir_raw_event_reset(priv->rdev);
 165                 symb_num = readl_relaxed(priv->base + IR_DATAH);
 166                 for (i = 0; i < symb_num; i++)
 167                         readl_relaxed(priv->base + IR_DATAL);
 168 
 169                 writel_relaxed(INT_CLR_OVERFLOW, priv->base + IR_INTC);
 170                 dev_info(priv->dev, "overflow, level=%d\n",
 171                          IR_CFG_INT_THRESHOLD);
 172         }
 173 
 174         if ((irq_sr & INTMS_SYMBRCV) || (irq_sr & INTMS_TIMEOUT)) {
 175                 struct ir_raw_event ev = {};
 176 
 177                 symb_num = readl_relaxed(priv->base + IR_DATAH);
 178                 for (i = 0; i < symb_num; i++) {
 179                         symb_val = readl_relaxed(priv->base + IR_DATAL);
 180                         data_l = ((symb_val & 0xffff) * 10);
 181                         data_h =  ((symb_val >> 16) & 0xffff) * 10;
 182                         symb_time = (data_l + data_h) / 10;
 183 
 184                         ev.duration = US_TO_NS(data_l);
 185                         ev.pulse = true;
 186                         ir_raw_event_store(priv->rdev, &ev);
 187 
 188                         if (symb_time < IR_CFG_SYMBOL_MAXWIDTH) {
 189                                 ev.duration = US_TO_NS(data_h);
 190                                 ev.pulse = false;
 191                                 ir_raw_event_store(priv->rdev, &ev);
 192                         } else {
 193                                 ir_raw_event_set_idle(priv->rdev, true);
 194                         }
 195                 }
 196 
 197                 if (irq_sr & INTMS_SYMBRCV)
 198                         writel_relaxed(INT_CLR_RCV, priv->base + IR_INTC);
 199                 if (irq_sr & INTMS_TIMEOUT)
 200                         writel_relaxed(INT_CLR_TIMEOUT, priv->base + IR_INTC);
 201         }
 202 
 203         /* Empty software fifo */
 204         ir_raw_event_handle(priv->rdev);
 205         return IRQ_HANDLED;
 206 }
 207 
 208 static int hix5hd2_ir_probe(struct platform_device *pdev)
 209 {
 210         struct rc_dev *rdev;
 211         struct device *dev = &pdev->dev;
 212         struct resource *res;
 213         struct hix5hd2_ir_priv *priv;
 214         struct device_node *node = pdev->dev.of_node;
 215         const char *map_name;
 216         int ret;
 217 
 218         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 219         if (!priv)
 220                 return -ENOMEM;
 221 
 222         priv->regmap = syscon_regmap_lookup_by_phandle(node,
 223                                                        "hisilicon,power-syscon");
 224         if (IS_ERR(priv->regmap)) {
 225                 dev_info(dev, "no power-reg\n");
 226                 priv->regmap = NULL;
 227         }
 228 
 229         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 230         priv->base = devm_ioremap_resource(dev, res);
 231         if (IS_ERR(priv->base))
 232                 return PTR_ERR(priv->base);
 233 
 234         priv->irq = platform_get_irq(pdev, 0);
 235         if (priv->irq < 0)
 236                 return priv->irq;
 237 
 238         rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
 239         if (!rdev)
 240                 return -ENOMEM;
 241 
 242         priv->clock = devm_clk_get(dev, NULL);
 243         if (IS_ERR(priv->clock)) {
 244                 dev_err(dev, "clock not found\n");
 245                 ret = PTR_ERR(priv->clock);
 246                 goto err;
 247         }
 248         ret = clk_prepare_enable(priv->clock);
 249         if (ret)
 250                 goto err;
 251         priv->rate = clk_get_rate(priv->clock);
 252 
 253         rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
 254         rdev->priv = priv;
 255         rdev->open = hix5hd2_ir_open;
 256         rdev->close = hix5hd2_ir_close;
 257         rdev->driver_name = IR_HIX5HD2_NAME;
 258         map_name = of_get_property(node, "linux,rc-map-name", NULL);
 259         rdev->map_name = map_name ?: RC_MAP_EMPTY;
 260         rdev->device_name = IR_HIX5HD2_NAME;
 261         rdev->input_phys = IR_HIX5HD2_NAME "/input0";
 262         rdev->input_id.bustype = BUS_HOST;
 263         rdev->input_id.vendor = 0x0001;
 264         rdev->input_id.product = 0x0001;
 265         rdev->input_id.version = 0x0100;
 266         rdev->rx_resolution = US_TO_NS(10);
 267         rdev->timeout = US_TO_NS(IR_CFG_SYMBOL_MAXWIDTH * 10);
 268 
 269         ret = rc_register_device(rdev);
 270         if (ret < 0)
 271                 goto clkerr;
 272 
 273         if (devm_request_irq(dev, priv->irq, hix5hd2_ir_rx_interrupt,
 274                              0, pdev->name, priv) < 0) {
 275                 dev_err(dev, "IRQ %d register failed\n", priv->irq);
 276                 ret = -EINVAL;
 277                 goto regerr;
 278         }
 279 
 280         priv->rdev = rdev;
 281         priv->dev = dev;
 282         platform_set_drvdata(pdev, priv);
 283 
 284         return ret;
 285 
 286 regerr:
 287         rc_unregister_device(rdev);
 288         rdev = NULL;
 289 clkerr:
 290         clk_disable_unprepare(priv->clock);
 291 err:
 292         rc_free_device(rdev);
 293         dev_err(dev, "Unable to register device (%d)\n", ret);
 294         return ret;
 295 }
 296 
 297 static int hix5hd2_ir_remove(struct platform_device *pdev)
 298 {
 299         struct hix5hd2_ir_priv *priv = platform_get_drvdata(pdev);
 300 
 301         clk_disable_unprepare(priv->clock);
 302         rc_unregister_device(priv->rdev);
 303         return 0;
 304 }
 305 
 306 #ifdef CONFIG_PM_SLEEP
 307 static int hix5hd2_ir_suspend(struct device *dev)
 308 {
 309         struct hix5hd2_ir_priv *priv = dev_get_drvdata(dev);
 310 
 311         clk_disable_unprepare(priv->clock);
 312         hix5hd2_ir_enable(priv, false);
 313 
 314         return 0;
 315 }
 316 
 317 static int hix5hd2_ir_resume(struct device *dev)
 318 {
 319         struct hix5hd2_ir_priv *priv = dev_get_drvdata(dev);
 320         int ret;
 321 
 322         ret = hix5hd2_ir_enable(priv, true);
 323         if (ret)
 324                 return ret;
 325 
 326         ret = clk_prepare_enable(priv->clock);
 327         if (ret) {
 328                 hix5hd2_ir_enable(priv, false);
 329                 return ret;
 330         }
 331 
 332         writel_relaxed(0x01, priv->base + IR_ENABLE);
 333         writel_relaxed(0x00, priv->base + IR_INTM);
 334         writel_relaxed(0xff, priv->base + IR_INTC);
 335         writel_relaxed(0x01, priv->base + IR_START);
 336 
 337         return 0;
 338 }
 339 #endif
 340 
 341 static SIMPLE_DEV_PM_OPS(hix5hd2_ir_pm_ops, hix5hd2_ir_suspend,
 342                          hix5hd2_ir_resume);
 343 
 344 static const struct of_device_id hix5hd2_ir_table[] = {
 345         { .compatible = "hisilicon,hix5hd2-ir", },
 346         {},
 347 };
 348 MODULE_DEVICE_TABLE(of, hix5hd2_ir_table);
 349 
 350 static struct platform_driver hix5hd2_ir_driver = {
 351         .driver = {
 352                 .name = IR_HIX5HD2_NAME,
 353                 .of_match_table = hix5hd2_ir_table,
 354                 .pm     = &hix5hd2_ir_pm_ops,
 355         },
 356         .probe = hix5hd2_ir_probe,
 357         .remove = hix5hd2_ir_remove,
 358 };
 359 
 360 module_platform_driver(hix5hd2_ir_driver);
 361 
 362 MODULE_DESCRIPTION("IR controller driver for hix5hd2 platforms");
 363 MODULE_AUTHOR("Guoxiong Yan <yanguoxiong@huawei.com>");
 364 MODULE_LICENSE("GPL v2");
 365 MODULE_ALIAS("platform:hix5hd2-ir");

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