全志H3 耳机检测驱动代码

一管脚注册

耳机插入的管脚gpio注册放在了sys_config.fex文件里面了。
Linein_gpio1 = port:PG09<0>~~~

二 驱动代码文件

/*
*   Copyright (c) 2015, lvan xiong
*   All rights reserved.
*
*   文件名称: zhc_key.c
*   摘    要: 按键检测驱动
*   
*   当前版本: 1.0
*   作    者: ~~~~
*   完成日期: 
*
*   取代版本: 
*   原作者  :
*   完成日期:
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/pm.h>
#include <linux/earlysuspend.h>
#endif
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/keyboard.h>
#include <linux/ioport.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/timer.h> 
#include <linux/clk.h>
#include <mach/sys_config.h>
#include <linux/gpio.h>
#include <mach/irqs.h>
//#include <mach/system.h>
#include <mach/hardware.h>
#include <mach/gpio.h> 
//#include <mach/clock.h>
#include <linux/regulator/consumer.h>
#include <linux/platform_device.h>


//#include "sun8i-keyboard.h"
//#include <linux/power/scenelock.h> 

//#define __ISDEBUG__
#ifdef  __ISDEBUG__
#define dprintk(format,...) printk(" --> Fun: %s, Line: %05d "format" <--\n", __func__, __LINE__,##__VA_ARGS__)
#else
#define dprintk(format,...)
#endif

u32 linein1     = 0;                
u32 linein2     = 0;
static char* machine;
script_item_u   item_val;
script_item_value_type_e  item_type;
//u32 g_PowerDetectIO2  = 0;            // 船型开关检测IO
//u32 TouchKeyIO2   = 0;            // 功放电源控制电路
//u32 TouchKeyIO3   = 0;            // 小负载控制电路
int gpio1,gpio2;                           
//static int virq;


//u32 g_IRQPowerDetectHandle = 0;           // 中断句柄
//struct work_struct g_stIRQPowerDetect;    // 中断下半部    
struct delayed_work g_DelayTask;        
//static struct input_dev *g_PowerDec_input_dev;    // 键值上报

//struct device g_dev;
//struct device *dev = &pdev->dev;

#ifdef CONFIG_HAS_EARLYSUSPEND  
struct sunxi_g_power_data {
    struct early_suspend early_suspend;
};
/*
#else
#ifdef CONFIG_PM
static struct dev_pm_domain keyboard_pm_domain;
#endif
*/
#endif

#ifdef CONFIG_HAS_EARLYSUSPEND
static struct sunxi_g_power_data *g_power_data;
#endif
///////////////////////////////////////////////////////////////////////////

int GetLineInDetectStatus(void)
{   
    gpio1 = __gpio_get_value(linein1);  

    item_type = script_get_item("product", "machine", &item_val);
    if(SCIRPT_ITEM_VALUE_TYPE_STR != item_type) {;
        printk("%s: product machine script_get_item err.\n", __func__);
    } else {
        machine = item_val.str;
//      printk("MYDEBUG --->> linein_detect.c line = %d  machine = %s\n",__LINE__, machine);
       if (!strncmp(machine, "dolphin-h3-zhc-a803-gb", strlen(machine))) {  
            gpio2 = __gpio_get_value(linein2);
//          printk("MYDEBUG --->> linein gpio detect gpio1 = %d, gpio2 = %d", gpio1, gpio2);
            if((gpio1 == 0) && (gpio2 == 0))
            {
                return 2;
            }

            if((gpio1 == 1) && (gpio2 == 1))
                return 1;
            if(((gpio1 == 1) && (gpio2 == 0)) || ((gpio1 == 0) && (gpio2 == 1)))
                return 0;
        }
    }

    return gpio1;
}

#if 1
static void linein_decetect(struct work_struct *work)
{
//  dprintk();  
    int ret;
    ret = GetLineInDetectStatus(); 
//  printk("MYDEBUG --->>GetLineInDetectStatus = %d\n", ret);
    schedule_delayed_work(&g_DelayTask, 50);
    }
#endif  

#if 0
u32 sunxi_gpio_irq_test_handler(void * para)
{
    u32 upio_index = *(u32 *)para;
    printk("MYDEBUG ---> %s :upio_index 0x%08x\n", __func__, upio_index);
}

static int LineInDetect_Probe(struct platform_device *pdev)
{

    struct device *dev = &pdev->dev;
    int virq;
    int ret;
    /* map the virq of gpio */
    virq = gpio_to_irq(GPIOG(9));
    if (IS_ERR_VALUE(virq)) {
    pr_warn("map gpio [%d] to virq failed, errno = %d\n",
    GPIOL(0), virq);
    return -EINVAL;
    }
    pr_debug("gpio [%d] map to virq [%d] ok\n", GPIOL(0), virq);
    /* request virq, set virq type to high level trigger */
    ret = devm_request_irq(dev, virq, sunxi_gpio_irq_test_handler,
    IRQF_TRIGGER_HIGH, "PL0_EINT", NULL);
    if (IS_ERR_VALUE(ret)) {
    pr_warn("request virq %d failed, errno = %d\n", virq, ret);
    return -EINVAL;
    }

    return 0;
}
#endif

static struct platform_device LineInDetect_device = { 
    .name = "LineInDetect",//"PowerControl",
};
static struct platform_driver LineInDetect_driver = {
    .driver = {
        .name = "LineInDetect",//"PowerControl",
        .owner  = THIS_MODULE,
    },
//  .shutdown = PowerControl_shutdown,
//  .probe   = LineInDetect_Probe,
};  


static int Init(void)  //重要的函数来了
{   
#if 1   
    int ret = 0;
    static script_item_u val;
    static script_item_value_type_e type;
    dprintk();
    type = script_get_item("linein_detect", "linein_user" , &val);  //“linein_detect”,“linein_user”在sys_config.fex里面预先定义的元素
    if (SCIRPT_ITEM_VALUE_TYPE_INT != type) {   //判断获取的元素是否正确
        printk("[linein_detect] linein_user type err\n");  
        goto err;
    }
    if( 0 == val.val){
        printk("[linein_detect] linein_user type == 0\n");
        goto err;
    }

    type = script_get_item("linein_detect", "linein_gpio1", &val); 
    if (SCIRPT_ITEM_VALUE_TYPE_PIO != type) {
        printk("[linein_detect] script_get_item linein_gpio1 err\n");
        goto err;
    }
    //以上几个if均为判断元素对应属性,错误代码返回err:-EFAULT,反之则goto err1:gpio_free(~~); 将这个gpio口释放掉
    linein1 = val.gpio.gpio; 
    ret = gpio_request(linein1, "linein1");  //返回0 表示成功申请到gpio
    if (ret != 0) 
    {
        printk("[linein_detect] gpio_request linein1 failed\n");
        goto err1;  //释放gpio
    }

    ret = gpio_direction_input(linein1); //以上各种判断OK之后将此gpio设置为输入模式
    if (ret != 0)  //再次判断设置是否成功(0---成功,否则设置失败)
    {
        printk("[linein_detect]Set linein1 by input failed\n");
    }       

    item_type = script_get_item("product", "machine", &item_val);
    if(SCIRPT_ITEM_VALUE_TYPE_STR != item_type) {;
        printk("%s: product machine script_get_item err.\n", __func__);
    } else {
        machine = item_val.str;
        printk("MYDEBUG --->> linein_detect.c line = %d  machine = %s\n",__LINE__, machine);
       if (!strncmp(machine, "dolphin-h3-zhc-a803-gb", strlen(machine))) {  
        type = script_get_item("linein_detect", "linein_gpio2", &val); 
        if (SCIRPT_ITEM_VALUE_TYPE_PIO != type) {
            printk("[linein_detect] script_get_item linein_gpio2 err\n");
            goto err;
        }
        linein2 = val.gpio.gpio; 
        ret = gpio_request(linein2, "linein2");
        if (ret != 0) 
        {
            printk("[linein_detect] gpio_request linein2 failed\n");
            goto err1;
        }

        ret = gpio_direction_input(linein2);
        if (ret != 0) 
        {
            printk("[linein_detect]Set linein2 by input failed\n");
        }       
       }
    }
    INIT_DELAYED_WORK(&g_DelayTask, linein_decetect);
    __cancel_delayed_work(&g_DelayTask);
    schedule_delayed_work(&g_DelayTask, 2000);
#endif
     ret = platform_device_register(&LineInDetect_device);
     if (ret == 0) {     
        ret = platform_driver_register(&LineInDetect_driver);
     }

 //   PowerOnProcess();

    return 0;

//err3:
//  gpio_free(TouchKeyIO3); 
//err2:
//  gpio_free(TouchKeyIO2);
err1:
    gpio_free(linein1);

err:
    return -EFAULT;

}

static void Exit(void)
{
    platform_driver_unregister(&LineInDetect_driver);
    platform_device_unregister(&LineInDetect_device);
}

static ssize_t LineInDetect_store(struct class *class, struct class_attribute *attr, const char *buf, size_t count)
{
    dprintk();

    return count;
}

static ssize_t LineInDetect_show(struct class *class, struct class_attribute *attr, char *buf)
{
//      dprintk();
    return sprintf(buf, "%d", GetLineInDetectStatus());
}
//注册文件节点
//  __ATTR(cmd, 0777, PowerControl_show, PowerControl_store),
static struct class_attribute LineInDetect_class_attrs[] = {
    __ATTR(cmd, 0777, LineInDetect_show, LineInDetect_store),
    __ATTR_NULL
};

//文件节点的路径名字:KeyDetect, 文件节点的属性:KeyDetect_class_attrs  //PowerControl_class
static struct class LineInDetect_class = { 
    .name = "LineInDetect",
    .class_attrs = LineInDetect_class_attrs,
    .class_attrs = LineInDetect_class_attrs,
};

#if 1

#ifdef CONFIG_HAS_EARLYSUSPEND
struct early_suspend    linein_detect_early_suspend;
// 休眠
static void linein_detect_pm_early_suspend(struct early_suspend *handler)
//static void sunxi_keyboard_early_suspend(struct early_suspend *h)
{
    printk("MYDEBUG ----->> LineIn_Detect_suspend++++++++++++++\n");
//  PowerOffProcess();
}

// 唤醒
static void linein_detect_pm_resume(struct early_suspend *handler)
//static void sunxi_keyboard_late_resume(struct early_suspend *h)
{
    printk("MYDEBUG ----->> LineIn_Detect_pm_resume++++++++++++++\n");
//  PowerOnProcess();

//  if(Exp_GetPowerDetectStatus())
//      SendPowerOffKey();
}
/*
#else
#ifdef CONFIG_PM
static int sunxi_keyboard_suspend(struct device *dev)
{
    printk("MYDBUG --->> line = %d, fun = %s \n", __LINE__, __func__);
    return 0;
}   

static int sunxi_keyboard_resume(struct device *dev)
{
    printk("MYDBUG --->> line = %d, fun = %s \n", __LINE__, __func__);
    return 0;   
}   

#endif
*/
#endif /* CONFIG_HAS_EARLYSUSPEND */


#endif
//调用初始化函数的地方(请看返回的函数)
static int __init LineInDetect_init(void)
{
    dprintk();
    class_register(&LineInDetect_class); //PowerControl_class

    #if 0
/*  
    g_PowerCtrl_early_suspend.suspend   = PowerCtrl_pm_early_suspend;
    g_PowerCtrl_early_suspend.resume    = PowerCtrl_pm_resume;
    g_PowerCtrl_early_suspend.level     = 3;
    register_early_suspend(&g_PowerCtrl_early_suspend);             // <--- 向电源管理系统注册
*/  
    printk("MYDBUG zhc_power_ctr--->> ==register_early_suspend init=\n");
    g_PowerCtrl_data = kzalloc(sizeof(*g_PowerCtrl_data), GFP_KERNEL);
    if (g_PowerCtrl_data == NULL) {
        printk("MYDBUG zhc_power_ctr--->>  g_PowerCtrl_data == err \n");
    }
    g_PowerCtrl_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 3;   
    g_PowerCtrl_data->early_suspend.suspend = PowerCtrl_pm_early_suspend;
    g_PowerCtrl_data->early_suspend.resume  = PowerCtrl_pm_resume;
    g_PowerCtrl_data(&g_PowerCtrl_data->early_suspend); 
    #endif
/*
#ifdef CONFIG_HAS_EARLYSUSPEND
#else
#ifdef CONFIG_PM
    keyboard_pm_domain.ops.suspend = sunxi_keyboard_suspend;
    keyboard_pm_domain.ops.resume = sunxi_keyboard_resume;
    g_PowerDec_input_dev->dev.pm_domain = &keyboard_pm_domain;  
#endif
#endif  
*/
#ifdef CONFIG_HAS_EARLYSUSPEND 
    linein_detect_early_suspend.suspend = linein_detect_pm_early_suspend;
    linein_detect_early_suspend.resume  = linein_detect_pm_resume;
    linein_detect_early_suspend.level   = 0;
    register_early_suspend(&linein_detect_early_suspend);               
#endif

    return Init();
//  return 0;
}

static void __exit LineInDetect_exit(void)
{
//#ifdef CONFIG_HAS_EARLYSUSPEND    
    unregister_early_suspend(&linein_detect_early_suspend); 
//#endif
    dprintk();
    Exit();
    class_unregister(&LineInDetect_class);
}

late_initcall(LineInDetect_init); //PowerControl_init
module_exit(LineInDetect_exit);//PowerControl_exit
MODULE_LICENSE("GPL");

猜你喜欢

转载自blog.csdn.net/zhaoqi2617/article/details/78785230
h3