1bdbf80c8SZhangbin Tong /* 2bdbf80c8SZhangbin Tong * (C) Copyright 2017 Rockchip Electronics Co., Ltd 3bdbf80c8SZhangbin Tong * 4bdbf80c8SZhangbin Tong * SPDX-License-Identifier: GPL-2.0+ 5bdbf80c8SZhangbin Tong */ 6bdbf80c8SZhangbin Tong 7bdbf80c8SZhangbin Tong #include <common.h> 8*f21c060eSLei Chen #include <clk.h> 9bdbf80c8SZhangbin Tong #include <dm.h> 10bdbf80c8SZhangbin Tong #include <dm/pinctrl.h> 11bdbf80c8SZhangbin Tong #include <errno.h> 12bdbf80c8SZhangbin Tong #include <rc.h> 13bdbf80c8SZhangbin Tong #include <rockchip_ir.h> 14bdbf80c8SZhangbin Tong #include <irq-generic.h> 15bdbf80c8SZhangbin Tong #include <irq-platform.h> 16bdbf80c8SZhangbin Tong 17bdbf80c8SZhangbin Tong #include <linux/bitrev.h> 18bdbf80c8SZhangbin Tong #include <linux/input.h> 19bdbf80c8SZhangbin Tong 20bdbf80c8SZhangbin Tong #include <asm/arch/periph.h> 21bdbf80c8SZhangbin Tong #include <asm/io.h> 22*f21c060eSLei Chen #include <dm/ofnode.h> 23bdbf80c8SZhangbin Tong DECLARE_GLOBAL_DATA_PTR; 24bdbf80c8SZhangbin Tong 25bdbf80c8SZhangbin Tong static struct nec_dec nec; 26bdbf80c8SZhangbin Tong static struct rc_map *rc_map; 27bdbf80c8SZhangbin Tong 28bdbf80c8SZhangbin Tong static int rockchip_ir_get_keycode(struct udevice *dev) 29bdbf80c8SZhangbin Tong { 30bdbf80c8SZhangbin Tong struct rockchip_ir_priv *priv = dev_get_priv(dev); 31bdbf80c8SZhangbin Tong 32bdbf80c8SZhangbin Tong return priv->keycode; 33bdbf80c8SZhangbin Tong } 34bdbf80c8SZhangbin Tong 35bdbf80c8SZhangbin Tong static int rockchip_ir_get_repeat(struct udevice *dev) 36bdbf80c8SZhangbin Tong { 37bdbf80c8SZhangbin Tong struct rockchip_ir_priv *priv = dev_get_priv(dev); 38bdbf80c8SZhangbin Tong 39bdbf80c8SZhangbin Tong return priv->repeat; 40bdbf80c8SZhangbin Tong } 41bdbf80c8SZhangbin Tong 42bdbf80c8SZhangbin Tong static int ir_lookup_by_scancode(struct rockchip_ir_priv *priv, 43bdbf80c8SZhangbin Tong u32 usercode, 44bdbf80c8SZhangbin Tong u32 scancode) 45bdbf80c8SZhangbin Tong { 46bdbf80c8SZhangbin Tong int i, j; 47bdbf80c8SZhangbin Tong 48bdbf80c8SZhangbin Tong for (i = 0; i < priv->num; i++) { 49bdbf80c8SZhangbin Tong if (rc_map[i].usercode == usercode) 50bdbf80c8SZhangbin Tong break; 51bdbf80c8SZhangbin Tong } 52bdbf80c8SZhangbin Tong for (j = 0; i < priv->num && j < rc_map[i].nbuttons; j++) { 53bdbf80c8SZhangbin Tong if (rc_map[i].scan[j].scancode == scancode) { 54bdbf80c8SZhangbin Tong if (priv->keycode == rc_map[i].scan[j].keycode) 55bdbf80c8SZhangbin Tong priv->repeat++; 56bdbf80c8SZhangbin Tong else 57bdbf80c8SZhangbin Tong priv->repeat = 0; 58bdbf80c8SZhangbin Tong priv->keycode = rc_map[i].scan[j].keycode; 59bdbf80c8SZhangbin Tong return 0; 60bdbf80c8SZhangbin Tong } 61bdbf80c8SZhangbin Tong } 62bdbf80c8SZhangbin Tong 63bdbf80c8SZhangbin Tong priv->keycode = KEY_RESERVED; 64bdbf80c8SZhangbin Tong priv->repeat = 0; 65bdbf80c8SZhangbin Tong 66bdbf80c8SZhangbin Tong return -1; 67bdbf80c8SZhangbin Tong } 68bdbf80c8SZhangbin Tong 69bdbf80c8SZhangbin Tong static int ir_parse_keys(struct udevice *dev) 70bdbf80c8SZhangbin Tong { 71bdbf80c8SZhangbin Tong int i, j; 72bdbf80c8SZhangbin Tong int len; 73bdbf80c8SZhangbin Tong int ret; 74*f21c060eSLei Chen u32 val; 75*f21c060eSLei Chen ofnode node; 76bdbf80c8SZhangbin Tong 77bdbf80c8SZhangbin Tong i = 0; 78*f21c060eSLei Chen dev_for_each_subnode(node, dev) { 79*f21c060eSLei Chen ret = ofnode_read_u32(node, "rockchip,usercode", &val); 80*f21c060eSLei Chen if (ret) { 81*f21c060eSLei Chen debug("unable to get usercode\n"); 82*f21c060eSLei Chen return -1; 83*f21c060eSLei Chen } 84*f21c060eSLei Chen rc_map[i].usercode = val; 85*f21c060eSLei Chen if (rc_map[i].usercode == 0) { 86bdbf80c8SZhangbin Tong debug("missing usercode property in the dts\n"); 87bdbf80c8SZhangbin Tong return -1; 88bdbf80c8SZhangbin Tong } 89bdbf80c8SZhangbin Tong debug("add new usercode:0x%x\n", rc_map[i].usercode); 90*f21c060eSLei Chen len = ofnode_read_size(node, "rockchip,key_table"); 91bdbf80c8SZhangbin Tong len /= sizeof(u32); 92bdbf80c8SZhangbin Tong debug("len:%d\n", len); 93bdbf80c8SZhangbin Tong rc_map[i].nbuttons = len / 2; 94*f21c060eSLei Chen 95*f21c060eSLei Chen ret = ofnode_read_u32_array(node, "rockchip,key_table", 96bdbf80c8SZhangbin Tong (u32 *)rc_map[i].scan, len); 97bdbf80c8SZhangbin Tong if (ret) { 98bdbf80c8SZhangbin Tong debug("missing key_table property in the dts\n"); 99bdbf80c8SZhangbin Tong return -1; 100bdbf80c8SZhangbin Tong } 101bdbf80c8SZhangbin Tong for (j = 0; j < (len / 2); j++) { 102bdbf80c8SZhangbin Tong debug("[%d],usercode=0x%x scancode=0x%x keycode=0x%x\n", 103bdbf80c8SZhangbin Tong i, 104bdbf80c8SZhangbin Tong rc_map[i].usercode, 105bdbf80c8SZhangbin Tong rc_map[i].scan[j].scancode, 106bdbf80c8SZhangbin Tong rc_map[i].scan[j].keycode); 107bdbf80c8SZhangbin Tong } 108bdbf80c8SZhangbin Tong i++; 109bdbf80c8SZhangbin Tong } 110bdbf80c8SZhangbin Tong 111bdbf80c8SZhangbin Tong return 0; 112bdbf80c8SZhangbin Tong } 113bdbf80c8SZhangbin Tong 114bdbf80c8SZhangbin Tong /** 115bdbf80c8SZhangbin Tong * ir_nec_decode() - Decode one NEC pulse or space 116bdbf80c8SZhangbin Tong * @duration: the struct ir_raw_event descriptor of the pulse/space 117bdbf80c8SZhangbin Tong */ 118bdbf80c8SZhangbin Tong static int ir_nec_decode(struct rockchip_ir_priv *priv, struct ir_raw_event *ev) 119bdbf80c8SZhangbin Tong { 120bdbf80c8SZhangbin Tong int ret; 121bdbf80c8SZhangbin Tong u32 usercode; 122bdbf80c8SZhangbin Tong u32 scancode; 123bdbf80c8SZhangbin Tong u8 __maybe_unused address, not_address, command, not_command; 124bdbf80c8SZhangbin Tong struct nec_dec *data = &nec; 125bdbf80c8SZhangbin Tong 126bdbf80c8SZhangbin Tong switch (data->state) { 127bdbf80c8SZhangbin Tong case STATE_INACTIVE: 128bdbf80c8SZhangbin Tong if (!ev->pulse) 129bdbf80c8SZhangbin Tong break; 130bdbf80c8SZhangbin Tong 131bdbf80c8SZhangbin Tong if (!eq_margin(ev->duration, NEC_HEADER_PULSE, NEC_UNIT * 2)) 132bdbf80c8SZhangbin Tong break; 133bdbf80c8SZhangbin Tong 134bdbf80c8SZhangbin Tong data->count = 0; 135bdbf80c8SZhangbin Tong data->state = STATE_HEADER_SPACE; 136bdbf80c8SZhangbin Tong return 0; 137bdbf80c8SZhangbin Tong 138bdbf80c8SZhangbin Tong case STATE_HEADER_SPACE: 139bdbf80c8SZhangbin Tong if (ev->pulse) 140bdbf80c8SZhangbin Tong break; 141bdbf80c8SZhangbin Tong 142bdbf80c8SZhangbin Tong if (eq_margin(ev->duration, NEC_HEADER_SPACE, NEC_UNIT)) { 143bdbf80c8SZhangbin Tong data->state = STATE_BIT_PULSE; 144bdbf80c8SZhangbin Tong return 0; 145bdbf80c8SZhangbin Tong } 146bdbf80c8SZhangbin Tong 147bdbf80c8SZhangbin Tong break; 148bdbf80c8SZhangbin Tong 149bdbf80c8SZhangbin Tong case STATE_BIT_PULSE: 150bdbf80c8SZhangbin Tong if (!ev->pulse) 151bdbf80c8SZhangbin Tong break; 152bdbf80c8SZhangbin Tong 153bdbf80c8SZhangbin Tong if (!eq_margin(ev->duration, NEC_BIT_PULSE, NEC_UNIT / 2)) 154bdbf80c8SZhangbin Tong break; 155bdbf80c8SZhangbin Tong 156bdbf80c8SZhangbin Tong data->state = STATE_BIT_SPACE; 157bdbf80c8SZhangbin Tong return 0; 158bdbf80c8SZhangbin Tong 159bdbf80c8SZhangbin Tong case STATE_BIT_SPACE: 160bdbf80c8SZhangbin Tong if (ev->pulse) 161bdbf80c8SZhangbin Tong break; 162bdbf80c8SZhangbin Tong 163bdbf80c8SZhangbin Tong data->bits <<= 1; 164*f21c060eSLei Chen if (eq_margin(ev->duration, NEC_BIT_1_SPACE, NEC_UNIT / 2)) { 165bdbf80c8SZhangbin Tong data->bits |= 1; 166*f21c060eSLei Chen } else if (!eq_margin(ev->duration, NEC_BIT_0_SPACE, 167*f21c060eSLei Chen NEC_UNIT / 2)) { 168bdbf80c8SZhangbin Tong break; 169*f21c060eSLei Chen } 170bdbf80c8SZhangbin Tong data->count++; 171bdbf80c8SZhangbin Tong 172bdbf80c8SZhangbin Tong if (data->count == NEC_NBITS) { 173bdbf80c8SZhangbin Tong address = ((data->bits >> 24) & 0xff); 174bdbf80c8SZhangbin Tong not_address = ((data->bits >> 16) & 0xff); 175bdbf80c8SZhangbin Tong command = ((data->bits >> 8) & 0xff); 176bdbf80c8SZhangbin Tong not_command = ((data->bits >> 0) & 0xff); 177bdbf80c8SZhangbin Tong 178bdbf80c8SZhangbin Tong if ((command ^ not_command) != 0xff) { 179bdbf80c8SZhangbin Tong debug("NEC checksum error: received 0x%08x\n", 180bdbf80c8SZhangbin Tong data->bits); 181bdbf80c8SZhangbin Tong } 182bdbf80c8SZhangbin Tong usercode = address << 8 | not_address; 183bdbf80c8SZhangbin Tong scancode = command << 8 | not_command; 184*f21c060eSLei Chen 185bdbf80c8SZhangbin Tong /* change to dts format */ 186bdbf80c8SZhangbin Tong usercode = bitrev16(usercode); 187bdbf80c8SZhangbin Tong scancode = (bitrev16(scancode) >> 8) & 0xFF; 188*f21c060eSLei Chen debug("usercode 0x%04x scancode 0x%04x\n", 189*f21c060eSLei Chen usercode, scancode); 190bdbf80c8SZhangbin Tong 191bdbf80c8SZhangbin Tong data->state = STATE_INACTIVE; 192bdbf80c8SZhangbin Tong ret = ir_lookup_by_scancode(priv, usercode, scancode); 193bdbf80c8SZhangbin Tong if (!ret) 194bdbf80c8SZhangbin Tong debug("keycode 0x%02x repeat 0x%x\n", 195bdbf80c8SZhangbin Tong priv->keycode, priv->repeat); 196bdbf80c8SZhangbin Tong else 197bdbf80c8SZhangbin Tong debug("ir lookup by scancode failed\n"); 198bdbf80c8SZhangbin Tong } else { 199bdbf80c8SZhangbin Tong data->state = STATE_BIT_PULSE; 200bdbf80c8SZhangbin Tong } 201bdbf80c8SZhangbin Tong 202bdbf80c8SZhangbin Tong return 0; 203bdbf80c8SZhangbin Tong } 204bdbf80c8SZhangbin Tong 205bdbf80c8SZhangbin Tong debug("NEC decode failed at count %d state %d (%uus %s)\n", 206bdbf80c8SZhangbin Tong data->count, data->state, TO_US(ev->duration), TO_STR(ev->pulse)); 207bdbf80c8SZhangbin Tong data->state = STATE_INACTIVE; 208bdbf80c8SZhangbin Tong 209bdbf80c8SZhangbin Tong return -1; 210bdbf80c8SZhangbin Tong } 211bdbf80c8SZhangbin Tong 212bdbf80c8SZhangbin Tong static void rockchip_ir_irq(int irq, void *data) 213bdbf80c8SZhangbin Tong { 214bdbf80c8SZhangbin Tong u32 val; 215bdbf80c8SZhangbin Tong u32 cycle_hpr, cycle_lpr, cycle; 216bdbf80c8SZhangbin Tong struct ir_raw_event ev; 217bdbf80c8SZhangbin Tong struct rockchip_ir_priv *priv = (struct rockchip_ir_priv *)data; 218bdbf80c8SZhangbin Tong 219bdbf80c8SZhangbin Tong val = readl(priv->base + PWM_STA_REG(priv->id)); 220bdbf80c8SZhangbin Tong cycle_hpr = readl(priv->base + PWM_HPR_REG); 221bdbf80c8SZhangbin Tong cycle_lpr = readl(priv->base + PWM_LPR_REG); 222bdbf80c8SZhangbin Tong if (val & PWM_CH_POL(priv->id)) { 223bdbf80c8SZhangbin Tong cycle = cycle_hpr; 224bdbf80c8SZhangbin Tong ev.pulse = 0; 225bdbf80c8SZhangbin Tong } else { 226bdbf80c8SZhangbin Tong cycle = cycle_lpr; 227bdbf80c8SZhangbin Tong ev.pulse = 1; 228bdbf80c8SZhangbin Tong } 229bdbf80c8SZhangbin Tong writel(PWM_CH_INT(priv->id), 230bdbf80c8SZhangbin Tong priv->base + PWM_STA_REG(priv->id)); 231*f21c060eSLei Chen 232bdbf80c8SZhangbin Tong ev.duration = cycle * priv->period; 233bdbf80c8SZhangbin Tong ir_nec_decode(priv, &ev); 234bdbf80c8SZhangbin Tong } 235bdbf80c8SZhangbin Tong 236bdbf80c8SZhangbin Tong static void rockchip_ir_hw_init(struct udevice *dev) 237bdbf80c8SZhangbin Tong { 238bdbf80c8SZhangbin Tong unsigned long tmp; 239bdbf80c8SZhangbin Tong struct rockchip_ir_priv *priv = dev_get_priv(dev); 240bdbf80c8SZhangbin Tong 241bdbf80c8SZhangbin Tong /* Enable capture mode, non-scaled clock, prescale 1 */ 242bdbf80c8SZhangbin Tong writel(REG_CTL_MD, priv->base + PWM_CTL_REG); 243bdbf80c8SZhangbin Tong 244bdbf80c8SZhangbin Tong /* Clear Interrupt Status */ 245bdbf80c8SZhangbin Tong writel(PWM_CH_INT(priv->id), 246bdbf80c8SZhangbin Tong priv->base + PWM_STA_REG(priv->id)); 247bdbf80c8SZhangbin Tong 248bdbf80c8SZhangbin Tong /* Enable IRQ */ 249bdbf80c8SZhangbin Tong writel(PWM_CH_INT(priv->id), 250bdbf80c8SZhangbin Tong priv->base + PWM_INT_REG(priv->id)); 251bdbf80c8SZhangbin Tong 252bdbf80c8SZhangbin Tong /* Enable IR Module */ 253bdbf80c8SZhangbin Tong tmp = readl(priv->base + PWM_CTL_REG); 254bdbf80c8SZhangbin Tong writel(tmp | REG_CTL_EN, priv->base + PWM_CTL_REG); 255bdbf80c8SZhangbin Tong } 256bdbf80c8SZhangbin Tong 257bdbf80c8SZhangbin Tong static int rockchip_ir_ofdata_to_platdata(struct udevice *dev) 258bdbf80c8SZhangbin Tong { 259*f21c060eSLei Chen ofnode node; 260*f21c060eSLei Chen int ret; 261*f21c060eSLei Chen int subnode_num = 0; 262*f21c060eSLei Chen u32 val; 263bdbf80c8SZhangbin Tong struct rockchip_ir_priv *priv = dev_get_priv(dev); 264bdbf80c8SZhangbin Tong 265*f21c060eSLei Chen dev_for_each_subnode(node, dev) { 266*f21c060eSLei Chen ret = ofnode_read_u32(node, "rockchip,usercode", &val); 267*f21c060eSLei Chen if (!ret) 268*f21c060eSLei Chen subnode_num++; 269*f21c060eSLei Chen } 270*f21c060eSLei Chen 271*f21c060eSLei Chen priv->num = subnode_num; 272*f21c060eSLei Chen 273bdbf80c8SZhangbin Tong if (priv->num == 0) { 274bdbf80c8SZhangbin Tong debug("no ir map in dts\n"); 275bdbf80c8SZhangbin Tong return -1; 276bdbf80c8SZhangbin Tong } 277*f21c060eSLei Chen priv->base = dev_read_addr(dev); 278bdbf80c8SZhangbin Tong priv->id = (priv->base >> 4) & 0xF; 279bdbf80c8SZhangbin Tong 280bdbf80c8SZhangbin Tong return 0; 281bdbf80c8SZhangbin Tong } 282bdbf80c8SZhangbin Tong 283bdbf80c8SZhangbin Tong static int rockchip_ir_probe(struct udevice *dev) 284bdbf80c8SZhangbin Tong { 285bdbf80c8SZhangbin Tong int ret; 286bdbf80c8SZhangbin Tong struct clk clk; 287bdbf80c8SZhangbin Tong struct udevice *pinctrl; 288bdbf80c8SZhangbin Tong struct rockchip_ir_priv *priv = dev_get_priv(dev); 289bdbf80c8SZhangbin Tong 290bdbf80c8SZhangbin Tong rc_map = calloc(1, priv->num * sizeof(struct rc_map)); 291bdbf80c8SZhangbin Tong if (!rc_map) { 292bdbf80c8SZhangbin Tong debug("%s: failed to calloc\n", __func__); 293bdbf80c8SZhangbin Tong return -EINVAL; 294bdbf80c8SZhangbin Tong } 295bdbf80c8SZhangbin Tong 296bdbf80c8SZhangbin Tong ret = ir_parse_keys(dev); 297bdbf80c8SZhangbin Tong if (ret) { 298bdbf80c8SZhangbin Tong debug("%s: failed to parse keys\n", __func__); 299bdbf80c8SZhangbin Tong return -EINVAL; 300bdbf80c8SZhangbin Tong } 301bdbf80c8SZhangbin Tong /* 302bdbf80c8SZhangbin Tong * The PWM does not have decicated interrupt number in dts and can 303bdbf80c8SZhangbin Tong * not get periph_id by pinctrl framework, so let's init then here. 304bdbf80c8SZhangbin Tong */ 305bdbf80c8SZhangbin Tong ret = uclass_get_device(UCLASS_PINCTRL, 0, &pinctrl); 306bdbf80c8SZhangbin Tong if (ret) { 307bdbf80c8SZhangbin Tong debug("%s: can't find pinctrl device\n", __func__); 308bdbf80c8SZhangbin Tong return -EINVAL; 309bdbf80c8SZhangbin Tong } 310bdbf80c8SZhangbin Tong 311bdbf80c8SZhangbin Tong ret = clk_get_by_index(dev, 0, &clk); 312bdbf80c8SZhangbin Tong if (ret) { 313bdbf80c8SZhangbin Tong debug("%s get clock fail!\n", __func__); 314bdbf80c8SZhangbin Tong return -EINVAL; 315bdbf80c8SZhangbin Tong } 316bdbf80c8SZhangbin Tong priv->freq = clk_get_rate(&clk); 317bdbf80c8SZhangbin Tong debug("%s pwm clk = %lu\n", __func__, priv->freq); 318bdbf80c8SZhangbin Tong priv->period = 1000000000 / priv->freq; 319bdbf80c8SZhangbin Tong 320bdbf80c8SZhangbin Tong irq_install_handler(IRQ_PWM, 321bdbf80c8SZhangbin Tong (interrupt_handler_t *)rockchip_ir_irq, priv); 322bdbf80c8SZhangbin Tong irq_handler_enable(IRQ_PWM); 323bdbf80c8SZhangbin Tong 324bdbf80c8SZhangbin Tong rockchip_ir_hw_init(dev); 325bdbf80c8SZhangbin Tong 326bdbf80c8SZhangbin Tong return ret; 327bdbf80c8SZhangbin Tong } 328bdbf80c8SZhangbin Tong 329bdbf80c8SZhangbin Tong static const struct dm_rc_ops rockchip_ir_ops = { 330bdbf80c8SZhangbin Tong .get_keycode = rockchip_ir_get_keycode, 331bdbf80c8SZhangbin Tong .get_repeat = rockchip_ir_get_repeat, 332bdbf80c8SZhangbin Tong }; 333bdbf80c8SZhangbin Tong 334bdbf80c8SZhangbin Tong static const struct udevice_id rockchip_ir_ids[] = { 335bdbf80c8SZhangbin Tong { .compatible = "rockchip,remotectl-pwm" }, 336bdbf80c8SZhangbin Tong { } 337bdbf80c8SZhangbin Tong }; 338bdbf80c8SZhangbin Tong 339bdbf80c8SZhangbin Tong U_BOOT_DRIVER(rockchip_ir) = { 340bdbf80c8SZhangbin Tong .name = "rockchip_ir", 341bdbf80c8SZhangbin Tong .id = UCLASS_RC, 342bdbf80c8SZhangbin Tong .of_match = rockchip_ir_ids, 343bdbf80c8SZhangbin Tong .ofdata_to_platdata = rockchip_ir_ofdata_to_platdata, 344bdbf80c8SZhangbin Tong .probe = rockchip_ir_probe, 345bdbf80c8SZhangbin Tong .ops = &rockchip_ir_ops, 346bdbf80c8SZhangbin Tong .priv_auto_alloc_size = sizeof(struct rockchip_ir_priv), 347bdbf80c8SZhangbin Tong }; 348