#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/wakelock.h>
+#include <linux/slab.h>
#include "rockchip_pwm_remotectl.h"
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 {
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;
struct input_dev *input;
struct timer_list timer;
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_remote_key_table remote_key_table_0x1dcc[] = {
- {0xee, KEY_REPLY},
- {0xf0, KEY_BACK},
- {0xf8, KEY_UP},
- {0xbb, KEY_DOWN},
- {0xef, KEY_LEFT},
- {0xed, KEY_RIGHT},
- {0xfc, KEY_HOME},
- {0xf1, KEY_VOLUMEUP},
- {0xfd, KEY_VOLUMEDOWN},
- {0xb7, KEY_SEARCH},
- {0xff, KEY_POWER},
- {0xf3, KEY_MUTE},
- {0xbf, KEY_MENU},
- {0xf9, 0x191},
- {0xf5, 0x192},
- {0xb3, 388},
- {0xbe, KEY_1},
- {0xba, KEY_2},
- {0xb2, KEY_3},
- {0xbd, KEY_4},
- {0xf9, KEY_5},
- {0xb1, KEY_6},
- {0xfc, KEY_7},
- {0xf8, KEY_8},
- {0xb0, KEY_9},
- {0xb6, KEY_0},
- {0xb5, KEY_BACKSPACE},
-};
-
-
-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],
- },
- {
- .usercode = 0x1dcc,
- .nbuttons = 27,
- .key_table = &remote_key_table_0x1dcc[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;
}
+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;
+ u32 loop;
+ u32 ret;
+ u32 len;
+ u32 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)
{
struct rkxx_remotectl_drvdata *ddata;
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) == 0) {
- val = readl_relaxed(ddata->base + PWM_REG_HPR);
- ddata->period = val;
- tasklet_hi_schedule(&ddata->remote_tasklet);
- DBG("hpr=0x%x\n", val);
- } else {
- val = readl_relaxed(ddata->base + PWM_REG_LPR);
- DBG("lpr=0x%x\n", val);
+ switch (ddata->remote_pwm_id) {
+ case 0: {
+ val = readl_relaxed(ddata->base + PWM0_REG_INTSTS);
+ if (val & PWM_CH0_INT) {
+ if ((val & PWM_CH0_POL) == 0) {
+ val = readl_relaxed(ddata->base + PWM_REG_HPR);
+ ddata->period = val;
+ tasklet_hi_schedule(&ddata->remote_tasklet);
+ DBG("hpr=0x%x\n", val);
+ } else {
+ val = readl_relaxed(ddata->base + PWM_REG_LPR);
+ DBG("lpr=0x%x\n", val);
+ }
+ writel_relaxed(PWM_CH0_INT, ddata->base + PWM0_REG_INTSTS);
+ if (ddata->state == RMC_PRELOAD)
+ wake_lock_timeout(&ddata->remotectl_wake_lock, HZ);
+ return IRQ_HANDLED;
+ }
+ }
+ break;
+ case 1: {
+ val = readl_relaxed(ddata->base + PWM1_REG_INTSTS);
+ if (val & PWM_CH1_INT) {
+ if ((val & PWM_CH1_POL) == 0) {
+ val = readl_relaxed(ddata->base + PWM_REG_HPR);
+ ddata->period = val;
+ tasklet_hi_schedule(&ddata->remote_tasklet);
+ DBG("hpr=0x%x\n", val);
+ } else {
+ val = readl_relaxed(ddata->base + PWM_REG_LPR);
+ DBG("lpr=0x%x\n", val);
+ }
+ writel_relaxed(PWM_CH1_INT, ddata->base + PWM1_REG_INTSTS);
+ if (ddata->state == RMC_PRELOAD)
+ wake_lock_timeout(&ddata->remotectl_wake_lock, HZ);
+ return IRQ_HANDLED;
}
- 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;
}
+ break;
+ case 2: {
+ val = readl_relaxed(ddata->base + PWM2_REG_INTSTS);
+ if (val & PWM_CH2_INT) {
+ if ((val & PWM_CH2_POL) == 0) {
+ val = readl_relaxed(ddata->base + PWM_REG_HPR);
+ ddata->period = val;
+ tasklet_hi_schedule(&ddata->remote_tasklet);
+ DBG("hpr=0x%x\n", val);
+ } else {
+ val = readl_relaxed(ddata->base + PWM_REG_LPR);
+ DBG("lpr=0x%x\n", val);
+ }
+ writel_relaxed(PWM_CH2_INT, ddata->base + PWM2_REG_INTSTS);
+ if (ddata->state == RMC_PRELOAD)
+ wake_lock_timeout(&ddata->remotectl_wake_lock, HZ);
+ return IRQ_HANDLED;
+ }
+ }
+ break;
+ case 3: {
+ val = readl_relaxed(ddata->base + PWM3_REG_INTSTS);
+ if (val & PWM_CH3_INT) {
+ if ((val & PWM_CH3_POL) == 0) {
+ val = readl_relaxed(ddata->base + PWM_REG_HPR);
+ ddata->period = val;
+ tasklet_hi_schedule(&ddata->remote_tasklet);
+ DBG("hpr=0x%x\n", val);
+ } else {
+ val = readl_relaxed(ddata->base + PWM_REG_LPR);
+ DBG("lpr=0x%x\n", val);
+ }
+ writel_relaxed(PWM_CH3_INT, ddata->base + PWM3_REG_INTSTS);
+ if (ddata->state == RMC_PRELOAD)
+ wake_lock_timeout(&ddata->remotectl_wake_lock, HZ);
+ return IRQ_HANDLED;
+ }
+ }
+ break;
+ default:
+ break;
+ }
return IRQ_NONE;
}
val = readl_relaxed(ddata->base + PWM_REG_CTRL);
val = (val & 0xFF008DFF) | 0x00646200;
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);
static int rk_pwm_probe(struct platform_device *pdev)
{
struct rkxx_remotectl_drvdata *ddata;
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *child_node;
struct resource *r;
struct input_dev *input;
struct clk *clk;
+ struct cpumask cpumask;
int num;
int irq;
int ret;
int i, j;
-
- DBG(".. rk pwm remotectl v1.1 init\n");
+ int cpu_id;
+ int pwm_id;
+
+ 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");
if (IS_ERR(clk))
return PTR_ERR(clk);
platform_set_drvdata(pdev, ddata);
+ num = 0;
+ for_each_child_of_node(np, child_node){
+ if(of_device_is_compatible(child_node, "rockchip,ir_key"))
+ num++;
+ }
+ 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";
}
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++) {
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);
rk_pwm_remotectl_hw_init(ddata);
return ret;
}
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);
+
+ 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 = remotectl_suspend,
+ .resume = remotectl_resume,
+};
+#endif
static const struct of_device_id rk_pwm_of_match[] = {
{ .compatible = "rockchip,remotectl-pwm"},
.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,