diff options
Diffstat (limited to 'drivers/input/keyboard/qt2160.c')
| -rw-r--r-- | drivers/input/keyboard/qt2160.c | 230 |
1 files changed, 66 insertions, 164 deletions
diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c index 1c0ddad0a1cc..53f5255fd19d 100644 --- a/drivers/input/keyboard/qt2160.c +++ b/drivers/input/keyboard/qt2160.c @@ -1,25 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * qt2160.c - Atmel AT42QT2160 Touch Sense Controller * * Copyright (C) 2009 Raphael Derosso Pereira <raphaelpereira@gmail.com> - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/leds.h> #include <linux/module.h> #include <linux/slab.h> @@ -46,7 +32,7 @@ #define QT2160_NUM_LEDS_X 8 -#define QT2160_CYCLE_INTERVAL (2*HZ) +#define QT2160_CYCLE_INTERVAL 2000 /* msec - 2 sec */ static unsigned char qt2160_key2code[] = { KEY_0, KEY_1, KEY_2, KEY_3, @@ -59,23 +45,19 @@ static unsigned char qt2160_key2code[] = { struct qt2160_led { struct qt2160_data *qt2160; struct led_classdev cdev; - struct work_struct work; char name[32]; int id; - enum led_brightness new_brightness; + enum led_brightness brightness; }; #endif struct qt2160_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(qt2160_key2code)]; u16 key_matrix; #ifdef CONFIG_LEDS_CLASS struct qt2160_led leds[QT2160_NUM_LEDS_X]; - struct mutex led_lock; #endif }; @@ -84,46 +66,39 @@ static int qt2160_write(struct i2c_client *client, u8 reg, u8 data); #ifdef CONFIG_LEDS_CLASS -static void qt2160_led_work(struct work_struct *work) +static int qt2160_led_set(struct led_classdev *cdev, + enum led_brightness value) { - struct qt2160_led *led = container_of(work, struct qt2160_led, work); + struct qt2160_led *led = container_of(cdev, struct qt2160_led, cdev); struct qt2160_data *qt2160 = led->qt2160; struct i2c_client *client = qt2160->client; - int value = led->new_brightness; u32 drive, pwmen; - mutex_lock(&qt2160->led_lock); - - drive = qt2160_read(client, QT2160_CMD_DRIVE_X); - pwmen = qt2160_read(client, QT2160_CMD_PWMEN_X); - if (value != LED_OFF) { - drive |= (1 << led->id); - pwmen |= (1 << led->id); - - } else { - drive &= ~(1 << led->id); - pwmen &= ~(1 << led->id); - } - qt2160_write(client, QT2160_CMD_DRIVE_X, drive); - qt2160_write(client, QT2160_CMD_PWMEN_X, pwmen); + if (value != led->brightness) { + drive = qt2160_read(client, QT2160_CMD_DRIVE_X); + pwmen = qt2160_read(client, QT2160_CMD_PWMEN_X); + if (value != LED_OFF) { + drive |= BIT(led->id); + pwmen |= BIT(led->id); - /* - * Changing this register will change the brightness - * of every LED in the qt2160. It's a HW limitation. - */ - if (value != LED_OFF) - qt2160_write(client, QT2160_CMD_PWM_DUTY, value); + } else { + drive &= ~BIT(led->id); + pwmen &= ~BIT(led->id); + } + qt2160_write(client, QT2160_CMD_DRIVE_X, drive); + qt2160_write(client, QT2160_CMD_PWMEN_X, pwmen); - mutex_unlock(&qt2160->led_lock); -} + /* + * Changing this register will change the brightness + * of every LED in the qt2160. It's a HW limitation. + */ + if (value != LED_OFF) + qt2160_write(client, QT2160_CMD_PWM_DUTY, value); -static void qt2160_led_set(struct led_classdev *cdev, - enum led_brightness value) -{ - struct qt2160_led *led = container_of(cdev, struct qt2160_led, cdev); + led->brightness = value; + } - led->new_brightness = value; - schedule_work(&led->work); + return 0; } #endif /* CONFIG_LEDS_CLASS */ @@ -179,10 +154,10 @@ static int qt2160_read_block(struct i2c_client *client, return 0; } -static int qt2160_get_key_matrix(struct qt2160_data *qt2160) +static void qt2160_get_key_matrix(struct input_dev *input) { + struct qt2160_data *qt2160 = input_get_drvdata(input); struct i2c_client *client = qt2160->client; - struct input_dev *input = qt2160->input; u8 regs[6]; u16 old_matrix, new_matrix; int ret, i, mask; @@ -197,7 +172,7 @@ static int qt2160_get_key_matrix(struct qt2160_data *qt2160) if (ret) { dev_err(&client->dev, "could not perform chip read.\n"); - return ret; + return; } old_matrix = qt2160->key_matrix; @@ -215,44 +190,17 @@ static int qt2160_get_key_matrix(struct qt2160_data *qt2160) } input_sync(input); - - return 0; } -static irqreturn_t qt2160_irq(int irq, void *_qt2160) +static irqreturn_t qt2160_irq(int irq, void *data) { - struct qt2160_data *qt2160 = _qt2160; - unsigned long flags; - - spin_lock_irqsave(&qt2160->lock, flags); + struct input_dev *input = data; - mod_delayed_work(system_wq, &qt2160->dwork, 0); - - spin_unlock_irqrestore(&qt2160->lock, flags); + qt2160_get_key_matrix(input); return IRQ_HANDLED; } -static void qt2160_schedule_read(struct qt2160_data *qt2160) -{ - spin_lock_irq(&qt2160->lock); - schedule_delayed_work(&qt2160->dwork, QT2160_CYCLE_INTERVAL); - spin_unlock_irq(&qt2160->lock); -} - -static void qt2160_worker(struct work_struct *work) -{ - struct qt2160_data *qt2160 = - container_of(work, struct qt2160_data, dwork.work); - - dev_dbg(&qt2160->client->dev, "worker\n"); - - qt2160_get_key_matrix(qt2160); - - /* Avoid device lock up by checking every so often */ - qt2160_schedule_read(qt2160); -} - static int qt2160_read(struct i2c_client *client, u8 reg) { int ret; @@ -291,26 +239,22 @@ static int qt2160_write(struct i2c_client *client, u8 reg, u8 data) static int qt2160_register_leds(struct qt2160_data *qt2160) { struct i2c_client *client = qt2160->client; - int ret; + int error; int i; - mutex_init(&qt2160->led_lock); - for (i = 0; i < QT2160_NUM_LEDS_X; i++) { struct qt2160_led *led = &qt2160->leds[i]; snprintf(led->name, sizeof(led->name), "qt2160:x%d", i); led->cdev.name = led->name; - led->cdev.brightness_set = qt2160_led_set; + led->cdev.brightness_set_blocking = qt2160_led_set; led->cdev.brightness = LED_OFF; led->id = i; led->qt2160 = qt2160; - INIT_WORK(&led->work, qt2160_led_work); - - ret = led_classdev_register(&client->dev, &led->cdev); - if (ret < 0) - return ret; + error = devm_led_classdev_register(&client->dev, &led->cdev); + if (error) + return error; } /* Tur off LEDs */ @@ -321,16 +265,6 @@ static int qt2160_register_leds(struct qt2160_data *qt2160) return 0; } -static void qt2160_unregister_leds(struct qt2160_data *qt2160) -{ - int i; - - for (i = 0; i < QT2160_NUM_LEDS_X; i++) { - led_classdev_unregister(&qt2160->leds[i].cdev); - cancel_work_sync(&qt2160->leds[i].work); - } -} - #else static inline int qt2160_register_leds(struct qt2160_data *qt2160) @@ -338,10 +272,6 @@ static inline int qt2160_register_leds(struct qt2160_data *qt2160) return 0; } -static inline void qt2160_unregister_leds(struct qt2160_data *qt2160) -{ -} - #endif static bool qt2160_identify(struct i2c_client *client) @@ -375,20 +305,16 @@ static bool qt2160_identify(struct i2c_client *client) return true; } -static int qt2160_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int qt2160_probe(struct i2c_client *client) { struct qt2160_data *qt2160; struct input_dev *input; int i; int error; - /* Check functionality */ - error = i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_BYTE); - if (!error) { + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { dev_err(&client->dev, "%s adapter not supported\n", - dev_driver_string(&client->adapter->dev)); + dev_driver_string(&client->adapter->dev)); return -ENODEV; } @@ -396,18 +322,16 @@ static int qt2160_probe(struct i2c_client *client, return -ENODEV; /* Chip is valid and active. Allocate structure */ - qt2160 = kzalloc(sizeof(struct qt2160_data), GFP_KERNEL); - input = input_allocate_device(); - if (!qt2160 || !input) { - dev_err(&client->dev, "insufficient memory\n"); - error = -ENOMEM; - goto err_free_mem; - } + qt2160 = devm_kzalloc(&client->dev, sizeof(*qt2160), GFP_KERNEL); + if (!qt2160) + return -ENOMEM; + + input = devm_input_allocate_device(&client->dev); + if (!input) + return -ENOMEM; qt2160->client = client; qt2160->input = input; - INIT_DELAYED_WORK(&qt2160->dwork, qt2160_worker); - spin_lock_init(&qt2160->lock); input->name = "AT42QT2160 Touch Sense Keyboard"; input->id.bustype = BUS_I2C; @@ -424,72 +348,52 @@ static int qt2160_probe(struct i2c_client *client, } __clear_bit(KEY_RESERVED, input->keybit); + input_set_drvdata(input, qt2160); + /* Calibrate device */ error = qt2160_write(client, QT2160_CMD_CALIBRATE, 1); if (error) { dev_err(&client->dev, "failed to calibrate device\n"); - goto err_free_mem; + return error; } if (client->irq) { - error = request_irq(client->irq, qt2160_irq, - IRQF_TRIGGER_FALLING, "qt2160", qt2160); + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, qt2160_irq, + IRQF_ONESHOT, + "qt2160", input); if (error) { dev_err(&client->dev, "failed to allocate irq %d\n", client->irq); - goto err_free_mem; + return error; + } + } else { + error = input_setup_polling(input, qt2160_get_key_matrix); + if (error) { + dev_err(&client->dev, "Failed to setup polling\n"); + return error; } + input_set_poll_interval(input, QT2160_CYCLE_INTERVAL); } error = qt2160_register_leds(qt2160); if (error) { dev_err(&client->dev, "Failed to register leds\n"); - goto err_free_irq; + return error; } error = input_register_device(qt2160->input); if (error) { dev_err(&client->dev, "Failed to register input device\n"); - goto err_unregister_leds; + return error; } - i2c_set_clientdata(client, qt2160); - qt2160_schedule_read(qt2160); - - return 0; - -err_unregister_leds: - qt2160_unregister_leds(qt2160); -err_free_irq: - if (client->irq) - free_irq(client->irq, qt2160); -err_free_mem: - input_free_device(input); - kfree(qt2160); - return error; -} - -static int qt2160_remove(struct i2c_client *client) -{ - struct qt2160_data *qt2160 = i2c_get_clientdata(client); - - qt2160_unregister_leds(qt2160); - - /* Release IRQ so no queue will be scheduled */ - if (client->irq) - free_irq(client->irq, qt2160); - - cancel_delayed_work_sync(&qt2160->dwork); - - input_unregister_device(qt2160->input); - kfree(qt2160); - return 0; } static const struct i2c_device_id qt2160_idtable[] = { - { "qt2160", 0, }, + { "qt2160" }, { } }; @@ -498,12 +402,10 @@ MODULE_DEVICE_TABLE(i2c, qt2160_idtable); static struct i2c_driver qt2160_driver = { .driver = { .name = "qt2160", - .owner = THIS_MODULE, }, .id_table = qt2160_idtable, .probe = qt2160_probe, - .remove = qt2160_remove, }; module_i2c_driver(qt2160_driver); |
