Input: adxl34x - add support for ADXL346 orientation sensing
authorMichael Hennerich <michael.hennerich@analog.com>
Fri, 25 Jun 2010 15:44:10 +0000 (08:44 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Fri, 25 Jun 2010 15:55:15 +0000 (08:55 -0700)
Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
drivers/input/misc/adxl34x.c
include/linux/input/adxl34x.h

index 07f9ef6315402601315f8a9ec43e81f533ef8c01..77fb4098705944587d0e6d50b302e81e0dc6b96d 100644 (file)
@@ -196,6 +196,8 @@ struct adxl34x {
        struct axis_triple hwcal;
        struct axis_triple saved;
        char phys[32];
+       unsigned orient2d_saved;
+       unsigned orient3d_saved;
        bool disabled;  /* P: mutex */
        bool opened;    /* P: mutex */
        bool fifo_delay;
@@ -296,7 +298,7 @@ static irqreturn_t adxl34x_irq(int irq, void *handle)
 {
        struct adxl34x *ac = handle;
        struct adxl34x_platform_data *pdata = &ac->pdata;
-       int int_stat, tap_stat, samples;
+       int int_stat, tap_stat, samples, orient, orient_code;
 
        /*
         * ACT_TAP_STATUS should be read before clearing the interrupt
@@ -332,6 +334,36 @@ static irqreturn_t adxl34x_irq(int irq, void *handle)
                                         pdata->ev_code_act_inactivity, 0);
        }
 
+       /*
+        * ORIENTATION SENSING ADXL346 only
+        */
+       if (pdata->orientation_enable) {
+               orient = AC_READ(ac, ORIENT);
+               if ((pdata->orientation_enable & ADXL_EN_ORIENTATION_2D) &&
+                   (orient & ADXL346_2D_VALID)) {
+
+                       orient_code = ADXL346_2D_ORIENT(orient);
+                       /* Report orientation only when it changes */
+                       if (ac->orient2d_saved != orient_code) {
+                               ac->orient2d_saved = orient_code;
+                               adxl34x_report_key_single(ac->input,
+                                       pdata->ev_codes_orient_2d[orient_code]);
+                       }
+               }
+
+               if ((pdata->orientation_enable & ADXL_EN_ORIENTATION_3D) &&
+                   (orient & ADXL346_3D_VALID)) {
+
+                       orient_code = ADXL346_3D_ORIENT(orient) - 1;
+                       /* Report orientation only when it changes */
+                       if (ac->orient3d_saved != orient_code) {
+                               ac->orient3d_saved = orient_code;
+                               adxl34x_report_key_single(ac->input,
+                                       pdata->ev_codes_orient_3d[orient_code]);
+                       }
+               }
+       }
+
        if (int_stat & (DATA_READY | WATERMARK)) {
 
                if (pdata->fifo_mode)
@@ -641,7 +673,7 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
        struct adxl34x *ac;
        struct input_dev *input_dev;
        const struct adxl34x_platform_data *pdata;
-       int err, range;
+       int err, range, i;
        unsigned char revid;
 
        if (!irq) {
@@ -797,12 +829,34 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
        AC_WRITE(ac, FIFO_CTL, FIFO_MODE(pdata->fifo_mode) |
                        SAMPLES(pdata->watermark));
 
-       if (pdata->use_int2)
+       if (pdata->use_int2) {
                /* Map all INTs to INT2 */
                AC_WRITE(ac, INT_MAP, ac->int_mask | OVERRUN);
-       else
+       } else {
                /* Map all INTs to INT1 */
                AC_WRITE(ac, INT_MAP, 0);
+       }
+
+       if (ac->model == 346 && ac->pdata.orientation_enable) {
+               AC_WRITE(ac, ORIENT_CONF,
+                       ORIENT_DEADZONE(ac->pdata.deadzone_angle) |
+                       ORIENT_DIVISOR(ac->pdata.divisor_length));
+
+               ac->orient2d_saved = 1234;
+               ac->orient3d_saved = 1234;
+
+               if (pdata->orientation_enable & ADXL_EN_ORIENTATION_3D)
+                       for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_3d); i++)
+                               __set_bit(pdata->ev_codes_orient_3d[i],
+                                         input_dev->keybit);
+
+               if (pdata->orientation_enable & ADXL_EN_ORIENTATION_2D)
+                       for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_2d); i++)
+                               __set_bit(pdata->ev_codes_orient_2d[i],
+                                         input_dev->keybit);
+       } else {
+               ac->pdata.orientation_enable = 0;
+       }
 
        AC_WRITE(ac, INT_ENABLE, ac->int_mask | OVERRUN);
 
index 712118238038de2c1ae8ca1dd92041017eadaa23..df00d998a44abbebab9604c1307645f6e6bf2511 100644 (file)
@@ -288,6 +288,62 @@ struct adxl34x_platform_data {
        u32 ev_code_ff; /* EV_KEY */
        u32 ev_code_act_inactivity;     /* EV_KEY */
 
+       /*
+        * Use ADXL34x INT2 instead of INT1
+        */
        u8 use_int2;
+
+       /*
+        * ADXL346 only ORIENTATION SENSING feature
+        * The orientation function of the ADXL346 reports both 2-D and
+        * 3-D orientation concurrently.
+        */
+
+#define ADXL_EN_ORIENTATION_2D         1
+#define ADXL_EN_ORIENTATION_3D         2
+#define ADXL_EN_ORIENTATION_2D_3D      3
+
+       u8 orientation_enable;
+
+       /*
+        * The width of the deadzone region between two or more
+        * orientation positions is determined by setting the Deadzone
+        * value. The deadzone region size can be specified with a
+        * resolution of 3.6deg. The deadzone angle represents the total
+        * angle where the orientation is considered invalid.
+        */
+
+#define ADXL_DEADZONE_ANGLE_0p0                0       /* !!!0.0 [deg] */
+#define ADXL_DEADZONE_ANGLE_3p6                1       /* 3.6 [deg] */
+#define ADXL_DEADZONE_ANGLE_7p2                2       /* 7.2 [deg] */
+#define ADXL_DEADZONE_ANGLE_10p8       3       /* 10.8 [deg] */
+#define ADXL_DEADZONE_ANGLE_14p4       4       /* 14.4 [deg] */
+#define ADXL_DEADZONE_ANGLE_18p0       5       /* 18.0 [deg] */
+#define ADXL_DEADZONE_ANGLE_21p6       6       /* 21.6 [deg] */
+#define ADXL_DEADZONE_ANGLE_25p2       7       /* 25.2 [deg] */
+
+       u8 deadzone_angle;
+
+       /*
+        * To eliminate most human motion such as walking or shaking,
+        * a Divisor value should be selected to effectively limit the
+        * orientation bandwidth. Set the depth of the filter used to
+        * low-pass filter the measured acceleration for stable
+        * orientation sensing
+        */
+
+#define ADXL_LP_FILTER_DIVISOR_2       0
+#define ADXL_LP_FILTER_DIVISOR_4       1
+#define ADXL_LP_FILTER_DIVISOR_8       2
+#define ADXL_LP_FILTER_DIVISOR_16      3
+#define ADXL_LP_FILTER_DIVISOR_32      4
+#define ADXL_LP_FILTER_DIVISOR_64      5
+#define ADXL_LP_FILTER_DIVISOR_128     6
+#define ADXL_LP_FILTER_DIVISOR_256     7
+
+       u8 divisor_length;
+
+       u32 ev_codes_orient_2d[4];      /* EV_KEY {+X, -X, +Y, -Y} */
+       u32 ev_codes_orient_3d[6];      /* EV_KEY {+Z, +Y, +X, -X, -Y, -Z} */
 };
 #endif
This page took 0.030768 seconds and 5 git commands to generate.