1
1
mirror of https://github.com/NixOS/mobile-nixos.git synced 2024-12-18 13:31:36 +03:00
mobile-nixos/devices/oneplus-oneplus3/kernel/0001-Imports-drivers-input-changes-from-lineage-16.0.patch

15103 lines
431 KiB
Diff
Raw Normal View History

From ee9cf13e13330fcc614b13d2b2338f22810c6601 Mon Sep 17 00:00:00 2001
From: Shantanu Jain <shjain@codeaurora.org>
Date: Wed, 20 Sep 2017 16:22:41 +0530
Subject: [PATCH] Imports `drivers/input/` changes from lineage-16.0
input: synaptics_dsx_2.6: correct suspend path for Synaptics V2.6 driver
Correct the suspend path for Synaptics V2.6 driver by adding the brackets
in the error path while calling the pinctrl call. This change will make
the driver not go into undesirable path and complete the function calls
necessary for suspend routine.
Change-Id: I327eff97f584cefb2c957c43e9820f3a37d4751c
Signed-off-by: Shantanu Jain <shjain@codeaurora.org>
input: synaptics_dsx_2.6: enable wakeup gesture for synaptics driver
Enable wakeup gesture for Synaptics V2.6 touch driver. Below changes
are added for the same:
- Enable the wakeup gesture as it was disabled by default as a macro.
- Add change to suspend the touch device for FB_BLANK_VSYNC_SUSPEND
fb event, when display goes to dim setting for this event.
- Enable wakeup feature and make irq as wake-able only once while
going suspend or resume.
- Don't put off regulators when wakeup geature is enabled.
Change-Id: Icd59de0411d92a791bbeb08ec3d368359edf8993
Signed-off-by: Shantanu Jain <shjain@codeaurora.org>
drivers: input: add general hall sensor driver
This change adds general hall sensor driver.
This snapshot is taken as of msm-3.10 'commit 1227f5746677 ("soc:
qcom: smp2p: spinlock_test: Initialize work item")' with minor
errors fixed.
Change-Id: Icd048fea42facca48b5d6b387218d6847f730d58
Signed-off-by: Bingzhe Cai <bingzhec@codeaurora.org>
input: sensors: add Lite-on ltr553 ALPS sensor driver
MSM8909 SKUE uses ltr553 as ambient light and proximity sensor.
Add ltr553 sensor driver to enable it.
This snapshot is taken as of msm-3.10 'commit 1227f5746677 ("soc:
qcom: smp2p: spinlock_test: Initialize work item")'with
minor compile error fixed.
Change-Id: Ib5462672d8029396acaca5999b0c14a11a68382b
Signed-off-by: Bingzhe Cai <bingzhec@codeaurora.org>
input: sensors: add BOSCH bma2x2 accelerometer driver
Add BOSCH bma2x2 accelerometer driver to support sensors on
MSM8909.
This snapshot is taken as of msm-3.10 'commit 1227f5746677 ("soc:
qcom: smp2p: spinlock_test: Initialize work item")'
Change-Id: I0169725857887307f755b6fdf899e407d8ad74ad
Signed-off-by: Bingzhe Cai <bingzhec@codeaurora.org>
input: sensors: fix code scan error in bma2x2 driver
Fix code scan error in BOSCH bma2x2 accelerometer driver.
Change-Id: I8b1277c0f204ec5e8df02ebef4452efa91e10cd2
Signed-off-by: Bingzhe Cai <bingzhec@codeaurora.org>
input: touchscreen: correct regulator calls in suspend/resume
Correct regulator calls in suspend/resume path of Synaptics DSX
V2.6 touch driver. Don't execute regulator_get or regulaotr_put
calls in suspend/resume, if touch-to-wake is disabled.
Change-Id: Ifce1ca9a6e8a08acc0bf22050727f976f959bb75
Signed-off-by: Shantanu Jain <shjain@codeaurora.org>
input: touchscreen: enable/disable wakeup gestures for synaptics v2.6
Add devicetree property for wakeup gesture enable.
Override this choice through sysfs.
Change-Id: I61e386e89dda7ac12291a9b0138f649f71678ff8
Signed-off-by: Venkata Prahlad Valluru <vvalluru@codeaurora.org>
input: touchpanel: Fix abnormal crash caused by Synaptics TP
There was a abnormal kernel crash when TP resumes. The root
cause is that the call of reset_device in TP reusme function
may fail sometimes and watchdog's timeout occurred to make
kernel crash. After removing this useless reset-device by
undefine FB_READY_RESET, TP can work normally.
Change-Id: I1c9e15631b619ce2b2426cb93da99d9b988a0aed
Signed-off-by: Wenjun Zhang <wjzhan@codeaurora.org>
ANDROID: keychord: Check for write data size
keychord driver causes a kernel warning when writing more than
(1 << (MAX_ORDER - 1)) * PAGE_SIZE bytes to /dev/keychord.
In reality writes to this file should be much smaller, so
limiting data size to PAGE_SIZE seems to be appropriate.
This change checks write data size and if it's more than
PAGE_SIZE causes write to fail.
Bug: 73962978
Change-Id: I8a064a396d4259ffca924fa35d80e9700c4f8d79
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
input: touchscreen: synaptics_2.6: Add regulator configuration support
Add bus and power regulator configurations for both active
and suspend mode. Move to low power mode during idle suspend.
Enable configuration options through device tree.
Change-Id: Ic1509ab7e31e7488460a6cc86e5cd434a84fa7a8
Signed-off-by: Venkata Prahlad Valluru <vvalluru@codeaurora.org>
input: touchscreen: synaptics_dsx: Fix buffer overflow
Limit the index to buffer length while copying from
'strptr' to 'firmware_id'.
Change-Id: I1d7cb7a3d9593ca213c7f7341776632e635eb0df
Signed-off-by: Venkata Prahlad Valluru <vvalluru@codeaurora.org>
input: touchscreen: Fix buffer overflow issue in synaptics driver
Limit the index to buffer length while copying from
'strptr' to 'imagePR'.
Change-Id: Id78931c9c1f2c00b5d5c561b2ac83d947aa70bcc
Signed-off-by: Venkata Prahlad Valluru <vvalluru@codeaurora.org>
input: synaptics_dsx_2.6: Add support for automatic FW upgrade
Enable firmware upgrade at startup. Add devicetree node to
set the firmware name.
Change-Id: I4dbbcbf223529f1bff02b2591957040f1fc7609d
Signed-off-by: Venkata Prahlad Valluru <vvalluru@codeaurora.org>
input: touchscreen: synaptics_dsx_2.6: reset device when resume
For SDW2500 device, don't need to reset device when resume. But
for other projects which use same touch IC, we must reset device;
otherwise the touch IC will not work well.
Change-Id: Ie367bf95366cd8c9f8b63dc013a751a1d5073077
Signed-off-by: Fei Mao <feim1@codeaurora.org>
input: synaptics_s3320: Clean up oneplus' logic
Change-Id: If2077637d8cff3886de8dbaa3d445431c0f4158b
input: synaptics: Ditch oneplus virtual abs code
* WTF is this
Change-Id: I0d8b5a6e23f827fd945dce236e1024ab3dc97c35
input: synaptics_s3320: Create custom procfs nodes for gestures
Author: dianlujitao <dianlujitao@gmail.com>
Date: Wed Feb 1 19:19:17 2017 +0800
input: synaptics_s3320: Support all gestures
* Letter W, M and S are ignored because they're hard to reproduce
Change-Id: I407dce6473851cc2949dfd359c4296c228c05a1b
Author: dianlujitao <dianlujitao@gmail.com>
Date: Wed Feb 1 17:17:45 2017 +0800
input: synaptics_s3320: Clean up gesture handling
* Simplify procfs creation
Change-Id: I5f56bfa7e1a180071d8c25f921193f500e2ed53a
Author: dianlujitao <dianlujitao@gmail.com>
Date: Wed Feb 1 11:15:15 2017 +0800
input: synaptics_s3320: Commonize gesture flags
* Add support for up arrow gesture
Change-Id: I82f28542a085dbaa2f0e7a34e606c006905c8ac1
Author: Willi Ye <williye97@gmail.com>
Date: Tue Jun 14 22:04:01 2016 +0200
input: synpatics_s3320: Get gestures ready for CM
Change-Id: Ibbf9d6d736a7b794fe8a4cab79868abe0c09069b
Change-Id: Ief3a17fc5c07b20bb1e4f14a16aa0da7ed56974a
input: synaptics: s3320: Fix unsafe memory accesses in procfs nodes
*Use snprintf() instead of sprintf() to prevent buffer overflows
*Do not directly access user memory in type##_write_func()
*Simplify type##_read_func() routines
Change-Id: I5f86eb2f56c0d2bc6db365c2e87fa58b442a0643
Signed-off-by: Sultanxda <sultanxda@gmail.com>
input: synaptics: s3320: Fix type##_read_func function
For some reason, GCC doesn't care about type checking in here, so a lot of
crazy stuff happened.
*Normalize type##_enable to make it always boolean
*Pass the correct address of the buffer to be copied to userspace (instead
of a NULL pointer)
Change-Id: Ia97bfd7d48d103963d19ae8dd2a8ff06b5c812d7
Signed-off-by: Sultanxda <sultanxda@gmail.com>
input: synaptics_s3320: Report nanosecond timestamps to improve accuracy
Change-Id: Ia6f96dafcd4fa3c3938530a865b08dc1b07fc57e
input: synaptics_s3320: Remove unused workqueue
Change-Id: Ifcfcb4939ce229c8acdb2210e9fce2c95f5b916c
input: synaptics: s1302: Clean up PM routines and move them into worker
Reduce framebuffer blank latency by performing PM routines in a worker
outside of the fb notifier.
Change-Id: I11c4b1a150f47c095e34981e297ea74cba48016e
Signed-off-by: Sultanxda <sultanxda@gmail.com>
input: synaptics: s3320: Silence log spam
Change-Id: Icb9d94a2df9b0c15aef0ef909d75bb78a17a9d93
synaptics_driver: Fix transposed memset() arguments
Change-Id: Iaf403b766bf1814be4a1d97a71fa056de3dffc0a
input: synaptics: fw_update: Fix various memory leaks
Memory allocated to fwu->read_config_buf is not freed in both the success
and error paths. Fix it.
Change-Id: I36e6399cd33c049318884d161c890369dd9568ca
Signed-off-by: Sultanxda <sultanxda@gmail.com>
input: synaptics: s3320: Don't run baseline inside IRQ handler
tp_baseline_get() disables the touchscreen IRQ, so it should not be called
from within the IRQ handler it disables. Call it from inside a worker instead.
Change-Id: Ia797f3bd53619389d78a23d2ccee1a0b1bc7e0ef
Signed-off-by: Sultanxda <sultanxda@gmail.com>
misc: fpc1020: Clean up PM routines and move them into dedicated worker
Reduce framebuffer blank latency by performing PM routines in a worker
outside of the fb notifier.
Change-Id: Id39008f690ed1e08479f78f86d8f306d0f1acc86
Signed-off-by: Sultanxda <sultanxda@gmail.com>
misc: fpc1020: Set fingerprint hal priority to max when screen is off
Give fingerprintd the highest priority (MIN_NICE) when the screen is off to
speed up fingerprint processing, and then reset its priority back to normal
when the screen is on.
Change-Id: I71a2ebbe4ea8746fd598a246bcc9c827f0826cb9
Signed-off-by: Sultanxda <sultanxda@gmail.com>
misc: fpc1020: Clean up interrupt handler
*Don't call for a wake-lock when the screen is already on
Change-Id: If6d7d1461def5621757d449b09bc288ec09801e5
input: tri-state-key: Get it ready for CM
Change-Id: I761518d81d94331a906340d7c989acb391f27ed9
input: tri-state-key: Properly filter out spurious interrupts
All of the three pins used for the tri-state key are falling-edge
sensitive, and their IRQs are properly configured as such; however,
spurious interrupts can easily be reproduced where all of the three pins
are in a high state, causing unwanted notification-mode changes as a result.
Add a filter to IRQ worker in order to block the spurious interrupts.
Change-Id: I7fadce119a0ca039eeb563a389ac6aa181f658a3
Signed-off-by: Sultanxda <sultanxda@gmail.com>
input: tri-state-key: Rewrite and optimize
A driver for such a simple device shouldn't be so ugly. Clean it up and
optimize it in the process.
Summary of changes:
-Remove unneeded switch device
-Remove unused/unnecessary struct members
-Remove module references (this driver will always be built in)
-Utilize fixed loops and clever logic to eliminate significant amounts of
code duplication
-Remove unused pinctrl code
-Use a threaded interrupt handler
-Process interrupts directly in the threaded interrupt handler (which runs
with realtime priority) rather than a worker
-Read the initial switch state upon init (so userspace gets the correct
switch state upon boot)
-Refactor code wherever possible to make it cleaner
Note that although the procfs naming scheme is non-standard (i.e.
"keyCode_top" instead of "keycode_top"), the old naming scheme is retained
in order to maintain compatibility with userspace.
Change-Id: Ic2de6ddeb223aa7669d61c186be0b57a15e1488b
Signed-off-by: Sultanxda <sultanxda@gmail.com>
input: tri-state-key: Clean up some code styling
Use a macro to store the number of states, reduce the curr_state member in
the struct to uint8_t (since it only needs to contain 3 bits), and use
find_first_zero_bit() instead of a loop to find the first zero bit.
Change-Id: I35f369dc30186ab95033a4d27b550a07e4dc2dd8
Suggested-by: Joel Porquet <joel@porquet.org>
Signed-off-by: Sultanxda <sultanxda@gmail.com>
input: tri-state-key: Use ffz() instead of find_first_zero_bit()
find_first_zero_bit() is intended for large bitmaps; ffz() is much faster
when only a single word needs to be searched through.
Change-Id: Ib81b742805489947164af96bb8603f6732d64e8b
Suggested-by: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Sultanxda <sultanxda@gmail.com>
input: tri-state-key: Fix trivial code style issue in IRQ handler
Change-Id: Ie1e9396cf4674586a68dbf606a1d51fbffeaaca4
Signed-off-by: Sultanxda <sultanxda@gmail.com>
---
.../touchscreen/synaptics_dsxv26_i2c.txt | 4 +
drivers/input/Kconfig | 7 +
drivers/input/Makefile | 2 +-
drivers/input/hall_sensor.c | 333 +
drivers/input/misc/Kconfig | 45 +
drivers/input/misc/Makefile | 11 +
drivers/input/misc/bma2x2.c | 8959 +++++++++++++++++
drivers/input/misc/bstclass.c | 270 +
drivers/input/misc/bstclass.h | 78 +
drivers/input/misc/fpc1020_tee.c | 105 +-
drivers/input/misc/keychord.c | 2 +-
drivers/input/misc/ltr553.c | 2260 +++++
drivers/input/misc/tri_state_key.c | 682 +-
drivers/input/touchscreen/fw_update_v7.if | 22 +-
.../touchscreen/synaptics_driver_s1302.c | 149 +-
.../touchscreen/synaptics_driver_s3320.c | 443 +-
.../synaptics_dsx/synaptics_dsx_fw_update.c | 4 +-
.../synaptics_dsx_2.6/synaptics_dsx_core.c | 197 +-
.../synaptics_dsx_2.6/synaptics_dsx_core.h | 1 +
.../synaptics_dsx_fw_update.c | 17 +-
.../synaptics_dsx_2.6/synaptics_dsx_i2c.c | 19 +-
.../input/touchscreen/synaptics_fw_update.c | 3 +-
include/linux/input/synaptics_dsx_v2_6.h | 8 +-
23 files changed, 12784 insertions(+), 837 deletions(-)
create mode 100644 drivers/input/hall_sensor.c
create mode 100644 drivers/input/misc/bma2x2.c
create mode 100644 drivers/input/misc/bstclass.c
create mode 100644 drivers/input/misc/bstclass.h
create mode 100644 drivers/input/misc/ltr553.c
diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt
index f693d72442ff..f7de07f57a87 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt
@@ -18,13 +18,17 @@ Optional property:
- vcc_i2c-supply : analog voltage power supply needed to power device.
- synaptics,pwr-reg-name : power reg name of digital voltage.
- synaptics,bus-reg-name : bus reg name of analog voltage.
+ - synaptics,do-not-disable-regulators : If specified, regulators cannot be disabled/enabled during suspend/resume.
- synaptics,irq-on-state : status of irq gpio.
- synaptics,cap-button-codes : virtual key code mappings to be used.
- synaptics,vir-button-codes : virtual key code and the response region on panel.
+ - synaptics,wakeup-gestures-en: enable wakeup gestures.
- synaptics,x-flip : modify orientation of the x axis.
- synaptics,y-flip : modify orientation of the y axis.
- synaptics,reset-delay-ms : reset delay for controller (ms), default 100.
- synaptics,max-y-for-2d : maximal y value of the panel.
+ - synaptics,bus-lpm-cur-uA : I2C bus idle mode current setting.
+ - synaptics,fw-name : name of firmware .img file in /lib/firmware
- clock-names : Clock names used for secure touch. They are: "iface_clk", "core_clk"
- clocks : Defined if 'clock-names' DT property is defined. These clocks
are associated with the underlying I2C bus.
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 2a4c51377f86..1819769051f3 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -187,6 +187,13 @@ config INPUT_KEYCOMBO
---help---
Say Y here if you want to take action when some keys are pressed;
+config SENSORS_HALL
+ bool "Hall sensor"
+ depends on INPUT
+ ---help---
+ Say y here if you want to use this hall sensor driver, it
+ is like a switch. For example, lid.
+
comment "Input Device Drivers"
source "drivers/input/keyboard/Kconfig"
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index ee4c06520bb4..93289a43536e 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -27,4 +27,4 @@ obj-$(CONFIG_INPUT_MISC) += misc/
obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o
obj-$(CONFIG_INPUT_KEYRESET) += keyreset.o
obj-$(CONFIG_INPUT_KEYCOMBO) += keycombo.o
-
+obj-$(CONFIG_SENSORS_HALL) += hall_sensor.o
diff --git a/drivers/input/hall_sensor.c b/drivers/input/hall_sensor.c
new file mode 100644
index 000000000000..7f0a3d3f821c
--- /dev/null
+++ b/drivers/input/hall_sensor.c
@@ -0,0 +1,333 @@
+/*
+ *
+ * Copyright (c) 2014-2015,2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+
+#define LID_DEV_NAME "hall_sensor"
+#define HALL_INPUT "/dev/input/hall_dev"
+
+struct hall_data {
+ int gpio; /* device use gpio number */
+ int irq; /* device request irq number */
+ int active_low; /* gpio active high or low for valid value */
+ bool wakeup; /* device can wakeup system or not */
+ struct input_dev *hall_dev;
+ struct regulator *vddio;
+ u32 min_uv; /* device allow minimum voltage */
+ u32 max_uv; /* device allow max voltage */
+};
+
+static irqreturn_t hall_interrupt_handler(int irq, void *dev)
+{
+ int value;
+ struct hall_data *data = dev;
+
+ value = (gpio_get_value_cansleep(data->gpio) ? 1 : 0) ^
+ data->active_low;
+ if (value) {
+ input_report_switch(data->hall_dev, SW_LID, 0);
+ dev_dbg(&data->hall_dev->dev, "far\n");
+ } else {
+ input_report_switch(data->hall_dev, SW_LID, 1);
+ dev_dbg(&data->hall_dev->dev, "near\n");
+ }
+ input_sync(data->hall_dev);
+
+ return IRQ_HANDLED;
+}
+
+static int hall_input_init(struct platform_device *pdev,
+ struct hall_data *data)
+{
+ int err = -1;
+
+ data->hall_dev = devm_input_allocate_device(&pdev->dev);
+ if (!data->hall_dev) {
+ dev_err(&data->hall_dev->dev,
+ "input device allocation failed\n");
+ return -EINVAL;
+ }
+ data->hall_dev->name = LID_DEV_NAME;
+ data->hall_dev->phys = HALL_INPUT;
+ __set_bit(EV_SW, data->hall_dev->evbit);
+ __set_bit(SW_LID, data->hall_dev->swbit);
+
+ err = input_register_device(data->hall_dev);
+ if (err < 0) {
+ dev_err(&data->hall_dev->dev,
+ "unable to register input device %s\n",
+ LID_DEV_NAME);
+ return err;
+ }
+
+ return 0;
+}
+
+static int hall_config_regulator(struct platform_device *dev, bool on)
+{
+ struct hall_data *data = dev_get_drvdata(&dev->dev);
+ int rc = 0;
+
+ if (on) {
+ data->vddio = devm_regulator_get(&dev->dev, "vddio");
+ if (IS_ERR(data->vddio)) {
+ rc = PTR_ERR(data->vddio);
+ dev_err(&dev->dev, "Regulator vddio get failed rc=%d\n",
+ rc);
+ data->vddio = NULL;
+ return rc;
+ }
+
+ if (regulator_count_voltages(data->vddio) > 0) {
+ rc = regulator_set_voltage(
+ data->vddio,
+ data->min_uv,
+ data->max_uv);
+ if (rc) {
+ dev_err(&dev->dev, "Regulator vddio Set voltage failed rc=%d\n",
+ rc);
+ goto deinit_vregs;
+ }
+ }
+ return rc;
+ }
+
+deinit_vregs:
+ if (regulator_count_voltages(data->vddio) > 0)
+ regulator_set_voltage(data->vddio, 0, data->max_uv);
+
+ return rc;
+}
+
+static int hall_set_regulator(struct platform_device *dev, bool on)
+{
+ struct hall_data *data = dev_get_drvdata(&dev->dev);
+ int rc = 0;
+
+ if (on) {
+ if (!IS_ERR_OR_NULL(data->vddio)) {
+ rc = regulator_enable(data->vddio);
+ if (rc) {
+ dev_err(&dev->dev, "Enable regulator vddio failed rc=%d\n",
+ rc);
+ goto disable_regulator;
+ }
+ }
+ return rc;
+ }
+ if (!IS_ERR_OR_NULL(data->vddio)) {
+ rc = regulator_disable(data->vddio);
+ if (rc)
+ dev_err(&dev->dev, "Disable regulator vddio failed rc=%d\n",
+ rc);
+ }
+ return 0;
+
+disable_regulator:
+ if (!IS_ERR_OR_NULL(data->vddio))
+ regulator_disable(data->vddio);
+ return rc;
+}
+
+#ifdef CONFIG_OF
+static int hall_parse_dt(struct device *dev, struct hall_data *data)
+{
+ unsigned int tmp;
+ u32 tempval;
+ int rc;
+ struct device_node *np = dev->of_node;
+
+ data->gpio = of_get_named_gpio_flags(dev->of_node,
+ "linux,gpio-int", 0, &tmp);
+ if (!gpio_is_valid(data->gpio)) {
+ dev_err(dev, "hall gpio is not valid\n");
+ return -EINVAL;
+ }
+ data->active_low = tmp & OF_GPIO_ACTIVE_LOW ? 0 : 1;
+
+ data->wakeup = of_property_read_bool(np, "linux,wakeup");
+
+ rc = of_property_read_u32(np, "linux,max-uv", &tempval);
+ if (rc) {
+ dev_err(dev, "unable to read max-uv\n");
+ return -EINVAL;
+ }
+ data->max_uv = tempval;
+
+ rc = of_property_read_u32(np, "linux,min-uv", &tempval);
+ if (rc) {
+ dev_err(dev, "unable to read min-uv\n");
+ return -EINVAL;
+ }
+ data->min_uv = tempval;
+
+ return 0;
+}
+#else
+static int hall_parse_dt(struct device *dev, struct hall_data *data)
+{
+ return -EINVAL;
+}
+#endif
+
+static int hall_driver_probe(struct platform_device *dev)
+{
+ struct hall_data *data;
+ int err = 0;
+ int irq_flags;
+
+ dev_dbg(&dev->dev, "hall_driver probe\n");
+ data = devm_kzalloc(&dev->dev, sizeof(struct hall_data), GFP_KERNEL);
+ if (data == NULL) {
+ err = -ENOMEM;
+ dev_err(&dev->dev,
+ "failed to allocate memory %d\n", err);
+ goto exit;
+ }
+ dev_set_drvdata(&dev->dev, data);
+ if (dev->dev.of_node) {
+ err = hall_parse_dt(&dev->dev, data);
+ if (err < 0) {
+ dev_err(&dev->dev, "Failed to parse device tree\n");
+ goto exit;
+ }
+ } else if (dev->dev.platform_data != NULL) {
+ memcpy(data, dev->dev.platform_data, sizeof(*data));
+ } else {
+ dev_err(&dev->dev, "No valid platform data.\n");
+ err = -ENODEV;
+ goto exit;
+ }
+
+ err = hall_input_init(dev, data);
+ if (err < 0) {
+ dev_err(&dev->dev, "input init failed\n");
+ goto exit;
+ }
+
+ if (!gpio_is_valid(data->gpio)) {
+ dev_err(&dev->dev, "gpio is not valid\n");
+ err = -EINVAL;
+ goto exit;
+ }
+
+ irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+ | IRQF_ONESHOT;
+ err = gpio_request_one(data->gpio, GPIOF_DIR_IN, "hall_sensor_irq");
+ if (err) {
+ dev_err(&dev->dev, "unable to request gpio %d\n", data->gpio);
+ goto exit;
+ }
+
+ data->irq = gpio_to_irq(data->gpio);
+ err = devm_request_threaded_irq(&dev->dev, data->irq, NULL,
+ hall_interrupt_handler,
+ irq_flags, "hall_sensor", data);
+ if (err < 0) {
+ dev_err(&dev->dev, "request irq failed : %d\n", data->irq);
+ goto free_gpio;
+ }
+
+ device_init_wakeup(&dev->dev, data->wakeup);
+ enable_irq_wake(data->irq);
+
+ err = hall_config_regulator(dev, true);
+ if (err < 0) {
+ dev_err(&dev->dev, "Configure power failed: %d\n", err);
+ goto free_irq;
+ }
+
+ err = hall_set_regulator(dev, true);
+ if (err < 0) {
+ dev_err(&dev->dev, "power on failed: %d\n", err);
+ goto err_regulator_init;
+ }
+
+ return 0;
+
+err_regulator_init:
+ hall_config_regulator(dev, false);
+free_irq:
+ disable_irq_wake(data->irq);
+ device_init_wakeup(&dev->dev, 0);
+free_gpio:
+ gpio_free(data->gpio);
+exit:
+ return err;
+}
+
+static int hall_driver_remove(struct platform_device *dev)
+{
+ struct hall_data *data = dev_get_drvdata(&dev->dev);
+
+ disable_irq_wake(data->irq);
+ device_init_wakeup(&dev->dev, 0);
+ if (data->gpio)
+ gpio_free(data->gpio);
+ hall_set_regulator(dev, false);
+ hall_config_regulator(dev, false);
+
+ return 0;
+}
+
+static struct platform_device_id hall_id[] = {
+ {LID_DEV_NAME, 0 },
+ { },
+};
+
+
+#ifdef CONFIG_OF
+static struct of_device_id hall_match_table[] = {
+ {.compatible = "hall-switch", },
+ { },
+};
+#endif
+
+static struct platform_driver hall_driver = {
+ .driver = {
+ .name = LID_DEV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(hall_match_table),
+ },
+ .probe = hall_driver_probe,
+ .remove = hall_driver_remove,
+ .id_table = hall_id,
+};
+
+static int __init hall_init(void)
+{
+ return platform_driver_register(&hall_driver);
+}
+
+static void __exit hall_exit(void)
+{
+ platform_driver_unregister(&hall_driver);
+}
+
+module_init(hall_init);
+module_exit(hall_exit);
+MODULE_DESCRIPTION("Hall sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index c5a98270284c..2a1b94f5708e 100755
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -789,4 +789,49 @@ config INPUT_DRV2667_HAPTICS
source "drivers/input/misc/ots_pat9125/Kconfig"
+config SENSORS_LTR553
+ tristate "LTR553 light and proximity device driver"
+ depends on I2C
+ help
+ Say Y here if you want to enable the LTR553 light and
+ proximity sensor driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ltr553.
+
+config SENSORS_BMA2X2
+ tristate "BMA2x2 acceleration sensor support"
+ depends on I2C
+ help
+ If you say yes here, you get support for Bosch Sensortec's
+ acceleration sensors BMA255/BMA254/BMA355/BMA250E/BMA222E/BMA280.
+
+config SENSORS_BMA2X2_ENABLE_INT1
+ tristate "BMA2X2 acceleration sensor interrupt INT1 support"
+ depends on SENSORS_BMA2X2
+ help
+ If you say yes here, you get INT1 support for Bosch Sensortec
+ acceleration sensors BMA255/BMA254/BMA355/BMA250E/BMA222E/BMA280.
+ Select it will disable interrupt INT2 support
+
+config SENSORS_BMA2X2_ENABLE_INT2
+ tristate "BMA2X2 acceleration sensor interrupt INT2 support"
+ depends on SENSORS_BMA2X2 && !SENSORS_BMA2X2_ENABLE_INT1
+ help
+ If you say yes here, you get INT2 support for Bosch Sensortec
+ acceleration sensors BMA255/BMA254/BMA355/BMA250E/BMA222E/BMA280.
+ Can only open if you do NOT open interrupt INT1 support
+
+config SIG_MOTION
+ tristate "support significant motion sensor function"
+ depends on SENSORS_BMA2X2 && ( SENSORS_BMA2X2_ENABLE_INT1 || SENSORS_BMA2X2_ENABLE_INT2)
+ help
+ If you say yes here, if you want to support Bosch significant motion sensor function
+
+config DOUBLE_TAP
+ tristate "support double tap sensor function"
+ depends on SENSORS_BMA2X2 && ( SENSORS_BMA2X2_ENABLE_INT1 || SENSORS_BMA2X2_ENABLE_INT2)
+ help
+ If you say yes here, you get support Bosch double tap sensor function
+
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 9c97e7d840f5..28df9bb72f51 100755
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -72,6 +72,17 @@ obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
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_SENSORS_LTR553) += ltr553.o
+obj-$(CONFIG_SENSORS_BMA2X2) += bstclass.o
+
+obj-$(CONFIG_SENSORS_BMA2X2) += bma2x2.o
+ifeq ($(CONFIG_SENSORS_BMA2X2_ENABLE_INT1),y)
+ EXTRA_CFLAGS += -DBMA2X2_ENABLE_INT1
+endif
+
+ifeq ($(CONFIG_BOSCH_BMA2X2_ENABLE_INT2),y)
+ EXTRA_CFLAGS += -DBMA2X2_ENABLE_INT2
+endif
obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o
obj-$(CONFIG_INPUT_PIXART_OTS_PAT9125_SWITCH) += ots_pat9125/
obj-$(CONFIG_TRI_STATE_KEY) += tri_state_key.o
diff --git a/drivers/input/misc/bma2x2.c b/drivers/input/misc/bma2x2.c
new file mode 100644
index 000000000000..7b526277a862
--- /dev/null
+++ b/drivers/input/misc/bma2x2.c
@@ -0,0 +1,8959 @@
+/*!
+ * @section LICENSE
+ * (C) Copyright 2013 Bosch Sensortec GmbH All Rights Reserved
+ *
+ * This software program is licensed subject to the GNU General
+ * Public License (GPL).Version 2,June 1991,
+ * available at http://www.fsf.org/copyleft/gpl.html
+ *
+ * @filename bma2x2.c
+ * @date 2014/02/13 15:50
+ * @id "564eaab"
+ * @version 2.0
+ *
+ * @brief
+ * This file contains all function implementations for the BMA2X2 in linux
+*/
+
+#define BMA2X2_ENABLE_INT2
+
+#if !defined(BMA2X2_ENABLE_INT1) && !defined(BMA2X2_ENABLE_INT2)
+#if defined(CONFIG_BMA_ENABLE_NEWDATA_INT) || defined(CONFIG_SIG_MOTION)
+#error Please enable INT1 or INT2 to support new data int and sig-motion int!
+#endif
+#endif
+
+#ifdef CONFIG_SIG_MOTION
+#undef CONFIG_HAS_EARLYSUSPEND
+#endif
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/irq.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+#include <linux/sensors.h>
+#include <linux/kthread.h>
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/unistd.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#else
+#include <unistd.h>
+#include <sys/types.h>
+#include <string.h>
+#endif
+
+#include "bstclass.h"
+
+#define ACC_NAME "ACC"
+
+#ifdef ENABLE_ISR_DEBUG_MSG
+#define ISR_INFO(dev, fmt, arg...) dev_info(dev, fmt, ##arg)
+#else
+#define ISR_INFO(dev, fmt, arg...)
+#endif
+
+#define BMA2X2_SENSOR_IDENTIFICATION_ENABLE
+
+#define SENSOR_NAME "bma2x2-accel"
+#define ABSMIN -512
+#define ABSMAX 512
+#define SLOPE_THRESHOLD_VALUE 32
+#define SLOPE_DURATION_VALUE 1
+#define INTERRUPT_LATCH_MODE 13
+#define INTERRUPT_ENABLE 1
+#define INTERRUPT_DISABLE 0
+#define MAP_SLOPE_INTERRUPT 2
+#define SLOPE_X_INDEX 5
+#define SLOPE_Y_INDEX 6
+#define SLOPE_Z_INDEX 7
+#define BMA2X2_RANGE_SET 3 /* +/- 2G */
+#define BMA2X2_RANGE_SHIFT 4 /* shift 4 bits for 2G */
+#define BMA2X2_BW_SET 12 /* 125HZ */
+
+#define I2C_RETRY_DELAY() usleep_range(1000, 2000)
+/* wait 2ms for calibration ready */
+#define WAIT_CAL_READY() usleep_range(2000, 2500)
+/* >3ms wait device ready */
+#define WAIT_DEVICE_READY() usleep_range(3000, 5000)
+/* >5ms for device reset */
+#define RESET_DELAY() usleep_range(5000, 10000)
+/* wait 10ms for self test done */
+#define SELF_TEST_DELAY() usleep_range(10000, 15000)
+
+#ifdef USE_BMA_INTERRUPT
+#define LOW_G_INTERRUPT REL_Z
+#define HIGH_G_INTERRUPT REL_HWHEEL
+#define SLOP_INTERRUPT REL_DIAL
+#define DOUBLE_TAP_INTERRUPT REL_WHEEL
+#define SINGLE_TAP_INTERRUPT REL_MISC
+#define ORIENT_INTERRUPT ABS_PRESSURE
+#define FLAT_INTERRUPT ABS_DISTANCE
+#define SLOW_NO_MOTION_INTERRUPT REL_Y
+#else
+/* AndroidM didn't use the dev-interrupt,bypass above defines */
+#define LOW_G_INTERRUPT REL_Z
+#define HIGH_G_INTERRUPT REL_Z
+#define SLOP_INTERRUPT REL_Z
+#define DOUBLE_TAP_INTERRUPT REL_Z
+#define SINGLE_TAP_INTERRUPT REL_Z
+#define ORIENT_INTERRUPT REL_Z
+#define FLAT_INTERRUPT REL_Z
+#define SLOW_NO_MOTION_INTERRUPT REL_Z
+#endif
+
+#define HIGH_G_INTERRUPT_X_HAPPENED 1
+#define HIGH_G_INTERRUPT_Y_HAPPENED 2
+#define HIGH_G_INTERRUPT_Z_HAPPENED 3
+#define HIGH_G_INTERRUPT_X_NEGATIVE_HAPPENED 4
+#define HIGH_G_INTERRUPT_Y_NEGATIVE_HAPPENED 5
+#define HIGH_G_INTERRUPT_Z_NEGATIVE_HAPPENED 6
+#define SLOPE_INTERRUPT_X_HAPPENED 7
+#define SLOPE_INTERRUPT_Y_HAPPENED 8
+#define SLOPE_INTERRUPT_Z_HAPPENED 9
+#define SLOPE_INTERRUPT_X_NEGATIVE_HAPPENED 10
+#define SLOPE_INTERRUPT_Y_NEGATIVE_HAPPENED 11
+#define SLOPE_INTERRUPT_Z_NEGATIVE_HAPPENED 12
+#define DOUBLE_TAP_INTERRUPT_HAPPENED 13
+#define SINGLE_TAP_INTERRUPT_HAPPENED 14
+#define UPWARD_PORTRAIT_UP_INTERRUPT_HAPPENED 15
+#define UPWARD_PORTRAIT_DOWN_INTERRUPT_HAPPENED 16
+#define UPWARD_LANDSCAPE_LEFT_INTERRUPT_HAPPENED 17
+#define UPWARD_LANDSCAPE_RIGHT_INTERRUPT_HAPPENED 18
+#define DOWNWARD_PORTRAIT_UP_INTERRUPT_HAPPENED 19
+#define DOWNWARD_PORTRAIT_DOWN_INTERRUPT_HAPPENED 20
+#define DOWNWARD_LANDSCAPE_LEFT_INTERRUPT_HAPPENED 21
+#define DOWNWARD_LANDSCAPE_RIGHT_INTERRUPT_HAPPENED 22
+#define FLAT_INTERRUPT_TRUE_HAPPENED 23
+#define FLAT_INTERRUPT_FALSE_HAPPENED 24
+#define LOW_G_INTERRUPT_HAPPENED 25
+#define SLOW_NO_MOTION_INTERRUPT_HAPPENED 26
+
+#define PAD_LOWG 0
+#define PAD_HIGHG 1
+#define PAD_SLOP 2
+#define PAD_DOUBLE_TAP 3
+#define PAD_SINGLE_TAP 4
+#define PAD_ORIENT 5
+#define PAD_FLAT 6
+#define PAD_SLOW_NO_MOTION 7
+
+#define BMA2X2_EEP_OFFSET 0x16
+#define BMA2X2_IMAGE_BASE 0x38
+#define BMA2X2_IMAGE_LEN 22
+
+#define BMA2X2_CHIP_ID_REG 0x00
+#define BMA2X2_VERSION_REG 0x01
+#define BMA2X2_X_AXIS_LSB_REG 0x02
+#define BMA2X2_X_AXIS_MSB_REG 0x03
+#define BMA2X2_Y_AXIS_LSB_REG 0x04
+#define BMA2X2_Y_AXIS_MSB_REG 0x05
+#define BMA2X2_Z_AXIS_LSB_REG 0x06
+#define BMA2X2_Z_AXIS_MSB_REG 0x07
+#define BMA2X2_TEMPERATURE_REG 0x08
+#define BMA2X2_STATUS1_REG 0x09
+#define BMA2X2_STATUS2_REG 0x0A
+#define BMA2X2_STATUS_TAP_SLOPE_REG 0x0B
+#define BMA2X2_STATUS_ORIENT_HIGH_REG 0x0C
+#define BMA2X2_STATUS_FIFO_REG 0x0E
+#define BMA2X2_RANGE_SEL_REG 0x0F
+#define BMA2X2_BW_SEL_REG 0x10
+#define BMA2X2_MODE_CTRL_REG 0x11
+#define BMA2X2_LOW_NOISE_CTRL_REG 0x12
+#define BMA2X2_DATA_CTRL_REG 0x13
+#define BMA2X2_RESET_REG 0x14
+#define BMA2X2_INT_ENABLE1_REG 0x16
+#define BMA2X2_INT_ENABLE2_REG 0x17
+#define BMA2X2_INT_SLO_NO_MOT_REG 0x18
+#define BMA2X2_INT1_PAD_SEL_REG 0x19
+#define BMA2X2_INT_DATA_SEL_REG 0x1A
+#define BMA2X2_INT2_PAD_SEL_REG 0x1B
+#define BMA2X2_INT_SRC_REG 0x1E
+#define BMA2X2_INT_SET_REG 0x20
+#define BMA2X2_INT_CTRL_REG 0x21
+#define BMA2X2_LOW_DURN_REG 0x22
+#define BMA2X2_LOW_THRES_REG 0x23
+#define BMA2X2_LOW_HIGH_HYST_REG 0x24
+#define BMA2X2_HIGH_DURN_REG 0x25
+#define BMA2X2_HIGH_THRES_REG 0x26
+#define BMA2X2_SLOPE_DURN_REG 0x27
+#define BMA2X2_SLOPE_THRES_REG 0x28
+#define BMA2X2_SLO_NO_MOT_THRES_REG 0x29
+#define BMA2X2_TAP_PARAM_REG 0x2A
+#define BMA2X2_TAP_THRES_REG 0x2B
+#define BMA2X2_ORIENT_PARAM_REG 0x2C
+#define BMA2X2_THETA_BLOCK_REG 0x2D
+#define BMA2X2_THETA_FLAT_REG 0x2E
+#define BMA2X2_FLAT_HOLD_TIME_REG 0x2F
+#define BMA2X2_FIFO_WML_TRIG 0x30
+#define BMA2X2_SELF_TEST_REG 0x32
+#define BMA2X2_EEPROM_CTRL_REG 0x33
+#define BMA2X2_SERIAL_CTRL_REG 0x34
+#define BMA2X2_EXTMODE_CTRL_REG 0x35
+#define BMA2X2_OFFSET_CTRL_REG 0x36
+#define BMA2X2_OFFSET_PARAMS_REG 0x37
+#define BMA2X2_OFFSET_X_AXIS_REG 0x38
+#define BMA2X2_OFFSET_Y_AXIS_REG 0x39
+#define BMA2X2_OFFSET_Z_AXIS_REG 0x3A
+#define BMA2X2_GP0_REG 0x3B
+#define BMA2X2_GP1_REG 0x3C
+#define BMA2X2_FIFO_MODE_REG 0x3E
+#define BMA2X2_FIFO_DATA_OUTPUT_REG 0x3F
+
+#define BMA2X2_CHIP_ID__POS 0
+#define BMA2X2_CHIP_ID__MSK 0xFF
+#define BMA2X2_CHIP_ID__LEN 8
+#define BMA2X2_CHIP_ID__REG BMA2X2_CHIP_ID_REG
+
+#define BMA2X2_VERSION__POS 0
+#define BMA2X2_VERSION__LEN 8
+#define BMA2X2_VERSION__MSK 0xFF
+#define BMA2X2_VERSION__REG BMA2X2_VERSION_REG
+
+#define BMA2x2_SLO_NO_MOT_DUR__POS 2
+#define BMA2x2_SLO_NO_MOT_DUR__LEN 6
+#define BMA2x2_SLO_NO_MOT_DUR__MSK 0xFC
+#define BMA2x2_SLO_NO_MOT_DUR__REG BMA2X2_SLOPE_DURN_REG
+
+#define BMA2X2_NEW_DATA_X__POS 0
+#define BMA2X2_NEW_DATA_X__LEN 1
+#define BMA2X2_NEW_DATA_X__MSK 0x01
+#define BMA2X2_NEW_DATA_X__REG BMA2X2_X_AXIS_LSB_REG
+
+#define BMA2X2_ACC_X14_LSB__POS 2
+#define BMA2X2_ACC_X14_LSB__LEN 6
+#define BMA2X2_ACC_X14_LSB__MSK 0xFC
+#define BMA2X2_ACC_X14_LSB__REG BMA2X2_X_AXIS_LSB_REG
+
+#define BMA2X2_ACC_X12_LSB__POS 4
+#define BMA2X2_ACC_X12_LSB__LEN 4
+#define BMA2X2_ACC_X12_LSB__MSK 0xF0
+#define BMA2X2_ACC_X12_LSB__REG BMA2X2_X_AXIS_LSB_REG
+
+#define BMA2X2_ACC_X10_LSB__POS 6
+#define BMA2X2_ACC_X10_LSB__LEN 2
+#define BMA2X2_ACC_X10_LSB__MSK 0xC0
+#define BMA2X2_ACC_X10_LSB__REG BMA2X2_X_AXIS_LSB_REG
+
+#define BMA2X2_ACC_X8_LSB__POS 0
+#define BMA2X2_ACC_X8_LSB__LEN 0
+#define BMA2X2_ACC_X8_LSB__MSK 0x00
+#define BMA2X2_ACC_X8_LSB__REG BMA2X2_X_AXIS_LSB_REG
+
+#define BMA2X2_ACC_X_MSB__POS 0
+#define BMA2X2_ACC_X_MSB__LEN 8
+#define BMA2X2_ACC_X_MSB__MSK 0xFF
+#define BMA2X2_ACC_X_MSB__REG BMA2X2_X_AXIS_MSB_REG
+
+#define BMA2X2_NEW_DATA_Y__POS 0
+#define BMA2X2_NEW_DATA_Y__LEN 1
+#define BMA2X2_NEW_DATA_Y__MSK 0x01
+#define BMA2X2_NEW_DATA_Y__REG BMA2X2_Y_AXIS_LSB_REG
+
+#define BMA2X2_ACC_Y14_LSB__POS 2
+#define BMA2X2_ACC_Y14_LSB__LEN 6
+#define BMA2X2_ACC_Y14_LSB__MSK 0xFC
+#define BMA2X2_ACC_Y14_LSB__REG BMA2X2_Y_AXIS_LSB_REG
+
+#define BMA2X2_ACC_Y12_LSB__POS 4
+#define BMA2X2_ACC_Y12_LSB__LEN 4
+#define BMA2X2_ACC_Y12_LSB__MSK 0xF0
+#define BMA2X2_ACC_Y12_LSB__REG BMA2X2_Y_AXIS_LSB_REG
+
+#define BMA2X2_ACC_Y10_LSB__POS 6
+#define BMA2X2_ACC_Y10_LSB__LEN 2
+#define BMA2X2_ACC_Y10_LSB__MSK 0xC0
+#define BMA2X2_ACC_Y10_LSB__REG BMA2X2_Y_AXIS_LSB_REG
+
+#define BMA2X2_ACC_Y8_LSB__POS 0
+#define BMA2X2_ACC_Y8_LSB__LEN 0
+#define BMA2X2_ACC_Y8_LSB__MSK 0x00
+#define BMA2X2_ACC_Y8_LSB__REG BMA2X2_Y_AXIS_LSB_REG
+
+#define BMA2X2_ACC_Y_MSB__POS 0
+#define BMA2X2_ACC_Y_MSB__LEN 8
+#define BMA2X2_ACC_Y_MSB__MSK 0xFF
+#define BMA2X2_ACC_Y_MSB__REG BMA2X2_Y_AXIS_MSB_REG
+
+#define BMA2X2_NEW_DATA_Z__POS 0
+#define BMA2X2_NEW_DATA_Z__LEN 1
+#define BMA2X2_NEW_DATA_Z__MSK 0x01
+#define BMA2X2_NEW_DATA_Z__REG BMA2X2_Z_AXIS_LSB_REG
+
+#define BMA2X2_ACC_Z14_LSB__POS 2
+#define BMA2X2_ACC_Z14_LSB__LEN 6
+#define BMA2X2_ACC_Z14_LSB__MSK 0xFC
+#define BMA2X2_ACC_Z14_LSB__REG BMA2X2_Z_AXIS_LSB_REG
+
+#define BMA2X2_ACC_Z12_LSB__POS 4
+#define BMA2X2_ACC_Z12_LSB__LEN 4
+#define BMA2X2_ACC_Z12_LSB__MSK 0xF0
+#define BMA2X2_ACC_Z12_LSB__REG BMA2X2_Z_AXIS_LSB_REG
+
+#define BMA2X2_ACC_Z10_LSB__POS 6
+#define BMA2X2_ACC_Z10_LSB__LEN 2
+#define BMA2X2_ACC_Z10_LSB__MSK 0xC0
+#define BMA2X2_ACC_Z10_LSB__REG BMA2X2_Z_AXIS_LSB_REG
+
+#define BMA2X2_ACC_Z8_LSB__POS 0
+#define BMA2X2_ACC_Z8_LSB__LEN 0
+#define BMA2X2_ACC_Z8_LSB__MSK 0x00
+#define BMA2X2_ACC_Z8_LSB__REG BMA2X2_Z_AXIS_LSB_REG
+
+#define BMA2X2_ACC_Z_MSB__POS 0
+#define BMA2X2_ACC_Z_MSB__LEN 8
+#define BMA2X2_ACC_Z_MSB__MSK 0xFF
+#define BMA2X2_ACC_Z_MSB__REG BMA2X2_Z_AXIS_MSB_REG
+
+#define BMA2X2_TEMPERATURE__POS 0
+#define BMA2X2_TEMPERATURE__LEN 8
+#define BMA2X2_TEMPERATURE__MSK 0xFF
+#define BMA2X2_TEMPERATURE__REG BMA2X2_TEMP_RD_REG
+
+#define BMA2X2_LOWG_INT_S__POS 0
+#define BMA2X2_LOWG_INT_S__LEN 1
+#define BMA2X2_LOWG_INT_S__MSK 0x01
+#define BMA2X2_LOWG_INT_S__REG BMA2X2_STATUS1_REG
+
+#define BMA2X2_HIGHG_INT_S__POS 1
+#define BMA2X2_HIGHG_INT_S__LEN 1
+#define BMA2X2_HIGHG_INT_S__MSK 0x02
+#define BMA2X2_HIGHG_INT_S__REG BMA2X2_STATUS1_REG
+
+#define BMA2X2_SLOPE_INT_S__POS 2
+#define BMA2X2_SLOPE_INT_S__LEN 1
+#define BMA2X2_SLOPE_INT_S__MSK 0x04
+#define BMA2X2_SLOPE_INT_S__REG BMA2X2_STATUS1_REG
+
+
+#define BMA2X2_SLO_NO_MOT_INT_S__POS 3
+#define BMA2X2_SLO_NO_MOT_INT_S__LEN 1
+#define BMA2X2_SLO_NO_MOT_INT_S__MSK 0x08
+#define BMA2X2_SLO_NO_MOT_INT_S__REG BMA2X2_STATUS1_REG
+
+#define BMA2X2_DOUBLE_TAP_INT_S__POS 4
+#define BMA2X2_DOUBLE_TAP_INT_S__LEN 1
+#define BMA2X2_DOUBLE_TAP_INT_S__MSK 0x10
+#define BMA2X2_DOUBLE_TAP_INT_S__REG BMA2X2_STATUS1_REG
+
+#define BMA2X2_SINGLE_TAP_INT_S__POS 5
+#define BMA2X2_SINGLE_TAP_INT_S__LEN 1
+#define BMA2X2_SINGLE_TAP_INT_S__MSK 0x20
+#define BMA2X2_SINGLE_TAP_INT_S__REG BMA2X2_STATUS1_REG
+
+#define BMA2X2_ORIENT_INT_S__POS 6
+#define BMA2X2_ORIENT_INT_S__LEN 1
+#define BMA2X2_ORIENT_INT_S__MSK 0x40
+#define BMA2X2_ORIENT_INT_S__REG BMA2X2_STATUS1_REG
+
+#define BMA2X2_FLAT_INT_S__POS 7
+#define BMA2X2_FLAT_INT_S__LEN 1
+#define BMA2X2_FLAT_INT_S__MSK 0x80
+#define BMA2X2_FLAT_INT_S__REG BMA2X2_STATUS1_REG
+
+#define BMA2X2_FIFO_FULL_INT_S__POS 5
+#define BMA2X2_FIFO_FULL_INT_S__LEN 1
+#define BMA2X2_FIFO_FULL_INT_S__MSK 0x20
+#define BMA2X2_FIFO_FULL_INT_S__REG BMA2X2_STATUS2_REG
+
+#define BMA2X2_FIFO_WM_INT_S__POS 6
+#define BMA2X2_FIFO_WM_INT_S__LEN 1
+#define BMA2X2_FIFO_WM_INT_S__MSK 0x40
+#define BMA2X2_FIFO_WM_INT_S__REG BMA2X2_STATUS2_REG
+
+#define BMA2X2_DATA_INT_S__POS 7
+#define BMA2X2_DATA_INT_S__LEN 1
+#define BMA2X2_DATA_INT_S__MSK 0x80
+#define BMA2X2_DATA_INT_S__REG BMA2X2_STATUS2_REG
+
+#define BMA2X2_SLOPE_FIRST_X__POS 0
+#define BMA2X2_SLOPE_FIRST_X__LEN 1
+#define BMA2X2_SLOPE_FIRST_X__MSK 0x01
+#define BMA2X2_SLOPE_FIRST_X__REG BMA2X2_STATUS_TAP_SLOPE_REG
+
+#define BMA2X2_SLOPE_FIRST_Y__POS 1
+#define BMA2X2_SLOPE_FIRST_Y__LEN 1
+#define BMA2X2_SLOPE_FIRST_Y__MSK 0x02
+#define BMA2X2_SLOPE_FIRST_Y__REG BMA2X2_STATUS_TAP_SLOPE_REG
+
+#define BMA2X2_SLOPE_FIRST_Z__POS 2
+#define BMA2X2_SLOPE_FIRST_Z__LEN 1
+#define BMA2X2_SLOPE_FIRST_Z__MSK 0x04
+#define BMA2X2_SLOPE_FIRST_Z__REG BMA2X2_STATUS_TAP_SLOPE_REG
+
+#define BMA2X2_SLOPE_SIGN_S__POS 3
+#define BMA2X2_SLOPE_SIGN_S__LEN 1
+#define BMA2X2_SLOPE_SIGN_S__MSK 0x08
+#define BMA2X2_SLOPE_SIGN_S__REG BMA2X2_STATUS_TAP_SLOPE_REG
+
+#define BMA2X2_TAP_FIRST_X__POS 4
+#define BMA2X2_TAP_FIRST_X__LEN 1
+#define BMA2X2_TAP_FIRST_X__MSK 0x10
+#define BMA2X2_TAP_FIRST_X__REG BMA2X2_STATUS_TAP_SLOPE_REG
+
+#define BMA2X2_TAP_FIRST_Y__POS 5
+#define BMA2X2_TAP_FIRST_Y__LEN 1
+#define BMA2X2_TAP_FIRST_Y__MSK 0x20
+#define BMA2X2_TAP_FIRST_Y__REG BMA2X2_STATUS_TAP_SLOPE_REG
+
+#define BMA2X2_TAP_FIRST_Z__POS 6
+#define BMA2X2_TAP_FIRST_Z__LEN 1
+#define BMA2X2_TAP_FIRST_Z__MSK 0x40
+#define BMA2X2_TAP_FIRST_Z__REG BMA2X2_STATUS_TAP_SLOPE_REG
+
+#define BMA2X2_TAP_SIGN_S__POS 7
+#define BMA2X2_TAP_SIGN_S__LEN 1
+#define BMA2X2_TAP_SIGN_S__MSK 0x80
+#define BMA2X2_TAP_SIGN_S__REG BMA2X2_STATUS_TAP_SLOPE_REG
+
+#define BMA2X2_HIGHG_FIRST_X__POS 0
+#define BMA2X2_HIGHG_FIRST_X__LEN 1
+#define BMA2X2_HIGHG_FIRST_X__MSK 0x01
+#define BMA2X2_HIGHG_FIRST_X__REG BMA2X2_STATUS_ORIENT_HIGH_REG
+
+#define BMA2X2_HIGHG_FIRST_Y__POS 1
+#define BMA2X2_HIGHG_FIRST_Y__LEN 1
+#define BMA2X2_HIGHG_FIRST_Y__MSK 0x02
+#define BMA2X2_HIGHG_FIRST_Y__REG BMA2X2_STATUS_ORIENT_HIGH_REG
+
+#define BMA2X2_HIGHG_FIRST_Z__POS 2
+#define BMA2X2_HIGHG_FIRST_Z__LEN 1
+#define BMA2X2_HIGHG_FIRST_Z__MSK 0x04
+#define BMA2X2_HIGHG_FIRST_Z__REG BMA2X2_STATUS_ORIENT_HIGH_REG
+
+#define BMA2X2_HIGHG_SIGN_S__POS 3
+#define BMA2X2_HIGHG_SIGN_S__LEN 1
+#define BMA2X2_HIGHG_SIGN_S__MSK 0x08
+#define BMA2X2_HIGHG_SIGN_S__REG BMA2X2_STATUS_ORIENT_HIGH_REG
+
+#define BMA2X2_ORIENT_S__POS 4
+#define BMA2X2_ORIENT_S__LEN 3
+#define BMA2X2_ORIENT_S__MSK 0x70
+#define BMA2X2_ORIENT_S__REG BMA2X2_STATUS_ORIENT_HIGH_REG
+
+#define BMA2X2_FLAT_S__POS 7
+#define BMA2X2_FLAT_S__LEN 1
+#define BMA2X2_FLAT_S__MSK 0x80
+#define BMA2X2_FLAT_S__REG BMA2X2_STATUS_ORIENT_HIGH_REG
+
+#define BMA2X2_FIFO_FRAME_COUNTER_S__POS 0
+#define BMA2X2_FIFO_FRAME_COUNTER_S__LEN 7
+#define BMA2X2_FIFO_FRAME_COUNTER_S__MSK 0x7F
+#define BMA2X2_FIFO_FRAME_COUNTER_S__REG BMA2X2_STATUS_FIFO_REG
+
+#define BMA2X2_FIFO_OVERRUN_S__POS 7
+#define BMA2X2_FIFO_OVERRUN_S__LEN 1
+#define BMA2X2_FIFO_OVERRUN_S__MSK 0x80
+#define BMA2X2_FIFO_OVERRUN_S__REG BMA2X2_STATUS_FIFO_REG
+
+#define BMA2X2_RANGE_SEL__POS 0
+#define BMA2X2_RANGE_SEL__LEN 4
+#define BMA2X2_RANGE_SEL__MSK 0x0F
+#define BMA2X2_RANGE_SEL__REG BMA2X2_RANGE_SEL_REG
+
+#define BMA2X2_BANDWIDTH__POS 0
+#define BMA2X2_BANDWIDTH__LEN 5
+#define BMA2X2_BANDWIDTH__MSK 0x1F
+#define BMA2X2_BANDWIDTH__REG BMA2X2_BW_SEL_REG
+
+#define BMA2X2_SLEEP_DUR__POS 1
+#define BMA2X2_SLEEP_DUR__LEN 4
+#define BMA2X2_SLEEP_DUR__MSK 0x1E
+#define BMA2X2_SLEEP_DUR__REG BMA2X2_MODE_CTRL_REG
+
+#define BMA2X2_MODE_CTRL__POS 5
+#define BMA2X2_MODE_CTRL__LEN 3
+#define BMA2X2_MODE_CTRL__MSK 0xE0
+#define BMA2X2_MODE_CTRL__REG BMA2X2_MODE_CTRL_REG
+
+#define BMA2X2_DEEP_SUSPEND__POS 5
+#define BMA2X2_DEEP_SUSPEND__LEN 1
+#define BMA2X2_DEEP_SUSPEND__MSK 0x20
+#define BMA2X2_DEEP_SUSPEND__REG BMA2X2_MODE_CTRL_REG
+
+#define BMA2X2_EN_LOW_POWER__POS 6
+#define BMA2X2_EN_LOW_POWER__LEN 1
+#define BMA2X2_EN_LOW_POWER__MSK 0x40
+#define BMA2X2_EN_LOW_POWER__REG BMA2X2_MODE_CTRL_REG
+
+#define BMA2X2_EN_SUSPEND__POS 7
+#define BMA2X2_EN_SUSPEND__LEN 1
+#define BMA2X2_EN_SUSPEND__MSK 0x80
+#define BMA2X2_EN_SUSPEND__REG BMA2X2_MODE_CTRL_REG
+
+#define BMA2X2_SLEEP_TIMER__POS 5
+#define BMA2X2_SLEEP_TIMER__LEN 1
+#define BMA2X2_SLEEP_TIMER__MSK 0x20
+#define BMA2X2_SLEEP_TIMER__REG BMA2X2_LOW_NOISE_CTRL_REG
+
+#define BMA2X2_LOW_POWER_MODE__POS 6
+#define BMA2X2_LOW_POWER_MODE__LEN 1
+#define BMA2X2_LOW_POWER_MODE__MSK 0x40
+#define BMA2X2_LOW_POWER_MODE__REG BMA2X2_LOW_NOISE_CTRL_REG
+
+#define BMA2X2_EN_LOW_NOISE__POS 7
+#define BMA2X2_EN_LOW_NOISE__LEN 1
+#define BMA2X2_EN_LOW_NOISE__MSK 0x80
+#define BMA2X2_EN_LOW_NOISE__REG BMA2X2_LOW_NOISE_CTRL_REG
+
+#define BMA2X2_DIS_SHADOW_PROC__POS 6
+#define BMA2X2_DIS_SHADOW_PROC__LEN 1
+#define BMA2X2_DIS_SHADOW_PROC__MSK 0x40
+#define BMA2X2_DIS_SHADOW_PROC__REG BMA2X2_DATA_CTRL_REG
+
+#define BMA2X2_EN_DATA_HIGH_BW__POS 7
+#define BMA2X2_EN_DATA_HIGH_BW__LEN 1
+#define BMA2X2_EN_DATA_HIGH_BW__MSK 0x80
+#define BMA2X2_EN_DATA_HIGH_BW__REG BMA2X2_DATA_CTRL_REG
+
+#define BMA2X2_EN_SOFT_RESET__POS 0
+#define BMA2X2_EN_SOFT_RESET__LEN 8
+#define BMA2X2_EN_SOFT_RESET__MSK 0xFF
+#define BMA2X2_EN_SOFT_RESET__REG BMA2X2_RESET_REG
+
+#define BMA2X2_EN_SOFT_RESET_VALUE 0xB6
+
+#define BMA2X2_EN_SLOPE_X_INT__POS 0
+#define BMA2X2_EN_SLOPE_X_INT__LEN 1
+#define BMA2X2_EN_SLOPE_X_INT__MSK 0x01
+#define BMA2X2_EN_SLOPE_X_INT__REG BMA2X2_INT_ENABLE1_REG
+
+#define BMA2X2_EN_SLOPE_Y_INT__POS 1
+#define BMA2X2_EN_SLOPE_Y_INT__LEN 1
+#define BMA2X2_EN_SLOPE_Y_INT__MSK 0x02
+#define BMA2X2_EN_SLOPE_Y_INT__REG BMA2X2_INT_ENABLE1_REG
+
+#define BMA2X2_EN_SLOPE_Z_INT__POS 2
+#define BMA2X2_EN_SLOPE_Z_INT__LEN 1
+#define BMA2X2_EN_SLOPE_Z_INT__MSK 0x04
+#define BMA2X2_EN_SLOPE_Z_INT__REG BMA2X2_INT_ENABLE1_REG
+
+#define BMA2X2_EN_DOUBLE_TAP_INT__POS 4
+#define BMA2X2_EN_DOUBLE_TAP_INT__LEN 1
+#define BMA2X2_EN_DOUBLE_TAP_INT__MSK 0x10
+#define BMA2X2_EN_DOUBLE_TAP_INT__REG BMA2X2_INT_ENABLE1_REG
+
+#define BMA2X2_EN_SINGLE_TAP_INT__POS 5
+#define BMA2X2_EN_SINGLE_TAP_INT__LEN 1
+#define BMA2X2_EN_SINGLE_TAP_INT__MSK 0x20
+#define BMA2X2_EN_SINGLE_TAP_INT__REG BMA2X2_INT_ENABLE1_REG
+
+#define BMA2X2_EN_ORIENT_INT__POS 6
+#define BMA2X2_EN_ORIENT_INT__LEN 1
+#define BMA2X2_EN_ORIENT_INT__MSK 0x40
+#define BMA2X2_EN_ORIENT_INT__REG BMA2X2_INT_ENABLE1_REG
+
+#define BMA2X2_EN_FLAT_INT__POS 7
+#define BMA2X2_EN_FLAT_INT__LEN 1
+#define BMA2X2_EN_FLAT_INT__MSK 0x80
+#define BMA2X2_EN_FLAT_INT__REG BMA2X2_INT_ENABLE1_REG
+
+#define BMA2X2_EN_HIGHG_X_INT__POS 0
+#define BMA2X2_EN_HIGHG_X_INT__LEN 1
+#define BMA2X2_EN_HIGHG_X_INT__MSK 0x01
+#define BMA2X2_EN_HIGHG_X_INT__REG BMA2X2_INT_ENABLE2_REG
+
+#define BMA2X2_EN_HIGHG_Y_INT__POS 1
+#define BMA2X2_EN_HIGHG_Y_INT__LEN 1
+#define BMA2X2_EN_HIGHG_Y_INT__MSK 0x02
+#define BMA2X2_EN_HIGHG_Y_INT__REG BMA2X2_INT_ENABLE2_REG
+
+#define BMA2X2_EN_HIGHG_Z_INT__POS 2
+#define BMA2X2_EN_HIGHG_Z_INT__LEN 1
+#define BMA2X2_EN_HIGHG_Z_INT__MSK 0x04
+#define BMA2X2_EN_HIGHG_Z_INT__REG BMA2X2_INT_ENABLE2_REG
+
+#define BMA2X2_EN_LOWG_INT__POS 3
+#define BMA2X2_EN_LOWG_INT__LEN 1
+#define BMA2X2_EN_LOWG_INT__MSK 0x08
+#define BMA2X2_EN_LOWG_INT__REG BMA2X2_INT_ENABLE2_REG
+
+#define BMA2X2_EN_NEW_DATA_INT__POS 4
+#define BMA2X2_EN_NEW_DATA_INT__LEN 1
+#define BMA2X2_EN_NEW_DATA_INT__MSK 0x10
+#define BMA2X2_EN_NEW_DATA_INT__REG BMA2X2_INT_ENABLE2_REG
+
+#define BMA2X2_INT_FFULL_EN_INT__POS 5
+#define BMA2X2_INT_FFULL_EN_INT__LEN 1
+#define BMA2X2_INT_FFULL_EN_INT__MSK 0x20
+#define BMA2X2_INT_FFULL_EN_INT__REG BMA2X2_INT_ENABLE2_REG
+
+#define BMA2X2_INT_FWM_EN_INT__POS 6
+#define BMA2X2_INT_FWM_EN_INT__LEN 1
+#define BMA2X2_INT_FWM_EN_INT__MSK 0x40
+#define BMA2X2_INT_FWM_EN_INT__REG BMA2X2_INT_ENABLE2_REG
+
+#define BMA2X2_INT_SLO_NO_MOT_EN_X_INT__POS 0
+#define BMA2X2_INT_SLO_NO_MOT_EN_X_INT__LEN 1
+#define BMA2X2_INT_SLO_NO_MOT_EN_X_INT__MSK 0x01
+#define BMA2X2_INT_SLO_NO_MOT_EN_X_INT__REG BMA2X2_INT_SLO_NO_MOT_REG
+
+#define BMA2X2_INT_SLO_NO_MOT_EN_Y_INT__POS 1
+#define BMA2X2_INT_SLO_NO_MOT_EN_Y_INT__LEN 1
+#define BMA2X2_INT_SLO_NO_MOT_EN_Y_INT__MSK 0x02
+#define BMA2X2_INT_SLO_NO_MOT_EN_Y_INT__REG BMA2X2_INT_SLO_NO_MOT_REG
+
+#define BMA2X2_INT_SLO_NO_MOT_EN_Z_INT__POS 2
+#define BMA2X2_INT_SLO_NO_MOT_EN_Z_INT__LEN 1
+#define BMA2X2_INT_SLO_NO_MOT_EN_Z_INT__MSK 0x04
+#define BMA2X2_INT_SLO_NO_MOT_EN_Z_INT__REG BMA2X2_INT_SLO_NO_MOT_REG
+
+#define BMA2X2_INT_SLO_NO_MOT_EN_SEL_INT__POS 3
+#define BMA2X2_INT_SLO_NO_MOT_EN_SEL_INT__LEN 1
+#define BMA2X2_INT_SLO_NO_MOT_EN_SEL_INT__MSK 0x08
+#define BMA2X2_INT_SLO_NO_MOT_EN_SEL_INT__REG BMA2X2_INT_SLO_NO_MOT_REG
+
+#define BMA2X2_EN_INT1_PAD_LOWG__POS 0
+#define BMA2X2_EN_INT1_PAD_LOWG__LEN 1
+#define BMA2X2_EN_INT1_PAD_LOWG__MSK 0x01
+#define BMA2X2_EN_INT1_PAD_LOWG__REG BMA2X2_INT1_PAD_SEL_REG
+
+#define BMA2X2_EN_INT1_PAD_HIGHG__POS 1
+#define BMA2X2_EN_INT1_PAD_HIGHG__LEN 1
+#define BMA2X2_EN_INT1_PAD_HIGHG__MSK 0x02
+#define BMA2X2_EN_INT1_PAD_HIGHG__REG BMA2X2_INT1_PAD_SEL_REG
+
+#define BMA2X2_EN_INT1_PAD_SLOPE__POS 2
+#define BMA2X2_EN_INT1_PAD_SLOPE__LEN 1
+#define BMA2X2_EN_INT1_PAD_SLOPE__MSK 0x04
+#define BMA2X2_EN_INT1_PAD_SLOPE__REG BMA2X2_INT1_PAD_SEL_REG
+
+#define BMA2X2_EN_INT1_PAD_SLO_NO_MOT__POS 3
+#define BMA2X2_EN_INT1_PAD_SLO_NO_MOT__LEN 1
+#define BMA2X2_EN_INT1_PAD_SLO_NO_MOT__MSK 0x08
+#define BMA2X2_EN_INT1_PAD_SLO_NO_MOT__REG BMA2X2_INT1_PAD_SEL_REG
+
+#define BMA2X2_EN_INT1_PAD_DB_TAP__POS 4
+#define BMA2X2_EN_INT1_PAD_DB_TAP__LEN 1
+#define BMA2X2_EN_INT1_PAD_DB_TAP__MSK 0x10
+#define BMA2X2_EN_INT1_PAD_DB_TAP__REG BMA2X2_INT1_PAD_SEL_REG
+
+#define BMA2X2_EN_INT1_PAD_SNG_TAP__POS 5
+#define BMA2X2_EN_INT1_PAD_SNG_TAP__LEN 1
+#define BMA2X2_EN_INT1_PAD_SNG_TAP__MSK 0x20
+#define BMA2X2_EN_INT1_PAD_SNG_TAP__REG BMA2X2_INT1_PAD_SEL_REG
+
+#define BMA2X2_EN_INT1_PAD_ORIENT__POS 6
+#define BMA2X2_EN_INT1_PAD_ORIENT__LEN 1
+#define BMA2X2_EN_INT1_PAD_ORIENT__MSK 0x40
+#define BMA2X2_EN_INT1_PAD_ORIENT__REG BMA2X2_INT1_PAD_SEL_REG
+
+#define BMA2X2_EN_INT1_PAD_FLAT__POS 7
+#define BMA2X2_EN_INT1_PAD_FLAT__LEN 1
+#define BMA2X2_EN_INT1_PAD_FLAT__MSK 0x80
+#define BMA2X2_EN_INT1_PAD_FLAT__REG BMA2X2_INT1_PAD_SEL_REG
+
+#define BMA2X2_EN_INT2_PAD_LOWG__POS 0
+#define BMA2X2_EN_INT2_PAD_LOWG__LEN 1
+#define BMA2X2_EN_INT2_PAD_LOWG__MSK 0x01
+#define BMA2X2_EN_INT2_PAD_LOWG__REG BMA2X2_INT2_PAD_SEL_REG
+
+#define BMA2X2_EN_INT2_PAD_HIGHG__POS 1
+#define BMA2X2_EN_INT2_PAD_HIGHG__LEN 1
+#define BMA2X2_EN_INT2_PAD_HIGHG__MSK 0x02
+#define BMA2X2_EN_INT2_PAD_HIGHG__REG BMA2X2_INT2_PAD_SEL_REG
+
+#define BMA2X2_EN_INT2_PAD_SLOPE__POS 2
+#define BMA2X2_EN_INT2_PAD_SLOPE__LEN 1
+#define BMA2X2_EN_INT2_PAD_SLOPE__MSK 0x04
+#define BMA2X2_EN_INT2_PAD_SLOPE__REG BMA2X2_INT2_PAD_SEL_REG
+
+#define BMA2X2_EN_INT2_PAD_SLO_NO_MOT__POS 3
+#define BMA2X2_EN_INT2_PAD_SLO_NO_MOT__LEN 1
+#define BMA2X2_EN_INT2_PAD_SLO_NO_MOT__MSK 0x08
+#define BMA2X2_EN_INT2_PAD_SLO_NO_MOT__REG BMA2X2_INT2_PAD_SEL_REG
+
+#define BMA2X2_EN_INT2_PAD_DB_TAP__POS 4
+#define BMA2X2_EN_INT2_PAD_DB_TAP__LEN 1
+#define BMA2X2_EN_INT2_PAD_DB_TAP__MSK 0x10
+#define BMA2X2_EN_INT2_PAD_DB_TAP__REG BMA2X2_INT2_PAD_SEL_REG
+
+#define BMA2X2_EN_INT2_PAD_SNG_TAP__POS 5
+#define BMA2X2_EN_INT2_PAD_SNG_TAP__LEN 1
+#define BMA2X2_EN_INT2_PAD_SNG_TAP__MSK 0x20
+#define BMA2X2_EN_INT2_PAD_SNG_TAP__REG BMA2X2_INT2_PAD_SEL_REG
+
+#define BMA2X2_EN_INT2_PAD_ORIENT__POS 6
+#define BMA2X2_EN_INT2_PAD_ORIENT__LEN 1
+#define BMA2X2_EN_INT2_PAD_ORIENT__MSK 0x40
+#define BMA2X2_EN_INT2_PAD_ORIENT__REG BMA2X2_INT2_PAD_SEL_REG
+
+#define BMA2X2_EN_INT2_PAD_FLAT__POS 7
+#define BMA2X2_EN_INT2_PAD_FLAT__LEN 1
+#define BMA2X2_EN_INT2_PAD_FLAT__MSK 0x80
+#define BMA2X2_EN_INT2_PAD_FLAT__REG BMA2X2_INT2_PAD_SEL_REG
+
+#define BMA2X2_EN_INT1_PAD_NEWDATA__POS 0
+#define BMA2X2_EN_INT1_PAD_NEWDATA__LEN 1
+#define BMA2X2_EN_INT1_PAD_NEWDATA__MSK 0x01
+#define BMA2X2_EN_INT1_PAD_NEWDATA__REG BMA2X2_INT_DATA_SEL_REG
+
+#define BMA2X2_EN_INT1_PAD_FWM__POS 1
+#define BMA2X2_EN_INT1_PAD_FWM__LEN 1
+#define BMA2X2_EN_INT1_PAD_FWM__MSK 0x02
+#define BMA2X2_EN_INT1_PAD_FWM__REG BMA2X2_INT_DATA_SEL_REG
+
+#define BMA2X2_EN_INT1_PAD_FFULL__POS 2
+#define BMA2X2_EN_INT1_PAD_FFULL__LEN 1
+#define BMA2X2_EN_INT1_PAD_FFULL__MSK 0x04
+#define BMA2X2_EN_INT1_PAD_FFULL__REG BMA2X2_INT_DATA_SEL_REG
+
+#define BMA2X2_EN_INT2_PAD_FFULL__POS 5
+#define BMA2X2_EN_INT2_PAD_FFULL__LEN 1
+#define BMA2X2_EN_INT2_PAD_FFULL__MSK 0x20
+#define BMA2X2_EN_INT2_PAD_FFULL__REG BMA2X2_INT_DATA_SEL_REG
+
+#define BMA2X2_EN_INT2_PAD_FWM__POS 6
+#define BMA2X2_EN_INT2_PAD_FWM__LEN 1
+#define BMA2X2_EN_INT2_PAD_FWM__MSK 0x40
+#define BMA2X2_EN_INT2_PAD_FWM__REG BMA2X2_INT_DATA_SEL_REG
+
+#define BMA2X2_EN_INT2_PAD_NEWDATA__POS 7
+#define BMA2X2_EN_INT2_PAD_NEWDATA__LEN 1
+#define BMA2X2_EN_INT2_PAD_NEWDATA__MSK 0x80
+#define BMA2X2_EN_INT2_PAD_NEWDATA__REG BMA2X2_INT_DATA_SEL_REG
+
+#define BMA2X2_UNFILT_INT_SRC_LOWG__POS 0
+#define BMA2X2_UNFILT_INT_SRC_LOWG__LEN 1
+#define BMA2X2_UNFILT_INT_SRC_LOWG__MSK 0x01
+#define BMA2X2_UNFILT_INT_SRC_LOWG__REG BMA2X2_INT_SRC_REG
+
+#define BMA2X2_UNFILT_INT_SRC_HIGHG__POS 1
+#define BMA2X2_UNFILT_INT_SRC_HIGHG__LEN 1
+#define BMA2X2_UNFILT_INT_SRC_HIGHG__MSK 0x02
+#define BMA2X2_UNFILT_INT_SRC_HIGHG__REG BMA2X2_INT_SRC_REG
+
+#define BMA2X2_UNFILT_INT_SRC_SLOPE__POS 2
+#define BMA2X2_UNFILT_INT_SRC_SLOPE__LEN 1
+#define BMA2X2_UNFILT_INT_SRC_SLOPE__MSK 0x04
+#define BMA2X2_UNFILT_INT_SRC_SLOPE__REG BMA2X2_INT_SRC_REG
+
+#define BMA2X2_UNFILT_INT_SRC_SLO_NO_MOT__POS 3
+#define BMA2X2_UNFILT_INT_SRC_SLO_NO_MOT__LEN 1
+#define BMA2X2_UNFILT_INT_SRC_SLO_NO_MOT__MSK 0x08
+#define BMA2X2_UNFILT_INT_SRC_SLO_NO_MOT__REG BMA2X2_INT_SRC_REG
+
+#define BMA2X2_UNFILT_INT_SRC_TAP__POS 4
+#define BMA2X2_UNFILT_INT_SRC_TAP__LEN 1
+#define BMA2X2_UNFILT_INT_SRC_TAP__MSK 0x10
+#define BMA2X2_UNFILT_INT_SRC_TAP__REG BMA2X2_INT_SRC_REG
+
+#define BMA2X2_UNFILT_INT_SRC_DATA__POS 5
+#define BMA2X2_UNFILT_INT_SRC_DATA__LEN 1
+#define BMA2X2_UNFILT_INT_SRC_DATA__MSK 0x20
+#define BMA2X2_UNFILT_INT_SRC_DATA__REG BMA2X2_INT_SRC_REG
+
+#define BMA2X2_INT1_PAD_ACTIVE_LEVEL__POS 0
+#define BMA2X2_INT1_PAD_ACTIVE_LEVEL__LEN 1
+#define BMA2X2_INT1_PAD_ACTIVE_LEVEL__MSK 0x01
+#define BMA2X2_INT1_PAD_ACTIVE_LEVEL__REG BMA2X2_INT_SET_REG
+
+#define BMA2X2_INT2_PAD_ACTIVE_LEVEL__POS 2
+#define BMA2X2_INT2_PAD_ACTIVE_LEVEL__LEN 1
+#define BMA2X2_INT2_PAD_ACTIVE_LEVEL__MSK 0x04
+#define BMA2X2_INT2_PAD_ACTIVE_LEVEL__REG BMA2X2_INT_SET_REG
+
+#define BMA2X2_INT1_PAD_OUTPUT_TYPE__POS 1
+#define BMA2X2_INT1_PAD_OUTPUT_TYPE__LEN 1
+#define BMA2X2_INT1_PAD_OUTPUT_TYPE__MSK 0x02
+#define BMA2X2_INT1_PAD_OUTPUT_TYPE__REG BMA2X2_INT_SET_REG
+
+#define BMA2X2_INT2_PAD_OUTPUT_TYPE__POS 3
+#define BMA2X2_INT2_PAD_OUTPUT_TYPE__LEN 1
+#define BMA2X2_INT2_PAD_OUTPUT_TYPE__MSK 0x08
+#define BMA2X2_INT2_PAD_OUTPUT_TYPE__REG BMA2X2_INT_SET_REG
+
+#define BMA2X2_INT_MODE_SEL__POS 0
+#define BMA2X2_INT_MODE_SEL__LEN 4
+#define BMA2X2_INT_MODE_SEL__MSK 0x0F
+#define BMA2X2_INT_MODE_SEL__REG BMA2X2_INT_CTRL_REG
+
+#define BMA2X2_RESET_INT__POS 7
+#define BMA2X2_RESET_INT__LEN 1
+#define BMA2X2_RESET_INT__MSK 0x80
+#define BMA2X2_RESET_INT__REG BMA2X2_INT_CTRL_REG
+
+#define BMA2X2_LOWG_DUR__POS 0
+#define BMA2X2_LOWG_DUR__LEN 8
+#define BMA2X2_LOWG_DUR__MSK 0xFF
+#define BMA2X2_LOWG_DUR__REG BMA2X2_LOW_DURN_REG
+
+#define BMA2X2_LOWG_THRES__POS 0
+#define BMA2X2_LOWG_THRES__LEN 8
+#define BMA2X2_LOWG_THRES__MSK 0xFF
+#define BMA2X2_LOWG_THRES__REG BMA2X2_LOW_THRES_REG
+
+#define BMA2X2_LOWG_HYST__POS 0
+#define BMA2X2_LOWG_HYST__LEN 2
+#define BMA2X2_LOWG_HYST__MSK 0x03
+#define BMA2X2_LOWG_HYST__REG BMA2X2_LOW_HIGH_HYST_REG
+
+#define BMA2X2_LOWG_INT_MODE__POS 2
+#define BMA2X2_LOWG_INT_MODE__LEN 1
+#define BMA2X2_LOWG_INT_MODE__MSK 0x04
+#define BMA2X2_LOWG_INT_MODE__REG BMA2X2_LOW_HIGH_HYST_REG
+
+#define BMA2X2_HIGHG_DUR__POS 0
+#define BMA2X2_HIGHG_DUR__LEN 8
+#define BMA2X2_HIGHG_DUR__MSK 0xFF
+#define BMA2X2_HIGHG_DUR__REG BMA2X2_HIGH_DURN_REG
+
+#define BMA2X2_HIGHG_THRES__POS 0
+#define BMA2X2_HIGHG_THRES__LEN 8
+#define BMA2X2_HIGHG_THRES__MSK 0xFF
+#define BMA2X2_HIGHG_THRES__REG BMA2X2_HIGH_THRES_REG
+
+#define BMA2X2_HIGHG_HYST__POS 6
+#define BMA2X2_HIGHG_HYST__LEN 2
+#define BMA2X2_HIGHG_HYST__MSK 0xC0
+#define BMA2X2_HIGHG_HYST__REG BMA2X2_LOW_HIGH_HYST_REG
+
+#define BMA2X2_SLOPE_DUR__POS 0
+#define BMA2X2_SLOPE_DUR__LEN 2
+#define BMA2X2_SLOPE_DUR__MSK 0x03
+#define BMA2X2_SLOPE_DUR__REG BMA2X2_SLOPE_DURN_REG
+
+#define BMA2X2_SLO_NO_MOT_DUR__POS 2
+#define BMA2X2_SLO_NO_MOT_DUR__LEN 6
+#define BMA2X2_SLO_NO_MOT_DUR__MSK 0xFC
+#define BMA2X2_SLO_NO_MOT_DUR__REG BMA2X2_SLOPE_DURN_REG
+
+#define BMA2X2_SLOPE_THRES__POS 0
+#define BMA2X2_SLOPE_THRES__LEN 8
+#define BMA2X2_SLOPE_THRES__MSK 0xFF
+#define BMA2X2_SLOPE_THRES__REG BMA2X2_SLOPE_THRES_REG
+
+#define BMA2X2_SLO_NO_MOT_THRES__POS 0
+#define BMA2X2_SLO_NO_MOT_THRES__LEN 8
+#define BMA2X2_SLO_NO_MOT_THRES__MSK 0xFF
+#define BMA2X2_SLO_NO_MOT_THRES__REG BMA2X2_SLO_NO_MOT_THRES_REG
+
+#define BMA2X2_TAP_DUR__POS 0
+#define BMA2X2_TAP_DUR__LEN 3
+#define BMA2X2_TAP_DUR__MSK 0x07
+#define BMA2X2_TAP_DUR__REG BMA2X2_TAP_PARAM_REG
+
+#define BMA2X2_TAP_SHOCK_DURN__POS 6
+#define BMA2X2_TAP_SHOCK_DURN__LEN 1
+#define BMA2X2_TAP_SHOCK_DURN__MSK 0x40
+#define BMA2X2_TAP_SHOCK_DURN__REG BMA2X2_TAP_PARAM_REG
+
+#define BMA2X2_ADV_TAP_INT__POS 5
+#define BMA2X2_ADV_TAP_INT__LEN 1
+#define BMA2X2_ADV_TAP_INT__MSK 0x20
+#define BMA2X2_ADV_TAP_INT__REG BMA2X2_TAP_PARAM_REG
+
+#define BMA2X2_TAP_QUIET_DURN__POS 7
+#define BMA2X2_TAP_QUIET_DURN__LEN 1
+#define BMA2X2_TAP_QUIET_DURN__MSK 0x80
+#define BMA2X2_TAP_QUIET_DURN__REG BMA2X2_TAP_PARAM_REG
+
+#define BMA2X2_TAP_THRES__POS 0
+#define BMA2X2_TAP_THRES__LEN 5
+#define BMA2X2_TAP_THRES__MSK 0x1F
+#define BMA2X2_TAP_THRES__REG BMA2X2_TAP_THRES_REG
+
+#define BMA2X2_TAP_SAMPLES__POS 6
+#define BMA2X2_TAP_SAMPLES__LEN 2
+#define BMA2X2_TAP_SAMPLES__MSK 0xC0
+#define BMA2X2_TAP_SAMPLES__REG BMA2X2_TAP_THRES_REG
+
+#define BMA2X2_ORIENT_MODE__POS 0
+#define BMA2X2_ORIENT_MODE__LEN 2
+#define BMA2X2_ORIENT_MODE__MSK 0x03
+#define BMA2X2_ORIENT_MODE__REG BMA2X2_ORIENT_PARAM_REG
+
+#define BMA2X2_ORIENT_BLOCK__POS 2
+#define BMA2X2_ORIENT_BLOCK__LEN 2
+#define BMA2X2_ORIENT_BLOCK__MSK 0x0C
+#define BMA2X2_ORIENT_BLOCK__REG BMA2X2_ORIENT_PARAM_REG
+
+#define BMA2X2_ORIENT_HYST__POS 4
+#define BMA2X2_ORIENT_HYST__LEN 3
+#define BMA2X2_ORIENT_HYST__MSK 0x70
+#define BMA2X2_ORIENT_HYST__REG BMA2X2_ORIENT_PARAM_REG
+
+#define BMA2X2_ORIENT_AXIS__POS 7
+#define BMA2X2_ORIENT_AXIS__LEN 1
+#define BMA2X2_ORIENT_AXIS__MSK 0x80
+#define BMA2X2_ORIENT_AXIS__REG BMA2X2_THETA_BLOCK_REG
+
+#define BMA2X2_ORIENT_UD_EN__POS 6
+#define BMA2X2_ORIENT_UD_EN__LEN 1
+#define BMA2X2_ORIENT_UD_EN__MSK 0x40
+#define BMA2X2_ORIENT_UD_EN__REG BMA2X2_THETA_BLOCK_REG
+
+#define BMA2X2_THETA_BLOCK__POS 0
+#define BMA2X2_THETA_BLOCK__LEN 6
+#define BMA2X2_THETA_BLOCK__MSK 0x3F
+#define BMA2X2_THETA_BLOCK__REG BMA2X2_THETA_BLOCK_REG
+
+#define BMA2X2_THETA_FLAT__POS 0
+#define BMA2X2_THETA_FLAT__LEN 6
+#define BMA2X2_THETA_FLAT__MSK 0x3F
+#define BMA2X2_THETA_FLAT__REG BMA2X2_THETA_FLAT_REG
+
+#define BMA2X2_FLAT_HOLD_TIME__POS 4
+#define BMA2X2_FLAT_HOLD_TIME__LEN 2
+#define BMA2X2_FLAT_HOLD_TIME__MSK 0x30
+#define BMA2X2_FLAT_HOLD_TIME__REG BMA2X2_FLAT_HOLD_TIME_REG
+
+#define BMA2X2_FLAT_HYS__POS 0
+#define BMA2X2_FLAT_HYS__LEN 3
+#define BMA2X2_FLAT_HYS__MSK 0x07
+#define BMA2X2_FLAT_HYS__REG BMA2X2_FLAT_HOLD_TIME_REG
+
+#define BMA2X2_FIFO_WML_TRIG_RETAIN__POS 0
+#define BMA2X2_FIFO_WML_TRIG_RETAIN__LEN 6
+#define BMA2X2_FIFO_WML_TRIG_RETAIN__MSK 0x3F
+#define BMA2X2_FIFO_WML_TRIG_RETAIN__REG BMA2X2_FIFO_WML_TRIG
+
+#define BMA2X2_EN_SELF_TEST__POS 0
+#define BMA2X2_EN_SELF_TEST__LEN 2
+#define BMA2X2_EN_SELF_TEST__MSK 0x03
+#define BMA2X2_EN_SELF_TEST__REG BMA2X2_SELF_TEST_REG
+
+#define BMA2X2_NEG_SELF_TEST__POS 2
+#define BMA2X2_NEG_SELF_TEST__LEN 1
+#define BMA2X2_NEG_SELF_TEST__MSK 0x04
+#define BMA2X2_NEG_SELF_TEST__REG BMA2X2_SELF_TEST_REG
+
+#define BMA2X2_SELF_TEST_AMP__POS 4
+#define BMA2X2_SELF_TEST_AMP__LEN 1
+#define BMA2X2_SELF_TEST_AMP__MSK 0x10
+#define BMA2X2_SELF_TEST_AMP__REG BMA2X2_SELF_TEST_REG
+
+
+#define BMA2X2_UNLOCK_EE_PROG_MODE__POS 0
+#define BMA2X2_UNLOCK_EE_PROG_MODE__LEN 1
+#define BMA2X2_UNLOCK_EE_PROG_MODE__MSK 0x01
+#define BMA2X2_UNLOCK_EE_PROG_MODE__REG BMA2X2_EEPROM_CTRL_REG
+
+#define BMA2X2_START_EE_PROG_TRIG__POS 1
+#define BMA2X2_START_EE_PROG_TRIG__LEN 1
+#define BMA2X2_START_EE_PROG_TRIG__MSK 0x02
+#define BMA2X2_START_EE_PROG_TRIG__REG BMA2X2_EEPROM_CTRL_REG
+
+#define BMA2X2_EE_PROG_READY__POS 2
+#define BMA2X2_EE_PROG_READY__LEN 1
+#define BMA2X2_EE_PROG_READY__MSK 0x04
+#define BMA2X2_EE_PROG_READY__REG BMA2X2_EEPROM_CTRL_REG
+
+#define BMA2X2_UPDATE_IMAGE__POS 3
+#define BMA2X2_UPDATE_IMAGE__LEN 1
+#define BMA2X2_UPDATE_IMAGE__MSK 0x08
+#define BMA2X2_UPDATE_IMAGE__REG BMA2X2_EEPROM_CTRL_REG
+
+#define BMA2X2_EE_REMAIN__POS 4
+#define BMA2X2_EE_REMAIN__LEN 4
+#define BMA2X2_EE_REMAIN__MSK 0xF0
+#define BMA2X2_EE_REMAIN__REG BMA2X2_EEPROM_CTRL_REG
+
+#define BMA2X2_EN_SPI_MODE_3__POS 0
+#define BMA2X2_EN_SPI_MODE_3__LEN 1
+#define BMA2X2_EN_SPI_MODE_3__MSK 0x01
+#define BMA2X2_EN_SPI_MODE_3__REG BMA2X2_SERIAL_CTRL_REG
+
+#define BMA2X2_I2C_WATCHDOG_PERIOD__POS 1
+#define BMA2X2_I2C_WATCHDOG_PERIOD__LEN 1
+#define BMA2X2_I2C_WATCHDOG_PERIOD__MSK 0x02
+#define BMA2X2_I2C_WATCHDOG_PERIOD__REG BMA2X2_SERIAL_CTRL_REG
+
+#define BMA2X2_EN_I2C_WATCHDOG__POS 2
+#define BMA2X2_EN_I2C_WATCHDOG__LEN 1
+#define BMA2X2_EN_I2C_WATCHDOG__MSK 0x04
+#define BMA2X2_EN_I2C_WATCHDOG__REG BMA2X2_SERIAL_CTRL_REG
+
+#define BMA2X2_EXT_MODE__POS 7
+#define BMA2X2_EXT_MODE__LEN 1
+#define BMA2X2_EXT_MODE__MSK 0x80
+#define BMA2X2_EXT_MODE__REG BMA2X2_EXTMODE_CTRL_REG
+
+#define BMA2X2_ALLOW_UPPER__POS 6
+#define BMA2X2_ALLOW_UPPER__LEN 1
+#define BMA2X2_ALLOW_UPPER__MSK 0x40
+#define BMA2X2_ALLOW_UPPER__REG BMA2X2_EXTMODE_CTRL_REG
+
+#define BMA2X2_MAP_2_LOWER__POS 5
+#define BMA2X2_MAP_2_LOWER__LEN 1
+#define BMA2X2_MAP_2_LOWER__MSK 0x20
+#define BMA2X2_MAP_2_LOWER__REG BMA2X2_EXTMODE_CTRL_REG
+
+#define BMA2X2_MAGIC_NUMBER__POS 0
+#define BMA2X2_MAGIC_NUMBER__LEN 5
+#define BMA2X2_MAGIC_NUMBER__MSK 0x1F
+#define BMA2X2_MAGIC_NUMBER__REG BMA2X2_EXTMODE_CTRL_REG
+
+#define BMA2X2_UNLOCK_EE_WRITE_TRIM__POS 4
+#define BMA2X2_UNLOCK_EE_WRITE_TRIM__LEN 4
+#define BMA2X2_UNLOCK_EE_WRITE_TRIM__MSK 0xF0
+#define BMA2X2_UNLOCK_EE_WRITE_TRIM__REG BMA2X2_CTRL_UNLOCK_REG
+
+#define BMA2X2_EN_SLOW_COMP_X__POS 0
+#define BMA2X2_EN_SLOW_COMP_X__LEN 1
+#define BMA2X2_EN_SLOW_COMP_X__MSK 0x01
+#define BMA2X2_EN_SLOW_COMP_X__REG BMA2X2_OFFSET_CTRL_REG
+
+#define BMA2X2_EN_SLOW_COMP_Y__POS 1
+#define BMA2X2_EN_SLOW_COMP_Y__LEN 1
+#define BMA2X2_EN_SLOW_COMP_Y__MSK 0x02
+#define BMA2X2_EN_SLOW_COMP_Y__REG BMA2X2_OFFSET_CTRL_REG
+
+#define BMA2X2_EN_SLOW_COMP_Z__POS 2
+#define BMA2X2_EN_SLOW_COMP_Z__LEN 1
+#define BMA2X2_EN_SLOW_COMP_Z__MSK 0x04
+#define BMA2X2_EN_SLOW_COMP_Z__REG BMA2X2_OFFSET_CTRL_REG
+
+#define BMA2X2_FAST_CAL_RDY_S__POS 4
+#define BMA2X2_FAST_CAL_RDY_S__LEN 1
+#define BMA2X2_FAST_CAL_RDY_S__MSK 0x10
+#define BMA2X2_FAST_CAL_RDY_S__REG BMA2X2_OFFSET_CTRL_REG
+
+#define BMA2X2_CAL_TRIGGER__POS 5
+#define BMA2X2_CAL_TRIGGER__LEN 2
+#define BMA2X2_CAL_TRIGGER__MSK 0x60
+#define BMA2X2_CAL_TRIGGER__REG BMA2X2_OFFSET_CTRL_REG
+
+#define BMA2X2_RESET_OFFSET_REGS__POS 7
+#define BMA2X2_RESET_OFFSET_REGS__LEN 1
+#define BMA2X2_RESET_OFFSET_REGS__MSK 0x80
+#define BMA2X2_RESET_OFFSET_REGS__REG BMA2X2_OFFSET_CTRL_REG
+
+#define BMA2X2_COMP_CUTOFF__POS 0
+#define BMA2X2_COMP_CUTOFF__LEN 1
+#define BMA2X2_COMP_CUTOFF__MSK 0x01
+#define BMA2X2_COMP_CUTOFF__REG BMA2X2_OFFSET_PARAMS_REG
+
+#define BMA2X2_COMP_TARGET_OFFSET_X__POS 1
+#define BMA2X2_COMP_TARGET_OFFSET_X__LEN 2
+#define BMA2X2_COMP_TARGET_OFFSET_X__MSK 0x06
+#define BMA2X2_COMP_TARGET_OFFSET_X__REG BMA2X2_OFFSET_PARAMS_REG
+
+#define BMA2X2_COMP_TARGET_OFFSET_Y__POS 3
+#define BMA2X2_COMP_TARGET_OFFSET_Y__LEN 2
+#define BMA2X2_COMP_TARGET_OFFSET_Y__MSK 0x18
+#define BMA2X2_COMP_TARGET_OFFSET_Y__REG BMA2X2_OFFSET_PARAMS_REG
+
+#define BMA2X2_COMP_TARGET_OFFSET_Z__POS 5
+#define BMA2X2_COMP_TARGET_OFFSET_Z__LEN 2
+#define BMA2X2_COMP_TARGET_OFFSET_Z__MSK 0x60
+#define BMA2X2_COMP_TARGET_OFFSET_Z__REG BMA2X2_OFFSET_PARAMS_REG
+
+#define BMA2X2_FIFO_DATA_SELECT__POS 0
+#define BMA2X2_FIFO_DATA_SELECT__LEN 2
+#define BMA2X2_FIFO_DATA_SELECT__MSK 0x03
+#define BMA2X2_FIFO_DATA_SELECT__REG BMA2X2_FIFO_MODE_REG
+
+#define BMA2X2_FIFO_TRIGGER_SOURCE__POS 2
+#define BMA2X2_FIFO_TRIGGER_SOURCE__LEN 2
+#define BMA2X2_FIFO_TRIGGER_SOURCE__MSK 0x0C
+#define BMA2X2_FIFO_TRIGGER_SOURCE__REG BMA2X2_FIFO_MODE_REG
+
+#define BMA2X2_FIFO_TRIGGER_ACTION__POS 4
+#define BMA2X2_FIFO_TRIGGER_ACTION__LEN 2
+#define BMA2X2_FIFO_TRIGGER_ACTION__MSK 0x30
+#define BMA2X2_FIFO_TRIGGER_ACTION__REG BMA2X2_FIFO_MODE_REG
+
+#define BMA2X2_FIFO_MODE__POS 6
+#define BMA2X2_FIFO_MODE__LEN 2
+#define BMA2X2_FIFO_MODE__MSK 0xC0
+#define BMA2X2_FIFO_MODE__REG BMA2X2_FIFO_MODE_REG
+
+
+#define BMA2X2_STATUS1 0
+#define BMA2X2_STATUS2 1
+#define BMA2X2_STATUS3 2
+#define BMA2X2_STATUS4 3
+#define BMA2X2_STATUS5 4
+
+
+#define BMA2X2_RANGE_2G 3
+#define BMA2X2_RANGE_4G 5
+#define BMA2X2_RANGE_8G 8
+#define BMA2X2_RANGE_16G 12
+
+
+#define BMA2X2_BW_7_81HZ 0x08
+#define BMA2X2_BW_15_63HZ 0x09
+#define BMA2X2_BW_31_25HZ 0x0A
+#define BMA2X2_BW_62_50HZ 0x0B
+#define BMA2X2_BW_125HZ 0x0C
+#define BMA2X2_BW_250HZ 0x0D
+#define BMA2X2_BW_500HZ 0x0E
+#define BMA2X2_BW_1000HZ 0x0F
+
+#define BMA2X2_SLEEP_DUR_0_5MS 0x05
+#define BMA2X2_SLEEP_DUR_1MS 0x06
+#define BMA2X2_SLEEP_DUR_2MS 0x07
+#define BMA2X2_SLEEP_DUR_4MS 0x08
+#define BMA2X2_SLEEP_DUR_6MS 0x09
+#define BMA2X2_SLEEP_DUR_10MS 0x0A
+#define BMA2X2_SLEEP_DUR_25MS 0x0B
+#define BMA2X2_SLEEP_DUR_50MS 0x0C
+#define BMA2X2_SLEEP_DUR_100MS 0x0D
+#define BMA2X2_SLEEP_DUR_500MS 0x0E
+#define BMA2X2_SLEEP_DUR_1S 0x0F
+
+#define BMA2X2_LATCH_DUR_NON_LATCH 0x00
+#define BMA2X2_LATCH_DUR_250MS 0x01
+#define BMA2X2_LATCH_DUR_500MS 0x02
+#define BMA2X2_LATCH_DUR_1S 0x03
+#define BMA2X2_LATCH_DUR_2S 0x04
+#define BMA2X2_LATCH_DUR_4S 0x05
+#define BMA2X2_LATCH_DUR_8S 0x06
+#define BMA2X2_LATCH_DUR_LATCH 0x07
+#define BMA2X2_LATCH_DUR_NON_LATCH1 0x08
+#define BMA2X2_LATCH_DUR_250US 0x09
+#define BMA2X2_LATCH_DUR_500US 0x0A
+#define BMA2X2_LATCH_DUR_1MS 0x0B
+#define BMA2X2_LATCH_DUR_12_5MS 0x0C
+#define BMA2X2_LATCH_DUR_25MS 0x0D
+#define BMA2X2_LATCH_DUR_50MS 0x0E
+#define BMA2X2_LATCH_DUR_LATCH1 0x0F
+
+#define BMA2X2_MODE_NORMAL 0
+#define BMA2X2_MODE_LOWPOWER1 1
+#define BMA2X2_MODE_SUSPEND 2
+#define BMA2X2_MODE_DEEP_SUSPEND 3
+#define BMA2X2_MODE_LOWPOWER2 4
+#define BMA2X2_MODE_STANDBY 5
+
+#define BMA2X2_X_AXIS 0
+#define BMA2X2_Y_AXIS 1
+#define BMA2X2_Z_AXIS 2
+
+#define BMA2X2_Low_G_Interrupt 0
+#define BMA2X2_High_G_X_Interrupt 1
+#define BMA2X2_High_G_Y_Interrupt 2
+#define BMA2X2_High_G_Z_Interrupt 3
+#define BMA2X2_DATA_EN 4
+#define BMA2X2_Slope_X_Interrupt 5
+#define BMA2X2_Slope_Y_Interrupt 6
+#define BMA2X2_Slope_Z_Interrupt 7
+#define BMA2X2_Single_Tap_Interrupt 8
+#define BMA2X2_Double_Tap_Interrupt 9
+#define BMA2X2_Orient_Interrupt 10
+#define BMA2X2_Flat_Interrupt 11
+#define BMA2X2_FFULL_INTERRUPT 12
+#define BMA2X2_FWM_INTERRUPT 13
+
+#define BMA2X2_INT1_LOWG 0
+#define BMA2X2_INT2_LOWG 1
+#define BMA2X2_INT1_HIGHG 0
+#define BMA2X2_INT2_HIGHG 1
+#define BMA2X2_INT1_SLOPE 0
+#define BMA2X2_INT2_SLOPE 1
+#define BMA2X2_INT1_SLO_NO_MOT 0
+#define BMA2X2_INT2_SLO_NO_MOT 1
+#define BMA2X2_INT1_DTAP 0
+#define BMA2X2_INT2_DTAP 1
+#define BMA2X2_INT1_STAP 0
+#define BMA2X2_INT2_STAP 1
+#define BMA2X2_INT1_ORIENT 0
+#define BMA2X2_INT2_ORIENT 1
+#define BMA2X2_INT1_FLAT 0
+#define BMA2X2_INT2_FLAT 1
+#define BMA2X2_INT1_NDATA 0
+#define BMA2X2_INT2_NDATA 1
+#define BMA2X2_INT1_FWM 0
+#define BMA2X2_INT2_FWM 1
+#define BMA2X2_INT1_FFULL 0
+#define BMA2X2_INT2_FFULL 1
+
+#define BMA2X2_SRC_LOWG 0
+#define BMA2X2_SRC_HIGHG 1
+#define BMA2X2_SRC_SLOPE 2
+#define BMA2X2_SRC_SLO_NO_MOT 3
+#define BMA2X2_SRC_TAP 4
+#define BMA2X2_SRC_DATA 5
+
+#define BMA2X2_INT1_OUTPUT 0
+#define BMA2X2_INT2_OUTPUT 1
+#define BMA2X2_INT1_LEVEL 0
+#define BMA2X2_INT2_LEVEL 1
+
+#define BMA2X2_LOW_DURATION 0
+#define BMA2X2_HIGH_DURATION 1
+#define BMA2X2_SLOPE_DURATION 2
+#define BMA2X2_SLO_NO_MOT_DURATION 3
+
+#define BMA2X2_LOW_THRESHOLD 0
+#define BMA2X2_HIGH_THRESHOLD 1
+#define BMA2X2_SLOPE_THRESHOLD 2
+#define BMA2X2_SLO_NO_MOT_THRESHOLD 3
+
+
+#define BMA2X2_LOWG_HYST 0
+#define BMA2X2_HIGHG_HYST 1
+
+#define BMA2X2_ORIENT_THETA 0
+#define BMA2X2_FLAT_THETA 1
+
+#define BMA2X2_I2C_SELECT 0
+#define BMA2X2_I2C_EN 1
+
+#define BMA2X2_SLOW_COMP_X 0
+#define BMA2X2_SLOW_COMP_Y 1
+#define BMA2X2_SLOW_COMP_Z 2
+
+#define BMA2X2_CUT_OFF 0
+#define BMA2X2_OFFSET_TRIGGER_X 1
+#define BMA2X2_OFFSET_TRIGGER_Y 2
+#define BMA2X2_OFFSET_TRIGGER_Z 3
+
+#define BMA2X2_GP0 0
+#define BMA2X2_GP1 1
+
+#define BMA2X2_SLO_NO_MOT_EN_X 0
+#define BMA2X2_SLO_NO_MOT_EN_Y 1
+#define BMA2X2_SLO_NO_MOT_EN_Z 2
+#define BMA2X2_SLO_NO_MOT_EN_SEL 3
+
+#define BMA2X2_WAKE_UP_DUR_20MS 0
+#define BMA2X2_WAKE_UP_DUR_80MS 1
+#define BMA2X2_WAKE_UP_DUR_320MS 2
+#define BMA2X2_WAKE_UP_DUR_2560MS 3
+
+#define BMA2X2_SELF_TEST0_ON 1
+#define BMA2X2_SELF_TEST1_ON 2
+
+#define BMA2X2_EE_W_OFF 0
+#define BMA2X2_EE_W_ON 1
+
+#define BMA2X2_LOW_TH_IN_G(gthres, range) ((256 * gthres) / range)
+
+
+#define BMA2X2_HIGH_TH_IN_G(gthres, range) ((256 * gthres) / range)
+
+
+#define BMA2X2_LOW_HY_IN_G(ghyst, range) ((32 * ghyst) / range)
+
+
+#define BMA2X2_HIGH_HY_IN_G(ghyst, range) ((32 * ghyst) / range)
+
+
+#define BMA2X2_SLOPE_TH_IN_G(gthres, range) ((128 * gthres) / range)
+
+
+#define BMA2X2_GET_BITSLICE(regvar, bitname)\
+ ((regvar & bitname##__MSK) >> bitname##__POS)
+
+
+#define BMA2X2_SET_BITSLICE(regvar, bitname, val)\
+ ((regvar & ~bitname##__MSK) | ((val<<bitname##__POS)&bitname##__MSK))
+
+#ifdef BMA2X2_SENSOR_IDENTIFICATION_ENABLE
+#define BMA2X2_SHIFT_BITWIDTH(data, bitwidth)
+#else
+#define BMA2X2_SHIFT_BITWIDTH(data, bitwidth)\
+ (data = data >> (16 - bitwidth))
+#endif
+
+#ifdef CONFIG_BMA_ENABLE_NEWDATA_INT
+#define BMA2x2_IS_NEWDATA_INT_ENABLED() (true)
+#else
+#define BMA2x2_IS_NEWDATA_INT_ENABLED() (false)
+#endif
+
+#ifdef BMA2X2_ENABLE_INT1
+#define BMA2x2_IS_INT1_ENABLED() (true)
+#else
+#define BMA2x2_IS_INT1_ENABLED() (false)
+#endif
+
+#ifdef BMA2X2_ENABLE_INT2
+#define BMA2x2_IS_INT2_ENABLED() (true)
+#else
+#define BMA2x2_IS_INT2_ENABLED() (false)
+#endif
+
+#define CHECK_CHIP_ID_TIME_MAX 5
+#define BMA255_CHIP_ID 0XFA
+#define BMA250E_CHIP_ID 0XF9
+#define BMA222E_CHIP_ID 0XF8
+#define BMA280_CHIP_ID 0XFB
+#define BMA355_CHIP_ID 0XEA
+
+#define BMA255_TYPE 0
+#define BMA250E_TYPE 1
+#define BMA222E_TYPE 2
+#define BMA280_TYPE 3
+
+#define MAX_FIFO_F_LEVEL 32
+#define MAX_FIFO_F_BYTES 6
+#define FIFO_FRAMESIZE_3_AXIS 6
+#define FIFO_FRAMESIZE_1_AXIS 2
+#define BMA_MAX_RETRY_I2C_XFER (100)
+
+#ifdef CONFIG_DOUBLE_TAP
+#define DEFAULT_TAP_JUDGE_PERIOD 1000 /* default judge in 1 second */
+#endif
+
+#define BMA2X2_SMD_DET_TIME_NS (2200UL * 1000 * 1000)
+#define BMA2X2_SMD_DET_CNT (7)
+#define BMA2X2_SMD_SLOPE_DUR 0x3
+#define BMA2X2_SMD_SLOPE_TH 0x20
+#define BMA2X2_SMD_NO_MOT_DUR 0x1
+#define BMA2X2_SMD_NO_MOT_TH 0x20
+
+/*! Bosch sensor unknown place*/
+#define BOSCH_SENSOR_PLACE_UNKNOWN (-1)
+/*! Bosch sensor remapping table size P0~P7*/
+#define MAX_AXIS_REMAP_TAB_SZ 8
+#define BOSCH_SENSOR_PLANE 0
+#define BOSCH_SENSOR_UP 1
+#define BOSCH_SENSOR_DOWN 2
+#define RETRY_TIME 50
+/*!
+ * @brief:BMI058 feature
+ * macro definition
+*/
+
+#define BMA2X2_IS_NEWDATA_INT BMA2X2_DATA_INT_S__MSK
+#define BMA2X2_FIFO_MODE_BYPASS 0x0
+#define BMA2X2_FIFO_MODE_FIFO 0x1
+#define BMA2X2_FIFO_MODE_STREAM 0x2
+
+#define BMA2X2_FIFO_DAT_SEL_XYZ 0
+#define BMA2X2_FIFO_DAT_SEL_X 1
+#define BMA2X2_FIFO_DAT_SEL_Y 2
+#define BMA2X2_FIFO_DAT_SEL_Z 3
+
+#define BMA2X2_FIFO_WM_INT_FLAG BMA2X2_FIFO_WM_INT_S__MSK
+#define BMA2X2_FIFO_FULL_INT_FLAG BMA2X2_FIFO_FULL_INT_S__MSK
+#define BMA2X2_IS_FIFO_INT\
+ (BMA2X2_FIFO_WM_INT_FLAG | BMA2X2_FIFO_FULL_INT_FLAG)
+
+#define BMA2x2_NEWDATA_INT_MASK 0x80
+#define BMA2x2_NEWDATA_INT_FLAG 0x80
+
+#ifdef CONFIG_SENSORS_BMI058
+#define C_BMI058_One_U8X 1
+#define C_BMI058_Two_U8X 2
+#define BMI058_OFFSET_TRIGGER_X BMA2X2_OFFSET_TRIGGER_Y
+#define BMI058_OFFSET_TRIGGER_Y BMA2X2_OFFSET_TRIGGER_X
+
+/*! BMI058 X AXIS OFFSET REG definition*/
+#define BMI058_OFFSET_X_AXIS_REG BMA2X2_OFFSET_Y_AXIS_REG
+/*! BMI058 Y AXIS OFFSET REG definition*/
+#define BMI058_OFFSET_Y_AXIS_REG BMA2X2_OFFSET_X_AXIS_REG
+
+#define BMI058_FIFO_DAT_SEL_X BMA2X2_FIFO_DAT_SEL_Y
+#define BMI058_FIFO_DAT_SEL_Y BMA2X2_FIFO_DAT_SEL_X
+
+/*! BMA2x2 common slow no motion X interrupt type definition*/
+#define BMA2X2_SLOW_NO_MOT_X_INT 12
+/*! BMA2x2 common slow no motion Y interrupt type definition*/
+#define BMA2X2_SLOW_NO_MOT_Y_INT 13
+/*! BMA2x2 common High G X interrupt type definition*/
+#define BMA2X2_HIGHG_X_INT 1
+/*! BMA2x2 common High G Y interrupt type definition*/
+#define BMA2X2_HIGHG_Y_INT 2
+/*! BMA2x2 common slope X interrupt type definition*/
+#define BMA2X2_SLOPE_X_INT 5
+/*! BMA2x2 common slope Y interrupt type definition*/
+#define BMA2X2_SLOPE_Y_INT 6
+
+/*! this structure holds some interrupt types difference
+**between BMA2x2 and BMI058.
+*/
+struct interrupt_map_t {
+ int x;
+ int y;
+};
+/*!*Need to use BMA2x2 Common interrupt type definition to
+* instead of Some of BMI058 reversed Interrupt type
+* because of HW Register.
+* The reversed Interrupt types contain:
+* slow_no_mot_x_int && slow_not_mot_y_int
+* highg_x_int && highg_y_int
+* slope_x_int && slope_y_int
+**/
+static const struct interrupt_map_t int_map[] = {
+ {BMA2X2_SLOW_NO_MOT_X_INT, BMA2X2_SLOW_NO_MOT_Y_INT},
+ {BMA2X2_HIGHG_X_INT, BMA2X2_HIGHG_Y_INT},
+ {BMA2X2_SLOPE_X_INT, BMA2X2_SLOPE_Y_INT}
+};
+
+/*! high g or slope interrupt type definition for BMI058*/
+/*! High G interrupt of x, y, z axis happened */
+#define HIGH_G_INTERRUPT_X HIGH_G_INTERRUPT_Y_HAPPENED
+#define HIGH_G_INTERRUPT_Y HIGH_G_INTERRUPT_X_HAPPENED
+#define HIGH_G_INTERRUPT_Z HIGH_G_INTERRUPT_Z_HAPPENED
+/*! High G interrupt of x, y, z negative axis happened */
+#define HIGH_G_INTERRUPT_X_N HIGH_G_INTERRUPT_Y_NEGATIVE_HAPPENED
+#define HIGH_G_INTERRUPT_Y_N HIGH_G_INTERRUPT_X_NEGATIVE_HAPPENED
+#define HIGH_G_INTERRUPT_Z_N HIGH_G_INTERRUPT_Z_NEGATIVE_HAPPENED
+/*! Slope interrupt of x, y, z axis happened */
+#define SLOPE_INTERRUPT_X SLOPE_INTERRUPT_Y_HAPPENED
+#define SLOPE_INTERRUPT_Y SLOPE_INTERRUPT_X_HAPPENED
+#define SLOPE_INTERRUPT_Z SLOPE_INTERRUPT_Z_HAPPENED
+/*! Slope interrupt of x, y, z negative axis happened */
+#define SLOPE_INTERRUPT_X_N SLOPE_INTERRUPT_Y_NEGATIVE_HAPPENED
+#define SLOPE_INTERRUPT_Y_N SLOPE_INTERRUPT_X_NEGATIVE_HAPPENED
+#define SLOPE_INTERRUPT_Z_N SLOPE_INTERRUPT_Z_NEGATIVE_HAPPENED
+
+
+#else
+
+/*! high g or slope interrupt type definition*/
+/*! High G interrupt of x, y, z axis happened */
+#define HIGH_G_INTERRUPT_X HIGH_G_INTERRUPT_X_HAPPENED
+#define HIGH_G_INTERRUPT_Y HIGH_G_INTERRUPT_Y_HAPPENED
+#define HIGH_G_INTERRUPT_Z HIGH_G_INTERRUPT_Z_HAPPENED
+/*! High G interrupt of x, y, z negative axis happened */
+#define HIGH_G_INTERRUPT_X_N HIGH_G_INTERRUPT_X_NEGATIVE_HAPPENED
+#define HIGH_G_INTERRUPT_Y_N HIGH_G_INTERRUPT_Y_NEGATIVE_HAPPENED
+#define HIGH_G_INTERRUPT_Z_N HIGH_G_INTERRUPT_Z_NEGATIVE_HAPPENED
+/*! Slope interrupt of x, y, z axis happened */
+#define SLOPE_INTERRUPT_X SLOPE_INTERRUPT_X_HAPPENED
+#define SLOPE_INTERRUPT_Y SLOPE_INTERRUPT_Y_HAPPENED
+#define SLOPE_INTERRUPT_Z SLOPE_INTERRUPT_Z_HAPPENED
+/*! Slope interrupt of x, y, z negative axis happened */
+#define SLOPE_INTERRUPT_X_N SLOPE_INTERRUPT_X_NEGATIVE_HAPPENED
+#define SLOPE_INTERRUPT_Y_N SLOPE_INTERRUPT_Y_NEGATIVE_HAPPENED
+#define SLOPE_INTERRUPT_Z_N SLOPE_INTERRUPT_Z_NEGATIVE_HAPPENED
+
+
+#endif/*End of CONFIG_SENSORS_BMI058*/
+
+/*BMA power supply VDD 1.62V-3.6V VIO 1.2-3.6V */
+#define BMA2x2_VDD_MIN_UV 2000000
+#define BMA2x2_VDD_MAX_UV 3400000
+#define BMA2x2_VIO_MIN_UV 1500000
+#define BMA2x2_VIO_MAX_UV 3400000
+
+/* Polling delay in msecs */
+#define POLL_INTERVAL_MIN_MS 10
+#define POLL_INTERVAL_MAX_MS 4000
+#define POLL_DEFAULT_INTERVAL_MS 200
+
+#define POLL_MS_100HZ 10
+
+/* Interrupt delay in msecs */
+#define BMA_INT_MAX_DELAY 64
+
+#define MAX_RANGE_MAP 4
+
+#define BMA_CAL_BUF_SIZE 99
+
+struct bma2x2_type_map_t {
+
+ /*! bma2x2 sensor chip id */
+ uint16_t chip_id;
+
+ /*! bma2x2 sensor type */
+ uint16_t sensor_type;
+
+ /*! bma2x2 sensor name */
+ const char *sensor_name;
+
+ /*! bma2x2 sensor resolution */
+ const char *resolution;
+};
+
+static const struct bma2x2_type_map_t sensor_type_map[] = {
+
+ {BMA255_CHIP_ID, BMA255_TYPE, "BMA255/254", "0.00957031"},
+ {BMA355_CHIP_ID, BMA255_TYPE, "BMA355", "0.00957031"},
+ {BMA250E_CHIP_ID, BMA250E_TYPE, "BMA250E", "0.03828125"},
+ {BMA222E_CHIP_ID, BMA222E_TYPE, "BMA222E", "0.153125"},
+ {BMA280_CHIP_ID, BMA280_TYPE, "BMA280", "0.00239258"},
+
+};
+
+/*!
+ * we use a typedef to hide the detail,
+ * because this type might be changed
+ */
+struct bosch_sensor_axis_remap {
+ /* src means which source will be mapped to target x, y, z axis */
+ /* if an target OS axis is remapped from (-)x,
+ * src is 0, sign_* is (-)1 */
+ /* if an target OS axis is remapped from (-)y,
+ * src is 1, sign_* is (-)1 */
+ /* if an target OS axis is remapped from (-)z,
+ * src is 2, sign_* is (-)1 */
+ int src_x:3;
+ int src_y:3;
+ int src_z:3;
+
+ int sign_x:2;
+ int sign_y:2;
+ int sign_z:2;
+};
+
+struct bosch_sensor_data {
+ union {
+ int16_t v[3];
+ struct {
+ int16_t x;
+ int16_t y;
+ int16_t z;
+ };
+ };
+};
+
+struct bma2x2acc {
+ s16 x;
+ s16 y;
+ s16 z;
+};
+
+struct bma2x2_platform_data {
+ int poll_interval;
+ int gpio_int1;
+ int gpio_int2;
+ unsigned int int1_flag;
+ unsigned int int2_flag;
+ s8 place;
+ bool int_en;
+ bool use_int2; /* Use interrupt pin2 */
+ bool use_smd;
+ bool use_hrtimer;
+};
+
+struct bma2x2_suspend_state {
+ bool powerEn;
+};
+
+struct bma2x2_pinctrl_data {
+ struct pinctrl *pctrl;
+ struct pinctrl_state *pins_default;
+ struct pinctrl_state *pins_sleep;
+};
+
+struct bma2x2_data {
+ struct i2c_client *bma2x2_client;
+ struct sensors_classdev cdev;
+ struct sensors_classdev smd_cdev;
+ atomic_t delay;
+ atomic_t enable;
+ atomic_t selftest_result;
+ atomic_t cal_status;
+ atomic_t fifo_enabled;
+ atomic_t en_sig_motion;
+ char calibrate_buf[BMA_CAL_BUF_SIZE];
+ unsigned int chip_id;
+ unsigned int chip_type;
+ unsigned char mode;
+ signed char sensor_type;
+ unsigned char fifo_datasel;
+ unsigned int fifo_count;
+ signed char *fifo_buf;
+ s64 fifo_start_ns;
+ unsigned int max_latency_ms;
+ struct input_dev *input;
+
+ struct bst_dev *bst_acc;
+
+ struct bma2x2acc value;
+ struct mutex value_mutex;
+ struct mutex enable_mutex;
+ struct mutex mode_mutex;
+ struct mutex op_lock;
+
+ struct workqueue_struct *data_wq;
+ struct delayed_work work;
+ struct work_struct irq_work;
+ struct hrtimer accel_timer;
+ int accel_wkp_flag;
+ struct task_struct *accel_task;
+ bool accel_delay_change;
+ wait_queue_head_t accel_wq;
+ struct regulator *vdd;
+ struct regulator *vio;
+ bool power_enabled;
+ unsigned char bandwidth;
+ unsigned char range;
+ unsigned int int_flag;
+ int sensitivity;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif
+ int IRQ;
+ struct bma2x2_platform_data *pdata;
+ struct bma2x2_suspend_state suspend_state;
+ struct bma2x2_pinctrl_data *pctrl_data;
+
+ int ref_count;
+ struct input_dev *dev_interrupt;
+
+#ifdef CONFIG_SIG_MOTION
+ struct class *g_sensor_class;
+ struct device *g_sensor_dev;
+ struct input_dev *smd_input;
+
+ /*struct bma250_platform_data *pdata;*/
+ unsigned int smd_count;
+#endif
+
+#ifdef CONFIG_DOUBLE_TAP
+ struct class *g_sensor_class_doubletap;
+ struct device *g_sensor_dev_doubletap;
+ atomic_t en_double_tap;
+ unsigned char tap_times;
+ struct mutex tap_mutex;
+ struct timer_list tap_timer;
+ int tap_time_period;
+#endif
+};
+
+struct bma2x2_delay2bw {
+ unsigned int delay_ms;
+ unsigned int bw_config;
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void bma2x2_early_suspend(struct early_suspend *h);
+static void bma2x2_late_resume(struct early_suspend *h);
+#endif
+
+static int bma2x2_open_init(struct i2c_client *client,
+ struct bma2x2_data *data);
+static int bma2x2_set_mode(struct i2c_client *client, u8 mode);
+static int bma2x2_get_mode(struct i2c_client *client, u8 *mode);
+static int bma2x2_get_fifo_mode(struct i2c_client *client, u8 *fifo_mode);
+static int bma2x2_set_fifo_mode(struct i2c_client *client, u8 fifo_mode);
+static int bma2x2_normal_to_suspend(struct bma2x2_data *bma2x2,
+ unsigned char data1, unsigned char data2);
+static int bma2x2_store_state(struct i2c_client *client,
+ struct bma2x2_data *data);
+static int bma2x2_power_ctl(struct bma2x2_data *data, bool on);
+static int bma2x2_eeprom_prog(struct i2c_client *client);
+static int bma2x2_get_sensitivity(struct bma2x2_data *bma2x2, int range);
+static void bma2x2_pinctrl_state(struct bma2x2_data *data, bool active);
+static int bma2x2_flush_fifo(struct bma2x2_data *bma2x2);
+
+static struct sensors_classdev sensors_cdev = {
+ .name = "bma2x2-accel",
+ .vendor = "bosch",
+ .version = 1,
+ .handle = SENSORS_ACCELERATION_HANDLE,
+ .type = SENSOR_TYPE_ACCELEROMETER,
+ .max_range = "156.8", /* 16g */
+ .resolution = "0.153125", /* 15.6mg */
+ .sensor_power = "0.13", /* typical value */
+ .min_delay = POLL_INTERVAL_MIN_MS * 1000, /* in microseconds */
+ .max_delay = POLL_INTERVAL_MAX_MS,
+ .max_latency = POLL_INTERVAL_MAX_MS,
+ .fifo_reserved_event_count = 0,
+ .fifo_max_event_count = 0,
+ .enabled = 0,
+ .delay_msec = POLL_DEFAULT_INTERVAL_MS, /* in millisecond */
+ .sensors_enable = NULL,
+ .sensors_poll_delay = NULL,
+ .sensors_self_test = NULL,
+};
+
+#ifdef CONFIG_SIG_MOTION
+static struct sensors_classdev smd_cdev = {
+ .name = "bma2x2-smd",
+ .vendor = "bosch",
+ .version = 1,
+ .handle = 0,
+ .type = SENSOR_TYPE_SIGNIFICANT_MOTION,
+ .max_range = "1",
+ .resolution = "1.0",
+ .sensor_power = "0.25",
+ .min_delay = -1,
+ .max_delay = 0,
+ .fifo_reserved_event_count = 0,
+ .fifo_max_event_count = 0,
+ .flags = 5,
+ .enabled = 0,
+ .delay_msec = 0,
+ .sensors_enable = NULL,
+ .sensors_poll_delay = NULL,
+};
+#endif
+
+/*Remapping for BMA2X2*/
+
+static const struct bosch_sensor_axis_remap
+bst_axis_remap_tab_dft[MAX_AXIS_REMAP_TAB_SZ] = {
+ /* src_x src_y src_z sign_x sign_y sign_z */
+ { 0, 1, 2, 1, 1, 1 }, /* P0 */
+ { 1, 0, 2, 1, -1, 1 }, /* P1 */
+ { 0, 1, 2, -1, -1, 1 }, /* P2 */
+ { 1, 0, 2, -1, 1, 1 }, /* P3 */
+
+ { 0, 1, 2, -1, 1, -1 }, /* P4 */
+ { 1, 0, 2, -1, -1, -1 }, /* P5 */
+ { 0, 1, 2, 1, -1, -1 }, /* P6 */
+ { 1, 0, 2, 1, 1, -1 }, /* P7 */
+};
+
+static const int bosch_sensor_range_map[MAX_RANGE_MAP] = {
+ 0, /*2G range*/
+ 1, /*4G range*/
+ 2, /*8G range*/
+ 3 /*16G range*/
+};
+
+/* Convert bandwidth to sampling delay */
+static const struct bma2x2_delay2bw bma2x2_delay2bw_table[] = {
+ { 1, BMA2X2_BW_500HZ },
+ { 2, BMA2X2_BW_250HZ },
+ { 4, BMA2X2_BW_125HZ },
+ { 8, BMA2X2_BW_62_50HZ },
+ { 16, BMA2X2_BW_31_25HZ },
+ { 32, BMA2X2_BW_15_63HZ },
+ { 64, BMA2X2_BW_7_81HZ },
+};
+
+
+static inline bool bma2x2_use_data_polling(const struct bma2x2_data *bma2x2)
+{
+ return !bma2x2->pdata->int_en ||
+ ((bma2x2->pdata->int_en) &&
+ !BMA2x2_IS_NEWDATA_INT_ENABLED());
+}
+
+static inline void bma2x2_set_fifo_start_time(struct bma2x2_data *bma2x2)
+{
+ struct timespec ts;
+
+ get_monotonic_boottime(&ts);
+ bma2x2->fifo_start_ns = timespec_to_ns(&ts);
+}
+
+static void bst_remap_sensor_data(struct bosch_sensor_data *data,
+ const struct bosch_sensor_axis_remap *remap)
+{
+ struct bosch_sensor_data tmp;
+
+ tmp.x = data->v[remap->src_x] * remap->sign_x;
+ tmp.y = data->v[remap->src_y] * remap->sign_y;
+ tmp.z = data->v[remap->src_z] * remap->sign_z;
+
+ memcpy(data, &tmp, sizeof(*data));
+}
+
+
+static void bst_remap_sensor_data_dft_tab(struct bosch_sensor_data *data,
+ int place)
+{
+ /* sensor with place 0 needs not to be remapped */
+ if ((place <= 0) || (place >= MAX_AXIS_REMAP_TAB_SZ))
+ return;
+
+ bst_remap_sensor_data(data, &bst_axis_remap_tab_dft[place]);
+}
+
+static void bma2x2_remap_sensor_data(struct bma2x2acc *val,
+ struct bma2x2_data *client_data)
+{
+ struct bosch_sensor_data bsd;
+
+#ifdef CONFIG_SENSORS_BMI058
+/*x,y need to be invesed becase of HW Register for BMI058*/
+ bsd.y = val->x;
+ bsd.x = val->y;
+ bsd.z = val->z;
+#else
+ bsd.x = val->x;
+ bsd.y = val->y;
+ bsd.z = val->z;
+#endif
+
+ bst_remap_sensor_data_dft_tab(&bsd,
+ client_data->pdata->place);
+
+ val->x = bsd.x;
+ val->y = bsd.y;
+ val->z = bsd.z;
+
+}
+
+
+static int bma2x2_smbus_read_byte(struct i2c_client *client,
+ unsigned char reg_addr, unsigned char *data)
+{
+ s32 dummy;
+
+ dummy = i2c_smbus_read_byte_data(client, reg_addr);
+ if (dummy < 0)
+ return -EIO;
+ *data = dummy & 0x000000ff;
+
+ return 0;
+}
+
+static int bma2x2_smbus_write_byte(struct i2c_client *client,
+ unsigned char reg_addr, unsigned char *data)
+{
+ s32 dummy;
+
+ dummy = i2c_smbus_write_byte_data(client, reg_addr, *data);
+ if (dummy < 0)
+ return -EIO;
+ udelay(2);
+ return 0;
+}
+
+static int bma2x2_smbus_read_byte_block(struct i2c_client *client,
+ unsigned char reg_addr, unsigned char *data, unsigned char len)
+{
+ s32 dummy;
+
+ dummy = i2c_smbus_read_i2c_block_data(client, reg_addr, len, data);
+ if (dummy < 0)
+ return -EIO;
+ return 0;
+}
+
+static int bma_i2c_burst_read(struct i2c_client *client, u8 reg_addr,
+ u8 *data, u16 len)
+{
+ int retry;
+
+ struct i2c_msg msg[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &reg_addr,
+ },
+
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = len,
+ .buf = data,
+ },
+ };
+
+ for (retry = 0; retry < BMA_MAX_RETRY_I2C_XFER; retry++) {
+ if (i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)) > 0)
+ break;
+
+ I2C_RETRY_DELAY();
+ }
+
+ if (BMA_MAX_RETRY_I2C_XFER <= retry) {
+ dev_err(&client->dev, "I2C xfer error");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int bma2x2_check_chip_id(struct i2c_client *client,
+ struct bma2x2_data *data)
+{
+ int i = 0;
+ int err = 0;
+ unsigned char chip_id;
+ unsigned char read_count = 0;
+ unsigned char bma2x2_sensor_type_count = 0;
+
+ bma2x2_sensor_type_count =
+ sizeof(sensor_type_map) / sizeof(struct bma2x2_type_map_t);
+
+ while (read_count++ < CHECK_CHIP_ID_TIME_MAX) {
+ err = bma2x2_smbus_read_byte(client, BMA2X2_CHIP_ID_REG,
+ &chip_id);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "Bosch Sensortec Device not foundi2c bus read error, read chip_id:%d\n",
+ chip_id);
+ err = -ENODEV;
+ return err;
+ }
+ for (i = 0; i < bma2x2_sensor_type_count; i++) {
+ if (sensor_type_map[i].chip_id == chip_id) {
+ data->sensor_type =
+ sensor_type_map[i].sensor_type;
+ data->chip_id = chip_id;
+ dev_dbg(&client->dev,
+ "Bosch Sensortec Device detected, HW IC name: %s\n",
+ sensor_type_map[i].sensor_name);
+ data->chip_type = i;
+ return err;
+ }
+ }
+ if (i < bma2x2_sensor_type_count) {
+ return err;
+ } else if (read_count == CHECK_CHIP_ID_TIME_MAX) {
+ dev_err(&client->dev,
+ "Failed!Bosch Sensortec Device not found, mismatch chip_id:%d\n",
+ chip_id);
+ err = -ENODEV;
+ return err;
+ }
+ I2C_RETRY_DELAY();
+ }
+ return err;
+}
+
+#if defined(BMA2X2_ENABLE_INT1) || defined(BMA2X2_ENABLE_INT2)
+static int bma2x2_set_newdata(struct i2c_client *client,
+ unsigned char channel, unsigned char int_newdata)
+{
+
+ unsigned char data;
+ int comres = 0;
+
+ switch (channel) {
+ case BMA2X2_INT1_NDATA:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT1_PAD_NEWDATA__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data,
+ BMA2X2_EN_INT1_PAD_NEWDATA, int_newdata);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT1_PAD_NEWDATA__REG, &data);
+ break;
+ case BMA2X2_INT2_NDATA:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT2_PAD_NEWDATA__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data,
+ BMA2X2_EN_INT2_PAD_NEWDATA, int_newdata);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT2_PAD_NEWDATA__REG, &data);
+ break;
+ default:
+ comres = -1;
+ break;
+ }
+
+ return comres;
+
+}
+
+static int bma2x2_set_fwm_int_pad_sel(struct i2c_client *client,
+ unsigned char channel, unsigned char fifo_int)
+{
+ unsigned char data;
+ int comres = 0;
+
+ switch (channel) {
+ case BMA2X2_INT1_FWM:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT1_PAD_FWM__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data,
+ BMA2X2_EN_INT1_PAD_FWM, fifo_int);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT1_PAD_FWM__REG, &data);
+ break;
+ case BMA2X2_INT2_FWM:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT2_PAD_FWM__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data,
+ BMA2X2_EN_INT2_PAD_FWM, fifo_int);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT2_PAD_FWM__REG, &data);
+ break;
+ default:
+ comres = -1;
+ break;
+ }
+
+ return comres;
+}
+
+static int bma2x2_set_ffull_int_pad_sel(struct i2c_client *client,
+ unsigned char channel, unsigned char fifo_int)
+{
+ unsigned char data;
+ int comres = 0;
+
+ switch (channel) {
+ case BMA2X2_INT1_FFULL:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT1_PAD_FFULL__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data,
+ BMA2X2_EN_INT1_PAD_FFULL, fifo_int);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT1_PAD_FFULL__REG, &data);
+ break;
+ case BMA2X2_INT2_FFULL:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT2_PAD_FFULL__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data,
+ BMA2X2_EN_INT2_PAD_FFULL, fifo_int);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT2_PAD_FFULL__REG, &data);
+ break;
+ default:
+ comres = -1;
+ break;
+ }
+
+ return comres;
+}
+#endif
+
+#ifdef BMA2X2_ENABLE_INT1
+static int bma2x2_set_int1_pad_sel(struct i2c_client *client, unsigned char
+ int1sel)
+{
+ int comres = 0;
+ unsigned char data;
+ unsigned char state = 0x01;
+
+ switch (int1sel) {
+ case 0:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT1_PAD_LOWG__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT1_PAD_LOWG,
+ state);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT1_PAD_LOWG__REG, &data);
+ break;
+ case 1:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT1_PAD_HIGHG__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT1_PAD_HIGHG,
+ state);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT1_PAD_HIGHG__REG, &data);
+ break;
+ case 2:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT1_PAD_SLOPE__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT1_PAD_SLOPE,
+ state);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT1_PAD_SLOPE__REG, &data);
+ break;
+ case 3:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT1_PAD_DB_TAP__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT1_PAD_DB_TAP,
+ state);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT1_PAD_DB_TAP__REG, &data);
+ break;
+ case 4:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT1_PAD_SNG_TAP__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT1_PAD_SNG_TAP,
+ state);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT1_PAD_SNG_TAP__REG, &data);
+ break;
+ case 5:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT1_PAD_ORIENT__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT1_PAD_ORIENT,
+ state);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT1_PAD_ORIENT__REG, &data);
+ break;
+ case 6:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT1_PAD_FLAT__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT1_PAD_FLAT,
+ state);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT1_PAD_FLAT__REG, &data);
+ break;
+ case 7:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT1_PAD_SLO_NO_MOT__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT1_PAD_SLO_NO_MOT,
+ state);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT1_PAD_SLO_NO_MOT__REG, &data);
+ break;
+
+ default:
+ break;
+ }
+
+ return comres;
+}
+#endif /* BMA2X2_ENABLE_INT1 */
+
+#ifdef BMA2X2_ENABLE_INT2
+static int bma2x2_set_int2_pad_sel(struct i2c_client *client, unsigned char
+ int2sel)
+{
+ int comres = 0;
+ unsigned char data;
+ unsigned char state = 0x01;
+
+ switch (int2sel) {
+ case 0:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT2_PAD_LOWG__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT2_PAD_LOWG,
+ state);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT2_PAD_LOWG__REG, &data);
+ break;
+ case 1:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT2_PAD_HIGHG__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT2_PAD_HIGHG,
+ state);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT2_PAD_HIGHG__REG, &data);
+ break;
+ case 2:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT2_PAD_SLOPE__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT2_PAD_SLOPE,
+ state);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT2_PAD_SLOPE__REG, &data);
+ break;
+ case 3:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT2_PAD_DB_TAP__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT2_PAD_DB_TAP,
+ state);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT2_PAD_DB_TAP__REG, &data);
+ break;
+ case 4:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT2_PAD_SNG_TAP__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT2_PAD_SNG_TAP,
+ state);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT2_PAD_SNG_TAP__REG, &data);
+ break;
+ case 5:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT2_PAD_ORIENT__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT2_PAD_ORIENT,
+ state);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT2_PAD_ORIENT__REG, &data);
+ break;
+ case 6:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT2_PAD_FLAT__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT2_PAD_FLAT,
+ state);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT2_PAD_FLAT__REG, &data);
+ break;
+ case 7:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_EN_INT2_PAD_SLO_NO_MOT__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT2_PAD_SLO_NO_MOT,
+ state);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_EN_INT2_PAD_SLO_NO_MOT__REG, &data);
+ break;
+ default:
+ break;
+ }
+
+ return comres;
+}
+#endif /* BMA2X2_ENABLE_INT2 */
+
+static int bma2x2_set_Int_Enable(struct i2c_client *client, unsigned char
+ InterruptType , unsigned char value)
+{
+ int comres = 0;
+ unsigned char data1, data2;
+
+ if ((11 < InterruptType) && (InterruptType < 16)) {
+ switch (InterruptType) {
+ case 12:
+ /* slow/no motion X Interrupt */
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_INT_SLO_NO_MOT_EN_X_INT__REG, &data1);
+ data1 = BMA2X2_SET_BITSLICE(data1,
+ BMA2X2_INT_SLO_NO_MOT_EN_X_INT, value);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_INT_SLO_NO_MOT_EN_X_INT__REG, &data1);
+ break;
+ case 13:
+ /* slow/no motion Y Interrupt */
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_INT_SLO_NO_MOT_EN_Y_INT__REG, &data1);
+ data1 = BMA2X2_SET_BITSLICE(data1,
+ BMA2X2_INT_SLO_NO_MOT_EN_Y_INT, value);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_INT_SLO_NO_MOT_EN_Y_INT__REG, &data1);
+ break;
+ case 14:
+ /* slow/no motion Z Interrupt */
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_INT_SLO_NO_MOT_EN_Z_INT__REG, &data1);
+ data1 = BMA2X2_SET_BITSLICE(data1,
+ BMA2X2_INT_SLO_NO_MOT_EN_Z_INT, value);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_INT_SLO_NO_MOT_EN_Z_INT__REG, &data1);
+ break;
+ case 15:
+ /* slow / no motion Interrupt select */
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_INT_SLO_NO_MOT_EN_SEL_INT__REG, &data1);
+ data1 = BMA2X2_SET_BITSLICE(data1,
+ BMA2X2_INT_SLO_NO_MOT_EN_SEL_INT, value);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_INT_SLO_NO_MOT_EN_SEL_INT__REG, &data1);
+ }
+
+ return comres;
+ }
+
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_INT_ENABLE1_REG, &data1);
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_INT_ENABLE2_REG, &data2);
+
+ value = value & 1;
+ switch (InterruptType) {
+ case 0:
+ /* Low G Interrupt */
+ data2 = BMA2X2_SET_BITSLICE(data2, BMA2X2_EN_LOWG_INT, value);
+ break;
+
+ case 1:
+ /* High G X Interrupt */
+ data2 = BMA2X2_SET_BITSLICE(data2, BMA2X2_EN_HIGHG_X_INT,
+ value);
+ break;
+
+ case 2:
+ /* High G Y Interrupt */
+ data2 = BMA2X2_SET_BITSLICE(data2, BMA2X2_EN_HIGHG_Y_INT,
+ value);
+ break;
+
+ case 3:
+ /* High G Z Interrupt */
+ data2 = BMA2X2_SET_BITSLICE(data2, BMA2X2_EN_HIGHG_Z_INT,
+ value);
+ break;
+
+ case 4:
+ /* New Data Interrupt */
+ data2 = BMA2X2_SET_BITSLICE(data2, BMA2X2_EN_NEW_DATA_INT,
+ value);
+ break;
+
+ case 5:
+ /* Slope X Interrupt */
+ data1 = BMA2X2_SET_BITSLICE(data1, BMA2X2_EN_SLOPE_X_INT,
+ value);
+ break;
+
+ case 6:
+ /* Slope Y Interrupt */
+ data1 = BMA2X2_SET_BITSLICE(data1, BMA2X2_EN_SLOPE_Y_INT,
+ value);
+ break;
+
+ case 7:
+ /* Slope Z Interrupt */
+ data1 = BMA2X2_SET_BITSLICE(data1, BMA2X2_EN_SLOPE_Z_INT,
+ value);
+ break;
+
+ case 8:
+ /* Single Tap Interrupt */
+ data1 = BMA2X2_SET_BITSLICE(data1, BMA2X2_EN_SINGLE_TAP_INT,
+ value);
+ break;
+
+ case 9:
+ /* Double Tap Interrupt */
+ data1 = BMA2X2_SET_BITSLICE(data1, BMA2X2_EN_DOUBLE_TAP_INT,
+ value);
+ break;
+
+ case 10:
+ /* Orient Interrupt */
+ data1 = BMA2X2_SET_BITSLICE(data1, BMA2X2_EN_ORIENT_INT, value);
+ break;
+
+ case 11:
+ /* Flat Interrupt */
+ data1 = BMA2X2_SET_BITSLICE(data1, BMA2X2_EN_FLAT_INT, value);
+ break;
+
+ default:
+ break;
+ }
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_INT_ENABLE1_REG,
+ &data1);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_INT_ENABLE2_REG,
+ &data2);
+
+ return comres;
+}
+
+static int bma2x2_set_watermark_int(struct i2c_client *client, bool enable)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_INT_FWM_EN_INT__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data,
+ BMA2X2_INT_FWM_EN_INT, (unsigned char)(enable ? 1 : 0));
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_INT_FWM_EN_INT__REG, &data);
+
+ return comres;
+}
+
+static int bma2x2_set_fifo_full_int(struct i2c_client *client, bool enable)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_INT_FFULL_EN_INT__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data,
+ BMA2X2_INT_FFULL_EN_INT, (unsigned char)(enable ? 1 : 0));
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_INT_FFULL_EN_INT__REG, &data);
+
+ return comres;
+}
+
+#if defined(BMA2X2_ENABLE_INT1) || defined(BMA2X2_ENABLE_INT2)
+static int bma2x2_get_HIGH_first(struct i2c_client *client, unsigned char
+ param, unsigned char *intstatus)
+{
+ int comres = 0;
+ unsigned char data;
+
+ switch (param) {
+ case 0:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_STATUS_ORIENT_HIGH_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_HIGHG_FIRST_X);
+ *intstatus = data;
+ break;
+ case 1:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_STATUS_ORIENT_HIGH_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_HIGHG_FIRST_Y);
+ *intstatus = data;
+ break;
+ case 2:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_STATUS_ORIENT_HIGH_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_HIGHG_FIRST_Z);
+ *intstatus = data;
+ break;
+ default:
+ break;
+ }
+
+ return comres;
+}
+
+static int bma2x2_get_HIGH_sign(struct i2c_client *client, unsigned char
+ *intstatus)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_STATUS_ORIENT_HIGH_REG,
+ &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_HIGHG_SIGN_S);
+ *intstatus = data;
+
+ return comres;
+}
+
+#ifndef CONFIG_SIG_MOTION
+static int bma2x2_get_slope_first(struct i2c_client *client, unsigned char
+ param, unsigned char *intstatus)
+{
+ int comres = 0;
+ unsigned char data;
+
+ switch (param) {
+ case 0:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_STATUS_TAP_SLOPE_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_SLOPE_FIRST_X);
+ *intstatus = data;
+ break;
+ case 1:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_STATUS_TAP_SLOPE_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_SLOPE_FIRST_Y);
+ *intstatus = data;
+ break;
+ case 2:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_STATUS_TAP_SLOPE_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_SLOPE_FIRST_Z);
+ *intstatus = data;
+ break;
+ default:
+ break;
+ }
+
+ return comres;
+}
+
+static int bma2x2_get_slope_sign(struct i2c_client *client, unsigned char
+ *intstatus)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_STATUS_TAP_SLOPE_REG,
+ &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_SLOPE_SIGN_S);
+ *intstatus = data;
+
+ return comres;
+}
+#endif /* CONFIG_SIG_MOTION */
+
+static int bma2x2_get_orient_status(struct i2c_client *client, unsigned char
+ *intstatus)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_STATUS_ORIENT_HIGH_REG,
+ &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_ORIENT_S);
+ *intstatus = data;
+
+ return comres;
+}
+
+static int bma2x2_get_orient_flat_status(struct i2c_client *client, unsigned
+ char *intstatus)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_STATUS_ORIENT_HIGH_REG,
+ &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_FLAT_S);
+ *intstatus = data;
+
+ return comres;
+}
+#endif /* defined(BMA2X2_ENABLE_INT1)||defined(BMA2X2_ENABLE_INT2) */
+
+static int bma2x2_set_Int_Mode(struct i2c_client *client, unsigned char Mode)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_INT_MODE_SEL__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_INT_MODE_SEL, Mode);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_INT_MODE_SEL__REG, &data);
+
+ return comres;
+}
+
+static int bma2x2_set_int1_active_lvl(struct i2c_client *client,
+ bool activeHigh)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_INT1_PAD_ACTIVE_LEVEL__REG, &data);
+ if (comres)
+ return comres;
+
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_INT1_PAD_ACTIVE_LEVEL,
+ (unsigned char)(activeHigh ? 1 : 0));
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_INT1_PAD_ACTIVE_LEVEL__REG, &data);
+
+ return comres;
+}
+
+static int bma2x2_set_int2_active_lvl(struct i2c_client *client,
+ bool activeHigh)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_INT2_PAD_ACTIVE_LEVEL__REG, &data);
+ if (comres)
+ return comres;
+
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_INT2_PAD_ACTIVE_LEVEL,
+ (unsigned char)(activeHigh ? 1 : 0));
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_INT2_PAD_ACTIVE_LEVEL__REG, &data);
+
+ return comres;
+}
+
+static int bma2x2_get_Int_Mode(struct i2c_client *client, unsigned char *Mode)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_INT_MODE_SEL__REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_INT_MODE_SEL);
+ *Mode = data;
+
+
+ return comres;
+}
+static int bma2x2_set_slope_duration(struct i2c_client *client, unsigned char
+ duration)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_SLOPE_DUR__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_SLOPE_DUR, duration);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_SLOPE_DUR__REG, &data);
+
+ return comres;
+}
+
+static int bma2x2_get_slope_duration(struct i2c_client *client, unsigned char
+ *status)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_SLOPE_DURN_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_SLOPE_DUR);
+ *status = data;
+
+
+ return comres;
+}
+
+static int bma2x2_set_slope_no_mot_duration(struct i2c_client *client,
+ unsigned char duration)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2x2_SLO_NO_MOT_DUR__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2x2_SLO_NO_MOT_DUR, duration);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2x2_SLO_NO_MOT_DUR__REG, &data);
+
+
+ return comres;
+}
+
+static int bma2x2_get_slope_no_mot_duration(struct i2c_client *client,
+ unsigned char *status)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2x2_SLO_NO_MOT_DUR__REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2x2_SLO_NO_MOT_DUR);
+ *status = data;
+
+
+ return comres;
+}
+
+static int bma2x2_set_slope_threshold(struct i2c_client *client,
+ unsigned char threshold)
+{
+ int comres = 0;
+ unsigned char data;
+
+ data = threshold;
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_SLOPE_THRES__REG, &data);
+
+ return comres;
+}
+
+static int bma2x2_get_slope_threshold(struct i2c_client *client,
+ unsigned char *status)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_SLOPE_THRES_REG, &data);
+ *status = data;
+
+ return comres;
+}
+
+static int bma2x2_set_slope_no_mot_threshold(struct i2c_client *client,
+ unsigned char threshold)
+{
+ int comres = 0;
+ unsigned char data;
+
+ data = threshold;
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_SLO_NO_MOT_THRES_REG, &data);
+
+ return comres;
+}
+
+static int bma2x2_get_slope_no_mot_threshold(struct i2c_client *client,
+ unsigned char *status)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_SLO_NO_MOT_THRES_REG, &data);
+ *status = data;
+
+ return comres;
+}
+
+
+static int bma2x2_set_low_g_duration(struct i2c_client *client, unsigned char
+ duration)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_LOWG_DUR__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_LOWG_DUR, duration);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_LOWG_DUR__REG, &data);
+
+ return comres;
+}
+
+static int bma2x2_get_low_g_duration(struct i2c_client *client, unsigned char
+ *status)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_LOW_DURN_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_LOWG_DUR);
+ *status = data;
+
+ return comres;
+}
+
+static int bma2x2_set_low_g_threshold(struct i2c_client *client, unsigned char
+ threshold)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_LOWG_THRES__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_LOWG_THRES, threshold);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_LOWG_THRES__REG, &data);
+
+ return comres;
+}
+
+static int bma2x2_get_low_g_threshold(struct i2c_client *client, unsigned char
+ *status)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_LOW_THRES_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_LOWG_THRES);
+ *status = data;
+
+ return comres;
+}
+
+static int bma2x2_set_high_g_duration(struct i2c_client *client, unsigned char
+ duration)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_HIGHG_DUR__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_HIGHG_DUR, duration);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_HIGHG_DUR__REG, &data);
+
+ return comres;
+}
+
+static int bma2x2_get_high_g_duration(struct i2c_client *client, unsigned char
+ *status)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_HIGH_DURN_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_HIGHG_DUR);
+ *status = data;
+
+ return comres;
+}
+
+static int bma2x2_set_high_g_threshold(struct i2c_client *client, unsigned char
+ threshold)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_HIGHG_THRES__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_HIGHG_THRES, threshold);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_HIGHG_THRES__REG,
+ &data);
+
+ return comres;
+}
+
+static int bma2x2_get_high_g_threshold(struct i2c_client *client, unsigned char
+ *status)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_HIGH_THRES_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_HIGHG_THRES);
+ *status = data;
+
+ return comres;
+}
+
+
+static int bma2x2_set_tap_duration(struct i2c_client *client, unsigned char
+ duration)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_DUR__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_TAP_DUR, duration);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_TAP_DUR__REG, &data);
+
+ return comres;
+}
+
+static int bma2x2_get_tap_duration(struct i2c_client *client, unsigned char
+ *status)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_PARAM_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_TAP_DUR);
+ *status = data;
+
+ return comres;
+}
+
+static int bma2x2_set_tap_shock(struct i2c_client *client, unsigned char setval)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_SHOCK_DURN__REG,
+ &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_TAP_SHOCK_DURN, setval);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_TAP_SHOCK_DURN__REG,
+ &data);
+
+ return comres;
+}
+
+static int bma2x2_get_tap_shock(struct i2c_client *client, unsigned char
+ *status)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_PARAM_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_TAP_SHOCK_DURN);
+ *status = data;
+
+ return comres;
+}
+
+static int bma2x2_set_tap_quiet(struct i2c_client *client, unsigned char
+ duration)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_QUIET_DURN__REG,
+ &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_TAP_QUIET_DURN, duration);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_TAP_QUIET_DURN__REG,
+ &data);
+
+ return comres;
+}
+
+static int bma2x2_get_tap_quiet(struct i2c_client *client, unsigned char
+ *status)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_PARAM_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_TAP_QUIET_DURN);
+ *status = data;
+
+ return comres;
+}
+
+static int bma2x2_set_tap_threshold(struct i2c_client *client, unsigned char
+ threshold)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_THRES__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_TAP_THRES, threshold);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_TAP_THRES__REG, &data);
+
+ return comres;
+}
+
+static int bma2x2_get_tap_threshold(struct i2c_client *client, unsigned char
+ *status)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_THRES_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_TAP_THRES);
+ *status = data;
+
+ return comres;
+}
+
+static int bma2x2_set_tap_samp(struct i2c_client *client, unsigned char samp)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_SAMPLES__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_TAP_SAMPLES, samp);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_TAP_SAMPLES__REG,
+ &data);
+
+ return comres;
+}
+
+static int bma2x2_get_tap_samp(struct i2c_client *client, unsigned char *status)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_THRES_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_TAP_SAMPLES);
+ *status = data;
+
+ return comres;
+}
+
+static int bma2x2_set_orient_mode(struct i2c_client *client, unsigned char mode)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_ORIENT_MODE__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_ORIENT_MODE, mode);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_ORIENT_MODE__REG,
+ &data);
+
+ return comres;
+}
+
+static int bma2x2_get_orient_mode(struct i2c_client *client, unsigned char
+ *status)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_ORIENT_PARAM_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_ORIENT_MODE);
+ *status = data;
+
+ return comres;
+}
+
+static int bma2x2_set_orient_blocking(struct i2c_client *client, unsigned char
+ samp)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_ORIENT_BLOCK__REG,
+ &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_ORIENT_BLOCK, samp);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_ORIENT_BLOCK__REG,
+ &data);
+
+ return comres;
+}
+
+static int bma2x2_get_orient_blocking(struct i2c_client *client, unsigned char
+ *status)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_ORIENT_PARAM_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_ORIENT_BLOCK);
+ *status = data;
+
+ return comres;
+}
+
+static int bma2x2_set_orient_hyst(struct i2c_client *client, unsigned char
+ orienthyst)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_ORIENT_HYST__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_ORIENT_HYST, orienthyst);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_ORIENT_HYST__REG,
+ &data);
+
+ return comres;
+}
+
+static int bma2x2_get_orient_hyst(struct i2c_client *client, unsigned char
+ *status)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_ORIENT_PARAM_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_ORIENT_HYST);
+ *status = data;
+
+ return comres;
+}
+static int bma2x2_set_theta_blocking(struct i2c_client *client, unsigned char
+ thetablk)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_THETA_BLOCK__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_THETA_BLOCK, thetablk);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_THETA_BLOCK__REG,
+ &data);
+
+ return comres;
+}
+
+static int bma2x2_get_theta_blocking(struct i2c_client *client, unsigned char
+ *status)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_THETA_BLOCK_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_THETA_BLOCK);
+ *status = data;
+
+ return comres;
+}
+
+static int bma2x2_set_theta_flat(struct i2c_client *client, unsigned char
+ thetaflat)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_THETA_FLAT__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_THETA_FLAT, thetaflat);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_THETA_FLAT__REG, &data);
+
+ return comres;
+}
+
+static int bma2x2_get_theta_flat(struct i2c_client *client, unsigned char
+ *status)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_THETA_FLAT_REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_THETA_FLAT);
+ *status = data;
+
+ return comres;
+}
+
+static int bma2x2_set_flat_hold_time(struct i2c_client *client, unsigned char
+ holdtime)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_FLAT_HOLD_TIME__REG,
+ &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_FLAT_HOLD_TIME, holdtime);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_FLAT_HOLD_TIME__REG,
+ &data);
+
+ return comres;
+}
+
+static int bma2x2_get_flat_hold_time(struct i2c_client *client, unsigned char
+ *holdtime)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_FLAT_HOLD_TIME_REG,
+ &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_FLAT_HOLD_TIME);
+ *holdtime = data;
+
+ return comres;
+}
+
+/*!
+ * brief: bma2x2 switch from normal to suspend mode
+ * @param[i] bma2x2
+ * @param[i] data1, write to PMU_LPW
+ * @param[i] data2, write to PMU_LOW_NOSIE
+ *
+ * @return zero success, none-zero failed
+ */
+static int bma2x2_normal_to_suspend(struct bma2x2_data *bma2x2,
+ unsigned char data1, unsigned char data2)
+{
+ unsigned char current_fifo_mode;
+ unsigned char current_op_mode;
+
+ if (bma2x2 == NULL)
+ return -EINVAL;
+ /* get current op mode from mode register */
+ if (bma2x2_get_mode(bma2x2->bma2x2_client, &current_op_mode) < 0)
+ return -EIO;
+ /* only aimed at operatiom mode chang from normal/lpw1 mode
+ * to suspend state.
+ */
+ if (current_op_mode == BMA2X2_MODE_NORMAL ||
+ current_op_mode == BMA2X2_MODE_LOWPOWER1) {
+ /* get current fifo mode from fifo config register */
+ if (bma2x2_get_fifo_mode(bma2x2->bma2x2_client,
+ &current_fifo_mode) < 0)
+ return -EIO;
+
+ bma2x2_smbus_write_byte(bma2x2->bma2x2_client,
+ BMA2X2_LOW_NOISE_CTRL_REG, &data2);
+ bma2x2_smbus_write_byte(bma2x2->bma2x2_client,
+ BMA2X2_MODE_CTRL_REG, &data1);
+ bma2x2_smbus_write_byte(bma2x2->bma2x2_client,
+ BMA2X2_FIFO_MODE__REG, &current_fifo_mode);
+ WAIT_DEVICE_READY();
+
+ return 0;
+ }
+
+ bma2x2_smbus_write_byte(bma2x2->bma2x2_client,
+ BMA2X2_LOW_NOISE_CTRL_REG, &data2);
+ bma2x2_smbus_write_byte(bma2x2->bma2x2_client,
+ BMA2X2_MODE_CTRL_REG, &data1);
+ WAIT_DEVICE_READY();
+
+ return 0;
+}
+
+static int bma2x2_set_mode(struct i2c_client *client, unsigned char mode)
+{
+ int comres = 0;
+ unsigned char data1, data2;
+ int ret = 0;
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ mutex_lock(&bma2x2->mode_mutex);
+ if (BMA2X2_MODE_SUSPEND == mode) {
+ if (bma2x2->ref_count > 0) {
+ bma2x2->ref_count--;
+ if (0 < bma2x2->ref_count) {
+ mutex_unlock(&bma2x2->mode_mutex);
+ return 0;
+ }
+ }
+ } else {
+ bma2x2->ref_count++;
+ if (1 < bma2x2->ref_count) {
+ mutex_unlock(&bma2x2->mode_mutex);
+ return 0;
+ }
+ }
+ mutex_unlock(&bma2x2->mode_mutex);
+
+ if (mode < 6) {
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_MODE_CTRL_REG,
+ &data1);
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_LOW_NOISE_CTRL_REG,
+ &data2);
+ switch (mode) {
+ case BMA2X2_MODE_NORMAL:
+ data1 = BMA2X2_SET_BITSLICE(data1,
+ BMA2X2_MODE_CTRL, 0);
+ data2 = BMA2X2_SET_BITSLICE(data2,
+ BMA2X2_LOW_POWER_MODE, 0);
+ bma2x2_smbus_write_byte(client,
+ BMA2X2_MODE_CTRL_REG, &data1);
+ WAIT_DEVICE_READY();
+ bma2x2_smbus_write_byte(client,
+ BMA2X2_LOW_NOISE_CTRL_REG, &data2);
+ break;
+ case BMA2X2_MODE_LOWPOWER1:
+ data1 = BMA2X2_SET_BITSLICE(data1,
+ BMA2X2_MODE_CTRL, 2);
+ data2 = BMA2X2_SET_BITSLICE(data2,
+ BMA2X2_LOW_POWER_MODE, 0);
+ bma2x2_smbus_write_byte(client,
+ BMA2X2_MODE_CTRL_REG, &data1);
+ WAIT_DEVICE_READY();
+ bma2x2_smbus_write_byte(client,
+ BMA2X2_LOW_NOISE_CTRL_REG, &data2);
+ break;
+ case BMA2X2_MODE_SUSPEND:
+ data1 = BMA2X2_SET_BITSLICE(data1,
+ BMA2X2_MODE_CTRL, 4);
+ data2 = BMA2X2_SET_BITSLICE(data2,
+ BMA2X2_LOW_POWER_MODE, 0);
+ /*aimed at anomaly resolution when switch to suspend*/
+ ret = bma2x2_normal_to_suspend(bma2x2, data1, data2);
+ if (ret < 0)
+ dev_err(&client->dev,
+ "Error switching to suspend");
+ break;
+ case BMA2X2_MODE_DEEP_SUSPEND:
+ data1 = BMA2X2_SET_BITSLICE(data1,
+ BMA2X2_MODE_CTRL, 1);
+ data2 = BMA2X2_SET_BITSLICE(data2,
+ BMA2X2_LOW_POWER_MODE, 1);
+ bma2x2_smbus_write_byte(client,
+ BMA2X2_MODE_CTRL_REG, &data1);
+ WAIT_DEVICE_READY();
+ bma2x2_smbus_write_byte(client,
+ BMA2X2_LOW_NOISE_CTRL_REG, &data2);
+ break;
+ case BMA2X2_MODE_LOWPOWER2:
+ data1 = BMA2X2_SET_BITSLICE(data1,
+ BMA2X2_MODE_CTRL, 2);
+ data2 = BMA2X2_SET_BITSLICE(data2,
+ BMA2X2_LOW_POWER_MODE, 1);
+ bma2x2_smbus_write_byte(client,
+ BMA2X2_MODE_CTRL_REG, &data1);
+ WAIT_DEVICE_READY();
+ bma2x2_smbus_write_byte(client,
+ BMA2X2_LOW_NOISE_CTRL_REG, &data2);
+ break;
+ case BMA2X2_MODE_STANDBY:
+ data1 = BMA2X2_SET_BITSLICE(data1,
+ BMA2X2_MODE_CTRL, 4);
+ data2 = BMA2X2_SET_BITSLICE(data2,
+ BMA2X2_LOW_POWER_MODE, 1);
+ bma2x2_smbus_write_byte(client,
+ BMA2X2_LOW_NOISE_CTRL_REG, &data2);
+ WAIT_DEVICE_READY();
+ bma2x2_smbus_write_byte(client,
+ BMA2X2_MODE_CTRL_REG, &data1);
+ break;
+ }
+ } else {
+ comres = -1;
+ }
+
+ return comres;
+}
+
+
+static int bma2x2_get_mode(struct i2c_client *client, unsigned char *mode)
+{
+ int comres = 0;
+ unsigned char data1, data2;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_MODE_CTRL_REG, &data1);
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_LOW_NOISE_CTRL_REG,
+ &data2);
+
+ data1 = (data1 & 0xE0) >> 5;
+ data2 = (data2 & 0x40) >> 6;
+
+ if (data2 == 0x00) {
+ switch (data1) {
+ case 0:
+ *mode = BMA2X2_MODE_NORMAL;
+ break;
+ case 1:
+ *mode = BMA2X2_MODE_DEEP_SUSPEND;
+ break;
+ case 2:
+ *mode = BMA2X2_MODE_LOWPOWER1;
+ break;
+ case 4:
+ case 6:
+ *mode = BMA2X2_MODE_SUSPEND;
+ break;
+ default:
+ comres = -ENODEV;
+ break;
+ }
+ } else if (data2 == 0x01) {
+ switch (data1) {
+ case 0:
+ case 1:
+ case 6:
+ *mode = BMA2X2_MODE_DEEP_SUSPEND;
+ break;
+ case 2:
+ *mode = BMA2X2_MODE_LOWPOWER2;
+ break;
+ case 4:
+ *mode = BMA2X2_MODE_STANDBY;
+ break;
+ default:
+ comres = -ENODEV;
+ break;
+ }
+ } else {
+ comres = -ENODEV;
+ }
+
+ return comres;
+}
+
+static int bma2x2_set_range(struct i2c_client *client, unsigned char Range)
+{
+ int comres = 0;
+ unsigned char data1;
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if ((Range == 3) || (Range == 5) || (Range == 8) || (Range == 12)) {
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_RANGE_SEL_REG,
+ &data1);
+ switch (Range) {
+ case BMA2X2_RANGE_2G:
+ data1 = BMA2X2_SET_BITSLICE(data1,
+ BMA2X2_RANGE_SEL, 3);
+ break;
+ case BMA2X2_RANGE_4G:
+ data1 = BMA2X2_SET_BITSLICE(data1,
+ BMA2X2_RANGE_SEL, 5);
+ break;
+ case BMA2X2_RANGE_8G:
+ data1 = BMA2X2_SET_BITSLICE(data1,
+ BMA2X2_RANGE_SEL, 8);
+ break;
+ case BMA2X2_RANGE_16G:
+ data1 = BMA2X2_SET_BITSLICE(data1,
+ BMA2X2_RANGE_SEL, 12);
+ break;
+ default:
+ break;
+ }
+ comres += bma2x2_smbus_write_byte(client, BMA2X2_RANGE_SEL_REG,
+ &data1);
+ bma2x2_get_sensitivity(bma2x2, Range);
+ } else {
+ comres = -1;
+ }
+
+ return comres;
+}
+
+static int bma2x2_get_range(struct i2c_client *client, unsigned char *Range)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_RANGE_SEL__REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_RANGE_SEL);
+ *Range = data;
+
+ return comres;
+}
+
+static int bma2x2_set_watermark_lvl(struct i2c_client *client,
+ unsigned char watermark)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_FIFO_WML_TRIG_RETAIN__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data,
+ BMA2X2_FIFO_WML_TRIG_RETAIN, watermark);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_FIFO_WML_TRIG_RETAIN__REG, &data);
+
+ return comres;
+}
+
+static int bma2x2_set_bandwidth(struct i2c_client *client, unsigned char BW)
+{
+ int comres = 0;
+ unsigned char data;
+ int Bandwidth = 0;
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (BW > 7 && BW < 16) {
+ switch (BW) {
+ case BMA2X2_BW_7_81HZ:
+ Bandwidth = BMA2X2_BW_7_81HZ;
+
+ /* 7.81 Hz 64000 uS */
+ break;
+ case BMA2X2_BW_15_63HZ:
+ Bandwidth = BMA2X2_BW_15_63HZ;
+
+ /* 15.63 Hz 32000 uS */
+ break;
+ case BMA2X2_BW_31_25HZ:
+ Bandwidth = BMA2X2_BW_31_25HZ;
+
+ /* 31.25 Hz 16000 uS */
+ break;
+ case BMA2X2_BW_62_50HZ:
+ Bandwidth = BMA2X2_BW_62_50HZ;
+
+ /* 62.50 Hz 8000 uS */
+ break;
+ case BMA2X2_BW_125HZ:
+ Bandwidth = BMA2X2_BW_125HZ;
+
+ /* 125 Hz 4000 uS */
+ break;
+ case BMA2X2_BW_250HZ:
+ Bandwidth = BMA2X2_BW_250HZ;
+
+ /* 250 Hz 2000 uS */
+ break;
+ case BMA2X2_BW_500HZ:
+ Bandwidth = BMA2X2_BW_500HZ;
+
+ /* 500 Hz 1000 uS */
+ break;
+ case BMA2X2_BW_1000HZ:
+ Bandwidth = BMA2X2_BW_1000HZ;
+
+ /* 1000 Hz 500 uS */
+ break;
+ default:
+ break;
+ }
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_BANDWIDTH__REG,
+ &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_BANDWIDTH, Bandwidth);
+ comres += bma2x2_smbus_write_byte(client, BMA2X2_BANDWIDTH__REG,
+ &data);
+ if (comres == 0)
+ bma2x2->bandwidth = Bandwidth;
+ } else {
+ comres = -1;
+ }
+
+ return comres;
+}
+
+static int bma2x2_get_bandwidth(struct i2c_client *client, unsigned char *BW)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_BANDWIDTH__REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_BANDWIDTH);
+ *BW = data;
+
+ return comres;
+}
+
+static int bma2x2_get_sleep_duration(struct i2c_client *client, unsigned char
+ *sleep_dur)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_SLEEP_DUR__REG, &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_SLEEP_DUR);
+ *sleep_dur = data;
+
+ return comres;
+}
+
+static int bma2x2_set_sleep_duration(struct i2c_client *client, unsigned char
+ sleep_dur)
+{
+ int comres = 0;
+ unsigned char data;
+ int sleep_duration = 0;
+
+ if (sleep_dur > 4 && sleep_dur < 16) {
+ switch (sleep_dur) {
+ case BMA2X2_SLEEP_DUR_0_5MS:
+ sleep_duration = BMA2X2_SLEEP_DUR_0_5MS;
+
+ /* 0.5 MS */
+ break;
+ case BMA2X2_SLEEP_DUR_1MS:
+ sleep_duration = BMA2X2_SLEEP_DUR_1MS;
+
+ /* 1 MS */
+ break;
+ case BMA2X2_SLEEP_DUR_2MS:
+ sleep_duration = BMA2X2_SLEEP_DUR_2MS;
+
+ /* 2 MS */
+ break;
+ case BMA2X2_SLEEP_DUR_4MS:
+ sleep_duration = BMA2X2_SLEEP_DUR_4MS;
+
+ /* 4 MS */
+ break;
+ case BMA2X2_SLEEP_DUR_6MS:
+ sleep_duration = BMA2X2_SLEEP_DUR_6MS;
+
+ /* 6 MS */
+ break;
+ case BMA2X2_SLEEP_DUR_10MS:
+ sleep_duration = BMA2X2_SLEEP_DUR_10MS;
+
+ /* 10 MS */
+ break;
+ case BMA2X2_SLEEP_DUR_25MS:
+ sleep_duration = BMA2X2_SLEEP_DUR_25MS;
+
+ /* 25 MS */
+ break;
+ case BMA2X2_SLEEP_DUR_50MS:
+ sleep_duration = BMA2X2_SLEEP_DUR_50MS;
+
+ /* 50 MS */
+ break;
+ case BMA2X2_SLEEP_DUR_100MS:
+ sleep_duration = BMA2X2_SLEEP_DUR_100MS;
+
+ /* 100 MS */
+ break;
+ case BMA2X2_SLEEP_DUR_500MS:
+ sleep_duration = BMA2X2_SLEEP_DUR_500MS;
+
+ /* 500 MS */
+ break;
+ case BMA2X2_SLEEP_DUR_1S:
+ sleep_duration = BMA2X2_SLEEP_DUR_1S;
+
+ /* 1 SECS */
+ break;
+ default:
+ break;
+ }
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_SLEEP_DUR__REG,
+ &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_SLEEP_DUR,
+ sleep_duration);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_SLEEP_DUR__REG,
+ &data);
+ } else {
+ comres = -1;
+ }
+
+ return comres;
+}
+
+static int bma2x2_get_fifo_mode(struct i2c_client *client, unsigned char
+ *fifo_mode)
+{
+ int comres;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_FIFO_MODE__REG, &data);
+ *fifo_mode = BMA2X2_GET_BITSLICE(data, BMA2X2_FIFO_MODE);
+
+ return comres;
+}
+
+static int bma2x2_set_fifo_mode(struct i2c_client *client, unsigned char
+ fifo_mode)
+{
+ unsigned char data;
+ int comres = 0;
+
+ if (fifo_mode < 4) {
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_FIFO_MODE__REG,
+ &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_FIFO_MODE, fifo_mode);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_FIFO_MODE__REG,
+ &data);
+ } else {
+ comres = -1;
+ }
+
+ return comres;
+}
+
+static int bma2x2_get_fifo_trig(struct i2c_client *client, unsigned char
+ *fifo_trig)
+{
+ int comres;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_FIFO_TRIGGER_ACTION__REG, &data);
+ *fifo_trig = BMA2X2_GET_BITSLICE(data, BMA2X2_FIFO_TRIGGER_ACTION);
+
+ return comres;
+}
+
+static int bma2x2_set_fifo_trig(struct i2c_client *client, unsigned char
+ fifo_trig)
+{
+ unsigned char data;
+ int comres = 0;
+
+ if (fifo_trig < 4) {
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_FIFO_TRIGGER_ACTION__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_FIFO_TRIGGER_ACTION,
+ fifo_trig);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_FIFO_TRIGGER_ACTION__REG, &data);
+ } else {
+ comres = -1;
+ }
+
+ return comres;
+}
+
+static int bma2x2_get_fifo_trig_src(struct i2c_client *client, unsigned char
+ *trig_src)
+{
+ int comres;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_FIFO_TRIGGER_SOURCE__REG, &data);
+ *trig_src = BMA2X2_GET_BITSLICE(data, BMA2X2_FIFO_TRIGGER_SOURCE);
+
+ return comres;
+}
+
+static int bma2x2_set_fifo_trig_src(struct i2c_client *client, unsigned char
+ trig_src)
+{
+ unsigned char data;
+ int comres = 0;
+
+ if (trig_src < 4) {
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_FIFO_TRIGGER_SOURCE__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_FIFO_TRIGGER_SOURCE,
+ trig_src);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_FIFO_TRIGGER_SOURCE__REG, &data);
+ } else {
+ comres = -1;
+ }
+
+ return comres;
+}
+
+static int bma2x2_get_fifo_framecount(struct i2c_client *client, unsigned char
+ *framecount)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_FIFO_FRAME_COUNTER_S__REG, &data);
+ *framecount = BMA2X2_GET_BITSLICE(data, BMA2X2_FIFO_FRAME_COUNTER_S);
+
+ return comres;
+}
+
+static int bma2x2_get_fifo_data_sel(struct i2c_client *client, unsigned char
+ *data_sel)
+{
+ int comres;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_FIFO_DATA_SELECT__REG, &data);
+ *data_sel = BMA2X2_GET_BITSLICE(data, BMA2X2_FIFO_DATA_SELECT);
+
+ return comres;
+}
+
+static int bma2x2_set_fifo_data_sel(struct i2c_client *client, unsigned char
+ data_sel)
+{
+ unsigned char data;
+ int comres = 0;
+
+ if (data_sel < 4) {
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_FIFO_DATA_SELECT__REG,
+ &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_FIFO_DATA_SELECT,
+ data_sel);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_FIFO_DATA_SELECT__REG,
+ &data);
+ } else {
+ comres = -1;
+ }
+
+ return comres;
+}
+
+
+static int bma2x2_get_offset_target(struct i2c_client *client, unsigned char
+ channel, unsigned char *offset)
+{
+ unsigned char data;
+ int comres = 0;
+
+ switch (channel) {
+ case BMA2X2_CUT_OFF:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_COMP_CUTOFF__REG, &data);
+ *offset = BMA2X2_GET_BITSLICE(data, BMA2X2_COMP_CUTOFF);
+ break;
+ case BMA2X2_OFFSET_TRIGGER_X:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_COMP_TARGET_OFFSET_X__REG, &data);
+ *offset = BMA2X2_GET_BITSLICE(data,
+ BMA2X2_COMP_TARGET_OFFSET_X);
+ break;
+ case BMA2X2_OFFSET_TRIGGER_Y:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_COMP_TARGET_OFFSET_Y__REG, &data);
+ *offset = BMA2X2_GET_BITSLICE(data,
+ BMA2X2_COMP_TARGET_OFFSET_Y);
+ break;
+ case BMA2X2_OFFSET_TRIGGER_Z:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_COMP_TARGET_OFFSET_Z__REG, &data);
+ *offset = BMA2X2_GET_BITSLICE(data,
+ BMA2X2_COMP_TARGET_OFFSET_Z);
+ break;
+ default:
+ comres = -1;
+ break;
+ }
+
+ return comres;
+}
+
+static int bma2x2_set_offset_target(struct i2c_client *client, unsigned char
+ channel, unsigned char offset)
+{
+ unsigned char data;
+ int comres = 0;
+
+ switch (channel) {
+ case BMA2X2_CUT_OFF:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_COMP_CUTOFF__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_COMP_CUTOFF,
+ offset);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_COMP_CUTOFF__REG, &data);
+ break;
+ case BMA2X2_OFFSET_TRIGGER_X:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_COMP_TARGET_OFFSET_X__REG,
+ &data);
+ data = BMA2X2_SET_BITSLICE(data,
+ BMA2X2_COMP_TARGET_OFFSET_X,
+ offset);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_COMP_TARGET_OFFSET_X__REG,
+ &data);
+ break;
+ case BMA2X2_OFFSET_TRIGGER_Y:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_COMP_TARGET_OFFSET_Y__REG,
+ &data);
+ data = BMA2X2_SET_BITSLICE(data,
+ BMA2X2_COMP_TARGET_OFFSET_Y,
+ offset);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_COMP_TARGET_OFFSET_Y__REG,
+ &data);
+ break;
+ case BMA2X2_OFFSET_TRIGGER_Z:
+ comres = bma2x2_smbus_read_byte(client,
+ BMA2X2_COMP_TARGET_OFFSET_Z__REG,
+ &data);
+ data = BMA2X2_SET_BITSLICE(data,
+ BMA2X2_COMP_TARGET_OFFSET_Z,
+ offset);
+ comres = bma2x2_smbus_write_byte(client,
+ BMA2X2_COMP_TARGET_OFFSET_Z__REG,
+ &data);
+ break;
+ default:
+ comres = -1;
+ break;
+ }
+
+ return comres;
+}
+
+static int bma2x2_get_cal_ready(struct i2c_client *client,
+ unsigned char *calrdy)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_FAST_CAL_RDY_S__REG,
+ &data);
+ data = BMA2X2_GET_BITSLICE(data, BMA2X2_FAST_CAL_RDY_S);
+ *calrdy = data;
+
+ return comres;
+}
+
+static int bma2x2_set_cal_trigger(struct i2c_client *client, unsigned char
+ caltrigger)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_CAL_TRIGGER__REG, &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_CAL_TRIGGER, caltrigger);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_CAL_TRIGGER__REG,
+ &data);
+
+ return comres;
+}
+
+static int bma2x2_write_reg(struct i2c_client *client, unsigned char addr,
+ unsigned char *data)
+{
+ int comres = 0;
+
+ comres = bma2x2_smbus_write_byte(client, addr, data);
+
+ return comres;
+}
+
+
+static int bma2x2_set_offset_x(struct i2c_client *client, unsigned char
+ offsetfilt)
+{
+ int comres = 0;
+ unsigned char data;
+
+ data = offsetfilt;
+
+#ifdef CONFIG_SENSORS_BMI058
+ comres = bma2x2_smbus_write_byte(client, BMI058_OFFSET_X_AXIS_REG,
+ &data);
+#else
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_OFFSET_X_AXIS_REG,
+ &data);
+#endif
+
+ return comres;
+}
+
+
+static int bma2x2_get_offset_x(struct i2c_client *client, unsigned char
+ *offsetfilt)
+{
+ int comres = 0;
+ unsigned char data;
+
+#ifdef CONFIG_SENSORS_BMI058
+ comres = bma2x2_smbus_read_byte(client, BMI058_OFFSET_X_AXIS_REG,
+ &data);
+#else
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_OFFSET_X_AXIS_REG,
+ &data);
+#endif
+ *offsetfilt = data;
+
+ return comres;
+}
+
+static int bma2x2_set_offset_y(struct i2c_client *client, unsigned char
+ offsetfilt)
+{
+ int comres = 0;
+ unsigned char data;
+
+ data = offsetfilt;
+
+#ifdef CONFIG_SENSORS_BMI058
+ comres = bma2x2_smbus_write_byte(client, BMI058_OFFSET_Y_AXIS_REG,
+ &data);
+#else
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_OFFSET_Y_AXIS_REG,
+ &data);
+#endif
+ return comres;
+}
+
+static int bma2x2_get_offset_y(struct i2c_client *client, unsigned char
+ *offsetfilt)
+{
+ int comres = 0;
+ unsigned char data;
+
+#ifdef CONFIG_SENSORS_BMI058
+ comres = bma2x2_smbus_read_byte(client, BMI058_OFFSET_Y_AXIS_REG,
+ &data);
+#else
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_OFFSET_Y_AXIS_REG,
+ &data);
+#endif
+ *offsetfilt = data;
+
+ return comres;
+}
+
+static int bma2x2_set_offset_z(struct i2c_client *client, unsigned char
+ offsetfilt)
+{
+ int comres = 0;
+ unsigned char data;
+
+ data = offsetfilt;
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_OFFSET_Z_AXIS_REG,
+ &data);
+
+ return comres;
+}
+
+static int bma2x2_get_offset_z(struct i2c_client *client, unsigned char
+ *offsetfilt)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_OFFSET_Z_AXIS_REG,
+ &data);
+ *offsetfilt = data;
+
+ return comres;
+}
+
+
+static int bma2x2_set_selftest_st(struct i2c_client *client, unsigned char
+ selftest)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_EN_SELF_TEST__REG,
+ &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_SELF_TEST, selftest);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_EN_SELF_TEST__REG,
+ &data);
+
+ return comres;
+}
+
+static int bma2x2_set_selftest_stn(struct i2c_client *client, unsigned char stn)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_NEG_SELF_TEST__REG,
+ &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_NEG_SELF_TEST, stn);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_NEG_SELF_TEST__REG,
+ &data);
+
+ return comres;
+}
+
+static int bma2x2_set_selftest_amp(struct i2c_client *client, unsigned char amp)
+{
+ int comres = 0;
+ unsigned char data;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_SELF_TEST_AMP__REG,
+ &data);
+ data = BMA2X2_SET_BITSLICE(data, BMA2X2_SELF_TEST_AMP, amp);
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_SELF_TEST_AMP__REG,
+ &data);
+
+ return comres;
+}
+
+static int bma2x2_read_accel_x(struct i2c_client *client,
+ signed char sensor_type, short *a_x)
+{
+ int comres = 0;
+ unsigned char data[2];
+
+ switch (sensor_type) {
+ case 0:
+ comres = bma2x2_smbus_read_byte_block(client,
+ BMA2X2_ACC_X12_LSB__REG, data, 2);
+ *a_x = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_X12_LSB)|
+ (BMA2X2_GET_BITSLICE(data[1],
+ BMA2X2_ACC_X_MSB)<<(BMA2X2_ACC_X12_LSB__LEN));
+ *a_x = *a_x << (sizeof(short)*8-(BMA2X2_ACC_X12_LSB__LEN
+ + BMA2X2_ACC_X_MSB__LEN));
+ *a_x = *a_x >> (sizeof(short)*8-(BMA2X2_ACC_X12_LSB__LEN
+ + BMA2X2_ACC_X_MSB__LEN));
+ break;
+ case 1:
+ comres = bma2x2_smbus_read_byte_block(client,
+ BMA2X2_ACC_X10_LSB__REG, data, 2);
+ *a_x = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_X10_LSB)|
+ (BMA2X2_GET_BITSLICE(data[1],
+ BMA2X2_ACC_X_MSB)<<(BMA2X2_ACC_X10_LSB__LEN));
+ *a_x = *a_x << (sizeof(short)*8-(BMA2X2_ACC_X10_LSB__LEN
+ + BMA2X2_ACC_X_MSB__LEN));
+ *a_x = *a_x >> (sizeof(short)*8-(BMA2X2_ACC_X10_LSB__LEN
+ + BMA2X2_ACC_X_MSB__LEN));
+ break;
+ case 2:
+ comres = bma2x2_smbus_read_byte_block(client,
+ BMA2X2_ACC_X8_LSB__REG, data, 2);
+ *a_x = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_X8_LSB)|
+ (BMA2X2_GET_BITSLICE(data[1],
+ BMA2X2_ACC_X_MSB)<<(BMA2X2_ACC_X8_LSB__LEN));
+ *a_x = *a_x << (sizeof(short)*8-(BMA2X2_ACC_X8_LSB__LEN
+ + BMA2X2_ACC_X_MSB__LEN));
+ *a_x = *a_x >> (sizeof(short)*8-(BMA2X2_ACC_X8_LSB__LEN
+ + BMA2X2_ACC_X_MSB__LEN));
+ break;
+ case 3:
+ comres = bma2x2_smbus_read_byte_block(client,
+ BMA2X2_ACC_X14_LSB__REG, data, 2);
+ *a_x = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_X14_LSB)|
+ (BMA2X2_GET_BITSLICE(data[1],
+ BMA2X2_ACC_X_MSB)<<(BMA2X2_ACC_X14_LSB__LEN));
+ *a_x = *a_x << (sizeof(short)*8-(BMA2X2_ACC_X14_LSB__LEN
+ + BMA2X2_ACC_X_MSB__LEN));
+ *a_x = *a_x >> (sizeof(short)*8-(BMA2X2_ACC_X14_LSB__LEN
+ + BMA2X2_ACC_X_MSB__LEN));
+ break;
+ default:
+ break;
+ }
+
+ return comres;
+}
+
+static int bma2x2_soft_reset(struct i2c_client *client)
+{
+ int comres = 0;
+ unsigned char data = BMA2X2_EN_SOFT_RESET_VALUE;
+
+ comres = bma2x2_smbus_write_byte(client, BMA2X2_EN_SOFT_RESET__REG,
+ &data);
+
+ return comres;
+}
+
+static int bma2x2_read_accel_y(struct i2c_client *client,
+ signed char sensor_type, short *a_y)
+{
+ int comres = 0;
+ unsigned char data[2];
+
+ switch (sensor_type) {
+ case 0:
+ comres = bma2x2_smbus_read_byte_block(client,
+ BMA2X2_ACC_Y12_LSB__REG, data, 2);
+ *a_y = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_Y12_LSB)|
+ (BMA2X2_GET_BITSLICE(data[1],
+ BMA2X2_ACC_Y_MSB)<<(BMA2X2_ACC_Y12_LSB__LEN));
+ *a_y = *a_y << (sizeof(short)*8-(BMA2X2_ACC_Y12_LSB__LEN
+ + BMA2X2_ACC_Y_MSB__LEN));
+ *a_y = *a_y >> (sizeof(short)*8-(BMA2X2_ACC_Y12_LSB__LEN
+ + BMA2X2_ACC_Y_MSB__LEN));
+ break;
+ case 1:
+ comres = bma2x2_smbus_read_byte_block(client,
+ BMA2X2_ACC_Y10_LSB__REG, data, 2);
+ *a_y = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_Y10_LSB)|
+ (BMA2X2_GET_BITSLICE(data[1],
+ BMA2X2_ACC_Y_MSB)<<(BMA2X2_ACC_Y10_LSB__LEN));
+ *a_y = *a_y << (sizeof(short)*8-(BMA2X2_ACC_Y10_LSB__LEN
+ + BMA2X2_ACC_Y_MSB__LEN));
+ *a_y = *a_y >> (sizeof(short)*8-(BMA2X2_ACC_Y10_LSB__LEN
+ + BMA2X2_ACC_Y_MSB__LEN));
+ break;
+ case 2:
+ comres = bma2x2_smbus_read_byte_block(client,
+ BMA2X2_ACC_Y8_LSB__REG, data, 2);
+ *a_y = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_Y8_LSB)|
+ (BMA2X2_GET_BITSLICE(data[1],
+ BMA2X2_ACC_Y_MSB)<<(BMA2X2_ACC_Y8_LSB__LEN));
+ *a_y = *a_y << (sizeof(short)*8-(BMA2X2_ACC_Y8_LSB__LEN
+ + BMA2X2_ACC_Y_MSB__LEN));
+ *a_y = *a_y >> (sizeof(short)*8-(BMA2X2_ACC_Y8_LSB__LEN
+ + BMA2X2_ACC_Y_MSB__LEN));
+ break;
+ case 3:
+ comres = bma2x2_smbus_read_byte_block(client,
+ BMA2X2_ACC_Y14_LSB__REG, data, 2);
+ *a_y = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_Y14_LSB)|
+ (BMA2X2_GET_BITSLICE(data[1],
+ BMA2X2_ACC_Y_MSB)<<(BMA2X2_ACC_Y14_LSB__LEN));
+ *a_y = *a_y << (sizeof(short)*8-(BMA2X2_ACC_Y14_LSB__LEN
+ + BMA2X2_ACC_Y_MSB__LEN));
+ *a_y = *a_y >> (sizeof(short)*8-(BMA2X2_ACC_Y14_LSB__LEN
+ + BMA2X2_ACC_Y_MSB__LEN));
+ break;
+ default:
+ break;
+ }
+
+ return comres;
+}
+
+static int bma2x2_read_accel_z(struct i2c_client *client,
+ signed char sensor_type, short *a_z)
+{
+ int comres = 0;
+ unsigned char data[2];
+
+ switch (sensor_type) {
+ case 0:
+ comres = bma2x2_smbus_read_byte_block(client,
+ BMA2X2_ACC_Z12_LSB__REG, data, 2);
+ *a_z = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_Z12_LSB)|
+ (BMA2X2_GET_BITSLICE(data[1],
+ BMA2X2_ACC_Z_MSB)<<(BMA2X2_ACC_Z12_LSB__LEN));
+ *a_z = *a_z << (sizeof(short)*8-(BMA2X2_ACC_Z12_LSB__LEN
+ + BMA2X2_ACC_Z_MSB__LEN));
+ *a_z = *a_z >> (sizeof(short)*8-(BMA2X2_ACC_Z12_LSB__LEN
+ + BMA2X2_ACC_Z_MSB__LEN));
+ break;
+ case 1:
+ comres = bma2x2_smbus_read_byte_block(client,
+ BMA2X2_ACC_Z10_LSB__REG, data, 2);
+ *a_z = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_Z10_LSB)|
+ (BMA2X2_GET_BITSLICE(data[1],
+ BMA2X2_ACC_Z_MSB)<<(BMA2X2_ACC_Z10_LSB__LEN));
+ *a_z = *a_z << (sizeof(short)*8-(BMA2X2_ACC_Z10_LSB__LEN
+ + BMA2X2_ACC_Z_MSB__LEN));
+ *a_z = *a_z >> (sizeof(short)*8-(BMA2X2_ACC_Z10_LSB__LEN
+ + BMA2X2_ACC_Z_MSB__LEN));
+ break;
+ case 2:
+ comres = bma2x2_smbus_read_byte_block(client,
+ BMA2X2_ACC_Z8_LSB__REG, data, 2);
+ *a_z = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_Z8_LSB)|
+ (BMA2X2_GET_BITSLICE(data[1],
+ BMA2X2_ACC_Z_MSB)<<(BMA2X2_ACC_Z8_LSB__LEN));
+ *a_z = *a_z << (sizeof(short)*8-(BMA2X2_ACC_Z8_LSB__LEN
+ + BMA2X2_ACC_Z_MSB__LEN));
+ *a_z = *a_z >> (sizeof(short)*8-(BMA2X2_ACC_Z8_LSB__LEN
+ + BMA2X2_ACC_Z_MSB__LEN));
+ break;
+ case 3:
+ comres = bma2x2_smbus_read_byte_block(client,
+ BMA2X2_ACC_Z14_LSB__REG, data, 2);
+ *a_z = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_Z14_LSB)|
+ (BMA2X2_GET_BITSLICE(data[1],
+ BMA2X2_ACC_Z_MSB)<<(BMA2X2_ACC_Z14_LSB__LEN));
+ *a_z = *a_z << (sizeof(short)*8-(BMA2X2_ACC_Z14_LSB__LEN
+ + BMA2X2_ACC_Z_MSB__LEN));
+ *a_z = *a_z >> (sizeof(short)*8-(BMA2X2_ACC_Z14_LSB__LEN
+ + BMA2X2_ACC_Z_MSB__LEN));
+ break;
+ default:
+ break;
+ }
+
+ return comres;
+}
+
+
+static int bma2x2_read_temperature(struct i2c_client *client,
+ signed char *temperature)
+{
+ unsigned char data;
+ int comres = 0;
+
+ comres = bma2x2_smbus_read_byte(client, BMA2X2_TEMPERATURE_REG, &data);
+ *temperature = (signed char)data;
+
+ return comres;
+}
+
+static ssize_t bma2x2_enable_int_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int type, value;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+#ifdef CONFIG_SENSORS_BMI058
+ int i;
+#endif
+
+ if (sscanf(buf, "%3d %3d", &type, &value) != 2)
+ return -EINVAL;
+
+#ifdef CONFIG_SENSORS_BMI058
+ for (i = 0; i < sizeof(int_map) / sizeof(struct interrupt_map_t); i++) {
+ if (int_map[i].x == type) {
+ type = int_map[i].y;
+ break;
+ }
+ if (int_map[i].y == type) {
+ type = int_map[i].x;
+ break;
+ }
+ }
+#endif
+
+ if (bma2x2_set_Int_Enable(bma2x2->bma2x2_client, type, value) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static int bma2x2_update_bandwidth(const struct bma2x2_data *bma2x2)
+{
+ int err = 0;
+ int i;
+ int delay = atomic_read(&bma2x2->delay);
+
+ for (i = ARRAY_SIZE(bma2x2_delay2bw_table) - 1; i > 0; i--) {
+ if (bma2x2_delay2bw_table[i].delay_ms <= delay)
+ break;
+ }
+
+ err = bma2x2_set_bandwidth(bma2x2->bma2x2_client,
+ bma2x2_delay2bw_table[i].bw_config);
+ if (err)
+ dev_err(&bma2x2->bma2x2_client->dev,
+ "Update bandwidth not success,delay=%d err=%d\n",
+ delay, err);
+
+ dev_dbg(&bma2x2->bma2x2_client->dev,
+ "Update bandwidth success,delay=%d config=%u\n",
+ delay, bma2x2_delay2bw_table[i].bw_config);
+ return err;
+}
+
+static int bma2x2_update_delay(struct bma2x2_data *bma2x2, unsigned int delay)
+{
+ int pre_enable = atomic_read(&bma2x2->enable);
+ int err = 0;
+ ktime_t ktime;
+
+ atomic_set(&bma2x2->delay, delay);
+
+ if (!pre_enable)
+ return 0;
+
+ /*
+ * Flush fifo data as ODR is about to change.
+ * Data acquisition and fifo buffering is not disabled during this
+ * configuration changing process, timestamp of sensor
+ * event my not correct. Set sensor to standby state during
+ * configuration update if accurate timestamp is required.
+ */
+ if (atomic_read(&bma2x2->fifo_enabled)) {
+ bma2x2_flush_fifo(bma2x2);
+ err = bma2x2_update_bandwidth(bma2x2);
+ } else if (bma2x2_use_data_polling(bma2x2)) {
+ if (!bma2x2->pdata->use_hrtimer) {
+ if (cancel_delayed_work_sync(&bma2x2->work))
+ queue_delayed_work(bma2x2->data_wq,
+ &bma2x2->work,
+ msecs_to_jiffies(delay));
+ } else {
+ hrtimer_cancel(&bma2x2->accel_timer);
+ ktime = ktime_set(0,
+ atomic_read(&bma2x2->delay) * NSEC_PER_MSEC);
+ hrtimer_start(&bma2x2->accel_timer,
+ ktime,
+ HRTIMER_MODE_REL);
+ }
+ } else if (bma2x2->pdata->int_en && BMA2x2_IS_NEWDATA_INT_ENABLED()) {
+ err = bma2x2_update_bandwidth(bma2x2);
+ } else {
+ dev_err(&bma2x2->bma2x2_client->dev,
+ "Incorrect state! enable=%d, fifoEnable=%d, delay=%d, latency=%d\n",
+ pre_enable, atomic_read(&bma2x2->fifo_enabled),
+ delay, bma2x2->max_latency_ms);
+ }
+ return err;
+}
+
+#if defined(BMA2X2_ENABLE_INT1)
+static int bma2x2_sel_int1_pad(const struct bma2x2_data *data)
+{
+ struct i2c_client *client = data->bma2x2_client;
+ int err = 0;
+
+ /* maps interrupt to INT1 pin */
+ err |= bma2x2_set_int1_pad_sel(client, PAD_LOWG);
+ err |= bma2x2_set_int1_pad_sel(client, PAD_HIGHG);
+ err |= bma2x2_set_int1_pad_sel(client, PAD_SLOP);
+ err |= bma2x2_set_int1_pad_sel(client, PAD_DOUBLE_TAP);
+ err |= bma2x2_set_int1_pad_sel(client, PAD_SINGLE_TAP);
+ err |= bma2x2_set_int1_pad_sel(client, PAD_ORIENT);
+ err |= bma2x2_set_int1_pad_sel(client, PAD_FLAT);
+ err |= bma2x2_set_int1_pad_sel(client, PAD_SLOW_NO_MOTION);
+ err |= bma2x2_set_newdata(client, BMA2X2_INT1_NDATA, 1);
+ err |= bma2x2_set_newdata(client, BMA2X2_INT2_NDATA, 0);
+ err |= bma2x2_set_fwm_int_pad_sel(client, BMA2X2_INT1_FWM, 1);
+ err |= bma2x2_set_fwm_int_pad_sel(client, BMA2X2_INT2_FWM, 0);
+ err |= bma2x2_set_ffull_int_pad_sel(client, BMA2X2_INT1_FFULL, 1);
+ err |= bma2x2_set_ffull_int_pad_sel(client, BMA2X2_INT2_FFULL, 0);
+
+ if (err) {
+ dev_err(&client->dev, "select pad int1 error, ret=%d\n", err);
+ err = -EIO;
+ }
+ return err;
+}
+#else
+static int bma2x2_sel_int1_pad(const struct bma2x2_data *data)
+{
+ return -EPERM;
+}
+#endif /* BMA2X2_ENABLE_INT1 */
+
+#if defined(BMA2X2_ENABLE_INT2)
+static int bma2x2_sel_int2_pad(const struct bma2x2_data *data)
+{
+ struct i2c_client *client = data->bma2x2_client;
+ int err = 0;
+
+ /* maps interrupt to INT2 pin */
+ err |= bma2x2_set_int2_pad_sel(client, PAD_LOWG);
+ err |= bma2x2_set_int2_pad_sel(client, PAD_HIGHG);
+ err |= bma2x2_set_int2_pad_sel(client, PAD_SLOP);
+ err |= bma2x2_set_int2_pad_sel(client, PAD_DOUBLE_TAP);
+ err |= bma2x2_set_int2_pad_sel(client, PAD_SINGLE_TAP);
+ err |= bma2x2_set_int2_pad_sel(client, PAD_ORIENT);
+ err |= bma2x2_set_int2_pad_sel(client, PAD_FLAT);
+ err |= bma2x2_set_int2_pad_sel(client, PAD_SLOW_NO_MOTION);
+ err |= bma2x2_set_newdata(client, BMA2X2_INT1_NDATA, 0);
+ err |= bma2x2_set_newdata(client, BMA2X2_INT2_NDATA, 1);
+ err |= bma2x2_set_fwm_int_pad_sel(client, BMA2X2_INT1_FWM, 0);
+ err |= bma2x2_set_fwm_int_pad_sel(client, BMA2X2_INT2_FWM, 1);
+ err |= bma2x2_set_ffull_int_pad_sel(client, BMA2X2_INT1_FFULL, 0);
+ err |= bma2x2_set_ffull_int_pad_sel(client, BMA2X2_INT2_FFULL, 1);
+
+ if (err) {
+ dev_err(&client->dev, "select pad int1 error, ret=%d\n", err);
+ err = -EIO;
+ }
+ return err;
+}
+#else
+static int bma2x2_sel_int2_pad(const struct bma2x2_data *data)
+{
+ return -EPERM;
+}
+#endif /* BMA2X2_ENABLE_INT2 */
+
+static ssize_t bma2x2_int_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_Int_Mode(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+}
+
+static ssize_t bma2x2_int_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2_set_Int_Mode(bma2x2->bma2x2_client, (unsigned char)data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+static ssize_t bma2x2_slope_duration_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_slope_duration(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_slope_duration_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2_set_slope_duration(bma2x2->bma2x2_client, (unsigned
+ char)data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t bma2x2_slope_no_mot_duration_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_slope_no_mot_duration(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_slope_no_mot_duration_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2_set_slope_no_mot_duration(bma2x2->bma2x2_client, (unsigned
+ char)data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+
+static ssize_t bma2x2_slope_threshold_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_slope_threshold(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_slope_threshold_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+ if (bma2x2_set_slope_threshold(bma2x2->bma2x2_client, (unsigned
+ char)data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t bma2x2_slope_no_mot_threshold_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_slope_no_mot_threshold(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_slope_no_mot_threshold_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+ if (bma2x2_set_slope_no_mot_threshold(bma2x2->bma2x2_client, (unsigned
+ char)data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t bma2x2_high_g_duration_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_high_g_duration(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_high_g_duration_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2_set_high_g_duration(bma2x2->bma2x2_client, (unsigned
+ char)data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t bma2x2_high_g_threshold_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_high_g_threshold(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_high_g_threshold_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+ if (bma2x2_set_high_g_threshold(bma2x2->bma2x2_client, (unsigned
+ char)data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t bma2x2_low_g_duration_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_low_g_duration(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_low_g_duration_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2_set_low_g_duration(bma2x2->bma2x2_client, (unsigned
+ char)data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t bma2x2_low_g_threshold_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_low_g_threshold(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_low_g_threshold_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+ if (bma2x2_set_low_g_threshold(bma2x2->bma2x2_client, (unsigned
+ char)data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+static ssize_t bma2x2_tap_threshold_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_tap_threshold(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_tap_threshold_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+ if (bma2x2_set_tap_threshold(bma2x2->bma2x2_client, (unsigned char)data)
+ < 0)
+ return -EINVAL;
+
+ return count;
+}
+static ssize_t bma2x2_tap_duration_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_tap_duration(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_tap_duration_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2_set_tap_duration(bma2x2->bma2x2_client, (unsigned char)data)
+ < 0)
+ return -EINVAL;
+
+ return count;
+}
+static ssize_t bma2x2_tap_quiet_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_tap_quiet(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_tap_quiet_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2_set_tap_quiet(bma2x2->bma2x2_client, (unsigned char)data) <
+ 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t bma2x2_tap_shock_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_tap_shock(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_tap_shock_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2_set_tap_shock(bma2x2->bma2x2_client, (unsigned char)data) <
+ 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t bma2x2_tap_samp_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_tap_samp(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_tap_samp_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2_set_tap_samp(bma2x2->bma2x2_client, (unsigned char)data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t bma2x2_orient_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_orient_mode(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_orient_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2_set_orient_mode(bma2x2->bma2x2_client, (unsigned char)data) <
+ 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t bma2x2_orient_blocking_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_orient_blocking(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_orient_blocking_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2_set_orient_blocking(bma2x2->bma2x2_client, (unsigned
+ char)data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+static ssize_t bma2x2_orient_hyst_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_orient_hyst(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_orient_hyst_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2_set_orient_hyst(bma2x2->bma2x2_client, (unsigned char)data) <
+ 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t bma2x2_orient_theta_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_theta_blocking(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_orient_theta_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2_set_theta_blocking(bma2x2->bma2x2_client, (unsigned
+ char)data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t bma2x2_flat_theta_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_theta_flat(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_flat_theta_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2_set_theta_flat(bma2x2->bma2x2_client, (unsigned char)data) <
+ 0)
+ return -EINVAL;
+
+ return count;
+}
+static ssize_t bma2x2_flat_hold_time_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_flat_hold_time(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+static ssize_t bma2x2_selftest_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ atomic_read(&bma2x2->selftest_result));
+
+}
+
+static ssize_t bma2x2_softreset_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_soft_reset(bma2x2->bma2x2_client) < 0)
+ return -EINVAL;
+
+ return count;
+}
+static ssize_t bma2x2_selftest_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+
+ unsigned long data;
+ unsigned char clear_value = 0;
+ int error;
+ short value1 = 0;
+ short value2 = 0;
+ short diff = 0;
+ unsigned long result = 0;
+ unsigned long test_result_branch = 0;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ bma2x2_soft_reset(bma2x2->bma2x2_client);
+ RESET_DELAY();
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (data != 1)
+ return -EINVAL;
+
+ bma2x2_write_reg(bma2x2->bma2x2_client, 0x32, &clear_value);
+
+ if ((bma2x2->sensor_type == BMA280_TYPE) ||
+ (bma2x2->sensor_type == BMA255_TYPE)) {
+#ifdef CONFIG_SENSORS_BMI058
+ /*set self test amp */
+ if (bma2x2_set_selftest_amp(bma2x2->bma2x2_client, 1) < 0)
+ return -EINVAL;
+ /* set to 8 G range */
+ if (bma2x2_set_range(bma2x2->bma2x2_client,
+ BMA2X2_RANGE_8G) < 0)
+ return -EINVAL;
+#else
+ /* set to 4 G range */
+ if (bma2x2_set_range(bma2x2->bma2x2_client,
+ BMA2X2_RANGE_4G) < 0)
+ return -EINVAL;
+#endif
+ }
+
+ if ((bma2x2->sensor_type == BMA250E_TYPE) ||
+ (bma2x2->sensor_type == BMA222E_TYPE)) {
+ /* set to 8 G range */
+ if (bma2x2_set_range(bma2x2->bma2x2_client, 8) < 0)
+ return -EINVAL;
+ if (bma2x2_set_selftest_amp(bma2x2->bma2x2_client, 1) < 0)
+ return -EINVAL;
+ }
+
+ /* 1 for x-axis(but BMI058 is 1 for y-axis )*/
+ bma2x2_set_selftest_st(bma2x2->bma2x2_client, 1);
+ bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 0);
+ SELF_TEST_DELAY();
+ bma2x2_read_accel_x(bma2x2->bma2x2_client,
+ bma2x2->sensor_type, &value1);
+ bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 1);
+ SELF_TEST_DELAY();
+ bma2x2_read_accel_x(bma2x2->bma2x2_client,
+ bma2x2->sensor_type, &value2);
+ diff = value1-value2;
+
+#ifdef CONFIG_SENSORS_BMI058
+ dev_dbg(dev, "diff y is %d,value1 is %d, value2 is %d\n", diff,
+ value1, value2);
+ test_result_branch = 2;
+#else
+ dev_dbg(dev, "diff x is %d,value1 is %d, value2 is %d\n", diff,
+ value1, value2);
+ test_result_branch = 1;
+#endif
+
+ if (bma2x2->sensor_type == BMA280_TYPE) {
+#ifdef CONFIG_SENSORS_BMI058
+ if (abs(diff) < 819)
+ result |= test_result_branch;
+#else
+ if (abs(diff) < 1638)
+ result |= test_result_branch;
+#endif
+ }
+ if (bma2x2->sensor_type == BMA255_TYPE) {
+ if (abs(diff) < 409)
+ result |= 1;
+ }
+ if (bma2x2->sensor_type == BMA250E_TYPE) {
+ if (abs(diff) < 51)
+ result |= 1;
+ }
+ if (bma2x2->sensor_type == BMA222E_TYPE) {
+ if (abs(diff) < 12)
+ result |= 1;
+ }
+
+ /* 2 for y-axis but BMI058 is 1*/
+ bma2x2_set_selftest_st(bma2x2->bma2x2_client, 2);
+ bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 0);
+ SELF_TEST_DELAY();
+ bma2x2_read_accel_y(bma2x2->bma2x2_client,
+ bma2x2->sensor_type, &value1);
+ bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 1);
+ SELF_TEST_DELAY();
+ bma2x2_read_accel_y(bma2x2->bma2x2_client,
+ bma2x2->sensor_type, &value2);
+ diff = value1-value2;
+
+#ifdef CONFIG_SENSORS_BMI058
+ dev_dbg(dev, "diff x is %d,value1 is %d, value2 is %d\n", diff,
+ value1, value2);
+ test_result_branch = 1;
+#else
+ dev_dbg(dev, "diff y is %d,value1 is %d, value2 is %d\n", diff,
+ value1, value2);
+ test_result_branch = 2;
+#endif
+
+ if (bma2x2->sensor_type == BMA280_TYPE) {
+#ifdef CONFIG_SENSORS_BMI058
+ if (abs(diff) < 819)
+ result |= test_result_branch;
+#else
+ if (abs(diff) < 1638)
+ result |= test_result_branch;
+#endif
+ }
+ if (bma2x2->sensor_type == BMA255_TYPE) {
+ if (abs(diff) < 409)
+ result |= test_result_branch;
+ }
+ if (bma2x2->sensor_type == BMA250E_TYPE) {
+ if (abs(diff) < 51)
+ result |= test_result_branch;
+ }
+ if (bma2x2->sensor_type == BMA222E_TYPE) {
+ if (abs(diff) < 12)
+ result |= test_result_branch;
+ }
+
+
+ bma2x2_set_selftest_st(bma2x2->bma2x2_client, 3); /* 3 for z-axis*/
+ bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 0);
+ SELF_TEST_DELAY();
+ bma2x2_read_accel_z(bma2x2->bma2x2_client,
+ bma2x2->sensor_type, &value1);
+ bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 1);
+ SELF_TEST_DELAY();
+ bma2x2_read_accel_z(bma2x2->bma2x2_client,
+ bma2x2->sensor_type, &value2);
+ diff = value1-value2;
+
+ dev_dbg(dev, "diff z is %d,value1 is %d, value2 is %d\n", diff,
+ value1, value2);
+
+ if (bma2x2->sensor_type == BMA280_TYPE) {
+#ifdef CONFIG_SENSORS_BMI058
+ if (abs(diff) < 409)
+ result |= 4;
+#else
+ if (abs(diff) < 819)
+ result |= 4;
+#endif
+ }
+ if (bma2x2->sensor_type == BMA255_TYPE) {
+ if (abs(diff) < 204)
+ result |= 4;
+ }
+ if (bma2x2->sensor_type == BMA250E_TYPE) {
+ if (abs(diff) < 25)
+ result |= 4;
+ }
+ if (bma2x2->sensor_type == BMA222E_TYPE) {
+ if (abs(diff) < 6)
+ result |= 4;
+ }
+
+ /* self test for bma254 */
+ if ((bma2x2->sensor_type == BMA255_TYPE) && (result > 0)) {
+ result = 0;
+ bma2x2_soft_reset(bma2x2->bma2x2_client);
+ RESET_DELAY();
+ bma2x2_write_reg(bma2x2->bma2x2_client, 0x32, &clear_value);
+ /* set to 8 G range */
+ if (bma2x2_set_range(bma2x2->bma2x2_client, 8) < 0)
+ return -EINVAL;
+ if (bma2x2_set_selftest_amp(bma2x2->bma2x2_client, 1) < 0)
+ return -EINVAL;
+
+ bma2x2_set_selftest_st(bma2x2->bma2x2_client, 1); /* 1
+ for x-axis*/
+ bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 0); /*
+ positive direction*/
+ SELF_TEST_DELAY();
+ bma2x2_read_accel_x(bma2x2->bma2x2_client,
+ bma2x2->sensor_type, &value1);
+ bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 1); /*
+ negative direction*/
+ SELF_TEST_DELAY();
+ bma2x2_read_accel_x(bma2x2->bma2x2_client,
+ bma2x2->sensor_type, &value2);
+ diff = value1-value2;
+
+ dev_dbg(dev, "diff x is %d,value1 is %d, value2 is %d\n",
+ diff, value1, value2);
+ if (abs(diff) < 204)
+ result |= 1;
+
+ bma2x2_set_selftest_st(bma2x2->bma2x2_client, 2); /* 2
+ for y-axis*/
+ bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 0); /*
+ positive direction*/
+ SELF_TEST_DELAY();
+ bma2x2_read_accel_y(bma2x2->bma2x2_client,
+ bma2x2->sensor_type, &value1);
+ bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 1); /*
+ negative direction*/
+ SELF_TEST_DELAY();
+ bma2x2_read_accel_y(bma2x2->bma2x2_client,
+ bma2x2->sensor_type, &value2);
+ diff = value1-value2;
+ dev_dbg(dev, "diff y is %d,value1 is %d, value2 is %d\n",
+ diff, value1, value2);
+
+ if (abs(diff) < 204)
+ result |= 2;
+
+ bma2x2_set_selftest_st(bma2x2->bma2x2_client, 3); /* 3
+ for z-axis*/
+ bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 0); /*
+ positive direction*/
+ SELF_TEST_DELAY();
+ bma2x2_read_accel_z(bma2x2->bma2x2_client,
+ bma2x2->sensor_type, &value1);
+ bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 1); /*
+ negative direction*/
+ SELF_TEST_DELAY();
+ bma2x2_read_accel_z(bma2x2->bma2x2_client,
+ bma2x2->sensor_type, &value2);
+ diff = value1-value2;
+
+ dev_dbg(dev, "diff z is %d,value1 is %d, value2 is %d\n",
+ diff, value1, value2);
+ if (abs(diff) < 102)
+ result |= 4;
+ }
+
+ atomic_set(&bma2x2->selftest_result, (unsigned int)result);
+
+ bma2x2_soft_reset(bma2x2->bma2x2_client);
+ RESET_DELAY();
+ dev_dbg(dev, "self test finished\n");
+
+ return count;
+}
+
+
+
+static ssize_t bma2x2_flat_hold_time_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2_set_flat_hold_time(bma2x2->bma2x2_client, (unsigned
+ char)data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static const int bma2x2_sensor_bitwidth[] = {
+ 12, 10, 8, 14
+};
+
+static int bma2x2_get_sensitivity(struct bma2x2_data *bma2x2, int range)
+{
+
+ switch (range) {
+ case BMA2X2_RANGE_2G:
+ bma2x2->sensitivity = bosch_sensor_range_map[0];
+ break;
+ case BMA2X2_RANGE_4G:
+ bma2x2->sensitivity = bosch_sensor_range_map[1];
+ break;
+ case BMA2X2_RANGE_8G:
+ bma2x2->sensitivity = bosch_sensor_range_map[2];
+ break;
+ case BMA2X2_RANGE_16G:
+ bma2x2->sensitivity = bosch_sensor_range_map[3];
+ break;
+ default:
+ bma2x2->sensitivity = bosch_sensor_range_map[0];
+ break;
+ }
+ return 0;
+}
+
+static int bma2x2_read_accel_xyz(struct i2c_client *client,
+ signed char sensor_type, struct bma2x2acc *acc)
+{
+ int comres = 0;
+ unsigned char data[6];
+ struct bma2x2_data *client_data = i2c_get_clientdata(client);
+ int bitwidth;
+
+ comres = bma2x2_smbus_read_byte_block(client,
+ BMA2X2_ACC_X12_LSB__REG, data, 6);
+ if (sensor_type >= 4)
+ return -EINVAL;
+
+ acc->x = (data[1]<<8)|data[0];
+ acc->y = (data[3]<<8)|data[2];
+ acc->z = (data[5]<<8)|data[4];
+
+ bitwidth = bma2x2_sensor_bitwidth[sensor_type];
+ BMA2X2_SHIFT_BITWIDTH(acc->x, bitwidth);
+ BMA2X2_SHIFT_BITWIDTH(acc->y, bitwidth);
+ BMA2X2_SHIFT_BITWIDTH(acc->z, bitwidth);
+
+ bma2x2_remap_sensor_data(acc, client_data);
+ return comres;
+}
+
+static void bma2x2_report_axis_data(struct bma2x2_data *bma2x2,
+ struct bma2x2acc *value)
+{
+ ktime_t ts;
+ int err;
+
+ ts = ktime_get_boottime();
+ err = bma2x2_read_accel_xyz(bma2x2->bma2x2_client,
+ bma2x2->sensor_type, value);
+ if (err < 0) {
+ dev_err(&bma2x2->bma2x2_client->dev,
+ "read accel data failed! err = %d\n", err);
+ return;
+ }
+ input_report_abs(bma2x2->input, ABS_X,
+ (int)value->x << bma2x2->sensitivity);
+ input_report_abs(bma2x2->input, ABS_Y,
+ (int)value->y << bma2x2->sensitivity);
+ input_report_abs(bma2x2->input, ABS_Z,
+ (int)value->z << bma2x2->sensitivity);
+ input_event(bma2x2->input, EV_SYN, SYN_TIME_SEC,
+ ktime_to_timespec(ts).tv_sec);
+ input_event(bma2x2->input, EV_SYN, SYN_TIME_NSEC,
+ ktime_to_timespec(ts).tv_nsec);
+ input_sync(bma2x2->input);
+}
+
+static void bma2x2_work_func(struct work_struct *work)
+{
+ struct bma2x2_data *bma2x2 = container_of((struct delayed_work *)work,
+ struct bma2x2_data, work);
+ struct bma2x2acc value;
+ unsigned long delay = msecs_to_jiffies(atomic_read(&bma2x2->delay));
+
+ bma2x2_report_axis_data(bma2x2, &value);
+ mutex_lock(&bma2x2->value_mutex);
+ bma2x2->value = value;
+ mutex_unlock(&bma2x2->value_mutex);
+ queue_delayed_work(bma2x2->data_wq, &bma2x2->work, delay);
+}
+
+static enum hrtimer_restart accel_timer_handle(struct hrtimer *hrtimer)
+{
+ struct bma2x2_data *bma2x2;
+ ktime_t ktime;
+
+ bma2x2 = container_of(hrtimer, struct bma2x2_data, accel_timer);
+ ktime = ktime_set(0, atomic_read(&bma2x2->delay) * NSEC_PER_MSEC);
+ hrtimer_forward_now(&bma2x2->accel_timer, ktime);
+ bma2x2->accel_wkp_flag = 1;
+ wake_up_interruptible(&bma2x2->accel_wq);
+ return HRTIMER_RESTART;
+}
+
+static int accel_poll_thread(void *data)
+{
+ struct bma2x2_data *bma2x2 = data;
+ struct bma2x2acc value;
+
+ while (1) {
+ wait_event_interruptible(bma2x2->accel_wq,
+ ((bma2x2->accel_wkp_flag != 0) ||
+ kthread_should_stop()));
+ bma2x2->accel_wkp_flag = 0;
+ if (kthread_should_stop())
+ break;
+
+ mutex_lock(&bma2x2->op_lock);
+ if (bma2x2->accel_delay_change) {
+ if (atomic_read(&bma2x2->delay) <= POLL_MS_100HZ)
+ set_wake_up_idle(true);
+ else
+ set_wake_up_idle(false);
+ bma2x2->accel_delay_change = false;
+ }
+ mutex_unlock(&bma2x2->op_lock);
+
+ bma2x2_report_axis_data(bma2x2, &value);
+ mutex_lock(&bma2x2->value_mutex);
+ bma2x2->value = value;
+ mutex_unlock(&bma2x2->value_mutex);
+ }
+
+ return 0;
+}
+
+static ssize_t bma2x2_register_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int address, value;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (sscanf(buf, "%3d %3d", &address, &value) != 2)
+ return -EINVAL;
+
+ if (bma2x2_write_reg(bma2x2->bma2x2_client, (unsigned char)address,
+ (unsigned char *)&value) < 0)
+ return -EINVAL;
+ return count;
+}
+static ssize_t bma2x2_register_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ size_t count = 0;
+ u8 reg[0x40];
+ int i;
+
+ for (i = 0; i < 0x40; i++) {
+ bma2x2_smbus_read_byte(bma2x2->bma2x2_client, i, reg+i);
+
+ count += snprintf(&buf[count], PAGE_SIZE,
+ "0x%x: 0x%x\n", i, reg[i]);
+ }
+ return count;
+
+
+}
+
+static ssize_t bma2x2_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_range(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+}
+
+static ssize_t bma2x2_range_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+ if (bma2x2_set_range(bma2x2->bma2x2_client, (unsigned char) data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t bma2x2_bandwidth_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_bandwidth(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_bandwidth_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2->sensor_type == BMA280_TYPE)
+ if ((unsigned char) data > 14)
+ return -EINVAL;
+
+ if (bma2x2_set_bandwidth(bma2x2->bma2x2_client,
+ (unsigned char) data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t bma2x2_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_mode(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d %d\n", data, bma2x2->ref_count);
+}
+
+static ssize_t bma2x2_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+ if (bma2x2_set_mode(bma2x2->bma2x2_client, (unsigned char) data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t bma2x2_value_cache_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct input_dev *input = to_input_dev(dev);
+ struct bma2x2_data *bma2x2 = input_get_drvdata(input);
+ struct bma2x2acc acc_value;
+
+ mutex_lock(&bma2x2->value_mutex);
+ acc_value = bma2x2->value;
+ mutex_unlock(&bma2x2->value_mutex);
+
+ return snprintf(buf, PAGE_SIZE, "%d %d %d\n", acc_value.x, acc_value.y,
+ acc_value.z);
+}
+
+static ssize_t bma2x2_value_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct input_dev *input = to_input_dev(dev);
+ struct bma2x2_data *bma2x2 = input_get_drvdata(input);
+ struct bma2x2acc acc_value;
+
+ bma2x2_read_accel_xyz(bma2x2->bma2x2_client, bma2x2->sensor_type,
+ &acc_value);
+
+ return snprintf(buf, PAGE_SIZE, "%d %d %d\n", acc_value.x, acc_value.y,
+ acc_value.z);
+}
+
+static ssize_t bma2x2_delay_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&bma2x2->delay));
+
+}
+
+static ssize_t bma2x2_chip_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", bma2x2->chip_id);
+
+}
+
+
+static ssize_t bma2x2_place_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+ int place = BOSCH_SENSOR_PLACE_UNKNOWN;
+
+ place = bma2x2->pdata->place;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", place);
+}
+
+
+static ssize_t bma2x2_delay_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+ data = clamp_val(data, POLL_INTERVAL_MIN_MS, POLL_INTERVAL_MAX_MS);
+
+ error = bma2x2_update_delay(bma2x2, (unsigned int)data);
+ if (error)
+ return -EBUSY;
+ else
+ return count;
+}
+
+
+static ssize_t bma2x2_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&bma2x2->enable));
+
+}
+
+static int bma2x2_config_interrupt(struct bma2x2_data *data, int enable)
+{
+ struct i2c_client *client = data->bma2x2_client;
+ int err = 0;
+ bool act_high;
+
+ if (!enable)
+ /* No need reset these interrupt configurations */
+ goto exit;
+
+ if ((data->int_flag & IRQF_TRIGGER_RISING) ||
+ (data->int_flag & IRQF_TRIGGER_HIGH))
+ act_high = true;
+ else
+ act_high = false;
+
+ if (data->pdata->use_int2) {
+ err = bma2x2_sel_int2_pad(data);
+ if (err) {
+ dev_err(&client->dev,
+ "Failed to select int2 pad, err=%d\n",
+ err);
+ goto exit;
+ }
+
+ err = bma2x2_set_int2_active_lvl(client, act_high);
+ if (err) {
+ dev_err(&client->dev,
+ "Failed to select int2 level, err=%d\n",
+ err);
+ goto exit;
+ }
+ } else {
+ err = bma2x2_sel_int1_pad(data);
+ if (err) {
+ dev_err(&client->dev,
+ "Failed to select int1 pad, err=%d\n",
+ err);
+ goto exit;
+ }
+ err = bma2x2_set_int1_active_lvl(client, act_high);
+ if (err) {
+ dev_err(&client->dev,
+ "Failed to select int2 level, err=%d\n",
+ err);
+ goto exit;
+ }
+ }
+
+ err = bma2x2_set_Int_Mode(client, BMA2X2_LATCH_DUR_NON_LATCH);
+ if (err) {
+ dev_err(&client->dev,
+ "Failed to set interrupt latch, err=%d\n",
+ err);
+ goto exit;
+ }
+
+exit:
+ return err;
+}
+
+static unsigned int bma2x2_bandwidth_to_interval(struct bma2x2_data *bma2x2)
+{
+ unsigned int i;
+
+ for (i = ARRAY_SIZE(bma2x2_delay2bw_table) - 1; i > 0; i--) {
+ if (bma2x2_delay2bw_table[i].bw_config == bma2x2->bandwidth)
+ break;
+ }
+
+ return bma2x2_delay2bw_table[i].delay_ms;
+}
+
+static int bma2x2_set_fifo_enable(struct bma2x2_data *bma2x2, bool enable)
+{
+ struct i2c_client *client = bma2x2->bma2x2_client;
+ unsigned int interval, wml;
+ unsigned int latency = bma2x2->max_latency_ms;
+ int delay = atomic_read(&bma2x2->delay);
+ int fifo_en = atomic_read(&bma2x2->fifo_enabled);
+ int err = 0;
+
+ dev_dbg(&client->dev,
+ "bma2x2_set_fifo_enable latency=%d,delay=%d,enable=%d,fifo_en=%d\n",
+ latency, delay, enable, fifo_en);
+ if (enable && !fifo_en) {
+ if ((latency == 0) || (latency < delay)) {
+ dev_err(&client->dev,
+ "Invalid parameter! latency=%d delay=%d\n",
+ latency, delay);
+ err = -EINVAL;
+ goto exit;
+ }
+ if (IS_ERR_OR_NULL(bma2x2->fifo_buf)) {
+ dev_err(&client->dev,
+ "Not enough memory for sensor FIFO\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+ err = bma2x2_update_bandwidth(bma2x2);
+ if (err)
+ goto print_error;
+
+ interval = bma2x2_bandwidth_to_interval(bma2x2);
+ wml = (unsigned int)(latency / interval);
+ if (wml > MAX_FIFO_F_LEVEL)
+ wml = MAX_FIFO_F_LEVEL;
+ err = bma2x2_set_watermark_lvl(client, wml);
+ if (err)
+ goto print_error;
+
+ bma2x2->fifo_datasel = BMA2X2_FIFO_DAT_SEL_XYZ;
+ err = bma2x2_set_fifo_data_sel(bma2x2->bma2x2_client,
+ (unsigned char)BMA2X2_FIFO_DAT_SEL_XYZ);
+ if (err)
+ goto print_error;
+
+ err = bma2x2_set_watermark_int(client, true);
+ if (err)
+ goto print_error;
+
+ err = bma2x2_set_fifo_full_int(client, true);
+ if (err)
+ goto print_error;
+
+ err = bma2x2_set_fifo_mode(client, BMA2X2_FIFO_MODE_FIFO);
+ if (err)
+ goto print_error;
+ bma2x2_set_fifo_start_time(bma2x2);
+ atomic_set(&bma2x2->fifo_enabled, 1);
+ } else if (!enable && fifo_en) {
+ bma2x2_flush_fifo(bma2x2);
+ bma2x2_set_watermark_int(client, false);
+ bma2x2_set_fifo_full_int(client, false);
+ err = bma2x2_set_fifo_mode(client, BMA2X2_FIFO_MODE_BYPASS);
+ if (err)
+ goto print_error;
+ atomic_set(&bma2x2->fifo_enabled, 0);
+ } else {
+ dev_err(&client->dev,
+ "FIFO state incorrect! enable=%d, fifo enable=%d\n",
+ enable, fifo_en);
+ err = -EINVAL;
+ goto exit;
+ }
+
+print_error:
+ if (err)
+ dev_err(&client->dev,
+ "Set fifo error! enable=%d latency=%d, err=%d\n",
+ enable, latency, err);
+exit:
+ return err;
+}
+
+static int bma2x2_set_enable(struct device *dev, int enable)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+ int pre_enable = atomic_read(&bma2x2->enable);
+ int en_sig_motion = atomic_read(&bma2x2->en_sig_motion);
+ int err = 0;
+ ktime_t ktime;
+ int delay_ms;
+
+ dev_dbg(&client->dev,
+ "set enable: en=%d, en_state=%d en_SMD=%d\n",
+ enable, pre_enable, en_sig_motion);
+
+ if (atomic_read(&bma2x2->cal_status)) {
+ dev_err(dev, "can not enable or disable when calibration\n");
+ return -EBUSY;
+ }
+
+ mutex_lock(&bma2x2->enable_mutex);
+ if (enable && !pre_enable) {
+ if (!en_sig_motion) {
+ if (bma2x2_power_ctl(bma2x2, true)) {
+ dev_err(dev, "power failed\n");
+ goto mutex_exit;
+ }
+ if (bma2x2_open_init(client, bma2x2) < 0) {
+ dev_err(dev, "set init failed\n");
+ goto mutex_exit;
+ }
+ bma2x2_set_mode(bma2x2->bma2x2_client,
+ BMA2X2_MODE_NORMAL);
+ }
+
+ if ((bma2x2->pdata->int_en) &&
+ (bma2x2->max_latency_ms > 0)) {
+ err = bma2x2_set_fifo_enable(bma2x2, true);
+ if (err)
+ goto mutex_exit;
+ } else if ((bma2x2->pdata->int_en) &&
+ (BMA2x2_IS_NEWDATA_INT_ENABLED())) {
+ if (bma2x2_set_Int_Enable(client, BMA2X2_DATA_EN, 1)) {
+ dev_err(&client->dev,
+ "enable interrupt failed\n");
+ goto mutex_exit;
+ }
+ } else {
+ if (!bma2x2->pdata->use_hrtimer) {
+ delay_ms = atomic_read(&bma2x2->delay);
+ queue_delayed_work(bma2x2->data_wq,
+ &bma2x2->work,
+ msecs_to_jiffies(delay_ms));
+ } else {
+ ktime = ktime_set(0,
+ atomic_read(&bma2x2->delay)
+ * NSEC_PER_MSEC);
+ hrtimer_start(&bma2x2->accel_timer,
+ ktime, HRTIMER_MODE_REL);
+ }
+ }
+ if (!en_sig_motion && bma2x2->pdata->int_en) {
+ err = bma2x2_config_interrupt(bma2x2, true);
+ if (err) {
+ dev_err(&client->dev,
+ "Config interrupt failed\n");
+ goto mutex_exit;
+ }
+ bma2x2_pinctrl_state(bma2x2, true);
+ enable_irq(bma2x2->IRQ);
+ }
+ atomic_set(&bma2x2->enable, 1);
+ } else if (!enable && pre_enable) {
+ if (!en_sig_motion && bma2x2->pdata->int_en) {
+ if (bma2x2_store_state(client, bma2x2) < 0) {
+ dev_err(dev, "set state failed\n");
+ goto mutex_exit;
+ }
+ bma2x2_set_mode(bma2x2->bma2x2_client,
+ BMA2X2_MODE_SUSPEND);
+ disable_irq(bma2x2->IRQ);
+ bma2x2_pinctrl_state(bma2x2, false);
+ if (bma2x2_config_interrupt(bma2x2, false)) {
+ dev_err(&client->dev,
+ "Deconfig interrupt failed\n");
+ goto mutex_exit;
+ }
+ }
+
+ if (atomic_read(&bma2x2->fifo_enabled)) {
+ err = bma2x2_set_fifo_enable(bma2x2, false);
+ if (err)
+ goto mutex_exit;
+ } else if ((bma2x2->pdata->int_en) &&
+ (BMA2x2_IS_NEWDATA_INT_ENABLED())) {
+ if (bma2x2_set_Int_Enable(client, BMA2X2_DATA_EN, 0)) {
+ dev_err(&client->dev,
+ "disable interrupt failed\n");
+ goto mutex_exit;
+ }
+ } else {
+ if (!bma2x2->pdata->use_hrtimer)
+ cancel_delayed_work_sync(&bma2x2->work);
+ else
+ hrtimer_cancel(&bma2x2->accel_timer);
+ }
+
+ atomic_set(&bma2x2->enable, 0);
+ if (!en_sig_motion) {
+ if (bma2x2_power_ctl(bma2x2, false)) {
+ dev_err(dev, "power failed\n");
+ goto mutex_exit;
+ }
+ }
+ } else {
+ dev_err(&client->dev,
+ "Incorrect enable state! enable=%d, state=%d\n",
+ enable, pre_enable);
+ }
+mutex_exit:
+ mutex_unlock(&bma2x2->enable_mutex);
+ if (!!enable != atomic_read(&bma2x2->enable)) {
+ dev_err(&client->dev,
+ "Set enable failed! en=%d, en_state=%d, use_int=%d\n",
+ enable, atomic_read(&bma2x2->enable),
+ bma2x2->pdata->int_en);
+ err = -EBUSY;
+ }
+ return err;
+}
+
+static ssize_t bma2x2_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+ if ((data == 0) || (data == 1)) {
+ error = bma2x2_set_enable(dev, data);
+ if (error)
+ return -EBUSY;
+ }
+
+ return count;
+}
+
+static int bma2x2_cdev_enable(struct sensors_classdev *sensors_cdev,
+ unsigned int enable)
+{
+ struct bma2x2_data *data = container_of(sensors_cdev,
+ struct bma2x2_data, cdev);
+
+ bma2x2_set_enable(&data->bma2x2_client->dev, enable);
+ return 0;
+}
+
+static int bma2x2_is_power_enabled(struct bma2x2_data *data)
+{
+ return atomic_read(&data->enable);
+}
+
+static int bma2x2_cdev_poll_delay(struct sensors_classdev *sensors_cdev,
+ unsigned int delay_ms)
+{
+ struct bma2x2_data *data = container_of(sensors_cdev,
+ struct bma2x2_data, cdev);
+ int err;
+
+ delay_ms = clamp_val(delay_ms,
+ POLL_INTERVAL_MIN_MS, POLL_INTERVAL_MAX_MS);
+
+ dev_dbg(&data->bma2x2_client->dev,
+ "bma2x2_cdev_poll_delay delay_ms=%d\n",
+ delay_ms);
+ err = bma2x2_update_delay(data, delay_ms);
+ if (err)
+ return -EBUSY;
+ else
+ return 0;
+}
+
+static int bma2x2_cdev_set_latency(struct sensors_classdev *sensors_cdev,
+ unsigned int max_latency_ms)
+{
+ struct bma2x2_data *bma2x2 = container_of(sensors_cdev,
+ struct bma2x2_data, cdev);
+ struct i2c_client *client = bma2x2->bma2x2_client;
+ unsigned int delay = atomic_read(&bma2x2->delay);
+ int err = 0;
+
+ dev_dbg(&client->dev,
+ "bma2x2_cdev_set_latency latency=%d\n",
+ max_latency_ms);
+ if ((max_latency_ms > 0) && (max_latency_ms < delay)) {
+ dev_err(&client->dev,
+ "Latency should not less than delay! latency=%d, delay=%d\n",
+ max_latency_ms, delay);
+ return -EINVAL;
+ }
+
+ bma2x2->max_latency_ms = max_latency_ms;
+ if (!atomic_read(&bma2x2->enable))
+ return 0;
+
+ if (max_latency_ms > 0) {
+ /* Data polling and batching should not work at same time */
+ if (!bma2x2->pdata->use_hrtimer)
+ cancel_delayed_work_sync(&bma2x2->work);
+ else
+ hrtimer_cancel(&bma2x2->accel_timer);
+
+ err = bma2x2_set_fifo_enable(bma2x2, true);
+ } else {
+ err = bma2x2_set_fifo_enable(bma2x2, false);
+ if (!err && bma2x2_use_data_polling(bma2x2))
+ mod_delayed_work(bma2x2->data_wq, &bma2x2->work,
+ msecs_to_jiffies(delay));
+ }
+ if (err)
+ dev_err(&client->dev,
+ "Set latency error! latency=%d, err=%d\n",
+ max_latency_ms, err);
+ return err;
+}
+
+static int bma2x2_cdev_flush(struct sensors_classdev *sensors_cdev)
+{
+ struct bma2x2_data *bma2x2 = container_of(sensors_cdev,
+ struct bma2x2_data, cdev);
+
+ if (atomic_read(&bma2x2->fifo_enabled))
+ return bma2x2_flush_fifo(bma2x2);
+ else
+ return 0;
+}
+
+#ifdef CONFIG_SENSORS_BMI058
+static int bma2x2_select_chanel(struct i2c_client *client)
+{
+ unsigned char data_ore[3] = { BOSCH_SENSOR_PLANE };
+ signed char tmp;
+ int error, i;
+ int timeout;
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+ unsigned char bmi058_channel_tb = {BMI058_OFFSET_TRIGGER_X,
+ BMI058_OFFSET_TRIGGER_Y, BMI058_OFFSET_TRIGGER_Z};
+
+ if (bma2x2->pdata->place > 3 && bma2x2->pdata->place < 8)
+ data_ore[2] = BOSCH_SENSOR_DOWN;
+ else if (bma2x2->pdata->place >= 0 && bma2x2->pdata->place < 4)
+ data_ore[2] = BOSCH_SENSOR_UP;
+ else {
+ dev_err(&client->dev, "unknown sensor place\n");
+ return -EINVAL;
+ }
+ if (bma2x2_set_mode(client, BMA2X2_MODE_NORMAL) < 0) {
+ dev_err(&client->dev, "set calibrate mode error\n");
+ return -EINVAL;
+ }
+ if (bma2x2_set_bandwidth(client, BMA2X2_BW_1000HZ) < 0) {
+ dev_err(&client->dev, "set calibrate bandwidth error\n");
+ return -EINVAL;
+ }
+ if (bma2x2_set_range(client, BMA2X2_RANGE_SET) < 0) {
+ dev_err(&client->dev, "set calibrate range error\n");
+ return -EINVAL;
+ }
+ for (i = 0; i < 3; i++) {
+ if (bma2x2_set_offset_target(client, bmi058_channel_tb[i],
+ (unsigned char)data_ore[i]) < 0) {
+ dev_err(&client->dev,
+ "set offset target error\n");
+ return -EINVAL;
+ }
+ if (bma2x2_set_cal_trigger(client, (i + 1)) < 0) {
+ dev_err(&client->dev,
+ "read calibration state error\n");
+ return -EINVAL;
+ }
+ timeout = 0;
+ do {
+ WAIT_CAL_READY();
+ error = bma2x2_get_cal_ready(client, &tmp);
+ if (error < 0) {
+ dev_err(&client->dev,
+ "read cal_ready error\n");
+ return error;
+ }
+ timeout++;
+ if (timeout == RETRY_TIME) {
+ dev_err(&client->dev,
+ "get fast calibration ready error\n");
+ return -EINVAL;
+ };
+
+ } while (tmp == 0);
+ }
+ bma2x2_set_bandwidth(client, bma2x2->bandwidth);
+ if (error < 0) {
+ dev_err(&client->dev, "restore calibrate bandwidth error\n");
+ return error;
+ }
+ return 0;
+}
+#else
+static int bma2x2_select_chanel(struct i2c_client *client)
+{
+ unsigned char data_ore[3] = { BOSCH_SENSOR_PLANE };
+ signed char tmp;
+ int error, i;
+ int timeout;
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+ unsigned char channel_tab[] = {BMA2X2_OFFSET_TRIGGER_X,
+ BMA2X2_OFFSET_TRIGGER_Y, BMA2X2_OFFSET_TRIGGER_Z};
+
+ if (bma2x2->pdata->place > 3 && bma2x2->pdata->place < 8)
+ data_ore[2] = BOSCH_SENSOR_DOWN;
+ else if (bma2x2->pdata->place >= 0 && bma2x2->pdata->place < 4)
+ data_ore[2] = BOSCH_SENSOR_UP;
+ else {
+ dev_err(&client->dev, "unknown sensor place\n");
+ return -EINVAL;
+ }
+
+ if (bma2x2_set_mode(client, BMA2X2_MODE_NORMAL) < 0) {
+ dev_err(&client->dev, "set calibrate mode error\n");
+ return -EINVAL;
+ }
+ if (bma2x2_set_bandwidth(client, BMA2X2_BW_1000HZ) < 0) {
+ dev_err(&client->dev, "set calibrate bandwidth error\n");
+ return -EINVAL;
+ }
+ if (bma2x2_set_range(client, BMA2X2_RANGE_SET) < 0) {
+ dev_err(&client->dev, "set calibrate range error\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (bma2x2_set_offset_target(client, channel_tab[i],
+ (unsigned char)data_ore[i]) < 0) {
+ dev_err(&client->dev,
+ "set offset target error\n");
+ return -EINVAL;
+ }
+ if (bma2x2_set_cal_trigger(client, (i + 1)) < 0) {
+ dev_err(&client->dev,
+ "read calibration state error\n");
+ return -EINVAL;
+ }
+ timeout = 0;
+ do {
+ WAIT_CAL_READY();
+ error = bma2x2_get_cal_ready(client, &tmp);
+ if (error < 0) {
+ dev_err(&client->dev,
+ "read cal_ready error\n");
+ return error;
+ }
+ timeout++;
+ if (timeout == RETRY_TIME) {
+ dev_err(&client->dev,
+ "get fast calibration ready error\n");
+ return -EINVAL;
+ };
+
+ } while (tmp == 0);
+ }
+
+ error = bma2x2_set_bandwidth(client, bma2x2->bandwidth);
+ if (error < 0) {
+ dev_err(&client->dev, "restore calibrate bandwidth error\n");
+ return error;
+ }
+ return 0;
+}
+#endif
+
+static int bma2x2_self_calibration_xyz(struct sensors_classdev *sensors_cdev,
+ int axis, int apply_now)
+{
+ int error;
+ bool pre_enable;
+ struct bma2x2_data *data = container_of(sensors_cdev,
+ struct bma2x2_data, cdev);
+ struct i2c_client *client = data->bma2x2_client;
+
+ pre_enable = atomic_read(&data->enable);
+ if (pre_enable)
+ bma2x2_set_enable(&client->dev, 0);
+ if (atomic_cmpxchg(&data->cal_status, 0, 1)) {
+ dev_err(&client->dev, "do calibration error\n");
+ return -EBUSY;
+ }
+
+ error = bma2x2_power_ctl(data, true);
+ if (error) {
+ dev_err(&client->dev, "Failed to enable sensor power\n");
+ error = -EINVAL;
+ goto exit;
+ }
+ error = bma2x2_select_chanel(client);
+ if (error < 0) {
+ dev_err(&client->dev, "xyz calibration error\n");
+ goto exit;
+ }
+ dev_dbg(&client->dev, "xyz axis fast calibration finished\n");
+ error = bma2x2_eeprom_prog(client);
+ if (error < 0) {
+ dev_err(&client->dev, "write calibration to eeprom failed\n");
+ goto exit;
+ }
+ snprintf(data->calibrate_buf, sizeof(data->calibrate_buf),
+ "%d,%d,%d", 0, 0, 0);
+ sensors_cdev->params = data->calibrate_buf;
+
+ error = bma2x2_power_ctl(data, false);
+ if (error) {
+ dev_err(&client->dev, "Failed to disable sensor power\n");
+ goto exit;
+ }
+
+exit:
+ atomic_set(&data->cal_status, 0);
+ if (pre_enable)
+ bma2x2_set_enable(&client->dev, 1);
+
+ return error;
+}
+
+static int bma2x2_eeprom_prog(struct i2c_client *client)
+{
+ int res = 0, timeout = 0;
+ unsigned char databuf;
+
+ res = bma2x2_smbus_read_byte(client, BMA2X2_EEPROM_CTRL_REG,
+ &databuf);
+ if (res < 0) {
+ dev_err(&client->dev, "read eeprom control reg error1\n");
+ return res;
+ }
+ databuf |= 0x01;
+ res = bma2x2_smbus_write_byte(client, BMA2X2_EEPROM_CTRL_REG,
+ &databuf);
+ if (res < 0) {
+ dev_err(&client->dev, "write eeprom control reg error1\n");
+ return res;
+ }
+
+ res = bma2x2_smbus_read_byte(client, BMA2X2_EEPROM_CTRL_REG,
+ &databuf);
+ if (res < 0) {
+ dev_err(&client->dev, "read eeprom control reg error2\n");
+ return res;
+ }
+ databuf |= 0x02;
+ res = bma2x2_smbus_write_byte(client, BMA2X2_EEPROM_CTRL_REG,
+ &databuf);
+ if (res < 0) {
+ dev_err(&client->dev, "write eeprom control reg error2\n");
+ return res;
+ }
+ do {
+ WAIT_CAL_READY();
+ res = bma2x2_smbus_read_byte(client, BMA2X2_EEPROM_CTRL_REG,
+ &databuf);
+ if (res < 0) {
+ dev_err(&client->dev, "read nvm_rdy error\n");
+ return res;
+ }
+ databuf = (databuf >> 2) & 0x01;
+ if (++timeout == 50) {
+ dev_err(&client->dev, "check nvm_rdy time out\n");
+ break;
+ }
+ } while (databuf == 0);
+
+ res = bma2x2_smbus_read_byte(client, BMA2X2_EEPROM_CTRL_REG,
+ &databuf);
+ if (res < 0) {
+ dev_err(&client->dev, "read eeprom control reg error3\n");
+ return res;
+ }
+ databuf &= 0xFE;
+ res = bma2x2_smbus_write_byte(client, BMA2X2_EEPROM_CTRL_REG,
+ &databuf);
+ if (res < 0) {
+ dev_err(&client->dev, "write eeprom control reg error3\n");
+ return res;
+ }
+ return res;
+}
+
+static int bma2x2_write_cal_params(struct sensors_classdev *sensors_cdev,
+ struct cal_result_t *cal_result)
+{
+ struct bma2x2_data *data = container_of(sensors_cdev,
+ struct bma2x2_data, cdev);
+
+ snprintf(data->calibrate_buf, sizeof(data->calibrate_buf),
+ "%d,%d,%d", 0, 0, 0);
+ sensors_cdev->params = data->calibrate_buf;
+ return 0;
+}
+
+static ssize_t bma2x2_fast_calibration_x_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+#ifdef CONFIG_SENSORS_BMI058
+ if (bma2x2_get_offset_target(bma2x2->bma2x2_client,
+ BMI058_OFFSET_TRIGGER_X, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+#else
+ if (bma2x2_get_offset_target(bma2x2->bma2x2_client,
+ BMA2X2_OFFSET_TRIGGER_X, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+#endif
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_fast_calibration_x_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ signed char tmp;
+ unsigned char timeout = 0;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+#ifdef CONFIG_SENSORS_BMI058
+ if (bma2x2_set_offset_target(bma2x2->bma2x2_client,
+ BMI058_OFFSET_TRIGGER_X, (unsigned char)data) < 0)
+ return -EINVAL;
+#else
+ if (bma2x2_set_offset_target(bma2x2->bma2x2_client,
+ BMA2X2_OFFSET_TRIGGER_X, (unsigned char)data) < 0)
+ return -EINVAL;
+#endif
+
+ if (bma2x2_set_cal_trigger(bma2x2->bma2x2_client, 1) < 0)
+ return -EINVAL;
+
+ do {
+ WAIT_CAL_READY();
+ bma2x2_get_cal_ready(bma2x2->bma2x2_client, &tmp);
+
+ timeout++;
+ if (timeout == 50) {
+ dev_err(&client->dev, "get fast calibration ready error\n");
+ return -EINVAL;
+ };
+
+ } while (tmp == 0);
+
+ dev_dbg(&client->dev, "x axis fast calibration finished\n");
+ return count;
+}
+
+static ssize_t bma2x2_fast_calibration_y_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+#ifdef CONFIG_SENSORS_BMI058
+ if (bma2x2_get_offset_target(bma2x2->bma2x2_client,
+ BMI058_OFFSET_TRIGGER_Y, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+#else
+ if (bma2x2_get_offset_target(bma2x2->bma2x2_client,
+ BMA2X2_OFFSET_TRIGGER_Y, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+#endif
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_fast_calibration_y_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ signed char tmp;
+ unsigned char timeout = 0;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+#ifdef CONFIG_SENSORS_BMI058
+ if (bma2x2_set_offset_target(bma2x2->bma2x2_client,
+ BMI058_OFFSET_TRIGGER_Y, (unsigned char)data) < 0)
+ return -EINVAL;
+#else
+ if (bma2x2_set_offset_target(bma2x2->bma2x2_client,
+ BMA2X2_OFFSET_TRIGGER_Y, (unsigned char)data) < 0)
+ return -EINVAL;
+#endif
+
+ if (bma2x2_set_cal_trigger(bma2x2->bma2x2_client, 2) < 0)
+ return -EINVAL;
+
+ do {
+ WAIT_CAL_READY();
+ bma2x2_get_cal_ready(bma2x2->bma2x2_client, &tmp);
+
+ timeout++;
+ if (timeout == 50) {
+ dev_err(&client->dev, "get fast calibration ready error\n");
+ return -EINVAL;
+ };
+
+ } while (tmp == 0);
+
+ dev_dbg(&client->dev, "y axis fast calibration finished\n");
+ return count;
+}
+
+static ssize_t bma2x2_fast_calibration_z_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_offset_target(bma2x2->bma2x2_client, 3, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_fast_calibration_z_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ signed char tmp;
+ unsigned char timeout = 0;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2_set_offset_target(bma2x2->bma2x2_client, 3, (unsigned
+ char)data) < 0)
+ return -EINVAL;
+
+ if (bma2x2_set_cal_trigger(bma2x2->bma2x2_client, 3) < 0)
+ return -EINVAL;
+
+ do {
+ WAIT_CAL_READY();
+ bma2x2_get_cal_ready(bma2x2->bma2x2_client, &tmp);
+
+ timeout++;
+ if (timeout == 50) {
+ dev_err(&client->dev, "get fast calibration ready error\n");
+ return -EINVAL;
+ };
+
+ } while (tmp == 0);
+
+ dev_dbg(&client->dev, "z axis fast calibration finished\n");
+ return count;
+}
+
+
+static ssize_t bma2x2_SleepDur_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_sleep_duration(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_SleepDur_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+ if (bma2x2_set_sleep_duration(bma2x2->bma2x2_client,
+ (unsigned char) data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t bma2x2_fifo_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_fifo_mode(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_fifo_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+ if (bma2x2_set_fifo_mode(bma2x2->bma2x2_client,
+ (unsigned char) data) < 0)
+ return -EINVAL;
+ return count;
+}
+
+
+
+static ssize_t bma2x2_fifo_trig_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_fifo_trig(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_fifo_trig_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+ if (bma2x2_set_fifo_trig(bma2x2->bma2x2_client,
+ (unsigned char) data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+
+
+static ssize_t bma2x2_fifo_trig_src_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_fifo_trig_src(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_fifo_trig_src_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+ if (bma2x2_set_fifo_trig_src(bma2x2->bma2x2_client,
+ (unsigned char) data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+
+/*!
+ * @brief show fifo_data_sel axis definition(Android definition, not sensor HW reg).
+ * 0--> x, y, z axis fifo data for every frame
+ * 1--> only x axis fifo data for every frame
+ * 2--> only y axis fifo data for every frame
+ * 3--> only z axis fifo data for every frame
+ */
+static ssize_t bma2x2_fifo_data_sel_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+ signed char place = BOSCH_SENSOR_PLACE_UNKNOWN;
+
+ if (bma2x2_get_fifo_data_sel(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+#ifdef CONFIG_SENSORS_BMI058
+/*Update BMI058 fifo_data_sel to the BMA2x2 common definition*/
+ if (BMI058_FIFO_DAT_SEL_X == data)
+ data = BMA2X2_FIFO_DAT_SEL_X;
+ else if (BMI058_FIFO_DAT_SEL_Y == data)
+ data = BMA2X2_FIFO_DAT_SEL_Y;
+#endif
+
+ /*remaping fifo_dat_sel if define virtual place in BSP files*/
+ place = bma2x2->pdata->place;
+ /* sensor with place 0 needs not to be remapped */
+ if ((place > 0) && (place < MAX_AXIS_REMAP_TAB_SZ)) {
+ /* BMA2X2_FIFO_DAT_SEL_X: 1, Y:2, Z:3;
+ * but bst_axis_remap_tab_dft[i].src_x:0, y:1, z:2
+ * so we need to +1*/
+ if (BMA2X2_FIFO_DAT_SEL_X == data)
+ data = bst_axis_remap_tab_dft[place].src_x + 1;
+ else if (BMA2X2_FIFO_DAT_SEL_Y == data)
+ data = bst_axis_remap_tab_dft[place].src_y + 1;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_fifo_framecount_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_fifo_framecount(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_fifo_framecount_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+ bma2x2->fifo_count = (unsigned int) data;
+
+ return count;
+}
+
+static ssize_t bma2x2_temperature_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_read_temperature(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+/*!
+ * @brief store fifo_data_sel axis definition(Android definition, not sensor HW reg).
+ * 0--> x, y, z axis fifo data for every frame
+ * 1--> only x axis fifo data for every frame
+ * 2--> only y axis fifo data for every frame
+ * 3--> only z axis fifo data for every frame
+ */
+static ssize_t bma2x2_fifo_data_sel_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+ signed char place;
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+ /*save fifo_data_sel(android definition)*/
+ bma2x2->fifo_datasel = (unsigned char) data;
+
+ /*remaping fifo_dat_sel if define virtual place*/
+ place = bma2x2->pdata->place;
+ /* sensor with place 0 needs not to be remapped */
+ if ((place > 0) && (place < MAX_AXIS_REMAP_TAB_SZ)) {
+ /*Need X Y axis revesal sensor place: P1, P3, P5, P7 */
+ /* BMA2X2_FIFO_DAT_SEL_X: 1, Y:2, Z:3;
+ * but bst_axis_remap_tab_dft[i].src_x:0, y:1, z:2
+ * so we need to +1*/
+ if (BMA2X2_FIFO_DAT_SEL_X == data)
+ data = bst_axis_remap_tab_dft[place].src_x + 1;
+ else if (BMA2X2_FIFO_DAT_SEL_Y == data)
+ data = bst_axis_remap_tab_dft[place].src_y + 1;
+ }
+#ifdef CONFIG_SENSORS_BMI058
+ /*Update BMI058 fifo_data_sel to the BMA2x2 common definition*/
+ if (BMA2X2_FIFO_DAT_SEL_X == data)
+ data = BMI058_FIFO_DAT_SEL_X;
+ else if (BMA2X2_FIFO_DAT_SEL_Y == data)
+ data = BMI058_FIFO_DAT_SEL_Y;
+
+#endif
+ if (bma2x2_set_fifo_data_sel(bma2x2->bma2x2_client,
+ (unsigned char) data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+
+/*!
+ * brief: bma2x2 single axis data remaping
+ * @param[i] fifo_datasel fifo axis data select setting
+ * @param[i/o] remap_dir remapping direction
+ * @param[i] client_data to transfer sensor place
+ *
+ * @return none
+ */
+static void bma2x2_single_axis_remaping(unsigned char fifo_datasel,
+ unsigned char *remap_dir, struct bma2x2_data *client_data)
+{
+ signed char place = client_data->pdata->place;
+ /* sensor with place 0 needs not to be remapped */
+ if ((place <= 0) || (place >= MAX_AXIS_REMAP_TAB_SZ))
+ return;
+
+ if (fifo_datasel < 1 || fifo_datasel > 3)
+ return;
+
+ switch (fifo_datasel) {
+ /*P2, P3, P4, P5 X axis(andorid) need to reverse*/
+ case BMA2X2_FIFO_DAT_SEL_X:
+ if (-1 == bst_axis_remap_tab_dft[place].sign_x)
+ *remap_dir = 1;
+ else
+ *remap_dir = 0;
+ break;
+ /*P1, P2, P5, P6 Y axis(andorid) need to reverse*/
+ case BMA2X2_FIFO_DAT_SEL_Y:
+ if (-1 == bst_axis_remap_tab_dft[place].sign_y)
+ *remap_dir = 1;
+ else
+ *remap_dir = 0;
+ break;
+ case BMA2X2_FIFO_DAT_SEL_Z:
+ /*P4, P5, P6, P7 Z axis(andorid) need to reverse*/
+ if (-1 == bst_axis_remap_tab_dft[place].sign_z)
+ *remap_dir = 1;
+ else
+ *remap_dir = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+static int bma2x2_flush_fifo(struct bma2x2_data *bma2x2)
+{
+ struct i2c_client *client = bma2x2->bma2x2_client;
+ int bitwidth, i, err, ns;
+ unsigned char f_len = 0;
+ unsigned char fifo_count;
+ s64 interval_ns, ts_ns, sec;
+ struct bma2x2acc acc;
+
+ err = bma2x2_get_fifo_framecount(bma2x2->bma2x2_client, &fifo_count);
+ if (err)
+ dev_err(&client->dev,
+ "Get fifo count error! err=%d\n", err);
+
+ dev_dbg(&client->dev,
+ "bma2x2_flush_fifo fifo_count=%d\n", fifo_count);
+ if (fifo_count > MAX_FIFO_F_LEVEL) {
+ dev_err(&client->dev,
+ "Invalid fifo framecount: %d\n", fifo_count);
+ return -EINVAL;
+ }
+
+ if (IS_ERR_OR_NULL(bma2x2->fifo_buf)) {
+ dev_err(&client->dev,
+ "Not enough memory for fifo data\n");
+ return -ENOMEM;
+ }
+ interval_ns = bma2x2_bandwidth_to_interval(bma2x2) * NSEC_PER_MSEC;
+ ts_ns = bma2x2->fifo_start_ns + interval_ns;
+ bma2x2_set_fifo_start_time(bma2x2);
+ f_len = bma2x2->fifo_datasel ?
+ FIFO_FRAMESIZE_1_AXIS : FIFO_FRAMESIZE_3_AXIS;
+ if (f_len != FIFO_FRAMESIZE_3_AXIS) {
+ /* Reset FIFO if it doesn't contain X Y Z three axis data */
+ dev_err(&client->dev,
+ "Incorrect FIFO data select (0x%x)!\n",
+ bma2x2->fifo_datasel);
+ err = -EBUSY;
+ goto reset_fifo;
+ }
+ err = bma_i2c_burst_read(client,
+ BMA2X2_FIFO_DATA_OUTPUT_REG, bma2x2->fifo_buf,
+ fifo_count * f_len);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "Read byte block error ret=%d\n", err);
+ err = -EIO;
+ goto reset_fifo;
+ }
+
+ for (i = 0; i < fifo_count; i++) {
+ acc.x =
+ ((unsigned char)bma2x2->fifo_buf[i * f_len + 1] << 8 |
+ (unsigned char)bma2x2->fifo_buf[i * f_len + 0]);
+ acc.y =
+ ((unsigned char)bma2x2->fifo_buf[i * f_len + 3] << 8 |
+ (unsigned char)bma2x2->fifo_buf[i * f_len + 2]);
+ acc.z =
+ ((unsigned char)bma2x2->fifo_buf[i * f_len + 5] << 8 |
+ (unsigned char)bma2x2->fifo_buf[i * f_len + 4]);
+ bitwidth = bma2x2_sensor_bitwidth[bma2x2->sensor_type];
+ BMA2X2_SHIFT_BITWIDTH(acc.x, bitwidth);
+ BMA2X2_SHIFT_BITWIDTH(acc.y, bitwidth);
+ BMA2X2_SHIFT_BITWIDTH(acc.z, bitwidth);
+
+ bma2x2_remap_sensor_data(&acc, bma2x2);
+
+ sec = ts_ns;
+ ns = do_div(sec, NSEC_PER_SEC);
+ ts_ns += interval_ns;
+ input_report_abs(bma2x2->input, ABS_X,
+ (int)acc.x << bma2x2->sensitivity);
+ input_report_abs(bma2x2->input, ABS_Y,
+ (int)acc.y << bma2x2->sensitivity);
+ input_report_abs(bma2x2->input, ABS_Z,
+ (int)acc.z << bma2x2->sensitivity);
+ input_event(bma2x2->input, EV_SYN, SYN_TIME_SEC,
+ (int)sec);
+ input_event(bma2x2->input, EV_SYN, SYN_TIME_NSEC,
+ (int)ns);
+ input_sync(bma2x2->input);
+ }
+ return 0;
+
+reset_fifo:
+ /* Clear FIFO content and reset interrupt */
+ bma2x2_set_fifo_mode(client, BMA2X2_FIFO_MODE_FIFO);
+ return err;
+}
+
+static ssize_t bma2x2_fifo_data_out_frame_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int err, i, len;
+ signed char fifo_data_out[MAX_FIFO_F_LEVEL * MAX_FIFO_F_BYTES] = {0};
+ unsigned char f_len = 0;
+ s16 value;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+ struct bma2x2acc acc_lsb;
+ unsigned char axis_dir_remap = 0;
+
+ if (bma2x2->fifo_datasel) {
+ /*Select one axis data output for every fifo frame*/
+ f_len = FIFO_FRAMESIZE_1_AXIS;
+ } else {
+ /*Select X Y Z axis data output for every fifo frame*/
+ f_len = FIFO_FRAMESIZE_3_AXIS;
+ }
+
+ if (bma2x2->fifo_count == 0)
+ return -EINVAL;
+
+ if (bma_i2c_burst_read(bma2x2->bma2x2_client,
+ BMA2X2_FIFO_DATA_OUTPUT_REG, fifo_data_out,
+ bma2x2->fifo_count * f_len) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read byte block error\n");
+
+
+ err = 0;
+
+/* please give attation for the fifo output data format*/
+ if (f_len == FIFO_FRAMESIZE_3_AXIS) {
+ /* Select X Y Z axis data output for every frame */
+ for (i = 0; i < bma2x2->fifo_count; i++) {
+ acc_lsb.x =
+ ((unsigned char)fifo_data_out[i * f_len + 1] << 8 |
+ (unsigned char)fifo_data_out[i * f_len + 0]);
+ acc_lsb.y =
+ ((unsigned char)fifo_data_out[i * f_len + 3] << 8 |
+ (unsigned char)fifo_data_out[i * f_len + 2]);
+ acc_lsb.z =
+ ((unsigned char)fifo_data_out[i * f_len + 5] << 8 |
+ (unsigned char)fifo_data_out[i * f_len + 4]);
+#ifndef BMA2X2_SENSOR_IDENTIFICATION_ENABLE
+ acc_lsb.x >>=
+ (16 - bma2x2_sensor_bitwidth[bma2x2->sensor_type]);
+ acc_lsb.y >>=
+ (16 - bma2x2_sensor_bitwidth[bma2x2->sensor_type]);
+ acc_lsb.z >>=
+ (16 - bma2x2_sensor_bitwidth[bma2x2->sensor_type]);
+#endif
+ bma2x2_remap_sensor_data(&acc_lsb, bma2x2);
+ len = snprintf(buf, PAGE_SIZE, "%d %d %d ",
+ acc_lsb.x, acc_lsb.y, acc_lsb.z);
+ buf += len;
+ err += len;
+ }
+ } else {
+ /* single axis data output for every frame */
+ bma2x2_single_axis_remaping(bma2x2->fifo_datasel,
+ &axis_dir_remap, bma2x2);
+ for (i = 0; i < bma2x2->fifo_count * f_len / 2; i++) {
+ value = ((unsigned char)fifo_data_out[2 * i + 1] << 8 |
+ (unsigned char)fifo_data_out[2 * i]);
+#ifndef BMA2X2_SENSOR_IDENTIFICATION_ENABLE
+ value >>=
+ (16 - bma2x2_sensor_bitwidth[bma2x2->sensor_type]);
+#endif
+ if (axis_dir_remap)
+ value = 0 - value;
+ len = snprintf(buf, PAGE_SIZE, "%d ", value);
+ buf += len;
+ err += len;
+ }
+ }
+
+ return err;
+}
+
+static ssize_t bma2x2_offset_x_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_offset_x(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_offset_x_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2_set_offset_x(bma2x2->bma2x2_client, (unsigned
+ char)data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t bma2x2_offset_y_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_offset_y(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_offset_y_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2_set_offset_y(bma2x2->bma2x2_client, (unsigned
+ char)data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t bma2x2_offset_z_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char data;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ if (bma2x2_get_offset_z(bma2x2->bma2x2_client, &data) < 0)
+ return snprintf(buf, PAGE_SIZE, "Read error\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data);
+
+}
+
+static ssize_t bma2x2_offset_z_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if (bma2x2_set_offset_z(bma2x2->bma2x2_client, (unsigned
+ char)data) < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+#ifdef CONFIG_SIG_MOTION
+static int bma2x2_set_en_slope_int(struct bma2x2_data *bma2x2,
+ int en)
+{
+ int err;
+ struct i2c_client *client = bma2x2->bma2x2_client;
+
+ if (en) {
+ /* Set the related parameters which needs to be fine tuned by
+ * interfaces: slope_threshold and slope_duration
+ */
+ /*dur: 192 samples ~= 3s*/
+ err = bma2x2_set_slope_duration(client, BMA2X2_SMD_SLOPE_DUR);
+ err += bma2x2_set_slope_threshold(client, BMA2X2_SMD_SLOPE_TH);
+
+ /*Enable the interrupts*/
+ err += bma2x2_set_Int_Enable(client, 5, 1);/*Slope X*/
+ err += bma2x2_set_Int_Enable(client, 6, 1);/*Slope Y*/
+ err += bma2x2_set_Int_Enable(client, 7, 1);/*Slope Z*/
+ } else {
+ err = bma2x2_set_Int_Enable(client, 5, 0);/*Slope X*/
+ err += bma2x2_set_Int_Enable(client, 6, 0);/*Slope Y*/
+ err += bma2x2_set_Int_Enable(client, 7, 0);/*Slope Z*/
+ }
+ dev_dbg(&bma2x2->bma2x2_client->dev,
+ "bma2x2_set_en_slope_int en=%d, err=%d\n", en, err);
+ return err;
+}
+
+static ssize_t bma2x2_en_sig_motion_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ atomic_read(&bma2x2->en_sig_motion));
+}
+
+static int bma2x2_set_en_sig_motion(struct bma2x2_data *bma2x2,
+ int en)
+{
+ int err = 0;
+
+ en = (en >= 1) ? 1 : 0; /* set sig motion sensor status */
+
+ if (atomic_read(&bma2x2->en_sig_motion) != en) {
+ if (en) {
+ err = bma2x2_set_mode(bma2x2->bma2x2_client,
+ BMA2X2_MODE_NORMAL);
+ err = bma2x2_set_en_slope_int(bma2x2, en);
+ enable_irq_wake(bma2x2->IRQ);
+ } else {
+ disable_irq_wake(bma2x2->IRQ);
+ err = bma2x2_set_en_slope_int(bma2x2, en);
+ err = bma2x2_set_mode(bma2x2->bma2x2_client,
+ BMA2X2_MODE_SUSPEND);
+ }
+ atomic_set(&bma2x2->en_sig_motion, en);
+ }
+ return err;
+}
+
+static int bma2x2_smd_enable(struct bma2x2_data *bma2x2, bool enable)
+{
+ struct i2c_client *client = bma2x2->bma2x2_client;
+ int acc_enable = atomic_read(&bma2x2->enable);
+ int smd_enable = atomic_read(&bma2x2->en_sig_motion);
+ int err = 0;
+
+ mutex_lock(&bma2x2->enable_mutex);
+ if (enable && !smd_enable) {
+ if (!acc_enable) {
+ if (bma2x2_power_ctl(bma2x2, true)) {
+ err = -EBUSY;
+ goto mutex_exit;
+ }
+ if (bma2x2_open_init(client, bma2x2) < 0) {
+ bma2x2_power_ctl(bma2x2, false);
+ err = -EBUSY;
+ goto mutex_exit;
+ }
+ bma2x2_pinctrl_state(bma2x2, true);
+ bma2x2_set_mode(client, BMA2X2_MODE_NORMAL);
+ }
+ err = bma2x2_set_en_slope_int(bma2x2, enable);
+ if (err) {
+ bma2x2_set_mode(client, BMA2X2_MODE_SUSPEND);
+ bma2x2_pinctrl_state(bma2x2, false);
+ bma2x2_power_ctl(bma2x2, false);
+ goto mutex_exit;
+ }
+ if (!acc_enable) {
+ bma2x2_config_interrupt(bma2x2, true);
+ enable_irq(bma2x2->IRQ);
+ }
+ enable_irq_wake(bma2x2->IRQ);
+ atomic_set(&bma2x2->en_sig_motion, 1);
+ } else if (!enable && smd_enable) {
+ disable_irq_wake(bma2x2->IRQ);
+ if (!acc_enable)
+ disable_irq(bma2x2->IRQ);
+
+ err = bma2x2_set_en_slope_int(bma2x2, enable);
+ if (err)
+ goto mutex_exit;
+ if (!acc_enable) {
+ bma2x2_store_state(client, bma2x2);
+ bma2x2_set_mode(client, BMA2X2_MODE_SUSPEND);
+ bma2x2_pinctrl_state(bma2x2, false);
+ bma2x2_power_ctl(bma2x2, false);
+ }
+ atomic_set(&bma2x2->en_sig_motion, 0);
+ } else {
+ dev_err(&bma2x2->bma2x2_client->dev,
+ "SMD state incorrect! enable=%d, state=%d\n",
+ enable, smd_enable);
+ }
+
+mutex_exit:
+ mutex_unlock(&bma2x2->enable_mutex);
+ if (err)
+ dev_err(&client->dev, "Set SMD error! enable=%d, err=%d\n",
+ enable, err);
+ return err;
+}
+
+static int bma2x2_smd_cdev_enable(struct sensors_classdev *sensors_cdev,
+ unsigned int enable)
+{
+ struct bma2x2_data *bma2x2 = container_of(sensors_cdev,
+ struct bma2x2_data, smd_cdev);
+
+ return bma2x2_smd_enable(bma2x2, !!enable);
+}
+
+static ssize_t bma2x2_en_sig_motion_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if ((data == 0) || (data == 1))
+ bma2x2_set_en_sig_motion(bma2x2, data);
+
+ return count;
+}
+#endif /* CONFIG_SIG_MOTION */
+
+#ifdef CONFIG_DOUBLE_TAP
+static int bma2x2_set_en_single_tap_int(struct bma2x2_data *bma2x2, int en)
+{
+ int err;
+ struct i2c_client *client = bma2x2->bma2x2_client;
+
+ if (en) {
+ /* set tap interruption parameter here if needed.
+ bma2x2_set_tap_duration(client, 0xc0);
+ bma2x2_set_tap_threshold(client, 0x16);
+ */
+
+ /*Enable the single tap interrupts*/
+ err = bma2x2_set_Int_Enable(client, 8, 1);
+ #ifdef BMA2X2_ENABLE_INT1
+ err += bma2x2_set_int1_pad_sel(client, PAD_SINGLE_TAP);
+ #else
+ err += bma2x2_set_int2_pad_sel(client, PAD_SINGLE_TAP);
+ #endif
+ } else {
+ err = bma2x2_set_Int_Enable(client, 8, 0);
+ }
+ return err;
+}
+
+static ssize_t bma2x2_tap_time_period_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", bma2x2->tap_time_period);
+}
+
+static ssize_t bma2x2_tap_time_period_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ bma2x2->tap_time_period = data;
+
+ return count;
+}
+
+static ssize_t bma2x2_en_double_tap_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ atomic_read(&bma2x2->en_double_tap));
+}
+
+static int bma2x2_set_en_double_tap(struct bma2x2_data *bma2x2,
+ int en)
+{
+ int err = 0;
+
+ en = (en >= 1) ? 1 : 0;
+
+ if (atomic_read(&bma2x2->en_double_tap) != en) {
+ if (en) {
+ err = bma2x2_set_mode(bma2x2->bma2x2_client,
+ BMA2X2_MODE_NORMAL);
+ err = bma2x2_set_en_single_tap_int(bma2x2, en);
+ } else {
+ err = bma2x2_set_en_single_tap_int(bma2x2, en);
+ err = bma2x2_set_mode(bma2x2->bma2x2_client,
+ BMA2X2_MODE_SUSPEND);
+ }
+ atomic_set(&bma2x2->en_double_tap, en);
+ }
+ return err;
+}
+
+static ssize_t bma2x2_en_double_tap_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);
+
+ error = kstrtoul(buf, 10, &data);
+ if (error)
+ return error;
+
+ if ((data == 0) || (data == 1))
+ bma2x2_set_en_double_tap(bma2x2, data);
+
+ return count;
+}
+
+static void bma2x2_tap_timeout_handle(unsigned long data)
+{
+ struct bma2x2_data *bma2x2 = (struct bma2x2_data *)data;
+
+ dev_dbg(&bma2x2->bma2x2_client->dev,
+ "tap interrupt handle, timeout\n");
+ mutex_lock(&bma2x2->tap_mutex);
+ bma2x2->tap_times = 0;
+ mutex_unlock(&bma2x2->tap_mutex);
+
+ /* if a single tap need to report, open the define */
+#ifdef REPORT_SINGLE_TAP_WHEN_DOUBLE_TAP_SENSOR_ENABLED
+ input_report_rel(bma2x2->dev_interrupt,
+ SINGLE_TAP_INTERRUPT,
+ SINGLE_TAP_INTERRUPT_HAPPENED);
+ input_sync(bma2x2->dev_interrupt);
+#endif
+
+}
+#endif
+
+static DEVICE_ATTR(range, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_range_show, bma2x2_range_store);
+static DEVICE_ATTR(bandwidth, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_bandwidth_show, bma2x2_bandwidth_store);
+static DEVICE_ATTR(op_mode, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_mode_show, bma2x2_mode_store);
+static DEVICE_ATTR(value, S_IRUSR|S_IRGRP,
+ bma2x2_value_show, NULL);
+static DEVICE_ATTR(value_cache, S_IRUSR|S_IRGRP,
+ bma2x2_value_cache_show, NULL);
+static DEVICE_ATTR(delay, S_IRUSR|S_IRGRP|S_IWUSR|S_IWGRP,
+ bma2x2_delay_show, bma2x2_delay_store);
+static DEVICE_ATTR(enable, S_IRUSR|S_IRGRP|S_IWUSR|S_IWGRP,
+ bma2x2_enable_show, bma2x2_enable_store);
+static DEVICE_ATTR(SleepDur, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_SleepDur_show, bma2x2_SleepDur_store);
+static DEVICE_ATTR(fast_calibration_x, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_fast_calibration_x_show,
+ bma2x2_fast_calibration_x_store);
+static DEVICE_ATTR(fast_calibration_y, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_fast_calibration_y_show,
+ bma2x2_fast_calibration_y_store);
+static DEVICE_ATTR(fast_calibration_z, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_fast_calibration_z_show,
+ bma2x2_fast_calibration_z_store);
+static DEVICE_ATTR(fifo_mode, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_fifo_mode_show, bma2x2_fifo_mode_store);
+static DEVICE_ATTR(fifo_framecount, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_fifo_framecount_show, bma2x2_fifo_framecount_store);
+static DEVICE_ATTR(fifo_trig, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_fifo_trig_show, bma2x2_fifo_trig_store);
+static DEVICE_ATTR(fifo_trig_src, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_fifo_trig_src_show, bma2x2_fifo_trig_src_store);
+static DEVICE_ATTR(fifo_data_sel, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_fifo_data_sel_show, bma2x2_fifo_data_sel_store);
+static DEVICE_ATTR(fifo_data_frame, S_IRUSR|S_IRGRP,
+ bma2x2_fifo_data_out_frame_show, NULL);
+static DEVICE_ATTR(reg, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_register_show, bma2x2_register_store);
+static DEVICE_ATTR(chip_id, S_IRUSR|S_IRGRP,
+ bma2x2_chip_id_show, NULL);
+static DEVICE_ATTR(offset_x, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_offset_x_show,
+ bma2x2_offset_x_store);
+static DEVICE_ATTR(offset_y, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_offset_y_show,
+ bma2x2_offset_y_store);
+static DEVICE_ATTR(offset_z, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_offset_z_show,
+ bma2x2_offset_z_store);
+static DEVICE_ATTR(enable_int, S_IWUSR,
+ NULL, bma2x2_enable_int_store);
+static DEVICE_ATTR(int_mode, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_int_mode_show, bma2x2_int_mode_store);
+static DEVICE_ATTR(slope_duration, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_slope_duration_show, bma2x2_slope_duration_store);
+static DEVICE_ATTR(slope_threshold, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_slope_threshold_show, bma2x2_slope_threshold_store);
+static DEVICE_ATTR(slope_no_mot_duration, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_slope_no_mot_duration_show,
+ bma2x2_slope_no_mot_duration_store);
+static DEVICE_ATTR(slope_no_mot_threshold, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_slope_no_mot_threshold_show,
+ bma2x2_slope_no_mot_threshold_store);
+static DEVICE_ATTR(high_g_duration, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_high_g_duration_show, bma2x2_high_g_duration_store);
+static DEVICE_ATTR(high_g_threshold, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_high_g_threshold_show, bma2x2_high_g_threshold_store);
+static DEVICE_ATTR(low_g_duration, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_low_g_duration_show, bma2x2_low_g_duration_store);
+static DEVICE_ATTR(low_g_threshold, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_low_g_threshold_show, bma2x2_low_g_threshold_store);
+static DEVICE_ATTR(tap_duration, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_tap_duration_show, bma2x2_tap_duration_store);
+static DEVICE_ATTR(tap_threshold, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_tap_threshold_show, bma2x2_tap_threshold_store);
+static DEVICE_ATTR(tap_quiet, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_tap_quiet_show, bma2x2_tap_quiet_store);
+static DEVICE_ATTR(tap_shock, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_tap_shock_show, bma2x2_tap_shock_store);
+static DEVICE_ATTR(tap_samp, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_tap_samp_show, bma2x2_tap_samp_store);
+static DEVICE_ATTR(orient_mode, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_orient_mode_show, bma2x2_orient_mode_store);
+static DEVICE_ATTR(orient_blocking, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_orient_blocking_show, bma2x2_orient_blocking_store);
+static DEVICE_ATTR(orient_hyst, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_orient_hyst_show, bma2x2_orient_hyst_store);
+static DEVICE_ATTR(orient_theta, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_orient_theta_show, bma2x2_orient_theta_store);
+static DEVICE_ATTR(flat_theta, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_flat_theta_show, bma2x2_flat_theta_store);
+static DEVICE_ATTR(flat_hold_time, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_flat_hold_time_show, bma2x2_flat_hold_time_store);
+static DEVICE_ATTR(selftest, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_selftest_show, bma2x2_selftest_store);
+static DEVICE_ATTR(softreset, S_IWUSR,
+ NULL, bma2x2_softreset_store);
+static DEVICE_ATTR(temperature, S_IRUSR|S_IRGRP,
+ bma2x2_temperature_show, NULL);
+static DEVICE_ATTR(place, S_IRUSR|S_IRGRP,
+ bma2x2_place_show, NULL);
+#ifdef CONFIG_SIG_MOTION
+static DEVICE_ATTR(en_sig_motion, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_en_sig_motion_show, bma2x2_en_sig_motion_store);
+#endif
+#ifdef CONFIG_DOUBLE_TAP
+static DEVICE_ATTR(tap_time_period, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_tap_time_period_show, bma2x2_tap_time_period_store);
+static DEVICE_ATTR(en_double_tap, S_IRUSR|S_IRGRP|S_IWUSR,
+ bma2x2_en_double_tap_show, bma2x2_en_double_tap_store);
+#endif
+
+static struct attribute *bma2x2_attributes[] = {
+ &dev_attr_range.attr,
+ &dev_attr_bandwidth.attr,
+ &dev_attr_op_mode.attr,
+ &dev_attr_value.attr,
+ &dev_attr_value_cache.attr,
+ &dev_attr_delay.attr,
+ &dev_attr_enable.attr,
+ &dev_attr_SleepDur.attr,
+ &dev_attr_reg.attr,
+ &dev_attr_fast_calibration_x.attr,
+ &dev_attr_fast_calibration_y.attr,
+ &dev_attr_fast_calibration_z.attr,
+ &dev_attr_fifo_mode.attr,
+ &dev_attr_fifo_framecount.attr,
+ &dev_attr_fifo_trig.attr,
+ &dev_attr_fifo_trig_src.attr,
+ &dev_attr_fifo_data_sel.attr,
+ &dev_attr_fifo_data_frame.attr,
+ &dev_attr_chip_id.attr,
+ &dev_attr_offset_x.attr,
+ &dev_attr_offset_y.attr,
+ &dev_attr_offset_z.attr,
+ &dev_attr_enable_int.attr,
+ &dev_attr_int_mode.attr,
+ &dev_attr_slope_duration.attr,
+ &dev_attr_slope_threshold.attr,
+ &dev_attr_slope_no_mot_duration.attr,
+ &dev_attr_slope_no_mot_threshold.attr,
+ &dev_attr_high_g_duration.attr,
+ &dev_attr_high_g_threshold.attr,
+ &dev_attr_low_g_duration.attr,
+ &dev_attr_low_g_threshold.attr,
+ &dev_attr_tap_threshold.attr,
+ &dev_attr_tap_duration.attr,
+ &dev_attr_tap_quiet.attr,
+ &dev_attr_tap_shock.attr,
+ &dev_attr_tap_samp.attr,
+ &dev_attr_orient_mode.attr,
+ &dev_attr_orient_blocking.attr,
+ &dev_attr_orient_hyst.attr,
+ &dev_attr_orient_theta.attr,
+ &dev_attr_flat_theta.attr,
+ &dev_attr_flat_hold_time.attr,
+ &dev_attr_selftest.attr,
+ &dev_attr_softreset.attr,
+ &dev_attr_temperature.attr,
+ &dev_attr_place.attr,
+#ifdef CONFIG_SIG_MOTION
+ &dev_attr_en_sig_motion.attr,
+#endif
+#ifdef CONFIG_DOUBLE_TAP
+ &dev_attr_en_double_tap.attr,
+#endif
+
+ NULL
+};
+
+static struct attribute_group bma2x2_attribute_group = {
+ .attrs = bma2x2_attributes
+};
+
+#ifdef CONFIG_SIG_MOTION
+static struct attribute *bma2x2_sig_motion_attributes[] = {
+ &dev_attr_slope_duration.attr,
+ &dev_attr_slope_threshold.attr,
+ &dev_attr_en_sig_motion.attr,
+ NULL
+};
+static struct attribute_group bma2x2_sig_motion_attribute_group = {
+ .attrs = bma2x2_sig_motion_attributes
+};
+#endif
+
+#ifdef CONFIG_DOUBLE_TAP
+static struct attribute *bma2x2_double_tap_attributes[] = {
+ &dev_attr_tap_threshold.attr,
+ &dev_attr_tap_duration.attr,
+ &dev_attr_tap_quiet.attr,
+ &dev_attr_tap_shock.attr,
+ &dev_attr_tap_samp.attr,
+ &dev_attr_tap_time_period.attr,
+ &dev_attr_en_double_tap.attr,
+ NULL
+};
+static struct attribute_group bma2x2_double_tap_attribute_group = {
+ .attrs = bma2x2_double_tap_attributes
+};
+#endif
+
+
+#if defined(BMA2X2_ENABLE_INT1) || defined(BMA2X2_ENABLE_INT2)
+#ifdef ENABLE_ISR_DEBUG_MSG
+static unsigned char *orient[] = {"upward looking portrait upright",
+ "upward looking portrait upside-down",
+ "upward looking landscape left",
+ "upward looking landscape right",
+ "downward looking portrait upright",
+ "downward looking portrait upside-down",
+ "downward looking landscape left",
+ "downward looking landscape right"};
+#endif
+
+
+static void bma2x2_high_g_interrupt_handle(struct bma2x2_data *bma2x2)
+{
+ unsigned char first_value = 0;
+ unsigned char sign_value = 0;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ bma2x2_get_HIGH_first(bma2x2->bma2x2_client, i, &first_value);
+ if (first_value == 1) {
+ bma2x2_get_HIGH_sign(bma2x2->bma2x2_client,
+ &sign_value);
+ if (sign_value == 1) {
+ if (i == 0)
+ input_report_rel(bma2x2->dev_interrupt,
+ HIGH_G_INTERRUPT,
+ HIGH_G_INTERRUPT_X_N);
+ if (i == 1)
+ input_report_rel(bma2x2->dev_interrupt,
+ HIGH_G_INTERRUPT,
+ HIGH_G_INTERRUPT_Y_N);
+ if (i == 2)
+ input_report_rel(bma2x2->dev_interrupt,
+ HIGH_G_INTERRUPT,
+ HIGH_G_INTERRUPT_Z_N);
+ } else {
+ if (i == 0)
+ input_report_rel(bma2x2->dev_interrupt,
+ HIGH_G_INTERRUPT,
+ HIGH_G_INTERRUPT_X);
+ if (i == 1)
+ input_report_rel(bma2x2->dev_interrupt,
+ HIGH_G_INTERRUPT,
+ HIGH_G_INTERRUPT_Y);
+ if (i == 2)
+ input_report_rel(bma2x2->dev_interrupt,
+ HIGH_G_INTERRUPT,
+ HIGH_G_INTERRUPT_Z);
+ }
+ }
+
+ ISR_INFO(&bma2x2->bma2x2_client->dev,
+ "High G interrupt happened,exis is %d, first is %d,sign is %d\n",
+ i, first_value, sign_value);
+ }
+}
+
+#ifndef CONFIG_SIG_MOTION
+static void bma2x2_slope_interrupt_handle(struct bma2x2_data *bma2x2)
+{
+ unsigned char first_value = 0;
+ unsigned char sign_value = 0;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ bma2x2_get_slope_first(bma2x2->bma2x2_client, i, &first_value);
+ if (first_value == 1) {
+ bma2x2_get_slope_sign(bma2x2->bma2x2_client,
+ &sign_value);
+ if (sign_value == 1) {
+ if (i == 0)
+ input_report_rel(bma2x2->dev_interrupt,
+ SLOP_INTERRUPT,
+ SLOPE_INTERRUPT_X_N);
+ if (i == 1)
+ input_report_rel(bma2x2->dev_interrupt,
+ SLOP_INTERRUPT,
+ SLOPE_INTERRUPT_Y_N);
+ if (i == 2)
+ input_report_rel(bma2x2->dev_interrupt,
+ SLOP_INTERRUPT,
+ SLOPE_INTERRUPT_Z_N);
+ } else {
+ if (i == 0)
+ input_report_rel(bma2x2->dev_interrupt,
+ SLOP_INTERRUPT,
+ SLOPE_INTERRUPT_X);
+ if (i == 1)
+ input_report_rel(bma2x2->dev_interrupt,
+ SLOP_INTERRUPT,
+ SLOPE_INTERRUPT_Y);
+ if (i == 2)
+ input_report_rel(bma2x2->dev_interrupt,
+ SLOP_INTERRUPT,
+ SLOPE_INTERRUPT_Z);
+
+ }
+ }
+
+ ISR_INFO(&bma2x2->bma2x2_client->dev,
+ "Slop interrupt happened,exis is %d, first is %d,sign is %d\n",
+ i, first_value, sign_value);
+ }
+}
+#endif
+
+#ifdef CONFIG_BMA_ENABLE_NEWDATA_INT
+static void bma2x2_read_new_data(struct bma2x2_data *bma2x2)
+{
+ struct bma2x2acc value;
+
+ bma2x2_report_axis_data(bma2x2, &value);
+ mutex_lock(&bma2x2->value_mutex);
+ bma2x2->value = value;
+ mutex_unlock(&bma2x2->value_mutex);
+}
+#else
+static void bma2x2_read_new_data(struct bma2x2_data *bma2x2)
+{
+
+}
+#endif
+
+#ifdef CONFIG_SIG_MOTION
+static int bma2x2_register_smd(struct bma2x2_data *bma2x2, bool enable)
+{
+ struct input_dev *smd_input;
+ int err;
+
+ if (!enable) {
+ sensors_classdev_unregister(&bma2x2->smd_cdev);
+ return 0;
+ }
+
+ smd_input = devm_input_allocate_device(&bma2x2->bma2x2_client->dev);
+ if (IS_ERR_OR_NULL(smd_input)) {
+ dev_err(&bma2x2->bma2x2_client->dev,
+ "Cannot allocate SMD device\n");
+ return -ENOMEM;
+ }
+
+ smd_input->name = "bma2x2-smd";
+ smd_input->id.bustype = BUS_I2C;
+ input_set_capability(smd_input, EV_ABS, ABS_MISC);
+ input_set_drvdata(smd_input, bma2x2);
+
+ err = input_register_device(smd_input);
+ if (err < 0) {
+ dev_err(&bma2x2->bma2x2_client->dev,
+ "Cannot register input interrupt device\n");
+ input_free_device(smd_input);
+ return err;
+ }
+
+ if (!bma2x2->pdata->int_en) {
+ dev_err(&bma2x2->bma2x2_client->dev,
+ "SMD need interrupt for wakeup!\n");
+ input_unregister_device(smd_input);
+ return -EINVAL;
+ }
+
+ bma2x2->smd_cdev = smd_cdev;
+ bma2x2->smd_cdev.sensors_enable = bma2x2_smd_cdev_enable;
+ err = sensors_classdev_register(&bma2x2->smd_input->dev,
+ &bma2x2->smd_cdev);
+ if (err)
+ dev_err(&bma2x2->bma2x2_client->dev,
+ "Create SMD device file failed!\n");
+
+ bma2x2->smd_input = smd_input;
+
+ return err;
+}
+#else
+static inline int bma2x2_register_smd(struct bma2x2_data *bma2x2, bool enable)
+{
+ dev_err(&bma2x2->bma2x2_client->dev,
+ "SMD feature is not enabled!\n");
+ return -EINVAL;
+}
+#endif
+
+#ifdef CONFIG_SIG_MOTION
+static void bma2x2_report_sig_motion(struct bma2x2_data *bma2x2)
+{
+ ktime_t ts;
+
+ ts = ktime_get_boottime();
+
+ ISR_INFO(&bma2x2->bma2x2_client->dev,
+ "REPORT Significant motion interrupt\n");
+ pm_wakeup_event(&bma2x2->smd_input->dev, 200);
+ /* report SMD event */
+ input_report_abs(bma2x2->smd_input, ABS_MISC,
+ bma2x2->smd_count++);
+ input_event(bma2x2->smd_input, EV_SYN, SYN_TIME_SEC,
+ ktime_to_timespec(ts).tv_sec);
+ input_event(bma2x2->smd_input, EV_SYN, SYN_TIME_NSEC,
+ ktime_to_timespec(ts).tv_nsec);
+ input_sync(bma2x2->smd_input);
+}
+
+#ifdef BMA2X2_SMD_SW_ENHANCE
+
+static bool bma2x2_detect_sig_motion(struct bma2x2_data *bma2x2)
+{
+ static int det_cnt;
+ static s64 last_ns;
+ ktime_t ts;
+
+ ts = ktime_get_boottime();
+ dev_dbg(&bma2x2->bma2x2_client->dev,
+ "ts=%lld, lastns=%lld, delta=%lld, det_cnt=%d\n",
+ ts.tv64, last_ns, (ts.tv64 - last_ns), det_cnt);
+ if (last_ns == 0) {
+ last_ns = ts.tv64;
+ return false;
+ }
+ if (ts.tv64 - last_ns < BMA2X2_SMD_DET_TIME_NS)
+ det_cnt++;
+ else
+ det_cnt = 0;
+
+ last_ns = ts.tv64;
+
+ if (det_cnt >= BMA2X2_SMD_DET_CNT) {
+ det_cnt = 0;
+ return true;
+ } else {
+ return false;
+ }
+}
+#else
+static bool bma2x2_detect_sig_motion(struct bma2x2_data *bma2x2)
+{
+ return true;
+}
+#endif /* !BMA2X2_SMD_SW_ENHANCE */
+#endif
+
+static void bma2x2_irq_work_func(struct work_struct *work)
+{
+ struct bma2x2_data *bma2x2 = container_of((struct work_struct *)work,
+ struct bma2x2_data, irq_work);
+ struct i2c_client *client = bma2x2->bma2x2_client;
+ unsigned char intstatus[2] = {0};
+ unsigned char first_value = 0;
+ unsigned char sign_value = 0;
+ int ret;
+
+ ret = bma2x2_smbus_read_byte_block(client,
+ BMA2X2_STATUS1_REG, intstatus, ARRAY_SIZE(intstatus));
+ if (ret) {
+ dev_err(&client->dev,
+ "read interrupt status2 err, err=%d\n", ret);
+ return;
+ }
+
+ ISR_INFO(&client->dev,
+ "bma2x2_irq_work_func, intstatus=0x%x,0x%x\n",
+ intstatus[0], intstatus[1]);
+
+ if (intstatus[1] & BMA2X2_IS_FIFO_INT)
+ bma2x2_flush_fifo(bma2x2);
+ if (intstatus[1] & BMA2X2_IS_NEWDATA_INT)
+ bma2x2_read_new_data(bma2x2);
+ if ((intstatus[1] == 0) && (intstatus[0] == 0)) {
+ /*
+ * Read new data if no other interrupt is triggered.
+ * BMA2x2 data ready flag will be cleared if new data
+ * acquisition is started, sometimes we cannot get that flag.
+ */
+ bma2x2_read_new_data(bma2x2);
+ return;
+ }
+
+#ifdef CONFIG_SIG_MOTION
+ if (intstatus[0] & 0x04) {
+ if (atomic_read(&bma2x2->en_sig_motion) == 1) {
+ ISR_INFO(&bma2x2->bma2x2_client->dev,
+ "Significant motion interrupt happened\n");
+ if (bma2x2_detect_sig_motion(bma2x2)) {
+ /*
+ * Close signification motion sensor,
+ * it will be open again if APP wants
+ */
+
+ bma2x2_smd_enable(bma2x2, false);
+ bma2x2_report_sig_motion(bma2x2);
+ }
+ }
+ }
+#endif
+
+#ifdef CONFIG_DOUBLE_TAP
+ if (intstatus[0] & 0x20) {
+ if (atomic_read(&bma2x2->en_double_tap) == 1) {
+ ISR_INFO(&bma2x2->bma2x2_client->dev,
+ "single tap interrupt happened\n");
+ bma2x2_set_Int_Enable(client, 8, 0);
+ if (bma2x2->tap_times == 0) {
+ mod_timer(&bma2x2->tap_timer, jiffies +
+ msecs_to_jiffies(bma2x2->tap_time_period));
+ bma2x2->tap_times = 1;
+ } else {
+ /* only double tap is judged */
+ ISR_INFO(&bma2x2->bma2x2_client->dev,
+ "double tap\n");
+ mutex_lock(&bma2x2->tap_mutex);
+ bma2x2->tap_times = 0;
+ del_timer(&bma2x2->tap_timer);
+ mutex_unlock(&bma2x2->tap_mutex);
+ input_report_rel(bma2x2->dev_interrupt,
+ DOUBLE_TAP_INTERRUPT,
+ DOUBLE_TAP_INTERRUPT_HAPPENED);
+ input_sync(bma2x2->dev_interrupt);
+ }
+ bma2x2_set_Int_Enable(client, 8, 1);
+ }
+ }
+#endif
+
+ switch (intstatus[0]) {
+ case 0x01:
+ ISR_INFO(&bma2x2->bma2x2_client->dev,
+ "Low G interrupt happened\n");
+ input_report_rel(bma2x2->dev_interrupt, LOW_G_INTERRUPT,
+ LOW_G_INTERRUPT_HAPPENED);
+ break;
+
+ case 0x02:
+ bma2x2_high_g_interrupt_handle(bma2x2);
+ break;
+
+#ifndef CONFIG_SIG_MOTION
+ case 0x04:
+ bma2x2_slope_interrupt_handle(bma2x2);
+ break;
+#endif
+
+ case 0x08:
+ ISR_INFO(&bma2x2->bma2x2_client->dev,
+ "slow/ no motion interrupt happened\n");
+ input_report_rel(bma2x2->dev_interrupt,
+ SLOW_NO_MOTION_INTERRUPT,
+ SLOW_NO_MOTION_INTERRUPT_HAPPENED);
+ break;
+
+#ifndef CONFIG_DOUBLE_TAP
+ case 0x10:
+ ISR_INFO(&bma2x2->bma2x2_client->dev,
+ "double tap interrupt happened\n");
+ input_report_rel(bma2x2->dev_interrupt,
+ DOUBLE_TAP_INTERRUPT,
+ DOUBLE_TAP_INTERRUPT_HAPPENED);
+ break;
+ case 0x20:
+ ISR_INFO(&bma2x2->bma2x2_client->dev,
+ "single tap interrupt happened\n");
+ input_report_rel(bma2x2->dev_interrupt,
+ SINGLE_TAP_INTERRUPT,
+ SINGLE_TAP_INTERRUPT_HAPPENED);
+ break;
+#endif
+
+ case 0x40:
+ bma2x2_get_orient_status(bma2x2->bma2x2_client,
+ &first_value);
+ ISR_INFO(&bma2x2->bma2x2_client->dev,
+ "orient interrupt happened,%s\n",
+ orient[first_value]);
+ if (first_value == 0)
+ input_report_abs(bma2x2->dev_interrupt,
+ ORIENT_INTERRUPT,
+ UPWARD_PORTRAIT_UP_INTERRUPT_HAPPENED);
+ else if (first_value == 1)
+ input_report_abs(bma2x2->dev_interrupt,
+ ORIENT_INTERRUPT,
+ UPWARD_PORTRAIT_DOWN_INTERRUPT_HAPPENED);
+ else if (first_value == 2)
+ input_report_abs(bma2x2->dev_interrupt,
+ ORIENT_INTERRUPT,
+ UPWARD_LANDSCAPE_LEFT_INTERRUPT_HAPPENED);
+ else if (first_value == 3)
+ input_report_abs(bma2x2->dev_interrupt,
+ ORIENT_INTERRUPT,
+ UPWARD_LANDSCAPE_RIGHT_INTERRUPT_HAPPENED);
+ else if (first_value == 4)
+ input_report_abs(bma2x2->dev_interrupt,
+ ORIENT_INTERRUPT,
+ DOWNWARD_PORTRAIT_UP_INTERRUPT_HAPPENED);
+ else if (first_value == 5)
+ input_report_abs(bma2x2->dev_interrupt,
+ ORIENT_INTERRUPT,
+ DOWNWARD_PORTRAIT_DOWN_INTERRUPT_HAPPENED);
+ else if (first_value == 6)
+ input_report_abs(bma2x2->dev_interrupt,
+ ORIENT_INTERRUPT,
+ DOWNWARD_LANDSCAPE_LEFT_INTERRUPT_HAPPENED);
+ else if (first_value == 7)
+ input_report_abs(bma2x2->dev_interrupt,
+ ORIENT_INTERRUPT,
+ DOWNWARD_LANDSCAPE_RIGHT_INTERRUPT_HAPPENED);
+ break;
+ case 0x80:
+ bma2x2_get_orient_flat_status(bma2x2->bma2x2_client,
+ &sign_value);
+ ISR_INFO(&bma2x2->bma2x2_client->dev,
+ "flat interrupt happened,flat status is %d\n",
+ sign_value);
+ if (sign_value == 1) {
+ input_report_abs(bma2x2->dev_interrupt,
+ FLAT_INTERRUPT,
+ FLAT_INTERRUPT_TRUE_HAPPENED);
+ } else {
+ input_report_abs(bma2x2->dev_interrupt,
+ FLAT_INTERRUPT,
+ FLAT_INTERRUPT_FALSE_HAPPENED);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static irqreturn_t bma2x2_irq_handler(int irq, void *handle)
+{
+ struct bma2x2_data *data = handle;
+
+ if (data == NULL)
+ return IRQ_HANDLED;
+ if (data->bma2x2_client == NULL)
+ return IRQ_HANDLED;
+
+ queue_work(data->data_wq, &data->irq_work);
+
+ return IRQ_HANDLED;
+}
+#else
+static void bma2x2_irq_work_func(struct work_struct *work)
+{
+ struct bma2x2_data *bma2x2 = container_of((struct work_struct *)work,
+ struct bma2x2_data, irq_work);
+
+ dev_dbg(&bma2x2->bma2x2_client->dev,
+ "Interrupt feature is not enabled!\n");
+}
+
+static irqreturn_t bma2x2_irq_handler(int irq, void *handle)
+{
+ struct bma2x2_data *bma2x2 = handle;
+
+ dev_dbg(&bma2x2->bma2x2_client->dev,
+ "Interrupt feature is not enabled!\n");
+ return IRQ_HANDLED;
+}
+#endif /* defined(BMA2X2_ENABLE_INT1)||defined(BMA2X2_ENABLE_INT2) */
+
+static int bma2x2_power_ctl(struct bma2x2_data *data, bool on)
+{
+ int ret = 0;
+ int err = 0;
+
+ if (!on && data->power_enabled) {
+ ret = regulator_disable(data->vdd);
+ if (ret) {
+ dev_err(&data->bma2x2_client->dev,
+ "Regulator vdd disable failed ret=%d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_disable(data->vio);
+ if (ret) {
+ dev_err(&data->bma2x2_client->dev,
+ "Regulator vio disable failed ret=%d\n", ret);
+ err = regulator_enable(data->vdd);
+ return ret;
+ }
+ data->power_enabled = on;
+ } else if (on && !data->power_enabled) {
+ ret = regulator_enable(data->vdd);
+ if (ret) {
+ dev_err(&data->bma2x2_client->dev,
+ "Regulator vdd enable failed ret=%d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_enable(data->vio);
+ if (ret) {
+ dev_err(&data->bma2x2_client->dev,
+ "Regulator vio enable failed ret=%d\n", ret);
+ err = regulator_disable(data->vdd);
+ return ret;
+ }
+ data->power_enabled = on;
+ } else {
+ dev_info(&data->bma2x2_client->dev,
+ "Power on=%d. enabled=%d\n",
+ on, data->power_enabled);
+ }
+
+ return ret;
+}
+
+static int bma2x2_power_init(struct bma2x2_data *data)
+{
+ int ret;
+
+ data->vdd = regulator_get(&data->bma2x2_client->dev, "vdd");
+ if (IS_ERR(data->vdd)) {
+ ret = PTR_ERR(data->vdd);
+ dev_err(&data->bma2x2_client->dev,
+ "Regulator get failed vdd ret=%d\n", ret);
+ return ret;
+ }
+
+ if (regulator_count_voltages(data->vdd) > 0) {
+ ret = regulator_set_voltage(data->vdd,
+ BMA2x2_VDD_MIN_UV,
+ BMA2x2_VDD_MAX_UV);
+ if (ret) {
+ dev_err(&data->bma2x2_client->dev,
+ "Regulator set failed vdd ret=%d\n",
+ ret);
+ goto reg_vdd_put;
+ }
+ }
+
+ data->vio = regulator_get(&data->bma2x2_client->dev, "vio");
+ if (IS_ERR(data->vio)) {
+ ret = PTR_ERR(data->vio);
+ dev_err(&data->bma2x2_client->dev,
+ "Regulator get failed vio ret=%d\n", ret);
+ goto reg_vdd_set;
+ }
+
+ if (regulator_count_voltages(data->vio) > 0) {
+ ret = regulator_set_voltage(data->vio,
+ BMA2x2_VIO_MIN_UV,
+ BMA2x2_VIO_MAX_UV);
+ if (ret) {
+ dev_err(&data->bma2x2_client->dev,
+ "Regulator set failed vio ret=%d\n", ret);
+ goto reg_vio_put;
+ }
+ }
+
+ return 0;
+
+reg_vio_put:
+ regulator_put(data->vio);
+reg_vdd_set:
+ if (regulator_count_voltages(data->vdd) > 0)
+ regulator_set_voltage(data->vdd, 0, BMA2x2_VDD_MAX_UV);
+reg_vdd_put:
+ regulator_put(data->vdd);
+ return ret;
+}
+
+static int bma2x2_power_deinit(struct bma2x2_data *data)
+{
+ if (regulator_count_voltages(data->vdd) > 0)
+ regulator_set_voltage(data->vdd,
+ 0, BMA2x2_VDD_MAX_UV);
+
+ regulator_put(data->vdd);
+
+ if (regulator_count_voltages(data->vio) > 0)
+ regulator_set_voltage(data->vio,
+ 0, BMA2x2_VIO_MAX_UV);
+
+ regulator_put(data->vio);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static int bma2x2_parse_dt(struct device *dev,
+ struct bma2x2_platform_data *pdata)
+{
+ struct device_node *np = dev->of_node;
+ u32 temp_val;
+ int rc;
+
+ rc = of_property_read_u32(np, "bosch,init-interval", &temp_val);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Unable to read init-interval\n");
+ return rc;
+ }
+
+ pdata->poll_interval = temp_val;
+
+ rc = of_property_read_u32(np, "bosch,place", &temp_val);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Unable to read sensor place parameter\n");
+ return rc;
+ }
+ if (temp_val > 7) {
+ dev_err(dev, "Invalid place parameter, use default value 0\n");
+ pdata->place = 0;
+ } else {
+ pdata->place = temp_val;
+ }
+
+ pdata->int_en = of_property_read_bool(np, "bosch,use-interrupt");
+
+ pdata->use_int2 = of_property_read_bool(np, "bosch,use-int2");
+
+ pdata->use_smd = of_property_read_bool(np, "bosch,use-smd");
+
+ pdata->use_hrtimer = of_property_read_bool(np, "bosch,use-hrtimer");
+
+ pdata->gpio_int1 = of_get_named_gpio_flags(dev->of_node,
+ "bosch,gpio-int1", 0, &pdata->int1_flag);
+
+ pdata->gpio_int2 = of_get_named_gpio_flags(dev->of_node,
+ "bosch,gpio-int2", 0, &pdata->int2_flag);
+
+ return 0;
+}
+#else
+static int bma2x2_parse_dt(struct device *dev,
+ struct bma2x2_platform_data *pdata)
+{
+ return -EINVAL;
+}
+#endif
+
+#ifdef CONFIG_DOUBLE_TAP
+static void bma2x2_double_tap_disable(struct bma2x2_data *data)
+{
+ if (data->g_sensor_dev_doubletap) {
+ sysfs_remove_group(&data->g_sensor_dev_doubletap->kobj,
+ &bma2x2_double_tap_attribute_group);
+ device_destroy(data->g_sensor_dev_doubletap);
+ class_destroy(data->g_sensor_class_doubletap);
+ }
+}
+#else
+static void bma2x2_double_tap_disable(struct bma2x2_data *data)
+{
+
+}
+#endif
+
+#ifdef CONFIG_SIG_MOTION
+static void bma2x2_sig_motion_disable(struct bma2x2_data *data)
+{
+ if (data->g_sensor_dev) {
+ sysfs_remove_group(&data->g_sensor_dev->kobj,
+ &bma2x2_sig_motion_attribute_group);
+ device_destroy(data->g_sensor_class, 0);
+ class_destroy(data->g_sensor_class);
+ }
+}
+#else
+static void bma2x2_sig_motion_disable(struct bma2x2_data *data)
+{
+
+}
+#endif
+
+static int bma2x2_open_init(struct i2c_client *client,
+ struct bma2x2_data *data)
+{
+ int err;
+
+ err = bma2x2_set_bandwidth(client, data->bandwidth);
+ if (err < 0) {
+ dev_err(&client->dev, "init bandwidth error\n");
+ return err;
+ }
+ err = bma2x2_set_range(client, data->range);
+ if (err < 0) {
+ dev_err(&client->dev, "init bandwidth error\n");
+ return err;
+ }
+ return 0;
+}
+
+static int bma2x2_get_interrupt_gpio(const struct bma2x2_data *data,
+ const unsigned int gpio)
+{
+ struct i2c_client *client = data->bma2x2_client;
+ int err;
+
+ if (!gpio_is_valid(gpio)) {
+ dev_err(&client->dev,
+ "gpio(%d) is invalid,\n", gpio);
+ return -EINVAL;
+ }
+
+ err = gpio_request(gpio, "bma2x2_gpio_int");
+ if (err) {
+ dev_err(&client->dev,
+ "Unable to request gpio %d, err=%d\n",
+ gpio, err);
+ return err;
+ }
+
+ err = gpio_direction_input(gpio);
+ if (err) {
+ dev_err(&client->dev,
+ "Unable to set gpio direction %d, err=%d\n",
+ gpio, err);
+ gpio_free(gpio);
+ return err;
+ }
+
+ client->irq = gpio_to_irq(gpio);
+ dev_dbg(&client->dev, "Interrupt gpio=%d, irq=%d\n",
+ gpio, client->irq);
+
+ return 0;
+}
+
+static int bma2x2_pinctrl_init(struct bma2x2_data *data)
+{
+ struct i2c_client *client = data->bma2x2_client;
+ struct bma2x2_pinctrl_data *pctrl_data;
+ struct pinctrl *pctrl;
+ int ret = 0;
+
+ pctrl = devm_pinctrl_get(&client->dev);
+ if (IS_ERR_OR_NULL(pctrl)) {
+ ret = PTR_ERR(pctrl);
+ dev_err(&client->dev,
+ "Failed to get pin pinctrl, err:%d\n", ret);
+ goto exit;
+ }
+ pctrl_data = devm_kzalloc(&client->dev,
+ sizeof(*pctrl_data), GFP_KERNEL);
+ if (!pctrl_data) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+ pctrl_data->pctrl = pctrl;
+
+ pctrl_data->pins_default = pinctrl_lookup_state(pctrl, "default");
+ if (IS_ERR_OR_NULL(pctrl_data->pins_default)) {
+ ret = PTR_ERR(pctrl_data->pins_default);
+ dev_err(&client->dev,
+ "Could not get default pinstate, err:%d\n", ret);
+ goto exit;
+ }
+ /* "sleep" state is optional to compatible with old config */
+ pctrl_data->pins_sleep = pinctrl_lookup_state(pctrl, "sleep");
+ if (IS_ERR_OR_NULL(pctrl_data->pins_sleep)) {
+ dev_info(&client->dev,
+ "Could not get sleep pinstate, err:%ld\n",
+ PTR_ERR(pctrl_data->pins_sleep));
+ pctrl_data->pins_sleep = NULL;
+ }
+ data->pctrl_data = pctrl_data;
+
+exit:
+ return ret;
+}
+
+static void bma2x2_pinctrl_state(struct bma2x2_data *data,
+ bool active)
+{
+ struct device dev = data->bma2x2_client->dev;
+ int ret;
+
+ if (!data->pctrl_data)
+ return;
+
+ if (active) {
+ ret = pinctrl_select_state(data->pctrl_data->pctrl,
+ data->pctrl_data->pins_default);
+ if (ret)
+ dev_info(&dev,
+ "Select default pinstate err:%d\n", ret);
+ } else {
+ if (!data->pctrl_data->pins_sleep) {
+ dev_dbg(&dev, "Pinstate 'sleep' is not defined\n");
+ } else {
+ ret = pinctrl_select_state(data->pctrl_data->pctrl,
+ data->pctrl_data->pins_sleep);
+ if (ret)
+ dev_info(&dev, "Select sleep pinstate err:%d\n",
+ ret);
+ }
+ }
+ dev_dbg(&dev, "Select pinctrl state=%d\n", active);
+}
+
+static int bma2x2_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int err = 0;
+ struct bma2x2_data *data;
+ struct input_dev *dev;
+ struct bst_dev *dev_acc;
+ struct bma2x2_platform_data *pdata;
+ struct input_dev *dev_interrupt;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "i2c_check_functionality error\n");
+ err = -EPERM;
+ goto exit;
+ }
+ data = kzalloc(sizeof(struct bma2x2_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ memset(data, 0, sizeof(*data));
+
+ if (client->dev.of_node) {
+ pdata = devm_kzalloc(&client->dev,
+ sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ err = -ENOMEM;
+ goto kfree_exit;
+ }
+ err = bma2x2_parse_dt(&client->dev, pdata);
+ if (err) {
+ dev_err(&client->dev, "Failed to parse device tree\n");
+ err = -EINVAL;
+ goto pdata_free_exit;
+ }
+ } else {
+ pdata = client->dev.platform_data;
+ dev_err(&client->dev, "Use platform data\n");
+ }
+
+ if (!pdata) {
+ dev_err(&client->dev, "Cannot get device platform data\n");
+ err = -EINVAL;
+ goto kfree_exit;
+ }
+ data->pdata = pdata;
+ i2c_set_clientdata(client, data);
+ data->bma2x2_client = client;
+
+ err = bma2x2_power_init(data);
+ if (err) {
+ dev_err(&client->dev, "Failed to get sensor regulators\n");
+ err = -EINVAL;
+ goto free_i2c_clientdata_exit;
+ }
+ err = bma2x2_power_ctl(data, true);
+ if (err) {
+ dev_err(&client->dev, "Failed to enable sensor power\n");
+ err = -EINVAL;
+ goto deinit_power_exit;
+ }
+
+ RESET_DELAY();
+ if (bma2x2_soft_reset(client) < 0) {
+ dev_err(&client->dev,
+ "i2c bus write error, pls check HW connection\n");
+ err = -EINVAL;
+ goto disable_power_exit;
+ }
+ RESET_DELAY();
+ /* read and check chip id */
+ if (bma2x2_check_chip_id(client, data) < 0) {
+ err = -EINVAL;
+ goto disable_power_exit;
+ }
+ mutex_init(&data->value_mutex);
+ mutex_init(&data->mode_mutex);
+ mutex_init(&data->enable_mutex);
+ mutex_init(&data->op_lock);
+ data->bandwidth = BMA2X2_BW_SET;
+ data->range = BMA2X2_RANGE_SET;
+ data->sensitivity = bosch_sensor_range_map[0];
+ atomic_set(&data->cal_status, 0);
+ data->fifo_buf = NULL;
+ err = bma2x2_open_init(client, data);
+ if (err < 0) {
+ err = -EINVAL;
+ goto disable_power_exit;
+ }
+
+ if (pdata->int_en) {
+ /* check interrupt feature enable state */
+ err = bma2x2_pinctrl_init(data);
+ if (err) {
+ dev_err(&client->dev,
+ "Failed to init pinctrl err=%d\n", err);
+ err = -EINVAL;
+ goto disable_power_exit;
+ }
+
+ if ((pdata->use_int2 && (!BMA2x2_IS_INT2_ENABLED())) ||
+ (!pdata->use_int2 && (!BMA2x2_IS_INT1_ENABLED()))) {
+ dev_err(&client->dev,
+ "Interrupt support is not enabled, int1=%d, int2=%d use_int2=%d\n",
+ BMA2x2_IS_INT1_ENABLED(),
+ BMA2x2_IS_INT2_ENABLED(),
+ pdata->use_int2);
+ err = -EINVAL;
+ goto disable_power_exit;
+ }
+
+ if (pdata->use_int2) {
+ data->int_flag = pdata->int2_flag;
+ err = bma2x2_get_interrupt_gpio(data,
+ pdata->gpio_int2);
+ } else {
+ data->int_flag = pdata->int1_flag;
+ err = bma2x2_get_interrupt_gpio(data,
+ pdata->gpio_int1);
+ }
+ if (err) {
+ dev_err(&client->dev,
+ "Failed to get interrupt gpio, err=%d\n",
+ err);
+ err = -EINVAL;
+ goto set_pinctrl_sleep;
+ }
+
+ data->IRQ = client->irq;
+ if (!data->int_flag)
+ data->int_flag = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+
+ dev_dbg(&client->dev, "IRQ=%d, use_int2=%d, int_flag=0x%x\n",
+ data->IRQ, pdata->use_int2, data->int_flag);
+ err = request_irq(data->IRQ, bma2x2_irq_handler,
+ data->int_flag, "bma2x2", data);
+ if (err) {
+ dev_err(&client->dev, "Could not request irq\n");
+ goto free_interrupt_gpio;
+ }
+ disable_irq(data->IRQ);
+ device_init_wakeup(&client->dev, 1);
+
+ INIT_WORK(&data->irq_work, bma2x2_irq_work_func);
+ data->fifo_buf = devm_kmalloc(&client->dev,
+ (MAX_FIFO_F_LEVEL * MAX_FIFO_F_BYTES), GFP_KERNEL);
+ }
+
+ if (!pdata->use_hrtimer) {
+ INIT_DELAYED_WORK(&data->work, bma2x2_work_func);
+
+ if (!pdata->int_en || !BMA2x2_IS_NEWDATA_INT_ENABLED())
+ INIT_DELAYED_WORK(&data->work, bma2x2_work_func);
+
+ data->data_wq = create_freezable_workqueue("bma2x2_data_work");
+ if (!data->data_wq) {
+ dev_err(&client->dev, "Cannot get create workqueue!\n");
+ goto free_irq_exit;
+ }
+ } else {
+ hrtimer_init(&data->accel_timer,
+ CLOCK_BOOTTIME, HRTIMER_MODE_REL);
+ data->accel_timer.function = accel_timer_handle;
+
+ init_waitqueue_head(&data->accel_wq);
+ data->accel_wkp_flag = 0;
+ data->accel_task = kthread_run(accel_poll_thread, data,
+ "bma_accel");
+ }
+
+ atomic_set(&data->delay, POLL_DEFAULT_INTERVAL_MS);
+ atomic_set(&data->enable, 0);
+
+ dev = devm_input_allocate_device(&client->dev);
+ if (!dev) {
+ dev_err(&client->dev,
+ "Cannot allocate input device\n");
+ err = -ENOMEM;
+ goto destroy_workqueue_exit;
+ }
+
+ dev_interrupt = devm_input_allocate_device(&client->dev);
+ if (!dev_interrupt) {
+ dev_err(&client->dev,
+ "Cannot allocate input interrupt device\n");
+ err = -ENOMEM;
+ goto destroy_workqueue_exit;
+ }
+
+ /* only value events reported */
+ dev->name = SENSOR_NAME;
+ dev->id.bustype = BUS_I2C;
+ input_set_capability(dev, EV_ABS, ABS_MISC);
+ input_set_abs_params(dev, ABS_X, ABSMIN, ABSMAX, 0, 0);
+ input_set_abs_params(dev, ABS_Y, ABSMIN, ABSMAX, 0, 0);
+ input_set_abs_params(dev, ABS_Z, ABSMIN, ABSMAX, 0, 0);
+
+ input_set_drvdata(dev, data);
+ err = input_register_device(dev);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "Cannot register input device\n");
+ goto free_irq_exit;
+ }
+
+ /* all interrupt generated events are moved to interrupt input devices*/
+ dev_interrupt->name = "bma_interrupt";
+ dev_interrupt->id.bustype = BUS_I2C;
+ input_set_capability(dev_interrupt, EV_REL,
+ SLOW_NO_MOTION_INTERRUPT);
+ input_set_capability(dev_interrupt, EV_REL,
+ LOW_G_INTERRUPT);
+ input_set_capability(dev_interrupt, EV_REL,
+ HIGH_G_INTERRUPT);
+ input_set_capability(dev_interrupt, EV_REL,
+ SLOP_INTERRUPT);
+ input_set_capability(dev_interrupt, EV_REL,
+ DOUBLE_TAP_INTERRUPT);
+ input_set_capability(dev_interrupt, EV_REL,
+ SINGLE_TAP_INTERRUPT);
+ input_set_capability(dev_interrupt, EV_ABS,
+ ORIENT_INTERRUPT);
+ input_set_capability(dev_interrupt, EV_ABS,
+ FLAT_INTERRUPT);
+ input_set_drvdata(dev_interrupt, data);
+
+ err = input_register_device(dev_interrupt);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "Cannot register input interrupt device\n");
+ goto free_irq_exit;
+ }
+
+ data->dev_interrupt = dev_interrupt;
+ data->input = dev;
+
+#ifdef CONFIG_SIG_MOTION
+ data->g_sensor_class = class_create(THIS_MODULE, "sig_sensor");
+ if (IS_ERR(data->g_sensor_class)) {
+ err = PTR_ERR(data->g_sensor_class);
+ data->g_sensor_class = NULL;
+ dev_err(&client->dev, "could not allocate g_sensor_class\n");
+ goto free_irq_exit;
+ }
+
+ data->g_sensor_dev = device_create(data->g_sensor_class,
+ NULL, 0, "%s", "g_sensor");
+ if (unlikely(IS_ERR(data->g_sensor_dev))) {
+ err = PTR_ERR(data->g_sensor_dev);
+ data->g_sensor_dev = NULL;
+
+ dev_err(&client->dev, "could not allocate g_sensor_dev\n");
+ goto destroy_g_sensor_class_exit;
+ }
+
+ dev_set_drvdata(data->g_sensor_dev, data);
+
+ err = sysfs_create_group(&data->g_sensor_dev->kobj,
+ &bma2x2_sig_motion_attribute_group);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "could not create sysfs for sig motion sensor\n");
+ goto free_g_sensor_dev_exit;
+ }
+#endif
+
+#ifdef CONFIG_DOUBLE_TAP
+ data->g_sensor_class_doubletap =
+ class_create(THIS_MODULE, "dtap_sensor");
+ if (IS_ERR(data->g_sensor_class_doubletap)) {
+ err = PTR_ERR(data->g_sensor_class_doubletap);
+ data->g_sensor_class_doubletap = NULL;
+ dev_err(&client->dev, "could not allocate g_sensor_class_doubletap\n");
+ goto remove_sig_motion_sysfs_exit;
+ }
+
+ data->g_sensor_dev_doubletap = device_create(
+ data->g_sensor_class_doubletap,
+ NULL, 0, "%s", "g_sensor");
+ if (unlikely(IS_ERR(data->g_sensor_dev_doubletap))) {
+ err = PTR_ERR(data->g_sensor_dev_doubletap);
+ data->g_sensor_dev_doubletap = NULL;
+
+ dev_err(&client->dev, "could not allocate g_sensor_dev_doubletap\n");
+ goto destroy_dtap_class_exit;
+ }
+
+ dev_set_drvdata(data->g_sensor_dev_doubletap, data);
+
+ err = sysfs_create_group(&data->g_sensor_dev_doubletap->kobj,
+ &bma2x2_double_tap_attribute_group);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "could not create sysfs for double tap sensor\n");
+ goto destroy_dtap_dev_exit;
+ }
+#endif
+
+ err = sysfs_create_group(&data->input->dev.kobj,
+ &bma2x2_attribute_group);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "Cannot create sysfs for bma2x2\n");
+ goto remove_dtap_sysfs_exit;
+ }
+
+ dev_acc = bst_allocate_device();
+ if (!dev_acc) {
+ dev_err(&client->dev,
+ "Cannot allocate bst device\n");
+ err = -ENOMEM;
+ goto remove_bma2x2_sysfs_exit;
+ }
+ dev_acc->name = ACC_NAME;
+
+ bst_set_drvdata(dev_acc, data);
+
+ err = bst_register_device(dev_acc);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "Cannot register bst device\n");
+ goto bst_free_acc_exit;
+ }
+
+ data->bst_acc = dev_acc;
+ err = sysfs_create_group(&data->bst_acc->dev.kobj,
+ &bma2x2_attribute_group);
+
+ if (err < 0) {
+ dev_err(&client->dev,
+ "Cannot create sysfs for bst_acc.\n");
+ goto bst_free_exit;
+ }
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ data->early_suspend.suspend = bma2x2_early_suspend;
+ data->early_suspend.resume = bma2x2_late_resume;
+ register_early_suspend(&data->early_suspend);
+#endif
+
+ data->ref_count = 0;
+ data->fifo_datasel = 0;
+ data->fifo_count = 0;
+#ifdef CONFIG_SIG_MOTION
+ atomic_set(&data->en_sig_motion, 0);
+#endif
+#ifdef CONFIG_DOUBLE_TAP
+ atomic_set(&data->en_double_tap, 0);
+ data->tap_times = 0;
+ data->tap_time_period = DEFAULT_TAP_JUDGE_PERIOD;
+ mutex_init(&data->tap_mutex);
+ setup_timer(&data->tap_timer, bma2x2_tap_timeout_handle,
+ (unsigned long)data);
+#endif
+
+ data->cdev = sensors_cdev;
+ data->cdev.min_delay = POLL_INTERVAL_MIN_MS * 1000;
+ data->cdev.delay_msec = pdata->poll_interval;
+ data->cdev.sensors_enable = bma2x2_cdev_enable;
+ data->cdev.sensors_poll_delay = bma2x2_cdev_poll_delay;
+ data->cdev.sensors_calibrate = bma2x2_self_calibration_xyz;
+ data->cdev.sensors_write_cal_params = bma2x2_write_cal_params;
+ data->cdev.resolution = sensor_type_map[data->chip_type].resolution;
+ if (pdata->int_en) {
+ if (BMA2x2_IS_NEWDATA_INT_ENABLED())
+ data->cdev.max_delay = BMA_INT_MAX_DELAY;
+ data->cdev.sensors_set_latency = bma2x2_cdev_set_latency;
+ data->cdev.sensors_flush = bma2x2_cdev_flush;
+ data->cdev.fifo_max_event_count = MAX_FIFO_F_LEVEL;
+ data->cdev.fifo_reserved_event_count = MAX_FIFO_F_LEVEL;
+ }
+ err = sensors_classdev_register(&data->input->dev, &data->cdev);
+ if (err) {
+ dev_err(&client->dev, "Create class device file failed!\n");
+ err = -EINVAL;
+ goto remove_bst_acc_sysfs_exit;
+ }
+
+ if (pdata->use_smd) {
+ err = bma2x2_register_smd(data, true);
+ if (err)
+ dev_err(&client->dev, "Register SMD device failed!\n");
+ }
+
+ dev_notice(&client->dev, "BMA2x2 driver probe successfully");
+
+ bma2x2_pinctrl_state(data, false);
+ bma2x2_power_ctl(data, false);
+ return 0;
+
+remove_bst_acc_sysfs_exit:
+ sysfs_remove_group(&data->bst_acc->dev.kobj,
+ &bma2x2_attribute_group);
+bst_free_exit:
+ bst_unregister_device(dev_acc);
+
+bst_free_acc_exit:
+ bst_free_device(dev_acc);
+
+remove_bma2x2_sysfs_exit:
+ sysfs_remove_group(&data->input->dev.kobj,
+ &bma2x2_attribute_group);
+remove_dtap_sysfs_exit:
+#ifdef CONFIG_DOUBLE_TAP
+sysfs_remove_group(&data->g_sensor_dev_doubletap->kobj,
+ &bma2x2_double_tap_attribute_group);
+destroy_dtap_dev_exit:
+ device_destroy(data->g_sensor_dev_doubletap);
+destroy_dtap_class_exit:
+ class_destroy(data->g_sensor_class_doubletap);
+remove_sig_motion_sysfs_exit:
+#endif
+
+#ifdef CONFIG_SIG_MOTION
+sysfs_remove_group(&data->g_sensor_dev->kobj,
+ &bma2x2_sig_motion_attribute_group);
+free_g_sensor_dev_exit:
+ device_destroy(data->g_sensor_class, 0);
+destroy_g_sensor_class_exit:
+ class_destroy(data->g_sensor_class);
+#endif
+
+destroy_workqueue_exit:
+ if (!pdata->use_hrtimer) {
+ destroy_workqueue(data->data_wq);
+ } else {
+ hrtimer_cancel(&data->accel_timer);
+ kthread_stop(data->accel_task);
+ }
+free_irq_exit:
+free_interrupt_gpio:
+ if (pdata->int_en) {
+ if (pdata->use_int2)
+ gpio_free(pdata->gpio_int2);
+ else
+ gpio_free(pdata->gpio_int1);
+ }
+set_pinctrl_sleep:
+ if (pdata->int_en)
+ bma2x2_pinctrl_state(data, false);
+disable_power_exit:
+ bma2x2_power_ctl(data, false);
+deinit_power_exit:
+ bma2x2_power_deinit(data);
+free_i2c_clientdata_exit:
+ i2c_set_clientdata(client, NULL);
+pdata_free_exit:
+ if (pdata && (client->dev.of_node))
+ devm_kfree(&client->dev, pdata);
+ data->pdata = NULL;
+kfree_exit:
+ kfree(data);
+exit:
+ return err;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void bma2x2_early_suspend(struct early_suspend *h)
+{
+ struct bma2x2_data *data =
+ container_of(h, struct bma2x2_data, early_suspend);
+
+ mutex_lock(&data->enable_mutex);
+ if (atomic_read(&data->enable) == 1) {
+ bma2x2_set_mode(data->bma2x2_client, BMA2X2_MODE_SUSPEND);
+ if (!data->pdata->int_en) {
+ if (!data->pdata->use_hrtimer)
+ cancel_delayed_work_sync(&data->work);
+ else
+ hrtimer_cancel(&data->accel_timer);
+ }
+ }
+ mutex_unlock(&data->enable_mutex);
+}
+
+static void bma2x2_late_resume(struct early_suspend *h)
+{
+ struct bma2x2_data *data =
+ container_of(h, struct bma2x2_data, early_suspend);
+
+ mutex_lock(&data->enable_mutex);
+ if (atomic_read(&data->enable) == 1) {
+ bma2x2_set_mode(data->bma2x2_client, BMA2X2_MODE_NORMAL);
+ if (!data->pdata->int_en) {
+ if (!data->pdata->use_hrtimer) {
+ queue_delayed_work(data->data_wq,
+ &data->work,
+ msecs_to_jiffies(atomic_read(&data->delay)));
+ } else {
+ ktime = ktime_set(0,
+ atomic_read(&bma2x2->delay) * NSEC_PER_MSEC);
+ hrtimer_start(&bma2x2->accle_timer,
+ ktime, HRTIMER_MODE_REL);
+ }
+ }
+ }
+ mutex_unlock(&data->enable_mutex);
+}
+#endif
+
+static int bma2x2_remove(struct i2c_client *client)
+{
+ struct bma2x2_data *data = i2c_get_clientdata(client);
+
+ sensors_classdev_unregister(&data->cdev);
+ if (data->pdata && data->pdata->use_smd)
+ bma2x2_register_smd(data, false);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&data->early_suspend);
+#endif
+
+ if (data->bst_acc) {
+ bst_unregister_device(data->bst_acc);
+ bst_free_device(data->bst_acc);
+ }
+
+ bma2x2_double_tap_disable(data);
+
+ bma2x2_sig_motion_disable(data);
+
+ if (data->input)
+ sysfs_remove_group(&data->input->dev.kobj,
+ &bma2x2_attribute_group);
+
+ bma2x2_set_enable(&client->dev, 0);
+ if (data->pdata && !data->pdata->use_hrtimer) {
+ destroy_workqueue(data->data_wq);
+ } else {
+ hrtimer_cancel(&data->accel_timer);
+ kthread_stop(data->accel_task);
+ }
+ bma2x2_power_deinit(data);
+ i2c_set_clientdata(client, NULL);
+ if (data->pdata && (client->dev.of_node))
+ devm_kfree(&client->dev, data->pdata);
+ data->pdata = NULL;
+
+ kfree(data);
+
+ return 0;
+}
+
+static void bma2x2_shutdown(struct i2c_client *client)
+{
+ struct bma2x2_data *data = i2c_get_clientdata(client);
+
+ mutex_lock(&data->enable_mutex);
+ bma2x2_set_mode(data->bma2x2_client, BMA2X2_MODE_DEEP_SUSPEND);
+ mutex_unlock(&data->enable_mutex);
+}
+
+static int bma2x2_store_state(struct i2c_client *client,
+ struct bma2x2_data *data)
+{
+ int err;
+
+ err = bma2x2_get_bandwidth(client, &(data->bandwidth));
+ if (err < 0) {
+ dev_err(&client->dev, "get state bandwidth failed\n");
+ return err;
+ }
+ err = bma2x2_get_range(client, &(data->range));
+ if (err < 0) {
+ dev_err(&client->dev, "get state range failed\n");
+ return err;
+ }
+ return err;
+}
+
+#ifdef CONFIG_PM
+static int bma2x2_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ struct bma2x2_data *data = i2c_get_clientdata(client);
+
+ data->suspend_state.powerEn = bma2x2_is_power_enabled(data);
+ bma2x2_set_enable(&client->dev, 0);
+ return 0;
+}
+
+static int bma2x2_resume(struct i2c_client *client)
+{
+ struct bma2x2_data *data = i2c_get_clientdata(client);
+
+ if (data->suspend_state.powerEn)
+ bma2x2_set_enable(&client->dev, 1);
+
+ return 0;
+}
+
+#else
+
+#define bma2x2_suspend NULL
+#define bma2x2_resume NULL
+
+#endif /* CONFIG_PM */
+
+static const struct i2c_device_id bma2x2_id[] = {
+ { SENSOR_NAME, 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, bma2x2_id);
+
+static const struct of_device_id bma2x2_of_match[] = {
+ { .compatible = "bosch,bma2x2", },
+ { },
+};
+
+static struct i2c_driver bma2x2_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = SENSOR_NAME,
+ .of_match_table = bma2x2_of_match,
+ },
+ .suspend = bma2x2_suspend,
+ .resume = bma2x2_resume,
+ .id_table = bma2x2_id,
+ .probe = bma2x2_probe,
+ .remove = bma2x2_remove,
+ .shutdown = bma2x2_shutdown,
+};
+
+static int __init BMA2X2_init(void)
+{
+ return i2c_add_driver(&bma2x2_driver);
+}
+
+static void __exit BMA2X2_exit(void)
+{
+ i2c_del_driver(&bma2x2_driver);
+}
+
+MODULE_AUTHOR("contact@bosch-sensortec.com");
+MODULE_DESCRIPTION("BMA2X2 ACCELEROMETER SENSOR DRIVER");
+MODULE_LICENSE("GPL v2");
+
+module_init(BMA2X2_init);
+module_exit(BMA2X2_exit);
diff --git a/drivers/input/misc/bstclass.c b/drivers/input/misc/bstclass.c
new file mode 100644
index 000000000000..042eeff89ad5
--- /dev/null
+++ b/drivers/input/misc/bstclass.c
@@ -0,0 +1,270 @@
+/*!
+ * @section LICENSE
+ * (C) Copyright 2013 Bosch Sensortec GmbH All Rights Reserved
+ *
+ * This software program is licensed subject to the GNU General
+ * Public License (GPL).Version 2,June 1991,
+ * available at http://www.fsf.org/copyleft/gpl.html
+ *
+ * @filename bstclass.c
+ * @date "Wed Feb 19 13:22:52 2014 +0800"
+ * @id "6d7c0bb"
+ *
+ * @brief
+ * The core code of bst device driver
+*/
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/poll.h>
+#include <linux/mutex.h>
+#include <linux/rcupdate.h>
+#include <linux/compiler.h>
+#include <linux/compat.h>
+#include "bstclass.h"
+
+static LIST_HEAD(bst_dev_list);
+
+/*
+ * bst_mutex protects access to both bst_dev_list and input_handler_list.
+ * This also causes bst_[un]register_device and bst_[un]register_handler
+ * be mutually exclusive which simplifies locking in drivers implementing
+ * input handlers.
+ */
+static DEFINE_MUTEX(bst_mutex);
+
+
+static void bst_dev_release(struct device *device)
+{
+ struct bst_dev *dev = to_bst_dev(device);
+
+ if (NULL != dev)
+ kfree(dev);
+ module_put(THIS_MODULE);
+}
+
+
+#ifdef CONFIG_PM
+static int bst_dev_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int bst_dev_resume(struct device *dev)
+{
+ return 0;
+}
+
+static const struct dev_pm_ops bst_dev_pm_ops = {
+ .suspend = bst_dev_suspend,
+ .resume = bst_dev_resume,
+ .poweroff = bst_dev_suspend,
+ .restore = bst_dev_resume,
+};
+#endif /* CONFIG_PM */
+
+static const struct attribute_group *bst_dev_attr_groups[] = {
+ NULL
+};
+
+static struct device_type bst_dev_type = {
+ .groups = bst_dev_attr_groups,
+ .release = bst_dev_release,
+#ifdef CONFIG_PM
+ .pm = &bst_dev_pm_ops,
+#endif
+};
+
+
+
+static char *bst_devnode(struct device *dev, umode_t *mode)
+{
+ return kasprintf(GFP_KERNEL, "%s", dev_name(dev));
+}
+
+struct class bst_class = {
+ .name = "bst",
+ .owner = THIS_MODULE,
+ .devnode = bst_devnode,
+ .dev_release = bst_dev_release,
+};
+EXPORT_SYMBOL_GPL(bst_class);
+
+/**
+ * bst_allocate_device - allocate memory for new input device
+ *
+ * Returns prepared struct bst_dev or NULL.
+ *
+ * NOTE: Use bst_free_device() to free devices that have not been
+ * registered; bst_unregister_device() should be used for already
+ * registered devices.
+ */
+struct bst_dev *bst_allocate_device(void)
+{
+ struct bst_dev *dev;
+
+ dev = kzalloc(sizeof(struct bst_dev), GFP_KERNEL);
+ if (dev) {
+ dev->dev.type = &bst_dev_type;
+ dev->dev.class = &bst_class;
+ device_initialize(&dev->dev);
+ mutex_init(&dev->mutex);
+ INIT_LIST_HEAD(&dev->node);
+ __module_get(THIS_MODULE);
+ }
+ return dev;
+}
+EXPORT_SYMBOL(bst_allocate_device);
+
+
+
+/**
+ * bst_free_device - free memory occupied by bst_dev structure
+ * @dev: input device to free
+ *
+ * This function should only be used if bst_register_device()
+ * was not called yet or if it failed. Once device was registered
+ * use bst_unregister_device() and memory will be freed once last
+ * reference to the device is dropped.
+ *
+ * Device should be allocated by bst_allocate_device().
+ *
+ * NOTE: If there are references to the input device then memory
+ * will not be freed until last reference is dropped.
+ */
+void bst_free_device(struct bst_dev *dev)
+{
+ if (dev)
+ bst_put_device(dev);
+}
+EXPORT_SYMBOL(bst_free_device);
+
+/**
+ * bst_register_device - register device with input core
+ * @dev: device to be registered
+ *
+ * This function registers device with input core. The device must be
+ * allocated with bst_allocate_device() and all it's capabilities
+ * set up before registering.
+ * If function fails the device must be freed with bst_free_device().
+ * Once device has been successfully registered it can be unregistered
+ * with bst_unregister_device(); bst_free_device() should not be
+ * called in this case.
+ */
+int bst_register_device(struct bst_dev *dev)
+{
+ const char *path;
+ int error;
+
+
+ /*
+ * If delay and period are pre-set by the driver, then autorepeating
+ * is handled by the driver itself and we don't do it in input.c.
+ */
+ dev_set_name(&dev->dev, dev->name);
+
+ error = device_add(&dev->dev);
+ if (error)
+ return error;
+
+ path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
+ dev_dbg(&dev->dev, "%s as %s\n",
+ dev->name ? dev->name : "Unspecified device",
+ path ? path : "N/A");
+ kfree(path);
+ error = mutex_lock_interruptible(&bst_mutex);
+ if (error) {
+ device_del(&dev->dev);
+ return error;
+ }
+
+ list_add_tail(&dev->node, &bst_dev_list);
+
+ mutex_unlock(&bst_mutex);
+ return 0;
+}
+EXPORT_SYMBOL(bst_register_device);
+
+/**
+ * bst_unregister_device - unregister previously registered device
+ * @dev: device to be unregistered
+ *
+ * This function unregisters an input device. Once device is unregistered
+ * the caller should not try to access it as it may get freed at any moment.
+ */
+void bst_unregister_device(struct bst_dev *dev)
+{
+ int error;
+
+ error = mutex_lock_interruptible(&bst_mutex);
+ list_del_init(&dev->node);
+ if (!error)
+ mutex_unlock(&bst_mutex);
+ device_unregister(&dev->dev);
+}
+EXPORT_SYMBOL(bst_unregister_device);
+
+static int bst_open_file(struct inode *inode, struct file *file)
+{
+ const struct file_operations *old_fops, *new_fops = NULL;
+ int err;
+
+ /*
+ * That's _really_ odd. Usually NULL ->open means "nothing special",
+ * not "no device". Oh, well...
+ */
+ if (!new_fops || !new_fops->open) {
+ fops_put(new_fops);
+ err = -ENODEV;
+ goto out;
+ }
+
+ old_fops = file->f_op;
+ file->f_op = new_fops;
+
+ err = new_fops->open(inode, file);
+ if (err) {
+ fops_put(file->f_op);
+ file->f_op = fops_get(old_fops);
+ }
+ fops_put(old_fops);
+out:
+ return err;
+}
+
+static const struct file_operations bst_fops = {
+ .owner = THIS_MODULE,
+ .open = bst_open_file,
+ /*.llseek = noop_llseek,*/
+};
+
+static int __init bst_init(void)
+{
+ int err;
+ /*bst class register*/
+ err = class_register(&bst_class);
+ if (err) {
+ pr_err("unable to register bst_dev class\n");
+ return err;
+ }
+ return err;
+}
+
+static void __exit bst_exit(void)
+{
+ /*bst class*/
+ class_unregister(&bst_class);
+}
+
+/*subsys_initcall(bst_init);*/
+
+MODULE_AUTHOR("contact@bosch-sensortec.com");
+MODULE_DESCRIPTION("BST CLASS CORE");
+MODULE_LICENSE("GPL V2");
+
+module_init(bst_init);
+module_exit(bst_exit);
diff --git a/drivers/input/misc/bstclass.h b/drivers/input/misc/bstclass.h
new file mode 100644
index 000000000000..50ae68852855
--- /dev/null
+++ b/drivers/input/misc/bstclass.h
@@ -0,0 +1,78 @@
+/*!
+ * @section LICENSE
+ * (C) Copyright 2013 Bosch Sensortec GmbH All Rights Reserved
+ *
+ * This software program is licensed subject to the GNU General
+ * Public License (GPL).Version 2,June 1991,
+ * available at http://www.fsf.org/copyleft/gpl.html
+ *
+ * @filename bstclass.h
+ * @date "Fri Aug 2 17:41:45 2013 +0800"
+ * @id "644147c"
+ *
+ * @brief
+ * The core code of bst device driver
+*/
+
+#ifndef _BSTCLASS_H
+#define _BSTCLASS_H
+
+#ifdef __KERNEL__
+#include <linux/time.h>
+#include <linux/list.h>
+#else
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <linux/types.h>
+#endif
+
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/mod_devicetable.h>
+
+struct bst_dev {
+ const char *name;
+
+ int (*open)(struct bst_dev *dev);
+ void (*close)(struct bst_dev *dev);
+ struct mutex mutex;
+ struct device dev;
+ struct list_head node;
+};
+
+#define to_bst_dev(d) container_of(d, struct bst_dev, dev)
+
+struct bst_dev *bst_allocate_device(void);
+void bst_free_device(struct bst_dev *dev);
+
+static inline struct bst_dev *bst_get_device(struct bst_dev *dev)
+{
+ return dev ? to_bst_dev(get_device(&dev->dev)) : NULL;
+}
+
+static inline void bst_put_device(struct bst_dev *dev)
+{
+ if (dev)
+ put_device(&dev->dev);
+}
+
+static inline void *bst_get_drvdata(struct bst_dev *dev)
+{
+ return dev_get_drvdata(&dev->dev);
+}
+
+static inline void bst_set_drvdata(struct bst_dev *dev, void *data)
+{
+ dev_set_drvdata(&dev->dev, data);
+}
+
+int __must_check bst_register_device(struct bst_dev *);
+void bst_unregister_device(struct bst_dev *);
+
+void bst_reset_device(struct bst_dev *);
+
+
+extern struct class bst_class;
+
+#endif
diff --git a/drivers/input/misc/fpc1020_tee.c b/drivers/input/misc/fpc1020_tee.c
index ea8987a1f0f9..97376dfabbf6 100755
--- a/drivers/input/misc/fpc1020_tee.c
+++ b/drivers/input/misc/fpc1020_tee.c
@@ -87,6 +87,7 @@ struct fpc1020_data {
#if defined(CONFIG_FB)
struct notifier_block fb_notif;
#endif
+ struct work_struct pm_work;
};
static int fpc1020_request_named_gpio(struct fpc1020_data *fpc1020,
@@ -277,27 +278,18 @@ static ssize_t irq_ack(struct device* device,
return count;
}
static DEVICE_ATTR(irq, S_IRUSR | S_IWUSR, irq_get, irq_ack);
-extern void int_touch(void);
-extern struct completion key_cm;
-extern bool virtual_key_enable;
-
-bool key_home_pressed = false;
-EXPORT_SYMBOL(key_home_pressed);
-
+extern bool virtual_key_enable;
static ssize_t report_home_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct fpc1020_data *fpc1020 = dev_get_drvdata(dev);
- unsigned long time;
if(ignor_home_for_ESD)
return -EINVAL;
if (!strncmp(buf, "down", strlen("down")))
{
- if(virtual_key_enable){
- key_home_pressed = true;
- }else{
+ if(!virtual_key_enable){
input_report_key(fpc1020->input_dev,
KEY_HOME, 1);
input_sync(fpc1020->input_dev);
@@ -305,9 +297,7 @@ static ssize_t report_home_set(struct device *dev,
}
else if (!strncmp(buf, "up", strlen("up")))
{
- if(virtual_key_enable){
- key_home_pressed = false;
- }else{
+ if(!virtual_key_enable){
input_report_key(fpc1020->input_dev,
KEY_HOME, 0);
input_sync(fpc1020->input_dev);
@@ -322,16 +312,7 @@ static ssize_t report_home_set(struct device *dev,
}
else
return -EINVAL;
- if(virtual_key_enable){
- if(!key_home_pressed){
- reinit_completion(&key_cm);
- time = wait_for_completion_timeout(&key_cm,msecs_to_jiffies(60));
- if (!time)
- int_touch();
- }else{
- int_touch();
- }
- }
+
return count;
}
static DEVICE_ATTR(report_home, S_IWUSR, NULL, report_home_set);
@@ -420,29 +401,53 @@ void fpc1020_input_destroy(struct fpc1020_data *fpc1020)
input_free_device(fpc1020->input_dev);
}
+static void set_fingerprint_hal_nice(int nice)
+{
+ struct task_struct *p;
+
+ read_lock(&tasklist_lock);
+ for_each_process(p) {
+ if(!memcmp(p->comm, "fps_work", 9)) {
+ set_user_nice(p, nice);
+ break;
+ }
+ }
+ read_unlock(&tasklist_lock);
+}
+
+static void fpc1020_suspend_resume(struct work_struct *work)
+{
+ struct fpc1020_data *fpc1020 =
+ container_of(work, typeof(*fpc1020), pm_work);
+
+ /* Escalate fingerprintd priority when screen is off */
+ if (fpc1020->screen_state)
+ set_fingerprint_hal_nice(0);
+ else
+ set_fingerprint_hal_nice(MIN_NICE);
+
+ sysfs_notify(&fpc1020->dev->kobj, NULL,
+ dev_attr_screen_state.attr.name);
+}
+
#if defined(CONFIG_FB)
static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data)
{
+ struct fpc1020_data *fpc1020 = container_of(self, struct fpc1020_data, fb_notif);
struct fb_event *evdata = data;
- int *blank;
+ int *blank = evdata->data;
- struct fpc1020_data *fpc1020 = container_of(self, struct fpc1020_data, fb_notif);
+ if (event != FB_EARLY_EVENT_BLANK)
+ return 0;
- if(FB_EARLY_EVENT_BLANK != event && FB_EVENT_BLANK != event)
- return 0;
- if((evdata) && (evdata->data) && (fpc1020)) {
- blank = evdata->data;
- if( *blank == FB_BLANK_UNBLANK && (event == FB_EARLY_EVENT_BLANK )) {
- dev_err(fpc1020->dev, "%s screen on\n", __func__);
- fpc1020->screen_state = 1;
- sysfs_notify(&fpc1020->dev->kobj, NULL, dev_attr_screen_state.attr.name);
-
- } else if( *blank == FB_BLANK_POWERDOWN && (event == FB_EARLY_EVENT_BLANK/*FB_EVENT_BLANK*/ )) {
- dev_err(fpc1020->dev, "%s screen off\n", __func__);
- fpc1020->screen_state = 0;
- sysfs_notify(&fpc1020->dev->kobj, NULL, dev_attr_screen_state.attr.name);
- }
+ if (*blank == FB_BLANK_UNBLANK) {
+ fpc1020->screen_state = 1;
+ queue_work(system_highpri_wq, &fpc1020->pm_work);
+ } else if (*blank == FB_BLANK_POWERDOWN) {
+ fpc1020->screen_state = 0;
+ queue_work(system_highpri_wq, &fpc1020->pm_work);
}
+
return 0;
}
#endif
@@ -450,21 +455,13 @@ static int fb_notifier_callback(struct notifier_block *self, unsigned long event
static irqreturn_t fpc1020_irq_handler(int irq, void *handle)
{
struct fpc1020_data *fpc1020 = handle;
- //dev_err(fpc1020->dev, "%s\n", __func__);
-
- /* Make sure 'wakeup_enabled' is updated before using it
- ** since this is interrupt context (other thread...) */
- //smp_rmb();
-/*
- if (fpc1020->wakeup_enabled ) {
- wake_lock_timeout(&fpc1020->ttw_wl, msecs_to_jiffies(FPC_TTW_HOLD_TIME));
- }
-*/
- wake_lock_timeout(&fpc1020->ttw_wl, msecs_to_jiffies(FPC_TTW_HOLD_TIME));//changhua add for KeyguardUpdateMonitor: fingerprint acquired, grabbing fp wakelock
- //dev_err(fpc1020->dev, "%s before sysfs_notify\n", __func__);
sysfs_notify(&fpc1020->dev->kobj, NULL, dev_attr_irq.attr.name);
- //dev_err(fpc1020->dev, "%s after sysfs_notify\n", __func__);
+
+ if (fpc1020->screen_state)
+ return IRQ_HANDLED;
+
+ wake_lock_timeout(&fpc1020->ttw_wl, msecs_to_jiffies(FPC_TTW_HOLD_TIME));
return IRQ_HANDLED;
}
@@ -552,6 +549,8 @@ static int fpc1020_probe(struct platform_device *pdev)
if (rc)
goto exit;
+ INIT_WORK(&fpc1020->pm_work, fpc1020_suspend_resume);
+
#if defined(CONFIG_FB)
fpc1020->fb_notif.notifier_call = fb_notifier_callback;
rc = fb_register_client(&fpc1020->fb_notif);
diff --git a/drivers/input/misc/keychord.c b/drivers/input/misc/keychord.c
index fdcc14653b64..82fefdff366a 100644
--- a/drivers/input/misc/keychord.c
+++ b/drivers/input/misc/keychord.c
@@ -276,7 +276,7 @@ static ssize_t keychord_write(struct file *file, const char __user *buffer,
size_t resid = count;
size_t key_bytes;
- if (count < sizeof(struct input_keychord))
+ if (count < sizeof(struct input_keychord) || count > PAGE_SIZE)
return -EINVAL;
keychords = kzalloc(count, GFP_KERNEL);
if (!keychords)
diff --git a/drivers/input/misc/ltr553.c b/drivers/input/misc/ltr553.c
new file mode 100644
index 000000000000..e3281f74d34d
--- /dev/null
+++ b/drivers/input/misc/ltr553.c
@@ -0,0 +1,2260 @@
+/* Copyright (c) 2014-2015,2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/mm.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/sysctl.h>
+#include <linux/regulator/consumer.h>
+#include <linux/input.h>
+#include <linux/regmap.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/interrupt.h>
+#include <linux/sensors.h>
+#include <linux/pm_wakeup.h>
+#include <linux/uaccess.h>
+#include <linux/atomic.h>
+
+#define LTR553_I2C_NAME "ltr553"
+#define LTR553_LIGHT_INPUT_NAME "ltr553-light"
+#define LTR553_PROXIMITY_INPUT_NAME "ltr553-proximity"
+
+#define LTR553_REG_ALS_CTL 0x80
+#define LTR553_REG_PS_CTL 0x81
+#define LTR553_REG_PS_LED 0x82
+#define LTR553_REG_PS_N_PULSES 0x83
+#define LTR553_REG_PS_MEAS_RATE 0x84
+#define LTR553_REG_ALS_MEAS_RATE 0x85
+#define LTR553_REG_PART_ID 0x86
+#define LTR553_REG_ALS_DATA_CH1_0 0x88
+#define LTR553_REG_ALS_DATA_CH1_1 0x89
+#define LTR553_REG_ALS_DATA_CH0_0 0x8A
+#define LTR553_REG_ALS_DATA_CH0_1 0x8B
+#define LTR553_REG_ALS_PS_STATUS 0x8C
+#define LTR553_REG_PS_DATA_0 0x8D
+#define LTR553_REG_INTERRUPT 0x8F
+#define LTR553_REG_PS_THRES_UP_0 0x90
+#define LTR553_REG_PS_OFFSET_1 0x94
+#define LTR553_REG_PS_OFFSET_0 0x95
+#define LTR553_REG_ALS_THRES_UP_0 0x97
+#define LTR553_REG_INTERRUPT_PERSIST 0x9E
+#define LTR553_REG_MAGIC 0xFF
+
+#define LTR553_PART_ID 0x92
+
+#define LTR553_ALS_SENSITIVITY 70
+
+#define LTR553_BOOT_TIME_MS 120
+#define LTR553_WAKE_TIME_MS 10
+
+#define LTR553_PS_SATURATE_MASK 0x8000
+#define LTR553_ALS_INT_MASK 0x08
+#define LTR553_PS_INT_MASK 0x02
+
+#define LTR553_ALS_MEASURE_MASK 0x38
+#define LTR553_ALS_GAIN_MASK 0x1c
+
+/* default measurement rate is 100 ms */
+#define LTR553_ALS_DEFAULT_MEASURE_RATE 0x01
+#define LTR553_PS_MEASUREMENT_RATE_10MS 0x08
+
+#define LTR553_CALIBRATE_SAMPLES 15
+
+#define ALS_GAIN_SWITCH_THRESHOLD 60000
+
+#define LTR553_ALS_INVALID(value) (value & 0x80)
+
+/* LTR553 ALS data is 16 bit */
+#define ALS_DATA_MASK 0xffff
+#define ALS_LOW_BYTE(data) ((data) & 0xff)
+#define ALS_HIGH_BYTE(data) (((data) >> 8) & 0xff)
+
+/* LTR553 PS data is 11 bit */
+#define PS_DATA_MASK 0x7ff
+#define PS_LOW_BYTE(data) ((data) & 0xff)
+#define PS_HIGH_BYTE(data) (((data) >> 8) & 0x7)
+
+/* Calculated by 10% transmittance */
+#define LTR553_MAX_LUX (ALS_DATA_MASK * 10)
+
+/* both als and ps interrupt are enabled */
+#define LTR553_INTERRUPT_SETTING 0x03
+
+/* Any proximity distance change will wakeup SoC */
+#define LTR553_WAKEUP_ANY_CHANGE 0xff
+
+#define CAL_BUF_LEN 16
+enum {
+ CMD_WRITE = 0,
+ CMD_READ = 1,
+};
+
+struct regulator_map {
+ struct regulator *regulator;
+ int min_uv;
+ int max_uv;
+ char *supply;
+};
+
+struct pinctrl_config {
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *state[2];
+ char *name[2];
+};
+
+struct ltr553_data {
+ struct i2c_client *i2c;
+ struct regmap *regmap;
+ struct regulator *config;
+ struct input_dev *input_light;
+ struct input_dev *input_proximity;
+ struct workqueue_struct *workqueue;
+
+ struct sensors_classdev als_cdev;
+ struct sensors_classdev ps_cdev;
+ struct mutex ops_lock;
+ ktime_t last_als_ts;
+ ktime_t last_ps_ts;
+ struct work_struct report_work;
+ struct work_struct als_enable_work;
+ struct work_struct als_disable_work;
+ struct work_struct ps_enable_work;
+ struct work_struct ps_disable_work;
+ atomic_t wake_count;
+
+ int irq_gpio;
+ int irq;
+ bool als_enabled;
+ bool ps_enabled;
+ u32 irq_flags;
+ int als_delay;
+ int ps_delay;
+ int als_cal;
+ int ps_cal;
+ int als_gain;
+ int als_persist;
+ int als_integration_time;
+ int als_measure_rate;
+ int ps_led;
+ int ps_pulses;
+ int ps_measure_rate;
+ int als_ps_persist;
+ int ps_wakeup_threshold;
+
+ int last_als;
+ int last_ps;
+ int flush_count;
+ int power_enabled;
+
+ unsigned int reg_addr;
+ char calibrate_buf[CAL_BUF_LEN];
+ unsigned int bias;
+};
+
+struct als_coeff {
+ int ch0_coeff_i;
+ int ch1_coeff_i;
+ int ch0_coeff_f;
+ int ch1_coeff_f;
+ int win_fac;
+ int sign;
+} __attribute__((__packed__));
+
+static struct regulator_map power_config[] = {
+ {.supply = "vdd", .min_uv = 2000000, .max_uv = 3300000, },
+ {.supply = "vio", .min_uv = 1750000, .max_uv = 1950000, },
+};
+
+static struct pinctrl_config pin_config = {
+ .name = { "default", "sleep" },
+};
+
+static struct als_coeff eqtn_map[] = {
+ {
+ .ch0_coeff_i = 1,
+ .ch1_coeff_i = 1,
+ .ch0_coeff_f = 7743,
+ .ch1_coeff_f = 1059,
+ .win_fac = 44,
+ .sign = 1,
+ },
+ {
+ .ch0_coeff_i = 4,
+ .ch1_coeff_i = 1,
+ .ch0_coeff_f = 2785,
+ .ch1_coeff_f = 9548,
+ .win_fac = 50,
+ .sign = -1,
+ },
+ {
+ .ch0_coeff_i = 0,
+ .ch1_coeff_i = 0,
+ .ch0_coeff_f = 5926,
+ .ch1_coeff_f = 1185,
+ .win_fac = 40,
+ .sign = 1,
+ },
+ {
+ .ch0_coeff_i = 0,
+ .ch1_coeff_i = 0,
+ .ch0_coeff_f = 0,
+ .ch1_coeff_f = 0,
+ .win_fac = 1,
+ .sign = 1,
+ },
+};
+
+/* ALS integration time in 10ms */
+static int als_int_fac_table[] = { 10, 5, 20, 40, 15, 25, 30, 35 };
+/* ALS gain table, index 4 & 5 are reserved */
+static int als_gain_table[] = {1, 2, 4, 8, 1, 1, 48, 96};
+/* ALS measurement repeat rate in ms */
+static int als_mrr_table[] = {50, 100, 200, 500, 1000, 2000, 2000, 2000};
+/* PS measurement repeat rate in ms */
+static int ps_mrr_table[] = { 50, 70, 100, 200, 500, 1000, 2000, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10};
+
+/* Tuned for devices with rubber */
+static int ps_distance_table[] = { 790, 337, 195, 114, 78, 62, 50 };
+
+static int sensitivity_table[] = {150, 150, 100, 100, 0, 0, 100, 1};
+
+static struct sensors_classdev als_cdev = {
+ .name = "ltr553-light",
+ .vendor = "Lite-On Technology Corp",
+ .version = 1,
+ .handle = SENSORS_LIGHT_HANDLE,
+ .type = SENSOR_TYPE_LIGHT,
+ .max_range = "65536",
+ .resolution = "1.0",
+ .sensor_power = "0.25",
+ .min_delay = 50000,
+ .max_delay = 2000,
+ .fifo_reserved_event_count = 0,
+ .fifo_max_event_count = 0,
+ .flags = 2,
+ .enabled = 0,
+ .delay_msec = 50,
+ .sensors_enable = NULL,
+ .sensors_poll_delay = NULL,
+};
+
+static struct sensors_classdev ps_cdev = {
+ .name = "ltr553-proximity",
+ .vendor = "Lite-On Technology Corp",
+ .version = 1,
+ .handle = SENSORS_PROXIMITY_HANDLE,
+ .type = SENSOR_TYPE_PROXIMITY,
+ .max_range = "7",
+ .resolution = "1.0",
+ .sensor_power = "0.25",
+ .min_delay = 10000,
+ .max_delay = 2000,
+ .fifo_reserved_event_count = 0,
+ .fifo_max_event_count = 0,
+ .flags = 3,
+ .enabled = 0,
+ .delay_msec = 50,
+ .sensors_enable = NULL,
+ .sensors_poll_delay = NULL,
+};
+
+static int sensor_power_init(struct device *dev, struct regulator_map *map,
+ int size)
+{
+ int rc;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ map[i].regulator = devm_regulator_get(dev, map[i].supply);
+ if (IS_ERR(map[i].regulator)) {
+ rc = PTR_ERR(map[i].regulator);
+ dev_err(dev, "Regualtor get failed vdd rc=%d\n", rc);
+ goto exit;
+ }
+ if (regulator_count_voltages(map[i].regulator) > 0) {
+ rc = regulator_set_voltage(map[i].regulator,
+ map[i].min_uv, map[i].max_uv);
+ if (rc) {
+ dev_err(dev, "Regulator set failed vdd rc=%d\n",
+ rc);
+ goto exit;
+ }
+ }
+ }
+
+ return 0;
+
+exit:
+ /* Regulator not set correctly */
+ for (i = i - 1; i >= 0; i--) {
+ if (regulator_count_voltages(map[i].regulator))
+ regulator_set_voltage(map[i].regulator, 0,
+ map[i].max_uv);
+ }
+
+ return rc;
+}
+
+static int sensor_power_deinit(struct device *dev, struct regulator_map *map,
+ int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (!IS_ERR_OR_NULL(map[i].regulator)) {
+ if (regulator_count_voltages(map[i].regulator) > 0)
+ regulator_set_voltage(map[i].regulator, 0,
+ map[i].max_uv);
+ }
+ }
+
+ return 0;
+}
+
+static int sensor_power_config(struct device *dev, struct regulator_map *map,
+ int size, bool enable)
+{
+ int i;
+ int rc = 0;
+
+ if (enable) {
+ for (i = 0; i < size; i++) {
+ rc = regulator_enable(map[i].regulator);
+ if (rc) {
+ dev_err(dev, "enable %s failed.\n",
+ map[i].supply);
+ goto exit_enable;
+ }
+ }
+ } else {
+ for (i = 0; i < size; i++) {
+ rc = regulator_disable(map[i].regulator);
+ if (rc) {
+ dev_err(dev, "disable %s failed.\n",
+ map[i].supply);
+ goto exit_disable;
+ }
+ }
+ }
+
+ return 0;
+
+exit_enable:
+ for (i = i - 1; i >= 0; i--)
+ regulator_disable(map[i].regulator);
+
+ return rc;
+
+exit_disable:
+ for (i = i - 1; i >= 0; i--)
+ if (regulator_enable(map[i].regulator))
+ dev_err(dev, "enable %s failed\n", map[i].supply);
+
+ return rc;
+}
+
+static int sensor_pinctrl_init(struct device *dev,
+ struct pinctrl_config *config)
+{
+ config->pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR_OR_NULL(config->pinctrl)) {
+ dev_err(dev, "Failed to get pinctrl\n");
+ return PTR_ERR(config->pinctrl);
+ }
+
+ config->state[0] =
+ pinctrl_lookup_state(config->pinctrl, config->name[0]);
+ if (IS_ERR_OR_NULL(config->state[0])) {
+ dev_err(dev, "Failed to look up %s\n", config->name[0]);
+ return PTR_ERR(config->state[0]);
+ }
+
+ config->state[1] =
+ pinctrl_lookup_state(config->pinctrl, config->name[1]);
+ if (IS_ERR_OR_NULL(config->state[1])) {
+ dev_err(dev, "Failed to look up %s\n", config->name[1]);
+ return PTR_ERR(config->state[1]);
+ }
+
+ return 0;
+}
+
+static int ltr553_parse_dt(struct device *dev, struct ltr553_data *ltr)
+{
+ struct device_node *dp = dev->of_node;
+ u32 value;
+ int rc;
+ int i;
+
+ rc = of_get_named_gpio_flags(dp, "liteon,irq-gpio", 0,
+ &ltr->irq_flags);
+ if (rc < 0) {
+ dev_err(dev, "unable to read irq gpio\n");
+ return rc;
+ }
+ ltr->irq_gpio = rc;
+
+ /* als ps persist */
+ rc = of_property_read_u32(dp, "liteon,als-ps-persist", &value);
+ if (rc) {
+ dev_err(dev, "read liteon,als-ps-persist failed\n");
+ return rc;
+ }
+ ltr->als_ps_persist = value;
+
+ /* ps led */
+ rc = of_property_read_u32(dp, "liteon,ps-led", &value);
+ if (rc) {
+ dev_err(dev, "read liteon,ps-led failed\n");
+ return rc;
+ }
+ ltr->ps_led = value;
+
+ /* ps pulses */
+ rc = of_property_read_u32(dp, "liteon,ps-pulses", &value);
+ if (rc) {
+ dev_err(dev, "read liteon,ps-pulses failed\n");
+ return rc;
+ }
+ if (value > 0x7) {
+ dev_err(dev, "liteon,ps-pulses out of range\n");
+ return -EINVAL;
+ }
+ ltr->ps_pulses = value;
+
+ /* als integration time */
+ rc = of_property_read_u32(dp, "liteon,als-integration-time", &value);
+ if (rc) {
+ dev_err(dev, "read liteon,als-integration-time failed\n");
+ return rc;
+ }
+ if (value > 0x7) {
+ dev_err(dev, "liteon,als-integration-time out of range\n");
+ return -EINVAL;
+ }
+ ltr->als_integration_time = value;
+
+ /* ps wakeup threshold */
+ rc = of_property_read_u32(dp, "liteon,wakeup-threshold", &value);
+ if (rc) {
+ dev_err(dev, "liteon,wakeup-threshold incorrect, drop to default\n");
+ value = LTR553_WAKEUP_ANY_CHANGE;
+ }
+ if ((value >= ARRAY_SIZE(ps_distance_table)) &&
+ (value != LTR553_WAKEUP_ANY_CHANGE)) {
+ dev_err(dev, "wakeup threshold too big\n");
+ return -EINVAL;
+ }
+ ltr->ps_wakeup_threshold = value;
+
+ /* ps distance table */
+ rc = of_property_read_u32_array(dp, "liteon,ps-distance-table",
+ ps_distance_table, ARRAY_SIZE(ps_distance_table));
+ if ((rc == -ENODATA) || (rc == -EOVERFLOW)) {
+ dev_warn(dev, "liteon,ps-distance-table not correctly set\n");
+ return rc;
+ }
+
+ for (i = 1; i < ARRAY_SIZE(ps_distance_table); i++) {
+ if (ps_distance_table[i - 1] < ps_distance_table[i]) {
+ dev_err(dev, "ps distance table should in descend order\n");
+ return -EINVAL;
+ }
+ }
+
+ if (ps_distance_table[0] > PS_DATA_MASK) {
+ dev_err(dev, "distance table out of range\n");
+ return -EINVAL;
+ }
+
+ /* als gain */
+ rc = of_property_read_u32(dp, "liteon,als-gain", &value);
+ if (rc) {
+ dev_err(dev, "read liteon,als-gain failed. Drop to default\n");
+ value = 0;
+ }
+ /* 4 & 5 are reserved */
+ if ((value > 0x7) || (value == 0x4) || (value == 0x5)) {
+ dev_err(dev, "liteon,als-gain invalid\n");
+ return -EINVAL;
+ }
+ ltr->als_gain = value;
+
+ /* als sensitivity */
+ rc = of_property_read_u32_array(dp, "liteon,als-sensitivity",
+ sensitivity_table, ARRAY_SIZE(sensitivity_table));
+ if (rc)
+ dev_info(dev, "read liteon,als-sensitivity failed. Drop to default\n");
+
+ /* als equation map */
+ rc = of_property_read_u32_array(dp, "liteon,als-equation-0",
+ &eqtn_map[0].ch0_coeff_i, 6);
+ if (rc)
+ dev_warn(dev, "read liteon,als-equation-0 failed. Drop to default\n");
+
+ rc = of_property_read_u32_array(dp, "liteon,als-equation-0",
+ &eqtn_map[1].ch0_coeff_i, 6);
+ if (rc)
+ dev_warn(dev, "read liteon,als-equation-1 failed. Drop to default\n");
+
+ rc = of_property_read_u32_array(dp, "liteon,als-equation-0",
+ &eqtn_map[2].ch0_coeff_i, 6);
+ if (rc)
+ dev_warn(dev, "read liteon,als-equation-2 failed. Drop to default\n");
+
+ rc = of_property_read_u32_array(dp, "liteon,als-equation-3",
+ &eqtn_map[3].ch0_coeff_i, 6);
+ if (rc)
+ dev_warn(dev, "read liteon,als-equation-3 failed. Drop to default\n");
+
+ return 0;
+}
+
+static int ltr553_check_device(struct ltr553_data *ltr)
+{
+ unsigned int part_id;
+ int rc;
+
+ rc = regmap_read(ltr->regmap, LTR553_REG_PART_ID, &part_id);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "read reg %d failed.(%d)\n",
+ LTR553_REG_PART_ID, rc);
+ return rc;
+ }
+
+ if (part_id != LTR553_PART_ID)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int ltr553_init_input(struct ltr553_data *ltr)
+{
+ struct input_dev *input;
+ int status;
+
+ input = devm_input_allocate_device(&ltr->i2c->dev);
+ if (!input) {
+ dev_err(&ltr->i2c->dev, "allocate light input device failed\n");
+ return -ENOMEM;
+ }
+
+ input->name = LTR553_LIGHT_INPUT_NAME;
+ input->phys = "ltr553/input0";
+ input->id.bustype = BUS_I2C;
+
+ input_set_capability(input, EV_ABS, ABS_MISC);
+ input_set_abs_params(input, ABS_MISC, 0, LTR553_MAX_LUX, 0, 0);
+
+ status = input_register_device(input);
+ if (status) {
+ dev_err(&ltr->i2c->dev, "register light input device failed.\n");
+ return status;
+ }
+
+ ltr->input_light = input;
+
+ input = devm_input_allocate_device(&ltr->i2c->dev);
+ if (!input) {
+ dev_err(&ltr->i2c->dev, "allocate proximity input device failed\n");
+ return -ENOMEM;
+ }
+
+ input->name = LTR553_PROXIMITY_INPUT_NAME;
+ input->phys = "ltr553/input1";
+ input->id.bustype = BUS_I2C;
+
+ input_set_capability(input, EV_ABS, ABS_DISTANCE);
+ input_set_abs_params(input, ABS_DISTANCE, 0,
+ ARRAY_SIZE(ps_distance_table), 0, 0);
+
+ status = input_register_device(input);
+ if (status) {
+ dev_err(&ltr->i2c->dev, "register proxmity input device failed.\n");
+ return status;
+ }
+
+ ltr->input_proximity = input;
+
+ return 0;
+}
+
+static int ltr553_init_device(struct ltr553_data *ltr)
+{
+ int rc;
+ unsigned int tmp;
+
+ /* Enable als/ps interrupt */
+ rc = regmap_write(ltr->regmap, LTR553_REG_INTERRUPT,
+ LTR553_INTERRUPT_SETTING);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d register failed\n",
+ LTR553_REG_INTERRUPT);
+ return rc;
+ }
+
+ rc = regmap_write(ltr->regmap, LTR553_REG_INTERRUPT_PERSIST,
+ ltr->als_ps_persist);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d register failed\n",
+ LTR553_REG_INTERRUPT_PERSIST);
+ return rc;
+ }
+
+ rc = regmap_write(ltr->regmap, LTR553_REG_PS_N_PULSES, ltr->ps_pulses);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d register failed\n",
+ LTR553_REG_PS_N_PULSES);
+ return rc;
+ }
+
+ rc = regmap_write(ltr->regmap, LTR553_REG_ALS_MEAS_RATE,
+ (ltr->als_integration_time << 3) | (ltr->als_measure_rate));
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d failed\n",
+ LTR553_REG_ALS_MEAS_RATE);
+ return rc;
+ }
+
+ rc = regmap_write(ltr->regmap, LTR553_REG_PS_MEAS_RATE,
+ ltr->ps_measure_rate);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d failed\n",
+ LTR553_REG_PS_MEAS_RATE);
+ return rc;
+ }
+
+ /* Set calibration parameter low byte */
+ rc = regmap_write(ltr->regmap, LTR553_REG_PS_OFFSET_0,
+ PS_LOW_BYTE(ltr->bias));
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d register failed\n",
+ LTR553_REG_PS_OFFSET_0);
+ return rc;
+ }
+
+ /* Set calibration parameter high byte */
+ rc = regmap_write(ltr->regmap, LTR553_REG_PS_OFFSET_1,
+ PS_HIGH_BYTE(ltr->bias));
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d register failed\n",
+ LTR553_REG_PS_OFFSET_1);
+ return rc;
+ }
+
+ /* set up als gain */
+ rc = regmap_read(ltr->regmap, LTR553_REG_ALS_CTL, &tmp);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "read %d register failed\n",
+ LTR553_REG_ALS_CTL);
+ return rc;
+ }
+ rc = regmap_write(ltr->regmap, LTR553_REG_ALS_CTL,
+ (tmp & (~0x1c)) | (ltr->als_gain << 2));
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d register failed\n",
+ LTR553_REG_ALS_CTL);
+ return rc;
+ }
+
+ return 0;
+}
+
+/* Calculate the lux value based on ADC data */
+static int ltr553_calc_lux(int ch0data, int ch1data, int gain, int als_int_fac)
+{
+ int ratio;
+ int lux_i;
+ int lux_f;
+ int lux;
+ struct als_coeff *eqtn;
+
+ /* avoid divided by 0 */
+ if ((ch0data == 0) && (ch1data == 0))
+ return 0;
+
+ ratio = ch1data * 100 / (ch0data + ch1data);
+ if (ratio < 45)
+ eqtn = &eqtn_map[0];
+ else if ((ratio >= 45) && (ratio < 68))
+ eqtn = &eqtn_map[1];
+ else if ((ratio >= 68) && (ratio < 99))
+ eqtn = &eqtn_map[2];
+ else
+ eqtn = &eqtn_map[3];
+
+ lux_i = (ch0data * eqtn->ch0_coeff_i + ch1data * eqtn->ch1_coeff_i *
+ eqtn->sign) * eqtn->win_fac;
+ lux_f = (ch0data * eqtn->ch0_coeff_f + ch1data * eqtn->ch1_coeff_f *
+ eqtn->sign) / 100 * eqtn->win_fac;
+
+ lux = (lux_i + abs(lux_f) / 100) / (gain * als_int_fac);
+
+ return lux;
+}
+
+/* Calculate adc value based on lux. Return value is positive */
+static int ltr553_calc_adc(int ratio, int lux, int gain, int als_int_fac)
+{
+ int divisor_i;
+ int divisor_f;
+ int dividend;
+ struct als_coeff *eqtn;
+ int result;
+
+ /* avoid divided by 0 */
+ if (ratio == 0)
+ return 0;
+
+ if (ratio < 45)
+ eqtn = &eqtn_map[0];
+ else if ((ratio >= 45) && (ratio < 68))
+ eqtn = &eqtn_map[1];
+ else if ((ratio >= 68) && (ratio < 99))
+ eqtn = &eqtn_map[2];
+ else
+ eqtn = &eqtn_map[3];
+
+ dividend = lux * gain * als_int_fac;
+ divisor_i = ((100 - ratio) * eqtn->ch0_coeff_i / ratio +
+ eqtn->ch1_coeff_i * eqtn->sign) * eqtn->win_fac;
+ divisor_f = abs((100 - ratio) * eqtn->ch0_coeff_f / ratio +
+ eqtn->ch1_coeff_f * eqtn->sign) * eqtn->win_fac / 10000;
+
+ /* avoid divided by 0 */
+ if ((divisor_i + divisor_f) == 0)
+ return 0;
+
+ result = dividend / (divisor_i + divisor_f);
+
+ return result <= 0 ? 1 : result;
+}
+
+/* update als gain and threshold */
+static int ltr553_als_update_setting(struct ltr553_data *ltr,
+ int ch0data, int ch1data, int als_int_fac)
+{
+ int gain_index;
+ unsigned int config;
+ unsigned int ratio;
+ unsigned int adc_base;
+ int rc;
+ int adc;
+ int i;
+ u8 als_data[4];
+
+ for (i = ARRAY_SIZE(als_gain_table) - 1; i >= 0; i--) {
+ if ((i == 4) || (i == 5))
+ continue;
+
+ if ((ch0data + ch1data) * als_gain_table[i] /
+ als_gain_table[ltr->als_gain] <
+ ALS_GAIN_SWITCH_THRESHOLD)
+ break;
+ }
+
+ gain_index = i < 0 ? 0 : i;
+
+ /*
+ * Disable als and enable it again to avoid incorrect value.
+ * Updating als gain during als measurement cycle will cause
+ * incorrect light sensor adc value. The logic here is to handle
+ * this scenario.
+ */
+
+ if (ltr->als_gain != gain_index) {
+ rc = regmap_read(ltr->regmap, LTR553_REG_ALS_CTL, &config);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "read %d failed.(%d)\n",
+ LTR553_REG_ALS_CTL, rc);
+ return rc;
+ }
+
+ /* disable als sensor */
+ rc = regmap_write(ltr->regmap, LTR553_REG_ALS_CTL,
+ config & (~0x1));
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d failed.(%d)\n",
+ LTR553_REG_ALS_CTL, rc);
+ return rc;
+ }
+
+ /* write new als gain */
+ rc = regmap_write(ltr->regmap, LTR553_REG_ALS_CTL,
+ (config & (~0x1c)) | (gain_index << 2));
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d register failed\n",
+ LTR553_REG_ALS_CTL);
+ return rc;
+ }
+ }
+
+ if ((ch0data == 0) && (ch1data == 0)) {
+ adc = 1;
+ } else {
+ ratio = ch1data * 100 / (ch0data + ch1data);
+ dev_dbg(&ltr->i2c->dev, "ratio:%d\n", ratio);
+ adc = ltr553_calc_adc(ratio, sensitivity_table[gain_index],
+ als_gain_table[gain_index], als_int_fac);
+ }
+
+ dev_dbg(&ltr->i2c->dev, "adc:%d\n", adc);
+
+ /* catch'ya! */
+ adc_base = ch0data * als_gain_table[gain_index] /
+ als_gain_table[ltr->als_gain];
+
+ /* upper threshold */
+ if (adc_base + adc > ALS_DATA_MASK) {
+ als_data[0] = 0xff;
+ als_data[1] = 0xff;
+ } else {
+ als_data[0] = ALS_LOW_BYTE(adc_base + adc);
+ als_data[1] = ALS_HIGH_BYTE(adc_base + adc);
+ }
+
+ /* lower threshold */
+ if (adc_base < adc) {
+ als_data[2] = 0x0;
+ als_data[3] = 0x0;
+ } else {
+ als_data[2] = ALS_LOW_BYTE(adc_base - adc);
+ als_data[3] = ALS_HIGH_BYTE(adc_base - adc);
+ }
+
+ rc = regmap_bulk_write(ltr->regmap, LTR553_REG_ALS_THRES_UP_0,
+ als_data, 4);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d failed.(%d)\n",
+ LTR553_REG_ALS_THRES_UP_0, rc);
+ return rc;
+ }
+
+ if (ltr->als_gain != gain_index) {
+ /* enable als_sensor */
+ rc = regmap_write(ltr->regmap, LTR553_REG_ALS_CTL,
+ (config & (~0x1c)) | (gain_index << 2) | 0x1);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d failed.(%d)\n",
+ LTR553_REG_ALS_CTL, rc);
+ return rc;
+ }
+
+ ltr->als_gain = gain_index;
+ }
+
+ return 0;
+}
+
+static int ltr553_process_data(struct ltr553_data *ltr, int als_ps)
+{
+ int als_int_fac;
+ ktime_t timestamp;
+ int rc = 0;
+
+ unsigned int tmp;
+ u8 als_data[4];
+ int lux;
+ int ch0data;
+ int ch1data;
+
+ u8 ps_data[4];
+ int i;
+ int distance;
+
+ timestamp = ktime_get_boottime();
+
+ if (als_ps) { /* process als data */
+ /* Read data */
+ rc = regmap_bulk_read(ltr->regmap, LTR553_REG_ALS_DATA_CH1_0,
+ als_data, 4);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "read %d failed.(%d)\n",
+ LTR553_REG_ALS_DATA_CH1_0, rc);
+ goto exit;
+ }
+ ch0data = als_data[2] | (als_data[3] << 8);
+ ch1data = als_data[0] | (als_data[1] << 8);
+
+ rc = regmap_read(ltr->regmap, LTR553_REG_ALS_MEAS_RATE, &tmp);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "read %d failed.(%d)\n",
+ LTR553_REG_ALS_MEAS_RATE, rc);
+ goto exit;
+ }
+
+ tmp = (tmp & LTR553_ALS_MEASURE_MASK) >> 3;
+ als_int_fac = als_int_fac_table[tmp];
+ lux = ltr553_calc_lux(ch0data, ch1data,
+ als_gain_table[ltr->als_gain], als_int_fac);
+
+ dev_dbg(&ltr->i2c->dev, "lux:%d als_data:0x%x-0x%x-0x%x-0x%x\n",
+ lux, als_data[0], als_data[1],
+ als_data[2], als_data[3]);
+
+ rc = regmap_read(ltr->regmap, LTR553_REG_ALS_PS_STATUS, &tmp);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "read %d failed.(%d)\n",
+ LTR553_REG_ALS_PS_STATUS, rc);
+ goto exit;
+ }
+
+
+ if ((lux != ltr->last_als) && (!LTR553_ALS_INVALID(tmp))) {
+ input_report_abs(ltr->input_light, ABS_MISC, lux);
+ input_event(ltr->input_light, EV_SYN, SYN_TIME_SEC,
+ ktime_to_timespec(timestamp).tv_sec);
+ input_event(ltr->input_light, EV_SYN, SYN_TIME_NSEC,
+ ktime_to_timespec(timestamp).tv_nsec);
+ input_sync(ltr->input_light);
+
+ ltr->last_als_ts = timestamp;
+ }
+
+ ltr->last_als = lux;
+
+ dev_dbg(&ltr->i2c->dev, "previous als_gain:%d\n",
+ ltr->als_gain);
+
+ rc = ltr553_als_update_setting(ltr, ch0data, ch1data,
+ als_int_fac);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "update setting failed\n");
+ goto exit;
+ }
+
+ dev_dbg(&ltr->i2c->dev, "new als_gain:%d\n",
+ ltr->als_gain);
+
+
+ } else { /* process ps value */
+ rc = regmap_bulk_read(ltr->regmap, LTR553_REG_PS_DATA_0,
+ ps_data, 2);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "read %d failed.(%d)\n",
+ LTR553_REG_PS_DATA_0, rc);
+ goto exit;
+ }
+
+ dev_dbg(&ltr->i2c->dev, "ps data: 0x%x 0x%x\n",
+ ps_data[0], ps_data[1]);
+
+ tmp = (ps_data[1] << 8) | ps_data[0];
+ if (tmp & LTR553_PS_SATURATE_MASK)
+ distance = 0;
+ else {
+ for (i = 0; i < ARRAY_SIZE(ps_distance_table); i++) {
+ if (tmp > ps_distance_table[i]) {
+ distance = i;
+ break;
+ }
+ }
+ distance = i;
+ }
+
+ if (distance != ltr->last_ps) {
+ input_report_abs(ltr->input_proximity, ABS_DISTANCE,
+ distance);
+ input_event(ltr->input_proximity, EV_SYN, SYN_TIME_SEC,
+ ktime_to_timespec(timestamp).tv_sec);
+ input_event(ltr->input_proximity, EV_SYN, SYN_TIME_NSEC,
+ ktime_to_timespec(timestamp).tv_nsec);
+ input_sync(ltr->input_proximity);
+
+ ltr->last_ps_ts = timestamp;
+ }
+
+ ltr->last_ps = distance;
+
+ /* lower threshold */
+ if (distance < ARRAY_SIZE(ps_distance_table))
+ tmp = ps_distance_table[distance];
+ else
+ tmp = 0;
+
+ ps_data[2] = PS_LOW_BYTE(tmp);
+ ps_data[3] = PS_HIGH_BYTE(tmp);
+
+ /* upper threshold */
+ if (distance > 0)
+ tmp = ps_distance_table[distance - 1];
+ else
+ tmp = PS_DATA_MASK;
+
+ ps_data[0] = PS_LOW_BYTE(tmp);
+ ps_data[1] = PS_HIGH_BYTE(tmp);
+
+ dev_dbg(&ltr->i2c->dev, "ps threshold: 0x%x 0x%x 0x%x 0x%x\n",
+ ps_data[0], ps_data[1], ps_data[2], ps_data[3]);
+
+ rc = regmap_bulk_write(ltr->regmap, LTR553_REG_PS_THRES_UP_0,
+ ps_data, 4);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d failed.(%d)\n",
+ LTR553_REG_PS_THRES_UP_0, rc);
+ goto exit;
+ }
+ }
+exit:
+ return rc;
+}
+
+static irqreturn_t ltr553_irq_handler(int irq, void *data)
+{
+ struct ltr553_data *ltr = data;
+ bool rc;
+
+ rc = queue_work(ltr->workqueue, &ltr->report_work);
+ /* wake up event should hold a wake lock until reported */
+ if (rc && (atomic_inc_return(&ltr->wake_count) == 1))
+ pm_stay_awake(&ltr->i2c->dev);
+
+
+ return IRQ_HANDLED;
+}
+
+static void ltr553_report_work(struct work_struct *work)
+{
+ struct ltr553_data *ltr = container_of(work, struct ltr553_data,
+ report_work);
+ int rc;
+ unsigned int status;
+ u8 buf[7];
+ int fake_interrupt = 0;
+
+ mutex_lock(&ltr->ops_lock);
+
+ /* avoid fake interrupt */
+ if (!ltr->power_enabled) {
+ dev_dbg(&ltr->i2c->dev, "fake interrupt triggered\n");
+ fake_interrupt = 1;
+ goto exit;
+ }
+
+ /* read status */
+ rc = regmap_read(ltr->regmap, LTR553_REG_ALS_PS_STATUS, &status);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "read %d failed.(%d)\n",
+ LTR553_REG_ALS_PS_STATUS, rc);
+ status |= LTR553_PS_INT_MASK;
+ goto exit;
+ }
+
+ dev_dbg(&ltr->i2c->dev, "interrupt issued status=0x%x.\n", status);
+
+ /* als interrupt issueed */
+ if ((status & LTR553_ALS_INT_MASK) && (ltr->als_enabled)) {
+ rc = ltr553_process_data(ltr, 1);
+ if (rc)
+ goto exit;
+ dev_dbg(&ltr->i2c->dev, "process als done!\n");
+ }
+
+ if ((status & LTR553_PS_INT_MASK) && (ltr->ps_enabled)) {
+ rc = ltr553_process_data(ltr, 0);
+ if (rc)
+ goto exit;
+ dev_dbg(&ltr->i2c->dev, "process ps data done!\n");
+ pm_wakeup_event(&ltr->input_proximity->dev, 200);
+ }
+
+exit:
+ if (atomic_dec_and_test(&ltr->wake_count)) {
+ pm_relax(&ltr->i2c->dev);
+ dev_dbg(&ltr->i2c->dev, "wake lock released\n");
+ }
+
+ /* clear interrupt */
+ if (!fake_interrupt) {
+ if (regmap_bulk_read(ltr->regmap, LTR553_REG_ALS_DATA_CH1_0,
+ buf, ARRAY_SIZE(buf)))
+ dev_err(&ltr->i2c->dev, "clear interrupt failed\n");
+ }
+
+ mutex_unlock(&ltr->ops_lock);
+}
+
+static int ltr553_enable_ps(struct ltr553_data *ltr, int enable)
+{
+ unsigned int config;
+ unsigned int tmp;
+ int rc = 0;
+ u8 buf[7];
+
+ rc = regmap_read(ltr->regmap, LTR553_REG_PS_CTL, &config);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "read %d failed.(%d)\n",
+ LTR553_REG_PS_CTL, rc);
+ return rc;
+ }
+
+ if (enable) {
+ /* Enable ps sensor */
+ rc = regmap_write(ltr->regmap, LTR553_REG_PS_CTL,
+ config | 0x02);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d failed.(%d)\n",
+ LTR553_REG_PS_CTL, rc);
+ goto exit;
+ }
+
+ rc = regmap_read(ltr->regmap, LTR553_REG_PS_MEAS_RATE, &tmp);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "read %d failed.(%d)\n",
+ LTR553_REG_PS_MEAS_RATE, rc);
+ goto exit;
+ }
+
+ /* Wait for data ready */
+ msleep(ps_mrr_table[tmp & 0xf] + LTR553_WAKE_TIME_MS);
+
+ /* clear last ps value */
+ ltr->last_ps = -1;
+
+ rc = ltr553_process_data(ltr, 0);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "process ps data failed\n");
+ goto exit;
+ }
+
+ /* clear interrupt */
+ rc = regmap_bulk_read(ltr->regmap, LTR553_REG_ALS_DATA_CH1_0,
+ buf, ARRAY_SIZE(buf));
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "clear interrupt failed\n");
+ goto exit;
+ }
+
+ ltr->ps_enabled = true;
+
+ } else {
+ /* disable ps_sensor */
+ rc = regmap_write(ltr->regmap, LTR553_REG_PS_CTL,
+ config & (~0x02));
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d failed.(%d)\n",
+ LTR553_REG_PS_CTL, rc);
+ goto exit;
+ }
+
+ ltr->ps_enabled = false;
+ }
+exit:
+ return rc;
+}
+
+static int ltr553_enable_als(struct ltr553_data *ltr, int enable)
+{
+ int rc = 0;
+ unsigned int config;
+ unsigned int tmp;
+ u8 buf[7];
+
+ rc = regmap_read(ltr->regmap, LTR553_REG_ALS_CTL, &config);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "read %d failed.(%d)\n",
+ LTR553_REG_ALS_CTL, rc);
+ goto exit;
+ }
+
+ if (enable) {
+ /* enable als_sensor */
+ rc = regmap_write(ltr->regmap, LTR553_REG_ALS_CTL,
+ config | 0x1);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d failed.(%d)\n",
+ LTR553_REG_ALS_CTL, rc);
+ goto exit;
+ }
+
+ rc = regmap_read(ltr->regmap, LTR553_REG_ALS_MEAS_RATE, &tmp);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d failed.(%d)\n",
+ LTR553_REG_ALS_MEAS_RATE, rc);
+ goto exit;
+ }
+
+ /* Wait for data ready */
+ msleep(als_mrr_table[tmp & 0x7] + LTR553_WAKE_TIME_MS);
+
+ /* Clear last value and report even not change. */
+ ltr->last_als = -1;
+
+ rc = ltr553_process_data(ltr, 1);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "process als data failed\n");
+ goto exit;
+ }
+
+ /* clear interrupt */
+ rc = regmap_bulk_read(ltr->regmap, LTR553_REG_ALS_DATA_CH1_0,
+ buf, ARRAY_SIZE(buf));
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "clear interrupt failed\n");
+ goto exit;
+ }
+
+ ltr->als_enabled = true;
+ } else {
+ /* disable als sensor */
+ rc = regmap_write(ltr->regmap, LTR553_REG_ALS_CTL,
+ config & (~0x1));
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d failed.(%d)\n",
+ LTR553_REG_ALS_CTL, rc);
+ goto exit;
+ }
+
+ ltr->als_enabled = false;
+ }
+
+exit:
+ return rc;
+}
+
+static int ltr553_als_sync_delay(struct ltr553_data *ltr,
+ unsigned int als_delay)
+{
+ int index = 0;
+ int i;
+ unsigned int val;
+ int rc = 0;
+ int min;
+
+ if (!ltr->power_enabled) {
+ dev_dbg(&ltr->i2c->dev, "power is not enabled\n");
+ return 0;
+ }
+
+ min = abs(als_delay - als_mrr_table[0]);
+ for (i = 0; i < ARRAY_SIZE(als_mrr_table); i++) {
+ if (als_mrr_table[i] >= 10 *
+ als_int_fac_table[ltr->als_integration_time]) {
+ if (als_delay == als_mrr_table[i]) {
+ index = i;
+ break;
+ }
+ if (min > abs(als_delay - als_mrr_table[i])) {
+ index = i;
+ min = abs(als_delay - als_mrr_table[i]);
+ }
+ }
+ }
+
+ dev_dbg(&ltr->i2c->dev, "als delay %d ms\n", als_mrr_table[index]);
+
+ rc = regmap_read(ltr->regmap, LTR553_REG_ALS_MEAS_RATE, &val);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "read %d failed\n",
+ LTR553_REG_ALS_MEAS_RATE);
+ goto exit;
+ }
+ val &= ~0x7;
+
+ ltr->als_measure_rate = index;
+ rc = regmap_write(ltr->regmap, LTR553_REG_ALS_MEAS_RATE, val | index);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d failed\n",
+ LTR553_REG_ALS_MEAS_RATE);
+ goto exit;
+ }
+
+exit:
+ return rc;
+}
+
+
+static int ltr553_ps_sync_delay(struct ltr553_data *ltr, unsigned int ps_delay)
+{
+ int index = 0;
+ int i;
+ int rc = 0;
+ int min;
+
+ if (!ltr->power_enabled) {
+ dev_dbg(&ltr->i2c->dev, "power is not enabled\n");
+ return 0;
+ }
+
+ min = abs(ps_delay - ps_mrr_table[0]);
+ for (i = 0; i < ARRAY_SIZE(ps_mrr_table); i++) {
+ if (ps_delay == ps_mrr_table[i]) {
+ index = i;
+ break;
+ }
+ if (min > abs(ps_delay - ps_mrr_table[i])) {
+ min = abs(ps_delay - ps_mrr_table[i]);
+ index = i;
+ }
+ }
+
+ ltr->ps_measure_rate = index;
+ dev_dbg(&ltr->i2c->dev, "ps delay %d ms\n", ps_mrr_table[index]);
+
+ rc = regmap_write(ltr->regmap, LTR553_REG_PS_MEAS_RATE, index);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d failed\n",
+ LTR553_REG_PS_MEAS_RATE);
+ goto exit;
+ }
+
+exit:
+ return rc;
+}
+
+static void ltr553_als_enable_work(struct work_struct *work)
+{
+ struct ltr553_data *ltr = container_of(work, struct ltr553_data,
+ als_enable_work);
+
+ mutex_lock(&ltr->ops_lock);
+ if (!ltr->power_enabled) { /* new HAL? */
+ if (sensor_power_config(&ltr->i2c->dev, power_config,
+ ARRAY_SIZE(power_config), true)) {
+ dev_err(&ltr->i2c->dev, "power up sensor failed.\n");
+ goto exit;
+ }
+
+ msleep(LTR553_BOOT_TIME_MS);
+ ltr->power_enabled = true;
+ if (ltr553_init_device(ltr)) {
+ dev_err(&ltr->i2c->dev, "init device failed\n");
+ goto exit_power_off;
+ }
+
+ ltr553_als_sync_delay(ltr, ltr->als_delay);
+ }
+
+ if (ltr553_enable_als(ltr, 1)) {
+ dev_err(&ltr->i2c->dev, "enable als failed\n");
+ goto exit_power_off;
+ }
+
+exit_power_off:
+ if ((!ltr->als_enabled) && (!ltr->ps_enabled) &&
+ ltr->power_enabled) {
+ if (sensor_power_config(&ltr->i2c->dev, power_config,
+ ARRAY_SIZE(power_config), false)) {
+ dev_err(&ltr->i2c->dev, "power up sensor failed.\n");
+ goto exit;
+ }
+ ltr->power_enabled = false;
+ }
+exit:
+ mutex_unlock(&ltr->ops_lock);
+}
+
+
+static void ltr553_als_disable_work(struct work_struct *work)
+{
+ struct ltr553_data *ltr = container_of(work, struct ltr553_data,
+ als_disable_work);
+
+ mutex_lock(&ltr->ops_lock);
+
+ if (ltr553_enable_als(ltr, 0)) {
+ dev_err(&ltr->i2c->dev, "disable als failed\n");
+ goto exit;
+ }
+
+ if ((!ltr->als_enabled) && (!ltr->ps_enabled) && ltr->power_enabled) {
+ if (sensor_power_config(&ltr->i2c->dev, power_config,
+ ARRAY_SIZE(power_config), false)) {
+ dev_err(&ltr->i2c->dev, "power up sensor failed.\n");
+ goto exit;
+ }
+
+ ltr->power_enabled = false;
+ }
+
+exit:
+ mutex_unlock(&ltr->ops_lock);
+}
+
+static void ltr553_ps_enable_work(struct work_struct *work)
+{
+ struct ltr553_data *ltr = container_of(work, struct ltr553_data,
+ ps_enable_work);
+
+ mutex_lock(&ltr->ops_lock);
+ if (!ltr->power_enabled) {
+ if (sensor_power_config(&ltr->i2c->dev, power_config,
+ ARRAY_SIZE(power_config), true)) {
+ dev_err(&ltr->i2c->dev, "power up sensor failed.\n");
+ goto exit;
+ }
+
+ msleep(LTR553_BOOT_TIME_MS);
+ ltr->power_enabled = true;
+
+ if (ltr553_init_device(ltr)) {
+ dev_err(&ltr->i2c->dev, "init device failed\n");
+ goto exit_power_off;
+ }
+
+ ltr553_ps_sync_delay(ltr, ltr->ps_delay);
+ }
+
+ if (ltr553_enable_ps(ltr, 1)) {
+ dev_err(&ltr->i2c->dev, "enable ps failed\n");
+ goto exit_power_off;
+ }
+
+exit_power_off:
+ if ((!ltr->als_enabled) && (!ltr->ps_enabled) &&
+ ltr->power_enabled) {
+ if (sensor_power_config(&ltr->i2c->dev, power_config,
+ ARRAY_SIZE(power_config), false)) {
+ dev_err(&ltr->i2c->dev, "power up sensor failed.\n");
+ goto exit;
+ }
+ ltr->power_enabled = false;
+ }
+
+exit:
+ mutex_unlock(&ltr->ops_lock);
+}
+
+static void ltr553_ps_disable_work(struct work_struct *work)
+{
+ struct ltr553_data *ltr = container_of(work, struct ltr553_data,
+ ps_disable_work);
+
+ mutex_lock(&ltr->ops_lock);
+
+ if (ltr553_enable_ps(ltr, 0)) {
+ dev_err(&ltr->i2c->dev, "ltrsable ps failed\n");
+ goto exit;
+ }
+
+ if ((!ltr->als_enabled) && (!ltr->ps_enabled) && ltr->power_enabled) {
+ if (sensor_power_config(&ltr->i2c->dev, power_config,
+ ARRAY_SIZE(power_config), false)) {
+ dev_err(&ltr->i2c->dev, "power up sensor failed.\n");
+ goto exit;
+ }
+
+ ltr->power_enabled = false;
+ }
+exit:
+ mutex_unlock(&ltr->ops_lock);
+}
+
+
+static struct regmap_config ltr553_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int ltr553_cdev_enable_als(struct sensors_classdev *sensors_cdev,
+ unsigned int enable)
+{
+ struct ltr553_data *ltr = container_of(sensors_cdev,
+ struct ltr553_data, als_cdev);
+
+ mutex_lock(&ltr->ops_lock);
+
+ if (enable)
+ queue_work(ltr->workqueue, &ltr->als_enable_work);
+ else
+ queue_work(ltr->workqueue, &ltr->als_disable_work);
+
+ mutex_unlock(&ltr->ops_lock);
+
+ return 0;
+}
+
+static int ltr553_cdev_enable_ps(struct sensors_classdev *sensors_cdev,
+ unsigned int enable)
+{
+ struct ltr553_data *ltr = container_of(sensors_cdev,
+ struct ltr553_data, ps_cdev);
+
+ mutex_lock(&ltr->ops_lock);
+
+ if (enable)
+ queue_work(ltr->workqueue, &ltr->ps_enable_work);
+ else
+ queue_work(ltr->workqueue, &ltr->ps_disable_work);
+
+ mutex_unlock(&ltr->ops_lock);
+
+ return 0;
+}
+
+static int ltr553_cdev_set_als_delay(struct sensors_classdev *sensors_cdev,
+ unsigned int delay_msec)
+{
+ struct ltr553_data *ltr = container_of(sensors_cdev,
+ struct ltr553_data, als_cdev);
+ int rc;
+
+ mutex_lock(&ltr->ops_lock);
+
+ ltr->als_delay = delay_msec;
+ rc = ltr553_als_sync_delay(ltr, delay_msec);
+
+ mutex_unlock(&ltr->ops_lock);
+
+ return rc;
+}
+
+static int ltr553_cdev_set_ps_delay(struct sensors_classdev *sensors_cdev,
+ unsigned int delay_msec)
+{
+ struct ltr553_data *ltr = container_of(sensors_cdev,
+ struct ltr553_data, ps_cdev);
+ int rc;
+
+ mutex_lock(&ltr->ops_lock);
+
+ ltr->ps_delay = delay_msec;
+ rc = ltr553_ps_sync_delay(ltr, delay_msec);
+
+ mutex_unlock(&ltr->ops_lock);
+
+ return 0;
+}
+
+static int ltr553_cdev_ps_flush(struct sensors_classdev *sensors_cdev)
+{
+ struct ltr553_data *ltr = container_of(sensors_cdev,
+ struct ltr553_data, ps_cdev);
+
+ input_event(ltr->input_proximity, EV_SYN, SYN_CONFIG,
+ ltr->flush_count++);
+ input_sync(ltr->input_proximity);
+
+ return 0;
+}
+
+static int ltr553_cdev_als_flush(struct sensors_classdev *sensors_cdev)
+{
+ struct ltr553_data *ltr = container_of(sensors_cdev,
+ struct ltr553_data, als_cdev);
+
+ input_event(ltr->input_light, EV_SYN, SYN_CONFIG, ltr->flush_count++);
+ input_sync(ltr->input_light);
+
+ return 0;
+}
+
+/* This function should be called when sensor is disabled */
+static int ltr553_cdev_ps_calibrate(struct sensors_classdev *sensors_cdev,
+ int axis, int apply_now)
+{
+ int rc;
+ int power;
+ unsigned int config;
+ unsigned int interrupt;
+ u16 min = PS_DATA_MASK;
+ u8 ps_data[2];
+ int count = LTR553_CALIBRATE_SAMPLES;
+ struct ltr553_data *ltr = container_of(sensors_cdev,
+ struct ltr553_data, ps_cdev);
+
+
+ if (axis != AXIS_BIAS)
+ return 0;
+
+ mutex_lock(&ltr->ops_lock);
+
+ /* Ensure only be called when sensors in standy mode */
+ if (ltr->als_enabled || ltr->ps_enabled) {
+ rc = -EPERM;
+ goto exit;
+ }
+
+ power = ltr->power_enabled;
+ if (!power) {
+ rc = sensor_power_config(&ltr->i2c->dev, power_config,
+ ARRAY_SIZE(power_config), true);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "power up sensor failed.\n");
+ goto exit;
+ }
+
+ msleep(LTR553_BOOT_TIME_MS);
+
+ rc = ltr553_init_device(ltr);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "init ltr553 failed\n");
+ goto exit;
+ }
+ }
+
+ rc = regmap_read(ltr->regmap, LTR553_REG_INTERRUPT, &interrupt);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "read interrupt configuration failed\n");
+ goto exit_power_off;
+ }
+
+ /* disable interrupt */
+ rc = regmap_write(ltr->regmap, LTR553_REG_INTERRUPT, 0x0);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "disable interrupt failed\n");
+ goto exit_power_off;
+ }
+
+ rc = regmap_read(ltr->regmap, LTR553_REG_PS_CTL, &config);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "read %d failed.(%d)\n",
+ LTR553_REG_PS_CTL, rc);
+ goto exit_enable_interrupt;
+ }
+
+ /* clear offset */
+ ps_data[0] = 0;
+ ps_data[1] = 0;
+ rc = regmap_bulk_write(ltr->regmap, LTR553_REG_PS_OFFSET_1,
+ ps_data, 2);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d failed.(%d)\n",
+ LTR553_REG_PS_OFFSET_1, rc);
+ goto exit_enable_interrupt;
+ }
+
+ /* enable ps sensor */
+ rc = regmap_write(ltr->regmap, LTR553_REG_PS_CTL, config | 0x02);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d failed.(%d)\n",
+ LTR553_REG_PS_CTL, rc);
+ goto exit_enable_interrupt;
+ }
+
+ /* ps measurement rate set to fastest rate */
+ rc = regmap_write(ltr->regmap, LTR553_REG_PS_MEAS_RATE,
+ LTR553_PS_MEASUREMENT_RATE_10MS);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "read %d failed.(%d)\n",
+ LTR553_REG_PS_MEAS_RATE, rc);
+ goto exit_enable_interrupt;
+ }
+
+ msleep(LTR553_WAKE_TIME_MS);
+
+ while (--count) {
+ /* the measurement rate is 10 ms */
+ usleep_range(11000, 12000);
+ rc = regmap_bulk_read(ltr->regmap, LTR553_REG_PS_DATA_0,
+ ps_data, 2);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "read PS data failed\n");
+ break;
+ }
+ if (min > ((ps_data[1] << 8) | ps_data[0]))
+ min = (ps_data[1] << 8) | ps_data[0];
+ }
+
+ /* disable ps sensor */
+ rc = regmap_write(ltr->regmap, LTR553_REG_PS_CTL, config);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d failed.(%d)\n",
+ LTR553_REG_PS_CTL, rc);
+ goto exit_enable_interrupt;
+ }
+
+ if (!count) {
+ if (min > (PS_DATA_MASK >> 1)) {
+ dev_err(&ltr->i2c->dev, "ps data out of range, check if shield\n");
+ rc = -EINVAL;
+ goto exit_enable_interrupt;
+ }
+
+ if (apply_now) {
+ ps_data[1] = PS_LOW_BYTE(min);
+ ps_data[0] = PS_HIGH_BYTE(min);
+ rc = regmap_bulk_write(ltr->regmap,
+ LTR553_REG_PS_OFFSET_1, ps_data, 2);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d failed.(%d)\n",
+ LTR553_REG_PS_OFFSET_1, rc);
+ goto exit_enable_interrupt;
+ }
+ ltr->bias = min;
+ }
+
+ snprintf(ltr->calibrate_buf, sizeof(ltr->calibrate_buf),
+ "0,0,%d", min);
+ dev_dbg(&ltr->i2c->dev, "result: %s\n", ltr->calibrate_buf);
+ } else {
+ dev_err(&ltr->i2c->dev, "calibration failed\n");
+ rc = -EINVAL;
+ }
+
+exit_enable_interrupt:
+ if (regmap_write(ltr->regmap, LTR553_REG_INTERRUPT, interrupt)) {
+ dev_err(&ltr->i2c->dev, "enable interrupt failed\n");
+ goto exit_power_off;
+ }
+
+exit_power_off:
+ if (!power) {
+ if (sensor_power_config(&ltr->i2c->dev, power_config,
+ ARRAY_SIZE(power_config), false)) {
+ dev_err(&ltr->i2c->dev, "power off sensor failed.\n");
+ goto exit;
+ }
+ }
+exit:
+ mutex_unlock(&ltr->ops_lock);
+ return rc;
+}
+
+static int ltr553_cdev_ps_write_cal(struct sensors_classdev *sensors_cdev,
+ struct cal_result_t *cal_result)
+{
+ int power;
+ u8 ps_data[2];
+ int rc = 0;
+ struct ltr553_data *ltr = container_of(sensors_cdev,
+ struct ltr553_data, ps_cdev);
+
+ mutex_lock(&ltr->ops_lock);
+ power = ltr->power_enabled;
+ if (!power) {
+ rc = sensor_power_config(&ltr->i2c->dev, power_config,
+ ARRAY_SIZE(power_config), true);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "power up sensor failed.\n");
+ goto exit;
+ }
+ }
+
+ ltr->bias = cal_result->bias;
+ ps_data[1] = PS_LOW_BYTE(cal_result->bias);
+ ps_data[0] = PS_HIGH_BYTE(cal_result->bias);
+ rc = regmap_bulk_write(ltr->regmap, LTR553_REG_PS_OFFSET_1,
+ ps_data, 2);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d failed.(%d)\n",
+ LTR553_REG_PS_OFFSET_1, rc);
+ goto exit_power_off;
+ }
+
+ snprintf(ltr->calibrate_buf, sizeof(ltr->calibrate_buf), "0,0,%d",
+ ltr->bias);
+
+exit_power_off:
+ if (!power) {
+ if (sensor_power_config(&ltr->i2c->dev, power_config,
+ ARRAY_SIZE(power_config), false)) {
+ dev_err(&ltr->i2c->dev, "power off sensor failed.\n");
+ goto exit;
+ }
+ }
+exit:
+
+ mutex_unlock(&ltr->ops_lock);
+ return rc;
+};
+
+static ssize_t ltr553_register_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ltr553_data *ltr = dev_get_drvdata(dev);
+ unsigned int val;
+ int rc;
+ ssize_t count = 0;
+ int i;
+
+ if (ltr->reg_addr == LTR553_REG_MAGIC) {
+ for (i = 0; i <= 0x1f; i++) {
+ rc = regmap_read(ltr->regmap, LTR553_REG_ALS_CTL + i,
+ &val);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "read %d failed\n",
+ LTR553_REG_ALS_CTL + i);
+ break;
+ }
+ count += snprintf(&buf[count], PAGE_SIZE,
+ "0x%x: 0x%x\n", LTR553_REG_ALS_CTL + i,
+ val);
+ }
+ } else {
+ rc = regmap_read(ltr->regmap, ltr->reg_addr, &val);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "read %d failed\n",
+ ltr->reg_addr);
+ return rc;
+ }
+ count += snprintf(&buf[count], PAGE_SIZE, "0x%x:0x%x\n",
+ ltr->reg_addr, val);
+ }
+
+ return count;
+}
+
+static ssize_t ltr553_register_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct ltr553_data *ltr = dev_get_drvdata(dev);
+ unsigned int reg;
+ unsigned int val;
+ unsigned int cmd;
+ int rc;
+
+ if (sscanf(buf, "%u %u %u\n", &cmd, &reg, &val) < 2) {
+ dev_err(&ltr->i2c->dev, "argument error\n");
+ return -EINVAL;
+ }
+
+ if (cmd == CMD_WRITE) {
+ rc = regmap_write(ltr->regmap, reg, val);
+ if (rc) {
+ dev_err(&ltr->i2c->dev, "write %d failed\n", reg);
+ return rc;
+ }
+ } else if (cmd == CMD_READ) {
+ ltr->reg_addr = reg;
+ dev_dbg(&ltr->i2c->dev, "register address set to 0x%x\n", reg);
+ }
+
+ return size;
+}
+
+static DEVICE_ATTR(register, S_IWUSR | S_IRUGO,
+ ltr553_register_show,
+ ltr553_register_store);
+
+static struct attribute *ltr553_attr[] = {
+ &dev_attr_register.attr,
+ NULL
+};
+
+static const struct attribute_group ltr553_attr_group = {
+ .attrs = ltr553_attr,
+};
+
+static int ltr553_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ltr553_data *ltr;
+ int res = 0;
+
+ dev_dbg(&client->dev, "probling ltr553...\n");
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "ltr553 i2c check failed.\n");
+ return -ENODEV;
+ }
+
+ ltr = devm_kzalloc(&client->dev, sizeof(struct ltr553_data),
+ GFP_KERNEL);
+ if (!ltr)
+ return -ENOMEM;
+
+ ltr->i2c = client;
+
+ if (client->dev.of_node) {
+ res = ltr553_parse_dt(&client->dev, ltr);
+ if (res) {
+ dev_err(&client->dev,
+ "unable to parse device tree.(%d)\n", res);
+ goto out;
+ }
+ } else {
+ dev_err(&client->dev, "device tree not found.\n");
+ res = -ENODEV;
+ goto out;
+ }
+
+ dev_set_drvdata(&client->dev, ltr);
+ mutex_init(&ltr->ops_lock);
+
+ ltr->regmap = devm_regmap_init_i2c(client, &ltr553_regmap_config);
+ if (IS_ERR(ltr->regmap)) {
+ dev_err(&client->dev, "init regmap failed.(%ld)\n",
+ PTR_ERR(ltr->regmap));
+ res = PTR_ERR(ltr->regmap);
+ goto out;
+ }
+
+ res = sensor_power_init(&client->dev, power_config,
+ ARRAY_SIZE(power_config));
+ if (res) {
+ dev_err(&client->dev, "init power failed.\n");
+ goto out;
+ }
+
+ res = sensor_power_config(&client->dev, power_config,
+ ARRAY_SIZE(power_config), true);
+ if (res) {
+ dev_err(&client->dev, "power up sensor failed.\n");
+ goto err_power_config;
+ }
+
+ res = sensor_pinctrl_init(&client->dev, &pin_config);
+ if (res) {
+ dev_err(&client->dev, "init pinctrl failed.\n");
+ goto err_pinctrl_init;
+ }
+
+ msleep(LTR553_BOOT_TIME_MS);
+
+ res = ltr553_check_device(ltr);
+ if (res) {
+ dev_err(&client->dev, "check device failed.\n");
+ goto err_check_device;
+ }
+
+ ltr->als_measure_rate = LTR553_ALS_DEFAULT_MEASURE_RATE;
+
+ res = ltr553_init_device(ltr);
+ if (res) {
+ dev_err(&client->dev, "check device failed.\n");
+ goto err_init_device;
+ }
+
+ /* configure interrupt */
+ if (gpio_is_valid(ltr->irq_gpio)) {
+ res = gpio_request(ltr->irq_gpio, "ltr553_interrupt");
+ if (res) {
+ dev_err(&client->dev,
+ "unable to request interrupt gpio %d\n",
+ ltr->irq_gpio);
+ goto err_request_gpio;
+ }
+
+ res = gpio_direction_input(ltr->irq_gpio);
+ if (res) {
+ dev_err(&client->dev,
+ "unable to set direction for gpio %d\n",
+ ltr->irq_gpio);
+ goto err_set_direction;
+ }
+
+ ltr->irq = gpio_to_irq(ltr->irq_gpio);
+
+ res = devm_request_irq(&client->dev, ltr->irq,
+ ltr553_irq_handler,
+ ltr->irq_flags | IRQF_ONESHOT,
+ "ltr553", ltr);
+
+ if (res) {
+ dev_err(&client->dev,
+ "request irq %d failed(%d),\n",
+ ltr->irq, res);
+ goto err_request_irq;
+ }
+
+ /* device wakeup initialization */
+ device_init_wakeup(&client->dev, 1);
+
+ ltr->workqueue = alloc_workqueue("ltr553_workqueue",
+ WQ_FREEZABLE, 0);
+ INIT_WORK(&ltr->report_work, ltr553_report_work);
+ INIT_WORK(&ltr->als_enable_work, ltr553_als_enable_work);
+ INIT_WORK(&ltr->als_disable_work, ltr553_als_disable_work);
+ INIT_WORK(&ltr->ps_enable_work, ltr553_ps_enable_work);
+ INIT_WORK(&ltr->ps_disable_work, ltr553_ps_disable_work);
+
+ } else {
+ res = -ENODEV;
+ goto err_init_device;
+ }
+
+ res = sysfs_create_group(&client->dev.kobj, &ltr553_attr_group);
+ if (res) {
+ dev_err(&client->dev, "sysfs create group failed\n");
+ goto err_create_group;
+ }
+
+ res = ltr553_init_input(ltr);
+ if (res) {
+ dev_err(&client->dev, "init input failed.\n");
+ goto err_init_input;
+ }
+
+ ltr->als_cdev = als_cdev;
+ ltr->als_cdev.sensors_enable = ltr553_cdev_enable_als;
+ ltr->als_cdev.sensors_poll_delay = ltr553_cdev_set_als_delay;
+ ltr->als_cdev.sensors_flush = ltr553_cdev_als_flush;
+ res = sensors_classdev_register(&ltr->input_light->dev, &ltr->als_cdev);
+ if (res) {
+ dev_err(&client->dev, "sensors class register failed.\n");
+ goto err_register_als_cdev;
+ }
+
+ ltr->ps_cdev = ps_cdev;
+ ltr->ps_cdev.sensors_enable = ltr553_cdev_enable_ps;
+ ltr->ps_cdev.sensors_poll_delay = ltr553_cdev_set_ps_delay;
+ ltr->ps_cdev.sensors_flush = ltr553_cdev_ps_flush;
+ ltr->ps_cdev.sensors_calibrate = ltr553_cdev_ps_calibrate;
+ ltr->ps_cdev.sensors_write_cal_params = ltr553_cdev_ps_write_cal;
+ ltr->ps_cdev.params = ltr->calibrate_buf;
+ res = sensors_classdev_register(&ltr->input_proximity->dev,
+ &ltr->ps_cdev);
+ if (res) {
+ dev_err(&client->dev, "sensors class register failed.\n");
+ goto err_register_ps_cdev;
+ }
+
+ sensor_power_config(&client->dev, power_config,
+ ARRAY_SIZE(power_config), false);
+
+ dev_dbg(&client->dev, "ltr553 successfully probed!\n");
+
+ return 0;
+
+err_register_ps_cdev:
+ sensors_classdev_unregister(&ltr->als_cdev);
+err_register_als_cdev:
+err_init_input:
+ sysfs_remove_group(&client->dev.kobj, &ltr553_attr_group);
+err_create_group:
+err_request_irq:
+err_set_direction:
+ gpio_free(ltr->irq_gpio);
+err_request_gpio:
+err_init_device:
+ device_init_wakeup(&client->dev, 0);
+err_check_device:
+err_pinctrl_init:
+ sensor_power_config(&client->dev, power_config,
+ ARRAY_SIZE(power_config), false);
+err_power_config:
+ sensor_power_deinit(&client->dev, power_config,
+ ARRAY_SIZE(power_config));
+out:
+ return res;
+}
+
+static int ltr553_remove(struct i2c_client *client)
+{
+ struct ltr553_data *ltr = dev_get_drvdata(&client->dev);
+
+ sensors_classdev_unregister(&ltr->ps_cdev);
+ sensors_classdev_unregister(&ltr->als_cdev);
+
+ if (ltr->input_light)
+ input_unregister_device(ltr->input_light);
+
+ if (ltr->input_proximity)
+ input_unregister_device(ltr->input_proximity);
+
+ destroy_workqueue(ltr->workqueue);
+ device_init_wakeup(&ltr->i2c->dev, 0);
+ sensor_power_config(&client->dev, power_config,
+ ARRAY_SIZE(power_config), false);
+ sensor_power_deinit(&client->dev, power_config,
+ ARRAY_SIZE(power_config));
+ return 0;
+}
+
+static int ltr553_suspend(struct device *dev)
+{
+ int res = 0;
+ struct ltr553_data *ltr = dev_get_drvdata(dev);
+ u8 ps_data[4];
+ unsigned int config;
+ int idx = ltr->ps_wakeup_threshold;
+
+ dev_dbg(dev, "suspending ltr553...");
+
+ mutex_lock(&ltr->ops_lock);
+
+ /* proximity is enabled */
+ if (ltr->ps_enabled) {
+ /* disable als sensor to avoid wake up by als interrupt */
+ if (ltr->als_enabled) {
+ res = regmap_read(ltr->regmap, LTR553_REG_ALS_CTL,
+ &config);
+ if (res) {
+ dev_err(&ltr->i2c->dev, "read %d failed.(%d)\n",
+ LTR553_REG_ALS_CTL, res);
+ return res;
+ }
+
+ res = regmap_write(ltr->regmap, LTR553_REG_ALS_CTL,
+ config & (~0x1));
+ if (res) {
+ dev_err(&ltr->i2c->dev, "write %d failed.(%d)\n",
+ LTR553_REG_ALS_CTL, res);
+ goto exit;
+ }
+ }
+
+ /* Don't power off sensor because proximity is a
+ * wake up sensor.
+ */
+ if (device_may_wakeup(&ltr->i2c->dev)) {
+ dev_dbg(&ltr->i2c->dev, "enable irq wake\n");
+ enable_irq_wake(ltr->irq);
+ }
+
+ /* Setup threshold to avoid frequent wakeup */
+ if (device_may_wakeup(&ltr->i2c->dev) &&
+ (idx != LTR553_WAKEUP_ANY_CHANGE)) {
+ dev_dbg(&ltr->i2c->dev, "last ps: %d\n", ltr->last_ps);
+ if (ltr->last_ps > idx) {
+ ps_data[2] = 0x0;
+ ps_data[3] = 0x0;
+ ps_data[0] =
+ PS_LOW_BYTE(ps_distance_table[idx]);
+ ps_data[1] =
+ PS_HIGH_BYTE(ps_distance_table[idx]);
+ } else {
+ ps_data[2] =
+ PS_LOW_BYTE(ps_distance_table[idx]);
+ ps_data[3] =
+ PS_HIGH_BYTE(ps_distance_table[idx]);
+ ps_data[0] = PS_LOW_BYTE(PS_DATA_MASK);
+ ps_data[1] = PS_HIGH_BYTE(PS_DATA_MASK);
+ }
+
+ res = regmap_bulk_write(ltr->regmap,
+ LTR553_REG_PS_THRES_UP_0, ps_data, 4);
+ if (res) {
+ dev_err(&ltr->i2c->dev, "set up threshold failed\n");
+ goto exit;
+ }
+ }
+ } else {
+ /* power off */
+ disable_irq(ltr->irq);
+ if (ltr->power_enabled) {
+ res = sensor_power_config(dev, power_config,
+ ARRAY_SIZE(power_config), false);
+ if (res) {
+ dev_err(dev, "failed to suspend ltr553\n");
+ enable_irq(ltr->irq);
+ goto exit;
+ }
+ }
+ pinctrl_select_state(pin_config.pinctrl, pin_config.state[1]);
+ }
+exit:
+ mutex_unlock(&ltr->ops_lock);
+ return res;
+}
+
+static int ltr553_resume(struct device *dev)
+{
+ int res = 0;
+ struct ltr553_data *ltr = dev_get_drvdata(dev);
+ unsigned int config;
+
+ dev_dbg(dev, "resuming ltr553...");
+ if (ltr->ps_enabled) {
+ if (device_may_wakeup(&ltr->i2c->dev)) {
+ dev_dbg(&ltr->i2c->dev, "disable irq wake\n");
+ disable_irq_wake(ltr->irq);
+ }
+
+ if (ltr->als_enabled) {
+ res = regmap_read(ltr->regmap, LTR553_REG_ALS_CTL,
+ &config);
+ if (res) {
+ dev_err(&ltr->i2c->dev, "read %d failed.(%d)\n",
+ LTR553_REG_ALS_CTL, res);
+ goto exit;
+ }
+
+ res = regmap_write(ltr->regmap, LTR553_REG_ALS_CTL,
+ config | 0x1);
+ if (res) {
+ dev_err(&ltr->i2c->dev, "write %d failed.(%d)\n",
+ LTR553_REG_ALS_CTL, res);
+ goto exit;
+ }
+ }
+ } else {
+ pinctrl_select_state(pin_config.pinctrl, pin_config.state[0]);
+ /* Power up sensor */
+ if (ltr->power_enabled) {
+ res = sensor_power_config(dev, power_config,
+ ARRAY_SIZE(power_config), true);
+ if (res) {
+ dev_err(dev, "failed to power up ltr553\n");
+ goto exit;
+ }
+ msleep(LTR553_BOOT_TIME_MS);
+
+ res = ltr553_init_device(ltr);
+ if (res) {
+ dev_err(dev, "failed to init ltr553\n");
+ goto exit_power_off;
+ }
+ }
+
+ if (ltr->als_enabled) {
+ res = ltr553_enable_als(ltr, ltr->als_enabled);
+ if (res) {
+ dev_err(dev, "failed to enable ltr553\n");
+ goto exit_power_off;
+ }
+ }
+
+ enable_irq(ltr->irq);
+ }
+
+ return res;
+
+exit_power_off:
+ if ((!ltr->als_enabled) && (!ltr->ps_enabled) &&
+ ltr->power_enabled) {
+ if (sensor_power_config(&ltr->i2c->dev, power_config,
+ ARRAY_SIZE(power_config), false)) {
+ dev_err(&ltr->i2c->dev, "power up sensor failed.\n");
+ goto exit;
+ }
+ ltr->power_enabled = false;
+ }
+
+exit:
+ return res;
+}
+
+static const struct i2c_device_id ltr553_id[] = {
+ { LTR553_I2C_NAME, 0 },
+ { }
+};
+
+static struct of_device_id ltr553_match_table[] = {
+ { .compatible = "liteon,ltr553", },
+ { },
+};
+
+static const struct dev_pm_ops ltr553_pm_ops = {
+ .suspend = ltr553_suspend,
+ .resume = ltr553_resume,
+};
+
+static struct i2c_driver ltr553_driver = {
+ .probe = ltr553_probe,
+ .remove = ltr553_remove,
+ .id_table = ltr553_id,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = LTR553_I2C_NAME,
+ .of_match_table = ltr553_match_table,
+ .pm = &ltr553_pm_ops,
+ },
+};
+
+module_i2c_driver(ltr553_driver);
+
+MODULE_DESCRIPTION("LTR-553ALPS Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/misc/tri_state_key.c b/drivers/input/misc/tri_state_key.c
index 560f25d16116..5f622384e070 100755
--- a/drivers/input/misc/tri_state_key.c
+++ b/drivers/input/misc/tri_state_key.c
@@ -1,504 +1,344 @@
/*
+ * drivers/input/misc/tri_state_key.c
*
- * 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.
+ * Copyright (C) 2018, Sultanxda <sultanxda@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
#include <linux/gpio.h>
-#include <linux/gpio_keys.h>
-#include <linux/of_platform.h>
-#include <linux/of_gpio.h>
-
-#include <linux/switch.h>
-#include <linux/workqueue.h>
+#include <linux/input.h>
#include <linux/interrupt.h>
-#include <asm/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
-#include <linux/regulator/consumer.h>
+#define DRIVER_NAME "tri-state-key"
+#define NR_STATES (3)
-#include <linux/timer.h>
+enum key_vals {
+ KEYCODE_TOTAL_SILENCE = 600,
+ KEYCODE_MODE_ALARMS_ONLY,
+ KEYCODE_MODE_PRIORITY_ONLY,
+ KEYCODE_MODE_NONE,
+ KEYCODE_MODE_MAX
+};
-#define DRV_NAME "tri-state-key"
+static const char *const proc_names[] = {
+ "keyCode_top", "keyCode_middle", "keyCode_bottom"
+};
-/*
- KEY1(GPIO1) KEY2(GPIO92)
-1<>ź<EFBFBD>4<EFBFBD><34><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 0 1 | MUTE
-2<>ź<EFBFBD>5<EFBFBD><35><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1 1 | Do Not Disturb
-4<>ź<EFBFBD>3<EFBFBD><33><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1 0 | Normal
-
-*/
-typedef enum {
- MODE_UNKNOWN,
- MODE_MUTE,
- MODE_DO_NOT_DISTURB,
- MODE_NORMAL,
- MODE_MAX_NUM
-} tri_mode_t;
-
-struct switch_dev_data {
- //tri_mode_t last_type;
- //tri_mode_t mode_type;
- //int switch_enable;
- int irq_key3;
- int irq_key2;
- int irq_key1;
- int key1_gpio;//key1 gpio34
- int key2_gpio;//key2 gpio77
- int key3_gpio;
-
- struct regulator *vdd_io;
- //bool power_enabled;
-
- struct work_struct work;
- struct switch_dev sdev;
+struct tristate_data {
struct device *dev;
- //struct input_dev *input;
-
- struct timer_list s_timer;
- struct pinctrl * key_pinctrl;
- struct pinctrl_state * set_state;
-
+ struct input_dev *input;
+ struct mutex irq_lock;
+ enum key_vals key_codes[NR_STATES];
+ int key_gpios[NR_STATES];
+ uint8_t curr_state;
};
-static struct switch_dev_data *switch_data;
-static DEFINE_MUTEX(sem);
-#if 0
-static int set_gpio_by_pinctrl(void)
+static struct tristate_data *tdata_g;
+
+static void send_input(struct tristate_data *t, int keycode)
{
- printk(KERN_ERR "tristate_key set_gpio_by_pinctrl. \n");
- return pinctrl_select_state(switch_data->key_pinctrl, switch_data->set_state);
+ input_report_key(t->input, keycode, 1);
+ input_sync(t->input);
+ input_report_key(t->input, keycode, 0);
+ input_sync(t->input);
}
-#endif
-static void switch_dev_work(struct work_struct *work)
+
+static void tristate_process_state(struct tristate_data *t)
{
+ unsigned long key_state = 0;
+ int i;
+
+ /* Store the GPIO values of the keys as a bitmap */
+ for (i = 0; i < NR_STATES; i++)
+ key_state |= !!gpio_get_value(t->key_gpios[i]) << i;
+
+ /* Spurious interrupt; at least one of the pins should be zero */
+ if (key_state == 0x7)
+ return;
+
+ /* Redundant interrupt */
+ if (key_state == t->curr_state)
+ return;
+
+ t->curr_state = key_state;
+
+ /*
+ * Find the first bit set to zero; this is the current position. Bit 0
+ * corresponds to the top position, bit 1 corresponds to the middle
+ * position, and bit 2 corresponds to the bottom position.
+ */
+ i = ffz(key_state);
+ send_input(t, t->key_codes[i]);
+}
- int key1,key2,key3;
- //pr_err("%s gpio_get_value(%d)=%d\n",__func__,switch_data->key1_gpio,gpio_get_value(switch_data->key1_gpio));
- //pr_err("%s gpio_get_value(%d)=%d\n",__func__,switch_data->key2_gpio,gpio_get_value(switch_data->key2_gpio));
- //pr_err("%s gpio_get_value(%d)=%d\n",__func__,switch_data->key3_gpio,gpio_get_value(switch_data->key3_gpio));
-
- mutex_lock(&sem);
- key1=gpio_get_value(switch_data->key1_gpio);
- key2=gpio_get_value(switch_data->key2_gpio);
- key3=gpio_get_value(switch_data->key3_gpio);
-
- if(((key1==0)&&(key2==1)&&(key3==1))||((key1==1)&&(key2==0)&&(key3==1))||((key1==1)&&(key2==1)&&(key3==0)))
- {
- //gpio_set_value(switch_data->key3_gpio,0);
- //pr_err("%s gpio_22get_value(%d)=%d\n",__func__,switch_data->key3_gpio,gpio_get_value(switch_data->key3_gpio));
- if(!key2)
- {
- switch_set_state(&switch_data->sdev, MODE_DO_NOT_DISTURB);
- }
+static irqreturn_t tristate_irq_handler(int irq, void *dev_id)
+{
+ struct tristate_data *t = dev_id;
- if(!key3)
- {
- switch_set_state(&switch_data->sdev, MODE_NORMAL);
+ /* This handler is shared between three interrupt lines */
+ mutex_lock(&t->irq_lock);
+ tristate_process_state(t);
+ mutex_unlock(&t->irq_lock);
- }
+ return IRQ_HANDLED;
+}
- if(!key1)
- {
- switch_set_state(&switch_data->sdev, MODE_MUTE);
- }
+static int keycode_get_idx(const char *filename)
+{
+ int i;
- printk(KERN_ERR "%s ,tristatekey set to state(%d) \n",__func__,switch_data->sdev.state);
+ for (i = 0; i < NR_STATES; i++) {
+ if (!strcmp(proc_names[i], filename))
+ break;
}
- mutex_unlock(&sem);
-}
-irqreturn_t switch_dev_interrupt(int irq, void *_dev)
-{
-//printk("%s\n",__func__);
- schedule_work(&switch_data->work);
- return IRQ_HANDLED;
+ return i;
}
-static void timer_handle(unsigned long arg)
+static int keycode_show(struct seq_file *seq, void *offset)
{
- //mod_timer(&s_timer, jiffies + HZ);
- // if(set_gpio_by_pinctrl() < 0)
- // printk(KERN_ERR "tristate_key set_gpio_by_pinctrl FAILD!!!. \n");
- schedule_work(&switch_data->work);
- //del_timer(&switch_data->s_timer);
+ struct tristate_data *t = tdata_g;
+ int idx = (int)(long)seq->private;
- //printk(KERN_ERR "tristate_key set gpio77 timer. \n");
+ seq_printf(seq, "%d\n", t->key_codes[idx]);
+ return 0;
}
-/* //no need cause switch_class.c state_show()
-static ssize_t switch_dev_print_state(struct switch_dev *sdev, char *buf)
+static ssize_t tristate_keycode_write(struct file *file,
+ const char __user *page, size_t count, loff_t *offset)
{
- tri_mode_t state;
- state = switch_data->mode_type;
+ struct tristate_data *t = tdata_g;
+ char buf[sizeof("600")];
+ int data, idx;
- if (state)
- return sprintf(buf, "%d\n", state);
- return -1;
-}
-*/
-
-#ifdef CONFIG_OF
-static int switch_dev_get_devtree_pdata(struct device *dev)
-{
- struct device_node *node;
+ memset(buf, 0, sizeof(buf));
- node = dev->of_node;
- if (!node)
- return -EINVAL;
+ if (copy_from_user(buf, page, min_t(int, count, 3))) {
+ dev_err(t->dev, "Failed to read procfs input\n");
+ return count;
+ }
- switch_data->key3_gpio= of_get_named_gpio(node, "tristate,gpio_key3", 0);
- if ((!gpio_is_valid(switch_data->key3_gpio)))
- return -EINVAL;
- pr_err("switch_data->key3_gpio=%d \n", switch_data->key3_gpio);
+ if (kstrtoint(buf, 10, &data) < 0)
+ return count;
- switch_data->key2_gpio= of_get_named_gpio(node, "tristate,gpio_key2", 0);
- if ((!gpio_is_valid(switch_data->key2_gpio)))
- return -EINVAL;
- pr_err("switch_data->key2_gpio=%d \n", switch_data->key2_gpio);
-//printk("%s, key2 gpio:%d \n", __func__, switch_data->key2_gpio);
+ if (data < KEYCODE_TOTAL_SILENCE || data >= KEYCODE_MODE_MAX)
+ return count;
- switch_data->key1_gpio= of_get_named_gpio(node, "tristate,gpio_key1", 0);
- if ((!gpio_is_valid(switch_data->key1_gpio)))
- return -EINVAL;
- pr_err("switch_data->key1_gpio=%d \n", switch_data->key1_gpio);
-//printk("%s, key1 gpio:%d \n", __func__, switch_data->key1_gpio);
- return 0;
-}
+ idx = keycode_get_idx(file->f_path.dentry->d_iname);
-static struct of_device_id tristate_dev_of_match[] = {
- { .compatible = "oneplus,tri-state-key", },
- { },
-};
-MODULE_DEVICE_TABLE(of, tristate_dev_of_match);
+ mutex_lock(&t->irq_lock);
+ t->key_codes[idx] = data;
+ if (!(t->curr_state & BIT(idx)))
+ send_input(t, data);
+ mutex_unlock(&t->irq_lock);
-#else
+ return count;
+}
-static inline int
-switch_dev_get_devtree_pdata(struct device *dev)
+static int tristate_keycode_open(struct inode *inode, struct file *file)
{
- return 0;
+ int idx = keycode_get_idx(file->f_path.dentry->d_iname);
+
+ /* Pass the index to keycode_show */
+ return single_open(file, keycode_show, (void *)(long)idx);
}
-#endif
-/*
-#define SUPPLY_1V8 1800000UL
-#define SUPPLY_IO_MIN SUPPLY_1V8
-#define SUPPLY_IO_MAX SUPPLY_1V8
-#define SUPPLY_IO_REQ_CURRENT 6000U
-int tristate_regulator_release(void)
+static const struct file_operations tristate_keycode_proc = {
+ .owner = THIS_MODULE,
+ .open = tristate_keycode_open,
+ .read = seq_read,
+ .write = tristate_keycode_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int tristate_parse_dt(struct tristate_data *t)
{
+ struct device_node *np;
+ char prop_name[sizeof("tristate,gpio_key#")];
+ int i;
+ np = t->dev->of_node;
+ if (!np)
+ return -EINVAL;
+ for (i = 0; i < NR_STATES; i++) {
+ sprintf(prop_name, "tristate,gpio_key%d", i + 1);
- if (switch_data->vdd_io != NULL) {
- regulator_put(switch_data->vdd_io);
- switch_data->vdd_io = NULL;
+ t->key_gpios[i] = of_get_named_gpio(np, prop_name, 0);
+ if (!gpio_is_valid(t->key_gpios[i])) {
+ dev_err(t->dev, "Invalid %s property\n", prop_name);
+ return -EINVAL;
+ }
}
- switch_data->power_enabled = false;
-
return 0;
}
-int tristate_regulator_set(bool enable)
+static int tristate_register_irqs(struct tristate_data *t)
{
- int error = 0;
-
- if (switch_data->vdd_io == NULL) {
- dev_err(switch_data->dev,
- "Regulators not set\n");
+ char label[sizeof("tristate_key#-int")];
+ int i, j, key_irqs[NR_STATES], ret;
+
+ /* Get the IRQ numbers corresponding to the GPIOs */
+ for (i = 0; i < NR_STATES; i++) {
+ key_irqs[i] = gpio_to_irq(t->key_gpios[i]);
+ if (key_irqs[i] < 0) {
+ dev_err(t->dev, "Invalid IRQ (%d) for GPIO%d\n",
+ key_irqs[i], i + 1);
return -EINVAL;
+ }
}
- if (enable) {
- dev_dbg(switch_data->dev, "%s on\n", __func__);
-
- regulator_set_optimum_mode(switch_data->vdd_io,
- SUPPLY_IO_REQ_CURRENT);
-
- error = (regulator_is_enabled(switch_data->vdd_io) == 0) ?
- regulator_enable(switch_data->vdd_io) : 0;
+ for (i = 0; i < NR_STATES; i++) {
+ sprintf(label, "tristate_key%d-int", i + 1);
- if (error) {
- dev_err(switch_data->dev,
- "Regulator vdd_io enable failed, error=%d\n",
- error);
- goto out_err;
+ ret = gpio_request(t->key_gpios[i], label);
+ if (ret < 0) {
+ dev_err(t->dev, "Failed to request GPIO%d, ret: %d\n",
+ i + 1, ret);
+ goto free_gpios;
}
- } else {
- dev_dbg(switch_data->dev, "%s off\n", __func__);
+ ret = gpio_direction_input(t->key_gpios[i]);
+ if (ret < 0) {
+ dev_err(t->dev, "Failed to set GPIO%d dir, ret: %d\n",
+ i + 1, ret);
+ goto free_gpios;
+ }
- error = (switch_data->power_enabled &&
- regulator_is_enabled(switch_data->vdd_io) > 0) ?
- regulator_disable(switch_data->vdd_io) : 0;
+ sprintf(label, "tristate_key%d", i + 1);
- if (error) {
- dev_err(switch_data->dev,
- "Regulator vdd_io disable failed, error=%d\n",
- error);
- goto out_err;
+ ret = request_threaded_irq(key_irqs[i], NULL,
+ tristate_irq_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT, label, t);
+ if (ret < 0) {
+ dev_err(t->dev, "Failed to register %s IRQ, ret: %d\n",
+ label, ret);
+ goto free_irqs;
}
-
}
- switch_data->power_enabled = enable;
+
+ for (i = 0; i < NR_STATES; i++)
+ enable_irq_wake(key_irqs[i]);
+
return 0;
-out_err:
- tristate_regulator_release();
- return error;
+free_irqs:
+ for (j = i; j--;)
+ free_irq(key_irqs[j], t);
+ i = NR_STATES;
+free_gpios:
+ for (j = i; j--;)
+ gpio_free(t->key_gpios[j]);
+ return -EINVAL;
}
-static int tristate_supply_init(void)
+static void tristate_create_procfs(void)
{
- int error = 0;
-
- switch_data->vdd_io = regulator_get(switch_data->dev, "vdd_io");
- if (IS_ERR(switch_data->vdd_io)) {
- error = PTR_ERR(switch_data->vdd_io);
- dev_err(switch_data->dev,
- "Regulator get failed, vdd_io, error=%d\n", error);
- goto err;
- }
+ struct proc_dir_entry *proc_dir;
+ int i;
- if (regulator_count_voltages(switch_data->vdd_io) > 0) {
- error = regulator_set_voltage(switch_data->vdd_io,
- SUPPLY_IO_MIN, SUPPLY_IO_MAX);
- if (error) {
- dev_err(switch_data->dev,
- "regulator set(io) failed, error=%d\n", error);
- goto err;
- }
- }
- if (error) {
- dev_err(switch_data->dev,
- "regulator configuration failed.\n");
- goto err;
- }
+ proc_dir = proc_mkdir("tri-state-key", NULL);
+ if (!proc_dir)
+ return;
- error = tristate_regulator_set(true);
- if (error) {
- dev_err(switch_data->dev,
- "regulator enable failed.\n");
- goto err;
+ for (i = 0; i < NR_STATES; i++)
+ proc_create_data(proc_names[i], 0644, proc_dir,
+ &tristate_keycode_proc, NULL);
+}
+
+static int tristate_probe(struct platform_device *pdev)
+{
+ struct tristate_data *t;
+ int i, ret;
+
+ t = kzalloc(sizeof(*t), GFP_KERNEL);
+ if (!t)
+ return -ENOMEM;
+
+ t->dev = &pdev->dev;
+ tdata_g = t;
+
+ ret = tristate_parse_dt(t);
+ if (ret)
+ goto free_t;
+
+ t->input = input_allocate_device();
+ if (!t->input) {
+ dev_err(t->dev, "Failed to allocate input device\n");
+ ret = -ENOMEM;
+ goto free_t;
}
-err:
- return error;
-}
+ t->input->name = DRIVER_NAME;
+ t->input->dev.parent = t->dev;
+ input_set_drvdata(t->input, t);
-*/
+ set_bit(EV_KEY, t->input->evbit);
+ set_bit(KEYCODE_TOTAL_SILENCE, t->input->keybit);
+ set_bit(KEYCODE_MODE_ALARMS_ONLY, t->input->keybit);
+ set_bit(KEYCODE_MODE_PRIORITY_ONLY, t->input->keybit);
+ set_bit(KEYCODE_MODE_NONE, t->input->keybit);
-static int tristate_dev_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
-
- int error=0;
-
- //void __iomem *cfg_reg;
-
- switch_data = kzalloc(sizeof(struct switch_dev_data), GFP_KERNEL);
- switch_data->dev = dev;
- #if 0
- switch_data->key_pinctrl = devm_pinctrl_get(switch_data->dev);
- if (IS_ERR_OR_NULL(switch_data->key_pinctrl)) {
- dev_err(switch_data->dev, "Failed to get pinctrl \n");
- goto err_switch_dev_register;
- }
- switch_data->set_state =pinctrl_lookup_state(switch_data->key_pinctrl,"pmx_tri_state_key_active");
- if (IS_ERR_OR_NULL(switch_data->set_state)) {
- dev_err(switch_data->dev, "Failed to lookup_state \n");
- goto err_switch_dev_register;
- }
-
- set_gpio_by_pinctrl();
- #endif
- //switch_data->last_type = MODE_UNKNOWN;
-
- //tristate_supply_init();
- error = switch_dev_get_devtree_pdata(dev);
- if (error) {
- dev_err(dev, "parse device tree fail!!!\n");
- goto err_switch_dev_register;
- }
+ ret = input_register_device(t->input);
+ if (ret)
+ goto free_input;
- //config irq gpio and request irq
- switch_data->irq_key1 = gpio_to_irq(switch_data->key1_gpio);
- if (switch_data->irq_key1 <= 0)
- {
- printk("%s, irq number is not specified, irq #= %d, int pin=%d\n\n", __func__, switch_data->irq_key1, switch_data->key1_gpio);
- goto err_detect_irq_num_failed;
- }
- else
- {
- error = gpio_request(switch_data->key1_gpio,"tristate_key1-int");
- if(error < 0)
- {
- printk(KERN_ERR "%s: gpio_request, err=%d", __func__, error);
- goto err_request_gpio;
- }
- error = gpio_direction_input(switch_data->key1_gpio);
- if(error < 0)
- {
- printk(KERN_ERR "%s: gpio_direction_input, err=%d", __func__, error);
- goto err_set_gpio_input;
- }
-
- error = request_irq(switch_data->irq_key1, switch_dev_interrupt,
- IRQF_TRIGGER_FALLING, "tristate_key1", switch_data);
-
- if (error) {
- dev_err(dev,
- "request_irq %i failed.\n",
- switch_data->irq_key1);
-
- switch_data->irq_key1 = -EINVAL;
- goto err_request_irq;
- }
- }
- //config irq gpio and request irq
- switch_data->irq_key2 = gpio_to_irq(switch_data->key2_gpio);
- if (switch_data->irq_key2 <= 0)
- {
- printk("%s, irq number is not specified, irq #= %d, int pin=%d\n\n", __func__, switch_data->irq_key2, switch_data->key2_gpio);
- goto err_detect_irq_num_failed;
- }
- else
- {
- error = gpio_request(switch_data->key2_gpio,"tristate_key2-int");
- if(error < 0)
- {
- printk(KERN_ERR "%s: gpio_request, err=%d", __func__, error);
- goto err_request_gpio;
- }
- error = gpio_direction_input(switch_data->key2_gpio);
- if(error < 0)
- {
- printk(KERN_ERR "%s: gpio_direction_input, err=%d", __func__, error);
- goto err_set_gpio_input;
- }
-
- error = request_irq(switch_data->irq_key2, switch_dev_interrupt,
- IRQF_TRIGGER_FALLING, "tristate_key2", switch_data);
-
- if (error) {
- dev_err(dev,
- "request_irq %i failed.\n",
- switch_data->irq_key2);
-
- switch_data->irq_key2 = -EINVAL;
- goto err_request_irq;
- }
-
- }
-
- switch_data->irq_key3 = gpio_to_irq(switch_data->key3_gpio);
- if (switch_data->irq_key3 <= 0)
- {
- printk("%s, irq number is not specified, irq #= %d, int pin=%d\n\n", __func__, \
- switch_data->irq_key3, switch_data->key3_gpio);
- goto err_detect_irq_num_failed;
- }
- else
- {
- error = gpio_request(switch_data->key3_gpio,"tristate_key3-int");
- if(error < 0)
- {
- printk(KERN_ERR "%s: gpio_request, err=%d", __func__, error);
- goto err_request_gpio;
- }
- error = gpio_direction_input(switch_data->key3_gpio);
- if(error < 0)
- {
- printk(KERN_ERR "%s: gpio_direction_input, err=%d", __func__, error);
- goto err_set_gpio_input;
- }
-
-
- error = request_irq(switch_data->irq_key3, switch_dev_interrupt,
- IRQF_TRIGGER_FALLING, "tristate_key3", switch_data);
-
- if (error) {
- dev_err(dev,
- "request_irq %i failed.\n",
- switch_data->irq_key3);
-
- switch_data->irq_key3 = -EINVAL;
- goto err_request_irq;
- }
-
- }
-
-
- INIT_WORK(&switch_data->work, switch_dev_work);
-
- init_timer(&switch_data->s_timer);
- switch_data->s_timer.function = &timer_handle;
- switch_data->s_timer.expires = jiffies + 5*HZ;
-
- add_timer(&switch_data->s_timer);
-
- enable_irq_wake(switch_data->irq_key1);
- enable_irq_wake(switch_data->irq_key2);
- enable_irq_wake(switch_data->irq_key3);
-
-
- switch_data->sdev.name = DRV_NAME;
- error = switch_dev_register(&switch_data->sdev);
- if (error < 0)
- goto err_request_gpio;
- //set_gpio_by_pinctrl();
- //report the first switch
- //switch_dev_work(&switch_data->work);
- return 0;
-
-
-err_request_gpio:
- switch_dev_unregister(&switch_data->sdev);
-err_request_irq:
-err_detect_irq_num_failed:
-err_set_gpio_input:
- gpio_free(switch_data->key2_gpio);
- gpio_free(switch_data->key1_gpio);
- gpio_free(switch_data->key3_gpio);
-err_switch_dev_register:
- kfree(switch_data);
-
- return error;
-}
+ /* Initialize with default keycodes */
+ for (i = 0; i < NR_STATES; i++)
+ t->key_codes[i] = KEYCODE_TOTAL_SILENCE + i;
-static int tristate_dev_remove(struct platform_device *pdev)
-{
-printk("%s\n",__func__);
- cancel_work_sync(&switch_data->work);
- gpio_free(switch_data->key1_gpio);
- gpio_free(switch_data->key2_gpio);
- gpio_free(switch_data->key3_gpio);
- switch_dev_unregister(&switch_data->sdev);
- kfree(switch_data);
+ /* Process initial state */
+ tristate_process_state(t);
+
+ mutex_init(&t->irq_lock);
+ ret = tristate_register_irqs(t);
+ if (ret)
+ goto input_unregister;
+ tristate_create_procfs();
return 0;
+
+input_unregister:
+ input_unregister_device(t->input);
+free_input:
+ input_free_device(t->input);
+free_t:
+ kfree(t);
+ return ret;
}
-static struct platform_driver tristate_dev_driver = {
- .probe = tristate_dev_probe,
- .remove = tristate_dev_remove,
+static const struct of_device_id tristate_of_match[] = {
+ { .compatible = "oneplus,tri-state-key", },
+ { },
+};
+
+static struct platform_driver tristate_driver = {
+ .probe = tristate_probe,
.driver = {
- .name = DRV_NAME,
+ .name = DRIVER_NAME,
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(tristate_dev_of_match),
+ .of_match_table = tristate_of_match,
},
};
-module_platform_driver(tristate_dev_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("switch Profiles by this triple key driver");
+static int __init tristate_init(void)
+{
+ return platform_driver_register(&tristate_driver);
+}
+device_initcall(tristate_init);
diff --git a/drivers/input/touchscreen/fw_update_v7.if b/drivers/input/touchscreen/fw_update_v7.if
index 76b3339ed30c..0bb4e1f5f4a7 100644
--- a/drivers/input/touchscreen/fw_update_v7.if
+++ b/drivers/input/touchscreen/fw_update_v7.if
@@ -1204,7 +1204,6 @@ static int fwu_read_f34_v7_queries(void)
fwu->partition_table_bytes = fwu->partitions * 8 + 2;
- kfree(fwu->read_config_buf);
fwu->read_config_buf = kzalloc(fwu->partition_table_bytes, GFP_KERNEL);
if (!fwu->read_config_buf) {
TPD_ERR("%s: Failed to alloc mem for fwu->read_config_buf\n",
@@ -1219,11 +1218,13 @@ static int fwu_read_f34_v7_queries(void)
if (retval < 0) {
TPD_ERR("%s: Failed to read partition table\n",
__func__);
- return retval;
+ goto free;
}
fwu_parse_partition_table(ptable, &fwu->blkcount, &fwu->phyaddr);
+free:
+ kfree(fwu->read_config_buf);
return 0;
}
@@ -1605,7 +1606,6 @@ static int fwu_write_partition_table(void)
block_count = fwu->blkcount.bl_config;
fwu->config_area = BL_CONFIG_AREA;
fwu->config_size = fwu->block_size * block_count;
- kfree(fwu->read_config_buf);
fwu->read_config_buf = kzalloc(fwu->config_size, GFP_KERNEL);
if (!fwu->read_config_buf) {
TPD_ERR("%s: Failed to alloc mem for fwu->read_config_buf\n",__func__);
@@ -1616,11 +1616,11 @@ static int fwu_write_partition_table(void)
retval = fwu_read_f34_blocks(block_count, CMD_READ_CONFIG);
if (retval < 0)
- return retval;
+ goto free;
retval = fwu_write_flash_configuration();
if (retval < 0)
- return retval;
+ goto free;
fwu->config_area = BL_CONFIG_AREA;
fwu->config_data = fwu->read_config_buf;
@@ -1629,8 +1629,9 @@ static int fwu_write_partition_table(void)
retval = fwu_write_configuration();
if (retval < 0)
- return retval;
-
+ goto free;
+free:
+ kfree(fwu->read_config_buf);
return 0;
}
@@ -1788,7 +1789,7 @@ int fwu_start_reflash_check(const unsigned char *fw_image, struct i2c_client *cl
retval = scan_pdt();
if (retval < 0)
- return retval;
+ goto free;
fwu->image = fw_image;
memset(&fwu->blkcount, 0x00, sizeof(fwu->blkcount));
@@ -1796,14 +1797,15 @@ int fwu_start_reflash_check(const unsigned char *fw_image, struct i2c_client *cl
retval = fwu_read_f34_v7_queries();
if (retval < 0) {
TPD_ERR("%s: fwu_read_f34_v7_queries\n",__func__);
- return retval;
+ goto free;
}
TPD_DEBUG("%s: fwu_read_f34_serialization\n",__func__);
retval = fwu_read_f34_serialization();
+free:
kfree(fwu);
return retval;
- }
+}
int fwu_start_reflash(const unsigned char *fw_image, struct i2c_client *client)
{
diff --git a/drivers/input/touchscreen/synaptics_driver_s1302.c b/drivers/input/touchscreen/synaptics_driver_s1302.c
index d4bac27f9762..45404ae997e8 100644
--- a/drivers/input/touchscreen/synaptics_driver_s1302.c
+++ b/drivers/input/touchscreen/synaptics_driver_s1302.c
@@ -71,6 +71,7 @@ enum oem_boot_mode{
/*------------------------------------------------Global Define--------------------------------------------*/
#define TP_TEST_ENABLE 1
+#define TPD_NAME "synaptics"
#define TPD_DEVICE "HWK,synaptics,s1302"
#define LOG_TAG "touchkey,s1302"
@@ -298,6 +299,8 @@ struct synaptics_ts_data {
char fw_name[TP_FW_NAME_MAX_LEN];
char fw_id[12];
char manu_name[12];
+
+ struct work_struct pm_work;
};
static int tc_hw_pwron(struct synaptics_ts_data *ts)
@@ -671,81 +674,8 @@ static bool is_report_key = true;
#define REP_KEY_MENU (key_reverse?(KEY_BACK):(KEY_APPSELECT))
#ifdef SUPPORT_VIRTUAL_KEY //WayneChang, 2015/12/29, add flag to enable virtual key
-bool virtual_key_enable = false;
+bool virtual_key_enable;
EXPORT_SYMBOL(virtual_key_enable);
-struct completion key_cm;
-bool key_appselect_pressed = false;
-bool key_back_pressed = false;
-bool check_key_down= false;
-EXPORT_SYMBOL(key_appselect_pressed);
-EXPORT_SYMBOL(key_back_pressed);
-EXPORT_SYMBOL(key_cm);
-EXPORT_SYMBOL(check_key_down);
-
-extern void int_touch(void);
-
-static void int_virtual_key(struct synaptics_ts_data *ts )
-{
-
- int ret;
- int button_key;
- long time =0 ;
- bool key_up_report = false;
-
- ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x02 );
- if (ret < 0) {
- TPD_ERR("%s: Failed to change page 2!!\n",
- __func__);
- return;
- }
-
- button_key = synaptics_rmi4_i2c_read_byte(ts->client,0x00);
- if (6 == (++log_count % 12))
- printk("%s button_key:%d pre_btn_state:%d\n",__func__,button_key,ts->pre_btn_state);
- if((button_key & 0x01) && !(ts->pre_btn_state & 0x01))//back
- {
- key_appselect_pressed = true;
- }else if(!(button_key & 0x01) && (ts->pre_btn_state & 0x01)){
- key_appselect_pressed = false;
- key_up_report = true;
- }
-
- if((button_key & 0x02) && !(ts->pre_btn_state & 0x02))//menu
- {
- key_back_pressed = true;
- }else if(!(button_key & 0x02) && (ts->pre_btn_state & 0x02)){
- key_back_pressed = false;
- key_up_report = true;
- }
-
- if((button_key & 0x04) && !(ts->pre_btn_state & 0x04))//home
- {
- input_report_key(ts->input_dev, KEY_HOMEPAGE, 1);//KEY_HOMEPAGE
- input_sync(ts->input_dev);
- }else if(!(button_key & 0x04) && (ts->pre_btn_state & 0x04)){
- input_report_key(ts->input_dev, KEY_HOMEPAGE, 0);
- input_sync(ts->input_dev);
- }
- if(key_up_report){
- reinit_completion(&key_cm);
- time = wait_for_completion_timeout(&key_cm,msecs_to_jiffies(touchkey_wait_time));
- if (!time){
- check_key_down = false;
- int_touch();
- }
- }else{
- check_key_down = true;
- int_touch();
- }
- ts->pre_btn_state = button_key & 0x07;
- ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x00);
- if (ret < 0) {
- TPD_ERR("%s: Failed to change page 2!!\n",
- __func__);
- return;
- }
- return;
-}
#endif
static void int_key(struct synaptics_ts_data *ts )
{
@@ -917,11 +847,10 @@ static void synaptics_ts_report(struct synaptics_ts_data *ts )
int_key_cover(ts);
else
int_key(ts);
-#elif (defined SUPPORT_VIRTUAL_KEY)
- if (virtual_key_enable)
- int_virtual_key(ts);
- else
+#else
+ if (!virtual_key_enable) {
int_key(ts);
+ }
#endif
}
END:
@@ -957,7 +886,7 @@ static int synaptics_input_init(struct synaptics_ts_data *ts)
TPD_ERR("synaptics_ts_probe: Failed to allocate input device\n");
return ret;
}
- ts->input_dev->name = TPD_DEVICE;;
+ ts->input_dev->name = TPD_NAME;
ts->input_dev->dev.parent = &ts->client->dev;
set_bit(EV_SYN, ts->input_dev->evbit);
set_bit(EV_KEY, ts->input_dev->evbit);
@@ -1099,7 +1028,7 @@ static ssize_t synaptics_s1302_key_reverse_write(struct file *file, const char _
}
static int synaptics_s1302_key_reverse_show(struct seq_file *seq, void *offset)
{
- seq_printf(seq, "s1302 menu key in %s\n",key_reverse?("right"):("left"));
+ seq_printf(seq, "%d\n", key_reverse ? 1 : 0);
return 0 ;
}
static int synaptics_s1302_key_reverse_open(struct inode *inode, struct file *file)
@@ -1544,7 +1473,7 @@ static ssize_t synaptics_s1302_virtual_key_enable_write(struct file *file, const
}
static int synaptics_s1302_virtual_key_enable_show(struct seq_file *seq, void *offset)
{
- seq_printf(seq, "s1302 virtual key %s\n",virtual_key_enable?("enabled"):("disabled"));
+ seq_printf(seq, "%d\n", virtual_key_enable ? 1 : 0);
return 0 ;
}
static int synaptics_s1302_virtual_key_enable_open(struct inode *inode, struct file *file)
@@ -1934,6 +1863,18 @@ static void synaptics_hard_reset(struct synaptics_ts_data *ts)
}
}
+
+static void synaptics_suspend_resume(struct work_struct *work)
+{
+ struct synaptics_ts_data *ts =
+ container_of(work, typeof(*ts), pm_work);
+
+ if (ts->suspended)
+ synaptics_ts_suspend(&ts->client->dev);
+ else
+ synaptics_ts_resume(&ts->client->dev);
+}
+
static int synaptics_parse_dts(struct device *dev, struct synaptics_ts_data *ts)
{
int rc;
@@ -2094,9 +2035,6 @@ static int synaptics_ts_probe(struct i2c_client *client, const struct i2c_device
ts->dev = &client->dev;
ts->loading_fw = false;
tc_g = ts;
-#if (defined SUPPORT_VIRTUAL_KEY)
- init_completion(&key_cm);
-#endif
ret = synaptics_dsx_pinctrl_init(ts);
if (!ret && ts->pinctrl) {
ret = pinctrl_select_state(ts->pinctrl,
@@ -2134,7 +2072,7 @@ static int synaptics_ts_probe(struct i2c_client *client, const struct i2c_device
TPD_ERR("CURRENT_FIRMWARE_ID = 0x%x\n", CURRENT_FIRMWARE_ID);
sprintf(ts->fw_id,"0x%x",CURRENT_FIRMWARE_ID);
- memset(ts->fw_name,TP_FW_NAME_MAX_LEN,0);
+ memset(ts->fw_name,0,TP_FW_NAME_MAX_LEN);
strcpy(ts->fw_name,"tp/fw_synaptics_touchkey.img");
TPD_DEBUG("synatpitcs_fw: fw_name = %s \n",ts->fw_name);
@@ -2157,6 +2095,9 @@ static int synaptics_ts_probe(struct i2c_client *client, const struct i2c_device
ret = synaptics_enable_interrupt(ts, 1);
if(ret < 0)
TPD_ERR("%s enable interrupt error ret=%d\n",__func__,ret);
+
+ INIT_WORK(&ts->pm_work, synaptics_suspend_resume);
+
#if defined(CONFIG_FB)
ts->suspended = 0;
ts->fb_notif.notifier_call = fb_notifier_callback;
@@ -2311,30 +2252,30 @@ ERR_RESUME:
#if defined(CONFIG_FB)
static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data)
{
+ struct synaptics_ts_data *ts =
+ container_of(self, struct synaptics_ts_data, fb_notif);
struct fb_event *evdata = data;
- int *blank;
+ int *blank = evdata->data;
- struct synaptics_ts_data *ts = container_of(self, struct synaptics_ts_data, fb_notif);
+ if (event != FB_EVENT_BLANK)
+ return NOTIFY_OK;
- if(FB_EVENT_BLANK != event)
- return 0;
- if((evdata) && (evdata->data) && (ts) && (ts->client)&&(event == FB_EVENT_BLANK)) {
- blank = evdata->data;
- if( *blank == FB_BLANK_UNBLANK || *blank == FB_BLANK_NORMAL) {
- TPD_DEBUG("%s going TP resume\n", __func__);
- if(ts->suspended == 1){
- ts->suspended = 0;
- synaptics_ts_resume(&ts->client->dev);
- }
- } else if( *blank == FB_BLANK_POWERDOWN) {
- TPD_DEBUG("%s : going TP suspend\n", __func__);
- if(ts->suspended == 0) {
- ts->suspended = 1;
- synaptics_ts_suspend(&ts->client->dev);
- }
+ switch (*blank) {
+ case FB_BLANK_UNBLANK:
+ case FB_BLANK_NORMAL:
+ if (ts->suspended) {
+ ts->suspended = 0;
+ queue_work(system_highpri_wq, &ts->pm_work);
+ }
+ break;
+ case FB_BLANK_POWERDOWN:
+ if (!ts->suspended) {
+ ts->suspended = 1;
+ queue_work(system_highpri_wq, &ts->pm_work);
}
}
- return 0;
+
+ return NOTIFY_OK;
}
#endif
diff --git a/drivers/input/touchscreen/synaptics_driver_s3320.c b/drivers/input/touchscreen/synaptics_driver_s3320.c
index b3a434440111..4b07aa6f5d39 100644
--- a/drivers/input/touchscreen/synaptics_driver_s3320.c
+++ b/drivers/input/touchscreen/synaptics_driver_s3320.c
@@ -73,6 +73,7 @@
#define PAGESIZE 512
#define TPD_USE_EINT
+#define TPD_NAME "synaptics"
#define TPD_DEVICE "synaptics,s3320"
//#define SUPPORT_SLEEP_POWEROFF
@@ -80,7 +81,6 @@
#define RESET_ONESECOND
//#define SUPPORT_GLOVES_MODE
//#define REPORT_2D_PRESSURE
-#define SUPPORT_VIRTUAL_KEY
#define SUPPORT_TP_SLEEP_MODE
@@ -137,12 +137,17 @@ struct test_header {
#define KEY_GESTURE_W 246 //w
#define KEY_GESTURE_M 247 //m
#define KEY_GESTURE_S 248 //s
-#define KEY_DOUBLE_TAP 249 // double tap to wake
-#define KEY_GESTURE_CIRCLE 250 // draw circle to lunch camera
-#define KEY_GESTURE_TWO_SWIPE 251 // swipe two finger vertically to play/pause
-#define KEY_GESTURE_V 252 // draw v to toggle flashlight
-#define KEY_GESTURE_LEFT_V 253 // draw left arrow for previous track
-#define KEY_GESTURE_RIGHT_V 254 // draw right arrow for next track
+#define KEY_DOUBLE_TAP KEY_WAKEUP // double tap to wake
+#define KEY_GESTURE_CIRCLE 250 // draw circle
+#define KEY_GESTURE_TWO_SWIPE 251 // swipe two finger vertically
+#define KEY_GESTURE_DOWN_ARROW 252 // draw v
+#define KEY_GESTURE_LEFT_V 253 // draw left arrow
+#define KEY_GESTURE_RIGHT_V 254 // draw right arrow
+#define KEY_GESTURE_UP_ARROW 255 // draw ^
+#define KEY_GESTURE_SWIPE_RIGHT KEY_F5
+#define KEY_GESTURE_SWIPE_LEFT KEY_F6
+#define KEY_GESTURE_SWIPE_DOWN KEY_F7
+#define KEY_GESTURE_SWIPE_UP KEY_F8
#define BIT0 (0x1 << 0)
#define BIT1 (0x1 << 1)
@@ -153,22 +158,22 @@ struct test_header {
#define BIT6 (0x1 << 6)
#define BIT7 (0x1 << 7)
-int LeftVee_gesture = 0; //">"
-int RightVee_gesture = 0; //"<"
-int DouSwip_gesture = 0; // "||"
-int Circle_gesture = 0; // "O"
-int UpVee_gesture = 0; //"V"
-int DownVee_gesture = 0; //"^"
-int DouTap_gesture = 0; //"double tap"
-
-int Left2RightSwip_gesture=0;//"(-->)"
-int Right2LeftSwip_gesture=0;//"(<--)"
-int Up2DownSwip_gesture =0;//"up to down |"
-int Down2UpSwip_gesture =0;//"down to up |"
-
-int Wgestrue_gesture =0;//"(W)"
-int Mgestrue_gesture =0;//"(M)"
-int Sgestrue_gesture =0;//"(S)"
+int left_arrow_enable = 0; //">"
+int right_arrow_enable = 0; //"<"
+int double_swipe_enable = 0; // "||"
+int letter_o_enable = 0; // "O"
+int down_arrow_enable = 0; //"V"
+int up_arrow_enable = 0; //"^"
+int double_tap_enable = 0; //"double tap"
+
+int right_swipe_enable=0;//"(-->)"
+int left_swipe_enable=0;//"(<--)"
+int down_swipe_enable =0;//"up to down |"
+int up_swipe_enable =0;//"down to up |"
+
+int letter_w_enable =0;//"(W)"
+int letter_m_enable =0;//"(M)"
+int letter_s_enable =0;//"(S)"
static int gesture_switch = 0;
#endif
@@ -186,7 +191,7 @@ static int gesture_switch = 0;
static int baseline_ret = 0;
static int TP_FW;
static int tp_dev = 6;
-static unsigned int tp_debug = 1;
+static unsigned int tp_debug = 0;
static int button_map[3];
static int tx_rx_num[2];
static int16_t Rxdata[30][30];
@@ -216,7 +221,6 @@ static int sleep_enable;
static struct synaptics_ts_data *ts_g = NULL;
static struct workqueue_struct *synaptics_wq = NULL;
-static struct workqueue_struct *synaptics_report = NULL;
static struct workqueue_struct *get_base_report = NULL;
static struct proc_dir_entry *prEntry_tp = NULL;
@@ -456,7 +460,7 @@ struct synaptics_ts_data {
uint32_t pre_finger_state;
uint32_t pre_btn_state;
struct delayed_work base_work;
- struct work_struct report_work;
+ struct work_struct base_work_intr;
struct delayed_work speed_up_work;
struct input_dev *input_dev;
struct hrtimer timer;
@@ -492,9 +496,8 @@ struct synaptics_ts_data {
char test_limit_name[TP_FW_NAME_MAX_LEN];
char fw_id[12];
char manu_name[10];
-#ifdef SUPPORT_VIRTUAL_KEY
- struct kobject *properties_kobj;
-#endif
+
+ ktime_t timestamp;
};
static struct device_attribute attrs_oem[] = {
@@ -1200,10 +1203,10 @@ static void gesture_judge(struct synaptics_ts_data *ts)
keyCode = KEY_DOUBLE_TAP;
break;
case UpVee:
- keyCode = KEY_GESTURE_V;
+ keyCode = KEY_GESTURE_DOWN_ARROW;
break;
case DownVee:
- keyCode = KEY_GESTURE_V;
+ keyCode = KEY_GESTURE_UP_ARROW;
break;
case LeftVee:
keyCode = KEY_GESTURE_RIGHT_V;
@@ -1226,11 +1229,24 @@ static void gesture_judge(struct synaptics_ts_data *ts)
case Sgestrue:
keyCode = KEY_GESTURE_S;
break;
+ case Left2RightSwip:
+ keyCode = KEY_GESTURE_SWIPE_RIGHT;
+ break;
+ case Right2LeftSwip:
+ keyCode = KEY_GESTURE_SWIPE_LEFT;
+ break;
+ case Up2DownSwip:
+ keyCode = KEY_GESTURE_SWIPE_DOWN;
+ break;
+ case Down2UpSwip:
+ keyCode = KEY_GESTURE_SWIPE_UP;
+ break;
default:
break;
}
- TPD_ERR("detect %s gesture\n", gesture == DouTap ? "(double tap)" :
+ TPD_ERR("detect %s gesture\n",
+ gesture == DouTap ? "(double tap)" :
gesture == UpVee ? "(V)" :
gesture == DownVee ? "(^)" :
gesture == LeftVee ? "(>)" :
@@ -1246,12 +1262,16 @@ static void gesture_judge(struct synaptics_ts_data *ts)
gesture == Wgestrue ? "(W)" : "[unknown]");
synaptics_get_coordinate_point(ts);
- TPD_DEBUG("gesture suport LeftVee:%d RightVee:%d DouSwip:%d Circle:%d UpVee:%d DouTap:%d\n",\
- LeftVee_gesture,RightVee_gesture,DouSwip_gesture,Circle_gesture,UpVee_gesture,DouTap_gesture);
- if((gesture == DouTap && DouTap_gesture)||(gesture == RightVee && RightVee_gesture)\
- ||(gesture == LeftVee && LeftVee_gesture)||(gesture == UpVee && UpVee_gesture)\
- ||(gesture == Circle && Circle_gesture)||(gesture == DouSwip && DouSwip_gesture)\
- ||gesture == Sgestrue || gesture == Wgestrue || gesture == Mgestrue){
+ TPD_DEBUG("gesture suport LeftVee:%d RightVee:%d DouSwip:%d Circle:%d UpVee:%d DownVee:%d DouTap:%d \
+Left2RightSwip:%d Right2LeftSwip:%d Up2DownSwip:%d Down2UpSwip:%d\n",
+ left_arrow_enable,right_arrow_enable,double_swipe_enable,letter_o_enable,down_arrow_enable,up_arrow_enable,double_tap_enable,
+ right_swipe_enable,left_swipe_enable,down_swipe_enable,up_swipe_enable);
+ if ((gesture == DouTap && double_tap_enable) || (gesture == RightVee && right_arrow_enable)
+ || (gesture == LeftVee && left_arrow_enable) || (gesture == UpVee && down_arrow_enable)
+ || (gesture == DownVee && up_arrow_enable) || (gesture == Circle && letter_o_enable)
+ || (gesture == DouSwip && double_swipe_enable) || (gesture == Left2RightSwip && right_swipe_enable)
+ || (gesture == Right2LeftSwip && left_swipe_enable) || (gesture == Up2DownSwip && down_swipe_enable)
+ || (gesture == Down2UpSwip && up_swipe_enable)) {
gesture_upload = gesture;
input_report_key(ts->input_dev, keyCode, 1);
input_sync(ts->input_dev);
@@ -1277,14 +1297,7 @@ static char prlog_count = 0;
#ifdef REPORT_2D_PRESSURE
static unsigned char pres_value = 1;
#endif
-#ifdef SUPPORT_VIRTUAL_KEY //WayneChang, 2015/12/02, add for key to abs, simulate key in abs through virtual key system
-extern struct completion key_cm;
-extern bool key_back_pressed;
-extern bool key_appselect_pressed;
-extern bool key_home_pressed;
-extern bool virtual_key_enable;
-#endif
-void int_touch(void)
+uint8_t int_touch(void)
{
int ret = -1,i = 0;
uint8_t buf[90];
@@ -1297,12 +1310,6 @@ void int_touch(void)
uint32_t finger_info = 0;
static uint8_t current_status = 0;
uint8_t last_status = 0 ;
-#ifdef SUPPORT_VIRTUAL_KEY //WayneChang, 2015/12/02, add for key to abs, simulate key in abs through virtual key system
- bool key_appselect_check = false;
- bool key_back_check = false;
- bool key_home_check = false;
- bool key_pressed = key_appselect_pressed || key_back_pressed;// || key_home_pressed;
-#endif
struct synaptics_ts_data *ts = ts_g;
memset(buf, 0, sizeof(buf));
@@ -1362,6 +1369,12 @@ void int_touch(void)
TPD_ERR("synaptics_int_touch F12_2D_DATA_BASE: i2c_transfer failed\n");
goto INT_TOUCH_END;
}
+
+ input_event(ts->input_dev, EV_SYN, SYN_TIME_SEC,
+ ktime_to_timespec(ts->timestamp).tv_sec);
+ input_event(ts->input_dev, EV_SYN, SYN_TIME_NSEC,
+ ktime_to_timespec(ts->timestamp).tv_nsec);
+
for( i = 0; i < count_data; i++ ) {
points.status = buf[i*8];
points.x = ((buf[i*8+2]&0x0f)<<8) | (buf[i*8+1] & 0xff);
@@ -1371,52 +1384,6 @@ void int_touch(void)
points.z = buf[i*8+5];
finger_info <<= 1;
finger_status = points.status & 0x03;
-#ifdef SUPPORT_VIRTUAL_KEY //WayneChang, 2015/12/02, add for key to abs, simulate key in abs through virtual key system
- if(virtual_key_enable){
- if(points.y > 0x780 && key_pressed){
- TPD_DEBUG("Drop TP event due to key pressed\n");
- finger_status = 0;
- }else{
- finger_status = points.status & 0x03;
- }
- }else{
- finger_status = points.status & 0x03;
- }
- if(virtual_key_enable){
- if (!finger_status){
- if (key_appselect_pressed && !key_appselect_check){
- points.x = 0xb4;
- points.y = 0x7e2;
- points.z = 0x33;
- points.raw_x = 4;
- points.raw_y = 6;
- key_appselect_check = true;
- points.status = 1;
- finger_status = points.status & 0x03;
- }else if (key_back_pressed && !key_back_check){
- points.x = 0x384;
- points.y = 0x7e2;
- points.z = 0x33;
- points.raw_x = 4;
- points.raw_y = 6;
- key_back_check = true;
- points.status = 1;
- finger_status = points.status & 0x03;
- }else if(key_home_pressed && !key_home_check){
- points.x = 0x21c;
- points.y = 0x7e2;
- points.z = 0x33;
- points.raw_x = 4;
- points.raw_y = 6;
- key_home_check = true;
- points.status = 1;
- finger_status = points.status & 0x03;
- }else{
- //TPD_DEBUG(" finger %d with !finger_statue and no key match\n",i);
- }
- }
- }
-#endif
if (finger_status) {
input_mt_slot(ts->input_dev, i);
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, finger_status);
@@ -1435,11 +1402,6 @@ void int_touch(void)
#endif
#ifndef TYPE_B_PROTOCOL
input_mt_sync(ts->input_dev);
-#endif
-#ifdef SUPPORT_VIRTUAL_KEY //WayneChang, 2015/12/02, add for key to abs, simulate key in abs through virtual key system
- if(virtual_key_enable){
- complete(&key_cm);
- }
#endif
finger_num++;
finger_info |= 1 ;
@@ -1475,12 +1437,6 @@ void int_touch(void)
}
input_sync(ts->input_dev);
- if ((finger_num == 0) && (get_tp_base == 0)){//all finger up do get base once
- get_tp_base = 1;
- TPD_ERR("start get base data:%d\n",get_tp_base);
- tp_baseline_get(ts, false);
- }
-
#ifdef SUPPORT_GESTURE
if (ts->in_gesture_mode == 1 && ts->is_suspended == 1) {
gesture_judge(ts);
@@ -1488,6 +1444,7 @@ void int_touch(void)
#endif
INT_TOUCH_END:
mutex_unlock(&ts->mutexreport);
+ return finger_num;
}
static int synaptics_rmi4_free_fingers(struct synaptics_ts_data *ts)
@@ -1511,7 +1468,7 @@ static int synaptics_rmi4_free_fingers(struct synaptics_ts_data *ts)
return 0;
}
-static void synaptics_ts_work_func(struct work_struct *work)
+static void synaptics_ts_work_func(void)
{
int ret,status_check;
uint8_t status = 0;
@@ -1564,10 +1521,17 @@ static void synaptics_ts_work_func(struct work_struct *work)
}
}
- if( inte & 0x04 ) {
+ if (inte & 0x04) {
+ uint8_t finger_num = int_touch();
- int_touch();
+ /* All fingers up; do get base once */
+ if (!get_tp_base && !finger_num) {
+ get_tp_base = 1;
+ TPD_ERR("start get base data: 1\n");
+ schedule_work(&ts->base_work_intr);
+ }
}
+
END:
//ret = set_changer_bit(ts);
touch_enable(ts);
@@ -1588,8 +1552,9 @@ static enum hrtimer_restart synaptics_ts_timer_func(struct hrtimer *timer)
static irqreturn_t synaptics_irq_thread_fn(int irq, void *dev_id)
{
struct synaptics_ts_data *ts = (struct synaptics_ts_data *)dev_id;
- touch_disable(ts);
- synaptics_ts_work_func(&ts->report_work);
+ ts->timestamp = ktime_get();
+ touch_disable(ts);
+ synaptics_ts_work_func();
return IRQ_HANDLED;
}
#endif
@@ -1619,7 +1584,7 @@ static ssize_t i2c_device_test_read_func(struct file *file, char __user *user_bu
if(!ts_g)
return ret;
TPD_DEBUG("gesture enable is: %d\n", ts->gesture_enable);
- ret = sprintf(page, "%d\n", ts->i2c_device_test);
+ ret = snprintf(page, sizeof(page), "%d\n", ts->i2c_device_test);
ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page));
return ret;
}
@@ -1633,7 +1598,7 @@ static ssize_t tp_gesture_read_func(struct file *file, char __user *user_buf, si
if(!ts)
return ret;
TPD_DEBUG("gesture enable is: %d\n", ts->gesture_enable);
- ret = sprintf(page, "%d\n", ts->gesture_enable);
+ ret = snprintf(page, sizeof(page), "%d\n", ts->gesture_enable);
ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page));
return ret;
}
@@ -1652,19 +1617,20 @@ static ssize_t tp_gesture_write_func(struct file *file, const char __user *buffe
}
TPD_ERR("%s write [0x%x]\n",__func__,buf[0]);
- UpVee_gesture = (buf[0] & BIT0)?1:0; //"V"
- DouSwip_gesture = (buf[0] & BIT1)?1:0;//"||"
- LeftVee_gesture = (buf[0] & BIT3)?1:0; //">"
- RightVee_gesture = (buf[0] & BIT4)?1:0;//"<"
- Circle_gesture = (buf[0] & BIT6)?1:0; //"O"
- DouTap_gesture = (buf[0] & BIT7)?1:0; //double tap
+ down_arrow_enable = (buf[0] & BIT0)?1:0; //"V"
+ double_swipe_enable = (buf[0] & BIT1)?1:0;//"||"
+ up_arrow_enable = (buf[0] & BIT2)?1:0; //"^"
+ left_arrow_enable = (buf[0] & BIT3)?1:0; //">"
+ right_arrow_enable = (buf[0] & BIT4)?1:0;//"<"
+ letter_o_enable = (buf[0] & BIT6)?1:0; //"O"
+ double_tap_enable = (buf[0] & BIT7)?1:0; //double tap
- Sgestrue_gesture = (buf[1] & BIT0)?1:0;//"S"
- Mgestrue_gesture = (buf[1] & BIT1)?1:0; //"M"
- Wgestrue_gesture = (buf[1] & BIT2)?1:0; //"W"
+ letter_s_enable = (buf[1] & BIT0)?1:0;//"S"
+ letter_m_enable = (buf[1] & BIT1)?1:0; //"M"
+ letter_w_enable = (buf[1] & BIT2)?1:0; //"W"
- if(DouTap_gesture||Circle_gesture||UpVee_gesture||LeftVee_gesture\
- ||RightVee_gesture||DouSwip_gesture||Sgestrue_gesture||Mgestrue_gesture||Wgestrue_gesture)
+ if(double_tap_enable||letter_o_enable||down_arrow_enable||up_arrow_enable||left_arrow_enable\
+ ||right_arrow_enable||double_swipe_enable)
{
ts->gesture_enable = 1;
}
@@ -1679,7 +1645,7 @@ static ssize_t coordinate_proc_read_func(struct file *file, char __user *user_bu
int ret = 0;
char page[PAGESIZE];
TPD_ERR("%s:gesture_upload = %d \n",__func__,gesture_upload);
- ret = sprintf(page, "%d,%d:%d,%d:%d,%d:%d,%d:%d,%d:%d,%d:%d,%d\n", gesture_upload,
+ ret = snprintf(page, sizeof(page), "%d,%d:%d,%d:%d,%d:%d,%d:%d,%d:%d,%d:%d,%d\n", gesture_upload,
Point_start.x, Point_start.y, Point_end.x, Point_end.y,
Point_1st.x, Point_1st.y, Point_2nd.x, Point_2nd.y,
Point_3rd.x, Point_3rd.y, Point_4th.x, Point_4th.y,
@@ -1696,7 +1662,7 @@ static ssize_t gesture_switch_read_func(struct file *file, char __user *user_buf
struct synaptics_ts_data *ts = ts_g;
if(!ts)
return ret;
- ret = sprintf(page, "gesture_switch:%d\n", gesture_switch);
+ ret = snprintf(page, sizeof(page), "gesture_switch:%d\n", gesture_switch);
ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page));
return ret;
}
@@ -1739,6 +1705,13 @@ static ssize_t gesture_switch_write_func(struct file *file, const char __user *p
return count;
}
+static void gesture_enable(struct synaptics_ts_data *ts)
+{
+ ts->gesture_enable = double_tap_enable || letter_o_enable || down_arrow_enable || up_arrow_enable ||
+ left_arrow_enable || right_arrow_enable || double_swipe_enable || right_swipe_enable ||
+ left_swipe_enable || down_swipe_enable || up_swipe_enable ? 1 : 0;
+}
+
// chenggang.li@BSP.TP modified for oem 2014-08-08 create node
/******************************start****************************/
static const struct file_operations tp_gesture_proc_fops = {
@@ -1760,6 +1733,44 @@ static const struct file_operations coordinate_proc_fops = {
.open = simple_open,
.owner = THIS_MODULE,
};
+
+#define TS_ENABLE_FOPS(type) \
+static ssize_t type##_read_func(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) \
+{ \
+ char enable[3]; \
+ sprintf(enable, "%d\n", !!type##_enable); \
+ return simple_read_from_buffer(user_buf, sizeof(enable), ppos, enable - *ppos, sizeof(enable)); \
+} \
+static ssize_t type##_write_func(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) \
+{ \
+ int ret; \
+ char enable; \
+ struct synaptics_ts_data *ts = ts_g; \
+ ret = copy_from_user(&enable, user_buf, sizeof(enable)); \
+ if (ret) \
+ return ret; \
+ type##_enable = enable - '0'; \
+ gesture_enable(ts); \
+ return count; \
+} \
+static const struct file_operations type##_proc_fops = { \
+ .write = type##_write_func, \
+ .read = type##_read_func, \
+ .open = simple_open, \
+ .owner = THIS_MODULE, \
+};
+
+TS_ENABLE_FOPS(double_swipe);
+TS_ENABLE_FOPS(double_tap);
+TS_ENABLE_FOPS(down_arrow);
+TS_ENABLE_FOPS(down_swipe);
+TS_ENABLE_FOPS(left_arrow);
+TS_ENABLE_FOPS(left_swipe);
+TS_ENABLE_FOPS(letter_o);
+TS_ENABLE_FOPS(right_arrow);
+TS_ENABLE_FOPS(right_swipe);
+TS_ENABLE_FOPS(up_arrow);
+TS_ENABLE_FOPS(up_swipe);
#endif
static int page ,address,block;
static ssize_t synap_read_address(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
@@ -1832,7 +1843,7 @@ static ssize_t tp_glove_read_func(struct file *file, char __user *user_buf, size
if(!ts)
return ret;
TPD_DEBUG("glove mode enable is: %d\n", ts->glove_enable);
- ret = sprintf(page, "%d\n", ts->glove_enable);
+ ret = snprintf(page, sizeof(page), "%d\n", ts->glove_enable);
ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page));
return ret;
}
@@ -1879,7 +1890,7 @@ static ssize_t tp_sleep_read_func(struct file *file, char __user *user_buf, size
int ret = 0;
char page[PAGESIZE];
TPD_DEBUG("sleep mode enable is: %d\n", sleep_enable);
- ret = sprintf(page, "%d\n", sleep_enable);
+ ret = snprintf(page, sizeof(page), "%d\n", sleep_enable);
ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page));
return ret;
}
@@ -1953,7 +1964,7 @@ static ssize_t vendor_id_read_func(struct file *file, char __user *user_buf, siz
{
int ret = 0;
char page[4];
- ret = sprintf(page, "%d\n",7);
+ ret = snprintf(page, sizeof(page), "%d\n",7);
ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page));
return ret;
}
@@ -2486,7 +2497,7 @@ static int synaptics_input_init(struct synaptics_ts_data *ts)
TPD_ERR("synaptics_ts_probe: Failed to allocate input device\n");
return ret;
}
- ts->input_dev->name = TPD_DEVICE;;
+ ts->input_dev->name = TPD_NAME;
ts->input_dev->dev.parent = &ts->client->dev;
set_bit(EV_SYN, ts->input_dev->evbit);
set_bit(EV_ABS, ts->input_dev->evbit);
@@ -2501,10 +2512,15 @@ static int synaptics_input_init(struct synaptics_ts_data *ts)
set_bit(KEY_F4 , ts->input_dev->keybit);//doulbe-tap resume
set_bit(KEY_DOUBLE_TAP, ts->input_dev->keybit);
set_bit(KEY_GESTURE_CIRCLE, ts->input_dev->keybit);
- set_bit(KEY_GESTURE_V, ts->input_dev->keybit);
+ set_bit(KEY_GESTURE_UP_ARROW, ts->input_dev->keybit);
+ set_bit(KEY_GESTURE_DOWN_ARROW, ts->input_dev->keybit);
set_bit(KEY_GESTURE_TWO_SWIPE, ts->input_dev->keybit);
set_bit(KEY_GESTURE_LEFT_V, ts->input_dev->keybit);
set_bit(KEY_GESTURE_RIGHT_V, ts->input_dev->keybit);
+ set_bit(KEY_GESTURE_SWIPE_RIGHT, ts->input_dev->keybit);
+ set_bit(KEY_GESTURE_SWIPE_LEFT, ts->input_dev->keybit);
+ set_bit(KEY_GESTURE_SWIPE_DOWN, ts->input_dev->keybit);
+ set_bit(KEY_GESTURE_SWIPE_UP, ts->input_dev->keybit);
#endif
/* For multi touch */
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
@@ -2909,7 +2925,7 @@ static ssize_t changer_read_func(struct file *file, char __user *user_buf, size_
struct synaptics_ts_data *ts = ts_g;
if(!ts)
return ret;
- ret = sprintf(page, "the changer is %s!\n", ts->changer_connet?("conneted"):("disconneted"));
+ ret = snprintf(page, sizeof(page), "the changer is %s!\n", ts->changer_connet?("conneted"):("disconneted"));
ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page));
return ret;
}
@@ -2999,6 +3015,13 @@ static void tp_baseline_get_work(struct work_struct *work)
tp_baseline_get(ts, true);//get the delta data
}
+static void tp_baseline_get_in_intr(struct work_struct *work)
+{
+ struct synaptics_ts_data *ts = ts_g;
+
+ tp_baseline_get(ts, false);
+}
+
static ssize_t touch_press_status_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
{
int ret = 0;
@@ -3070,7 +3093,7 @@ static ssize_t limit_enable_read(struct file *file, char __user *user_buf, size_
char page[PAGESIZE];
TPD_DEBUG("the limit_enable is: %d\n", limit_enable);
- ret = sprintf(page, "%d\n", limit_enable);
+ ret = snprintf(page, sizeof(page), "%d\n", limit_enable);
ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page));
return ret;
}
@@ -3161,6 +3184,72 @@ static int init_synaptics_proc(void)
ret = -ENOMEM;
TPD_ERR("Couldn't create coordinate\n");
}
+
+ prEntry_tmp = proc_create("double_tap_enable", 0666, prEntry_tp, &double_tap_proc_fops);
+ if(prEntry_tmp == NULL){
+ ret = -ENOMEM;
+ TPD_ERR("Couldn't create double_tap_enable\n");
+ }
+
+ prEntry_tmp = proc_create("double_swipe_enable", 0666, prEntry_tp, &double_swipe_proc_fops);
+ if(prEntry_tmp == NULL){
+ ret = -ENOMEM;
+ TPD_ERR("Couldn't create double_swipe_enable\n");
+ }
+
+ prEntry_tmp = proc_create("letter_o_enable", 0666, prEntry_tp, &letter_o_proc_fops);
+ if(prEntry_tmp == NULL){
+ ret = -ENOMEM;
+ TPD_ERR("Couldn't create letter_o_enable\n");
+ }
+
+ prEntry_tmp = proc_create("left_arrow_enable", 0666, prEntry_tp, &left_arrow_proc_fops);
+ if(prEntry_tmp == NULL){
+ ret = -ENOMEM;
+ TPD_ERR("Couldn't create left_arrow_enable\n");
+ }
+
+ prEntry_tmp = proc_create("right_arrow_enable", 0666, prEntry_tp, &right_arrow_proc_fops);
+ if(prEntry_tmp == NULL){
+ ret = -ENOMEM;
+ TPD_ERR("Couldn't create right_arrow_enable\n");
+ }
+
+ prEntry_tmp = proc_create("up_arrow_enable", 0666, prEntry_tp, &up_arrow_proc_fops);
+ if(prEntry_tmp == NULL){
+ ret = -ENOMEM;
+ TPD_ERR("Couldn't create up_arrow_enable\n");
+ }
+
+ prEntry_tmp = proc_create("down_arrow_enable", 0666, prEntry_tp, &down_arrow_proc_fops);
+ if(prEntry_tmp == NULL){
+ ret = -ENOMEM;
+ TPD_ERR("Couldn't create down_arrow_enable\n");
+ }
+
+ prEntry_tmp = proc_create("left_swipe_enable", 0666, prEntry_tp, &left_swipe_proc_fops);
+ if(prEntry_tmp == NULL){
+ ret = -ENOMEM;
+ TPD_ERR("Couldn't create left_swipe\n");
+ }
+
+ prEntry_tmp = proc_create("right_swipe_enable", 0666, prEntry_tp, &right_swipe_proc_fops);
+ if(prEntry_tmp == NULL){
+ ret = -ENOMEM;
+ TPD_ERR("Couldn't create right_swipe_enable\n");
+ }
+
+ prEntry_tmp = proc_create("up_swipe_enable", 0666, prEntry_tp, &up_swipe_proc_fops);
+ if(prEntry_tmp == NULL){
+ ret = -ENOMEM;
+ TPD_ERR("Couldn't create up_swipe_enable\n");
+ }
+
+ prEntry_tmp = proc_create("down_swipe_enable", 0666, prEntry_tp, &down_swipe_proc_fops);
+ if(prEntry_tmp == NULL){
+ ret = -ENOMEM;
+ TPD_ERR("Couldn't create down_swipe_enable\n");
+ }
#endif
#ifdef SUPPORT_GLOVES_MODE
@@ -3905,61 +3994,6 @@ err_pinctrl_get:
return retval;
}
-#ifdef SUPPORT_VIRTUAL_KEY
-#define VK_KEY_X 180
-#define VK_CENTER_Y 2020//2260
-#define VK_WIDTH 170
-#define VK_HIGHT 200
-static ssize_t vk_syna_show(struct kobject *kobj,
- struct kobj_attribute *attr, char *buf)
-{
- int len ;
-
- len = sprintf(buf,
- __stringify(EV_KEY) ":" __stringify(KEY_APPSELECT) ":%d:%d:%d:%d"
- ":" __stringify(EV_KEY) ":" __stringify(KEY_HOMEPAGE) ":%d:%d:%d:%d"
- ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":%d:%d:%d:%d" "\n",
- VK_KEY_X, VK_CENTER_Y, VK_WIDTH, VK_HIGHT,
- VK_KEY_X*3, VK_CENTER_Y, VK_WIDTH, VK_HIGHT,
- VK_KEY_X*5, VK_CENTER_Y, VK_WIDTH, VK_HIGHT);
-
- return len ;
-}
-
-static struct kobj_attribute vk_syna_attr = {
- .attr = {
- .name = "virtualkeys."TPD_DEVICE,
- .mode = S_IRUGO,
- },
- .show = &vk_syna_show,
-};
-
-static struct attribute *syna_properties_attrs[] = {
- &vk_syna_attr.attr,
- NULL
-};
-
-static struct attribute_group syna_properties_attr_group = {
- .attrs = syna_properties_attrs,
-};
-static int synaptics_ts_init_virtual_key(struct synaptics_ts_data *ts )
-{
- int ret = 0;
-
- /* virtual keys */
- if(ts->properties_kobj)
- return 0 ;
- ts->properties_kobj = kobject_create_and_add("board_properties", NULL);
- if (ts->properties_kobj)
- ret = sysfs_create_group(ts->properties_kobj, &syna_properties_attr_group);
-
- if (!ts->properties_kobj || ret)
- printk("%s: failed to create board_properties\n", __func__);
- /* virtual keys */
- return ret;
-}
-#endif
-
static int synaptics_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
#ifdef CONFIG_SYNAPTIC_RED
@@ -4017,9 +4051,6 @@ static int synaptics_ts_probe(struct i2c_client *client, const struct i2c_device
if( ret < 0 ) {
ret = synaptics_rmi4_i2c_read_byte(client, 0x13);
if( ret < 0 ) {
- #ifdef SUPPORT_VIRTUAL_KEY
- virtual_key_enable = 0;//if touch is no valid report key
- #endif
TPD_ERR("tp is no exist!\n");
goto err_check_functionality_failed;
}
@@ -4039,8 +4070,8 @@ static int synaptics_ts_probe(struct i2c_client *client, const struct i2c_device
TP_FW = CURRENT_FIRMWARE_ID;
sprintf(ts->fw_id,"0x%x",TP_FW);
- memset(ts->fw_name,TP_FW_NAME_MAX_LEN,0);
- memset(ts->test_limit_name,TP_FW_NAME_MAX_LEN,0);
+ memset(ts->fw_name,0,TP_FW_NAME_MAX_LEN);
+ memset(ts->test_limit_name,0,TP_FW_NAME_MAX_LEN);
//sprintf(ts->manu_name, "TP_SYNAPTICS");
synaptics_rmi4_i2c_read_block(ts->client, F01_RMI_QUERY11,10, ts->manu_name);
@@ -4070,6 +4101,7 @@ static int synaptics_ts_probe(struct i2c_client *client, const struct i2c_device
goto exit_createworkqueue_failed;
}
INIT_DELAYED_WORK(&ts->base_work,tp_baseline_get_work);
+ INIT_WORK(&ts->base_work_intr, tp_baseline_get_in_intr);
ret = synaptics_init_panel(ts); /* will also switch back to page 0x04 */
if (ret < 0) {
@@ -4165,9 +4197,6 @@ static int synaptics_ts_probe(struct i2c_client *client, const struct i2c_device
TPDTM_DMESG("driver_create_file failt\n");
goto exit_init_failed;
}
-#ifdef SUPPORT_VIRTUAL_KEY
- synaptics_ts_init_virtual_key(ts);
-#endif
#ifdef CONFIG_SYNAPTIC_RED
premote_data = remote_alloc_panel_data();
if(premote_data) {
@@ -4190,8 +4219,6 @@ exit_init_failed:
exit_createworkqueue_failed:
destroy_workqueue(synaptics_wq);
synaptics_wq = NULL;
- destroy_workqueue(synaptics_report);
- synaptics_report = NULL;
destroy_workqueue(get_base_report);
get_base_report = NULL;
@@ -4422,11 +4449,11 @@ static int fb_notifier_callback(struct notifier_block *self, unsigned long event
mutex_lock(&ts->mutex);
if (gesture_flag == 1) {
ts->gesture_enable = 0;
- DouTap_gesture = 0;
+ double_tap_enable = 0;
synaptics_enable_interrupt_for_gesture(ts, 0);
gesture_flag = 0;
} else if (gesture_flag == 2) {
- DouTap_gesture = 0;
+ double_tap_enable = 0;
gesture_flag = 0;
}
if (ts->is_suspended == 1) {
@@ -4441,7 +4468,7 @@ static int fb_notifier_callback(struct notifier_block *self, unsigned long event
mutex_unlock(&ts->mutex);
} else if (*blank == FB_BLANK_NORMAL) {
if (ts->gesture_enable == 0) {
- DouTap_gesture = 1;
+ double_tap_enable = 1;
ts->gesture_enable = 1;
i2c_smbus_write_byte_data(ts->client,
0xff, 0x0);
@@ -4449,20 +4476,20 @@ static int fb_notifier_callback(struct notifier_block *self, unsigned long event
synaptics_ts_suspend(&ts->client->dev);
gesture_flag = 1;
} else if ((ts->gesture_enable == 1) &&
- (DouTap_gesture == 0)) {
- DouTap_gesture = 1;
+ (double_tap_enable == 0)) {
+ double_tap_enable = 1;
gesture_flag = 2;
}
} else if (*blank == FB_BLANK_POWERDOWN &&
(event == FB_EARLY_EVENT_BLANK)) {
if (gesture_flag == 1) {
ts->gesture_enable = 0;
- DouTap_gesture = 0;
+ double_tap_enable = 0;
synaptics_enable_interrupt_for_gesture(ts, 0);
ts->is_suspended = 0;
gesture_flag = 0;
} else if (gesture_flag == 2) {
- DouTap_gesture = 0;
+ double_tap_enable = 0;
ts->is_suspended = 0;
gesture_flag = 0;
}
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
index 4787f2bcd768..13680130c2de 100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
@@ -681,10 +681,12 @@ static enum flash_area fwu_go_nogo(struct image_header_data *header)
goto exit;
}
- while (strptr[index] >= '0' && strptr[index] <= '9') {
+ while ((index < MAX_FIRMWARE_ID_LEN - 1) && strptr[index] >= '0'
+ && strptr[index] <= '9') {
firmware_id[index] = strptr[index];
index++;
}
+ firmware_id[index] = '\0';
retval = sstrtoul(firmware_id, 10, &image_fw_id);
kfree(firmware_id);
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c
index f50371c833c0..1436a685f7ac 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c
@@ -55,8 +55,6 @@
#define TYPE_B_PROTOCOL
#endif
-#define WAKEUP_GESTURE false
-
#define NO_0D_WHILE_2D
#define REPORT_2D_Z
#define REPORT_2D_W
@@ -69,6 +67,8 @@
#define IGNORE_FN_INIT_FAILURE
#define FB_READY_RESET
+#define SDW2500_I2C_ADDR 0x20
+
#define FB_READY_WAIT_MS 100
#define FB_READY_TIMEOUT_S 30
@@ -114,6 +114,13 @@
#define F12_WAKEUP_GESTURE_MODE 0x02
#define F12_UDG_DETECT 0x0f
+#define PWR_VTG_MIN_UV 2700000
+#define PWR_VTG_MAX_UV 3600000
+#define PWR_ACTIVE_LOAD_UA 2000
+#define I2C_VTG_MIN_UV 1710000
+#define I2C_VTG_MAX_UV 2000000
+#define I2C_ACTIVE_LOAD_UA 7000
+
static int synaptics_rmi4_check_status(struct synaptics_rmi4_data *rmi4_data,
bool *was_in_bl_mode);
static int synaptics_rmi4_free_fingers(struct synaptics_rmi4_data *rmi4_data);
@@ -1013,8 +1020,10 @@ static ssize_t synaptics_rmi4_wake_gesture_store(struct device *dev,
input = input > 0 ? 1 : 0;
- if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture)
+ if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture) {
rmi4_data->enable_wakeup_gesture = input;
+ rmi4_data->wakeup_gesture_en = input;
+ }
return count;
}
@@ -1088,7 +1097,6 @@ static int synaptics_rmi4_f11_abs_report(struct synaptics_rmi4_data *rmi4_data,
input_sync(rmi4_data->input_dev);
input_report_key(rmi4_data->input_dev, KEY_WAKEUP, 0);
input_sync(rmi4_data->input_dev);
- rmi4_data->suspend = false;
}
return 0;
@@ -1249,7 +1257,6 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data,
input_sync(rmi4_data->input_dev);
input_report_key(rmi4_data->input_dev, KEY_WAKEUP, 0);
input_sync(rmi4_data->input_dev);
- rmi4_data->suspend = false;
}
return 0;
@@ -3113,7 +3120,7 @@ flash_prog_mode:
}
if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture)
- rmi4_data->enable_wakeup_gesture = WAKEUP_GESTURE;
+ rmi4_data->enable_wakeup_gesture = rmi4_data->wakeup_gesture_en;
else
rmi4_data->enable_wakeup_gesture = false;
@@ -3408,6 +3415,66 @@ err_gpio_irq:
return retval;
}
+static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA)
+{
+ return (regulator_count_voltages(reg) > 0) ?
+ regulator_set_optimum_mode(reg, load_uA) : 0;
+}
+
+static int synaptics_rmi4_configure_reg(struct synaptics_rmi4_data *rmi4_data,
+ bool on)
+{
+ int retval;
+
+ if (on == false)
+ goto hw_shutdown;
+
+ if (rmi4_data->pwr_reg) {
+ if (regulator_count_voltages(rmi4_data->pwr_reg) > 0) {
+ retval = regulator_set_voltage(rmi4_data->pwr_reg,
+ PWR_VTG_MIN_UV, PWR_VTG_MAX_UV);
+ if (retval) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "regulator set_vtg failed retval =%d\n",
+ retval);
+ goto err_set_vtg_pwr;
+ }
+ }
+ }
+
+ if (rmi4_data->bus_reg) {
+ if (regulator_count_voltages(rmi4_data->bus_reg) > 0) {
+ retval = regulator_set_voltage(rmi4_data->bus_reg,
+ I2C_VTG_MIN_UV, I2C_VTG_MAX_UV);
+ if (retval) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "regulator set_vtg failed retval =%d\n",
+ retval);
+ goto err_set_vtg_bus;
+ }
+ }
+ }
+
+ return 0;
+
+err_set_vtg_bus:
+ if (rmi4_data->pwr_reg &&
+ regulator_count_voltages(rmi4_data->pwr_reg) > 0)
+ regulator_set_voltage(rmi4_data->pwr_reg, 0, PWR_VTG_MAX_UV);
+err_set_vtg_pwr:
+ return retval;
+
+hw_shutdown:
+ if (rmi4_data->pwr_reg &&
+ regulator_count_voltages(rmi4_data->pwr_reg) > 0)
+ regulator_set_voltage(rmi4_data->pwr_reg, 0, PWR_VTG_MAX_UV);
+ if (rmi4_data->bus_reg &&
+ regulator_count_voltages(rmi4_data->bus_reg) > 0)
+ regulator_set_voltage(rmi4_data->bus_reg, 0, I2C_VTG_MAX_UV);
+
+ return 0;
+}
+
static int synaptics_rmi4_get_reg(struct synaptics_rmi4_data *rmi4_data,
bool get)
{
@@ -3473,37 +3540,66 @@ static int synaptics_rmi4_enable_reg(struct synaptics_rmi4_data *rmi4_data,
}
if (rmi4_data->bus_reg) {
+ retval = reg_set_optimum_mode_check(rmi4_data->bus_reg,
+ I2C_ACTIVE_LOAD_UA);
+ if (retval < 0) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "%s: Regulator set_opt failed rc=%d\n",
+ __func__, retval);
+ return retval;
+ }
+
retval = regulator_enable(rmi4_data->bus_reg);
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to enable bus pullup regulator\n",
__func__);
- goto exit;
+ goto err_bus_reg_en;
}
}
if (rmi4_data->pwr_reg) {
+ retval = reg_set_optimum_mode_check(rmi4_data->pwr_reg,
+ PWR_ACTIVE_LOAD_UA);
+ if (retval < 0) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "%s: Regulator set_opt failed rc=%d\n",
+ __func__, retval);
+ goto disable_bus_reg;
+ }
+
retval = regulator_enable(rmi4_data->pwr_reg);
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to enable power regulator\n",
__func__);
- goto disable_bus_reg;
+ goto err_pwr_reg_en;
}
msleep(bdata->power_delay_ms);
}
return 0;
+err_pwr_reg_en:
+ reg_set_optimum_mode_check(rmi4_data->pwr_reg, 0);
+ goto disable_bus_reg;
+err_bus_reg_en:
+ reg_set_optimum_mode_check(rmi4_data->bus_reg, 0);
+
+ return retval;
+
disable_pwr_reg:
- if (rmi4_data->pwr_reg)
+ if (rmi4_data->pwr_reg) {
+ reg_set_optimum_mode_check(rmi4_data->pwr_reg, 0);
regulator_disable(rmi4_data->pwr_reg);
+ }
disable_bus_reg:
- if (rmi4_data->bus_reg)
+ if (rmi4_data->bus_reg) {
+ reg_set_optimum_mode_check(rmi4_data->bus_reg, 0);
regulator_disable(rmi4_data->bus_reg);
+ }
-exit:
return retval;
}
@@ -3953,6 +4049,7 @@ static int synaptics_rmi4_probe(struct platform_device *pdev)
rmi4_data->suspend = false;
rmi4_data->irq_enabled = false;
rmi4_data->fingers_on_2d = false;
+ rmi4_data->wakeup_gesture_en = bdata->wakeup_gesture_en;
rmi4_data->reset_device = synaptics_rmi4_reset_device;
rmi4_data->irq_enable = synaptics_rmi4_irq_enable;
@@ -3976,6 +4073,14 @@ static int synaptics_rmi4_probe(struct platform_device *pdev)
goto err_get_reg;
}
+ retval = synaptics_rmi4_configure_reg(rmi4_data, true);
+ if (retval < 0) {
+ dev_err(&pdev->dev,
+ "%s: Failed to configure regulators\n",
+ __func__);
+ goto err_configure_reg;
+ }
+
retval = synaptics_rmi4_enable_reg(rmi4_data, true);
if (retval < 0) {
dev_err(&pdev->dev,
@@ -4202,6 +4307,8 @@ err_set_gpio:
err_enable_reg:
synaptics_rmi4_get_reg(rmi4_data, false);
+err_configure_reg:
+ synaptics_rmi4_configure_reg(rmi4_data, false);
err_get_reg:
kfree(rmi4_data);
@@ -4284,6 +4391,7 @@ static int synaptics_rmi4_remove(struct platform_device *pdev)
}
synaptics_rmi4_enable_reg(rmi4_data, false);
+ synaptics_rmi4_configure_reg(rmi4_data, false);
synaptics_rmi4_get_reg(rmi4_data, false);
kfree(rmi4_data);
@@ -4422,7 +4530,8 @@ static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self,
synaptics_secure_touch_stop(rmi4_data, false);
} else if (event == FB_EVENT_BLANK) {
transition = evdata->data;
- if (*transition == FB_BLANK_POWERDOWN) {
+ if (*transition == FB_BLANK_POWERDOWN ||
+ *transition == FB_BLANK_VSYNC_SUSPEND) {
flush_work(
&(rmi4_data->fb_notify_work));
synaptics_rmi4_suspend(
@@ -4556,6 +4665,7 @@ static int synaptics_rmi4_suspend(struct device *dev)
struct synaptics_rmi4_exp_fhandler *exp_fhandler;
struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
int retval;
+ int lpm_uA;
if (rmi4_data->stay_awake)
return 0;
@@ -4563,8 +4673,21 @@ static int synaptics_rmi4_suspend(struct device *dev)
synaptics_secure_touch_stop(rmi4_data, true);
if (rmi4_data->enable_wakeup_gesture) {
- synaptics_rmi4_wakeup_gesture(rmi4_data, true);
- enable_irq_wake(rmi4_data->irq);
+ if (!rmi4_data->suspend) {
+ /* Set lpm current for bus regulator */
+ lpm_uA = rmi4_data->hw_if->board_data->bus_lpm_cur_uA;
+ if (lpm_uA) {
+ retval = reg_set_optimum_mode_check(
+ rmi4_data->bus_reg, lpm_uA);
+ if (retval < 0)
+ dev_err(dev,
+ "Bus Regulator set_opt failed rc=%d\n",
+ retval);
+ }
+
+ synaptics_rmi4_wakeup_gesture(rmi4_data, true);
+ enable_irq_wake(rmi4_data->irq);
+ }
goto exit;
}
@@ -4577,9 +4700,10 @@ static int synaptics_rmi4_suspend(struct device *dev)
if (rmi4_data->ts_pinctrl) {
retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
rmi4_data->pinctrl_state_suspend);
- if (retval < 0)
+ if (retval < 0) {
dev_err(dev, "Cannot get idle pinctrl state\n");
goto err_pinctrl;
+ }
}
exit:
mutex_lock(&exp_data.mutex);
@@ -4590,10 +4714,10 @@ exit:
}
mutex_unlock(&exp_data.mutex);
- if (!rmi4_data->suspend) {
+ if (!rmi4_data->suspend && !rmi4_data->enable_wakeup_gesture &&
+ !rmi4_data->hw_if->board_data->dont_disable_regs)
synaptics_rmi4_enable_reg(rmi4_data, false);
- synaptics_rmi4_get_reg(rmi4_data, false);
- }
+
rmi4_data->suspend = true;
return 0;
@@ -4619,17 +4743,30 @@ static int synaptics_rmi4_resume(struct device *dev)
synaptics_secure_touch_stop(rmi4_data, true);
if (rmi4_data->enable_wakeup_gesture) {
- synaptics_rmi4_wakeup_gesture(rmi4_data, false);
- disable_irq_wake(rmi4_data->irq);
+ if (rmi4_data->suspend) {
+ /* Set active current for the bus regulator */
+ if (rmi4_data->hw_if->board_data->bus_lpm_cur_uA) {
+ retval = reg_set_optimum_mode_check(
+ rmi4_data->bus_reg,
+ I2C_ACTIVE_LOAD_UA);
+ if (retval < 0)
+ dev_err(dev,
+ "Pwr regulator set_opt failed rc=%d\n",
+ retval);
+ }
+
+
+ synaptics_rmi4_wakeup_gesture(rmi4_data, false);
+ disable_irq_wake(rmi4_data->irq);
+ }
goto exit;
}
rmi4_data->current_page = MASK_8BIT;
- if(rmi4_data->suspend) {
- synaptics_rmi4_get_reg(rmi4_data, true);
+ if (rmi4_data->suspend &&
+ !rmi4_data->hw_if->board_data->dont_disable_regs)
synaptics_rmi4_enable_reg(rmi4_data, true);
- }
synaptics_rmi4_sleep_enable(rmi4_data, false);
synaptics_rmi4_irq_enable(rmi4_data, true, false);
@@ -4641,12 +4778,14 @@ static int synaptics_rmi4_resume(struct device *dev)
}
exit:
-#ifdef FB_READY_RESET
- retval = synaptics_rmi4_reset_device(rmi4_data, false);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to issue reset command\n",
- __func__);
+ #ifdef FB_READY_RESET
+ if (rmi4_data->hw_if->board_data->i2c_addr != SDW2500_I2C_ADDR) {
+ retval = synaptics_rmi4_reset_device(rmi4_data, false);
+ if (retval < 0) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "%s: Failed to issue reset command\n",
+ __func__);
+ }
}
#endif
mutex_lock(&exp_data.mutex);
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h
index 7d92791afb25..7a5b3b5abb47 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h
@@ -371,6 +371,7 @@ struct synaptics_rmi4_data {
bool fb_ready;
bool f11_wakeup_gesture;
bool f12_wakeup_gesture;
+ bool wakeup_gesture_en;
bool enable_wakeup_gesture;
bool wedge_sensor;
bool report_pressure;
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c
index f4854a93a446..b3afc714b812 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c
@@ -43,10 +43,9 @@
#include "synaptics_dsx_core.h"
#define FW_IMAGE_NAME "synaptics/startup_fw_update.img"
-/*
+
#define DO_STARTUP_FW_UPDATE
-*/
-/*
+
#ifdef DO_STARTUP_FW_UPDATE
#ifdef CONFIG_FB
#define WAIT_FOR_FB_READY
@@ -54,7 +53,7 @@
#define FB_READY_TIMEOUT_S 30
#endif
#endif
-*/
+
#define FORCE_UPDATE false
#define DO_LOCKDOWN false
@@ -3418,6 +3417,7 @@ static int fwu_start_reflash(void)
enum flash_area flash_area;
const struct firmware *fw_entry = NULL;
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ const unsigned char *image_name;
if (rmi4_data->sensor_sleep) {
dev_err(rmi4_data->pdev->dev.parent,
@@ -3433,9 +3433,14 @@ static int fwu_start_reflash(void)
pr_notice("%s: Start of reflash process\n", __func__);
if (fwu->image == NULL) {
+ if (rmi4_data->hw_if->board_data->fw_name)
+ image_name = rmi4_data->hw_if->board_data->fw_name;
+ else
+ image_name = FW_IMAGE_NAME;
+
retval = secure_memcpy(fwu->image_name, MAX_IMAGE_NAME_LEN,
- FW_IMAGE_NAME, sizeof(FW_IMAGE_NAME),
- sizeof(FW_IMAGE_NAME));
+ image_name, strlen(image_name),
+ strlen(image_name));
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to copy image file name\n",
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c
index 563ce16885b3..95ea222663a4 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c
@@ -5,7 +5,8 @@
*
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- * Copyright (C) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2016, 2018 The Linux Foundation. All rights reserved.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -81,6 +82,12 @@ static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata)
bdata->resume_in_workqueue = of_property_read_bool(np,
"synaptics,resume-in-workqueue");
+ bdata->wakeup_gesture_en = of_property_read_bool(np,
+ "synaptics,wakeup-gestures-en");
+
+ bdata->dont_disable_regs = of_property_read_bool(np,
+ "synaptics,do-not-disable-regulators");
+
retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name);
if (retval < 0)
bdata->pwr_reg_name = NULL;
@@ -181,6 +188,10 @@ static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata)
bdata->max_y_for_2d = -1;
}
+ retval = of_property_read_u32(np, "synaptics,bus-lpm-cur-uA",
+ &value);
+ bdata->bus_lpm_cur_uA = retval < 0 ? 0 : value;
+
prop = of_find_property(np, "synaptics,swap-axes", NULL);
bdata->swap_axes = prop > 0 ? true : false;
@@ -205,6 +216,12 @@ static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata)
bdata->ub_i2c_addr = -1;
}
+ retval = of_property_read_string(np, "synaptics,fw-name", &name);
+ if (retval < 0)
+ bdata->fw_name = NULL;
+ else
+ bdata->fw_name = name;
+
prop = of_find_property(np, "synaptics,cap-button-codes", NULL);
if (prop && prop->length) {
bdata->cap_button_map->map = devm_kzalloc(dev,
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index 98e25339c0b7..18a637d4c537 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -865,7 +865,8 @@ static enum flash_area fwu_go_nogo(void)
}
strptr += 2;
- while (strptr[index] >= '0' && strptr[index] <= '9') {
+ while ((index < MAX_FIRMWARE_ID_LEN - 1) && strptr[index] >= '0'
+ && strptr[index] <= '9') {
imagePR[index] = strptr[index];
index++;
}
diff --git a/include/linux/input/synaptics_dsx_v2_6.h b/include/linux/input/synaptics_dsx_v2_6.h
index 5d4bbedb5f1a..7cf0a16c7cc9 100644
--- a/include/linux/input/synaptics_dsx_v2_6.h
+++ b/include/linux/input/synaptics_dsx_v2_6.h
@@ -5,7 +5,7 @@
*
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- * Copyright (C) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2016, 2018 The Linux Foundation. All rights reserved.
*
* 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
@@ -59,6 +59,7 @@ struct synaptics_dsx_button_map {
* @y_flip: y flip flag
* @swap_axes: swap axes flag
* @resume_in_workqueue: defer resume function to workqueue
+ * @resume_in_workqueue: do not disable/enable regulators in suspend/resume
* @irq_gpio: attention interrupt GPIO
* @irq_on_state: attention interrupt active state
* @power_gpio: power switch GPIO
@@ -75,6 +76,7 @@ struct synaptics_dsx_button_map {
* @power_delay_ms: delay time to wait after powering up device
* @reset_delay_ms: delay time to wait after resetting device
* @reset_active_ms: reset active time
+ * @bus_lpm_cur_uA: low power mode current setting for bus
* @byte_delay_us: delay time between two bytes of SPI data
* @block_delay_us: delay time between two SPI transfers
* @pwr_reg_name: pointer to name of regulator for power control
@@ -88,12 +90,15 @@ struct synaptics_dsx_board_data {
bool y_flip;
bool swap_axes;
bool resume_in_workqueue;
+ bool wakeup_gesture_en;
+ bool dont_disable_regs;
int irq_gpio;
int irq_on_state;
int power_gpio;
int power_on_state;
int reset_gpio;
int reset_on_state;
+ int bus_lpm_cur_uA;
int max_y_for_2d;
unsigned long irq_flags;
unsigned short i2c_addr;
@@ -110,6 +115,7 @@ struct synaptics_dsx_board_data {
const char *bus_reg_name;
struct synaptics_dsx_button_map *cap_button_map;
struct synaptics_dsx_button_map *vir_button_map;
+ const char *fw_name;
};
#endif
--
2.23.0