[PATCH] iio: accel: mxc4005: report orientation of accelerometer

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Quentin Schulz <quentin.schulz@xxxxxxxxxxxxxxxxxxxxx>

The accelerometer can report precise values for x, y and z accelerations
but it can also simply report its orientation on XY plane and Z axis.

Since the orientation of the device may be enough information for
userspace and allows to avoid expensive fusion algorithms, let's add
support for it.

The orientation register stores a 2b value for XY plane orientation:
between 225° and 315°, returns 0, between 315° and 45°, 1, between 45°
and 135°, 2 and between 135° and 225°, 3. We "round" those to 270°,
0°, 90° and 180° degrees.

For Z axis, the register bit returns 0 if facing the user, 1 otherwise,
which the driver translates to 0° and 180° respectively.

Those values are proper if the accelerometer is mounted such that the
XYZ axes are as follows when the device is facing the user in portrait
mode (respecting the right-hand rule):

     y
     ^
     |
     |
     |
     +----------> x
    /
   /
  /
 L
z

Since this information is very basic, imprecise (only 4 values for XY
plane and 2 for Z axis) and can be extrapolated from the actual,
precise, x, y and z acceleration values, it is not made available
through buffers.

A change in XY plane or Z axis orientation can also trigger an interrupt
but this feature is not added in this commit.

Signed-off-by: Quentin Schulz <quentin.schulz@xxxxxxxxxxxxxxxxxxxxx>
---
 drivers/iio/accel/mxc4005.c | 39 +++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c
index b3afbf064915..61f24058d239 100644
--- a/drivers/iio/accel/mxc4005.c
+++ b/drivers/iio/accel/mxc4005.c
@@ -20,6 +20,11 @@
 #define MXC4005_IRQ_NAME		"mxc4005_event"
 #define MXC4005_REGMAP_NAME		"mxc4005_regmap"
 
+#define MXC4005_REG_TILT_ORIENT		0x01
+#define MXC4005_REG_TILT_ORIENT_Z_MASK		BIT(6)
+#define MXC4005_REG_TILT_ORIENT_XY_MASK		GENMASK(5, 4)
+#define MXC4005_REG_TILT_ORIENT_XY_SHIFT	4
+
 #define MXC4005_REG_XOUT_UPPER		0x03
 #define MXC4005_REG_XOUT_LOWER		0x04
 #define MXC4005_REG_YOUT_UPPER		0x05
@@ -96,6 +101,7 @@ static const struct attribute_group mxc4005_attrs_group = {
 static bool mxc4005_is_readable_reg(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
+	case MXC4005_REG_TILT_ORIENT:
 	case MXC4005_REG_XOUT_UPPER:
 	case MXC4005_REG_XOUT_LOWER:
 	case MXC4005_REG_YOUT_UPPER:
@@ -214,6 +220,28 @@ static int mxc4005_read_raw(struct iio_dev *indio_dev,
 	int ret;
 
 	switch (mask) {
+	case IIO_CHAN_INFO_PROCESSED:
+		switch (chan->type) {
+		case IIO_ROT:
+			ret = regmap_read(data->regmap, chan->address, val);
+			if (ret < 0) {
+				dev_err(data->dev, "failed to read rotation\n");
+				return ret;
+			}
+
+			if (chan->channel2 == IIO_MOD_X_AND_Y) {
+				*val &= MXC4005_REG_TILT_ORIENT_XY_MASK;
+				*val >>= MXC4005_REG_TILT_ORIENT_XY_SHIFT;
+				/* 00 = 270°; 01 = 0°; 10 = 90°; 11 = 180° */
+				*val = (360 + (*val - 1) * 90) % 360;
+			} else {
+				*val &= MXC4005_REG_TILT_ORIENT_Z_MASK;
+				*val = *val ? 180 : 0;
+			}
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
 	case IIO_CHAN_INFO_RAW:
 		switch (chan->type) {
 		case IIO_ACCEL:
@@ -287,11 +315,22 @@ static const unsigned long mxc4005_scan_masks[] = {
 	},							\
 }
 
+#define MXC4005_CHANNEL_ORIENTATION(_axis) {			\
+	.type = IIO_ROT,					\
+	.modified = 1,						\
+	.channel2 = IIO_MOD_##_axis,				\
+	.address = MXC4005_REG_TILT_ORIENT,			\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),	\
+	.scan_index = -1,					\
+}
+
 static const struct iio_chan_spec mxc4005_channels[] = {
 	MXC4005_CHANNEL(X, MXC4005_REG_XOUT_UPPER),
 	MXC4005_CHANNEL(Y, MXC4005_REG_YOUT_UPPER),
 	MXC4005_CHANNEL(Z, MXC4005_REG_ZOUT_UPPER),
 	IIO_CHAN_SOFT_TIMESTAMP(3),
+	MXC4005_CHANNEL_ORIENTATION(X_AND_Y),
+	MXC4005_CHANNEL_ORIENTATION(Z),
 };
 
 static irqreturn_t mxc4005_trigger_handler(int irq, void *private)
-- 
2.36.1




[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux