~mil/ppbbq10

f19e8c430b2d4912b146a35149163fe0db8b5a96 — arturo182 6 years ago dc8147f
Changed the keymap to sparse, WIP
1 files changed, 281 insertions(+), 27 deletions(-)

M bbq10pmod.c
M bbq10pmod.c => bbq10pmod.c +281 -27
@@ 8,6 8,7 @@
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/input/sparse-keymap.h>

#define REG_VER		0x01
#define REG_CFG		0x02


@@ 49,13 50,229 @@ struct bbq10pmod_data {
	struct input_dev *input;
};

static const struct key_entry bbq10pmod_keys[] = {
	{ KE_KEY, 'a', { KEY_A } },
	{ KE_KEY, 'b', { KEY_B } },
	{ KE_KEY, 'c', { KEY_C } },
	{ KE_KEY, 'd', { KEY_D } },
	{ KE_KEY, 'e', { KEY_E } },
	{ KE_KEY, 'f', { KEY_F } },
	{ KE_KEY, 'g', { KEY_G } },
	{ KE_KEY, 'h', { KEY_H } },
	{ KE_KEY, 'i', { KEY_I } },
	{ KE_KEY, 'j', { KEY_J } },
	{ KE_KEY, 'k', { KEY_K } },
	{ KE_KEY, 'l', { KEY_L } },
	{ KE_KEY, 'm', { KEY_M } },
	{ KE_KEY, 'n', { KEY_N } },
	{ KE_KEY, 'o', { KEY_O } },
	{ KE_KEY, 'p', { KEY_P } },
	{ KE_KEY, 'q', { KEY_Q } },
	{ KE_KEY, 'r', { KEY_R } },
	{ KE_KEY, 's', { KEY_S } },
	{ KE_KEY, 't', { KEY_T } },
	{ KE_KEY, 'u', { KEY_U } },
	{ KE_KEY, 'w', { KEY_W } },
	{ KE_KEY, 'v', { KEY_V } },
	{ KE_KEY, 'x', { KEY_X } },
	{ KE_KEY, 'y', { KEY_Y } },
	{ KE_KEY, 'z', { KEY_Z } },
	{ KE_KEY, '0', { KEY_0 } },
	{ KE_KEY, '1', { KEY_1 } },
	{ KE_KEY, '2', { KEY_2 } },
	{ KE_KEY, '3', { KEY_3 } },
	{ KE_KEY, '4', { KEY_4 } },
	{ KE_KEY, '5', { KEY_5 } },
	{ KE_KEY, '6', { KEY_6 } },
	{ KE_KEY, '7', { KEY_7 } },
	{ KE_KEY, '8', { KEY_8 } },
	{ KE_KEY, '9', { KEY_9 } },
	{ KE_KEY, '-', { KEY_MINUS } },
	//{ KE_KEY, '+', { KEY_PLUS } },
	{ KE_KEY, '=', { KEY_EQUAL } },
	{ KE_KEY, '\b', { KEY_BACKSPACE } },
	{ KE_KEY, ' ', { KEY_SPACE } },
	//{ KE_KEY, '', { KEY_ } },
	//{ KE_KEY, '', { KEY_ } },
	//{ KE_KEY, '', { KEY_ } },
	//{ KE_KEY, '', { KEY_ } },
	//{ KE_KEY, '', { KEY_ } },
	//{ KE_KEY, '', { KEY_ } },
};

static unsigned int sparse_keymap_get_key_index(struct input_dev *dev,
						const struct key_entry *k)
{
	struct key_entry *key;
	unsigned int idx = 0;

	for (key = dev->keycode; key->type != KE_END; key++) {
		if (key->type == KE_KEY) {
			if (key == k)
				break;
			idx++;
		}
	}

	return idx;
}

static struct key_entry *sparse_keymap_entry_by_index(struct input_dev *dev,
						      unsigned int index)
{
	struct key_entry *key;
	unsigned int key_cnt = 0;

	for (key = dev->keycode; key->type != KE_END; key++)
		if (key->type == KE_KEY)
			if (key_cnt++ == index)
				return key;

	return NULL;
}

struct key_entry *sparse_keymap_entry_from_scancode(struct input_dev *dev,
						    unsigned int code)
{
	struct key_entry *key;

	for (key = dev->keycode; key->type != KE_END; key++)
		if (code == key->code)
			return key;

	return NULL;
}

struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev,
						   unsigned int keycode)
{
	struct key_entry *key;

	for (key = dev->keycode; key->type != KE_END; key++)
		if (key->type == KE_KEY && keycode == key->keycode)
			return key;

	return NULL;
}

static struct key_entry *sparse_keymap_locate(struct input_dev *dev,
					const struct input_keymap_entry *ke)
{
	struct key_entry *key;
	unsigned int scancode;

	if (ke->flags & INPUT_KEYMAP_BY_INDEX)
		key = sparse_keymap_entry_by_index(dev, ke->index);
	else if (input_scancode_to_scalar(ke, &scancode) == 0)
		key = sparse_keymap_entry_from_scancode(dev, scancode);
	else
		key = NULL;

	return key;
}

static int sparse_keymap_getkeycode(struct input_dev *dev,
				    struct input_keymap_entry *ke)
{
	const struct key_entry *key;

	if (dev->keycode) {
		key = sparse_keymap_locate(dev, ke);
		if (key && key->type == KE_KEY) {
			ke->keycode = key->keycode;
			if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
				ke->index =
					sparse_keymap_get_key_index(dev, key);
			ke->len = sizeof(key->code);
			memcpy(ke->scancode, &key->code, sizeof(key->code));
			return 0;
		}
	}

	return -EINVAL;
}

static int sparse_keymap_setkeycode(struct input_dev *dev,
				    const struct input_keymap_entry *ke,
				    unsigned int *old_keycode)
{
	struct key_entry *key;

	if (dev->keycode) {
		key = sparse_keymap_locate(dev, ke);
		if (key && key->type == KE_KEY) {
			*old_keycode = key->keycode;
			key->keycode = ke->keycode;
			set_bit(ke->keycode, dev->keybit);
			if (!sparse_keymap_entry_from_keycode(dev, *old_keycode))
				clear_bit(*old_keycode, dev->keybit);
			return 0;
		}
	}

	return -EINVAL;
}

int sparse_keymap_setup(struct input_dev *dev,
			const struct key_entry *keymap,
			int (*setup)(struct input_dev *, struct key_entry *))
{
	size_t map_size = 1; /* to account for the last KE_END entry */
	const struct key_entry *e;
	struct key_entry *map, *entry;
	int i;
	int error;

	for (e = keymap; e->type != KE_END; e++)
		map_size++;

	map = devm_kmemdup(&dev->dev, keymap, map_size * sizeof(*map),
			   GFP_KERNEL);
	if (!map)
		return -ENOMEM;

	for (i = 0; i < map_size; i++) {
		entry = &map[i];

		if (setup) {
			error = setup(dev, entry);
			if (error)
				return error;
		}

		switch (entry->type) {
		case KE_KEY:
			__set_bit(EV_KEY, dev->evbit);
			__set_bit(entry->keycode, dev->keybit);
			break;

		case KE_SW:
		case KE_VSW:
			__set_bit(EV_SW, dev->evbit);
			__set_bit(entry->sw.code, dev->swbit);
			break;
		}
	}

	if (test_bit(EV_KEY, dev->evbit)) {
		__set_bit(KEY_UNKNOWN, dev->keybit);
		__set_bit(EV_MSC, dev->evbit);
		__set_bit(MSC_SCAN, dev->mscbit);
	}

	dev->keycode = map;
	dev->keycodemax = map_size;
	dev->getkeycode = sparse_keymap_getkeycode;
	dev->setkeycode = sparse_keymap_setkeycode;

	return 0;
}

static int bbq10pmod_write_reg(struct bbq10pmod_data *drv_data, u8 reg)
{
	struct i2c_client *client;
	struct i2c_client *client = drv_data->client;
	int error;
	
	client = drv_data->client;
	
	struct i2c_msg msgs[] = {
		{ .addr = client->addr, .flags = I2C_M_STOP, .len = sizeof(u8), .buf = &reg, },
	};


@@ 74,14 291,12 @@ static int bbq10pmod_write_reg(struct bbq10pmod_data *drv_data, u8 reg)

static int bbq10pmod_write_data(struct bbq10pmod_data *drv_data, u8 reg, u8 *buf, u8 len)
{
	struct i2c_client *client;
	struct i2c_client *client = drv_data->client;
	int error;
	
	client = drv_data->client;
	
	struct i2c_msg msgs[] = {
		{ .addr = client->addr | 0xC0, .flags = 0, .len = sizeof(u8), .buf = &reg, },
		{ .addr = client->addr | 0xC0, .flags = I2C_M_STOP, .len = len, .buf = buf, },
		{ .addr = client->addr | 0xC0, .flags = 0, .len = len, .buf = buf, },
	};
	
	error = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));


@@ 98,40 313,76 @@ static int bbq10pmod_write_data(struct bbq10pmod_data *drv_data, u8 reg, u8 *buf

static int bbq10pmod_read_reg(struct bbq10pmod_data *drv_data, u8 reg, u8 *buf, u8 len)
{
	struct i2c_client *client;
	struct i2c_client *client = drv_data->client;
	int error;
	
	client = drv_data->client;
	
	
	struct i2c_msg msgs[] = {
		{ .addr = client->addr, .flags = 0, .len = sizeof(u8), .buf = &reg, },
		{ .addr = client->addr, .flags = I2C_M_RD | I2C_M_STOP, .len = len, .buf = buf }
		{ .addr = client->addr, .flags = I2C_M_RD, .len = len, .buf = buf }
	};
	
	error = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
	if (error != ARRAY_SIZE(msgs)) {
		dev_err(&client->dev,
		"%s failed, reg: %d, error: %d\n",
		"%s 1 failed, reg: %d, error: %d\n",
		__func__, reg, error);
		
		return error;
	}
	
	msleep(100);
	
	return 0;
}

static irqreturn_t bbq10pmod_irq_handler(int irq, void *dev_id)
static void bbq10pmod_read_fifo(struct bbq10pmod_data *drv_data)
{
	struct bbq10pmod_data *drv_data = dev_id;
	struct input_dev *input = drv_data->input;
	u8 data[2];
	u8 count;
	int error;
	const struct key_entry *ke;
	unsigned int keycode;
	
	error = bbq10pmod_read_reg(drv_data, REG_KEY, data, sizeof(u8));
	if (error < 0)
		dev_err(&drv_data->client->dev, "%s: Failed to read KEY: %d\n", __func__, error);
		
	printk("%s: status: 0x%02X\n", __func__, data[0]);
	
	count = (data[0] & KEY_COUNT_MASK);
	
	while (count > 0) {
		error = bbq10pmod_read_reg(drv_data, REG_FIF, data, sizeof(u8) * 2);
		if (error < 0)
			dev_err(&drv_data->client->dev, "%s: Failed to read KEY: %d\n", __func__, error);
		
		printk("%s: key %d/%c, state: %d\n", __func__, data[1], data[1], data[0]);
		
		count -= 1;
		
		if (data[1] != 0 && data[1] != 0xFF && (data[0] == STATE_PRESS || data[0] == STATE_RELEASE)) {
			ke = sparse_keymap_entry_from_scancode(input, data[1]);
			keycode = ke ? ke->keycode : KEY_UNKNOWN;
			printk("input data 0x%04x--> keycode %d\n", data[1], keycode);

			input_report_key(input, keycode, data[0] == STATE_PRESS);
		}
	}
	input_sync(input);
}

static irqreturn_t bbq10pmod_irq_handler(int irq, void *dev_id)
{
	struct bbq10pmod_data *drv_data = dev_id;
	
	printk("%s fired\n", __func__);
	
	/*error = bbq10pmod_read_reg(drv_data, REG_KEY, data, sizeof(u8));
	if (error < 0)
		dev_err(&drv_data->client->dev, "Failed to read KEY\n");*/
	// TODO: Read INT reg and see reason
	
	bbq10pmod_read_fifo(drv_data);
	
	// clear INT reg
	
	return IRQ_HANDLED;
}


@@ 150,23 401,22 @@ static int bbq10pmod_probe(struct i2c_client *client, const struct i2c_device_id
	
	drv_data->client = client;
	
	//error = bbq10pmod_read_reg(drv_data, REG_VER, &reg, sizeof(reg));
	error = bbq10pmod_write_reg(drv_data, REG_RST);
	if (error)
		return -ENODEV;
		
	//msleep(100);
	msleep(100);
	
	//reg = 0;
	//error = bbq10pmod_write_data(drv_data, REG_BKL, &reg, 1);
	//if (error)
	//	return -ENODEV;
	
	//error = bbq10pmod_read_reg(drv_data, REG_VER, &reg, sizeof(reg));
	//if (error)
	//	return -ENODEV;
	error = bbq10pmod_read_reg(drv_data, REG_VER, &reg, sizeof(reg));
	if (error)
		return -ENODEV;
		
	//printk("%s: version: 0x%02X\n", __func__, reg);
	printk("%s: version: 0x%02X\n", __func__, reg);
	
	input = devm_input_allocate_device(dev);
	if (!input)


@@ 180,10 430,14 @@ static int bbq10pmod_probe(struct i2c_client *client, const struct i2c_device_id
	input->id.product = 0x0001;
	input->id.version = 0x0001;
	
	if (device_property_read_bool(dev, "keypad,autorepeat"))
		__set_bit(EV_REP, input->evbit);
	//if (device_property_read_bool(dev, "keypad,autorepeat"))
	//	__set_bit(EV_REP, input->evbit);
	
	//input_set_capability(input, EV_MSC, MSC_SCAN);
	
	input_set_capability(input, EV_MSC, MSC_SCAN);
	error = sparse_keymap_setup(input, bbq10pmod_keys, NULL);
	if (error)
		return error;
	
	error = devm_request_threaded_irq(dev, client->irq,
										NULL, bbq10pmod_irq_handler,