ARM64: DTS: Fix Firefly board audio driver
[firefly-linux-kernel-4.4.55.git] / drivers / input / remotectl / rockchip_pwm_remotectl.c
old mode 100755 (executable)
new mode 100644 (file)
index b1db3dc..2b58628
 #include <linux/input.h>
 #include <linux/workqueue.h>
 #include <linux/wakelock.h>
+#include <linux/slab.h>
 #include "rockchip_pwm_remotectl.h"
-
-
+#include <linux/leds.h>
+#include <linux/fb.h>
 
 /*sys/module/rk_pwm_remotectl/parameters,
 modify code_print to change the value*/
 
 static int rk_remote_print_code;
+static bool remote_suspend = false;
 module_param_named(code_print, rk_remote_print_code, int, 0644);
 #define DBG_CODE(args...) \
        do { \
@@ -35,7 +37,19 @@ module_param_named(dbg_level, rk_remote_pwm_dbg_level, int, 0644);
                } \
        } while (0)
 
+#define BLINK_DELAY 50
+DEFINE_LED_TRIGGER(ledtrig_ir_click);
+static unsigned long ir_blink_delay = BLINK_DELAY;
+
+bool get_state_remotectl(void)
+{
+        return remote_suspend;
+}
 
+void ledtrig_ir_activity(void)
+{
+    led_trigger_blink_oneshot(ledtrig_ir_click, &ir_blink_delay, &ir_blink_delay,1);
+}
 struct rkxx_remote_key_table {
        int scancode;
        int keycode;
@@ -44,7 +58,7 @@ struct rkxx_remote_key_table {
 struct rkxx_remotectl_button {
        int usercode;
        int nbuttons;
-       struct rkxx_remote_key_table *key_table;
+       struct rkxx_remote_key_table key_table[MAX_NUM_KEYS];
 };
 
 struct rkxx_remotectl_drvdata {
@@ -55,107 +69,32 @@ struct rkxx_remotectl_drvdata {
        int scandata;
        int count;
        int keynum;
+       int maxkeybdnum;
        int keycode;
        int press;
        int pre_press;
-       int period;
        int irq;
+       int remote_pwm_id;
+       int handle_cpu_id;
        int wakeup;
+       int clk_rate;
+       unsigned long period;
+       unsigned long temp_period;
+       int pwm_freq_nstime;
        struct input_dev *input;
        struct timer_list timer;
        struct tasklet_struct remote_tasklet;
        struct wake_lock remotectl_wake_lock;
 };
 
-
-static struct rkxx_remote_key_table remote_key_table_meiyu_4040[] = {
-       {0xf2, KEY_REPLY},
-       {0xba, KEY_BACK},
-       {0xf4, KEY_UP},
-       {0xf1, KEY_DOWN},
-       {0xef, KEY_LEFT},
-       {0xee, KEY_RIGHT},
-       {0xbd, KEY_HOME},
-       {0xea, KEY_VOLUMEUP},
-       {0xe3, KEY_VOLUMEDOWN},
-       {0xe2, KEY_SEARCH},
-       {0xb2, KEY_POWER},
-       {0xbc, KEY_MUTE},
-       {0xec, KEY_MENU},
-/*lay pause*/
-       {0xbf, 0x190},
-/*pre*/
-       {0xe0, 0x191},
-/*next*/
-       {0xe1, 0x192},
-/*pic,rorate left*/
-       {0xe9, 183},
-/*rorate right*/
-       {0xe6, 248},
-/*zoom out*/
-       {0xe8, 185},
-/*zoom in*/
-       {0xe7, 186},
-/*mouse switch*/
-       {0xb8, 388},
-/*zoom outdisplay switch*/
-       {0xbe, 0x175},
-};
-
-
-static struct rkxx_remote_key_table remote_key_table_sunchip_ff00[] = {
-       {0xf9, KEY_HOME},
-       {0xbf, KEY_BACK},
-       {0xfb, KEY_MENU},
-       {0xaa, KEY_REPLY},
-       {0xb9, KEY_UP},
-       {0xe9, KEY_DOWN},
-       {0xb8, KEY_LEFT},
-       {0xea, KEY_RIGHT},
-       {0xeb, KEY_VOLUMEDOWN},
-       {0xef, KEY_VOLUMEUP},
-       {0xf7, KEY_MUTE},
-       {0xe7, KEY_POWER},
-       {0xfc, KEY_POWER},
-       {0xa9, KEY_VOLUMEDOWN},
-       {0xa8, KEY_VOLUMEDOWN},
-       {0xe0, KEY_VOLUMEDOWN},
-       {0xa5, KEY_VOLUMEDOWN},
-       {0xab, 183},
-       {0xb7, 388},
-       {0xf8, 184},
-       {0xaf, 185},
-       {0xed, KEY_VOLUMEDOWN},
-       {0xee, 186},
-       {0xb3, KEY_VOLUMEDOWN},
-       {0xf1, KEY_VOLUMEDOWN},
-       {0xf2, KEY_VOLUMEDOWN},
-       {0xf3, KEY_SEARCH},
-       {0xb4, KEY_VOLUMEDOWN},
-       {0xbe, KEY_SEARCH},
-};
-
-
-static struct rkxx_remotectl_button remotectl_button[] = {
-       {
-               .usercode = 0xff00,
-               .nbuttons =  29,
-               .key_table = &remote_key_table_sunchip_ff00[0],
-       },
-       {
-               .usercode = 0x4040,
-               .nbuttons =  22,
-               .key_table = &remote_key_table_meiyu_4040[0],
-       },
-};
-
+static struct rkxx_remotectl_button *remotectl_button;
 
 static int remotectl_keybd_num_lookup(struct rkxx_remotectl_drvdata *ddata)
 {
        int i;
        int num;
 
-       num =  sizeof(remotectl_button)/sizeof(struct rkxx_remotectl_button);
+       num = ddata->maxkeybdnum;
        for (i = 0; i < num; i++) {
                if (remotectl_button[i].usercode == (ddata->scandata&0xFFFF)) {
                        ddata->keynum = i;
@@ -182,6 +121,72 @@ static int remotectl_keycode_lookup(struct rkxx_remotectl_drvdata *ddata)
        return 0;
 }
 
+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 property 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 property 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)
 {
@@ -194,7 +199,7 @@ static void rk_pwm_remotectl_do_something(unsigned long  data)
                break;
        }
        case RMC_PRELOAD: {
-               mod_timer(&ddata->timer, jiffies + msecs_to_jiffies(130));
+               mod_timer(&ddata->timer, jiffies + msecs_to_jiffies(140));
                if ((RK_PWM_TIME_PRE_MIN < ddata->period) &&
                    (ddata->period < RK_PWM_TIME_PRE_MAX)) {
                        ddata->scandata = 0;
@@ -217,12 +222,24 @@ static void rk_pwm_remotectl_do_something(unsigned long  data)
                                ddata->scandata = 0;
                                ddata->count = 0;
                        } else {
-                               ddata->state = RMC_PRELOAD;
+                               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(!get_state_remotectl() && (ddata->keycode != KEY_POWER))
+                {
+                        ledtrig_ir_activity();
+                }
+               if(ddata->keycode != KEY_POWER)
+               led_trigger_blink_oneshot(ledtrig_ir_click, &ir_blink_delay, &ir_blink_delay,1);
+
                if ((RK_PWM_TIME_BIT1_MIN < ddata->period) &&
                    (ddata->period < RK_PWM_TIME_BIT1_MAX))
                        ddata->scandata |= (0x01<<ddata->count);
@@ -234,6 +251,9 @@ static void rk_pwm_remotectl_do_something(unsigned long  data)
                    ((~ddata->scandata >> 8) & 0x0ff)) {
                        if (remotectl_keycode_lookup(ddata)) {
                                ddata->press = 1;
+                               if(ddata->keycode== KEY_POWER && !get_state_remotectl()){
+                                       led_trigger_event(ledtrig_ir_click,LED_OFF);
+                }
                                input_event(ddata->input, EV_KEY,
                                            ddata->keycode, 1);
                                input_sync(ddata->input);
@@ -247,22 +267,22 @@ static void rk_pwm_remotectl_do_something(unsigned long  data)
        }
        break;
        case RMC_SEQUENCE:{
-               DBG("S=%d\n", ddata->period);
+               DBG("S=%ld\n", ddata->period);
                if ((RK_PWM_TIME_RPT_MIN < ddata->period) &&
                    (ddata->period < RK_PWM_TIME_RPT_MAX)) {
                        DBG("S1\n");
                        mod_timer(&ddata->timer, jiffies
-                                 + msecs_to_jiffies(110));
+                                 + msecs_to_jiffies(130));
                } else if ((RK_PWM_TIME_SEQ1_MIN < ddata->period) &&
                           (ddata->period < RK_PWM_TIME_SEQ1_MAX)) {
                        DBG("S2\n");
                        mod_timer(&ddata->timer, jiffies
-                                 + msecs_to_jiffies(110));
+                                 + msecs_to_jiffies(130));
                } else if ((RK_PWM_TIME_SEQ2_MIN < ddata->period) &&
                          (ddata->period < RK_PWM_TIME_SEQ2_MAX)) {
                        DBG("S3\n");
                        mod_timer(&ddata->timer, jiffies
-                                 + msecs_to_jiffies(110));
+                                 + msecs_to_jiffies(130));
                } else {
                        DBG("S4\n");
                        input_event(ddata->input, EV_KEY,
@@ -295,29 +315,45 @@ static void rk_pwm_remotectl_timer(unsigned long _data)
 
 static irqreturn_t rockchip_pwm_irq(int irq, void *dev_id)
 {
-       struct rkxx_remotectl_drvdata *ddata;
+       struct rkxx_remotectl_drvdata *ddata = dev_id;
        int val;
-
-       ddata = (struct rkxx_remotectl_drvdata *)dev_id;
-       val = readl_relaxed(ddata->base + PWM_REG_INTSTS);
-       if (val&PWM_CH3_INT) {
-               if (val & PWM_CH3_POL) {
-                       val = readl_relaxed(ddata->base + PWM_REG_HPR);
-                       ddata->period = 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);
+               DBG("hpr=%d\n", temp_hpr);
+               temp_lpr = readl_relaxed(ddata->base + PWM_REG_LPR);
+               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);
-                       DBG("hpr=0x%x\n", val);
+                       ddata->temp_period = 0;
+                       DBG("period+ =%ld\n", ddata->period);
                } else {
-                       val = readl_relaxed(ddata->base + PWM_REG_LPR);
-                       DBG("lpr=0x%x\n", val);
+                       ddata->temp_period += ddata->pwm_freq_nstime
+                           * (temp_hpr + temp_lpr) / 1000;
                }
-               writel_relaxed(PWM_CH3_INT, ddata->base + PWM_REG_INTSTS);
-               if (ddata->state == RMC_PRELOAD)
-                       wake_lock_timeout(&ddata->remotectl_wake_lock, HZ);
-               return IRQ_HANDLED;
        }
-       return IRQ_NONE;
+       writel_relaxed(PWM_CH_INT(id), ddata->base + PWM_REG_INTSTS(id));
+#if ! defined(CONFIG_RK_IR_NO_DEEP_SLEEP)
+       if (ddata->state == RMC_PRELOAD)
+               wake_lock_timeout(&ddata->remotectl_wake_lock, HZ);
+#endif
+       return IRQ_HANDLED;
 }
 
+
+
 static int rk_pwm_remotectl_hw_init(struct rkxx_remotectl_drvdata *ddata)
 {
        int val;
@@ -329,31 +365,89 @@ static int rk_pwm_remotectl_hw_init(struct rkxx_remotectl_drvdata *ddata)
        val = (val & 0xFFFFFFF9) | PWM_MODE_CAPTURE;
        writel_relaxed(val, ddata->base + PWM_REG_CTRL);
        val = readl_relaxed(ddata->base + PWM_REG_CTRL);
-       val = (val & 0xFF008DFF) | 0x00646200;
+       val = (val & 0xFF008DFF) | 0x0006000;
        writel_relaxed(val, ddata->base + PWM_REG_CTRL);
-       val = readl_relaxed(ddata->base + PWM_REG_INT_EN);
-       val = (val & 0xFFFFFFF7) | PWM_CH3_INT_ENABLE;
-       writel_relaxed(val, ddata->base + PWM_REG_INT_EN);
+       switch (ddata->remote_pwm_id) {
+       case 0: {
+               val = readl_relaxed(ddata->base + PWM0_REG_INT_EN);
+               val = (val & 0xFFFFFFFE) | PWM_CH0_INT_ENABLE;
+               writel_relaxed(val, ddata->base + PWM0_REG_INT_EN);
+       }
+       break;
+       case 1: {
+               val = readl_relaxed(ddata->base + PWM1_REG_INT_EN);
+               val = (val & 0xFFFFFFFD) | PWM_CH1_INT_ENABLE;
+               writel_relaxed(val, ddata->base + PWM1_REG_INT_EN);
+       }
+       break;
+       case 2: {
+               val = readl_relaxed(ddata->base + PWM2_REG_INT_EN);
+               val = (val & 0xFFFFFFFB) | PWM_CH2_INT_ENABLE;
+               writel_relaxed(val, ddata->base + PWM2_REG_INT_EN);
+       }
+       break;
+       case 3: {
+               val = readl_relaxed(ddata->base + PWM3_REG_INT_EN);
+               val = (val & 0xFFFFFFF7) | PWM_CH3_INT_ENABLE;
+               writel_relaxed(val, ddata->base + PWM3_REG_INT_EN);
+       }
+       break;
+       default:
+       break;
+       }
        val = readl_relaxed(ddata->base + PWM_REG_CTRL);
        val = (val & 0xFFFFFFFE) | PWM_ENABLE;
        writel_relaxed(val, ddata->base + PWM_REG_CTRL);
        return 0;
 }
 
-
+static int remotectl_fb_event_notify(struct notifier_block *self, unsigned long action, void *data)
+{
+       struct fb_event *event = data;
+
+       if (action == FB_EARLY_EVENT_BLANK) {
+               switch (*((int *)event->data)) {
+                       case FB_BLANK_UNBLANK:
+                               break;
+                       default:
+                               led_trigger_event(ledtrig_ir_click,LED_OFF);
+                               remote_suspend = true;
+                               break;
+               }
+       }
+       else if (action == FB_EVENT_BLANK) {
+               switch (*((int *)event->data)) {
+                       case FB_BLANK_UNBLANK:
+                               remote_suspend = false;
+                               led_trigger_event(ledtrig_ir_click,LED_FULL);
+                               break;
+                       default:
+                               break;
+               }
+       }
+       return NOTIFY_OK;
+}
+static struct notifier_block remotectl_fb_notifier = {
+         .notifier_call = remotectl_fb_event_notify,
+};
 
 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 cpumask cpumask;
        int num;
        int irq;
        int ret;
        int i, j;
+       int cpu_id;
+       int pwm_id;
+       int pwm_freq;
 
-       DBG(".. rk pwm remotectl v1.1 init\n");
+       pr_err(".. rk pwm remotectl v1.1 init\n");
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!r) {
                dev_err(&pdev->dev, "no memory resources defined\n");
@@ -366,13 +460,27 @@ static int rk_pwm_probe(struct platform_device *pdev)
                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);
-       clk = devm_clk_get(&pdev->dev, "pclk_pwm");
+       clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(clk))
                return PTR_ERR(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");
+               return -1;
+       }
+       ddata->maxkeybdnum = num;
+       remotectl_button = kmalloc(
+                                       num*sizeof(struct rkxx_remotectl_button),
+                                       GFP_KERNEL);
+       if (!remotectl_button) {
+               pr_err("failed to malloc remote button memory\n");
+               return -ENOMEM;
+       }
        input = input_allocate_device();
        input->name = pdev->name;
        input->phys = "gpio-keys/remotectl";
@@ -383,8 +491,12 @@ static int rk_pwm_probe(struct platform_device *pdev)
        input->id.version = 0x0100;
        ddata->input = input;
        ddata->input = input;
+    fb_register_client(&remotectl_fb_notifier);
        wake_lock_init(&ddata->remotectl_wake_lock,
                       WAKE_LOCK_SUSPEND, "rk29_pwm_remote");
+#if defined(CONFIG_RK_IR_NO_DEEP_SLEEP)
+    wake_lock(&ddata->remotectl_wake_lock);
+#endif
        ret = clk_prepare_enable(clk);
        if (ret)
                return ret;
@@ -395,9 +507,15 @@ static int rk_pwm_probe(struct platform_device *pdev)
        }
        ddata->irq = irq;
        ddata->wakeup = 1;
+       of_property_read_u32(np, "remote_pwm_id", &pwm_id);
+       ddata->remote_pwm_id = pwm_id;
+       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);
-       num =  sizeof(remotectl_button)/sizeof(struct rkxx_remotectl_button);
        for (j = 0; j < num; j++) {
                DBG("remotectl probe j = 0x%x\n", j);
                for (i = 0; i < remotectl_button[j].nbuttons; i++) {
@@ -412,25 +530,72 @@ static int rk_pwm_probe(struct platform_device *pdev)
                pr_err("remotectl: 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);
+       setup_timer(&ddata->timer, rk_pwm_remotectl_timer,
+                   (unsigned long)ddata);
+       //mod_timer(&ddata->timer, jiffies + msecs_to_jiffies(1000));
+       cpumask_clear(&cpumask);
+       cpumask_set_cpu(cpu_id, &cpumask);
+       irq_set_affinity(irq, &cpumask);
        ret = devm_request_irq(&pdev->dev, irq, rockchip_pwm_irq,
-                              0, "rk_pwm_irq", ddata);
+                              IRQF_NO_SUSPEND, "rk_pwm_irq", ddata);
        if (ret) {
                dev_err(&pdev->dev, "cannot claim IRQ %d\n", irq);
                return ret;
        }
-       enable_irq_wake(irq);
-       setup_timer(&ddata->timer, rk_pwm_remotectl_timer,
-                   (unsigned long)ddata);
-       mod_timer(&ddata->timer, jiffies + msecs_to_jiffies(1000));
        rk_pwm_remotectl_hw_init(ddata);
+       pwm_freq = clk_get_rate(clk) / 64;
+       ddata->pwm_freq_nstime = 1000000000 / pwm_freq;
+       led_trigger_register_simple("ir-power-click", &ledtrig_ir_click);
+
        return ret;
 }
 
 static int rk_pwm_remove(struct platform_device *pdev)
 {
+#if defined(CONFIG_RK_IR_NO_DEEP_SLEEP)
+    struct rkxx_remotectl_drvdata *ddata = platform_get_drvdata(pdev);
+#endif
+       led_trigger_unregister_simple(ledtrig_ir_click);
+#if defined(CONFIG_RK_IR_NO_DEEP_SLEEP)
+    wake_unlock(&ddata->remotectl_wake_lock);
+#endif
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int remotectl_suspend(struct device *dev)
+{
+       int cpu = 0;
+       struct cpumask cpumask;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rkxx_remotectl_drvdata *ddata = platform_get_drvdata(pdev);
+
+       cpumask_clear(&cpumask);
+       cpumask_set_cpu(cpu, &cpumask);
+       irq_set_affinity(ddata->irq, &cpumask);
+       return 0;
+}
+
+
+static int remotectl_resume(struct device *dev)
+{
+       struct cpumask cpumask;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rkxx_remotectl_drvdata *ddata = platform_get_drvdata(pdev);
+
+       led_trigger_event(ledtrig_ir_click,LED_FULL);
+       cpumask_clear(&cpumask);
+       cpumask_set_cpu(ddata->handle_cpu_id, &cpumask);
+       irq_set_affinity(ddata->irq, &cpumask);
+       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"},
@@ -443,6 +608,9 @@ 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
        },
        .probe = rk_pwm_probe,
        .remove = rk_pwm_remove,