ANDROID HALL KEY DEMO以及SC6820实现

本文详细介绍了手机中HALL传感器的工作原理及其在手机应用中的使用,包括翻盖合上的挂机信号检测。同时,阐述了如何通过GPIO按键实现系统的唤醒与睡眠功能,并提供了具体的操作步骤和代码实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.HALL开关原理及手机应用

 手机中HALL传感器由一个开关型HALL元件和两个电源开关控制管组成。其导通与否完全受到手机CPU输

 出的HALL高电平信号控制,电源则来自于电池。当翻盖合上时装在翻盖中的磁铁的磁场作用于HALL传感器 

(一般翻盖/折叠手机都把磁铁安装在翻盖上),HALL电路中的三极管导通,从传感器的引脚输出低电平,如果

是在通话后则作为“挂机”信号送给CPU挂机。(这也就是为什么合上翻盖后手机就挂断的道理)。

2.硬件连接

 
3.HALL KEY实现
在驱动gpio_event.c里添加中断注册和回掉函数
#define GN_HALL_KEY_OPEN    111 
#define GN_HALL_KEY_CLOSE   112 			-------给系统上报的键值
#define GN_GPIO_HALL_EINT_PIN         	40

u8  hall_key_state_bak; 
spinlock_t	hall_lock; 
struct hall_irq_info 
{ 
    int irq; 
    struct work_struct work; 
}; 
struct hall_irq_info hall_info; 
enum hall_state 
{ 
    HALL_CLOSE = 0, 
    HALL_OPEN =1 
};

INIT_WORK(&(hall_info.work), work_func);
         ---------------初始化工作队列
err = gpio_request(GN_GPIO_HALL_EINT_PIN, "Hall Key IRQ GPIO"); 
 if (err) { 
        printk(KERN_ERR "%s: Failed to request GPIO %d\n", 
                __func__, GN_GPIO_HALL_EINT_PIN); 
        goto err_request_gpio_failed; 
    } 
    gpio_tlmm_config(GPIO_CFG(GN_GPIO_HALL_EINT_PIN, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP, GPIO_CFG_6MA),GPIO_CFG_ENABLE); 
    gpio_free(GN_GPIO_HALL_EINT_PIN); 
    hall_info.irq= gpio_to_irq(GN_GPIO_HALL_EINT_PIN); 
    if (__gpio_get_value(GN_GPIO_HALL_EINT_PIN) == 0) { 
        pr_info("HALL_KEY: init the request irq for RISING\n"); 
		hall_key_state_bak = 0; 
        switch_set_state((struct switch_dev *)&hall_data, HALL_CLOSE); 
        err = request_irq(hall_info.irq, hall_irq, IRQF_TRIGGER_HIGH, "Hall_Key", NULL); 
    } else { 
        pr_info("HALL_KEY: init the request irq for FALLING\n"); 
        hall_key_state_bak = 1; 
        switch_set_state((struct switch_dev *)&hall_data, HALL_OPEN); 
        err = request_irq(hall_info.irq, hall_irq, IRQF_TRIGGER_LOW, "Hall_Key", NULL); 
    } 
    enable_irq_wake(hall_info.irq); 
    if (err < 0) { 
        pr_err("HALL_KEY: enable_irq_wake failed...\n"); 
        goto err_request_irq_failed; 
    }
			-------------中断的配置
static void work_func(struct work_struct *work) 
{

	-
	-
	if (kpd_hallkey_state==1) { //hall open 
        input_report_key(hall_input_dev, GN_HALL_KEY_OPEN, 1); 
        input_sync(hall_input_dev); 
        input_report_key(hall_input_dev, GN_HALL_KEY_OPEN, 0); 
        input_sync(hall_input_dev); 
        switch_set_state((struct switch_dev *)&hall_data, HALL_OPEN); 
    } else {//hall close 
        input_report_key(hall_input_dev, GN_HALL_KEY_CLOSE, 1); 
        input_sync(hall_input_dev); 
        input_report_key(hall_input_dev, GN_HALL_KEY_CLOSE, 0); 
        input_sync(hall_input_dev); 
        switch_set_state((struct switch_dev *)&hall_data, HALL_CLOSE); 
    }
	-
	-
}
	
static irqreturn_t hall_irq(int irq, void *dev_id) 
{ 

    disable_irq_nosync(hall_info.irq); 
    schedule_work(&hall_info.work); 
    return IRQ_HANDLED; 

}

4.按键唤醒系统

       要实现按键唤醒系统,首先,在驱动中,设置此键会被上报。如:
               __set_bit(KEY_2, kpd_input_dev->keybit);
               __set_bit(KEY_3, kpd_input_dev->keybit);
       这样,才能确保按键被注册处理,否则,上层收不到按键事件。
       另外,在7x27a_kp.kl文件中,设置devices\qcom\msm7627a_sku3\7x27a_kpd.kl

                      key 111   GN_HALL_KEY_OPEN  WAKE
               key 112   GN_HALL_KEY_CLOSE

         这样就可实现按键唤醒系统了。

5.新增两个按键实现hall key

1. 首先修改底层gpio_event.c文件中的按键定义:
              #define GN_HALL_KEY_OPEN 111
              #define GN_HALL_KEY_CLOSE 112
       2. 修改devices\qcom\msm7627a_sku3\7x27a_kpd.kl文件,增加
              key 111  GN_HALL_KEY_OPEN WAKE  (打开可以唤醒)
              key 112  GN_HALL_KEY_CLOSE
       3. 在frameworks\base\include\ui\keycodelabels.h KEYCODES结构体中增加
              { "GN_HALL_KEY_OPEN", 111 },
              { "GN_HALL_KEY_CLOSE", 112 },
       4. 在frameworks\base\core\java\android\view\keyevent.java构造函数中增加:
              public static final int KEYCODE_GN_HALL_KEY_OPEN    = 111;
              public static final int KEYCODE_ GN_HALL_KEY_CLOSE = 112;
       5. 修改:  private static final int LAST_KEYCODE           = KEYCODE_BUTTON_MODE;
           为private static final int LAST_KEYCODE =KEYCODE_ GN_HALL_KEY_CLOSE;
           在frameworks\base\native\include\android\keycodes.h的enum中增加:
              AKEYCODE_GN_HALL_KEY_CLOSE   = 250,
              AKEYCODE_GN_HALL_KEY_CLOSE  = 251,
       6. 在frameworks\base\libs\ui\input.cpp的issystemkey中增加:
              case AKEYCODE_GN_HALL_KEY_CLOSE:
              case AKEYCODE_GN_HALL_KEY_CLOSE: 
           这样bool KeyEvent::isSystemKey() const {
                     return isSystemKey(getKeyCode());
           才能由scancode转换为keycode供上层应用截取。

       7. 修改development/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
           private static final String[] KEY_NAMES = {
              …
              …
             "KEYCODE_GN_HALL_KEY_OPEN", 
             "KEYCODE_GN_HALL_KEY_CLOSE", 
             "TAG_LAST_KEYCODE"
          } 


6.展讯平台【SC6820 ANDROID2.3.5】驱动实现部分

在sc8800g-keys.c文件中,包括了GPIO KEY, 中断KEY的实现机制,包括POWER KEY的实现。

1. pinma_cfg.c

MFP_CFG_X(RFCTL5, AF3,DS1, F_PULL_UP,S_PULL_UP, IO_IE) ----配置GPIO为中断模式

2. key_cfg.c

int sprd_3rdparty_gpio_key1 = 95;
/*note: now driver support max 3 gpio keys*/  ----- SC6820 最多支持3个GPIO
static struct sprd_gpio_keys sprd_gpio_keymap[] = 
{
{&sprd_3rdparty_gpio_key1,ANDROID_KEY_HALL},  -----  配置GPIO_NUM, KEY_VALUE
};

3. 关键部分修改:sc8800g-keys.c

用展讯默认代码,会出现一直有eic中断,导致系统无法睡眠的问题,因此,需要对系统gpio按键机制进行修改

1>修改函数 gpio_key_init

屏蔽原来代码,添加如下代码

INIT_WORK(&hallwork, hall_work);
err = gpio_request(gpio, "hall key");
if (err)
printk("can not alloc gpio for %d Key\n", gpio);
else
printk("alloc gpio for %d Key\n", gpio);
gpio_direction_input(gpio);
hallirq = sprd_alloc_gpio_irq(gpio);

ret = request_threaded_irq(hallirq, NULL, hall_interrupt,  IRQF_TRIGGER_LOW| IRQF_ONESHOT, NULL, (void*)gpio_id);
2>实现中断处理函数

static irqreturn_t hall_interrupt(int irq, void *dev_id)
{
int irq_type,gpio,ret=0;
printk("%s\n", __func__);
disable_irq_nosync(irq);

gpio = irq_to_gpio(irq);
ret = gpio_get_value(gpio);        
schedule_work(&hallwork);
printk("hall interrupt %d\n",ret);

if(ret)
{
irq_type = IRQF_TRIGGER_LOW;
mHallStatus = 1;
printk("hall interrupt ret:%d,irq_type:%d\n",ret,irq_type);
set_irq_type(irq,irq_type);
}
else
{
irq_type = IRQF_TRIGGER_HIGH;
mHallStatus = 0;
printk("hall interrupt ret:%d,irq_type:%d\n",ret,irq_type);
set_irq_type(irq,irq_type);
}
return IRQ_HANDLED;
}

3>中断消息队列处理

static void hall_work(struct work_struct *work)
{
int ret = 0;
int gpio;

gpio = irq_to_gpio(hallirq);
ret = gpio_get_value(gpio);   

printk("%s   :   %d    :  %d \n",__func__,ANDROID_KEY_HALL, ret);

if(ret)
{
//release
input_report_key(sprd_kpad->input, ANDROID_KEY_HALL, 0); ---  上报键值,事件
input_sync(sprd_kpad->input);  
}
else
{
//press
input_report_key(sprd_kpad->input, ANDROID_KEY_HALL, 1);
input_sync(sprd_kpad->input);
}


enable_irq(hallirq);
}

到此为止,GPIO按键驱动部分已经OK,上层就可以根据上报的键值进行处理了。如何定义一个新增加的键值,看第一部分,有介绍。最重要的就是

第一部分中的第5点LAST_KEYCODE,这个很关键,需要修改为你新添加的键值,不然,上层的检查会有问题。


GPIO按键作为系统的唤醒、睡眠处理部分

1.按键WAKE部分定义在 sprd-keypad.kl

key 216     HALL              WAKE

2.关键部分修改:interceptKeyBeforeQueueing

            case KeyEvent.KEYCODE_HALL: 
   {
result &= ~ACTION_PASS_TO_USER;

if (down) 
{
Log.d(TAG, "runyee hall down: screenIsOn=" + isScreenOn);
if(isScreenOn)
{
Log.d(TAG, "runyee hall down:   goToSleep" );
pm.goToSleep(SystemClock.uptimeMillis());
}
}
else
{
Log.d(TAG, "runyee hall up: screenIsOn=" + isScreenOn);
//mWL.acquire();
if(!isScreenOn)
{
Log.d(TAG, "runyee hall up:   wakeUp" );
mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode);
}
}
            }
break;

对应键值的处理,上面就是睡眠和唤醒的关键部分。细节部分就是上面的条件判断,会对应屏的亮灭进行控制。同样,因为我们定义的按键

带WAKE属性,因此,在这个函数中还有个细节需要进行处理:

            if (down && isWakeKey) {
                if (keyguardActive) {
                    // If the keyguard is showing, let it decide what to do with the wake key.
                    if(111 != keyCode) //------这就起到屏蔽作用,各位可以先不加此条件判断,看看效果。
                    {
                    Log.d(TAG, "runyee hall down: wakekey" );
                    mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode);
                    }
                } else {
                    // Otherwise, wake the device ourselves.
                    result |= ACTION_POKE_USER_ACTIVITY;
                }
            }

到此,按键对系统的唤醒,睡眠实现完成。如果还要根据这个GPIO状态做进一步的开发的话,还需要修改sc8800g-key.c,注册设备文件节点,

通过JNI获取状态,返回给相应的服务,做进一步处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值