summaryrefslogtreecommitdiff
path: root/drivers/misc/m4sensorhub_pedometer.c
diff options
context:
space:
mode:
authorEric Tashakkor <w36098@motorola.com>2014-05-06 10:23:34 -0500
committerERIC TASHAKKOR <w36098@motorola.com>2014-05-07 15:34:05 +0000
commitcbe7c918fe51e44e009b2839716c8ca9d5a1fefd (patch)
treef8bbcd7fea39310d0ce7dd5dbac7f018f95b2bd9 /drivers/misc/m4sensorhub_pedometer.c
parent4f75bd140f9838c09ac62c1cfded9df37327b022 (diff)
downloadolio-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.c129
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,
};