diff options
Diffstat (limited to 'drivers/misc')
| -rw-r--r-- | drivers/misc/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/misc/Makefile | 1 | ||||
| -rw-r--r-- | drivers/misc/als_notify.c | 50 | ||||
| -rw-r--r-- | drivers/misc/c55_ctrl.c | 16 | ||||
| -rw-r--r-- | drivers/misc/m4sensorhub_als.c | 118 | ||||
| -rw-r--r-- | drivers/misc/m4sensorhub_fusion.c | 84 | ||||
| -rw-r--r-- | drivers/misc/m4sensorhub_gesture.c | 8 | ||||
| -rw-r--r-- | drivers/misc/m4sensorhub_mpu9150.c | 64 | ||||
| -rw-r--r-- | drivers/misc/m4sensorhub_pedometer.c | 194 |
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__); |