mirror of
https://github.com/NixOS/mobile-nixos.git
synced 2024-12-18 21:41:53 +03:00
15103 lines
431 KiB
Diff
15103 lines
431 KiB
Diff
|
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 = ®_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, ¤t_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,
|
|||
|
+ ¤t_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, ¤t_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,
|
|||
|
+ <r->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(<r->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(<r->i2c->dev);
|
|||
|
+ if (!input) {
|
|||
|
+ dev_err(<r->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(<r->i2c->dev, "register light input device failed.\n");
|
|||
|
+ return status;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ ltr->input_light = input;
|
|||
|
+
|
|||
|
+ input = devm_input_allocate_device(<r->i2c->dev);
|
|||
|
+ if (!input) {
|
|||
|
+ dev_err(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->i2c->dev, "update setting failed\n");
|
|||
|
+ goto exit;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ dev_dbg(<r->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(<r->i2c->dev, "read %d failed.(%d)\n",
|
|||
|
+ LTR553_REG_PS_DATA_0, rc);
|
|||
|
+ goto exit;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ dev_dbg(<r->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(<r->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(<r->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, <r->report_work);
|
|||
|
+ /* wake up event should hold a wake lock until reported */
|
|||
|
+ if (rc && (atomic_inc_return(<r->wake_count) == 1))
|
|||
|
+ pm_stay_awake(<r->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(<r->ops_lock);
|
|||
|
+
|
|||
|
+ /* avoid fake interrupt */
|
|||
|
+ if (!ltr->power_enabled) {
|
|||
|
+ dev_dbg(<r->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(<r->i2c->dev, "read %d failed.(%d)\n",
|
|||
|
+ LTR553_REG_ALS_PS_STATUS, rc);
|
|||
|
+ status |= LTR553_PS_INT_MASK;
|
|||
|
+ goto exit;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ dev_dbg(<r->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(<r->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(<r->i2c->dev, "process ps data done!\n");
|
|||
|
+ pm_wakeup_event(<r->input_proximity->dev, 200);
|
|||
|
+ }
|
|||
|
+
|
|||
|
+exit:
|
|||
|
+ if (atomic_dec_and_test(<r->wake_count)) {
|
|||
|
+ pm_relax(<r->i2c->dev);
|
|||
|
+ dev_dbg(<r->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(<r->i2c->dev, "clear interrupt failed\n");
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ mutex_unlock(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->ops_lock);
|
|||
|
+ if (!ltr->power_enabled) { /* new HAL? */
|
|||
|
+ if (sensor_power_config(<r->i2c->dev, power_config,
|
|||
|
+ ARRAY_SIZE(power_config), true)) {
|
|||
|
+ dev_err(<r->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(<r->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(<r->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(<r->i2c->dev, power_config,
|
|||
|
+ ARRAY_SIZE(power_config), false)) {
|
|||
|
+ dev_err(<r->i2c->dev, "power up sensor failed.\n");
|
|||
|
+ goto exit;
|
|||
|
+ }
|
|||
|
+ ltr->power_enabled = false;
|
|||
|
+ }
|
|||
|
+exit:
|
|||
|
+ mutex_unlock(<r->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(<r->ops_lock);
|
|||
|
+
|
|||
|
+ if (ltr553_enable_als(ltr, 0)) {
|
|||
|
+ dev_err(<r->i2c->dev, "disable als failed\n");
|
|||
|
+ goto exit;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ if ((!ltr->als_enabled) && (!ltr->ps_enabled) && ltr->power_enabled) {
|
|||
|
+ if (sensor_power_config(<r->i2c->dev, power_config,
|
|||
|
+ ARRAY_SIZE(power_config), false)) {
|
|||
|
+ dev_err(<r->i2c->dev, "power up sensor failed.\n");
|
|||
|
+ goto exit;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ ltr->power_enabled = false;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+exit:
|
|||
|
+ mutex_unlock(<r->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(<r->ops_lock);
|
|||
|
+ if (!ltr->power_enabled) {
|
|||
|
+ if (sensor_power_config(<r->i2c->dev, power_config,
|
|||
|
+ ARRAY_SIZE(power_config), true)) {
|
|||
|
+ dev_err(<r->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(<r->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(<r->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(<r->i2c->dev, power_config,
|
|||
|
+ ARRAY_SIZE(power_config), false)) {
|
|||
|
+ dev_err(<r->i2c->dev, "power up sensor failed.\n");
|
|||
|
+ goto exit;
|
|||
|
+ }
|
|||
|
+ ltr->power_enabled = false;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+exit:
|
|||
|
+ mutex_unlock(<r->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(<r->ops_lock);
|
|||
|
+
|
|||
|
+ if (ltr553_enable_ps(ltr, 0)) {
|
|||
|
+ dev_err(<r->i2c->dev, "ltrsable ps failed\n");
|
|||
|
+ goto exit;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ if ((!ltr->als_enabled) && (!ltr->ps_enabled) && ltr->power_enabled) {
|
|||
|
+ if (sensor_power_config(<r->i2c->dev, power_config,
|
|||
|
+ ARRAY_SIZE(power_config), false)) {
|
|||
|
+ dev_err(<r->i2c->dev, "power up sensor failed.\n");
|
|||
|
+ goto exit;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ ltr->power_enabled = false;
|
|||
|
+ }
|
|||
|
+exit:
|
|||
|
+ mutex_unlock(<r->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(<r->ops_lock);
|
|||
|
+
|
|||
|
+ if (enable)
|
|||
|
+ queue_work(ltr->workqueue, <r->als_enable_work);
|
|||
|
+ else
|
|||
|
+ queue_work(ltr->workqueue, <r->als_disable_work);
|
|||
|
+
|
|||
|
+ mutex_unlock(<r->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(<r->ops_lock);
|
|||
|
+
|
|||
|
+ if (enable)
|
|||
|
+ queue_work(ltr->workqueue, <r->ps_enable_work);
|
|||
|
+ else
|
|||
|
+ queue_work(ltr->workqueue, <r->ps_disable_work);
|
|||
|
+
|
|||
|
+ mutex_unlock(<r->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(<r->ops_lock);
|
|||
|
+
|
|||
|
+ ltr->als_delay = delay_msec;
|
|||
|
+ rc = ltr553_als_sync_delay(ltr, delay_msec);
|
|||
|
+
|
|||
|
+ mutex_unlock(<r->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(<r->ops_lock);
|
|||
|
+
|
|||
|
+ ltr->ps_delay = delay_msec;
|
|||
|
+ rc = ltr553_ps_sync_delay(ltr, delay_msec);
|
|||
|
+
|
|||
|
+ mutex_unlock(<r->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(<r->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(<r->i2c->dev, power_config,
|
|||
|
+ ARRAY_SIZE(power_config), true);
|
|||
|
+ if (rc) {
|
|||
|
+ dev_err(<r->i2c->dev, "power up sensor failed.\n");
|
|||
|
+ goto exit;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ msleep(LTR553_BOOT_TIME_MS);
|
|||
|
+
|
|||
|
+ rc = ltr553_init_device(ltr);
|
|||
|
+ if (rc) {
|
|||
|
+ dev_err(<r->i2c->dev, "init ltr553 failed\n");
|
|||
|
+ goto exit;
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ rc = regmap_read(ltr->regmap, LTR553_REG_INTERRUPT, &interrupt);
|
|||
|
+ if (rc) {
|
|||
|
+ dev_err(<r->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(<r->i2c->dev, "disable interrupt failed\n");
|
|||
|
+ goto exit_power_off;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ rc = regmap_read(ltr->regmap, LTR553_REG_PS_CTL, &config);
|
|||
|
+ if (rc) {
|
|||
|
+ dev_err(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->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(<r->i2c->dev, "result: %s\n", ltr->calibrate_buf);
|
|||
|
+ } else {
|
|||
|
+ dev_err(<r->i2c->dev, "calibration failed\n");
|
|||
|
+ rc = -EINVAL;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+exit_enable_interrupt:
|
|||
|
+ if (regmap_write(ltr->regmap, LTR553_REG_INTERRUPT, interrupt)) {
|
|||
|
+ dev_err(<r->i2c->dev, "enable interrupt failed\n");
|
|||
|
+ goto exit_power_off;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+exit_power_off:
|
|||
|
+ if (!power) {
|
|||
|
+ if (sensor_power_config(<r->i2c->dev, power_config,
|
|||
|
+ ARRAY_SIZE(power_config), false)) {
|
|||
|
+ dev_err(<r->i2c->dev, "power off sensor failed.\n");
|
|||
|
+ goto exit;
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+exit:
|
|||
|
+ mutex_unlock(<r->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(<r->ops_lock);
|
|||
|
+ power = ltr->power_enabled;
|
|||
|
+ if (!power) {
|
|||
|
+ rc = sensor_power_config(<r->i2c->dev, power_config,
|
|||
|
+ ARRAY_SIZE(power_config), true);
|
|||
|
+ if (rc) {
|
|||
|
+ dev_err(<r->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(<r->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(<r->i2c->dev, power_config,
|
|||
|
+ ARRAY_SIZE(power_config), false)) {
|
|||
|
+ dev_err(<r->i2c->dev, "power off sensor failed.\n");
|
|||
|
+ goto exit;
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+exit:
|
|||
|
+
|
|||
|
+ mutex_unlock(<r->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(<r->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(<r->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, ®, &val) < 2) {
|
|||
|
+ dev_err(<r->i2c->dev, "argument error\n");
|
|||
|
+ return -EINVAL;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ if (cmd == CMD_WRITE) {
|
|||
|
+ rc = regmap_write(ltr->regmap, reg, val);
|
|||
|
+ if (rc) {
|
|||
|
+ dev_err(<r->i2c->dev, "write %d failed\n", reg);
|
|||
|
+ return rc;
|
|||
|
+ }
|
|||
|
+ } else if (cmd == CMD_READ) {
|
|||
|
+ ltr->reg_addr = reg;
|
|||
|
+ dev_dbg(<r->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(<r->ops_lock);
|
|||
|
+
|
|||
|
+ ltr->regmap = devm_regmap_init_i2c(client, <r553_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(<r->report_work, ltr553_report_work);
|
|||
|
+ INIT_WORK(<r->als_enable_work, ltr553_als_enable_work);
|
|||
|
+ INIT_WORK(<r->als_disable_work, ltr553_als_disable_work);
|
|||
|
+ INIT_WORK(<r->ps_enable_work, ltr553_ps_enable_work);
|
|||
|
+ INIT_WORK(<r->ps_disable_work, ltr553_ps_disable_work);
|
|||
|
+
|
|||
|
+ } else {
|
|||
|
+ res = -ENODEV;
|
|||
|
+ goto err_init_device;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ res = sysfs_create_group(&client->dev.kobj, <r553_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(<r->input_light->dev, <r->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(<r->input_proximity->dev,
|
|||
|
+ <r->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(<r->als_cdev);
|
|||
|
+err_register_als_cdev:
|
|||
|
+err_init_input:
|
|||
|
+ sysfs_remove_group(&client->dev.kobj, <r553_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(<r->ps_cdev);
|
|||
|
+ sensors_classdev_unregister(<r->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(<r->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(<r->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(<r->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(<r->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(<r->i2c->dev)) {
|
|||
|
+ dev_dbg(<r->i2c->dev, "enable irq wake\n");
|
|||
|
+ enable_irq_wake(ltr->irq);
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ /* Setup threshold to avoid frequent wakeup */
|
|||
|
+ if (device_may_wakeup(<r->i2c->dev) &&
|
|||
|
+ (idx != LTR553_WAKEUP_ANY_CHANGE)) {
|
|||
|
+ dev_dbg(<r->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(<r->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(<r->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(<r->i2c->dev)) {
|
|||
|
+ dev_dbg(<r->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(<r->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(<r->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(<r->i2c->dev, power_config,
|
|||
|
+ ARRAY_SIZE(power_config), false)) {
|
|||
|
+ dev_err(<r->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 = <r553_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
|
|||
|
|