summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/Kconfig7
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/als_notify.c50
-rw-r--r--drivers/misc/c55_ctrl.c16
-rw-r--r--drivers/misc/m4sensorhub_als.c118
-rw-r--r--drivers/misc/m4sensorhub_fusion.c84
-rw-r--r--drivers/misc/m4sensorhub_gesture.c8
-rw-r--r--drivers/misc/m4sensorhub_mpu9150.c64
-rw-r--r--drivers/misc/m4sensorhub_pedometer.c194
9 files changed, 417 insertions, 125 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 5b96da5fda8..5aed79aa3c4 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -586,6 +586,13 @@ config WAKEUP_SOURCE_NOTIFY
help
Driver to allow early notification of wakeups
+config ALS_WHILE_CHARGING
+ tristate "use ALS when on charger"
+ depends on WAKEUP_SOURCE_NOTIFY
+ help
+ ALS when unit is on charger
+
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 2f57dbac599..39d1e04e896 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -68,3 +68,4 @@ obj-$(CONFIG_MOT_UTAG) += utag/
obj-$(CONFIG_BQ5105X_CTRL) += bq5105x_ctrl.o
obj-$(CONFIG_BQ5105X_DETECT) += bq5105x_detect.o
obj-$(CONFIG_WAKEUP_SOURCE_NOTIFY) += wakeup_source_notify.o
+obj-$(CONFIG_WAKEUP_SOURCE_NOTIFY) += als_notify.o
diff --git a/drivers/misc/als_notify.c b/drivers/misc/als_notify.c
new file mode 100644
index 00000000000..cbb4f3a55cd
--- /dev/null
+++ b/drivers/misc/als_notify.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2014 Motorola Mobility LLC.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/notifier.h>
+#include <linux/als_notify.h>
+
+static BLOCKING_NOTIFIER_HEAD(als_notifier_list);
+
+/**
+ * als_register_notify - register a notifier callback for triggering display init
+ * @nb: pointer to the notifier block for the callback events.
+ *
+ */
+void als_register_notify(struct notifier_block *nb)
+{
+ blocking_notifier_chain_register(&als_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(als_register_notify);
+
+/**
+ * als_unregister_notify - unregister a notifier callback
+ * @nb: pointer to the notifier block for the callback events.
+ *
+ * als_register_notify() must have been previously called
+ * for this function to work properly.
+ */
+void als_unregister_notify(struct notifier_block *nb)
+{
+ blocking_notifier_chain_unregister(&als_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(als_unregister_notify);
+
+void als_notify_subscriber(unsigned long event)
+{
+ blocking_notifier_call_chain(&als_notifier_list, event, NULL);
+}
+EXPORT_SYMBOL_GPL(als_notify_subscriber);
diff --git a/drivers/misc/c55_ctrl.c b/drivers/misc/c55_ctrl.c
index 54ffc6e5b2b..cf763272922 100644
--- a/drivers/misc/c55_ctrl.c
+++ b/drivers/misc/c55_ctrl.c
@@ -143,7 +143,6 @@ static ssize_t c55_ctrl_enable(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct c55_ctrl_data *cdata = dev_get_drvdata(dev);
- struct m4sensorhub_data *m4sensorhub = m4sensorhub_client_get_drvdata();
int mode;
if (kstrtoint(buf, 10, &mode) < 0)
@@ -154,7 +153,7 @@ static ssize_t c55_ctrl_enable(struct device *dev,
return -EINVAL;
}
- if (m4sensorhub->mode != NORMALMODE) {
+ if (m4sensorhub_get_current_mode() != NORMALMODE) {
dev_err(dev, "M4 not ready, Unable to set screen status\n");
return -EINVAL;
}
@@ -169,9 +168,7 @@ static ssize_t c55_ctrl_enable(struct device *dev,
gpio_set_value(cdata->ap_c55_int_gpio, 1);
- if (m4sensorhub_reg_write_1byte
- (m4sensorhub, M4SH_REG_USERSETTINGS_AUDIOSTATUS,
- AUDIO_STATUS_ON, 0xFF) != 1) {
+ if (m4sensorhub_extern_set_audio_status(AUDIO_STATUS_ON) < 0) {
dev_err(dev, "Unable to set screen status to 0x01\n");
mutex_unlock(&cdata->ctrl_mutex);
return -EINVAL;
@@ -189,9 +186,7 @@ static ssize_t c55_ctrl_enable(struct device *dev,
cdata->c55_ap_int_enabled = 0;
}
- if (m4sensorhub_reg_write_1byte
- (m4sensorhub, M4SH_REG_USERSETTINGS_AUDIOSTATUS,
- AUDIO_STATUS_OFF, 0xFF) != 1) {
+ if (m4sensorhub_extern_set_audio_status(AUDIO_STATUS_OFF) < 0) {
dev_err(dev, "Unable to set screen status to 0x00\n");
mutex_unlock(&cdata->ctrl_mutex);
return -EINVAL;
@@ -363,7 +358,6 @@ static int c55_ctrl_remove(struct platform_device *pdev)
static int c55_ctrl_suspend(struct platform_device *dev, pm_message_t state)
{
struct c55_ctrl_data *cdata = dev_get_drvdata(&dev->dev);
- struct m4sensorhub_data *m4sensorhub = m4sensorhub_client_get_drvdata();
if (cdata->c55_mode != C55_OFF) {
dev_warn(&dev->dev, "C55 still ON when going into suspend\n");
@@ -375,9 +369,7 @@ static int c55_ctrl_suspend(struct platform_device *dev, pm_message_t state)
cdata->c55_ap_int_enabled = 0;
}
- if (m4sensorhub_reg_write_1byte
- (m4sensorhub, M4SH_REG_USERSETTINGS_AUDIOSTATUS,
- AUDIO_STATUS_OFF, 0xFF) != 1) {
+ if (m4sensorhub_extern_set_audio_status(AUDIO_STATUS_OFF) < 0) {
dev_err(&dev->dev,
"Unable to set screen status to 0x00\n");
}
diff --git a/drivers/misc/m4sensorhub_als.c b/drivers/misc/m4sensorhub_als.c
index 3f61edefff2..6445d9f0181 100644
--- a/drivers/misc/m4sensorhub_als.c
+++ b/drivers/misc/m4sensorhub_als.c
@@ -28,12 +28,21 @@
#include <linux/m4sensorhub.h>
#include <linux/input.h>
#include <linux/slab.h>
+#include <linux/delay.h>
+#ifdef CONFIG_WAKEUP_SOURCE_NOTIFY
+#include <linux/notifier.h>
+#include <linux/als_notify.h>
+#ifdef CONFIG_ALS_WHILE_CHARGING
+#include <linux/wakeup_source_notify.h>
+#endif /* CONFIG_ALS_WHILE_CHARGING */
+#endif
#define m4als_err(format, args...) KDEBUG(M4SH_ERROR, format, ## args)
#define M4ALS_DRIVER_NAME "m4sensorhub_als"
#define M4ALS_IRQ_ENABLED_BIT 0
+#define ALS_SAMPLERATE_WHILE_DOCKED 10 /* in seconds */
struct m4als_driver_data {
struct platform_device *pdev;
@@ -42,13 +51,39 @@ struct m4als_driver_data {
struct input_dev *indev;
struct delayed_work m4als_work;
+ /* Beware of changing this from uint16, check als_notify.h
+ since notifier uses values outside luminosity range for
+ conveying enable/disable status */
uint16_t luminosity;
int16_t samplerate;
int16_t latest_samplerate;
int16_t fastest_rate;
uint16_t status;
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ struct notifier_block charger_nb;
+ bool chargerstatus;
+#endif
};
+#ifdef CONFIG_ALS_WHILE_CHARGING
+static int charger_notify(struct notifier_block *self,
+ unsigned long action, void *dev)
+{
+ struct m4als_driver_data *dd =
+ container_of(self, struct m4als_driver_data, charger_nb);
+ switch (action) {
+ case DISPLAY_WAKE_EVENT_DOCKON:
+ case DISPLAY_WAKE_EVENT_DOCKOFF:
+ dd->chargerstatus = (action == DISPLAY_WAKE_EVENT_DOCKON);
+ pr_info("%s: dd->chargerstatus is %d\n",
+ __func__, dd->chargerstatus);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+#endif
+
static void m4als_work_func(struct work_struct *work)
{
int err = 0;
@@ -81,8 +116,18 @@ static void m4als_work_func(struct work_struct *work)
dd->luminosity = luminosity;
- input_event(dd->indev, EV_MSC, MSC_RAW, dd->luminosity);
- input_sync(dd->indev);
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ if (dd->chargerstatus == true) {
+ als_notify_subscriber(luminosity);
+ } else {
+ input_event(dd->indev, EV_MSC, MSC_RAW, dd->luminosity);
+ input_sync(dd->indev);
+ }
+#else
+ input_event(dd->indev, EV_MSC, MSC_RAW, dd->luminosity);
+ input_sync(dd->indev);
+#endif
+
if (dd->samplerate > 0)
queue_delayed_work(system_freezable_wq, &(dd->m4als_work),
msecs_to_jiffies(dd->samplerate));
@@ -101,6 +146,12 @@ static int m4als_set_samplerate(struct m4als_driver_data *dd, int16_t rate)
int err = 0;
int size = 0;
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ if (rate == -1 && dd->chargerstatus == true) {
+ rate = ALS_SAMPLERATE_WHILE_DOCKED * 1000;
+ }
+#endif
+
if ((rate >= 0) && (rate <= dd->fastest_rate))
rate = dd->fastest_rate;
@@ -132,9 +183,17 @@ static int m4als_set_samplerate(struct m4als_driver_data *dd, int16_t rate)
}
cancel_delayed_work(&(dd->m4als_work));
dd->samplerate = rate;
- if (dd->samplerate > 0)
+ if (dd->samplerate > 0) {
queue_delayed_work(system_freezable_wq, &(dd->m4als_work),
msecs_to_jiffies(rate));
+#ifdef CONFIG_WAKEUP_SOURCE_NOTIFY
+ als_notify_subscriber(ALS_ENABLED);
+#endif
+ } else {
+#ifdef CONFIG_WAKEUP_SOURCE_NOTIFY
+ als_notify_subscriber(ALS_DISABLED);
+#endif
+ }
m4als_set_samplerate_fail:
return err;
@@ -153,6 +212,8 @@ static ssize_t m4als_setrate_store(struct device *dev,
int err = 0;
struct m4als_driver_data *dd = dev_get_drvdata(dev);
int value = 0;
+ int regsize = 0;
+ uint16_t luminosity = 0;
mutex_lock(&(dd->mutex));
@@ -175,6 +236,32 @@ static ssize_t m4als_setrate_store(struct device *dev,
goto m4als_enable_store_exit;
}
+ /* Read and send raw value for gesture wakeup */
+ msleep(120);
+ regsize = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_LIGHTSENSOR_SIGNAL);
+ if (regsize < 0) {
+ m4als_err("%s: Reading from invalid register %d.\n",
+ __func__, regsize);
+ err = regsize;
+ goto m4als_enable_store_exit;
+ }
+
+ err = m4sensorhub_reg_read(dd->m4, M4SH_REG_LIGHTSENSOR_SIGNAL,
+ (char *)&luminosity);
+ if (err < 0) {
+ m4als_err("%s: Failed to read luminosity data.\n", __func__);
+ goto m4als_enable_store_exit;
+ } else if (err != regsize) {
+ m4als_err("%s: Read %d bytes instead of %d.\n",
+ __func__, err, regsize);
+ goto m4als_enable_store_exit;
+ }
+
+ dd->luminosity = luminosity;
+
+ input_event(dd->indev, EV_MSC, MSC_RAW, dd->luminosity);
+ input_sync(dd->indev);
+
m4als_enable_store_exit:
if (err < 0)
m4als_err("%s: Failed with error code %d.\n", __func__, err);
@@ -304,12 +391,6 @@ static int m4als_driver_init(struct init_calldata *p_arg)
goto m4als_driver_init_fail;
}
- err = m4als_create_sysfs(dd);
- if (err < 0) {
- m4als_err("%s: Failed to create sysfs.\n", __func__);
- goto m4als_driver_init_sysfs_fail;
- }
-
INIT_DELAYED_WORK(&(dd->m4als_work), m4als_work_func);
err = m4sensorhub_panic_register(dd->m4, PANICHDL_ALS_RESTORE,
@@ -318,8 +399,6 @@ static int m4als_driver_init(struct init_calldata *p_arg)
KDEBUG(M4SH_ERROR, "Als panic callback register failed\n");
goto m4als_driver_init_exit;
-m4als_driver_init_sysfs_fail:
- input_unregister_device(dd->indev);
m4als_driver_init_fail:
m4als_err("%s: Init failed with error code %d.\n", __func__, err);
m4als_driver_init_exit:
@@ -359,8 +438,22 @@ static int m4als_probe(struct platform_device *pdev)
goto m4als_probe_fail;
}
+ err = m4als_create_sysfs(dd);
+ if (err < 0) {
+ m4als_err("%s: Failed to create sysfs.\n", __func__);
+ goto m4als_driver_init_sysfs_fail;
+ }
+
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ dd->chargerstatus = false;
+ dd->charger_nb.notifier_call = charger_notify;
+ wakeup_source_register_notify(&dd->charger_nb);
+#endif
+
return 0;
+m4als_driver_init_sysfs_fail:
+ m4sensorhub_unregister_initcall(m4als_driver_init);
m4als_probe_fail:
mutex_destroy(&(dd->mutex));
kfree(dd);
@@ -377,6 +470,9 @@ static int __exit m4als_remove(struct platform_device *pdev)
cancel_delayed_work(&(dd->m4als_work));
m4als_remove_sysfs(dd);
m4sensorhub_unregister_initcall(m4als_driver_init);
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ wakeup_source_unregister_notify(&dd->charger_nb);
+#endif
if (dd->indev != NULL)
input_unregister_device(dd->indev);
mutex_destroy(&(dd->mutex));
diff --git a/drivers/misc/m4sensorhub_fusion.c b/drivers/misc/m4sensorhub_fusion.c
index e1330f56263..816b89bea39 100644
--- a/drivers/misc/m4sensorhub_fusion.c
+++ b/drivers/misc/m4sensorhub_fusion.c
@@ -126,6 +126,90 @@ static void m4fus_work_func(struct work_struct *work)
dd->iiodat[1].type = FUSION_TYPE_ORIENTATION;
dd->iiodat[1].timestamp = iio_get_time_ns();
+ size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_FUSION_GRAVITYX);
+ err = m4sensorhub_reg_read(dd->m4, M4SH_REG_FUSION_GRAVITYX,
+ (char *)&(dd->iiodat[2].values[0]));
+ if (err < 0) {
+ m4fus_err("%s: Failed to read gravityX data.\n", __func__);
+ goto m4fus_isr_fail;
+ } else if (err != size) {
+ m4fus_err("%s: Read %d bytes instead of %d for %s.\n",
+ __func__, err, size, "gravityX");
+ err = -EBADE;
+ goto m4fus_isr_fail;
+ }
+
+ size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_FUSION_GRAVITYY);
+ err = m4sensorhub_reg_read(dd->m4, M4SH_REG_FUSION_GRAVITYY,
+ (char *)&(dd->iiodat[2].values[1]));
+ if (err < 0) {
+ m4fus_err("%s: Failed to read gravityY data.\n", __func__);
+ goto m4fus_isr_fail;
+ } else if (err != size) {
+ m4fus_err("%s: Read %d bytes instead of %d for %s.\n",
+ __func__, err, size, "gravityY");
+ err = -EBADE;
+ goto m4fus_isr_fail;
+ }
+
+ size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_FUSION_GRAVITYZ);
+ err = m4sensorhub_reg_read(dd->m4, M4SH_REG_FUSION_GRAVITYZ,
+ (char *)&(dd->iiodat[2].values[2]));
+ if (err < 0) {
+ m4fus_err("%s: Failed to read gravityZ data.\n", __func__);
+ goto m4fus_isr_fail;
+ } else if (err != size) {
+ m4fus_err("%s: Read %d bytes instead of %d for %s.\n",
+ __func__, err, size, "gravityZ");
+ err = -EBADE;
+ goto m4fus_isr_fail;
+ }
+
+ dd->iiodat[2].type = FUSION_TYPE_GRAVITY;
+ dd->iiodat[2].timestamp = iio_get_time_ns();
+
+ size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_FUSION_LOCALX);
+ err = m4sensorhub_reg_read(dd->m4, M4SH_REG_FUSION_LOCALX,
+ (char *)&(dd->iiodat[3].values[0]));
+ if (err < 0) {
+ m4fus_err("%s: Failed to read localX data.\n", __func__);
+ goto m4fus_isr_fail;
+ } else if (err != size) {
+ m4fus_err("%s: Read %d bytes instead of %d for %s.\n",
+ __func__, err, size, "localX");
+ err = -EBADE;
+ goto m4fus_isr_fail;
+ }
+
+ size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_FUSION_LOCALY);
+ err = m4sensorhub_reg_read(dd->m4, M4SH_REG_FUSION_LOCALY,
+ (char *)&(dd->iiodat[3].values[1]));
+ if (err < 0) {
+ m4fus_err("%s: Failed to read localY data.\n", __func__);
+ goto m4fus_isr_fail;
+ } else if (err != size) {
+ m4fus_err("%s: Read %d bytes instead of %d for %s.\n",
+ __func__, err, size, "localY");
+ err = -EBADE;
+ goto m4fus_isr_fail;
+ }
+
+ size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_FUSION_LOCALZ);
+ err = m4sensorhub_reg_read(dd->m4, M4SH_REG_FUSION_LOCALZ,
+ (char *)&(dd->iiodat[3].values[2]));
+ if (err < 0) {
+ m4fus_err("%s: Failed to read localZ data.\n", __func__);
+ goto m4fus_isr_fail;
+ } else if (err != size) {
+ m4fus_err("%s: Read %d bytes instead of %d for %s.\n",
+ __func__, err, size, "localZ");
+ err = -EBADE;
+ goto m4fus_isr_fail;
+ }
+
+ dd->iiodat[3].type = FUSION_TYPE_LINEAR_ACCELERATION;
+ dd->iiodat[3].timestamp = iio_get_time_ns();
+
/*
* For some reason, IIO knows we are sending an array,
* so all FUSION_TYPE_* indicies will be sent
diff --git a/drivers/misc/m4sensorhub_gesture.c b/drivers/misc/m4sensorhub_gesture.c
index d5e364ea6c5..9ccbbe3091e 100644
--- a/drivers/misc/m4sensorhub_gesture.c
+++ b/drivers/misc/m4sensorhub_gesture.c
@@ -114,7 +114,7 @@ static void m4ges_isr(enum m4sensorhub_irqs int_event, void *handle)
/* the GESTURE_VIEW is only effect for kernel now
* do not send gesture to android
*/
- goto m4ges_isr_fail;
+ goto m4ges_no_iio_push;
}
#endif /* CONFIG_WAKEUP_SOURCE_NOTIFY */
@@ -122,6 +122,12 @@ static void m4ges_isr(enum m4sensorhub_irqs int_event, void *handle)
iio_push_to_buffers(iio, (unsigned char *)&(dd->iiodat));
dd->gesture_count++;
+m4ges_no_iio_push:
+ /* Log gestures received */
+ pr_info("%s: Gesture received: count=%u, type=%hhu, value=%hhd.\n",
+ __func__, dd->gesture_count, dd->iiodat.gesture_type,
+ dd->iiodat.gesture_value);
+
m4ges_isr_fail:
if (err < 0)
m4ges_err("%s: Failed with error code %d.\n", __func__, err);
diff --git a/drivers/misc/m4sensorhub_mpu9150.c b/drivers/misc/m4sensorhub_mpu9150.c
index a2411c27d4f..55d160bc607 100644
--- a/drivers/misc/m4sensorhub_mpu9150.c
+++ b/drivers/misc/m4sensorhub_mpu9150.c
@@ -79,8 +79,6 @@ struct mpu9150_client {
struct mutex mutex; /* prevent concurrent thread access */
struct delayed_work mpu9150_work[NUM_TYPES];
signed short fastest_rate[NUM_TYPES];
- int calibration_done;
- int app_override;
};
struct mpu9150_client *misc_mpu9150_data;
@@ -142,23 +140,6 @@ static void m4_report_mpu9150_inputevent(
}
}
-static void m4_queue_delayed_work(struct mpu9150_client *dd,
- int delay, enum mpu9150_sensor type)
-{
- if (type == TYPE_COMPASS) {
- /* initial calibration is not done and there is
- no app requesting compass data */
- if ((!dd->calibration_done) && (!dd->app_override))
- /* For current drain saving, m4 is sampling
- compass at 40ms while omap is polling
- for compass data at 15 secs */
- delay = 15000;
- }
- queue_delayed_work(system_freezable_wq,
- &(dd->mpu9150_work[type]),
- msecs_to_jiffies(delay));
-}
-
static void m4_set_mpu9150_delay(struct mpu9150_client *mpu9150_client_data,
int delay, enum mpu9150_sensor type)
{
@@ -197,18 +178,19 @@ static void m4_set_mpu9150_delay(struct mpu9150_client *mpu9150_client_data,
cancel_delayed_work(&(dd->mpu9150_work[type]));
dd->samplerate[type] = delay;
if (dd->samplerate[type] > 0)
- m4_queue_delayed_work(dd, delay, type);
+ queue_delayed_work(system_freezable_wq,
+ &(dd->mpu9150_work[type]),
+ msecs_to_jiffies(delay));
+
}
}
-
static void m4_read_mpu9150_data(struct mpu9150_client *mpu9150_client_data,
enum mpu9150_sensor type)
{
sCompassData compassdata;
sAccelData acceldata;
sGyroData gyrodata;
- struct mpu9150_client *dd = mpu9150_client_data;
switch (type) {
case TYPE_GYRO:
@@ -249,18 +231,6 @@ static void m4_read_mpu9150_data(struct mpu9150_client *mpu9150_client_data,
mpu9150_client_data->compass_data.cz = compassdata.z;
mpu9150_client_data->compass_data.ca = compassdata.accuracy;
- /* Check if calibration is complete */
- if ((!(dd->calibration_done)) && (compassdata.accuracy)) {
- dd->calibration_done = 1;
- KDEBUG(M4SH_INFO, "Calibration complete\n");
- /* Stop compass sampling if no app is using the data */
- if (dd->app_override == 0) {
- m4_set_mpu9150_delay(dd,
- -1,
- TYPE_COMPASS);
- KDEBUG(M4SH_INFO, "Init cal done. Turning off compass");
- }
- }
break;
default:
@@ -320,7 +290,9 @@ static void m4compass_work_func(struct work_struct *work)
m4_report_mpu9150_inputevent(dd, TYPE_COMPASS);
rate = dd->samplerate[TYPE_COMPASS];
if (rate > 0)
- m4_queue_delayed_work(dd, rate, TYPE_COMPASS);
+ queue_delayed_work(system_freezable_wq,
+ &(dd->mpu9150_work[TYPE_COMPASS]),
+ msecs_to_jiffies(rate));
mutex_unlock(&(dd->mutex));
}
@@ -407,20 +379,8 @@ static ssize_t m4_mpu9150_write_compass_setdelay(struct device *dev,
mutex_lock(&(misc_mpu9150_data->mutex));
- if (misc_mpu9150_data->calibration_done == 0) {
- /* If calibration is not complete and app tries to
- turn off ignore */
- if (scanresult < 0) {
- misc_mpu9150_data->app_override = 0;
- goto compass_setdelay_exit;
- } else {
- misc_mpu9150_data->app_override = 1;
- }
- }
m4_set_mpu9150_delay(misc_mpu9150_data, scanresult, TYPE_COMPASS);
-compass_setdelay_exit:
-
mutex_unlock(&(misc_mpu9150_data->mutex));
return count;
@@ -611,7 +571,9 @@ static void mpu9150_panic_restore(struct m4sensorhub_data *m4sensorhub,
m4_set_mpu9150_delay(dd, rate, type);
cancel_delayed_work(&(dd->mpu9150_work[type]));
if (rate > 0)
- m4_queue_delayed_work(dd, rate, type);
+ queue_delayed_work(system_freezable_wq,
+ &(dd->mpu9150_work[type]),
+ msecs_to_jiffies(rate));
}
mutex_unlock(&(dd->mutex));
}
@@ -633,9 +595,7 @@ static int mpu9150_driver_init(struct init_calldata *p_arg)
dd);
if (ret < 0)
KDEBUG(M4SH_ERROR, "HR panic callback register failed\n");
- m4_set_mpu9150_delay(dd,
- 40,
- TYPE_COMPASS);
+
mutex_unlock(&(dd->mutex));
return ret;
}
@@ -668,8 +628,6 @@ static int mpu9150_client_probe(struct platform_device *pdev)
mpu9150_client_data->fastest_rate[TYPE_ACCEL] = 40;
mpu9150_client_data->fastest_rate[TYPE_GYRO] = 40;
mpu9150_client_data->fastest_rate[TYPE_COMPASS] = 40;
- mpu9150_client_data->calibration_done = 0;
- mpu9150_client_data->app_override = 0;
mpu9150_client_data->input_dev = input_allocate_device();
if (!mpu9150_client_data->input_dev) {
diff --git a/drivers/misc/m4sensorhub_pedometer.c b/drivers/misc/m4sensorhub_pedometer.c
index cf326454bea..0be14698e1d 100644
--- a/drivers/misc/m4sensorhub_pedometer.c
+++ b/drivers/misc/m4sensorhub_pedometer.c
@@ -40,6 +40,8 @@
#define M4PED_IRQ_ENABLED_BIT 0
#define M4PED_FEATURE_ENABLED_BIT 1
+#define M4PED_USERDATA_SIZE 5
+
struct m4ped_driver_data {
struct platform_device *pdev;
struct m4sensorhub_data *m4;
@@ -47,9 +49,12 @@ struct m4ped_driver_data {
struct m4sensorhub_pedometer_iio_data iiodat;
struct m4sensorhub_pedometer_iio_data base_dat;
- struct delayed_work m4ped_work;
+ struct m4sensorhub_pedometer_iio_data last_dat;
+ struct delayed_work m4ped_work;
+
int16_t samplerate;
int16_t fastest_rate;
+ uint8_t userdata[M4PED_USERDATA_SIZE];
uint16_t status;
};
@@ -57,6 +62,7 @@ static int m4ped_read_report_data(struct iio_dev *iio,
struct m4ped_driver_data *dd)
{
int err = 0, size = 0;
+ struct m4sensorhub_pedometer_iio_data dat;
/*input validations */
if ((iio == NULL) || (dd == NULL)) {
@@ -80,7 +86,7 @@ static int m4ped_read_report_data(struct iio_dev *iio,
size = m4sensorhub_reg_getsize(dd->m4,
M4SH_REG_PEDOMETER_TOTALDISTANCE);
err = m4sensorhub_reg_read(dd->m4, M4SH_REG_PEDOMETER_TOTALDISTANCE,
- (char *)&(dd->iiodat.total_distance));
+ (char *)&(dat.total_distance));
if (err < 0) {
m4ped_err("%s: Failed to read total_distance data.\n",
__func__);
@@ -94,7 +100,7 @@ static int m4ped_read_report_data(struct iio_dev *iio,
size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_PEDOMETER_TOTALSTEPS);
err = m4sensorhub_reg_read(dd->m4, M4SH_REG_PEDOMETER_TOTALSTEPS,
- (char *)&(dd->iiodat.total_steps));
+ (char *)&(dat.total_steps));
if (err < 0) {
m4ped_err("%s: Failed to read total_steps data.\n", __func__);
goto m4ped_read_fail;
@@ -121,7 +127,7 @@ static int m4ped_read_report_data(struct iio_dev *iio,
size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_METS_HEALTHYMINUTES);
err = m4sensorhub_reg_read(dd->m4, M4SH_REG_METS_HEALTHYMINUTES,
- (char *)&(dd->iiodat.healthy_minutes));
+ (char *)&(dat.healthy_minutes));
if (err < 0) {
m4ped_err("%s: Failed to read healthy_minutes data.\n",
__func__);
@@ -135,7 +141,7 @@ static int m4ped_read_report_data(struct iio_dev *iio,
size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_METS_CALORIES);
err = m4sensorhub_reg_read(dd->m4, M4SH_REG_METS_CALORIES,
- (char *)&(dd->iiodat.calories));
+ (char *)&(dat.calories));
if (err < 0) {
m4ped_err("%s: Failed to read calories data.\n", __func__);
goto m4ped_read_fail;
@@ -146,12 +152,63 @@ static int m4ped_read_report_data(struct iio_dev *iio,
goto m4ped_read_fail;
}
+ size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_METS_CALORIES_NO_RMR);
+ err = m4sensorhub_reg_read(dd->m4, M4SH_REG_METS_CALORIES_NO_RMR,
+ (char *)&(dat.calories_normr));
+ if (err < 0) {
+ m4ped_err("%s: Failed to read calories_normr data.\n",
+ __func__);
+ goto m4ped_read_fail;
+ } else if (err != size) {
+ m4ped_err("%s: Read %d bytes instead of %d for %s.\n",
+ __func__, err, size, "calories_normr");
+ err = -EBADE;
+ goto m4ped_read_fail;
+ }
+
dd->iiodat.timestamp = iio_get_time_ns();
- dd->iiodat.total_distance += dd->base_dat.total_distance;
- dd->iiodat.total_steps += dd->base_dat.total_steps;
- dd->iiodat.healthy_minutes += dd->base_dat.healthy_minutes;
- dd->iiodat.calories += dd->base_dat.calories;
+ /* Save data if these values decrease (they monotonically increase) */
+ if ((dat.total_distance < dd->last_dat.total_distance) ||
+ (dat.total_steps < dd->last_dat.total_steps) ||
+ (dat.healthy_minutes < dd->last_dat.healthy_minutes) ||
+ (dat.calories < dd->last_dat.calories) ||
+ (dat.calories_normr < dd->last_dat.calories_normr)) {
+ m4ped_err("%s: Error: Current = %u %u %u %u %u "
+ "Last = %u %u %u %u %u, Base = %u %u %u %u %u\n",
+ __func__, dat.total_distance,
+ dat.total_steps, dat.healthy_minutes,
+ dat.calories, dat.calories_normr,
+ dd->last_dat.total_distance,
+ dd->last_dat.total_steps,
+ dd->last_dat.healthy_minutes, dd->last_dat.calories,
+ dd->last_dat.calories_normr,
+ dd->base_dat.total_distance,
+ dd->base_dat.total_steps,
+ dd->base_dat.healthy_minutes, dd->base_dat.calories,
+ dd->base_dat.calories_normr);
+ m4ped_err("%s: iio = %u %u %u %u %u\n", __func__,
+ dd->iiodat.total_distance,
+ dd->iiodat.total_steps,
+ dd->iiodat.healthy_minutes, dd->iiodat.calories,
+ dd->iiodat.calories_normr);
+ goto m4ped_read_fail;
+ }
+
+ dd->last_dat.total_distance = dat.total_distance;
+ dd->last_dat.total_steps = dat.total_steps;
+ dd->last_dat.healthy_minutes = dat.healthy_minutes;
+ dd->last_dat.calories = dat.calories;
+ dd->last_dat.calories_normr = dat.calories_normr;
+
+ dd->iiodat.total_distance = dat.total_distance +
+ dd->base_dat.total_distance;
+ dd->iiodat.total_steps = dat.total_steps + dd->base_dat.total_steps;
+ dd->iiodat.healthy_minutes = dat.healthy_minutes +
+ dd->base_dat.healthy_minutes;
+ dd->iiodat.calories = dat.calories + dd->base_dat.calories;
+ dd->iiodat.calories_normr = dat.calories_normr +
+ dd->base_dat.calories_normr;
iio_push_to_buffers(iio, (unsigned char *)&(dd->iiodat));
@@ -181,6 +238,42 @@ static void m4ped_work_func(struct work_struct *work)
return;
}
+static int m4ped_write_userdata(struct m4ped_driver_data *dd)
+{
+ int err;
+
+ err = m4sensorhub_reg_write(dd->m4, M4SH_REG_USERSETTINGS_USERAGE,
+ &(dd->userdata[0]), m4sh_no_mask);
+ if (err < 0) {
+ m4ped_err("%s: Failed to write age.\n", __func__);
+ goto m4ped_write_userdata_fail;
+ }
+
+ err = m4sensorhub_reg_write(dd->m4, M4SH_REG_USERSETTINGS_USERGENDER,
+ &(dd->userdata[1]), m4sh_no_mask);
+ if (err < 0) {
+ m4ped_err("%s: Failed to write gender.\n", __func__);
+ goto m4ped_write_userdata_fail;
+ }
+
+ err = m4sensorhub_reg_write(dd->m4, M4SH_REG_USERSETTINGS_USERHEIGHT,
+ &(dd->userdata[2]), m4sh_no_mask);
+ if (err < 0) {
+ m4ped_err("%s: Failed to write height.\n", __func__);
+ goto m4ped_write_userdata_fail;
+ }
+
+ err = m4sensorhub_reg_write(dd->m4, M4SH_REG_USERSETTINGS_USERWEIGHT,
+ &(dd->userdata[3]), m4sh_no_mask);
+ if (err < 0) {
+ m4ped_err("%s: Failed to write weight.\n", __func__);
+ goto m4ped_write_userdata_fail;
+ }
+
+m4ped_write_userdata_fail:
+ return err;
+}
+
static int m4ped_set_samplerate(struct iio_dev *iio, int16_t rate)
{
int err = 0;
@@ -278,13 +371,14 @@ static ssize_t m4ped_iiodata_show(struct device *dev,
mutex_lock(&(dd->mutex));
size = snprintf(buf, PAGE_SIZE,
- "%s%hhu\n%s%u\n%s%u\n%s%hu\n%s%u\n%s%u\n",
+ "%s%hhu\n%s%u\n%s%u\n%s%hu\n%s%u\n%s%u\n%s%u\n",
"ped_activity: ", dd->iiodat.ped_activity,
"total_distance: ", dd->iiodat.total_distance,
"total_steps: ", dd->iiodat.total_steps,
"current_speed: ", dd->iiodat.current_speed,
"healthy_minutes: ", dd->iiodat.healthy_minutes,
- "calories: ", dd->iiodat.calories);
+ "calories: ", dd->iiodat.calories,
+ "calories_normr: ", dd->iiodat.calories_normr);
mutex_unlock(&(dd->mutex));
return size;
}
@@ -298,11 +392,11 @@ static ssize_t m4ped_userdata_show(struct device *dev,
struct iio_dev *iio = platform_get_drvdata(pdev);
struct m4ped_driver_data *dd = iio_priv(iio);
ssize_t size = 0;
- uint8_t data[5] = {0x00, 0x00, 0x00, 0x00, 0x00};
+ uint8_t data[M4PED_USERDATA_SIZE] = {0x00};
mutex_lock(&(dd->mutex));
- err = m4sensorhub_reg_read_n(dd->m4, M4SH_REG_USERSETTINGS_SCREENSTATUS,
+ err = m4sensorhub_reg_read_n(dd->m4, M4SH_REG_USERSETTINGS_USERAGE,
(char *)&(data[0]), ARRAY_SIZE(data));
if (err < 0) {
m4ped_err("%s: Failed to read user data.\n", __func__);
@@ -315,11 +409,11 @@ static ssize_t m4ped_userdata_show(struct device *dev,
}
size = snprintf(buf, PAGE_SIZE,
- "%s%s\n%s%hhu\n%s%hhu\n%s%hhu\n",
- "Gender (M/F): ", data[2] ? "M" : "F",
- "Age (yrs): ", data[1],
- "Height (cm): ", data[3],
- "Weight (kg): ", data[4]);
+ "%s%s\n%s%hhu\n%s%hhu\n%s%hu\n",
+ "Gender (M/F): ", data[1] ? "M" : "F",
+ "Age (yrs): ", data[0],
+ "Height (cm): ", data[2],
+ "Weight (kg): ", data[3] | (data[4] << 8));
m4ped_userdata_show_fail:
mutex_unlock(&(dd->mutex));
@@ -334,6 +428,7 @@ m4ped_userdata_show_fail:
* Example:
* Female, 22, 168cm, 49kg
* 0x00,0x16,0xA7,0x31\n
+ * echo 0x00,0x16,0xA7,0x31 > userdata
*/
static ssize_t m4ped_userdata_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
@@ -344,7 +439,7 @@ static ssize_t m4ped_userdata_store(struct device *dev,
struct m4ped_driver_data *dd = iio_priv(iio);
unsigned int value = 0;
unsigned char convbuf[5] = {0x00, 0x00, 0x00, 0x00, 0x00};
- unsigned char outbuf[4] = {0x00, 0x00, 0x00, 0x00};
+ unsigned char outbuf[M4PED_USERDATA_SIZE] = {0x00};
int i = 0;
mutex_lock(&(dd->mutex));
@@ -373,31 +468,16 @@ static ssize_t m4ped_userdata_store(struct device *dev,
outbuf[i] = (unsigned char) value;
}
- err = m4sensorhub_reg_write(dd->m4, M4SH_REG_USERSETTINGS_USERAGE,
- &(outbuf[1]), m4sh_no_mask);
- if (err < 0) {
- m4ped_err("%s: Failed to write user data.\n", __func__);
- goto m4ped_userdata_store_fail;
- }
+ for (i = 0; i < M4PED_USERDATA_SIZE; i++)
+ dd->userdata[i] = outbuf[i];
- err = m4sensorhub_reg_write(dd->m4, M4SH_REG_USERSETTINGS_USERGENDER,
- &(outbuf[0]), m4sh_no_mask);
- if (err < 0) {
- m4ped_err("%s: Failed to write user data.\n", __func__);
- goto m4ped_userdata_store_fail;
- }
-
- err = m4sensorhub_reg_write(dd->m4, M4SH_REG_USERSETTINGS_USERHEIGHT,
- &(outbuf[2]), m4sh_no_mask);
- if (err < 0) {
- m4ped_err("%s: Failed to write user data.\n", __func__);
- goto m4ped_userdata_store_fail;
- }
+ dd->userdata[0] = outbuf[1]; /* Age */
+ dd->userdata[1] = outbuf[0]; /* Gender */
- err = m4sensorhub_reg_write_n(dd->m4, M4SH_REG_USERSETTINGS_USERWEIGHT,
- &(outbuf[3]), m4sh_no_mask, 1);
+ err = m4ped_write_userdata(dd);
if (err < 0) {
- m4ped_err("%s: Failed to write user data.\n", __func__);
+ m4ped_err("%s: Failed to write user data (%d).\n",
+ __func__, err);
goto m4ped_userdata_store_fail;
}
@@ -606,13 +686,12 @@ static void m4ped_panic_restore(struct m4sensorhub_data *m4sensorhub,
mutex_lock(&(dd->mutex));
- dd->base_dat.total_distance = dd->iiodat.total_distance;
- dd->base_dat.total_steps = dd->iiodat.total_steps;
- dd->base_dat.healthy_minutes = dd->iiodat.healthy_minutes;
- dd->base_dat.calories = dd->iiodat.calories;
- m4ped_err("%s: Pedometer bases after panic = %d %d %d %d", __func__,
- dd->base_dat.total_distance, dd->base_dat.total_steps,
- dd->base_dat.healthy_minutes, dd->base_dat.calories);
+ err = m4ped_write_userdata(dd);
+ if (err < 0) {
+ m4ped_err("%s: Failed to write user data (%d).\n",
+ __func__, err);
+ goto m4ped_panic_restore_fail;
+ }
if (!(dd->status & (1 << M4PED_FEATURE_ENABLED_BIT))) {
err = m4sensorhub_reg_write(dd->m4, M4SH_REG_PEDOMETER_ENABLE,
@@ -631,6 +710,19 @@ static void m4ped_panic_restore(struct m4sensorhub_data *m4sensorhub,
goto m4ped_panic_restore_fail;
}
}
+ /* Update base and reset last */
+ dd->base_dat.total_distance = dd->iiodat.total_distance;
+ dd->base_dat.total_steps = dd->iiodat.total_steps;
+ dd->base_dat.healthy_minutes = dd->iiodat.healthy_minutes;
+ dd->base_dat.calories = dd->iiodat.calories;
+ dd->base_dat.calories_normr = dd->iiodat.calories_normr;
+
+ dd->last_dat.total_distance = 0;
+ dd->last_dat.total_steps = 0;
+ dd->last_dat.healthy_minutes = 0;
+ dd->last_dat.calories = 0;
+ dd->last_dat.calories_normr = 0;
+
cancel_delayed_work(&(dd->m4ped_work));
if (dd->samplerate > 0)
queue_delayed_work(system_freezable_wq, &(dd->m4ped_work),
@@ -692,6 +784,12 @@ static int m4ped_probe(struct platform_device *pdev)
dd->fastest_rate = 1000; /* in milli secs */
dd->status = dd->status | (1 << M4PED_FEATURE_ENABLED_BIT);
+ dd->userdata[0] = 0x23; /* Age (35) */
+ dd->userdata[1] = 0x01; /* Gender (Male) */
+ dd->userdata[2] = 0xB2; /* Height (178cm) */
+ dd->userdata[3] = 0x5B; /* Weight (91kg) */
+ dd->userdata[4] = 0x00; /* Weight */
+
err = m4ped_create_iiodev(iio); /* iio and dd are freed on fail */
if (err < 0) {
m4ped_err("%s: Failed to create IIO device.\n", __func__);