diff options
| author | Eric Tashakkor <w36098@motorola.com> | 2014-05-06 10:23:34 -0500 |
|---|---|---|
| committer | ERIC TASHAKKOR <w36098@motorola.com> | 2014-05-07 15:34:05 +0000 |
| commit | cbe7c918fe51e44e009b2839716c8ca9d5a1fefd (patch) | |
| tree | f8bbcd7fea39310d0ce7dd5dbac7f018f95b2bd9 /drivers/misc/m4sensorhub_pedometer.c | |
| parent | 4f75bd140f9838c09ac62c1cfded9df37327b022 (diff) | |
| download | olio-linux-3.10-cbe7c918fe51e44e009b2839716c8ca9d5a1fefd.tar.xz olio-linux-3.10-cbe7c918fe51e44e009b2839716c8ca9d5a1fefd.zip | |
IKXCLOCK-1067 Need User Profile to improve pedometer/calorie accuracy (Kernel changes)
Added "userdata" sysfs interface to handle writing/reading M4 user data.
Change-Id: I50c66a96ad4a1f8c060fe886dc20a3dce37a47eb
Signed-off-by: Eric Tashakkor <w36098@motorola.com>
Diffstat (limited to 'drivers/misc/m4sensorhub_pedometer.c')
| -rw-r--r-- | drivers/misc/m4sensorhub_pedometer.c | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/drivers/misc/m4sensorhub_pedometer.c b/drivers/misc/m4sensorhub_pedometer.c index ce932cc4df9..68b2299e1ac 100644 --- a/drivers/misc/m4sensorhub_pedometer.c +++ b/drivers/misc/m4sensorhub_pedometer.c @@ -313,9 +313,138 @@ static ssize_t m4ped_iiodata_show(struct device *dev, } static IIO_DEVICE_ATTR(iiodata, S_IRUGO, m4ped_iiodata_show, NULL, 0); +static ssize_t m4ped_userdata_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err = 0; + struct platform_device *pdev = to_platform_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}; + + mutex_lock(&(dd->mutex)); + + err = m4sensorhub_reg_read_n(dd->m4, M4SH_REG_USERSETTINGS_VERSION, + (char *)&(data[0]), ARRAY_SIZE(data)); + if (err < 0) { + m4ped_err("%s: Failed to read user data.\n", __func__); + goto m4ped_userdata_show_fail; + } else if (err < ARRAY_SIZE(data)) { + m4ped_err("%s: Read %d bytes instead of %d.\n", + __func__, err, size); + err = -EBADE; + goto m4ped_userdata_show_fail; + } + + if (data[0] > 0) { + m4ped_err("%s: User settings version is too new (0x%02X)\n", + __func__, data[0]); + err = -EINVAL; + goto m4ped_userdata_show_fail; + } + + 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]); + +m4ped_userdata_show_fail: + mutex_unlock(&(dd->mutex)); + + if (err < 0) + size = snprintf(buf, PAGE_SIZE, "Read failed (check dmesg)\n"); + + return size; +} +/* + * Expected input is Gender, Age, Height, Weight + * Example: + * Female, 22, 168cm, 49kg + * 0x00,0x16,0xA7,0x31\n + */ +static ssize_t m4ped_userdata_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int err = 0; + struct platform_device *pdev = to_platform_device(dev); + struct iio_dev *iio = platform_get_drvdata(pdev); + 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}; + int i = 0; + + mutex_lock(&(dd->mutex)); + + /* Size includes a terminating '\n' but not the terminating null */ + if (size != 20) { + m4ped_err("%s: Invalid data format. %s\n", + __func__, "Use \"0xHH,0xHH,0xHH,0xHH\\n\" instead."); + err = -EINVAL; + goto m4ped_userdata_store_fail; + } + + for (i = 0; i < 4; i++) { + memcpy(convbuf, &(buf[i*5]), 4); + err = kstrtouint(convbuf, 16, &value); + if (err < 0) { + m4ped_err("%s: Argument %d conversion failed.\n", + __func__, i); + goto m4ped_userdata_store_fail; + } else if (value > 255) { + m4ped_err("%s: Value 0x%08X is too large.\n", + __func__, value); + err = -EOVERFLOW; + goto m4ped_userdata_store_fail; + } + 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; + } + + 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; + } + + err = m4sensorhub_reg_write_n(dd->m4, M4SH_REG_USERSETTINGS_USERWEIGHT, + &(outbuf[3]), m4sh_no_mask, 1); + if (err < 0) { + m4ped_err("%s: Failed to write user data.\n", __func__); + goto m4ped_userdata_store_fail; + } + + err = size; + +m4ped_userdata_store_fail: + mutex_unlock(&(dd->mutex)); + + return (ssize_t) err; +} +static IIO_DEVICE_ATTR(userdata, S_IRUSR | S_IWUSR, + m4ped_userdata_show, m4ped_userdata_store, 0); + static struct attribute *m4ped_iio_attributes[] = { &iio_dev_attr_setrate.dev_attr.attr, &iio_dev_attr_iiodata.dev_attr.attr, + &iio_dev_attr_userdata.dev_attr.attr, NULL, }; |