栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux系统CH452 keypad按键调测总结

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux系统CH452 keypad按键调测总结

【硬件平台】

处理器:sim8950,msm8953
内核版本:linux4.4
按键芯片:CH452A

【硬件连接】

SIM8950 CH452A
M_GPIO_19(PIN52) DCLK(PIN27) -》I2C_SCL
M_GPIO_18(PIN51) DIN(PIN26) -》 I2C_SDA
M_GPIO_59(PIN68) DOUT(PIN24) -》 KEYBOARD_INT
NA ADDR -》高,I2C设备地址
NA VCC(PIN23) -》 3.3V
NA ADDR(PIN25) -》 3.3V

【软件流程】

1、设备树中添加I2C键盘设备;
kernel/arch/arm64/boot/dts/qcom/msm8953.dtsi

	i2c_5: i2c@7af5000 { 
		compatible = "qcom,i2c-msm-v2";
        ...
		status = "ok";
	    ch452@60 {
	        status = "okay";
	        compatible = "wch,ch452-keypad";
	        reg = <0x60>;   // CH452 ADDR为高,此处地址为0x60
	        interrupt-parent = <&tlmm>;
	        interrupts = <59 0x2008>;
	        wch,i2c-sda-gpios = <&tlmm 18 0x00>;   // GPIO模拟I2C,设置SDA GPIO编号
	        wch,i2c-scl-gpios = <&tlmm 19 0x00>;   // GPIO模拟I2C,设置SCL GPIO编号
	        wch,interrupt-gpios = <&tlmm 59 0x00>; // 中断上报,用于在中断中获取键值
        };
    };

参考文档:
kernel/documentation/input/input-programming.txt

2、添加CH452按键编译规则
kernel/arch/arm64/configs/msm8953_defconfig

CONFIG_KEYBOARD_CH452=y

kernel/drivers/input/keyboard/Kconfig

config KEYBOARD_CH452
        tristate "ch452_keypad support"
        depends on I2C

kernel/drivers/input/keyboard/Makefile

obj-$(CONFIG_KEYBOARD_CH452)            += ch452_keypad.o 

3、CH452内核驱动代码

static const unsigned int g_ch452_keyinfo[][3] = {
    // {row, col, val}
    {1, 1, KEY_APPSELECT}, // APP
    {1, 0, KEY_LEFT},      // left
    {0, 2, KEY_UP},        // up
    {7, 0, KEY_DOWN},      // down
    {0, 0, KEY_RIGHT},     // right
    {0, 1, KEY_ENTER},     // ok
    ...
};
static int ch452_parse_dt(struct device *dev)
{
    enum of_gpio_flags gpio_flag;
    struct device_node *np = dev->of_node;
    struct ch452_data *pData = &g_ch452Data;

#if (CH452_I2C_SIMULATE == 1)	
    pData->scl_pin = of_get_named_gpio_flags(np, "wch,i2c-scl-gpios", 0, &gpio_flag);
    CH452_INFO("%s, pData->scl_pin=%dn", __FUNCTION__, pData->scl_pin);
	
    pData->sda_pin = of_get_named_gpio_flags(np, "wch,i2c-sda-gpios", 0, &gpio_flag);
    CH452_INFO("%s, pData->sda_pin=%dn", __FUNCTION__, pData->sda_pin);
#endif	
    pData->int_pin = of_get_named_gpio_flags(np, "wch,interrupt-gpios", 0, &gpio_flag);
    CH452_INFO("%s, pData->int_pin=%dn", __FUNCTION__, pData->int_pin);
    return 0;
}

static int ch452_gpio_init(void)
{
    struct ch452_data *pData = &g_ch452Data;

#if (CH452_I2C_SIMULATE == 1)
    if (gpio_is_valid(pData->sda_pin)) {
        gpio_request(pData->sda_pin, "ch452 sda pin");
        gpio_direction_output(pData->sda_pin, GPIO_ST_HIGH);
    }

    if (gpio_is_valid(pData->scl_pin)) {
        gpio_request(pData->scl_pin, "ch452 scl pin");
        gpio_direction_output(pData->scl_pin, GPIO_ST_HIGH);
    }
#endif
    if (gpio_is_valid(pData->int_pin)) {
        gpio_request(pData->int_pin, "ch452 int pin");
        gpio_direction_input(pData->int_pin);
    }
    return 0;
}
int ch452_get_keycode(int row, int col, int *keyCode)
{
    int i;
    int keyNum = sizeof(g_ch452_keyinfo) / sizeof(g_ch452_keyinfo[0]); 

    for (i = 0; i < keyNum; i++) {
        if ((row == g_ch452_keyinfo[i][0]) && (col == g_ch452_keyinfo[i][1])) {
            *keyCode = g_ch452_keyinfo[i][2];
            return 0;
        }
    }
    CH452_ERROR("%s key not found! %d %dn", row, col);
    return -1;
}
static void ch452_worker(struct work_struct *work)
{
    unsigned char val;
    int row, col, keycode;
    struct ch452_data *pData = &g_ch452Data;

    val = Ch452_Read(CH452_I2C_ADDR1, (unsigned short)CH452_GET_KEY); // 读取扫描行列号
	
    row = val & 0x7;
    col = (val >> 3) & 0x7;
    if (ch452_get_keycode(row, col, &keycode) == 0) {
        input_report_key(pData->input, keycode, -1); // 上报按键按下
        input_sync(pData->input);
        udelay(1);
        input_report_key(pData->input, keycode, 0);  // 上报按键抬起
        input_sync(pData->input);
    }
    return;
}
static irqreturn_t ch452_interrupt(int irq, void *dev_id)
{
    ch452_worker(NULL);
    return IRQ_HANDLED;
}

static int ch452_irq_init(struct i2c_client *client)
{
    int ret;
    struct ch452_data *pData = &g_ch452Data;
	
    pData->int_irq = gpio_to_irq(pData->int_pin);
    CH452_INFO("%s irq num:%dn", __FUNCTION__, pData->int_irq);
    if (pData->int_irq) {
        // key up: int pin = 0; key down: int pin = 1
        ret = request_threaded_irq(pData->int_irq, NULL, ch452_interrupt,
                          IRQF_TRIGGER_RISING | IRQF_ONESHOT,
                          client->name, pData);
        if (ret < 0) {
            CH452_ERROR("%s call request_irq failedn", __FUNCTION__);
            return ret;
        }
    }
    return ret;
}
static struct input_dev* ch452_input_init(struct i2c_client *client)
{
    int i, ret;
    struct ch452_data *pData = &g_ch452Data;
    struct input_dev *input;
    int row,col,keyCode;
    int keyNum = sizeof(g_ch452_keyinfo) / sizeof(g_ch452_keyinfo[0]);
	
    CH452_DEBUG("%s entryn", __FUNCTION__);
    input = input_allocate_device();
    if (input == NULL) {
        dev_err(&client->dev, "%s call input_allocate_device failedn", __FUNCTION__);
        return NULL;
    }
    input->name         = client->name;
    input->id.bustype   = BUS_I2C;
    input->open         = ch452_open;
    input->close        = ch452_close;
    input->evbit[0]     = BIT_MASK(EV_KEY);   // input处理按键事件
    for (i = 0; i < keyNum; i++) {
        keyCode = g_ch452_keyinfo[i][2];
        row = g_ch452_keyinfo[i][0];
        col = g_ch452_keyinfo[i][1];
        input->keybit[BIT_WORD(keyCode)] |= BIT_MASK(keyCode);  // 注册需要上报的keycode
        CH452_INFO("%s i=%d,row=%d,col=%d,keycode=0x%xn", __FUNCTION__, i, row, col, keyCode);
    }
    ret = input_register_device(input);       // 注册input设备,用于上报上层系统
    if (ret) {
        CH452_ERROR("failed to register input devicen");
        return NULL;
    }	
    return input;
}
static int ch452_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret;
    struct ch452_data *pData = &g_ch452Data;	

    CH452_INFO("%s entry, client name=%sn", __FUNCTION__, client->name);
    ret = ch452_parse_dt(&client->dev);
    if (ret != 0) {
        CH452_ERROR("%s call ch452_parse_dt failedn", __FUNCTION__);
        return ret;
    }

    ret = ch452_gpio_init();
    if (ret != 0) {
        CH452_ERROR("%s call ch452_gpio_init failedn", __FUNCTION__);
        return ret;
    }
	
    pData->client = client;
    pData->input = ch452_input_init(client);
    if (pData->input == NULL) {
        CH452_ERROR("%s call ch452_input_init failedn", __FUNCTION__);
        return -1;		
    }

    ret = ch452_irq_init(client);
    if (ret != 0) {
	    CH452_ERROR("call ch452_irq_init failed!n");
	    return -1;		
    }
	
    ch452_hw_init();
    i2c_set_clientdata(client, pData);
    return 0;
}
static int ch452_remove(struct i2c_client *client)
{
    struct ch452_data *pData = &g_ch452Data;

    CH452_INFO("%s entryn", __FUNCTION__);
    input_unregister_device(pData->input);
    return 0;
}
static const struct of_device_id ch452_dt_match[] = {
    {.compatible = "wch,ch452-keypad",},
    {},
};
static const struct i2c_device_id ch452_i2c_id[] = {
    {"ch452-keypad", 0},
    {}
};
static struct i2c_driver ch452_i2c_driver = {
    .probe          = ch452_probe,
    .remove         = ch452_remove,
    .id_table       = ch452_i2c_id,
    .driver         = {
        .name  = "ch452-keypad",
	    .owner = THIS_MODULE,
        .of_match_table = ch452_dt_match,
    },
};

static int __init ch452_init(void)
{
    CH452_DEBUG("%s entryn", __FUNCTION__);
    return i2c_add_driver(&ch452_i2c_driver);
}
module_init(ch452_init);

static void __exit ch452_exit(void)
{
    struct ch452_data *pData = &g_ch452Data;
	
#if (CH452_I2C_SIMULATE == 1)
    gpio_free(pData->scl_pin);
    gpio_free(pData->sda_pin);
#endif    
    gpio_free(pData->int_pin);
    i2c_del_driver(&ch452_i2c_driver);
}
module_exit(ch452_exit);

MODULE_AUTHOR("Leo.li");
MODULE_DEscriptION("CH452 Keypad Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:ch452-keypad");

GPIO模拟I2C驱动与参考Linux驱动参考如下:
https://download.csdn.net/download/wulang4220/9938539?ops_request_misc=&request_id=&biz_id=103&utm_term=CH452%20linux%20keyboard%E9%A9%B1%E5%8A%A8&utm_medium=distribute.pc_search_result.none-task-download-2allsobaiduweb~default-0-9938539.first_rank_v2_pc_rank_v29&spm=1018.2226.3001.4187.2

【调试问题】

1、驱动加载时无法进入probe入口函数
解决办法:添加id table解决
static const struct i2c_device_id ch452_i2c_id[] = {
{“ch452-keypad”, 0},
{}
};

【参考资料】

1、input子系统——kernel中input设备介绍
https://blog.csdn.net/u013604527/article/details/53432623

2、input子系统按键处理实例介绍
https://blog.csdn.net/liyanfei123456/article/details/53197277

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/752226.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号