aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/joystick/analog.c6
-rw-r--r--drivers/input/joystick/xpad.c7
-rw-r--r--drivers/input/keyboard/adp5588-keys.c10
-rw-r--r--drivers/input/keyboard/adp5589-keys.c12
-rw-r--r--drivers/input/keyboard/clps711x-keypad.c4
-rw-r--r--drivers/input/keyboard/gpio_keys.c190
-rw-r--r--drivers/input/keyboard/gpio_keys_polled.c128
-rw-r--r--drivers/input/keyboard/lpc32xx-keys.c2
-rw-r--r--drivers/input/keyboard/pxa27x_keypad.c2
-rw-r--r--drivers/input/keyboard/tca8418_keypad.c21
-rw-r--r--drivers/input/misc/Kconfig7
-rw-r--r--drivers/input/misc/bma150.c9
-rw-r--r--drivers/input/misc/da9063_onkey.c9
-rw-r--r--drivers/input/misc/drv260x.c119
-rw-r--r--drivers/input/misc/drv2665.c6
-rw-r--r--drivers/input/misc/drv2667.c4
-rw-r--r--drivers/input/misc/max77693-haptic.c17
-rw-r--r--drivers/input/misc/max8997_haptic.c6
-rw-r--r--drivers/input/misc/pwm-beeper.c6
-rw-r--r--drivers/input/misc/soc_button_array.c8
-rw-r--r--drivers/input/mouse/alps.c56
-rw-r--r--drivers/input/mouse/alps.h24
-rw-r--r--drivers/input/mouse/elan_i2c_core.c17
-rw-r--r--drivers/input/rmi4/Kconfig53
-rw-r--r--drivers/input/rmi4/Makefile5
-rw-r--r--drivers/input/rmi4/rmi_2d_sensor.c10
-rw-r--r--drivers/input/rmi4/rmi_2d_sensor.h2
-rw-r--r--drivers/input/rmi4/rmi_bus.c15
-rw-r--r--drivers/input/rmi4/rmi_bus.h12
-rw-r--r--drivers/input/rmi4/rmi_driver.c420
-rw-r--r--drivers/input/rmi4/rmi_driver.h32
-rw-r--r--drivers/input/rmi4/rmi_f01.c12
-rw-r--r--drivers/input/rmi4/rmi_f03.c250
-rw-r--r--drivers/input/rmi4/rmi_f11.c98
-rw-r--r--drivers/input/rmi4/rmi_f12.c146
-rw-r--r--drivers/input/rmi4/rmi_f30.c22
-rw-r--r--drivers/input/rmi4/rmi_f34.c516
-rw-r--r--drivers/input/rmi4/rmi_f34.h314
-rw-r--r--drivers/input/rmi4/rmi_f34v7.c1372
-rw-r--r--drivers/input/rmi4/rmi_f54.c764
-rw-r--r--drivers/input/rmi4/rmi_f55.c131
-rw-r--r--drivers/input/rmi4/rmi_i2c.c74
-rw-r--r--drivers/input/rmi4/rmi_smbus.c447
-rw-r--r--drivers/input/rmi4/rmi_spi.c72
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h78
-rw-r--r--drivers/input/serio/i8042.c2
-rw-r--r--drivers/input/touchscreen/Kconfig9
-rw-r--r--drivers/input/touchscreen/ad7879.c10
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c521
-rw-r--r--drivers/input/touchscreen/cyttsp4_core.c2
-rw-r--r--drivers/input/touchscreen/fsl-imx25-tcq.c1
-rw-r--r--drivers/input/touchscreen/imx6ul_tsc.c83
-rw-r--r--drivers/input/touchscreen/melfas_mip4.c51
-rw-r--r--drivers/input/touchscreen/raydium_i2c_ts.c2
-rw-r--r--drivers/input/touchscreen/silead.c29
-rw-r--r--drivers/input/touchscreen/sun4i-ts.c9
-rw-r--r--drivers/input/touchscreen/sur40.c159
57 files changed, 5607 insertions, 786 deletions
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 6f8b084e13d0..3d8ff09eba57 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -143,9 +143,9 @@ struct analog_port {
#include <linux/i8253.h>
-#define GET_TIME(x) do { if (cpu_has_tsc) x = (unsigned int)rdtsc(); else x = get_time_pit(); } while (0)
-#define DELTA(x,y) (cpu_has_tsc ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? PIT_TICK_RATE / HZ : 0)))
-#define TIME_NAME (cpu_has_tsc?"TSC":"PIT")
+#define GET_TIME(x) do { if (boot_cpu_has(X86_FEATURE_TSC)) x = (unsigned int)rdtsc(); else x = get_time_pit(); } while (0)
+#define DELTA(x,y) (boot_cpu_has(X86_FEATURE_TSC) ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? PIT_TICK_RATE / HZ : 0)))
+#define TIME_NAME (boot_cpu_has(X86_FEATURE_TSC)?"TSC":"PIT")
static unsigned int get_time_pit(void)
{
unsigned long flags;
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 83af17ad0f1f..6d9499658671 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -134,6 +134,7 @@ static const struct xpad_device {
{ 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
{ 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE },
{ 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", 0, XTYPE_XBOXONE },
+ { 0x045e, 0x02ea, "Microsoft X-Box One S pad", 0, XTYPE_XBOXONE },
{ 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
@@ -1044,9 +1045,9 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
packet->data[7] = 0x00;
packet->data[8] = strong / 512; /* left actuator */
packet->data[9] = weak / 512; /* right actuator */
- packet->data[10] = 0xFF;
- packet->data[11] = 0x00;
- packet->data[12] = 0x00;
+ packet->data[10] = 0xFF; /* on period */
+ packet->data[11] = 0x00; /* off period */
+ packet->data[12] = 0xFF; /* repeat count */
packet->len = 13;
packet->pending = true;
break;
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index 21a62d0fa764..53fe9a3fb620 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -73,7 +73,7 @@ static int adp5588_write(struct i2c_client *client, u8 reg, u8 val)
#ifdef CONFIG_GPIOLIB
static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
{
- struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+ struct adp5588_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
int val;
@@ -93,7 +93,7 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
static void adp5588_gpio_set_value(struct gpio_chip *chip,
unsigned off, int val)
{
- struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+ struct adp5588_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
@@ -112,7 +112,7 @@ static void adp5588_gpio_set_value(struct gpio_chip *chip,
static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off)
{
- struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+ struct adp5588_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
int ret;
@@ -130,7 +130,7 @@ static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off)
static int adp5588_gpio_direction_output(struct gpio_chip *chip,
unsigned off, int val)
{
- struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+ struct adp5588_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
int ret;
@@ -210,7 +210,7 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad)
mutex_init(&kpad->gpio_lock);
- error = gpiochip_add(&kpad->gc);
+ error = gpiochip_add_data(&kpad->gc, kpad);
if (error) {
dev_err(dev, "gpiochip_add failed, err: %d\n", error);
return error;
diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c
index c01a1d648f9f..32d94c63dc33 100644
--- a/drivers/input/keyboard/adp5589-keys.c
+++ b/drivers/input/keyboard/adp5589-keys.c
@@ -387,7 +387,7 @@ static int adp5589_write(struct i2c_client *client, u8 reg, u8 val)
#ifdef CONFIG_GPIOLIB
static int adp5589_gpio_get_value(struct gpio_chip *chip, unsigned off)
{
- struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+ struct adp5589_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
@@ -399,7 +399,7 @@ static int adp5589_gpio_get_value(struct gpio_chip *chip, unsigned off)
static void adp5589_gpio_set_value(struct gpio_chip *chip,
unsigned off, int val)
{
- struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+ struct adp5589_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
@@ -418,7 +418,7 @@ static void adp5589_gpio_set_value(struct gpio_chip *chip,
static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off)
{
- struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+ struct adp5589_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
int ret;
@@ -438,7 +438,7 @@ static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off)
static int adp5589_gpio_direction_output(struct gpio_chip *chip,
unsigned off, int val)
{
- struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+ struct adp5589_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
int ret;
@@ -525,9 +525,9 @@ static int adp5589_gpio_add(struct adp5589_kpad *kpad)
mutex_init(&kpad->gpio_lock);
- error = gpiochip_add(&kpad->gc);
+ error = gpiochip_add_data(&kpad->gc, kpad);
if (error) {
- dev_err(dev, "gpiochip_add failed, err: %d\n", error);
+ dev_err(dev, "gpiochip_add_data() failed, err: %d\n", error);
return error;
}
diff --git a/drivers/input/keyboard/clps711x-keypad.c b/drivers/input/keyboard/clps711x-keypad.c
index b637f1af842e..997e3e97f573 100644
--- a/drivers/input/keyboard/clps711x-keypad.c
+++ b/drivers/input/keyboard/clps711x-keypad.c
@@ -101,7 +101,7 @@ static int clps711x_keypad_probe(struct platform_device *pdev)
return -ENOMEM;
priv->syscon =
- syscon_regmap_lookup_by_compatible("cirrus,clps711x-syscon1");
+ syscon_regmap_lookup_by_compatible("cirrus,ep7209-syscon1");
if (IS_ERR(priv->syscon))
return PTR_ERR(priv->syscon);
@@ -181,7 +181,7 @@ static int clps711x_keypad_remove(struct platform_device *pdev)
}
static const struct of_device_id clps711x_keypad_of_match[] = {
- { .compatible = "cirrus,clps711x-keypad", },
+ { .compatible = "cirrus,ep7209-keypad", },
{ }
};
MODULE_DEVICE_TABLE(of, clps711x_keypad_of_match);
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 29093657f2ef..582462d0af75 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -26,15 +26,15 @@
#include <linux/gpio_keys.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/spinlock.h>
struct gpio_button_data {
const struct gpio_keys_button *button;
struct input_dev *input;
+ struct gpio_desc *gpiod;
struct timer_list release_timer;
unsigned int release_delay; /* in msecs, for IRQ-only buttons */
@@ -140,7 +140,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata)
*/
disable_irq(bdata->irq);
- if (gpio_is_valid(bdata->button->gpio))
+ if (bdata->gpiod)
cancel_delayed_work_sync(&bdata->work);
else
del_timer_sync(&bdata->release_timer);
@@ -358,19 +358,20 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
const struct gpio_keys_button *button = bdata->button;
struct input_dev *input = bdata->input;
unsigned int type = button->type ?: EV_KEY;
- int state = gpio_get_value_cansleep(button->gpio);
+ int state;
+ state = gpiod_get_value_cansleep(bdata->gpiod);
if (state < 0) {
- dev_err(input->dev.parent, "failed to get gpio state\n");
+ dev_err(input->dev.parent,
+ "failed to get gpio state: %d\n", state);
return;
}
- state = (state ? 1 : 0) ^ button->active_low;
if (type == EV_ABS) {
if (state)
input_event(input, type, button->code, button->value);
} else {
- input_event(input, type, button->code, !!state);
+ input_event(input, type, button->code, state);
}
input_sync(input);
}
@@ -456,7 +457,7 @@ static void gpio_keys_quiesce_key(void *data)
{
struct gpio_button_data *bdata = data;
- if (gpio_is_valid(bdata->button->gpio))
+ if (bdata->gpiod)
cancel_delayed_work_sync(&bdata->work);
else
del_timer_sync(&bdata->release_timer);
@@ -465,7 +466,8 @@ static void gpio_keys_quiesce_key(void *data)
static int gpio_keys_setup_key(struct platform_device *pdev,
struct input_dev *input,
struct gpio_button_data *bdata,
- const struct gpio_keys_button *button)
+ const struct gpio_keys_button *button,
+ struct fwnode_handle *child)
{
const char *desc = button->desc ? button->desc : "gpio_keys";
struct device *dev = &pdev->dev;
@@ -478,18 +480,56 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
bdata->button = button;
spin_lock_init(&bdata->lock);
- if (gpio_is_valid(button->gpio)) {
+ if (child) {
+ bdata->gpiod = devm_get_gpiod_from_child(dev, NULL, child);
+ if (IS_ERR(bdata->gpiod)) {
+ error = PTR_ERR(bdata->gpiod);
+ if (error == -ENOENT) {
+ /*
+ * GPIO is optional, we may be dealing with
+ * purely interrupt-driven setup.
+ */
+ bdata->gpiod = NULL;
+ } else {
+ if (error != -EPROBE_DEFER)
+ dev_err(dev, "failed to get gpio: %d\n",
+ error);
+ return error;
+ }
+ } else {
+ error = gpiod_direction_input(bdata->gpiod);
+ if (error) {
+ dev_err(dev, "Failed to configure GPIO %d as input: %d\n",
+ desc_to_gpio(bdata->gpiod), error);
+ return error;
+ }
+ }
+ } else if (gpio_is_valid(button->gpio)) {
+ /*
+ * Legacy GPIO number, so request the GPIO here and
+ * convert it to descriptor.
+ */
+ unsigned flags = GPIOF_IN;
+
+ if (button->active_low)
+ flags |= GPIOF_ACTIVE_LOW;
- error = devm_gpio_request_one(&pdev->dev, button->gpio,
- GPIOF_IN, desc);
+ error = devm_gpio_request_one(&pdev->dev, button->gpio, flags,
+ desc);
if (error < 0) {
dev_err(dev, "Failed to request GPIO %d, error %d\n",
button->gpio, error);
return error;
}
+ bdata->gpiod = gpio_to_desc(button->gpio);
+ if (!bdata->gpiod)
+ return -EINVAL;
+ }
+
+ if (bdata->gpiod) {
if (button->debounce_interval) {
- error = gpio_set_debounce(button->gpio,
+ error = gpiod_set_debounce(bdata->gpiod,
button->debounce_interval * 1000);
/* use timer if gpiolib doesn't provide debounce */
if (error < 0)
@@ -500,7 +540,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
if (button->irq) {
bdata->irq = button->irq;
} else {
- irq = gpio_to_irq(button->gpio);
+ irq = gpiod_to_irq(bdata->gpiod);
if (irq < 0) {
error = irq;
dev_err(dev,
@@ -518,9 +558,10 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
} else {
if (!button->irq) {
- dev_err(dev, "No IRQ specified\n");
+ dev_err(dev, "Found button without gpio or irq\n");
return -EINVAL;
}
+
bdata->irq = button->irq;
if (button->type && button->type != EV_KEY) {
@@ -575,7 +616,7 @@ static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata)
for (i = 0; i < ddata->pdata->nbuttons; i++) {
struct gpio_button_data *bdata = &ddata->data[i];
- if (gpio_is_valid(bdata->button->gpio))
+ if (bdata->gpiod)
gpio_keys_gpio_report_event(bdata);
}
input_sync(input);
@@ -612,25 +653,18 @@ static void gpio_keys_close(struct input_dev *input)
* Handlers for alternative sources of platform_data
*/
-#ifdef CONFIG_OF
/*
- * Translate OpenFirmware node properties into platform_data
+ * Translate properties into platform_data
*/
static struct gpio_keys_platform_data *
gpio_keys_get_devtree_pdata(struct device *dev)
{
- struct device_node *node, *pp;
struct gpio_keys_platform_data *pdata;
struct gpio_keys_button *button;
- int error;
+ struct fwnode_handle *child;
int nbuttons;
- int i;
- node = dev->of_node;
- if (!node)
- return ERR_PTR(-ENODEV);
-
- nbuttons = of_get_available_child_count(node);
+ nbuttons = device_get_child_node_count(dev);
if (nbuttons == 0)
return ERR_PTR(-ENODEV);
@@ -640,64 +674,47 @@ gpio_keys_get_devtree_pdata(struct device *dev)
if (!pdata)
return ERR_PTR(-ENOMEM);
- pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
- pdata->nbuttons = nbuttons;
-
- pdata->rep = !!of_get_property(node, "autorepeat", NULL);
-
- of_property_read_string(node, "label", &pdata->name);
-
- i = 0;
- for_each_available_child_of_node(node, pp) {
- enum of_gpio_flags flags;
+ button = (struct gpio_keys_button *)(pdata + 1);
- button = &pdata->buttons[i++];
+ pdata->buttons = button;
+ pdata->nbuttons = nbuttons;
- button->gpio = of_get_gpio_flags(pp, 0, &flags);
- if (button->gpio < 0) {
- error = button->gpio;
- if (error != -ENOENT) {
- if (error != -EPROBE_DEFER)
- dev_err(dev,
- "Failed to get gpio flags, error: %d\n",
- error);
- return ERR_PTR(error);
- }
- } else {
- button->active_low = flags & OF_GPIO_ACTIVE_LOW;
- }
+ pdata->rep = device_property_read_bool(dev, "autorepeat");
- button->irq = irq_of_parse_and_map(pp, 0);
+ device_property_read_string(dev, "label", &pdata->name);
- if (!gpio_is_valid(button->gpio) && !button->irq) {
- dev_err(dev, "Found button without gpios or irqs\n");
- return ERR_PTR(-EINVAL);
- }
+ device_for_each_child_node(dev, child) {
+ if (is_of_node(child))
+ button->irq =
+ irq_of_parse_and_map(to_of_node(child), 0);
- if (of_property_read_u32(pp, "linux,code", &button->code)) {
- dev_err(dev, "Button without keycode: 0x%x\n",
- button->gpio);
+ if (fwnode_property_read_u32(child, "linux,code",
+ &button->code)) {
+ dev_err(dev, "Button without keycode\n");
+ fwnode_handle_put(child);
return ERR_PTR(-EINVAL);
}
- button->desc = of_get_property(pp, "label", NULL);
+ fwnode_property_read_string(child, "label", &button->desc);
- if (of_property_read_u32(pp, "linux,input-type", &button->type))
+ if (fwnode_property_read_u32(child, "linux,input-type",
+ &button->type))
button->type = EV_KEY;
- button->wakeup = of_property_read_bool(pp, "wakeup-source") ||
- /* legacy name */
- of_property_read_bool(pp, "gpio-key,wakeup");
+ button->wakeup =
+ fwnode_property_read_bool(child, "wakeup-source") ||
+ /* legacy name */
+ fwnode_property_read_bool(child, "gpio-key,wakeup");
- button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL);
+ button->can_disable =
+ fwnode_property_read_bool(child, "linux,can-disable");
- if (of_property_read_u32(pp, "debounce-interval",
+ if (fwnode_property_read_u32(child, "debounce-interval",
&button->debounce_interval))
button->debounce_interval = 5;
- }
- if (pdata->nbuttons == 0)
- return ERR_PTR(-EINVAL);
+ button++;
+ }
return pdata;
}
@@ -708,20 +725,11 @@ static const struct of_device_id gpio_keys_of_match[] = {
};
MODULE_DEVICE_TABLE(of, gpio_keys_of_match);
-#else
-
-static inline struct gpio_keys_platform_data *
-gpio_keys_get_devtree_pdata(struct device *dev)
-{
- return ERR_PTR(-ENODEV);
-}
-
-#endif
-
static int gpio_keys_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
+ struct fwnode_handle *child = NULL;
struct gpio_keys_drvdata *ddata;
struct input_dev *input;
size_t size;
@@ -774,14 +782,28 @@ static int gpio_keys_probe(struct platform_device *pdev)
const struct gpio_keys_button *button = &pdata->buttons[i];
struct gpio_button_data *bdata = &ddata->data[i];
- error = gpio_keys_setup_key(pdev, input, bdata, button);
- if (error)
+ if (!dev_get_platdata(dev)) {
+ child = device_get_next_child_node(&pdev->dev, child);
+ if (!child) {
+ dev_err(&pdev->dev,
+ "missing child device node for entry %d\n",
+ i);
+ return -EINVAL;
+ }
+ }
+
+ error = gpio_keys_setup_key(pdev, input, bdata, button, child);
+ if (error) {
+ fwnode_handle_put(child);
return error;
+ }
if (button->wakeup)
wakeup = 1;
}
+ fwnode_handle_put(child);
+
error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);
if (error) {
dev_err(dev, "Unable to export keys/switches, error: %d\n",
@@ -814,8 +836,7 @@ static int gpio_keys_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int gpio_keys_suspend(struct device *dev)
+static int __maybe_unused gpio_keys_suspend(struct device *dev)
{
struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
struct input_dev *input = ddata->input;
@@ -837,7 +858,7 @@ static int gpio_keys_suspend(struct device *dev)
return 0;
}
-static int gpio_keys_resume(struct device *dev)
+static int __maybe_unused gpio_keys_resume(struct device *dev)
{
struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
struct input_dev *input = ddata->input;
@@ -863,7 +884,6 @@ static int gpio_keys_resume(struct device *dev)
gpio_keys_report_state(ddata);
return 0;
}
-#endif
static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
@@ -873,7 +893,7 @@ static struct platform_driver gpio_keys_device_driver = {
.driver = {
.name = "gpio-keys",
.pm = &gpio_keys_pm_ops,
- .of_match_table = of_match_ptr(gpio_keys_of_match),
+ .of_match_table = gpio_keys_of_match,
}
};
diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c
index 62bdb1d48c49..bed4f2086158 100644
--- a/drivers/input/keyboard/gpio_keys_polled.c
+++ b/drivers/input/keyboard/gpio_keys_polled.c
@@ -30,10 +30,10 @@
#define DRV_NAME "gpio-keys-polled"
struct gpio_keys_button_data {
+ struct gpio_desc *gpiod;
int last_state;
int count;
int threshold;
- int can_sleep;
};
struct gpio_keys_polled_dev {
@@ -46,7 +46,7 @@ struct gpio_keys_polled_dev {
};
static void gpio_keys_button_event(struct input_polled_dev *dev,
- struct gpio_keys_button *button,
+ const struct gpio_keys_button *button,
int state)
{
struct gpio_keys_polled_dev *bdev = dev->private;
@@ -70,21 +70,22 @@ static void gpio_keys_button_event(struct input_polled_dev *dev,
}
static void gpio_keys_polled_check_state(struct input_polled_dev *dev,
- struct gpio_keys_button *button,
+ const struct gpio_keys_button *button,
struct gpio_keys_button_data *bdata)
{
int state;
- if (bdata->can_sleep)
- state = !!gpiod_get_value_cansleep(button->gpiod);
- else
- state = !!gpiod_get_value(button->gpiod);
-
- gpio_keys_button_event(dev, button, state);
+ state = gpiod_get_value_cansleep(bdata->gpiod);
+ if (state < 0) {
+ dev_err(dev->input->dev.parent,
+ "failed to get gpio state: %d\n", state);
+ } else {
+ gpio_keys_button_event(dev, button, state);
- if (state != bdata->last_state) {
- bdata->count = 0;
- bdata->last_state = state;
+ if (state != bdata->last_state) {
+ bdata->count = 0;
+ bdata->last_state = state;
+ }
}
}
@@ -142,48 +143,35 @@ static void gpio_keys_polled_close(struct input_polled_dev *dev)
pdata->disable(bdev->dev);
}
-static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct device *dev)
+static struct gpio_keys_platform_data *
+gpio_keys_polled_get_devtree_pdata(struct device *dev)
{
struct gpio_keys_platform_data *pdata;
struct gpio_keys_button *button;
struct fwnode_handle *child;
- int error;
int nbuttons;
nbuttons = device_get_child_node_count(dev);
if (nbuttons == 0)
- return NULL;
+ return ERR_PTR(-EINVAL);
pdata = devm_kzalloc(dev, sizeof(*pdata) + nbuttons * sizeof(*button),
GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
- pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
+ button = (struct gpio_keys_button *)(pdata + 1);
+
+ pdata->buttons = button;
+ pdata->nbuttons = nbuttons;
pdata->rep = device_property_present(dev, "autorepeat");
device_property_read_u32(dev, "poll-interval", &pdata->poll_interval);
device_for_each_child_node(dev, child) {
- struct gpio_desc *desc;
-
- desc = devm_get_gpiod_from_child(dev, NULL, child);
- if (IS_ERR(desc)) {
- error = PTR_ERR(desc);
- if (error != -EPROBE_DEFER)
- dev_err(dev,
- "Failed to get gpio flags, error: %d\n",
- error);
- fwnode_handle_put(child);
- return ERR_PTR(error);
- }
-
- button = &pdata->buttons[pdata->nbuttons++];
- button->gpiod = desc;
-
- if (fwnode_property_read_u32(child, "linux,code", &button->code)) {
- dev_err(dev, "Button without keycode: %d\n",
- pdata->nbuttons - 1);
+ if (fwnode_property_read_u32(child, "linux,code",
+ &button->code)) {
+ dev_err(dev, "button without keycode\n");
fwnode_handle_put(child);
return ERR_PTR(-EINVAL);
}
@@ -206,10 +194,9 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
if (fwnode_property_read_u32(child, "debounce-interval",
&button->debounce_interval))
button->debounce_interval = 5;
- }
- if (pdata->nbuttons == 0)
- return ERR_PTR(-EINVAL);
+ button++;
+ }
return pdata;
}
@@ -220,7 +207,7 @@ static void gpio_keys_polled_set_abs_params(struct input_dev *input,
int i, min = 0, max = 0;
for (i = 0; i < pdata->nbuttons; i++) {
- struct gpio_keys_button *button = &pdata->buttons[i];
+ const struct gpio_keys_button *button = &pdata->buttons[i];
if (button->type != EV_ABS || button->code != code)
continue;
@@ -230,6 +217,7 @@ static void gpio_keys_polled_set_abs_params(struct input_dev *input,
if (button->value > max)
max = button->value;
}
+
input_set_abs_params(input, code, min, max, 0, 0);
}
@@ -242,6 +230,7 @@ MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match);
static int gpio_keys_polled_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct fwnode_handle *child = NULL;
const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
struct gpio_keys_polled_dev *bdev;
struct input_polled_dev *poll_dev;
@@ -254,10 +243,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
pdata = gpio_keys_polled_get_devtree_pdata(dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
- if (!pdata) {
- dev_err(dev, "missing platform data\n");
- return -EINVAL;
- }
}
if (!pdata->poll_interval) {
@@ -300,20 +285,48 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
__set_bit(EV_REP, input->evbit);
for (i = 0; i < pdata->nbuttons; i++) {
- struct gpio_keys_button *button = &pdata->buttons[i];
+ const struct gpio_keys_button *button = &pdata->buttons[i];
struct gpio_keys_button_data *bdata = &bdev->data[i];
unsigned int type = button->type ?: EV_KEY;
if (button->wakeup) {
dev_err(dev, DRV_NAME " does not support wakeup\n");
+ fwnode_handle_put(child);
return -EINVAL;
}
- /*
- * Legacy GPIO number so request the GPIO here and
- * convert it to descriptor.
- */
- if (!button->gpiod && gpio_is_valid(button->gpio)) {
+ if (!dev_get_platdata(dev)) {
+ /* No legacy static platform data */
+ child = device_get_next_child_node(dev, child);
+ if (!child) {
+ dev_err(dev, "missing child device node\n");
+ return -EINVAL;
+ }
+
+ bdata->gpiod = devm_get_gpiod_from_child(dev, NULL,
+ child);
+ if (IS_ERR(bdata->gpiod)) {
+ error = PTR_ERR(bdata->gpiod);
+ if (error != -EPROBE_DEFER)
+ dev_err(dev,
+ "failed to get gpio: %d\n",
+ error);
+ fwnode_handle_put(child);
+ return error;
+ }
+
+ error = gpiod_direction_input(bdata->gpiod);
+ if (error) {
+ dev_err(dev, "Failed to configure GPIO %d as input: %d\n",
+ desc_to_gpio(bdata->gpiod), error);
+ fwnode_handle_put(child);
+ return error;
+ }
+ } else if (gpio_is_valid(button->gpio)) {
+ /*
+ * Legacy GPIO number so request the GPIO here and
+ * convert it to descriptor.
+ */
unsigned flags = GPIOF_IN;
if (button->active_low)
@@ -322,18 +335,21 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
error = devm_gpio_request_one(&pdev->dev, button->gpio,
flags, button->desc ? : DRV_NAME);
if (error) {
- dev_err(dev, "unable to claim gpio %u, err=%d\n",
+ dev_err(dev,
+ "unable to claim gpio %u, err=%d\n",
button->gpio, error);
return error;
}
- button->gpiod = gpio_to_desc(button->gpio);
+ bdata->gpiod = gpio_to_desc(button->gpio);
+ if (!bdata->gpiod) {
+ dev_err(dev,
+ "unable to convert gpio %u to descriptor\n",
+ button->gpio);
+ return -EINVAL;
+ }
}
- if (IS_ERR(button->gpiod))
- return PTR_ERR(button->gpiod);
-
- bdata->can_sleep = gpiod_cansleep(button->gpiod);
bdata->last_state = -1;
bdata->threshold = DIV_ROUND_UP(button->debounce_interval,
pdata->poll_interval);
@@ -344,6 +360,8 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
button->code);
}
+ fwnode_handle_put(child);
+
bdev->poll_dev = poll_dev;
bdev->dev = dev;
bdev->pdata = pdata;
diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c
index 265d641c40e2..632523d4f5dc 100644
--- a/drivers/input/keyboard/lpc32xx-keys.c
+++ b/drivers/input/keyboard/lpc32xx-keys.c
@@ -182,7 +182,7 @@ static int lpc32xx_kscan_probe(struct platform_device *pdev)
}
irq = platform_get_irq(pdev, 0);
- if (irq < 0 || irq >= NR_IRQS) {
+ if (irq < 0) {
dev_err(&pdev->dev, "failed to get platform irq\n");
return -EINVAL;
}
diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c
index fcef5d1365e2..e24443376e75 100644
--- a/drivers/input/keyboard/pxa27x_keypad.c
+++ b/drivers/input/keyboard/pxa27x_keypad.c
@@ -316,7 +316,7 @@ static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad)
error = of_property_read_u32(np, "marvell,debounce-interval",
&pdata->debounce_interval);
if (error) {
- dev_err(dev, "failed to parse debpunce-interval\n");
+ dev_err(dev, "failed to parse debounce-interval\n");
return error;
}
diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c
index 9002298698fc..3048ef3e3e16 100644
--- a/drivers/input/keyboard/tca8418_keypad.c
+++ b/drivers/input/keyboard/tca8418_keypad.c
@@ -164,11 +164,18 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data)
int error, col, row;
u8 reg, state, code;
- /* Initial read of the key event FIFO */
- error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
+ do {
+ error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
+ if (error < 0) {
+ dev_err(&keypad_data->client->dev,
+ "unable to read REG_KEY_EVENT_A\n");
+ break;
+ }
+
+ /* Assume that key code 0 signifies empty FIFO */
+ if (reg <= 0)
+ break;
- /* Assume that key code 0 signifies empty FIFO */
- while (error >= 0 && reg > 0) {
state = reg & KEY_EVENT_VALUE;
code = reg & KEY_EVENT_CODE;
@@ -184,11 +191,7 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data)
/* Read for next loop */
error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
- }
-
- if (error < 0)
- dev_err(&keypad_data->client->dev,
- "unable to read REG_KEY_EVENT_A\n");
+ } while (1);
input_sync(input);
}
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 7ffb614ce566..1ae4d9617ff8 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -625,11 +625,12 @@ config INPUT_DA9055_ONKEY
will be called da9055_onkey.
config INPUT_DA9063_ONKEY
- tristate "Dialog DA9062/63 OnKey"
+ tristate "Dialog DA9063/62/61 OnKey"
depends on MFD_DA9063 || MFD_DA9062
help
- Support the ONKEY of Dialog DA9063 and DA9062 Power Management ICs
- as an input device capable of reporting the power button status.
+ Support the ONKEY of Dialog DA9063, DA9062 and DA9061 Power
+ Management ICs as an input device capable of reporting the
+ power button status.
To compile this driver as a module, choose M here: the module
will be called da9063_onkey.
diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c
index b0d445390ee4..2124390ec38c 100644
--- a/drivers/input/misc/bma150.c
+++ b/drivers/input/misc/bma150.c
@@ -538,8 +538,13 @@ static int bma150_probe(struct i2c_client *client,
return -EIO;
}
+ /*
+ * Note if the IIO CONFIG_BMA180 driver is enabled we want to fail
+ * the probe for the bma180 as the iio driver is preferred.
+ */
chip_id = i2c_smbus_read_byte_data(client, BMA150_CHIP_ID_REG);
- if (chip_id != BMA150_CHIP_ID && chip_id != BMA180_CHIP_ID) {
+ if (chip_id != BMA150_CHIP_ID &&
+ (IS_ENABLED(CONFIG_BMA180) || chip_id != BMA180_CHIP_ID)) {
dev_err(&client->dev, "BMA150 chip id error: %d\n", chip_id);
return -EINVAL;
}
@@ -643,7 +648,9 @@ static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL);
static const struct i2c_device_id bma150_id[] = {
{ "bma150", 0 },
+#if !IS_ENABLED(CONFIG_BMA180)
{ "bma180", 0 },
+#endif
{ "smb380", 0 },
{ "bma023", 0 },
{ }
diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c
index bb863e062b03..b4ff1e86d3d3 100644
--- a/drivers/input/misc/da9063_onkey.c
+++ b/drivers/input/misc/da9063_onkey.c
@@ -1,5 +1,5 @@
/*
- * OnKey device driver for DA9063 and DA9062 PMICs
+ * OnKey device driver for DA9063, DA9062 and DA9061 PMICs
* Copyright (C) 2015 Dialog Semiconductor Ltd.
*
* This program is free software; you can redistribute it and/or
@@ -87,6 +87,7 @@ static const struct of_device_id da9063_compatible_reg_id_table[] = {
{ .compatible = "dlg,da9062-onkey", .data = &da9062_regs },
{ },
};
+MODULE_DEVICE_TABLE(of, da9063_compatible_reg_id_table);
static void da9063_poll_on(struct work_struct *work)
{
@@ -149,13 +150,13 @@ static void da9063_poll_on(struct work_struct *work)
* and then send shutdown command
*/
dev_dbg(&onkey->input->dev,
- "Sending SHUTDOWN to DA9063 ...\n");
+ "Sending SHUTDOWN to PMIC ...\n");
error = regmap_write(onkey->regmap,
config->onkey_shutdown,
config->onkey_shutdown_mask);
if (error)
dev_err(&onkey->input->dev,
- "Cannot SHUTDOWN DA9063: %d\n",
+ "Cannot SHUTDOWN PMIC: %d\n",
error);
}
}
@@ -300,6 +301,6 @@ static struct platform_driver da9063_onkey_driver = {
module_platform_driver(da9063_onkey_driver);
MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
-MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063 and DA9062");
+MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063, DA9062 and DA9061");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DA9063_DRVNAME_ONKEY);
diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c
index 2adfd86c869a..0a2b865b1000 100644
--- a/drivers/input/misc/drv260x.c
+++ b/drivers/input/misc/drv260x.c
@@ -18,8 +18,6 @@
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
-#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -27,7 +25,6 @@
#include <linux/regulator/consumer.h>
#include <dt-bindings/input/ti-drv260x.h>
-#include <linux/platform_data/drv260x-pdata.h>
#define DRV260X_STATUS 0x0
#define DRV260X_MODE 0x1
@@ -468,90 +465,39 @@ static const struct regmap_config drv260x_regmap_config = {
.cache_type = REGCACHE_NONE,
};
-#ifdef CONFIG_OF
-static int drv260x_parse_dt(struct device *dev,
- struct drv260x_data *haptics)
-{
- struct device_node *np = dev->of_node;
- unsigned int voltage;
- int error;
-
- error = of_property_read_u32(np, "mode", &haptics->mode);
- if (error) {
- dev_err(dev, "%s: No entry for mode\n", __func__);
- return error;
- }
-
- error = of_property_read_u32(np, "library-sel", &haptics->library);
- if (error) {
- dev_err(dev, "%s: No entry for library selection\n",
- __func__);
- return error;
- }
-
- error = of_property_read_u32(np, "vib-rated-mv", &voltage);
- if (!error)
- haptics->rated_voltage = drv260x_calculate_voltage(voltage);
-
-
- error = of_property_read_u32(np, "vib-overdrive-mv", &voltage);
- if (!error)
- haptics->overdrive_voltage = drv260x_calculate_voltage(voltage);
-
- return 0;
-}
-#else
-static inline int drv260x_parse_dt(struct device *dev,
- struct drv260x_data *haptics)
-{
- dev_err(dev, "no platform data defined\n");
-
- return -EINVAL;
-}
-#endif
-
static int drv260x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- const struct drv260x_platform_data *pdata = dev_get_platdata(&client->dev);
+ struct device *dev = &client->dev;
struct drv260x_data *haptics;
+ u32 voltage;
int error;
- haptics = devm_kzalloc(&client->dev, sizeof(*haptics), GFP_KERNEL);
+ haptics = devm_kzalloc(dev, sizeof(*haptics), GFP_KERNEL);
if (!haptics)
return -ENOMEM;
- haptics->rated_voltage = DRV260X_DEF_OD_CLAMP_VOLT;
- haptics->rated_voltage = DRV260X_DEF_RATED_VOLT;
-
- if (pdata) {
- haptics->mode = pdata->mode;
- haptics->library = pdata->library_selection;
- if (pdata->vib_overdrive_voltage)
- haptics->overdrive_voltage = drv260x_calculate_voltage(pdata->vib_overdrive_voltage);
- if (pdata->vib_rated_voltage)
- haptics->rated_voltage = drv260x_calculate_voltage(pdata->vib_rated_voltage);
- } else if (client->dev.of_node) {
- error = drv260x_parse_dt(&client->dev, haptics);
- if (error)
- return error;
- } else {
- dev_err(&client->dev, "Platform data not set\n");
- return -ENODEV;
+ error = device_property_read_u32(dev, "mode", &haptics->mode);
+ if (error) {
+ dev_err(dev, "Can't fetch 'mode' property: %d\n", error);
+ return error;
}
-
if (haptics->mode < DRV260X_LRA_MODE ||
haptics->mode > DRV260X_ERM_MODE) {
- dev_err(&client->dev,
- "Vibrator mode is invalid: %i\n",
- haptics->mode);
+ dev_err(dev, "Vibrator mode is invalid: %i\n", haptics->mode);
return -EINVAL;
}
+ error = device_property_read_u32(dev, "library-sel", &haptics->library);
+ if (error) {
+ dev_err(dev, "Can't fetch 'library-sel' property: %d\n", error);
+ return error;
+ }
+
if (haptics->library < DRV260X_LIB_EMPTY ||
haptics->library > DRV260X_ERM_LIB_F) {
- dev_err(&client->dev,
+ dev_err(dev,
"Library value is invalid: %i\n", haptics->library);
return -EINVAL;
}
@@ -559,40 +505,44 @@ static int drv260x_probe(struct i2c_client *client,
if (haptics->mode == DRV260X_LRA_MODE &&
haptics->library != DRV260X_LIB_EMPTY &&
haptics->library != DRV260X_LIB_LRA) {
- dev_err(&client->dev,
- "LRA Mode with ERM Library mismatch\n");
+ dev_err(dev, "LRA Mode with ERM Library mismatch\n");
return -EINVAL;
}
if (haptics->mode == DRV260X_ERM_MODE &&
(haptics->library == DRV260X_LIB_EMPTY ||
haptics->library == DRV260X_LIB_LRA)) {
- dev_err(&client->dev,
- "ERM Mode with LRA Library mismatch\n");
+ dev_err(dev, "ERM Mode with LRA Library mismatch\n");
return -EINVAL;
}
- haptics->regulator = devm_regulator_get(&client->dev, "vbat");
+ error = device_property_read_u32(dev, "vib-rated-mv", &voltage);
+ haptics->rated_voltage = error ? DRV260X_DEF_RATED_VOLT :
+ drv260x_calculate_voltage(voltage);
+
+ error = device_property_read_u32(dev, "vib-overdrive-mv", &voltage);
+ haptics->overdrive_voltage = error ? DRV260X_DEF_OD_CLAMP_VOLT :
+ drv260x_calculate_voltage(voltage);
+
+ haptics->regulator = devm_regulator_get(dev, "vbat");
if (IS_ERR(haptics->regulator)) {
error = PTR_ERR(haptics->regulator);
- dev_err(&client->dev,
- "unable to get regulator, error: %d\n", error);
+ dev_err(dev, "unable to get regulator, error: %d\n", error);
return error;
}
- haptics->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable",
+ haptics->enable_gpio = devm_gpiod_get_optional(dev, "enable",
GPIOD_OUT_HIGH);
if (IS_ERR(haptics->enable_gpio))
return PTR_ERR(haptics->enable_gpio);
- haptics->input_dev = devm_input_allocate_device(&client->dev);
+ haptics->input_dev = devm_input_allocate_device(dev);
if (!haptics->input_dev) {
dev_err(&client->dev, "Failed to allocate input device\n");
return -ENOMEM;
}
haptics->input_dev->name = "drv260x:haptics";
- haptics->input_dev->dev.parent = client->dev.parent;
haptics->input_dev->close = drv260x_close;
input_set_drvdata(haptics->input_dev, haptics);
input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE);
@@ -600,8 +550,7 @@ static int drv260x_probe(struct i2c_client *client,
error = input_ff_create_memless(haptics->input_dev, NULL,
drv260x_haptics_play);
if (error) {
- dev_err(&client->dev, "input_ff_create() failed: %d\n",
- error);
+ dev_err(dev, "input_ff_create() failed: %d\n", error);
return error;
}
@@ -613,21 +562,19 @@ static int drv260x_probe(struct i2c_client *client,
haptics->regmap = devm_regmap_init_i2c(client, &drv260x_regmap_config);
if (IS_ERR(haptics->regmap)) {
error = PTR_ERR(haptics->regmap);
- dev_err(&client->dev, "Failed to allocate register map: %d\n",
- error);
+ dev_err(dev, "Failed to allocate register map: %d\n", error);
return error;
}
error = drv260x_init(haptics);
if (error) {
- dev_err(&client->dev, "Device init failed: %d\n", error);
+ dev_err(dev, "Device init failed: %d\n", error);
return error;
}
error = input_register_device(haptics->input_dev);
if (error) {
- dev_err(&client->dev, "couldn't register input device: %d\n",
- error);
+ dev_err(dev, "couldn't register input device: %d\n", error);
return error;
}
diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c
index ef9bc12b3be3..dcb6d8e94b11 100644
--- a/drivers/input/misc/drv2665.c
+++ b/drivers/input/misc/drv2665.c
@@ -125,8 +125,8 @@ static void drv2665_close(struct input_dev *input)
cancel_work_sync(&haptics->work);
- error = regmap_update_bits(haptics->regmap,
- DRV2665_CTRL_2, DRV2665_STANDBY, 1);
+ error = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
+ DRV2665_STANDBY, DRV2665_STANDBY);
if (error)
dev_err(&haptics->client->dev,
"Failed to enter standby mode: %d\n", error);
@@ -240,7 +240,7 @@ static int __maybe_unused drv2665_suspend(struct device *dev)
if (haptics->input_dev->users) {
ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
- DRV2665_STANDBY, 1);
+ DRV2665_STANDBY, DRV2665_STANDBY);
if (ret) {
dev_err(dev, "Failed to set standby mode\n");
regulator_disable(haptics->regulator);
diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c
index d5ba7481328c..2849bb6906a8 100644
--- a/drivers/input/misc/drv2667.c
+++ b/drivers/input/misc/drv2667.c
@@ -256,7 +256,7 @@ static void drv2667_close(struct input_dev *input)
cancel_work_sync(&haptics->work);
error = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2,
- DRV2667_STANDBY, 1);
+ DRV2667_STANDBY, DRV2667_STANDBY);
if (error)
dev_err(&haptics->client->dev,
"Failed to enter standby mode: %d\n", error);
@@ -415,7 +415,7 @@ static int __maybe_unused drv2667_suspend(struct device *dev)
if (haptics->input_dev->users) {
ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2,
- DRV2667_STANDBY, 1);
+ DRV2667_STANDBY, DRV2667_STANDBY);
if (ret) {
dev_err(dev, "Failed to set standby mode\n");
regulator_disable(haptics->regulator);
diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c
index 08d5394dd981..46b0f48fbf49 100644
--- a/drivers/input/misc/max77693-haptic.c
+++ b/drivers/input/misc/max77693-haptic.c
@@ -70,10 +70,13 @@ struct max77693_haptic {
static int max77693_haptic_set_duty_cycle(struct max77693_haptic *haptic)
{
- int delta = (haptic->pwm_dev->period + haptic->pwm_duty) / 2;
+ struct pwm_args pargs;
+ int delta;
int error;
- error = pwm_config(haptic->pwm_dev, delta, haptic->pwm_dev->period);
+ pwm_get_args(haptic->pwm_dev, &pargs);
+ delta = (pargs.period + haptic->pwm_duty) / 2;
+ error = pwm_config(haptic->pwm_dev, delta, pargs.period);
if (error) {
dev_err(haptic->dev, "failed to configure pwm: %d\n", error);
return error;
@@ -234,6 +237,7 @@ static int max77693_haptic_play_effect(struct input_dev *dev, void *data,
struct ff_effect *effect)
{
struct max77693_haptic *haptic = input_get_drvdata(dev);
+ struct pwm_args pargs;
u64 period_mag_multi;
haptic->magnitude = effect->u.rumble.strong_magnitude;
@@ -245,7 +249,8 @@ static int max77693_haptic_play_effect(struct input_dev *dev, void *data,
* The formula to convert magnitude to pwm_duty as follows:
* - pwm_duty = (magnitude * pwm_period) / MAX_MAGNITUDE(0xFFFF)
*/
- period_mag_multi = (u64)haptic->pwm_dev->period * haptic->magnitude;
+ pwm_get_args(haptic->pwm_dev, &pargs);
+ period_mag_multi = (u64)pargs.period * haptic->magnitude;
haptic->pwm_duty = (unsigned int)(period_mag_multi >>
MAX_MAGNITUDE_SHIFT);
@@ -329,6 +334,12 @@ static int max77693_haptic_probe(struct platform_device *pdev)
return PTR_ERR(haptic->pwm_dev);
}
+ /*
+ * FIXME: pwm_apply_args() should be removed when switching to the
+ * atomic PWM API.
+ */
+ pwm_apply_args(haptic->pwm_dev);
+
haptic->motor_reg = devm_regulator_get(&pdev->dev, "haptic");
if (IS_ERR(haptic->motor_reg)) {
dev_err(&pdev->dev, "failed to get regulator\n");
diff --git a/drivers/input/misc/max8997_haptic.c b/drivers/input/misc/max8997_haptic.c
index 8d6326d7e7be..99bc762881d5 100644
--- a/drivers/input/misc/max8997_haptic.c
+++ b/drivers/input/misc/max8997_haptic.c
@@ -306,6 +306,12 @@ static int max8997_haptic_probe(struct platform_device *pdev)
error);
goto err_free_mem;
}
+
+ /*
+ * FIXME: pwm_apply_args() should be removed when switching to
+ * the atomic PWM API.
+ */
+ pwm_apply_args(chip->pwm);
break;
default:
diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c
index 18663d4edae5..5f9655d49a65 100644
--- a/drivers/input/misc/pwm-beeper.c
+++ b/drivers/input/misc/pwm-beeper.c
@@ -115,6 +115,12 @@ static int pwm_beeper_probe(struct platform_device *pdev)
goto err_free;
}
+ /*
+ * FIXME: pwm_apply_args() should be removed when switching to
+ * the atomic PWM API.
+ */
+ pwm_apply_args(beeper->pwm);
+
INIT_WORK(&beeper->work, pwm_beeper_work);
beeper->input = input_allocate_device();
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
index c14b82709b0f..908b51089dee 100644
--- a/drivers/input/misc/soc_button_array.c
+++ b/drivers/input/misc/soc_button_array.c
@@ -17,6 +17,7 @@
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
+#include <linux/gpio.h>
#include <linux/platform_device.h>
/*
@@ -92,7 +93,7 @@ soc_button_device_create(struct platform_device *pdev,
continue;
gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
- if (gpio < 0)
+ if (!gpio_is_valid(gpio))
continue;
gpio_keys[n_buttons].type = info->event_type;
@@ -166,6 +167,11 @@ static int soc_button_probe(struct platform_device *pdev)
button_info = (struct soc_button_info *)id->driver_data;
+ if (gpiod_count(&pdev->dev, KBUILD_MODNAME) <= 0) {
+ dev_dbg(&pdev->dev, "no GPIO attached, ignoring...\n");
+ return -ENODEV;
+ }
+
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 6d7de9bfed9a..328edc8c8786 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -1153,15 +1153,13 @@ static void alps_process_packet_v7(struct psmouse *psmouse)
alps_process_touchpad_packet_v7(psmouse);
}
-static unsigned char alps_get_pkt_id_ss4_v2(unsigned char *byte)
+static enum SS4_PACKET_ID alps_get_pkt_id_ss4_v2(unsigned char *byte)
{
- unsigned char pkt_id = SS4_PACKET_ID_IDLE;
+ enum SS4_PACKET_ID pkt_id = SS4_PACKET_ID_IDLE;
switch (byte[3] & 0x30) {
case 0x00:
- if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 &&
- (byte[3] & 0x88) == 0x08 && byte[4] == 0x10 &&
- byte[5] == 0x00) {
+ if (SS4_IS_IDLE_V2(byte)) {
pkt_id = SS4_PACKET_ID_IDLE;
} else {
pkt_id = SS4_PACKET_ID_ONE;
@@ -1188,7 +1186,7 @@ static int alps_decode_ss4_v2(struct alps_fields *f,
unsigned char *p, struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
- unsigned char pkt_id;
+ enum SS4_PACKET_ID pkt_id;
unsigned int no_data_x, no_data_y;
pkt_id = alps_get_pkt_id_ss4_v2(p);
@@ -1267,18 +1265,12 @@ static int alps_decode_ss4_v2(struct alps_fields *f,
break;
case SS4_PACKET_ID_STICK:
- if (!(priv->flags & ALPS_DUALPOINT)) {
- psmouse_warn(psmouse,
- "Rejected trackstick packet from non DualPoint device");
- } else {
- int x = (s8)(((p[0] & 1) << 7) | (p[1] & 0x7f));
- int y = (s8)(((p[3] & 1) << 7) | (p[2] & 0x7f));
- int pressure = (s8)(p[4] & 0x7f);
-
- input_report_rel(priv->dev2, REL_X, x);
- input_report_rel(priv->dev2, REL_Y, -y);
- input_report_abs(priv->dev2, ABS_PRESSURE, pressure);
- }
+ /*
+ * x, y, and pressure are decoded in
+ * alps_process_packet_ss4_v2()
+ */
+ f->first_mp = 0;
+ f->is_mp = 0;
break;
case SS4_PACKET_ID_IDLE:
@@ -1346,6 +1338,27 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse)
priv->multi_packet = 0;
+ /* Report trackstick */
+ if (alps_get_pkt_id_ss4_v2(packet) == SS4_PACKET_ID_STICK) {
+ if (!(priv->flags & ALPS_DUALPOINT)) {
+ psmouse_warn(psmouse,
+ "Rejected trackstick packet from non DualPoint device");
+ return;
+ }
+
+ input_report_rel(dev2, REL_X, SS4_TS_X_V2(packet));
+ input_report_rel(dev2, REL_Y, SS4_TS_Y_V2(packet));
+ input_report_abs(dev2, ABS_PRESSURE, SS4_TS_Z_V2(packet));
+
+ input_report_key(dev2, BTN_LEFT, f->ts_left);
+ input_report_key(dev2, BTN_RIGHT, f->ts_right);
+ input_report_key(dev2, BTN_MIDDLE, f->ts_middle);
+
+ input_sync(dev2);
+ return;
+ }
+
+ /* Report touchpad */
alps_report_mt_data(psmouse, (f->fingers <= 4) ? f->fingers : 4);
input_mt_report_finger_count(dev, f->fingers);
@@ -1356,13 +1369,6 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse)
input_report_abs(dev, ABS_PRESSURE, f->pressure);
input_sync(dev);
-
- if (priv->flags & ALPS_DUALPOINT) {
- input_report_key(dev2, BTN_LEFT, f->ts_left);
- input_report_key(dev2, BTN_RIGHT, f->ts_right);
- input_report_key(dev2, BTN_MIDDLE, f->ts_middle);
- input_sync(dev2);
- }
}
static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse)
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index b9417e2d7ad3..cde6f4bd8ea2 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -54,7 +54,15 @@ enum SS4_PACKET_ID {
#define SS4_MASK_NORMAL_BUTTONS 0x07
-#define SS4_1F_X_V2(_b) ((_b[0] & 0x0007) | \
+#define SS4_IS_IDLE_V2(_b) (((_b[0]) == 0x18) && \
+ ((_b[1]) == 0x10) && \
+ ((_b[2]) == 0x00) && \
+ ((_b[3] & 0x88) == 0x08) && \
+ ((_b[4]) == 0x10) && \
+ ((_b[5]) == 0x00) \
+ )
+
+#define SS4_1F_X_V2(_b) (((_b[0]) & 0x0007) | \
((_b[1] << 3) & 0x0078) | \
((_b[1] << 2) & 0x0380) | \
((_b[2] << 5) & 0x1C00) \
@@ -101,6 +109,18 @@ enum SS4_PACKET_ID {
#define SS4_IS_MF_CONTINUE(_b) ((_b[2] & 0x10) == 0x10)
#define SS4_IS_5F_DETECTED(_b) ((_b[2] & 0x10) == 0x10)
+#define SS4_TS_X_V2(_b) (s8)( \
+ ((_b[0] & 0x01) << 7) | \
+ (_b[1] & 0x7F) \
+ )
+
+#define SS4_TS_Y_V2(_b) (s8)( \
+ ((_b[3] & 0x01) << 7) | \
+ (_b[2] & 0x7F) \
+ )
+
+#define SS4_TS_Z_V2(_b) (s8)(_b[4] & 0x7F)
+
#define SS4_MFPACKET_NO_AX 8160 /* X-Coordinate value */
#define SS4_MFPACKET_NO_AY 4080 /* Y-Coordinate value */
@@ -146,7 +166,7 @@ struct alps_protocol_info {
* (aka command mode response) identifies the firmware minor version. This
* can be used to distinguish different hardware models which are not
* uniquely identifiable through their E7 responses.
- * @protocol_info: information about protcol used by the device.
+ * @protocol_info: information about protocol used by the device.
*
* Many (but not all) ALPS touchpads can be identified by looking at the
* values returned in the "E7 report" and/or the "EC report." This table
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index d15b33813021..fa598f7f4372 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -1093,19 +1093,18 @@ static int elan_probe(struct i2c_client *client,
if (error)
return error;
+ dev_info(&client->dev,
+ "Elan Touchpad: Module ID: 0x%04x, Firmware: 0x%04x, Sample: 0x%04x, IAP: 0x%04x\n",
+ data->product_id,
+ data->fw_version,
+ data->sm_version,
+ data->iap_version);
+
dev_dbg(&client->dev,
- "Elan Touchpad Information:\n"
- " Module product ID: 0x%04x\n"
- " Firmware Version: 0x%04x\n"
- " Sample Version: 0x%04x\n"
- " IAP Version: 0x%04x\n"
+ "Elan Touchpad Extra Information:\n"
" Max ABS X,Y: %d,%d\n"
" Width X,Y: %d,%d\n"
" Resolution X,Y: %d,%d (dots/mm)\n",
- data->product_id,
- data->fw_version,
- data->sm_version,
- data->iap_version,
data->max_x, data->max_y,
data->width_x, data->width_y,
data->x_res, data->y_res);
diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig
index f73df2495fed..30cc627a4f45 100644
--- a/drivers/input/rmi4/Kconfig
+++ b/drivers/input/rmi4/Kconfig
@@ -27,6 +27,27 @@ config RMI4_SPI
If unsure, say N.
+config RMI4_SMB
+ tristate "RMI4 SMB Support"
+ depends on RMI4_CORE && I2C
+ help
+ Say Y here if you want to support RMI4 devices connected to an SMB
+ bus.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the module will be
+ called rmi_smbus.
+
+config RMI4_F03
+ bool "RMI4 Function 03 (PS2 Guest)"
+ depends on RMI4_CORE && SERIO
+ help
+ Say Y here if you want to add support for RMI4 function 03.
+
+ Function 03 provides PS2 guest support for RMI4 devices. This
+ includes support for TrackPoints on TouchPads.
+
config RMI4_2D_SENSOR
bool
depends on RMI4_CORE
@@ -61,3 +82,35 @@ config RMI4_F30
Function 30 provides GPIO and LED support for RMI4 devices. This
includes support for buttons on TouchPads and ClickPads.
+
+config RMI4_F34
+ bool "RMI4 Function 34 (Device reflash)"
+ depends on RMI4_CORE
+ select FW_LOADER
+ help
+ Say Y here if you want to add support for RMI4 function 34.
+
+ Function 34 provides support for upgrading the firmware on the RMI4
+ device via the firmware loader interface. This is triggered using a
+ sysfs attribute.
+
+config RMI4_F54
+ bool "RMI4 Function 54 (Analog diagnostics)"
+ depends on RMI4_CORE
+ depends on VIDEO_V4L2=y || (RMI4_CORE=m && VIDEO_V4L2=m)
+ select VIDEOBUF2_VMALLOC
+ select RMI4_F55
+ help
+ Say Y here if you want to add support for RMI4 function 54
+
+ Function 54 provides access to various diagnostic features in certain
+ RMI4 touch sensors.
+
+config RMI4_F55
+ bool "RMI4 Function 55 (Sensor tuning)"
+ depends on RMI4_CORE
+ help
+ Say Y here if you want to add support for RMI4 function 55
+
+ Function 55 provides access to the RMI4 touch sensor tuning
+ mechanism.
diff --git a/drivers/input/rmi4/Makefile b/drivers/input/rmi4/Makefile
index 95c00a783992..9aaac3dd8613 100644
--- a/drivers/input/rmi4/Makefile
+++ b/drivers/input/rmi4/Makefile
@@ -4,10 +4,15 @@ rmi_core-y := rmi_bus.o rmi_driver.o rmi_f01.o
rmi_core-$(CONFIG_RMI4_2D_SENSOR) += rmi_2d_sensor.o
# Function drivers
+rmi_core-$(CONFIG_RMI4_F03) += rmi_f03.o
rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o
rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o
rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o
+rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o rmi_f34v7.o
+rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o
+rmi_core-$(CONFIG_RMI4_F55) += rmi_f55.o
# Transports
obj-$(CONFIG_RMI4_I2C) += rmi_i2c.o
obj-$(CONFIG_RMI4_SPI) += rmi_spi.o
+obj-$(CONFIG_RMI4_SMB) += rmi_smbus.o
diff --git a/drivers/input/rmi4/rmi_2d_sensor.c b/drivers/input/rmi4/rmi_2d_sensor.c
index e97bd7fabccc..07007ff8e29f 100644
--- a/drivers/input/rmi4/rmi_2d_sensor.c
+++ b/drivers/input/rmi4/rmi_2d_sensor.c
@@ -177,10 +177,12 @@ static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor)
sensor->dmax = DMAX * res_x;
}
- input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0);
- input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
- input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
- input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+ input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0);
+ input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
+ input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
+ input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+ input_set_abs_params(input, ABS_MT_TOOL_TYPE,
+ 0, MT_TOOL_MAX, 0, 0);
if (sensor->sensor_type == rmi_sensor_touchpad)
input_flags = INPUT_MT_POINTER;
diff --git a/drivers/input/rmi4/rmi_2d_sensor.h b/drivers/input/rmi4/rmi_2d_sensor.h
index 77fcdfef003c..c871bef4dac0 100644
--- a/drivers/input/rmi4/rmi_2d_sensor.h
+++ b/drivers/input/rmi4/rmi_2d_sensor.h
@@ -67,6 +67,8 @@ struct rmi_2d_sensor {
u8 report_rel;
u8 x_mm;
u8 y_mm;
+ enum rmi_reg_state dribble;
+ enum rmi_reg_state palm_detect;
};
int rmi_2d_sensor_of_probe(struct device *dev,
diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c
index a73580654c6b..df97d8679bad 100644
--- a/drivers/input/rmi4/rmi_bus.c
+++ b/drivers/input/rmi4/rmi_bus.c
@@ -231,6 +231,9 @@ err_put_device:
void rmi_unregister_function(struct rmi_function *fn)
{
+ rmi_dbg(RMI_DEBUG_CORE, &fn->dev, "Unregistering F%02X.\n",
+ fn->fd.function_number);
+
device_del(&fn->dev);
of_node_put(fn->dev.of_node);
put_device(&fn->dev);
@@ -303,6 +306,9 @@ struct bus_type rmi_bus_type = {
static struct rmi_function_handler *fn_handlers[] = {
&rmi_f01_handler,
+#ifdef CONFIG_RMI4_F03
+ &rmi_f03_handler,
+#endif
#ifdef CONFIG_RMI4_F11
&rmi_f11_handler,
#endif
@@ -312,6 +318,15 @@ static struct rmi_function_handler *fn_handlers[] = {
#ifdef CONFIG_RMI4_F30
&rmi_f30_handler,
#endif
+#ifdef CONFIG_RMI4_F34
+ &rmi_f34_handler,
+#endif
+#ifdef CONFIG_RMI4_F54
+ &rmi_f54_handler,
+#endif
+#ifdef CONFIG_RMI4_F55
+ &rmi_f55_handler,
+#endif
};
static void __rmi_unregister_function_handlers(int start_idx)
diff --git a/drivers/input/rmi4/rmi_bus.h b/drivers/input/rmi4/rmi_bus.h
index 899579830536..b7625a9ac66a 100644
--- a/drivers/input/rmi4/rmi_bus.h
+++ b/drivers/input/rmi4/rmi_bus.h
@@ -105,6 +105,18 @@ rmi_get_platform_data(struct rmi_device *d)
bool rmi_is_physical_device(struct device *dev);
/**
+ * rmi_reset - reset a RMI4 device
+ * @d: Pointer to an RMI device
+ *
+ * Calls for a reset of each function implemented by a specific device.
+ * Returns 0 on success or a negative error code.
+ */
+static inline int rmi_reset(struct rmi_device *d)
+{
+ return d->driver->reset_handler(d);
+}
+
+/**
* rmi_read - read a single byte
* @d: Pointer to an RMI device
* @addr: The address to read from
diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index c83bce89028b..cb6efe693302 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -17,6 +17,7 @@
#include <linux/bitmap.h>
#include <linux/delay.h>
#include <linux/fs.h>
+#include <linux/irq.h>
#include <linux/kconfig.h>
#include <linux/pm.h>
#include <linux/slab.h>
@@ -34,12 +35,22 @@
#define RMI_DEVICE_RESET_CMD 0x01
#define DEFAULT_RESET_DELAY_MS 100
-static void rmi_free_function_list(struct rmi_device *rmi_dev)
+void rmi_free_function_list(struct rmi_device *rmi_dev)
{
struct rmi_function *fn, *tmp;
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+ rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Freeing function list\n");
+
+ devm_kfree(&rmi_dev->dev, data->irq_memory);
+ data->irq_memory = NULL;
+ data->irq_status = NULL;
+ data->fn_irq_bits = NULL;
+ data->current_irq_mask = NULL;
+ data->new_irq_mask = NULL;
+
data->f01_container = NULL;
+ data->f34_container = NULL;
/* Doing it in the reverse order so F01 will be removed last */
list_for_each_entry_safe_reverse(fn, tmp,
@@ -134,7 +145,7 @@ static void process_one_interrupt(struct rmi_driver_data *data,
}
}
-int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
+static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
{
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
struct device *dev = &rmi_dev->dev;
@@ -144,7 +155,7 @@ int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
if (!data)
return 0;
- if (!rmi_dev->xport->attn_data) {
+ if (!data->attn_data.data) {
error = rmi_read_block(rmi_dev,
data->f01_container->fd.data_base_addr + 1,
data->irq_status, data->num_of_irq_regs);
@@ -179,7 +190,81 @@ int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
return 0;
}
-EXPORT_SYMBOL_GPL(rmi_process_interrupt_requests);
+
+void rmi_set_attn_data(struct rmi_device *rmi_dev, unsigned long irq_status,
+ void *data, size_t size)
+{
+ struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
+ struct rmi4_attn_data attn_data;
+ void *fifo_data;
+
+ if (!drvdata->enabled)
+ return;
+
+ fifo_data = kmemdup(data, size, GFP_ATOMIC);
+ if (!fifo_data)
+ return;
+
+ attn_data.irq_status = irq_status;
+ attn_data.size = size;
+ attn_data.data = fifo_data;
+
+ kfifo_put(&drvdata->attn_fifo, attn_data);
+}
+EXPORT_SYMBOL_GPL(rmi_set_attn_data);
+
+static irqreturn_t rmi_irq_fn(int irq, void *dev_id)
+{
+ struct rmi_device *rmi_dev = dev_id;
+ struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
+ struct rmi4_attn_data attn_data = {0};
+ int ret, count;
+
+ count = kfifo_get(&drvdata->attn_fifo, &attn_data);
+ if (count) {
+ *(drvdata->irq_status) = attn_data.irq_status;
+ drvdata->attn_data = attn_data;
+ }
+
+ ret = rmi_process_interrupt_requests(rmi_dev);
+ if (ret)
+ rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev,
+ "Failed to process interrupt request: %d\n", ret);
+
+ if (count)
+ kfree(attn_data.data);
+
+ if (!kfifo_is_empty(&drvdata->attn_fifo))
+ return rmi_irq_fn(irq, dev_id);
+
+ return IRQ_HANDLED;
+}
+
+static int rmi_irq_init(struct rmi_device *rmi_dev)
+{
+ struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+ int irq_flags = irq_get_trigger_type(pdata->irq);
+ int ret;
+
+ if (!irq_flags)
+ irq_flags = IRQF_TRIGGER_LOW;
+
+ ret = devm_request_threaded_irq(&rmi_dev->dev, pdata->irq, NULL,
+ rmi_irq_fn, irq_flags | IRQF_ONESHOT,
+ dev_name(rmi_dev->xport->dev),
+ rmi_dev);
+ if (ret < 0) {
+ dev_err(&rmi_dev->dev, "Failed to register interrupt %d\n",
+ pdata->irq);
+
+ return ret;
+ }
+
+ data->enabled = true;
+
+ return 0;
+}
static int suspend_one_function(struct rmi_function *fn)
{
@@ -249,7 +334,7 @@ static int rmi_resume_functions(struct rmi_device *rmi_dev)
return 0;
}
-static int enable_sensor(struct rmi_device *rmi_dev)
+int rmi_enable_sensor(struct rmi_device *rmi_dev)
{
int retval = 0;
@@ -380,8 +465,8 @@ static int rmi_driver_reset_handler(struct rmi_device *rmi_dev)
return 0;
}
-int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
- u16 pdt_address)
+static int rmi_read_pdt_entry(struct rmi_device *rmi_dev,
+ struct pdt_entry *entry, u16 pdt_address)
{
u8 buf[RMI_PDT_ENTRY_SIZE];
int error;
@@ -404,7 +489,6 @@ int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
return 0;
}
-EXPORT_SYMBOL_GPL(rmi_read_pdt_entry);
static void rmi_driver_copy_pdt_to_fd(const struct pdt_entry *pdt,
struct rmi_function_descriptor *fd)
@@ -423,6 +507,7 @@ static void rmi_driver_copy_pdt_to_fd(const struct pdt_entry *pdt,
static int rmi_scan_pdt_page(struct rmi_device *rmi_dev,
int page,
+ int *empty_pages,
void *ctx,
int (*callback)(struct rmi_device *rmi_dev,
void *ctx,
@@ -450,20 +535,30 @@ static int rmi_scan_pdt_page(struct rmi_device *rmi_dev,
return retval;
}
- return (data->f01_bootloader_mode || addr == pdt_start) ?
+ /*
+ * Count number of empty PDT pages. If a gap of two pages
+ * or more is found, stop scanning.
+ */
+ if (addr == pdt_start)
+ ++*empty_pages;
+ else
+ *empty_pages = 0;
+
+ return (data->bootloader_mode || *empty_pages >= 2) ?
RMI_SCAN_DONE : RMI_SCAN_CONTINUE;
}
-static int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
- int (*callback)(struct rmi_device *rmi_dev,
- void *ctx,
- const struct pdt_entry *entry))
+int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
+ int (*callback)(struct rmi_device *rmi_dev,
+ void *ctx, const struct pdt_entry *entry))
{
int page;
+ int empty_pages = 0;
int retval = RMI_SCAN_DONE;
for (page = 0; page <= RMI4_MAX_PAGE; page++) {
- retval = rmi_scan_pdt_page(rmi_dev, page, ctx, callback);
+ retval = rmi_scan_pdt_page(rmi_dev, page, &empty_pages,
+ ctx, callback);
if (retval != RMI_SCAN_CONTINUE)
break;
}
@@ -601,7 +696,6 @@ free_struct_buff:
kfree(struct_buf);
return ret;
}
-EXPORT_SYMBOL_GPL(rmi_read_register_desc);
const struct rmi_register_desc_item *rmi_get_register_desc_item(
struct rmi_register_descriptor *rdesc, u16 reg)
@@ -617,7 +711,6 @@ const struct rmi_register_desc_item *rmi_get_register_desc_item(
return NULL;
}
-EXPORT_SYMBOL_GPL(rmi_get_register_desc_item);
size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc)
{
@@ -631,7 +724,6 @@ size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc)
}
return size;
}
-EXPORT_SYMBOL_GPL(rmi_register_desc_calc_size);
/* Compute the register offset relative to the base address */
int rmi_register_desc_calc_reg_offset(
@@ -649,7 +741,6 @@ int rmi_register_desc_calc_reg_offset(
}
return -1;
}
-EXPORT_SYMBOL_GPL(rmi_register_desc_calc_reg_offset);
bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
u8 subpacket)
@@ -658,51 +749,55 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
subpacket) == subpacket;
}
-/* Indicates that flash programming is enabled (bootloader mode). */
-#define RMI_F01_STATUS_BOOTLOADER(status) (!!((status) & 0x40))
-
-/*
- * Given the PDT entry for F01, read the device status register to determine
- * if we're stuck in bootloader mode or not.
- *
- */
static int rmi_check_bootloader_mode(struct rmi_device *rmi_dev,
const struct pdt_entry *pdt)
{
- int error;
- u8 device_status;
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+ int ret;
+ u8 status;
- error = rmi_read(rmi_dev, pdt->data_base_addr + pdt->page_start,
- &device_status);
- if (error) {
- dev_err(&rmi_dev->dev,
- "Failed to read device status: %d.\n", error);
- return error;
+ if (pdt->function_number == 0x34 && pdt->function_version > 1) {
+ ret = rmi_read(rmi_dev, pdt->data_base_addr, &status);
+ if (ret) {
+ dev_err(&rmi_dev->dev,
+ "Failed to read F34 status: %d.\n", ret);
+ return ret;
+ }
+
+ if (status & BIT(7))
+ data->bootloader_mode = true;
+ } else if (pdt->function_number == 0x01) {
+ ret = rmi_read(rmi_dev, pdt->data_base_addr, &status);
+ if (ret) {
+ dev_err(&rmi_dev->dev,
+ "Failed to read F01 status: %d.\n", ret);
+ return ret;
+ }
+
+ if (status & BIT(6))
+ data->bootloader_mode = true;
}
- return RMI_F01_STATUS_BOOTLOADER(device_status);
+ return 0;
}
static int rmi_count_irqs(struct rmi_device *rmi_dev,
void *ctx, const struct pdt_entry *pdt)
{
- struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
int *irq_count = ctx;
+ int ret;
*irq_count += pdt->interrupt_source_count;
- if (pdt->function_number == 0x01) {
- data->f01_bootloader_mode =
- rmi_check_bootloader_mode(rmi_dev, pdt);
- if (data->f01_bootloader_mode)
- dev_warn(&rmi_dev->dev,
- "WARNING: RMI4 device is in bootloader mode!\n");
- }
+
+ ret = rmi_check_bootloader_mode(rmi_dev, pdt);
+ if (ret < 0)
+ return ret;
return RMI_SCAN_CONTINUE;
}
-static int rmi_initial_reset(struct rmi_device *rmi_dev,
- void *ctx, const struct pdt_entry *pdt)
+int rmi_initial_reset(struct rmi_device *rmi_dev, void *ctx,
+ const struct pdt_entry *pdt)
{
int error;
@@ -721,6 +816,7 @@ static int rmi_initial_reset(struct rmi_device *rmi_dev,
return RMI_SCAN_DONE;
}
+ rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Sending reset\n");
error = rmi_write_block(rmi_dev, cmd_addr, &cmd_buf, 1);
if (error) {
dev_err(&rmi_dev->dev,
@@ -777,6 +873,8 @@ static int rmi_create_function(struct rmi_device *rmi_dev,
if (pdt->function_number == 0x01)
data->f01_container = fn;
+ else if (pdt->function_number == 0x34)
+ data->f34_container = fn;
list_add_tail(&fn->node, &data->function_list);
@@ -787,23 +885,95 @@ err_put_fn:
return error;
}
-int rmi_driver_suspend(struct rmi_device *rmi_dev)
+void rmi_enable_irq(struct rmi_device *rmi_dev, bool clear_wake)
{
- int retval = 0;
+ struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+ int irq = pdata->irq;
+ int irq_flags;
+ int retval;
+
+ mutex_lock(&data->enabled_mutex);
+
+ if (data->enabled)
+ goto out;
+
+ enable_irq(irq);
+ data->enabled = true;
+ if (clear_wake && device_may_wakeup(rmi_dev->xport->dev)) {
+ retval = disable_irq_wake(irq);
+ if (!retval)
+ dev_warn(&rmi_dev->dev,
+ "Failed to disable irq for wake: %d\n",
+ retval);
+ }
+
+ /*
+ * Call rmi_process_interrupt_requests() after enabling irq,
+ * otherwise we may lose interrupt on edge-triggered systems.
+ */
+ irq_flags = irq_get_trigger_type(pdata->irq);
+ if (irq_flags & IRQ_TYPE_EDGE_BOTH)
+ rmi_process_interrupt_requests(rmi_dev);
+
+out:
+ mutex_unlock(&data->enabled_mutex);
+}
+
+void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake)
+{
+ struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+ struct rmi4_attn_data attn_data = {0};
+ int irq = pdata->irq;
+ int retval, count;
+
+ mutex_lock(&data->enabled_mutex);
+
+ if (!data->enabled)
+ goto out;
+
+ data->enabled = false;
+ disable_irq(irq);
+ if (enable_wake && device_may_wakeup(rmi_dev->xport->dev)) {
+ retval = enable_irq_wake(irq);
+ if (!retval)
+ dev_warn(&rmi_dev->dev,
+ "Failed to enable irq for wake: %d\n",
+ retval);
+ }
+
+ /* make sure the fifo is clean */
+ while (!kfifo_is_empty(&data->attn_fifo)) {
+ count = kfifo_get(&data->attn_fifo, &attn_data);
+ if (count)
+ kfree(attn_data.data);
+ }
+
+out:
+ mutex_unlock(&data->enabled_mutex);
+}
+
+int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake)
+{
+ int retval;
retval = rmi_suspend_functions(rmi_dev);
if (retval)
dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
retval);
+ rmi_disable_irq(rmi_dev, enable_wake);
return retval;
}
EXPORT_SYMBOL_GPL(rmi_driver_suspend);
-int rmi_driver_resume(struct rmi_device *rmi_dev)
+int rmi_driver_resume(struct rmi_device *rmi_dev, bool clear_wake)
{
int retval;
+ rmi_enable_irq(rmi_dev, clear_wake);
+
retval = rmi_resume_functions(rmi_dev);
if (retval)
dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
@@ -817,6 +987,9 @@ static int rmi_driver_remove(struct device *dev)
{
struct rmi_device *rmi_dev = to_rmi_device(dev);
+ rmi_disable_irq(rmi_dev, false);
+
+ rmi_f34_remove_sysfs(rmi_dev);
rmi_free_function_list(rmi_dev);
return 0;
@@ -843,15 +1016,95 @@ static inline int rmi_driver_of_probe(struct device *dev,
}
#endif
+int rmi_probe_interrupts(struct rmi_driver_data *data)
+{
+ struct rmi_device *rmi_dev = data->rmi_dev;
+ struct device *dev = &rmi_dev->dev;
+ int irq_count;
+ size_t size;
+ int retval;
+
+ /*
+ * We need to count the IRQs and allocate their storage before scanning
+ * the PDT and creating the function entries, because adding a new
+ * function can trigger events that result in the IRQ related storage
+ * being accessed.
+ */
+ rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Counting IRQs.\n", __func__);
+ irq_count = 0;
+ data->bootloader_mode = false;
+
+ retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs);
+ if (retval < 0) {
+ dev_err(dev, "IRQ counting failed with code %d.\n", retval);
+ return retval;
+ }
+
+ if (data->bootloader_mode)
+ dev_warn(&rmi_dev->dev, "Device in bootloader mode.\n");
+
+ data->irq_count = irq_count;
+ data->num_of_irq_regs = (data->irq_count + 7) / 8;
+
+ size = BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long);
+ data->irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL);
+ if (!data->irq_memory) {
+ dev_err(dev, "Failed to allocate memory for irq masks.\n");
+ return retval;
+ }
+
+ data->irq_status = data->irq_memory + size * 0;
+ data->fn_irq_bits = data->irq_memory + size * 1;
+ data->current_irq_mask = data->irq_memory + size * 2;
+ data->new_irq_mask = data->irq_memory + size * 3;
+
+ return retval;
+}
+
+int rmi_init_functions(struct rmi_driver_data *data)
+{
+ struct rmi_device *rmi_dev = data->rmi_dev;
+ struct device *dev = &rmi_dev->dev;
+ int irq_count;
+ int retval;
+
+ irq_count = 0;
+ rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Creating functions.\n", __func__);
+ retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function);
+ if (retval < 0) {
+ dev_err(dev, "Function creation failed with code %d.\n",
+ retval);
+ goto err_destroy_functions;
+ }
+
+ if (!data->f01_container) {
+ dev_err(dev, "Missing F01 container!\n");
+ retval = -EINVAL;
+ goto err_destroy_functions;
+ }
+
+ retval = rmi_read_block(rmi_dev,
+ data->f01_container->fd.control_base_addr + 1,
+ data->current_irq_mask, data->num_of_irq_regs);
+ if (retval < 0) {
+ dev_err(dev, "%s: Failed to read current IRQ mask.\n",
+ __func__);
+ goto err_destroy_functions;
+ }
+
+ return 0;
+
+err_destroy_functions:
+ rmi_free_function_list(rmi_dev);
+ return retval;
+}
+
static int rmi_driver_probe(struct device *dev)
{
struct rmi_driver *rmi_driver;
struct rmi_driver_data *data;
struct rmi_device_platform_data *pdata;
struct rmi_device *rmi_dev;
- size_t size;
- void *irq_memory;
- int irq_count;
int retval;
rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Starting probe.\n",
@@ -917,35 +1170,12 @@ static int rmi_driver_probe(struct device *dev)
PDT_PROPERTIES_LOCATION, retval);
}
- /*
- * We need to count the IRQs and allocate their storage before scanning
- * the PDT and creating the function entries, because adding a new
- * function can trigger events that result in the IRQ related storage
- * being accessed.
- */
- rmi_dbg(RMI_DEBUG_CORE, dev, "Counting IRQs.\n");
- irq_count = 0;
- retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs);
- if (retval < 0) {
- dev_err(dev, "IRQ counting failed with code %d.\n", retval);
- goto err;
- }
- data->irq_count = irq_count;
- data->num_of_irq_regs = (data->irq_count + 7) / 8;
-
mutex_init(&data->irq_mutex);
+ mutex_init(&data->enabled_mutex);
- size = BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long);
- irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL);
- if (!irq_memory) {
- dev_err(dev, "Failed to allocate memory for irq masks.\n");
+ retval = rmi_probe_interrupts(data);
+ if (retval)
goto err;
- }
-
- data->irq_status = irq_memory + size * 0;
- data->fn_irq_bits = irq_memory + size * 1;
- data->current_irq_mask = irq_memory + size * 2;
- data->new_irq_mask = irq_memory + size * 3;
if (rmi_dev->xport->input) {
/*
@@ -962,36 +1192,20 @@ static int rmi_driver_probe(struct device *dev)
dev_err(dev, "%s: Failed to allocate input device.\n",
__func__);
retval = -ENOMEM;
- goto err_destroy_functions;
+ goto err;
}
rmi_driver_set_input_params(rmi_dev, data->input);
data->input->phys = devm_kasprintf(dev, GFP_KERNEL,
"%s/input0", dev_name(dev));
}
- irq_count = 0;
- rmi_dbg(RMI_DEBUG_CORE, dev, "Creating functions.");
- retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function);
- if (retval < 0) {
- dev_err(dev, "Function creation failed with code %d.\n",
- retval);
- goto err_destroy_functions;
- }
-
- if (!data->f01_container) {
- dev_err(dev, "Missing F01 container!\n");
- retval = -EINVAL;
- goto err_destroy_functions;
- }
+ retval = rmi_init_functions(data);
+ if (retval)
+ goto err;
- retval = rmi_read_block(rmi_dev,
- data->f01_container->fd.control_base_addr + 1,
- data->current_irq_mask, data->num_of_irq_regs);
- if (retval < 0) {
- dev_err(dev, "%s: Failed to read current IRQ mask.\n",
- __func__);
- goto err_destroy_functions;
- }
+ retval = rmi_f34_create_sysfs(rmi_dev);
+ if (retval)
+ goto err;
if (data->input) {
rmi_driver_set_input_name(rmi_dev, data->input);
@@ -1004,9 +1218,13 @@ static int rmi_driver_probe(struct device *dev)
}
}
+ retval = rmi_irq_init(rmi_dev);
+ if (retval < 0)
+ goto err_destroy_functions;
+
if (data->f01_container->dev.driver)
/* Driver already bound, so enable ATTN now. */
- return enable_sensor(rmi_dev);
+ return rmi_enable_sensor(rmi_dev);
return 0;
diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h
index 6e140fa3cce1..24f8f764d171 100644
--- a/drivers/input/rmi4/rmi_driver.h
+++ b/drivers/input/rmi4/rmi_driver.h
@@ -51,9 +51,6 @@ struct pdt_entry {
u8 function_number;
};
-int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
- u16 pdt_address);
-
#define RMI_REG_DESC_PRESENSE_BITS (32 * BITS_PER_BYTE)
#define RMI_REG_DESC_SUBPACKET_BITS (37 * BITS_PER_BYTE)
@@ -95,11 +92,40 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
bool rmi_is_physical_driver(struct device_driver *);
int rmi_register_physical_driver(void);
void rmi_unregister_physical_driver(void);
+void rmi_free_function_list(struct rmi_device *rmi_dev);
+int rmi_enable_sensor(struct rmi_device *rmi_dev);
+int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
+ int (*callback)(struct rmi_device *rmi_dev, void *ctx,
+ const struct pdt_entry *entry));
+int rmi_probe_interrupts(struct rmi_driver_data *data);
+void rmi_enable_irq(struct rmi_device *rmi_dev, bool clear_wake);
+void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake);
+int rmi_init_functions(struct rmi_driver_data *data);
+int rmi_initial_reset(struct rmi_device *rmi_dev, void *ctx,
+ const struct pdt_entry *pdt);
char *rmi_f01_get_product_ID(struct rmi_function *fn);
+#ifdef CONFIG_RMI4_F34
+int rmi_f34_create_sysfs(struct rmi_device *rmi_dev);
+void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev);
+#else
+static inline int rmi_f34_create_sysfs(struct rmi_device *rmi_dev)
+{
+ return 0;
+}
+
+static inline void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev)
+{
+}
+#endif /* CONFIG_RMI_F34 */
+
extern struct rmi_function_handler rmi_f01_handler;
+extern struct rmi_function_handler rmi_f03_handler;
extern struct rmi_function_handler rmi_f11_handler;
extern struct rmi_function_handler rmi_f12_handler;
extern struct rmi_function_handler rmi_f30_handler;
+extern struct rmi_function_handler rmi_f34_handler;
+extern struct rmi_function_handler rmi_f54_handler;
+extern struct rmi_function_handler rmi_f55_handler;
#endif
diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c
index fac81fc9bcf6..cae35c6cde31 100644
--- a/drivers/input/rmi4/rmi_f01.c
+++ b/drivers/input/rmi4/rmi_f01.c
@@ -63,6 +63,8 @@ struct f01_basic_properties {
#define RMI_F01_STATUS_CODE(status) ((status) & 0x0f)
/* The device has lost its configuration for some reason. */
#define RMI_F01_STATUS_UNCONFIGURED(status) (!!((status) & 0x80))
+/* The device is in bootloader mode */
+#define RMI_F01_STATUS_BOOTLOADER(status) ((status) & 0x40)
/* Control register bits */
@@ -327,12 +329,12 @@ static int rmi_f01_probe(struct rmi_function *fn)
}
switch (pdata->power_management.nosleep) {
- case RMI_F01_NOSLEEP_DEFAULT:
+ case RMI_REG_STATE_DEFAULT:
break;
- case RMI_F01_NOSLEEP_OFF:
+ case RMI_REG_STATE_OFF:
f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_NOSLEEP_BIT;
break;
- case RMI_F01_NOSLEEP_ON:
+ case RMI_REG_STATE_ON:
f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT;
break;
}
@@ -594,6 +596,10 @@ static int rmi_f01_attention(struct rmi_function *fn,
return error;
}
+ if (RMI_F01_STATUS_BOOTLOADER(device_status))
+ dev_warn(&fn->dev,
+ "Device in bootloader mode, please update firmware\n");
+
if (RMI_F01_STATUS_UNCONFIGURED(device_status)) {
dev_warn(&fn->dev, "Device reset detected.\n");
error = rmi_dev->driver->reset_handler(rmi_dev);
diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c
new file mode 100644
index 000000000000..8a7ca3e2f95e
--- /dev/null
+++ b/drivers/input/rmi4/rmi_f03.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2015-2016 Red Hat
+ * Copyright (C) 2015 Lyude Paul <thatslyude@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/serio.h>
+#include <linux/notifier.h>
+#include "rmi_driver.h"
+
+#define RMI_F03_RX_DATA_OFB 0x01
+#define RMI_F03_OB_SIZE 2
+
+#define RMI_F03_OB_OFFSET 2
+#define RMI_F03_OB_DATA_OFFSET 1
+#define RMI_F03_OB_FLAG_TIMEOUT BIT(6)
+#define RMI_F03_OB_FLAG_PARITY BIT(7)
+
+#define RMI_F03_DEVICE_COUNT 0x07
+#define RMI_F03_BYTES_PER_DEVICE 0x07
+#define RMI_F03_BYTES_PER_DEVICE_SHIFT 4
+#define RMI_F03_QUEUE_LENGTH 0x0F
+
+struct f03_data {
+ struct rmi_function *fn;
+
+ struct serio *serio;
+
+ u8 device_count;
+ u8 rx_queue_length;
+};
+
+static int rmi_f03_pt_write(struct serio *id, unsigned char val)
+{
+ struct f03_data *f03 = id->port_data;
+ int error;
+
+ rmi_dbg(RMI_DEBUG_FN, &f03->fn->dev,
+ "%s: Wrote %.2hhx to PS/2 passthrough address",
+ __func__, val);
+
+ error = rmi_write(f03->fn->rmi_dev, f03->fn->fd.data_base_addr, val);
+ if (error) {
+ dev_err(&f03->fn->dev,
+ "%s: Failed to write to F03 TX register (%d).\n",
+ __func__, error);
+ return error;
+ }
+
+ return 0;
+}
+
+static int rmi_f03_initialize(struct f03_data *f03)
+{
+ struct rmi_function *fn = f03->fn;
+ struct device *dev = &fn->dev;
+ int error;
+ u8 bytes_per_device;
+ u8 query1;
+ u8 query2[RMI_F03_DEVICE_COUNT * RMI_F03_BYTES_PER_DEVICE];
+ size_t query2_len;
+
+ error = rmi_read(fn->rmi_dev, fn->fd.query_base_addr, &query1);
+ if (error) {
+ dev_err(dev, "Failed to read query register (%d).\n", error);
+ return error;
+ }
+
+ f03->device_count = query1 & RMI_F03_DEVICE_COUNT;
+ bytes_per_device = (query1 >> RMI_F03_BYTES_PER_DEVICE_SHIFT) &
+ RMI_F03_BYTES_PER_DEVICE;
+
+ query2_len = f03->device_count * bytes_per_device;
+
+ /*
+ * The first generation of image sensors don't have a second part to
+ * their f03 query, as such we have to set some of these values manually
+ */
+ if (query2_len < 1) {
+ f03->device_count = 1;
+ f03->rx_queue_length = 7;
+ } else {
+ error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr + 1,
+ query2, query2_len);
+ if (error) {
+ dev_err(dev,
+ "Failed to read second set of query registers (%d).\n",
+ error);
+ return error;
+ }
+
+ f03->rx_queue_length = query2[0] & RMI_F03_QUEUE_LENGTH;
+ }
+
+ return 0;
+}
+
+static int rmi_f03_register_pt(struct f03_data *f03)
+{
+ struct serio *serio;
+
+ serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!serio)
+ return -ENOMEM;
+
+ serio->id.type = SERIO_8042;
+ serio->write = rmi_f03_pt_write;
+ serio->port_data = f03;
+
+ strlcpy(serio->name, "Synaptics RMI4 PS/2 pass-through",
+ sizeof(serio->name));
+ strlcpy(serio->phys, "synaptics-rmi4-pt/serio1",
+ sizeof(serio->phys));
+ serio->dev.parent = &f03->fn->dev;
+
+ f03->serio = serio;
+
+ serio_register_port(serio);
+
+ return 0;
+}
+
+static int rmi_f03_probe(struct rmi_function *fn)
+{
+ struct device *dev = &fn->dev;
+ struct f03_data *f03;
+ int error;
+
+ f03 = devm_kzalloc(dev, sizeof(struct f03_data), GFP_KERNEL);
+ if (!f03)
+ return -ENOMEM;
+
+ f03->fn = fn;
+
+ error = rmi_f03_initialize(f03);
+ if (error < 0)
+ return error;
+
+ if (f03->device_count != 1)
+ dev_warn(dev, "found %d devices on PS/2 passthrough",
+ f03->device_count);
+
+ dev_set_drvdata(dev, f03);
+
+ error = rmi_f03_register_pt(f03);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static int rmi_f03_config(struct rmi_function *fn)
+{
+ fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
+
+ return 0;
+}
+
+static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
+{
+ struct rmi_device *rmi_dev = fn->rmi_dev;
+ struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
+ struct f03_data *f03 = dev_get_drvdata(&fn->dev);
+ u16 data_addr = fn->fd.data_base_addr;
+ const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE;
+ u8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE];
+ u8 ob_status;
+ u8 ob_data;
+ unsigned int serio_flags;
+ int i;
+ int error;
+
+ if (!rmi_dev)
+ return -ENODEV;
+
+ if (drvdata->attn_data.data) {
+ /* First grab the data passed by the transport device */
+ if (drvdata->attn_data.size < ob_len) {
+ dev_warn(&fn->dev, "F03 interrupted, but data is missing!\n");
+ return 0;
+ }
+
+ memcpy(obs, drvdata->attn_data.data, ob_len);
+
+ drvdata->attn_data.data += ob_len;
+ drvdata->attn_data.size -= ob_len;
+ } else {
+ /* Grab all of the data registers, and check them for data */
+ error = rmi_read_block(fn->rmi_dev, data_addr + RMI_F03_OB_OFFSET,
+ &obs, ob_len);
+ if (error) {
+ dev_err(&fn->dev,
+ "%s: Failed to read F03 output buffers: %d\n",
+ __func__, error);
+ serio_interrupt(f03->serio, 0, SERIO_TIMEOUT);
+ return error;
+ }
+ }
+
+ for (i = 0; i < ob_len; i += RMI_F03_OB_SIZE) {
+ ob_status = obs[i];
+ ob_data = obs[i + RMI_F03_OB_DATA_OFFSET];
+ serio_flags = 0;
+
+ if (!(ob_status & RMI_F03_RX_DATA_OFB))
+ continue;
+
+ if (ob_status & RMI_F03_OB_FLAG_TIMEOUT)
+ serio_flags |= SERIO_TIMEOUT;
+ if (ob_status & RMI_F03_OB_FLAG_PARITY)
+ serio_flags |= SERIO_PARITY;
+
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev,
+ "%s: Received %.2hhx from PS2 guest T: %c P: %c\n",
+ __func__, ob_data,
+ serio_flags & SERIO_TIMEOUT ? 'Y' : 'N',
+ serio_flags & SERIO_PARITY ? 'Y' : 'N');
+
+ serio_interrupt(f03->serio, ob_data, serio_flags);
+ }
+
+ return 0;
+}
+
+static void rmi_f03_remove(struct rmi_function *fn)
+{
+ struct f03_data *f03 = dev_get_drvdata(&fn->dev);
+
+ serio_unregister_port(f03->serio);
+}
+
+struct rmi_function_handler rmi_f03_handler = {
+ .driver = {
+ .name = "rmi4_f03",
+ },
+ .func = 0x03,
+ .probe = rmi_f03_probe,
+ .config = rmi_f03_config,
+ .attention = rmi_f03_attention,
+ .remove = rmi_f03_remove,
+};
+
+MODULE_AUTHOR("Lyude Paul <thatslyude@gmail.com>");
+MODULE_DESCRIPTION("RMI F03 module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c
index 20c7134b3d3b..68279f3c5130 100644
--- a/drivers/input/rmi4/rmi_f11.c
+++ b/drivers/input/rmi4/rmi_f11.c
@@ -572,31 +572,48 @@ static inline u8 rmi_f11_parse_finger_state(const u8 *f_state, u8 n_finger)
static void rmi_f11_finger_handler(struct f11_data *f11,
struct rmi_2d_sensor *sensor,
- unsigned long *irq_bits, int num_irq_regs)
+ unsigned long *irq_bits, int num_irq_regs,
+ int size)
{
const u8 *f_state = f11->data.f_state;
u8 finger_state;
u8 i;
+ int abs_fingers;
+ int rel_fingers;
+ int abs_size = sensor->nbr_fingers * RMI_F11_ABS_BYTES;
int abs_bits = bitmap_and(f11->result_bits, irq_bits, f11->abs_mask,
num_irq_regs * 8);
int rel_bits = bitmap_and(f11->result_bits, irq_bits, f11->rel_mask,
num_irq_regs * 8);
- for (i = 0; i < sensor->nbr_fingers; i++) {
- /* Possible of having 4 fingers per f_statet register */
- finger_state = rmi_f11_parse_finger_state(f_state, i);
- if (finger_state == F11_RESERVED) {
- pr_err("Invalid finger state[%d]: 0x%02x", i,
- finger_state);
- continue;
- }
+ if (abs_bits) {
+ if (abs_size > size)
+ abs_fingers = size / RMI_F11_ABS_BYTES;
+ else
+ abs_fingers = sensor->nbr_fingers;
+
+ for (i = 0; i < abs_fingers; i++) {
+ /* Possible of having 4 fingers per f_state register */
+ finger_state = rmi_f11_parse_finger_state(f_state, i);
+ if (finger_state == F11_RESERVED) {
+ pr_err("Invalid finger state[%d]: 0x%02x", i,
+ finger_state);
+ continue;
+ }
- if (abs_bits)
rmi_f11_abs_pos_process(f11, sensor, &sensor->objs[i],
finger_state, i);
+ }
+ }
+
+ if (rel_bits) {
+ if ((abs_size + sensor->nbr_fingers * RMI_F11_REL_BYTES) > size)
+ rel_fingers = (size - abs_size) / RMI_F11_REL_BYTES;
+ else
+ rel_fingers = sensor->nbr_fingers;
- if (rel_bits)
+ for (i = 0; i < rel_fingers; i++)
rmi_f11_rel_pos_report(f11, i);
}
@@ -612,7 +629,7 @@ static void rmi_f11_finger_handler(struct f11_data *f11,
sensor->nbr_fingers,
sensor->dmax);
- for (i = 0; i < sensor->nbr_fingers; i++) {
+ for (i = 0; i < abs_fingers; i++) {
finger_state = rmi_f11_parse_finger_state(f_state, i);
if (finger_state == F11_RESERVED)
/* no need to send twice the error */
@@ -1063,8 +1080,8 @@ static int rmi_f11_initialize(struct rmi_function *fn)
rc = rmi_2d_sensor_of_probe(&fn->dev, &f11->sensor_pdata);
if (rc)
return rc;
- } else if (pdata->sensor_pdata) {
- f11->sensor_pdata = *pdata->sensor_pdata;
+ } else {
+ f11->sensor_pdata = pdata->sensor_pdata;
}
f11->rezero_wait_ms = f11->sensor_pdata.rezero_wait;
@@ -1125,6 +1142,8 @@ static int rmi_f11_initialize(struct rmi_function *fn)
sensor->topbuttonpad = f11->sensor_pdata.topbuttonpad;
sensor->kernel_tracking = f11->sensor_pdata.kernel_tracking;
sensor->dmax = f11->sensor_pdata.dmax;
+ sensor->dribble = f11->sensor_pdata.dribble;
+ sensor->palm_detect = f11->sensor_pdata.palm_detect;
if (f11->sens_query.has_physical_props) {
sensor->x_mm = f11->sens_query.x_sensor_size_mm;
@@ -1192,11 +1211,33 @@ static int rmi_f11_initialize(struct rmi_function *fn)
ctrl->ctrl0_11[RMI_F11_DELTA_Y_THRESHOLD] =
sensor->axis_align.delta_y_threshold;
- if (f11->sens_query.has_dribble)
- ctrl->ctrl0_11[0] = ctrl->ctrl0_11[0] & ~BIT(6);
+ if (f11->sens_query.has_dribble) {
+ switch (sensor->dribble) {
+ case RMI_REG_STATE_OFF:
+ ctrl->ctrl0_11[0] &= ~BIT(6);
+ break;
+ case RMI_REG_STATE_ON:
+ ctrl->ctrl0_11[0] |= BIT(6);
+ break;
+ case RMI_REG_STATE_DEFAULT:
+ default:
+ break;
+ }
+ }
- if (f11->sens_query.has_palm_det)
- ctrl->ctrl0_11[11] = ctrl->ctrl0_11[11] & ~BIT(0);
+ if (f11->sens_query.has_palm_det) {
+ switch (sensor->palm_detect) {
+ case RMI_REG_STATE_OFF:
+ ctrl->ctrl0_11[11] &= ~BIT(0);
+ break;
+ case RMI_REG_STATE_ON:
+ ctrl->ctrl0_11[11] |= BIT(0);
+ break;
+ case RMI_REG_STATE_DEFAULT:
+ default:
+ break;
+ }
+ }
rc = f11_write_control_regs(fn, &f11->sens_query,
&f11->dev_controls, fn->fd.query_base_addr);
@@ -1242,12 +1283,21 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
struct f11_data *f11 = dev_get_drvdata(&fn->dev);
u16 data_base_addr = fn->fd.data_base_addr;
int error;
+ int valid_bytes = f11->sensor.pkt_size;
- if (rmi_dev->xport->attn_data) {
- memcpy(f11->sensor.data_pkt, rmi_dev->xport->attn_data,
- f11->sensor.attn_size);
- rmi_dev->xport->attn_data += f11->sensor.attn_size;
- rmi_dev->xport->attn_size -= f11->sensor.attn_size;
+ if (drvdata->attn_data.data) {
+ /*
+ * The valid data in the attention report is less then
+ * expected. Only process the complete fingers.
+ */
+ if (f11->sensor.attn_size > drvdata->attn_data.size)
+ valid_bytes = drvdata->attn_data.size;
+ else
+ valid_bytes = f11->sensor.attn_size;
+ memcpy(f11->sensor.data_pkt, drvdata->attn_data.data,
+ valid_bytes);
+ drvdata->attn_data.data += f11->sensor.attn_size;
+ drvdata->attn_data.size -= f11->sensor.attn_size;
} else {
error = rmi_read_block(rmi_dev,
data_base_addr, f11->sensor.data_pkt,
@@ -1257,7 +1307,7 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
}
rmi_f11_finger_handler(f11, &f11->sensor, irq_bits,
- drvdata->num_of_irq_regs);
+ drvdata->num_of_irq_regs, valid_bytes);
return 0;
}
diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c
index 332c02f0b107..07aff4356fe0 100644
--- a/drivers/input/rmi4/rmi_f12.c
+++ b/drivers/input/rmi4/rmi_f12.c
@@ -26,9 +26,12 @@ enum rmi_f12_object_type {
RMI_F12_OBJECT_SMALL_OBJECT = 0x0D,
};
+#define F12_DATA1_BYTES_PER_OBJ 8
+
struct f12_data {
struct rmi_2d_sensor sensor;
struct rmi_2d_sensor_platform_data sensor_pdata;
+ bool has_dribble;
u16 data_addr;
@@ -68,10 +71,6 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
u8 buf[15];
int pitch_x = 0;
int pitch_y = 0;
- int clip_x_low = 0;
- int clip_x_high = 0;
- int clip_y_low = 0;
- int clip_y_high = 0;
int rx_receivers = 0;
int tx_receivers = 0;
int sensor_flags = 0;
@@ -124,7 +123,9 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
}
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: x low: %d x high: %d y low: %d y high: %d\n",
- __func__, clip_x_low, clip_x_high, clip_y_low, clip_y_high);
+ __func__,
+ sensor->axis_align.clip_x_low, sensor->axis_align.clip_x_high,
+ sensor->axis_align.clip_y_low, sensor->axis_align.clip_y_high);
if (rmi_register_desc_has_subpacket(item, 3)) {
rx_receivers = buf[offset];
@@ -146,12 +147,16 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
return 0;
}
-static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
+static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1, int size)
{
int i;
struct rmi_2d_sensor *sensor = &f12->sensor;
+ int objects = f12->data1->num_subpackets;
+
+ if ((f12->data1->num_subpackets * F12_DATA1_BYTES_PER_OBJ) > size)
+ objects = size / F12_DATA1_BYTES_PER_OBJ;
- for (i = 0; i < f12->data1->num_subpackets; i++) {
+ for (i = 0; i < objects; i++) {
struct rmi_2d_sensor_abs_object *obj = &sensor->objs[i];
obj->type = RMI_2D_OBJECT_NONE;
@@ -182,7 +187,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
rmi_2d_sensor_abs_process(sensor, obj, i);
- data1 += 8;
+ data1 += F12_DATA1_BYTES_PER_OBJ;
}
if (sensor->kernel_tracking)
@@ -192,7 +197,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
sensor->nbr_fingers,
sensor->dmax);
- for (i = 0; i < sensor->nbr_fingers; i++)
+ for (i = 0; i < objects; i++)
rmi_2d_sensor_abs_report(sensor, &sensor->objs[i], i);
}
@@ -201,14 +206,20 @@ static int rmi_f12_attention(struct rmi_function *fn,
{
int retval;
struct rmi_device *rmi_dev = fn->rmi_dev;
+ struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
struct f12_data *f12 = dev_get_drvdata(&fn->dev);
struct rmi_2d_sensor *sensor = &f12->sensor;
-
- if (rmi_dev->xport->attn_data) {
- memcpy(sensor->data_pkt, rmi_dev->xport->attn_data,
- sensor->attn_size);
- rmi_dev->xport->attn_data += sensor->attn_size;
- rmi_dev->xport->attn_size -= sensor->attn_size;
+ int valid_bytes = sensor->pkt_size;
+
+ if (drvdata->attn_data.data) {
+ if (sensor->attn_size > drvdata->attn_data.size)
+ valid_bytes = drvdata->attn_data.size;
+ else
+ valid_bytes = sensor->attn_size;
+ memcpy(sensor->data_pkt, drvdata->attn_data.data,
+ valid_bytes);
+ drvdata->attn_data.data += sensor->attn_size;
+ drvdata->attn_data.size -= sensor->attn_size;
} else {
retval = rmi_read_block(rmi_dev, f12->data_addr,
sensor->data_pkt, sensor->pkt_size);
@@ -221,19 +232,83 @@ static int rmi_f12_attention(struct rmi_function *fn,
if (f12->data1)
rmi_f12_process_objects(f12,
- &sensor->data_pkt[f12->data1_offset]);
+ &sensor->data_pkt[f12->data1_offset], valid_bytes);
input_mt_sync_frame(sensor->input);
return 0;
}
+static int rmi_f12_write_control_regs(struct rmi_function *fn)
+{
+ int ret;
+ const struct rmi_register_desc_item *item;
+ struct rmi_device *rmi_dev = fn->rmi_dev;
+ struct f12_data *f12 = dev_get_drvdata(&fn->dev);
+ int control_size;
+ char buf[3];
+ u16 control_offset = 0;
+ u8 subpacket_offset = 0;
+
+ if (f12->has_dribble
+ && (f12->sensor.dribble != RMI_REG_STATE_DEFAULT)) {
+ item = rmi_get_register_desc_item(&f12->control_reg_desc, 20);
+ if (item) {
+ control_offset = rmi_register_desc_calc_reg_offset(
+ &f12->control_reg_desc, 20);
+
+ /*
+ * The byte containing the EnableDribble bit will be
+ * in either byte 0 or byte 2 of control 20. Depending
+ * on the existence of subpacket 0. If control 20 is
+ * larger then 3 bytes, just read the first 3.
+ */
+ control_size = min(item->reg_size, 3UL);
+
+ ret = rmi_read_block(rmi_dev, fn->fd.control_base_addr
+ + control_offset, buf, control_size);
+ if (ret)
+ return ret;
+
+ if (rmi_register_desc_has_subpacket(item, 0))
+ subpacket_offset += 1;
+
+ switch (f12->sensor.dribble) {
+ case RMI_REG_STATE_OFF:
+ buf[subpacket_offset] &= ~BIT(2);
+ break;
+ case RMI_REG_STATE_ON:
+ buf[subpacket_offset] |= BIT(2);
+ break;
+ case RMI_REG_STATE_DEFAULT:
+ default:
+ break;
+ }
+
+ ret = rmi_write_block(rmi_dev,
+ fn->fd.control_base_addr + control_offset,
+ buf, control_size);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+
+}
+
static int rmi_f12_config(struct rmi_function *fn)
{
struct rmi_driver *drv = fn->rmi_dev->driver;
+ int ret;
drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
+ ret = rmi_f12_write_control_regs(fn);
+ if (ret)
+ dev_warn(&fn->dev,
+ "Failed to write F12 control registers: %d\n", ret);
+
return 0;
}
@@ -247,7 +322,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
const struct rmi_register_desc_item *item;
struct rmi_2d_sensor *sensor;
struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
- struct rmi_transport_dev *xport = rmi_dev->xport;
+ struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
u16 data_offset = 0;
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s\n", __func__);
@@ -260,7 +335,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
}
++query_addr;
- if (!(buf & 0x1)) {
+ if (!(buf & BIT(0))) {
dev_err(&fn->dev,
"Behavior of F12 without register descriptors is undefined.\n");
return -ENODEV;
@@ -270,12 +345,14 @@ static int rmi_f12_probe(struct rmi_function *fn)
if (!f12)
return -ENOMEM;
+ f12->has_dribble = !!(buf & BIT(3));
+
if (fn->dev.of_node) {
ret = rmi_2d_sensor_of_probe(&fn->dev, &f12->sensor_pdata);
if (ret)
return ret;
- } else if (pdata->sensor_pdata) {
- f12->sensor_pdata = *pdata->sensor_pdata;
+ } else {
+ f12->sensor_pdata = pdata->sensor_pdata;
}
ret = rmi_read_register_desc(rmi_dev, query_addr,
@@ -318,6 +395,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
sensor->x_mm = f12->sensor_pdata.x_mm;
sensor->y_mm = f12->sensor_pdata.y_mm;
+ sensor->dribble = f12->sensor_pdata.dribble;
if (sensor->sensor_type == rmi_sensor_default)
sensor->sensor_type =
@@ -343,7 +421,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
* HID attention reports.
*/
item = rmi_get_register_desc_item(&f12->data_reg_desc, 0);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 1);
@@ -357,15 +435,15 @@ static int rmi_f12_probe(struct rmi_function *fn)
}
item = rmi_get_register_desc_item(&f12->data_reg_desc, 2);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 3);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 4);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 5);
@@ -377,22 +455,22 @@ static int rmi_f12_probe(struct rmi_function *fn)
}
item = rmi_get_register_desc_item(&f12->data_reg_desc, 6);
- if (item && !xport->attn_data) {
+ if (item && !drvdata->attn_data.data) {
f12->data6 = item;
f12->data6_offset = data_offset;
data_offset += item->reg_size;
}
item = rmi_get_register_desc_item(&f12->data_reg_desc, 7);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 8);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 9);
- if (item && !xport->attn_data) {
+ if (item && !drvdata->attn_data.data) {
f12->data9 = item;
f12->data9_offset = data_offset;
data_offset += item->reg_size;
@@ -401,27 +479,27 @@ static int rmi_f12_probe(struct rmi_function *fn)
}
item = rmi_get_register_desc_item(&f12->data_reg_desc, 10);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 11);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 12);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 13);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 14);
- if (item && !xport->attn_data)
+ if (item && !drvdata->attn_data.data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 15);
- if (item && !xport->attn_data) {
+ if (item && !drvdata->attn_data.data) {
f12->data15 = item;
f12->data15_offset = data_offset;
data_offset += item->reg_size;
diff --git a/drivers/input/rmi4/rmi_f30.c b/drivers/input/rmi4/rmi_f30.c
index 760aff1bc420..f4b491e3e0fd 100644
--- a/drivers/input/rmi4/rmi_f30.c
+++ b/drivers/input/rmi4/rmi_f30.c
@@ -99,6 +99,7 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
{
struct f30_data *f30 = dev_get_drvdata(&fn->dev);
struct rmi_device *rmi_dev = fn->rmi_dev;
+ struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
int retval;
int gpiled = 0;
int value = 0;
@@ -109,11 +110,15 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
return 0;
/* Read the gpi led data. */
- if (rmi_dev->xport->attn_data) {
- memcpy(f30->data_regs, rmi_dev->xport->attn_data,
+ if (drvdata->attn_data.data) {
+ if (drvdata->attn_data.size < f30->register_count) {
+ dev_warn(&fn->dev, "F30 interrupted, but data is missing\n");
+ return 0;
+ }
+ memcpy(f30->data_regs, drvdata->attn_data.data,
f30->register_count);
- rmi_dev->xport->attn_data += f30->register_count;
- rmi_dev->xport->attn_size -= f30->register_count;
+ drvdata->attn_data.data += f30->register_count;
+ drvdata->attn_data.size -= f30->register_count;
} else {
retval = rmi_read_block(rmi_dev, fn->fd.data_base_addr,
f30->data_regs, f30->register_count);
@@ -192,7 +197,7 @@ static int rmi_f30_config(struct rmi_function *fn)
rmi_get_platform_data(fn->rmi_dev);
int error;
- if (pdata->f30_data && pdata->f30_data->disable) {
+ if (pdata->f30_data.disable) {
drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
} else {
/* Write Control Register values back to device */
@@ -351,7 +356,7 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)
f30->gpioled_key_map = (u16 *)map_memory;
pdata = rmi_get_platform_data(rmi_dev);
- if (pdata && f30->has_gpio) {
+ if (f30->has_gpio) {
button = BTN_LEFT;
for (i = 0; i < f30->gpioled_count; i++) {
if (rmi_f30_is_valid_button(i, f30->ctrl)) {
@@ -362,8 +367,7 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)
* f30->has_mech_mouse_btns, but I am
* not sure, so use only the pdata info
*/
- if (pdata->f30_data &&
- pdata->f30_data->buttonpad)
+ if (pdata->f30_data.buttonpad)
break;
}
}
@@ -378,7 +382,7 @@ static int rmi_f30_probe(struct rmi_function *fn)
const struct rmi_device_platform_data *pdata =
rmi_get_platform_data(fn->rmi_dev);
- if (pdata->f30_data && pdata->f30_data->disable)
+ if (pdata->f30_data.disable)
return 0;
rc = rmi_f30_initialize(fn);
diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c
new file mode 100644
index 000000000000..9774dfbab9bb
--- /dev/null
+++ b/drivers/input/rmi4/rmi_f34.c
@@ -0,0 +1,516 @@
+/*
+ * Copyright (c) 2007-2016, Synaptics Incorporated
+ * Copyright (C) 2016 Zodiac Inflight Innovations
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/rmi.h>
+#include <linux/firmware.h>
+#include <asm/unaligned.h>
+#include <asm/unaligned.h>
+#include <linux/bitops.h>
+
+#include "rmi_driver.h"
+#include "rmi_f34.h"
+
+static int rmi_f34_write_bootloader_id(struct f34_data *f34)
+{
+ struct rmi_function *fn = f34->fn;
+ struct rmi_device *rmi_dev = fn->rmi_dev;
+ u8 bootloader_id[F34_BOOTLOADER_ID_LEN];
+ int ret;
+
+ ret = rmi_read_block(rmi_dev, fn->fd.query_base_addr,
+ bootloader_id, sizeof(bootloader_id));
+ if (ret) {
+ dev_err(&fn->dev, "%s: Reading bootloader ID failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: writing bootloader id '%c%c'\n",
+ __func__, bootloader_id[0], bootloader_id[1]);
+
+ ret = rmi_write_block(rmi_dev,
+ fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET,
+ bootloader_id, sizeof(bootloader_id));
+ if (ret) {
+ dev_err(&fn->dev, "Failed to write bootloader ID: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rmi_f34_command(struct f34_data *f34, u8 command,
+ unsigned int timeout, bool write_bl_id)
+{
+ struct rmi_function *fn = f34->fn;
+ struct rmi_device *rmi_dev = fn->rmi_dev;
+ int ret;
+
+ if (write_bl_id) {
+ ret = rmi_f34_write_bootloader_id(f34);
+ if (ret)
+ return ret;
+ }
+
+ init_completion(&f34->v5.cmd_done);
+
+ ret = rmi_read(rmi_dev, f34->v5.ctrl_address, &f34->v5.status);
+ if (ret) {
+ dev_err(&f34->fn->dev,
+ "%s: Failed to read cmd register: %d (command %#02x)\n",
+ __func__, ret, command);
+ return ret;
+ }
+
+ f34->v5.status |= command & 0x0f;
+
+ ret = rmi_write(rmi_dev, f34->v5.ctrl_address, f34->v5.status);
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "Failed to write F34 command %#02x: %d\n",
+ command, ret);
+ return ret;
+ }
+
+ if (!wait_for_completion_timeout(&f34->v5.cmd_done,
+ msecs_to_jiffies(timeout))) {
+
+ ret = rmi_read(rmi_dev, f34->v5.ctrl_address, &f34->v5.status);
+ if (ret) {
+ dev_err(&f34->fn->dev,
+ "%s: cmd %#02x timed out: %d\n",
+ __func__, command, ret);
+ return ret;
+ }
+
+ if (f34->v5.status & 0x7f) {
+ dev_err(&f34->fn->dev,
+ "%s: cmd %#02x timed out, status: %#02x\n",
+ __func__, command, f34->v5.status);
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static int rmi_f34_attention(struct rmi_function *fn, unsigned long *irq_bits)
+{
+ struct f34_data *f34 = dev_get_drvdata(&fn->dev);
+ int ret;
+
+ if (f34->bl_version != 5)
+ return 0;
+
+ ret = rmi_read(f34->fn->rmi_dev, f34->v5.ctrl_address, &f34->v5.status);
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: status: %#02x, ret: %d\n",
+ __func__, f34->v5.status, ret);
+
+ if (!ret && !(f34->v5.status & 0x7f))
+ complete(&f34->v5.cmd_done);
+
+ return 0;
+}
+
+static int rmi_f34_write_blocks(struct f34_data *f34, const void *data,
+ int block_count, u8 command)
+{
+ struct rmi_function *fn = f34->fn;
+ struct rmi_device *rmi_dev = fn->rmi_dev;
+ u16 address = fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET;
+ u8 start_address[] = { 0, 0 };
+ int i;
+ int ret;
+
+ ret = rmi_write_block(rmi_dev, fn->fd.data_base_addr,
+ start_address, sizeof(start_address));
+ if (ret) {
+ dev_err(&fn->dev, "Failed to write initial zeros: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < block_count; i++) {
+ ret = rmi_write_block(rmi_dev, address,
+ data, f34->v5.block_size);
+ if (ret) {
+ dev_err(&fn->dev,
+ "failed to write block #%d: %d\n", i, ret);
+ return ret;
+ }
+
+ ret = rmi_f34_command(f34, command, F34_IDLE_WAIT_MS, false);
+ if (ret) {
+ dev_err(&fn->dev,
+ "Failed to write command for block #%d: %d\n",
+ i, ret);
+ return ret;
+ }
+
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "wrote block %d of %d\n",
+ i + 1, block_count);
+
+ data += f34->v5.block_size;
+ }
+
+ return 0;
+}
+
+static int rmi_f34_write_firmware(struct f34_data *f34, const void *data)
+{
+ return rmi_f34_write_blocks(f34, data, f34->v5.fw_blocks,
+ F34_WRITE_FW_BLOCK);
+}
+
+static int rmi_f34_write_config(struct f34_data *f34, const void *data)
+{
+ return rmi_f34_write_blocks(f34, data, f34->v5.config_blocks,
+ F34_WRITE_CONFIG_BLOCK);
+}
+
+int rmi_f34_enable_flash(struct f34_data *f34)
+{
+ return rmi_f34_command(f34, F34_ENABLE_FLASH_PROG,
+ F34_ENABLE_WAIT_MS, true);
+}
+
+static int rmi_f34_flash_firmware(struct f34_data *f34,
+ const struct rmi_f34_firmware *syn_fw)
+{
+ struct rmi_function *fn = f34->fn;
+ int ret;
+
+ if (syn_fw->image_size) {
+ dev_info(&fn->dev, "Erasing firmware...\n");
+ ret = rmi_f34_command(f34, F34_ERASE_ALL,
+ F34_ERASE_WAIT_MS, true);
+ if (ret)
+ return ret;
+
+ dev_info(&fn->dev, "Writing firmware (%d bytes)...\n",
+ syn_fw->image_size);
+ ret = rmi_f34_write_firmware(f34, syn_fw->data);
+ if (ret)
+ return ret;
+ }
+
+ if (syn_fw->config_size) {
+ /*
+ * We only need to erase config if we haven't updated
+ * firmware.
+ */
+ if (!syn_fw->image_size) {
+ dev_info(&fn->dev, "Erasing config...\n");
+ ret = rmi_f34_command(f34, F34_ERASE_CONFIG,
+ F34_ERASE_WAIT_MS, true);
+ if (ret)
+ return ret;
+ }
+
+ dev_info(&fn->dev, "Writing config (%d bytes)...\n",
+ syn_fw->config_size);
+ ret = rmi_f34_write_config(f34,
+ &syn_fw->data[syn_fw->image_size]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int rmi_f34_update_firmware(struct f34_data *f34, const struct firmware *fw)
+{
+ const struct rmi_f34_firmware *syn_fw;
+ int ret;
+
+ syn_fw = (const struct rmi_f34_firmware *)fw->data;
+ BUILD_BUG_ON(offsetof(struct rmi_f34_firmware, data) !=
+ F34_FW_IMAGE_OFFSET);
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "FW size:%d, checksum:%08x, image_size:%d, config_size:%d\n",
+ (int)fw->size,
+ le32_to_cpu(syn_fw->checksum),
+ le32_to_cpu(syn_fw->image_size),
+ le32_to_cpu(syn_fw->config_size));
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "FW bootloader_id:%02x, product_id:%.*s, info: %02x%02x\n",
+ syn_fw->bootloader_version,
+ (int)sizeof(syn_fw->product_id), syn_fw->product_id,
+ syn_fw->product_info[0], syn_fw->product_info[1]);
+
+ if (syn_fw->image_size &&
+ syn_fw->image_size != f34->v5.fw_blocks * f34->v5.block_size) {
+ dev_err(&f34->fn->dev,
+ "Bad firmware image: fw size %d, expected %d\n",
+ syn_fw->image_size,
+ f34->v5.fw_blocks * f34->v5.block_size);
+ ret = -EILSEQ;
+ goto out;
+ }
+
+ if (syn_fw->config_size &&
+ syn_fw->config_size != f34->v5.config_blocks * f34->v5.block_size) {
+ dev_err(&f34->fn->dev,
+ "Bad firmware image: config size %d, expected %d\n",
+ syn_fw->config_size,
+ f34->v5.config_blocks * f34->v5.block_size);
+ ret = -EILSEQ;
+ goto out;
+ }
+
+ if (syn_fw->image_size && !syn_fw->config_size) {
+ dev_err(&f34->fn->dev, "Bad firmware image: no config data\n");
+ ret = -EILSEQ;
+ goto out;
+ }
+
+ dev_info(&f34->fn->dev, "Firmware image OK\n");
+ mutex_lock(&f34->v5.flash_mutex);
+
+ ret = rmi_f34_flash_firmware(f34, syn_fw);
+
+ mutex_unlock(&f34->v5.flash_mutex);
+
+out:
+ return ret;
+}
+
+static int rmi_firmware_update(struct rmi_driver_data *data,
+ const struct firmware *fw)
+{
+ struct rmi_device *rmi_dev = data->rmi_dev;
+ struct device *dev = &rmi_dev->dev;
+ struct f34_data *f34;
+ int ret;
+
+ if (!data->f34_container) {
+ dev_warn(dev, "%s: No F34 present!\n", __func__);
+ return -EINVAL;
+ }
+
+ f34 = dev_get_drvdata(&data->f34_container->dev);
+
+ if (f34->bl_version == 7) {
+ if (data->pdt_props & HAS_BSR) {
+ dev_err(dev, "%s: LTS not supported\n", __func__);
+ return -ENODEV;
+ }
+ } else if (f34->bl_version != 5) {
+ dev_warn(dev, "F34 V%d not supported!\n",
+ data->f34_container->fd.function_version);
+ return -ENODEV;
+ }
+
+ /* Enter flash mode */
+ if (f34->bl_version == 7)
+ ret = rmi_f34v7_start_reflash(f34, fw);
+ else
+ ret = rmi_f34_enable_flash(f34);
+ if (ret)
+ return ret;
+
+ rmi_disable_irq(rmi_dev, false);
+
+ /* Tear down functions and re-probe */
+ rmi_free_function_list(rmi_dev);
+
+ ret = rmi_probe_interrupts(data);
+ if (ret)
+ return ret;
+
+ ret = rmi_init_functions(data);
+ if (ret)
+ return ret;
+
+ if (!data->bootloader_mode || !data->f34_container) {
+ dev_warn(dev, "%s: No F34 present or not in bootloader!\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ rmi_enable_irq(rmi_dev, false);
+
+ f34 = dev_get_drvdata(&data->f34_container->dev);
+
+ /* Perform firmware update */
+ if (f34->bl_version == 7)
+ ret = rmi_f34v7_do_reflash(f34, fw);
+ else
+ ret = rmi_f34_update_firmware(f34, fw);
+
+ dev_info(&f34->fn->dev, "Firmware update complete, status:%d\n", ret);
+
+ rmi_disable_irq(rmi_dev, false);
+
+ /* Re-probe */
+ rmi_dbg(RMI_DEBUG_FN, dev, "Re-probing device\n");
+ rmi_free_function_list(rmi_dev);
+
+ ret = rmi_scan_pdt(rmi_dev, NULL, rmi_initial_reset);
+ if (ret < 0)
+ dev_warn(dev, "RMI reset failed!\n");
+
+ ret = rmi_probe_interrupts(data);
+ if (ret)
+ return ret;
+
+ ret = rmi_init_functions(data);
+ if (ret)
+ return ret;
+
+ rmi_enable_irq(rmi_dev, false);
+
+ if (data->f01_container->dev.driver)
+ /* Driver already bound, so enable ATTN now. */
+ return rmi_enable_sensor(rmi_dev);
+
+ rmi_dbg(RMI_DEBUG_FN, dev, "%s complete\n", __func__);
+
+ return ret;
+}
+
+static int rmi_firmware_update(struct rmi_driver_data *data,
+ const struct firmware *fw);
+
+static ssize_t rmi_driver_update_fw_store(struct device *dev,
+ struct device_attribute *dattr,
+ const char *buf, size_t count)
+{
+ struct rmi_driver_data *data = dev_get_drvdata(dev);
+ char fw_name[NAME_MAX];
+ const struct firmware *fw;
+ size_t copy_count = count;
+ int ret;
+
+ if (count == 0 || count >= NAME_MAX)
+ return -EINVAL;
+
+ if (buf[count - 1] == '\0' || buf[count - 1] == '\n')
+ copy_count -= 1;
+
+ strncpy(fw_name, buf, copy_count);
+ fw_name[copy_count] = '\0';
+
+ ret = request_firmware(&fw, fw_name, dev);
+ if (ret)
+ return ret;
+
+ dev_info(dev, "Flashing %s\n", fw_name);
+
+ ret = rmi_firmware_update(data, fw);
+
+ release_firmware(fw);
+
+ return ret ?: count;
+}
+
+static DEVICE_ATTR(update_fw, 0200, NULL, rmi_driver_update_fw_store);
+
+static struct attribute *rmi_firmware_attrs[] = {
+ &dev_attr_update_fw.attr,
+ NULL
+};
+
+static struct attribute_group rmi_firmware_attr_group = {
+ .attrs = rmi_firmware_attrs,
+};
+
+static int rmi_f34_probe(struct rmi_function *fn)
+{
+ struct f34_data *f34;
+ unsigned char f34_queries[9];
+ bool has_config_id;
+ u8 version = fn->fd.function_version;
+ int ret;
+
+ f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL);
+ if (!f34)
+ return -ENOMEM;
+
+ f34->fn = fn;
+ dev_set_drvdata(&fn->dev, f34);
+
+ /* v5 code only supported version 0, try V7 probe */
+ if (version > 0)
+ return rmi_f34v7_probe(f34);
+ else if (version != 0)
+ return -ENODEV;
+
+ f34->bl_version = 5;
+
+ ret = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
+ f34_queries, sizeof(f34_queries));
+ if (ret) {
+ dev_err(&fn->dev, "%s: Failed to query properties\n",
+ __func__);
+ return ret;
+ }
+
+ snprintf(f34->bootloader_id, sizeof(f34->bootloader_id),
+ "%c%c", f34_queries[0], f34_queries[1]);
+
+ mutex_init(&f34->v5.flash_mutex);
+ init_completion(&f34->v5.cmd_done);
+
+ f34->v5.block_size = get_unaligned_le16(&f34_queries[3]);
+ f34->v5.fw_blocks = get_unaligned_le16(&f34_queries[5]);
+ f34->v5.config_blocks = get_unaligned_le16(&f34_queries[7]);
+ f34->v5.ctrl_address = fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET +
+ f34->v5.block_size;
+ has_config_id = f34_queries[2] & (1 << 2);
+
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Bootloader ID: %s\n",
+ f34->bootloader_id);
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Block size: %d\n",
+ f34->v5.block_size);
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "FW blocks: %d\n",
+ f34->v5.fw_blocks);
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "CFG blocks: %d\n",
+ f34->v5.config_blocks);
+
+ if (has_config_id) {
+ ret = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr,
+ f34_queries, sizeof(f34_queries));
+ if (ret) {
+ dev_err(&fn->dev, "Failed to read F34 config ID\n");
+ return ret;
+ }
+
+ snprintf(f34->configuration_id, sizeof(f34->configuration_id),
+ "%02x%02x%02x%02x",
+ f34_queries[0], f34_queries[1],
+ f34_queries[2], f34_queries[3]);
+
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Configuration ID: %s\n",
+ f34->configuration_id);
+ }
+
+ return 0;
+}
+
+int rmi_f34_create_sysfs(struct rmi_device *rmi_dev)
+{
+ return sysfs_create_group(&rmi_dev->dev.kobj, &rmi_firmware_attr_group);
+}
+
+void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev)
+{
+ sysfs_remove_group(&rmi_dev->dev.kobj, &rmi_firmware_attr_group);
+}
+
+struct rmi_function_handler rmi_f34_handler = {
+ .driver = {
+ .name = "rmi4_f34",
+ },
+ .func = 0x34,
+ .probe = rmi_f34_probe,
+ .attention = rmi_f34_attention,
+};
diff --git a/drivers/input/rmi4/rmi_f34.h b/drivers/input/rmi4/rmi_f34.h
new file mode 100644
index 000000000000..2c21056dc375
--- /dev/null
+++ b/drivers/input/rmi4/rmi_f34.h
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2007-2016, Synaptics Incorporated
+ * Copyright (C) 2016 Zodiac Inflight Innovations
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#ifndef _RMI_F34_H
+#define _RMI_F34_H
+
+/* F34 image file offsets. */
+#define F34_FW_IMAGE_OFFSET 0x100
+
+/* F34 register offsets. */
+#define F34_BLOCK_DATA_OFFSET 2
+
+/* F34 commands */
+#define F34_WRITE_FW_BLOCK 0x2
+#define F34_ERASE_ALL 0x3
+#define F34_READ_CONFIG_BLOCK 0x5
+#define F34_WRITE_CONFIG_BLOCK 0x6
+#define F34_ERASE_CONFIG 0x7
+#define F34_ENABLE_FLASH_PROG 0xf
+
+#define F34_STATUS_IN_PROGRESS 0xff
+#define F34_STATUS_IDLE 0x80
+
+#define F34_IDLE_WAIT_MS 500
+#define F34_ENABLE_WAIT_MS 300
+#define F34_ERASE_WAIT_MS 5000
+
+#define F34_BOOTLOADER_ID_LEN 2
+
+/* F34 V7 defines */
+#define V7_FLASH_STATUS_OFFSET 0
+#define V7_PARTITION_ID_OFFSET 1
+#define V7_BLOCK_NUMBER_OFFSET 2
+#define V7_TRANSFER_LENGTH_OFFSET 3
+#define V7_COMMAND_OFFSET 4
+#define V7_PAYLOAD_OFFSET 5
+#define V7_BOOTLOADER_ID_OFFSET 1
+
+#define IMAGE_HEADER_VERSION_10 0x10
+
+#define CONFIG_ID_SIZE 32
+#define PRODUCT_ID_SIZE 10
+
+#define ENABLE_WAIT_MS (1 * 1000)
+#define WRITE_WAIT_MS (3 * 1000)
+
+#define MIN_SLEEP_TIME_US 50
+#define MAX_SLEEP_TIME_US 100
+
+#define HAS_BSR BIT(5)
+#define HAS_CONFIG_ID BIT(3)
+#define HAS_GUEST_CODE BIT(6)
+#define HAS_DISP_CFG BIT(5)
+
+/* F34 V7 commands */
+#define CMD_V7_IDLE 0
+#define CMD_V7_ENTER_BL 1
+#define CMD_V7_READ 2
+#define CMD_V7_WRITE 3
+#define CMD_V7_ERASE 4
+#define CMD_V7_ERASE_AP 5
+#define CMD_V7_SENSOR_ID 6
+
+#define v7_CMD_IDLE 0
+#define v7_CMD_WRITE_FW 1
+#define v7_CMD_WRITE_CONFIG 2
+#define v7_CMD_WRITE_LOCKDOWN 3
+#define v7_CMD_WRITE_GUEST_CODE 4
+#define v7_CMD_READ_CONFIG 5
+#define v7_CMD_ERASE_ALL 6
+#define v7_CMD_ERASE_UI_FIRMWARE 7
+#define v7_CMD_ERASE_UI_CONFIG 8
+#define v7_CMD_ERASE_BL_CONFIG 9
+#define v7_CMD_ERASE_DISP_CONFIG 10
+#define v7_CMD_ERASE_FLASH_CONFIG 11
+#define v7_CMD_ERASE_GUEST_CODE 12
+#define v7_CMD_ENABLE_FLASH_PROG 13
+
+#define v7_UI_CONFIG_AREA 0
+#define v7_PM_CONFIG_AREA 1
+#define v7_BL_CONFIG_AREA 2
+#define v7_DP_CONFIG_AREA 3
+#define v7_FLASH_CONFIG_AREA 4
+
+/* F34 V7 partition IDs */
+#define BOOTLOADER_PARTITION 1
+#define DEVICE_CONFIG_PARTITION 2
+#define FLASH_CONFIG_PARTITION 3
+#define MANUFACTURING_BLOCK_PARTITION 4
+#define GUEST_SERIALIZATION_PARTITION 5
+#define GLOBAL_PARAMETERS_PARTITION 6
+#define CORE_CODE_PARTITION 7
+#define CORE_CONFIG_PARTITION 8
+#define GUEST_CODE_PARTITION 9
+#define DISPLAY_CONFIG_PARTITION 10
+
+/* F34 V7 container IDs */
+#define TOP_LEVEL_CONTAINER 0
+#define UI_CONTAINER 1
+#define UI_CONFIG_CONTAINER 2
+#define BL_CONTAINER 3
+#define BL_IMAGE_CONTAINER 4
+#define BL_CONFIG_CONTAINER 5
+#define BL_LOCKDOWN_INFO_CONTAINER 6
+#define PERMANENT_CONFIG_CONTAINER 7
+#define GUEST_CODE_CONTAINER 8
+#define BL_PROTOCOL_DESCRIPTOR_CONTAINER 9
+#define UI_PROTOCOL_DESCRIPTOR_CONTAINER 10
+#define RMI_SELF_DISCOVERY_CONTAINER 11
+#define RMI_PAGE_CONTENT_CONTAINER 12
+#define GENERAL_INFORMATION_CONTAINER 13
+#define DEVICE_CONFIG_CONTAINER 14
+#define FLASH_CONFIG_CONTAINER 15
+#define GUEST_SERIALIZATION_CONTAINER 16
+#define GLOBAL_PARAMETERS_CONTAINER 17
+#define CORE_CODE_CONTAINER 18
+#define CORE_CONFIG_CONTAINER 19
+#define DISPLAY_CONFIG_CONTAINER 20
+
+struct f34v7_query_1_7 {
+ u8 bl_minor_revision; /* query 1 */
+ u8 bl_major_revision;
+ __le32 bl_fw_id; /* query 2 */
+ u8 minimum_write_size; /* query 3 */
+ __le16 block_size;
+ __le16 flash_page_size;
+ __le16 adjustable_partition_area_size; /* query 4 */
+ __le16 flash_config_length; /* query 5 */
+ __le16 payload_length; /* query 6 */
+ u8 partition_support[4]; /* query 7 */
+} __packed;
+
+struct f34v7_data_1_5 {
+ u8 partition_id;
+ __le16 block_offset;
+ __le16 transfer_length;
+ u8 command;
+ u8 payload[2];
+} __packed;
+
+struct block_data {
+ const void *data;
+ int size;
+};
+
+struct partition_table {
+ u8 partition_id;
+ u8 byte_1_reserved;
+ __le16 partition_length;
+ __le16 start_physical_address;
+ __le16 partition_properties;
+} __packed;
+
+struct physical_address {
+ u16 ui_firmware;
+ u16 ui_config;
+ u16 dp_config;
+ u16 guest_code;
+};
+
+struct container_descriptor {
+ __le32 content_checksum;
+ __le16 container_id;
+ u8 minor_version;
+ u8 major_version;
+ u8 reserved_08;
+ u8 reserved_09;
+ u8 reserved_0a;
+ u8 reserved_0b;
+ u8 container_option_flags[4];
+ __le32 content_options_length;
+ __le32 content_options_address;
+ __le32 content_length;
+ __le32 content_address;
+} __packed;
+
+struct block_count {
+ u16 ui_firmware;
+ u16 ui_config;
+ u16 dp_config;
+ u16 fl_config;
+ u16 pm_config;
+ u16 bl_config;
+ u16 lockdown;
+ u16 guest_code;
+};
+
+struct image_header_10 {
+ __le32 checksum;
+ u8 reserved_04;
+ u8 reserved_05;
+ u8 minor_header_version;
+ u8 major_header_version;
+ u8 reserved_08;
+ u8 reserved_09;
+ u8 reserved_0a;
+ u8 reserved_0b;
+ __le32 top_level_container_start_addr;
+};
+
+struct image_metadata {
+ bool contains_firmware_id;
+ bool contains_bootloader;
+ bool contains_display_cfg;
+ bool contains_guest_code;
+ bool contains_flash_config;
+ unsigned int firmware_id;
+ unsigned int checksum;
+ unsigned int bootloader_size;
+ unsigned int display_cfg_offset;
+ unsigned char bl_version;
+ unsigned char product_id[PRODUCT_ID_SIZE + 1];
+ unsigned char cstmr_product_id[PRODUCT_ID_SIZE + 1];
+ struct block_data bootloader;
+ struct block_data ui_firmware;
+ struct block_data ui_config;
+ struct block_data dp_config;
+ struct block_data fl_config;
+ struct block_data bl_config;
+ struct block_data guest_code;
+ struct block_data lockdown;
+ struct block_count blkcount;
+ struct physical_address phyaddr;
+};
+
+struct register_offset {
+ u8 properties;
+ u8 properties_2;
+ u8 block_size;
+ u8 block_count;
+ u8 gc_block_count;
+ u8 flash_status;
+ u8 partition_id;
+ u8 block_number;
+ u8 transfer_length;
+ u8 flash_cmd;
+ u8 payload;
+};
+
+struct rmi_f34_firmware {
+ __le32 checksum;
+ u8 pad1[3];
+ u8 bootloader_version;
+ __le32 image_size;
+ __le32 config_size;
+ u8 product_id[10];
+ u8 product_info[2];
+ u8 pad2[228];
+ u8 data[];
+};
+
+struct f34v5_data {
+ u16 block_size;
+ u16 fw_blocks;
+ u16 config_blocks;
+ u16 ctrl_address;
+ u8 status;
+
+ struct completion cmd_done;
+ struct mutex flash_mutex;
+};
+
+struct f34v7_data {
+ bool has_display_cfg;
+ bool has_guest_code;
+ bool force_update;
+ bool in_bl_mode;
+ u8 *read_config_buf;
+ size_t read_config_buf_size;
+ u8 command;
+ u8 flash_status;
+ u16 block_size;
+ u16 config_block_count;
+ u16 config_size;
+ u16 config_area;
+ u16 flash_config_length;
+ u16 payload_length;
+ u8 partitions;
+ u16 partition_table_bytes;
+ bool new_partition_table;
+
+ struct register_offset off;
+ struct block_count blkcount;
+ struct physical_address phyaddr;
+ struct image_metadata img;
+
+ const void *config_data;
+ const void *image;
+};
+
+struct f34_data {
+ struct rmi_function *fn;
+
+ u8 bl_version;
+ unsigned char bootloader_id[5];
+ unsigned char configuration_id[CONFIG_ID_SIZE*2 + 1];
+
+ union {
+ struct f34v5_data v5;
+ struct f34v7_data v7;
+ };
+};
+
+int rmi_f34v7_start_reflash(struct f34_data *f34, const struct firmware *fw);
+int rmi_f34v7_do_reflash(struct f34_data *f34, const struct firmware *fw);
+int rmi_f34v7_probe(struct f34_data *f34);
+
+#endif /* _RMI_F34_H */
diff --git a/drivers/input/rmi4/rmi_f34v7.c b/drivers/input/rmi4/rmi_f34v7.c
new file mode 100644
index 000000000000..ca31f9539d9b
--- /dev/null
+++ b/drivers/input/rmi4/rmi_f34v7.c
@@ -0,0 +1,1372 @@
+/*
+ * Copyright (c) 2016, Zodiac Inflight Innovations
+ * Copyright (c) 2007-2016, Synaptics Incorporated
+ * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
+ * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/rmi.h>
+#include <linux/firmware.h>
+#include <asm/unaligned.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include "rmi_driver.h"
+#include "rmi_f34.h"
+
+static int rmi_f34v7_read_flash_status(struct f34_data *f34)
+{
+ u8 status;
+ u8 command;
+ int ret;
+
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ f34->fn->fd.data_base_addr + f34->v7.off.flash_status,
+ &status,
+ sizeof(status));
+ if (ret < 0) {
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Failed to read flash status\n", __func__);
+ return ret;
+ }
+
+ f34->v7.in_bl_mode = status >> 7;
+ f34->v7.flash_status = status & 0x1f;
+
+ if (f34->v7.flash_status != 0x00) {
+ dev_err(&f34->fn->dev, "%s: status=%d, command=0x%02x\n",
+ __func__, f34->v7.flash_status, f34->v7.command);
+ }
+
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ f34->fn->fd.data_base_addr + f34->v7.off.flash_cmd,
+ &command,
+ sizeof(command));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to read flash command\n",
+ __func__);
+ return ret;
+ }
+
+ f34->v7.command = command;
+
+ return 0;
+}
+
+static int rmi_f34v7_wait_for_idle(struct f34_data *f34, int timeout_ms)
+{
+ int count = 0;
+ int timeout_count = ((timeout_ms * 1000) / MAX_SLEEP_TIME_US) + 1;
+
+ do {
+ usleep_range(MIN_SLEEP_TIME_US, MAX_SLEEP_TIME_US);
+
+ count++;
+
+ rmi_f34v7_read_flash_status(f34);
+
+ if ((f34->v7.command == v7_CMD_IDLE)
+ && (f34->v7.flash_status == 0x00)) {
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "Idle status detected\n");
+ return 0;
+ }
+ } while (count < timeout_count);
+
+ dev_err(&f34->fn->dev,
+ "%s: Timed out waiting for idle status\n", __func__);
+
+ return -ETIMEDOUT;
+}
+
+static int rmi_f34v7_write_command_single_transaction(struct f34_data *f34,
+ u8 cmd)
+{
+ int ret;
+ u8 base;
+ struct f34v7_data_1_5 data_1_5;
+
+ base = f34->fn->fd.data_base_addr;
+
+ memset(&data_1_5, 0, sizeof(data_1_5));
+
+ switch (cmd) {
+ case v7_CMD_ERASE_ALL:
+ data_1_5.partition_id = CORE_CODE_PARTITION;
+ data_1_5.command = CMD_V7_ERASE_AP;
+ break;
+ case v7_CMD_ERASE_UI_FIRMWARE:
+ data_1_5.partition_id = CORE_CODE_PARTITION;
+ data_1_5.command = CMD_V7_ERASE;
+ break;
+ case v7_CMD_ERASE_BL_CONFIG:
+ data_1_5.partition_id = GLOBAL_PARAMETERS_PARTITION;
+ data_1_5.command = CMD_V7_ERASE;
+ break;
+ case v7_CMD_ERASE_UI_CONFIG:
+ data_1_5.partition_id = CORE_CONFIG_PARTITION;
+ data_1_5.command = CMD_V7_ERASE;
+ break;
+ case v7_CMD_ERASE_DISP_CONFIG:
+ data_1_5.partition_id = DISPLAY_CONFIG_PARTITION;
+ data_1_5.command = CMD_V7_ERASE;
+ break;
+ case v7_CMD_ERASE_FLASH_CONFIG:
+ data_1_5.partition_id = FLASH_CONFIG_PARTITION;
+ data_1_5.command = CMD_V7_ERASE;
+ break;
+ case v7_CMD_ERASE_GUEST_CODE:
+ data_1_5.partition_id = GUEST_CODE_PARTITION;
+ data_1_5.command = CMD_V7_ERASE;
+ break;
+ case v7_CMD_ENABLE_FLASH_PROG:
+ data_1_5.partition_id = BOOTLOADER_PARTITION;
+ data_1_5.command = CMD_V7_ENTER_BL;
+ break;
+ }
+
+ data_1_5.payload[0] = f34->bootloader_id[0];
+ data_1_5.payload[1] = f34->bootloader_id[1];
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.partition_id,
+ &data_1_5, sizeof(data_1_5));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "%s: Failed to write single transaction command\n",
+ __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rmi_f34v7_write_command(struct f34_data *f34, u8 cmd)
+{
+ int ret;
+ u8 base;
+ u8 command;
+
+ base = f34->fn->fd.data_base_addr;
+
+ switch (cmd) {
+ case v7_CMD_WRITE_FW:
+ case v7_CMD_WRITE_CONFIG:
+ case v7_CMD_WRITE_GUEST_CODE:
+ command = CMD_V7_WRITE;
+ break;
+ case v7_CMD_READ_CONFIG:
+ command = CMD_V7_READ;
+ break;
+ case v7_CMD_ERASE_ALL:
+ command = CMD_V7_ERASE_AP;
+ break;
+ case v7_CMD_ERASE_UI_FIRMWARE:
+ case v7_CMD_ERASE_BL_CONFIG:
+ case v7_CMD_ERASE_UI_CONFIG:
+ case v7_CMD_ERASE_DISP_CONFIG:
+ case v7_CMD_ERASE_FLASH_CONFIG:
+ case v7_CMD_ERASE_GUEST_CODE:
+ command = CMD_V7_ERASE;
+ break;
+ case v7_CMD_ENABLE_FLASH_PROG:
+ command = CMD_V7_ENTER_BL;
+ break;
+ default:
+ dev_err(&f34->fn->dev, "%s: Invalid command 0x%02x\n",
+ __func__, cmd);
+ return -EINVAL;
+ }
+
+ f34->v7.command = command;
+
+ switch (cmd) {
+ case v7_CMD_ERASE_ALL:
+ case v7_CMD_ERASE_UI_FIRMWARE:
+ case v7_CMD_ERASE_BL_CONFIG:
+ case v7_CMD_ERASE_UI_CONFIG:
+ case v7_CMD_ERASE_DISP_CONFIG:
+ case v7_CMD_ERASE_FLASH_CONFIG:
+ case v7_CMD_ERASE_GUEST_CODE:
+ case v7_CMD_ENABLE_FLASH_PROG:
+ ret = rmi_f34v7_write_command_single_transaction(f34, cmd);
+ if (ret < 0)
+ return ret;
+ else
+ return 0;
+ default:
+ break;
+ }
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: writing cmd %02X\n",
+ __func__, command);
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.flash_cmd,
+ &command, sizeof(command));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to write flash command\n",
+ __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rmi_f34v7_write_partition_id(struct f34_data *f34, u8 cmd)
+{
+ int ret;
+ u8 base;
+ u8 partition;
+
+ base = f34->fn->fd.data_base_addr;
+
+ switch (cmd) {
+ case v7_CMD_WRITE_FW:
+ partition = CORE_CODE_PARTITION;
+ break;
+ case v7_CMD_WRITE_CONFIG:
+ case v7_CMD_READ_CONFIG:
+ if (f34->v7.config_area == v7_UI_CONFIG_AREA)
+ partition = CORE_CONFIG_PARTITION;
+ else if (f34->v7.config_area == v7_DP_CONFIG_AREA)
+ partition = DISPLAY_CONFIG_PARTITION;
+ else if (f34->v7.config_area == v7_PM_CONFIG_AREA)
+ partition = GUEST_SERIALIZATION_PARTITION;
+ else if (f34->v7.config_area == v7_BL_CONFIG_AREA)
+ partition = GLOBAL_PARAMETERS_PARTITION;
+ else if (f34->v7.config_area == v7_FLASH_CONFIG_AREA)
+ partition = FLASH_CONFIG_PARTITION;
+ break;
+ case v7_CMD_WRITE_GUEST_CODE:
+ partition = GUEST_CODE_PARTITION;
+ break;
+ case v7_CMD_ERASE_ALL:
+ partition = CORE_CODE_PARTITION;
+ break;
+ case v7_CMD_ERASE_BL_CONFIG:
+ partition = GLOBAL_PARAMETERS_PARTITION;
+ break;
+ case v7_CMD_ERASE_UI_CONFIG:
+ partition = CORE_CONFIG_PARTITION;
+ break;
+ case v7_CMD_ERASE_DISP_CONFIG:
+ partition = DISPLAY_CONFIG_PARTITION;
+ break;
+ case v7_CMD_ERASE_FLASH_CONFIG:
+ partition = FLASH_CONFIG_PARTITION;
+ break;
+ case v7_CMD_ERASE_GUEST_CODE:
+ partition = GUEST_CODE_PARTITION;
+ break;
+ case v7_CMD_ENABLE_FLASH_PROG:
+ partition = BOOTLOADER_PARTITION;
+ break;
+ default:
+ dev_err(&f34->fn->dev, "%s: Invalid command 0x%02x\n",
+ __func__, cmd);
+ return -EINVAL;
+ }
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.partition_id,
+ &partition, sizeof(partition));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to write partition ID\n",
+ __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rmi_f34v7_read_f34v7_partition_table(struct f34_data *f34)
+{
+ int ret;
+ u8 base;
+ __le16 length;
+ u16 block_number = 0;
+
+ base = f34->fn->fd.data_base_addr;
+
+ f34->v7.config_area = v7_FLASH_CONFIG_AREA;
+
+ ret = rmi_f34v7_write_partition_id(f34, v7_CMD_READ_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.block_number,
+ &block_number, sizeof(block_number));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to write block number\n",
+ __func__);
+ return ret;
+ }
+
+ put_unaligned_le16(f34->v7.flash_config_length, &length);
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.transfer_length,
+ &length, sizeof(length));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to write transfer length\n",
+ __func__);
+ return ret;
+ }
+
+ ret = rmi_f34v7_write_command(f34, v7_CMD_READ_CONFIG);
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to write command\n",
+ __func__);
+ return ret;
+ }
+
+ ret = rmi_f34v7_wait_for_idle(f34, WRITE_WAIT_MS);
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to wait for idle status\n",
+ __func__);
+ return ret;
+ }
+
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ base + f34->v7.off.payload,
+ f34->v7.read_config_buf,
+ f34->v7.partition_table_bytes);
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to read block data\n",
+ __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void rmi_f34v7_parse_partition_table(struct f34_data *f34,
+ const void *partition_table,
+ struct block_count *blkcount,
+ struct physical_address *phyaddr)
+{
+ int i;
+ int index;
+ u16 partition_length;
+ u16 physical_address;
+ const struct partition_table *ptable;
+
+ for (i = 0; i < f34->v7.partitions; i++) {
+ index = i * 8 + 2;
+ ptable = partition_table + index;
+ partition_length = le16_to_cpu(ptable->partition_length);
+ physical_address = le16_to_cpu(ptable->start_physical_address);
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Partition entry %d: %*ph\n",
+ __func__, i, sizeof(struct partition_table), ptable);
+ switch (ptable->partition_id & 0x1f) {
+ case CORE_CODE_PARTITION:
+ blkcount->ui_firmware = partition_length;
+ phyaddr->ui_firmware = physical_address;
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Core code block count: %d\n",
+ __func__, blkcount->ui_firmware);
+ break;
+ case CORE_CONFIG_PARTITION:
+ blkcount->ui_config = partition_length;
+ phyaddr->ui_config = physical_address;
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Core config block count: %d\n",
+ __func__, blkcount->ui_config);
+ break;
+ case DISPLAY_CONFIG_PARTITION:
+ blkcount->dp_config = partition_length;
+ phyaddr->dp_config = physical_address;
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Display config block count: %d\n",
+ __func__, blkcount->dp_config);
+ break;
+ case FLASH_CONFIG_PARTITION:
+ blkcount->fl_config = partition_length;
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Flash config block count: %d\n",
+ __func__, blkcount->fl_config);
+ break;
+ case GUEST_CODE_PARTITION:
+ blkcount->guest_code = partition_length;
+ phyaddr->guest_code = physical_address;
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Guest code block count: %d\n",
+ __func__, blkcount->guest_code);
+ break;
+ case GUEST_SERIALIZATION_PARTITION:
+ blkcount->pm_config = partition_length;
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Guest serialization block count: %d\n",
+ __func__, blkcount->pm_config);
+ break;
+ case GLOBAL_PARAMETERS_PARTITION:
+ blkcount->bl_config = partition_length;
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Global parameters block count: %d\n",
+ __func__, blkcount->bl_config);
+ break;
+ case DEVICE_CONFIG_PARTITION:
+ blkcount->lockdown = partition_length;
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Device config block count: %d\n",
+ __func__, blkcount->lockdown);
+ break;
+ }
+ }
+}
+
+static int rmi_f34v7_read_queries_bl_version(struct f34_data *f34)
+{
+ int ret;
+ u8 base;
+ int offset;
+ u8 query_0;
+ struct f34v7_query_1_7 query_1_7;
+
+ base = f34->fn->fd.query_base_addr;
+
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ base,
+ &query_0,
+ sizeof(query_0));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "%s: Failed to read query 0\n", __func__);
+ return ret;
+ }
+
+ offset = (query_0 & 0x7) + 1;
+
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ base + offset,
+ &query_1_7,
+ sizeof(query_1_7));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to read queries 1 to 7\n",
+ __func__);
+ return ret;
+ }
+
+ f34->bootloader_id[0] = query_1_7.bl_minor_revision;
+ f34->bootloader_id[1] = query_1_7.bl_major_revision;
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "Bootloader V%d.%d\n",
+ f34->bootloader_id[1], f34->bootloader_id[0]);
+
+ return 0;
+}
+
+static int rmi_f34v7_read_queries(struct f34_data *f34)
+{
+ int ret;
+ int i, j;
+ u8 base;
+ int offset;
+ u8 *ptable;
+ u8 query_0;
+ struct f34v7_query_1_7 query_1_7;
+
+ base = f34->fn->fd.query_base_addr;
+
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ base,
+ &query_0,
+ sizeof(query_0));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "%s: Failed to read query 0\n", __func__);
+ return ret;
+ }
+
+ offset = (query_0 & 0x07) + 1;
+
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ base + offset,
+ &query_1_7,
+ sizeof(query_1_7));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to read queries 1 to 7\n",
+ __func__);
+ return ret;
+ }
+
+ f34->bootloader_id[0] = query_1_7.bl_minor_revision;
+ f34->bootloader_id[1] = query_1_7.bl_major_revision;
+
+ f34->v7.block_size = le16_to_cpu(query_1_7.block_size);
+ f34->v7.flash_config_length =
+ le16_to_cpu(query_1_7.flash_config_length);
+ f34->v7.payload_length = le16_to_cpu(query_1_7.payload_length);
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: f34->v7.block_size = %d\n",
+ __func__, f34->v7.block_size);
+
+ f34->v7.off.flash_status = V7_FLASH_STATUS_OFFSET;
+ f34->v7.off.partition_id = V7_PARTITION_ID_OFFSET;
+ f34->v7.off.block_number = V7_BLOCK_NUMBER_OFFSET;
+ f34->v7.off.transfer_length = V7_TRANSFER_LENGTH_OFFSET;
+ f34->v7.off.flash_cmd = V7_COMMAND_OFFSET;
+ f34->v7.off.payload = V7_PAYLOAD_OFFSET;
+
+ f34->v7.has_display_cfg = query_1_7.partition_support[1] & HAS_DISP_CFG;
+ f34->v7.has_guest_code =
+ query_1_7.partition_support[1] & HAS_GUEST_CODE;
+
+ if (query_0 & HAS_CONFIG_ID) {
+ char f34_ctrl[CONFIG_ID_SIZE];
+ int i = 0;
+ u8 *p = f34->configuration_id;
+ *p = '\0';
+
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ f34->fn->fd.control_base_addr,
+ f34_ctrl,
+ sizeof(f34_ctrl));
+ if (ret)
+ return ret;
+
+ /* Eat leading zeros */
+ while (i < sizeof(f34_ctrl) && !f34_ctrl[i])
+ i++;
+
+ for (; i < sizeof(f34_ctrl); i++)
+ p += snprintf(p, f34->configuration_id
+ + sizeof(f34->configuration_id) - p,
+ "%02X", f34_ctrl[i]);
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "Configuration ID: %s\n",
+ f34->configuration_id);
+ }
+
+ f34->v7.partitions = 0;
+ for (i = 0; i < sizeof(query_1_7.partition_support); i++)
+ for (j = 0; j < 8; j++)
+ if (query_1_7.partition_support[i] & (1 << j))
+ f34->v7.partitions++;
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: Supported partitions: %*ph\n",
+ __func__, sizeof(query_1_7.partition_support),
+ query_1_7.partition_support);
+
+
+ f34->v7.partition_table_bytes = f34->v7.partitions * 8 + 2;
+
+ f34->v7.read_config_buf = devm_kzalloc(&f34->fn->dev,
+ f34->v7.partition_table_bytes,
+ GFP_KERNEL);
+ if (!f34->v7.read_config_buf) {
+ f34->v7.read_config_buf_size = 0;
+ return -ENOMEM;
+ }
+
+ f34->v7.read_config_buf_size = f34->v7.partition_table_bytes;
+ ptable = f34->v7.read_config_buf;
+
+ ret = rmi_f34v7_read_f34v7_partition_table(f34);
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to read partition table\n",
+ __func__);
+ return ret;
+ }
+
+ rmi_f34v7_parse_partition_table(f34, ptable,
+ &f34->v7.blkcount, &f34->v7.phyaddr);
+
+ return 0;
+}
+
+static int rmi_f34v7_check_ui_firmware_size(struct f34_data *f34)
+{
+ u16 block_count;
+
+ block_count = f34->v7.img.ui_firmware.size / f34->v7.block_size;
+
+ if (block_count != f34->v7.blkcount.ui_firmware) {
+ dev_err(&f34->fn->dev,
+ "UI firmware size mismatch: %d != %d\n",
+ block_count, f34->v7.blkcount.ui_firmware);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rmi_f34v7_check_ui_config_size(struct f34_data *f34)
+{
+ u16 block_count;
+
+ block_count = f34->v7.img.ui_config.size / f34->v7.block_size;
+
+ if (block_count != f34->v7.blkcount.ui_config) {
+ dev_err(&f34->fn->dev, "UI config size mismatch\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rmi_f34v7_check_dp_config_size(struct f34_data *f34)
+{
+ u16 block_count;
+
+ block_count = f34->v7.img.dp_config.size / f34->v7.block_size;
+
+ if (block_count != f34->v7.blkcount.dp_config) {
+ dev_err(&f34->fn->dev, "Display config size mismatch\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rmi_f34v7_check_guest_code_size(struct f34_data *f34)
+{
+ u16 block_count;
+
+ block_count = f34->v7.img.guest_code.size / f34->v7.block_size;
+ if (block_count != f34->v7.blkcount.guest_code) {
+ dev_err(&f34->fn->dev, "Guest code size mismatch\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rmi_f34v7_check_bl_config_size(struct f34_data *f34)
+{
+ u16 block_count;
+
+ block_count = f34->v7.img.bl_config.size / f34->v7.block_size;
+
+ if (block_count != f34->v7.blkcount.bl_config) {
+ dev_err(&f34->fn->dev, "Bootloader config size mismatch\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rmi_f34v7_erase_config(struct f34_data *f34)
+{
+ int ret;
+
+ dev_info(&f34->fn->dev, "Erasing config...\n");
+
+ switch (f34->v7.config_area) {
+ case v7_UI_CONFIG_AREA:
+ ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_UI_CONFIG);
+ if (ret < 0)
+ return ret;
+ break;
+ case v7_DP_CONFIG_AREA:
+ ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_DISP_CONFIG);
+ if (ret < 0)
+ return ret;
+ break;
+ case v7_BL_CONFIG_AREA:
+ ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_BL_CONFIG);
+ if (ret < 0)
+ return ret;
+ break;
+ }
+
+ ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static int rmi_f34v7_erase_guest_code(struct f34_data *f34)
+{
+ int ret;
+
+ dev_info(&f34->fn->dev, "Erasing guest code...\n");
+
+ ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_GUEST_CODE);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int rmi_f34v7_erase_all(struct f34_data *f34)
+{
+ int ret;
+
+ dev_info(&f34->fn->dev, "Erasing firmware...\n");
+
+ ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_UI_FIRMWARE);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+ if (ret < 0)
+ return ret;
+
+ f34->v7.config_area = v7_UI_CONFIG_AREA;
+ ret = rmi_f34v7_erase_config(f34);
+ if (ret < 0)
+ return ret;
+
+ if (f34->v7.has_display_cfg) {
+ f34->v7.config_area = v7_DP_CONFIG_AREA;
+ ret = rmi_f34v7_erase_config(f34);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (f34->v7.new_partition_table && f34->v7.has_guest_code) {
+ ret = rmi_f34v7_erase_guest_code(f34);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rmi_f34v7_read_f34v7_blocks(struct f34_data *f34, u16 block_cnt,
+ u8 command)
+{
+ int ret;
+ u8 base;
+ __le16 length;
+ u16 transfer;
+ u16 max_transfer;
+ u16 remaining = block_cnt;
+ u16 block_number = 0;
+ u16 index = 0;
+
+ base = f34->fn->fd.data_base_addr;
+
+ ret = rmi_f34v7_write_partition_id(f34, command);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.block_number,
+ &block_number, sizeof(block_number));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to write block number\n",
+ __func__);
+ return ret;
+ }
+
+ max_transfer = min(f34->v7.payload_length,
+ (u16)(PAGE_SIZE / f34->v7.block_size));
+
+ do {
+ transfer = min(remaining, max_transfer);
+ put_unaligned_le16(transfer, &length);
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.transfer_length,
+ &length, sizeof(length));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "%s: Write transfer length fail (%d remaining)\n",
+ __func__, remaining);
+ return ret;
+ }
+
+ ret = rmi_f34v7_write_command(f34, command);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "%s: Wait for idle failed (%d blks remaining)\n",
+ __func__, remaining);
+ return ret;
+ }
+
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ base + f34->v7.off.payload,
+ &f34->v7.read_config_buf[index],
+ transfer * f34->v7.block_size);
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "%s: Read block failed (%d blks remaining)\n",
+ __func__, remaining);
+ return ret;
+ }
+
+ index += (transfer * f34->v7.block_size);
+ remaining -= transfer;
+ } while (remaining);
+
+ return 0;
+}
+
+static int rmi_f34v7_write_f34v7_blocks(struct f34_data *f34,
+ const void *block_ptr, u16 block_cnt,
+ u8 command)
+{
+ int ret;
+ u8 base;
+ __le16 length;
+ u16 transfer;
+ u16 max_transfer;
+ u16 remaining = block_cnt;
+ u16 block_number = 0;
+
+ base = f34->fn->fd.data_base_addr;
+
+ ret = rmi_f34v7_write_partition_id(f34, command);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.block_number,
+ &block_number, sizeof(block_number));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to write block number\n",
+ __func__);
+ return ret;
+ }
+
+ if (f34->v7.payload_length > (PAGE_SIZE / f34->v7.block_size))
+ max_transfer = PAGE_SIZE / f34->v7.block_size;
+ else
+ max_transfer = f34->v7.payload_length;
+
+ do {
+ transfer = min(remaining, max_transfer);
+ put_unaligned_le16(transfer, &length);
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.transfer_length,
+ &length, sizeof(length));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "%s: Write transfer length fail (%d remaining)\n",
+ __func__, remaining);
+ return ret;
+ }
+
+ ret = rmi_f34v7_write_command(f34, command);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_write_block(f34->fn->rmi_dev,
+ base + f34->v7.off.payload,
+ block_ptr, transfer * f34->v7.block_size);
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "%s: Failed writing data (%d blks remaining)\n",
+ __func__, remaining);
+ return ret;
+ }
+
+ ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+ if (ret < 0) {
+ dev_err(&f34->fn->dev,
+ "%s: Failed wait for idle (%d blks remaining)\n",
+ __func__, remaining);
+ return ret;
+ }
+
+ block_ptr += (transfer * f34->v7.block_size);
+ remaining -= transfer;
+ } while (remaining);
+
+ return 0;
+}
+
+static int rmi_f34v7_write_config(struct f34_data *f34)
+{
+ return rmi_f34v7_write_f34v7_blocks(f34, f34->v7.config_data,
+ f34->v7.config_block_count,
+ v7_CMD_WRITE_CONFIG);
+}
+
+static int rmi_f34v7_write_ui_config(struct f34_data *f34)
+{
+ f34->v7.config_area = v7_UI_CONFIG_AREA;
+ f34->v7.config_data = f34->v7.img.ui_config.data;
+ f34->v7.config_size = f34->v7.img.ui_config.size;
+ f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size;
+
+ return rmi_f34v7_write_config(f34);
+}
+
+static int rmi_f34v7_write_dp_config(struct f34_data *f34)
+{
+ f34->v7.config_area = v7_DP_CONFIG_AREA;
+ f34->v7.config_data = f34->v7.img.dp_config.data;
+ f34->v7.config_size = f34->v7.img.dp_config.size;
+ f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size;
+
+ return rmi_f34v7_write_config(f34);
+}
+
+static int rmi_f34v7_write_guest_code(struct f34_data *f34)
+{
+ return rmi_f34v7_write_f34v7_blocks(f34, f34->v7.img.guest_code.data,
+ f34->v7.img.guest_code.size /
+ f34->v7.block_size,
+ v7_CMD_WRITE_GUEST_CODE);
+}
+
+static int rmi_f34v7_write_flash_config(struct f34_data *f34)
+{
+ int ret;
+
+ f34->v7.config_area = v7_FLASH_CONFIG_AREA;
+ f34->v7.config_data = f34->v7.img.fl_config.data;
+ f34->v7.config_size = f34->v7.img.fl_config.size;
+ f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size;
+
+ if (f34->v7.config_block_count != f34->v7.blkcount.fl_config) {
+ dev_err(&f34->fn->dev, "%s: Flash config size mismatch\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_FLASH_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: Erase flash config command written\n", __func__);
+
+ ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_f34v7_write_config(f34);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int rmi_f34v7_write_partition_table(struct f34_data *f34)
+{
+ u16 block_count;
+ int ret;
+
+ block_count = f34->v7.blkcount.bl_config;
+ f34->v7.config_area = v7_BL_CONFIG_AREA;
+ f34->v7.config_size = f34->v7.block_size * block_count;
+ devm_kfree(&f34->fn->dev, f34->v7.read_config_buf);
+ f34->v7.read_config_buf = devm_kzalloc(&f34->fn->dev,
+ f34->v7.config_size, GFP_KERNEL);
+ if (!f34->v7.read_config_buf) {
+ f34->v7.read_config_buf_size = 0;
+ return -ENOMEM;
+ }
+
+ f34->v7.read_config_buf_size = f34->v7.config_size;
+
+ ret = rmi_f34v7_read_f34v7_blocks(f34, block_count, v7_CMD_READ_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_f34v7_erase_config(f34);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_f34v7_write_flash_config(f34);
+ if (ret < 0)
+ return ret;
+
+ f34->v7.config_area = v7_BL_CONFIG_AREA;
+ f34->v7.config_data = f34->v7.read_config_buf;
+ f34->v7.config_size = f34->v7.img.bl_config.size;
+ f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size;
+
+ ret = rmi_f34v7_write_config(f34);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int rmi_f34v7_write_firmware(struct f34_data *f34)
+{
+ u16 blk_count;
+
+ blk_count = f34->v7.img.ui_firmware.size / f34->v7.block_size;
+
+ return rmi_f34v7_write_f34v7_blocks(f34, f34->v7.img.ui_firmware.data,
+ blk_count, v7_CMD_WRITE_FW);
+}
+
+static void rmi_f34v7_compare_partition_tables(struct f34_data *f34)
+{
+ if (f34->v7.phyaddr.ui_firmware != f34->v7.img.phyaddr.ui_firmware) {
+ f34->v7.new_partition_table = true;
+ return;
+ }
+
+ if (f34->v7.phyaddr.ui_config != f34->v7.img.phyaddr.ui_config) {
+ f34->v7.new_partition_table = true;
+ return;
+ }
+
+ if (f34->v7.has_display_cfg &&
+ f34->v7.phyaddr.dp_config != f34->v7.img.phyaddr.dp_config) {
+ f34->v7.new_partition_table = true;
+ return;
+ }
+
+ if (f34->v7.has_guest_code &&
+ f34->v7.phyaddr.guest_code != f34->v7.img.phyaddr.guest_code) {
+ f34->v7.new_partition_table = true;
+ return;
+ }
+
+ f34->v7.new_partition_table = false;
+}
+
+static void rmi_f34v7_parse_img_header_10_bl_container(struct f34_data *f34,
+ const void *image)
+{
+ int i;
+ int num_of_containers;
+ unsigned int addr;
+ unsigned int container_id;
+ unsigned int length;
+ const void *content;
+ const struct container_descriptor *descriptor;
+
+ num_of_containers = f34->v7.img.bootloader.size / 4 - 1;
+
+ for (i = 1; i <= num_of_containers; i++) {
+ addr = get_unaligned_le32(f34->v7.img.bootloader.data + i * 4);
+ descriptor = image + addr;
+ container_id = le16_to_cpu(descriptor->container_id);
+ content = image + le32_to_cpu(descriptor->content_address);
+ length = le32_to_cpu(descriptor->content_length);
+ switch (container_id) {
+ case BL_CONFIG_CONTAINER:
+ case GLOBAL_PARAMETERS_CONTAINER:
+ f34->v7.img.bl_config.data = content;
+ f34->v7.img.bl_config.size = length;
+ break;
+ case BL_LOCKDOWN_INFO_CONTAINER:
+ case DEVICE_CONFIG_CONTAINER:
+ f34->v7.img.lockdown.data = content;
+ f34->v7.img.lockdown.size = length;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void rmi_f34v7_parse_image_header_10(struct f34_data *f34)
+{
+ unsigned int i;
+ unsigned int num_of_containers;
+ unsigned int addr;
+ unsigned int offset;
+ unsigned int container_id;
+ unsigned int length;
+ const void *image = f34->v7.image;
+ const u8 *content;
+ const struct container_descriptor *descriptor;
+ const struct image_header_10 *header = image;
+
+ f34->v7.img.checksum = le32_to_cpu(header->checksum);
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: f34->v7.img.checksum=%X\n",
+ __func__, f34->v7.img.checksum);
+
+ /* address of top level container */
+ offset = le32_to_cpu(header->top_level_container_start_addr);
+ descriptor = image + offset;
+
+ /* address of top level container content */
+ offset = le32_to_cpu(descriptor->content_address);
+ num_of_containers = le32_to_cpu(descriptor->content_length) / 4;
+
+ for (i = 0; i < num_of_containers; i++) {
+ addr = get_unaligned_le32(image + offset);
+ offset += 4;
+ descriptor = image + addr;
+ container_id = le16_to_cpu(descriptor->container_id);
+ content = image + le32_to_cpu(descriptor->content_address);
+ length = le32_to_cpu(descriptor->content_length);
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: container_id=%d, length=%d\n", __func__,
+ container_id, length);
+
+ switch (container_id) {
+ case UI_CONTAINER:
+ case CORE_CODE_CONTAINER:
+ f34->v7.img.ui_firmware.data = content;
+ f34->v7.img.ui_firmware.size = length;
+ break;
+ case UI_CONFIG_CONTAINER:
+ case CORE_CONFIG_CONTAINER:
+ f34->v7.img.ui_config.data = content;
+ f34->v7.img.ui_config.size = length;
+ break;
+ case BL_CONTAINER:
+ f34->v7.img.bl_version = *content;
+ f34->v7.img.bootloader.data = content;
+ f34->v7.img.bootloader.size = length;
+ rmi_f34v7_parse_img_header_10_bl_container(f34, image);
+ break;
+ case GUEST_CODE_CONTAINER:
+ f34->v7.img.contains_guest_code = true;
+ f34->v7.img.guest_code.data = content;
+ f34->v7.img.guest_code.size = length;
+ break;
+ case DISPLAY_CONFIG_CONTAINER:
+ f34->v7.img.contains_display_cfg = true;
+ f34->v7.img.dp_config.data = content;
+ f34->v7.img.dp_config.size = length;
+ break;
+ case FLASH_CONFIG_CONTAINER:
+ f34->v7.img.contains_flash_config = true;
+ f34->v7.img.fl_config.data = content;
+ f34->v7.img.fl_config.size = length;
+ break;
+ case GENERAL_INFORMATION_CONTAINER:
+ f34->v7.img.contains_firmware_id = true;
+ f34->v7.img.firmware_id =
+ get_unaligned_le32(content + 4);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static int rmi_f34v7_parse_image_info(struct f34_data *f34)
+{
+ const struct image_header_10 *header = f34->v7.image;
+
+ memset(&f34->v7.img, 0x00, sizeof(f34->v7.img));
+
+ rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+ "%s: header->major_header_version = %d\n",
+ __func__, header->major_header_version);
+
+ switch (header->major_header_version) {
+ case IMAGE_HEADER_VERSION_10:
+ rmi_f34v7_parse_image_header_10(f34);
+ break;
+ default:
+ dev_err(&f34->fn->dev, "Unsupported image file format %02X\n",
+ header->major_header_version);
+ return -EINVAL;
+ }
+
+ if (!f34->v7.img.contains_flash_config) {
+ dev_err(&f34->fn->dev, "%s: No flash config in fw image\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ rmi_f34v7_parse_partition_table(f34, f34->v7.img.fl_config.data,
+ &f34->v7.img.blkcount, &f34->v7.img.phyaddr);
+
+ rmi_f34v7_compare_partition_tables(f34);
+
+ return 0;
+}
+
+int rmi_f34v7_do_reflash(struct f34_data *f34, const struct firmware *fw)
+{
+ int ret;
+
+ rmi_f34v7_read_queries_bl_version(f34);
+
+ f34->v7.image = fw->data;
+
+ ret = rmi_f34v7_parse_image_info(f34);
+ if (ret < 0)
+ goto fail;
+
+ if (!f34->v7.new_partition_table) {
+ ret = rmi_f34v7_check_ui_firmware_size(f34);
+ if (ret < 0)
+ goto fail;
+
+ ret = rmi_f34v7_check_ui_config_size(f34);
+ if (ret < 0)
+ goto fail;
+
+ if (f34->v7.has_display_cfg &&
+ f34->v7.img.contains_display_cfg) {
+ ret = rmi_f34v7_check_dp_config_size(f34);
+ if (ret < 0)
+ goto fail;
+ }
+
+ if (f34->v7.has_guest_code && f34->v7.img.contains_guest_code) {
+ ret = rmi_f34v7_check_guest_code_size(f34);
+ if (ret < 0)
+ goto fail;
+ }
+ } else {
+ ret = rmi_f34v7_check_bl_config_size(f34);
+ if (ret < 0)
+ goto fail;
+ }
+
+ ret = rmi_f34v7_erase_all(f34);
+ if (ret < 0)
+ goto fail;
+
+ if (f34->v7.new_partition_table) {
+ ret = rmi_f34v7_write_partition_table(f34);
+ if (ret < 0)
+ goto fail;
+ dev_info(&f34->fn->dev, "%s: Partition table programmed\n",
+ __func__);
+ }
+
+ dev_info(&f34->fn->dev, "Writing firmware (%d bytes)...\n",
+ f34->v7.img.ui_firmware.size);
+
+ ret = rmi_f34v7_write_firmware(f34);
+ if (ret < 0)
+ goto fail;
+
+ dev_info(&f34->fn->dev, "Writing config (%d bytes)...\n",
+ f34->v7.img.ui_config.size);
+
+ f34->v7.config_area = v7_UI_CONFIG_AREA;
+ ret = rmi_f34v7_write_ui_config(f34);
+ if (ret < 0)
+ goto fail;
+
+ if (f34->v7.has_display_cfg && f34->v7.img.contains_display_cfg) {
+ dev_info(&f34->fn->dev, "Writing display config...\n");
+
+ ret = rmi_f34v7_write_dp_config(f34);
+ if (ret < 0)
+ goto fail;
+ }
+
+ if (f34->v7.new_partition_table) {
+ if (f34->v7.has_guest_code && f34->v7.img.contains_guest_code) {
+ dev_info(&f34->fn->dev, "Writing guest code...\n");
+
+ ret = rmi_f34v7_write_guest_code(f34);
+ if (ret < 0)
+ goto fail;
+ }
+ }
+
+fail:
+ return ret;
+}
+
+static int rmi_f34v7_enter_flash_prog(struct f34_data *f34)
+{
+ int ret;
+
+ ret = rmi_f34v7_read_flash_status(f34);
+ if (ret < 0)
+ return ret;
+
+ if (f34->v7.in_bl_mode)
+ return 0;
+
+ ret = rmi_f34v7_write_command(f34, v7_CMD_ENABLE_FLASH_PROG);
+ if (ret < 0)
+ return ret;
+
+ ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+ if (ret < 0)
+ return ret;
+
+ if (!f34->v7.in_bl_mode) {
+ dev_err(&f34->fn->dev, "%s: BL mode not entered\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int rmi_f34v7_start_reflash(struct f34_data *f34, const struct firmware *fw)
+{
+ int ret = 0;
+
+ f34->v7.config_area = v7_UI_CONFIG_AREA;
+ f34->v7.image = fw->data;
+
+ ret = rmi_f34v7_parse_image_info(f34);
+ if (ret < 0)
+ goto exit;
+
+ if (!f34->v7.force_update && f34->v7.new_partition_table) {
+ dev_err(&f34->fn->dev, "%s: Partition table mismatch\n",
+ __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ dev_info(&f34->fn->dev, "Firmware image OK\n");
+
+ ret = rmi_f34v7_read_flash_status(f34);
+ if (ret < 0)
+ goto exit;
+
+ if (f34->v7.in_bl_mode) {
+ dev_info(&f34->fn->dev, "%s: Device in bootloader mode\n",
+ __func__);
+ }
+
+ rmi_f34v7_enter_flash_prog(f34);
+
+ return 0;
+
+exit:
+ return ret;
+}
+
+int rmi_f34v7_probe(struct f34_data *f34)
+{
+ int ret;
+
+ /* Read bootloader version */
+ ret = rmi_read_block(f34->fn->rmi_dev,
+ f34->fn->fd.query_base_addr + V7_BOOTLOADER_ID_OFFSET,
+ f34->bootloader_id,
+ sizeof(f34->bootloader_id));
+ if (ret < 0) {
+ dev_err(&f34->fn->dev, "%s: Failed to read bootloader ID\n",
+ __func__);
+ return ret;
+ }
+
+ if (f34->bootloader_id[1] == '5') {
+ f34->bl_version = 5;
+ } else if (f34->bootloader_id[1] == '6') {
+ f34->bl_version = 6;
+ } else if (f34->bootloader_id[1] == 7) {
+ f34->bl_version = 7;
+ } else {
+ dev_err(&f34->fn->dev, "%s: Unrecognized bootloader version\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ memset(&f34->v7.blkcount, 0x00, sizeof(f34->v7.blkcount));
+ memset(&f34->v7.phyaddr, 0x00, sizeof(f34->v7.phyaddr));
+ rmi_f34v7_read_queries(f34);
+
+ f34->v7.force_update = false;
+ return 0;
+}
diff --git a/drivers/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c
new file mode 100644
index 000000000000..dea63e2db3e6
--- /dev/null
+++ b/drivers/input/rmi4/rmi_f54.c
@@ -0,0 +1,764 @@
+/*
+ * Copyright (c) 2012-2015 Synaptics Incorporated
+ * Copyright (C) 2016 Zodiac Inflight Innovations
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/rmi.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-vmalloc.h>
+#include "rmi_driver.h"
+
+#define F54_NAME "rmi4_f54"
+
+/* F54 data offsets */
+#define F54_REPORT_DATA_OFFSET 3
+#define F54_FIFO_OFFSET 1
+#define F54_NUM_TX_OFFSET 1
+#define F54_NUM_RX_OFFSET 0
+
+/* F54 commands */
+#define F54_GET_REPORT 1
+#define F54_FORCE_CAL 2
+
+/* Fixed sizes of reports */
+#define F54_QUERY_LEN 27
+
+/* F54 capabilities */
+#define F54_CAP_BASELINE (1 << 2)
+#define F54_CAP_IMAGE8 (1 << 3)
+#define F54_CAP_IMAGE16 (1 << 6)
+
+/**
+ * enum rmi_f54_report_type - RMI4 F54 report types
+ *
+ * @F54_8BIT_IMAGE: Normalized 8-Bit Image Report. The capacitance variance
+ * from baseline for each pixel.
+ *
+ * @F54_16BIT_IMAGE: Normalized 16-Bit Image Report. The capacitance variance
+ * from baseline for each pixel.
+ *
+ * @F54_RAW_16BIT_IMAGE:
+ * Raw 16-Bit Image Report. The raw capacitance for each
+ * pixel.
+ *
+ * @F54_TRUE_BASELINE: True Baseline Report. The baseline capacitance for each
+ * pixel.
+ *
+ * @F54_FULL_RAW_CAP: Full Raw Capacitance Report. The raw capacitance with
+ * low reference set to its minimum value and high
+ * reference set to its maximum value.
+ *
+ * @F54_FULL_RAW_CAP_RX_OFFSET_REMOVED:
+ * Full Raw Capacitance with Receiver Offset Removed
+ * Report. Set Low reference to its minimum value and high
+ * references to its maximum value, then report the raw
+ * capacitance for each pixel.
+ */
+enum rmi_f54_report_type {
+ F54_REPORT_NONE = 0,
+ F54_8BIT_IMAGE = 1,
+ F54_16BIT_IMAGE = 2,
+ F54_RAW_16BIT_IMAGE = 3,
+ F54_TRUE_BASELINE = 9,
+ F54_FULL_RAW_CAP = 19,
+ F54_FULL_RAW_CAP_RX_OFFSET_REMOVED = 20,
+ F54_MAX_REPORT_TYPE,
+};
+
+const char *rmi_f54_report_type_names[] = {
+ [F54_REPORT_NONE] = "Unknown",
+ [F54_8BIT_IMAGE] = "Normalized 8-Bit Image",
+ [F54_16BIT_IMAGE] = "Normalized 16-Bit Image",
+ [F54_RAW_16BIT_IMAGE] = "Raw 16-Bit Image",
+ [F54_TRUE_BASELINE] = "True Baseline",
+ [F54_FULL_RAW_CAP] = "Full Raw Capacitance",
+ [F54_FULL_RAW_CAP_RX_OFFSET_REMOVED]
+ = "Full Raw Capacitance RX Offset Removed",
+};
+
+struct rmi_f54_reports {
+ int start;
+ int size;
+};
+
+struct f54_data {
+ struct rmi_function *fn;
+
+ u8 qry[F54_QUERY_LEN];
+ u8 num_rx_electrodes;
+ u8 num_tx_electrodes;
+ u8 capabilities;
+ u16 clock_rate;
+ u8 family;
+
+ enum rmi_f54_report_type report_type;
+ u8 *report_data;
+ int report_size;
+ struct rmi_f54_reports standard_report[2];
+
+ bool is_busy;
+ struct mutex status_mutex;
+ struct mutex data_mutex;
+
+ struct workqueue_struct *workqueue;
+ struct delayed_work work;
+ unsigned long timeout;
+
+ struct completion cmd_done;
+
+ /* V4L2 support */
+ struct v4l2_device v4l2;
+ struct v4l2_pix_format format;
+ struct video_device vdev;
+ struct vb2_queue queue;
+ struct mutex lock;
+ int input;
+ enum rmi_f54_report_type inputs[F54_MAX_REPORT_TYPE];
+};
+
+/*
+ * Basic checks on report_type to ensure we write a valid type
+ * to the sensor.
+ */
+static bool is_f54_report_type_valid(struct f54_data *f54,
+ enum rmi_f54_report_type reptype)
+{
+ switch (reptype) {
+ case F54_8BIT_IMAGE:
+ return f54->capabilities & F54_CAP_IMAGE8;
+ case F54_16BIT_IMAGE:
+ case F54_RAW_16BIT_IMAGE:
+ return f54->capabilities & F54_CAP_IMAGE16;
+ case F54_TRUE_BASELINE:
+ return f54->capabilities & F54_CAP_IMAGE16;
+ case F54_FULL_RAW_CAP:
+ case F54_FULL_RAW_CAP_RX_OFFSET_REMOVED:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static enum rmi_f54_report_type rmi_f54_get_reptype(struct f54_data *f54,
+ unsigned int i)
+{
+ if (i >= F54_MAX_REPORT_TYPE)
+ return F54_REPORT_NONE;
+
+ return f54->inputs[i];
+}
+
+static void rmi_f54_create_input_map(struct f54_data *f54)
+{
+ int i = 0;
+ enum rmi_f54_report_type reptype;
+
+ for (reptype = 1; reptype < F54_MAX_REPORT_TYPE; reptype++) {
+ if (!is_f54_report_type_valid(f54, reptype))
+ continue;
+
+ f54->inputs[i++] = reptype;
+ }
+
+ /* Remaining values are zero via kzalloc */
+}
+
+static int rmi_f54_request_report(struct rmi_function *fn, u8 report_type)
+{
+ struct f54_data *f54 = dev_get_drvdata(&fn->dev);
+ struct rmi_device *rmi_dev = fn->rmi_dev;
+ int error;
+
+ /* Write Report Type into F54_AD_Data0 */
+ if (f54->report_type != report_type) {
+ error = rmi_write(rmi_dev, f54->fn->fd.data_base_addr,
+ report_type);
+ if (error)
+ return error;
+ f54->report_type = report_type;
+ }
+
+ /*
+ * Small delay after disabling interrupts to avoid race condition
+ * in firmare. This value is a bit higher than absolutely necessary.
+ * Should be removed once issue is resolved in firmware.
+ */
+ usleep_range(2000, 3000);
+
+ mutex_lock(&f54->data_mutex);
+
+ error = rmi_write(rmi_dev, fn->fd.command_base_addr, F54_GET_REPORT);
+ if (error < 0)
+ goto unlock;
+
+ init_completion(&f54->cmd_done);
+
+ f54->is_busy = 1;
+ f54->timeout = jiffies + msecs_to_jiffies(100);
+
+ queue_delayed_work(f54->workqueue, &f54->work, 0);
+
+unlock:
+ mutex_unlock(&f54->data_mutex);
+
+ return error;
+}
+
+static size_t rmi_f54_get_report_size(struct f54_data *f54)
+{
+ struct rmi_device *rmi_dev = f54->fn->rmi_dev;
+ struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
+ u8 rx = drv_data->num_rx_electrodes ? : f54->num_rx_electrodes;
+ u8 tx = drv_data->num_tx_electrodes ? : f54->num_tx_electrodes;
+ size_t size;
+
+ switch (rmi_f54_get_reptype(f54, f54->input)) {
+ case F54_8BIT_IMAGE:
+ size = rx * tx;
+ break;
+ case F54_16BIT_IMAGE:
+ case F54_RAW_16BIT_IMAGE:
+ case F54_TRUE_BASELINE:
+ case F54_FULL_RAW_CAP:
+ case F54_FULL_RAW_CAP_RX_OFFSET_REMOVED:
+ size = sizeof(u16) * rx * tx;
+ break;
+ default:
+ size = 0;
+ }
+
+ return size;
+}
+
+static int rmi_f54_get_pixel_fmt(enum rmi_f54_report_type reptype, u32 *pixfmt)
+{
+ int ret = 0;
+
+ switch (reptype) {
+ case F54_8BIT_IMAGE:
+ *pixfmt = V4L2_TCH_FMT_DELTA_TD08;
+ break;
+
+ case F54_16BIT_IMAGE:
+ *pixfmt = V4L2_TCH_FMT_DELTA_TD16;
+ break;
+
+ case F54_RAW_16BIT_IMAGE:
+ case F54_TRUE_BASELINE:
+ case F54_FULL_RAW_CAP:
+ case F54_FULL_RAW_CAP_RX_OFFSET_REMOVED:
+ *pixfmt = V4L2_TCH_FMT_TU16;
+ break;
+
+ case F54_REPORT_NONE:
+ case F54_MAX_REPORT_TYPE:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static const struct v4l2_file_operations rmi_f54_video_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .unlocked_ioctl = video_ioctl2,
+ .read = vb2_fop_read,
+ .mmap = vb2_fop_mmap,
+ .poll = vb2_fop_poll,
+};
+
+static int rmi_f54_queue_setup(struct vb2_queue *q, unsigned int *nbuffers,
+ unsigned int *nplanes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct f54_data *f54 = q->drv_priv;
+
+ if (*nplanes)
+ return sizes[0] < rmi_f54_get_report_size(f54) ? -EINVAL : 0;
+
+ *nplanes = 1;
+ sizes[0] = rmi_f54_get_report_size(f54);
+
+ return 0;
+}
+
+static void rmi_f54_buffer_queue(struct vb2_buffer *vb)
+{
+ struct f54_data *f54 = vb2_get_drv_priv(vb->vb2_queue);
+ u16 *ptr;
+ enum vb2_buffer_state state;
+ enum rmi_f54_report_type reptype;
+ int ret;
+
+ mutex_lock(&f54->status_mutex);
+
+ reptype = rmi_f54_get_reptype(f54, f54->input);
+ if (reptype == F54_REPORT_NONE) {
+ state = VB2_BUF_STATE_ERROR;
+ goto done;
+ }
+
+ if (f54->is_busy) {
+ state = VB2_BUF_STATE_ERROR;
+ goto done;
+ }
+
+ ret = rmi_f54_request_report(f54->fn, reptype);
+ if (ret) {
+ dev_err(&f54->fn->dev, "Error requesting F54 report\n");
+ state = VB2_BUF_STATE_ERROR;
+ goto done;
+ }
+
+ /* get frame data */
+ mutex_lock(&f54->data_mutex);
+
+ while (f54->is_busy) {
+ mutex_unlock(&f54->data_mutex);
+ if (!wait_for_completion_timeout(&f54->cmd_done,
+ msecs_to_jiffies(1000))) {
+ dev_err(&f54->fn->dev, "Timed out\n");
+ state = VB2_BUF_STATE_ERROR;
+ goto done;
+ }
+ mutex_lock(&f54->data_mutex);
+ }
+
+ ptr = vb2_plane_vaddr(vb, 0);
+ if (!ptr) {
+ dev_err(&f54->fn->dev, "Error acquiring frame ptr\n");
+ state = VB2_BUF_STATE_ERROR;
+ goto data_done;
+ }
+
+ memcpy(ptr, f54->report_data, f54->report_size);
+ vb2_set_plane_payload(vb, 0, rmi_f54_get_report_size(f54));
+ state = VB2_BUF_STATE_DONE;
+
+data_done:
+ mutex_unlock(&f54->data_mutex);
+done:
+ vb2_buffer_done(vb, state);
+ mutex_unlock(&f54->status_mutex);
+}
+
+/* V4L2 structures */
+static const struct vb2_ops rmi_f54_queue_ops = {
+ .queue_setup = rmi_f54_queue_setup,
+ .buf_queue = rmi_f54_buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+static const struct vb2_queue rmi_f54_queue = {
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ,
+ .buf_struct_size = sizeof(struct vb2_buffer),
+ .ops = &rmi_f54_queue_ops,
+ .mem_ops = &vb2_vmalloc_memops,
+ .timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC,
+ .min_buffers_needed = 1,
+};
+
+static int rmi_f54_vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct f54_data *f54 = video_drvdata(file);
+
+ strlcpy(cap->driver, F54_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, SYNAPTICS_INPUT_DEVICE_NAME, sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info),
+ "rmi4:%s", dev_name(&f54->fn->dev));
+
+ return 0;
+}
+
+static int rmi_f54_vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct f54_data *f54 = video_drvdata(file);
+ enum rmi_f54_report_type reptype;
+
+ reptype = rmi_f54_get_reptype(f54, i->index);
+ if (reptype == F54_REPORT_NONE)
+ return -EINVAL;
+
+ i->type = V4L2_INPUT_TYPE_TOUCH;
+
+ strlcpy(i->name, rmi_f54_report_type_names[reptype], sizeof(i->name));
+ return 0;
+}
+
+static int rmi_f54_set_input(struct f54_data *f54, unsigned int i)
+{
+ struct rmi_device *rmi_dev = f54->fn->rmi_dev;
+ struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
+ u8 rx = drv_data->num_rx_electrodes ? : f54->num_rx_electrodes;
+ u8 tx = drv_data->num_tx_electrodes ? : f54->num_tx_electrodes;
+ struct v4l2_pix_format *f = &f54->format;
+ enum rmi_f54_report_type reptype;
+ int ret;
+
+ reptype = rmi_f54_get_reptype(f54, i);
+ if (reptype == F54_REPORT_NONE)
+ return -EINVAL;
+
+ ret = rmi_f54_get_pixel_fmt(reptype, &f->pixelformat);
+ if (ret)
+ return ret;
+
+ f54->input = i;
+
+ f->width = rx;
+ f->height = tx;
+ f->field = V4L2_FIELD_NONE;
+ f->colorspace = V4L2_COLORSPACE_RAW;
+ f->bytesperline = f->width * sizeof(u16);
+ f->sizeimage = f->width * f->height * sizeof(u16);
+
+ return 0;
+}
+
+static int rmi_f54_vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ return rmi_f54_set_input(video_drvdata(file), i);
+}
+
+static int rmi_f54_vidioc_g_input(struct file *file, void *priv,
+ unsigned int *i)
+{
+ struct f54_data *f54 = video_drvdata(file);
+
+ *i = f54->input;
+
+ return 0;
+}
+
+static int rmi_f54_vidioc_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct f54_data *f54 = video_drvdata(file);
+
+ f->fmt.pix = f54->format;
+
+ return 0;
+}
+
+static int rmi_f54_vidioc_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *fmt)
+{
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ switch (fmt->index) {
+ case 0:
+ fmt->pixelformat = V4L2_TCH_FMT_DELTA_TD16;
+ break;
+
+ case 1:
+ fmt->pixelformat = V4L2_TCH_FMT_DELTA_TD08;
+ break;
+
+ case 2:
+ fmt->pixelformat = V4L2_TCH_FMT_TU16;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rmi_f54_vidioc_g_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ a->parm.capture.readbuffers = 1;
+ a->parm.capture.timeperframe.numerator = 1;
+ a->parm.capture.timeperframe.denominator = 10;
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops rmi_f54_video_ioctl_ops = {
+ .vidioc_querycap = rmi_f54_vidioc_querycap,
+
+ .vidioc_enum_fmt_vid_cap = rmi_f54_vidioc_enum_fmt,
+ .vidioc_s_fmt_vid_cap = rmi_f54_vidioc_fmt,
+ .vidioc_g_fmt_vid_cap = rmi_f54_vidioc_fmt,
+ .vidioc_try_fmt_vid_cap = rmi_f54_vidioc_fmt,
+ .vidioc_g_parm = rmi_f54_vidioc_g_parm,
+
+ .vidioc_enum_input = rmi_f54_vidioc_enum_input,
+ .vidioc_g_input = rmi_f54_vidioc_g_input,
+ .vidioc_s_input = rmi_f54_vidioc_s_input,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+};
+
+static const struct video_device rmi_f54_video_device = {
+ .name = "Synaptics RMI4",
+ .fops = &rmi_f54_video_fops,
+ .ioctl_ops = &rmi_f54_video_ioctl_ops,
+ .release = video_device_release_empty,
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TOUCH |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING,
+};
+
+static void rmi_f54_work(struct work_struct *work)
+{
+ struct f54_data *f54 = container_of(work, struct f54_data, work.work);
+ struct rmi_function *fn = f54->fn;
+ u8 fifo[2];
+ struct rmi_f54_reports *report;
+ int report_size;
+ u8 command;
+ u8 *data;
+ int error;
+
+ data = f54->report_data;
+ report_size = rmi_f54_get_report_size(f54);
+ if (report_size == 0) {
+ dev_err(&fn->dev, "Bad report size, report type=%d\n",
+ f54->report_type);
+ error = -EINVAL;
+ goto error; /* retry won't help */
+ }
+ f54->standard_report[0].size = report_size;
+ report = f54->standard_report;
+
+ mutex_lock(&f54->data_mutex);
+
+ /*
+ * Need to check if command has completed.
+ * If not try again later.
+ */
+ error = rmi_read(fn->rmi_dev, f54->fn->fd.command_base_addr,
+ &command);
+ if (error) {
+ dev_err(&fn->dev, "Failed to read back command\n");
+ goto error;
+ }
+ if (command & F54_GET_REPORT) {
+ if (time_after(jiffies, f54->timeout)) {
+ dev_err(&fn->dev, "Get report command timed out\n");
+ error = -ETIMEDOUT;
+ }
+ report_size = 0;
+ goto error;
+ }
+
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Get report command completed, reading data\n");
+
+ report_size = 0;
+ for (; report->size; report++) {
+ fifo[0] = report->start & 0xff;
+ fifo[1] = (report->start >> 8) & 0xff;
+ error = rmi_write_block(fn->rmi_dev,
+ fn->fd.data_base_addr + F54_FIFO_OFFSET,
+ fifo, sizeof(fifo));
+ if (error) {
+ dev_err(&fn->dev, "Failed to set fifo start offset\n");
+ goto abort;
+ }
+
+ error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr +
+ F54_REPORT_DATA_OFFSET, data,
+ report->size);
+ if (error) {
+ dev_err(&fn->dev, "%s: read [%d bytes] returned %d\n",
+ __func__, report->size, error);
+ goto abort;
+ }
+ data += report->size;
+ report_size += report->size;
+ }
+
+abort:
+ f54->report_size = error ? 0 : report_size;
+error:
+ if (error)
+ report_size = 0;
+
+ if (report_size == 0 && !error) {
+ queue_delayed_work(f54->workqueue, &f54->work,
+ msecs_to_jiffies(1));
+ } else {
+ f54->is_busy = false;
+ complete(&f54->cmd_done);
+ }
+
+ mutex_unlock(&f54->data_mutex);
+}
+
+static int rmi_f54_attention(struct rmi_function *fn, unsigned long *irqbits)
+{
+ return 0;
+}
+
+static int rmi_f54_config(struct rmi_function *fn)
+{
+ struct rmi_driver *drv = fn->rmi_dev->driver;
+
+ drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
+
+ return 0;
+}
+
+static int rmi_f54_detect(struct rmi_function *fn)
+{
+ int error;
+ struct f54_data *f54;
+
+ f54 = dev_get_drvdata(&fn->dev);
+
+ error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
+ &f54->qry, sizeof(f54->qry));
+ if (error) {
+ dev_err(&fn->dev, "%s: Failed to query F54 properties\n",
+ __func__);
+ return error;
+ }
+
+ f54->num_rx_electrodes = f54->qry[0];
+ f54->num_tx_electrodes = f54->qry[1];
+ f54->capabilities = f54->qry[2];
+ f54->clock_rate = f54->qry[3] | (f54->qry[4] << 8);
+ f54->family = f54->qry[5];
+
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F54 num_rx_electrodes: %d\n",
+ f54->num_rx_electrodes);
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F54 num_tx_electrodes: %d\n",
+ f54->num_tx_electrodes);
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F54 capabilities: 0x%x\n",
+ f54->capabilities);
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F54 clock rate: 0x%x\n",
+ f54->clock_rate);
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F54 family: 0x%x\n",
+ f54->family);
+
+ f54->is_busy = false;
+
+ return 0;
+}
+
+static int rmi_f54_probe(struct rmi_function *fn)
+{
+ struct f54_data *f54;
+ int ret;
+ u8 rx, tx;
+
+ f54 = devm_kzalloc(&fn->dev, sizeof(struct f54_data), GFP_KERNEL);
+ if (!f54)
+ return -ENOMEM;
+
+ f54->fn = fn;
+ dev_set_drvdata(&fn->dev, f54);
+
+ ret = rmi_f54_detect(fn);
+ if (ret)
+ return ret;
+
+ mutex_init(&f54->data_mutex);
+ mutex_init(&f54->status_mutex);
+
+ rx = f54->num_rx_electrodes;
+ tx = f54->num_tx_electrodes;
+ f54->report_data = devm_kzalloc(&fn->dev,
+ sizeof(u16) * tx * rx,
+ GFP_KERNEL);
+ if (f54->report_data == NULL)
+ return -ENOMEM;
+
+ INIT_DELAYED_WORK(&f54->work, rmi_f54_work);
+
+ f54->workqueue = create_singlethread_workqueue("rmi4-poller");
+ if (!f54->workqueue)
+ return -ENOMEM;
+
+ rmi_f54_create_input_map(f54);
+
+ /* register video device */
+ strlcpy(f54->v4l2.name, F54_NAME, sizeof(f54->v4l2.name));
+ ret = v4l2_device_register(&fn->dev, &f54->v4l2);
+ if (ret) {
+ dev_err(&fn->dev, "Unable to register video dev.\n");
+ goto remove_wq;
+ }
+
+ /* initialize the queue */
+ mutex_init(&f54->lock);
+ f54->queue = rmi_f54_queue;
+ f54->queue.drv_priv = f54;
+ f54->queue.lock = &f54->lock;
+ f54->queue.dev = &fn->dev;
+
+ ret = vb2_queue_init(&f54->queue);
+ if (ret)
+ goto remove_v4l2;
+
+ f54->vdev = rmi_f54_video_device;
+ f54->vdev.v4l2_dev = &f54->v4l2;
+ f54->vdev.lock = &f54->lock;
+ f54->vdev.vfl_dir = VFL_DIR_RX;
+ f54->vdev.queue = &f54->queue;
+ video_set_drvdata(&f54->vdev, f54);
+
+ ret = video_register_device(&f54->vdev, VFL_TYPE_TOUCH, -1);
+ if (ret) {
+ dev_err(&fn->dev, "Unable to register video subdevice.");
+ goto remove_v4l2;
+ }
+
+ return 0;
+
+remove_v4l2:
+ v4l2_device_unregister(&f54->v4l2);
+remove_wq:
+ cancel_delayed_work_sync(&f54->work);
+ flush_workqueue(f54->workqueue);
+ destroy_workqueue(f54->workqueue);
+ return ret;
+}
+
+static void rmi_f54_remove(struct rmi_function *fn)
+{
+ struct f54_data *f54 = dev_get_drvdata(&fn->dev);
+
+ video_unregister_device(&f54->vdev);
+ v4l2_device_unregister(&f54->v4l2);
+}
+
+struct rmi_function_handler rmi_f54_handler = {
+ .driver = {
+ .name = F54_NAME,
+ },
+ .func = 0x54,
+ .probe = rmi_f54_probe,
+ .config = rmi_f54_config,
+ .attention = rmi_f54_attention,
+ .remove = rmi_f54_remove,
+};
diff --git a/drivers/input/rmi4/rmi_f55.c b/drivers/input/rmi4/rmi_f55.c
new file mode 100644
index 000000000000..37390ca6a924
--- /dev/null
+++ b/drivers/input/rmi4/rmi_f55.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2012-2015 Synaptics Incorporated
+ * Copyright (C) 2016 Zodiac Inflight Innovations
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/rmi.h>
+#include <linux/slab.h>
+#include "rmi_driver.h"
+
+#define F55_NAME "rmi4_f55"
+
+/* F55 data offsets */
+#define F55_NUM_RX_OFFSET 0
+#define F55_NUM_TX_OFFSET 1
+#define F55_PHYS_CHAR_OFFSET 2
+
+/* Only read required query registers */
+#define F55_QUERY_LEN 3
+
+/* F55 capabilities */
+#define F55_CAP_SENSOR_ASSIGN BIT(0)
+
+struct f55_data {
+ struct rmi_function *fn;
+
+ u8 qry[F55_QUERY_LEN];
+ u8 num_rx_electrodes;
+ u8 cfg_num_rx_electrodes;
+ u8 num_tx_electrodes;
+ u8 cfg_num_tx_electrodes;
+};
+
+static int rmi_f55_detect(struct rmi_function *fn)
+{
+ struct rmi_device *rmi_dev = fn->rmi_dev;
+ struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
+ struct f55_data *f55;
+ int error;
+
+ f55 = dev_get_drvdata(&fn->dev);
+
+ error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
+ &f55->qry, sizeof(f55->qry));
+ if (error) {
+ dev_err(&fn->dev, "%s: Failed to query F55 properties\n",
+ __func__);
+ return error;
+ }
+
+ f55->num_rx_electrodes = f55->qry[F55_NUM_RX_OFFSET];
+ f55->num_tx_electrodes = f55->qry[F55_NUM_TX_OFFSET];
+
+ f55->cfg_num_rx_electrodes = f55->num_rx_electrodes;
+ f55->cfg_num_tx_electrodes = f55->num_rx_electrodes;
+
+ drv_data->num_rx_electrodes = f55->cfg_num_rx_electrodes;
+ drv_data->num_tx_electrodes = f55->cfg_num_rx_electrodes;
+
+ if (f55->qry[F55_PHYS_CHAR_OFFSET] & F55_CAP_SENSOR_ASSIGN) {
+ int i, total;
+ u8 buf[256];
+
+ /*
+ * Calculate the number of enabled receive and transmit
+ * electrodes by reading F55:Ctrl1 (sensor receiver assignment)
+ * and F55:Ctrl2 (sensor transmitter assignment). The number of
+ * enabled electrodes is the sum of all field entries with a
+ * value other than 0xff.
+ */
+ error = rmi_read_block(fn->rmi_dev,
+ fn->fd.control_base_addr + 1,
+ buf, f55->num_rx_electrodes);
+ if (!error) {
+ total = 0;
+ for (i = 0; i < f55->num_rx_electrodes; i++) {
+ if (buf[i] != 0xff)
+ total++;
+ }
+ f55->cfg_num_rx_electrodes = total;
+ drv_data->num_rx_electrodes = total;
+ }
+
+ error = rmi_read_block(fn->rmi_dev,
+ fn->fd.control_base_addr + 2,
+ buf, f55->num_tx_electrodes);
+ if (!error) {
+ total = 0;
+ for (i = 0; i < f55->num_tx_electrodes; i++) {
+ if (buf[i] != 0xff)
+ total++;
+ }
+ f55->cfg_num_tx_electrodes = total;
+ drv_data->num_tx_electrodes = total;
+ }
+ }
+
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_rx_electrodes: %d (raw %d)\n",
+ f55->cfg_num_rx_electrodes, f55->num_rx_electrodes);
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_tx_electrodes: %d (raw %d)\n",
+ f55->cfg_num_tx_electrodes, f55->num_tx_electrodes);
+
+ return 0;
+}
+
+static int rmi_f55_probe(struct rmi_function *fn)
+{
+ struct f55_data *f55;
+
+ f55 = devm_kzalloc(&fn->dev, sizeof(struct f55_data), GFP_KERNEL);
+ if (!f55)
+ return -ENOMEM;
+
+ f55->fn = fn;
+ dev_set_drvdata(&fn->dev, f55);
+
+ return rmi_f55_detect(fn);
+}
+
+struct rmi_function_handler rmi_f55_handler = {
+ .driver = {
+ .name = F55_NAME,
+ },
+ .func = 0x55,
+ .probe = rmi_f55_probe,
+};
diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c
index 1ebc2c1debae..082306d7c207 100644
--- a/drivers/input/rmi4/rmi_i2c.c
+++ b/drivers/input/rmi4/rmi_i2c.c
@@ -9,7 +9,6 @@
#include <linux/i2c.h>
#include <linux/rmi.h>
-#include <linux/irq.h>
#include <linux/of.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
@@ -35,8 +34,6 @@ struct rmi_i2c_xport {
struct mutex page_mutex;
int page;
- int irq;
-
u8 *tx_buf;
size_t tx_buf_size;
@@ -177,42 +174,6 @@ static const struct rmi_transport_ops rmi_i2c_ops = {
.read_block = rmi_i2c_read_block,
};
-static irqreturn_t rmi_i2c_irq(int irq, void *dev_id)
-{
- struct rmi_i2c_xport *rmi_i2c = dev_id;
- struct rmi_device *rmi_dev = rmi_i2c->xport.rmi_dev;
- int ret;
-
- ret = rmi_process_interrupt_requests(rmi_dev);
- if (ret)
- rmi_dbg(RMI_DEBUG_XPORT, &rmi_dev->dev,
- "Failed to process interrupt request: %d\n", ret);
-
- return IRQ_HANDLED;
-}
-
-static int rmi_i2c_init_irq(struct i2c_client *client)
-{
- struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
- int irq_flags = irqd_get_trigger_type(irq_get_irq_data(rmi_i2c->irq));
- int ret;
-
- if (!irq_flags)
- irq_flags = IRQF_TRIGGER_LOW;
-
- ret = devm_request_threaded_irq(&client->dev, rmi_i2c->irq, NULL,
- rmi_i2c_irq, irq_flags | IRQF_ONESHOT, client->name,
- rmi_i2c);
- if (ret < 0) {
- dev_warn(&client->dev, "Failed to register interrupt %d\n",
- rmi_i2c->irq);
-
- return ret;
- }
-
- return 0;
-}
-
#ifdef CONFIG_OF
static const struct of_device_id rmi_i2c_of_match[] = {
{ .compatible = "syna,rmi4-i2c" },
@@ -255,8 +216,7 @@ static int rmi_i2c_probe(struct i2c_client *client,
if (!client->dev.of_node && client_pdata)
*pdata = *client_pdata;
- if (client->irq > 0)
- rmi_i2c->irq = client->irq;
+ pdata->irq = client->irq;
rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n",
dev_name(&client->dev));
@@ -321,10 +281,6 @@ static int rmi_i2c_probe(struct i2c_client *client,
if (retval)
return retval;
- retval = rmi_i2c_init_irq(client);
- if (retval < 0)
- return retval;
-
dev_info(&client->dev, "registered rmi i2c driver at %#04x.\n",
client->addr);
return 0;
@@ -337,18 +293,10 @@ static int rmi_i2c_suspend(struct device *dev)
struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
int ret;
- ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev);
+ ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev, true);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
- disable_irq(rmi_i2c->irq);
- if (device_may_wakeup(&client->dev)) {
- ret = enable_irq_wake(rmi_i2c->irq);
- if (!ret)
- dev_warn(dev, "Failed to enable irq for wake: %d\n",
- ret);
- }
-
regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
rmi_i2c->supplies);
@@ -368,15 +316,7 @@ static int rmi_i2c_resume(struct device *dev)
msleep(rmi_i2c->startup_delay);
- enable_irq(rmi_i2c->irq);
- if (device_may_wakeup(&client->dev)) {
- ret = disable_irq_wake(rmi_i2c->irq);
- if (!ret)
- dev_warn(dev, "Failed to disable irq for wake: %d\n",
- ret);
- }
-
- ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev);
+ ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev, true);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
@@ -391,12 +331,10 @@ static int rmi_i2c_runtime_suspend(struct device *dev)
struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
int ret;
- ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev);
+ ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev, false);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
- disable_irq(rmi_i2c->irq);
-
regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
rmi_i2c->supplies);
@@ -416,9 +354,7 @@ static int rmi_i2c_runtime_resume(struct device *dev)
msleep(rmi_i2c->startup_delay);
- enable_irq(rmi_i2c->irq);
-
- ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev);
+ ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev, false);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c
new file mode 100644
index 000000000000..76752555d809
--- /dev/null
+++ b/drivers/input/rmi4/rmi_smbus.c
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2015 - 2016 Red Hat, Inc
+ * Copyright (c) 2011, 2012 Synaptics Incorporated
+ * Copyright (c) 2011 Unixphere
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kconfig.h>
+#include <linux/lockdep.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/rmi.h>
+#include <linux/slab.h>
+#include "rmi_driver.h"
+
+#define SMB_PROTOCOL_VERSION_ADDRESS 0xfd
+#define SMB_MAX_COUNT 32
+#define RMI_SMB2_MAP_SIZE 8 /* 8 entry of 4 bytes each */
+#define RMI_SMB2_MAP_FLAGS_WE 0x01
+
+struct mapping_table_entry {
+ __le16 rmiaddr;
+ u8 readcount;
+ u8 flags;
+};
+
+struct rmi_smb_xport {
+ struct rmi_transport_dev xport;
+ struct i2c_client *client;
+
+ struct mutex page_mutex;
+ int page;
+ u8 table_index;
+ struct mutex mappingtable_mutex;
+ struct mapping_table_entry mapping_table[RMI_SMB2_MAP_SIZE];
+};
+
+static int rmi_smb_get_version(struct rmi_smb_xport *rmi_smb)
+{
+ struct i2c_client *client = rmi_smb->client;
+ int retval;
+
+ /* Check if for SMBus new version device by reading version byte. */
+ retval = i2c_smbus_read_byte_data(client, SMB_PROTOCOL_VERSION_ADDRESS);
+ if (retval < 0) {
+ dev_err(&client->dev, "failed to get SMBus version number!\n");
+ return retval;
+ }
+ return retval + 1;
+}
+
+/* SMB block write - wrapper over ic2_smb_write_block */
+static int smb_block_write(struct rmi_transport_dev *xport,
+ u8 commandcode, const void *buf, size_t len)
+{
+ struct rmi_smb_xport *rmi_smb =
+ container_of(xport, struct rmi_smb_xport, xport);
+ struct i2c_client *client = rmi_smb->client;
+ int retval;
+
+ retval = i2c_smbus_write_block_data(client, commandcode, len, buf);
+
+ rmi_dbg(RMI_DEBUG_XPORT, &client->dev,
+ "wrote %zd bytes at %#04x: %d (%*ph)\n",
+ len, commandcode, retval, (int)len, buf);
+
+ return retval;
+}
+
+/*
+ * The function to get command code for smbus operations and keeps
+ * records to the driver mapping table
+ */
+static int rmi_smb_get_command_code(struct rmi_transport_dev *xport,
+ u16 rmiaddr, int bytecount, bool isread, u8 *commandcode)
+{
+ struct rmi_smb_xport *rmi_smb =
+ container_of(xport, struct rmi_smb_xport, xport);
+ int i;
+ int retval;
+ struct mapping_table_entry mapping_data[1];
+
+ mutex_lock(&rmi_smb->mappingtable_mutex);
+ for (i = 0; i < RMI_SMB2_MAP_SIZE; i++) {
+ if (rmi_smb->mapping_table[i].rmiaddr == rmiaddr) {
+ if (isread) {
+ if (rmi_smb->mapping_table[i].readcount
+ == bytecount) {
+ *commandcode = i;
+ retval = 0;
+ goto exit;
+ }
+ } else {
+ if (rmi_smb->mapping_table[i].flags &
+ RMI_SMB2_MAP_FLAGS_WE) {
+ *commandcode = i;
+ retval = 0;
+ goto exit;
+ }
+ }
+ }
+ }
+ i = rmi_smb->table_index;
+ rmi_smb->table_index = (i + 1) % RMI_SMB2_MAP_SIZE;
+
+ /* constructs mapping table data entry. 4 bytes each entry */
+ memset(mapping_data, 0, sizeof(mapping_data));
+
+ mapping_data[0].rmiaddr = cpu_to_le16(rmiaddr);
+ mapping_data[0].readcount = bytecount;
+ mapping_data[0].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0;
+
+ retval = smb_block_write(xport, i + 0x80, mapping_data,
+ sizeof(mapping_data));
+
+ if (retval < 0) {
+ /*
+ * if not written to device mapping table
+ * clear the driver mapping table records
+ */
+ rmi_smb->mapping_table[i].rmiaddr = 0x0000;
+ rmi_smb->mapping_table[i].readcount = 0;
+ rmi_smb->mapping_table[i].flags = 0;
+ goto exit;
+ }
+ /* save to the driver level mapping table */
+ rmi_smb->mapping_table[i].rmiaddr = rmiaddr;
+ rmi_smb->mapping_table[i].readcount = bytecount;
+ rmi_smb->mapping_table[i].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0;
+ *commandcode = i;
+
+exit:
+ mutex_unlock(&rmi_smb->mappingtable_mutex);
+
+ return retval;
+}
+
+static int rmi_smb_write_block(struct rmi_transport_dev *xport, u16 rmiaddr,
+ const void *databuff, size_t len)
+{
+ int retval = 0;
+ u8 commandcode;
+ struct rmi_smb_xport *rmi_smb =
+ container_of(xport, struct rmi_smb_xport, xport);
+ int cur_len = (int)len;
+
+ mutex_lock(&rmi_smb->page_mutex);
+
+ while (cur_len > 0) {
+ /*
+ * break into 32 bytes chunks to write get command code
+ */
+ int block_len = min_t(int, len, SMB_MAX_COUNT);
+
+ retval = rmi_smb_get_command_code(xport, rmiaddr, block_len,
+ false, &commandcode);
+ if (retval < 0)
+ goto exit;
+
+ retval = smb_block_write(xport, commandcode,
+ databuff, block_len);
+ if (retval < 0)
+ goto exit;
+
+ /* prepare to write next block of bytes */
+ cur_len -= SMB_MAX_COUNT;
+ databuff += SMB_MAX_COUNT;
+ rmiaddr += SMB_MAX_COUNT;
+ }
+exit:
+ mutex_unlock(&rmi_smb->page_mutex);
+ return retval;
+}
+
+/* SMB block read - wrapper over ic2_smb_read_block */
+static int smb_block_read(struct rmi_transport_dev *xport,
+ u8 commandcode, void *buf, size_t len)
+{
+ struct rmi_smb_xport *rmi_smb =
+ container_of(xport, struct rmi_smb_xport, xport);
+ struct i2c_client *client = rmi_smb->client;
+ int retval;
+
+ retval = i2c_smbus_read_block_data(client, commandcode, buf);
+ if (retval < 0)
+ return retval;
+
+ return retval;
+}
+
+static int rmi_smb_read_block(struct rmi_transport_dev *xport, u16 rmiaddr,
+ void *databuff, size_t len)
+{
+ struct rmi_smb_xport *rmi_smb =
+ container_of(xport, struct rmi_smb_xport, xport);
+ int retval;
+ u8 commandcode;
+ int cur_len = (int)len;
+
+ mutex_lock(&rmi_smb->page_mutex);
+ memset(databuff, 0, len);
+
+ while (cur_len > 0) {
+ /* break into 32 bytes chunks to write get command code */
+ int block_len = min_t(int, cur_len, SMB_MAX_COUNT);
+
+ retval = rmi_smb_get_command_code(xport, rmiaddr, block_len,
+ true, &commandcode);
+ if (retval < 0)
+ goto exit;
+
+ retval = smb_block_read(xport, commandcode,
+ databuff, block_len);
+ if (retval < 0)
+ goto exit;
+
+ /* prepare to read next block of bytes */
+ cur_len -= SMB_MAX_COUNT;
+ databuff += SMB_MAX_COUNT;
+ rmiaddr += SMB_MAX_COUNT;
+ }
+
+ retval = 0;
+
+exit:
+ mutex_unlock(&rmi_smb->page_mutex);
+ return retval;
+}
+
+static void rmi_smb_clear_state(struct rmi_smb_xport *rmi_smb)
+{
+ /* the mapping table has been flushed, discard the current one */
+ mutex_lock(&rmi_smb->mappingtable_mutex);
+ memset(rmi_smb->mapping_table, 0, sizeof(rmi_smb->mapping_table));
+ mutex_unlock(&rmi_smb->mappingtable_mutex);
+}
+
+static int rmi_smb_enable_smbus_mode(struct rmi_smb_xport *rmi_smb)
+{
+ int retval;
+
+ /* we need to get the smbus version to activate the touchpad */
+ retval = rmi_smb_get_version(rmi_smb);
+ if (retval < 0)
+ return retval;
+
+ return 0;
+}
+
+static int rmi_smb_reset(struct rmi_transport_dev *xport, u16 reset_addr)
+{
+ struct rmi_smb_xport *rmi_smb =
+ container_of(xport, struct rmi_smb_xport, xport);
+
+ rmi_smb_clear_state(rmi_smb);
+
+ /*
+ * we do not call the actual reset command, it has to be handled in
+ * PS/2 or there will be races between PS/2 and SMBus.
+ * PS/2 should ensure that a psmouse_reset is called before
+ * intializing the device and after it has been removed to be in a known
+ * state.
+ */
+ return rmi_smb_enable_smbus_mode(rmi_smb);
+}
+
+static const struct rmi_transport_ops rmi_smb_ops = {
+ .write_block = rmi_smb_write_block,
+ .read_block = rmi_smb_read_block,
+ .reset = rmi_smb_reset,
+};
+
+static int rmi_smb_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct rmi_device_platform_data *pdata = dev_get_platdata(&client->dev);
+ struct rmi_smb_xport *rmi_smb;
+ int retval;
+ int smbus_version;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+ I2C_FUNC_SMBUS_HOST_NOTIFY)) {
+ dev_err(&client->dev,
+ "adapter does not support required functionality.\n");
+ return -ENODEV;
+ }
+
+ if (client->irq <= 0) {
+ dev_err(&client->dev, "no IRQ provided, giving up.\n");
+ return client->irq ? client->irq : -ENODEV;
+ }
+
+ rmi_smb = devm_kzalloc(&client->dev, sizeof(struct rmi_smb_xport),
+ GFP_KERNEL);
+ if (!rmi_smb)
+ return -ENOMEM;
+
+ if (!pdata) {
+ dev_err(&client->dev, "no platform data, aborting\n");
+ return -ENOMEM;
+ }
+
+ rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n",
+ dev_name(&client->dev));
+
+ rmi_smb->client = client;
+ mutex_init(&rmi_smb->page_mutex);
+ mutex_init(&rmi_smb->mappingtable_mutex);
+
+ rmi_smb->xport.dev = &client->dev;
+ rmi_smb->xport.pdata = *pdata;
+ rmi_smb->xport.pdata.irq = client->irq;
+ rmi_smb->xport.proto_name = "smb2";
+ rmi_smb->xport.ops = &rmi_smb_ops;
+
+ retval = rmi_smb_get_version(rmi_smb);
+ if (retval < 0)
+ return retval;
+
+ smbus_version = retval;
+ rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Smbus version is %d",
+ smbus_version);
+
+ if (smbus_version != 2) {
+ dev_err(&client->dev, "Unrecognized SMB version %d.\n",
+ smbus_version);
+ return -ENODEV;
+ }
+
+ i2c_set_clientdata(client, rmi_smb);
+
+ retval = rmi_register_transport_device(&rmi_smb->xport);
+ if (retval) {
+ dev_err(&client->dev, "Failed to register transport driver at 0x%.2X.\n",
+ client->addr);
+ i2c_set_clientdata(client, NULL);
+ return retval;
+ }
+
+ dev_info(&client->dev, "registered rmi smb driver at %#04x.\n",
+ client->addr);
+ return 0;
+
+}
+
+static int rmi_smb_remove(struct i2c_client *client)
+{
+ struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+
+ rmi_unregister_transport_device(&rmi_smb->xport);
+
+ return 0;
+}
+
+static int __maybe_unused rmi_smb_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+ int ret;
+
+ ret = rmi_driver_suspend(rmi_smb->xport.rmi_dev, true);
+ if (ret)
+ dev_warn(dev, "Failed to suspend device: %d\n", ret);
+
+ return ret;
+}
+
+static int __maybe_unused rmi_smb_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+ int ret;
+
+ ret = rmi_driver_suspend(rmi_smb->xport.rmi_dev, false);
+ if (ret)
+ dev_warn(dev, "Failed to suspend device: %d\n", ret);
+
+ return ret;
+}
+
+static int __maybe_unused rmi_smb_resume(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+ struct rmi_device *rmi_dev = rmi_smb->xport.rmi_dev;
+ int ret;
+
+ rmi_smb_reset(&rmi_smb->xport, 0);
+
+ rmi_reset(rmi_dev);
+
+ ret = rmi_driver_resume(rmi_smb->xport.rmi_dev, true);
+ if (ret)
+ dev_warn(dev, "Failed to resume device: %d\n", ret);
+
+ return 0;
+}
+
+static int __maybe_unused rmi_smb_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+ int ret;
+
+ ret = rmi_driver_resume(rmi_smb->xport.rmi_dev, false);
+ if (ret)
+ dev_warn(dev, "Failed to resume device: %d\n", ret);
+
+ return 0;
+}
+
+static const struct dev_pm_ops rmi_smb_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(rmi_smb_suspend, rmi_smb_resume)
+ SET_RUNTIME_PM_OPS(rmi_smb_runtime_suspend, rmi_smb_runtime_resume,
+ NULL)
+};
+
+static const struct i2c_device_id rmi_id[] = {
+ { "rmi4_smbus", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rmi_id);
+
+static struct i2c_driver rmi_smb_driver = {
+ .driver = {
+ .name = "rmi4_smbus",
+ .pm = &rmi_smb_pm,
+ },
+ .id_table = rmi_id,
+ .probe = rmi_smb_probe,
+ .remove = rmi_smb_remove,
+};
+
+module_i2c_driver(rmi_smb_driver);
+
+MODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com>");
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");
+MODULE_DESCRIPTION("RMI4 SMBus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/rmi4/rmi_spi.c b/drivers/input/rmi4/rmi_spi.c
index 4ebef607e214..69548d7d1f10 100644
--- a/drivers/input/rmi4/rmi_spi.c
+++ b/drivers/input/rmi4/rmi_spi.c
@@ -12,7 +12,6 @@
#include <linux/rmi.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
-#include <linux/irq.h>
#include <linux/of.h>
#include "rmi_driver.h"
@@ -44,8 +43,6 @@ struct rmi_spi_xport {
struct mutex page_mutex;
int page;
- int irq;
-
u8 *rx_buf;
u8 *tx_buf;
int xfer_buf_size;
@@ -326,41 +323,6 @@ static const struct rmi_transport_ops rmi_spi_ops = {
.read_block = rmi_spi_read_block,
};
-static irqreturn_t rmi_spi_irq(int irq, void *dev_id)
-{
- struct rmi_spi_xport *rmi_spi = dev_id;
- struct rmi_device *rmi_dev = rmi_spi->xport.rmi_dev;
- int ret;
-
- ret = rmi_process_interrupt_requests(rmi_dev);
- if (ret)
- rmi_dbg(RMI_DEBUG_XPORT, &rmi_dev->dev,
- "Failed to process interrupt request: %d\n", ret);
-
- return IRQ_HANDLED;
-}
-
-static int rmi_spi_init_irq(struct spi_device *spi)
-{
- struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
- int irq_flags = irqd_get_trigger_type(irq_get_irq_data(rmi_spi->irq));
- int ret;
-
- if (!irq_flags)
- irq_flags = IRQF_TRIGGER_LOW;
-
- ret = devm_request_threaded_irq(&spi->dev, rmi_spi->irq, NULL,
- rmi_spi_irq, irq_flags | IRQF_ONESHOT,
- dev_name(&spi->dev), rmi_spi);
- if (ret < 0) {
- dev_warn(&spi->dev, "Failed to register interrupt %d\n",
- rmi_spi->irq);
- return ret;
- }
-
- return 0;
-}
-
#ifdef CONFIG_OF
static int rmi_spi_of_probe(struct spi_device *spi,
struct rmi_device_platform_data *pdata)
@@ -440,8 +402,7 @@ static int rmi_spi_probe(struct spi_device *spi)
return retval;
}
- if (spi->irq > 0)
- rmi_spi->irq = spi->irq;
+ pdata->irq = spi->irq;
rmi_spi->spi = spi;
mutex_init(&rmi_spi->page_mutex);
@@ -477,10 +438,6 @@ static int rmi_spi_probe(struct spi_device *spi)
if (retval)
return retval;
- retval = rmi_spi_init_irq(spi);
- if (retval < 0)
- return retval;
-
dev_info(&spi->dev, "registered RMI SPI driver\n");
return 0;
}
@@ -492,17 +449,10 @@ static int rmi_spi_suspend(struct device *dev)
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
int ret;
- ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev);
+ ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, true);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
- disable_irq(rmi_spi->irq);
- if (device_may_wakeup(&spi->dev)) {
- ret = enable_irq_wake(rmi_spi->irq);
- if (!ret)
- dev_warn(dev, "Failed to enable irq for wake: %d\n",
- ret);
- }
return ret;
}
@@ -512,15 +462,7 @@ static int rmi_spi_resume(struct device *dev)
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
int ret;
- enable_irq(rmi_spi->irq);
- if (device_may_wakeup(&spi->dev)) {
- ret = disable_irq_wake(rmi_spi->irq);
- if (!ret)
- dev_warn(dev, "Failed to disable irq for wake: %d\n",
- ret);
- }
-
- ret = rmi_driver_resume(rmi_spi->xport.rmi_dev);
+ ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, true);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
@@ -535,12 +477,10 @@ static int rmi_spi_runtime_suspend(struct device *dev)
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
int ret;
- ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev);
+ ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, false);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
- disable_irq(rmi_spi->irq);
-
return 0;
}
@@ -550,9 +490,7 @@ static int rmi_spi_runtime_resume(struct device *dev)
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
int ret;
- enable_irq(rmi_spi->irq);
-
- ret = rmi_driver_resume(rmi_spi->xport.rmi_dev);
+ ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, false);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 073246c7d163..73a4e68448fc 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -517,79 +517,7 @@ static const struct dmi_system_id i8042_dmi_noselftest_table[] = {
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "A455LD"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "K401LB"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "K501LB"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "K501LX"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "R409L"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "V502LX"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "X302LA"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "X450LD"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "X455LAB"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "X455LDB"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "X455LF"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "Z450LA"),
+ DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
},
},
{ }
@@ -1131,10 +1059,10 @@ static int __init i8042_pnp_init(void)
return 0;
}
-#else
+#else /* !CONFIG_PNP */
static inline int i8042_pnp_init(void) { return 0; }
static inline void i8042_pnp_exit(void) { }
-#endif
+#endif /* CONFIG_PNP */
static int __init i8042_platform_init(void)
{
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 89abfdb539ac..62685a768913 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -387,7 +387,7 @@ static int i8042_aux_write(struct serio *serio, unsigned char c)
/*
- * i8042_aux_close attempts to clear AUX or KBD port state by disabling
+ * i8042_port_close attempts to clear AUX or KBD port state by disabling
* and then re-enabling it.
*/
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 507981356921..efca0133e266 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -115,6 +115,15 @@ config TOUCHSCREEN_ATMEL_MXT
To compile this driver as a module, choose M here: the
module will be called atmel_mxt_ts.
+config TOUCHSCREEN_ATMEL_MXT_T37
+ bool "Support T37 Diagnostic Data"
+ depends on TOUCHSCREEN_ATMEL_MXT
+ depends on VIDEO_V4L2=y || (TOUCHSCREEN_ATMEL_MXT=m && VIDEO_V4L2=m)
+ select VIDEOBUF2_VMALLOC
+ help
+ Say Y here if you want support to output data from the T37
+ Diagnostic Data object using a V4L device.
+
config TOUCHSCREEN_AUO_PIXCIR
tristate "AUO in-cell touchscreen using Pixcir ICs"
depends on I2C
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c
index 8a84fd4d9147..e16a44667da7 100644
--- a/drivers/input/touchscreen/ad7879.c
+++ b/drivers/input/touchscreen/ad7879.c
@@ -379,7 +379,7 @@ static const struct attribute_group ad7879_attr_group = {
static int ad7879_gpio_direction_input(struct gpio_chip *chip,
unsigned gpio)
{
- struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+ struct ad7879 *ts = gpiochip_get_data(chip);
int err;
mutex_lock(&ts->mutex);
@@ -393,7 +393,7 @@ static int ad7879_gpio_direction_input(struct gpio_chip *chip,
static int ad7879_gpio_direction_output(struct gpio_chip *chip,
unsigned gpio, int level)
{
- struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+ struct ad7879 *ts = gpiochip_get_data(chip);
int err;
mutex_lock(&ts->mutex);
@@ -412,7 +412,7 @@ static int ad7879_gpio_direction_output(struct gpio_chip *chip,
static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
{
- struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+ struct ad7879 *ts = gpiochip_get_data(chip);
u16 val;
mutex_lock(&ts->mutex);
@@ -425,7 +425,7 @@ static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
static void ad7879_gpio_set_value(struct gpio_chip *chip,
unsigned gpio, int value)
{
- struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+ struct ad7879 *ts = gpiochip_get_data(chip);
mutex_lock(&ts->mutex);
if (value)
@@ -456,7 +456,7 @@ static int ad7879_gpio_add(struct ad7879 *ts,
ts->gc.owner = THIS_MODULE;
ts->gc.parent = ts->dev;
- ret = gpiochip_add(&ts->gc);
+ ret = gpiochip_add_data(&ts->gc, ts);
if (ret)
dev_err(ts->dev, "failed to register gpio %d\n",
ts->gc.base);
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 5af7907d0af4..e5d185fe69b9 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -4,6 +4,7 @@
* Copyright (C) 2010 Samsung Electronics Co.Ltd
* Copyright (C) 2011-2014 Atmel Corporation
* Copyright (C) 2012 Google, Inc.
+ * Copyright (C) 2016 Zodiac Inflight Innovations
*
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
*
@@ -28,6 +29,10 @@
#include <linux/of.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-vmalloc.h>
/* Firmware files */
#define MXT_FW_NAME "maxtouch.fw"
@@ -99,6 +104,8 @@ struct t7_config {
/* MXT_TOUCH_MULTI_T9 field */
#define MXT_T9_CTRL 0
+#define MXT_T9_XSIZE 3
+#define MXT_T9_YSIZE 4
#define MXT_T9_ORIENT 9
#define MXT_T9_RANGE 18
@@ -119,11 +126,31 @@ struct t9_range {
/* MXT_TOUCH_MULTI_T9 orient */
#define MXT_T9_ORIENT_SWITCH (1 << 0)
+#define MXT_T9_ORIENT_INVERTX (1 << 1)
+#define MXT_T9_ORIENT_INVERTY (1 << 2)
/* MXT_SPT_COMMSCONFIG_T18 */
#define MXT_COMMS_CTRL 0
#define MXT_COMMS_CMD 1
+/* MXT_DEBUG_DIAGNOSTIC_T37 */
+#define MXT_DIAGNOSTIC_PAGEUP 0x01
+#define MXT_DIAGNOSTIC_DELTAS 0x10
+#define MXT_DIAGNOSTIC_REFS 0x11
+#define MXT_DIAGNOSTIC_SIZE 128
+
+#define MXT_FAMILY_1386 160
+#define MXT1386_COLUMNS 3
+#define MXT1386_PAGES_PER_COLUMN 8
+
+struct t37_debug {
+#ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37
+ u8 mode;
+ u8 page;
+ u8 data[MXT_DIAGNOSTIC_SIZE];
+#endif
+};
+
/* Define for MXT_GEN_COMMAND_T6 */
#define MXT_BOOT_VALUE 0xa5
#define MXT_RESET_VALUE 0x01
@@ -133,10 +160,14 @@ struct t9_range {
#define MXT_T100_CTRL 0
#define MXT_T100_CFG1 1
#define MXT_T100_TCHAUX 3
+#define MXT_T100_XSIZE 9
#define MXT_T100_XRANGE 13
+#define MXT_T100_YSIZE 20
#define MXT_T100_YRANGE 24
#define MXT_T100_CFG_SWITCHXY BIT(5)
+#define MXT_T100_CFG_INVERTY BIT(6)
+#define MXT_T100_CFG_INVERTX BIT(7)
#define MXT_T100_TCHAUX_VECT BIT(0)
#define MXT_T100_TCHAUX_AMPL BIT(1)
@@ -205,6 +236,37 @@ struct mxt_object {
u8 num_report_ids;
} __packed;
+struct mxt_dbg {
+ u16 t37_address;
+ u16 diag_cmd_address;
+ struct t37_debug *t37_buf;
+ unsigned int t37_pages;
+ unsigned int t37_nodes;
+
+ struct v4l2_device v4l2;
+ struct v4l2_pix_format format;
+ struct video_device vdev;
+ struct vb2_queue queue;
+ struct mutex lock;
+ int input;
+};
+
+enum v4l_dbg_inputs {
+ MXT_V4L_INPUT_DELTAS,
+ MXT_V4L_INPUT_REFS,
+ MXT_V4L_INPUT_MAX,
+};
+
+static const struct v4l2_file_operations mxt_video_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .unlocked_ioctl = video_ioctl2,
+ .read = vb2_fop_read,
+ .mmap = vb2_fop_mmap,
+ .poll = vb2_fop_poll,
+};
+
/* Each client has this additional data */
struct mxt_data {
struct i2c_client *client;
@@ -216,7 +278,11 @@ struct mxt_data {
unsigned int irq;
unsigned int max_x;
unsigned int max_y;
+ bool invertx;
+ bool inverty;
bool xy_switch;
+ u8 xsize;
+ u8 ysize;
bool in_bootloader;
u16 mem_size;
u8 t100_aux_ampl;
@@ -233,6 +299,7 @@ struct mxt_data {
u8 num_touchids;
u8 multitouch;
struct t7_config t7_cfg;
+ struct mxt_dbg dbg;
/* Cached parameters from object table */
u16 T5_address;
@@ -257,6 +324,11 @@ struct mxt_data {
struct completion crc_completion;
};
+struct mxt_vb2_buffer {
+ struct vb2_buffer vb;
+ struct list_head list;
+};
+
static size_t mxt_obj_size(const struct mxt_object *obj)
{
return obj->size_minus_one + 1;
@@ -1503,6 +1575,11 @@ static void mxt_free_input_device(struct mxt_data *data)
static void mxt_free_object_table(struct mxt_data *data)
{
+#ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37
+ video_unregister_device(&data->dbg.vdev);
+ v4l2_device_unregister(&data->dbg.v4l2);
+#endif
+
kfree(data->object_table);
data->object_table = NULL;
kfree(data->msg_buf);
@@ -1661,6 +1738,18 @@ static int mxt_read_t9_resolution(struct mxt_data *data)
return -EINVAL;
error = __mxt_read_reg(client,
+ object->start_address + MXT_T9_XSIZE,
+ sizeof(data->xsize), &data->xsize);
+ if (error)
+ return error;
+
+ error = __mxt_read_reg(client,
+ object->start_address + MXT_T9_YSIZE,
+ sizeof(data->ysize), &data->ysize);
+ if (error)
+ return error;
+
+ error = __mxt_read_reg(client,
object->start_address + MXT_T9_RANGE,
sizeof(range), &range);
if (error)
@@ -1676,6 +1765,8 @@ static int mxt_read_t9_resolution(struct mxt_data *data)
return error;
data->xy_switch = orient & MXT_T9_ORIENT_SWITCH;
+ data->invertx = orient & MXT_T9_ORIENT_INVERTX;
+ data->inverty = orient & MXT_T9_ORIENT_INVERTY;
return 0;
}
@@ -1710,6 +1801,18 @@ static int mxt_read_t100_config(struct mxt_data *data)
data->max_y = get_unaligned_le16(&range_y);
+ error = __mxt_read_reg(client,
+ object->start_address + MXT_T100_XSIZE,
+ sizeof(data->xsize), &data->xsize);
+ if (error)
+ return error;
+
+ error = __mxt_read_reg(client,
+ object->start_address + MXT_T100_YSIZE,
+ sizeof(data->ysize), &data->ysize);
+ if (error)
+ return error;
+
/* read orientation config */
error = __mxt_read_reg(client,
object->start_address + MXT_T100_CFG1,
@@ -1718,6 +1821,8 @@ static int mxt_read_t100_config(struct mxt_data *data)
return error;
data->xy_switch = cfg & MXT_T100_CFG_SWITCHXY;
+ data->invertx = cfg & MXT_T100_CFG_INVERTX;
+ data->inverty = cfg & MXT_T100_CFG_INVERTY;
/* allocate aux bytes */
error = __mxt_read_reg(client,
@@ -2043,6 +2148,420 @@ recheck:
return 0;
}
+#ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37
+static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x,
+ unsigned int y)
+{
+ struct mxt_info *info = &data->info;
+ struct mxt_dbg *dbg = &data->dbg;
+ unsigned int ofs, page;
+ unsigned int col = 0;
+ unsigned int col_width;
+
+ if (info->family_id == MXT_FAMILY_1386) {
+ col_width = info->matrix_ysize / MXT1386_COLUMNS;
+ col = y / col_width;
+ y = y % col_width;
+ } else {
+ col_width = info->matrix_ysize;
+ }
+
+ ofs = (y + (x * col_width)) * sizeof(u16);
+ page = ofs / MXT_DIAGNOSTIC_SIZE;
+ ofs %= MXT_DIAGNOSTIC_SIZE;
+
+ if (info->family_id == MXT_FAMILY_1386)
+ page += col * MXT1386_PAGES_PER_COLUMN;
+
+ return get_unaligned_le16(&dbg->t37_buf[page].data[ofs]);
+}
+
+static int mxt_convert_debug_pages(struct mxt_data *data, u16 *outbuf)
+{
+ struct mxt_dbg *dbg = &data->dbg;
+ unsigned int x = 0;
+ unsigned int y = 0;
+ unsigned int i, rx, ry;
+
+ for (i = 0; i < dbg->t37_nodes; i++) {
+ /* Handle orientation */
+ rx = data->xy_switch ? y : x;
+ ry = data->xy_switch ? x : y;
+ rx = data->invertx ? (data->xsize - 1 - rx) : rx;
+ ry = data->inverty ? (data->ysize - 1 - ry) : ry;
+
+ outbuf[i] = mxt_get_debug_value(data, rx, ry);
+
+ /* Next value */
+ if (++x >= (data->xy_switch ? data->ysize : data->xsize)) {
+ x = 0;
+ y++;
+ }
+ }
+
+ return 0;
+}
+
+static int mxt_read_diagnostic_debug(struct mxt_data *data, u8 mode,
+ u16 *outbuf)
+{
+ struct mxt_dbg *dbg = &data->dbg;
+ int retries = 0;
+ int page;
+ int ret;
+ u8 cmd = mode;
+ struct t37_debug *p;
+ u8 cmd_poll;
+
+ for (page = 0; page < dbg->t37_pages; page++) {
+ p = dbg->t37_buf + page;
+
+ ret = mxt_write_reg(data->client, dbg->diag_cmd_address,
+ cmd);
+ if (ret)
+ return ret;
+
+ retries = 0;
+ msleep(20);
+wait_cmd:
+ /* Read back command byte */
+ ret = __mxt_read_reg(data->client, dbg->diag_cmd_address,
+ sizeof(cmd_poll), &cmd_poll);
+ if (ret)
+ return ret;
+
+ /* Field is cleared once the command has been processed */
+ if (cmd_poll) {
+ if (retries++ > 100)
+ return -EINVAL;
+
+ msleep(20);
+ goto wait_cmd;
+ }
+
+ /* Read T37 page */
+ ret = __mxt_read_reg(data->client, dbg->t37_address,
+ sizeof(struct t37_debug), p);
+ if (ret)
+ return ret;
+
+ if (p->mode != mode || p->page != page) {
+ dev_err(&data->client->dev, "T37 page mismatch\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(&data->client->dev, "%s page:%d retries:%d\n",
+ __func__, page, retries);
+
+ /* For remaining pages, write PAGEUP rather than mode */
+ cmd = MXT_DIAGNOSTIC_PAGEUP;
+ }
+
+ return mxt_convert_debug_pages(data, outbuf);
+}
+
+static int mxt_queue_setup(struct vb2_queue *q,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], struct device *alloc_devs[])
+{
+ struct mxt_data *data = q->drv_priv;
+ size_t size = data->dbg.t37_nodes * sizeof(u16);
+
+ if (*nplanes)
+ return sizes[0] < size ? -EINVAL : 0;
+
+ *nplanes = 1;
+ sizes[0] = size;
+
+ return 0;
+}
+
+static void mxt_buffer_queue(struct vb2_buffer *vb)
+{
+ struct mxt_data *data = vb2_get_drv_priv(vb->vb2_queue);
+ u16 *ptr;
+ int ret;
+ u8 mode;
+
+ ptr = vb2_plane_vaddr(vb, 0);
+ if (!ptr) {
+ dev_err(&data->client->dev, "Error acquiring frame ptr\n");
+ goto fault;
+ }
+
+ switch (data->dbg.input) {
+ case MXT_V4L_INPUT_DELTAS:
+ default:
+ mode = MXT_DIAGNOSTIC_DELTAS;
+ break;
+
+ case MXT_V4L_INPUT_REFS:
+ mode = MXT_DIAGNOSTIC_REFS;
+ break;
+ }
+
+ ret = mxt_read_diagnostic_debug(data, mode, ptr);
+ if (ret)
+ goto fault;
+
+ vb2_set_plane_payload(vb, 0, data->dbg.t37_nodes * sizeof(u16));
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ return;
+
+fault:
+ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+}
+
+/* V4L2 structures */
+static const struct vb2_ops mxt_queue_ops = {
+ .queue_setup = mxt_queue_setup,
+ .buf_queue = mxt_buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+static const struct vb2_queue mxt_queue = {
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ,
+ .buf_struct_size = sizeof(struct mxt_vb2_buffer),
+ .ops = &mxt_queue_ops,
+ .mem_ops = &vb2_vmalloc_memops,
+ .timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC,
+ .min_buffers_needed = 1,
+};
+
+static int mxt_vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct mxt_data *data = video_drvdata(file);
+
+ strlcpy(cap->driver, "atmel_mxt_ts", sizeof(cap->driver));
+ strlcpy(cap->card, "atmel_mxt_ts touch", sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info),
+ "I2C:%s", dev_name(&data->client->dev));
+ return 0;
+}
+
+static int mxt_vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ if (i->index >= MXT_V4L_INPUT_MAX)
+ return -EINVAL;
+
+ i->type = V4L2_INPUT_TYPE_TOUCH;
+
+ switch (i->index) {
+ case MXT_V4L_INPUT_REFS:
+ strlcpy(i->name, "Mutual Capacitance References",
+ sizeof(i->name));
+ break;
+ case MXT_V4L_INPUT_DELTAS:
+ strlcpy(i->name, "Mutual Capacitance Deltas", sizeof(i->name));
+ break;
+ }
+
+ return 0;
+}
+
+static int mxt_set_input(struct mxt_data *data, unsigned int i)
+{
+ struct v4l2_pix_format *f = &data->dbg.format;
+
+ if (i >= MXT_V4L_INPUT_MAX)
+ return -EINVAL;
+
+ if (i == MXT_V4L_INPUT_DELTAS)
+ f->pixelformat = V4L2_TCH_FMT_DELTA_TD16;
+ else
+ f->pixelformat = V4L2_TCH_FMT_TU16;
+
+ f->width = data->xy_switch ? data->ysize : data->xsize;
+ f->height = data->xy_switch ? data->xsize : data->ysize;
+ f->field = V4L2_FIELD_NONE;
+ f->colorspace = V4L2_COLORSPACE_RAW;
+ f->bytesperline = f->width * sizeof(u16);
+ f->sizeimage = f->width * f->height * sizeof(u16);
+
+ data->dbg.input = i;
+
+ return 0;
+}
+
+static int mxt_vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ return mxt_set_input(video_drvdata(file), i);
+}
+
+static int mxt_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct mxt_data *data = video_drvdata(file);
+
+ *i = data->dbg.input;
+
+ return 0;
+}
+
+static int mxt_vidioc_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct mxt_data *data = video_drvdata(file);
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix = data->dbg.format;
+
+ return 0;
+}
+
+static int mxt_vidioc_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *fmt)
+{
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ switch (fmt->index) {
+ case 0:
+ fmt->pixelformat = V4L2_TCH_FMT_TU16;
+ break;
+
+ case 1:
+ fmt->pixelformat = V4L2_TCH_FMT_DELTA_TD16;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mxt_vidioc_g_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ a->parm.capture.readbuffers = 1;
+ a->parm.capture.timeperframe.numerator = 1;
+ a->parm.capture.timeperframe.denominator = 10;
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops mxt_video_ioctl_ops = {
+ .vidioc_querycap = mxt_vidioc_querycap,
+
+ .vidioc_enum_fmt_vid_cap = mxt_vidioc_enum_fmt,
+ .vidioc_s_fmt_vid_cap = mxt_vidioc_fmt,
+ .vidioc_g_fmt_vid_cap = mxt_vidioc_fmt,
+ .vidioc_try_fmt_vid_cap = mxt_vidioc_fmt,
+ .vidioc_g_parm = mxt_vidioc_g_parm,
+
+ .vidioc_enum_input = mxt_vidioc_enum_input,
+ .vidioc_g_input = mxt_vidioc_g_input,
+ .vidioc_s_input = mxt_vidioc_s_input,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+};
+
+static const struct video_device mxt_video_device = {
+ .name = "Atmel maxTouch",
+ .fops = &mxt_video_fops,
+ .ioctl_ops = &mxt_video_ioctl_ops,
+ .release = video_device_release_empty,
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TOUCH |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING,
+};
+
+static void mxt_debug_init(struct mxt_data *data)
+{
+ struct mxt_info *info = &data->info;
+ struct mxt_dbg *dbg = &data->dbg;
+ struct mxt_object *object;
+ int error;
+
+ object = mxt_get_object(data, MXT_GEN_COMMAND_T6);
+ if (!object)
+ goto error;
+
+ dbg->diag_cmd_address = object->start_address + MXT_COMMAND_DIAGNOSTIC;
+
+ object = mxt_get_object(data, MXT_DEBUG_DIAGNOSTIC_T37);
+ if (!object)
+ goto error;
+
+ if (mxt_obj_size(object) != sizeof(struct t37_debug)) {
+ dev_warn(&data->client->dev, "Bad T37 size");
+ goto error;
+ }
+
+ dbg->t37_address = object->start_address;
+
+ /* Calculate size of data and allocate buffer */
+ dbg->t37_nodes = data->xsize * data->ysize;
+
+ if (info->family_id == MXT_FAMILY_1386)
+ dbg->t37_pages = MXT1386_COLUMNS * MXT1386_PAGES_PER_COLUMN;
+ else
+ dbg->t37_pages = DIV_ROUND_UP(data->xsize *
+ data->info.matrix_ysize *
+ sizeof(u16),
+ sizeof(dbg->t37_buf->data));
+
+ dbg->t37_buf = devm_kmalloc_array(&data->client->dev, dbg->t37_pages,
+ sizeof(struct t37_debug), GFP_KERNEL);
+ if (!dbg->t37_buf)
+ goto error;
+
+ /* init channel to zero */
+ mxt_set_input(data, 0);
+
+ /* register video device */
+ snprintf(dbg->v4l2.name, sizeof(dbg->v4l2.name), "%s", "atmel_mxt_ts");
+ error = v4l2_device_register(&data->client->dev, &dbg->v4l2);
+ if (error)
+ goto error;
+
+ /* initialize the queue */
+ mutex_init(&dbg->lock);
+ dbg->queue = mxt_queue;
+ dbg->queue.drv_priv = data;
+ dbg->queue.lock = &dbg->lock;
+ dbg->queue.dev = &data->client->dev;
+
+ error = vb2_queue_init(&dbg->queue);
+ if (error)
+ goto error_unreg_v4l2;
+
+ dbg->vdev = mxt_video_device;
+ dbg->vdev.v4l2_dev = &dbg->v4l2;
+ dbg->vdev.lock = &dbg->lock;
+ dbg->vdev.vfl_dir = VFL_DIR_RX;
+ dbg->vdev.queue = &dbg->queue;
+ video_set_drvdata(&dbg->vdev, data);
+
+ error = video_register_device(&dbg->vdev, VFL_TYPE_TOUCH, -1);
+ if (error)
+ goto error_unreg_v4l2;
+
+ return;
+
+error_unreg_v4l2:
+ v4l2_device_unregister(&dbg->v4l2);
+error:
+ dev_warn(&data->client->dev, "Error initializing T37\n");
+}
+#else
+static void mxt_debug_init(struct mxt_data *data)
+{
+}
+#endif
+
static int mxt_configure_objects(struct mxt_data *data,
const struct firmware *cfg)
{
@@ -2070,6 +2589,8 @@ static int mxt_configure_objects(struct mxt_data *data,
dev_warn(dev, "No touch object detected\n");
}
+ mxt_debug_init(data);
+
dev_info(dev,
"Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n",
info->family_id, info->variant_id, info->version >> 4,
diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c
index 5ed31057430c..44deca88c579 100644
--- a/drivers/input/touchscreen/cyttsp4_core.c
+++ b/drivers/input/touchscreen/cyttsp4_core.c
@@ -1499,7 +1499,7 @@ static int cyttsp4_core_sleep_(struct cyttsp4 *cd)
if (IS_BOOTLOADER(mode[0], mode[1])) {
mutex_unlock(&cd->system_lock);
- dev_err(cd->dev, "%s: Device in BOOTLADER mode.\n", __func__);
+ dev_err(cd->dev, "%s: Device in BOOTLOADER mode.\n", __func__);
rc = -EINVAL;
goto error;
}
diff --git a/drivers/input/touchscreen/fsl-imx25-tcq.c b/drivers/input/touchscreen/fsl-imx25-tcq.c
index fe9877a6af9e..d50ee490c9cc 100644
--- a/drivers/input/touchscreen/fsl-imx25-tcq.c
+++ b/drivers/input/touchscreen/fsl-imx25-tcq.c
@@ -55,6 +55,7 @@ static const struct of_device_id mx25_tcq_ids[] = {
{ .compatible = "fsl,imx25-tcq", },
{ /* Sentinel */ }
};
+MODULE_DEVICE_TABLE(of, mx25_tcq_ids);
#define TSC_4WIRE_PRE_INDEX 0
#define TSC_4WIRE_X_INDEX 1
diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c
index 8275267eac25..7098e0a47019 100644
--- a/drivers/input/touchscreen/imx6ul_tsc.c
+++ b/drivers/input/touchscreen/imx6ul_tsc.c
@@ -21,17 +21,25 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/log2.h>
/* ADC configuration registers field define */
#define ADC_AIEN (0x1 << 7)
#define ADC_CONV_DISABLE 0x1F
+#define ADC_AVGE (0x1 << 5)
#define ADC_CAL (0x1 << 7)
#define ADC_CALF 0x2
#define ADC_12BIT_MODE (0x2 << 2)
+#define ADC_CONV_MODE_MASK (0x3 << 2)
#define ADC_IPG_CLK 0x00
+#define ADC_INPUT_CLK_MASK 0x3
#define ADC_CLK_DIV_8 (0x03 << 5)
+#define ADC_CLK_DIV_MASK (0x3 << 5)
#define ADC_SHORT_SAMPLE_MODE (0x0 << 4)
+#define ADC_SAMPLE_MODE_MASK (0x1 << 4)
#define ADC_HARDWARE_TRIGGER (0x1 << 13)
+#define ADC_AVGS_SHIFT 14
+#define ADC_AVGS_MASK (0x3 << 14)
#define SELECT_CHANNEL_4 0x04
#define SELECT_CHANNEL_1 0x01
#define DISABLE_CONVERSION_INT (0x0 << 7)
@@ -84,8 +92,10 @@ struct imx6ul_tsc {
struct clk *adc_clk;
struct gpio_desc *xnur_gpio;
- int measure_delay_time;
- int pre_charge_time;
+ u32 measure_delay_time;
+ u32 pre_charge_time;
+ bool average_enable;
+ u32 average_select;
struct completion completion;
};
@@ -96,17 +106,23 @@ struct imx6ul_tsc {
*/
static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
{
- int adc_hc = 0;
- int adc_gc;
- int adc_gs;
- int adc_cfg;
- int timeout;
+ u32 adc_hc = 0;
+ u32 adc_gc;
+ u32 adc_gs;
+ u32 adc_cfg;
+ unsigned long timeout;
reinit_completion(&tsc->completion);
adc_cfg = readl(tsc->adc_regs + REG_ADC_CFG);
+ adc_cfg &= ~(ADC_CONV_MODE_MASK | ADC_INPUT_CLK_MASK);
adc_cfg |= ADC_12BIT_MODE | ADC_IPG_CLK;
+ adc_cfg &= ~(ADC_CLK_DIV_MASK | ADC_SAMPLE_MODE_MASK);
adc_cfg |= ADC_CLK_DIV_8 | ADC_SHORT_SAMPLE_MODE;
+ if (tsc->average_enable) {
+ adc_cfg &= ~ADC_AVGS_MASK;
+ adc_cfg |= (tsc->average_select) << ADC_AVGS_SHIFT;
+ }
adc_cfg &= ~ADC_HARDWARE_TRIGGER;
writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG);
@@ -118,6 +134,8 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
/* start ADC calibration */
adc_gc = readl(tsc->adc_regs + REG_ADC_GC);
adc_gc |= ADC_CAL;
+ if (tsc->average_enable)
+ adc_gc |= ADC_AVGE;
writel(adc_gc, tsc->adc_regs + REG_ADC_GC);
timeout = wait_for_completion_timeout
@@ -148,7 +166,7 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
*/
static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc)
{
- int adc_hc0, adc_hc1, adc_hc2, adc_hc3, adc_hc4;
+ u32 adc_hc0, adc_hc1, adc_hc2, adc_hc3, adc_hc4;
adc_hc0 = DISABLE_CONVERSION_INT;
writel(adc_hc0, tsc->adc_regs + REG_ADC_HC0);
@@ -173,8 +191,8 @@ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc)
*/
static void imx6ul_tsc_set(struct imx6ul_tsc *tsc)
{
- int basic_setting = 0;
- int start;
+ u32 basic_setting = 0;
+ u32 start;
basic_setting |= tsc->measure_delay_time << 8;
basic_setting |= DETECT_4_WIRE_MODE | AUTO_MEASURE;
@@ -209,8 +227,8 @@ static int imx6ul_tsc_init(struct imx6ul_tsc *tsc)
static void imx6ul_tsc_disable(struct imx6ul_tsc *tsc)
{
- int tsc_flow;
- int adc_cfg;
+ u32 tsc_flow;
+ u32 adc_cfg;
/* TSC controller enters to idle status */
tsc_flow = readl(tsc->tsc_regs + REG_TSC_FLOW_CONTROL);
@@ -227,8 +245,8 @@ static void imx6ul_tsc_disable(struct imx6ul_tsc *tsc)
static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc)
{
unsigned long timeout = jiffies + msecs_to_jiffies(2);
- int state_machine;
- int debug_mode2;
+ u32 state_machine;
+ u32 debug_mode2;
do {
if (time_after(jiffies, timeout))
@@ -246,10 +264,10 @@ static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc)
static irqreturn_t tsc_irq_fn(int irq, void *dev_id)
{
struct imx6ul_tsc *tsc = dev_id;
- int status;
- int value;
- int x, y;
- int start;
+ u32 status;
+ u32 value;
+ u32 x, y;
+ u32 start;
status = readl(tsc->tsc_regs + REG_TSC_INT_STATUS);
@@ -289,8 +307,8 @@ static irqreturn_t tsc_irq_fn(int irq, void *dev_id)
static irqreturn_t adc_irq_fn(int irq, void *dev_id)
{
struct imx6ul_tsc *tsc = dev_id;
- int coco;
- int value;
+ u32 coco;
+ u32 value;
coco = readl(tsc->adc_regs + REG_ADC_HS);
if (coco & 0x01) {
@@ -346,6 +364,7 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
int err;
int tsc_irq;
int adc_irq;
+ u32 average_samples;
tsc = devm_kzalloc(&pdev->dev, sizeof(*tsc), GFP_KERNEL);
if (!tsc)
@@ -450,6 +469,30 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
if (err)
tsc->pre_charge_time = 0xfff;
+ err = of_property_read_u32(np, "touchscreen-average-samples",
+ &average_samples);
+ if (err)
+ average_samples = 1;
+
+ switch (average_samples) {
+ case 1:
+ tsc->average_enable = false;
+ tsc->average_select = 0; /* value unused; initialize anyway */
+ break;
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ tsc->average_enable = true;
+ tsc->average_select = ilog2(average_samples) - 2;
+ break;
+ default:
+ dev_err(&pdev->dev,
+ "touchscreen-average-samples (%u) must be 1, 4, 8, 16 or 32\n",
+ average_samples);
+ return -EINVAL;
+ }
+
err = input_register_device(tsc->input);
if (err) {
dev_err(&pdev->dev,
diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c
index 552a3773f79d..703d7f983d0a 100644
--- a/drivers/input/touchscreen/melfas_mip4.c
+++ b/drivers/input/touchscreen/melfas_mip4.c
@@ -33,7 +33,7 @@
/*****************************************************************
* Protocol
- * Version : MIP 4.0 Rev 4.6
+ * Version : MIP 4.0 Rev 5.4
*****************************************************************/
/* Address */
@@ -81,6 +81,9 @@
#define MIP4_R1_INFO_IC_HW_CATEGORY 0x77
#define MIP4_R1_INFO_CONTACT_THD_SCR 0x78
#define MIP4_R1_INFO_CONTACT_THD_KEY 0x7A
+#define MIP4_R1_INFO_PID 0x7C
+#define MIP4_R1_INFO_VID 0x7E
+#define MIP4_R1_INFO_SLAVE_ADDR 0x80
#define MIP4_R0_EVENT 0x02
#define MIP4_R1_EVENT_SUPPORTED_FUNC 0x00
@@ -157,7 +160,9 @@ struct mip4_ts {
char phys[32];
char product_name[16];
+ u16 product_id;
char ic_name[4];
+ char fw_name[32];
unsigned int max_x;
unsigned int max_y;
@@ -264,6 +269,23 @@ static int mip4_query_device(struct mip4_ts *ts)
dev_dbg(&ts->client->dev, "product name: %.*s\n",
(int)sizeof(ts->product_name), ts->product_name);
+ /* Product ID */
+ cmd[0] = MIP4_R0_INFO;
+ cmd[1] = MIP4_R1_INFO_PID;
+ error = mip4_i2c_xfer(ts, cmd, sizeof(cmd), buf, 2);
+ if (error) {
+ dev_warn(&ts->client->dev,
+ "Failed to retrieve product id: %d\n", error);
+ } else {
+ ts->product_id = get_unaligned_le16(&buf[0]);
+ dev_dbg(&ts->client->dev, "product id: %04X\n", ts->product_id);
+ }
+
+ /* Firmware name */
+ snprintf(ts->fw_name, sizeof(ts->fw_name),
+ "melfas_mip4_%04X.fw", ts->product_id);
+ dev_dbg(&ts->client->dev, "firmware name: %s\n", ts->fw_name);
+
/* IC name */
cmd[0] = MIP4_R0_INFO;
cmd[1] = MIP4_R1_INFO_IC_NAME;
@@ -1269,11 +1291,11 @@ static ssize_t mip4_sysfs_fw_update(struct device *dev,
const struct firmware *fw;
int error;
- error = request_firmware(&fw, MIP4_FW_NAME, dev);
+ error = request_firmware(&fw, ts->fw_name, dev);
if (error) {
dev_err(&ts->client->dev,
"Failed to retrieve firmware %s: %d\n",
- MIP4_FW_NAME, error);
+ ts->fw_name, error);
return error;
}
@@ -1348,6 +1370,25 @@ static ssize_t mip4_sysfs_read_hw_version(struct device *dev,
static DEVICE_ATTR(hw_version, S_IRUGO, mip4_sysfs_read_hw_version, NULL);
+static ssize_t mip4_sysfs_read_product_id(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mip4_ts *ts = i2c_get_clientdata(client);
+ size_t count;
+
+ mutex_lock(&ts->input->mutex);
+
+ count = snprintf(buf, PAGE_SIZE, "%04X\n", ts->product_id);
+
+ mutex_unlock(&ts->input->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(product_id, S_IRUGO, mip4_sysfs_read_product_id, NULL);
+
static ssize_t mip4_sysfs_read_ic_name(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -1371,6 +1412,7 @@ static DEVICE_ATTR(ic_name, S_IRUGO, mip4_sysfs_read_ic_name, NULL);
static struct attribute *mip4_attrs[] = {
&dev_attr_fw_version.attr,
&dev_attr_hw_version.attr,
+ &dev_attr_product_id.attr,
&dev_attr_ic_name.attr,
&dev_attr_update_fw.attr,
NULL,
@@ -1435,6 +1477,7 @@ static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id)
input->id.bustype = BUS_I2C;
input->id.vendor = 0x13c5;
+ input->id.product = ts->product_id;
input->open = mip4_input_open;
input->close = mip4_input_close;
@@ -1572,6 +1615,6 @@ static struct i2c_driver mip4_driver = {
module_i2c_driver(mip4_driver);
MODULE_DESCRIPTION("MELFAS MIP4 Touchscreen");
-MODULE_VERSION("2016.09.28");
+MODULE_VERSION("2016.10.31");
MODULE_AUTHOR("Sangwon Jee <jeesw@melfas.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c
index a99fb5cac5a0..2658afa016c9 100644
--- a/drivers/input/touchscreen/raydium_i2c_ts.c
+++ b/drivers/input/touchscreen/raydium_i2c_ts.c
@@ -669,7 +669,7 @@ static int raydium_i2c_do_update_firmware(struct raydium_data *ts,
if (ts->boot_mode == RAYDIUM_TS_MAIN) {
dev_err(&client->dev,
- "failied to jump to boot loader: %d\n",
+ "failed to jump to boot loader: %d\n",
error);
return -EIO;
}
diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
index f502c8488be8..404830a4a366 100644
--- a/drivers/input/touchscreen/silead.c
+++ b/drivers/input/touchscreen/silead.c
@@ -29,6 +29,7 @@
#include <linux/input/touchscreen.h>
#include <linux/pm.h>
#include <linux/irq.h>
+#include <linux/regulator/consumer.h>
#include <asm/unaligned.h>
@@ -73,6 +74,7 @@ struct silead_ts_data {
struct i2c_client *client;
struct gpio_desc *gpio_power;
struct input_dev *input;
+ struct regulator_bulk_data regulators[2];
char fw_name[64];
struct touchscreen_properties prop;
u32 max_fingers;
@@ -433,6 +435,13 @@ static int silead_ts_set_default_fw_name(struct silead_ts_data *data,
}
#endif
+static void silead_disable_regulator(void *arg)
+{
+ struct silead_ts_data *data = arg;
+
+ regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
+}
+
static int silead_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -465,6 +474,26 @@ static int silead_ts_probe(struct i2c_client *client,
if (client->irq <= 0)
return -ENODEV;
+ data->regulators[0].supply = "vddio";
+ data->regulators[1].supply = "avdd";
+ error = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->regulators),
+ data->regulators);
+ if (error)
+ return error;
+
+ /*
+ * Enable regulators at probe and disable them at remove, we need
+ * to keep the chip powered otherwise it forgets its firmware.
+ */
+ error = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
+ data->regulators);
+ if (error)
+ return error;
+
+ error = devm_add_action_or_reset(dev, silead_disable_regulator, data);
+ if (error)
+ return error;
+
/* Power GPIO pin */
data->gpio_power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
if (IS_ERR(data->gpio_power)) {
diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c
index 485794376ee5..d07dd29d4848 100644
--- a/drivers/input/touchscreen/sun4i-ts.c
+++ b/drivers/input/touchscreen/sun4i-ts.c
@@ -115,7 +115,6 @@
struct sun4i_ts_data {
struct device *dev;
struct input_dev *input;
- struct thermal_zone_device *tz;
void __iomem *base;
unsigned int irq;
bool ignore_fifo_data;
@@ -366,10 +365,7 @@ static int sun4i_ts_probe(struct platform_device *pdev)
if (IS_ERR(hwmon))
return PTR_ERR(hwmon);
- ts->tz = thermal_zone_of_sensor_register(ts->dev, 0, ts,
- &sun4i_ts_tz_ops);
- if (IS_ERR(ts->tz))
- ts->tz = NULL;
+ devm_thermal_zone_of_sensor_register(ts->dev, 0, ts, &sun4i_ts_tz_ops);
writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
@@ -377,7 +373,6 @@ static int sun4i_ts_probe(struct platform_device *pdev)
error = input_register_device(ts->input);
if (error) {
writel(0, ts->base + TP_INT_FIFOC);
- thermal_zone_of_sensor_unregister(ts->dev, ts->tz);
return error;
}
}
@@ -394,8 +389,6 @@ static int sun4i_ts_remove(struct platform_device *pdev)
if (ts->input)
input_unregister_device(ts->input);
- thermal_zone_of_sensor_unregister(ts->dev, ts->tz);
-
/* Deactivate all IRQs */
writel(0, ts->base + TP_INT_FIFOC);
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index 880c40b23f66..aefb6e11f88a 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -126,7 +126,7 @@ struct sur40_image_header {
#define VIDEO_PACKET_SIZE 16384
/* polling interval (ms) */
-#define POLL_INTERVAL 4
+#define POLL_INTERVAL 1
/* maximum number of contacts FIXME: this is a guess? */
#define MAX_CONTACTS 64
@@ -139,6 +139,27 @@ struct sur40_image_header {
#define SUR40_GET_STATE 0xc5 /* 4 bytes state (?) */
#define SUR40_GET_SENSORS 0xb1 /* 8 bytes sensors */
+static const struct v4l2_pix_format sur40_pix_format[] = {
+ {
+ .pixelformat = V4L2_TCH_FMT_TU08,
+ .width = SENSOR_RES_X / 2,
+ .height = SENSOR_RES_Y / 2,
+ .field = V4L2_FIELD_NONE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .bytesperline = SENSOR_RES_X / 2,
+ .sizeimage = (SENSOR_RES_X/2) * (SENSOR_RES_Y/2),
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_GREY,
+ .width = SENSOR_RES_X / 2,
+ .height = SENSOR_RES_Y / 2,
+ .field = V4L2_FIELD_NONE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .bytesperline = SENSOR_RES_X / 2,
+ .sizeimage = (SENSOR_RES_X/2) * (SENSOR_RES_Y/2),
+ }
+};
+
/* master device state */
struct sur40_state {
@@ -149,9 +170,9 @@ struct sur40_state {
struct v4l2_device v4l2;
struct video_device vdev;
struct mutex lock;
+ struct v4l2_pix_format pix_fmt;
struct vb2_queue queue;
- struct vb2_alloc_ctx *alloc_ctx;
struct list_head buf_list;
spinlock_t qlock;
int sequence;
@@ -170,7 +191,6 @@ struct sur40_buffer {
/* forward declarations */
static const struct video_device sur40_video_device;
-static const struct v4l2_pix_format sur40_video_format;
static const struct vb2_queue sur40_queue;
static void sur40_process_video(struct sur40_state *sur40);
@@ -421,7 +441,7 @@ static void sur40_process_video(struct sur40_state *sur40)
goto err_poll;
}
- if (le32_to_cpu(img->size) != sur40_video_format.sizeimage) {
+ if (le32_to_cpu(img->size) != sur40->pix_fmt.sizeimage) {
dev_err(sur40->dev, "image size mismatch\n");
goto err_poll;
}
@@ -432,7 +452,7 @@ static void sur40_process_video(struct sur40_state *sur40)
result = usb_sg_init(&sgr, sur40->usbdev,
usb_rcvbulkpipe(sur40->usbdev, VIDEO_ENDPOINT), 0,
- sgt->sgl, sgt->nents, sur40_video_format.sizeimage, 0);
+ sgt->sgl, sgt->nents, sur40->pix_fmt.sizeimage, 0);
if (result < 0) {
dev_err(sur40->dev, "error %d in usb_sg_init\n", result);
goto err_poll;
@@ -448,7 +468,7 @@ static void sur40_process_video(struct sur40_state *sur40)
/* return error if streaming was stopped in the meantime */
if (sur40->sequence == -1)
- goto err_poll;
+ return;
/* mark as finished */
new_buf->vb.vb2_buf.timestamp = ktime_get_ns();
@@ -580,26 +600,21 @@ static int sur40_probe(struct usb_interface *interface,
sur40->queue = sur40_queue;
sur40->queue.drv_priv = sur40;
sur40->queue.lock = &sur40->lock;
+ sur40->queue.dev = sur40->dev;
/* initialize the queue */
error = vb2_queue_init(&sur40->queue);
if (error)
goto err_unreg_v4l2;
- sur40->alloc_ctx = vb2_dma_sg_init_ctx(sur40->dev);
- if (IS_ERR(sur40->alloc_ctx)) {
- dev_err(sur40->dev, "Can't allocate buffer context");
- error = PTR_ERR(sur40->alloc_ctx);
- goto err_unreg_v4l2;
- }
-
+ sur40->pix_fmt = sur40_pix_format[0];
sur40->vdev = sur40_video_device;
sur40->vdev.v4l2_dev = &sur40->v4l2;
sur40->vdev.lock = &sur40->lock;
sur40->vdev.queue = &sur40->queue;
video_set_drvdata(&sur40->vdev, sur40);
- error = video_register_device(&sur40->vdev, VFL_TYPE_GRABBER, -1);
+ error = video_register_device(&sur40->vdev, VFL_TYPE_TOUCH, -1);
if (error) {
dev_err(&interface->dev,
"Unable to register video subdevice.");
@@ -633,7 +648,6 @@ static void sur40_disconnect(struct usb_interface *interface)
video_unregister_device(&sur40->vdev);
v4l2_device_unregister(&sur40->v4l2);
- vb2_dma_sg_cleanup_ctx(sur40->alloc_ctx);
input_unregister_polled_device(sur40->input);
input_free_polled_device(sur40->input);
@@ -653,19 +667,18 @@ static void sur40_disconnect(struct usb_interface *interface)
*/
static int sur40_queue_setup(struct vb2_queue *q,
unsigned int *nbuffers, unsigned int *nplanes,
- unsigned int sizes[], void *alloc_ctxs[])
+ unsigned int sizes[], struct device *alloc_devs[])
{
struct sur40_state *sur40 = vb2_get_drv_priv(q);
if (q->num_buffers + *nbuffers < 3)
*nbuffers = 3 - q->num_buffers;
- alloc_ctxs[0] = sur40->alloc_ctx;
if (*nplanes)
- return sizes[0] < sur40_video_format.sizeimage ? -EINVAL : 0;
+ return sizes[0] < sur40->pix_fmt.sizeimage ? -EINVAL : 0;
*nplanes = 1;
- sizes[0] = sur40_video_format.sizeimage;
+ sizes[0] = sur40->pix_fmt.sizeimage;
return 0;
}
@@ -677,7 +690,7 @@ static int sur40_queue_setup(struct vb2_queue *q,
static int sur40_buffer_prepare(struct vb2_buffer *vb)
{
struct sur40_state *sur40 = vb2_get_drv_priv(vb->vb2_queue);
- unsigned long size = sur40_video_format.sizeimage;
+ unsigned long size = sur40->pix_fmt.sizeimage;
if (vb2_plane_size(vb, 0) < size) {
dev_err(&sur40->usbdev->dev, "buffer too small (%lu < %lu)\n",
@@ -736,6 +749,7 @@ static int sur40_start_streaming(struct vb2_queue *vq, unsigned int count)
static void sur40_stop_streaming(struct vb2_queue *vq)
{
struct sur40_state *sur40 = vb2_get_drv_priv(vq);
+ vb2_wait_for_all_buffers(vq);
sur40->sequence = -1;
/* Release all active buffers */
@@ -751,7 +765,7 @@ static int sur40_vidioc_querycap(struct file *file, void *priv,
strlcpy(cap->driver, DRIVER_SHORT, sizeof(cap->driver));
strlcpy(cap->card, DRIVER_LONG, sizeof(cap->card));
usb_make_path(sur40->usbdev, cap->bus_info, sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TOUCH |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -763,7 +777,7 @@ static int sur40_vidioc_enum_input(struct file *file, void *priv,
{
if (i->index != 0)
return -EINVAL;
- i->type = V4L2_INPUT_TYPE_CAMERA;
+ i->type = V4L2_INPUT_TYPE_TOUCH;
i->std = V4L2_STD_UNKNOWN;
strlcpy(i->name, "In-Cell Sensor", sizeof(i->name));
i->capabilities = 0;
@@ -781,20 +795,70 @@ static int sur40_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
return 0;
}
-static int sur40_vidioc_fmt(struct file *file, void *priv,
+static int sur40_vidioc_try_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ switch (f->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_GREY:
+ f->fmt.pix = sur40_pix_format[1];
+ break;
+
+ default:
+ f->fmt.pix = sur40_pix_format[0];
+ break;
+ }
+
+ return 0;
+}
+
+static int sur40_vidioc_s_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct sur40_state *sur40 = video_drvdata(file);
+
+ switch (f->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_GREY:
+ sur40->pix_fmt = sur40_pix_format[1];
+ break;
+
+ default:
+ sur40->pix_fmt = sur40_pix_format[0];
+ break;
+ }
+
+ f->fmt.pix = sur40->pix_fmt;
+ return 0;
+}
+
+static int sur40_vidioc_g_fmt(struct file *file, void *priv,
struct v4l2_format *f)
{
- f->fmt.pix = sur40_video_format;
+ struct sur40_state *sur40 = video_drvdata(file);
+
+ f->fmt.pix = sur40->pix_fmt;
+ return 0;
+}
+
+static int sur40_ioctl_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *p)
+{
+ if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ p->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+ p->parm.capture.timeperframe.numerator = 1;
+ p->parm.capture.timeperframe.denominator = 60;
+ p->parm.capture.readbuffers = 3;
return 0;
}
static int sur40_vidioc_enum_fmt(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- if (f->index != 0)
+ if (f->index >= ARRAY_SIZE(sur40_pix_format))
return -EINVAL;
- strlcpy(f->description, "8-bit greyscale", sizeof(f->description));
- f->pixelformat = V4L2_PIX_FMT_GREY;
+
+ f->pixelformat = sur40_pix_format[f->index].pixelformat;
f->flags = 0;
return 0;
}
@@ -802,25 +866,31 @@ static int sur40_vidioc_enum_fmt(struct file *file, void *priv,
static int sur40_vidioc_enum_framesizes(struct file *file, void *priv,
struct v4l2_frmsizeenum *f)
{
- if ((f->index != 0) || (f->pixel_format != V4L2_PIX_FMT_GREY))
+ struct sur40_state *sur40 = video_drvdata(file);
+
+ if ((f->index != 0) || ((f->pixel_format != V4L2_TCH_FMT_TU08)
+ && (f->pixel_format != V4L2_PIX_FMT_GREY)))
return -EINVAL;
f->type = V4L2_FRMSIZE_TYPE_DISCRETE;
- f->discrete.width = sur40_video_format.width;
- f->discrete.height = sur40_video_format.height;
+ f->discrete.width = sur40->pix_fmt.width;
+ f->discrete.height = sur40->pix_fmt.height;
return 0;
}
static int sur40_vidioc_enum_frameintervals(struct file *file, void *priv,
struct v4l2_frmivalenum *f)
{
- if ((f->index > 1) || (f->pixel_format != V4L2_PIX_FMT_GREY)
- || (f->width != sur40_video_format.width)
- || (f->height != sur40_video_format.height))
- return -EINVAL;
+ struct sur40_state *sur40 = video_drvdata(file);
+
+ if ((f->index > 0) || ((f->pixel_format != V4L2_TCH_FMT_TU08)
+ && (f->pixel_format != V4L2_PIX_FMT_GREY))
+ || (f->width != sur40->pix_fmt.width)
+ || (f->height != sur40->pix_fmt.height))
+ return -EINVAL;
f->type = V4L2_FRMIVAL_TYPE_DISCRETE;
- f->discrete.denominator = 60/(f->index+1);
+ f->discrete.denominator = 60;
f->discrete.numerator = 1;
return 0;
}
@@ -873,13 +943,16 @@ static const struct v4l2_ioctl_ops sur40_video_ioctl_ops = {
.vidioc_querycap = sur40_vidioc_querycap,
.vidioc_enum_fmt_vid_cap = sur40_vidioc_enum_fmt,
- .vidioc_try_fmt_vid_cap = sur40_vidioc_fmt,
- .vidioc_s_fmt_vid_cap = sur40_vidioc_fmt,
- .vidioc_g_fmt_vid_cap = sur40_vidioc_fmt,
+ .vidioc_try_fmt_vid_cap = sur40_vidioc_try_fmt,
+ .vidioc_s_fmt_vid_cap = sur40_vidioc_s_fmt,
+ .vidioc_g_fmt_vid_cap = sur40_vidioc_g_fmt,
.vidioc_enum_framesizes = sur40_vidioc_enum_framesizes,
.vidioc_enum_frameintervals = sur40_vidioc_enum_frameintervals,
+ .vidioc_g_parm = sur40_ioctl_parm,
+ .vidioc_s_parm = sur40_ioctl_parm,
+
.vidioc_enum_input = sur40_vidioc_enum_input,
.vidioc_g_input = sur40_vidioc_g_input,
.vidioc_s_input = sur40_vidioc_s_input,
@@ -902,16 +975,6 @@ static const struct video_device sur40_video_device = {
.release = video_device_release_empty,
};
-static const struct v4l2_pix_format sur40_video_format = {
- .pixelformat = V4L2_PIX_FMT_GREY,
- .width = SENSOR_RES_X / 2,
- .height = SENSOR_RES_Y / 2,
- .field = V4L2_FIELD_NONE,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .bytesperline = SENSOR_RES_X / 2,
- .sizeimage = (SENSOR_RES_X/2) * (SENSOR_RES_Y/2),
-};
-
/* USB-specific object needed to register this driver with the USB subsystem. */
static struct usb_driver sur40_driver = {
.name = DRIVER_SHORT,

Privacy Policy