/* SPDX-License-Identifier: GPL-2.0 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rockchip_pwm_remotectl.h" /* * sys/module/rk_pwm_remotectl/parameters, * modify code_print to change the value */ static int rk_remote_print_code; module_param_named(code_print, rk_remote_print_code, int, 0644); #define DBG_CODE(args...) \ do { \ if (rk_remote_print_code) { \ pr_info(args); \ } \ } while (0) static int rk_remote_pwm_dbg_level; module_param_named(dbg_level, rk_remote_pwm_dbg_level, int, 0644); #define DBG(args...) \ do { \ if (rk_remote_pwm_dbg_level) { \ pr_info(args); \ } \ } while (0) struct rkxx_remote_key_table { int scancode; int keycode; }; struct rkxx_remotectl_button { int usercode; int nbuttons; struct rkxx_remote_key_table key_table[MAX_NUM_KEYS]; }; struct rkxx_remotectl_drvdata { void __iomem *base; int state; int nbuttons; int scandata; int count; int keynum; int maxkeybdnum; int keycode; int press; int pre_press; int irq; int remote_pwm_id; int handle_cpu_id; int wakeup; int support_psci; int pwm_pwrkey_capture; unsigned long period; unsigned long temp_period; int pwm_freq_nstime; int pwrkey_wakeup; struct input_dev *input; struct timer_list timer; struct tasklet_struct remote_tasklet; struct wake_lock remotectl_wake_lock; int keymode; /* DPAD (0) or REL_X/Y (1-3) */ u64 timestamp; }; static struct rkxx_remotectl_button *remotectl_button; static int remotectl_keybd_num_lookup(struct rkxx_remotectl_drvdata *ddata) { int i; int num; num = ddata->maxkeybdnum; for (i = 0; i < num; i++) { if (remotectl_button[i].usercode == (ddata->scandata&0xFFFF)) { ddata->keynum = i; return 1; } } return 0; } static int remotectl_keycode_lookup(struct rkxx_remotectl_drvdata *ddata) { int i; unsigned char keydata = (unsigned char)((ddata->scandata >> 8) & 0xff); int ret = 0; for (i = 0; i < remotectl_button[ddata->keynum].nbuttons; i++) { if (remotectl_button[ddata->keynum].key_table[i].scancode == keydata) { ddata->keycode = remotectl_button[ddata->keynum].key_table[i].keycode; ret = 1; break; } } if (ddata->keycode == KEY_MODE) { ddata->keymode = (ddata->keymode + 1) % 3; } else if (ddata->keymode > 0) { int rel, val; u64 ts = ddata->timestamp; ddata->timestamp = ktime_get_ns(); ts = (ddata->timestamp - ts) >> 24; /* in 16.7ms */ if (ts < 15) val = 80; else if (ts < 25) val = 43; else if (ts < 60) val = 16; else if (ts < 120) val = 5; /* quicker key event means faster move speed */ DBG("delta = %llu, rel = %d\n", ts, val); switch (ddata->keycode) { case KEY_LEFT: rel = REL_X; val *= -ddata->keymode; break; case KEY_RIGHT: rel = REL_X; val *= ddata->keymode; break; case KEY_UP: rel = REL_Y; val *= -ddata->keymode; break; case KEY_DOWN: rel = REL_Y; val *= ddata->keymode; break; case KEY_VOLUMEDOWN: rel = REL_WHEEL; val = -ddata->keymode; break; case KEY_VOLUMEUP: rel = REL_WHEEL; val = ddata->keymode; break; /* remapping some keys for mouse mode */ case KEY_SYSRQ: ddata->keycode = 204; return ret; case KEY_MENU: ddata->keycode = BTN_RIGHT; return ret; case 232: case KEY_ENTER: ddata->keycode = BTN_LEFT; fallthrough; default: return ret; } input_report_rel(ddata->input, rel, val); input_sync(ddata->input); return 0; } return ret; } static int rk_remotectl_get_irkeybd_count(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct device_node *child_node; int boardnum; int temp_usercode; boardnum = 0; for_each_child_of_node(node, child_node) { if (of_property_read_u32(child_node, "rockchip,usercode", &temp_usercode)) { DBG("get keybd num error.\n"); } else { boardnum++; } } DBG("get keybd num = 0x%x.\n", boardnum); return boardnum; } static int rk_remotectl_parse_ir_keys(struct platform_device *pdev) { struct rkxx_remotectl_drvdata *ddata = platform_get_drvdata(pdev); struct device_node *node = pdev->dev.of_node; struct device_node *child_node; int loop; int ret; int len; int boardnum; boardnum = 0; for_each_child_of_node(node, child_node) { if (of_property_read_u32(child_node, "rockchip,usercode", &remotectl_button[boardnum].usercode)) { dev_err(&pdev->dev, "Missing usercode in the DTS.\n"); ret = -1; return ret; } DBG("remotectl_button[0].usercode=0x%x\n", remotectl_button[boardnum].usercode); of_get_property(child_node, "rockchip,key_table", &len); len /= sizeof(u32); DBG("len=0x%x\n", len); remotectl_button[boardnum].nbuttons = len/2; if (of_property_read_u32_array(child_node, "rockchip,key_table", (u32 *)remotectl_button[boardnum].key_table, len)) { dev_err(&pdev->dev, "Missing key_table in the DTS.\n"); ret = -1; return ret; } for (loop = 0; loop < (len/2); loop++) { DBG("board[%d].scanCode[%d]=0x%x\n", boardnum, loop, remotectl_button[boardnum].key_table[loop].scancode); DBG("board[%d].keyCode[%d]=%d\n", boardnum, loop, remotectl_button[boardnum].key_table[loop].keycode); } boardnum++; if (boardnum > ddata->maxkeybdnum) break; } DBG("keybdNum=0x%x\n", boardnum); return 0; } static void rk_pwm_remotectl_do_something(unsigned long data) { struct rkxx_remotectl_drvdata *ddata; ddata = (struct rkxx_remotectl_drvdata *)data; switch (ddata->state) { case RMC_IDLE: { ; break; } case RMC_PRELOAD: { mod_timer(&ddata->timer, jiffies + msecs_to_jiffies(140)); if ((ddata->period > RK_PWM_TIME_PRE_MIN) && (ddata->period < RK_PWM_TIME_PRE_MAX)) { ddata->scandata = 0; ddata->count = 0; ddata->state = RMC_USERCODE; } else { ddata->state = RMC_PRELOAD; } break; } case RMC_USERCODE: { if ((ddata->period > RK_PWM_TIME_BIT1_MIN) && (ddata->period < RK_PWM_TIME_BIT1_MAX)) ddata->scandata |= (0x01 << ddata->count); ddata->count++; if (ddata->count == 0x10) { DBG_CODE("USERCODE=0x%x\n", ddata->scandata); if (remotectl_keybd_num_lookup(ddata)) { ddata->state = RMC_GETDATA; ddata->scandata = 0; ddata->count = 0; } else { if (rk_remote_print_code) { ddata->state = RMC_GETDATA; ddata->scandata = 0; ddata->count = 0; } else ddata->state = RMC_PRELOAD; } } } break; case RMC_GETDATA: { if ((ddata->period > RK_PWM_TIME_BIT1_MIN) && (ddata->period < RK_PWM_TIME_BIT1_MAX)) ddata->scandata |= (0x01<count); ddata->count++; if (ddata->count < 0x10) return; DBG_CODE("RMC_GETDATA=%x\n", (ddata->scandata>>8)); if ((ddata->scandata&0x0ff) == ((~ddata->scandata >> 8) & 0x0ff)) { if (remotectl_keycode_lookup(ddata)) { ddata->press = 1; input_event(ddata->input, EV_KEY, ddata->keycode, 1); input_sync(ddata->input); ddata->state = RMC_SEQUENCE; } else { ddata->state = RMC_PRELOAD; } } else { ddata->state = RMC_PRELOAD; } } break; case RMC_SEQUENCE:{ DBG("S=%ld\n", ddata->period); if ((ddata->period > RK_PWM_TIME_RPT_MIN) && (ddata->period < RK_PWM_TIME_RPT_MAX)) { DBG("S1\n"); mod_timer(&ddata->timer, jiffies + msecs_to_jiffies(130)); } else if ((ddata->period > RK_PWM_TIME_SEQ1_MIN) && (ddata->period < RK_PWM_TIME_SEQ1_MAX)) { DBG("S2\n"); mod_timer(&ddata->timer, jiffies + msecs_to_jiffies(130)); } else if ((ddata->period > RK_PWM_TIME_SEQ2_MIN) && (ddata->period < RK_PWM_TIME_SEQ2_MAX)) { DBG("S3\n"); mod_timer(&ddata->timer, jiffies + msecs_to_jiffies(130)); } else { DBG("S4\n"); input_event(ddata->input, EV_KEY, ddata->keycode, 0); input_sync(ddata->input); ddata->state = RMC_PRELOAD; ddata->press = 0; } } break; default: break; } } static void rk_pwm_remotectl_timer(struct timer_list *t) { struct rkxx_remotectl_drvdata *ddata = from_timer(ddata, t, timer); if (ddata->press != ddata->pre_press) { ddata->pre_press = 0; ddata->press = 0; input_event(ddata->input, EV_KEY, ddata->keycode, 0); input_sync(ddata->input); } ddata->state = RMC_PRELOAD; } static irqreturn_t rockchip_pwm_pwrirq(int irq, void *dev_id) { struct rkxx_remotectl_drvdata *ddata = dev_id; int val; unsigned int id = ddata->remote_pwm_id; if (id > 3) return IRQ_NONE; val = readl_relaxed(ddata->base + PWM_REG_INTSTS(id)); if (val & PWM_PWR_KEY_INT) { DBG("pwr=0x%x\n", readl_relaxed(ddata->base + PWM_PWRCAPTURE_VALUE(id))); writel_relaxed(PWM_PWR_KEY_INT, ddata->base + PWM_REG_INTSTS(id)); ddata->pwrkey_wakeup = 1; return IRQ_HANDLED; } return IRQ_NONE; } static irqreturn_t rockchip_pwm_irq(int irq, void *dev_id) { struct rkxx_remotectl_drvdata *ddata = dev_id; int val; int temp_hpr; int temp_lpr; int temp_period; unsigned int id = ddata->remote_pwm_id; if (id > 3) return IRQ_NONE; val = readl_relaxed(ddata->base + PWM_REG_INTSTS(id)); if ((val & PWM_CH_INT(id)) == 0) return IRQ_NONE; if ((val & PWM_CH_POL(id)) == 0) { temp_hpr = readl_relaxed(ddata->base + PWM_REG_HPR); writel_relaxed(0, ddata->base + PWM_REG_HPR); temp_lpr = readl_relaxed(ddata->base + PWM_REG_LPR); writel_relaxed(0, ddata->base + PWM_REG_LPR); DBG("hpr=%d\n", temp_hpr); DBG("lpr=%d\n", temp_lpr); temp_period = ddata->pwm_freq_nstime * temp_lpr / 1000; if (temp_period > RK_PWM_TIME_BIT0_MIN) { ddata->period = ddata->temp_period + ddata->pwm_freq_nstime * temp_hpr / 1000; tasklet_hi_schedule(&ddata->remote_tasklet); ddata->temp_period = 0; DBG("period+ =%ld\n", ddata->period); } else { ddata->temp_period += ddata->pwm_freq_nstime * (temp_hpr + temp_lpr) / 1000; } } writel_relaxed(PWM_CH_INT(id), ddata->base + PWM_REG_INTSTS(id)); if (ddata->state == RMC_PRELOAD) wake_lock_timeout(&ddata->remotectl_wake_lock, HZ); return IRQ_HANDLED; } static int rk_pwm_pwrkey_wakeup_init(struct platform_device *pdev) { struct rkxx_remotectl_drvdata *ddata = platform_get_drvdata(pdev); int val, min_temp, max_temp; unsigned int pwm_id = ddata->remote_pwm_id; int version; int i, j; int num = 0; int ret = -1; int pwr_irq; ddata->pwm_pwrkey_capture = 0; version = readl_relaxed(ddata->base + RK_PWM_VERSION_ID(pwm_id)); dev_info(&pdev->dev, "pwm version is 0x%x\n", version & 0xffff0000); if (((version >> 24) & 0xFF) < 2) { dev_info(&pdev->dev, "pwm version is less v2.0\n"); goto end; } pwr_irq = platform_get_irq(pdev, 1); if (pwr_irq < 0) { dev_err(&pdev->dev, "cannot find PWR IRQ\n"); goto end; } ret = devm_request_irq(&pdev->dev, pwr_irq, rockchip_pwm_pwrirq, IRQF_NO_SUSPEND, "rk_pwm_pwr_irq", ddata); if (ret) { dev_err(&pdev->dev, "cannot claim PWR_IRQ!!!\n"); goto end; } val = readl_relaxed(ddata->base + PWM_REG_CTRL); val = (val & 0xFFFFFFFE) | PWM_DISABLE; writel_relaxed(val, ddata->base + PWM_REG_CTRL); //preloader low min:8000us, max:10000us min_temp = RK_PWM_TIME_PRE_MIN_LOW * 1000 / ddata->pwm_freq_nstime; max_temp = RK_PWM_TIME_PRE_MAX_LOW * 1000 / ddata->pwm_freq_nstime; val = (max_temp & 0xffff) << 16 | (min_temp & 0xffff); writel_relaxed(val, ddata->base + PWM_REG_PWRMATCH_LPRE(pwm_id)); //preloader higt min:4000us, max:5000us min_temp = RK_PWM_TIME_PRE_MIN * 1000 / ddata->pwm_freq_nstime; max_temp = RK_PWM_TIME_PRE_MAX * 1000 / ddata->pwm_freq_nstime; val = (max_temp & 0xffff) << 16 | (min_temp & 0xffff); writel_relaxed(val, ddata->base + PWM_REG_PWRMATCH_HPRE(pwm_id)); //logic 0/1 low min:480us, max 700us min_temp = RK_PWM_TIME_BIT_MIN_LOW * 1000 / ddata->pwm_freq_nstime; max_temp = RK_PWM_TIME_BIT_MAX_LOW * 1000 / ddata->pwm_freq_nstime; val = (max_temp & 0xffff) << 16 | (min_temp & 0xffff); writel_relaxed(val, ddata->base + PWM_REG_PWRMATCH_LD(pwm_id)); //logic 0 higt min:480us, max 700us min_temp = RK_PWM_TIME_BIT0_MIN * 1000 / ddata->pwm_freq_nstime; max_temp = RK_PWM_TIME_BIT0_MAX * 1000 / ddata->pwm_freq_nstime; val = (max_temp & 0xffff) << 16 | (min_temp & 0xffff); writel_relaxed(val, ddata->base + PWM_REG_PWRMATCH_HD_ZERO(pwm_id)); //logic 1 higt min:1300us, max 2000us min_temp = RK_PWM_TIME_BIT1_MIN * 1000 / ddata->pwm_freq_nstime; max_temp = RK_PWM_TIME_BIT1_MAX * 1000 / ddata->pwm_freq_nstime; val = (max_temp & 0xffff) << 16 | (min_temp & 0xffff); writel_relaxed(val, ddata->base + PWM_REG_PWRMATCH_HD_ONE(pwm_id)); for (j = 0; j < ddata->maxkeybdnum; j++) { for (i = 0; i < remotectl_button[j].nbuttons; i++) { int scancode, usercode, pwrkey; if (remotectl_button[j].key_table[i].keycode != KEY_POWER) continue; usercode = remotectl_button[j].usercode & 0xffff; scancode = remotectl_button[j].key_table[i].scancode & 0xff; DBG("usercode=%x, key=%x\n", usercode, scancode); pwrkey = usercode; pwrkey |= (scancode << 24) | ((~scancode & 0xff) << 16); DBG("pwrkey = %x\n", pwrkey); writel_relaxed(pwrkey, ddata->base + PWM_PWRMATCH_VALUE(pwm_id) + num * 4); num++; if (num >= PWM_PWR_KEY_CAPURURE_MAX) break; } } val = readl_relaxed(ddata->base + PWM_REG_INT_EN(pwm_id)); val = (val & 0xFFFFFF7F) | PWM_PWR_INT_ENABLE; writel_relaxed(val, ddata->base + PWM_REG_INT_EN(pwm_id)); val = CH3_PWRKEY_ENABLE; writel_relaxed(val, ddata->base + PWM_REG_PWRMATCH_CTRL(pwm_id)); val = readl_relaxed(ddata->base + PWM_REG_CTRL); val = (val & 0xFFFFFFFE) | PWM_ENABLE; writel_relaxed(val, ddata->base + PWM_REG_CTRL); ddata->pwm_pwrkey_capture = 1; end: return ret; } static void rk_pwm_int_ctrl(void __iomem *pwm_base, uint pwm_id, int ctrl) { int val; if (pwm_id > 3) return; val = readl_relaxed(pwm_base + PWM_REG_INT_EN(pwm_id)); if (ctrl) { val |= PWM_CH_INT_ENABLE(pwm_id); DBG("pwm int enabled, value is 0x%x\n", val); writel_relaxed(val, pwm_base + PWM_REG_INT_EN(pwm_id)); } else { val &= ~PWM_CH_INT_ENABLE(pwm_id); DBG("pwm int disabled, value is 0x%x\n", val); } writel_relaxed(val, pwm_base + PWM_REG_INT_EN(pwm_id)); } static int rk_pwm_remotectl_hw_init(void __iomem *pwm_base, uint pwm_id) { int val; if (pwm_id > 3) return -1; //1. disabled pwm val = readl_relaxed(pwm_base + PWM_REG_CTRL); val = (val & 0xFFFFFFFE) | PWM_DISABLE; writel_relaxed(val, pwm_base + PWM_REG_CTRL); //2. capture mode val = readl_relaxed(pwm_base + PWM_REG_CTRL); val = (val & 0xFFFFFFF9) | PWM_MODE_CAPTURE; writel_relaxed(val, pwm_base + PWM_REG_CTRL); //set clk div, clk div to 64 val = readl_relaxed(pwm_base + PWM_REG_CTRL); val = (val & 0xFF0001FF) | PWM_DIV64; writel_relaxed(val, pwm_base + PWM_REG_CTRL); //4. enabled pwm int rk_pwm_int_ctrl(pwm_base, pwm_id, PWM_INT_ENABLE); //5. enabled pwm val = readl_relaxed(pwm_base + PWM_REG_CTRL); val = (val & 0xFFFFFFFE) | PWM_ENABLE; writel_relaxed(val, pwm_base + PWM_REG_CTRL); return 0; } static int rk_pwm_sip_wakeup_init(struct platform_device *pdev) { struct rkxx_remotectl_drvdata *ddata = platform_get_drvdata(pdev); struct device_node *np = pdev->dev.of_node; struct irq_desc *desc; int support_psci = 0; int irq; int hwirq; int i, j; int num; int pwm_id; int ret = -1; if (of_property_read_u32(np, "remote_support_psci", &support_psci)) { dev_info(&pdev->dev, "PWM Missing psci property in the DT.\n"); goto end; } DBG("support_psci=0x%x\n", support_psci); if (!support_psci) goto end; irq = ddata->irq; desc = irq_to_desc(irq); if (!desc || !desc->irq_data.domain) goto end; hwirq = desc->irq_data.hwirq; ret = sip_smc_remotectl_config(REMOTECTL_SET_IRQ, hwirq); if (ret) { dev_err(&pdev->dev, "set irq err, set support_psci to 0 !!\n"); /* * if atf doesn't support, return probe success to abandon atf * function and still use kernel pwm parse function */ goto end; } pwm_id = ddata->remote_pwm_id; num = ddata->maxkeybdnum; sip_smc_remotectl_config(REMOTECTL_SET_PWM_CH, pwm_id); for (j = 0; j < num; j++) { for (i = 0; i < remotectl_button[j].nbuttons; i++) { int scancode, pwrkey; if (remotectl_button[j].key_table[i].keycode != KEY_POWER) continue; scancode = remotectl_button[j].key_table[i].scancode; DBG("usercode=%x, key=%x\n", remotectl_button[j].usercode, scancode); pwrkey = (remotectl_button[j].usercode & 0xffff) << 16; pwrkey |= (scancode & 0xff) << 8; DBG("deliver: key=%x\n", pwrkey); sip_smc_remotectl_config(REMOTECTL_SET_PWRKEY, pwrkey); } } sip_smc_remotectl_config(REMOTECTL_ENABLE, 1); ddata->support_psci = support_psci; DBG("rk pwm sip init end!\n"); return 0; end: dev_info(&pdev->dev, "pwm sip wakeup config error!!\n"); ddata->support_psci = 0; return ret; } static inline void rk_pwm_wakeup(struct input_dev *input) { input_event(input, EV_KEY, KEY_POWER, 1); input_event(input, EV_KEY, KEY_POWER, 0); input_sync(input); } static int rk_pwm_probe(struct platform_device *pdev) { struct rkxx_remotectl_drvdata *ddata; struct device_node *np = pdev->dev.of_node; struct resource *r; struct input_dev *input; struct clk *clk; struct clk *p_clk; struct cpumask cpumask; int num; int irq; int ret; int i, j; int cpu_id; int pwm_id; int pwm_freq; int count; pr_err(".. rk pwm remotectl v2.0 init\n"); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) { dev_err(&pdev->dev, "no memory resources defined\n"); return -ENODEV; } ddata = devm_kzalloc(&pdev->dev, sizeof(struct rkxx_remotectl_drvdata), GFP_KERNEL); if (!ddata) { dev_err(&pdev->dev, "failed to allocate memory\n"); return -ENOMEM; } ddata->state = RMC_PRELOAD; ddata->temp_period = 0; ddata->base = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(ddata->base)) return PTR_ERR(ddata->base); count = of_property_count_strings(np, "clock-names"); if (count == 2) { clk = devm_clk_get(&pdev->dev, "pwm"); p_clk = devm_clk_get(&pdev->dev, "pclk"); } else { clk = devm_clk_get(&pdev->dev, NULL); p_clk = clk; } if (IS_ERR(clk)) { ret = PTR_ERR(clk); if (ret != -EPROBE_DEFER) dev_err(&pdev->dev, "Can't get bus clk: %d\n", ret); return ret; } if (IS_ERR(p_clk)) { ret = PTR_ERR(p_clk); if (ret != -EPROBE_DEFER) dev_err(&pdev->dev, "Can't get periph clk: %d\n", ret); return ret; } ret = clk_prepare_enable(clk); if (ret) { dev_err(&pdev->dev, "Can't enable bus clk: %d\n", ret); return ret; } ret = clk_prepare_enable(p_clk); if (ret) { dev_err(&pdev->dev, "Can't enable bus periph clk: %d\n", ret); goto error_clk; } platform_set_drvdata(pdev, ddata); num = rk_remotectl_get_irkeybd_count(pdev); if (num == 0) { pr_err("remotectl: no ir keyboard add in dts!!\n"); ret = -EINVAL; goto error_pclk; } ddata->maxkeybdnum = num; remotectl_button = devm_kzalloc(&pdev->dev, num * sizeof(struct rkxx_remotectl_button), GFP_KERNEL); if (!remotectl_button) { pr_err("failed to malloc remote button memory\n"); ret = -ENOMEM; goto error_pclk; } input = devm_input_allocate_device(&pdev->dev); if (!input) { pr_err("failed to allocate input device\n"); ret = -ENOMEM; goto error_pclk; } input->name = pdev->name; input->phys = "gpio-keys/remotectl"; input->dev.parent = &pdev->dev; input->id.bustype = BUS_HOST; input->id.vendor = 0x524b; input->id.product = 0x0006; input->id.version = 0x0100; ddata->input = input; irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "cannot find IRQ\n"); goto error_pclk; } ddata->irq = irq; ddata->wakeup = 1; of_property_read_u32(np, "remote_pwm_id", &pwm_id); pwm_id %= 4; ddata->remote_pwm_id = pwm_id; if (pwm_id > 3) { dev_err(&pdev->dev, "pwm id error\n"); goto error_pclk; } DBG("remotectl: remote pwm id=0x%x\n", pwm_id); of_property_read_u32(np, "handle_cpu_id", &cpu_id); ddata->handle_cpu_id = cpu_id; DBG("remotectl: handle cpu id=0x%x\n", cpu_id); rk_remotectl_parse_ir_keys(pdev); tasklet_init(&ddata->remote_tasklet, rk_pwm_remotectl_do_something, (unsigned long)ddata); for (j = 0; j < num; j++) { DBG("remotectl probe j = 0x%x\n", j); for (i = 0; i < remotectl_button[j].nbuttons; i++) { int keycode; keycode = remotectl_button[j].key_table[i].keycode; input_set_capability(input, EV_KEY, keycode); } } input_set_capability(input, EV_REL, REL_X); input_set_capability(input, EV_REL, REL_Y); input_set_capability(input, EV_REL, REL_WHEEL); input_set_capability(input, EV_KEY, BTN_LEFT); input_set_capability(input, EV_KEY, BTN_RIGHT); ret = input_register_device(input); if (ret) dev_err(&pdev->dev, "register input device err, ret=%d\n", ret); input_set_capability(input, EV_KEY, KEY_WAKEUP); device_init_wakeup(&pdev->dev, 1); enable_irq_wake(irq); timer_setup(&ddata->timer, rk_pwm_remotectl_timer, 0); wake_lock_init(&ddata->remotectl_wake_lock, WAKE_LOCK_SUSPEND, "rockchip_pwm_remote"); cpumask_clear(&cpumask); cpumask_set_cpu(cpu_id, &cpumask); irq_set_affinity_hint(irq, &cpumask); ret = devm_request_irq(&pdev->dev, irq, rockchip_pwm_irq, IRQF_NO_SUSPEND, "rk_pwm_irq", ddata); if (ret) { dev_err(&pdev->dev, "cannot claim IRQ %d\n", irq); goto error_irq; } pwm_freq = clk_get_rate(clk) / 64; ddata->pwm_freq_nstime = 1000000000 / pwm_freq; rk_pwm_remotectl_hw_init(ddata->base, pwm_id); ret = rk_pwm_pwrkey_wakeup_init(pdev); if (!ret) { dev_info(&pdev->dev, "Controller support pwrkey capture\n"); goto end; } ret = rk_pwm_sip_wakeup_init(pdev); if (ret) dev_info(&pdev->dev, "Donot support ATF Wakeup\n"); else dev_info(&pdev->dev, "Support ATF Wakeup\n"); DBG("rk pwm remotectl init end!\n"); end: return 0; error_irq: wake_lock_destroy(&ddata->remotectl_wake_lock); error_pclk: clk_unprepare(p_clk); error_clk: clk_unprepare(clk); return ret; } static int rk_pwm_remove(struct platform_device *pdev) { return 0; } #ifdef CONFIG_PM static int remotectl_suspend(struct device *dev) { int cpu = 0; int pwm_id; struct cpumask cpumask; struct platform_device *pdev = to_platform_device(dev); struct rkxx_remotectl_drvdata *ddata = platform_get_drvdata(pdev); if (ddata->pwm_pwrkey_capture) { pwm_id = ddata->remote_pwm_id; ddata->pwrkey_wakeup = 0; rk_pwm_int_ctrl(ddata->base, pwm_id, PWM_INT_DISABLE); } cpumask_clear(&cpumask); cpumask_set_cpu(cpu, &cpumask); irq_set_affinity_hint(ddata->irq, &cpumask); return 0; } static int remotectl_resume(struct device *dev) { struct cpumask cpumask; int pwm_id; struct platform_device *pdev = to_platform_device(dev); struct rkxx_remotectl_drvdata *ddata = platform_get_drvdata(pdev); int state; cpumask_clear(&cpumask); cpumask_set_cpu(ddata->handle_cpu_id, &cpumask); irq_set_affinity_hint(ddata->irq, &cpumask); if (ddata->support_psci) { /* * loop wakeup state */ state = sip_smc_remotectl_config( REMOTECTL_GET_WAKEUP_STATE, 0); if (state == REMOTECTL_PWRKEY_WAKEUP) rk_pwm_wakeup(ddata->input); } else if (ddata->pwm_pwrkey_capture) { pwm_id = ddata->remote_pwm_id; rk_pwm_int_ctrl(ddata->base, pwm_id, PWM_INT_ENABLE); if (ddata->pwrkey_wakeup == 0) return 0; ddata->pwrkey_wakeup = 0; rk_pwm_wakeup(ddata->input); } return 0; } static const struct dev_pm_ops remotectl_pm_ops = { .suspend_late = remotectl_suspend, .resume_early = remotectl_resume, }; #endif static const struct of_device_id rk_pwm_of_match[] = { { .compatible = "rockchip,remotectl-pwm"}, { } }; MODULE_DEVICE_TABLE(of, rk_pwm_of_match); static struct platform_driver rk_pwm_driver = { .driver = { .name = "remotectl-pwm", .of_match_table = rk_pwm_of_match, #ifdef CONFIG_PM .pm = &remotectl_pm_ops, #endif }, .remove = rk_pwm_remove, }; module_platform_driver_probe(rk_pwm_driver, rk_pwm_probe); MODULE_LICENSE("GPL");