rk29_phonesdk: add headset hook key device

This commit is contained in:
邱建斌
2011-06-17 16:12:21 +08:00
parent 68d0b413f8
commit 86061d367c
7 changed files with 902 additions and 1139 deletions

View File

@@ -1509,8 +1509,9 @@ struct wm8994_pdata wm8994_platdata = {
.jd_scthr = 0,
.jd_thr = 0,
.PA_control =1,
.PA_control_pin = RK29_PIN6_PD3,
.Power_EN_Pin = RK29_PIN5_PA1,
.speaker_incall_vol = 0,
.speaker_incall_mic_vol = -9,
.speaker_normal_vol = 6,
@@ -1526,18 +1527,18 @@ struct wm8994_pdata wm8994_platdata = {
//#endif
#ifdef CONFIG_RK_HEADSET_DET
#define HEADSET_GPIO RK29_PIN3_PA6
struct rk2818_headset_data rk2818_headset_info = {
.gpio = HEADSET_GPIO,
.irq_type = IRQF_TRIGGER_RISING,//IRQF_TRIGGER_RISING -- ?????? IRQF_TRIGGER_FALLING -- ?½???
struct rk_headset_pdata rk_headset_info = {
.Headset_gpio = RK29_PIN3_PA6,
.headset_in_type= HEADSET_IN_HIGH,
.Hook_gpio = RK29_PIN4_PD1,//Detection Headset--Must be set
};
struct platform_device rk28_device_headset = {
.name = "rk2818_headsetdet",
struct platform_device rk_device_headset = {
.name = "rk_headsetdet",
.id = 0,
.dev = {
.platform_data = &rk2818_headset_info,
.platform_data = &rk_headset_info,
}
};
#endif
@@ -2676,7 +2677,7 @@ static struct platform_device *devices[] __initdata = {
&rk29_v4l2_output_devce,
#endif
#ifdef CONFIG_RK_HEADSET_DET
&rk28_device_headset,
&rk_device_headset,
#endif
#ifdef CONFIG_RK29_GPS
&rk29_device_gps,

View File

@@ -1562,7 +1562,8 @@ struct wm8994_pdata wm8994_platdata = {
.jd_scthr = 0,
.jd_thr = 0,
.PA_control =0,
.PA_control_pin = 0,
.Power_EN_Pin = RK29_PIN5_PA1,
.speaker_incall_vol = 0,
.speaker_incall_mic_vol = -9,
@@ -1580,17 +1581,17 @@ struct wm8994_pdata wm8994_platdata = {
#ifdef CONFIG_RK_HEADSET_DET
#define HEADSET_GPIO RK29_PIN4_PD2
struct rk2818_headset_data rk2818_headset_info = {
.gpio = HEADSET_GPIO,
.irq_type = IRQF_TRIGGER_RISING,//IRQF_TRIGGER_RISING -- ?????? IRQF_TRIGGER_FALLING -- ?½???
struct rk_headset_pdata rk_headset_info = {
.Headset_gpio = RK29_PIN4_PD2,
.headset_in_type= HEADSET_IN_HIGH,
.Hook_gpio = RK29_PIN4_PD1,//Detection Headset--Must be set
};
struct platform_device rk28_device_headset = {
.name = "rk2818_headsetdet",
struct platform_device rk_device_headset = {
.name = "rk_headsetdet",
.id = 0,
.dev = {
.platform_data = &rk2818_headset_info,
.platform_data = &rk_headset_info,
}
};
#endif
@@ -2603,7 +2604,7 @@ static struct platform_device *devices[] __initdata = {
&rk29_v4l2_output_devce,
#endif
#ifdef CONFIG_RK_HEADSET_DET
&rk28_device_headset,
&rk_device_headset,
#endif
#ifdef CONFIG_RK29_GPS
&rk29_device_gps,

View File

@@ -39,7 +39,7 @@
#include <linux/earlysuspend.h>
/* Debug */
#if 1
#if 0
#define DBG(x...) printk(x)
#else
#define DBG(x...) do { } while (0)
@@ -48,47 +48,65 @@
#define BIT_HEADSET (1 << 0)
#define BIT_HEADSET_NO_MIC (1 << 1)
struct rk2818_headset_dev{
#define HEADSET 0
#define HOOK 1
/* headset private data */
struct headset_priv {
struct input_dev *input_dev;
struct rk_headset_pdata *pdata;
unsigned int headset_status:1;
unsigned int hook_status:1;
struct switch_dev sdev;
int cur_headset_status;
int pre_headset_status;
struct mutex mutex_lock;
struct mutex mutex_lock[2];
unsigned int irq[2];
unsigned int irq_type[2];
struct delayed_work h_delayed_work[2];
unsigned char *keycodes;
};
static struct headset_priv *headset_info;
static struct rk2818_headset_dev Headset_dev;
static struct delayed_work g_headsetobserve_work;
static struct rk2818_headset_data *prk2818_headset_info;
#if defined(CONFIG_MACH_BENGO_V2) || defined(CONFIG_MACH_BENGO) || defined(CONFIG_MACH_Z5) || defined(CONFIG_MACH_Z5_V2) || defined(CONFIG_MACH_A22)
extern void detect_HSMic(void);
#endif
int headset_status(void)
{
if(Headset_dev.cur_headset_status & BIT_HEADSET)
return 1;
else
return 0;
}
EXPORT_SYMBOL_GPL(headset_status);
static irqreturn_t headset_interrupt(int irq, void *dev_id)
{
// DBG("---headset_interrupt---\n");
schedule_delayed_work(&g_headsetobserve_work, msecs_to_jiffies(20));
schedule_delayed_work(&headset_info->h_delayed_work[HEADSET], msecs_to_jiffies(20));
return IRQ_HANDLED;
}
static int headset_change_irqtype(unsigned int irq_type)
static irqreturn_t Hook_interrupt(int irq, void *dev_id)
{
// DBG("---Hook_interrupt---\n");
schedule_delayed_work(&headset_info->h_delayed_work[HOOK], msecs_to_jiffies(100));
return IRQ_HANDLED;
}
static int headset_change_irqtype(int type,unsigned int irq_type)
{
int ret = 0;
// DBG("--------%s----------\n",__FUNCTION__);
free_irq(prk2818_headset_info->irq,NULL);
free_irq(headset_info->irq[type],NULL);
ret = request_irq(prk2818_headset_info->irq, headset_interrupt, irq_type, NULL, NULL);
if (ret)
switch(type)
{
DBG("headsetobserve: request irq failed\n");
case HOOK:
ret = request_irq(headset_info->irq[type], Hook_interrupt, irq_type, NULL, NULL);
break;
case HEADSET:
ret = request_irq(headset_info->irq[type], headset_interrupt, irq_type, NULL, NULL);
break;
default:
ret = -1;
break;
}
if (ret<0)
{
DBG("headset_change_irqtype: request irq failed\n");
return ret;
}
return ret;
@@ -97,16 +115,126 @@ static int headset_change_irqtype(unsigned int irq_type)
static void headsetobserve_work(struct work_struct *work)
{
int i,level = 0;
struct rk_headset_pdata *pdata = headset_info->pdata;
static unsigned int old_status = 0;
// DBG("---headsetobserve_work---\n");
mutex_lock(&Headset_dev.mutex_lock);
mutex_lock(&headset_info->mutex_lock[HEADSET]);
for(i=0; i<3; i++)
{
level = gpio_get_value(prk2818_headset_info->gpio);
level = gpio_get_value(pdata->Headset_gpio);
if(level < 0)
{
printk("%s:get pin level again,pin=%d,i=%d\n",__FUNCTION__,prk2818_headset_info->gpio,i);
printk("%s:get pin level again,pin=%d,i=%d\n",__FUNCTION__,pdata->Headset_gpio,i);
msleep(1);
continue;
}
else
break;
}
if(level < 0)
{
printk("%s:get pin level err!\n",__FUNCTION__);
return;
}
old_status = headset_info->headset_status;
switch(pdata->headset_in_type)
{
case HEADSET_IN_HIGH:
if(level > 0)
headset_info->headset_status = 1;
else if(level == 0)
headset_info->headset_status = 0;
break;
case HEADSET_IN_LOW:
if(level == 0)
headset_info->headset_status = 1;
else if(level > 0)
headset_info->headset_status = 0;
break;
default:
DBG("---- ERROR: on headset headset_in_type error -----\n");
break;
}
if(old_status == headset_info->headset_status)
{
printk("old_status == headset_info->headset_status\n");
mutex_unlock(&headset_info->mutex_lock[HEADSET]);
return;
}
switch(pdata->headset_in_type)
{
case HEADSET_IN_HIGH:
if(level > 0)
{//in--High level
DBG("--- HEADSET_IN_HIGH headset in HIGH---\n");
enable_irq(headset_info->irq[HOOK]);
headset_info->headset_status = 1;
headset_info->cur_headset_status = BIT_HEADSET;
headset_change_irqtype(HEADSET,IRQF_TRIGGER_FALLING);//
}
else if(level == 0)
{//out--Low level
DBG("---HEADSET_IN_HIGH headset out HIGH---\n");
disable_irq(headset_info->irq[HOOK]);
headset_info->headset_status = 0;
headset_info->cur_headset_status = ~(BIT_HEADSET|BIT_HEADSET_NO_MIC);
headset_change_irqtype(HEADSET,IRQF_TRIGGER_RISING);//
}
break;
case HEADSET_IN_LOW:
if(level == 0)
{//in--High level
DBG("---HEADSET_IN_LOW headset in LOW ---\n");
headset_info->headset_status = 1;
headset_info->cur_headset_status = BIT_HEADSET;
headset_change_irqtype(HEADSET,IRQF_TRIGGER_RISING);//
enable_irq(headset_info->irq[HOOK]);
}
else if(level > 0)
{//out--High level
DBG("---HEADSET_IN_LOW headset out LOW ---\n");
headset_info->headset_status = 0;
headset_info->cur_headset_status = ~(BIT_HEADSET|BIT_HEADSET_NO_MIC);
headset_change_irqtype(HEADSET,IRQF_TRIGGER_FALLING);//
disable_irq(headset_info->irq[HOOK]);
}
break;
default:
DBG("---- ERROR: on headset headset_in_type error -----\n");
break;
}
switch_set_state(&headset_info->sdev, headset_info->cur_headset_status);
DBG("Headset_dev.cur_headset_status = %d\n",headset_info->cur_headset_status);
mutex_unlock(&headset_info->mutex_lock[HEADSET]);
}
static void Hook_work(struct work_struct *work)
{
int i,level = 0;
struct rk_headset_pdata *pdata = headset_info->pdata;
static unsigned int old_status = 0;
DBG("---Hook_work---\n");
mutex_lock(&headset_info->mutex_lock[HOOK]);
if(headset_info->headset_status == 0)
{
printk("Headset is out\n");
mutex_unlock(&headset_info->mutex_lock[HOOK]);
return;
}
for(i=0; i<3; i++)
{
level = gpio_get_value(pdata->Hook_gpio);
if(level < 0)
{
printk("%s:get pin level again,pin=%d,i=%d\n",__FUNCTION__,pdata->Hook_gpio,i);
msleep(1);
continue;
}
@@ -119,51 +247,34 @@ static void headsetobserve_work(struct work_struct *work)
return;
}
switch(prk2818_headset_info->headset_in_type)
old_status = headset_info->hook_status;
if(level == 0)
headset_info->hook_status = 1;
else if(level > 0)
headset_info->hook_status = 0;
if(old_status == headset_info->hook_status)
{
case HEADSET_IN_HIGH:
if(level > 0)
{//in--High level
DBG("--- HEADSET_IN_HIGH headset in---\n");
Headset_dev.cur_headset_status = BIT_HEADSET;
headset_change_irqtype(IRQF_TRIGGER_FALLING);//
}
else if(level == 0)
{//out--Low level
DBG("---HEADSET_IN_HIGH headset out---\n");
Headset_dev.cur_headset_status = ~(BIT_HEADSET|BIT_HEADSET_NO_MIC);
headset_change_irqtype(IRQF_TRIGGER_RISING);//
}
break;
case HEADSET_IN_LOW:
if(level == 0)
{//in--High level
DBG("---HEADSET_IN_LOW headset in---\n");
Headset_dev.cur_headset_status = BIT_HEADSET;
headset_change_irqtype(IRQF_TRIGGER_RISING);//
}
else if(level > 0)
{//out--High level
DBG("---HEADSET_IN_LOW headset out---\n");
Headset_dev.cur_headset_status = ~(BIT_HEADSET|BIT_HEADSET_NO_MIC);
headset_change_irqtype(IRQF_TRIGGER_FALLING);//
}
break;
default:
DBG("---- ERROR: on headset headset_in_type error -----\n");
break;
printk("old_status == headset_info->hook_status\n");
mutex_unlock(&headset_info->mutex_lock[HOOK]);
return;
}
if(level == 0)
{
DBG("---HOOK Down ---\n");
headset_change_irqtype(HOOK,IRQF_TRIGGER_RISING);//
input_report_key(headset_info->input_dev,KEY_MEDIA,headset_info->hook_status);
input_sync(headset_info->input_dev);
}
else if(level > 0)
{
DBG("---HOOK Up ---\n");
headset_change_irqtype(HOOK,IRQF_TRIGGER_FALLING);//
input_report_key(headset_info->input_dev,KEY_MEDIA,headset_info->hook_status);
input_sync(headset_info->input_dev);
}
if(Headset_dev.cur_headset_status != Headset_dev.pre_headset_status)
{
Headset_dev.pre_headset_status = Headset_dev.cur_headset_status;
switch_set_state(&Headset_dev.sdev, Headset_dev.cur_headset_status);
DBG("Headset_dev.cur_headset_status = %d\n",Headset_dev.cur_headset_status);
#if defined(CONFIG_MACH_BENGO_V2) || defined(CONFIG_MACH_BENGO) || defined(CONFIG_MACH_Z5) || defined(CONFIG_MACH_Z5_V2) || defined(CONFIG_MACH_A22)
detect_HSMic();
#endif
}
mutex_unlock(&Headset_dev.mutex_lock);
mutex_unlock(&headset_info->mutex_lock[HOOK]);
}
static ssize_t h2w_print_name(struct switch_dev *sdev, char *buf)
@@ -174,55 +285,123 @@ static ssize_t h2w_print_name(struct switch_dev *sdev, char *buf)
#ifdef CONFIG_HAS_EARLYSUSPEND
static void headset_early_resume(struct early_suspend *h)
{
schedule_delayed_work(&g_headsetobserve_work, msecs_to_jiffies(10));
schedule_delayed_work(&headset_info->h_delayed_work[HEADSET], msecs_to_jiffies(10));
//DBG(">>>>>headset_early_resume\n");
}
static struct early_suspend hs_early_suspend;
#endif
static int rk_Hskey_open(struct input_dev *dev)
{
//struct rk28_adckey *adckey = input_get_drvdata(dev);
// DBG("===========rk_Hskey_open===========\n");
return 0;
}
static void rk_Hskey_close(struct input_dev *dev)
{
// DBG("===========rk_Hskey_close===========\n");
// struct rk28_adckey *adckey = input_get_drvdata(dev);
}
static int rockchip_headsetobserve_probe(struct platform_device *pdev)
{
int ret;
DBG("RockChip headset observe driver\n");
prk2818_headset_info = pdev->dev.platform_data;
struct headset_priv *headset;
struct rk_headset_pdata *pdata;
Headset_dev.cur_headset_status = 0;
Headset_dev.pre_headset_status = 0;
Headset_dev.sdev.name = "h2w";
Headset_dev.sdev.print_name = h2w_print_name;
mutex_init(&Headset_dev.mutex_lock);
ret = switch_dev_register(&Headset_dev.sdev);
headset = kzalloc(sizeof(struct headset_priv), GFP_KERNEL);
if (headset == NULL) {
dev_err(&pdev->dev, "failed to allocate driver data\n");
return -ENOMEM;
}
headset->pdata = pdev->dev.platform_data;
pdata = headset->pdata;
headset->headset_status = 0;
headset->hook_status = 0;
headset->cur_headset_status = 0;
headset->sdev.name = "h2w";
headset->sdev.print_name = h2w_print_name;
ret = switch_dev_register(&headset->sdev);
if (ret < 0)
return ret;
INIT_DELAYED_WORK(&g_headsetobserve_work, headsetobserve_work);
ret = gpio_request(prk2818_headset_info->gpio, "headset_det");
if (ret)
{
DBG("headsetobserve: request gpio_request failed\n");
return ret;
}
gpio_pull_updown(prk2818_headset_info->gpio, PullDisable);
gpio_direction_input(prk2818_headset_info->gpio);
prk2818_headset_info->irq = gpio_to_irq(prk2818_headset_info->gpio);
if(prk2818_headset_info->headset_in_type == HEADSET_IN_HIGH)
prk2818_headset_info->irq_type = IRQF_TRIGGER_RISING;
else
prk2818_headset_info->irq_type = IRQF_TRIGGER_FALLING;
ret = request_irq(prk2818_headset_info->irq, headset_interrupt, prk2818_headset_info->irq_type, NULL, NULL);
if (ret)
{
DBG("headsetobserve: request irq failed\n");
return ret;
}
schedule_delayed_work(&g_headsetobserve_work, msecs_to_jiffies(500));
goto failed_free;
mutex_init(&headset->mutex_lock[HEADSET]);
mutex_init(&headset->mutex_lock[HOOK]);
INIT_DELAYED_WORK(&headset->h_delayed_work[HEADSET], headsetobserve_work);
INIT_DELAYED_WORK(&headset->h_delayed_work[HOOK], Hook_work);
//------------------------------------------------------------------
ret = gpio_request(pdata->Headset_gpio, NULL);
if (ret)
goto failed_free;
gpio_pull_updown(pdata->Headset_gpio, PullDisable);
gpio_direction_input(pdata->Headset_gpio);
headset->irq[HEADSET] = gpio_to_irq(pdata->Headset_gpio);
if(pdata->headset_in_type == HEADSET_IN_HIGH)
headset->irq_type[HEADSET] = IRQF_TRIGGER_RISING;
else
headset->irq_type[HEADSET] = IRQF_TRIGGER_FALLING;
ret = request_irq(headset->irq[HEADSET], headset_interrupt, headset->irq_type[HEADSET], NULL, NULL);
if (ret)
goto failed_free;
//------------------------------------------------------------------
ret = gpio_request(pdata->Hook_gpio , NULL);
if (ret)
goto failed_free;
gpio_pull_updown(pdata->Hook_gpio, PullDisable);
gpio_direction_input(pdata->Hook_gpio);
headset->irq[HOOK] = gpio_to_irq(pdata->Hook_gpio);
headset->irq_type[HOOK] = IRQF_TRIGGER_FALLING;
ret = request_irq(headset->irq[HOOK], Hook_interrupt, headset->irq_type[HOOK] , NULL, NULL);
if (ret)
goto failed_free;
disable_irq(headset->irq[HOOK]);
//------------------------------------------------------------------
// Create and register the input driver.
headset->input_dev = input_allocate_device();
if (!headset->input_dev) {
dev_err(&pdev->dev, "failed to allocate input device\n");
ret = -ENOMEM;
goto failed_free;
}
headset->input_dev->name = pdev->name;
headset->input_dev->open = rk_Hskey_open;
headset->input_dev->close = rk_Hskey_close;
headset->input_dev->dev.parent = &pdev->dev;
//input_dev->phys = KEY_PHYS_NAME;
headset->input_dev->id.vendor = 0x0001;
headset->input_dev->id.product = 0x0001;
headset->input_dev->id.version = 0x0100;
// Register the input device
ret = input_register_device(headset->input_dev);
if (ret) {
dev_err(&pdev->dev, "failed to register input device\n");
goto failed_free_dev;
}
// headset->input_dev->keycode = headset->keycodes;
// headset->input_dev->keycodesize = sizeof(unsigned char);
// headset->input_dev->keycodemax = 2;
// set_bit(KEY_MEDIA, headset->input_dev->keybit);
// clear_bit(0, headset->input_dev->keybit);
input_set_capability(headset->input_dev, EV_KEY, KEY_MEDIA);
// input_set_capability(headset->input_dev, EV_SW, SW_HEADPHONE_INSERT);
// input_set_capability(headset->input_dev, EV_KEY, KEY_END);
// headset->input_dev->evbit[0] = BIT_MASK(EV_KEY);
headset_info = headset;
schedule_delayed_work(&headset->h_delayed_work[HEADSET], msecs_to_jiffies(500));
#ifdef CONFIG_HAS_EARLYSUSPEND
hs_early_suspend.suspend = NULL;
hs_early_suspend.resume = headset_early_resume;
@@ -231,17 +410,23 @@ static int rockchip_headsetobserve_probe(struct platform_device *pdev)
#endif
return 0;
failed_free_dev:
platform_set_drvdata(pdev, NULL);
input_free_device(headset->input_dev);
failed_free:
kfree(headset);
return ret;
}
static struct platform_driver rockchip_headsetobserve_driver = {
.probe = rockchip_headsetobserve_probe,
.driver = {
.name = "rk2818_headsetdet",
.name = "rk_headsetdet",
.owner = THIS_MODULE,
},
};
static int __init rockchip_headsetobserve_init(void)
{
platform_driver_register(&rockchip_headsetobserve_driver);

View File

@@ -1,15 +1,15 @@
#ifndef RK2818_HEADSET_H
#define RK2818_HEADSET_H
#ifndef RK_HEADSET_H
#define RK_HEADSET_H
#define HEADSET_IN_HIGH 0x00000001
#define HEADSET_IN_LOW 0x00000000
struct rk2818_headset_data {
unsigned int gpio;//Detection Headset--Must be set
unsigned int irq;
unsigned int irq_type;
unsigned int headset_in_type;// Headphones into the state level--Must be set
struct rk_headset_pdata{
unsigned int Hook_gpio;//Detection Headset--Must be set
unsigned int Headset_gpio;//Detection Headset--Must be set
unsigned int headset_in_type;// Headphones into the state level--Must be set
};
#endif

View File

@@ -93,8 +93,11 @@ struct wm8994_pdata {
unsigned int jd_scthr:2;
unsigned int jd_thr:2;
//If an external amplifier speakers wm8994 enable=1 disable=0
unsigned int PA_control:1;
//If an external amplifier speakers wm8994 enable>0 disable=0
unsigned int PA_control_pin;
//wm8994 LDO1_ENA and LDO2_ENA
unsigned int Power_EN_Pin;
//volume
int speaker_incall_vol; //max = 6, min = -21

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@
*
* Author: Richard Purdie <richard@openedhand.com>
*
* Based on WM8753.h
* Based on WM8994.h
*
* 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
@@ -15,56 +15,22 @@
#define _WM8994_H
/* WM8994 register space */
#define WM8994_LINVOL 0x0f
#define WM8994_RINVOL 0x01
#define WM8994_LOUT1V 0x02
#define WM8994_ROUT1V 0x03
#define WM8994_ADCDAC 0x05
#define WM8994_IFACE 0x07
#define WM8994_SRATE 0x08
#define WM8994_LDAC 0x0a
#define WM8994_RDAC 0x0b
#define WM8994_BASS 0x0c
#define WM8994_TREBLE 0x0d
#define WM8994_RESET 0x00
#define WM8994_3D 0x10
#define WM8994_ALC1 0x11
#define WM8994_ALC2 0x12
#define WM8994_ALC3 0x13
#define WM8994_NGATE 0x14
#define WM8994_LADC 0x15
#define WM8994_RADC 0x16
#define WM8994_ADCTL1 0x17
#define WM8994_ADCTL2 0x18
#define WM8994_PWR1 0x19
#define WM8994_PWR2 0x1a
#define WM8994_ADCTL3 0x1b
#define WM8994_ADCIN 0x1f
#define WM8994_LADCIN 0x20
#define WM8994_RADCIN 0x21
#define WM8994_LOUTM1 0x22
#define WM8994_LOUTM2 0x23
#define WM8994_ROUTM1 0x24
#define WM8994_ROUTM2 0x25
#define WM8994_LOUT2V 0x28
#define WM8994_ROUT2V 0x29
#define WM8994_LPPB 0x43
#define WM8994_NUM_REG 0x44
#define WM8994_SYSCLK 0
#define wm8994_SYSCLK_3072M 0
#define wm8994_SYSCLK_12288M 1
#define wm8994_mic_VCC 0x0010
#define WM8994_DELAY 50
#define call_maxvol 5 //Sound level during a call
#define BT_call_maxvol 15
#define MAX_MIN(min,value,max) value = ((value>max) ? max: value); \
value = ((value<min) ? min: value)
extern struct snd_soc_dai wm8994_dai;
extern struct snd_soc_codec_device soc_codec_dev_wm8994;
void wm8994_codec_set_volume(unsigned char mode,unsigned char volume);
#define WM_EN_PIN RK29_PIN5_PA1
#define WM_PA_PIN RK29_PIN6_PD3
#define ERROR -1
#define TRUE 0
#endif