[PATCH 0/4] Accelerometer enhancements

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

[PATCH 0/4] Accelerometer enhancements

NeilBrown
I've been meaning to post these for some months now... finally I
remembered to :-)

The following patch series makes some useful changes to the interface
to the accelerometers.

The important changes are:
  'sample_rate' can now be any value, not just 100 or 400.
  For smaller values, a timer is used to deliver samples at
  the required rate.  This way userspace doesn't have to be
  reading constantly to still get useful data.

  'threshold' is made more reliable and useful.  Any change that
  exceeds the threshold is guaranteed to be reported as a change that
  appear to be larger than the threshold.

  Using these two together, you can arrange for regular updates
  (e.g. every second or so) but still get more frequent updates if the
  orientation of the device is changing quickly.

The only change that is not back-compatible is the last, and is
independent of the others.
It changes the 'full_scale' attribute to be more flexible in the
values it accepts, and to report the current value in a more useful
way.  Rather than "2.3" or "9.2", it reports
  2 [8]
or
  [2] 8

Thus listing valid values and showing which one is currently
active.

These patches are against andy-tracking.

I have the beginnings of patches to report 'tap' and maybe even
'double-tap' events too but they aren't quite there yet.

Thanks for any attention that these might get.

NeilBrown

---

NeilBrown (4):
      lis302dl: improve 'full_scale' attribute
      lis302d: make 'threshold' detection more reliable.
      lis302dl: tiny optimisation in __reg_set_bit_mask
      lis302dl:  allow accelerometer sample_rate to be other values including fractions.


 drivers/input/misc/lis302dl.c |  263 +++++++++++++++++++++++++++++++++++------
 include/linux/lis302dl.h      |   15 ++
 2 files changed, 241 insertions(+), 37 deletions(-)

--
Signature


Reply | Threaded
Open this post in threaded view
|

[PATCH 3/4] lis302d: make 'threshold' detection more reliable.

NeilBrown
Currently setting the threshold doesn't guarantee that every change
reported will be for that size, or that every change of that size will
be reported.

If a change is very fast, it can trigger the threshold detection
circuits, but might not produce two consecutive samples which differ
by the threshold amount.  Presumably this is because the trigger
circuit is more sensitive than the sampling circuit.
So if the threshold detection reports a crossing, force the value
reported on that access to differ from the previous reading by at
least the threshold amount.

If a change is very slow (seconds) it can go undetected by the
threshold circuit due to the use of a high-pass filter.
So make sure we look at samples at least every 500ms and if a large
change is measured that the threshold detector didn't report, report
it anyway.

This will ensure that the most recent value reported differs from the
currently correct value by no more than the threshold.


Signed-off-by: NeilBrown <[hidden email]>
---

 drivers/input/misc/lis302dl.c |   70 +++++++++++++++++++++++++++++++++++------
 1 files changed, 60 insertions(+), 10 deletions(-)

diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
index 52eaccd..f9dfc24 100644
--- a/drivers/input/misc/lis302dl.c
+++ b/drivers/input/misc/lis302dl.c
@@ -243,7 +243,10 @@ static void __enable_data_collection(struct lis302dl_info *lis)
  __lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_FF_WU_1);
  __lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_FF_WU_1);
 
- if (lis->sample_time)
+ if (lis->threshold && (lis->sample_time > HZ/2 ||
+       lis->sample_time == 0))
+ mod_timer(&lis->timer, jiffies + HZ/2);
+ else if (lis->sample_time)
  mod_timer(&lis->timer, jiffies + lis->sample_time);
  }
 }
@@ -268,6 +271,18 @@ static void _report_btn_double(struct input_dev *inp, int btn)
 }
 #endif
 
+static int force_diff(int val, int old, int diff)
+{
+ /* We want 'val' to differ from 'old' by at least 'diff'
+ * If it doesn't nudge it a bit in the right direction.
+ */
+ int delta = val - old;
+ if (delta < 0 && delta > -diff)
+ val = old - diff;
+ else if (delta < diff)
+ val = old + diff;
+ return val;
+}
 
 static void lis302dl_bitbang_read_sample(struct lis302dl_info *lis)
 {
@@ -279,6 +294,7 @@ static void lis302dl_bitbang_read_sample(struct lis302dl_info *lis)
  struct spi_transfer t;
  u8 wakeup;
  int need_sample = 0;
+ int x, y, z;
 
  spi_message_init(&msg);
  memset(&t, 0, sizeof t);
@@ -329,22 +345,56 @@ static void lis302dl_bitbang_read_sample(struct lis302dl_info *lis)
  lis->last_sample = jiffies;
  }
 
- if (lis->threshold && (wakeup & LIS302DL_FFWUCFG_AOI))
+ x = mg_per_sample * (s8)read[LIS302DL_REG_OUT_X - LIS302DL_REG_STATUS];
+ y = mg_per_sample * (s8)read[LIS302DL_REG_OUT_Y - LIS302DL_REG_STATUS];
+ z = mg_per_sample * (s8)read[LIS302DL_REG_OUT_Z - LIS302DL_REG_STATUS];
+
+ if (lis->threshold && (wakeup & LIS302DL_FFWUCFG_AOI)) {
+
  need_sample = 1;
 
+ /* Make sure the reported sample does differ from the previous
+ * one by the given threshold */
+ if (wakeup & LIS302DL_FFWUCFG_XHIE)
+ x = force_diff(x, lis->input_dev->abs[ABS_X],
+       lis->threshold);
+ if (wakeup & LIS302DL_FFWUCFG_YHIE)
+ y = force_diff(y, lis->input_dev->abs[ABS_Y],
+       lis->threshold);
+ if (wakeup & LIS302DL_FFWUCFG_ZHIE)
+ z = force_diff(z, lis->input_dev->abs[ABS_Z],
+       lis->threshold);
+
+ /* Clear the HP filter "starting point" */
+ __reg_read(lis, LIS302DL_REG_HP_FILTER_RESET);
+ } else if (abs(x - lis->input_dev->abs[ABS_X]) > lis->threshold ||
+   abs(y - lis->input_dev->abs[ABS_Y]) > lis->threshold ||
+   abs(z - lis->input_dev->abs[ABS_Z]) > lis->threshold) {
+ /* A difference larger than threshold.
+ * FIXME check time delay against 'duration'
+ */
+ need_sample = 1;
+ }
+
  if (need_sample) {
- input_report_abs(lis->input_dev, ABS_X, mg_per_sample *
-    (s8)read[LIS302DL_REG_OUT_X - LIS302DL_REG_STATUS]);
- input_report_abs(lis->input_dev, ABS_Y, mg_per_sample *
-    (s8)read[LIS302DL_REG_OUT_Y - LIS302DL_REG_STATUS]);
- input_report_abs(lis->input_dev, ABS_Z, mg_per_sample *
-    (s8)read[LIS302DL_REG_OUT_Z - LIS302DL_REG_STATUS]);
+ input_report_abs(lis->input_dev, ABS_X, x);
+ input_report_abs(lis->input_dev, ABS_Y, y);
+ input_report_abs(lis->input_dev, ABS_Z, z);
 
  input_sync(lis->input_dev);
  }
 
- if (lis->use_jiffies && lis->sample_time)
- mod_timer(&lis->timer, jiffies + lis->sample_time);
+ if (lis->use_jiffies) {
+ /* If threshold is set, then always check at 2Hz as
+ * the high-pass filter loses changes that are slower
+ * than that.
+ */
+ if (lis->threshold && (lis->sample_time > HZ/2 ||
+       lis->sample_time == 0))
+ mod_timer(&lis->timer, jiffies + HZ/2);
+ else if (lis->sample_time)
+ mod_timer(&lis->timer, jiffies + lis->sample_time);
+ }
 }
 
 static irqreturn_t lis302dl_interrupt(int irq, void *_lis)



Reply | Threaded
Open this post in threaded view
|

[PATCH 2/4] lis302dl: tiny optimisation in __reg_set_bit_mask

NeilBrown
In reply to this post by NeilBrown
Don't write out when there is nothing to change.

Signed-off-by: NeilBrown <[hidden email]>
---

 drivers/input/misc/lis302dl.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
index 894f928..52eaccd 100644
--- a/drivers/input/misc/lis302dl.c
+++ b/drivers/input/misc/lis302dl.c
@@ -96,6 +96,8 @@ static void __reg_set_bit_mask(struct lis302dl_info *lis, u8 reg, u8 mask,
  val &= mask;
 
  tmp = __reg_read(lis, reg);
+ if ((tmp & mask) == val)
+ return;
  tmp &= ~mask;
  tmp |= val;
  __reg_write(lis, reg, tmp);



Reply | Threaded
Open this post in threaded view
|

[PATCH 1/4] lis302dl: allow accelerometer sample_rate to be other values including fractions.

NeilBrown
In reply to this post by NeilBrown
This patch enhances the 'sample_rate' sysfs attribute so that it can
take on a wide range of "HZ" values including fractions.

If the HZ rate is 50 or larger, the lis302dl still generates
interrupts on each sample, but possibly not all of them are reported
to user-space.
If the HZ rate is below 50, the data-ready interrupt is disabled and
a timer is used to read the latest sample at the required rate.

The device is only set to take samples at the high 400HZ rate if
sample_rate exceeds 100. (i.e. if it is 200 or 400).

The actual sample rates that are supported at 50 or above are
50, 100, 200, 400.

Below 50, sample rates that are a submultiple of the kernel's internal
HZ rates are supported, including fractions down to 0.0001 or there
abouts.

To maintain backwards compatibility, if the threshold is set, the
sample_rate is automatically set to 0, so samples are only reported
when there are threshold crossing.  If the sample_rate is set after
the threshold, then samples are reported at that rate, or when
threshold crossings happen.

Signed-off-by: NeilBrown <[hidden email]>
---

 drivers/input/misc/lis302dl.c |  187 +++++++++++++++++++++++++++++++++++------
 include/linux/lis302dl.h      |   15 +++
 2 files changed, 173 insertions(+), 29 deletions(-)

diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
index f31e548..894f928 100644
--- a/drivers/input/misc/lis302dl.c
+++ b/drivers/input/misc/lis302dl.c
@@ -41,6 +41,7 @@
 #include <linux/interrupt.h>
 #include <linux/sysfs.h>
 #include <linux/spi/spi.h>
+#include <linux/ctype.h>
 
 #include <linux/lis302dl.h>
 
@@ -199,13 +200,21 @@ static void __enable_data_collection(struct lis302dl_info *lis)
  /* make sure we're powered up and generate data ready */
  __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, ctrl1);
 
- /* If the threshold is zero, let the device generated an interrupt
- * on each datum */
- if (lis->threshold == 0) {
- __reg_write(lis, LIS302DL_REG_CTRL2, 0);
- __lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_DATA_READY);
- __lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_DATA_READY);
+ /* set an appropriate sample rate */
+ if (lis->use_jiffies == 0 && lis->sample_time < 4) {
+ /* high-rate samples - 400Hz */
+ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
+   LIS302DL_CTRL1_DR);
+ lis->flags |= LIS302DL_F_DR;
  } else {
+ /* low-rate samples - 100Hz */
+ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
+   0);
+ lis->flags &= ~LIS302DL_F_DR;
+ }
+
+ if (lis->threshold) {
+ /* Enable WU detection, with high-pass filter engaged. */
  __reg_write(lis, LIS302DL_REG_CTRL2,
  LIS302DL_CTRL2_HPFF1);
  __reg_write(lis, LIS302DL_REG_FF_WU_THS_1,
@@ -218,8 +227,22 @@ static void __enable_data_collection(struct lis302dl_info *lis)
  __reg_write(lis, LIS302DL_REG_FF_WU_CFG_1,
  LIS302DL_FFWUCFG_XHIE | LIS302DL_FFWUCFG_YHIE |
  LIS302DL_FFWUCFG_ZHIE | LIS302DL_FFWUCFG_LIR);
- __lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_FF_WU_12);
- __lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_FF_WU_12);
+ } else {
+ /* Disable WU */
+ __reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, 0);
+ }
+
+ if (!lis->use_jiffies) {
+ /* Interrupt on data-ready */
+ __lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_DATA_READY);
+ __lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_DATA_READY);
+ } else {
+ /* Interrupt on WU1, which may well be disabled */
+ __lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_FF_WU_1);
+ __lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_FF_WU_1);
+
+ if (lis->sample_time)
+ mod_timer(&lis->timer, jiffies + lis->sample_time);
  }
 }
 
@@ -252,6 +275,8 @@ static void lis302dl_bitbang_read_sample(struct lis302dl_info *lis)
  int mg_per_sample = __threshold_to_mg(lis, 1);
  struct spi_message msg;
  struct spi_transfer t;
+ u8 wakeup;
+ int need_sample = 0;
 
  spi_message_init(&msg);
  memset(&t, 0, sizeof t);
@@ -283,8 +308,29 @@ static void lis302dl_bitbang_read_sample(struct lis302dl_info *lis)
        LIS302DL_STATUS_ZOR))
  lis->overruns++;
 
- /* we have a valid sample set? */
- if (read[0] & LIS302DL_STATUS_XYZDA) {
+ wakeup = __reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
+
+ if (!(read[0] & LIS302DL_STATUS_XYZDA))
+ return;
+
+ if (lis->use_jiffies == 0 && (read[0] & LIS302DL_STATUS_XYZDA)) {
+ if (lis->flags & LIS302DL_F_DR)
+ lis->last_sample++;
+ else
+ lis->last_sample += 4;
+ if (lis->last_sample >= lis->sample_time)
+ need_sample = 1;
+ }
+ if (lis->use_jiffies && lis->sample_time &&
+    time_before_eq(lis->last_sample + lis->sample_time, jiffies)) {
+ need_sample = 1;
+ lis->last_sample = jiffies;
+ }
+
+ if (lis->threshold && (wakeup & LIS302DL_FFWUCFG_AOI))
+ need_sample = 1;
+
+ if (need_sample) {
  input_report_abs(lis->input_dev, ABS_X, mg_per_sample *
     (s8)read[LIS302DL_REG_OUT_X - LIS302DL_REG_STATUS]);
  input_report_abs(lis->input_dev, ABS_Y, mg_per_sample *
@@ -295,9 +341,8 @@ static void lis302dl_bitbang_read_sample(struct lis302dl_info *lis)
  input_sync(lis->input_dev);
  }
 
- if (lis->threshold)
- /* acknowledge the wakeup source */
- __reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
+ if (lis->use_jiffies && lis->sample_time)
+ mod_timer(&lis->timer, jiffies + lis->sample_time);
 }
 
 static irqreturn_t lis302dl_interrupt(int irq, void *_lis)
@@ -308,6 +353,12 @@ static irqreturn_t lis302dl_interrupt(int irq, void *_lis)
  return IRQ_HANDLED;
 }
 
+static void lis302dl_timer_read_sample(unsigned long data)
+{
+ struct lis302dl_info *lis = (struct lis302dl_info *)data;
+ lis302dl_bitbang_read_sample(lis);
+}
+
 /* sysfs */
 
 static ssize_t show_overruns(struct device *dev, struct device_attribute *attr,
@@ -324,14 +375,25 @@ static ssize_t show_rate(struct device *dev, struct device_attribute *attr,
  char *buf)
 {
  struct lis302dl_info *lis = dev_get_drvdata(dev);
- u8 ctrl1;
- unsigned long flags;
-
- local_irq_save(flags);
- ctrl1 = __reg_read(lis, LIS302DL_REG_CTRL1);
- local_irq_restore(flags);
+ char *e;
+ int rate;
 
- return sprintf(buf, "%d\n", ctrl1 & LIS302DL_CTRL1_DR ? 400 : 100);
+ if (lis->sample_time == 0)
+ rate = 0;
+ else if (lis->use_jiffies)
+ rate = HZ*10000 / lis->sample_time;
+ else
+ rate = 4000000 / lis->sample_time;
+ sprintf(buf, "%u.%04u", rate/10000, rate%10000);
+ /* remove trailing zeros and possibly a '.' */
+ e = buf + strlen(buf);
+ while (e[-1] == '0')
+ *--e = 0;
+ if (e[-1] == '.')
+ *--e = 0;
+ *e++ = '\n';
+ *e++ = 0;
+ return strlen(buf);
 }
 
 static ssize_t set_rate(struct device *dev, struct device_attribute *attr,
@@ -339,18 +401,70 @@ static ssize_t set_rate(struct device *dev, struct device_attribute *attr,
 {
  struct lis302dl_info *lis = dev_get_drvdata(dev);
  unsigned long flags;
+ char nbuf[30];
+ int i;
+ int dot = 0;
+ unsigned long hz;
+ int scale = 1;
+
+ /* remove a period, and count digits after it */
+ if (count >= sizeof(nbuf))
+ return -EINVAL;
+ strlcpy(nbuf, buf, sizeof(nbuf));
+ for (i = 0; i < count; i++) {
+ if (dot) {
+ if (isdigit(nbuf[i])) {
+ nbuf[i-1] = nbuf[i];
+ scale *= 10;
+ } else
+ break;
+ nbuf[i] = 0;
+ } else if (nbuf[i] == '.') {
+ dot = 1;
+ nbuf[i] = 0;
+ } else if (!isdigit(nbuf[i]))
+ break;
+ }
+ if (i < count && nbuf[i] != '\n')
+ return -EINVAL;
+ nbuf[i] = 0;
+ if (strict_strtoul(nbuf, 10, &hz) < 0)
+ return -EINVAL;
+ if (hz) {
+ while (scale > 10000) {
+ hz /= 10;
+ scale /= 10;
+ }
+ while (scale < 10000) {
+ hz *= 10;
+ scale *= 10;
+ }
+ if (hz == 0)
+ hz = 1;
+ }
+ /* hz is now scaled so 10000 is 1Hz */
+ if (hz == 0) {
+ lis->use_jiffies = 1;
+ lis->sample_time = 0;
+ } else if (hz < 500000) {
+ /* below 50Hz, use jiffies */
+ lis->use_jiffies = 1;
+ lis->sample_time = (HZ * 10000 + hz/2) / hz;
+ } else {
+ /* Use interrupts */
+ lis->use_jiffies = 0;
+ lis->sample_time = (400 * 10000 + hz/2) / hz;
+ }
+ if (lis->use_jiffies)
+ lis->last_sample = jiffies - lis->sample_time;
+ else
+ lis->last_sample = 0;
 
  local_irq_save(flags);
 
- if (!strcmp(buf, "400\n")) {
- __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
- LIS302DL_CTRL1_DR);
- lis->flags |= LIS302DL_F_DR;
- } else {
- __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
- 0);
- lis->flags &= ~LIS302DL_F_DR;
- }
+ if (lis->flags & LIS302DL_F_INPUT_OPEN)
+ __enable_data_collection(lis);
+
  local_irq_restore(flags);
 
  return count;
@@ -425,6 +539,12 @@ static ssize_t set_threshold(struct device *dev, struct device_attribute *attr,
  /* Set the threshold and write it out if the device is used */
  lis->threshold = val;
 
+ /* for backwards compatibility, we clear sample_rate when setting
+ * threshold
+ */
+ lis->sample_time = 0;
+ lis->use_jiffies = 1;
+
  if (lis->flags & LIS302DL_F_INPUT_OPEN) {
  unsigned long flags;
 
@@ -595,6 +715,10 @@ static int lis302dl_input_open(struct input_dev *inp)
  struct lis302dl_info *lis = input_get_drvdata(inp);
  unsigned long flags;
 
+ lis->timer.function = lis302dl_timer_read_sample;
+ lis->timer.data = (unsigned long)lis;
+ init_timer(&lis->timer);
+
  local_irq_save(flags);
 
  __enable_data_collection(lis);
@@ -612,6 +736,7 @@ static void lis302dl_input_close(struct input_dev *inp)
  LIS302DL_CTRL1_Zen;
  unsigned long flags;
 
+ del_timer_sync(&lis->timer);
  local_irq_save(flags);
 
  /* since the input core already serializes access and makes sure we
@@ -720,6 +845,10 @@ static int __devinit lis302dl_probe(struct spi_device *spi)
 
  lis->threshold = 0;
  lis->duration = 0;
+ /* default to 100HZ sampling */
+ lis->use_jiffies = 0;
+ lis->sample_time = 4;
+ lis->last_sample = 0;
  memset(&lis->wakeup, 0, sizeof(lis->wakeup));
 
  if (__lis302dl_reset_device(lis))
diff --git a/include/linux/lis302dl.h b/include/linux/lis302dl.h
index 0c1fc30..de47a37 100644
--- a/include/linux/lis302dl.h
+++ b/include/linux/lis302dl.h
@@ -26,6 +26,21 @@ struct lis302dl_info {
  unsigned int flags;
  unsigned int threshold;
  unsigned int duration;
+
+ /* We store sample_rate as time-between-samples.
+ * For rates above 50Hz, the unit of time is 2.5ms, the
+ * time of the fastest interrupt from the device.
+ * For lower rates, the unit of time is one jiffy.
+ * When using jiffies, 'last_sample' is the value of 'jiffies'
+ * at the time of the last sample.
+ * When using 2.5ms, 'last_sample' is set to 0 when
+ * a sample is taken, and incremented on each interrupt.  So it
+ * is effectively 'time since last_sample'.
+ */
+ int use_jiffies;
+ unsigned int sample_time;
+ unsigned long last_sample;
+ struct timer_list timer;
  u32 overruns;
  struct {
  unsigned int threshold; /* mg */



Reply | Threaded
Open this post in threaded view
|

[PATCH 4/4] lis302dl: improve 'full_scale' attribute

NeilBrown
In reply to this post by NeilBrown
The 'full_scale' attribute currently reports either 9.2 or
2.3, which is not really correct, and doesn't error check the
value written, which must be 9.2 or anything else.

The accelerometers are advertised as "2g or 8g".  2.3 and 9.2
are reported as typical maximum values but are not guaranteed.
So encoding them in the interface doesn't really make sense.

This patch changes the value reported to either

  2 [8]

or

  [2] 8

which is commonly used was of reporting both the list of available
values, and also the current value.

The value written to the attribute must be a number (possibly with a
decimal point).  Values from 3 up to 9 set the '8g' mode.
Values below 3 set the '2g' mode.

This makes usage more obvious and more correct.  It should not break
old applications unless they depended on reading exactly "9.2" - which
would be sad.

Signed-off-by: NeilBrown <[hidden email]>
---

 drivers/input/misc/lis302dl.c |   12 ++++++++++--
 1 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
index f9dfc24..ab6a62b 100644
--- a/drivers/input/misc/lis302dl.c
+++ b/drivers/input/misc/lis302dl.c
@@ -535,7 +535,7 @@ static ssize_t show_scale(struct device *dev, struct device_attribute *attr,
  ctrl1 = __reg_read(lis, LIS302DL_REG_CTRL1);
  local_irq_restore(flags);
 
- return sprintf(buf, "%s\n", ctrl1 & LIS302DL_CTRL1_FS ? "9.2" : "2.3");
+ return sprintf(buf, "%s\n", ctrl1 & LIS302DL_CTRL1_FS ? "2 [8]" : "[2] 8");
 }
 
 static ssize_t set_scale(struct device *dev, struct device_attribute *attr,
@@ -543,10 +543,18 @@ static ssize_t set_scale(struct device *dev, struct device_attribute *attr,
 {
  struct lis302dl_info *lis = dev_get_drvdata(dev);
  unsigned long flags;
+ char *endp;
+ int val;
+
+ val = simple_strtoul(buf, &endp, 10);
+ if (endp == buf || (*endp != '.' && *endp != '\n' && *endp != '\0'))
+ return -EINVAL;
+ if (val < 2 || val > 9)
+ return -EINVAL;
 
  local_irq_save(flags);
 
- if (!strcmp(buf, "9.2\n")) {
+ if (val >= 3) {
  __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS,
  LIS302DL_CTRL1_FS);
  lis->flags |= LIS302DL_F_FS;



Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 0/4] Accelerometer enhancements

Michael 'Mickey' Lauer-2
In reply to this post by NeilBrown
Awesome stuff Neil, will adjust FSO asap.

Thanks!

:M: