AW9523 linux 按键驱动解析
硬件介绍
AW9523是国产芯片,中文手册也是看着方便很多,我从datasheet中摘录一些编写驱动过程中重要信息贴到下面,当然,最好还是看芯片手册,项目使用AW9523接入16个独立按键。
AW9523A 是一款 I2C 接口、 4 路呼吸灯及 16 路扩展 GPIO 控制器,它包含 16 路双向 GPIO 端口,其中 4 路可通过指令配置LED 驱动模式。
讯享网
| 寄存器地址 | W/R | 默认值 | 功能 | 描述 |
| 00H | R | xxH | Input_Port0 | P0 口输入状态 |
| 01H | R | xxH | Input_Port1 | P1 口输入状态 |
| 02H | W/R | 参考表 2 | Output_Port0 | P0 口输出状态 |
| 03H | W/R | 参考表 2 | Output_Port1 | P1 口输出状态 |
| 04H | W/R | 00H | Config_Port0 | P0 口输入或输出配置 |
| 05H | W/R | 00H | Config_Port1 | P1 口输入或输出配置 |
| 06H | W/R | 00H | Int_Port0 | P0 口中断使能 |
| 07H | W/R | 00H | Int_Port1 | P1 口中断使能 |
| 11H | W/R | 00H | CTL | 全局控制寄存器 |
| 13H | W/R | 0FH | LED Mode Switch | P1_3~P1_0 工作模式切换 |
| 20H | W | 00H | DIM0 | P1_0 口 LED 电流控制 |
| 21H | W | 00H | DIM1 | P1_1 口 LED 电流控制 |
| 22H | W | 00H | DIM2 | P1_2 口 LED 电流控制 |
| 23H | W | 00H | DIM3 | P1_3 口 LED 电流控制 |
| 7FH | W | 00H | Software Reset | 软复位寄存器 |
| 08H~10H 12H 14H~1FH 24H~7EH 80H~FFH |
- | - | - | 保留寄存器,用户不操作 |
注册设备
AW9523使用i2c_driver模型,在board中对应I2C i2c_board_info中注册设备如下,这里应该注意AW9523的AD0/AD1管脚应该接地。从上图中,可以确定其I2C地址。
#if defined(CONFIG_AW9523_KPD) { I2C_BOARD_INFO("aw9523", 0xB0), }, #endif
讯享网
驱动
probe函数
aw9523上电复位,代码如下
讯享网 // power on gpio_request(rst, "aw9523_rst"); gpio_direction_output(rst, 0); udelay(100); gpio_direction_output(rst, 1); mdelay(100); gpio_free(rst);
检测ID,代码如下
err = aw9523_read(data->client, 0x10, &val); if (!err && val == 0x23) return 0;
初始化配置,代码如下

讯享网 // port 0 input mode aw9523_write(data->client, AW9523_CONFIG_PORT_0, 0xff); // keys input // port 0 output low aw9523_write(data->client, AW9523_OUTPUT_PORT_0, 0x00); // port 0 enable int aw9523_write(data->client, AW9523_INT_PORT_0, 0x00); // enable irq // port 1 input mode aw9523_write(data->client, AW9523_CONFIG_PORT_1, 0xff); // keys input // port 1 output low aw9523_write(data->client, AW9523_OUTPUT_PORT_1, 0x00); // port 1 enable int aw9523_write(data->client, AW9523_INT_PORT_1, 0x00); // enable irq
注册输入设备
input = input_allocate_device(); if (!input) { err = -ENOMEM; goto exit_input_dev_alloc_failed; } input_set_drvdata(input, data); for(i=0; i<8*2; i++) { input_set_capability(input, EV_KEY, data->key_matrix[i]); } err = input_register_device(input); if (err) { goto exit_input_register_device_failed; }
创建工作队列
讯享网 INIT_WORK(&data->work, aw9523_work_func); data->work_q = create_singlethread_workqueue(dev_name(&client->dev)); if (!data->work_q) { err = -ESRCH; goto exit_create_singlethread_failed; } schedule_work(&data->work);
申请中断,aw9523中断管教是连接到我们CPU上的,所以有按键按下,会触发中断
err = request_irq(client->irq, aw9523_irq_handler, IRQF_TRIGGER_FALLING, client->name, data); if (err < 0) { dev_err(&client->dev, "aw9523_i2c_probe: request irq failed\n"); goto exit_irq_request_failed; }
中断服务函数
中断服务函数比较简单,只需要关闭AW9523中断,将工作加入到工作队列中,最终唤醒对应内核线程
讯享网 aw9523_irq_disable(data); if (!work_pending(&data->work)) queue_work(data->work_q, &data->work); return IRQ_HANDLED;
工作函数
工作函数读取AW9523 P0 P1口的管教状态,进行比对新旧状态比对,找到变化的管教,通过input系统上报。
// get port0 value aw9523_read(data->client, AW9523_INPUT_PORT_0, &p0); p0 = ~p0; if(p0 != data->port0_state) { chg = p0^data->port0_state; // xor tmp = p0; for(i=0; i<8; i++) { if(chg & 0x01) { input_report_key(data->input_dev, data->key_matrix[i], tmp & 0x01); input_sync(data->input_dev); } chg >>= 1; tmp >>= 1; } data->port0_state = p0; }
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/120253.html