summaryrefslogtreecommitdiff
path: root/drivers/misc/m4sensorhub_pedometer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/m4sensorhub_pedometer.c')
-rw-r--r--drivers/misc/m4sensorhub_pedometer.c194
1 files changed, 146 insertions, 48 deletions
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__);