完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
环境介绍
硬件:RK3288、键盘驱动芯片PCA9535(I2C-GPIO) 软件:android 7.1 linux4.4 原理图: I2C1_INT:GPIO5_B3 I2C1_RST:GPIO7_B4 配置介绍 1.dts &i2c1 { status = "okay"; clock-frequency = <400000>; pca9535@20 { compatible = "nxp,pca9535_keypad"; reg = <0x20>; irq_gpio_number = <&gpio5 11 IRQ_TYPE_LEVEL_LOW>; rst_gpio_number = <&gpio7 12 GPIO_ACTIVE_HIGH>; status = "okay"; }; }; 2.config CONFIG_KEYBOARD_PCA953X=y 3.Kconfig config KEYBOARD_PCA953X tristate "nxp PCA953X keyboard Sensor Chip" depends on I2C help Say Y here if you want to use nxp PCA953X keyboard Sensor chip as input device. To compile this driver as a module, choose M here: the module will be called PCA953X 4.Makefile obj-$(CONFIG_KEYBOARD_PCA953X) += pca953x-keypad.o 驱动源码 /* * PCA953x 4/8/16/24/40 bit I/O ports * * Copyright (C) 2005 Ben Gardner * Copyright (C) 2007 Marvell International Ltd. * * Derived from drivers/i2c/chips/pca9539.c * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_OF_GPIO #include #endif #include #include #include #include #include #define PCA_INT 0x0100 #define PCA953X_TYPE 0x1000 #define PCA957X_TYPE 0x2000 #define PCA_TYPE_MASK 0xF000 #define PAC9535_NAME "pac9535" enum pca9535kbd_cmd { PCA9535_INPUT_0 = 0, PCA9535_INPUT_1 = 1, PCA9535_OUTPUT_0 = 2, PCA9535_OUTPUT_1 = 3, PCA9535_INVERT_0 = 4, PCA9535_INVERT_1 = 5, PCA9535_DIRECTION_0 = 6, PCA9535_DIRECTION_1 = 7, }; struct gpio_key_button { u16 gpio_mask; int keycode; }; struct gpio_key_button key_buttons[] = { { .gpio_mask = 0x0001, .keycode = KEY_1 }, { .gpio_mask = 0x0002, .keycode = KEY_2 }, { .gpio_mask = 0x0004, .keycode = KEY_3 }, { .gpio_mask = 0x0008, .keycode = KEY_4 }, { .gpio_mask = 0x0010, .keycode = KEY_5 }, { .gpio_mask = 0x0020, .keycode = KEY_6 }, { .gpio_mask = 0x0040, .keycode = KEY_7 }, { .gpio_mask = 0x0080, .keycode = KEY_8 }, { .gpio_mask = 0x0100, .keycode = KEY_9 }, { .gpio_mask = 0x0200, .keycode = KEY_BACKSPACE }, { .gpio_mask = 0x0400, .keycode = KEY_0 }, { .gpio_mask = 0x0800, .keycode = KEY_ENTER }, { .gpio_mask = 0x1000, .keycode = KEY_UP }, { .gpio_mask = 0x2000, .keycode = KEY_DOWN }, { .gpio_mask = 0x4000, .keycode = KEY_LEFT }, { .gpio_mask = 0x8000, .keycode = KEY_RIGHT }, }; static const struct i2c_device_id pca953x_id[] = { { "pca9535", 16 | PCA953X_TYPE | PCA_INT, }, { } }; MODULE_DEVICE_TABLE(i2c, pca953x_id); static const struct acpi_device_id pca953x_acpi_ids[] = { { "INT3491", 16 | PCA953X_TYPE | PCA_INT, }, { } }; MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids); struct pca953x_priv{ struct i2c_client *client; struct input_dev *input; struct work_struct work; int irq_gpio_number ; int rst_gpio_number ; int irq_det_invert; u16 port_state; }; static int device_pca953x_init(struct pca953x_priv *pdata){ /* Initialize the PCA9535 to known state */ int ret; ret = i2c_smbus_write_byte_data(pdata->client, PCA9535_DIRECTION_0, 0xFF); if(ret < 0){ dev_err(&(pdata->client->dev), "fail to i2c_smbus_write_byte_data PCA9535_DIRECTION_0n"); goto exit; } ret = i2c_smbus_write_byte_data(pdata->client, PCA9535_DIRECTION_1, 0xFF); if(ret < 0){ dev_err(&(pdata->client->dev), "fail to i2c_smbus_write_byte_data PCA9535_DIRECTION_1n"); goto exit; } ret = i2c_smbus_write_byte_data(pdata->client, PCA9535_INVERT_0, 0xFF); if(ret < 0){ dev_err(&(pdata->client->dev), "fail to i2c_smbus_write_byte_data PCA9535_INVERT_0n"); goto exit; } ret = i2c_smbus_write_byte_data(pdata->client, PCA9535_INVERT_1, 0xFF); if(ret < 0){ dev_err(&(pdata->client->dev), "fail to i2c_smbus_write_byte_data PCA9535_INVERT_1n"); goto exit; } exit: return ret; } static void pca953x_do_work(struct work_struct *work_data) { int i; u16 new_state, pressed, released; struct pca953x_priv *data = container_of(work_data, struct pca953x_priv, work); new_state = i2c_smbus_read_byte_data(data->client, PCA9535_INPUT_0) | (i2c_smbus_read_byte_data(data->client, PCA9535_INPUT_1) << 8); dev_err(&(data->client->dev), "%s:0x%x" ,__func__, new_state); if(new_state == data->port_state) return; /* detect buttons which be newly pressed */ released = data->port_state & ~new_state; /* detect buttons which just has been released */ pressed = new_state & ~data->port_state; for(i = 0; i < ARRAY_SIZE(key_buttons); i++) { if(pressed & key_buttons.gpio_mask) { input_event(data->input, EV_KEY, key_buttons.keycode, 1); input_sync(data->input); } if(released & key_buttons.gpio_mask) { input_event(data->input, EV_KEY, key_buttons.keycode, 0); input_sync(data->input); } } data->port_state = new_state; } static irqreturn_t pca9535_irq_handler(int irq, void *data) { struct pca953x_priv *pdata = data; schedule_work(&pdata->work); return IRQ_HANDLED; } static int pca953x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct pca953x_priv *pdata; struct device_node *np = client->dev.of_node; int ret ; int i; int pca9535_irq; enum of_gpio_flags flags; pdata = devm_kzalloc(&client->dev,sizeof(struct pca953x_priv), GFP_KERNEL); if (pdata == NULL) return -ENOMEM; memset(pdata,0,sizeof(struct pca953x_priv)); pdata->client= client; /*input dev init*/ pdata->input = input_allocate_device(); if(!pdata->input) goto fail0; pdata->input->name = PAC9535_NAME; pdata->input->id.bustype = BUS_I2C; pdata->input->id.vendor = 0x0001; pdata->input->id.product = 0x0001; pdata->input->id.version = 0x0100; __set_bit(EV_KEY, pdata->input->evbit); __set_bit(INPUT_PROP_DIRECT, pdata->input->propbit); for(i = 0; i < ARRAY_SIZE(key_buttons); i++) { input_set_capability(pdata->input, EV_KEY, key_buttons.keycode); } if((ret = input_register_device(pdata->input))) { dev_err(&client->dev, "%s: failed to register input device: %sn", __func__, dev_name(&client->dev)); goto fail0; } pdata->irq_gpio_number = of_get_named_gpio_flags(np, "irq_gpio_number", 0, &flags); if (pdata->irq_gpio_number < 0) { dev_err(&client->dev, "Can not read property hp_det_gpion"); pdata->irq_gpio_number = -1; } else { INIT_WORK(&pdata->work, pca953x_do_work); pdata->irq_det_invert = !!(flags & OF_GPIO_ACTIVE_LOW); ret = devm_gpio_request_one(&client->dev, pdata->irq_gpio_number, GPIOF_IN, "pca9535_irq"); if (ret < 0) return ret; pca9535_irq = gpio_to_irq(pdata->irq_gpio_number); ret = devm_request_threaded_irq(&client->dev, pca9535_irq, NULL, pca9535_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "pca9535_interrupt", pdata); if (ret < 0) { dev_err(&client->dev, "request_irq failed: %dn", ret); return ret; } } pdata->rst_gpio_number = of_get_named_gpio_flags(np, "rst_gpio_number", 0, &flags); ret = devm_gpio_request_one(&client->dev, pdata->rst_gpio_number, GPIOF_IN, "pca9535_rst"); if (ret < 0) return ret; i2c_set_clientdata(client, pdata); ret = device_pca953x_init(pdata); return 0; fail0: return -1; } static int pca953x_remove(struct i2c_client *client) { struct pca953x_priv *pdata = i2c_get_clientdata(client); if(pdata == NULL) return 0; dev_err(&(client->dev), "%s:%d" ,__func__, __LINE__); if(pdata->input){ input_unregister_device(pdata->input); input_free_device(pdata->input); } dev_err(&(client->dev), "%s:%d" ,__func__, __LINE__); i2c_set_clientdata(client, NULL); kfree(pdata); dev_err(&(client->dev), "%s:%d" ,__func__, __LINE__); return 0; } static const struct of_device_id pca953x_dt_ids[] = { { .compatible = "nxp,pca9535_keypad", }, { } }; MODULE_DEVICE_TABLE(of, pca953x_dt_ids); static struct i2c_driver pca953x_driver = { .driver = { .name = PAC9535_NAME, .of_match_table = pca953x_dt_ids, .acpi_match_table = ACPI_PTR(pca953x_acpi_ids), }, .probe = pca953x_probe, .remove = pca953x_remove, .id_table = pca953x_id, }; static int __init pca953x_init(void) { return i2c_add_driver(&pca953x_driver); } /* register after i2c postcore initcall and before * subsys initcalls that may rely on these GPIOs */ subsys_initcall(pca953x_init); static void __exit pca953x_exit(void) { i2c_del_driver(&pca953x_driver); } module_exit(pca953x_exit); MODULE_AUTHOR("jerry deng MODULE_DESCRIPTION("keypad driver for PCA953x"); MODULE_LICENSE("GPL"); |
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
1861 浏览 1 评论
synopsys 的design ware:DW_fpv_div,浮点数除法器,默认32位下,想提升覆盖率(TMAX),如果用功能case去提升覆盖率呢?
2317 浏览 1 评论
RK3588 GStreamer调试四路鱼眼摄像头四宫格显示报错
5129 浏览 1 评论
【飞凌嵌入式OK3576-C开发板体验】RKNN神经网络-YOLO图像识别
254 浏览 0 评论
【飞凌嵌入式OK3576-C开发板体验】SSH远程登录网络配置及CAN通讯
1336 浏览 0 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-20 06:30 , Processed in 0.645486 second(s), Total 42, Slave 36 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号