mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 12:17:12 +09:00
input:ir:add remotectl support
This commit is contained in:
@@ -435,6 +435,18 @@
|
||||
clock-names = "pclk_pwm";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
remotectl: pwm@20050030 {
|
||||
compatible = "rockchip,remotectl-pwm";
|
||||
reg = <0x20050030 0x10>;
|
||||
#pwm-cells = <2>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm3_pin>;
|
||||
clocks = <&clk_gates7 10>;
|
||||
clock-names = "pclk_pwm";
|
||||
interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
emmc: rksdmmc@1021c000 {
|
||||
compatible = "rockchip,rk_mmc", "rockchip,rk3036-sdmmc";
|
||||
|
||||
@@ -299,6 +299,8 @@ CONFIG_INPUT_GPIO=y
|
||||
# CONFIG_COMPASS_DEVICE is not set
|
||||
# CONFIG_GYROSCOPE_DEVICE is not set
|
||||
# CONFIG_HALL_DEVICE is not set
|
||||
CONFIG_ROCKCHIP_REMOTECTL=y
|
||||
CONFIG_ROCKCHIP_REMOTECTL_PWM=y
|
||||
# CONFIG_SERIO is not set
|
||||
# CONFIG_VT is not set
|
||||
# CONFIG_LEGACY_PTYS is not set
|
||||
|
||||
2
drivers/input/Kconfig
Normal file → Executable file
2
drivers/input/Kconfig
Normal file → Executable file
@@ -198,6 +198,8 @@ source "drivers/input/touchscreen/Kconfig"
|
||||
source "drivers/input/misc/Kconfig"
|
||||
|
||||
source "drivers/input/sensors/Kconfig"
|
||||
|
||||
source "drivers/input/remotectl/Kconfig"
|
||||
endif
|
||||
|
||||
menu "Hardware I/O ports"
|
||||
|
||||
1
drivers/input/Makefile
Normal file → Executable file
1
drivers/input/Makefile
Normal file → Executable file
@@ -26,3 +26,4 @@ obj-$(CONFIG_INPUT_MISC) += misc/
|
||||
obj-$(CONFIG_SENSOR_DEVICE) += sensors/
|
||||
obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o
|
||||
obj-$(CONFIG_INPUT_KEYRESET) += keyreset.o
|
||||
obj-$(CONFIG_ROCKCHIP_REMOTECTL) += remotectl/
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Touchscreen driver configuration
|
||||
#
|
||||
menuconfig ROCKCHIP_REMOTECTL
|
||||
bool "rkxx remotectl"
|
||||
bool "rockchip remotectl"
|
||||
default n
|
||||
help
|
||||
Say Y here, will suport rk remotectl.
|
||||
@@ -11,12 +11,7 @@ menuconfig ROCKCHIP_REMOTECTL
|
||||
|
||||
if ROCKCHIP_REMOTECTL
|
||||
|
||||
config RK_REMOTECTL
|
||||
bool "rkxx remoctrl"
|
||||
config ROCKCHIP_REMOTECTL_PWM
|
||||
bool "rockchip remoctrl pwm capture"
|
||||
default n
|
||||
|
||||
config RK_IR_WAKEUP
|
||||
bool "rkxx remoctrl wakeup"
|
||||
depends on PLAT_RK
|
||||
default n
|
||||
endif
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
# Each configuration option enables a list of files.
|
||||
|
||||
|
||||
obj-$(CONFIG_RK_REMOTECTL) += rkxx_remotectl.o
|
||||
obj-$(CONFIG_ROCKCHIP_REMOTECTL_PWM) += rockchip_pwm_remotectl.o
|
||||
|
||||
@@ -1,686 +0,0 @@
|
||||
|
||||
/*
|
||||
* Driver for keys on GPIO lines capable of generating interrupts.
|
||||
*
|
||||
* Copyright 2005 Phil Blundell
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/adc.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <mach/remotectl.h>
|
||||
#include <mach/iomux.h>
|
||||
#include <linux/wakelock.h>
|
||||
#include <linux/suspend.h>
|
||||
|
||||
|
||||
#if 1
|
||||
#define remotectl_dbg(bdata, format, arg...) \
|
||||
dev_printk(KERN_INFO , &bdata->input->dev , format , ## arg)
|
||||
#else
|
||||
#define remotectl_dbg(bdata, format, arg...)
|
||||
#endif
|
||||
|
||||
extern suspend_state_t get_suspend_state(void);
|
||||
|
||||
struct rkxx_remotectl_suspend_data{
|
||||
int suspend_flag;
|
||||
int cnt;
|
||||
long scanTime[50];
|
||||
};
|
||||
|
||||
struct rkxx_remote_key_table{
|
||||
int scanCode;
|
||||
int keyCode;
|
||||
};
|
||||
|
||||
struct rkxx_remotectl_button {
|
||||
int usercode;
|
||||
int nbuttons;
|
||||
struct rkxx_remote_key_table *key_table;
|
||||
};
|
||||
|
||||
struct rkxx_remotectl_drvdata {
|
||||
int state;
|
||||
int nbuttons;
|
||||
int result;
|
||||
unsigned long pre_time;
|
||||
unsigned long cur_time;
|
||||
long int pre_sec;
|
||||
long int cur_sec;
|
||||
long period;
|
||||
int scanData;
|
||||
int count;
|
||||
int keybdNum;
|
||||
int keycode;
|
||||
int press;
|
||||
int pre_press;
|
||||
|
||||
struct input_dev *input;
|
||||
struct timer_list timer;
|
||||
struct tasklet_struct remote_tasklet;
|
||||
struct wake_lock remotectl_wake_lock;
|
||||
struct rkxx_remotectl_suspend_data remotectl_suspend_data;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//<2F><><EFBFBD><EFBFBD>ܼ<EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD>
|
||||
//193 //photo
|
||||
//194 //video
|
||||
//195 //music
|
||||
//196 //IE
|
||||
//197 //
|
||||
//198
|
||||
//199
|
||||
//200
|
||||
|
||||
//183 //rorate_left
|
||||
//184 //rorate_right
|
||||
//185 //zoom out
|
||||
//186 //zoom in
|
||||
|
||||
static struct rkxx_remote_key_table remote_key_table_meiyu_202[] = {
|
||||
{0xB0, KEY_ENTER},//ok = DPAD CENTER
|
||||
{0xA2, KEY_BACK},
|
||||
{0xD0, KEY_UP},
|
||||
{0x70, KEY_DOWN},
|
||||
{0x08, KEY_LEFT},
|
||||
{0x88, KEY_RIGHT}, ////////
|
||||
{0x42, KEY_HOME}, //home
|
||||
{0xA8, KEY_VOLUMEUP},
|
||||
{0x38, KEY_VOLUMEDOWN},
|
||||
{0xE2, KEY_SEARCH}, //search
|
||||
{0xB2, KEY_POWER}, //power off
|
||||
{0xC2, KEY_MUTE}, //mute
|
||||
{0xC8, KEY_MENU},
|
||||
|
||||
//media ctrl
|
||||
{0x78, 0x190}, //play pause
|
||||
{0xF8, 0x191}, //pre
|
||||
{0x02, 0x192}, //next
|
||||
|
||||
//pic
|
||||
{0xB8, 183}, //rorate left
|
||||
{0x58, 248}, //rorate right
|
||||
{0x68, 185}, //zoom out
|
||||
{0x98, 186}, //zoom in
|
||||
//mouse switch
|
||||
{0xf0,388},
|
||||
//display switch
|
||||
{0x82, 0x175},
|
||||
};
|
||||
|
||||
static struct rkxx_remote_key_table remote_key_table_df[] = {
|
||||
{0xf8, KEY_REPLY},
|
||||
{0xc0, KEY_BACK},
|
||||
{0xf0, KEY_UP},
|
||||
{0xd8, KEY_DOWN},
|
||||
{0xd0, KEY_LEFT},
|
||||
{0xe8,KEY_RIGHT}, ////////
|
||||
{0x90, KEY_VOLUMEDOWN},
|
||||
{0x60, KEY_VOLUMEUP},
|
||||
{0x80, KEY_HOME}, //home
|
||||
{0xe0, 183}, //rorate left
|
||||
{0x10, 184}, //rorate right
|
||||
{0x20, 185}, //zoom out
|
||||
{0xa0, 186}, //zoom in
|
||||
{0x70, KEY_MUTE}, //mute
|
||||
{0x50, KEY_POWER}, //power off
|
||||
{0x40, KEY_SEARCH}, //search
|
||||
};
|
||||
|
||||
extern suspend_state_t get_suspend_state(void);
|
||||
|
||||
|
||||
static struct rkxx_remotectl_button remotectl_button[] =
|
||||
{
|
||||
{
|
||||
.usercode = 0x206,
|
||||
.nbuttons = 22,
|
||||
.key_table = &remote_key_table_meiyu_202[0],
|
||||
},
|
||||
{
|
||||
.usercode = 0x12ee,
|
||||
.nbuttons = 22,
|
||||
.key_table = &remote_key_table_meiyu_202[0],
|
||||
},
|
||||
{
|
||||
.usercode = 0x202,
|
||||
.nbuttons = 22,
|
||||
.key_table = &remote_key_table_meiyu_202[0],
|
||||
},
|
||||
{
|
||||
.usercode = 0xdf,
|
||||
.nbuttons = 16,
|
||||
.key_table = &remote_key_table_df[0],
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
|
||||
static int remotectl_keybdNum_lookup(struct rkxx_remotectl_drvdata *ddata)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(remotectl_button)/sizeof(struct rkxx_remotectl_button); i++){
|
||||
if (remotectl_button[i].usercode == (ddata->scanData&0xFFFF)){
|
||||
ddata->keybdNum = i;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int remotectl_keycode_lookup(struct rkxx_remotectl_drvdata *ddata)
|
||||
{
|
||||
int i;
|
||||
unsigned char keyData = ((ddata->scanData >> 8) & 0xff);
|
||||
|
||||
for (i = 0; i < remotectl_button[ddata->keybdNum].nbuttons; i++){
|
||||
if (remotectl_button[ddata->keybdNum].key_table[i].scanCode == keyData){
|
||||
ddata->keycode = remotectl_button[ddata->keybdNum].key_table[i].keyCode;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void remotectl_get_pwr_scanData(struct rkxx_remotectl_drvdata *ddata,int *pwr_data,int loop)
|
||||
{
|
||||
int i;
|
||||
int temp_scanCode;
|
||||
int temp_pwr_data;
|
||||
|
||||
for (i = 0; i < remotectl_button[loop].nbuttons; i++){
|
||||
if (remotectl_button[loop].key_table[i].keyCode == KEY_POWER){
|
||||
temp_scanCode = remotectl_button[loop].key_table[i].scanCode;
|
||||
temp_pwr_data = (temp_scanCode<<8)|((~temp_scanCode)&0xFF);
|
||||
//printk("pwr data =0x%x\n",temp_pwr_data);
|
||||
}
|
||||
}
|
||||
*pwr_data = temp_pwr_data;
|
||||
}
|
||||
|
||||
static void remotectl_do_something(unsigned long data)
|
||||
{
|
||||
struct rkxx_remotectl_drvdata *ddata = (struct rkxx_remotectl_drvdata *)data;
|
||||
|
||||
switch (ddata->state)
|
||||
{
|
||||
case RMC_IDLE:
|
||||
{
|
||||
;
|
||||
}
|
||||
break;
|
||||
|
||||
case RMC_PRELOAD:
|
||||
{
|
||||
mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(130));
|
||||
//printk("RMC_PRELOAD,period=%d\n",ddata->period);
|
||||
if ((TIME_PRE_MIN < ddata->period) && (ddata->period < TIME_PRE_MAX)){
|
||||
|
||||
ddata->scanData = 0;
|
||||
ddata->count = 0;
|
||||
ddata->state = RMC_USERCODE;
|
||||
}else{
|
||||
ddata->state = RMC_PRELOAD;
|
||||
}
|
||||
ddata->pre_time = ddata->cur_time;
|
||||
//mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(130));
|
||||
}
|
||||
break;
|
||||
|
||||
case RMC_USERCODE:
|
||||
{
|
||||
ddata->scanData <<= 1;
|
||||
ddata->count ++;
|
||||
printk("RMC_USERCODE,period=%d<><64>count=%d\n",ddata->period,ddata->count );
|
||||
if ((TIME_BIT1_MIN < ddata->period) && (ddata->period < TIME_BIT1_MAX)){
|
||||
ddata->scanData |= 0x01;
|
||||
}
|
||||
|
||||
if (ddata->count == 0x10){//16 bit user code
|
||||
printk("u=0x%x\n",((ddata->scanData)&0xFFFF));
|
||||
if (remotectl_keybdNum_lookup(ddata)){
|
||||
ddata->state = RMC_GETDATA;
|
||||
ddata->scanData = 0;
|
||||
ddata->count = 0;
|
||||
}else{ //user code error
|
||||
ddata->state = RMC_PRELOAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RMC_GETDATA:
|
||||
{
|
||||
ddata->count ++;
|
||||
ddata->scanData <<= 1;
|
||||
|
||||
|
||||
if ((TIME_BIT1_MIN < ddata->period) && (ddata->period < TIME_BIT1_MAX)){
|
||||
ddata->scanData |= 0x01;
|
||||
}
|
||||
if (ddata->count == 0x10){
|
||||
//printk("RMC_GETDATA=%x\n",(ddata->scanData&0xFFFF));
|
||||
|
||||
if ((ddata->scanData&0x0ff) == ((~ddata->scanData >> 8)&0x0ff)){
|
||||
if (remotectl_keycode_lookup(ddata)){
|
||||
ddata->press = 1;
|
||||
/*
|
||||
if (get_suspend_state()==0){
|
||||
input_event(ddata->input, EV_KEY, ddata->keycode, 1);
|
||||
input_sync(ddata->input);
|
||||
}else if ((get_suspend_state())&&(ddata->keycode==KEY_POWER)){
|
||||
input_event(ddata->input, EV_KEY, KEY_WAKEUP, 1);
|
||||
input_sync(ddata->input);
|
||||
}*/
|
||||
//printk("0\n");
|
||||
input_event(ddata->input, EV_KEY, ddata->keycode, 1);
|
||||
input_sync(ddata->input);
|
||||
//input_event(ddata->input, EV_KEY, ddata->keycode, ddata->press);
|
||||
//input_sync(ddata->input);
|
||||
ddata->state = RMC_SEQUENCE;
|
||||
}else{
|
||||
ddata->state = RMC_PRELOAD;
|
||||
}
|
||||
}else{
|
||||
ddata->state = RMC_PRELOAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RMC_SEQUENCE:{
|
||||
|
||||
//printk( "S=%d\n",ddata->period);
|
||||
|
||||
if ((TIME_RPT_MIN < ddata->period) && (ddata->period < TIME_RPT_MAX)){
|
||||
mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(110));
|
||||
//printk("1\n");;
|
||||
}else if ((TIME_SEQ1_MIN < ddata->period) && (ddata->period < TIME_SEQ1_MAX)){
|
||||
mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(110));
|
||||
//printk("2\n");
|
||||
}else if ((TIME_SEQ2_MIN < ddata->period) && (ddata->period < TIME_SEQ2_MAX)){
|
||||
mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(110));
|
||||
//printk("3\n");;
|
||||
}else{
|
||||
input_event(ddata->input, EV_KEY, ddata->keycode, 0);
|
||||
input_sync(ddata->input);
|
||||
ddata->state = RMC_PRELOAD;
|
||||
ddata->press = 0;
|
||||
//printk("4\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
void remotectl_wakeup(unsigned long _data)
|
||||
{
|
||||
struct rkxx_remotectl_drvdata *ddata = (struct rkxx_remotectl_drvdata*)_data;
|
||||
long *time;
|
||||
int i;
|
||||
int power_scanData;
|
||||
|
||||
time = ddata->remotectl_suspend_data.scanTime;
|
||||
|
||||
if (get_suspend_state()){
|
||||
ddata->remotectl_suspend_data.suspend_flag = 0;
|
||||
ddata->count = 0;
|
||||
ddata->state = RMC_USERCODE;
|
||||
ddata->scanData = 0;
|
||||
|
||||
for (i=0;i<ddata->remotectl_suspend_data.cnt;i++){
|
||||
if (ddata->count>=32)
|
||||
break;
|
||||
|
||||
if ((TIME_BIT1_MIN < time[i]) && (time[i] < TIME_BIT1_MAX)){
|
||||
ddata->scanData |= 0x01;
|
||||
ddata->scanData <<= 1;
|
||||
ddata->count ++;;
|
||||
}else if ((TIME_BIT0_MIN < time[i]) && (time[i] < TIME_BIT0_MAX)){
|
||||
ddata->scanData <<= 1;
|
||||
ddata->count ++;;
|
||||
}/*else{
|
||||
if (ddata->count>16){
|
||||
break;
|
||||
}else{
|
||||
|
||||
printk(KERN_ERR "ddata->count=0x%x**********************\n",ddata->count);
|
||||
ddata->count = 0;
|
||||
ddata->scanData = 0;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
//printk(KERN_ERR"data=0x%x\n",ddata->scanData);
|
||||
if (ddata->scanData) //(ddata->scanData>16)
|
||||
{
|
||||
ddata->scanData=(ddata->scanData>>1)&0xFFFF;
|
||||
printk(KERN_ERR"data=0x%x\n",ddata->scanData);
|
||||
|
||||
for (i=0;i<sizeof(remotectl_button)/sizeof(struct rkxx_remotectl_button);i++){
|
||||
remotectl_get_pwr_scanData(ddata,&power_scanData,i);
|
||||
if ((ddata->scanData == power_scanData)||((ddata->scanData&0x0fff) == (power_scanData&0x0fff))||((ddata->scanData&0x00ff) == (power_scanData&0x00ff))) //modified by zwm 2013.06.19
|
||||
{
|
||||
input_event(ddata->input, EV_KEY, KEY_WAKEUP, 1);
|
||||
input_sync(ddata->input);
|
||||
input_event(ddata->input, EV_KEY, KEY_WAKEUP, 0);
|
||||
input_sync(ddata->input);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
memset(ddata->remotectl_suspend_data.scanTime,0,50*sizeof(long));
|
||||
ddata->remotectl_suspend_data.cnt= 0;
|
||||
ddata->state = RMC_PRELOAD;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static void remotectl_timer(unsigned long _data)
|
||||
{
|
||||
struct rkxx_remotectl_drvdata *ddata = (struct rkxx_remotectl_drvdata*)_data;
|
||||
|
||||
//printk("to\n");
|
||||
|
||||
if(ddata->press != ddata->pre_press) {
|
||||
ddata->pre_press = ddata->press = 0;
|
||||
|
||||
input_event(ddata->input, EV_KEY, ddata->keycode, 0);
|
||||
input_sync(ddata->input);
|
||||
//printk("5\n");
|
||||
//if (get_suspend_state()==0){
|
||||
//input_event(ddata->input, EV_KEY, ddata->keycode, 1);
|
||||
//input_sync(ddata->input);
|
||||
//input_event(ddata->input, EV_KEY, ddata->keycode, 0);
|
||||
//input_sync(ddata->input);
|
||||
//}else if ((get_suspend_state())&&(ddata->keycode==KEY_POWER)){
|
||||
//input_event(ddata->input, EV_KEY, KEY_WAKEUP, 1);
|
||||
//input_sync(ddata->input);
|
||||
//input_event(ddata->input, EV_KEY, KEY_WAKEUP, 0);
|
||||
//input_sync(ddata->input);
|
||||
//}
|
||||
}
|
||||
#ifdef CONFIG_PM
|
||||
remotectl_wakeup(_data);
|
||||
#endif
|
||||
ddata->state = RMC_PRELOAD;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static irqreturn_t remotectl_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct rkxx_remotectl_drvdata *ddata = (struct rkxx_remotectl_drvdata*)dev_id;
|
||||
struct timeval ts;
|
||||
|
||||
|
||||
ddata->pre_time = ddata->cur_time;
|
||||
ddata->pre_sec = ddata->cur_sec;
|
||||
do_gettimeofday(&ts);
|
||||
ddata->cur_time = ts.tv_usec;
|
||||
ddata->cur_sec = ts.tv_sec;
|
||||
|
||||
if (likely(ddata->cur_sec == ddata->pre_sec)){
|
||||
ddata->period = ddata->cur_time - ddata->pre_time;
|
||||
}else{
|
||||
ddata->period = 1000000 - ddata->pre_time + ddata->cur_time;
|
||||
}
|
||||
|
||||
tasklet_hi_schedule(&ddata->remote_tasklet);
|
||||
//if ((ddata->state==RMC_PRELOAD)||(ddata->state==RMC_SEQUENCE))
|
||||
//mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(130));
|
||||
#ifdef CONFIG_PM
|
||||
if (ddata->state==RMC_PRELOAD)
|
||||
wake_lock_timeout(&ddata->remotectl_wake_lock, HZ);
|
||||
if ((get_suspend_state())&&(ddata->remotectl_suspend_data.cnt<50)) //zwm
|
||||
ddata->remotectl_suspend_data.scanTime[ddata->remotectl_suspend_data.cnt++] = ddata->period;
|
||||
#endif
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
static int __devinit remotectl_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct RKxx_remotectl_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct rkxx_remotectl_drvdata *ddata;
|
||||
struct input_dev *input;
|
||||
int i, j;
|
||||
int irq;
|
||||
int error = 0;
|
||||
|
||||
printk("++++++++remotectl_probe\n");
|
||||
|
||||
if(!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
ddata = kzalloc(sizeof(struct rkxx_remotectl_drvdata),GFP_KERNEL);
|
||||
memset(ddata,0,sizeof(struct rkxx_remotectl_drvdata));
|
||||
|
||||
ddata->state = RMC_PRELOAD;
|
||||
input = input_allocate_device();
|
||||
|
||||
if (!ddata || !input) {
|
||||
error = -ENOMEM;
|
||||
goto fail0;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
|
||||
input->name = pdev->name;
|
||||
input->phys = "gpio-keys/input0";
|
||||
input->dev.parent = &pdev->dev;
|
||||
|
||||
input->id.bustype = BUS_HOST;
|
||||
input->id.vendor = 0x0001;
|
||||
input->id.product = 0x0001;
|
||||
input->id.version = 0x0100;
|
||||
|
||||
/* Enable auto repeat feature of Linux input subsystem */
|
||||
if (pdata->rep)
|
||||
__set_bit(EV_REP, input->evbit);
|
||||
|
||||
ddata->nbuttons = pdata->nbuttons;
|
||||
ddata->input = input;
|
||||
wake_lock_init(&ddata->remotectl_wake_lock, WAKE_LOCK_SUSPEND, "rk29_remote");
|
||||
if (pdata->set_iomux){
|
||||
pdata->set_iomux();
|
||||
}
|
||||
error = gpio_request(pdata->gpio, "remotectl");
|
||||
if (error < 0) {
|
||||
printk("gpio-keys: failed to request GPIO %d,"
|
||||
" error %d\n", pdata->gpio, error);
|
||||
//goto fail1;
|
||||
}
|
||||
error = gpio_direction_input(pdata->gpio);
|
||||
if (error < 0) {
|
||||
pr_err("gpio-keys: failed to configure input"
|
||||
" direction for GPIO %d, error %d\n",
|
||||
pdata->gpio, error);
|
||||
gpio_free(pdata->gpio);
|
||||
//goto fail1;
|
||||
}
|
||||
irq = gpio_to_irq(pdata->gpio);
|
||||
if (irq < 0) {
|
||||
error = irq;
|
||||
pr_err("gpio-keys: Unable to get irq number for GPIO %d, error %d\n",
|
||||
pdata->gpio, error);
|
||||
gpio_free(pdata->gpio);
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
error = request_irq(irq, remotectl_isr, IRQF_TRIGGER_FALLING , "remotectl", ddata);
|
||||
|
||||
if (error) {
|
||||
pr_err("gpio-remotectl: Unable to claim irq %d; error %d\n", irq, error);
|
||||
gpio_free(pdata->gpio);
|
||||
goto fail1;
|
||||
}
|
||||
setup_timer(&ddata->timer,remotectl_timer, (unsigned long)ddata);
|
||||
|
||||
tasklet_init(&ddata->remote_tasklet, remotectl_do_something, (unsigned long)ddata);
|
||||
|
||||
for (j=0;j<sizeof(remotectl_button)/sizeof(struct rkxx_remotectl_button);j++){
|
||||
printk("remotectl probe j=0x%x\n",j);
|
||||
for (i = 0; i < remotectl_button[j].nbuttons; i++) {
|
||||
unsigned int type = EV_KEY;
|
||||
|
||||
input_set_capability(input, type, remotectl_button[j].key_table[i].keyCode);
|
||||
}
|
||||
}
|
||||
error = input_register_device(input);
|
||||
if (error) {
|
||||
pr_err("gpio-keys: Unable to register input device, error: %d\n", error);
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
input_set_capability(input, EV_KEY, KEY_WAKEUP);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
return 0;
|
||||
|
||||
fail2:
|
||||
pr_err("gpio-remotectl input_allocate_device fail\n");
|
||||
input_free_device(input);
|
||||
kfree(ddata);
|
||||
fail1:
|
||||
pr_err("gpio-remotectl gpio irq request fail\n");
|
||||
free_irq(gpio_to_irq(pdata->gpio), ddata);
|
||||
del_timer_sync(&ddata->timer);
|
||||
tasklet_kill(&ddata->remote_tasklet);
|
||||
gpio_free(pdata->gpio);
|
||||
fail0:
|
||||
pr_err("gpio-remotectl input_register_device fail\n");
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit remotectl_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct RKxx_remotectl_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct rkxx_remotectl_drvdata *ddata = platform_get_drvdata(pdev);
|
||||
struct input_dev *input = ddata->input;
|
||||
int irq;
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
irq = gpio_to_irq(pdata->gpio);
|
||||
free_irq(irq, ddata);
|
||||
tasklet_kill(&ddata->remote_tasklet);
|
||||
gpio_free(pdata->gpio);
|
||||
|
||||
input_unregister_device(input);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int remotectl_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct RKxx_remotectl_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct rkxx_remotectl_drvdata *ddata = platform_get_drvdata(pdev);
|
||||
|
||||
//ddata->remotectl_suspend_data.suspend_flag = 1;
|
||||
ddata->remotectl_suspend_data.cnt = 0;
|
||||
|
||||
if (device_may_wakeup(&pdev->dev)) {
|
||||
if (pdata->wakeup) {
|
||||
int irq = gpio_to_irq(pdata->gpio);
|
||||
enable_irq_wake(irq);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int remotectl_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct RKxx_remotectl_platform_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
if (device_may_wakeup(&pdev->dev)) {
|
||||
if (pdata->wakeup) {
|
||||
int irq = gpio_to_irq(pdata->gpio);
|
||||
disable_irq_wake(irq);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops remotectl_pm_ops = {
|
||||
.suspend = remotectl_suspend,
|
||||
.resume = remotectl_resume,
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static struct platform_driver remotectl_device_driver = {
|
||||
.probe = remotectl_probe,
|
||||
.remove = __devexit_p(remotectl_remove),
|
||||
.driver = {
|
||||
.name = "rkxx-remotectl",
|
||||
.owner = THIS_MODULE,
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &remotectl_pm_ops,
|
||||
#endif
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
static int remotectl_init(void)
|
||||
{
|
||||
printk(KERN_INFO "++++++++remotectl_init\n");
|
||||
return platform_driver_register(&remotectl_device_driver);
|
||||
}
|
||||
|
||||
|
||||
static void remotectl_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&remotectl_device_driver);
|
||||
printk(KERN_INFO "++++++++remotectl_init\n");
|
||||
}
|
||||
|
||||
module_init(remotectl_init);
|
||||
module_exit(remotectl_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("rockchip");
|
||||
MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs");
|
||||
MODULE_ALIAS("platform:gpio-keys1");
|
||||
|
||||
|
||||
453
drivers/input/remotectl/rockchip_pwm_remotectl.c
Executable file
453
drivers/input/remotectl/rockchip_pwm_remotectl.c
Executable file
@@ -0,0 +1,453 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/wakelock.h>
|
||||
#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;
|
||||
};
|
||||
|
||||
struct rkxx_remotectl_drvdata {
|
||||
void __iomem *base;
|
||||
int state;
|
||||
int nbuttons;
|
||||
int result;
|
||||
int scandata;
|
||||
int count;
|
||||
int keynum;
|
||||
int keycode;
|
||||
int press;
|
||||
int pre_press;
|
||||
int period;
|
||||
int irq;
|
||||
int wakeup;
|
||||
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 int remotectl_keybd_num_lookup(struct rkxx_remotectl_drvdata *ddata)
|
||||
{
|
||||
int i;
|
||||
int num;
|
||||
|
||||
num = sizeof(remotectl_button)/sizeof(struct rkxx_remotectl_button);
|
||||
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);
|
||||
|
||||
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;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
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(130));
|
||||
if ((RK_PWM_TIME_PRE_MIN < ddata->period) &&
|
||||
(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 ((RK_PWM_TIME_BIT1_MIN < ddata->period) &&
|
||||
(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 {
|
||||
ddata->state = RMC_PRELOAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RMC_GETDATA: {
|
||||
if ((RK_PWM_TIME_BIT1_MIN < ddata->period) &&
|
||||
(ddata->period < RK_PWM_TIME_BIT1_MAX))
|
||||
ddata->scandata |= (0x01<<ddata->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=%d\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));
|
||||
} 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));
|
||||
} 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));
|
||||
} 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(unsigned long _data)
|
||||
{
|
||||
struct rkxx_remotectl_drvdata *ddata;
|
||||
|
||||
ddata = (struct rkxx_remotectl_drvdata *)_data;
|
||||
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_irq(int irq, void *dev_id)
|
||||
{
|
||||
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) {
|
||||
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 + PWM_REG_INTSTS);
|
||||
if (ddata->state == RMC_PRELOAD)
|
||||
wake_lock_timeout(&ddata->remotectl_wake_lock, HZ);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static int rk_pwm_remotectl_hw_init(struct rkxx_remotectl_drvdata *ddata)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = readl_relaxed(ddata->base + PWM_REG_CTRL);
|
||||
val = (val & 0xFFFFFFFE) | PWM_DISABLE;
|
||||
writel_relaxed(val, ddata->base + PWM_REG_CTRL);
|
||||
val = readl_relaxed(ddata->base + PWM_REG_CTRL);
|
||||
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;
|
||||
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);
|
||||
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 rk_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rkxx_remotectl_drvdata *ddata;
|
||||
struct resource *r;
|
||||
struct input_dev *input;
|
||||
struct clk *clk;
|
||||
int num;
|
||||
int irq;
|
||||
int ret;
|
||||
int i, j;
|
||||
|
||||
DBG(".. 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");
|
||||
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->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");
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
input = input_allocate_device();
|
||||
input->name = pdev->name;
|
||||
input->phys = "gpio-keys/remotectl";
|
||||
input->dev.parent = &pdev->dev;
|
||||
input->id.bustype = BUS_HOST;
|
||||
input->id.vendor = 0x0001;
|
||||
input->id.product = 0x0001;
|
||||
input->id.version = 0x0100;
|
||||
ddata->input = input;
|
||||
ddata->input = input;
|
||||
wake_lock_init(&ddata->remotectl_wake_lock,
|
||||
WAKE_LOCK_SUSPEND, "rk29_pwm_remote");
|
||||
ret = clk_prepare_enable(clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "cannot find IRQ\n");
|
||||
return ret;
|
||||
}
|
||||
ddata->irq = irq;
|
||||
ddata->wakeup = 1;
|
||||
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++) {
|
||||
unsigned int type = EV_KEY;
|
||||
|
||||
input_set_capability(input, type, remotectl_button[j].
|
||||
key_table[i].keycode);
|
||||
}
|
||||
}
|
||||
ret = input_register_device(input);
|
||||
if (ret)
|
||||
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);
|
||||
ret = devm_request_irq(&pdev->dev, irq, rockchip_pwm_irq,
|
||||
0, "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);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rk_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
},
|
||||
.probe = rk_pwm_probe,
|
||||
.remove = rk_pwm_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(rk_pwm_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
128
drivers/input/remotectl/rockchip_pwm_remotectl.h
Executable file
128
drivers/input/remotectl/rockchip_pwm_remotectl.h
Executable file
@@ -0,0 +1,128 @@
|
||||
|
||||
#ifndef __RKXX_PWM_REMOTECTL_H__
|
||||
#define __RKXX_PWM_REMOTECTL_H__
|
||||
#include <linux/input.h>
|
||||
|
||||
/* PWM0 registers */
|
||||
#define PWM_REG_CNTR 0x00 /* Counter Register */
|
||||
#define PWM_REG_HPR 0x04 /* Period Register */
|
||||
#define PWM_REG_LPR 0x08 /* Duty Cycle Register */
|
||||
#define PWM_REG_CTRL 0x0c /* Control Register */
|
||||
#define PWM_REG_INTSTS 0x10 /* Interrupt Status Refister */
|
||||
#define PWM_REG_INT_EN 0x14 /* Interrupt Enable Refister */
|
||||
|
||||
|
||||
/*REG_CTRL bits definitions*/
|
||||
#define PWM_ENABLE (1 << 0)
|
||||
#define PWM_DISABLE (0 << 0)
|
||||
|
||||
/*operation mode*/
|
||||
#define PWM_MODE_ONESHOT (0x00 << 1)
|
||||
#define PWM_MODE_CONTINUMOUS (0x01 << 1)
|
||||
#define PWM_MODE_CAPTURE (0x02 << 1)
|
||||
|
||||
/*duty cycle output polarity*/
|
||||
#define PWM_DUTY_POSTIVE (0x01 << 3)
|
||||
#define PWM_DUTY_NEGATIVE (0x00 << 3)
|
||||
|
||||
/*incative state output polarity*/
|
||||
#define PWM_INACTIVE_POSTIVE (0x01 << 4)
|
||||
#define PWM_INACTIVE_NEGATIVE (0x00 << 4)
|
||||
|
||||
/*clock source select*/
|
||||
#define PWM_CLK_SCALE (1 << 9)
|
||||
#define PWM_CLK_NON_SCALE (0 << 9)
|
||||
|
||||
#define PWM_CH0_INT (1 << 0)
|
||||
#define PWM_CH1_INT (1 << 1)
|
||||
#define PWM_CH2_INT (1 << 2)
|
||||
#define PWM_CH3_INT (1 << 3)
|
||||
|
||||
#define PWM_CH0_POL (1 << 8)
|
||||
#define PWM_CH1_POL (1 << 9)
|
||||
#define PWM_CH2_POL (1 << 10)
|
||||
#define PWM_CH3_POL (1 << 11)
|
||||
|
||||
#define PWM_CH0_INT_ENABLE (1 << 0)
|
||||
#define PWM_CH0_INT_DISABLE (0 << 0)
|
||||
|
||||
#define PWM_CH1_INT_ENABLE (1 << 0)
|
||||
#define PWM_CH1_INT_DISABLE (0 << 1)
|
||||
|
||||
#define PWM_CH2_INT_ENABLE (1 << 2)
|
||||
#define PWM_CH2_INT_DISABLE (0 << 2)
|
||||
|
||||
#define PWM_CH3_INT_ENABLE (1 << 3)
|
||||
#define PWM_CH3_INT_DISABLE (0 << 3)
|
||||
|
||||
/*prescale factor*/
|
||||
#define PWMCR_MIN_PRESCALE 0x00
|
||||
#define PWMCR_MAX_PRESCALE 0x07
|
||||
|
||||
#define PWMDCR_MIN_DUTY 0x0001
|
||||
#define PWMDCR_MAX_DUTY 0xFFFF
|
||||
|
||||
#define PWMPCR_MIN_PERIOD 0x0001
|
||||
#define PWMPCR_MAX_PERIOD 0xFFFF
|
||||
|
||||
#define PWMPCR_MIN_PERIOD 0x0001
|
||||
#define PWMPCR_MAX_PERIOD 0xFFFF
|
||||
|
||||
enum pwm_div {
|
||||
PWM_DIV1 = (0x0 << 12),
|
||||
PWM_DIV2 = (0x1 << 12),
|
||||
PWM_DIV4 = (0x2 << 12),
|
||||
PWM_DIV8 = (0x3 << 12),
|
||||
PWM_DIV16 = (0x4 << 12),
|
||||
PWM_DIV32 = (0x5 << 12),
|
||||
PWM_DIV64 = (0x6 << 12),
|
||||
PWM_DIV128 = (0x7 << 12),
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** <20>궨<EFBFBD><EAB6A8> *
|
||||
********************************************************************/
|
||||
#define RK_PWM_TIME_PRE_MIN 19 /*4500*/
|
||||
#define RK_PWM_TIME_PRE_MAX 30 /*5500*/ /*PreLoad 4.5+0.56 = 5.06ms*/
|
||||
|
||||
#define RK_PWM_TIME_BIT0_MIN 1 /*Bit0 1.125ms*/
|
||||
#define RK_PWM_TIME_BIT0_MAX 5
|
||||
|
||||
#define RK_PWM_TIME_BIT1_MIN 7 /*Bit1 2.25ms*/
|
||||
#define RK_PWM_TIME_BIT1_MAX 11
|
||||
|
||||
#define RK_PWM_TIME_RPT_MIN 200 /*101000*/
|
||||
#define RK_PWM_TIME_RPT_MAX 250 /*103000*/ /*Repeat 105-2.81=102.19ms*/ //110-9-2.25-0.56=98.19ms
|
||||
|
||||
#define RK_PWM_TIME_SEQ1_MIN 8 /*2650*/
|
||||
#define RK_PWM_TIME_SEQ1_MAX 12 /*3000*/ /*sequence 2.25+0.56=2.81ms*/ //11.25ms
|
||||
|
||||
#define RK_PWM_TIME_SEQ2_MIN 450 /*101000*/
|
||||
#define RK_PWM_TIME_SEQ2_MAX 500 /*103000*/ /*Repeat 105-2.81=102.19ms*/ //110-9-2.25-0.56=98.19ms
|
||||
|
||||
/********************************************************************
|
||||
** <20>ṹ<EFBFBD><E1B9B9><EFBFBD><EFBFBD> *
|
||||
********************************************************************/
|
||||
typedef enum _RMC_STATE
|
||||
{
|
||||
RMC_IDLE,
|
||||
RMC_PRELOAD,
|
||||
RMC_USERCODE,
|
||||
RMC_GETDATA,
|
||||
RMC_SEQUENCE
|
||||
}eRMC_STATE;
|
||||
|
||||
|
||||
struct RKxx_remotectl_platform_data {
|
||||
//struct rkxx_remotectl_button *buttons;
|
||||
int nbuttons;
|
||||
int rep;
|
||||
int timer;
|
||||
int wakeup;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user