Merge branch 'next' into for-linus

First round of input updates for 3.15.
This commit is contained in:
Dmitry Torokhov 2014-04-03 09:26:49 -07:00
commit 692d96552c
10308 changed files with 561190 additions and 219756 deletions

View file

@ -151,6 +151,18 @@ config KEYBOARD_BFIN
To compile this driver as a module, choose M here: the
module will be called bf54x-keys.
config KEYBOARD_CLPS711X
tristate "CLPS711X Keypad support"
depends on OF_GPIO && (ARCH_CLPS711X || COMPILE_TEST)
select INPUT_MATRIXKMAP
select INPUT_POLLDEV
help
Say Y here to enable the matrix keypad on the Cirrus Logic
CLPS711X CPUs.
To compile this driver as a module, choose M here: the
module will be called clps711x-keypad.
config KEYBOARD_LKKBD
tristate "DECstation/VAXstation LK201/LK401 keyboard"
select SERIO
@ -595,16 +607,6 @@ config KEYBOARD_TC3589X
To compile this driver as a module, choose M here: the
module will be called tc3589x-keypad.
config KEYBOARD_TNETV107X
tristate "TI TNETV107X keypad support"
depends on ARCH_DAVINCI_TNETV107X
select INPUT_MATRIXKMAP
help
Say Y here if you want to use the TNETV107X keypad.
To compile this driver as a module, choose M here: the
module will be called tnetv107x-keypad.
config KEYBOARD_TWL4030
tristate "TI TWL4030/TWL5030/TPS659x0 keypad support"
depends on TWL4030_CORE

View file

@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o
obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
@ -53,7 +54,6 @@ obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o
obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o
obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o

View file

@ -0,0 +1,207 @@
/*
* Cirrus Logic CLPS711X Keypad driver
*
* Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
*
* 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.
*/
#include <linux/input.h>
#include <linux/input-polldev.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/sched.h>
#include <linux/input/matrix_keypad.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/clps711x.h>
#define CLPS711X_KEYPAD_COL_COUNT 8
struct clps711x_gpio_data {
struct gpio_desc *desc;
DECLARE_BITMAP(last_state, CLPS711X_KEYPAD_COL_COUNT);
};
struct clps711x_keypad_data {
struct regmap *syscon;
int row_count;
unsigned int row_shift;
struct clps711x_gpio_data *gpio_data;
};
static void clps711x_keypad_poll(struct input_polled_dev *dev)
{
const unsigned short *keycodes = dev->input->keycode;
struct clps711x_keypad_data *priv = dev->private;
bool sync = false;
int col, row;
for (col = 0; col < CLPS711X_KEYPAD_COL_COUNT; col++) {
/* Assert column */
regmap_update_bits(priv->syscon, SYSCON_OFFSET,
SYSCON1_KBDSCAN_MASK,
SYSCON1_KBDSCAN(8 + col));
/* Scan rows */
for (row = 0; row < priv->row_count; row++) {
struct clps711x_gpio_data *data = &priv->gpio_data[row];
bool state, state1;
/* Read twice for protection against fluctuations */
do {
state = gpiod_get_value_cansleep(data->desc);
cond_resched();
state1 = gpiod_get_value_cansleep(data->desc);
} while (state != state1);
if (test_bit(col, data->last_state) != state) {
int code = MATRIX_SCAN_CODE(row, col,
priv->row_shift);
if (state) {
set_bit(col, data->last_state);
input_event(dev->input, EV_MSC,
MSC_SCAN, code);
} else {
clear_bit(col, data->last_state);
}
if (keycodes[code])
input_report_key(dev->input,
keycodes[code], state);
sync = true;
}
}
/* Set all columns to low */
regmap_update_bits(priv->syscon, SYSCON_OFFSET,
SYSCON1_KBDSCAN_MASK, SYSCON1_KBDSCAN(1));
}
if (sync)
input_sync(dev->input);
}
static int clps711x_keypad_probe(struct platform_device *pdev)
{
struct clps711x_keypad_data *priv;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct input_polled_dev *poll_dev;
u32 poll_interval;
int i, err;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->syscon =
syscon_regmap_lookup_by_compatible("cirrus,clps711x-syscon1");
if (IS_ERR(priv->syscon))
return PTR_ERR(priv->syscon);
priv->row_count = of_gpio_named_count(np, "row-gpios");
if (priv->row_count < 1)
return -EINVAL;
priv->gpio_data = devm_kzalloc(dev,
sizeof(*priv->gpio_data) * priv->row_count,
GFP_KERNEL);
if (!priv->gpio_data)
return -ENOMEM;
priv->row_shift = get_count_order(CLPS711X_KEYPAD_COL_COUNT);
for (i = 0; i < priv->row_count; i++) {
struct clps711x_gpio_data *data = &priv->gpio_data[i];
data->desc = devm_gpiod_get_index(dev, "row", i);
if (!data->desc)
return -EINVAL;
if (IS_ERR(data->desc))
return PTR_ERR(data->desc);
gpiod_direction_input(data->desc);
}
err = of_property_read_u32(np, "poll-interval", &poll_interval);
if (err)
return err;
poll_dev = input_allocate_polled_device();
if (!poll_dev)
return -ENOMEM;
poll_dev->private = priv;
poll_dev->poll = clps711x_keypad_poll;
poll_dev->poll_interval = poll_interval;
poll_dev->input->name = pdev->name;
poll_dev->input->dev.parent = dev;
poll_dev->input->id.bustype = BUS_HOST;
poll_dev->input->id.vendor = 0x0001;
poll_dev->input->id.product = 0x0001;
poll_dev->input->id.version = 0x0100;
err = matrix_keypad_build_keymap(NULL, NULL, priv->row_count,
CLPS711X_KEYPAD_COL_COUNT,
NULL, poll_dev->input);
if (err)
goto out_err;
input_set_capability(poll_dev->input, EV_MSC, MSC_SCAN);
if (of_property_read_bool(np, "autorepeat"))
__set_bit(EV_REP, poll_dev->input->evbit);
platform_set_drvdata(pdev, poll_dev);
/* Set all columns to low */
regmap_update_bits(priv->syscon, SYSCON_OFFSET, SYSCON1_KBDSCAN_MASK,
SYSCON1_KBDSCAN(1));
err = input_register_polled_device(poll_dev);
if (err)
goto out_err;
return 0;
out_err:
input_free_polled_device(poll_dev);
return err;
}
static int clps711x_keypad_remove(struct platform_device *pdev)
{
struct input_polled_dev *poll_dev = platform_get_drvdata(pdev);
input_unregister_polled_device(poll_dev);
input_free_polled_device(poll_dev);
return 0;
}
static struct of_device_id clps711x_keypad_of_match[] = {
{ .compatible = "cirrus,clps711x-keypad", },
{ }
};
MODULE_DEVICE_TABLE(of, clps711x_keypad_of_match);
static struct platform_driver clps711x_keypad_driver = {
.driver = {
.name = "clps711x-keypad",
.owner = THIS_MODULE,
.of_match_table = clps711x_keypad_of_match,
},
.probe = clps711x_keypad_probe,
.remove = clps711x_keypad_remove,
};
module_platform_driver(clps711x_keypad_driver);
MODULE_AUTHOR("Alexander Shiyan <[email protected]>");
MODULE_DESCRIPTION("Cirrus Logic CLPS711X Keypad driver");
MODULE_LICENSE("GPL");

View file

@ -439,7 +439,7 @@ static int imx_keypad_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq defined in platform data\n");
return -EINVAL;
return irq;
}
input_dev = devm_input_allocate_device(&pdev->dev);
@ -449,7 +449,7 @@ static int imx_keypad_probe(struct platform_device *pdev)
}
keypad = devm_kzalloc(&pdev->dev, sizeof(struct imx_keypad),
GFP_KERNEL);
GFP_KERNEL);
if (!keypad) {
dev_err(&pdev->dev, "not enough memory for driver data\n");
return -ENOMEM;

View file

@ -19,10 +19,9 @@
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/mfd/pm8xxx/core.h>
#include <linux/mfd/pm8xxx/gpio.h>
#include <linux/input/pmic8xxx-keypad.h>
#include <linux/regmap.h>
#include <linux/of.h>
#include <linux/input/matrix_keypad.h>
#define PM8XXX_MAX_ROWS 18
#define PM8XXX_MAX_COLS 8
@ -85,8 +84,10 @@
/**
* struct pmic8xxx_kp - internal keypad data structure
* @pdata - keypad platform data pointer
* @num_cols - number of columns of keypad
* @num_rows - number of row of keypad
* @input - input device pointer for keypad
* @regmap - regmap handle
* @key_sense_irq - key press/release irq number
* @key_stuck_irq - key stuck notification irq number
* @keycodes - array to hold the key codes
@ -96,8 +97,10 @@
* @ctrl_reg - control register value
*/
struct pmic8xxx_kp {
const struct pm8xxx_keypad_platform_data *pdata;
unsigned int num_rows;
unsigned int num_cols;
struct input_dev *input;
struct regmap *regmap;
int key_sense_irq;
int key_stuck_irq;
@ -110,40 +113,13 @@ struct pmic8xxx_kp {
u8 ctrl_reg;
};
static int pmic8xxx_kp_write_u8(struct pmic8xxx_kp *kp,
u8 data, u16 reg)
{
int rc;
rc = pm8xxx_writeb(kp->dev->parent, reg, data);
return rc;
}
static int pmic8xxx_kp_read(struct pmic8xxx_kp *kp,
u8 *data, u16 reg, unsigned num_bytes)
{
int rc;
rc = pm8xxx_read_buf(kp->dev->parent, reg, data, num_bytes);
return rc;
}
static int pmic8xxx_kp_read_u8(struct pmic8xxx_kp *kp,
u8 *data, u16 reg)
{
int rc;
rc = pmic8xxx_kp_read(kp, data, reg, 1);
return rc;
}
static u8 pmic8xxx_col_state(struct pmic8xxx_kp *kp, u8 col)
{
/* all keys pressed on that particular row? */
if (col == 0x00)
return 1 << kp->pdata->num_cols;
return 1 << kp->num_cols;
else
return col & ((1 << kp->pdata->num_cols) - 1);
return col & ((1 << kp->num_cols) - 1);
}
/*
@ -161,9 +137,9 @@ static u8 pmic8xxx_col_state(struct pmic8xxx_kp *kp, u8 col)
static int pmic8xxx_chk_sync_read(struct pmic8xxx_kp *kp)
{
int rc;
u8 scan_val;
unsigned int scan_val;
rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN);
rc = regmap_read(kp->regmap, KEYP_SCAN, &scan_val);
if (rc < 0) {
dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc);
return rc;
@ -171,7 +147,7 @@ static int pmic8xxx_chk_sync_read(struct pmic8xxx_kp *kp)
scan_val |= 0x1;
rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
rc = regmap_write(kp->regmap, KEYP_SCAN, scan_val);
if (rc < 0) {
dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
return rc;
@ -187,31 +163,29 @@ static int pmic8xxx_kp_read_data(struct pmic8xxx_kp *kp, u16 *state,
u16 data_reg, int read_rows)
{
int rc, row;
u8 new_data[PM8XXX_MAX_ROWS];
unsigned int val;
rc = pmic8xxx_kp_read(kp, new_data, data_reg, read_rows);
if (rc)
return rc;
for (row = 0; row < kp->pdata->num_rows; row++) {
dev_dbg(kp->dev, "new_data[%d] = %d\n", row,
new_data[row]);
state[row] = pmic8xxx_col_state(kp, new_data[row]);
for (row = 0; row < read_rows; row++) {
rc = regmap_read(kp->regmap, data_reg, &val);
if (rc)
return rc;
dev_dbg(kp->dev, "%d = %d\n", row, val);
state[row] = pmic8xxx_col_state(kp, val);
}
return rc;
return 0;
}
static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state,
u16 *old_state)
{
int rc, read_rows;
u8 scan_val;
unsigned int scan_val;
if (kp->pdata->num_rows < PM8XXX_MIN_ROWS)
if (kp->num_rows < PM8XXX_MIN_ROWS)
read_rows = PM8XXX_MIN_ROWS;
else
read_rows = kp->pdata->num_rows;
read_rows = kp->num_rows;
pmic8xxx_chk_sync_read(kp);
@ -236,14 +210,14 @@ static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state,
/* 4 * 32KHz clocks */
udelay((4 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1);
rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN);
rc = regmap_read(kp->regmap, KEYP_SCAN, &scan_val);
if (rc < 0) {
dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc);
return rc;
}
scan_val &= 0xFE;
rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
rc = regmap_write(kp->regmap, KEYP_SCAN, scan_val);
if (rc < 0)
dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
@ -255,13 +229,13 @@ static void __pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, u16 *new_state,
{
int row, col, code;
for (row = 0; row < kp->pdata->num_rows; row++) {
for (row = 0; row < kp->num_rows; row++) {
int bits_changed = new_state[row] ^ old_state[row];
if (!bits_changed)
continue;
for (col = 0; col < kp->pdata->num_cols; col++) {
for (col = 0; col < kp->num_cols; col++) {
if (!(bits_changed & (1 << col)))
continue;
@ -287,9 +261,9 @@ static bool pmic8xxx_detect_ghost_keys(struct pmic8xxx_kp *kp, u16 *new_state)
u16 check, row_state;
check = 0;
for (row = 0; row < kp->pdata->num_rows; row++) {
for (row = 0; row < kp->num_rows; row++) {
row_state = (~new_state[row]) &
((1 << kp->pdata->num_cols) - 1);
((1 << kp->num_cols) - 1);
if (hweight16(row_state) > 1) {
if (found_first == -1)
@ -379,10 +353,10 @@ static irqreturn_t pmic8xxx_kp_stuck_irq(int irq, void *data)
static irqreturn_t pmic8xxx_kp_irq(int irq, void *data)
{
struct pmic8xxx_kp *kp = data;
u8 ctrl_val, events;
unsigned int ctrl_val, events;
int rc;
rc = pmic8xxx_kp_read(kp, &ctrl_val, KEYP_CTRL, 1);
rc = regmap_read(kp->regmap, KEYP_CTRL, &ctrl_val);
if (rc < 0) {
dev_err(kp->dev, "failed to read keyp_ctrl register\n");
return IRQ_HANDLED;
@ -397,8 +371,13 @@ static irqreturn_t pmic8xxx_kp_irq(int irq, void *data)
return IRQ_HANDLED;
}
static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp)
static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp,
struct platform_device *pdev)
{
const struct device_node *of_node = pdev->dev.of_node;
unsigned int scan_delay_ms;
unsigned int row_hold_ns;
unsigned int debounce_ms;
int bits, rc, cycles;
u8 scan_val = 0, ctrl_val = 0;
static const u8 row_bits[] = {
@ -406,40 +385,69 @@ static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp)
};
/* Find column bits */
if (kp->pdata->num_cols < KEYP_CTRL_SCAN_COLS_MIN)
if (kp->num_cols < KEYP_CTRL_SCAN_COLS_MIN)
bits = 0;
else
bits = kp->pdata->num_cols - KEYP_CTRL_SCAN_COLS_MIN;
bits = kp->num_cols - KEYP_CTRL_SCAN_COLS_MIN;
ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) <<
KEYP_CTRL_SCAN_COLS_SHIFT;
/* Find row bits */
if (kp->pdata->num_rows < KEYP_CTRL_SCAN_ROWS_MIN)
if (kp->num_rows < KEYP_CTRL_SCAN_ROWS_MIN)
bits = 0;
else
bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN];
bits = row_bits[kp->num_rows - KEYP_CTRL_SCAN_ROWS_MIN];
ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT);
rc = pmic8xxx_kp_write_u8(kp, ctrl_val, KEYP_CTRL);
rc = regmap_write(kp->regmap, KEYP_CTRL, ctrl_val);
if (rc < 0) {
dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc);
return rc;
}
bits = (kp->pdata->debounce_ms / 5) - 1;
if (of_property_read_u32(of_node, "scan-delay", &scan_delay_ms))
scan_delay_ms = MIN_SCAN_DELAY;
if (scan_delay_ms > MAX_SCAN_DELAY || scan_delay_ms < MIN_SCAN_DELAY ||
!is_power_of_2(scan_delay_ms)) {
dev_err(&pdev->dev, "invalid keypad scan time supplied\n");
return -EINVAL;
}
if (of_property_read_u32(of_node, "row-hold", &row_hold_ns))
row_hold_ns = MIN_ROW_HOLD_DELAY;
if (row_hold_ns > MAX_ROW_HOLD_DELAY ||
row_hold_ns < MIN_ROW_HOLD_DELAY ||
((row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) {
dev_err(&pdev->dev, "invalid keypad row hold time supplied\n");
return -EINVAL;
}
if (of_property_read_u32(of_node, "debounce", &debounce_ms))
debounce_ms = MIN_DEBOUNCE_TIME;
if (((debounce_ms % 5) != 0) ||
debounce_ms > MAX_DEBOUNCE_TIME ||
debounce_ms < MIN_DEBOUNCE_TIME) {
dev_err(&pdev->dev, "invalid debounce time supplied\n");
return -EINVAL;
}
bits = (debounce_ms / 5) - 1;
scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT);
bits = fls(kp->pdata->scan_delay_ms) - 1;
bits = fls(scan_delay_ms) - 1;
scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT);
/* Row hold time is a multiple of 32KHz cycles. */
cycles = (kp->pdata->row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC;
cycles = (row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC;
scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT);
rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
rc = regmap_write(kp->regmap, KEYP_SCAN, scan_val);
if (rc)
dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
@ -447,34 +455,13 @@ static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp)
}
static int pmic8xxx_kp_config_gpio(int gpio_start, int num_gpios,
struct pmic8xxx_kp *kp, struct pm_gpio *gpio_config)
{
int rc, i;
if (gpio_start < 0 || num_gpios < 0)
return -EINVAL;
for (i = 0; i < num_gpios; i++) {
rc = pm8xxx_gpio_config(gpio_start + i, gpio_config);
if (rc) {
dev_err(kp->dev, "%s: FAIL pm8xxx_gpio_config():"
"for PM GPIO [%d] rc=%d.\n",
__func__, gpio_start + i, rc);
return rc;
}
}
return 0;
}
static int pmic8xxx_kp_enable(struct pmic8xxx_kp *kp)
{
int rc;
kp->ctrl_reg |= KEYP_CTRL_KEYP_EN;
rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL);
rc = regmap_write(kp->regmap, KEYP_CTRL, kp->ctrl_reg);
if (rc < 0)
dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc);
@ -487,7 +474,7 @@ static int pmic8xxx_kp_disable(struct pmic8xxx_kp *kp)
kp->ctrl_reg &= ~KEYP_CTRL_KEYP_EN;
rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL);
rc = regmap_write(kp->regmap, KEYP_CTRL, kp->ctrl_reg);
if (rc < 0)
return rc;
@ -520,106 +507,62 @@ static void pmic8xxx_kp_close(struct input_dev *dev)
*/
static int pmic8xxx_kp_probe(struct platform_device *pdev)
{
const struct pm8xxx_keypad_platform_data *pdata =
dev_get_platdata(&pdev->dev);
const struct matrix_keymap_data *keymap_data;
unsigned int rows, cols;
bool repeat;
bool wakeup;
struct pmic8xxx_kp *kp;
int rc;
u8 ctrl_val;
unsigned int ctrl_val;
struct pm_gpio kypd_drv = {
.direction = PM_GPIO_DIR_OUT,
.output_buffer = PM_GPIO_OUT_BUF_OPEN_DRAIN,
.output_value = 0,
.pull = PM_GPIO_PULL_NO,
.vin_sel = PM_GPIO_VIN_S3,
.out_strength = PM_GPIO_STRENGTH_LOW,
.function = PM_GPIO_FUNC_1,
.inv_int_pol = 1,
};
rc = matrix_keypad_parse_of_params(&pdev->dev, &rows, &cols);
if (rc)
return rc;
struct pm_gpio kypd_sns = {
.direction = PM_GPIO_DIR_IN,
.pull = PM_GPIO_PULL_UP_31P5,
.vin_sel = PM_GPIO_VIN_S3,
.out_strength = PM_GPIO_STRENGTH_NO,
.function = PM_GPIO_FUNC_NORMAL,
.inv_int_pol = 1,
};
if (!pdata || !pdata->num_cols || !pdata->num_rows ||
pdata->num_cols > PM8XXX_MAX_COLS ||
pdata->num_rows > PM8XXX_MAX_ROWS ||
pdata->num_cols < PM8XXX_MIN_COLS) {
if (cols > PM8XXX_MAX_COLS || rows > PM8XXX_MAX_ROWS ||
cols < PM8XXX_MIN_COLS) {
dev_err(&pdev->dev, "invalid platform data\n");
return -EINVAL;
}
if (!pdata->scan_delay_ms ||
pdata->scan_delay_ms > MAX_SCAN_DELAY ||
pdata->scan_delay_ms < MIN_SCAN_DELAY ||
!is_power_of_2(pdata->scan_delay_ms)) {
dev_err(&pdev->dev, "invalid keypad scan time supplied\n");
return -EINVAL;
}
repeat = !of_property_read_bool(pdev->dev.of_node,
"linux,input-no-autorepeat");
wakeup = of_property_read_bool(pdev->dev.of_node,
"linux,keypad-wakeup");
if (!pdata->row_hold_ns ||
pdata->row_hold_ns > MAX_ROW_HOLD_DELAY ||
pdata->row_hold_ns < MIN_ROW_HOLD_DELAY ||
((pdata->row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) {
dev_err(&pdev->dev, "invalid keypad row hold time supplied\n");
return -EINVAL;
}
if (!pdata->debounce_ms ||
((pdata->debounce_ms % 5) != 0) ||
pdata->debounce_ms > MAX_DEBOUNCE_TIME ||
pdata->debounce_ms < MIN_DEBOUNCE_TIME) {
dev_err(&pdev->dev, "invalid debounce time supplied\n");
return -EINVAL;
}
keymap_data = pdata->keymap_data;
if (!keymap_data) {
dev_err(&pdev->dev, "no keymap data supplied\n");
return -EINVAL;
}
kp = kzalloc(sizeof(*kp), GFP_KERNEL);
kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL);
if (!kp)
return -ENOMEM;
kp->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!kp->regmap)
return -ENODEV;
platform_set_drvdata(pdev, kp);
kp->pdata = pdata;
kp->num_rows = rows;
kp->num_cols = cols;
kp->dev = &pdev->dev;
kp->input = input_allocate_device();
kp->input = devm_input_allocate_device(&pdev->dev);
if (!kp->input) {
dev_err(&pdev->dev, "unable to allocate input device\n");
rc = -ENOMEM;
goto err_alloc_device;
return -ENOMEM;
}
kp->key_sense_irq = platform_get_irq(pdev, 0);
if (kp->key_sense_irq < 0) {
dev_err(&pdev->dev, "unable to get keypad sense irq\n");
rc = -ENXIO;
goto err_get_irq;
return kp->key_sense_irq;
}
kp->key_stuck_irq = platform_get_irq(pdev, 1);
if (kp->key_stuck_irq < 0) {
dev_err(&pdev->dev, "unable to get keypad stuck irq\n");
rc = -ENXIO;
goto err_get_irq;
return kp->key_stuck_irq;
}
kp->input->name = pdata->input_name ? : "PMIC8XXX keypad";
kp->input->phys = pdata->input_phys_device ? : "pmic8xxx_keypad/input0";
kp->input->dev.parent = &pdev->dev;
kp->input->name = "PMIC8XXX keypad";
kp->input->phys = "pmic8xxx_keypad/input0";
kp->input->id.bustype = BUS_I2C;
kp->input->id.version = 0x0001;
@ -629,15 +572,15 @@ static int pmic8xxx_kp_probe(struct platform_device *pdev)
kp->input->open = pmic8xxx_kp_open;
kp->input->close = pmic8xxx_kp_close;
rc = matrix_keypad_build_keymap(keymap_data, NULL,
rc = matrix_keypad_build_keymap(NULL, NULL,
PM8XXX_MAX_ROWS, PM8XXX_MAX_COLS,
kp->keycodes, kp->input);
if (rc) {
dev_err(&pdev->dev, "failed to build keymap\n");
goto err_get_irq;
return rc;
}
if (pdata->rep)
if (repeat)
__set_bit(EV_REP, kp->input->evbit);
input_set_capability(kp->input, EV_MSC, MSC_SCAN);
@ -647,44 +590,32 @@ static int pmic8xxx_kp_probe(struct platform_device *pdev)
memset(kp->keystate, 0xff, sizeof(kp->keystate));
memset(kp->stuckstate, 0xff, sizeof(kp->stuckstate));
rc = pmic8xxx_kpd_init(kp);
rc = pmic8xxx_kpd_init(kp, pdev);
if (rc < 0) {
dev_err(&pdev->dev, "unable to initialize keypad controller\n");
goto err_get_irq;
return rc;
}
rc = pmic8xxx_kp_config_gpio(pdata->cols_gpio_start,
pdata->num_cols, kp, &kypd_sns);
if (rc < 0) {
dev_err(&pdev->dev, "unable to configure keypad sense lines\n");
goto err_gpio_config;
}
rc = pmic8xxx_kp_config_gpio(pdata->rows_gpio_start,
pdata->num_rows, kp, &kypd_drv);
if (rc < 0) {
dev_err(&pdev->dev, "unable to configure keypad drive lines\n");
goto err_gpio_config;
}
rc = request_any_context_irq(kp->key_sense_irq, pmic8xxx_kp_irq,
IRQF_TRIGGER_RISING, "pmic-keypad", kp);
rc = devm_request_any_context_irq(&pdev->dev, kp->key_sense_irq,
pmic8xxx_kp_irq, IRQF_TRIGGER_RISING, "pmic-keypad",
kp);
if (rc < 0) {
dev_err(&pdev->dev, "failed to request keypad sense irq\n");
goto err_get_irq;
return rc;
}
rc = request_any_context_irq(kp->key_stuck_irq, pmic8xxx_kp_stuck_irq,
IRQF_TRIGGER_RISING, "pmic-keypad-stuck", kp);
rc = devm_request_any_context_irq(&pdev->dev, kp->key_stuck_irq,
pmic8xxx_kp_stuck_irq, IRQF_TRIGGER_RISING,
"pmic-keypad-stuck", kp);
if (rc < 0) {
dev_err(&pdev->dev, "failed to request keypad stuck irq\n");
goto err_req_stuck_irq;
return rc;
}
rc = pmic8xxx_kp_read_u8(kp, &ctrl_val, KEYP_CTRL);
rc = regmap_read(kp->regmap, KEYP_CTRL, &ctrl_val);
if (rc < 0) {
dev_err(&pdev->dev, "failed to read KEYP_CTRL register\n");
goto err_pmic_reg_read;
return rc;
}
kp->ctrl_reg = ctrl_val;
@ -692,34 +623,10 @@ static int pmic8xxx_kp_probe(struct platform_device *pdev)
rc = input_register_device(kp->input);
if (rc < 0) {
dev_err(&pdev->dev, "unable to register keypad input device\n");
goto err_pmic_reg_read;
return rc;
}
device_init_wakeup(&pdev->dev, pdata->wakeup);
return 0;
err_pmic_reg_read:
free_irq(kp->key_stuck_irq, kp);
err_req_stuck_irq:
free_irq(kp->key_sense_irq, kp);
err_gpio_config:
err_get_irq:
input_free_device(kp->input);
err_alloc_device:
kfree(kp);
return rc;
}
static int pmic8xxx_kp_remove(struct platform_device *pdev)
{
struct pmic8xxx_kp *kp = platform_get_drvdata(pdev);
device_init_wakeup(&pdev->dev, 0);
free_irq(kp->key_stuck_irq, kp);
free_irq(kp->key_sense_irq, kp);
input_unregister_device(kp->input);
kfree(kp);
device_init_wakeup(&pdev->dev, wakeup);
return 0;
}
@ -769,13 +676,20 @@ static int pmic8xxx_kp_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(pm8xxx_kp_pm_ops,
pmic8xxx_kp_suspend, pmic8xxx_kp_resume);
static const struct of_device_id pm8xxx_match_table[] = {
{ .compatible = "qcom,pm8058-keypad" },
{ .compatible = "qcom,pm8921-keypad" },
{ }
};
MODULE_DEVICE_TABLE(of, pm8xxx_match_table);
static struct platform_driver pmic8xxx_kp_driver = {
.probe = pmic8xxx_kp_probe,
.remove = pmic8xxx_kp_remove,
.driver = {
.name = PM8XXX_KEYPAD_DEV_NAME,
.name = "pm8xxx-keypad",
.owner = THIS_MODULE,
.pm = &pm8xxx_kp_pm_ops,
.of_match_table = pm8xxx_match_table,
},
};
module_platform_driver(pmic8xxx_kp_driver);

View file

@ -31,7 +31,7 @@
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/input/matrix_keypad.h>
#include <linux/clk/tegra.h>
#include <linux/reset.h>
#include <linux/err.h>
#define KBC_MAX_KPENT 8
@ -116,6 +116,7 @@ struct tegra_kbc {
u32 wakeup_key;
struct timer_list timer;
struct clk *clk;
struct reset_control *rst;
const struct tegra_kbc_hw_support *hw_support;
int max_keys;
int num_rows_and_columns;
@ -373,9 +374,9 @@ static int tegra_kbc_start(struct tegra_kbc *kbc)
clk_prepare_enable(kbc->clk);
/* Reset the KBC controller to clear all previous status.*/
tegra_periph_reset_assert(kbc->clk);
reset_control_assert(kbc->rst);
udelay(100);
tegra_periph_reset_deassert(kbc->clk);
reset_control_assert(kbc->rst);
udelay(100);
tegra_kbc_config_pins(kbc);
@ -663,6 +664,12 @@ static int tegra_kbc_probe(struct platform_device *pdev)
return PTR_ERR(kbc->clk);
}
kbc->rst = devm_reset_control_get(&pdev->dev, "kbc");
if (IS_ERR(kbc->rst)) {
dev_err(&pdev->dev, "failed to get keyboard reset\n");
return PTR_ERR(kbc->rst);
}
/*
* The time delay between two consecutive reads of the FIFO is
* the sum of the repeat time and the time taken for scanning

View file

@ -1,329 +0,0 @@
/*
* Texas Instruments TNETV107X Keypad Driver
*
* Copyright (C) 2010 Texas Instruments
*
* 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.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/input/matrix_keypad.h>
#include <linux/module.h>
#define BITS(x) (BIT(x) - 1)
#define KEYPAD_ROWS 9
#define KEYPAD_COLS 9
#define DEBOUNCE_MIN 0x400ul
#define DEBOUNCE_MAX 0x3ffffffful
struct keypad_regs {
u32 rev;
u32 mode;
u32 mask;
u32 pol;
u32 dclock;
u32 rclock;
u32 stable_cnt;
u32 in_en;
u32 out;
u32 out_en;
u32 in;
u32 lock;
u32 pres[3];
};
#define keypad_read(kp, reg) __raw_readl(&(kp)->regs->reg)
#define keypad_write(kp, reg, val) __raw_writel(val, &(kp)->regs->reg)
struct keypad_data {
struct input_dev *input_dev;
struct resource *res;
struct keypad_regs __iomem *regs;
struct clk *clk;
struct device *dev;
spinlock_t lock;
int irq_press;
int irq_release;
int rows, cols, row_shift;
int debounce_ms, active_low;
u32 prev_keys[3];
unsigned short keycodes[];
};
static irqreturn_t keypad_irq(int irq, void *data)
{
struct keypad_data *kp = data;
int i, bit, val, row, col, code;
unsigned long flags;
u32 curr_keys[3];
u32 change;
spin_lock_irqsave(&kp->lock, flags);
memset(curr_keys, 0, sizeof(curr_keys));
if (irq == kp->irq_press)
for (i = 0; i < 3; i++)
curr_keys[i] = keypad_read(kp, pres[i]);
for (i = 0; i < 3; i++) {
change = curr_keys[i] ^ kp->prev_keys[i];
while (change) {
bit = fls(change) - 1;
change ^= BIT(bit);
val = curr_keys[i] & BIT(bit);
bit += i * 32;
row = bit / KEYPAD_COLS;
col = bit % KEYPAD_COLS;
code = MATRIX_SCAN_CODE(row, col, kp->row_shift);
input_event(kp->input_dev, EV_MSC, MSC_SCAN, code);
input_report_key(kp->input_dev, kp->keycodes[code],
val);
}
}
input_sync(kp->input_dev);
memcpy(kp->prev_keys, curr_keys, sizeof(curr_keys));
if (irq == kp->irq_press)
keypad_write(kp, lock, 0); /* Allow hardware updates */
spin_unlock_irqrestore(&kp->lock, flags);
return IRQ_HANDLED;
}
static int keypad_start(struct input_dev *dev)
{
struct keypad_data *kp = input_get_drvdata(dev);
unsigned long mask, debounce, clk_rate_khz;
unsigned long flags;
clk_enable(kp->clk);
clk_rate_khz = clk_get_rate(kp->clk) / 1000;
spin_lock_irqsave(&kp->lock, flags);
/* Initialize device registers */
keypad_write(kp, mode, 0);
mask = BITS(kp->rows) << KEYPAD_COLS;
mask |= BITS(kp->cols);
keypad_write(kp, mask, ~mask);
keypad_write(kp, pol, kp->active_low ? 0 : 0x3ffff);
keypad_write(kp, stable_cnt, 3);
debounce = kp->debounce_ms * clk_rate_khz;
debounce = clamp(debounce, DEBOUNCE_MIN, DEBOUNCE_MAX);
keypad_write(kp, dclock, debounce);
keypad_write(kp, rclock, 4 * debounce);
keypad_write(kp, in_en, 1);
spin_unlock_irqrestore(&kp->lock, flags);
return 0;
}
static void keypad_stop(struct input_dev *dev)
{
struct keypad_data *kp = input_get_drvdata(dev);
synchronize_irq(kp->irq_press);
synchronize_irq(kp->irq_release);
clk_disable(kp->clk);
}
static int keypad_probe(struct platform_device *pdev)
{
const struct matrix_keypad_platform_data *pdata;
const struct matrix_keymap_data *keymap_data;
struct device *dev = &pdev->dev;
struct keypad_data *kp;
int error = 0, sz, row_shift;
u32 rev = 0;
pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(dev, "cannot find device data\n");
return -EINVAL;
}
keymap_data = pdata->keymap_data;
if (!keymap_data) {
dev_err(dev, "cannot find keymap data\n");
return -EINVAL;
}
row_shift = get_count_order(pdata->num_col_gpios);
sz = offsetof(struct keypad_data, keycodes);
sz += (pdata->num_row_gpios << row_shift) * sizeof(kp->keycodes[0]);
kp = kzalloc(sz, GFP_KERNEL);
if (!kp) {
dev_err(dev, "cannot allocate device info\n");
return -ENOMEM;
}
kp->dev = dev;
kp->rows = pdata->num_row_gpios;
kp->cols = pdata->num_col_gpios;
kp->row_shift = row_shift;
platform_set_drvdata(pdev, kp);
spin_lock_init(&kp->lock);
kp->irq_press = platform_get_irq_byname(pdev, "press");
kp->irq_release = platform_get_irq_byname(pdev, "release");
if (kp->irq_press < 0 || kp->irq_release < 0) {
dev_err(dev, "cannot determine device interrupts\n");
error = -ENODEV;
goto error_res;
}
kp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!kp->res) {
dev_err(dev, "cannot determine register area\n");
error = -ENODEV;
goto error_res;
}
if (!request_mem_region(kp->res->start, resource_size(kp->res),
pdev->name)) {
dev_err(dev, "cannot claim register memory\n");
kp->res = NULL;
error = -EINVAL;
goto error_res;
}
kp->regs = ioremap(kp->res->start, resource_size(kp->res));
if (!kp->regs) {
dev_err(dev, "cannot map register memory\n");
error = -ENOMEM;
goto error_map;
}
kp->clk = clk_get(dev, NULL);
if (IS_ERR(kp->clk)) {
dev_err(dev, "cannot claim device clock\n");
error = PTR_ERR(kp->clk);
goto error_clk;
}
error = request_threaded_irq(kp->irq_press, NULL, keypad_irq,
IRQF_ONESHOT, dev_name(dev), kp);
if (error < 0) {
dev_err(kp->dev, "Could not allocate keypad press key irq\n");
goto error_irq_press;
}
error = request_threaded_irq(kp->irq_release, NULL, keypad_irq,
IRQF_ONESHOT, dev_name(dev), kp);
if (error < 0) {
dev_err(kp->dev, "Could not allocate keypad release key irq\n");
goto error_irq_release;
}
kp->input_dev = input_allocate_device();
if (!kp->input_dev) {
dev_err(dev, "cannot allocate input device\n");
error = -ENOMEM;
goto error_input;
}
kp->input_dev->name = pdev->name;
kp->input_dev->dev.parent = &pdev->dev;
kp->input_dev->open = keypad_start;
kp->input_dev->close = keypad_stop;
clk_enable(kp->clk);
rev = keypad_read(kp, rev);
kp->input_dev->id.bustype = BUS_HOST;
kp->input_dev->id.product = ((rev >> 8) & 0x07);
kp->input_dev->id.version = ((rev >> 16) & 0xfff);
clk_disable(kp->clk);
error = matrix_keypad_build_keymap(keymap_data, NULL,
kp->rows, kp->cols,
kp->keycodes, kp->input_dev);
if (error) {
dev_err(dev, "Failed to build keymap\n");
goto error_reg;
}
if (!pdata->no_autorepeat)
kp->input_dev->evbit[0] |= BIT_MASK(EV_REP);
input_set_capability(kp->input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(kp->input_dev, kp);
error = input_register_device(kp->input_dev);
if (error < 0) {
dev_err(dev, "Could not register input device\n");
goto error_reg;
}
return 0;
error_reg:
input_free_device(kp->input_dev);
error_input:
free_irq(kp->irq_release, kp);
error_irq_release:
free_irq(kp->irq_press, kp);
error_irq_press:
clk_put(kp->clk);
error_clk:
iounmap(kp->regs);
error_map:
release_mem_region(kp->res->start, resource_size(kp->res));
error_res:
kfree(kp);
return error;
}
static int keypad_remove(struct platform_device *pdev)
{
struct keypad_data *kp = platform_get_drvdata(pdev);
free_irq(kp->irq_press, kp);
free_irq(kp->irq_release, kp);
input_unregister_device(kp->input_dev);
clk_put(kp->clk);
iounmap(kp->regs);
release_mem_region(kp->res->start, resource_size(kp->res));
kfree(kp);
return 0;
}
static struct platform_driver keypad_driver = {
.probe = keypad_probe,
.remove = keypad_remove,
.driver.name = "tnetv107x-keypad",
.driver.owner = THIS_MODULE,
};
module_platform_driver(keypad_driver);
MODULE_AUTHOR("Cyril Chemparathy");
MODULE_DESCRIPTION("TNETV107X Keypad Driver");
MODULE_ALIAS("platform:tnetv107x-keypad");
MODULE_LICENSE("GPL");

View file

@ -168,7 +168,7 @@ config INPUT_MAX8997_HAPTIC
config INPUT_MC13783_PWRBUTTON
tristate "MC13783 ON buttons"
depends on MFD_MC13783
depends on MFD_MC13XXX
help
Support the ON buttons of MC13783 PMIC as an input device
reporting power button status.
@ -269,7 +269,7 @@ config INPUT_COBALT_BTNS
config INPUT_WISTRON_BTNS
tristate "x86 Wistron laptop button interface"
depends on X86 && !X86_64
depends on X86_32
select INPUT_POLLDEV
select INPUT_SPARSEKMAP
select NEW_LEDS
@ -666,4 +666,14 @@ config INPUT_IDEAPAD_SLIDEBAR
To compile this driver as a module, choose M here: the
module will be called ideapad_slidebar.
config INPUT_SOC_BUTTON_ARRAY
tristate "Windows-compatible SoC Button Array"
depends on KEYBOARD_GPIO
help
Say Y here if you have a SoC-based tablet that originally
runs Windows 8.
To compile this driver as a module, choose M here: the
module will be called soc_button_array.
endif

View file

@ -53,6 +53,7 @@ obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o
obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o
obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o

View file

@ -27,8 +27,8 @@
#include <linux/module.h>
#include <linux/input.h>
#include <linux/types.h>
#include <linux/acpi.h>
#include <asm/uaccess.h>
#include <acpi/acpi_drivers.h>
#define ACPI_ATLAS_NAME "Atlas ACPI"
#define ACPI_ATLAS_CLASS "Atlas"

View file

@ -51,6 +51,8 @@ struct ims_pcu_backlight {
#define IMS_PCU_BL_VERSION_LEN (9 + 1)
#define IMS_PCU_BL_RESET_REASON_LEN (2 + 1)
#define IMS_PCU_PCU_B_DEVICE_ID 5
#define IMS_PCU_BUF_SIZE 128
struct ims_pcu {
@ -68,6 +70,9 @@ struct ims_pcu {
char bl_version[IMS_PCU_BL_VERSION_LEN];
char reset_reason[IMS_PCU_BL_RESET_REASON_LEN];
int update_firmware_status;
u8 device_id;
u8 ofn_reg_addr;
struct usb_interface *ctrl_intf;
@ -371,6 +376,8 @@ static void ims_pcu_destroy_gamepad(struct ims_pcu *pcu)
#define IMS_PCU_CMD_GET_DEVICE_ID 0xae
#define IMS_PCU_CMD_SPECIAL_INFO 0xb0
#define IMS_PCU_CMD_BOOTLOADER 0xb1 /* Pass data to bootloader */
#define IMS_PCU_CMD_OFN_SET_CONFIG 0xb3
#define IMS_PCU_CMD_OFN_GET_CONFIG 0xb4
/* PCU responses */
#define IMS_PCU_RSP_STATUS 0xc0
@ -389,6 +396,9 @@ static void ims_pcu_destroy_gamepad(struct ims_pcu *pcu)
#define IMS_PCU_RSP_GET_DEVICE_ID 0xce
#define IMS_PCU_RSP_SPECIAL_INFO 0xd0
#define IMS_PCU_RSP_BOOTLOADER 0xd1 /* Bootloader response */
#define IMS_PCU_RSP_OFN_SET_CONFIG 0xd2
#define IMS_PCU_RSP_OFN_GET_CONFIG 0xd3
#define IMS_PCU_RSP_EVNT_BUTTONS 0xe0 /* Unsolicited, button state */
#define IMS_PCU_GAMEPAD_MASK 0x0001ff80UL /* Bits 7 through 16 */
@ -1256,6 +1266,225 @@ static struct attribute_group ims_pcu_attr_group = {
.attrs = ims_pcu_attrs,
};
/* Support for a separate OFN attribute group */
#define OFN_REG_RESULT_OFFSET 2
static int ims_pcu_read_ofn_config(struct ims_pcu *pcu, u8 addr, u8 *data)
{
int error;
s16 result;
error = ims_pcu_execute_command(pcu, OFN_GET_CONFIG,
&addr, sizeof(addr));
if (error)
return error;
result = (s16)get_unaligned_le16(pcu->cmd_buf + OFN_REG_RESULT_OFFSET);
if (result < 0)
return -EIO;
/* We only need LSB */
*data = pcu->cmd_buf[OFN_REG_RESULT_OFFSET];
return 0;
}
static int ims_pcu_write_ofn_config(struct ims_pcu *pcu, u8 addr, u8 data)
{
u8 buffer[] = { addr, data };
int error;
s16 result;
error = ims_pcu_execute_command(pcu, OFN_SET_CONFIG,
&buffer, sizeof(buffer));
if (error)
return error;
result = (s16)get_unaligned_le16(pcu->cmd_buf + OFN_REG_RESULT_OFFSET);
if (result < 0)
return -EIO;
return 0;
}
static ssize_t ims_pcu_ofn_reg_data_show(struct device *dev,
struct device_attribute *dattr,
char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct ims_pcu *pcu = usb_get_intfdata(intf);
int error;
u8 data;
mutex_lock(&pcu->cmd_mutex);
error = ims_pcu_read_ofn_config(pcu, pcu->ofn_reg_addr, &data);
mutex_unlock(&pcu->cmd_mutex);
if (error)
return error;
return scnprintf(buf, PAGE_SIZE, "%x\n", data);
}
static ssize_t ims_pcu_ofn_reg_data_store(struct device *dev,
struct device_attribute *dattr,
const char *buf, size_t count)
{
struct usb_interface *intf = to_usb_interface(dev);
struct ims_pcu *pcu = usb_get_intfdata(intf);
int error;
u8 value;
error = kstrtou8(buf, 0, &value);
if (error)
return error;
mutex_lock(&pcu->cmd_mutex);
error = ims_pcu_write_ofn_config(pcu, pcu->ofn_reg_addr, value);
mutex_unlock(&pcu->cmd_mutex);
return error ?: count;
}
static DEVICE_ATTR(reg_data, S_IRUGO | S_IWUSR,
ims_pcu_ofn_reg_data_show, ims_pcu_ofn_reg_data_store);
static ssize_t ims_pcu_ofn_reg_addr_show(struct device *dev,
struct device_attribute *dattr,
char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct ims_pcu *pcu = usb_get_intfdata(intf);
int error;
mutex_lock(&pcu->cmd_mutex);
error = scnprintf(buf, PAGE_SIZE, "%x\n", pcu->ofn_reg_addr);
mutex_unlock(&pcu->cmd_mutex);
return error;
}
static ssize_t ims_pcu_ofn_reg_addr_store(struct device *dev,
struct device_attribute *dattr,
const char *buf, size_t count)
{
struct usb_interface *intf = to_usb_interface(dev);
struct ims_pcu *pcu = usb_get_intfdata(intf);
int error;
u8 value;
error = kstrtou8(buf, 0, &value);
if (error)
return error;
mutex_lock(&pcu->cmd_mutex);
pcu->ofn_reg_addr = value;
mutex_unlock(&pcu->cmd_mutex);
return error ?: count;
}
static DEVICE_ATTR(reg_addr, S_IRUGO | S_IWUSR,
ims_pcu_ofn_reg_addr_show, ims_pcu_ofn_reg_addr_store);
struct ims_pcu_ofn_bit_attribute {
struct device_attribute dattr;
u8 addr;
u8 nr;
};
static ssize_t ims_pcu_ofn_bit_show(struct device *dev,
struct device_attribute *dattr,
char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct ims_pcu *pcu = usb_get_intfdata(intf);
struct ims_pcu_ofn_bit_attribute *attr =
container_of(dattr, struct ims_pcu_ofn_bit_attribute, dattr);
int error;
u8 data;
mutex_lock(&pcu->cmd_mutex);
error = ims_pcu_read_ofn_config(pcu, attr->addr, &data);
mutex_unlock(&pcu->cmd_mutex);
if (error)
return error;
return scnprintf(buf, PAGE_SIZE, "%d\n", !!(data & (1 << attr->nr)));
}
static ssize_t ims_pcu_ofn_bit_store(struct device *dev,
struct device_attribute *dattr,
const char *buf, size_t count)
{
struct usb_interface *intf = to_usb_interface(dev);
struct ims_pcu *pcu = usb_get_intfdata(intf);
struct ims_pcu_ofn_bit_attribute *attr =
container_of(dattr, struct ims_pcu_ofn_bit_attribute, dattr);
int error;
int value;
u8 data;
error = kstrtoint(buf, 0, &value);
if (error)
return error;
if (value > 1)
return -EINVAL;
mutex_lock(&pcu->cmd_mutex);
error = ims_pcu_read_ofn_config(pcu, attr->addr, &data);
if (!error) {
if (value)
data |= 1U << attr->nr;
else
data &= ~(1U << attr->nr);
error = ims_pcu_write_ofn_config(pcu, attr->addr, data);
}
mutex_unlock(&pcu->cmd_mutex);
return error ?: count;
}
#define IMS_PCU_OFN_BIT_ATTR(_field, _addr, _nr) \
struct ims_pcu_ofn_bit_attribute ims_pcu_ofn_attr_##_field = { \
.dattr = __ATTR(_field, S_IWUSR | S_IRUGO, \
ims_pcu_ofn_bit_show, ims_pcu_ofn_bit_store), \
.addr = _addr, \
.nr = _nr, \
}
static IMS_PCU_OFN_BIT_ATTR(engine_enable, 0x60, 7);
static IMS_PCU_OFN_BIT_ATTR(speed_enable, 0x60, 6);
static IMS_PCU_OFN_BIT_ATTR(assert_enable, 0x60, 5);
static IMS_PCU_OFN_BIT_ATTR(xyquant_enable, 0x60, 4);
static IMS_PCU_OFN_BIT_ATTR(xyscale_enable, 0x60, 1);
static IMS_PCU_OFN_BIT_ATTR(scale_x2, 0x63, 6);
static IMS_PCU_OFN_BIT_ATTR(scale_y2, 0x63, 7);
static struct attribute *ims_pcu_ofn_attrs[] = {
&dev_attr_reg_data.attr,
&dev_attr_reg_addr.attr,
&ims_pcu_ofn_attr_engine_enable.dattr.attr,
&ims_pcu_ofn_attr_speed_enable.dattr.attr,
&ims_pcu_ofn_attr_assert_enable.dattr.attr,
&ims_pcu_ofn_attr_xyquant_enable.dattr.attr,
&ims_pcu_ofn_attr_xyscale_enable.dattr.attr,
&ims_pcu_ofn_attr_scale_x2.dattr.attr,
&ims_pcu_ofn_attr_scale_y2.dattr.attr,
NULL
};
static struct attribute_group ims_pcu_ofn_attr_group = {
.name = "ofn",
.attrs = ims_pcu_ofn_attrs,
};
static void ims_pcu_irq(struct urb *urb)
{
struct ims_pcu *pcu = urb->context;
@ -1624,7 +1853,6 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
static atomic_t device_no = ATOMIC_INIT(0);
const struct ims_pcu_device_info *info;
u8 device_id;
int error;
error = ims_pcu_get_device_info(pcu);
@ -1633,7 +1861,7 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
return error;
}
error = ims_pcu_identify_type(pcu, &device_id);
error = ims_pcu_identify_type(pcu, &pcu->device_id);
if (error) {
dev_err(pcu->dev,
"Failed to identify device, error: %d\n", error);
@ -1645,9 +1873,9 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
return 0;
}
if (device_id >= ARRAY_SIZE(ims_pcu_device_info) ||
!ims_pcu_device_info[device_id].keymap) {
dev_err(pcu->dev, "Device ID %d is not valid\n", device_id);
if (pcu->device_id >= ARRAY_SIZE(ims_pcu_device_info) ||
!ims_pcu_device_info[pcu->device_id].keymap) {
dev_err(pcu->dev, "Device ID %d is not valid\n", pcu->device_id);
/* Same as above, punt to userspace */
return 0;
}
@ -1655,11 +1883,21 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
/* Device appears to be operable, complete initialization */
pcu->device_no = atomic_inc_return(&device_no) - 1;
/*
* PCU-B devices, both GEN_1 and GEN_2 do not have OFN sensor
*/
if (pcu->device_id != IMS_PCU_PCU_B_DEVICE_ID) {
error = sysfs_create_group(&pcu->dev->kobj,
&ims_pcu_ofn_attr_group);
if (error)
return error;
}
error = ims_pcu_setup_backlight(pcu);
if (error)
return error;
info = &ims_pcu_device_info[device_id];
info = &ims_pcu_device_info[pcu->device_id];
error = ims_pcu_setup_buttons(pcu, info->keymap, info->keymap_len);
if (error)
goto err_destroy_backlight;
@ -1674,10 +1912,10 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
return 0;
err_destroy_backlight:
ims_pcu_destroy_backlight(pcu);
err_destroy_buttons:
ims_pcu_destroy_buttons(pcu);
err_destroy_backlight:
ims_pcu_destroy_backlight(pcu);
return error;
}
@ -1691,6 +1929,10 @@ static void ims_pcu_destroy_application_mode(struct ims_pcu *pcu)
ims_pcu_destroy_gamepad(pcu);
ims_pcu_destroy_buttons(pcu);
ims_pcu_destroy_backlight(pcu);
if (pcu->device_id != IMS_PCU_PCU_B_DEVICE_ID)
sysfs_remove_group(&pcu->dev->kobj,
&ims_pcu_ofn_attr_group);
}
}

View file

@ -142,7 +142,6 @@ static int pm8xxx_vib_play_effect(struct input_dev *dev, void *data,
}
static int pm8xxx_vib_probe(struct platform_device *pdev)
{
struct pm8xxx_vib *vib;
struct input_dev *input_dev;
@ -214,12 +213,20 @@ static int pm8xxx_vib_suspend(struct device *dev)
static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL);
static const struct of_device_id pm8xxx_vib_id_table[] = {
{ .compatible = "qcom,pm8058-vib" },
{ .compatible = "qcom,pm8921-vib" },
{ }
};
MODULE_DEVICE_TABLE(of, pm8xxx_vib_id_table);
static struct platform_driver pm8xxx_vib_driver = {
.probe = pm8xxx_vib_probe,
.driver = {
.name = "pm8xxx-vib",
.owner = THIS_MODULE,
.pm = &pm8xxx_vib_pm_ops,
.of_match_table = pm8xxx_vib_id_table,
},
};
module_platform_driver(pm8xxx_vib_driver);

View file

@ -19,8 +19,7 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/log2.h>
#include <linux/input/pmic8xxx-pwrkey.h>
#include <linux/of.h>
#define PON_CNTL_1 0x1C
#define PON_CNTL_PULL_UP BIT(7)
@ -89,15 +88,15 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
unsigned int pon_cntl;
struct regmap *regmap;
struct pmic8xxx_pwrkey *pwrkey;
const struct pm8xxx_pwrkey_platform_data *pdata =
dev_get_platdata(&pdev->dev);
u32 kpd_delay;
bool pull_up;
if (!pdata) {
dev_err(&pdev->dev, "power key platform data not supplied\n");
return -EINVAL;
}
if (of_property_read_u32(pdev->dev.of_node, "debounce", &kpd_delay))
kpd_delay = 0;
if (pdata->kpd_trigger_delay_us > 62500) {
pull_up = of_property_read_bool(pdev->dev.of_node, "pull-up");
if (kpd_delay > 62500) {
dev_err(&pdev->dev, "invalid power key trigger delay\n");
return -EINVAL;
}
@ -125,7 +124,7 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
pwr->name = "pmic8xxx_pwrkey";
pwr->phys = "pmic8xxx_pwrkey/input0";
delay = (pdata->kpd_trigger_delay_us << 10) / USEC_PER_SEC;
delay = (kpd_delay << 10) / USEC_PER_SEC;
delay = 1 + ilog2(delay);
err = regmap_read(regmap, PON_CNTL_1, &pon_cntl);
@ -136,7 +135,7 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
if (pdata->pull_up)
if (pull_up)
pon_cntl |= PON_CNTL_PULL_UP;
else
pon_cntl &= ~PON_CNTL_PULL_UP;
@ -172,7 +171,7 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, pwrkey);
device_init_wakeup(&pdev->dev, pdata->wakeup);
device_init_wakeup(&pdev->dev, 1);
return 0;
}
@ -184,13 +183,21 @@ static int pmic8xxx_pwrkey_remove(struct platform_device *pdev)
return 0;
}
static const struct of_device_id pm8xxx_pwr_key_id_table[] = {
{ .compatible = "qcom,pm8058-pwrkey" },
{ .compatible = "qcom,pm8921-pwrkey" },
{ }
};
MODULE_DEVICE_TABLE(of, pm8xxx_pwr_key_id_table);
static struct platform_driver pmic8xxx_pwrkey_driver = {
.probe = pmic8xxx_pwrkey_probe,
.remove = pmic8xxx_pwrkey_remove,
.driver = {
.name = PM8XXX_PWRKEY_DEV_NAME,
.name = "pm8xxx-pwrkey",
.owner = THIS_MODULE,
.pm = &pm8xxx_pwr_key_pm_ops,
.of_match_table = pm8xxx_pwr_key_id_table,
},
};
module_platform_driver(pmic8xxx_pwrkey_driver);

View file

@ -1,7 +1,8 @@
/*
* Power key driver for SiRF PrimaII
*
* Copyright (c) 2013 Cambridge Silicon Radio Limited, a CSR plc group company.
* Copyright (c) 2013 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
* company.
*
* Licensed under GPLv2 or later.
*/
@ -13,16 +14,41 @@
#include <linux/input.h>
#include <linux/rtc/sirfsoc_rtciobrg.h>
#include <linux/of.h>
#include <linux/workqueue.h>
struct sirfsoc_pwrc_drvdata {
u32 pwrc_base;
struct input_dev *input;
struct delayed_work work;
};
#define PWRC_ON_KEY_BIT (1 << 0)
#define PWRC_INT_STATUS 0xc
#define PWRC_INT_MASK 0x10
#define PWRC_PIN_STATUS 0x14
#define PWRC_KEY_DETECT_UP_TIME 20 /* ms*/
static int sirfsoc_pwrc_is_on_key_down(struct sirfsoc_pwrc_drvdata *pwrcdrv)
{
u32 state = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base +
PWRC_PIN_STATUS);
return !(state & PWRC_ON_KEY_BIT); /* ON_KEY is active low */
}
static void sirfsoc_pwrc_report_event(struct work_struct *work)
{
struct sirfsoc_pwrc_drvdata *pwrcdrv =
container_of(work, struct sirfsoc_pwrc_drvdata, work.work);
if (sirfsoc_pwrc_is_on_key_down(pwrcdrv)) {
schedule_delayed_work(&pwrcdrv->work,
msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME));
} else {
input_event(pwrcdrv->input, EV_KEY, KEY_POWER, 0);
input_sync(pwrcdrv->input);
}
}
static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
{
@ -34,21 +60,44 @@ static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
sirfsoc_rtc_iobrg_writel(int_status & ~PWRC_ON_KEY_BIT,
pwrcdrv->pwrc_base + PWRC_INT_STATUS);
/*
* For a typical Linux system, we report KEY_SUSPEND to trigger apm-power.c
* to queue a SUSPEND APM event
*/
input_event(pwrcdrv->input, EV_PWR, KEY_SUSPEND, 1);
input_event(pwrcdrv->input, EV_KEY, KEY_POWER, 1);
input_sync(pwrcdrv->input);
/*
* Todo: report KEY_POWER event for Android platforms, Android PowerManager
* will handle the suspend and powerdown/hibernation
*/
schedule_delayed_work(&pwrcdrv->work,
msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME));
return IRQ_HANDLED;
}
static void sirfsoc_pwrc_toggle_interrupts(struct sirfsoc_pwrc_drvdata *pwrcdrv,
bool enable)
{
u32 int_mask;
int_mask = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + PWRC_INT_MASK);
if (enable)
int_mask |= PWRC_ON_KEY_BIT;
else
int_mask &= ~PWRC_ON_KEY_BIT;
sirfsoc_rtc_iobrg_writel(int_mask, pwrcdrv->pwrc_base + PWRC_INT_MASK);
}
static int sirfsoc_pwrc_open(struct input_dev *input)
{
struct sirfsoc_pwrc_drvdata *pwrcdrv = input_get_drvdata(input);
sirfsoc_pwrc_toggle_interrupts(pwrcdrv, true);
return 0;
}
static void sirfsoc_pwrc_close(struct input_dev *input)
{
struct sirfsoc_pwrc_drvdata *pwrcdrv = input_get_drvdata(input);
sirfsoc_pwrc_toggle_interrupts(pwrcdrv, false);
cancel_delayed_work_sync(&pwrcdrv->work);
}
static const struct of_device_id sirfsoc_pwrc_of_match[] = {
{ .compatible = "sirf,prima2-pwrc" },
{},
@ -70,7 +119,7 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)
}
/*
* we can't use of_iomap because pwrc is not mapped in memory,
* We can't use of_iomap because pwrc is not mapped in memory,
* the so-called base address is only offset in rtciobrg
*/
error = of_property_read_u32(np, "reg", &pwrcdrv->pwrc_base);
@ -86,11 +135,22 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)
pwrcdrv->input->name = "sirfsoc pwrckey";
pwrcdrv->input->phys = "pwrc/input0";
pwrcdrv->input->evbit[0] = BIT_MASK(EV_PWR);
pwrcdrv->input->evbit[0] = BIT_MASK(EV_KEY);
input_set_capability(pwrcdrv->input, EV_KEY, KEY_POWER);
INIT_DELAYED_WORK(&pwrcdrv->work, sirfsoc_pwrc_report_event);
pwrcdrv->input->open = sirfsoc_pwrc_open;
pwrcdrv->input->close = sirfsoc_pwrc_close;
input_set_drvdata(pwrcdrv->input, pwrcdrv);
/* Make sure the device is quiesced */
sirfsoc_pwrc_toggle_interrupts(pwrcdrv, false);
irq = platform_get_irq(pdev, 0);
error = devm_request_irq(&pdev->dev, irq,
sirfsoc_pwrc_isr, IRQF_SHARED,
sirfsoc_pwrc_isr, 0,
"sirfsoc_pwrc_int", pwrcdrv);
if (error) {
dev_err(&pdev->dev, "unable to claim irq %d, error: %d\n",
@ -98,11 +158,6 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)
return error;
}
sirfsoc_rtc_iobrg_writel(
sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + PWRC_INT_MASK) |
PWRC_ON_KEY_BIT,
pwrcdrv->pwrc_base + PWRC_INT_MASK);
error = input_register_device(pwrcdrv->input);
if (error) {
dev_err(&pdev->dev,
@ -111,7 +166,7 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)
return error;
}
platform_set_drvdata(pdev, pwrcdrv);
dev_set_drvdata(&pdev->dev, pwrcdrv);
device_init_wakeup(&pdev->dev, 1);
return 0;
@ -125,25 +180,25 @@ static int sirfsoc_pwrc_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM_SLEEP
static int pwrc_resume(struct device *dev)
static int sirfsoc_pwrc_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct sirfsoc_pwrc_drvdata *pwrcdrv = platform_get_drvdata(pdev);
struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_get_drvdata(dev);
struct input_dev *input = pwrcdrv->input;
/*
* Do not mask pwrc interrupt as we want pwrc work as a wakeup source
* if users touch X_ONKEY_B, see arch/arm/mach-prima2/pm.c
*/
sirfsoc_rtc_iobrg_writel(
sirfsoc_rtc_iobrg_readl(
pwrcdrv->pwrc_base + PWRC_INT_MASK) | PWRC_ON_KEY_BIT,
pwrcdrv->pwrc_base + PWRC_INT_MASK);
mutex_lock(&input->mutex);
if (input->users)
sirfsoc_pwrc_toggle_interrupts(pwrcdrv, true);
mutex_unlock(&input->mutex);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, pwrc_resume);
static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, sirfsoc_pwrc_resume);
static struct platform_driver sirfsoc_pwrc_driver = {
.probe = sirfsoc_pwrc_probe,

View file

@ -0,0 +1,218 @@
/*
* Supports for the button array on SoC tablets originally running
* Windows 8.
*
* (C) Copyright 2014 Intel Corporation
*
* 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 <linux/module.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/pnp.h>
/*
* Definition of buttons on the tablet. The ACPI index of each button
* is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
* Platforms"
*/
#define MAX_NBUTTONS 5
struct soc_button_info {
const char *name;
int acpi_index;
unsigned int event_type;
unsigned int event_code;
bool autorepeat;
bool wakeup;
};
/*
* Some of the buttons like volume up/down are auto repeat, while others
* are not. To support both, we register two platform devices, and put
* buttons into them based on whether the key should be auto repeat.
*/
#define BUTTON_TYPES 2
struct soc_button_data {
struct platform_device *children[BUTTON_TYPES];
};
/*
* Get the Nth GPIO number from the ACPI object.
*/
static int soc_button_lookup_gpio(struct device *dev, int acpi_index)
{
struct gpio_desc *desc;
int gpio;
desc = gpiod_get_index(dev, KBUILD_MODNAME, acpi_index);
if (IS_ERR(desc))
return PTR_ERR(desc);
gpio = desc_to_gpio(desc);
gpiod_put(desc);
return gpio;
}
static struct platform_device *
soc_button_device_create(struct pnp_dev *pdev,
const struct soc_button_info *button_info,
bool autorepeat)
{
const struct soc_button_info *info;
struct platform_device *pd;
struct gpio_keys_button *gpio_keys;
struct gpio_keys_platform_data *gpio_keys_pdata;
int n_buttons = 0;
int gpio;
int error;
gpio_keys_pdata = devm_kzalloc(&pdev->dev,
sizeof(*gpio_keys_pdata) +
sizeof(*gpio_keys) * MAX_NBUTTONS,
GFP_KERNEL);
gpio_keys = (void *)(gpio_keys_pdata + 1);
for (info = button_info; info->name; info++) {
if (info->autorepeat != autorepeat)
continue;
gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
if (gpio < 0)
continue;
gpio_keys[n_buttons].type = info->event_type;
gpio_keys[n_buttons].code = info->event_code;
gpio_keys[n_buttons].gpio = gpio;
gpio_keys[n_buttons].active_low = 1;
gpio_keys[n_buttons].desc = info->name;
gpio_keys[n_buttons].wakeup = info->wakeup;
n_buttons++;
}
if (n_buttons == 0) {
error = -ENODEV;
goto err_free_mem;
}
gpio_keys_pdata->buttons = gpio_keys;
gpio_keys_pdata->nbuttons = n_buttons;
gpio_keys_pdata->rep = autorepeat;
pd = platform_device_alloc("gpio-keys", PLATFORM_DEVID_AUTO);
if (!pd) {
error = -ENOMEM;
goto err_free_mem;
}
error = platform_device_add_data(pd, gpio_keys_pdata,
sizeof(*gpio_keys_pdata));
if (error)
goto err_free_pdev;
error = platform_device_add(pd);
if (error)
goto err_free_pdev;
return pd;
err_free_pdev:
platform_device_put(pd);
err_free_mem:
devm_kfree(&pdev->dev, gpio_keys_pdata);
return ERR_PTR(error);
}
static void soc_button_remove(struct pnp_dev *pdev)
{
struct soc_button_data *priv = pnp_get_drvdata(pdev);
int i;
for (i = 0; i < BUTTON_TYPES; i++)
if (priv->children[i])
platform_device_unregister(priv->children[i]);
}
static int soc_button_pnp_probe(struct pnp_dev *pdev,
const struct pnp_device_id *id)
{
const struct soc_button_info *button_info = (void *)id->driver_data;
struct soc_button_data *priv;
struct platform_device *pd;
int i;
int error;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
pnp_set_drvdata(pdev, priv);
for (i = 0; i < BUTTON_TYPES; i++) {
pd = soc_button_device_create(pdev, button_info, i == 0);
if (IS_ERR(pd)) {
error = PTR_ERR(pd);
if (error != -ENODEV) {
soc_button_remove(pdev);
return error;
}
}
priv->children[i] = pd;
}
if (!priv->children[0] && !priv->children[1])
return -ENODEV;
return 0;
}
static struct soc_button_info soc_button_PNP0C40[] = {
{ "power", 0, EV_KEY, KEY_POWER, false, true },
{ "home", 1, EV_KEY, KEY_HOME, false, true },
{ "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
{ "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false },
{ "rotation_lock", 4, EV_SW, SW_ROTATE_LOCK, false, false },
{ }
};
static const struct pnp_device_id soc_button_pnp_match[] = {
{ .id = "PNP0C40", .driver_data = (long)soc_button_PNP0C40 },
{ .id = "" }
};
MODULE_DEVICE_TABLE(pnp, soc_button_pnp_match);
static struct pnp_driver soc_button_pnp_driver = {
.name = KBUILD_MODNAME,
.id_table = soc_button_pnp_match,
.probe = soc_button_pnp_probe,
.remove = soc_button_remove,
};
static int __init soc_button_init(void)
{
return pnp_register_driver(&soc_button_pnp_driver);
}
static void __exit soc_button_exit(void)
{
pnp_unregister_driver(&soc_button_pnp_driver);
}
module_init(soc_button_init);
module_exit(soc_button_exit);
MODULE_LICENSE("GPL");

View file

@ -20,6 +20,8 @@
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
*
* Changes/Revisions:
* 0.4 01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>)
* - add UI_GET_SYSNAME ioctl
* 0.3 09/04/2006 (Anssi Hannula <anssi.hannula@gmail.com>)
* - updated ff support for the changes in kernel interface
* - added MODULE_VERSION
@ -670,6 +672,31 @@ static int uinput_ff_upload_from_user(const char __user *buffer,
__ret; \
})
static int uinput_str_to_user(void __user *dest, const char *str,
unsigned int maxlen)
{
char __user *p = dest;
int len, ret;
if (!str)
return -ENOENT;
if (maxlen == 0)
return -EINVAL;
len = strlen(str) + 1;
if (len > maxlen)
len = maxlen;
ret = copy_to_user(p, str, len);
if (ret)
return -EFAULT;
/* force terminating '\0' */
ret = put_user(0, p + len - 1);
return ret ? -EFAULT : len;
}
static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
unsigned long arg, void __user *p)
{
@ -679,6 +706,8 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
struct uinput_ff_erase ff_erase;
struct uinput_request *req;
char *phys;
const char *name;
unsigned int size;
retval = mutex_lock_interruptible(&udev->mutex);
if (retval)
@ -693,51 +722,51 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
switch (cmd) {
case UI_DEV_CREATE:
retval = uinput_create_device(udev);
break;
goto out;
case UI_DEV_DESTROY:
uinput_destroy_device(udev);
break;
goto out;
case UI_SET_EVBIT:
retval = uinput_set_bit(arg, evbit, EV_MAX);
break;
goto out;
case UI_SET_KEYBIT:
retval = uinput_set_bit(arg, keybit, KEY_MAX);
break;
goto out;
case UI_SET_RELBIT:
retval = uinput_set_bit(arg, relbit, REL_MAX);
break;
goto out;
case UI_SET_ABSBIT:
retval = uinput_set_bit(arg, absbit, ABS_MAX);
break;
goto out;
case UI_SET_MSCBIT:
retval = uinput_set_bit(arg, mscbit, MSC_MAX);
break;
goto out;
case UI_SET_LEDBIT:
retval = uinput_set_bit(arg, ledbit, LED_MAX);
break;
goto out;
case UI_SET_SNDBIT:
retval = uinput_set_bit(arg, sndbit, SND_MAX);
break;
goto out;
case UI_SET_FFBIT:
retval = uinput_set_bit(arg, ffbit, FF_MAX);
break;
goto out;
case UI_SET_SWBIT:
retval = uinput_set_bit(arg, swbit, SW_MAX);
break;
goto out;
case UI_SET_PROPBIT:
retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX);
break;
goto out;
case UI_SET_PHYS:
if (udev->state == UIST_CREATED) {
@ -753,18 +782,18 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
kfree(udev->dev->phys);
udev->dev->phys = phys;
break;
goto out;
case UI_BEGIN_FF_UPLOAD:
retval = uinput_ff_upload_from_user(p, &ff_up);
if (retval)
break;
goto out;
req = uinput_request_find(udev, ff_up.request_id);
if (!req || req->code != UI_FF_UPLOAD ||
!req->u.upload.effect) {
retval = -EINVAL;
break;
goto out;
}
ff_up.retval = 0;
@ -775,65 +804,77 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
memset(&ff_up.old, 0, sizeof(struct ff_effect));
retval = uinput_ff_upload_to_user(p, &ff_up);
break;
goto out;
case UI_BEGIN_FF_ERASE:
if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
retval = -EFAULT;
break;
goto out;
}
req = uinput_request_find(udev, ff_erase.request_id);
if (!req || req->code != UI_FF_ERASE) {
retval = -EINVAL;
break;
goto out;
}
ff_erase.retval = 0;
ff_erase.effect_id = req->u.effect_id;
if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) {
retval = -EFAULT;
break;
goto out;
}
break;
goto out;
case UI_END_FF_UPLOAD:
retval = uinput_ff_upload_from_user(p, &ff_up);
if (retval)
break;
goto out;
req = uinput_request_find(udev, ff_up.request_id);
if (!req || req->code != UI_FF_UPLOAD ||
!req->u.upload.effect) {
retval = -EINVAL;
break;
goto out;
}
req->retval = ff_up.retval;
uinput_request_done(udev, req);
break;
goto out;
case UI_END_FF_ERASE:
if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
retval = -EFAULT;
break;
goto out;
}
req = uinput_request_find(udev, ff_erase.request_id);
if (!req || req->code != UI_FF_ERASE) {
retval = -EINVAL;
break;
goto out;
}
req->retval = ff_erase.retval;
uinput_request_done(udev, req);
break;
default:
retval = -EINVAL;
goto out;
}
size = _IOC_SIZE(cmd);
/* Now check variable-length commands */
switch (cmd & ~IOCSIZE_MASK) {
case UI_GET_SYSNAME(0):
if (udev->state != UIST_CREATED) {
retval = -ENOENT;
goto out;
}
name = dev_name(&udev->dev->dev);
retval = uinput_str_to_user(p, name, size);
goto out;
}
retval = -EINVAL;
out:
mutex_unlock(&udev->mutex);
return retval;

View file

@ -277,6 +277,16 @@ static struct key_entry keymap_fs_amilo_pro_v3505[] __initdata = {
{ KE_END, 0 }
};
static struct key_entry keymap_fs_amilo_pro_v8210[] __initdata = {
{ KE_KEY, 0x01, {KEY_HELP} }, /* Fn+F1 */
{ KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Fn+F4 */
{ KE_BLUETOOTH, 0x30 }, /* Fn+F10 */
{ KE_KEY, 0x31, {KEY_MAIL} }, /* mail button */
{ KE_KEY, 0x36, {KEY_WWW} }, /* www button */
{ KE_WIFI, 0x78 }, /* satelite dish button */
{ KE_END, FE_WIFI_LED }
};
static struct key_entry keymap_fujitsu_n3510[] __initdata = {
{ KE_KEY, 0x11, {KEY_PROG1} },
{ KE_KEY, 0x12, {KEY_PROG2} },
@ -653,6 +663,15 @@ static const struct dmi_system_id dmi_ids[] __initconst = {
},
.driver_data = keymap_fs_amilo_pro_v3505
},
{
/* Fujitsu-Siemens Amilo Pro Edition V8210 */
.callback = dmi_matched,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Series V8210"),
},
.driver_data = keymap_fs_amilo_pro_v8210
},
{
/* Fujitsu-Siemens Amilo M7400 */
.callback = dmi_matched,

View file

@ -29,6 +29,7 @@
#include <xen/interface/io/fbif.h>
#include <xen/interface/io/kbdif.h>
#include <xen/xenbus.h>
#include <xen/platform_pci.h>
struct xenkbd_info {
struct input_dev *kbd;
@ -380,6 +381,9 @@ static int __init xenkbd_init(void)
if (xen_initial_domain())
return -ENODEV;
if (!xen_has_pv_devices())
return -ENODEV;
return xenbus_register_frontend(&xenkbd_driver);
}

View file

@ -48,6 +48,7 @@ struct atp_info {
int yfact; /* Y multiplication factor */
int datalen; /* size of USB transfers */
void (*callback)(struct urb *); /* callback function */
int fuzz; /* fuzz touchpad generates */
};
static void atp_complete_geyser_1_2(struct urb *urb);
@ -61,6 +62,7 @@ static const struct atp_info fountain_info = {
.yfact = 43,
.datalen = 81,
.callback = atp_complete_geyser_1_2,
.fuzz = 16,
};
static const struct atp_info geyser1_info = {
@ -71,6 +73,7 @@ static const struct atp_info geyser1_info = {
.yfact = 43,
.datalen = 81,
.callback = atp_complete_geyser_1_2,
.fuzz = 16,
};
static const struct atp_info geyser2_info = {
@ -81,6 +84,7 @@ static const struct atp_info geyser2_info = {
.yfact = 43,
.datalen = 64,
.callback = atp_complete_geyser_1_2,
.fuzz = 0,
};
static const struct atp_info geyser3_info = {
@ -90,6 +94,7 @@ static const struct atp_info geyser3_info = {
.yfact = 64,
.datalen = 64,
.callback = atp_complete_geyser_3_4,
.fuzz = 0,
};
static const struct atp_info geyser4_info = {
@ -99,6 +104,7 @@ static const struct atp_info geyser4_info = {
.yfact = 64,
.datalen = 64,
.callback = atp_complete_geyser_3_4,
.fuzz = 0,
};
#define ATP_DEVICE(prod, info) \
@ -155,8 +161,11 @@ MODULE_DEVICE_TABLE(usb, atp_table);
#define ATP_XSENSORS 26
#define ATP_YSENSORS 16
/* amount of fuzz this touchpad generates */
#define ATP_FUZZ 16
/*
* The largest possible bank of sensors with additional buffer of 4 extra values
* on either side, for an array of smoothed sensor values.
*/
#define ATP_SMOOTHSIZE 34
/* maximum pressure this driver will report */
#define ATP_PRESSURE 300
@ -165,7 +174,13 @@ MODULE_DEVICE_TABLE(usb, atp_table);
* Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is
* ignored.
*/
#define ATP_THRESHOLD 5
#define ATP_THRESHOLD 5
/*
* How far we'll bitshift our sensor values before averaging them. Mitigates
* rounding errors.
*/
#define ATP_SCALE 12
/* Geyser initialization constants */
#define ATP_GEYSER_MODE_READ_REQUEST_ID 1
@ -203,11 +218,14 @@ struct atp {
bool valid; /* are the samples valid? */
bool size_detect_done;
bool overflow_warned;
int fingers_old; /* last reported finger count */
int x_old; /* last reported x/y, */
int y_old; /* used for smoothing */
signed char xy_cur[ATP_XSENSORS + ATP_YSENSORS];
signed char xy_old[ATP_XSENSORS + ATP_YSENSORS];
int xy_acc[ATP_XSENSORS + ATP_YSENSORS];
int smooth[ATP_SMOOTHSIZE];
int smooth_tmp[ATP_SMOOTHSIZE];
int idlecount; /* number of empty packets */
struct work_struct work;
};
@ -326,10 +344,17 @@ static void atp_reinit(struct work_struct *work)
retval);
}
static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
int *z, int *fingers)
static int atp_calculate_abs(struct atp *dev, int offset, int nb_sensors,
int fact, int *z, int *fingers)
{
int i;
int i, pass;
/*
* Use offset to point xy_sensors at the first value in dev->xy_acc
* for whichever dimension we're looking at this particular go-round.
*/
int *xy_sensors = dev->xy_acc + offset;
/* values to calculate mean */
int pcum = 0, psum = 0;
int is_increasing = 0;
@ -341,9 +366,6 @@ static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
if (is_increasing)
is_increasing = 0;
continue;
}
/*
* Makes the finger detection more versatile. For example,
* two fingers with no gap will be detected. Also, my
@ -358,27 +380,63 @@ static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
*
* - Jason Parekh <jasonparekh@gmail.com>
*/
if (i < 1 ||
} else if (i < 1 ||
(!is_increasing && xy_sensors[i - 1] < xy_sensors[i])) {
(*fingers)++;
is_increasing = 1;
} else if (i > 0 && (xy_sensors[i - 1] - xy_sensors[i] > threshold)) {
is_increasing = 0;
}
}
if (*fingers < 1) /* No need to continue if no fingers are found. */
return 0;
/*
* Use a smoothed version of sensor data for movement calculations, to
* combat noise without needing to rely so heavily on a threshold.
* This improves tracking.
*
* The smoothed array is bigger than the original so that the smoothing
* doesn't result in edge values being truncated.
*/
memset(dev->smooth, 0, 4 * sizeof(dev->smooth[0]));
/* Pull base values, scaled up to help avoid truncation errors. */
for (i = 0; i < nb_sensors; i++)
dev->smooth[i + 4] = xy_sensors[i] << ATP_SCALE;
memset(&dev->smooth[nb_sensors + 4], 0, 4 * sizeof(dev->smooth[0]));
for (pass = 0; pass < 4; pass++) {
/* Handle edge. */
dev->smooth_tmp[0] = (dev->smooth[0] + dev->smooth[1]) / 2;
/* Average values with neighbors. */
for (i = 1; i < nb_sensors + 7; i++)
dev->smooth_tmp[i] = (dev->smooth[i - 1] +
dev->smooth[i] * 2 +
dev->smooth[i + 1]) / 4;
/* Handle other edge. */
dev->smooth_tmp[i] = (dev->smooth[i - 1] + dev->smooth[i]) / 2;
memcpy(dev->smooth, dev->smooth_tmp, sizeof(dev->smooth));
}
for (i = 0; i < nb_sensors + 8; i++) {
/*
* Subtracts threshold so a high sensor that just passes the
* threshold won't skew the calculated absolute coordinate.
* Fixes an issue where slowly moving the mouse would
* occasionally jump a number of pixels (slowly moving the
* finger makes this issue most apparent.)
* Skip values if they're small enough to be truncated to 0
* by scale. Mostly noise.
*/
pcum += (xy_sensors[i] - threshold) * i;
psum += (xy_sensors[i] - threshold);
if ((dev->smooth[i] >> ATP_SCALE) > 0) {
pcum += dev->smooth[i] * i;
psum += dev->smooth[i];
}
}
if (psum > 0) {
*z = psum;
*z = psum >> ATP_SCALE; /* Scale down pressure output. */
return pcum * fact / psum;
}
@ -455,7 +513,7 @@ static void atp_detect_size(struct atp *dev)
input_set_abs_params(dev->input, ABS_X, 0,
(dev->info->xsensors_17 - 1) *
dev->info->xfact - 1,
ATP_FUZZ, 0);
dev->info->fuzz, 0);
break;
}
}
@ -471,7 +529,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)
{
int x, y, x_z, y_z, x_f, y_f;
int retval, i, j;
int key;
int key, fingers;
struct atp *dev = urb->context;
int status = atp_status_check(urb);
@ -548,16 +606,18 @@ static void atp_complete_geyser_1_2(struct urb *urb)
dbg_dump("accumulator", dev->xy_acc);
x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
x = atp_calculate_abs(dev, 0, ATP_XSENSORS,
dev->info->xfact, &x_z, &x_f);
y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
y = atp_calculate_abs(dev, ATP_XSENSORS, ATP_YSENSORS,
dev->info->yfact, &y_z, &y_f);
key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON;
if (x && y) {
fingers = max(x_f, y_f);
if (x && y && fingers == dev->fingers_old) {
if (dev->x_old != -1) {
x = (dev->x_old * 3 + x) >> 2;
y = (dev->y_old * 3 + y) >> 2;
x = (dev->x_old * 7 + x) >> 3;
y = (dev->y_old * 7 + y) >> 3;
dev->x_old = x;
dev->y_old = y;
@ -571,7 +631,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)
input_report_abs(dev->input, ABS_Y, y);
input_report_abs(dev->input, ABS_PRESSURE,
min(ATP_PRESSURE, x_z + y_z));
atp_report_fingers(dev->input, max(x_f, y_f));
atp_report_fingers(dev->input, fingers);
}
dev->x_old = x;
dev->y_old = y;
@ -579,6 +639,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)
} else if (!x && !y) {
dev->x_old = dev->y_old = -1;
dev->fingers_old = 0;
input_report_key(dev->input, BTN_TOUCH, 0);
input_report_abs(dev->input, ABS_PRESSURE, 0);
atp_report_fingers(dev->input, 0);
@ -587,6 +648,10 @@ static void atp_complete_geyser_1_2(struct urb *urb)
memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
}
if (fingers != dev->fingers_old)
dev->x_old = dev->y_old = -1;
dev->fingers_old = fingers;
input_report_key(dev->input, BTN_LEFT, key);
input_sync(dev->input);
@ -604,7 +669,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)
{
int x, y, x_z, y_z, x_f, y_f;
int retval, i, j;
int key;
int key, fingers;
struct atp *dev = urb->context;
int status = atp_status_check(urb);
@ -660,16 +725,19 @@ static void atp_complete_geyser_3_4(struct urb *urb)
dbg_dump("accumulator", dev->xy_acc);
x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
x = atp_calculate_abs(dev, 0, ATP_XSENSORS,
dev->info->xfact, &x_z, &x_f);
y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
y = atp_calculate_abs(dev, ATP_XSENSORS, ATP_YSENSORS,
dev->info->yfact, &y_z, &y_f);
key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON;
if (x && y) {
fingers = max(x_f, y_f);
if (x && y && fingers == dev->fingers_old) {
if (dev->x_old != -1) {
x = (dev->x_old * 3 + x) >> 2;
y = (dev->y_old * 3 + y) >> 2;
x = (dev->x_old * 7 + x) >> 3;
y = (dev->y_old * 7 + y) >> 3;
dev->x_old = x;
dev->y_old = y;
@ -683,7 +751,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)
input_report_abs(dev->input, ABS_Y, y);
input_report_abs(dev->input, ABS_PRESSURE,
min(ATP_PRESSURE, x_z + y_z));
atp_report_fingers(dev->input, max(x_f, y_f));
atp_report_fingers(dev->input, fingers);
}
dev->x_old = x;
dev->y_old = y;
@ -691,6 +759,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)
} else if (!x && !y) {
dev->x_old = dev->y_old = -1;
dev->fingers_old = 0;
input_report_key(dev->input, BTN_TOUCH, 0);
input_report_abs(dev->input, ABS_PRESSURE, 0);
atp_report_fingers(dev->input, 0);
@ -699,6 +768,10 @@ static void atp_complete_geyser_3_4(struct urb *urb)
memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
}
if (fingers != dev->fingers_old)
dev->x_old = dev->y_old = -1;
dev->fingers_old = fingers;
input_report_key(dev->input, BTN_LEFT, key);
input_sync(dev->input);
@ -843,10 +916,10 @@ static int atp_probe(struct usb_interface *iface,
input_set_abs_params(input_dev, ABS_X, 0,
(dev->info->xsensors - 1) * dev->info->xfact - 1,
ATP_FUZZ, 0);
dev->info->fuzz, 0);
input_set_abs_params(input_dev, ABS_Y, 0,
(dev->info->ysensors - 1) * dev->info->yfact - 1,
ATP_FUZZ, 0);
dev->info->fuzz, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0);
set_bit(EV_KEY, input_dev->evbit);

View file

@ -263,7 +263,7 @@ config SERIO_APBPS2
config SERIO_OLPC_APSP
tristate "OLPC AP-SP input support"
depends on OF
depends on OLPC || COMPILE_TEST
help
Say Y here if you want support for the keyboard and touchpad included
in the OLPC XO-1.75 and XO-4 laptops.

View file

@ -166,8 +166,6 @@ static int amba_kmi_remove(struct amba_device *dev)
{
struct amba_kmi_port *kmi = amba_get_drvdata(dev);
amba_set_drvdata(dev, NULL);
serio_unregister_port(kmi->io);
clk_put(kmi->clk);
iounmap(kmi->base);

View file

@ -984,7 +984,7 @@ static void hp_sdc_exit(void)
free_irq(hp_sdc.irq, &hp_sdc);
write_unlock_irq(&hp_sdc.lock);
del_timer(&hp_sdc.kicker);
del_timer_sync(&hp_sdc.kicker);
tasklet_kill(&hp_sdc.task);

View file

@ -124,7 +124,7 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c
{
struct serport *serport = (struct serport*) tty->disc_data;
unsigned long flags;
unsigned int ch_flags;
unsigned int ch_flags = 0;
int i;
spin_lock_irqsave(&serport->lock, flags);
@ -133,18 +133,20 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c
goto out;
for (i = 0; i < count; i++) {
switch (fp[i]) {
case TTY_FRAME:
ch_flags = SERIO_FRAME;
break;
if (fp) {
switch (fp[i]) {
case TTY_FRAME:
ch_flags = SERIO_FRAME;
break;
case TTY_PARITY:
ch_flags = SERIO_PARITY;
break;
case TTY_PARITY:
ch_flags = SERIO_PARITY;
break;
default:
ch_flags = 0;
break;
default:
ch_flags = 0;
break;
}
}
serio_interrupt(serport->serio, cp[i], ch_flags);

View file

@ -848,7 +848,7 @@ static int gtco_probe(struct usb_interface *usbinterface,
gtco->inputdevice = input_dev;
/* Save interface information */
gtco->usbdev = usb_get_dev(interface_to_usbdev(usbinterface));
gtco->usbdev = interface_to_usbdev(usbinterface);
gtco->intf = usbinterface;
/* Allocate some data for incoming reports */

View file

@ -514,15 +514,6 @@ config TOUCHSCREEN_MIGOR
To compile this driver as a module, choose M here: the
module will be called migor_ts.
config TOUCHSCREEN_TNETV107X
tristate "TI TNETV107X touchscreen support"
depends on ARCH_DAVINCI_TNETV107X
help
Say Y here if you want to use the TNETV107X touchscreen.
To compile this driver as a module, choose M here: the
module will be called tnetv107x-ts.
config TOUCHSCREEN_TOUCHRIGHT
tristate "Touchright serial touchscreen"
select SERIO
@ -717,7 +708,7 @@ config TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_MC13783
tristate "Freescale MC13783 touchscreen input driver"
depends on MFD_MC13783
depends on MFD_MC13XXX
help
Say Y here if you have an Freescale MC13783 PMIC on your
board and want to use its touchscreen

View file

@ -56,7 +56,6 @@ obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o

View file

@ -1,5 +1,7 @@
/*
* Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de>
* Daniel Wagener <daniel.wagener@kernelconcepts.de> (M09 firmware support)
* Lothar Waßmann <LW@KARO-electronics.de> (DT support)
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@ -33,6 +35,7 @@
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/input/mt.h>
#include <linux/input/edt-ft5x06.h>
@ -45,6 +48,14 @@
#define WORK_REGISTER_NUM_X 0x33
#define WORK_REGISTER_NUM_Y 0x34
#define M09_REGISTER_THRESHOLD 0x80
#define M09_REGISTER_GAIN 0x92
#define M09_REGISTER_OFFSET 0x93
#define M09_REGISTER_NUM_X 0x94
#define M09_REGISTER_NUM_Y 0x95
#define NO_REGISTER 0xff
#define WORK_REGISTER_OPMODE 0x3c
#define FACTORY_REGISTER_OPMODE 0x01
@ -59,12 +70,30 @@
#define EDT_RAW_DATA_RETRIES 100
#define EDT_RAW_DATA_DELAY 1 /* msec */
enum edt_ver {
M06,
M09,
};
struct edt_reg_addr {
int reg_threshold;
int reg_report_rate;
int reg_gain;
int reg_offset;
int reg_num_x;
int reg_num_y;
};
struct edt_ft5x06_ts_data {
struct i2c_client *client;
struct input_dev *input;
u16 num_x;
u16 num_y;
int reset_pin;
int irq_pin;
int wake_pin;
#if defined(CONFIG_DEBUG_FS)
struct dentry *debug_dir;
u8 *raw_buffer;
@ -79,6 +108,9 @@ struct edt_ft5x06_ts_data {
int report_rate;
char name[EDT_NAME_LEN];
struct edt_reg_addr reg_addr;
enum edt_ver version;
};
static int edt_ft5x06_ts_readwrite(struct i2c_client *client,
@ -136,33 +168,58 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
{
struct edt_ft5x06_ts_data *tsdata = dev_id;
struct device *dev = &tsdata->client->dev;
u8 cmd = 0xf9;
u8 rdbuf[26];
u8 cmd;
u8 rdbuf[29];
int i, type, x, y, id;
int offset, tplen, datalen;
int error;
switch (tsdata->version) {
case M06:
cmd = 0xf9; /* tell the controller to send touch data */
offset = 5; /* where the actual touch data starts */
tplen = 4; /* data comes in so called frames */
datalen = 26; /* how much bytes to listen for */
break;
case M09:
cmd = 0x02;
offset = 1;
tplen = 6;
datalen = 29;
break;
default:
goto out;
}
memset(rdbuf, 0, sizeof(rdbuf));
error = edt_ft5x06_ts_readwrite(tsdata->client,
sizeof(cmd), &cmd,
sizeof(rdbuf), rdbuf);
datalen, rdbuf);
if (error) {
dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n",
error);
goto out;
}
if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || rdbuf[2] != 26) {
dev_err_ratelimited(dev, "Unexpected header: %02x%02x%02x!\n",
rdbuf[0], rdbuf[1], rdbuf[2]);
goto out;
/* M09 does not send header or CRC */
if (tsdata->version == M06) {
if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa ||
rdbuf[2] != datalen) {
dev_err_ratelimited(dev,
"Unexpected header: %02x%02x%02x!\n",
rdbuf[0], rdbuf[1], rdbuf[2]);
goto out;
}
if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, datalen))
goto out;
}
if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, 26))
goto out;
for (i = 0; i < MAX_SUPPORT_POINTS; i++) {
u8 *buf = &rdbuf[i * 4 + 5];
u8 *buf = &rdbuf[i * tplen + offset];
bool down;
type = buf[0] >> 6;
@ -170,10 +227,14 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
if (type == TOUCH_EVENT_RESERVED)
continue;
/* M06 sometimes sends bogus coordinates in TOUCH_DOWN */
if (tsdata->version == M06 && type == TOUCH_EVENT_DOWN)
continue;
x = ((buf[0] << 8) | buf[1]) & 0x0fff;
y = ((buf[2] << 8) | buf[3]) & 0x0fff;
id = (buf[2] >> 4) & 0x0f;
down = (type != TOUCH_EVENT_UP);
down = type != TOUCH_EVENT_UP;
input_mt_slot(tsdata->input, id);
input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, down);
@ -197,12 +258,25 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
{
u8 wrbuf[4];
wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
wrbuf[2] = value;
wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
switch (tsdata->version) {
case M06:
wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
wrbuf[2] = value;
wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
return edt_ft5x06_ts_readwrite(tsdata->client, 4,
wrbuf, 0, NULL);
case M09:
wrbuf[0] = addr;
wrbuf[1] = value;
return edt_ft5x06_ts_readwrite(tsdata->client, 4, wrbuf, 0, NULL);
return edt_ft5x06_ts_readwrite(tsdata->client, 3,
wrbuf, 0, NULL);
default:
return -EINVAL;
}
}
static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
@ -211,19 +285,36 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
u8 wrbuf[2], rdbuf[2];
int error;
wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40;
switch (tsdata->version) {
case M06:
wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40;
error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2, rdbuf);
if (error)
return error;
error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2,
rdbuf);
if (error)
return error;
if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) {
dev_err(&tsdata->client->dev,
"crc error: 0x%02x expected, got 0x%02x\n",
wrbuf[0] ^ wrbuf[1] ^ rdbuf[0], rdbuf[1]);
return -EIO;
if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) {
dev_err(&tsdata->client->dev,
"crc error: 0x%02x expected, got 0x%02x\n",
wrbuf[0] ^ wrbuf[1] ^ rdbuf[0],
rdbuf[1]);
return -EIO;
}
break;
case M09:
wrbuf[0] = addr;
error = edt_ft5x06_ts_readwrite(tsdata->client, 1,
wrbuf, 1, rdbuf);
if (error)
return error;
break;
default:
return -EINVAL;
}
return rdbuf[0];
@ -234,19 +325,21 @@ struct edt_ft5x06_attribute {
size_t field_offset;
u8 limit_low;
u8 limit_high;
u8 addr;
u8 addr_m06;
u8 addr_m09;
};
#define EDT_ATTR(_field, _mode, _addr, _limit_low, _limit_high) \
#define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, \
_limit_low, _limit_high) \
struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = { \
.dattr = __ATTR(_field, _mode, \
edt_ft5x06_setting_show, \
edt_ft5x06_setting_store), \
.field_offset = \
offsetof(struct edt_ft5x06_ts_data, _field), \
.field_offset = offsetof(struct edt_ft5x06_ts_data, _field), \
.addr_m06 = _addr_m06, \
.addr_m09 = _addr_m09, \
.limit_low = _limit_low, \
.limit_high = _limit_high, \
.addr = _addr, \
}
static ssize_t edt_ft5x06_setting_show(struct device *dev,
@ -257,10 +350,11 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
struct edt_ft5x06_attribute *attr =
container_of(dattr, struct edt_ft5x06_attribute, dattr);
u8 *field = (u8 *)((char *)tsdata + attr->field_offset);
u8 *field = (u8 *)tsdata + attr->field_offset;
int val;
size_t count = 0;
int error = 0;
u8 addr;
mutex_lock(&tsdata->mutex);
@ -269,15 +363,33 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
goto out;
}
val = edt_ft5x06_register_read(tsdata, attr->addr);
if (val < 0) {
error = val;
dev_err(&tsdata->client->dev,
"Failed to fetch attribute %s, error %d\n",
dattr->attr.name, error);
switch (tsdata->version) {
case M06:
addr = attr->addr_m06;
break;
case M09:
addr = attr->addr_m09;
break;
default:
error = -ENODEV;
goto out;
}
if (addr != NO_REGISTER) {
val = edt_ft5x06_register_read(tsdata, addr);
if (val < 0) {
error = val;
dev_err(&tsdata->client->dev,
"Failed to fetch attribute %s, error %d\n",
dattr->attr.name, error);
goto out;
}
} else {
val = *field;
}
if (val != *field) {
dev_warn(&tsdata->client->dev,
"%s: read (%d) and stored value (%d) differ\n",
@ -299,9 +411,10 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
struct edt_ft5x06_attribute *attr =
container_of(dattr, struct edt_ft5x06_attribute, dattr);
u8 *field = (u8 *)((char *)tsdata + attr->field_offset);
u8 *field = (u8 *)tsdata + attr->field_offset;
unsigned int val;
int error;
u8 addr;
mutex_lock(&tsdata->mutex);
@ -319,14 +432,29 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,
goto out;
}
error = edt_ft5x06_register_write(tsdata, attr->addr, val);
if (error) {
dev_err(&tsdata->client->dev,
"Failed to update attribute %s, error: %d\n",
dattr->attr.name, error);
switch (tsdata->version) {
case M06:
addr = attr->addr_m06;
break;
case M09:
addr = attr->addr_m09;
break;
default:
error = -ENODEV;
goto out;
}
if (addr != NO_REGISTER) {
error = edt_ft5x06_register_write(tsdata, addr, val);
if (error) {
dev_err(&tsdata->client->dev,
"Failed to update attribute %s, error: %d\n",
dattr->attr.name, error);
goto out;
}
}
*field = val;
out:
@ -334,12 +462,14 @@ out:
return error ?: count;
}
static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, 0, 31);
static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, 0, 31);
static EDT_ATTR(threshold, S_IWUSR | S_IRUGO,
WORK_REGISTER_THRESHOLD, 20, 80);
static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO,
WORK_REGISTER_REPORT_RATE, 3, 14);
static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN,
M09_REGISTER_GAIN, 0, 31);
static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET,
M09_REGISTER_OFFSET, 0, 31);
static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD,
M09_REGISTER_THRESHOLD, 20, 80);
static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE,
NO_REGISTER, 3, 14);
static struct attribute *edt_ft5x06_attrs[] = {
&edt_ft5x06_attr_gain.dattr.attr,
@ -374,6 +504,9 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
}
/* mode register is 0x3c when in the work mode */
if (tsdata->version == M09)
goto m09_out;
error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03);
if (error) {
dev_err(&client->dev,
@ -406,12 +539,18 @@ err_out:
enable_irq(client->irq);
return error;
m09_out:
dev_err(&client->dev, "No factory mode support for M09\n");
return -EINVAL;
}
static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)
{
struct i2c_client *client = tsdata->client;
int retries = EDT_SWITCH_MODE_RETRIES;
struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
int ret;
int error;
@ -444,13 +583,14 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)
tsdata->raw_buffer = NULL;
/* restore parameters */
edt_ft5x06_register_write(tsdata, WORK_REGISTER_THRESHOLD,
edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold,
tsdata->threshold);
edt_ft5x06_register_write(tsdata, WORK_REGISTER_GAIN,
edt_ft5x06_register_write(tsdata, reg_addr->reg_gain,
tsdata->gain);
edt_ft5x06_register_write(tsdata, WORK_REGISTER_OFFSET,
edt_ft5x06_register_write(tsdata, reg_addr->reg_offset,
tsdata->offset);
edt_ft5x06_register_write(tsdata, WORK_REGISTER_REPORT_RATE,
if (reg_addr->reg_report_rate)
edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate,
tsdata->report_rate);
enable_irq(client->irq);
@ -479,7 +619,7 @@ static int edt_ft5x06_debugfs_mode_set(void *data, u64 mode)
if (mode != tsdata->factory_mode) {
retval = mode ? edt_ft5x06_factory_mode(tsdata) :
edt_ft5x06_work_mode(tsdata);
edt_ft5x06_work_mode(tsdata);
}
mutex_unlock(&tsdata->mutex);
@ -568,7 +708,6 @@ out:
return error ?: read;
};
static const struct file_operations debugfs_raw_data_fops = {
.open = simple_open,
.read = edt_ft5x06_debugfs_raw_data_read,
@ -614,58 +753,100 @@ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
#endif /* CONFIG_DEBUGFS */
static int edt_ft5x06_ts_reset(struct i2c_client *client,
int reset_pin)
struct edt_ft5x06_ts_data *tsdata)
{
int error;
if (gpio_is_valid(reset_pin)) {
/* this pulls reset down, enabling the low active reset */
error = devm_gpio_request_one(&client->dev, reset_pin,
GPIOF_OUT_INIT_LOW,
"edt-ft5x06 reset");
if (gpio_is_valid(tsdata->wake_pin)) {
error = devm_gpio_request_one(&client->dev,
tsdata->wake_pin, GPIOF_OUT_INIT_LOW,
"edt-ft5x06 wake");
if (error) {
dev_err(&client->dev,
"Failed to request GPIO %d as reset pin, error %d\n",
reset_pin, error);
"Failed to request GPIO %d as wake pin, error %d\n",
tsdata->wake_pin, error);
return error;
}
mdelay(50);
gpio_set_value(reset_pin, 1);
mdelay(100);
msleep(5);
gpio_set_value(tsdata->wake_pin, 1);
}
if (gpio_is_valid(tsdata->reset_pin)) {
/* this pulls reset down, enabling the low active reset */
error = devm_gpio_request_one(&client->dev,
tsdata->reset_pin, GPIOF_OUT_INIT_LOW,
"edt-ft5x06 reset");
if (error) {
dev_err(&client->dev,
"Failed to request GPIO %d as reset pin, error %d\n",
tsdata->reset_pin, error);
return error;
}
msleep(5);
gpio_set_value(tsdata->reset_pin, 1);
msleep(300);
}
return 0;
}
static int edt_ft5x06_ts_identify(struct i2c_client *client,
char *model_name,
char *fw_version)
struct edt_ft5x06_ts_data *tsdata,
char *fw_version)
{
u8 rdbuf[EDT_NAME_LEN];
char *p;
int error;
char *model_name = tsdata->name;
/* see what we find if we assume it is a M06 *
* if we get less than EDT_NAME_LEN, we don't want
* to have garbage in there
*/
memset(rdbuf, 0, sizeof(rdbuf));
error = edt_ft5x06_ts_readwrite(client, 1, "\xbb",
EDT_NAME_LEN - 1, rdbuf);
if (error)
return error;
/* remove last '$' end marker */
rdbuf[EDT_NAME_LEN - 1] = '\0';
if (rdbuf[EDT_NAME_LEN - 2] == '$')
rdbuf[EDT_NAME_LEN - 2] = '\0';
/* if we find something consistent, stay with that assumption
* at least M09 won't send 3 bytes here
*/
if (!(strnicmp(rdbuf + 1, "EP0", 3))) {
tsdata->version = M06;
/* look for Model/Version separator */
p = strchr(rdbuf, '*');
if (p)
*p++ = '\0';
/* remove last '$' end marker */
rdbuf[EDT_NAME_LEN - 1] = '\0';
if (rdbuf[EDT_NAME_LEN - 2] == '$')
rdbuf[EDT_NAME_LEN - 2] = '\0';
strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN);
strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
/* look for Model/Version separator */
p = strchr(rdbuf, '*');
if (p)
*p++ = '\0';
strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN);
strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
} else {
/* since there are only two versions around (M06, M09) */
tsdata->version = M09;
error = edt_ft5x06_ts_readwrite(client, 1, "\xA6",
2, rdbuf);
if (error)
return error;
strlcpy(fw_version, rdbuf, 2);
error = edt_ft5x06_ts_readwrite(client, 1, "\xA8",
1, rdbuf);
if (error)
return error;
snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09",
rdbuf[0] >> 4, rdbuf[0] & 0x0F);
}
return 0;
}
@ -675,33 +856,104 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
pdata->name <= edt_ft5x06_attr_##name.limit_high) \
edt_ft5x06_register_write(tsdata, reg, pdata->name)
#define EDT_GET_PROP(name, reg) { \
u32 val; \
if (of_property_read_u32(np, #name, &val) == 0) \
edt_ft5x06_register_write(tsdata, reg, val); \
}
static void edt_ft5x06_ts_get_dt_defaults(struct device_node *np,
struct edt_ft5x06_ts_data *tsdata)
{
struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
EDT_GET_PROP(threshold, reg_addr->reg_threshold);
EDT_GET_PROP(gain, reg_addr->reg_gain);
EDT_GET_PROP(offset, reg_addr->reg_offset);
}
static void
edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata,
const struct edt_ft5x06_platform_data *pdata)
{
struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
if (!pdata->use_parameters)
return;
/* pick up defaults from the platform data */
EDT_ATTR_CHECKSET(threshold, WORK_REGISTER_THRESHOLD);
EDT_ATTR_CHECKSET(gain, WORK_REGISTER_GAIN);
EDT_ATTR_CHECKSET(offset, WORK_REGISTER_OFFSET);
EDT_ATTR_CHECKSET(report_rate, WORK_REGISTER_REPORT_RATE);
EDT_ATTR_CHECKSET(threshold, reg_addr->reg_threshold);
EDT_ATTR_CHECKSET(gain, reg_addr->reg_gain);
EDT_ATTR_CHECKSET(offset, reg_addr->reg_offset);
if (reg_addr->reg_report_rate != NO_REGISTER)
EDT_ATTR_CHECKSET(report_rate, reg_addr->reg_report_rate);
}
static void
edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
{
struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
tsdata->threshold = edt_ft5x06_register_read(tsdata,
WORK_REGISTER_THRESHOLD);
tsdata->gain = edt_ft5x06_register_read(tsdata, WORK_REGISTER_GAIN);
tsdata->offset = edt_ft5x06_register_read(tsdata, WORK_REGISTER_OFFSET);
tsdata->report_rate = edt_ft5x06_register_read(tsdata,
WORK_REGISTER_REPORT_RATE);
tsdata->num_x = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_X);
tsdata->num_y = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_Y);
reg_addr->reg_threshold);
tsdata->gain = edt_ft5x06_register_read(tsdata, reg_addr->reg_gain);
tsdata->offset = edt_ft5x06_register_read(tsdata, reg_addr->reg_offset);
if (reg_addr->reg_report_rate != NO_REGISTER)
tsdata->report_rate = edt_ft5x06_register_read(tsdata,
reg_addr->reg_report_rate);
tsdata->num_x = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_x);
tsdata->num_y = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_y);
}
static void
edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
{
struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
switch (tsdata->version) {
case M06:
reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD;
reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE;
reg_addr->reg_gain = WORK_REGISTER_GAIN;
reg_addr->reg_offset = WORK_REGISTER_OFFSET;
reg_addr->reg_num_x = WORK_REGISTER_NUM_X;
reg_addr->reg_num_y = WORK_REGISTER_NUM_Y;
break;
case M09:
reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
reg_addr->reg_gain = M09_REGISTER_GAIN;
reg_addr->reg_offset = M09_REGISTER_OFFSET;
reg_addr->reg_num_x = M09_REGISTER_NUM_X;
reg_addr->reg_num_y = M09_REGISTER_NUM_Y;
break;
}
}
#ifdef CONFIG_OF
static int edt_ft5x06_i2c_ts_probe_dt(struct device *dev,
struct edt_ft5x06_ts_data *tsdata)
{
struct device_node *np = dev->of_node;
/*
* irq_pin is not needed for DT setup.
* irq is associated via 'interrupts' property in DT
*/
tsdata->irq_pin = -EINVAL;
tsdata->reset_pin = of_get_named_gpio(np, "reset-gpios", 0);
tsdata->wake_pin = of_get_named_gpio(np, "wake-gpios", 0);
return 0;
}
#else
static inline int edt_ft5x06_i2c_ts_probe_dt(struct device *dev,
struct edt_ft5x06_ts_data *tsdata)
{
return -ENODEV;
}
#endif
static int edt_ft5x06_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@ -714,32 +966,40 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n");
if (!pdata) {
dev_err(&client->dev, "no platform data?\n");
return -EINVAL;
}
error = edt_ft5x06_ts_reset(client, pdata->reset_pin);
if (error)
return error;
if (gpio_is_valid(pdata->irq_pin)) {
error = devm_gpio_request_one(&client->dev, pdata->irq_pin,
GPIOF_IN, "edt-ft5x06 irq");
if (error) {
dev_err(&client->dev,
"Failed to request GPIO %d, error %d\n",
pdata->irq_pin, error);
return error;
}
}
tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL);
if (!tsdata) {
dev_err(&client->dev, "failed to allocate driver data.\n");
return -ENOMEM;
}
if (!pdata) {
error = edt_ft5x06_i2c_ts_probe_dt(&client->dev, tsdata);
if (error) {
dev_err(&client->dev,
"DT probe failed and no platform data present\n");
return error;
}
} else {
tsdata->reset_pin = pdata->reset_pin;
tsdata->irq_pin = pdata->irq_pin;
tsdata->wake_pin = -EINVAL;
}
error = edt_ft5x06_ts_reset(client, tsdata);
if (error)
return error;
if (gpio_is_valid(tsdata->irq_pin)) {
error = devm_gpio_request_one(&client->dev, tsdata->irq_pin,
GPIOF_IN, "edt-ft5x06 irq");
if (error) {
dev_err(&client->dev,
"Failed to request GPIO %d, error %d\n",
tsdata->irq_pin, error);
return error;
}
}
input = devm_input_allocate_device(&client->dev);
if (!input) {
dev_err(&client->dev, "failed to allocate input device.\n");
@ -751,13 +1011,19 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
tsdata->input = input;
tsdata->factory_mode = false;
error = edt_ft5x06_ts_identify(client, tsdata->name, fw_version);
error = edt_ft5x06_ts_identify(client, tsdata, fw_version);
if (error) {
dev_err(&client->dev, "touchscreen probe failed\n");
return error;
}
edt_ft5x06_ts_get_defaults(tsdata, pdata);
edt_ft5x06_ts_set_regs(tsdata);
if (!pdata)
edt_ft5x06_ts_get_dt_defaults(client->dev.of_node, tsdata);
else
edt_ft5x06_ts_get_defaults(tsdata, pdata);
edt_ft5x06_ts_get_parameters(tsdata);
dev_dbg(&client->dev,
@ -787,10 +1053,10 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
input_set_drvdata(input, tsdata);
i2c_set_clientdata(client, tsdata);
error = devm_request_threaded_irq(&client->dev, client->irq,
NULL, edt_ft5x06_ts_isr,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->name, tsdata);
error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
edt_ft5x06_ts_isr,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->name, tsdata);
if (error) {
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
return error;
@ -801,19 +1067,21 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
return error;
error = input_register_device(input);
if (error) {
sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
return error;
}
if (error)
goto err_remove_attrs;
edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
device_init_wakeup(&client->dev, 1);
dev_dbg(&client->dev,
"EDT FT5x06 initialized: IRQ pin %d, Reset pin %d.\n",
pdata->irq_pin, pdata->reset_pin);
"EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n",
client->irq, tsdata->wake_pin, tsdata->reset_pin);
return 0;
err_remove_attrs:
sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
return error;
}
static int edt_ft5x06_ts_remove(struct i2c_client *client)
@ -852,15 +1120,26 @@ static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops,
edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume);
static const struct i2c_device_id edt_ft5x06_ts_id[] = {
{ "edt-ft5x06", 0 },
{ }
{ "edt-ft5x06", 0, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id);
#ifdef CONFIG_OF
static const struct of_device_id edt_ft5x06_of_match[] = {
{ .compatible = "edt,edt-ft5206", },
{ .compatible = "edt,edt-ft5306", },
{ .compatible = "edt,edt-ft5406", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match);
#endif
static struct i2c_driver edt_ft5x06_ts_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "edt_ft5x06",
.of_match_table = of_match_ptr(edt_ft5x06_of_match),
.pm = &edt_ft5x06_ts_pm_ops,
},
.id_table = edt_ft5x06_ts_id,

View file

@ -197,7 +197,7 @@ static void titsc_step_config(struct titsc *ts_dev)
/* The steps1 … end and bit 0 for TS_Charge */
stepenable = (1 << (end_step + 2)) - 1;
ts_dev->step_mask = stepenable;
am335x_tsc_se_set(ts_dev->mfd_tscadc, ts_dev->step_mask);
am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask);
}
static void titsc_read_coordinates(struct titsc *ts_dev,
@ -321,7 +321,7 @@ static irqreturn_t titsc_irq(int irq, void *dev)
if (irqclr) {
titsc_writel(ts_dev, REG_IRQSTATUS, irqclr);
am335x_tsc_se_set(ts_dev->mfd_tscadc, ts_dev->step_mask);
am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask);
return IRQ_HANDLED;
}
return IRQ_NONE;

View file

@ -1,384 +0,0 @@
/*
* Texas Instruments TNETV107X Touchscreen Driver
*
* Copyright (C) 2010 Texas Instruments
*
* 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.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <mach/tnetv107x.h>
#define TSC_PENUP_POLL (HZ / 5)
#define IDLE_TIMEOUT 100 /* msec */
/*
* The first and last samples of a touch interval are usually garbage and need
* to be filtered out with these devices. The following definitions control
* the number of samples skipped.
*/
#define TSC_HEAD_SKIP 1
#define TSC_TAIL_SKIP 1
#define TSC_SKIP (TSC_HEAD_SKIP + TSC_TAIL_SKIP + 1)
#define TSC_SAMPLES (TSC_SKIP + 1)
/* Register Offsets */
struct tsc_regs {
u32 rev;
u32 tscm;
u32 bwcm;
u32 swc;
u32 adcchnl;
u32 adcdata;
u32 chval[4];
};
/* TSC Mode Configuration Register (tscm) bits */
#define WMODE BIT(0)
#define TSKIND BIT(1)
#define ZMEASURE_EN BIT(2)
#define IDLE BIT(3)
#define TSC_EN BIT(4)
#define STOP BIT(5)
#define ONE_SHOT BIT(6)
#define SINGLE BIT(7)
#define AVG BIT(8)
#define AVGNUM(x) (((x) & 0x03) << 9)
#define PVSTC(x) (((x) & 0x07) << 11)
#define PON BIT(14)
#define PONBG BIT(15)
#define AFERST BIT(16)
/* ADC DATA Capture Register bits */
#define DATA_VALID BIT(16)
/* Register Access Macros */
#define tsc_read(ts, reg) __raw_readl(&(ts)->regs->reg)
#define tsc_write(ts, reg, val) __raw_writel(val, &(ts)->regs->reg);
#define tsc_set_bits(ts, reg, val) \
tsc_write(ts, reg, tsc_read(ts, reg) | (val))
#define tsc_clr_bits(ts, reg, val) \
tsc_write(ts, reg, tsc_read(ts, reg) & ~(val))
struct sample {
int x, y, p;
};
struct tsc_data {
struct input_dev *input_dev;
struct resource *res;
struct tsc_regs __iomem *regs;
struct timer_list timer;
spinlock_t lock;
struct clk *clk;
struct device *dev;
int sample_count;
struct sample samples[TSC_SAMPLES];
int tsc_irq;
};
static int tsc_read_sample(struct tsc_data *ts, struct sample* sample)
{
int x, y, z1, z2, t, p = 0;
u32 val;
val = tsc_read(ts, chval[0]);
if (val & DATA_VALID)
x = val & 0xffff;
else
return -EINVAL;
y = tsc_read(ts, chval[1]) & 0xffff;
z1 = tsc_read(ts, chval[2]) & 0xffff;
z2 = tsc_read(ts, chval[3]) & 0xffff;
if (z1) {
t = ((600 * x) * (z2 - z1));
p = t / (u32) (z1 << 12);
if (p < 0)
p = 0;
}
sample->x = x;
sample->y = y;
sample->p = p;
return 0;
}
static void tsc_poll(unsigned long data)
{
struct tsc_data *ts = (struct tsc_data *)data;
unsigned long flags;
int i, val, x, y, p;
spin_lock_irqsave(&ts->lock, flags);
if (ts->sample_count >= TSC_SKIP) {
input_report_abs(ts->input_dev, ABS_PRESSURE, 0);
input_report_key(ts->input_dev, BTN_TOUCH, 0);
input_sync(ts->input_dev);
} else if (ts->sample_count > 0) {
/*
* A touch event lasted less than our skip count. Salvage and
* report anyway.
*/
for (i = 0, val = 0; i < ts->sample_count; i++)
val += ts->samples[i].x;
x = val / ts->sample_count;
for (i = 0, val = 0; i < ts->sample_count; i++)
val += ts->samples[i].y;
y = val / ts->sample_count;
for (i = 0, val = 0; i < ts->sample_count; i++)
val += ts->samples[i].p;
p = val / ts->sample_count;
input_report_abs(ts->input_dev, ABS_X, x);
input_report_abs(ts->input_dev, ABS_Y, y);
input_report_abs(ts->input_dev, ABS_PRESSURE, p);
input_report_key(ts->input_dev, BTN_TOUCH, 1);
input_sync(ts->input_dev);
}
ts->sample_count = 0;
spin_unlock_irqrestore(&ts->lock, flags);
}
static irqreturn_t tsc_irq(int irq, void *dev_id)
{
struct tsc_data *ts = (struct tsc_data *)dev_id;
struct sample *sample;
int index;
spin_lock(&ts->lock);
index = ts->sample_count % TSC_SAMPLES;
sample = &ts->samples[index];
if (tsc_read_sample(ts, sample) < 0)
goto out;
if (++ts->sample_count >= TSC_SKIP) {
index = (ts->sample_count - TSC_TAIL_SKIP - 1) % TSC_SAMPLES;
sample = &ts->samples[index];
input_report_abs(ts->input_dev, ABS_X, sample->x);
input_report_abs(ts->input_dev, ABS_Y, sample->y);
input_report_abs(ts->input_dev, ABS_PRESSURE, sample->p);
if (ts->sample_count == TSC_SKIP)
input_report_key(ts->input_dev, BTN_TOUCH, 1);
input_sync(ts->input_dev);
}
mod_timer(&ts->timer, jiffies + TSC_PENUP_POLL);
out:
spin_unlock(&ts->lock);
return IRQ_HANDLED;
}
static int tsc_start(struct input_dev *dev)
{
struct tsc_data *ts = input_get_drvdata(dev);
unsigned long timeout = jiffies + msecs_to_jiffies(IDLE_TIMEOUT);
u32 val;
clk_enable(ts->clk);
/* Go to idle mode, before any initialization */
while (time_after(timeout, jiffies)) {
if (tsc_read(ts, tscm) & IDLE)
break;
}
if (time_before(timeout, jiffies)) {
dev_warn(ts->dev, "timeout waiting for idle\n");
clk_disable(ts->clk);
return -EIO;
}
/* Configure TSC Control register*/
val = (PONBG | PON | PVSTC(4) | ONE_SHOT | ZMEASURE_EN);
tsc_write(ts, tscm, val);
/* Bring TSC out of reset: Clear AFE reset bit */
val &= ~(AFERST);
tsc_write(ts, tscm, val);
/* Configure all pins for hardware control*/
tsc_write(ts, bwcm, 0);
/* Finally enable the TSC */
tsc_set_bits(ts, tscm, TSC_EN);
return 0;
}
static void tsc_stop(struct input_dev *dev)
{
struct tsc_data *ts = input_get_drvdata(dev);
tsc_clr_bits(ts, tscm, TSC_EN);
synchronize_irq(ts->tsc_irq);
del_timer_sync(&ts->timer);
clk_disable(ts->clk);
}
static int tsc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct tsc_data *ts;
int error = 0;
u32 rev = 0;
ts = kzalloc(sizeof(struct tsc_data), GFP_KERNEL);
if (!ts) {
dev_err(dev, "cannot allocate device info\n");
return -ENOMEM;
}
ts->dev = dev;
spin_lock_init(&ts->lock);
setup_timer(&ts->timer, tsc_poll, (unsigned long)ts);
platform_set_drvdata(pdev, ts);
ts->tsc_irq = platform_get_irq(pdev, 0);
if (ts->tsc_irq < 0) {
dev_err(dev, "cannot determine device interrupt\n");
error = -ENODEV;
goto error_res;
}
ts->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!ts->res) {
dev_err(dev, "cannot determine register area\n");
error = -ENODEV;
goto error_res;
}
if (!request_mem_region(ts->res->start, resource_size(ts->res),
pdev->name)) {
dev_err(dev, "cannot claim register memory\n");
ts->res = NULL;
error = -EINVAL;
goto error_res;
}
ts->regs = ioremap(ts->res->start, resource_size(ts->res));
if (!ts->regs) {
dev_err(dev, "cannot map register memory\n");
error = -ENOMEM;
goto error_map;
}
ts->clk = clk_get(dev, NULL);
if (IS_ERR(ts->clk)) {
dev_err(dev, "cannot claim device clock\n");
error = PTR_ERR(ts->clk);
goto error_clk;
}
error = request_threaded_irq(ts->tsc_irq, NULL, tsc_irq, IRQF_ONESHOT,
dev_name(dev), ts);
if (error < 0) {
dev_err(ts->dev, "Could not allocate ts irq\n");
goto error_irq;
}
ts->input_dev = input_allocate_device();
if (!ts->input_dev) {
dev_err(dev, "cannot allocate input device\n");
error = -ENOMEM;
goto error_input;
}
input_set_drvdata(ts->input_dev, ts);
ts->input_dev->name = pdev->name;
ts->input_dev->id.bustype = BUS_HOST;
ts->input_dev->dev.parent = &pdev->dev;
ts->input_dev->open = tsc_start;
ts->input_dev->close = tsc_stop;
clk_enable(ts->clk);
rev = tsc_read(ts, rev);
ts->input_dev->id.product = ((rev >> 8) & 0x07);
ts->input_dev->id.version = ((rev >> 16) & 0xfff);
clk_disable(ts->clk);
__set_bit(EV_KEY, ts->input_dev->evbit);
__set_bit(EV_ABS, ts->input_dev->evbit);
__set_bit(BTN_TOUCH, ts->input_dev->keybit);
input_set_abs_params(ts->input_dev, ABS_X, 0, 0xffff, 5, 0);
input_set_abs_params(ts->input_dev, ABS_Y, 0, 0xffff, 5, 0);
input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 4095, 128, 0);
error = input_register_device(ts->input_dev);
if (error < 0) {
dev_err(dev, "failed input device registration\n");
goto error_reg;
}
return 0;
error_reg:
input_free_device(ts->input_dev);
error_input:
free_irq(ts->tsc_irq, ts);
error_irq:
clk_put(ts->clk);
error_clk:
iounmap(ts->regs);
error_map:
release_mem_region(ts->res->start, resource_size(ts->res));
error_res:
kfree(ts);
return error;
}
static int tsc_remove(struct platform_device *pdev)
{
struct tsc_data *ts = platform_get_drvdata(pdev);
input_unregister_device(ts->input_dev);
free_irq(ts->tsc_irq, ts);
clk_put(ts->clk);
iounmap(ts->regs);
release_mem_region(ts->res->start, resource_size(ts->res));
kfree(ts);
return 0;
}
static struct platform_driver tsc_driver = {
.probe = tsc_probe,
.remove = tsc_remove,
.driver.name = "tnetv107x-ts",
.driver.owner = THIS_MODULE,
};
module_platform_driver(tsc_driver);
MODULE_AUTHOR("Cyril Chemparathy");
MODULE_DESCRIPTION("TNETV107X Touchscreen Driver");
MODULE_ALIAS("platform:tnetv107x-ts");
MODULE_LICENSE("GPL");

View file

@ -29,10 +29,13 @@
#include <linux/sysfs.h>
#include <linux/input/mt.h>
#include <linux/platform_data/zforce_ts.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#define WAIT_TIMEOUT msecs_to_jiffies(1000)
#define FRAME_START 0xee
#define FRAME_MAXSIZE 257
/* Offsets of the different parts of the payload the controller sends */
#define PAYLOAD_HEADER 0
@ -64,7 +67,7 @@
#define RESPONSE_STATUS 0X1e
/*
* Notifications are send by the touch controller without
* Notifications are sent by the touch controller without
* being requested by the driver and include for example
* touch indications
*/
@ -103,8 +106,8 @@ struct zforce_point {
* @suspended device suspended
* @access_mutex serialize i2c-access, to keep multipart reads together
* @command_done completion to wait for the command result
* @command_mutex serialize commands send to the ic
* @command_waiting the id of the command that that is currently waiting
* @command_mutex serialize commands sent to the ic
* @command_waiting the id of the command that is currently waiting
* for a result
* @command_result returned result of the command
*/
@ -235,7 +238,8 @@ static int zforce_scan_frequency(struct zforce_ts *ts, u16 idle, u16 finger,
(finger & 0xff), ((finger >> 8) & 0xff),
(stylus & 0xff), ((stylus >> 8) & 0xff) };
dev_dbg(&client->dev, "set scan frequency to (idle: %d, finger: %d, stylus: %d)\n",
dev_dbg(&client->dev,
"set scan frequency to (idle: %d, finger: %d, stylus: %d)\n",
idle, finger, stylus);
return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf));
@ -255,7 +259,7 @@ static int zforce_setconfig(struct zforce_ts *ts, char b1)
static int zforce_start(struct zforce_ts *ts)
{
struct i2c_client *client = ts->client;
const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev);
const struct zforce_ts_platdata *pdata = ts->pdata;
int ret;
dev_dbg(&client->dev, "starting device\n");
@ -326,13 +330,14 @@ static int zforce_stop(struct zforce_ts *ts)
static int zforce_touch_event(struct zforce_ts *ts, u8 *payload)
{
struct i2c_client *client = ts->client;
const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev);
const struct zforce_ts_platdata *pdata = ts->pdata;
struct zforce_point point;
int count, i, num = 0;
count = payload[0];
if (count > ZFORCE_REPORT_POINTS) {
dev_warn(&client->dev, "to many coordinates %d, expected max %d\n",
dev_warn(&client->dev,
"too many coordinates %d, expected max %d\n",
count, ZFORCE_REPORT_POINTS);
count = ZFORCE_REPORT_POINTS;
}
@ -421,7 +426,7 @@ static int zforce_read_packet(struct zforce_ts *ts, u8 *buf)
goto unlock;
}
if (buf[PAYLOAD_LENGTH] <= 0 || buf[PAYLOAD_LENGTH] > 255) {
if (buf[PAYLOAD_LENGTH] == 0) {
dev_err(&client->dev, "invalid payload length: %d\n",
buf[PAYLOAD_LENGTH]);
ret = -EIO;
@ -471,9 +476,9 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
{
struct zforce_ts *ts = dev_id;
struct i2c_client *client = ts->client;
const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev);
const struct zforce_ts_platdata *pdata = ts->pdata;
int ret;
u8 payload_buffer[512];
u8 payload_buffer[FRAME_MAXSIZE];
u8 *payload;
/*
@ -494,8 +499,8 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
while (!gpio_get_value(pdata->gpio_int)) {
ret = zforce_read_packet(ts, payload_buffer);
if (ret < 0) {
dev_err(&client->dev, "could not read packet, ret: %d\n",
ret);
dev_err(&client->dev,
"could not read packet, ret: %d\n", ret);
break;
}
@ -539,7 +544,8 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
payload[RESPONSE_DATA + 4];
ts->version_rev = (payload[RESPONSE_DATA + 7] << 8) |
payload[RESPONSE_DATA + 6];
dev_dbg(&ts->client->dev, "Firmware Version %04x:%04x %04x:%04x\n",
dev_dbg(&ts->client->dev,
"Firmware Version %04x:%04x %04x:%04x\n",
ts->version_major, ts->version_minor,
ts->version_build, ts->version_rev);
@ -552,7 +558,8 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
break;
default:
dev_err(&ts->client->dev, "unrecognized response id: 0x%x\n",
dev_err(&ts->client->dev,
"unrecognized response id: 0x%x\n",
payload[RESPONSE_ID]);
break;
}
@ -618,7 +625,8 @@ static int zforce_suspend(struct device *dev)
enable_irq_wake(client->irq);
} else if (input->users) {
dev_dbg(&client->dev, "suspend without being a wakeup source\n");
dev_dbg(&client->dev,
"suspend without being a wakeup source\n");
ret = zforce_stop(ts);
if (ret)
@ -684,6 +692,45 @@ static void zforce_reset(void *data)
gpio_set_value(ts->pdata->gpio_rst, 0);
}
static struct zforce_ts_platdata *zforce_parse_dt(struct device *dev)
{
struct zforce_ts_platdata *pdata;
struct device_node *np = dev->of_node;
if (!np)
return ERR_PTR(-ENOENT);
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
dev_err(dev, "failed to allocate platform data\n");
return ERR_PTR(-ENOMEM);
}
pdata->gpio_int = of_get_gpio(np, 0);
if (!gpio_is_valid(pdata->gpio_int)) {
dev_err(dev, "failed to get interrupt gpio\n");
return ERR_PTR(-EINVAL);
}
pdata->gpio_rst = of_get_gpio(np, 1);
if (!gpio_is_valid(pdata->gpio_rst)) {
dev_err(dev, "failed to get reset gpio\n");
return ERR_PTR(-EINVAL);
}
if (of_property_read_u32(np, "x-size", &pdata->x_max)) {
dev_err(dev, "failed to get x-size property\n");
return ERR_PTR(-EINVAL);
}
if (of_property_read_u32(np, "y-size", &pdata->y_max)) {
dev_err(dev, "failed to get y-size property\n");
return ERR_PTR(-EINVAL);
}
return pdata;
}
static int zforce_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@ -692,8 +739,11 @@ static int zforce_probe(struct i2c_client *client,
struct input_dev *input_dev;
int ret;
if (!pdata)
return -EINVAL;
if (!pdata) {
pdata = zforce_parse_dt(&client->dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
}
ts = devm_kzalloc(&client->dev, sizeof(struct zforce_ts), GFP_KERNEL);
if (!ts)
@ -798,7 +848,7 @@ static int zforce_probe(struct i2c_client *client,
return ret;
}
/* this gets the firmware version among other informations */
/* this gets the firmware version among other information */
ret = zforce_command_wait(ts, COMMAND_STATUS);
if (ret < 0) {
dev_err(&client->dev, "couldn't get status, %d\n", ret);
@ -829,11 +879,20 @@ static struct i2c_device_id zforce_idtable[] = {
};
MODULE_DEVICE_TABLE(i2c, zforce_idtable);
#ifdef CONFIG_OF
static struct of_device_id zforce_dt_idtable[] = {
{ .compatible = "neonode,zforce" },
{},
};
MODULE_DEVICE_TABLE(of, zforce_dt_idtable);
#endif
static struct i2c_driver zforce_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "zforce-ts",
.pm = &zforce_pm_ops,
.of_match_table = of_match_ptr(zforce_dt_idtable),
},
.probe = zforce_probe,
.id_table = zforce_idtable,