diff options
Diffstat (limited to 'drivers/misc/m4sensorhub_pedometer.c')
| -rw-r--r-- | drivers/misc/m4sensorhub_pedometer.c | 194 |
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__); |