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 dev_err(dev, "irq can not get\n"); 237 return priv->irq; 238 } 239 240 rdev = rc_allocate_device(RC_DRIVER_IR_RAW); 241 if (!rdev) 242 return -ENOMEM; 243 244 priv->clock = devm_clk_get(dev, NULL); 245 if (IS_ERR(priv->clock)) { 246 dev_err(dev, "clock not found\n"); 247 ret = PTR_ERR(priv->clock); 248 goto err; 249 } 250 ret = clk_prepare_enable(priv->clock); 251 if (ret) 252 goto err; 253 priv->rate = clk_get_rate(priv->clock); 254 255 rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; 256 rdev->priv = priv; 257 rdev->open = hix5hd2_ir_open; 258 rdev->close = hix5hd2_ir_close; 259 rdev->driver_name = IR_HIX5HD2_NAME; 260 map_name = of_get_property(node, "linux,rc-map-name", NULL); 261 rdev->map_name = map_name ?: RC_MAP_EMPTY; 262 rdev->device_name = IR_HIX5HD2_NAME; 263 rdev->input_phys = IR_HIX5HD2_NAME "/input0"; 264 rdev->input_id.bustype = BUS_HOST; 265 rdev->input_id.vendor = 0x0001; 266 rdev->input_id.product = 0x0001; 267 rdev->input_id.version = 0x0100; 268 rdev->rx_resolution = US_TO_NS(10); 269 rdev->timeout = US_TO_NS(IR_CFG_SYMBOL_MAXWIDTH * 10); 270 271 ret = rc_register_device(rdev); 272 if (ret < 0) 273 goto clkerr; 274 275 if (devm_request_irq(dev, priv->irq, hix5hd2_ir_rx_interrupt, 276 0, pdev->name, priv) < 0) { 277 dev_err(dev, "IRQ %d register failed\n", priv->irq); 278 ret = -EINVAL; 279 goto regerr; 280 } 281 282 priv->rdev = rdev; 283 priv->dev = dev; 284 platform_set_drvdata(pdev, priv); 285 286 return ret; 287 288 regerr: 289 rc_unregister_device(rdev); 290 rdev = NULL; 291 clkerr: 292 clk_disable_unprepare(priv->clock); 293 err: 294 rc_free_device(rdev); 295 dev_err(dev, "Unable to register device (%d)\n", ret); 296 return ret; 297 } 298 299 static int hix5hd2_ir_remove(struct platform_device *pdev) 300 { 301 struct hix5hd2_ir_priv *priv = platform_get_drvdata(pdev); 302 303 clk_disable_unprepare(priv->clock); 304 rc_unregister_device(priv->rdev); 305 return 0; 306 } 307 308 #ifdef CONFIG_PM_SLEEP 309 static int hix5hd2_ir_suspend(struct device *dev) 310 { 311 struct hix5hd2_ir_priv *priv = dev_get_drvdata(dev); 312 313 clk_disable_unprepare(priv->clock); 314 hix5hd2_ir_enable(priv, false); 315 316 return 0; 317 } 318 319 static int hix5hd2_ir_resume(struct device *dev) 320 { 321 struct hix5hd2_ir_priv *priv = dev_get_drvdata(dev); 322 int ret; 323 324 ret = hix5hd2_ir_enable(priv, true); 325 if (ret) 326 return ret; 327 328 ret = clk_prepare_enable(priv->clock); 329 if (ret) { 330 hix5hd2_ir_enable(priv, false); 331 return ret; 332 } 333 334 writel_relaxed(0x01, priv->base + IR_ENABLE); 335 writel_relaxed(0x00, priv->base + IR_INTM); 336 writel_relaxed(0xff, priv->base + IR_INTC); 337 writel_relaxed(0x01, priv->base + IR_START); 338 339 return 0; 340 } 341 #endif 342 343 static SIMPLE_DEV_PM_OPS(hix5hd2_ir_pm_ops, hix5hd2_ir_suspend, 344 hix5hd2_ir_resume); 345 346 static const struct of_device_id hix5hd2_ir_table[] = { 347 { .compatible = "hisilicon,hix5hd2-ir", }, 348 {}, 349 }; 350 MODULE_DEVICE_TABLE(of, hix5hd2_ir_table); 351 352 static struct platform_driver hix5hd2_ir_driver = { 353 .driver = { 354 .name = IR_HIX5HD2_NAME, 355 .of_match_table = hix5hd2_ir_table, 356 .pm = &hix5hd2_ir_pm_ops, 357 }, 358 .probe = hix5hd2_ir_probe, 359 .remove = hix5hd2_ir_remove, 360 }; 361 362 module_platform_driver(hix5hd2_ir_driver); 363 364 MODULE_DESCRIPTION("IR controller driver for hix5hd2 platforms"); 365 MODULE_AUTHOR("Guoxiong Yan <yanguoxiong@huawei.com>"); 366 MODULE_LICENSE("GPL v2"); 367 MODULE_ALIAS("platform:hix5hd2-ir"); 368