cregit-Linux how code gets into the kernel

Release 4.11 drivers/input/misc/pcf8574_keypad.c

/*
 * Driver for a keypad w/16 buttons connected to a PCF8574 I2C I/O expander
 *
 * Copyright 2005-2008 Analog Devices Inc.
 *
 * Licensed under the GPL-2 or later.
 */

#include <linux/module.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/workqueue.h>


#define DRV_NAME "pcf8574_keypad"


static const unsigned char pcf8574_kp_btncode[] = {
	[0] = KEY_RESERVED,
	[1] = KEY_ENTER,
	[2] = KEY_BACKSLASH,
	[3] = KEY_0,
	[4] = KEY_RIGHTBRACE,
	[5] = KEY_C,
	[6] = KEY_9,
	[7] = KEY_8,
	[8] = KEY_7,
	[9] = KEY_B,
	[10] = KEY_6,
	[11] = KEY_5,
	[12] = KEY_4,
	[13] = KEY_A,
	[14] = KEY_3,
	[15] = KEY_2,
	[16] = KEY_1
};


struct kp_data {
	
unsigned short btncode[ARRAY_SIZE(pcf8574_kp_btncode)];
	
struct input_dev *idev;
	
struct i2c_client *client;
	
char name[64];
	
char phys[32];
	
unsigned char laststate;
};


static short read_state(struct kp_data *lp) { unsigned char x, y, a, b; i2c_smbus_write_byte(lp->client, 240); x = 0xF & (~(i2c_smbus_read_byte(lp->client) >> 4)); i2c_smbus_write_byte(lp->client, 15); y = 0xF & (~i2c_smbus_read_byte(lp->client)); for (a = 0; x > 0; a++) x = x >> 1; for (b = 0; y > 0; b++) y = y >> 1; return ((a - 1) * 4) + b; }

Contributors

PersonTokensPropCommitsCommitProp
Bryan Wu122100.00%1100.00%
Total122100.00%1100.00%


static irqreturn_t pcf8574_kp_irq_handler(int irq, void *dev_id) { struct kp_data *lp = dev_id; unsigned char nextstate = read_state(lp); if (lp->laststate != nextstate) { int key_down = nextstate < ARRAY_SIZE(lp->btncode); unsigned short keycode = key_down ? lp->btncode[nextstate] : lp->btncode[lp->laststate]; input_report_key(lp->idev, keycode, key_down); input_sync(lp->idev); lp->laststate = nextstate; } return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
Bryan Wu9999.00%150.00%
Dan Carpenter11.00%150.00%
Total100100.00%2100.00%


static int pcf8574_kp_probe(struct i2c_client *client, const struct i2c_device_id *id) { int i, ret; struct input_dev *idev; struct kp_data *lp; if (i2c_smbus_write_byte(client, 240) < 0) { dev_err(&client->dev, "probe: write fail\n"); return -ENODEV; } lp = kzalloc(sizeof(*lp), GFP_KERNEL); if (!lp) return -ENOMEM; idev = input_allocate_device(); if (!idev) { dev_err(&client->dev, "Can't allocate input device\n"); ret = -ENOMEM; goto fail_allocate; } lp->idev = idev; lp->client = client; idev->evbit[0] = BIT_MASK(EV_KEY); idev->keycode = lp->btncode; idev->keycodesize = sizeof(lp->btncode[0]); idev->keycodemax = ARRAY_SIZE(lp->btncode); for (i = 0; i < ARRAY_SIZE(pcf8574_kp_btncode); i++) { if (lp->btncode[i] <= KEY_MAX) { lp->btncode[i] = pcf8574_kp_btncode[i]; __set_bit(lp->btncode[i], idev->keybit); } } __clear_bit(KEY_RESERVED, idev->keybit); sprintf(lp->name, DRV_NAME); sprintf(lp->phys, "kp_data/input0"); idev->name = lp->name; idev->phys = lp->phys; idev->id.bustype = BUS_I2C; idev->id.vendor = 0x0001; idev->id.product = 0x0001; idev->id.version = 0x0100; lp->laststate = read_state(lp); ret = request_threaded_irq(client->irq, NULL, pcf8574_kp_irq_handler, IRQF_TRIGGER_LOW | IRQF_ONESHOT, DRV_NAME, lp); if (ret) { dev_err(&client->dev, "IRQ %d is not free\n", client->irq); goto fail_free_device; } ret = input_register_device(idev); if (ret) { dev_err(&client->dev, "input_register_device() failed\n"); goto fail_free_irq; } i2c_set_clientdata(client, lp); return 0; fail_free_irq: free_irq(client->irq, lp); fail_free_device: input_free_device(idev); fail_allocate: kfree(lp); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Bryan Wu36086.33%133.33%
Dan Carpenter358.39%133.33%
Andrew Liu225.28%133.33%
Total417100.00%3100.00%


static int pcf8574_kp_remove(struct i2c_client *client) { struct kp_data *lp = i2c_get_clientdata(client); free_irq(client->irq, lp); input_unregister_device(lp->idev); kfree(lp); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Bryan Wu45100.00%1100.00%
Total45100.00%1100.00%

#ifdef CONFIG_PM
static int pcf8574_kp_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); enable_irq(client->irq); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Bryan Wu1961.29%150.00%
Dmitry Torokhov1238.71%150.00%
Total31100.00%2100.00%


static int pcf8574_kp_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); disable_irq(client->irq); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Bryan Wu1961.29%150.00%
Dmitry Torokhov1238.71%150.00%
Total31100.00%2100.00%

static const struct dev_pm_ops pcf8574_kp_pm_ops = { .suspend = pcf8574_kp_suspend, .resume = pcf8574_kp_resume, }; #else # define pcf8574_kp_resume NULL # define pcf8574_kp_suspend NULL #endif static const struct i2c_device_id pcf8574_kp_id[] = { { DRV_NAME, 0 }, { } }; MODULE_DEVICE_TABLE(i2c, pcf8574_kp_id); static struct i2c_driver pcf8574_kp_driver = { .driver = { .name = DRV_NAME, #ifdef CONFIG_PM .pm = &pcf8574_kp_pm_ops, #endif }, .probe = pcf8574_kp_probe, .remove = pcf8574_kp_remove, .id_table = pcf8574_kp_id, }; module_i2c_driver(pcf8574_kp_driver); MODULE_AUTHOR("Michael Hennerich"); MODULE_DESCRIPTION("Keypad input driver for 16 keys connected to PCF8574"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
Bryan Wu92989.16%116.67%
Dmitry Torokhov545.18%116.67%
Dan Carpenter363.45%233.33%
Andrew Liu222.11%116.67%
Axel Lin10.10%116.67%
Total1042100.00%6100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.