Commit af79ce47 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

Pull input subsystem updates from Dmitry Torokhov:

 - updated support for Synaptics RMI4 devices, including support for
   SMBus controllers, firmware update support, sensor tuning, and PS/2
   guest support

 - ALPS driver now supports tracksticks on SS5 controllers

 - i8042 now uses chassis info to skip selftest on Asus laptops as list
   of individual models became too unwieldy

 - miscellaneous fixes to other drivers

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (67 commits)
  Input: imx6ul_tsc - generalize the averaging property
  Input: drv260x - use generic device properties
  Input: drv260x - use temporary for &client->dev
  Input: drv260x - fix input device's parent assignment
  Input: synaptics-rmi4 - add support for F34 V7 bootloader
  Input: drv260x - fix initializing overdrive voltage
  Input: ALPS - fix protcol -> protocol
  Input: i8042 - comment #else/#endif of CONFIG_PNP
  Input: lpc32xx-keys - fix invalid error handling of a requested irq
  Input: synaptics-rmi4 - fix debug for sensor clip
  Input: synaptics-rmi4 - store the attn data in the driver
  Input: synaptics-rmi4 - allow to add attention data
  Input: synaptics-rmi4 - f03 - grab data passed by transport device
  Input: synaptics-rmi4 - add support for F03
  Input: imx6ul_tsc - convert int to u32
  Input: imx6ul_tsc - add mask when set REG_ADC_CFG
  Input: synaptics-rmi4 - have only one struct platform data
  Input: synaptics-rmi4 - remove EXPORT_SYMBOL_GPL for internal functions
  Input: synaptics-rmi4 - remove mutex calls while updating the firmware
  Input: drv2667 - fix misuse of regmap_update_bits
  ...
parents c07dee73 f26e8817
* Dialog DA9062/63 OnKey Module * Dialog DA9061/62/63 OnKey Module
This module is part of the DA9062/DA9063. For more details about entire This module is part of the DA9061/DA9062/DA9063. For more details about entire
chips see Documentation/devicetree/bindings/mfd/da9062.txt and DA9062 and DA9061 chips see Documentation/devicetree/bindings/mfd/da9062.txt
Documentation/devicetree/bindings/mfd/da9063.txt For DA9063 see Documentation/devicetree/bindings/mfd/da9063.txt
This module provides KEY_POWER, KEY_SLEEP and events. This module provides the KEY_POWER event.
Required properties: Required properties:
- compatible: should be one of: - compatible: should be one of the following valid compatible string lines:
dlg,da9062-onkey "dlg,da9061-onkey", "dlg,da9062-onkey"
dlg,da9063-onkey "dlg,da9062-onkey"
"dlg,da9063-onkey"
Optional properties: Optional properties:
- dlg,disable-key-power : Disable power-down using a long key-press. If this - dlg,disable-key-power : Disable power-down using a long key-press. If this
entry exists the OnKey driver will remove support for the KEY_POWER key entry exists the OnKey driver will remove support for the KEY_POWER key
press. If this entry does not exist then by default the key-press press when triggered using a long press of the OnKey.
triggered power down is enabled and the OnKey will support both KEY_POWER
and KEY_SLEEP.
Example: Example: DA9063
pmic0: da9062@58 {
pmic0: da9063@58 {
onkey { onkey {
compatible = "dlg,da9063-onkey"; compatible = "dlg,da9063-onkey";
dlg,disable-key-power; dlg,disable-key-power;
}; };
};
Example: DA9062
pmic0: da9062@58 {
onkey {
compatible = "dlg,da9062-onkey";
dlg,disable-key-power;
};
};
Example: DA9061 using a fall-back compatible for the DA9062 onkey driver
pmic0: da9061@58 {
onkey {
compatible = "dlg,da9061-onkey", "dlg,da9062-onkey";
dlg,disable-key-power;
};
}; };
...@@ -17,6 +17,8 @@ Optional properties: ...@@ -17,6 +17,8 @@ Optional properties:
This value depends on the touch screen. This value depends on the touch screen.
- pre-charge-time: the touch screen need some time to precharge. - pre-charge-time: the touch screen need some time to precharge.
This value depends on the touch screen. This value depends on the touch screen.
- touchscreen-average-samples: Number of data samples which are averaged for
each read. Valid values are 1, 4, 8, 16 and 32.
Example: Example:
tsc: tsc@02040000 { tsc: tsc@02040000 {
...@@ -32,5 +34,6 @@ Example: ...@@ -32,5 +34,6 @@ Example:
xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>; xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
measure-delay-time = <0xfff>; measure-delay-time = <0xfff>;
pre-charge-time = <0xffff>; pre-charge-time = <0xffff>;
touchscreen-average-samples = <32>;
status = "okay"; status = "okay";
}; };
...@@ -18,6 +18,8 @@ Optional properties: ...@@ -18,6 +18,8 @@ Optional properties:
- touchscreen-inverted-y : See touchscreen.txt - touchscreen-inverted-y : See touchscreen.txt
- touchscreen-swapped-x-y : See touchscreen.txt - touchscreen-swapped-x-y : See touchscreen.txt
- silead,max-fingers : maximum number of fingers the touchscreen can detect - silead,max-fingers : maximum number of fingers the touchscreen can detect
- vddio-supply : regulator phandle for controller VDDIO
- avdd-supply : regulator phandle for controller AVDD
Example: Example:
......
...@@ -14,6 +14,9 @@ Optional properties for Touchscreens: ...@@ -14,6 +14,9 @@ Optional properties for Touchscreens:
- touchscreen-fuzz-pressure : pressure noise value of the absolute input - touchscreen-fuzz-pressure : pressure noise value of the absolute input
device (arbitrary range dependent on the device (arbitrary range dependent on the
controller) controller)
- touchscreen-average-samples : Number of data samples which are averaged
for each read (valid values dependent on the
controller)
- touchscreen-inverted-x : X axis is inverted (boolean) - touchscreen-inverted-x : X axis is inverted (boolean)
- touchscreen-inverted-y : Y axis is inverted (boolean) - touchscreen-inverted-y : Y axis is inverted (boolean)
- touchscreen-swapped-x-y : X and Y axis are swapped (boolean) - touchscreen-swapped-x-y : X and Y axis are swapped (boolean)
......
...@@ -134,6 +134,7 @@ static const struct xpad_device { ...@@ -134,6 +134,7 @@ static const struct xpad_device {
{ 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE }, { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
{ 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 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, 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, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", 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 }, { 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 ...@@ -1044,9 +1045,9 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
packet->data[7] = 0x00; packet->data[7] = 0x00;
packet->data[8] = strong / 512; /* left actuator */ packet->data[8] = strong / 512; /* left actuator */
packet->data[9] = weak / 512; /* right actuator */ packet->data[9] = weak / 512; /* right actuator */
packet->data[10] = 0xFF; packet->data[10] = 0xFF; /* on period */
packet->data[11] = 0x00; packet->data[11] = 0x00; /* off period */
packet->data[12] = 0x00; packet->data[12] = 0xFF; /* repeat count */
packet->len = 13; packet->len = 13;
packet->pending = true; packet->pending = true;
break; break;
......
...@@ -26,15 +26,15 @@ ...@@ -26,15 +26,15 @@
#include <linux/gpio_keys.h> #include <linux/gpio_keys.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
struct gpio_button_data { struct gpio_button_data {
const struct gpio_keys_button *button; const struct gpio_keys_button *button;
struct input_dev *input; struct input_dev *input;
struct gpio_desc *gpiod;
struct timer_list release_timer; struct timer_list release_timer;
unsigned int release_delay; /* in msecs, for IRQ-only buttons */ 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) ...@@ -140,7 +140,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata)
*/ */
disable_irq(bdata->irq); disable_irq(bdata->irq);
if (gpio_is_valid(bdata->button->gpio)) if (bdata->gpiod)
cancel_delayed_work_sync(&bdata->work); cancel_delayed_work_sync(&bdata->work);
else else
del_timer_sync(&bdata->release_timer); del_timer_sync(&bdata->release_timer);
...@@ -358,19 +358,20 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata) ...@@ -358,19 +358,20 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
const struct gpio_keys_button *button = bdata->button; const struct gpio_keys_button *button = bdata->button;
struct input_dev *input = bdata->input; struct input_dev *input = bdata->input;
unsigned int type = button->type ?: EV_KEY; 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) { 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; return;
} }
state = (state ? 1 : 0) ^ button->active_low;
if (type == EV_ABS) { if (type == EV_ABS) {
if (state) if (state)
input_event(input, type, button->code, button->value); input_event(input, type, button->code, button->value);
} else { } else {
input_event(input, type, button->code, !!state); input_event(input, type, button->code, state);
} }
input_sync(input); input_sync(input);
} }
...@@ -456,7 +457,7 @@ static void gpio_keys_quiesce_key(void *data) ...@@ -456,7 +457,7 @@ static void gpio_keys_quiesce_key(void *data)
{ {
struct gpio_button_data *bdata = data; struct gpio_button_data *bdata = data;
if (gpio_is_valid(bdata->button->gpio)) if (bdata->gpiod)
cancel_delayed_work_sync(&bdata->work); cancel_delayed_work_sync(&bdata->work);
else else
del_timer_sync(&bdata->release_timer); del_timer_sync(&bdata->release_timer);
...@@ -465,7 +466,8 @@ static void gpio_keys_quiesce_key(void *data) ...@@ -465,7 +466,8 @@ static void gpio_keys_quiesce_key(void *data)
static int gpio_keys_setup_key(struct platform_device *pdev, static int gpio_keys_setup_key(struct platform_device *pdev,
struct input_dev *input, struct input_dev *input,
struct gpio_button_data *bdata, 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"; const char *desc = button->desc ? button->desc : "gpio_keys";
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -478,18 +480,56 @@ static int gpio_keys_setup_key(struct platform_device *pdev, ...@@ -478,18 +480,56 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
bdata->button = button; bdata->button = button;
spin_lock_init(&bdata->lock); 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, error = devm_gpio_request_one(&pdev->dev, button->gpio, flags,
GPIOF_IN, desc); desc);
if (error < 0) { if (error < 0) {
dev_err(dev, "Failed to request GPIO %d, error %d\n", dev_err(dev, "Failed to request GPIO %d, error %d\n",
button->gpio, error); button->gpio, error);
return error; return error;
} }
bdata->gpiod = gpio_to_desc(button->gpio);
if (!bdata->gpiod)
return -EINVAL;
}
if (bdata->gpiod) {
if (button->debounce_interval) { if (button->debounce_interval) {
error = gpio_set_debounce(button->gpio, error = gpiod_set_debounce(bdata->gpiod,
button->debounce_interval * 1000); button->debounce_interval * 1000);
/* use timer if gpiolib doesn't provide debounce */ /* use timer if gpiolib doesn't provide debounce */
if (error < 0) if (error < 0)
...@@ -500,7 +540,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev, ...@@ -500,7 +540,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
if (button->irq) { if (button->irq) {
bdata->irq = button->irq; bdata->irq = button->irq;
} else { } else {
irq = gpio_to_irq(button->gpio); irq = gpiod_to_irq(bdata->gpiod);
if (irq < 0) { if (irq < 0) {
error = irq; error = irq;
dev_err(dev, dev_err(dev,
...@@ -518,9 +558,10 @@ static int gpio_keys_setup_key(struct platform_device *pdev, ...@@ -518,9 +558,10 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
} else { } else {
if (!button->irq) { if (!button->irq) {
dev_err(dev, "No IRQ specified\n"); dev_err(dev, "Found button without gpio or irq\n");
return -EINVAL; return -EINVAL;
} }
bdata->irq = button->irq; bdata->irq = button->irq;
if (button->type && button->type != EV_KEY) { if (button->type && button->type != EV_KEY) {
...@@ -575,7 +616,7 @@ static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata) ...@@ -575,7 +616,7 @@ static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata)
for (i = 0; i < ddata->pdata->nbuttons; i++) { for (i = 0; i < ddata->pdata->nbuttons; i++) {
struct gpio_button_data *bdata = &ddata->data[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); gpio_keys_gpio_report_event(bdata);
} }
input_sync(input); input_sync(input);
...@@ -612,25 +653,18 @@ static void gpio_keys_close(struct input_dev *input) ...@@ -612,25 +653,18 @@ static void gpio_keys_close(struct input_dev *input)
* Handlers for alternative sources of platform_data * 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 * static struct gpio_keys_platform_data *
gpio_keys_get_devtree_pdata(struct device *dev) gpio_keys_get_devtree_pdata(struct device *dev)
{ {
struct device_node *node, *pp;
struct gpio_keys_platform_data *pdata; struct gpio_keys_platform_data *pdata;
struct gpio_keys_button *button; struct gpio_keys_button *button;
int error; struct fwnode_handle *child;
int nbuttons; int nbuttons;
int i;
node = dev->of_node; nbuttons = device_get_child_node_count(dev);
if (!node)
return ERR_PTR(-ENODEV);
nbuttons = of_get_available_child_count(node);
if (nbuttons == 0) if (nbuttons == 0)
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
...@@ -640,64 +674,47 @@ gpio_keys_get_devtree_pdata(struct device *dev) ...@@ -640,64 +674,47 @@ gpio_keys_get_devtree_pdata(struct device *dev)
if (!pdata) if (!pdata)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
pdata->buttons = (struct gpio_keys_button *)(pdata + 1); button = (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 = &pdata->buttons[i++]; pdata->buttons = button;
pdata->nbuttons = nbuttons;
button->gpio = of_get_gpio_flags(pp, 0, &flags); pdata->rep = device_property_read_bool(dev, "autorepeat");
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;
}
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) { device_for_each_child_node(dev, child) {
dev_err(dev, "Found button without gpios or irqs\n"); if (is_of_node(child))
return ERR_PTR(-EINVAL); button->irq =
} irq_of_parse_and_map(to_of_node(child), 0);
if (of_property_read_u32(pp, "linux,code", &button->code)) { if (fwnode_property_read_u32(child, "linux,code",
dev_err(dev, "Button without keycode: 0x%x\n", &button->code)) {
button->gpio); dev_err(dev, "Button without keycode\n");
fwnode_handle_put(child);
return ERR_PTR(-EINVAL); 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->type = EV_KEY;
button->wakeup = of_property_read_bool(pp, "wakeup-source") || button->wakeup =
/* legacy name */ fwnode_property_read_bool(child, "wakeup-source") ||
of_property_read_bool(pp, "gpio-key,wakeup"); /* 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))
button->debounce_interval = 5; button->debounce_interval = 5;
}
if (pdata->nbuttons == 0) button++;
return ERR_PTR(-EINVAL); }
return pdata; return pdata;
} }
...@@ -708,20 +725,11 @@ static const struct of_device_id gpio_keys_of_match[] = { ...@@ -708,20 +725,11 @@ static const struct of_device_id gpio_keys_of_match[] = {
}; };
MODULE_DEVICE_TABLE(of, 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) static int gpio_keys_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev); const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
struct fwnode_handle *child = NULL;
struct gpio_keys_drvdata *ddata; struct gpio_keys_drvdata *ddata;
struct input_dev *input; struct input_dev *input;
size_t size; size_t size;
...@@ -774,14 +782,28 @@ static int gpio_keys_probe(struct platform_device *pdev) ...@@ -774,14 +782,28 @@ static int gpio_keys_probe(struct platform_device *pdev)
const struct gpio_keys_button *button = &pdata->buttons[i]; const struct gpio_keys_button *button = &pdata->buttons[i];
struct gpio_button_data *bdata = &ddata->data[i]; struct gpio_button_data *bdata = &ddata->data[i];
error = gpio_keys_setup_key(pdev, input, bdata, button); if (!dev_get_platdata(dev)) {
if (error) 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; return error;
}
if (button->wakeup) if (button->wakeup)
wakeup = 1; wakeup = 1;
} }
fwnode_handle_put(child);
error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group); error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);
if (error) { if (error) {
dev_err(dev, "Unable to export keys/switches, error: %d\n", dev_err(dev, "Unable to export keys/switches, error: %d\n",
...@@ -814,8 +836,7 @@ static int gpio_keys_remove(struct platform_device *pdev) ...@@ -814,8 +836,7 @@ static int gpio_keys_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM_SLEEP static int __maybe_unused gpio_keys_suspend(struct device *dev)
static int gpio_keys_suspend(struct device *dev)
{ {
struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
struct input_dev *input = ddata->input; struct input_dev *input = ddata->input;
...@@ -837,7 +858,7 @@ static int gpio_keys_suspend(struct device *dev) ...@@ -837,7 +858,7 @@ static int gpio_keys_suspend(struct device *dev)
return 0; 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 gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
struct input_dev *input = ddata->input; struct input_dev *input = ddata->input;
...@@ -863,7 +884,6 @@ static int gpio_keys_resume(struct device *dev) ...@@ -863,7 +884,6 @@ static int gpio_keys_resume(struct device *dev)
gpio_keys_report_state(ddata); gpio_keys_report_state(ddata);
return 0; return 0;
} }
#endif
static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume); 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 = { ...@@ -873,7 +893,7 @@ static struct platform_driver gpio_keys_device_driver = {
.driver = { .driver = {
.name = "gpio-keys", .name = "gpio-keys",
.pm = &gpio_keys_pm_ops, .pm = &gpio_keys_pm_ops,
.of_match_table = of_match_ptr(gpio_keys_of_match), .of_match_table = gpio_keys_of_match,
} }
}; };
......
...@@ -30,10 +30,10 @@ ...@@ -30,10 +30,10 @@
#define DRV_NAME "gpio-keys-polled" #define DRV_NAME "gpio-keys-polled"
struct gpio_keys_button_data { struct gpio_keys_button_data {
struct gpio_desc *gpiod;
int last_state; int last_state;
int count; int count;
int threshold; int threshold;
int can_sleep;
}; };
struct gpio_keys_polled_dev { struct gpio_keys_polled_dev {
...@@ -46,7 +46,7 @@ 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, static void gpio_keys_button_event(struct input_polled_dev *dev,
struct gpio_keys_button *button, const struct gpio_keys_button *button,
int state) int state)
{ {
struct gpio_keys_polled_dev *bdev = dev->private; struct gpio_keys_polled_dev *bdev = dev->private;
...@@ -70,21 +70,22 @@ static void gpio_keys_button_event(struct input_polled_dev *dev, ...@@ -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, 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) struct gpio_keys_button_data *bdata)
{ {
int state; int state;
if (bdata->can_sleep) state = gpiod_get_value_cansleep(bdata->gpiod);
state = !!gpiod_get_value_cansleep(button->gpiod); if (state < 0) {
else dev_err(dev->input->dev.parent,
state = !!gpiod_get_value(button->gpiod); "failed to get gpio state: %d\n", state);
} else {
gpio_keys_button_event(dev, button, state); gpio_keys_button_event(dev, button, state);
if (state != bdata->last_state) { if (state != bdata->last_state) {
bdata->count = 0; bdata->count = 0;
bdata->last_state = state; bdata->last_state = state;
}
} }
} }
...@@ -142,48 +143,35 @@ static void gpio_keys_polled_close(struct input_polled_dev *dev) ...@@ -142,48 +143,35 @@ static void gpio_keys_polled_close(struct input_polled_dev *dev)
pdata->disable(bdev->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_platform_data *pdata;
struct gpio_keys_button *button; struct gpio_keys_button *button;
struct fwnode_handle *child; struct fwnode_handle *child;
int error;
int nbuttons; int nbuttons;
nbuttons = device_get_child_node_count(dev); nbuttons = device_get_child_node_count(dev);
if (nbuttons == 0) if (nbuttons == 0)
return NULL; return ERR_PTR(-EINVAL);
pdata = devm_kzalloc(dev, sizeof(*pdata) + nbuttons * sizeof(*button), pdata = devm_kzalloc(dev, sizeof(*pdata) + nbuttons * sizeof(*button),
GFP_KERNEL); GFP_KERNEL);
if (!pdata) if (!pdata)
return ERR_PTR(-ENOMEM); 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"); pdata->rep = device_property_present(dev, "autorepeat");
device_property_read_u32(dev, "poll-interval", &pdata->poll_interval); device_property_read_u32(dev, "poll-interval", &pdata->poll_interval);
device_for_each_child_node(dev, child) { device_for_each_child_node(dev, child) {
struct gpio_desc *desc; if (fwnode_property_read_u32(child, "linux,code",
&button->code)) {
desc = devm_get_gpiod_from_child(dev, NULL, child); dev_err(dev, "button without keycode\n");
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);
fwnode_handle_put(child); fwnode_handle_put(child);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
...@@ -206,10 +194,9 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct ...@@ -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", if (fwnode_property_read_u32(child, "debounce-interval",
&button->debounce_interval)) &button->debounce_interval))
button->debounce_interval = 5; button->debounce_interval = 5;
}
if (pdata->nbuttons == 0) button++;
return ERR_PTR(-EINVAL); }
return pdata; return pdata;
} }
...@@ -220,7 +207,7 @@ static void gpio_keys_polled_set_abs_params(struct input_dev *input, ...@@ -220,7 +207,7 @@ static void gpio_keys_polled_set_abs_params(struct input_dev *input,
int i, min = 0, max = 0; int i, min = 0, max = 0;
for (i = 0; i < pdata->nbuttons; i++) { 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) if (button->type != EV_ABS || button->code != code)
continue; continue;
...@@ -230,6 +217,7 @@ static void gpio_keys_polled_set_abs_params(struct input_dev *input, ...@@ -230,6 +217,7 @@ static void gpio_keys_polled_set_abs_params(struct input_dev *input,
if (button->value > max) if (button->value > max)
max = button->value; max = button->value;
} }
input_set_abs_params(input, code, min, max, 0, 0); input_set_abs_params(input, code, min, max, 0, 0);
} }
...@@ -242,6 +230,7 @@ MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match); ...@@ -242,6 +230,7 @@ MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match);
static int gpio_keys_polled_probe(struct platform_device *pdev) static int gpio_keys_polled_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct fwnode_handle *child = NULL;
const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev); const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
struct gpio_keys_polled_dev *bdev; struct gpio_keys_polled_dev *bdev;
struct input_polled_dev *poll_dev; struct input_polled_dev *poll_dev;
...@@ -254,10 +243,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) ...@@ -254,10 +243,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
pdata = gpio_keys_polled_get_devtree_pdata(dev); pdata = gpio_keys_polled_get_devtree_pdata(dev);
if (IS_ERR(pdata)) if (IS_ERR(pdata))
return PTR_ERR(pdata); return PTR_ERR(pdata);
if (!pdata) {
dev_err(dev, "missing platform data\n");
return -EINVAL;
}
} }
if (!pdata->poll_interval) { if (!pdata->poll_interval) {
...@@ -300,20 +285,48 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) ...@@ -300,20 +285,48 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
__set_bit(EV_REP, input->evbit); __set_bit(EV_REP, input->evbit);
for (i = 0; i < pdata->nbuttons; i++) { 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]; struct gpio_keys_button_data *bdata = &bdev->data[i];
unsigned int type = button->type ?: EV_KEY; unsigned int type = button->type ?: EV_KEY;
if (button->wakeup) { if (button->wakeup) {
dev_err(dev, DRV_NAME " does not support wakeup\n"); dev_err(dev, DRV_NAME " does not support wakeup\n");
fwnode_handle_put(child);
return -EINVAL; return -EINVAL;
} }
/* if (!dev_get_platdata(dev)) {
* Legacy GPIO number so request the GPIO here and /* No legacy static platform data */
* convert it to descriptor. child = device_get_next_child_node(dev, child);
*/ if (!child) {
if (!button->gpiod && gpio_is_valid(button->gpio)) { 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; unsigned flags = GPIOF_IN;
if (button->active_low) if (button->active_low)
...@@ -322,18 +335,21 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) ...@@ -322,18 +335,21 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
error = devm_gpio_request_one(&pdev->dev, button->gpio, error = devm_gpio_request_one(&pdev->dev, button->gpio,
flags, button->desc ? : DRV_NAME); flags, button->desc ? : DRV_NAME);
if (error) { 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); button->gpio, error);
return 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->last_state = -1;
bdata->threshold = DIV_ROUND_UP(button->debounce_interval, bdata->threshold = DIV_ROUND_UP(button->debounce_interval,
pdata->poll_interval); pdata->poll_interval);
...@@ -344,6 +360,8 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) ...@@ -344,6 +360,8 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
button->code); button->code);
} }
fwnode_handle_put(child);
bdev->poll_dev = poll_dev; bdev->poll_dev = poll_dev;
bdev->dev = dev; bdev->dev = dev;
bdev->pdata = pdata; bdev->pdata = pdata;
......
...@@ -182,7 +182,7 @@ static int lpc32xx_kscan_probe(struct platform_device *pdev) ...@@ -182,7 +182,7 @@ static int lpc32xx_kscan_probe(struct platform_device *pdev)
} }
irq = platform_get_irq(pdev, 0); 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"); dev_err(&pdev->dev, "failed to get platform irq\n");
return -EINVAL; return -EINVAL;
} }
......
...@@ -316,7 +316,7 @@ static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad) ...@@ -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", error = of_property_read_u32(np, "marvell,debounce-interval",
&pdata->debounce_interval); &pdata->debounce_interval);
if (error) { if (error) {
dev_err(dev, "failed to parse debpunce-interval\n"); dev_err(dev, "failed to parse debounce-interval\n");
return error; return error;
} }
......
...@@ -164,11 +164,18 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data) ...@@ -164,11 +164,18 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data)
int error, col, row; int error, col, row;
u8 reg, state, code; u8 reg, state, code;
/* Initial read of the key event FIFO */ do {
error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg); 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; state = reg & KEY_EVENT_VALUE;
code = reg & KEY_EVENT_CODE; code = reg & KEY_EVENT_CODE;
...@@ -184,11 +191,7 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data) ...@@ -184,11 +191,7 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data)
/* Read for next loop */ /* Read for next loop */
error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg); error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
} } while (1);
if (error < 0)
dev_err(&keypad_data->client->dev,
"unable to read REG_KEY_EVENT_A\n");
input_sync(input); input_sync(input);
} }
......
...@@ -625,11 +625,12 @@ config INPUT_DA9055_ONKEY ...@@ -625,11 +625,12 @@ config INPUT_DA9055_ONKEY
will be called da9055_onkey. will be called da9055_onkey.
config INPUT_DA9063_ONKEY config INPUT_DA9063_ONKEY
tristate "Dialog DA9062/63 OnKey" tristate "Dialog DA9063/62/61 OnKey"
depends on MFD_DA9063 || MFD_DA9062 depends on MFD_DA9063 || MFD_DA9062
help help
Support the ONKEY of Dialog DA9063 and DA9062 Power Management ICs Support the ONKEY of Dialog DA9063, DA9062 and DA9061 Power
as an input device capable of reporting the power button status. 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 To compile this driver as a module, choose M here: the module
will be called da9063_onkey. will be called da9063_onkey.
......
...@@ -538,8 +538,13 @@ static int bma150_probe(struct i2c_client *client, ...@@ -538,8 +538,13 @@ static int bma150_probe(struct i2c_client *client,
return -EIO; 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); 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); dev_err(&client->dev, "BMA150 chip id error: %d\n", chip_id);
return -EINVAL; return -EINVAL;
} }
...@@ -643,7 +648,9 @@ static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL); ...@@ -643,7 +648,9 @@ static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL);
static const struct i2c_device_id bma150_id[] = { static const struct i2c_device_id bma150_id[] = {
{ "bma150", 0 }, { "bma150", 0 },
#if !IS_ENABLED(CONFIG_BMA180)
{ "bma180", 0 }, { "bma180", 0 },
#endif
{ "smb380", 0 }, { "smb380", 0 },
{ "bma023", 0 }, { "bma023", 0 },
{ } { }
......
/* /*
* OnKey device driver for DA9063 and DA9062 PMICs * OnKey device driver for DA9063, DA9062 and DA9061 PMICs
* Copyright (C) 2015 Dialog Semiconductor Ltd. * Copyright (C) 2015 Dialog Semiconductor Ltd.
* *
* This program is free software; you can redistribute it and/or * 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[] = { ...@@ -87,6 +87,7 @@ static const struct of_device_id da9063_compatible_reg_id_table[] = {
{ .compatible = "dlg,da9062-onkey", .data = &da9062_regs }, { .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) static void da9063_poll_on(struct work_struct *work)
{ {
...@@ -149,13 +150,13 @@ 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 * and then send shutdown command
*/ */
dev_dbg(&onkey->input->dev, dev_dbg(&onkey->input->dev,
"Sending SHUTDOWN to DA9063 ...\n"); "Sending SHUTDOWN to PMIC ...\n");
error = regmap_write(onkey->regmap, error = regmap_write(onkey->regmap,
config->onkey_shutdown, config->onkey_shutdown,
config->onkey_shutdown_mask); config->onkey_shutdown_mask);
if (error) if (error)
dev_err(&onkey->input->dev, dev_err(&onkey->input->dev,
"Cannot SHUTDOWN DA9063: %d\n", "Cannot SHUTDOWN PMIC: %d\n",
error); error);
} }
} }
...@@ -300,6 +301,6 @@ static struct platform_driver da9063_onkey_driver = { ...@@ -300,6 +301,6 @@ static struct platform_driver da9063_onkey_driver = {
module_platform_driver(da9063_onkey_driver); module_platform_driver(da9063_onkey_driver);
MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>"); 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_LICENSE("GPL");
MODULE_ALIAS("platform:" DA9063_DRVNAME_ONKEY); MODULE_ALIAS("platform:" DA9063_DRVNAME_ONKEY);
...@@ -18,8 +18,6 @@ ...@@ -18,8 +18,6 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -27,7 +25,6 @@ ...@@ -27,7 +25,6 @@
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <dt-bindings/input/ti-drv260x.h> #include <dt-bindings/input/ti-drv260x.h>
#include <linux/platform_data/drv260x-pdata.h>
#define DRV260X_STATUS 0x0 #define DRV260X_STATUS 0x0
#define DRV260X_MODE 0x1 #define DRV260X_MODE 0x1
...@@ -468,90 +465,39 @@ static const struct regmap_config drv260x_regmap_config = { ...@@ -468,90 +465,39 @@ static const struct regmap_config drv260x_regmap_config = {
.cache_type = REGCACHE_NONE, .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, static int drv260x_probe(struct i2c_client *client,
const struct i2c_device_id *id) 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; struct drv260x_data *haptics;
u32 voltage;
int error; int error;
haptics = devm_kzalloc(&client->dev, sizeof(*haptics), GFP_KERNEL); haptics = devm_kzalloc(dev, sizeof(*haptics), GFP_KERNEL);
if (!haptics) if (!haptics)
return -ENOMEM; return -ENOMEM;
haptics->rated_voltage = DRV260X_DEF_OD_CLAMP_VOLT; error = device_property_read_u32(dev, "mode", &haptics->mode);
haptics->rated_voltage = DRV260X_DEF_RATED_VOLT; if (error) {
dev_err(dev, "Can't fetch 'mode' property: %d\n", error);
if (pdata) { return error;
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;
} }
if (haptics->mode < DRV260X_LRA_MODE || if (haptics->mode < DRV260X_LRA_MODE ||
haptics->mode > DRV260X_ERM_MODE) { haptics->mode > DRV260X_ERM_MODE) {
dev_err(&client->dev, dev_err(dev, "Vibrator mode is invalid: %i\n", haptics->mode);
"Vibrator mode is invalid: %i\n",
haptics->mode);
return -EINVAL; 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 || if (haptics->library < DRV260X_LIB_EMPTY ||
haptics->library > DRV260X_ERM_LIB_F) { haptics->library > DRV260X_ERM_LIB_F) {
dev_err(&client->dev, dev_err(dev,
"Library value is invalid: %i\n", haptics->library); "Library value is invalid: %i\n", haptics->library);
return -EINVAL; return -EINVAL;
} }
...@@ -559,40 +505,44 @@ static int drv260x_probe(struct i2c_client *client, ...@@ -559,40 +505,44 @@ static int drv260x_probe(struct i2c_client *client,
if (haptics->mode == DRV260X_LRA_MODE && if (haptics->mode == DRV260X_LRA_MODE &&
haptics->library != DRV260X_LIB_EMPTY && haptics->library != DRV260X_LIB_EMPTY &&
haptics->library != DRV260X_LIB_LRA) { haptics->library != DRV260X_LIB_LRA) {
dev_err(&client->dev, dev_err(dev, "LRA Mode with ERM Library mismatch\n");
"LRA Mode with ERM Library mismatch\n");
return -EINVAL; return -EINVAL;
} }
if (haptics->mode == DRV260X_ERM_MODE && if (haptics->mode == DRV260X_ERM_MODE &&
(haptics->library == DRV260X_LIB_EMPTY || (haptics->library == DRV260X_LIB_EMPTY ||
haptics->library == DRV260X_LIB_LRA)) { haptics->library == DRV260X_LIB_LRA)) {
dev_err(&client->dev, dev_err(dev, "ERM Mode with LRA Library mismatch\n");
"ERM Mode with LRA Library mismatch\n");
return -EINVAL; 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)) { if (IS_ERR(haptics->regulator)) {
error = PTR_ERR(haptics->regulator); error = PTR_ERR(haptics->regulator);
dev_err(&client->dev, dev_err(dev, "unable to get regulator, error: %d\n", error);
"unable to get regulator, error: %d\n", error);
return 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); GPIOD_OUT_HIGH);
if (IS_ERR(haptics->enable_gpio)) if (IS_ERR(haptics->enable_gpio))
return PTR_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) { if (!haptics->input_dev) {
dev_err(&client->dev, "Failed to allocate input device\n"); dev_err(&client->dev, "Failed to allocate input device\n");
return -ENOMEM; return -ENOMEM;
} }
haptics->input_dev->name = "drv260x:haptics"; haptics->input_dev->name = "drv260x:haptics";
haptics->input_dev->dev.parent = client->dev.parent;
haptics->input_dev->close = drv260x_close; haptics->input_dev->close = drv260x_close;
input_set_drvdata(haptics->input_dev, haptics); input_set_drvdata(haptics->input_dev, haptics);
input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE); input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE);
...@@ -600,8 +550,7 @@ static int drv260x_probe(struct i2c_client *client, ...@@ -600,8 +550,7 @@ static int drv260x_probe(struct i2c_client *client,
error = input_ff_create_memless(haptics->input_dev, NULL, error = input_ff_create_memless(haptics->input_dev, NULL,
drv260x_haptics_play); drv260x_haptics_play);
if (error) { if (error) {
dev_err(&client->dev, "input_ff_create() failed: %d\n", dev_err(dev, "input_ff_create() failed: %d\n", error);
error);
return error; return error;
} }
...@@ -613,21 +562,19 @@ static int drv260x_probe(struct i2c_client *client, ...@@ -613,21 +562,19 @@ static int drv260x_probe(struct i2c_client *client,
haptics->regmap = devm_regmap_init_i2c(client, &drv260x_regmap_config); haptics->regmap = devm_regmap_init_i2c(client, &drv260x_regmap_config);
if (IS_ERR(haptics->regmap)) { if (IS_ERR(haptics->regmap)) {
error = PTR_ERR(haptics->regmap); error = PTR_ERR(haptics->regmap);
dev_err(&client->dev, "Failed to allocate register map: %d\n", dev_err(dev, "Failed to allocate register map: %d\n", error);
error);
return error; return error;
} }
error = drv260x_init(haptics); error = drv260x_init(haptics);
if (error) { if (error) {
dev_err(&client->dev, "Device init failed: %d\n", error); dev_err(dev, "Device init failed: %d\n", error);
return error; return error;
} }
error = input_register_device(haptics->input_dev); error = input_register_device(haptics->input_dev);
if (error) { if (error) {
dev_err(&client->dev, "couldn't register input device: %d\n", dev_err(dev, "couldn't register input device: %d\n", error);
error);
return error; return error;
} }
......
...@@ -125,8 +125,8 @@ static void drv2665_close(struct input_dev *input) ...@@ -125,8 +125,8 @@ static void drv2665_close(struct input_dev *input)
cancel_work_sync(&haptics->work); cancel_work_sync(&haptics->work);
error = regmap_update_bits(haptics->regmap, error = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
DRV2665_CTRL_2, DRV2665_STANDBY, 1); DRV2665_STANDBY, DRV2665_STANDBY);
if (error) if (error)
dev_err(&haptics->client->dev, dev_err(&haptics->client->dev,
"Failed to enter standby mode: %d\n", error); "Failed to enter standby mode: %d\n", error);
...@@ -240,7 +240,7 @@ static int __maybe_unused drv2665_suspend(struct device *dev) ...@@ -240,7 +240,7 @@ static int __maybe_unused drv2665_suspend(struct device *dev)
if (haptics->input_dev->users) { if (haptics->input_dev->users) {
ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2, ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
DRV2665_STANDBY, 1); DRV2665_STANDBY, DRV2665_STANDBY);
if (ret) { if (ret) {
dev_err(dev, "Failed to set standby mode\n"); dev_err(dev, "Failed to set standby mode\n");
regulator_disable(haptics->regulator); regulator_disable(haptics->regulator);
......
...@@ -256,7 +256,7 @@ static void drv2667_close(struct input_dev *input) ...@@ -256,7 +256,7 @@ static void drv2667_close(struct input_dev *input)
cancel_work_sync(&haptics->work); cancel_work_sync(&haptics->work);
error = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, error = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2,
DRV2667_STANDBY, 1); DRV2667_STANDBY, DRV2667_STANDBY);
if (error) if (error)
dev_err(&haptics->client->dev, dev_err(&haptics->client->dev,
"Failed to enter standby mode: %d\n", error); "Failed to enter standby mode: %d\n", error);
...@@ -415,7 +415,7 @@ static int __maybe_unused drv2667_suspend(struct device *dev) ...@@ -415,7 +415,7 @@ static int __maybe_unused drv2667_suspend(struct device *dev)
if (haptics->input_dev->users) { if (haptics->input_dev->users) {
ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2,
DRV2667_STANDBY, 1); DRV2667_STANDBY, DRV2667_STANDBY);
if (ret) { if (ret) {
dev_err(dev, "Failed to set standby mode\n"); dev_err(dev, "Failed to set standby mode\n");
regulator_disable(haptics->regulator); regulator_disable(haptics->regulator);
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h> #include <linux/gpio_keys.h>
#include <linux/gpio.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
/* /*
...@@ -92,7 +93,7 @@ soc_button_device_create(struct platform_device *pdev, ...@@ -92,7 +93,7 @@ soc_button_device_create(struct platform_device *pdev,
continue; continue;
gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index); gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
if (gpio < 0) if (!gpio_is_valid(gpio))
continue; continue;
gpio_keys[n_buttons].type = info->event_type; gpio_keys[n_buttons].type = info->event_type;
...@@ -166,6 +167,11 @@ static int soc_button_probe(struct platform_device *pdev) ...@@ -166,6 +167,11 @@ static int soc_button_probe(struct platform_device *pdev)
button_info = (struct soc_button_info *)id->driver_data; 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); priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
......
...@@ -1153,15 +1153,13 @@ static void alps_process_packet_v7(struct psmouse *psmouse) ...@@ -1153,15 +1153,13 @@ static void alps_process_packet_v7(struct psmouse *psmouse)
alps_process_touchpad_packet_v7(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) { switch (byte[3] & 0x30) {
case 0x00: case 0x00:
if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 && if (SS4_IS_IDLE_V2(byte)) {
(byte[3] & 0x88) == 0x08 && byte[4] == 0x10 &&
byte[5] == 0x00) {
pkt_id = SS4_PACKET_ID_IDLE; pkt_id = SS4_PACKET_ID_IDLE;
} else { } else {
pkt_id = SS4_PACKET_ID_ONE; pkt_id = SS4_PACKET_ID_ONE;
...@@ -1188,7 +1186,7 @@ static int alps_decode_ss4_v2(struct alps_fields *f, ...@@ -1188,7 +1186,7 @@ static int alps_decode_ss4_v2(struct alps_fields *f,
unsigned char *p, struct psmouse *psmouse) unsigned char *p, struct psmouse *psmouse)
{ {
struct alps_data *priv = psmouse->private; struct alps_data *priv = psmouse->private;
unsigned char pkt_id; enum SS4_PACKET_ID pkt_id;
unsigned int no_data_x, no_data_y; unsigned int no_data_x, no_data_y;
pkt_id = alps_get_pkt_id_ss4_v2(p); pkt_id = alps_get_pkt_id_ss4_v2(p);
...@@ -1267,18 +1265,12 @@ static int alps_decode_ss4_v2(struct alps_fields *f, ...@@ -1267,18 +1265,12 @@ static int alps_decode_ss4_v2(struct alps_fields *f,
break; break;
case SS4_PACKET_ID_STICK: case SS4_PACKET_ID_STICK:
if (!(priv->flags & ALPS_DUALPOINT)) { /*
psmouse_warn(psmouse, * x, y, and pressure are decoded in
"Rejected trackstick packet from non DualPoint device"); * alps_process_packet_ss4_v2()
} else { */
int x = (s8)(((p[0] & 1) << 7) | (p[1] & 0x7f)); f->first_mp = 0;
int y = (s8)(((p[3] & 1) << 7) | (p[2] & 0x7f)); f->is_mp = 0;
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);
}
break; break;
case SS4_PACKET_ID_IDLE: case SS4_PACKET_ID_IDLE:
...@@ -1346,6 +1338,27 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse) ...@@ -1346,6 +1338,27 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse)
priv->multi_packet = 0; 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); alps_report_mt_data(psmouse, (f->fingers <= 4) ? f->fingers : 4);
input_mt_report_finger_count(dev, f->fingers); input_mt_report_finger_count(dev, f->fingers);
...@@ -1356,13 +1369,6 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse) ...@@ -1356,13 +1369,6 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse)
input_report_abs(dev, ABS_PRESSURE, f->pressure); input_report_abs(dev, ABS_PRESSURE, f->pressure);
input_sync(dev); 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) static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse)
......
...@@ -54,7 +54,15 @@ enum SS4_PACKET_ID { ...@@ -54,7 +54,15 @@ enum SS4_PACKET_ID {
#define SS4_MASK_NORMAL_BUTTONS 0x07 #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] << 3) & 0x0078) | \
((_b[1] << 2) & 0x0380) | \ ((_b[1] << 2) & 0x0380) | \
((_b[2] << 5) & 0x1C00) \ ((_b[2] << 5) & 0x1C00) \
...@@ -101,6 +109,18 @@ enum SS4_PACKET_ID { ...@@ -101,6 +109,18 @@ enum SS4_PACKET_ID {
#define SS4_IS_MF_CONTINUE(_b) ((_b[2] & 0x10) == 0x10) #define SS4_IS_MF_CONTINUE(_b) ((_b[2] & 0x10) == 0x10)
#define SS4_IS_5F_DETECTED(_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_AX 8160 /* X-Coordinate value */
#define SS4_MFPACKET_NO_AY 4080 /* Y-Coordinate value */ #define SS4_MFPACKET_NO_AY 4080 /* Y-Coordinate value */
...@@ -146,7 +166,7 @@ struct alps_protocol_info { ...@@ -146,7 +166,7 @@ struct alps_protocol_info {
* (aka command mode response) identifies the firmware minor version. This * (aka command mode response) identifies the firmware minor version. This
* can be used to distinguish different hardware models which are not * can be used to distinguish different hardware models which are not
* uniquely identifiable through their E7 responses. * 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 * 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 * values returned in the "E7 report" and/or the "EC report." This table
......
...@@ -1093,19 +1093,18 @@ static int elan_probe(struct i2c_client *client, ...@@ -1093,19 +1093,18 @@ static int elan_probe(struct i2c_client *client,
if (error) if (error)
return 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, dev_dbg(&client->dev,
"Elan Touchpad Information:\n" "Elan Touchpad Extra Information:\n"
" Module product ID: 0x%04x\n"
" Firmware Version: 0x%04x\n"
" Sample Version: 0x%04x\n"
" IAP Version: 0x%04x\n"
" Max ABS X,Y: %d,%d\n" " Max ABS X,Y: %d,%d\n"
" Width X,Y: %d,%d\n" " Width X,Y: %d,%d\n"
" Resolution X,Y: %d,%d (dots/mm)\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->max_x, data->max_y,
data->width_x, data->width_y, data->width_x, data->width_y,
data->x_res, data->y_res); data->x_res, data->y_res);
......
...@@ -27,6 +27,27 @@ config RMI4_SPI ...@@ -27,6 +27,27 @@ config RMI4_SPI
If unsure, say N. 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 config RMI4_2D_SENSOR
bool bool
depends on RMI4_CORE depends on RMI4_CORE
...@@ -62,13 +83,34 @@ config RMI4_F30 ...@@ -62,13 +83,34 @@ config RMI4_F30
Function 30 provides GPIO and LED support for RMI4 devices. This Function 30 provides GPIO and LED support for RMI4 devices. This
includes support for buttons on TouchPads and ClickPads. 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 config RMI4_F54
bool "RMI4 Function 54 (Analog diagnostics)" bool "RMI4 Function 54 (Analog diagnostics)"
depends on RMI4_CORE depends on RMI4_CORE
depends on VIDEO_V4L2=y || (RMI4_CORE=m && VIDEO_V4L2=m) depends on VIDEO_V4L2=y || (RMI4_CORE=m && VIDEO_V4L2=m)
select VIDEOBUF2_VMALLOC select VIDEOBUF2_VMALLOC
select RMI4_F55
help help
Say Y here if you want to add support for RMI4 function 54 Say Y here if you want to add support for RMI4 function 54
Function 54 provides access to various diagnostic features in certain Function 54 provides access to various diagnostic features in certain
RMI4 touch sensors. 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.
...@@ -4,11 +4,15 @@ rmi_core-y := rmi_bus.o rmi_driver.o rmi_f01.o ...@@ -4,11 +4,15 @@ rmi_core-y := rmi_bus.o rmi_driver.o rmi_f01.o
rmi_core-$(CONFIG_RMI4_2D_SENSOR) += rmi_2d_sensor.o rmi_core-$(CONFIG_RMI4_2D_SENSOR) += rmi_2d_sensor.o
# Function drivers # Function drivers
rmi_core-$(CONFIG_RMI4_F03) += rmi_f03.o
rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o
rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o
rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.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_F54) += rmi_f54.o
rmi_core-$(CONFIG_RMI4_F55) += rmi_f55.o
# Transports # Transports
obj-$(CONFIG_RMI4_I2C) += rmi_i2c.o obj-$(CONFIG_RMI4_I2C) += rmi_i2c.o
obj-$(CONFIG_RMI4_SPI) += rmi_spi.o obj-$(CONFIG_RMI4_SPI) += rmi_spi.o
obj-$(CONFIG_RMI4_SMB) += rmi_smbus.o
...@@ -177,10 +177,12 @@ static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor) ...@@ -177,10 +177,12 @@ static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor)
sensor->dmax = DMAX * res_x; sensor->dmax = DMAX * res_x;
} }
input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 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_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_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_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) if (sensor->sensor_type == rmi_sensor_touchpad)
input_flags = INPUT_MT_POINTER; input_flags = INPUT_MT_POINTER;
......
...@@ -67,6 +67,8 @@ struct rmi_2d_sensor { ...@@ -67,6 +67,8 @@ struct rmi_2d_sensor {
u8 report_rel; u8 report_rel;
u8 x_mm; u8 x_mm;
u8 y_mm; u8 y_mm;
enum rmi_reg_state dribble;
enum rmi_reg_state palm_detect;
}; };
int rmi_2d_sensor_of_probe(struct device *dev, int rmi_2d_sensor_of_probe(struct device *dev,
......
...@@ -230,6 +230,9 @@ int rmi_register_function(struct rmi_function *fn) ...@@ -230,6 +230,9 @@ int rmi_register_function(struct rmi_function *fn)
void rmi_unregister_function(struct rmi_function *fn) 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); device_del(&fn->dev);
of_node_put(fn->dev.of_node); of_node_put(fn->dev.of_node);
put_device(&fn->dev); put_device(&fn->dev);
...@@ -302,6 +305,9 @@ struct bus_type rmi_bus_type = { ...@@ -302,6 +305,9 @@ struct bus_type rmi_bus_type = {
static struct rmi_function_handler *fn_handlers[] = { static struct rmi_function_handler *fn_handlers[] = {
&rmi_f01_handler, &rmi_f01_handler,
#ifdef CONFIG_RMI4_F03
&rmi_f03_handler,
#endif
#ifdef CONFIG_RMI4_F11 #ifdef CONFIG_RMI4_F11
&rmi_f11_handler, &rmi_f11_handler,
#endif #endif
...@@ -311,9 +317,15 @@ static struct rmi_function_handler *fn_handlers[] = { ...@@ -311,9 +317,15 @@ static struct rmi_function_handler *fn_handlers[] = {
#ifdef CONFIG_RMI4_F30 #ifdef CONFIG_RMI4_F30
&rmi_f30_handler, &rmi_f30_handler,
#endif #endif
#ifdef CONFIG_RMI4_F34
&rmi_f34_handler,
#endif
#ifdef CONFIG_RMI4_F54 #ifdef CONFIG_RMI4_F54
&rmi_f54_handler, &rmi_f54_handler,
#endif #endif
#ifdef CONFIG_RMI4_F55
&rmi_f55_handler,
#endif
}; };
static void __rmi_unregister_function_handlers(int start_idx) static void __rmi_unregister_function_handlers(int start_idx)
......
...@@ -104,6 +104,18 @@ rmi_get_platform_data(struct rmi_device *d) ...@@ -104,6 +104,18 @@ rmi_get_platform_data(struct rmi_device *d)
bool rmi_is_physical_device(struct device *dev); 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 * rmi_read - read a single byte
* @d: Pointer to an RMI device * @d: Pointer to an RMI device
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/bitmap.h> #include <linux/bitmap.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/irq.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of.h> #include <linux/of.h>
...@@ -33,12 +34,22 @@ ...@@ -33,12 +34,22 @@
#define RMI_DEVICE_RESET_CMD 0x01 #define RMI_DEVICE_RESET_CMD 0x01
#define DEFAULT_RESET_DELAY_MS 100 #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_function *fn, *tmp;
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev); 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->f01_container = NULL;
data->f34_container = NULL;
/* Doing it in the reverse order so F01 will be removed last */ /* Doing it in the reverse order so F01 will be removed last */
list_for_each_entry_safe_reverse(fn, tmp, list_for_each_entry_safe_reverse(fn, tmp,
...@@ -133,7 +144,7 @@ static void process_one_interrupt(struct rmi_driver_data *data, ...@@ -133,7 +144,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 rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
struct device *dev = &rmi_dev->dev; struct device *dev = &rmi_dev->dev;
...@@ -143,7 +154,7 @@ int rmi_process_interrupt_requests(struct rmi_device *rmi_dev) ...@@ -143,7 +154,7 @@ int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
if (!data) if (!data)
return 0; return 0;
if (!rmi_dev->xport->attn_data) { if (!data->attn_data.data) {
error = rmi_read_block(rmi_dev, error = rmi_read_block(rmi_dev,
data->f01_container->fd.data_base_addr + 1, data->f01_container->fd.data_base_addr + 1,
data->irq_status, data->num_of_irq_regs); data->irq_status, data->num_of_irq_regs);
...@@ -178,7 +189,81 @@ int rmi_process_interrupt_requests(struct rmi_device *rmi_dev) ...@@ -178,7 +189,81 @@ int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
return 0; 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) static int suspend_one_function(struct rmi_function *fn)
{ {
...@@ -248,7 +333,7 @@ static int rmi_resume_functions(struct rmi_device *rmi_dev) ...@@ -248,7 +333,7 @@ static int rmi_resume_functions(struct rmi_device *rmi_dev)
return 0; return 0;
} }
static int enable_sensor(struct rmi_device *rmi_dev) int rmi_enable_sensor(struct rmi_device *rmi_dev)
{ {
int retval = 0; int retval = 0;
...@@ -379,8 +464,8 @@ static int rmi_driver_reset_handler(struct rmi_device *rmi_dev) ...@@ -379,8 +464,8 @@ static int rmi_driver_reset_handler(struct rmi_device *rmi_dev)
return 0; return 0;
} }
int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry, static int rmi_read_pdt_entry(struct rmi_device *rmi_dev,
u16 pdt_address) struct pdt_entry *entry, u16 pdt_address)
{ {
u8 buf[RMI_PDT_ENTRY_SIZE]; u8 buf[RMI_PDT_ENTRY_SIZE];
int error; int error;
...@@ -403,7 +488,6 @@ int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry, ...@@ -403,7 +488,6 @@ int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(rmi_read_pdt_entry);
static void rmi_driver_copy_pdt_to_fd(const struct pdt_entry *pdt, static void rmi_driver_copy_pdt_to_fd(const struct pdt_entry *pdt,
struct rmi_function_descriptor *fd) struct rmi_function_descriptor *fd)
...@@ -422,6 +506,7 @@ static void rmi_driver_copy_pdt_to_fd(const struct pdt_entry *pdt, ...@@ -422,6 +506,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, static int rmi_scan_pdt_page(struct rmi_device *rmi_dev,
int page, int page,
int *empty_pages,
void *ctx, void *ctx,
int (*callback)(struct rmi_device *rmi_dev, int (*callback)(struct rmi_device *rmi_dev,
void *ctx, void *ctx,
...@@ -449,20 +534,30 @@ static int rmi_scan_pdt_page(struct rmi_device *rmi_dev, ...@@ -449,20 +534,30 @@ static int rmi_scan_pdt_page(struct rmi_device *rmi_dev,
return retval; 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; RMI_SCAN_DONE : RMI_SCAN_CONTINUE;
} }
static int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx, int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
int (*callback)(struct rmi_device *rmi_dev, int (*callback)(struct rmi_device *rmi_dev,
void *ctx, void *ctx, const struct pdt_entry *entry))
const struct pdt_entry *entry))
{ {
int page; int page;
int empty_pages = 0;
int retval = RMI_SCAN_DONE; int retval = RMI_SCAN_DONE;
for (page = 0; page <= RMI4_MAX_PAGE; page++) { 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) if (retval != RMI_SCAN_CONTINUE)
break; break;
} }
...@@ -600,7 +695,6 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr, ...@@ -600,7 +695,6 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr,
kfree(struct_buf); kfree(struct_buf);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(rmi_read_register_desc);
const struct rmi_register_desc_item *rmi_get_register_desc_item( const struct rmi_register_desc_item *rmi_get_register_desc_item(
struct rmi_register_descriptor *rdesc, u16 reg) struct rmi_register_descriptor *rdesc, u16 reg)
...@@ -616,7 +710,6 @@ const struct rmi_register_desc_item *rmi_get_register_desc_item( ...@@ -616,7 +710,6 @@ const struct rmi_register_desc_item *rmi_get_register_desc_item(
return NULL; return NULL;
} }
EXPORT_SYMBOL_GPL(rmi_get_register_desc_item);
size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc) size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc)
{ {
...@@ -630,7 +723,6 @@ size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc) ...@@ -630,7 +723,6 @@ size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc)
} }
return size; return size;
} }
EXPORT_SYMBOL_GPL(rmi_register_desc_calc_size);
/* Compute the register offset relative to the base address */ /* Compute the register offset relative to the base address */
int rmi_register_desc_calc_reg_offset( int rmi_register_desc_calc_reg_offset(
...@@ -648,7 +740,6 @@ int rmi_register_desc_calc_reg_offset( ...@@ -648,7 +740,6 @@ int rmi_register_desc_calc_reg_offset(
} }
return -1; return -1;
} }
EXPORT_SYMBOL_GPL(rmi_register_desc_calc_reg_offset);
bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item, bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
u8 subpacket) u8 subpacket)
...@@ -657,51 +748,55 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item, ...@@ -657,51 +748,55 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
subpacket) == subpacket; 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, static int rmi_check_bootloader_mode(struct rmi_device *rmi_dev,
const struct pdt_entry *pdt) const struct pdt_entry *pdt)
{ {
int error; struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
u8 device_status; int ret;
u8 status;
error = rmi_read(rmi_dev, pdt->data_base_addr + pdt->page_start, if (pdt->function_number == 0x34 && pdt->function_version > 1) {
&device_status); ret = rmi_read(rmi_dev, pdt->data_base_addr, &status);
if (error) { if (ret) {
dev_err(&rmi_dev->dev, dev_err(&rmi_dev->dev,
"Failed to read device status: %d.\n", error); "Failed to read F34 status: %d.\n", ret);
return error; 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, static int rmi_count_irqs(struct rmi_device *rmi_dev,
void *ctx, const struct pdt_entry *pdt) void *ctx, const struct pdt_entry *pdt)
{ {
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
int *irq_count = ctx; int *irq_count = ctx;
int ret;
*irq_count += pdt->interrupt_source_count; *irq_count += pdt->interrupt_source_count;
if (pdt->function_number == 0x01) {
data->f01_bootloader_mode = ret = rmi_check_bootloader_mode(rmi_dev, pdt);
rmi_check_bootloader_mode(rmi_dev, pdt); if (ret < 0)
if (data->f01_bootloader_mode) return ret;
dev_warn(&rmi_dev->dev,
"WARNING: RMI4 device is in bootloader mode!\n");
}
return RMI_SCAN_CONTINUE; return RMI_SCAN_CONTINUE;
} }
static int rmi_initial_reset(struct rmi_device *rmi_dev, int rmi_initial_reset(struct rmi_device *rmi_dev, void *ctx,
void *ctx, const struct pdt_entry *pdt) const struct pdt_entry *pdt)
{ {
int error; int error;
...@@ -720,6 +815,7 @@ static int rmi_initial_reset(struct rmi_device *rmi_dev, ...@@ -720,6 +815,7 @@ static int rmi_initial_reset(struct rmi_device *rmi_dev,
return RMI_SCAN_DONE; 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); error = rmi_write_block(rmi_dev, cmd_addr, &cmd_buf, 1);
if (error) { if (error) {
dev_err(&rmi_dev->dev, dev_err(&rmi_dev->dev,
...@@ -776,6 +872,8 @@ static int rmi_create_function(struct rmi_device *rmi_dev, ...@@ -776,6 +872,8 @@ static int rmi_create_function(struct rmi_device *rmi_dev,
if (pdt->function_number == 0x01) if (pdt->function_number == 0x01)
data->f01_container = fn; data->f01_container = fn;
else if (pdt->function_number == 0x34)
data->f34_container = fn;
list_add_tail(&fn->node, &data->function_list); list_add_tail(&fn->node, &data->function_list);
...@@ -786,23 +884,95 @@ static int rmi_create_function(struct rmi_device *rmi_dev, ...@@ -786,23 +884,95 @@ static int rmi_create_function(struct rmi_device *rmi_dev,
return error; 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); retval = rmi_suspend_functions(rmi_dev);
if (retval) if (retval)
dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n", dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
retval); retval);
rmi_disable_irq(rmi_dev, enable_wake);
return retval; return retval;
} }
EXPORT_SYMBOL_GPL(rmi_driver_suspend); 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; int retval;
rmi_enable_irq(rmi_dev, clear_wake);
retval = rmi_resume_functions(rmi_dev); retval = rmi_resume_functions(rmi_dev);
if (retval) if (retval)
dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n", dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
...@@ -816,6 +986,9 @@ static int rmi_driver_remove(struct device *dev) ...@@ -816,6 +986,9 @@ static int rmi_driver_remove(struct device *dev)
{ {
struct rmi_device *rmi_dev = to_rmi_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); rmi_free_function_list(rmi_dev);
return 0; return 0;
...@@ -842,15 +1015,95 @@ static inline int rmi_driver_of_probe(struct device *dev, ...@@ -842,15 +1015,95 @@ static inline int rmi_driver_of_probe(struct device *dev,
} }
#endif #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) static int rmi_driver_probe(struct device *dev)
{ {
struct rmi_driver *rmi_driver; struct rmi_driver *rmi_driver;
struct rmi_driver_data *data; struct rmi_driver_data *data;
struct rmi_device_platform_data *pdata; struct rmi_device_platform_data *pdata;
struct rmi_device *rmi_dev; struct rmi_device *rmi_dev;
size_t size;
void *irq_memory;
int irq_count;
int retval; int retval;
rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Starting probe.\n", rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Starting probe.\n",
...@@ -916,35 +1169,12 @@ static int rmi_driver_probe(struct device *dev) ...@@ -916,35 +1169,12 @@ static int rmi_driver_probe(struct device *dev)
PDT_PROPERTIES_LOCATION, retval); 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->irq_mutex);
mutex_init(&data->enabled_mutex);
size = BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long); retval = rmi_probe_interrupts(data);
irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL); if (retval)
if (!irq_memory) {
dev_err(dev, "Failed to allocate memory for irq masks.\n");
goto err; 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) { if (rmi_dev->xport->input) {
/* /*
...@@ -961,36 +1191,20 @@ static int rmi_driver_probe(struct device *dev) ...@@ -961,36 +1191,20 @@ static int rmi_driver_probe(struct device *dev)
dev_err(dev, "%s: Failed to allocate input device.\n", dev_err(dev, "%s: Failed to allocate input device.\n",
__func__); __func__);
retval = -ENOMEM; retval = -ENOMEM;
goto err_destroy_functions; goto err;
} }
rmi_driver_set_input_params(rmi_dev, data->input); rmi_driver_set_input_params(rmi_dev, data->input);
data->input->phys = devm_kasprintf(dev, GFP_KERNEL, data->input->phys = devm_kasprintf(dev, GFP_KERNEL,
"%s/input0", dev_name(dev)); "%s/input0", dev_name(dev));
} }
irq_count = 0; retval = rmi_init_functions(data);
rmi_dbg(RMI_DEBUG_CORE, dev, "Creating functions."); if (retval)
retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function); goto err;
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, retval = rmi_f34_create_sysfs(rmi_dev);
data->f01_container->fd.control_base_addr + 1, if (retval)
data->current_irq_mask, data->num_of_irq_regs); goto err;
if (retval < 0) {
dev_err(dev, "%s: Failed to read current IRQ mask.\n",
__func__);
goto err_destroy_functions;
}
if (data->input) { if (data->input) {
rmi_driver_set_input_name(rmi_dev, data->input); rmi_driver_set_input_name(rmi_dev, data->input);
...@@ -1003,9 +1217,13 @@ static int rmi_driver_probe(struct device *dev) ...@@ -1003,9 +1217,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) if (data->f01_container->dev.driver)
/* Driver already bound, so enable ATTN now. */ /* Driver already bound, so enable ATTN now. */
return enable_sensor(rmi_dev); return rmi_enable_sensor(rmi_dev);
return 0; return 0;
......
...@@ -51,9 +51,6 @@ struct pdt_entry { ...@@ -51,9 +51,6 @@ struct pdt_entry {
u8 function_number; 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_PRESENSE_BITS (32 * BITS_PER_BYTE)
#define RMI_REG_DESC_SUBPACKET_BITS (37 * BITS_PER_BYTE) #define RMI_REG_DESC_SUBPACKET_BITS (37 * BITS_PER_BYTE)
...@@ -95,12 +92,40 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item, ...@@ -95,12 +92,40 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
bool rmi_is_physical_driver(struct device_driver *); bool rmi_is_physical_driver(struct device_driver *);
int rmi_register_physical_driver(void); int rmi_register_physical_driver(void);
void rmi_unregister_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); 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_f01_handler;
extern struct rmi_function_handler rmi_f03_handler;
extern struct rmi_function_handler rmi_f11_handler; extern struct rmi_function_handler rmi_f11_handler;
extern struct rmi_function_handler rmi_f12_handler; extern struct rmi_function_handler rmi_f12_handler;
extern struct rmi_function_handler rmi_f30_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_f54_handler;
extern struct rmi_function_handler rmi_f55_handler;
#endif #endif
...@@ -62,6 +62,8 @@ struct f01_basic_properties { ...@@ -62,6 +62,8 @@ struct f01_basic_properties {
#define RMI_F01_STATUS_CODE(status) ((status) & 0x0f) #define RMI_F01_STATUS_CODE(status) ((status) & 0x0f)
/* The device has lost its configuration for some reason. */ /* The device has lost its configuration for some reason. */
#define RMI_F01_STATUS_UNCONFIGURED(status) (!!((status) & 0x80)) #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 */ /* Control register bits */
...@@ -326,12 +328,12 @@ static int rmi_f01_probe(struct rmi_function *fn) ...@@ -326,12 +328,12 @@ static int rmi_f01_probe(struct rmi_function *fn)
} }
switch (pdata->power_management.nosleep) { switch (pdata->power_management.nosleep) {
case RMI_F01_NOSLEEP_DEFAULT: case RMI_REG_STATE_DEFAULT:
break; break;
case RMI_F01_NOSLEEP_OFF: case RMI_REG_STATE_OFF:
f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_NOSLEEP_BIT; f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_NOSLEEP_BIT;
break; break;
case RMI_F01_NOSLEEP_ON: case RMI_REG_STATE_ON:
f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT; f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT;
break; break;
} }
...@@ -593,6 +595,10 @@ static int rmi_f01_attention(struct rmi_function *fn, ...@@ -593,6 +595,10 @@ static int rmi_f01_attention(struct rmi_function *fn,
return error; 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)) { if (RMI_F01_STATUS_UNCONFIGURED(device_status)) {
dev_warn(&fn->dev, "Device reset detected.\n"); dev_warn(&fn->dev, "Device reset detected.\n");
error = rmi_dev->driver->reset_handler(rmi_dev); error = rmi_dev->driver->reset_handler(rmi_dev);
......
/*
* 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");
...@@ -571,31 +571,48 @@ static inline u8 rmi_f11_parse_finger_state(const u8 *f_state, u8 n_finger) ...@@ -571,31 +571,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, static void rmi_f11_finger_handler(struct f11_data *f11,
struct rmi_2d_sensor *sensor, 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; const u8 *f_state = f11->data.f_state;
u8 finger_state; u8 finger_state;
u8 i; 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, int abs_bits = bitmap_and(f11->result_bits, irq_bits, f11->abs_mask,
num_irq_regs * 8); num_irq_regs * 8);
int rel_bits = bitmap_and(f11->result_bits, irq_bits, f11->rel_mask, int rel_bits = bitmap_and(f11->result_bits, irq_bits, f11->rel_mask,
num_irq_regs * 8); num_irq_regs * 8);
for (i = 0; i < sensor->nbr_fingers; i++) { if (abs_bits) {
/* Possible of having 4 fingers per f_statet register */ if (abs_size > size)
finger_state = rmi_f11_parse_finger_state(f_state, i); abs_fingers = size / RMI_F11_ABS_BYTES;
if (finger_state == F11_RESERVED) { else
pr_err("Invalid finger state[%d]: 0x%02x", i, abs_fingers = sensor->nbr_fingers;
finger_state);
continue; 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], rmi_f11_abs_pos_process(f11, sensor, &sensor->objs[i],
finger_state, 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); rmi_f11_rel_pos_report(f11, i);
} }
...@@ -611,7 +628,7 @@ static void rmi_f11_finger_handler(struct f11_data *f11, ...@@ -611,7 +628,7 @@ static void rmi_f11_finger_handler(struct f11_data *f11,
sensor->nbr_fingers, sensor->nbr_fingers,
sensor->dmax); 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); finger_state = rmi_f11_parse_finger_state(f_state, i);
if (finger_state == F11_RESERVED) if (finger_state == F11_RESERVED)
/* no need to send twice the error */ /* no need to send twice the error */
...@@ -1062,8 +1079,8 @@ static int rmi_f11_initialize(struct rmi_function *fn) ...@@ -1062,8 +1079,8 @@ static int rmi_f11_initialize(struct rmi_function *fn)
rc = rmi_2d_sensor_of_probe(&fn->dev, &f11->sensor_pdata); rc = rmi_2d_sensor_of_probe(&fn->dev, &f11->sensor_pdata);
if (rc) if (rc)
return rc; return rc;
} else if (pdata->sensor_pdata) { } else {
f11->sensor_pdata = *pdata->sensor_pdata; f11->sensor_pdata = pdata->sensor_pdata;
} }
f11->rezero_wait_ms = f11->sensor_pdata.rezero_wait; f11->rezero_wait_ms = f11->sensor_pdata.rezero_wait;
...@@ -1124,6 +1141,8 @@ static int rmi_f11_initialize(struct rmi_function *fn) ...@@ -1124,6 +1141,8 @@ static int rmi_f11_initialize(struct rmi_function *fn)
sensor->topbuttonpad = f11->sensor_pdata.topbuttonpad; sensor->topbuttonpad = f11->sensor_pdata.topbuttonpad;
sensor->kernel_tracking = f11->sensor_pdata.kernel_tracking; sensor->kernel_tracking = f11->sensor_pdata.kernel_tracking;
sensor->dmax = f11->sensor_pdata.dmax; 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) { if (f11->sens_query.has_physical_props) {
sensor->x_mm = f11->sens_query.x_sensor_size_mm; sensor->x_mm = f11->sens_query.x_sensor_size_mm;
...@@ -1191,11 +1210,33 @@ static int rmi_f11_initialize(struct rmi_function *fn) ...@@ -1191,11 +1210,33 @@ static int rmi_f11_initialize(struct rmi_function *fn)
ctrl->ctrl0_11[RMI_F11_DELTA_Y_THRESHOLD] = ctrl->ctrl0_11[RMI_F11_DELTA_Y_THRESHOLD] =
sensor->axis_align.delta_y_threshold; sensor->axis_align.delta_y_threshold;
if (f11->sens_query.has_dribble) if (f11->sens_query.has_dribble) {
ctrl->ctrl0_11[0] = ctrl->ctrl0_11[0] & ~BIT(6); 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) if (f11->sens_query.has_palm_det) {
ctrl->ctrl0_11[11] = ctrl->ctrl0_11[11] & ~BIT(0); 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, rc = f11_write_control_regs(fn, &f11->sens_query,
&f11->dev_controls, fn->fd.query_base_addr); &f11->dev_controls, fn->fd.query_base_addr);
...@@ -1241,12 +1282,21 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits) ...@@ -1241,12 +1282,21 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
struct f11_data *f11 = dev_get_drvdata(&fn->dev); struct f11_data *f11 = dev_get_drvdata(&fn->dev);
u16 data_base_addr = fn->fd.data_base_addr; u16 data_base_addr = fn->fd.data_base_addr;
int error; int error;
int valid_bytes = f11->sensor.pkt_size;
if (rmi_dev->xport->attn_data) { if (drvdata->attn_data.data) {
memcpy(f11->sensor.data_pkt, rmi_dev->xport->attn_data, /*
f11->sensor.attn_size); * The valid data in the attention report is less then
rmi_dev->xport->attn_data += f11->sensor.attn_size; * expected. Only process the complete fingers.
rmi_dev->xport->attn_size -= f11->sensor.attn_size; */
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 { } else {
error = rmi_read_block(rmi_dev, error = rmi_read_block(rmi_dev,
data_base_addr, f11->sensor.data_pkt, data_base_addr, f11->sensor.data_pkt,
...@@ -1256,7 +1306,7 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits) ...@@ -1256,7 +1306,7 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
} }
rmi_f11_finger_handler(f11, &f11->sensor, 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; return 0;
} }
......
...@@ -26,9 +26,12 @@ enum rmi_f12_object_type { ...@@ -26,9 +26,12 @@ enum rmi_f12_object_type {
RMI_F12_OBJECT_SMALL_OBJECT = 0x0D, RMI_F12_OBJECT_SMALL_OBJECT = 0x0D,
}; };
#define F12_DATA1_BYTES_PER_OBJ 8
struct f12_data { struct f12_data {
struct rmi_2d_sensor sensor; struct rmi_2d_sensor sensor;
struct rmi_2d_sensor_platform_data sensor_pdata; struct rmi_2d_sensor_platform_data sensor_pdata;
bool has_dribble;
u16 data_addr; u16 data_addr;
...@@ -68,10 +71,6 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) ...@@ -68,10 +71,6 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
u8 buf[15]; u8 buf[15];
int pitch_x = 0; int pitch_x = 0;
int pitch_y = 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 rx_receivers = 0;
int tx_receivers = 0; int tx_receivers = 0;
int sensor_flags = 0; int sensor_flags = 0;
...@@ -124,7 +123,9 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) ...@@ -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", 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)) { if (rmi_register_desc_has_subpacket(item, 3)) {
rx_receivers = buf[offset]; rx_receivers = buf[offset];
...@@ -146,12 +147,16 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) ...@@ -146,12 +147,16 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
return 0; 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; int i;
struct rmi_2d_sensor *sensor = &f12->sensor; 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]; struct rmi_2d_sensor_abs_object *obj = &sensor->objs[i];
obj->type = RMI_2D_OBJECT_NONE; obj->type = RMI_2D_OBJECT_NONE;
...@@ -182,7 +187,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1) ...@@ -182,7 +187,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
rmi_2d_sensor_abs_process(sensor, obj, i); rmi_2d_sensor_abs_process(sensor, obj, i);
data1 += 8; data1 += F12_DATA1_BYTES_PER_OBJ;
} }
if (sensor->kernel_tracking) if (sensor->kernel_tracking)
...@@ -192,7 +197,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1) ...@@ -192,7 +197,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
sensor->nbr_fingers, sensor->nbr_fingers,
sensor->dmax); 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); rmi_2d_sensor_abs_report(sensor, &sensor->objs[i], i);
} }
...@@ -201,14 +206,20 @@ static int rmi_f12_attention(struct rmi_function *fn, ...@@ -201,14 +206,20 @@ static int rmi_f12_attention(struct rmi_function *fn,
{ {
int retval; int retval;
struct rmi_device *rmi_dev = fn->rmi_dev; 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 f12_data *f12 = dev_get_drvdata(&fn->dev);
struct rmi_2d_sensor *sensor = &f12->sensor; struct rmi_2d_sensor *sensor = &f12->sensor;
int valid_bytes = sensor->pkt_size;
if (rmi_dev->xport->attn_data) {
memcpy(sensor->data_pkt, rmi_dev->xport->attn_data, if (drvdata->attn_data.data) {
sensor->attn_size); if (sensor->attn_size > drvdata->attn_data.size)
rmi_dev->xport->attn_data += sensor->attn_size; valid_bytes = drvdata->attn_data.size;
rmi_dev->xport->attn_size -= sensor->attn_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 { } else {
retval = rmi_read_block(rmi_dev, f12->data_addr, retval = rmi_read_block(rmi_dev, f12->data_addr,
sensor->data_pkt, sensor->pkt_size); sensor->data_pkt, sensor->pkt_size);
...@@ -221,19 +232,83 @@ static int rmi_f12_attention(struct rmi_function *fn, ...@@ -221,19 +232,83 @@ static int rmi_f12_attention(struct rmi_function *fn,
if (f12->data1) if (f12->data1)
rmi_f12_process_objects(f12, 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); input_mt_sync_frame(sensor->input);
return 0; 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) static int rmi_f12_config(struct rmi_function *fn)
{ {
struct rmi_driver *drv = fn->rmi_dev->driver; struct rmi_driver *drv = fn->rmi_dev->driver;
int ret;
drv->set_irq_bits(fn->rmi_dev, fn->irq_mask); 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; return 0;
} }
...@@ -247,7 +322,7 @@ static int rmi_f12_probe(struct rmi_function *fn) ...@@ -247,7 +322,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
const struct rmi_register_desc_item *item; const struct rmi_register_desc_item *item;
struct rmi_2d_sensor *sensor; struct rmi_2d_sensor *sensor;
struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev); 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; u16 data_offset = 0;
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s\n", __func__); rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s\n", __func__);
...@@ -260,7 +335,7 @@ static int rmi_f12_probe(struct rmi_function *fn) ...@@ -260,7 +335,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
} }
++query_addr; ++query_addr;
if (!(buf & 0x1)) { if (!(buf & BIT(0))) {
dev_err(&fn->dev, dev_err(&fn->dev,
"Behavior of F12 without register descriptors is undefined.\n"); "Behavior of F12 without register descriptors is undefined.\n");
return -ENODEV; return -ENODEV;
...@@ -270,12 +345,14 @@ static int rmi_f12_probe(struct rmi_function *fn) ...@@ -270,12 +345,14 @@ static int rmi_f12_probe(struct rmi_function *fn)
if (!f12) if (!f12)
return -ENOMEM; return -ENOMEM;
f12->has_dribble = !!(buf & BIT(3));
if (fn->dev.of_node) { if (fn->dev.of_node) {
ret = rmi_2d_sensor_of_probe(&fn->dev, &f12->sensor_pdata); ret = rmi_2d_sensor_of_probe(&fn->dev, &f12->sensor_pdata);
if (ret) if (ret)
return ret; return ret;
} else if (pdata->sensor_pdata) { } else {
f12->sensor_pdata = *pdata->sensor_pdata; f12->sensor_pdata = pdata->sensor_pdata;
} }
ret = rmi_read_register_desc(rmi_dev, query_addr, ret = rmi_read_register_desc(rmi_dev, query_addr,
...@@ -318,6 +395,7 @@ static int rmi_f12_probe(struct rmi_function *fn) ...@@ -318,6 +395,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
sensor->x_mm = f12->sensor_pdata.x_mm; sensor->x_mm = f12->sensor_pdata.x_mm;
sensor->y_mm = f12->sensor_pdata.y_mm; sensor->y_mm = f12->sensor_pdata.y_mm;
sensor->dribble = f12->sensor_pdata.dribble;
if (sensor->sensor_type == rmi_sensor_default) if (sensor->sensor_type == rmi_sensor_default)
sensor->sensor_type = sensor->sensor_type =
...@@ -343,7 +421,7 @@ static int rmi_f12_probe(struct rmi_function *fn) ...@@ -343,7 +421,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
* HID attention reports. * HID attention reports.
*/ */
item = rmi_get_register_desc_item(&f12->data_reg_desc, 0); 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; data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 1); item = rmi_get_register_desc_item(&f12->data_reg_desc, 1);
...@@ -357,15 +435,15 @@ static int rmi_f12_probe(struct rmi_function *fn) ...@@ -357,15 +435,15 @@ static int rmi_f12_probe(struct rmi_function *fn)
} }
item = rmi_get_register_desc_item(&f12->data_reg_desc, 2); 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; data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 3); 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; data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 4); 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; data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 5); item = rmi_get_register_desc_item(&f12->data_reg_desc, 5);
...@@ -377,22 +455,22 @@ static int rmi_f12_probe(struct rmi_function *fn) ...@@ -377,22 +455,22 @@ static int rmi_f12_probe(struct rmi_function *fn)
} }
item = rmi_get_register_desc_item(&f12->data_reg_desc, 6); 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 = item;
f12->data6_offset = data_offset; f12->data6_offset = data_offset;
data_offset += item->reg_size; data_offset += item->reg_size;
} }
item = rmi_get_register_desc_item(&f12->data_reg_desc, 7); 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; data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 8); 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; data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 9); 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 = item;
f12->data9_offset = data_offset; f12->data9_offset = data_offset;
data_offset += item->reg_size; data_offset += item->reg_size;
...@@ -401,27 +479,27 @@ static int rmi_f12_probe(struct rmi_function *fn) ...@@ -401,27 +479,27 @@ static int rmi_f12_probe(struct rmi_function *fn)
} }
item = rmi_get_register_desc_item(&f12->data_reg_desc, 10); 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; data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 11); 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; data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 12); 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; data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 13); 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; data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 14); 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; data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 15); 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 = item;
f12->data15_offset = data_offset; f12->data15_offset = data_offset;
data_offset += item->reg_size; data_offset += item->reg_size;
......
...@@ -99,6 +99,7 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits) ...@@ -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 f30_data *f30 = dev_get_drvdata(&fn->dev);
struct rmi_device *rmi_dev = fn->rmi_dev; struct rmi_device *rmi_dev = fn->rmi_dev;
struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
int retval; int retval;
int gpiled = 0; int gpiled = 0;
int value = 0; int value = 0;
...@@ -109,11 +110,15 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits) ...@@ -109,11 +110,15 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
return 0; return 0;
/* Read the gpi led data. */ /* Read the gpi led data. */
if (rmi_dev->xport->attn_data) { if (drvdata->attn_data.data) {
memcpy(f30->data_regs, rmi_dev->xport->attn_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); f30->register_count);
rmi_dev->xport->attn_data += f30->register_count; drvdata->attn_data.data += f30->register_count;
rmi_dev->xport->attn_size -= f30->register_count; drvdata->attn_data.size -= f30->register_count;
} else { } else {
retval = rmi_read_block(rmi_dev, fn->fd.data_base_addr, retval = rmi_read_block(rmi_dev, fn->fd.data_base_addr,
f30->data_regs, f30->register_count); f30->data_regs, f30->register_count);
...@@ -192,7 +197,7 @@ static int rmi_f30_config(struct rmi_function *fn) ...@@ -192,7 +197,7 @@ static int rmi_f30_config(struct rmi_function *fn)
rmi_get_platform_data(fn->rmi_dev); rmi_get_platform_data(fn->rmi_dev);
int error; 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); drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
} else { } else {
/* Write Control Register values back to device */ /* Write Control Register values back to device */
...@@ -351,7 +356,7 @@ static inline int rmi_f30_initialize(struct rmi_function *fn) ...@@ -351,7 +356,7 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)
f30->gpioled_key_map = (u16 *)map_memory; f30->gpioled_key_map = (u16 *)map_memory;
pdata = rmi_get_platform_data(rmi_dev); pdata = rmi_get_platform_data(rmi_dev);
if (pdata && f30->has_gpio) { if (f30->has_gpio) {
button = BTN_LEFT; button = BTN_LEFT;
for (i = 0; i < f30->gpioled_count; i++) { for (i = 0; i < f30->gpioled_count; i++) {
if (rmi_f30_is_valid_button(i, f30->ctrl)) { if (rmi_f30_is_valid_button(i, f30->ctrl)) {
...@@ -362,8 +367,7 @@ static inline int rmi_f30_initialize(struct rmi_function *fn) ...@@ -362,8 +367,7 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)
* f30->has_mech_mouse_btns, but I am * f30->has_mech_mouse_btns, but I am
* not sure, so use only the pdata info * not sure, so use only the pdata info
*/ */
if (pdata->f30_data && if (pdata->f30_data.buttonpad)
pdata->f30_data->buttonpad)
break; break;
} }
} }
...@@ -378,7 +382,7 @@ static int rmi_f30_probe(struct rmi_function *fn) ...@@ -378,7 +382,7 @@ static int rmi_f30_probe(struct rmi_function *fn)
const struct rmi_device_platform_data *pdata = const struct rmi_device_platform_data *pdata =
rmi_get_platform_data(fn->rmi_dev); rmi_get_platform_data(fn->rmi_dev);
if (pdata->f30_data && pdata->f30_data->disable) if (pdata->f30_data.disable)
return 0; return 0;
rc = rmi_f30_initialize(fn); rc = rmi_f30_initialize(fn);
......
/*
* 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,
};
/*
* 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 */
/*
* 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;
}
...@@ -200,7 +200,7 @@ static int rmi_f54_request_report(struct rmi_function *fn, u8 report_type) ...@@ -200,7 +200,7 @@ static int rmi_f54_request_report(struct rmi_function *fn, u8 report_type)
error = rmi_write(rmi_dev, fn->fd.command_base_addr, F54_GET_REPORT); error = rmi_write(rmi_dev, fn->fd.command_base_addr, F54_GET_REPORT);
if (error < 0) if (error < 0)
return error; goto unlock;
init_completion(&f54->cmd_done); init_completion(&f54->cmd_done);
...@@ -209,15 +209,18 @@ static int rmi_f54_request_report(struct rmi_function *fn, u8 report_type) ...@@ -209,15 +209,18 @@ static int rmi_f54_request_report(struct rmi_function *fn, u8 report_type)
queue_delayed_work(f54->workqueue, &f54->work, 0); queue_delayed_work(f54->workqueue, &f54->work, 0);
unlock:
mutex_unlock(&f54->data_mutex); mutex_unlock(&f54->data_mutex);
return 0; return error;
} }
static size_t rmi_f54_get_report_size(struct f54_data *f54) static size_t rmi_f54_get_report_size(struct f54_data *f54)
{ {
u8 rx = f54->num_rx_electrodes ? : f54->num_rx_electrodes; struct rmi_device *rmi_dev = f54->fn->rmi_dev;
u8 tx = f54->num_tx_electrodes ? : f54->num_tx_electrodes; 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; size_t size;
switch (rmi_f54_get_reptype(f54, f54->input)) { switch (rmi_f54_get_reptype(f54, f54->input)) {
...@@ -401,6 +404,10 @@ static int rmi_f54_vidioc_enum_input(struct file *file, void *priv, ...@@ -401,6 +404,10 @@ static int rmi_f54_vidioc_enum_input(struct file *file, void *priv,
static int rmi_f54_set_input(struct f54_data *f54, unsigned int i) 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; struct v4l2_pix_format *f = &f54->format;
enum rmi_f54_report_type reptype; enum rmi_f54_report_type reptype;
int ret; int ret;
...@@ -415,8 +422,8 @@ static int rmi_f54_set_input(struct f54_data *f54, unsigned int i) ...@@ -415,8 +422,8 @@ static int rmi_f54_set_input(struct f54_data *f54, unsigned int i)
f54->input = i; f54->input = i;
f->width = f54->num_rx_electrodes; f->width = rx;
f->height = f54->num_tx_electrodes; f->height = tx;
f->field = V4L2_FIELD_NONE; f->field = V4L2_FIELD_NONE;
f->colorspace = V4L2_COLORSPACE_RAW; f->colorspace = V4L2_COLORSPACE_RAW;
f->bytesperline = f->width * sizeof(u16); f->bytesperline = f->width * sizeof(u16);
......
/*
* 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,
};
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/rmi.h> #include <linux/rmi.h>
#include <linux/irq.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
...@@ -35,8 +34,6 @@ struct rmi_i2c_xport { ...@@ -35,8 +34,6 @@ struct rmi_i2c_xport {
struct mutex page_mutex; struct mutex page_mutex;
int page; int page;
int irq;
u8 *tx_buf; u8 *tx_buf;
size_t tx_buf_size; size_t tx_buf_size;
...@@ -177,42 +174,6 @@ static const struct rmi_transport_ops rmi_i2c_ops = { ...@@ -177,42 +174,6 @@ static const struct rmi_transport_ops rmi_i2c_ops = {
.read_block = rmi_i2c_read_block, .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 #ifdef CONFIG_OF
static const struct of_device_id rmi_i2c_of_match[] = { static const struct of_device_id rmi_i2c_of_match[] = {
{ .compatible = "syna,rmi4-i2c" }, { .compatible = "syna,rmi4-i2c" },
...@@ -255,8 +216,7 @@ static int rmi_i2c_probe(struct i2c_client *client, ...@@ -255,8 +216,7 @@ static int rmi_i2c_probe(struct i2c_client *client,
if (!client->dev.of_node && client_pdata) if (!client->dev.of_node && client_pdata)
*pdata = *client_pdata; *pdata = *client_pdata;
if (client->irq > 0) pdata->irq = client->irq;
rmi_i2c->irq = client->irq;
rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n", rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n",
dev_name(&client->dev)); dev_name(&client->dev));
...@@ -321,10 +281,6 @@ static int rmi_i2c_probe(struct i2c_client *client, ...@@ -321,10 +281,6 @@ static int rmi_i2c_probe(struct i2c_client *client,
if (retval) if (retval)
return 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", dev_info(&client->dev, "registered rmi i2c driver at %#04x.\n",
client->addr); client->addr);
return 0; return 0;
...@@ -337,18 +293,10 @@ static int rmi_i2c_suspend(struct device *dev) ...@@ -337,18 +293,10 @@ static int rmi_i2c_suspend(struct device *dev)
struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client); struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
int ret; int ret;
ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev); ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev, true);
if (ret) if (ret)
dev_warn(dev, "Failed to resume device: %d\n", 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), regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
rmi_i2c->supplies); rmi_i2c->supplies);
...@@ -368,15 +316,7 @@ static int rmi_i2c_resume(struct device *dev) ...@@ -368,15 +316,7 @@ static int rmi_i2c_resume(struct device *dev)
msleep(rmi_i2c->startup_delay); msleep(rmi_i2c->startup_delay);
enable_irq(rmi_i2c->irq); ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev, true);
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);
if (ret) if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret); dev_warn(dev, "Failed to resume device: %d\n", ret);
...@@ -391,12 +331,10 @@ static int rmi_i2c_runtime_suspend(struct device *dev) ...@@ -391,12 +331,10 @@ static int rmi_i2c_runtime_suspend(struct device *dev)
struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client); struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
int ret; int ret;
ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev); ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev, false);
if (ret) if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret); dev_warn(dev, "Failed to resume device: %d\n", ret);
disable_irq(rmi_i2c->irq);
regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies), regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
rmi_i2c->supplies); rmi_i2c->supplies);
...@@ -416,9 +354,7 @@ static int rmi_i2c_runtime_resume(struct device *dev) ...@@ -416,9 +354,7 @@ static int rmi_i2c_runtime_resume(struct device *dev)
msleep(rmi_i2c->startup_delay); msleep(rmi_i2c->startup_delay);
enable_irq(rmi_i2c->irq); ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev, false);
ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev);
if (ret) if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret); dev_warn(dev, "Failed to resume device: %d\n", ret);
......
/*
* 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");
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#include <linux/rmi.h> #include <linux/rmi.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/irq.h>
#include <linux/of.h> #include <linux/of.h>
#include "rmi_driver.h" #include "rmi_driver.h"
...@@ -44,8 +43,6 @@ struct rmi_spi_xport { ...@@ -44,8 +43,6 @@ struct rmi_spi_xport {
struct mutex page_mutex; struct mutex page_mutex;
int page; int page;
int irq;
u8 *rx_buf; u8 *rx_buf;
u8 *tx_buf; u8 *tx_buf;
int xfer_buf_size; int xfer_buf_size;
...@@ -326,41 +323,6 @@ static const struct rmi_transport_ops rmi_spi_ops = { ...@@ -326,41 +323,6 @@ static const struct rmi_transport_ops rmi_spi_ops = {
.read_block = rmi_spi_read_block, .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 #ifdef CONFIG_OF
static int rmi_spi_of_probe(struct spi_device *spi, static int rmi_spi_of_probe(struct spi_device *spi,
struct rmi_device_platform_data *pdata) struct rmi_device_platform_data *pdata)
...@@ -440,8 +402,7 @@ static int rmi_spi_probe(struct spi_device *spi) ...@@ -440,8 +402,7 @@ static int rmi_spi_probe(struct spi_device *spi)
return retval; return retval;
} }
if (spi->irq > 0) pdata->irq = spi->irq;
rmi_spi->irq = spi->irq;
rmi_spi->spi = spi; rmi_spi->spi = spi;
mutex_init(&rmi_spi->page_mutex); mutex_init(&rmi_spi->page_mutex);
...@@ -477,10 +438,6 @@ static int rmi_spi_probe(struct spi_device *spi) ...@@ -477,10 +438,6 @@ static int rmi_spi_probe(struct spi_device *spi)
if (retval) if (retval)
return retval; return retval;
retval = rmi_spi_init_irq(spi);
if (retval < 0)
return retval;
dev_info(&spi->dev, "registered RMI SPI driver\n"); dev_info(&spi->dev, "registered RMI SPI driver\n");
return 0; return 0;
} }
...@@ -492,17 +449,10 @@ static int rmi_spi_suspend(struct device *dev) ...@@ -492,17 +449,10 @@ static int rmi_spi_suspend(struct device *dev)
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi); struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
int ret; int ret;
ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev); ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, true);
if (ret) if (ret)
dev_warn(dev, "Failed to resume device: %d\n", 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; return ret;
} }
...@@ -512,15 +462,7 @@ static int rmi_spi_resume(struct device *dev) ...@@ -512,15 +462,7 @@ static int rmi_spi_resume(struct device *dev)
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi); struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
int ret; int ret;
enable_irq(rmi_spi->irq); ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, true);
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);
if (ret) if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret); dev_warn(dev, "Failed to resume device: %d\n", ret);
...@@ -535,12 +477,10 @@ static int rmi_spi_runtime_suspend(struct device *dev) ...@@ -535,12 +477,10 @@ static int rmi_spi_runtime_suspend(struct device *dev)
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi); struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
int ret; int ret;
ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev); ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, false);
if (ret) if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret); dev_warn(dev, "Failed to resume device: %d\n", ret);
disable_irq(rmi_spi->irq);
return 0; return 0;
} }
...@@ -550,9 +490,7 @@ static int rmi_spi_runtime_resume(struct device *dev) ...@@ -550,9 +490,7 @@ static int rmi_spi_runtime_resume(struct device *dev)
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi); struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
int ret; int ret;
enable_irq(rmi_spi->irq); ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, false);
ret = rmi_driver_resume(rmi_spi->xport.rmi_dev);
if (ret) if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret); dev_warn(dev, "Failed to resume device: %d\n", ret);
......
...@@ -517,79 +517,7 @@ static const struct dmi_system_id i8042_dmi_noselftest_table[] = { ...@@ -517,79 +517,7 @@ static const struct dmi_system_id i8042_dmi_noselftest_table[] = {
{ {
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "A455LD"), DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
},
},
{
.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"),
}, },
}, },
{ } { }
...@@ -1131,10 +1059,10 @@ static int __init i8042_pnp_init(void) ...@@ -1131,10 +1059,10 @@ static int __init i8042_pnp_init(void)
return 0; return 0;
} }
#else #else /* !CONFIG_PNP */
static inline int i8042_pnp_init(void) { return 0; } static inline int i8042_pnp_init(void) { return 0; }
static inline void i8042_pnp_exit(void) { } static inline void i8042_pnp_exit(void) { }
#endif #endif /* CONFIG_PNP */
static int __init i8042_platform_init(void) static int __init i8042_platform_init(void)
{ {
......
...@@ -387,7 +387,7 @@ static int i8042_aux_write(struct serio *serio, unsigned char 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. * and then re-enabling it.
*/ */
......
...@@ -55,6 +55,7 @@ static const struct of_device_id mx25_tcq_ids[] = { ...@@ -55,6 +55,7 @@ static const struct of_device_id mx25_tcq_ids[] = {
{ .compatible = "fsl,imx25-tcq", }, { .compatible = "fsl,imx25-tcq", },
{ /* Sentinel */ } { /* Sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, mx25_tcq_ids);
#define TSC_4WIRE_PRE_INDEX 0 #define TSC_4WIRE_PRE_INDEX 0
#define TSC_4WIRE_X_INDEX 1 #define TSC_4WIRE_X_INDEX 1
......
...@@ -21,17 +21,25 @@ ...@@ -21,17 +21,25 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/log2.h>
/* ADC configuration registers field define */ /* ADC configuration registers field define */
#define ADC_AIEN (0x1 << 7) #define ADC_AIEN (0x1 << 7)
#define ADC_CONV_DISABLE 0x1F #define ADC_CONV_DISABLE 0x1F
#define ADC_AVGE (0x1 << 5)
#define ADC_CAL (0x1 << 7) #define ADC_CAL (0x1 << 7)
#define ADC_CALF 0x2 #define ADC_CALF 0x2
#define ADC_12BIT_MODE (0x2 << 2) #define ADC_12BIT_MODE (0x2 << 2)
#define ADC_CONV_MODE_MASK (0x3 << 2)
#define ADC_IPG_CLK 0x00 #define ADC_IPG_CLK 0x00
#define ADC_INPUT_CLK_MASK 0x3
#define ADC_CLK_DIV_8 (0x03 << 5) #define ADC_CLK_DIV_8 (0x03 << 5)
#define ADC_CLK_DIV_MASK (0x3 << 5)
#define ADC_SHORT_SAMPLE_MODE (0x0 << 4) #define ADC_SHORT_SAMPLE_MODE (0x0 << 4)
#define ADC_SAMPLE_MODE_MASK (0x1 << 4)
#define ADC_HARDWARE_TRIGGER (0x1 << 13) #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_4 0x04
#define SELECT_CHANNEL_1 0x01 #define SELECT_CHANNEL_1 0x01
#define DISABLE_CONVERSION_INT (0x0 << 7) #define DISABLE_CONVERSION_INT (0x0 << 7)
...@@ -84,8 +92,10 @@ struct imx6ul_tsc { ...@@ -84,8 +92,10 @@ struct imx6ul_tsc {
struct clk *adc_clk; struct clk *adc_clk;
struct gpio_desc *xnur_gpio; struct gpio_desc *xnur_gpio;
int measure_delay_time; u32 measure_delay_time;
int pre_charge_time; u32 pre_charge_time;
bool average_enable;
u32 average_select;
struct completion completion; struct completion completion;
}; };
...@@ -96,17 +106,23 @@ struct imx6ul_tsc { ...@@ -96,17 +106,23 @@ struct imx6ul_tsc {
*/ */
static int imx6ul_adc_init(struct imx6ul_tsc *tsc) static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
{ {
int adc_hc = 0; u32 adc_hc = 0;
int adc_gc; u32 adc_gc;
int adc_gs; u32 adc_gs;
int adc_cfg; u32 adc_cfg;
int timeout; unsigned long timeout;
reinit_completion(&tsc->completion); reinit_completion(&tsc->completion);
adc_cfg = readl(tsc->adc_regs + REG_ADC_CFG); 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_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; 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; adc_cfg &= ~ADC_HARDWARE_TRIGGER;
writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG); writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG);
...@@ -118,6 +134,8 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc) ...@@ -118,6 +134,8 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
/* start ADC calibration */ /* start ADC calibration */
adc_gc = readl(tsc->adc_regs + REG_ADC_GC); adc_gc = readl(tsc->adc_regs + REG_ADC_GC);
adc_gc |= ADC_CAL; adc_gc |= ADC_CAL;
if (tsc->average_enable)
adc_gc |= ADC_AVGE;
writel(adc_gc, tsc->adc_regs + REG_ADC_GC); writel(adc_gc, tsc->adc_regs + REG_ADC_GC);
timeout = wait_for_completion_timeout timeout = wait_for_completion_timeout
...@@ -148,7 +166,7 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc) ...@@ -148,7 +166,7 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
*/ */
static void imx6ul_tsc_channel_config(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; adc_hc0 = DISABLE_CONVERSION_INT;
writel(adc_hc0, tsc->adc_regs + REG_ADC_HC0); writel(adc_hc0, tsc->adc_regs + REG_ADC_HC0);
...@@ -173,8 +191,8 @@ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc) ...@@ -173,8 +191,8 @@ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc)
*/ */
static void imx6ul_tsc_set(struct imx6ul_tsc *tsc) static void imx6ul_tsc_set(struct imx6ul_tsc *tsc)
{ {
int basic_setting = 0; u32 basic_setting = 0;
int start; u32 start;
basic_setting |= tsc->measure_delay_time << 8; basic_setting |= tsc->measure_delay_time << 8;
basic_setting |= DETECT_4_WIRE_MODE | AUTO_MEASURE; basic_setting |= DETECT_4_WIRE_MODE | AUTO_MEASURE;
...@@ -209,8 +227,8 @@ static int imx6ul_tsc_init(struct imx6ul_tsc *tsc) ...@@ -209,8 +227,8 @@ static int imx6ul_tsc_init(struct imx6ul_tsc *tsc)
static void imx6ul_tsc_disable(struct imx6ul_tsc *tsc) static void imx6ul_tsc_disable(struct imx6ul_tsc *tsc)
{ {
int tsc_flow; u32 tsc_flow;
int adc_cfg; u32 adc_cfg;
/* TSC controller enters to idle status */ /* TSC controller enters to idle status */
tsc_flow = readl(tsc->tsc_regs + REG_TSC_FLOW_CONTROL); tsc_flow = readl(tsc->tsc_regs + REG_TSC_FLOW_CONTROL);
...@@ -227,8 +245,8 @@ static void imx6ul_tsc_disable(struct imx6ul_tsc *tsc) ...@@ -227,8 +245,8 @@ static void imx6ul_tsc_disable(struct imx6ul_tsc *tsc)
static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc) static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc)
{ {
unsigned long timeout = jiffies + msecs_to_jiffies(2); unsigned long timeout = jiffies + msecs_to_jiffies(2);
int state_machine; u32 state_machine;
int debug_mode2; u32 debug_mode2;
do { do {
if (time_after(jiffies, timeout)) if (time_after(jiffies, timeout))
...@@ -246,10 +264,10 @@ static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc) ...@@ -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) static irqreturn_t tsc_irq_fn(int irq, void *dev_id)
{ {
struct imx6ul_tsc *tsc = dev_id; struct imx6ul_tsc *tsc = dev_id;
int status; u32 status;
int value; u32 value;
int x, y; u32 x, y;
int start; u32 start;
status = readl(tsc->tsc_regs + REG_TSC_INT_STATUS); status = readl(tsc->tsc_regs + REG_TSC_INT_STATUS);
...@@ -289,8 +307,8 @@ static irqreturn_t tsc_irq_fn(int irq, void *dev_id) ...@@ -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) static irqreturn_t adc_irq_fn(int irq, void *dev_id)
{ {
struct imx6ul_tsc *tsc = dev_id; struct imx6ul_tsc *tsc = dev_id;
int coco; u32 coco;
int value; u32 value;
coco = readl(tsc->adc_regs + REG_ADC_HS); coco = readl(tsc->adc_regs + REG_ADC_HS);
if (coco & 0x01) { if (coco & 0x01) {
...@@ -346,6 +364,7 @@ static int imx6ul_tsc_probe(struct platform_device *pdev) ...@@ -346,6 +364,7 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
int err; int err;
int tsc_irq; int tsc_irq;
int adc_irq; int adc_irq;
u32 average_samples;
tsc = devm_kzalloc(&pdev->dev, sizeof(*tsc), GFP_KERNEL); tsc = devm_kzalloc(&pdev->dev, sizeof(*tsc), GFP_KERNEL);
if (!tsc) if (!tsc)
...@@ -450,6 +469,30 @@ static int imx6ul_tsc_probe(struct platform_device *pdev) ...@@ -450,6 +469,30 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
if (err) if (err)
tsc->pre_charge_time = 0xfff; 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); err = input_register_device(tsc->input);
if (err) { if (err) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
/***************************************************************** /*****************************************************************
* Protocol * Protocol
* Version : MIP 4.0 Rev 4.6 * Version : MIP 4.0 Rev 5.4
*****************************************************************/ *****************************************************************/
/* Address */ /* Address */
...@@ -81,6 +81,9 @@ ...@@ -81,6 +81,9 @@
#define MIP4_R1_INFO_IC_HW_CATEGORY 0x77 #define MIP4_R1_INFO_IC_HW_CATEGORY 0x77
#define MIP4_R1_INFO_CONTACT_THD_SCR 0x78 #define MIP4_R1_INFO_CONTACT_THD_SCR 0x78
#define MIP4_R1_INFO_CONTACT_THD_KEY 0x7A #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_R0_EVENT 0x02
#define MIP4_R1_EVENT_SUPPORTED_FUNC 0x00 #define MIP4_R1_EVENT_SUPPORTED_FUNC 0x00
...@@ -157,7 +160,9 @@ struct mip4_ts { ...@@ -157,7 +160,9 @@ struct mip4_ts {
char phys[32]; char phys[32];
char product_name[16]; char product_name[16];
u16 product_id;
char ic_name[4]; char ic_name[4];
char fw_name[32];
unsigned int max_x; unsigned int max_x;
unsigned int max_y; unsigned int max_y;
...@@ -264,6 +269,23 @@ static int mip4_query_device(struct mip4_ts *ts) ...@@ -264,6 +269,23 @@ static int mip4_query_device(struct mip4_ts *ts)
dev_dbg(&ts->client->dev, "product name: %.*s\n", dev_dbg(&ts->client->dev, "product name: %.*s\n",
(int)sizeof(ts->product_name), ts->product_name); (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 */ /* IC name */
cmd[0] = MIP4_R0_INFO; cmd[0] = MIP4_R0_INFO;
cmd[1] = MIP4_R1_INFO_IC_NAME; cmd[1] = MIP4_R1_INFO_IC_NAME;
...@@ -1269,11 +1291,11 @@ static ssize_t mip4_sysfs_fw_update(struct device *dev, ...@@ -1269,11 +1291,11 @@ static ssize_t mip4_sysfs_fw_update(struct device *dev,
const struct firmware *fw; const struct firmware *fw;
int error; int error;
error = request_firmware(&fw, MIP4_FW_NAME, dev); error = request_firmware(&fw, ts->fw_name, dev);
if (error) { if (error) {
dev_err(&ts->client->dev, dev_err(&ts->client->dev,
"Failed to retrieve firmware %s: %d\n", "Failed to retrieve firmware %s: %d\n",
MIP4_FW_NAME, error); ts->fw_name, error);
return error; return error;
} }
...@@ -1348,6 +1370,25 @@ static ssize_t mip4_sysfs_read_hw_version(struct device *dev, ...@@ -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 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, static ssize_t mip4_sysfs_read_ic_name(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
...@@ -1371,6 +1412,7 @@ static DEVICE_ATTR(ic_name, S_IRUGO, mip4_sysfs_read_ic_name, NULL); ...@@ -1371,6 +1412,7 @@ static DEVICE_ATTR(ic_name, S_IRUGO, mip4_sysfs_read_ic_name, NULL);
static struct attribute *mip4_attrs[] = { static struct attribute *mip4_attrs[] = {
&dev_attr_fw_version.attr, &dev_attr_fw_version.attr,
&dev_attr_hw_version.attr, &dev_attr_hw_version.attr,
&dev_attr_product_id.attr,
&dev_attr_ic_name.attr, &dev_attr_ic_name.attr,
&dev_attr_update_fw.attr, &dev_attr_update_fw.attr,
NULL, NULL,
...@@ -1435,6 +1477,7 @@ static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -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.bustype = BUS_I2C;
input->id.vendor = 0x13c5; input->id.vendor = 0x13c5;
input->id.product = ts->product_id;
input->open = mip4_input_open; input->open = mip4_input_open;
input->close = mip4_input_close; input->close = mip4_input_close;
...@@ -1572,6 +1615,6 @@ static struct i2c_driver mip4_driver = { ...@@ -1572,6 +1615,6 @@ static struct i2c_driver mip4_driver = {
module_i2c_driver(mip4_driver); module_i2c_driver(mip4_driver);
MODULE_DESCRIPTION("MELFAS MIP4 Touchscreen"); MODULE_DESCRIPTION("MELFAS MIP4 Touchscreen");
MODULE_VERSION("2016.09.28"); MODULE_VERSION("2016.10.31");
MODULE_AUTHOR("Sangwon Jee <jeesw@melfas.com>"); MODULE_AUTHOR("Sangwon Jee <jeesw@melfas.com>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -669,7 +669,7 @@ static int raydium_i2c_do_update_firmware(struct raydium_data *ts, ...@@ -669,7 +669,7 @@ static int raydium_i2c_do_update_firmware(struct raydium_data *ts,
if (ts->boot_mode == RAYDIUM_TS_MAIN) { if (ts->boot_mode == RAYDIUM_TS_MAIN) {
dev_err(&client->dev, dev_err(&client->dev,
"failied to jump to boot loader: %d\n", "failed to jump to boot loader: %d\n",
error); error);
return -EIO; return -EIO;
} }
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/input/touchscreen.h> #include <linux/input/touchscreen.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/regulator/consumer.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
...@@ -73,6 +74,7 @@ struct silead_ts_data { ...@@ -73,6 +74,7 @@ struct silead_ts_data {
struct i2c_client *client; struct i2c_client *client;
struct gpio_desc *gpio_power; struct gpio_desc *gpio_power;
struct input_dev *input; struct input_dev *input;
struct regulator_bulk_data regulators[2];
char fw_name[64]; char fw_name[64];
struct touchscreen_properties prop; struct touchscreen_properties prop;
u32 max_fingers; u32 max_fingers;
...@@ -433,6 +435,13 @@ static int silead_ts_set_default_fw_name(struct silead_ts_data *data, ...@@ -433,6 +435,13 @@ static int silead_ts_set_default_fw_name(struct silead_ts_data *data,
} }
#endif #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, static int silead_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
...@@ -465,6 +474,26 @@ static int silead_ts_probe(struct i2c_client *client, ...@@ -465,6 +474,26 @@ static int silead_ts_probe(struct i2c_client *client,
if (client->irq <= 0) if (client->irq <= 0)
return -ENODEV; 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 */ /* Power GPIO pin */
data->gpio_power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW); data->gpio_power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
if (IS_ERR(data->gpio_power)) { if (IS_ERR(data->gpio_power)) {
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
#define _GPIO_KEYS_H #define _GPIO_KEYS_H
struct device; struct device;
struct gpio_desc;
/** /**
* struct gpio_keys_button - configuration parameters * struct gpio_keys_button - configuration parameters
...@@ -18,7 +17,6 @@ struct gpio_desc; ...@@ -18,7 +17,6 @@ struct gpio_desc;
* disable button via sysfs * disable button via sysfs
* @value: axis value for %EV_ABS * @value: axis value for %EV_ABS
* @irq: Irq number in case of interrupt keys * @irq: Irq number in case of interrupt keys
* @gpiod: GPIO descriptor
*/ */
struct gpio_keys_button { struct gpio_keys_button {
unsigned int code; unsigned int code;
...@@ -31,7 +29,6 @@ struct gpio_keys_button { ...@@ -31,7 +29,6 @@ struct gpio_keys_button {
bool can_disable; bool can_disable;
int value; int value;
unsigned int irq; unsigned int irq;
struct gpio_desc *gpiod;
}; };
/** /**
...@@ -46,7 +43,7 @@ struct gpio_keys_button { ...@@ -46,7 +43,7 @@ struct gpio_keys_button {
* @name: input device name * @name: input device name
*/ */
struct gpio_keys_platform_data { struct gpio_keys_platform_data {
struct gpio_keys_button *buttons; const struct gpio_keys_button *buttons;
int nbuttons; int nbuttons;
unsigned int poll_interval; unsigned int poll_interval;
unsigned int rep:1; unsigned int rep:1;
......
/*
* Platform data for DRV260X haptics driver family
*
* Author: Dan Murphy <dmurphy@ti.com>
*
* Copyright: (C) 2014 Texas Instruments, Inc.
*
* 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.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#ifndef _LINUX_DRV260X_PDATA_H
#define _LINUX_DRV260X_PDATA_H
struct drv260x_platform_data {
u32 library_selection;
u32 mode;
u32 vib_rated_voltage;
u32 vib_overdrive_voltage;
};
#endif
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/kfifo.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -99,6 +100,8 @@ struct rmi_2d_sensor_platform_data { ...@@ -99,6 +100,8 @@ struct rmi_2d_sensor_platform_data {
bool topbuttonpad; bool topbuttonpad;
bool kernel_tracking; bool kernel_tracking;
int dmax; int dmax;
int dribble;
int palm_detect;
}; };
/** /**
...@@ -106,7 +109,7 @@ struct rmi_2d_sensor_platform_data { ...@@ -106,7 +109,7 @@ struct rmi_2d_sensor_platform_data {
* @buttonpad - the touchpad is a buttonpad, so enable only the first actual * @buttonpad - the touchpad is a buttonpad, so enable only the first actual
* button that is found. * button that is found.
* @trackstick_buttons - Set when the function 30 is handling the physical * @trackstick_buttons - Set when the function 30 is handling the physical
* buttons of the trackstick (as a PD/2 passthrough device. * buttons of the trackstick (as a PS/2 passthrough device).
* @disable - the touchpad incorrectly reports F30 and it should be ignored. * @disable - the touchpad incorrectly reports F30 and it should be ignored.
* This is a special case which is due to misconfigured firmware. * This is a special case which is due to misconfigured firmware.
*/ */
...@@ -116,14 +119,17 @@ struct rmi_f30_data { ...@@ -116,14 +119,17 @@ struct rmi_f30_data {
bool disable; bool disable;
}; };
/**
* struct rmi_f01_power - override default power management settings. /*
* * Set the state of a register
* DEFAULT - use the default value set by the firmware config
* OFF - explicitly disable the register
* ON - explicitly enable the register
*/ */
enum rmi_f01_nosleep { enum rmi_reg_state {
RMI_F01_NOSLEEP_DEFAULT = 0, RMI_REG_STATE_DEFAULT = 0,
RMI_F01_NOSLEEP_OFF = 1, RMI_REG_STATE_OFF = 1,
RMI_F01_NOSLEEP_ON = 2 RMI_REG_STATE_ON = 2
}; };
/** /**
...@@ -143,7 +149,7 @@ enum rmi_f01_nosleep { ...@@ -143,7 +149,7 @@ enum rmi_f01_nosleep {
* when the touch sensor is in doze mode, in units of 10ms. * when the touch sensor is in doze mode, in units of 10ms.
*/ */
struct rmi_f01_power_management { struct rmi_f01_power_management {
enum rmi_f01_nosleep nosleep; enum rmi_reg_state nosleep;
u8 wakeup_threshold; u8 wakeup_threshold;
u8 doze_holdoff; u8 doze_holdoff;
u8 doze_interval; u8 doze_interval;
...@@ -204,16 +210,18 @@ struct rmi_device_platform_data_spi { ...@@ -204,16 +210,18 @@ struct rmi_device_platform_data_spi {
* @reset_delay_ms - after issuing a reset command to the touch sensor, the * @reset_delay_ms - after issuing a reset command to the touch sensor, the
* driver waits a few milliseconds to give the firmware a chance to * driver waits a few milliseconds to give the firmware a chance to
* to re-initialize. You can override the default wait period here. * to re-initialize. You can override the default wait period here.
* @irq: irq associated with the attn gpio line, or negative
*/ */
struct rmi_device_platform_data { struct rmi_device_platform_data {
int reset_delay_ms; int reset_delay_ms;
int irq;
struct rmi_device_platform_data_spi spi_data; struct rmi_device_platform_data_spi spi_data;
/* function handler pdata */ /* function handler pdata */
struct rmi_2d_sensor_platform_data *sensor_pdata; struct rmi_2d_sensor_platform_data sensor_pdata;
struct rmi_f01_power_management power_management; struct rmi_f01_power_management power_management;
struct rmi_f30_data *f30_data; struct rmi_f30_data f30_data;
}; };
/** /**
...@@ -264,9 +272,6 @@ struct rmi_transport_dev { ...@@ -264,9 +272,6 @@ struct rmi_transport_dev {
struct rmi_device_platform_data pdata; struct rmi_device_platform_data pdata;
struct input_dev *input; struct input_dev *input;
void *attn_data;
int attn_size;
}; };
/** /**
...@@ -324,17 +329,24 @@ struct rmi_device { ...@@ -324,17 +329,24 @@ struct rmi_device {
}; };
struct rmi4_attn_data {
unsigned long irq_status;
size_t size;
void *data;
};
struct rmi_driver_data { struct rmi_driver_data {
struct list_head function_list; struct list_head function_list;
struct rmi_device *rmi_dev; struct rmi_device *rmi_dev;
struct rmi_function *f01_container; struct rmi_function *f01_container;
bool f01_bootloader_mode; struct rmi_function *f34_container;
bool bootloader_mode;
u32 attn_count;
int num_of_irq_regs; int num_of_irq_regs;
int irq_count; int irq_count;
void *irq_memory;
unsigned long *irq_status; unsigned long *irq_status;
unsigned long *fn_irq_bits; unsigned long *fn_irq_bits;
unsigned long *current_irq_mask; unsigned long *current_irq_mask;
...@@ -343,17 +355,23 @@ struct rmi_driver_data { ...@@ -343,17 +355,23 @@ struct rmi_driver_data {
struct input_dev *input; struct input_dev *input;
u8 pdt_props; u8 pdt_props;
u8 bsr;
u8 num_rx_electrodes;
u8 num_tx_electrodes;
bool enabled; bool enabled;
struct mutex enabled_mutex;
void *data; struct rmi4_attn_data attn_data;
DECLARE_KFIFO(attn_fifo, struct rmi4_attn_data, 16);
}; };
int rmi_register_transport_device(struct rmi_transport_dev *xport); int rmi_register_transport_device(struct rmi_transport_dev *xport);
void rmi_unregister_transport_device(struct rmi_transport_dev *xport); void rmi_unregister_transport_device(struct rmi_transport_dev *xport);
int rmi_process_interrupt_requests(struct rmi_device *rmi_dev);
int rmi_driver_suspend(struct rmi_device *rmi_dev); void rmi_set_attn_data(struct rmi_device *rmi_dev, unsigned long irq_status,
int rmi_driver_resume(struct rmi_device *rmi_dev); void *data, size_t size);
int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake);
int rmi_driver_resume(struct rmi_device *rmi_dev, bool clear_wake);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment