代码拉取完成,页面将自动刷新
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#define QT2120_VALID_CHIPID 0x3E
#define QT2120_CMD_CHIPID 0
#define QT2120_CMD_CODEVER 1
#define QT2120_CMD_GSTAT 2
#define QT2120_CMD_KEYS3 3
#define QT2120_CMD_KEYS4 4
#define QT2120_CMD_SLIDE 5
#define QT2120_CMD_CALIBRATE 6
#define QT2120_CMD_RESET 7
#define QT2120_CYCLE_INTERVAL (2*HZ)
static unsigned char qt2120_key2code[] = {
KEY_0, KEY_1, KEY_2, KEY_3,
KEY_4, KEY_5, KEY_6, KEY_7,
KEY_8, KEY_9, KEY_A, KEY_B,
KEY_C, KEY_D, KEY_E, KEY_F,
};
struct qt2120_data {
struct i2c_client *client;
struct input_dev *input;
struct delayed_work dwork;
spinlock_t lock; /* Protects canceling/rescheduling of dwork */
unsigned short keycodes[ARRAY_SIZE(qt2120_key2code)];
u16 key_matrix;
unsigned irq_gpio;
u32 irq_flags;
};
static int qt2120_read_block(struct i2c_client *client,
u8 inireg, u8 *buffer, unsigned int count)
{
int error, idx = 0;
/*
* Can't use SMBus block data read. Check for I2C functionality to speed
* things up whenever possible. Otherwise we will be forced to read
* sequentially.
*/
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
error = i2c_smbus_write_byte(client, inireg + idx);
if (error) {
dev_err(&client->dev,
"couldn't send request. Returned %d\n", error);
return error;
}
error = i2c_master_recv(client, buffer, count);
if (error != count) {
dev_err(&client->dev,
"couldn't read registers. Returned %d bytes\n", error);
return error;
}
} else {
while (count--) {
int data;
error = i2c_smbus_write_byte(client, inireg + idx);
if (error) {
dev_err(&client->dev,
"couldn't send request. Returned %d\n", error);
return error;
}
data = i2c_smbus_read_byte(client);
if (data < 0) {
dev_err(&client->dev,
"couldn't read register. Returned %d\n", data);
return data;
}
buffer[idx++] = data;
}
}
return 0;
}
static int qt2120_get_key_matrix(struct qt2120_data *qt2120)
{
struct i2c_client *client = qt2120->client;
struct input_dev *input = qt2120->input;
u8 regs[6];
u16 old_matrix, new_matrix;
int ret, i, mask;
dev_dbg(&client->dev, "requesting keys...\n");
/*
* Read all registers from General Status Register
* to GPIOs register
*/
ret = qt2120_read_block(client, QT2120_CMD_GSTAT, regs, 6);
if (ret) {
dev_err(&client->dev,
"could not perform chip read.\n");
return ret;
}
old_matrix = qt2120->key_matrix;
qt2120->key_matrix = new_matrix = (regs[2] << 8) | regs[1];
mask = 0x01;
for (i = 0; i < 16; ++i, mask <<= 1) {
int keyval = new_matrix & mask;
if ((old_matrix & mask) != keyval) {
input_report_key(input, qt2120->keycodes[i], keyval);
dev_dbg(&client->dev, "key %d %s\n",
i, keyval ? "pressed" : "released");
}
}
input_sync(input);
return 0;
}
static irqreturn_t qt2120_irq(int irq, void *_qt2120)
{
struct qt2120_data *qt2120 = _qt2120;
unsigned long flags;
spin_lock_irqsave(&qt2120->lock, flags);
__cancel_delayed_work(&qt2120->dwork);
schedule_delayed_work(&qt2120->dwork, 0);
spin_unlock_irqrestore(&qt2120->lock, flags);
return IRQ_HANDLED;
}
static void qt2120_schedule_read(struct qt2120_data *qt2120)
{
spin_lock_irq(&qt2120->lock);
schedule_delayed_work(&qt2120->dwork, QT2120_CYCLE_INTERVAL);
spin_unlock_irq(&qt2120->lock);
}
static void qt2120_worker(struct work_struct *work)
{
struct qt2120_data *qt2120 =
container_of(work, struct qt2120_data, dwork.work);
dev_dbg(&qt2120->client->dev, "worker\n");
qt2120_get_key_matrix(qt2120);
/* Avoid device lock up by checking every so often */
qt2120_schedule_read(qt2120);
}
static int __devinit qt2120_read(struct i2c_client *client, u8 reg)
{
int ret;
ret = i2c_smbus_write_byte(client, reg);
if (ret) {
dev_err(&client->dev,
"couldn't send request. Returned %d\n", ret);
return ret;
}
ret = i2c_smbus_read_byte(client);
if (ret < 0) {
dev_err(&client->dev,
"couldn't read register. Returned %d\n", ret);
return ret;
}
return ret;
}
static int __devinit qt2120_write(struct i2c_client *client, u8 reg, u8 data)
{
int error;
error = i2c_smbus_write_byte(client, reg);
if (error) {
dev_err(&client->dev,
"couldn't send request. Returned %d\n", error);
return error;
}
error = i2c_smbus_write_byte(client, data);
if (error) {
dev_err(&client->dev,
"couldn't write data. Returned %d\n", error);
return error;
}
return error;
}
static bool __devinit qt2120_identify(struct i2c_client *client)
{
int id, ver;
/* Read Chid ID to check if chip is valid */
id = qt2120_read(client, QT2120_CMD_CHIPID);
printk("qt2120 ChipID %d \n", id);
if (id != QT2120_VALID_CHIPID) {
dev_err(&client->dev, "ID %d not supported\n", id);
return false;
}
/* Read chip firmware version */
ver = qt2120_read(client, QT2120_CMD_CODEVER);
if (ver < 0) {
dev_err(&client->dev, "could not get firmware version\n");
return false;
}
dev_info(&client->dev, "AT42QT2120 firmware version %d\n",ver);
return true;
}
static int qt2120_parse_dt(struct device *dev,
struct qt2120_data *pdata)
{
struct device_node *np = dev->of_node;
/* irq gpio info */
pdata->irq_gpio = of_get_named_gpio_flags(np,
"qt2120,irq-gpio", 0, &pdata->irq_flags);
return 0;
}
static int __devinit qt2120_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct qt2120_data *qt2120;
struct input_dev *input;
int i;
int error;
printk("AT42QT2120 Probe\n");
/* Check functionality */
error = i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE);
if (!error) {
dev_err(&client->dev, "%s adapter not supported\n",
dev_driver_string(&client->adapter->dev));
return -ENODEV;
}
if (!qt2120_identify(client))
return -ENODEV;
/* Chip is valid and active. Allocate structure */
qt2120 = kzalloc(sizeof(struct qt2120_data), GFP_KERNEL);
input = input_allocate_device();
if (!qt2120 || !input) {
dev_err(&client->dev, "insufficient memory\n");
error = -ENOMEM;
goto err_free_mem;
}
/* Parse the device tree */
if (client->dev.of_node) {
error = qt2120_parse_dt(&client->dev, qt2120);
if (error)
return error;
}
qt2120->client = client;
qt2120->input = input;
INIT_DELAYED_WORK(&qt2120->dwork, qt2120_worker);
spin_lock_init(&qt2120->lock);
input->name = "AT42QT2120 Touch Sense Keyboard";
input->id.bustype = BUS_I2C;
input->keycode = qt2120->keycodes;
input->keycodesize = sizeof(qt2120->keycodes[0]);
input->keycodemax = ARRAY_SIZE(qt2120_key2code);
__set_bit(EV_KEY, input->evbit);
__clear_bit(EV_REP, input->evbit);
for (i = 0; i < ARRAY_SIZE(qt2120_key2code); i++) {
qt2120->keycodes[i] = qt2120_key2code[i];
__set_bit(qt2120_key2code[i], input->keybit);
}
__clear_bit(KEY_RESERVED, input->keybit);
/* Configure irq gpio */
if (gpio_is_valid(qt2120->irq_gpio)) {
error = gpio_request(qt2120->irq_gpio, "qt2120_irq_gpio");
if (error) {
dev_err(&client->dev, "unable to request gpio [%d]\n",
qt2120->irq_gpio);
goto err_free_mem;
}
error = gpio_direction_input(qt2120->irq_gpio);
if (error) {
dev_err(&client->dev,
"unable to set direction for gpio [%d]\n",
qt2120->irq_gpio);
goto err_irq_gpio_req;
}
client->irq = gpio_to_irq(qt2120->irq_gpio);
} else {
dev_err(&client->dev, "irq gpio not provided\n");
goto err_free_mem;
}
/* Calibrate device */
error = qt2120_write(client, QT2120_CMD_CALIBRATE, 1);
if (error) {
dev_err(&client->dev, "failed to calibrate device\n");
goto err_free_mem;
}
if (client->irq) {
error = request_irq(client->irq, qt2120_irq,
IRQF_TRIGGER_FALLING, "qt2120", qt2120);
if (error) {
dev_err(&client->dev,
"failed to allocate irq %d\n", client->irq);
goto err_free_mem;
}
}
error = input_register_device(qt2120->input);
if (error) {
dev_err(&client->dev,
"Failed to register input device\n");
goto err_free_irq;
}
i2c_set_clientdata(client, qt2120);
qt2120_schedule_read(qt2120);
return 0;
err_free_irq:
if (client->irq)
free_irq(client->irq, qt2120);
err_irq_gpio_req:
if (gpio_is_valid(qt2120->irq_gpio))
gpio_free(qt2120->irq_gpio);
err_free_mem:
input_free_device(input);
kfree(qt2120);
return error;
}
static int __devexit qt2120_remove(struct i2c_client *client)
{
struct qt2120_data *qt2120 = i2c_get_clientdata(client);
/* Release IRQ so no queue will be scheduled */
if (client->irq)
free_irq(client->irq, qt2120);
cancel_delayed_work_sync(&qt2120->dwork);
input_unregister_device(qt2120->input);
kfree(qt2120);
return 0;
}
static const struct of_device_id qt2120_of_match[] = {
{ .compatible = "atmel,qt2120", },
{ }
};
static const struct i2c_device_id qt2120_idtable[] = {
{ "qt2120", 0, },
{ }
};
MODULE_DEVICE_TABLE(i2c, qt2120_idtable);
static struct i2c_driver qt2120_driver = {
.driver = {
.name = "qt2120",
.owner = THIS_MODULE,
.of_match_table = qt2120_of_match,
},
.id_table = qt2120_idtable,
.probe = qt2120_probe,
.remove = __devexit_p(qt2120_remove),
};
static int __init qt2120_init_module(void)
{
printk("QT2120 init\n");
return i2c_add_driver(&qt2120_driver);
}
static void __exit qt2120_exit_module(void)
{
printk("QT2120 del\n");
i2c_del_driver(&qt2120_driver);
return;
}
module_init(qt2120_init_module);
module_exit(qt2120_exit_module);
MODULE_AUTHOR("Landy Zhou <landy.zhou@ovt.com>");
MODULE_DESCRIPTION("Driver for AT42QT2120 Touch Sensor");
MODULE_LICENSE("GPL");
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。