* Re: [PATCH v3 0/8] HID: sony: More Sony controller fixes and improvements.
From: Frank Praznik @ 2014-03-27 14:27 UTC (permalink / raw)
To: open list:HID CORE LAYER
In-Reply-To: <1394890882-2039-1-git-send-email-frank.praznik@oh.rr.com>
On Sat, Mar 15, 2014 at 9:41 AM, Frank Praznik <frank.praznik@oh.rr.com> wrote:
> Just a couple of small changes in v3:
>
> Patch 6 was changed to use the controller Bluetooth MAC address as the unique
> value for the battery name string.
>
> The IDA code was moved from patch 6 to 7 since it was no longer needed in
> patch 6. It's the same otherwise.
Just a quick note since the 3.15 merge window is approaching: patches
1 and 2 are strictly bug fixes and should be merged into the 3.15 tree
even if the rest of the series has to wait until 3.16.
^ permalink raw reply
* [PATCH v2] input: misc: Add driver for Intel Bay Trail GPIO buttons
From: Zhu, Lejun @ 2014-03-27 18:02 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: One Thousand Gnomes, linux-kernel, linux-input, lejun.zhu
In-Reply-To: <53345085.6020300@linux.intel.com>
This patch adds support for the GPIO buttons on some Intel Bay Trail
tablets originally running Windows 8. The ACPI description of these
buttons follows "Windows ACPI Design Guide for SoC Platforms".
v2:
- Change the driver name to "SoC button array".
- Use platform_device_alloc() instead of static devices. Unbind then
rebind works fine now.
Signed-off-by: Lejun Zhu <lejun.zhu@linux.intel.com>
---
drivers/input/misc/Kconfig | 10 ++
drivers/input/misc/Makefile | 1 +
drivers/input/misc/soc_button_array.c | 209
++++++++++++++++++++++++++++++++++
3 files changed, 220 insertions(+)
create mode 100644 drivers/input/misc/soc_button_array.c
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 7904ab0..c1298af 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -666,4 +666,14 @@ config INPUT_IDEAPAD_SLIDEBAR
To compile this driver as a module, choose M here: the
module will be called ideapad_slidebar.
+config INPUT_SOC_BUTTON_ARRAY
+ tristate "Windows-compatible SoC Button Array"
+ depends on KEYBOARD_GPIO
+ help
+ Say Y here if you have a SoC-based tablet that originally
+ runs Windows 8.
+
+ To compile this driver as a module, choose M here: the
+ module will be called soc_button_array.
+
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index cda71fc..850a6cd 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -63,3 +63,4 @@ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o
+obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o
diff --git a/drivers/input/misc/soc_button_array.c
b/drivers/input/misc/soc_button_array.c
new file mode 100644
index 0000000..e8f19e0
--- /dev/null
+++ b/drivers/input/misc/soc_button_array.c
@@ -0,0 +1,209 @@
+/*
+ * soc_button_array.c: supports the button array on SoC tablets originally
+ * running Windows 8.
+ *
+ * (C) Copyright 2014 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/pnp.h>
+
+/*
+ * Definition of buttons on the tablet. The ACPI index of each button
+ * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
+ * Platforms"
+ */
+#define MAX_NBUTTONS 5
+
+struct soc_button_info {
+ const char *name;
+ int acpi_index;
+ unsigned int event_code;
+ int repeat;
+ int wakeup;
+ int gpio;
+};
+
+static struct soc_button_info soc_button_tbl[] = {
+ {"power", 0, KEY_POWER, 0, 1, -1},
+ {"home", 1, KEY_HOME, 0, 1, -1},
+ {"volume_up", 2, KEY_VOLUMEUP, 1, 0, -1},
+ {"volume_down", 3, KEY_VOLUMEDOWN, 1, 0, -1},
+ {"rotation_lock", 4, KEY_RO, 0, 0, -1},
+};
+
+/*
+ * Some of the buttons like volume up/down are auto repeat, while others
+ * are not. To support both, we register two platform devices, and put
+ * buttons into them based on whether the key should be auto repeat.
+ */
+#define BUTTON_TYPES 2
+
+static struct gpio_keys_button soc_buttons[BUTTON_TYPES][MAX_NBUTTONS];
+
+static struct gpio_keys_platform_data soc_button_data[BUTTON_TYPES] = {
+ {
+ .buttons = soc_buttons[0],
+ .nbuttons = 0,
+ .rep = 0
+ },
+ {
+ .buttons = soc_buttons[1],
+ .nbuttons = 0,
+ .rep = 1
+ }
+};
+
+static struct platform_device *soc_button_device[BUTTON_TYPES];
+
+/*
+ * Get the Nth GPIO number from the ACPI object.
+ */
+static int soc_button_lookup_gpio(struct device *dev, int acpi_index)
+{
+ struct gpio_desc *desc;
+ int ret;
+
+ desc = gpiod_get_index(dev, KBUILD_MODNAME, acpi_index);
+
+ if (IS_ERR(desc))
+ return -1;
+
+ ret = desc_to_gpio(desc);
+
+ gpiod_put(desc);
+
+ return ret;
+}
+
+/*
+ * Register platform device for a set of buttons.
+ */
+static int soc_button_register(int r)
+{
+ struct platform_device *pd;
+ int err;
+
+ pd = platform_device_alloc("gpio-keys", PLATFORM_DEVID_AUTO);
+ if (!pd) {
+ err = -ENOMEM;
+ goto err0;
+ }
+
+ err = platform_device_add_data(pd, &soc_button_data[r],
+ sizeof(soc_button_data[r]));
+ if (err)
+ goto err1;
+
+ err = platform_device_add(pd);
+ if (err)
+ goto err1;
+
+ soc_button_device[r] = pd;
+
+ return 0;
+
+err1:
+ platform_device_put(pd);
+err0:
+ return err;
+}
+
+static int soc_button_pnp_probe(struct pnp_dev *pdev,
+ const struct pnp_device_id *id)
+{
+ int i, j, r, ret;
+ int sz_tbl = sizeof(soc_button_tbl) / sizeof(soc_button_tbl[0]);
+ struct gpio_keys_button *gk;
+
+ /* Find GPIO number of all the buttons */
+ for (i = 0; i < sz_tbl; i++) {
+ soc_button_tbl[i].gpio = soc_button_lookup_gpio(&pdev->dev,
+ soc_button_tbl[i].acpi_index);
+ }
+
+ for (r = 0; r < BUTTON_TYPES; r++) {
+ gk = soc_buttons[r];
+ j = 0;
+
+ /* Register buttons in the correct device */
+ for (i = 0; i < sz_tbl; i++) {
+ if (soc_button_tbl[i].repeat == r &&
+ soc_button_tbl[i].gpio > 0) {
+ gk[j].code = soc_button_tbl[i].event_code;
+ gk[j].gpio = soc_button_tbl[i].gpio;
+ gk[j].active_low = 1;
+ gk[j].desc = soc_button_tbl[i].name;
+ gk[j].type = EV_KEY;
+ gk[j].wakeup = soc_button_tbl[i].wakeup;
+ j++;
+ }
+ }
+
+ soc_button_data[r].nbuttons = j;
+
+ if (j == 0)
+ continue;
+
+ if (soc_button_register(r)) {
+ dev_err(&pdev->dev, "failed to register %d\n", r);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void soc_button_remove(struct pnp_dev *pdev)
+{
+ int r;
+
+ for (r = 0; r < BUTTON_TYPES; r++) {
+ if (soc_button_device[r]) {
+ platform_device_unregister(soc_button_device[r]);
+ soc_button_device[r] = NULL;
+ }
+ }
+}
+
+static const struct pnp_device_id soc_button_pnp_match[] = {
+ {.id = "INTCFD9", .driver_data = 0},
+ {.id = ""}
+};
+
+MODULE_DEVICE_TABLE(pnp, soc_button_pnp_match);
+
+static struct pnp_driver soc_button_pnp_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = soc_button_pnp_match,
+ .probe = soc_button_pnp_probe,
+ .remove = soc_button_remove,
+};
+
+static int __init soc_button_init(void)
+{
+ return pnp_register_driver(&soc_button_pnp_driver);
+}
+
+static void __exit soc_button_exit(void)
+{
+ pnp_unregister_driver(&soc_button_pnp_driver);
+}
+
+module_init(soc_button_init);
+module_exit(soc_button_exit);
+
+MODULE_LICENSE("GPL");
--
1.8.3.2
^ permalink raw reply related
* Re: [PATCH v4 2/3] input: appletouch: implement sensor data smoothing
From: Dmitry Torokhov @ 2014-03-27 18:26 UTC (permalink / raw)
To: Clinton Sprain; +Cc: linux-input, Henrik Rydberg
In-Reply-To: <5320EAC5.5000506@gmail.com>
Hi Clinton,
On Wed, Mar 12, 2014 at 06:16:21PM -0500, Clinton Sprain wrote:
> input: appletouch: implement sensor data smoothing
>
> Use smoothed version of sensor array data to calculate movement and add weight
> to prior values when calculating average. This gives more granular and more
> predictable movement.
>
> Signed-off-by: Clinton Sprain <clintonsprain@gmail.com>
> ---
> drivers/input/mouse/appletouch.c | 72 ++++++++++++++++++++++++++++----------
> 1 file changed, 53 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
> index 2745832..e00f126 100644
> --- a/drivers/input/mouse/appletouch.c
> +++ b/drivers/input/mouse/appletouch.c
> @@ -332,7 +332,11 @@ static void atp_reinit(struct work_struct *work)
> static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
> int *z, int *fingers)
> {
> - int i;
> + int i, k;
> + int smooth[nb_sensors + 8];
> + int smooth_tmp[nb_sensors + 8];
This unfortunately introduces variable-length arraus on stack which
makes sparse unhappy. Can we add these scratch buffers to the device
structure instead?
> + int scale = 12;
Probably better use a define rather than a variable.
> +
> /* values to calculate mean */
> int pcum = 0, psum = 0;
> int is_increasing = 0;
> @@ -344,9 +348,6 @@ static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
> if (is_increasing)
> is_increasing = 0;
>
> - continue;
> - }
> -
> /*
> * Makes the finger detection more versatile. For example,
> * two fingers with no gap will be detected. Also, my
> @@ -361,27 +362,60 @@ static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
> *
> * - Jason Parekh <jasonparekh@gmail.com>
> */
> - if (i < 1 ||
> +
> + } else if (i < 1 ||
> (!is_increasing && xy_sensors[i - 1] < xy_sensors[i])) {
> (*fingers)++;
> is_increasing = 1;
> } else if (i > 0 && (xy_sensors[i - 1] - xy_sensors[i] > threshold)) {
> is_increasing = 0;
> }
> + }
>
> - /*
> - * Subtracts threshold so a high sensor that just passes the
> - * threshold won't skew the calculated absolute coordinate.
> - * Fixes an issue where slowly moving the mouse would
> - * occasionally jump a number of pixels (slowly moving the
> - * finger makes this issue most apparent.)
> - */
> - pcum += (xy_sensors[i] - threshold) * i;
> - psum += (xy_sensors[i] - threshold);
> + /*
> + * Use a smoothed version of sensor data for movement calculations, to
> + * combat noise without needing to rely so heavily on a threshold.
> + * This improves tracking.
> + *
> + * The smoothed array is bigger than the original so that the smoothing
> + * doesn't result in edge values being truncated.
> + */
> +
> + for (i = 0; i < 4; i++)
> + smooth[i] = 0;
memset might be better?
> + for (i = nb_sensors + 4; i < nb_sensors + 8; i++)
> + smooth[i] = 0;
And here as well.
Thanks.
--
Dmitry
^ permalink raw reply
* [PATCH v3 05/10] input: misc: Add ABI docs for AXP20x PEK
From: Carlo Caione @ 2014-03-27 21:29 UTC (permalink / raw)
To: linux-arm-kernel, linux-sunxi, maxime.ripard, hdegoede, emilio,
wens, sameo, dmitry.torokhov, linux-input, linux-doc, lgirdwood,
broonie
Cc: Carlo Caione
In-Reply-To: <1395955764-18103-1-git-send-email-carlo@caione.org>
Add ABI entries for the PEK found on PMU X-Powers AXP202 and AXP209.
Signed-off-by: Carlo Caione <carlo@caione.org>
---
Documentation/ABI/testing/sysfs-driver-input-axp-pek | 11 +++++++++++
1 file changed, 11 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-driver-input-axp-pek
diff --git a/Documentation/ABI/testing/sysfs-driver-input-axp-pek b/Documentation/ABI/testing/sysfs-driver-input-axp-pek
new file mode 100644
index 0000000..f8cdad2
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-input-axp-pek
@@ -0,0 +1,11 @@
+What: /sys/class/input/input(x)/startup
+Date: March 2014
+Contact: Carlo Caione <carlo@caione.org>
+Description: Startup time. Board is powered on if the button is pressed
+ for more than <startup_time>
+
+What: /sys/class/input/input(x)/shutdown
+Date: March 2014
+Contact: Carlo Caione <carlo@caione.org>
+Description: Shutdown time. Board is powered off if the button is pressed
+ for more than <shutdown_time>
--
1.8.3.2
^ permalink raw reply related
* [PATCH v3 06/10] regulator: AXP20x: Add support for regulators subsystem
From: Carlo Caione @ 2014-03-27 21:29 UTC (permalink / raw)
To: linux-arm-kernel, linux-sunxi, maxime.ripard, hdegoede, emilio,
wens, sameo, dmitry.torokhov, linux-input, linux-doc, lgirdwood,
broonie
Cc: Carlo Caione
In-Reply-To: <1395955764-18103-1-git-send-email-carlo@caione.org>
AXP202 and AXP209 come with two synchronous step-down DC-DCs and five
LDOs. This patch introduces basic support for those regulators.
Signed-off-by: Carlo Caione <carlo@caione.org>
---
drivers/regulator/Kconfig | 7 +
drivers/regulator/Makefile | 1 +
drivers/regulator/axp20x-regulator.c | 280 +++++++++++++++++++++++++++++++++++
3 files changed, 288 insertions(+)
create mode 100644 drivers/regulator/axp20x-regulator.c
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 6a79328..9f3bc48 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -139,6 +139,13 @@ config REGULATOR_AS3722
AS3722 PMIC. This will enable support for all the software
controllable DCDC/LDO regulators.
+config REGULATOR_AXP20X
+ tristate "X-POWERS AXP20X PMIC Regulators"
+ depends on MFD_AXP20X
+ help
+ This driver provides support for the voltage regulators on the
+ AXP20X PMIC.
+
config REGULATOR_DA903X
tristate "Dialog Semiconductor DA9030/DA9034 regulators"
depends on PMIC_DA903X
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 979f9dd..1dd084a 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o
obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o
obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
+obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
new file mode 100644
index 0000000..3f1db88
--- /dev/null
+++ b/drivers/regulator/axp20x-regulator.c
@@ -0,0 +1,280 @@
+/*
+ * AXP20x regulators driver.
+ *
+ * Copyright (C) 2013 Carlo Caione <carlo@caione.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * 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.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/axp20x.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+#define AXP20X_IO_ENABLED (0x03)
+#define AXP20X_IO_DISABLED (0x07)
+
+#define AXP20X_WORKMODE_DCDC2_MASK BIT(2)
+#define AXP20X_WORKMODE_DCDC3_MASK BIT(1)
+
+#define AXP20X_FREQ_DCDC_MASK (0x0f)
+
+#define AXP20X_DESC_IO(_id, _min, _max, _step, _vreg, _vmask, _ereg, _emask, \
+ _enable_val, _disable_val) \
+ [AXP20X_##_id] = { \
+ .name = #_id, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = AXP20X_##_id, \
+ .n_voltages = (((_max) - (_min)) / (_step) + 1), \
+ .owner = THIS_MODULE, \
+ .min_uV = (_min) * 1000, \
+ .uV_step = (_step) * 1000, \
+ .vsel_reg = (_vreg), \
+ .vsel_mask = (_vmask), \
+ .enable_reg = (_ereg), \
+ .enable_mask = (_emask), \
+ .enable_val = (_enable_val), \
+ .disable_val = (_disable_val), \
+ .ops = &axp20x_ops, \
+ }
+
+#define AXP20X_DESC(_id, _min, _max, _step, _vreg, _vmask, _ereg, _emask) \
+ AXP20X_DESC_IO(_id, _min, _max, _step, _vreg, _vmask, _ereg, _emask, \
+ 0, 0)
+
+#define AXP20X_DESC_FIXED(_id, _volt) \
+ [AXP20X_##_id] = { \
+ .name = #_id, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = AXP20X_##_id, \
+ .n_voltages = 1, \
+ .owner = THIS_MODULE, \
+ .min_uV = (_volt) * 1000, \
+ .ops = &axp20x_ops, \
+ }
+
+#define AXP20X_DESC_TABLE(_id, _table, _vreg, _vmask, _ereg, _emask) \
+ [AXP20X_##_id] = { \
+ .name = #_id, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = AXP20X_##_id, \
+ .n_voltages = ARRAY_SIZE(_table), \
+ .owner = THIS_MODULE, \
+ .vsel_reg = (_vreg), \
+ .vsel_mask = (_vmask), \
+ .enable_reg = (_ereg), \
+ .enable_mask = (_emask), \
+ .volt_table = (_table), \
+ .ops = &axp20x_ops_table, \
+ }
+
+static int axp20x_ldo4_data[] = { 1250000, 1300000, 1400000, 1500000, 1600000, 1700000,
+ 1800000, 1900000, 2000000, 2500000, 2700000, 2800000,
+ 3000000, 3100000, 3200000, 3300000 };
+
+static int axp20x_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+ int sel = regulator_map_voltage_iterate(rdev, uV, uV);
+
+ if (sel < 0)
+ return sel;
+
+ return regulator_set_voltage_sel_regmap(rdev, sel);
+}
+
+static struct regulator_ops axp20x_ops_table = {
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_table,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_suspend_enable = regulator_enable_regmap,
+ .set_suspend_disable = regulator_disable_regmap,
+ .set_suspend_voltage = axp20x_set_suspend_voltage,
+};
+
+
+static struct regulator_ops axp20x_ops = {
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_suspend_enable = regulator_enable_regmap,
+ .set_suspend_disable = regulator_disable_regmap,
+ .set_suspend_voltage = axp20x_set_suspend_voltage,
+};
+
+static const struct regulator_desc axp20x_regulators[] = {
+ AXP20X_DESC(DCDC2, 700, 2275, 25, AXP20X_DCDC2_V_OUT, 0x3f,
+ AXP20X_PWR_OUT_CTRL, 0x10),
+ AXP20X_DESC(DCDC3, 700, 3500, 25, AXP20X_DCDC3_V_OUT, 0x7f,
+ AXP20X_PWR_OUT_CTRL, 0x02),
+ AXP20X_DESC_FIXED(LDO1, 1300),
+ AXP20X_DESC(LDO2, 1800, 3300, 100, AXP20X_LDO24_V_OUT, 0xf0,
+ AXP20X_PWR_OUT_CTRL, 0x04),
+ AXP20X_DESC(LDO3, 700, 3500, 25, AXP20X_LDO3_V_OUT, 0x7f,
+ AXP20X_PWR_OUT_CTRL, 0x40),
+ AXP20X_DESC_TABLE(LDO4, axp20x_ldo4_data, AXP20X_LDO24_V_OUT, 0x0f,
+ AXP20X_PWR_OUT_CTRL, 0x08),
+ AXP20X_DESC_IO(LDO5, 1800, 3300, 100, AXP20X_LDO5_V_OUT, 0xf0,
+ AXP20X_GPIO0_CTRL, 0x07, AXP20X_IO_ENABLED,
+ AXP20X_IO_DISABLED),
+};
+
+#define AXP_MATCH(_name, _id) \
+ [AXP20X_##_id] = { \
+ .name = #_name, \
+ .driver_data = (void *) &axp20x_regulators[AXP20X_##_id], \
+ }
+
+static struct of_regulator_match axp20x_matches[] = {
+ AXP_MATCH(dcdc2, DCDC2),
+ AXP_MATCH(dcdc3, DCDC3),
+ AXP_MATCH(ldo1, LDO1),
+ AXP_MATCH(ldo2, LDO2),
+ AXP_MATCH(ldo3, LDO3),
+ AXP_MATCH(ldo4, LDO4),
+ AXP_MATCH(ldo5, LDO5),
+};
+
+static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
+{
+ struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
+
+ if (dcdcfreq < 750) {
+ dcdcfreq = 750;
+ dev_warn(&pdev->dev, "DCDC frequency too low. Set to 750kHz\n");
+ }
+
+ if (dcdcfreq > 1875) {
+ dcdcfreq = 1875;
+ dev_warn(&pdev->dev, "DCDC frequency too high. Set to 1875kHz\n");
+ }
+
+ dcdcfreq = (dcdcfreq - 750) / 75;
+
+ return regmap_update_bits(axp20x->regmap, AXP20X_DCDC_FREQ,
+ AXP20X_FREQ_DCDC_MASK, dcdcfreq);
+}
+
+static int axp20x_regulator_parse_dt(struct platform_device *pdev)
+{
+ struct device_node *np, *regulators;
+ int ret;
+ u32 dcdcfreq;
+
+ np = of_node_get(pdev->dev.parent->of_node);
+ if (!np)
+ return 0;
+
+ regulators = of_find_node_by_name(np, "regulators");
+ if (!regulators) {
+ dev_warn(&pdev->dev, "regulators node not found\n");
+ } else {
+ ret = of_regulator_match(&pdev->dev, regulators, axp20x_matches,
+ ARRAY_SIZE(axp20x_matches));
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret);
+ return ret;
+ }
+
+ dcdcfreq = 1500;
+ of_property_read_u32(regulators, "x-powers,dcdc-freq", &dcdcfreq);
+ ret = axp20x_set_dcdc_freq(pdev, dcdcfreq);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error setting dcdc frequency: %d\n", ret);
+ return ret;
+ }
+
+ of_node_put(regulators);
+ }
+
+ return 0;
+}
+
+static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 workmode)
+{
+ unsigned int mask = AXP20X_WORKMODE_DCDC2_MASK;
+
+ if ((id != AXP20X_DCDC2) && (id != AXP20X_DCDC3))
+ return -EINVAL;
+
+ if (id == AXP20X_DCDC3)
+ mask = AXP20X_WORKMODE_DCDC3_MASK;
+
+ workmode <<= ffs(mask) - 1;
+
+ return regmap_update_bits(rdev->regmap, AXP20X_DCDC_MODE, mask, workmode);
+}
+
+static int axp20x_regulator_probe(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev;
+ struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = { };
+ struct regulator_init_data *init_data;
+ int ret, i;
+ u32 workmode;
+
+ ret = axp20x_regulator_parse_dt(pdev);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < AXP20X_REG_ID_MAX; i++) {
+ init_data = axp20x_matches[i].init_data;
+
+ config.dev = &pdev->dev;
+ config.init_data = init_data;
+ config.regmap = axp20x->regmap;
+ config.of_node = axp20x_matches[i].of_node;
+
+ rdev = devm_regulator_register(&pdev->dev, &axp20x_regulators[i],
+ &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "Failed to register %s\n",
+ axp20x_regulators[i].name);
+
+ return PTR_ERR(rdev);
+ }
+
+ ret = of_property_read_u32(axp20x_matches[i].of_node, "x-powers,dcdc-workmode",
+ &workmode);
+ if (!ret) {
+ if (axp20x_set_dcdc_workmode(rdev, i, workmode))
+ dev_err(&pdev->dev, "Failed to set workmode on %s\n",
+ axp20x_regulators[i].name);
+ }
+ }
+
+ return 0;
+}
+
+static struct platform_driver axp20x_regulator_driver = {
+ .probe = axp20x_regulator_probe,
+ .driver = {
+ .name = "axp20x-regulator",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(axp20x_regulator_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
+MODULE_DESCRIPTION("Regulator Driver for AXP20X PMIC");
--
1.8.3.2
^ permalink raw reply related
* [PATCH v3 10/10] ARM: sunxi: Add AXP20x support multi_v7_defconfig
From: Carlo Caione @ 2014-03-27 21:29 UTC (permalink / raw)
To: linux-arm-kernel, linux-sunxi, maxime.ripard, hdegoede, emilio,
wens, sameo, dmitry.torokhov, linux-input, linux-doc, lgirdwood,
broonie
Cc: Carlo Caione
In-Reply-To: <1395955764-18103-1-git-send-email-carlo@caione.org>
Signed-off-by: Carlo Caione <carlo@caione.org>
---
arch/arm/configs/multi_v7_defconfig | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index ee69829..239c014 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -134,6 +134,7 @@ CONFIG_KEYBOARD_SPEAR=y
CONFIG_KEYBOARD_CROS_EC=y
CONFIG_MOUSE_PS2_ELANTECH=y
CONFIG_INPUT_MISC=y
+CONFIG_INPUT_AXP20X_PEK=y
CONFIG_INPUT_MPU3050=y
CONFIG_SERIO_AMBAKMI=y
CONFIG_SERIAL_8250=y
@@ -189,6 +190,7 @@ CONFIG_SENSORS_LM90=y
CONFIG_THERMAL=y
CONFIG_ARMADA_THERMAL=y
CONFIG_MFD_AS3722=y
+CONFIG_MFD_AXP20X=y
CONFIG_MFD_CROS_EC=y
CONFIG_MFD_CROS_EC_SPI=y
CONFIG_MFD_MAX8907=y
@@ -199,6 +201,7 @@ CONFIG_MFD_TPS65910=y
CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
CONFIG_REGULATOR_AB8500=y
CONFIG_REGULATOR_AS3722=y
+CONFIG_REGULATOR_AXP20X=y
CONFIG_REGULATOR_GPIO=y
CONFIG_REGULATOR_MAX8907=y
CONFIG_REGULATOR_PALMAS=y
--
1.8.3.2
^ permalink raw reply related
* [PATCH v3 00/10] mfd: AXP20x: Add support for AXP202 and AXP209
From: Carlo Caione @ 2014-03-27 21:29 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
hdegoede-H+wXaHxf7aLQT0dZR+AlfA, emilio-0Z03zUJReD5OxF6Tv1QG9Q,
wens-jdAy2FN1RRM, sameo-VuQAYsv1563Yd54FQh9/CA,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A
Cc: Carlo Caione
AXP209 and AXP202 are the PMUs (Power Management Unit) used by A10, A13
and A20 SoCs and developed by X-Powers, a sister company of Allwinner.
AXP20x comprises an adaptive USB-Compatible PWM charger, 2 BUCK DC-DC
converters, 5 LDOs, multiple 12-bit ADCs of voltage, current and temperature
as well as 4 configurable GPIOs.
This set of patches introduces the core driver and support for two different
subsystems:
- Regulators
- PEK (Power Enable Key)
This patchset depends on patchsets:
irq: sun4i IRQ 0 / ENMI fixes (Hans de Goede)
ARM: sun7i/sun6i: irqchip: Irqchip driver for NMI controller (Carlo Caione)
regulator: helpers: Modify helpers enabling multi-bit control (Carlo Caione)
Changes since v1:
- Added a new standalone patch for defconfig
- MFD core:
* Removed axp,system-power-controller property
- Bindings documentation:
* Corrected description for dcdc-workmode property
* Removed unused axp20x-pek compatible
- Input misc PEK driver:
* Fixed seconds in lower case
- Regulators subsystem:
* Fixed axp20x_set_suspend_voltage()
* Switched to using multi-bit control for regulators
* When "regulators" node is not found driver doesn't quit
* Driver is now using devm_regulator_register()
* Added module_platform_driver() instead of subsys_initcall()
- DT:
* Added new DTSI for AXP209
* Added support for cubietruck and olinuxino-micro
Changes since v2:
- Added a new patch for multi_v7_defconfig to enable MFD core
and subsystems
- DT:
* Dropped axp,system-power-controller property from DTS
* Moved compatible and interrupt-related properties from the
DTSI file to the DTS board files
- Regulators subsystem:
* Deleted useless struct axp20x_regulators
* Added a warning when out of specs values are used for the
dcdc frequency
- MFD core:
* Fixed coding style
* Removed IDs from device table for i2c
- Bindings documentation:
* Several corrections and fixes
Carlo Caione (10):
mfd: AXP20x: Add mfd driver for AXP20x PMIC
dt-bindings: add vendor-prefix for X-Powers
mfd: AXP20x: Add bindings documentation
input: misc: Add driver for AXP20x Power Enable Key
input: misc: Add ABI docs for AXP20x PEK
regulator: AXP20x: Add support for regulators subsystem
ARM: sunxi: dt: Add x-powers-axp209.dtsi file
ARM: sun7i/sun4i: dt: Add AXP209 support to various boards
ARM: sunxi: Add AXP20x support in defconfig
ARM: sunxi: Add AXP20x support multi_v7_defconfig
.../ABI/testing/sysfs-driver-input-axp-pek | 11 +
Documentation/devicetree/bindings/mfd/axp20x.txt | 83 ++++++
.../devicetree/bindings/vendor-prefixes.txt | 1 +
arch/arm/boot/dts/sun4i-a10-a1000.dts | 13 +
arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 13 +
arch/arm/boot/dts/sun4i-a10-hackberry.dts | 19 ++
arch/arm/boot/dts/sun4i-a10-inet97fv2.dts | 13 +
arch/arm/boot/dts/sun4i-a10-mini-xplus.dts | 19 ++
arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts | 19 ++
arch/arm/boot/dts/sun4i-a10-pcduino.dts | 13 +
arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 14 ++
arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 15 ++
arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 14 ++
arch/arm/boot/dts/x-powers-axp209.dtsi | 54 ++++
arch/arm/configs/multi_v7_defconfig | 3 +
arch/arm/configs/sunxi_defconfig | 4 +
drivers/input/misc/Kconfig | 11 +
drivers/input/misc/Makefile | 1 +
drivers/input/misc/axp20x-pek.c | 260 +++++++++++++++++++
drivers/mfd/Kconfig | 12 +
drivers/mfd/Makefile | 1 +
drivers/mfd/axp20x.c | 240 ++++++++++++++++++
drivers/regulator/Kconfig | 7 +
drivers/regulator/Makefile | 1 +
drivers/regulator/axp20x-regulator.c | 280 +++++++++++++++++++++
include/linux/mfd/axp20x.h | 180 +++++++++++++
26 files changed, 1301 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-driver-input-axp-pek
create mode 100644 Documentation/devicetree/bindings/mfd/axp20x.txt
create mode 100644 arch/arm/boot/dts/x-powers-axp209.dtsi
create mode 100644 drivers/input/misc/axp20x-pek.c
create mode 100644 drivers/mfd/axp20x.c
create mode 100644 drivers/regulator/axp20x-regulator.c
create mode 100644 include/linux/mfd/axp20x.h
--
1.8.3.2
^ permalink raw reply
* [PATCH v3 01/10] mfd: AXP20x: Add mfd driver for AXP20x PMIC
From: Carlo Caione @ 2014-03-27 21:29 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
hdegoede-H+wXaHxf7aLQT0dZR+AlfA, emilio-0Z03zUJReD5OxF6Tv1QG9Q,
wens-jdAy2FN1RRM, sameo-VuQAYsv1563Yd54FQh9/CA,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A
Cc: Carlo Caione
In-Reply-To: <1395955764-18103-1-git-send-email-carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
This patch introduces the preliminary support for PMICs X-Powers AXP202
and AXP209. The AXP209 and AXP202 are the PMUs (Power Management Unit)
used by A10, A13 and A20 SoCs and developed by X-Powers, a sister company
of Allwinner.
The core enables support for two subsystems:
- PEK (Power Enable Key)
- Regulators
Signed-off-by: Carlo Caione <carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
---
drivers/mfd/Kconfig | 12 +++
drivers/mfd/Makefile | 1 +
drivers/mfd/axp20x.c | 240 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/mfd/axp20x.h | 180 ++++++++++++++++++++++++++++++++++
4 files changed, 433 insertions(+)
create mode 100644 drivers/mfd/axp20x.c
create mode 100644 include/linux/mfd/axp20x.h
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 49bb445..24ba61a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -59,6 +59,18 @@ config MFD_AAT2870_CORE
additional drivers must be enabled in order to use the
functionality of the device.
+config MFD_AXP20X
+ bool "X-Powers AXP20X"
+ select MFD_CORE
+ select REGMAP_I2C
+ select REGMAP_IRQ
+ depends on I2C=y
+ help
+ If you say Y here you get support for the AXP20X.
+ This driver provides common support for accessing the device,
+ additional drivers must be enabled in order to use the
+ functionality of the device.
+
config MFD_CROS_EC
tristate "ChromeOS Embedded Controller"
select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 5aea5ef..fb773b5 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -101,6 +101,7 @@ obj-$(CONFIG_PMIC_DA9052) += da9052-irq.o
obj-$(CONFIG_PMIC_DA9052) += da9052-core.o
obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o
obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o
+obj-$(CONFIG_MFD_AXP20X) += axp20x.o
obj-$(CONFIG_MFD_LP3943) += lp3943.o
obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
new file mode 100644
index 0000000..f77a663
--- /dev/null
+++ b/drivers/mfd/axp20x.c
@@ -0,0 +1,240 @@
+/*
+ * axp20x.c - MFD core driver for the X-Powers AXP202 and AXP209
+ *
+ * Author: Carlo Caione <carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
+ *
+ * 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/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/axp20x.h>
+#include <linux/mfd/core.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+
+#define AXP20X_OFF 0x80
+
+static const struct regmap_range axp20x_writeable_ranges[] = {
+ regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
+ regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES),
+};
+
+static const struct regmap_range axp20x_volatile_ranges[] = {
+ regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE),
+};
+
+static const struct regmap_access_table axp20x_writeable_table = {
+ .yes_ranges = axp20x_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(axp20x_writeable_ranges),
+};
+
+static const struct regmap_access_table axp20x_volatile_table = {
+ .yes_ranges = axp20x_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges),
+};
+
+static struct resource axp20x_pek_resources[] = {
+ {
+ .name = "PEK_DBR",
+ .start = AXP20X_IRQ_PEK_RIS_EDGE,
+ .end = AXP20X_IRQ_PEK_RIS_EDGE,
+ .flags = IORESOURCE_IRQ,
+ }, {
+ .name = "PEK_DBF",
+ .start = AXP20X_IRQ_PEK_FAL_EDGE,
+ .end = AXP20X_IRQ_PEK_FAL_EDGE,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static const struct regmap_config axp20x_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .wr_table = &axp20x_writeable_table,
+ .volatile_table = &axp20x_volatile_table,
+ .max_register = AXP20X_FG_RES,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+#define AXP20X_IRQ(_irq, _off, _mask) \
+ [AXP20X_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
+
+static const struct regmap_irq axp20x_regmap_irqs[] = {
+ AXP20X_IRQ(ACIN_OVER_V, 0, 7),
+ AXP20X_IRQ(ACIN_PLUGIN, 0, 6),
+ AXP20X_IRQ(ACIN_REMOVAL, 0, 5),
+ AXP20X_IRQ(VBUS_OVER_V, 0, 4),
+ AXP20X_IRQ(VBUS_PLUGIN, 0, 3),
+ AXP20X_IRQ(VBUS_REMOVAL, 0, 2),
+ AXP20X_IRQ(VBUS_V_LOW, 0, 1),
+ AXP20X_IRQ(BATT_PLUGIN, 1, 7),
+ AXP20X_IRQ(BATT_REMOVAL, 1, 6),
+ AXP20X_IRQ(BATT_ENT_ACT_MODE, 1, 5),
+ AXP20X_IRQ(BATT_EXIT_ACT_MODE, 1, 4),
+ AXP20X_IRQ(CHARG, 1, 3),
+ AXP20X_IRQ(CHARG_DONE, 1, 2),
+ AXP20X_IRQ(BATT_TEMP_HIGH, 1, 1),
+ AXP20X_IRQ(BATT_TEMP_LOW, 1, 0),
+ AXP20X_IRQ(DIE_TEMP_HIGH, 2, 7),
+ AXP20X_IRQ(CHARG_I_LOW, 2, 6),
+ AXP20X_IRQ(DCDC1_V_LONG, 2, 5),
+ AXP20X_IRQ(DCDC2_V_LONG, 2, 4),
+ AXP20X_IRQ(DCDC3_V_LONG, 2, 3),
+ AXP20X_IRQ(PEK_SHORT, 2, 1),
+ AXP20X_IRQ(PEK_LONG, 2, 0),
+ AXP20X_IRQ(N_OE_PWR_ON, 3, 7),
+ AXP20X_IRQ(N_OE_PWR_OFF, 3, 6),
+ AXP20X_IRQ(VBUS_VALID, 3, 5),
+ AXP20X_IRQ(VBUS_NOT_VALID, 3, 4),
+ AXP20X_IRQ(VBUS_SESS_VALID, 3, 3),
+ AXP20X_IRQ(VBUS_SESS_END, 3, 2),
+ AXP20X_IRQ(LOW_PWR_LVL1, 3, 1),
+ AXP20X_IRQ(LOW_PWR_LVL2, 3, 0),
+ AXP20X_IRQ(TIMER, 4, 7),
+ AXP20X_IRQ(PEK_RIS_EDGE, 4, 6),
+ AXP20X_IRQ(PEK_FAL_EDGE, 4, 5),
+ AXP20X_IRQ(GPIO3_INPUT, 4, 3),
+ AXP20X_IRQ(GPIO2_INPUT, 4, 2),
+ AXP20X_IRQ(GPIO1_INPUT, 4, 1),
+ AXP20X_IRQ(GPIO0_INPUT, 4, 0),
+};
+
+static const struct of_device_id axp20x_of_match[] = {
+ { .compatible = "x-powers,axp202", .data = (void *) AXP202_ID },
+ { .compatible = "x-powers,axp209", .data = (void *) AXP209_ID },
+ { },
+};
+MODULE_DEVICE_TABLE(of, axp20x_of_match);
+
+static const struct i2c_device_id axp20x_i2c_id[] = {
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
+
+static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
+ .name = "axp20x_irq_chip",
+ .status_base = AXP20X_IRQ1_STATE,
+ .ack_base = AXP20X_IRQ1_STATE,
+ .mask_base = AXP20X_IRQ1_EN,
+ .num_regs = 5,
+ .irqs = axp20x_regmap_irqs,
+ .num_irqs = ARRAY_SIZE(axp20x_regmap_irqs),
+ .mask_invert = true,
+ .init_ack_masked = true,
+};
+
+static struct mfd_cell axp20x_cells[] = {
+ {
+ .name = "axp20x-pek",
+ .num_resources = ARRAY_SIZE(axp20x_pek_resources),
+ .resources = axp20x_pek_resources,
+ }, {
+ .name = "axp20x-regulator",
+ },
+};
+
+static struct axp20x_dev *axp20x_pm_power_off;
+static void axp20x_power_off(void)
+{
+ regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
+ AXP20X_OFF);
+}
+
+static int axp20x_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct axp20x_dev *axp20x;
+ const struct of_device_id *of_id;
+ int ret;
+
+ axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL);
+ if (!axp20x)
+ return -ENOMEM;
+
+ of_id = of_match_device(axp20x_of_match, &i2c->dev);
+ if (!of_id) {
+ dev_err(&i2c->dev, "Unable to setup AXP20X data\n");
+ return -ENODEV;
+ }
+ axp20x->variant = (int) of_id->data;
+
+ axp20x->i2c_client = i2c;
+ axp20x->dev = &i2c->dev;
+ dev_set_drvdata(axp20x->dev, axp20x);
+
+ axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config);
+ if (IS_ERR(axp20x->regmap)) {
+ ret = PTR_ERR(axp20x->regmap);
+ dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq,
+ IRQF_ONESHOT | IRQF_SHARED, -1,
+ &axp20x_regmap_irq_chip,
+ &axp20x->regmap_irqc);
+ if (ret) {
+ dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret);
+ return ret;
+ }
+
+ ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells,
+ ARRAY_SIZE(axp20x_cells), NULL, 0, NULL);
+
+ if (ret) {
+ dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
+ regmap_del_irq_chip(i2c->irq, axp20x->regmap_irqc);
+ return ret;
+ }
+
+ if (!pm_power_off) {
+ axp20x_pm_power_off = axp20x;
+ pm_power_off = axp20x_power_off;
+ }
+
+ dev_info(&i2c->dev, "AXP20X driver loaded\n");
+
+ return 0;
+}
+
+static int axp20x_i2c_remove(struct i2c_client *i2c)
+{
+ struct axp20x_dev *axp20x = i2c_get_clientdata(i2c);
+
+ if (axp20x == axp20x_pm_power_off) {
+ axp20x_pm_power_off = NULL;
+ pm_power_off = NULL;
+ }
+
+ mfd_remove_devices(axp20x->dev);
+ regmap_del_irq_chip(axp20x->i2c_client->irq, axp20x->regmap_irqc);
+
+ return 0;
+}
+
+static struct i2c_driver axp20x_i2c_driver = {
+ .driver = {
+ .name = "axp20x",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(axp20x_of_match),
+ },
+ .probe = axp20x_i2c_probe,
+ .remove = axp20x_i2c_remove,
+ .id_table = axp20x_i2c_id,
+};
+
+module_i2c_driver(axp20x_i2c_driver);
+
+MODULE_DESCRIPTION("PMIC MFD core driver for AXP20X");
+MODULE_AUTHOR("Carlo Caione <carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
new file mode 100644
index 0000000..c7b1658
--- /dev/null
+++ b/include/linux/mfd/axp20x.h
@@ -0,0 +1,180 @@
+/*
+ * Functions and registers to access AXP20X power management chip.
+ *
+ * Copyright (C) 2013, Carlo Caione <carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
+ *
+ * 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 __LINUX_MFD_AXP20X_H
+#define __LINUX_MFD_AXP20X_H
+
+enum {
+ AXP202_ID = 0,
+ AXP209_ID,
+};
+
+#define AXP20X_DATACACHE(m) (0x04 + (m))
+
+/* Power supply */
+#define AXP20X_PWR_INPUT_STATUS 0x00
+#define AXP20X_PWR_OP_MODE 0x01
+#define AXP20X_USB_OTG_STATUS 0x02
+#define AXP20X_PWR_OUT_CTRL 0x12
+#define AXP20X_DCDC2_V_OUT 0x23
+#define AXP20X_DCDC2_LDO3_V_SCAL 0x25
+#define AXP20X_DCDC3_V_OUT 0x27
+#define AXP20X_LDO24_V_OUT 0x28
+#define AXP20X_LDO3_V_OUT 0x29
+#define AXP20X_VBUS_IPSOUT_MGMT 0x30
+#define AXP20X_V_OFF 0x31
+#define AXP20X_OFF_CTRL 0x32
+#define AXP20X_CHRG_CTRL1 0x33
+#define AXP20X_CHRG_CTRL2 0x34
+#define AXP20X_CHRG_BAK_CTRL 0x35
+#define AXP20X_PEK_KEY 0x36
+#define AXP20X_DCDC_FREQ 0x37
+#define AXP20X_V_LTF_CHRG 0x38
+#define AXP20X_V_HTF_CHRG 0x39
+#define AXP20X_APS_WARN_L1 0x3a
+#define AXP20X_APS_WARN_L2 0x3b
+#define AXP20X_V_LTF_DISCHRG 0x3c
+#define AXP20X_V_HTF_DISCHRG 0x3d
+
+/* Interrupt */
+#define AXP20X_IRQ1_EN 0x40
+#define AXP20X_IRQ2_EN 0x41
+#define AXP20X_IRQ3_EN 0x42
+#define AXP20X_IRQ4_EN 0x43
+#define AXP20X_IRQ5_EN 0x44
+#define AXP20X_IRQ1_STATE 0x48
+#define AXP20X_IRQ2_STATE 0x49
+#define AXP20X_IRQ3_STATE 0x4a
+#define AXP20X_IRQ4_STATE 0x4b
+#define AXP20X_IRQ5_STATE 0x4c
+
+/* ADC */
+#define AXP20X_ACIN_V_ADC_H 0x56
+#define AXP20X_ACIN_V_ADC_L 0x57
+#define AXP20X_ACIN_I_ADC_H 0x58
+#define AXP20X_ACIN_I_ADC_L 0x59
+#define AXP20X_VBUS_V_ADC_H 0x5a
+#define AXP20X_VBUS_V_ADC_L 0x5b
+#define AXP20X_VBUS_I_ADC_H 0x5c
+#define AXP20X_VBUS_I_ADC_L 0x5d
+#define AXP20X_TEMP_ADC_H 0x5e
+#define AXP20X_TEMP_ADC_L 0x5f
+#define AXP20X_TS_IN_H 0x62
+#define AXP20X_TS_IN_L 0x63
+#define AXP20X_GPIO0_V_ADC_H 0x64
+#define AXP20X_GPIO0_V_ADC_L 0x65
+#define AXP20X_GPIO1_V_ADC_H 0x66
+#define AXP20X_GPIO1_V_ADC_L 0x67
+#define AXP20X_PWR_BATT_H 0x70
+#define AXP20X_PWR_BATT_M 0x71
+#define AXP20X_PWR_BATT_L 0x72
+#define AXP20X_BATT_V_H 0x78
+#define AXP20X_BATT_V_L 0x79
+#define AXP20X_BATT_CHRG_I_H 0x7a
+#define AXP20X_BATT_CHRG_I_L 0x7b
+#define AXP20X_BATT_DISCHRG_I_H 0x7c
+#define AXP20X_BATT_DISCHRG_I_L 0x7d
+#define AXP20X_IPSOUT_V_HIGH_H 0x7e
+#define AXP20X_IPSOUT_V_HIGH_L 0x7f
+
+/* Power supply */
+#define AXP20X_DCDC_MODE 0x80
+#define AXP20X_ADC_EN1 0x82
+#define AXP20X_ADC_EN2 0x83
+#define AXP20X_ADC_RATE 0x84
+#define AXP20X_GPIO10_IN_RANGE 0x85
+#define AXP20X_GPIO1_ADC_IRQ_RIS 0x86
+#define AXP20X_GPIO1_ADC_IRQ_FAL 0x87
+#define AXP20X_TIMER_CTRL 0x8a
+#define AXP20X_VBUS_MON 0x8b
+#define AXP20X_OVER_TMP 0x8f
+
+/* GPIO */
+#define AXP20X_GPIO0_CTRL 0x90
+#define AXP20X_LDO5_V_OUT 0x91
+#define AXP20X_GPIO1_CTRL 0x92
+#define AXP20X_GPIO2_CTRL 0x93
+#define AXP20X_GPIO20_SS 0x94
+#define AXP20X_GPIO3_CTRL 0x95
+
+/* Battery */
+#define AXP20X_CHRG_CC_31_24 0xb0
+#define AXP20X_CHRG_CC_23_16 0xb1
+#define AXP20X_CHRG_CC_15_8 0xb2
+#define AXP20X_CHRG_CC_7_0 0xb3
+#define AXP20X_DISCHRG_CC_31_24 0xb4
+#define AXP20X_DISCHRG_CC_23_16 0xb5
+#define AXP20X_DISCHRG_CC_15_8 0xb6
+#define AXP20X_DISCHRG_CC_7_0 0xb7
+#define AXP20X_CC_CTRL 0xb8
+#define AXP20X_FG_RES 0xb9
+
+/* Regulators IDs */
+enum {
+ AXP20X_LDO1 = 0,
+ AXP20X_LDO2,
+ AXP20X_LDO3,
+ AXP20X_LDO4,
+ AXP20X_LDO5,
+ AXP20X_DCDC2,
+ AXP20X_DCDC3,
+ AXP20X_REG_ID_MAX,
+};
+
+/* IRQs */
+enum {
+ AXP20X_IRQ_ACIN_OVER_V = 1,
+ AXP20X_IRQ_ACIN_PLUGIN,
+ AXP20X_IRQ_ACIN_REMOVAL,
+ AXP20X_IRQ_VBUS_OVER_V,
+ AXP20X_IRQ_VBUS_PLUGIN,
+ AXP20X_IRQ_VBUS_REMOVAL,
+ AXP20X_IRQ_VBUS_V_LOW,
+ AXP20X_IRQ_BATT_PLUGIN,
+ AXP20X_IRQ_BATT_REMOVAL,
+ AXP20X_IRQ_BATT_ENT_ACT_MODE,
+ AXP20X_IRQ_BATT_EXIT_ACT_MODE,
+ AXP20X_IRQ_CHARG,
+ AXP20X_IRQ_CHARG_DONE,
+ AXP20X_IRQ_BATT_TEMP_HIGH,
+ AXP20X_IRQ_BATT_TEMP_LOW,
+ AXP20X_IRQ_DIE_TEMP_HIGH,
+ AXP20X_IRQ_CHARG_I_LOW,
+ AXP20X_IRQ_DCDC1_V_LONG,
+ AXP20X_IRQ_DCDC2_V_LONG,
+ AXP20X_IRQ_DCDC3_V_LONG,
+ AXP20X_IRQ_PEK_SHORT = 22,
+ AXP20X_IRQ_PEK_LONG,
+ AXP20X_IRQ_N_OE_PWR_ON,
+ AXP20X_IRQ_N_OE_PWR_OFF,
+ AXP20X_IRQ_VBUS_VALID,
+ AXP20X_IRQ_VBUS_NOT_VALID,
+ AXP20X_IRQ_VBUS_SESS_VALID,
+ AXP20X_IRQ_VBUS_SESS_END,
+ AXP20X_IRQ_LOW_PWR_LVL1,
+ AXP20X_IRQ_LOW_PWR_LVL2,
+ AXP20X_IRQ_TIMER,
+ AXP20X_IRQ_PEK_RIS_EDGE,
+ AXP20X_IRQ_PEK_FAL_EDGE,
+ AXP20X_IRQ_GPIO3_INPUT,
+ AXP20X_IRQ_GPIO2_INPUT,
+ AXP20X_IRQ_GPIO1_INPUT,
+ AXP20X_IRQ_GPIO0_INPUT,
+};
+
+struct axp20x_dev {
+ struct device *dev;
+ struct i2c_client *i2c_client;
+ struct regmap *regmap;
+ struct regmap_irq_chip_data *regmap_irqc;
+ int variant;
+};
+
+#endif /* __LINUX_MFD_AXP20X_H */
--
1.8.3.2
^ permalink raw reply related
* [PATCH v3 02/10] dt-bindings: add vendor-prefix for X-Powers
From: Carlo Caione @ 2014-03-27 21:29 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
hdegoede-H+wXaHxf7aLQT0dZR+AlfA, emilio-0Z03zUJReD5OxF6Tv1QG9Q,
wens-jdAy2FN1RRM, sameo-VuQAYsv1563Yd54FQh9/CA,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A
Cc: Carlo Caione
In-Reply-To: <1395955764-18103-1-git-send-email-carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
Signed-off-by: Carlo Caione <carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
---
Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 40ce2df..d06ba8c 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -95,3 +95,4 @@ winbond Winbond Electronics corp.
wlf Wolfson Microelectronics
wm Wondermedia Technologies, Inc.
xlnx Xilinx
+x-powers X-Powers
--
1.8.3.2
^ permalink raw reply related
* [PATCH v3 03/10] mfd: AXP20x: Add bindings documentation
From: Carlo Caione @ 2014-03-27 21:29 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
hdegoede-H+wXaHxf7aLQT0dZR+AlfA, emilio-0Z03zUJReD5OxF6Tv1QG9Q,
wens-jdAy2FN1RRM, sameo-VuQAYsv1563Yd54FQh9/CA,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A
Cc: Carlo Caione
In-Reply-To: <1395955764-18103-1-git-send-email-carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
Bindings documentation for the AXP20x driver. In this file also
sub-nodes are documented.
Signed-off-by: Carlo Caione <carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
---
Documentation/devicetree/bindings/mfd/axp20x.txt | 83 ++++++++++++++++++++++++
1 file changed, 83 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mfd/axp20x.txt
diff --git a/Documentation/devicetree/bindings/mfd/axp20x.txt b/Documentation/devicetree/bindings/mfd/axp20x.txt
new file mode 100644
index 0000000..ebc6772
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/axp20x.txt
@@ -0,0 +1,83 @@
+* axp20x device tree bindings
+
+The axp20x family current members :-
+axp202 (X-Powers)
+axp209 (X-Powers)
+
+Required properties:
+- compatible : Should be "x-powers,axp202" or "x-powers,axp209"
+- interrupt-controller : axp20x has its own internal IRQs
+- #interrupt-cells : Should be set to 1
+- interrupt-parent : The parent interrupt controller
+- interrupts : Interrupt specifiers for interrupt sources
+- reg : The I2C slave address for the AXP chip
+
+Sub-nodes:
+* regulators : Contain the regulator nodes. The regulators are bound using
+ their name as listed here: dcdc2, dcdc3, ldo1, ldo2, ldo3,
+ ldo4, ldo5.
+ The bindings details of individual regulator device can be found in:
+ Documentation/devicetree/bindings/regulator/regulator.txt with the
+ exception of:
+
+ - x-powers,dcdc-freq : defines the work frequency of DC-DC in KHz
+ (range: 750-1875). Default: 1.5MHz
+
+ For each DCDC:
+ - x-powers,dcdc-workmode: Optional. 1 for PWM mode, 0 for AUTO mode
+ Default: AUTO mode
+
+Example:
+
+axp: axp20x@34 {
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 8>;
+
+ compatible = "x-powers,axp209";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ regulators {
+ dcdc-freq = <1500>;
+
+ axp_dcdc2: dcdc2 {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <2275000>;
+ regulator-always-on;
+ };
+
+ axp_dcdc3: dcdc3 {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <3500000>;
+ regulator-always-on;
+ };
+
+ axp_ldo1: ldo1 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ };
+
+ axp_ldo2: ldo2 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ axp_ldo3: ldo3 {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <3500000>;
+ };
+
+ axp_ldo4: ldo4 {
+ regulator-min-microvolt = <1250000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ axp_ldo5: ldo5 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+ };
+};
+
--
1.8.3.2
^ permalink raw reply related
* [PATCH v3 04/10] input: misc: Add driver for AXP20x Power Enable Key
From: Carlo Caione @ 2014-03-27 21:29 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
hdegoede-H+wXaHxf7aLQT0dZR+AlfA, emilio-0Z03zUJReD5OxF6Tv1QG9Q,
wens-jdAy2FN1RRM, sameo-VuQAYsv1563Yd54FQh9/CA,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A
Cc: Carlo Caione
In-Reply-To: <1395955764-18103-1-git-send-email-carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
This patch add support for the Power Enable Key found on MFD AXP202 and
AXP209. Besides the basic support for the button, the driver adds two
entries in sysfs to configure the time delay for power on/off.
Signed-off-by: Carlo Caione <carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
---
drivers/input/misc/Kconfig | 11 ++
drivers/input/misc/Makefile | 1 +
drivers/input/misc/axp20x-pek.c | 260 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 272 insertions(+)
create mode 100644 drivers/input/misc/axp20x-pek.c
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 7904ab0..87244fb 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -393,6 +393,17 @@ config INPUT_RETU_PWRBUTTON
To compile this driver as a module, choose M here. The module will
be called retu-pwrbutton.
+config INPUT_AXP20X_PEK
+ tristate "X-Powers AXP20X power button driver"
+ depends on MFD_AXP20X
+ help
+ Say Y here if you want to enable power key reporting via the
+ AXP20X PMIC.
+
+ To compile this driver as a module, choose M here. The module will
+ be called axp20x-pek.
+
+
config INPUT_TWL4030_PWRBUTTON
tristate "TWL4030 Power button Driver"
depends on TWL4030_CORE
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index cda71fc..624abf5 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o
+obj-$(CONFIG_INPUT_AXP20X_PEK) += axp20x-pek.o
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o
diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c
new file mode 100644
index 0000000..6698a69
--- /dev/null
+++ b/drivers/input/misc/axp20x-pek.c
@@ -0,0 +1,260 @@
+/*
+ * axp20x power button driver.
+ *
+ * Copyright (C) 2013 Carlo Caione <carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * 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.
+ */
+
+#include <linux/errno.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/axp20x.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define AXP20X_PEK_STARTUP_MASK (0xc0)
+#define AXP20X_PEK_SHUTDOWN_MASK (0x03)
+
+static const char const *startup_time[] = { "128ms", "3s" , "1s", "2s" };
+static const char const *shutdown_time[] = { "4s", "6s" , "8s", "10s" };
+
+struct axp20x_pek {
+ struct axp20x_dev *axp20x;
+ struct input_dev *input;
+ int irq_dbr;
+ int irq_dbf;
+};
+
+struct axp20x_pek_ext_attr {
+ const char const **str;
+ unsigned int mask;
+};
+
+static struct axp20x_pek_ext_attr axp20x_pek_startup_ext_attr = {
+ .str = startup_time,
+ .mask = AXP20X_PEK_STARTUP_MASK,
+};
+
+static struct axp20x_pek_ext_attr axp20x_pek_shutdown_ext_attr = {
+ .str = shutdown_time,
+ .mask = AXP20X_PEK_SHUTDOWN_MASK,
+};
+
+static struct axp20x_pek_ext_attr *get_axp_ext_attr(struct device_attribute *attr)
+{
+ return container_of(attr, struct dev_ext_attribute, attr)->var;
+}
+
+static ssize_t axp20x_show_ext_attr(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
+ struct axp20x_pek_ext_attr *axp20x_ea = get_axp_ext_attr(attr);
+ unsigned int val;
+ int ret, i;
+ int cnt = 0;
+
+ ret = regmap_read(axp20x_pek->axp20x->regmap, AXP20X_PEK_KEY, &val);
+ if (ret != 0)
+ return ret;
+
+ val &= axp20x_ea->mask;
+ val >>= ffs(axp20x_ea->mask) - 1;
+
+ for (i = 0; i < 4; i++) {
+ if (val == i)
+ cnt += sprintf(buf + cnt, "[%s] ", axp20x_ea->str[i]);
+ else
+ cnt += sprintf(buf + cnt, "%s ", axp20x_ea->str[i]);
+ }
+
+ cnt += sprintf(buf + cnt, "\n");
+
+ return cnt;
+}
+
+static ssize_t axp20x_store_ext_attr(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
+ struct axp20x_pek_ext_attr *axp20x_ea = get_axp_ext_attr(attr);
+ char val_str[20];
+ int ret, i;
+ size_t len;
+
+ val_str[sizeof(val_str) - 1] = '\0';
+ strncpy(val_str, buf, sizeof(val_str) - 1);
+ len = strlen(val_str);
+
+ if (len && val_str[len - 1] == '\n')
+ val_str[len - 1] = '\0';
+
+ for (i = 0; i < 4; i++) {
+ if (!strcmp(val_str, axp20x_ea->str[i])) {
+
+ i <<= ffs(axp20x_ea->mask) - 1;
+ ret = regmap_update_bits(axp20x_pek->axp20x->regmap,
+ AXP20X_PEK_KEY,
+ axp20x_ea->mask, i);
+ if (ret != 0)
+ return -EINVAL;
+ return count;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static struct dev_ext_attribute axp20x_dev_attr_startup = {
+ .attr = __ATTR(startup, 0644, axp20x_show_ext_attr, axp20x_store_ext_attr),
+ .var = &axp20x_pek_startup_ext_attr
+};
+
+static struct dev_ext_attribute axp20x_dev_attr_shutdown = {
+ __ATTR(shutdown, 0644, axp20x_show_ext_attr, axp20x_store_ext_attr),
+ &axp20x_pek_shutdown_ext_attr
+};
+
+static struct attribute *dev_attrs[] = {
+ &axp20x_dev_attr_startup.attr.attr,
+ &axp20x_dev_attr_shutdown.attr.attr,
+ NULL,
+};
+
+static struct attribute_group dev_attr_group = {
+ .attrs = dev_attrs,
+};
+
+static const struct attribute_group *dev_attr_groups[] = {
+ &dev_attr_group,
+ NULL,
+};
+
+static irqreturn_t axp20x_pek_irq(int irq, void *pwr)
+{
+ struct input_dev *idev = pwr;
+ struct axp20x_pek *axp20x_pek = input_get_drvdata(idev);
+
+ if (irq == axp20x_pek->irq_dbr)
+ input_report_key(idev, KEY_POWER, true);
+ else if (irq == axp20x_pek->irq_dbf)
+ input_report_key(idev, KEY_POWER, false);
+
+ input_sync(idev);
+
+ return IRQ_HANDLED;
+}
+
+static int axp20x_pek_probe(struct platform_device *pdev)
+{
+ struct axp20x_pek *axp20x_pek;
+ struct axp20x_dev *axp20x;
+ struct input_dev *idev;
+ int error;
+
+ axp20x_pek = devm_kzalloc(&pdev->dev, sizeof(struct axp20x_pek),
+ GFP_KERNEL);
+ if (!axp20x_pek)
+ return -ENOMEM;
+
+ axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent);
+ axp20x = axp20x_pek->axp20x;
+
+ axp20x_pek->irq_dbr = platform_get_irq_byname(pdev, "PEK_DBR");
+ if (axp20x_pek->irq_dbr < 0) {
+ dev_err(&pdev->dev, "No IRQ for PEK_DBR, error=%d\n",
+ axp20x_pek->irq_dbr);
+ return axp20x_pek->irq_dbr;
+ }
+ axp20x_pek->irq_dbr = regmap_irq_get_virq(axp20x->regmap_irqc,
+ axp20x_pek->irq_dbr);
+
+ axp20x_pek->irq_dbf = platform_get_irq_byname(pdev, "PEK_DBF");
+ if (axp20x_pek->irq_dbf < 0) {
+ dev_err(&pdev->dev, "No IRQ for PEK_DBF, error=%d\n",
+ axp20x_pek->irq_dbf);
+ return axp20x_pek->irq_dbf;
+ }
+ axp20x_pek->irq_dbf = regmap_irq_get_virq(axp20x->regmap_irqc,
+ axp20x_pek->irq_dbf);
+
+ axp20x_pek->input = devm_input_allocate_device(&pdev->dev);
+ if (!axp20x_pek->input)
+ return -ENOMEM;
+
+ idev = axp20x_pek->input;
+
+ idev->name = "axp20x-pek";
+ idev->phys = "m1kbd/input2";
+ idev->dev.parent = &pdev->dev;
+
+ input_set_capability(idev, EV_KEY, KEY_POWER);
+
+ input_set_drvdata(idev, axp20x_pek);
+
+ error = devm_request_threaded_irq(&pdev->dev, axp20x_pek->irq_dbr,
+ NULL, axp20x_pek_irq, 0,
+ "axp20x-pek-dbr", idev);
+ if (error) {
+ dev_err(axp20x->dev, "Failed to request dbr IRQ#%d: %d\n",
+ axp20x_pek->irq_dbr, error);
+
+ return error;
+ }
+
+ error = devm_request_threaded_irq(&pdev->dev, axp20x_pek->irq_dbf,
+ NULL, axp20x_pek_irq, 0,
+ "axp20x-pek-dbf", idev);
+ if (error) {
+ dev_err(axp20x->dev, "Failed to request dbf IRQ#%d: %d\n",
+ axp20x_pek->irq_dbf, error);
+ return error;
+ }
+
+ idev->dev.groups = dev_attr_groups;
+ error = input_register_device(idev);
+ if (error) {
+ dev_err(axp20x->dev, "Can't register input device: %d\n", error);
+ return error;
+ }
+
+ platform_set_drvdata(pdev, axp20x_pek);
+
+ return 0;
+}
+
+static int axp20x_pek_remove(struct platform_device *pdev)
+{
+ struct axp20x_pek *axp20x_pek = platform_get_drvdata(pdev);
+
+ input_unregister_device(axp20x_pek->input);
+
+ return 0;
+}
+
+static struct platform_driver axp20x_pek_driver = {
+ .probe = axp20x_pek_probe,
+ .remove = axp20x_pek_remove,
+ .driver = {
+ .name = "axp20x-pek",
+ .owner = THIS_MODULE,
+ },
+};
+module_platform_driver(axp20x_pek_driver);
+
+MODULE_DESCRIPTION("axp20x Power Button");
+MODULE_AUTHOR("Carlo Caione <carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>");
+MODULE_LICENSE("GPL");
--
1.8.3.2
^ permalink raw reply related
* [PATCH v3 07/10] ARM: sunxi: dt: Add x-powers-axp209.dtsi file
From: Carlo Caione @ 2014-03-27 21:29 UTC (permalink / raw)
To: linux-arm-kernel, linux-sunxi, maxime.ripard, hdegoede, emilio,
wens, sameo, dmitry.torokhov, linux-input, linux-doc, lgirdwood,
broonie
Cc: Carlo Caione
In-Reply-To: <1395955764-18103-1-git-send-email-carlo@caione.org>
This dtsi describes the axp209 PMIC, and is to be included from inside
the i2c controller node to which the axp209 is connected.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Carlo Caione <carlo@caione.org>
---
arch/arm/boot/dts/x-powers-axp209.dtsi | 54 ++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
create mode 100644 arch/arm/boot/dts/x-powers-axp209.dtsi
diff --git a/arch/arm/boot/dts/x-powers-axp209.dtsi b/arch/arm/boot/dts/x-powers-axp209.dtsi
new file mode 100644
index 0000000..b05e54d
--- /dev/null
+++ b/arch/arm/boot/dts/x-powers-axp209.dtsi
@@ -0,0 +1,54 @@
+/*
+ * x-powers,axp209 common code to be include from inside the axp209 node
+ *
+ * Copyright 2014 - Carlo Caione <carlo@caione.org>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+regulators {
+ dcdc-freq = <1500>;
+
+ axp_dcdc2: dcdc2 {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <2275000>;
+ regulator-always-on;
+ };
+
+ axp_dcdc3: dcdc3 {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <3500000>;
+ regulator-always-on;
+ };
+
+ axp_ldo1: ldo1 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ };
+
+ axp_ldo2: ldo2 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ axp_ldo3: ldo3 {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <3500000>;
+ };
+
+ axp_ldo4: ldo4 {
+ regulator-min-microvolt = <1250000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ axp_ldo5: ldo5 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+};
--
1.8.3.2
^ permalink raw reply related
* [PATCH v3 08/10] ARM: sun7i/sun4i: dt: Add AXP209 support to various boards
From: Carlo Caione @ 2014-03-27 21:29 UTC (permalink / raw)
To: linux-arm-kernel, linux-sunxi, maxime.ripard, hdegoede, emilio,
wens, sameo, dmitry.torokhov, linux-input, linux-doc, lgirdwood,
broonie
Cc: Carlo Caione
In-Reply-To: <1395955764-18103-1-git-send-email-carlo@caione.org>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Carlo Caione <carlo@caione.org>
---
arch/arm/boot/dts/sun4i-a10-a1000.dts | 13 +++++++++++++
arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 13 +++++++++++++
arch/arm/boot/dts/sun4i-a10-hackberry.dts | 19 +++++++++++++++++++
arch/arm/boot/dts/sun4i-a10-inet97fv2.dts | 13 +++++++++++++
arch/arm/boot/dts/sun4i-a10-mini-xplus.dts | 19 +++++++++++++++++++
arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts | 19 +++++++++++++++++++
arch/arm/boot/dts/sun4i-a10-pcduino.dts | 13 +++++++++++++
arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 14 ++++++++++++++
arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 15 +++++++++++++++
arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 14 ++++++++++++++
10 files changed, 152 insertions(+)
diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts
index fa746aea..cf18c4d 100644
--- a/arch/arm/boot/dts/sun4i-a10-a1000.dts
+++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts
@@ -88,6 +88,19 @@
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins_a>;
status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ axp: axp20x@34 {
+ reg = <0x34>;
+ interrupts = <0>;
+
+ compatible = "x-powers,axp209";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ /include/ "x-powers-axp209.dtsi"
+ };
};
};
diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
index 4684cbe..52d21bb 100644
--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
@@ -80,6 +80,19 @@
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins_a>;
status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ axp: axp20x@34 {
+ reg = <0x34>;
+ interrupts = <0>;
+
+ compatible = "x-powers,axp209";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ /include/ "x-powers-axp209.dtsi"
+ };
};
i2c1: i2c@01c2b000 {
diff --git a/arch/arm/boot/dts/sun4i-a10-hackberry.dts b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
index d7c17e4..3960d67 100644
--- a/arch/arm/boot/dts/sun4i-a10-hackberry.dts
+++ b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
@@ -82,6 +82,25 @@
pinctrl-0 = <&uart0_pins_a>;
status = "okay";
};
+
+ i2c0: i2c@01c2ac00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ axp: axp20x@34 {
+ reg = <0x34>;
+ interrupts = <0>;
+
+ compatible = "x-powers,axp209";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ /include/ "x-powers-axp209.dtsi"
+ };
+ };
};
reg_emac_3v3: emac-3v3 {
diff --git a/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts b/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
index fe9272e..c797f5c 100644
--- a/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
+++ b/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
@@ -34,6 +34,19 @@
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins_a>;
status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ axp: axp20x@34 {
+ reg = <0x34>;
+ interrupts = <0>;
+
+ compatible = "x-powers,axp209";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ /include/ "x-powers-axp209.dtsi"
+ };
};
usbphy: phy@01c13400 {
diff --git a/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts b/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
index dd84a9e..c61902d 100644
--- a/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
+++ b/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
@@ -47,6 +47,25 @@
pinctrl-0 = <&uart0_pins_a>;
status = "okay";
};
+
+ i2c0: i2c@01c2ac00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ axp: axp20x@34 {
+ reg = <0x34>;
+ interrupts = <0>;
+
+ compatible = "x-powers,axp209";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ /include/ "x-powers-axp209.dtsi"
+ };
+ };
};
reg_usb1_vbus: usb1-vbus {
diff --git a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
index 66cf0c7..7e862d6 100644
--- a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
+++ b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
@@ -81,6 +81,25 @@
pinctrl-0 = <&uart0_pins_a>;
status = "okay";
};
+
+ i2c0: i2c@01c2ac00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ axp: axp20x@34 {
+ reg = <0x34>;
+ interrupts = <0>;
+
+ compatible = "x-powers,axp209";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ /include/ "x-powers-axp209.dtsi"
+ };
+ };
};
leds {
diff --git a/arch/arm/boot/dts/sun4i-a10-pcduino.dts b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
index 255b47e..8ad0a86 100644
--- a/arch/arm/boot/dts/sun4i-a10-pcduino.dts
+++ b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
@@ -66,6 +66,19 @@
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins_a>;
status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ axp: axp20x@34 {
+ reg = <0x34>;
+ interrupts = <0>;
+
+ compatible = "x-powers,axp209";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ /include/ "x-powers-axp209.dtsi"
+ };
};
};
diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
index 68de89f..c5c91b8 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
@@ -66,6 +66,20 @@
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins_a>;
status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ axp: axp20x@34 {
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 8>;
+
+ compatible = "x-powers,axp209";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ /include/ "x-powers-axp209.dtsi"
+ };
};
i2c1: i2c@01c2b000 {
diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
index cb25d3c..a42f5bc 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -73,6 +73,21 @@
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins_a>;
status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ axp: axp20x@34 {
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 8>;
+
+ compatible = "x-powers,axp209";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ /include/ "x-powers-axp209.dtsi"
+ };
+
};
i2c1: i2c@01c2b000 {
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
index eeadf76..63171c4 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
@@ -95,6 +95,20 @@
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins_a>;
status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ axp: axp20x@34 {
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 8>;
+
+ compatible = "x-powers,axp209";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ /include/ "x-powers-axp209.dtsi"
+ };
};
i2c1: i2c@01c2b000 {
--
1.8.3.2
^ permalink raw reply related
* [PATCH v3 09/10] ARM: sunxi: Add AXP20x support in defconfig
From: Carlo Caione @ 2014-03-27 21:29 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
hdegoede-H+wXaHxf7aLQT0dZR+AlfA, emilio-0Z03zUJReD5OxF6Tv1QG9Q,
wens-jdAy2FN1RRM, sameo-VuQAYsv1563Yd54FQh9/CA,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A
Cc: Carlo Caione
In-Reply-To: <1395955764-18103-1-git-send-email-carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
Signed-off-by: Carlo Caione <carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
---
arch/arm/configs/sunxi_defconfig | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
index b5df4a5..6e305da 100644
--- a/arch/arm/configs/sunxi_defconfig
+++ b/arch/arm/configs/sunxi_defconfig
@@ -40,6 +40,8 @@ CONFIG_SUN4I_EMAC=y
# CONFIG_NET_VENDOR_STMICRO is not set
# CONFIG_NET_VENDOR_WIZNET is not set
# CONFIG_WLAN is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_AXP20X_PEK=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=8
@@ -55,6 +57,7 @@ CONFIG_GPIO_SYSFS=y
# CONFIG_HWMON is not set
CONFIG_WATCHDOG=y
CONFIG_SUNXI_WATCHDOG=y
+CONFIG_MFD_AXP20X=y
# CONFIG_USB_SUPPORT is not set
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
@@ -69,3 +72,4 @@ CONFIG_NFS_FS=y
CONFIG_ROOT_NFS=y
CONFIG_NLS=y
CONFIG_PRINTK_TIME=y
+CONFIG_REGULATOR_AXP20X=y
--
1.8.3.2
^ permalink raw reply related
* hid-lg2ff handling of zero/low magnitude rumble effects
From: Elias Vanderstuyft @ 2014-03-27 22:13 UTC (permalink / raw)
To: Simon Wood, Anssi Hannula; +Cc: linux-input
Hi,
I noticed that my rumble wheel (Logitech Formula Vibration Feedback)
reacts in a strange way when sending low rumble magnitudes to the
device:
Assume the following USB command to be send to emit rumble:
report->field[0]->value[0] = 0x51;
report->field[0]->value[2] = weak;
report->field[0]->value[4] = strong;
When 'weak' or 'strong' is lower than 0x02 (i.e. 0x01 or 0x00), then
the corresponding rumble motor begins to rumble intermittently, this
resembles a bit to forcing a 2-state light-switch to be in the middle
position.
Now my question is whether all other devices (e.g. "Logitech
RumblePad", "Rumblepad 2") experience this behaviour?
(If you own such a device, please verify this.)
Best regards,
Elias
^ permalink raw reply
* Re: [PATCH v3 08/10] ARM: sun7i/sun4i: dt: Add AXP209 support to various boards
From: Chen-Yu Tsai @ 2014-03-28 3:12 UTC (permalink / raw)
To: Carlo Caione
Cc: linux-arm-kernel, linux-sunxi, maxime.ripard, Hans De Goede,
Emilio Lopez, sameo, dmitry.torokhov, linux-input, linux-doc,
lgirdwood, broonie
In-Reply-To: <1395955764-18103-9-git-send-email-carlo@caione.org>
On Fri, Mar 28, 2014 at 5:29 AM, Carlo Caione <carlo@caione.org> wrote:
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> Signed-off-by: Carlo Caione <carlo@caione.org>
> ---
> arch/arm/boot/dts/sun4i-a10-a1000.dts | 13 +++++++++++++
> arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 13 +++++++++++++
> arch/arm/boot/dts/sun4i-a10-hackberry.dts | 19 +++++++++++++++++++
> arch/arm/boot/dts/sun4i-a10-inet97fv2.dts | 13 +++++++++++++
> arch/arm/boot/dts/sun4i-a10-mini-xplus.dts | 19 +++++++++++++++++++
> arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts | 19 +++++++++++++++++++
> arch/arm/boot/dts/sun4i-a10-pcduino.dts | 13 +++++++++++++
> arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 14 ++++++++++++++
> arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 15 +++++++++++++++
> arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 14 ++++++++++++++
> 10 files changed, 152 insertions(+)
>
> diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts
> index fa746aea..cf18c4d 100644
> --- a/arch/arm/boot/dts/sun4i-a10-a1000.dts
> +++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts
> @@ -88,6 +88,19 @@
> pinctrl-names = "default";
> pinctrl-0 = <&i2c0_pins_a>;
> status = "okay";
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + axp: axp20x@34 {
Hi,
Sorry for spotting this just now. I suggest you change it to
axp209: pmic@34 {
or
axp209_pmic@34 {
to match the ePAPR policy that node names should be generic and
describe functionality. The latter is what some DTs use.
> + reg = <0x34>;
> + interrupts = <0>;
> +
> + compatible = "x-powers,axp209";
> + interrupt-controller;
> + #interrupt-cells = <1>;
> +
> + /include/ "x-powers-axp209.dtsi"
> + };
> };
> };
>
[...]
Same for all the other files.
Thanks for working on this!
ChenYu
^ permalink raw reply
* Re: [PATCH] input: add support for ALPS v7 protocol device
From: Elaine Chen @ 2014-03-28 3:36 UTC (permalink / raw)
To: Václav Krpec
Cc: Dmitry Torokhov, Kevin Cernekee, david turvene, linux-input,
jclift, Qiting Chen, Justin Clift
In-Reply-To: <20140327111019.9CF5518D@razdva.cz>
Hi Vencik,
(I resend this mail as the previous one failed to be delivered to linput-input)
I got it. You mean a click will mistakenly happen when you do a short
and quick move on touchpad.
Isn't it? I'm afraid this can not be tuned by driver, as tap to click
is recognized by XServer. The driver has few
controls over gesture detection. Actually, it just report coodinate
and finger information.etc. to Linux Input System.
Nevertheless, I'll look for some configurations of input(such as the
registered device size, eg. ABS_X) to see if they
have influence on "tap distance". And if you have any information.
Please let me know. Thank you!
2014-03-27 18:10 GMT+08:00 <vencik@razdva.cz>:
> Another clue: the odd behaviour described below disappears
> if I switch tap-to-click off in synaptics X11 driver
> (but no tap-to-click functionality, then, of course).
>
> vencik
>
> ______________________________________________________________
>> Od: <vencik@razdva.cz>
>> Komu: Elaine Chen <elaineee66@gmail.com>
>> Datum: 27.03.2014 10:58
>> Předmět: Re: [PATCH] input: add support for ALPS v7 protocol device
>>
>> CC: "Dmitry Torokhov" <dmitry.torokhov@gmail.com>, "Kevin Cernekee" <cernekee@gmail.com>, "david turvene" <dturvene@dahetral.com>, linux-input@vger.kernel.org, "Niels de Vos" <ndevos@redhat.com>, jclift@redhat.com--cc, "Qiting Chen" <qiting.chen@cn.alps.com>, "Justin Clift" <justin@gluster.org>
>>Hi again, Elaine,
>>
>>just something to add to the TP driver functionality;
>>I've experienced something that looked as involuntary left
>>button clicking.
>>
>>Using xev, I deduce that it happens when I remove the finger
>>after doing just a short motion on the pad; if the motion is longer
>>(apparently both in in distance and time) the click is not generated
>>at the end.
>>But when I do just a short and quite quick move, it produces a click.
>>
>>Perhaps it's just necessary to tune the driver a bit; what I'm talking about
>>is something close to a tap, but past it; the motion may take about 1/2 second
>>and the cursor moves for about a centimeter...
>>I'll try to identify the code bit responsible and play with that.
>>
>>Regards,
>>
>>vencik
>>
>>
>>______________________________________________________________
>>> Od: Elaine Chen <elaineee66@gmail.com>
>>> Komu: "Václav Krpec" <vencik@razdva.cz>
>>> Datum: 27.03.2014 08:57
>>> Předmět: Re: [PATCH] input: add support for ALPS v7 protocol device
>>>
>>> CC: "Dmitry Torokhov" <dmitry.torokhov@gmail.com>, "Kevin Cernekee" <cernekee@gmail.com>, "david turvene" <dturvene@dahetral.com>, linux-input@vger.kernel.org, "Niels de Vos" <ndevos@redhat.com>, jclift@redhat.com--cc, "Qiting Chen" <qiting.chen@cn.alps.com>, "Justin Clift" <justin@gluster.org>
>>>Hello Vencik,
>>>
>>>Thank you for evaluating the patch.
>>>
>>>1/ About stickpoint support
>>>Yes, this patch hasn't added stickpoint support for v7 protocol device.
>>>What's the SP behavior on your Toshiba laptop after
>>>applying our patch? No function or works abnormally? Please let me know the
>>>phenomenon as I don't have a v7 TP/SP dual device currently.
>>>I also checked your stickpoint process code. The SP packet decode seems
>>>doesn't match the format of Specification. Sorry I haven't tested it as
>>>lack of
>>>device.Did it work on your machine?
>>>I'll get down to support for SP next week I got such a device. And will
>>>release it with next patch.
>>>
>>>2/ This patch is against Dmitry Torokhov's input tree(3.13-rc4)
>>>https://git.kernel.org/cgit/linux/kernel/git/dtor/input.git/
>>>I've checked the alps.(ch) from 3.13-rc4 and 3.14-rc8, they are the same.
>>>Maybe there are something unmatch with patch format.
>>>My patch is made from git format-patch.
>>>
>>>
>>>
>>>2014-03-26 20:20 GMT+08:00 Václav Krpec <vencik@razdva.cz>:
>>>
>>>> Hello Qiting,
>>>>
>>>> I've applied your patch and tested the driver on my Toshiba Portege
>>>> Z30-A-12N (device ID is 73 03 0a, FW ver: 88 b3 22).
>>>>
>>>> The TP driver works nicely, however, I've observed a few things to note:
>>>>
>>>> 1/
>>>> There's no support for trackstick; my device has one.
>>>> Justin has suggested that it may be a Toshiba mod of the device...
>>>> Nevertheless, since I was in process of RA of the device myself before
>>>> you've committed the patch, I merged the TS driver to your patch;
>>>> see alps_process_trackstick_packet_v7 function + tiny bit of
>>>> refactoring of the packet ID resolving mechanism in the patch attached.
>>>> I hope it shouldn't break the driver functionality for devices w/o
>>>> the trackstick, but testing should definitely be done.
>>>>
>>>> 2/
>>>> I've noticed that your patch wasn't cleanly applicable to current 3.14
>>>> kernel; could you be more specific on what branch should it be applied?
>>>> The patch attached is valid for 3.14-rc8 tree.
>>>>
>>>> 3/
>>>> I also took the liberty of fixing indentation of your code a bit to put
>>>> it (hopefully) more in line with the conventions of the alps.[ch]
>>>>
>>>> So, could you (or anyone else) test the patch attached?
>>>> Comments, recommendations etc welcome.
>>>>
>>>> Thanks,
>>>>
>>>> Best regards
>>>>
>>>> vencik
>>>>
>>>>
>>>>
>>>> On Wed, 2014-03-19 at 16:55 +0800, Qiting Chen wrote:
>>>> > Here is a patch of supporting ALPS v7 protocol device.
>>>> > ALPS v7 protocol device is a clickpad that is currently used on
>>>> > Lenovo S430/S435/S530, Lenovo Z410/Z510, HP Odie, HP Revolve 810 G1,
>>>> > as well as other machines with ALPS Touchpad of following infomation:
>>>> > Device ID = 0x73, 0x03, 0x0a
>>>> > Firmware ID = 0x88, 0xb*, 0x**
>>>> >
>>>> > A v7 protocol support patch is first relesed 2 months ago:
>>>> > http://www.spinics.net/lists/linux-input/msg29084.html
>>>> > After that some feedbacks were received from end user. Now this patch
>>>> fixed the bugs
>>>> > reported by them:
>>>> > 1) Fix cursor jump when doing a right click drag
>>>> > 2) Fix cursor jitter when button clicking
>>>> >
>>>> > Signed-off-by: Qiting Chen <qiting.chen@cn.alps.com>
>>>> > ---
>>>> > drivers/input/mouse/alps.c | 560
>>>> ++++++++++++++++++++++++++++++++++++++++++---
>>>> > drivers/input/mouse/alps.h | 132 +++++++++--
>>>> > 2 files changed, 641 insertions(+), 51 deletions(-)
>>>> >
>>>> > diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
>>>> > index fb15c64..383281f 100644
>>>> > --- a/drivers/input/mouse/alps.c
>>>> > +++ b/drivers/input/mouse/alps.c
>>>> > @@ -32,6 +32,13 @@
>>>> > #define ALPS_REG_BASE_RUSHMORE 0xc2c0
>>>> > #define ALPS_REG_BASE_PINNACLE 0x0000
>>>> >
>>>> > +#define LEFT_BUTTON_BIT 0x01
>>>> > +#define RIGHT_BUTTON_BIT 0x02
>>>> > +
>>>> > +#define V7_LARGE_MOVEMENT 130
>>>> > +#define V7_DEAD_ZONE_OFFSET_X 72
>>>> > +#define V7_DEAD_ZONE_OFFSET_Y 72
>>>> > +
>>>> > static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
>>>> > { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */
>>>> > { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
>>>> > @@ -99,6 +106,7 @@ static const struct alps_nibble_commands
>>>> alps_v6_nibble_commands[] = {
>>>> > #define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */
>>>> > #define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved
>>>> with
>>>> > 6-byte ALPS packet */
>>>> > +#define ALPS_BTNLESS 0x100 /* ALPS ClickPad flag */
>>>> >
>>>> > static const struct alps_model_info alps_model_data[] = {
>>>> > { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS
>>>> | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
>>>> > @@ -140,6 +148,20 @@ static void alps_set_abs_params_mt(struct alps_data
>>>> *priv,
>>>> > * isn't valid per PS/2 spec.
>>>> > */
>>>> >
>>>> > +static unsigned int alps_pt_distance(struct alps_abs_data *pt0,
>>>> > + struct alps_abs_data *pt1)
>>>> > +{
>>>> > + int vect_x, vect_y;
>>>> > +
>>>> > + if (!pt0 || !pt1)
>>>> > + return 0;
>>>> > +
>>>> > + vect_x = pt0->x - pt1->x;
>>>> > + vect_y = pt0->y - pt1->y;
>>>> > +
>>>> > + return int_sqrt(vect_x * vect_x + vect_y * vect_y);
>>>> > +}
>>>> > +
>>>> > /* Packet formats are described in Documentation/input/alps.txt */
>>>> >
>>>> > static bool alps_is_valid_first_byte(struct alps_data *priv,
>>>> > @@ -320,8 +342,8 @@ static void alps_process_bitmap_dolphin(struct
>>>> alps_data *priv,
>>>> > end_bit = y_msb - 1;
>>>> > box_middle_y = (priv->y_max * (start_bit + end_bit)) /
>>>> > (2 * (priv->y_bits - 1));
>>>> > - *x1 = fields->x;
>>>> > - *y1 = fields->y;
>>>> > + *x1 = fields->pt.x;
>>>> > + *y1 = fields->pt.y;
>>>> > *x2 = 2 * box_middle_x - *x1;
>>>> > *y2 = 2 * box_middle_y - *y1;
>>>> > }
>>>> > @@ -461,6 +483,38 @@ static void alps_report_semi_mt_data(struct
>>>> input_dev *dev, int num_fingers,
>>>> > alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
>>>> > }
>>>> >
>>>> > +static void alps_report_coord_and_btn(struct psmouse *psmouse,
>>>> > + struct alps_fields *f)
>>>> > +{
>>>> > + struct input_dev *dev;
>>>> > +
>>>> > + if (!psmouse || !f)
>>>> > + return;
>>>> > +
>>>> > + dev = psmouse->dev;
>>>> > +
>>>> > + if (f->fingers) {
>>>> > + input_report_key(dev, BTN_TOUCH, 1);
>>>> > + alps_report_semi_mt_data(dev, f->fingers,
>>>> > + f->pt_img[0].x, f->pt_img[0].y,
>>>> > + f->pt_img[1].x, f->pt_img[1].y);
>>>> > + input_mt_report_finger_count(dev, f->fingers);
>>>> > +
>>>> > + input_report_abs(dev, ABS_X, f->pt_img[0].x);
>>>> > + input_report_abs(dev, ABS_Y, f->pt_img[0].y);
>>>> > + input_report_abs(dev, ABS_PRESSURE, f->pt_img[0].z);
>>>> > + } else {
>>>> > + input_report_key(dev, BTN_TOUCH, 0);
>>>> > + input_mt_report_finger_count(dev, 0);
>>>> > + input_report_abs(dev, ABS_PRESSURE, 0);
>>>> > + }
>>>> > +
>>>> > + input_report_key(dev, BTN_LEFT, f->btn.left);
>>>> > + input_report_key(dev, BTN_RIGHT, f->btn.right);
>>>> > +
>>>> > + input_sync(dev);
>>>> > +}
>>>> > +
>>>> > static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
>>>> > {
>>>> > struct alps_data *priv = psmouse->private;
>>>> > @@ -523,13 +577,13 @@ static void
>>>> alps_process_trackstick_packet_v3(struct psmouse *psmouse)
>>>> >
>>>> > static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char
>>>> *p)
>>>> > {
>>>> > - f->left = !!(p[3] & 0x01);
>>>> > - f->right = !!(p[3] & 0x02);
>>>> > - f->middle = !!(p[3] & 0x04);
>>>> > + f->btn.left = !!(p[3] & 0x01);
>>>> > + f->btn.right = !!(p[3] & 0x02);
>>>> > + f->btn.middle = !!(p[3] & 0x04);
>>>> >
>>>> > - f->ts_left = !!(p[3] & 0x10);
>>>> > - f->ts_right = !!(p[3] & 0x20);
>>>> > - f->ts_middle = !!(p[3] & 0x40);
>>>> > + f->btn.ts_left = !!(p[3] & 0x10);
>>>> > + f->btn.ts_right = !!(p[3] & 0x20);
>>>> > + f->btn.ts_middle = !!(p[3] & 0x40);
>>>> > }
>>>> >
>>>> > static void alps_decode_pinnacle(struct alps_fields *f, unsigned char
>>>> *p,
>>>> > @@ -546,10 +600,10 @@ static void alps_decode_pinnacle(struct
>>>> alps_fields *f, unsigned char *p,
>>>> > ((p[2] & 0x7f) << 1) |
>>>> > (p[4] & 0x01);
>>>> >
>>>> > - f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
>>>> > + f->pt.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
>>>> > ((p[0] & 0x30) >> 4);
>>>> > - f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
>>>> > - f->z = p[5] & 0x7f;
>>>> > + f->pt.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
>>>> > + f->pt.z = p[5] & 0x7f;
>>>> >
>>>> > alps_decode_buttons_v3(f, p);
>>>> > }
>>>> > @@ -573,9 +627,9 @@ static void alps_decode_dolphin(struct alps_fields
>>>> *f, unsigned char *p,
>>>> > f->is_mp = !!(p[0] & 0x20);
>>>> >
>>>> > if (!f->is_mp) {
>>>> > - f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
>>>> > - f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
>>>> > - f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
>>>> > + f->pt.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
>>>> > + f->pt.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
>>>> > + f->pt.z = (p[0] & 4) ? 0 : p[5] & 0x7f;
>>>> > alps_decode_buttons_v3(f, p);
>>>> > } else {
>>>> > f->fingers = ((p[0] & 0x6) >> 1 |
>>>> > @@ -687,7 +741,7 @@ static void
>>>> alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>>>> > * with x, y, and z all zero, so these seem to be flukes.
>>>> > * Ignore them.
>>>> > */
>>>> > - if (f.x && f.y && !f.z)
>>>> > + if (f.pt.x && f.pt.y && !f.pt.z)
>>>> > return;
>>>> >
>>>> > /*
>>>> > @@ -695,12 +749,12 @@ static void
>>>> alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>>>> > * to rely on ST data.
>>>> > */
>>>> > if (!fingers) {
>>>> > - x1 = f.x;
>>>> > - y1 = f.y;
>>>> > - fingers = f.z > 0 ? 1 : 0;
>>>> > + x1 = f.pt.x;
>>>> > + y1 = f.pt.y;
>>>> > + fingers = f.pt.z > 0 ? 1 : 0;
>>>> > }
>>>> >
>>>> > - if (f.z >= 64)
>>>> > + if (f.pt.z >= 64)
>>>> > input_report_key(dev, BTN_TOUCH, 1);
>>>> > else
>>>> > input_report_key(dev, BTN_TOUCH, 0);
>>>> > @@ -709,22 +763,22 @@ static void
>>>> alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>>>> >
>>>> > input_mt_report_finger_count(dev, fingers);
>>>> >
>>>> > - input_report_key(dev, BTN_LEFT, f.left);
>>>> > - input_report_key(dev, BTN_RIGHT, f.right);
>>>> > - input_report_key(dev, BTN_MIDDLE, f.middle);
>>>> > + input_report_key(dev, BTN_LEFT, f.btn.left);
>>>> > + input_report_key(dev, BTN_RIGHT, f.btn.right);
>>>> > + input_report_key(dev, BTN_MIDDLE, f.btn.middle);
>>>> >
>>>> > - if (f.z > 0) {
>>>> > - input_report_abs(dev, ABS_X, f.x);
>>>> > - input_report_abs(dev, ABS_Y, f.y);
>>>> > + if (f.pt.z > 0) {
>>>> > + input_report_abs(dev, ABS_X, f.pt.x);
>>>> > + input_report_abs(dev, ABS_Y, f.pt.y);
>>>> > }
>>>> > - input_report_abs(dev, ABS_PRESSURE, f.z);
>>>> > + input_report_abs(dev, ABS_PRESSURE, f.pt.z);
>>>> >
>>>> > input_sync(dev);
>>>> >
>>>> > if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
>>>> > - 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_report_key(dev2, BTN_LEFT, f.btn.ts_left);
>>>> > + input_report_key(dev2, BTN_RIGHT, f.btn.ts_right);
>>>> > + input_report_key(dev2, BTN_MIDDLE, f.btn.ts_middle);
>>>> > input_sync(dev2);
>>>> > }
>>>> > }
>>>> > @@ -916,6 +970,364 @@ static void alps_process_packet_v4(struct psmouse
>>>> *psmouse)
>>>> > input_sync(dev);
>>>> > }
>>>> >
>>>> > +static bool alps_is_valid_package_v7(struct psmouse *psmouse)
>>>> > +{
>>>> > + if ((psmouse->pktcnt == 3) && ((psmouse->packet[2] & 0x40) !=
>>>> 0x40))
>>>> > + return false;
>>>> > + if ((psmouse->pktcnt == 4) && ((psmouse->packet[3] & 0x48) !=
>>>> 0x48))
>>>> > + return false;
>>>> > + if ((psmouse->pktcnt == 6) && ((psmouse->packet[5] & 0x40) != 0x0))
>>>> > + return false;
>>>> > + return true;
>>>> > +}
>>>> > +
>>>> > +static int alps_drop_unsupported_packet_v7(struct psmouse *psmouse)
>>>> > +{
>>>> > + struct alps_data *priv = psmouse->private;
>>>> > + int drop = 1;
>>>> > +
>>>> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW ||
>>>> > + priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
>>>> > + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
>>>> > + priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
>>>> > + drop = 0;
>>>> > +
>>>> > + return drop;
>>>> > +}
>>>> > +
>>>> > +static unsigned char alps_get_packet_id_v7(char *byte)
>>>> > +{
>>>> > + unsigned char packet_id;
>>>> > +
>>>> > + if (byte[4] & 0x40)
>>>> > + packet_id = V7_PACKET_ID_TWO;
>>>> > + else if (byte[4] & 0x01)
>>>> > + packet_id = V7_PACKET_ID_MULTI;
>>>> > + else if ((byte[0] & 0x10) && !(byte[4] & 0x43))
>>>> > + packet_id = V7_PACKET_ID_NEW;
>>>> > + else
>>>> > + packet_id = V7_PACKET_ID_IDLE;
>>>> > +
>>>> > + return packet_id;
>>>> > +}
>>>> > +
>>>> > +static void alps_get_finger_coordinate_v7(struct alps_abs_data *pt,
>>>> > + unsigned char *pkt,
>>>> > + unsigned char pkt_id)
>>>> > +{
>>>> > + if ((pkt_id == V7_PACKET_ID_TWO) ||
>>>> > + (pkt_id == V7_PACKET_ID_MULTI) ||
>>>> > + (pkt_id == V7_PACKET_ID_NEW)) {
>>>> > + pt[0].x = ((pkt[2] & 0x80) << 4);
>>>> > + pt[0].x |= ((pkt[2] & 0x3F) << 5);
>>>> > + pt[0].x |= ((pkt[3] & 0x30) >> 1);
>>>> > + pt[0].x |= (pkt[3] & 0x07);
>>>> > + pt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
>>>> > +
>>>> > + pt[1].x = ((pkt[3] & 0x80) << 4);
>>>> > + pt[1].x |= ((pkt[4] & 0x80) << 3);
>>>> > + pt[1].x |= ((pkt[4] & 0x3F) << 4);
>>>> > + pt[1].y = ((pkt[5] & 0x80) << 3);
>>>> > + pt[1].y |= ((pkt[5] & 0x3F) << 4);
>>>> > +
>>>> > + if (pkt_id == V7_PACKET_ID_TWO) {
>>>> > + pt[1].x &= ~0x000F;
>>>> > + pt[1].y |= 0x000F;
>>>> > + } else if (pkt_id == V7_PACKET_ID_MULTI) {
>>>> > + pt[1].x &= ~0x003F;
>>>> > + pt[1].y &= ~0x0020;
>>>> > + pt[1].y |= ((pkt[4] & 0x02) << 4);
>>>> > + pt[1].y |= 0x001F;
>>>> > + } else if (pkt_id == V7_PACKET_ID_NEW) {
>>>> > + pt[1].x &= ~0x003F;
>>>> > + pt[1].x |= (pkt[0] & 0x20);
>>>> > + pt[1].y |= 0x000F;
>>>> > + }
>>>> > +
>>>> > + pt[0].y = 0x7FF - pt[0].y;
>>>> > + pt[1].y = 0x7FF - pt[1].y;
>>>> > +
>>>> > + pt[0].z = (pt[0].x && pt[0].y) ? 62 : 0;
>>>> > + pt[1].z = (pt[1].x && pt[1].y) ? 62 : 0;
>>>> > + }
>>>> > +}
>>>> > +
>>>> > +static void alps_decode_packet_v7(struct alps_fields *f,
>>>> > + unsigned char *p,
>>>> > + struct psmouse *psmouse)
>>>> > +{
>>>> > + struct alps_data *priv = psmouse->private;
>>>> > + static struct v7_raw prev_r;
>>>> > +
>>>> > + priv->r.v7.pkt_id = alps_get_packet_id_v7(p);
>>>> > +
>>>> > + alps_get_finger_coordinate_v7(f->pt_img, p, priv->r.v7.pkt_id);
>>>> > +
>>>> > + priv->r.v7.rest_left = 0;
>>>> > + priv->r.v7.rest_right = 0;
>>>> > + priv->r.v7.additional_fingers = 0;
>>>> > + priv->phy_btn = 0;
>>>> > +
>>>> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
>>>> > + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI) {
>>>> > + priv->r.v7.rest_left = (p[0] & 0x10) >> 4;
>>>> > + priv->r.v7.rest_right = (p[0] & 0x20) >> 5;
>>>> > + }
>>>> > +
>>>> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
>>>> > + priv->r.v7.additional_fingers = p[5] & 0x03;
>>>> > +
>>>> > + priv->phy_btn = (p[0] & 0x80) >> 7;
>>>> > +
>>>> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO) {
>>>> > + if (f->pt_img[0].z != 0 && f->pt_img[1].z != 0)
>>>> > + priv->r.v7.raw_fn = 2;
>>>> > + else
>>>> > + priv->r.v7.raw_fn = 1;
>>>> > + } else if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
>>>> > + priv->r.v7.raw_fn = 3 + priv->r.v7.additional_fingers;
>>>> > + else if (priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
>>>> > + priv->r.v7.raw_fn = 0;
>>>> > + else if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW)
>>>> > + priv->r.v7.raw_fn = prev_r.raw_fn;
>>>> > +
>>>> > + /* It is a trick to bypass firmware bug of older version
>>>> > + that 'New' Packet is missed when finger number changed.
>>>> > + We fake a 'New' Packet in such cases.*/
>>>> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
>>>> > + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
>>>> > + priv->r.v7.pkt_id == V7_PACKET_ID_IDLE) {
>>>> > + if (priv->r.v7.raw_fn != prev_r.raw_fn)
>>>> > + priv->r.v7.pkt_id = V7_PACKET_ID_NEW;
>>>> > + }
>>>> > +
>>>> > + memcpy(&prev_r, &priv->r.v7, sizeof(struct v7_raw));
>>>> > +}
>>>> > +
>>>> > +static void alps_set_each_pt_attr_v7(struct psmouse *psmouse,
>>>> > + struct alps_abs_data *pt,
>>>> > + struct alps_bl_pt_attr *pt_attr)
>>>> > +{
>>>> > + struct alps_data *priv = psmouse->private;
>>>> > + unsigned int dist;
>>>> > +
>>>> > + if (!pt_attr->is_init_pt_got && pt->z != 0) {
>>>> > + pt_attr->is_init_pt_got = 1;
>>>> > + pt_attr->is_counted = 0;
>>>> > + memcpy(&pt_attr->init_pt, pt, sizeof(pt_attr->init_pt));
>>>> > + }
>>>> > +
>>>> > + if (pt->z != 0) {
>>>> > + if (pt->y < priv->resting_zone_y_min) {
>>>> > + /* A finger is recognized as a non-resting finger
>>>> > + if it's position is outside the resting finger
>>>> zone.*/
>>>> > + pt_attr->zone = ZONE_NORMAL;
>>>> > + pt_attr->is_counted = 1;
>>>> > + } else {
>>>> > + /* A finger is recognized as a resting finger if
>>>> it's
>>>> > + position is inside the resting finger zone and
>>>> there's
>>>> > + no large movement from it's touch down position.*/
>>>> > + pt_attr->zone = ZONE_RESTING;
>>>> > +
>>>> > + if (pt->x > priv->x_max / 2)
>>>> > + pt_attr->zone |= ZONE_RIGHT_BTN;
>>>> > + else
>>>> > + pt_attr->zone |= ZONE_LEFT_BTN;
>>>> > +
>>>> > + /* A resting finger will turn to be a non-resting
>>>> > + finger if it has made large movement from it's
>>>> touch
>>>> > + down position. A non-resting finger will never turn
>>>> > + to a resting finger before it leaves the touchpad
>>>> > + surface.*/
>>>> > + if (pt_attr->is_init_pt_got) {
>>>> > + dist = alps_pt_distance(pt,
>>>> &pt_attr->init_pt);
>>>> > +
>>>> > + if (dist > V7_LARGE_MOVEMENT)
>>>> > + pt_attr->is_counted = 1;
>>>> > + }
>>>> > + }
>>>> > + }
>>>> > +}
>>>> > +
>>>> > +static void alps_set_pt_attr_v7(struct psmouse *psmouse,
>>>> > + struct alps_fields *f)
>>>> > +{
>>>> > + struct alps_data *priv = psmouse->private;
>>>> > + int i;
>>>> > +
>>>> > + switch (priv->r.v7.pkt_id) {
>>>> > + case V7_PACKET_ID_TWO:
>>>> > + case V7_PACKET_ID_MULTI:
>>>> > + for (i = 0; i < V7_IMG_PT_NUM; i++) {
>>>> > + alps_set_each_pt_attr_v7(psmouse,
>>>> > + &f->pt_img[i],
>>>> > + &priv->pt_attr[i]);
>>>> > + }
>>>> > + break;
>>>> > + default:
>>>> > + /*All finger attributes are cleared when packet ID is
>>>> > + 'IDLE', 'New'or other unknown IDs. An 'IDLE' packet
>>>> > + indicates that there's no finger and no button activity.
>>>> > + A 'NEW' packet indicates the finger position in packet
>>>> > + is not continues from previous packet. Such as the
>>>> > + condition there's finger placed or lifted. In these cases,
>>>> > + finger attributes will be reset.*/
>>>> > + memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
>>>> > + break;
>>>> > + }
>>>> > +}
>>>> > +
>>>> > +static void alps_cal_output_finger_num_v7(struct psmouse *psmouse,
>>>> > + struct alps_fields *f)
>>>> > +{
>>>> > + struct alps_data *priv = psmouse->private;
>>>> > + unsigned int fn = 0;
>>>> > + int i;
>>>> > +
>>>> > + switch (priv->r.v7.pkt_id) {
>>>> > + case V7_PACKET_ID_IDLE:
>>>> > + case V7_PACKET_ID_NEW:
>>>> > + /*No finger is reported when packet ID is 'IDLE' or 'New'.
>>>> > + An 'IDLE' packet indicates that there's no finger on
>>>> touchpad.
>>>> > + A 'NEW' packet indicates there's finger placed or lifted.
>>>> > + Finger position of 'New' packet is not continues from the
>>>> > + previous packet.*/
>>>> > + fn = 0;
>>>> > + break;
>>>> > + case V7_PACKET_ID_TWO:
>>>> > + if (f->pt_img[0].z == 0) {
>>>> > + /*The first finger slot is zero when a non-resting
>>>> > + finger lifted and remaining only one resting finger
>>>> > + on touchpad. Hardware report the remaining resting
>>>> > + finger in second slot. This resting is ignored*/
>>>> > + fn = 0;
>>>> > + } else if (f->pt_img[1].z == 0) {
>>>> > + /* The second finger slot is zero if there's
>>>> > + only one finger*/
>>>> > + fn = 1;
>>>> > + } else {
>>>> > + /*All non-resting fingers will be counted to
>>>> report*/
>>>> > + fn = 0;
>>>> > + for (i = 0; i < V7_IMG_PT_NUM; i++) {
>>>> > + if (priv->pt_attr[i].is_counted)
>>>> > + fn++;
>>>> > + }
>>>> > +
>>>> > + /*In the case that both fingers are
>>>> > + resting fingers, report the first one*/
>>>> > + if (!priv->pt_attr[0].is_counted &&
>>>> > + !priv->pt_attr[1].is_counted) {
>>>> > + fn = 1;
>>>> > + }
>>>> > + }
>>>> > + break;
>>>> > + case V7_PACKET_ID_MULTI:
>>>> > + /*A packet ID 'MULTI' indicats that at least 3 non-resting
>>>> > + finger exist.*/
>>>> > + fn = 3 + priv->r.v7.additional_fingers;
>>>> > + break;
>>>> > + }
>>>> > +
>>>> > + f->fingers = fn;
>>>> > +}
>>>> > +
>>>> > +static void alps_button_dead_zone_filter(struct psmouse *psmouse,
>>>> > + struct alps_fields *f,
>>>> > + struct alps_fields *prev_f)
>>>> > +{
>>>> > + struct alps_data *priv = psmouse->private;
>>>> > + int dx, dy;
>>>> > +
>>>> > + if (priv->prev_phy_btn == 0 && priv->phy_btn != 0) {
>>>> > + memcpy(&priv->pt_attr[0].init_dead_pt,
>>>> > + &f->pt_img[0],
>>>> > + sizeof(struct alps_abs_data));
>>>> > + }
>>>> > +
>>>> > + if (priv->pt_attr[0].init_dead_pt.x != 0 &&
>>>> > + priv->pt_attr[0].init_dead_pt.x != 0) {
>>>> > + dx = f->pt_img[0].x -
>>>> priv->pt_attr[0].init_dead_pt.x;
>>>> > + dy = f->pt_img[0].y -
>>>> priv->pt_attr[0].init_dead_pt.y;
>>>> > + if ((abs(dx) > V7_DEAD_ZONE_OFFSET_X) ||
>>>> > + (abs(dy) > V7_DEAD_ZONE_OFFSET_Y)) {
>>>> > + memset(&priv->pt_attr[0].init_dead_pt, 0,
>>>> > + sizeof(struct
>>>> alps_abs_data));
>>>> > + priv->btn_delay_cnt = 0;
>>>> > + } else {
>>>> > + memcpy(&f->pt_img[0],
>>>> > + &prev_f->pt_img[0],
>>>> > + sizeof(struct alps_abs_data));
>>>> > + if (priv->prev_phy_btn == 0 && priv->phy_btn != 0)
>>>> > + priv->btn_delay_cnt = 2;
>>>> > + }
>>>> > + }
>>>> > +
>>>> > + if (priv->btn_delay_cnt > 0) {
>>>> > + f->btn.left = 0;
>>>> > + f->btn.right = 0;
>>>> > + priv->btn_delay_cnt--;
>>>> > + }
>>>> > +}
>>>> > +
>>>> > +static void alps_assign_buttons_v7(struct psmouse *psmouse,
>>>> > + struct alps_fields *f,
>>>> > + struct alps_fields *prev_f)
>>>> > +{
>>>> > + struct alps_data *priv = psmouse->private;
>>>> > +
>>>> > + if (priv->phy_btn) {
>>>> > + if (!priv->prev_phy_btn) {
>>>> > + /* Report a right click as long as there's finger
>>>> on
>>>> > + right button zone. Othrewise, report a left
>>>> click.*/
>>>> > + if (priv->r.v7.rest_right ||
>>>> > + priv->pt_attr[0].zone & ZONE_RIGHT_BTN ||
>>>> > + priv->pt_attr[1].zone & ZONE_RIGHT_BTN) {
>>>> > + f->btn.right = 1;
>>>> > + priv->pressed_btn_bits |= RIGHT_BUTTON_BIT;
>>>> > + } else {
>>>> > + f->btn.left = 1;
>>>> > + priv->pressed_btn_bits |= LEFT_BUTTON_BIT;
>>>> > + }
>>>> > + } else {
>>>> > + if (priv->pressed_btn_bits & RIGHT_BUTTON_BIT)
>>>> > + f->btn.right = 1;
>>>> > + if (priv->pressed_btn_bits & LEFT_BUTTON_BIT)
>>>> > + f->btn.left = 1;
>>>> > + }
>>>> > + } else {
>>>> > + priv->pressed_btn_bits = 0;
>>>> > + f->btn.right = 0;
>>>> > + f->btn.left = 0;
>>>> > + }
>>>> > +
>>>> > + alps_button_dead_zone_filter(psmouse, f, prev_f);
>>>> > +
>>>> > + priv->prev_phy_btn = priv->phy_btn;
>>>> > +}
>>>> > +
>>>> > +static void alps_process_packet_v7(struct psmouse *psmouse)
>>>> > +{
>>>> > + struct alps_data *priv = psmouse->private;
>>>> > + struct alps_fields f = {0};
>>>> > + static struct alps_fields prev_f;
>>>> > + unsigned char *packet = psmouse->packet;
>>>> > +
>>>> > + priv->decode_fields(&f, packet, psmouse);
>>>> > +
>>>> > + if (alps_drop_unsupported_packet_v7(psmouse))
>>>> > + return;
>>>> > +
>>>> > + alps_set_pt_attr_v7(psmouse, &f);
>>>> > +
>>>> > + alps_cal_output_finger_num_v7(psmouse, &f);
>>>> > +
>>>> > + alps_assign_buttons_v7(psmouse, &f, &prev_f);
>>>> > +
>>>> > + alps_report_coord_and_btn(psmouse, &f);
>>>> > +
>>>> > + memcpy(&prev_f, &f, sizeof(struct alps_fields));
>>>> > +}
>>>> > +
>>>> > static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
>>>> > unsigned char packet[],
>>>> > bool report_buttons)
>>>> > @@ -1080,6 +1492,14 @@ static psmouse_ret_t alps_process_byte(struct
>>>> psmouse *psmouse)
>>>> > return PSMOUSE_BAD_DATA;
>>>> > }
>>>> >
>>>> > + if ((priv->proto_version == ALPS_PROTO_V7 &&
>>>> > + !alps_is_valid_package_v7(psmouse))) {
>>>> > + psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
>>>> > + psmouse->pktcnt - 1,
>>>> > + psmouse->packet[psmouse->pktcnt - 1]);
>>>> > + return PSMOUSE_BAD_DATA;
>>>> > + }
>>>> > +
>>>> > if (psmouse->pktcnt == psmouse->pktsize) {
>>>> > priv->process_packet(psmouse);
>>>> > return PSMOUSE_FULL_PACKET;
>>>> > @@ -1192,6 +1612,22 @@ static int alps_rpt_cmd(struct psmouse *psmouse,
>>>> int init_command,
>>>> > return 0;
>>>> > }
>>>> >
>>>> > +static int alps_check_valid_firmware_id(unsigned char id[])
>>>> > +{
>>>> > + int valid = 1;
>>>> > +
>>>> > + if (id[0] == 0x73)
>>>> > + valid = 1;
>>>> > + else if (id[0] == 0x88) {
>>>> > + if ((id[1] == 0x07) ||
>>>> > + (id[1] == 0x08) ||
>>>> > + ((id[1] & 0xf0) == 0xB0))
>>>> > + valid = 1;
>>>> > + }
>>>> > +
>>>> > + return valid;
>>>> > +}
>>>> > +
>>>> > static int alps_enter_command_mode(struct psmouse *psmouse)
>>>> > {
>>>> > unsigned char param[4];
>>>> > @@ -1201,8 +1637,7 @@ static int alps_enter_command_mode(struct psmouse
>>>> *psmouse)
>>>> > return -1;
>>>> > }
>>>> >
>>>> > - if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) &&
>>>> > - param[0] != 0x73) {
>>>> > + if (!alps_check_valid_firmware_id(param)) {
>>>> > psmouse_dbg(psmouse,
>>>> > "unknown response while entering command
>>>> mode\n");
>>>> > return -1;
>>>> > @@ -1704,6 +2139,36 @@ error:
>>>> > return ret;
>>>> > }
>>>> >
>>>> > +static int alps_hw_init_v7(struct psmouse *psmouse)
>>>> > +{
>>>> > + struct ps2dev *ps2dev = &psmouse->ps2dev;
>>>> > + int reg_val, ret = -1;
>>>> > +
>>>> > + if (alps_enter_command_mode(psmouse))
>>>> > + goto error;
>>>> > +
>>>> > + reg_val = alps_command_mode_read_reg(psmouse, 0xc2d9);
>>>> > + if (reg_val == -1)
>>>> > + goto error;
>>>> > +
>>>> > + if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64))
>>>> > + goto error;
>>>> > +
>>>> > + reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4);
>>>> > + if (reg_val == -1)
>>>> > + goto error;
>>>> > +
>>>> > + if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02))
>>>> > + goto error;
>>>> > +
>>>> > + alps_exit_command_mode(psmouse);
>>>> > + return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
>>>> > +
>>>> > +error:
>>>> > + alps_exit_command_mode(psmouse);
>>>> > + return ret;
>>>> > +}
>>>> > +
>>>> > /* Must be in command mode when calling this function */
>>>> > static int alps_absolute_mode_v4(struct psmouse *psmouse)
>>>> > {
>>>> > @@ -1875,6 +2340,7 @@ static void alps_set_defaults(struct alps_data
>>>> *priv)
>>>> > priv->set_abs_params = alps_set_abs_params_st;
>>>> > priv->x_max = 1023;
>>>> > priv->y_max = 767;
>>>> > + priv->slot_number = 1;
>>>> > break;
>>>> > case ALPS_PROTO_V3:
>>>> > priv->hw_init = alps_hw_init_v3;
>>>> > @@ -1883,6 +2349,7 @@ static void alps_set_defaults(struct alps_data
>>>> *priv)
>>>> > priv->decode_fields = alps_decode_pinnacle;
>>>> > priv->nibble_commands = alps_v3_nibble_commands;
>>>> > priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
>>>> > + priv->slot_number = 2;
>>>> > break;
>>>> > case ALPS_PROTO_V4:
>>>> > priv->hw_init = alps_hw_init_v4;
>>>> > @@ -1890,6 +2357,7 @@ static void alps_set_defaults(struct alps_data
>>>> *priv)
>>>> > priv->set_abs_params = alps_set_abs_params_mt;
>>>> > priv->nibble_commands = alps_v4_nibble_commands;
>>>> > priv->addr_command = PSMOUSE_CMD_DISABLE;
>>>> > + priv->slot_number = 2;
>>>> > break;
>>>> > case ALPS_PROTO_V5:
>>>> > priv->hw_init = alps_hw_init_dolphin_v1;
>>>> > @@ -1905,6 +2373,7 @@ static void alps_set_defaults(struct alps_data
>>>> *priv)
>>>> > priv->y_max = 660;
>>>> > priv->x_bits = 23;
>>>> > priv->y_bits = 12;
>>>> > + priv->slot_number = 2;
>>>> > break;
>>>> > case ALPS_PROTO_V6:
>>>> > priv->hw_init = alps_hw_init_v6;
>>>> > @@ -1913,6 +2382,28 @@ static void alps_set_defaults(struct alps_data
>>>> *priv)
>>>> > priv->nibble_commands = alps_v6_nibble_commands;
>>>> > priv->x_max = 2047;
>>>> > priv->y_max = 1535;
>>>> > + priv->slot_number = 2;
>>>> > + break;
>>>> > + case ALPS_PROTO_V7:
>>>> > + priv->hw_init = alps_hw_init_v7;
>>>> > + priv->process_packet = alps_process_packet_v7;
>>>> > + priv->decode_fields = alps_decode_packet_v7;
>>>> > + priv->set_abs_params = alps_set_abs_params_mt;
>>>> > + priv->nibble_commands = alps_v3_nibble_commands;
>>>> > + priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
>>>> > + priv->x_max = 0xfff;
>>>> > + priv->y_max = 0x7ff;
>>>> > + priv->resting_zone_y_min = 0x654;
>>>> > + priv->byte0 = 0x48;
>>>> > + priv->mask0 = 0x48;
>>>> > + priv->flags = 0;
>>>> > + priv->slot_number = 2;
>>>> > +
>>>> > + priv->phy_btn = 0;
>>>> > + priv->prev_phy_btn = 0;
>>>> > + priv->btn_delay_cnt = 0;
>>>> > + priv->pressed_btn_bits = 0;
>>>> > + memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
>>>> > break;
>>>> > }
>>>> > }
>>>> > @@ -1982,6 +2473,11 @@ static int alps_identify(struct psmouse *psmouse,
>>>> struct alps_data *priv)
>>>> > return -EIO;
>>>> > else
>>>> > return 0;
>>>> > + } else if (ec[0] == 0x88 && (ec[1] & 0xf0) == 0xB0) {
>>>> > + priv->proto_version = ALPS_PROTO_V7;
>>>> > + alps_set_defaults(priv);
>>>> > +
>>>> > + return 0;
>>>> > } else if (ec[0] == 0x88 && ec[1] == 0x08) {
>>>> > priv->proto_version = ALPS_PROTO_V3;
>>>> > alps_set_defaults(priv);
>>>> > @@ -2045,7 +2541,7 @@ static void alps_set_abs_params_mt(struct
>>>> alps_data *priv,
>>>> > struct input_dev *dev1)
>>>> > {
>>>> > set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
>>>> > - input_mt_init_slots(dev1, 2, 0);
>>>> > + input_mt_init_slots(dev1, priv->slot_number, 0);
>>>> > input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0,
>>>> 0);
>>>> > input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0,
>>>> 0);
>>>> >
>>>> > diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
>>>> > index 03f88b6..dedbd27 100644
>>>> > --- a/drivers/input/mouse/alps.h
>>>> > +++ b/drivers/input/mouse/alps.h
>>>> > @@ -18,11 +18,36 @@
>>>> > #define ALPS_PROTO_V4 4
>>>> > #define ALPS_PROTO_V5 5
>>>> > #define ALPS_PROTO_V6 6
>>>> > +#define ALPS_PROTO_V7 7
>>>> > +
>>>> > +#define MAX_IMG_PT_NUM 5
>>>> > +#define V7_IMG_PT_NUM 2
>>>> > +
>>>> > +#define ZONE_NORMAL 0x01
>>>> > +#define ZONE_RESTING 0x02
>>>> > +#define ZONE_LEFT_BTN 0x04
>>>> > +#define ZONE_RIGHT_BTN 0x08
>>>> >
>>>> > #define DOLPHIN_COUNT_PER_ELECTRODE 64
>>>> > #define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode
>>>> offset */
>>>> > #define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode
>>>> offset */
>>>> >
>>>> > +/*
>>>> > + * enum V7_PACKET_ID - defines the packet type for V7
>>>> > + * V7_PACKET_ID_IDLE: There's no finger and no button activity.
>>>> > + * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad
>>>> > + * or there's button activities.
>>>> > + * V7_PACKET_ID_MULTI: There are at least three non-resting fingers.
>>>> > + * V7_PACKET_ID_NEW: The finger position in slot is not continues from
>>>> > + * previous packet.
>>>> > +*/
>>>> > +enum V7_PACKET_ID {
>>>> > + V7_PACKET_ID_IDLE,
>>>> > + V7_PACKET_ID_TWO,
>>>> > + V7_PACKET_ID_MULTI,
>>>> > + V7_PACKET_ID_NEW,
>>>> > +};
>>>> > +
>>>> > /**
>>>> > * struct alps_model_info - touchpad ID table
>>>> > * @signature: E7 response string to match.
>>>> > @@ -66,15 +91,7 @@ struct alps_nibble_commands {
>>>> > };
>>>> >
>>>> > /**
>>>> > - * struct alps_fields - decoded version of the report packet
>>>> > - * @x_map: Bitmap of active X positions for MT.
>>>> > - * @y_map: Bitmap of active Y positions for MT.
>>>> > - * @fingers: Number of fingers for MT.
>>>> > - * @x: X position for ST.
>>>> > - * @y: Y position for ST.
>>>> > - * @z: Z position for ST.
>>>> > - * @first_mp: Packet is the first of a multi-packet report.
>>>> > - * @is_mp: Packet is part of a multi-packet report.
>>>> > + * struct alps_btn - decoded version of the button status
>>>> > * @left: Left touchpad button is active.
>>>> > * @right: Right touchpad button is active.
>>>> > * @middle: Middle touchpad button is active.
>>>> > @@ -82,16 +99,7 @@ struct alps_nibble_commands {
>>>> > * @ts_right: Right trackstick button is active.
>>>> > * @ts_middle: Middle trackstick button is active.
>>>> > */
>>>> > -struct alps_fields {
>>>> > - unsigned int x_map;
>>>> > - unsigned int y_map;
>>>> > - unsigned int fingers;
>>>> > - unsigned int x;
>>>> > - unsigned int y;
>>>> > - unsigned int z;
>>>> > - unsigned int first_mp:1;
>>>> > - unsigned int is_mp:1;
>>>> > -
>>>> > +struct alps_btn {
>>>> > unsigned int left:1;
>>>> > unsigned int right:1;
>>>> > unsigned int middle:1;
>>>> > @@ -102,6 +110,73 @@ struct alps_fields {
>>>> > };
>>>> >
>>>> > /**
>>>> > + * struct alps_btn - decoded version of the X Y Z postion for ST.
>>>> > + * @x: X position for ST.
>>>> > + * @y: Y position for ST.
>>>> > + * @z: Z position for ST.
>>>> > + */
>>>> > +struct alps_abs_data {
>>>> > + unsigned int x;
>>>> > + unsigned int y;
>>>> > + unsigned int z;
>>>> > +};
>>>> > +
>>>> > +/**
>>>> > + * struct alps_fields - decoded version of the report packet
>>>> > + * @fingers: Number of fingers for MT.
>>>> > + * @pt: X Y Z postion for ST.
>>>> > + * @pt: X Y Z postion for image MT.
>>>> > + * @x_map: Bitmap of active X positions for MT.
>>>> > + * @y_map: Bitmap of active Y positions for MT.
>>>> > + * @first_mp: Packet is the first of a multi-packet report.
>>>> > + * @is_mp: Packet is part of a multi-packet report.
>>>> > + * @btn: Button activity status
>>>> > + */
>>>> > +struct alps_fields {
>>>> > + unsigned int fingers;
>>>> > + struct alps_abs_data pt;
>>>> > + struct alps_abs_data pt_img[MAX_IMG_PT_NUM];
>>>> > + unsigned int x_map;
>>>> > + unsigned int y_map;
>>>> > + unsigned int first_mp:1;
>>>> > + unsigned int is_mp:1;
>>>> > + struct alps_btn btn;
>>>> > +};
>>>> > +
>>>> > +/**
>>>> > + * struct v7_raw - data decoded from raw packet for V7.
>>>> > + * @pkt_id: An id that specifies the type of packet.
>>>> > + * @additional_fingers: Number of additional finger that is neighter
>>>> included
>>>> > + * in pt slot nor reflected in rest_left and rest_right flag of data
>>>> packet.
>>>> > + * @rest_left: There are fingers on left resting zone.
>>>> > + * @rest_right: There are fingers on right resting zone.
>>>> > + * @raw_fn: The number of finger on touchpad.
>>>> > + */
>>>> > +struct v7_raw {
>>>> > + unsigned char pkt_id;
>>>> > + unsigned int additional_fingers;
>>>> > + unsigned char rest_left;
>>>> > + unsigned char rest_right;
>>>> > + unsigned char raw_fn;
>>>> > +};
>>>> > +
>>>> > +/**
>>>> > + * struct alps_bl_pt_attr - generic attributes of touch points for
>>>> buttonless device
>>>> > + * @zone: The part of touchpad that the touch point locates
>>>> > + * @is_counted: The touch point is not a resting finger.
>>>> > + * @is_init_pt_got: The touch down point is got.
>>>> > + * @init_pt: The X Y Z position of the touch down point.
>>>> > + * @init_dead_pt: The touch down point of a finger used by dead zone
>>>> process.
>>>> > + */
>>>> > +struct alps_bl_pt_attr {
>>>> > + unsigned char zone;
>>>> > + unsigned char is_counted;
>>>> > + unsigned char is_init_pt_got;
>>>> > + struct alps_abs_data init_pt;
>>>> > + struct alps_abs_data init_dead_pt;
>>>> > +};
>>>> > +
>>>> > +/**
>>>> > * struct alps_data - private data structure for the ALPS driver
>>>> > * @dev2: "Relative" device used to report trackstick or mouse activity.
>>>> > * @phys: Physical path for the relative device.
>>>> > @@ -116,8 +191,10 @@ struct alps_fields {
>>>> > * @flags: Additional device capabilities (passthrough port,
>>>> trackstick, etc.).
>>>> > * @x_max: Largest possible X position value.
>>>> > * @y_max: Largest possible Y position value.
>>>> > + * @resting_zone_y_min: Smallest Y postion value of the bottom resting
>>>> zone.
>>>> > * @x_bits: Number of X bits in the MT bitmap.
>>>> > * @y_bits: Number of Y bits in the MT bitmap.
>>>> > + * @img_fingers: Number of image fingers.
>>>> > * @hw_init: Protocol-specific hardware init function.
>>>> > * @process_packet: Protocol-specific function to process a report
>>>> packet.
>>>> > * @decode_fields: Protocol-specific function to read packet bitfields.
>>>> > @@ -132,6 +209,11 @@ struct alps_fields {
>>>> > * @fingers: Number of fingers from last MT report.
>>>> > * @quirks: Bitmap of ALPS_QUIRK_*.
>>>> > * @timer: Timer for flushing out the final report packet in the stream.
>>>> > + * @v7: Data decoded from raw packet for V7
>>>> > + * @phy_btn: Physical button is active.
>>>> > + * @prev_phy_btn: Physical button of previous packet is active.
>>>> > + * @pressed_btn_bits: Pressed positon of button zone
>>>> > + * @pt_attr: Generic attributes of touch points for buttonless device.
>>>> > */
>>>> > struct alps_data {
>>>> > struct input_dev *dev2;
>>>> > @@ -145,8 +227,10 @@ struct alps_data {
>>>> > unsigned char flags;
>>>> > int x_max;
>>>> > int y_max;
>>>> > + int resting_zone_y_min;
>>>> > int x_bits;
>>>> > int y_bits;
>>>> > + unsigned char slot_number;
>>>> >
>>>> > int (*hw_init)(struct psmouse *psmouse);
>>>> > void (*process_packet)(struct psmouse *psmouse);
>>>> > @@ -161,6 +245,16 @@ struct alps_data {
>>>> > int fingers;
>>>> > u8 quirks;
>>>> > struct timer_list timer;
>>>> > +
>>>> > + /* these are used for buttonless touchpad*/
>>>> > + union {
>>>> > + struct v7_raw v7;
>>>> > + } r;
>>>> > + unsigned char phy_btn;
>>>> > + unsigned char prev_phy_btn;
>>>> > + unsigned char btn_delay_cnt;
>>>> > + unsigned char pressed_btn_bits;
>>>> > + struct alps_bl_pt_attr pt_attr[MAX_IMG_PT_NUM];
>>>> > };
>>>> >
>>>> > #define ALPS_QUIRK_TRACKSTICK_BUTTONS 1 /* trakcstick buttons in
>>>> trackstick packet */
>>>>
>>>>
>>>
>>--
>>To unsubscribe from this list: send the line "unsubscribe linux-input" in
>>the body of a message to majordomo@vger.kernel.org
>>More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* 8 months to review a patch (was Re: [PATCH] Route kbd LEDs through the generic LEDs layer)
From: Pavel Machek @ 2014-03-28 7:01 UTC (permalink / raw)
To: Pali Rohár, dtor, linux-input, jkosina
Cc: Samuel Thibault, Dmitry Torokhov, Andrew Morton, jslaby,
Richard Purdie, LKML, Evan Broder, Arnaud Patard, Greg KH,
Linus Torvalds
In-Reply-To: <CAHYPw2EAgjdcNATy0d6DhbT9qHAHJLda7gsLrnSJ7F4Cj=a-JQ@mail.gmail.com>
On Thu 2014-03-27 02:08:17, Pali Rohár wrote:
> 2014-03-16 11:19 GMT+01:00 Samuel Thibault <samuel.thibault@ens-lyon.org>:
> > Pali Rohár, le Sun 16 Mar 2014 11:16:25 +0100, a écrit :
> >> Hello, what happened with this patch? Is there any problem with accepting it?
> >
> > Dmitry finding time to review it, I guess.
> Dmitry, can you look and review this patch?
Dmitry, what happened to you, are you there? This patch is like 8
months old, and not too scary, either. Can you at least pinpoint some
typos in it, or run in through the checkpatch?
If Dmitry does not respond, what are the next steps. Greg, could you
just take the patch? Linus?
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: 8 months to review a patch (was Re: [PATCH] Route kbd LEDs through the generic LEDs layer)
From: Greg KH @ 2014-03-28 7:17 UTC (permalink / raw)
To: Pavel Machek
Cc: Pali Rohár, dtor, linux-input, jkosina, Samuel Thibault,
Dmitry Torokhov, Andrew Morton, jslaby, Richard Purdie, LKML,
Evan Broder, Arnaud Patard, Linus Torvalds
In-Reply-To: <20140328070136.GA15953@amd.pavel.ucw.cz>
On Fri, Mar 28, 2014 at 08:01:36AM +0100, Pavel Machek wrote:
> On Thu 2014-03-27 02:08:17, Pali Rohár wrote:
> > 2014-03-16 11:19 GMT+01:00 Samuel Thibault <samuel.thibault@ens-lyon.org>:
> > > Pali Rohár, le Sun 16 Mar 2014 11:16:25 +0100, a écrit :
> > >> Hello, what happened with this patch? Is there any problem with accepting it?
> > >
> > > Dmitry finding time to review it, I guess.
>
> > Dmitry, can you look and review this patch?
>
> Dmitry, what happened to you, are you there? This patch is like 8
> months old, and not too scary, either. Can you at least pinpoint some
> typos in it, or run in through the checkpatch?
>
> If Dmitry does not respond, what are the next steps. Greg, could you
> just take the patch? Linus?
No, work with Dmitry please.
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [linux-sunxi] Re: [PATCH v3 08/10] ARM: sun7i/sun4i: dt: Add AXP209 support to various boards
From: Carlo Caione @ 2014-03-28 7:37 UTC (permalink / raw)
To: wens Tsai
Cc: linux-arm-kernel, maxime.ripard, Hans De Goede, Emilio Lopez,
sameo, dmitry.torokhov, linux-input, linux-doc, lgirdwood,
broonie, linux-sunxi
In-Reply-To: <CAGb2v67a6kVMe9vxBYrQQtucVqpyvUby1Hyt3RBina8sKj9HOw@mail.gmail.com>
On Fri, Mar 28, 2014 at 4:12 AM, Chen-Yu Tsai <wens@csie.org> wrote:
>> diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts
>> index fa746aea..cf18c4d 100644
>> --- a/arch/arm/boot/dts/sun4i-a10-a1000.dts
>> +++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts
>> @@ -88,6 +88,19 @@
>> pinctrl-names = "default";
>> pinctrl-0 = <&i2c0_pins_a>;
>> status = "okay";
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> +
>> + axp: axp20x@34 {
>
> Hi,
>
> Sorry for spotting this just now. I suggest you change it to
>
> axp209: pmic@34 {
>
> or
>
> axp209_pmic@34 {
>
> to match the ePAPR policy that node names should be generic and
> describe functionality. The latter is what some DTs use.
Right. Thanks for reviewing this.
> Same for all the other files.
>
> Thanks for working on this!
Thank you,
--
Carlo Caione
^ permalink raw reply
* Re: [PATCH v3 04/10] input: misc: Add driver for AXP20x Power Enable Key
From: Dmitry Torokhov @ 2014-03-28 7:38 UTC (permalink / raw)
To: Carlo Caione
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
hdegoede-H+wXaHxf7aLQT0dZR+AlfA, emilio-0Z03zUJReD5OxF6Tv1QG9Q,
wens-jdAy2FN1RRM, sameo-VuQAYsv1563Yd54FQh9/CA,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A
In-Reply-To: <1395955764-18103-5-git-send-email-carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
Hi Carlo,
On Thu, Mar 27, 2014 at 10:29:18PM +0100, Carlo Caione wrote:
> This patch add support for the Power Enable Key found on MFD AXP202 and
> AXP209. Besides the basic support for the button, the driver adds two
> entries in sysfs to configure the time delay for power on/off.
>
> Signed-off-by: Carlo Caione <carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
> ---
> drivers/input/misc/Kconfig | 11 ++
> drivers/input/misc/Makefile | 1 +
> drivers/input/misc/axp20x-pek.c | 260 ++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 272 insertions(+)
> create mode 100644 drivers/input/misc/axp20x-pek.c
>
> diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
> index 7904ab0..87244fb 100644
> --- a/drivers/input/misc/Kconfig
> +++ b/drivers/input/misc/Kconfig
> @@ -393,6 +393,17 @@ config INPUT_RETU_PWRBUTTON
> To compile this driver as a module, choose M here. The module will
> be called retu-pwrbutton.
>
> +config INPUT_AXP20X_PEK
> + tristate "X-Powers AXP20X power button driver"
> + depends on MFD_AXP20X
> + help
> + Say Y here if you want to enable power key reporting via the
> + AXP20X PMIC.
> +
> + To compile this driver as a module, choose M here. The module will
> + be called axp20x-pek.
> +
> +
> config INPUT_TWL4030_PWRBUTTON
> tristate "TWL4030 Power button Driver"
> depends on TWL4030_CORE
> diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
> index cda71fc..624abf5 100644
> --- a/drivers/input/misc/Makefile
> +++ b/drivers/input/misc/Makefile
> @@ -50,6 +50,7 @@ obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
> obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
> obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
> obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o
> +obj-$(CONFIG_INPUT_AXP20X_PEK) += axp20x-pek.o
> obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
> obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
> obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o
> diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c
> new file mode 100644
> index 0000000..6698a69
> --- /dev/null
> +++ b/drivers/input/misc/axp20x-pek.c
> @@ -0,0 +1,260 @@
> +/*
> + * axp20x power button driver.
> + *
> + * Copyright (C) 2013 Carlo Caione <carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>
> + *
> + * This file is subject to the terms and conditions of the GNU General
> + * Public License. See the file "COPYING" in the main directory of this
> + * archive for more details.
> + *
> + * 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.
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/irq.h>
> +#include <linux/init.h>
> +#include <linux/input.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/axp20x.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +
> +#define AXP20X_PEK_STARTUP_MASK (0xc0)
> +#define AXP20X_PEK_SHUTDOWN_MASK (0x03)
> +
> +static const char const *startup_time[] = { "128ms", "3s" , "1s", "2s" };
> +static const char const *shutdown_time[] = { "4s", "6s" , "8s", "10s" };
Why not have everything expressed in milliseconds and have sysfs
attribute apply the closest one possible?
By the way, do you want to plumb these through device tree as well?
> +
> +struct axp20x_pek {
> + struct axp20x_dev *axp20x;
> + struct input_dev *input;
> + int irq_dbr;
> + int irq_dbf;
> +};
> +
> +struct axp20x_pek_ext_attr {
> + const char const **str;
> + unsigned int mask;
> +};
> +
> +static struct axp20x_pek_ext_attr axp20x_pek_startup_ext_attr = {
> + .str = startup_time,
> + .mask = AXP20X_PEK_STARTUP_MASK,
> +};
> +
> +static struct axp20x_pek_ext_attr axp20x_pek_shutdown_ext_attr = {
> + .str = shutdown_time,
> + .mask = AXP20X_PEK_SHUTDOWN_MASK,
> +};
> +
> +static struct axp20x_pek_ext_attr *get_axp_ext_attr(struct device_attribute *attr)
> +{
> + return container_of(attr, struct dev_ext_attribute, attr)->var;
> +}
> +
> +static ssize_t axp20x_show_ext_attr(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
> + struct axp20x_pek_ext_attr *axp20x_ea = get_axp_ext_attr(attr);
> + unsigned int val;
> + int ret, i;
> + int cnt = 0;
> +
> + ret = regmap_read(axp20x_pek->axp20x->regmap, AXP20X_PEK_KEY, &val);
> + if (ret != 0)
> + return ret;
> +
> + val &= axp20x_ea->mask;
> + val >>= ffs(axp20x_ea->mask) - 1;
> +
> + for (i = 0; i < 4; i++) {
> + if (val == i)
> + cnt += sprintf(buf + cnt, "[%s] ", axp20x_ea->str[i]);
> + else
> + cnt += sprintf(buf + cnt, "%s ", axp20x_ea->str[i]);
Please just return the current value; why do we need pretty-printing?
> + }
> +
> + cnt += sprintf(buf + cnt, "\n");
> +
> + return cnt;
> +}
> +
> +static ssize_t axp20x_store_ext_attr(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
> + struct axp20x_pek_ext_attr *axp20x_ea = get_axp_ext_attr(attr);
> + char val_str[20];
> + int ret, i;
> + size_t len;
> +
> + val_str[sizeof(val_str) - 1] = '\0';
> + strncpy(val_str, buf, sizeof(val_str) - 1);
> + len = strlen(val_str);
> +
> + if (len && val_str[len - 1] == '\n')
> + val_str[len - 1] = '\0';
> +
> + for (i = 0; i < 4; i++) {
> + if (!strcmp(val_str, axp20x_ea->str[i])) {
> +
> + i <<= ffs(axp20x_ea->mask) - 1;
> + ret = regmap_update_bits(axp20x_pek->axp20x->regmap,
> + AXP20X_PEK_KEY,
> + axp20x_ea->mask, i);
> + if (ret != 0)
> + return -EINVAL;
> + return count;
> + }
> + }
> +
> + return -EINVAL;
> +}
> +
> +static struct dev_ext_attribute axp20x_dev_attr_startup = {
> + .attr = __ATTR(startup, 0644, axp20x_show_ext_attr, axp20x_store_ext_attr),
> + .var = &axp20x_pek_startup_ext_attr
> +};
> +
> +static struct dev_ext_attribute axp20x_dev_attr_shutdown = {
> + __ATTR(shutdown, 0644, axp20x_show_ext_attr, axp20x_store_ext_attr),
> + &axp20x_pek_shutdown_ext_attr
> +};
> +
> +static struct attribute *dev_attrs[] = {
> + &axp20x_dev_attr_startup.attr.attr,
> + &axp20x_dev_attr_shutdown.attr.attr,
> + NULL,
> +};
> +
> +static struct attribute_group dev_attr_group = {
> + .attrs = dev_attrs,
> +};
> +
> +static const struct attribute_group *dev_attr_groups[] = {
> + &dev_attr_group,
> + NULL,
> +};
> +
> +static irqreturn_t axp20x_pek_irq(int irq, void *pwr)
> +{
> + struct input_dev *idev = pwr;
> + struct axp20x_pek *axp20x_pek = input_get_drvdata(idev);
> +
> + if (irq == axp20x_pek->irq_dbr)
> + input_report_key(idev, KEY_POWER, true);
> + else if (irq == axp20x_pek->irq_dbf)
> + input_report_key(idev, KEY_POWER, false);
> +
> + input_sync(idev);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int axp20x_pek_probe(struct platform_device *pdev)
> +{
> + struct axp20x_pek *axp20x_pek;
> + struct axp20x_dev *axp20x;
> + struct input_dev *idev;
> + int error;
> +
> + axp20x_pek = devm_kzalloc(&pdev->dev, sizeof(struct axp20x_pek),
> + GFP_KERNEL);
> + if (!axp20x_pek)
> + return -ENOMEM;
> +
> + axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent);
> + axp20x = axp20x_pek->axp20x;
> +
> + axp20x_pek->irq_dbr = platform_get_irq_byname(pdev, "PEK_DBR");
> + if (axp20x_pek->irq_dbr < 0) {
> + dev_err(&pdev->dev, "No IRQ for PEK_DBR, error=%d\n",
> + axp20x_pek->irq_dbr);
> + return axp20x_pek->irq_dbr;
> + }
> + axp20x_pek->irq_dbr = regmap_irq_get_virq(axp20x->regmap_irqc,
> + axp20x_pek->irq_dbr);
> +
> + axp20x_pek->irq_dbf = platform_get_irq_byname(pdev, "PEK_DBF");
> + if (axp20x_pek->irq_dbf < 0) {
> + dev_err(&pdev->dev, "No IRQ for PEK_DBF, error=%d\n",
> + axp20x_pek->irq_dbf);
> + return axp20x_pek->irq_dbf;
> + }
> + axp20x_pek->irq_dbf = regmap_irq_get_virq(axp20x->regmap_irqc,
> + axp20x_pek->irq_dbf);
> +
> + axp20x_pek->input = devm_input_allocate_device(&pdev->dev);
> + if (!axp20x_pek->input)
> + return -ENOMEM;
> +
> + idev = axp20x_pek->input;
> +
> + idev->name = "axp20x-pek";
> + idev->phys = "m1kbd/input2";
> + idev->dev.parent = &pdev->dev;
> +
> + input_set_capability(idev, EV_KEY, KEY_POWER);
> +
> + input_set_drvdata(idev, axp20x_pek);
> +
> + error = devm_request_threaded_irq(&pdev->dev, axp20x_pek->irq_dbr,
> + NULL, axp20x_pek_irq, 0,
> + "axp20x-pek-dbr", idev);
Why does it have to be threaded IRQ?
> + if (error) {
> + dev_err(axp20x->dev, "Failed to request dbr IRQ#%d: %d\n",
> + axp20x_pek->irq_dbr, error);
> +
> + return error;
> + }
> +
> + error = devm_request_threaded_irq(&pdev->dev, axp20x_pek->irq_dbf,
> + NULL, axp20x_pek_irq, 0,
> + "axp20x-pek-dbf", idev);
> + if (error) {
> + dev_err(axp20x->dev, "Failed to request dbf IRQ#%d: %d\n",
> + axp20x_pek->irq_dbf, error);
> + return error;
> + }
> +
> + idev->dev.groups = dev_attr_groups;
These are not generic input attributes so they should belong to the platform
device, not input device.
> + error = input_register_device(idev);
> + if (error) {
> + dev_err(axp20x->dev, "Can't register input device: %d\n", error);
> + return error;
> + }
> +
> + platform_set_drvdata(pdev, axp20x_pek);
> +
> + return 0;
> +}
> +
> +static int axp20x_pek_remove(struct platform_device *pdev)
> +{
> + struct axp20x_pek *axp20x_pek = platform_get_drvdata(pdev);
> +
> + input_unregister_device(axp20x_pek->input);
No need to call input_unregister_device() for managed input devices.
> +
> + return 0;
> +}
> +
> +static struct platform_driver axp20x_pek_driver = {
> + .probe = axp20x_pek_probe,
> + .remove = axp20x_pek_remove,
> + .driver = {
> + .name = "axp20x-pek",
> + .owner = THIS_MODULE,
> + },
> +};
> +module_platform_driver(axp20x_pek_driver);
> +
> +MODULE_DESCRIPTION("axp20x Power Button");
> +MODULE_AUTHOR("Carlo Caione <carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org>");
> +MODULE_LICENSE("GPL");
> --
> 1.8.3.2
>
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH] input: sirfsoc-onkey - set the capability of reporting KEY_POWER
From: Dmitry Torokhov @ 2014-03-28 7:39 UTC (permalink / raw)
To: Barry Song
Cc: linux-input@vger.kernel.org, DL-SHA-WorkGroupLinux, Xianglong Du,
Barry Song
In-Reply-To: <CAGsJ_4wda0XnP9ML4e35_sjz8M5Qese-2yaeBVYBsW7gHEczxg@mail.gmail.com>
On Thu, Mar 27, 2014 at 03:35:46PM +0800, Barry Song wrote:
> 2014-02-25 21:36 GMT+08:00 Barry Song <21cnbao@gmail.com>:
> > From: Xianglong Du <Xianglong.Du@csr.com>
> >
> > commit a1a7521064428fc1cf8 moved to report EV_KEY event(KEY_POWER) instead of
> > reporting EV_PWR event(KEY_SUSPEND), but it didn't enable the capability, so
> > the KEY_POWER will not be reported to userspace by input core. this patch fixes
> > the issue.
> >
> > Signed-off-by: Xianglong Du <Xianglong.Du@csr.com>
> > Signed-off-by: Barry Song <Baohua.Song@csr.com>
> > ---
>
> Dmitry, i guess you missed this one, this one should be in 3.15,
> otherwise, onkey is broken.
Applied, thank you.
>
>
> > drivers/input/misc/sirfsoc-onkey.c | 1 +
> > 1 file changed, 1 insertion(+)
> >
> > diff --git a/drivers/input/misc/sirfsoc-onkey.c b/drivers/input/misc/sirfsoc-onkey.c
> > index 4d66c72..e4104f9 100644
> > --- a/drivers/input/misc/sirfsoc-onkey.c
> > +++ b/drivers/input/misc/sirfsoc-onkey.c
> > @@ -136,6 +136,7 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)
> > pwrcdrv->input->name = "sirfsoc pwrckey";
> > pwrcdrv->input->phys = "pwrc/input0";
> > pwrcdrv->input->evbit[0] = BIT_MASK(EV_KEY);
> > + input_set_capability(pwrcdrv->input, EV_KEY, KEY_POWER);
> >
> > INIT_DELAYED_WORK(&pwrcdrv->work, sirfsoc_pwrc_report_event);
> >
> > --
> > 1.7.9.5
> >
>
> -barry
--
Dmitry
^ permalink raw reply
* Re: [PATCH] atkbd: Samsung NP530U3C laptop forced key release
From: Dmitry Torokhov @ 2014-03-28 7:48 UTC (permalink / raw)
To: Arkadiusz Bokowy; +Cc: linux-input
In-Reply-To: <20140311195448.0b722ea5@sambook>
Hi Arkadiusz,
On Tue, Mar 11, 2014 at 07:54:48PM +0100, Arkadiusz Bokowy wrote:
> atkbd: Samsung NP530U3C laptop forced key release
>
> For Samsung NP530U3C laptop (observed on firmware P09ABH) not all Fn keys
> generates release event, which leaves key in a pressed state. This patch
> adds those keys into the "forced release" workaround. Fixed keys: WLAN,
> Settings, Fn Lock.
>
> Patch generated for kernel version 3.13.6
This should be done by udev nowadays, please submit patch for it instead
of modifying the kernel.
Thanks!
--
Dmitry
^ permalink raw reply
* Re: [PATCH 0/2] input/serio: Add a firmware_id sysfs attribute
From: Dmitry Torokhov @ 2014-03-28 7:56 UTC (permalink / raw)
To: Matthew Garrett
Cc: Hans de Goede, Benjamin Tissoires, Peter Hutterer,
platform-driver-x86, linux-input
In-Reply-To: <20140320172159.GA27400@srcf.ucam.org>
On Thu, Mar 20, 2014 at 05:21:59PM +0000, Matthew Garrett wrote:
> On Thu, Mar 20, 2014 at 11:12:08AM +0100, Hans de Goede wrote:
>
> > Which in the end turns out to be much nicer too, since it gets rid of needing
> > a udev-helper too. After this much too long introduction I'll let the patches
> > speak for themselves.
>
> Yeah, I was coming to the conclusion that this was probably the best we
> could do. It's unfortunate that "id" is already in use - we'd be able to
> get away without any X server modifications otherwise.
>
> Long term we probably still want to tie serio devices to the ACPI
> devices in case the vendor provides power management calls there, but we
> can leave that until there's an actual example.
I am still unsure if we shoudl be adding these new IDs to serio core...
Can't the X driver take a peek at ACPI devices on it's own?
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH] input: cypress_ps2: Don't report the cypress PS/2 trackpads as a button pad
From: Dmitry Torokhov @ 2014-03-28 8:01 UTC (permalink / raw)
To: Hans de Goede
Cc: Benjamin Tissoires, linux-input, Adam Williamson, Peter Hutterer
In-Reply-To: <1395668975-10588-1-git-send-email-hdegoede@redhat.com>
On Mon, Mar 24, 2014 at 02:49:35PM +0100, Hans de Goede wrote:
> The cypress PS/2 trackpad models supported by the cypress_ps2 driver emulate
> BTN_RIGHT events in firmware based on the finger position, as part of this
> no motion events are sent when the finger is in the button area.
>
> The INPUT_PROP_BUTTONPAD property is there to indicate to userspace that
> BTN_RIGHT events should be emulated in userspace, which is not necessary
> in this case.
>
> When INPUT_PROP_BUTTONPAD is advertised userspace will wait for a motion event
> before propagating the button event higher up the stack, as it needs current
> abs x + y data for its BTN_RIGHT emulation. Since in the cypress_ps2 pads
> don't report motion events in the button area, this means that clicks in the
> button area end up being ignored, so INPUT_PROP_BUTTONPAD actually causes
> problems for these touchpads, and removing it fixes:
>
> https://bugs.freedesktop.org/show_bug.cgi?id=76341
>
> Reported-by: Adam Williamson <awilliam@redhat.com>
> Tested-by: Adam Williamson <awilliam@redhat.com>
> Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
> Cc: Adam Williamson <awilliam@redhat.com>
> Cc: Peter Hutterer <peter.hutterer@who-t.net>
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Applied, thank you.
> ---
> drivers/input/mouse/cypress_ps2.c | 1 -
> 1 file changed, 1 deletion(-)
>
> diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c
> index 87095e2..8af34ff 100644
> --- a/drivers/input/mouse/cypress_ps2.c
> +++ b/drivers/input/mouse/cypress_ps2.c
> @@ -409,7 +409,6 @@ static int cypress_set_input_params(struct input_dev *input,
> __clear_bit(REL_X, input->relbit);
> __clear_bit(REL_Y, input->relbit);
>
> - __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
> __set_bit(EV_KEY, input->evbit);
> __set_bit(BTN_LEFT, input->keybit);
> __set_bit(BTN_RIGHT, input->keybit);
> --
> 1.9.0
>
--
Dmitry
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox