[PATCH] iio: accel: mma8452: Expose temperature channel

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

 



FXLS8471Q devices support temperature readout as 8-bit signed value,
0.960C/LSB, -40C to 125C.

Enabling temperature readout reduces the selected ODR by a factor of
2, e.g. with ODR set to 800Hz and temperature enabled the sample rate
will be 400Hz.

Signed-off-by: Dylan Howey <Dylan.Howey@xxxxxxxxxxxxx>
---
 drivers/iio/accel/mma8452.c | 119 ++++++++++++++++++++++++++++++------
 1 file changed, 101 insertions(+), 18 deletions(-)

diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index eb6e3dc789b2..016dcc14e96e 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -83,8 +83,13 @@
 #define MMA8452_OFF_X				0x2f
 #define MMA8452_OFF_Y				0x30
 #define MMA8452_OFF_Z				0x31
+#define FXLS8471_CLEAR_DRDY			0x33
+#define FXLS8471_TEMP_OUT			0x51
+#define FXLS8471_TEMP_EN_MASK			GENMASK(1, 0)
+#define FXLS8471_CTRL_REG6			0x5b
+#define FXLS8471_CTRL_REG7			0x5c
 
-#define MMA8452_MAX_REG				0x31
+#define MMA8452_MAX_REG				0x5c
 
 #define  MMA8452_INT_DRDY			BIT(0)
 #define  MMA8452_INT_FF_MT			BIT(2)
@@ -103,6 +108,7 @@ struct mma8452_data {
 	struct i2c_client *client;
 	struct mutex lock;
 	u8 ctrl_reg1;
+	u8 ctrl_reg6;
 	u8 data_cfg;
 	const struct mma_chip_info *chip_info;
 };
@@ -113,6 +119,7 @@ struct mma8452_data {
  * @channels:			struct iio_chan_spec matching the device's
  *				capabilities
  * @num_channels:		number of channels
+ * @avaiable_scan_masks:		bitmask of available scan elements
  * @mma_scales:			scale factors for converting register values
  *				to m/s^2; 3 modes: 2g, 4g, 8g; 2 integers
  *				per mode: m/s^2 and micro m/s^2
@@ -139,6 +146,7 @@ struct mma_chip_info {
 	u8 chip_id;
 	const struct iio_chan_spec *channels;
 	int num_channels;
+	unsigned long available_scan_masks[2];
 	const int mma_scales[3][2];
 	u8 ev_cfg;
 	u8 ev_cfg_ele;
@@ -156,6 +164,7 @@ enum {
 	idx_x,
 	idx_y,
 	idx_z,
+	idx_temp,
 	idx_ts,
 };
 
@@ -204,7 +213,7 @@ static int mma8452_set_runtime_pm_state(struct i2c_client *client, bool on)
 	return 0;
 }
 
-static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
+static int mma8452_read(struct mma8452_data *data, u8 buf[7])
 {
 	int ret = mma8452_drdy(data);
 
@@ -216,7 +225,19 @@ static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
 		return ret;
 
 	ret = i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X,
-					    3 * sizeof(__be16), (u8 *)buf);
+					    3 * sizeof(__be16), buf);
+
+	if (FXLS8471_TEMP_EN_MASK & data->ctrl_reg6) {
+		buf[6] = i2c_smbus_read_byte_data(data->client,
+							FXLS8471_TEMP_OUT);
+
+		/*
+		 * A read of the dummy register 33h is required to reset drdy
+		 * for the next interrupt cycle after reading the temperature.
+		 * Value read from register is don't care.
+		 */
+		i2c_smbus_read_byte_data(data->client, FXLS8471_CLEAR_DRDY);
+	}
 
 	ret = mma8452_set_runtime_pm_state(data->client, false);
 
@@ -454,7 +475,7 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
 			    int *val, int *val2, long mask)
 {
 	struct mma8452_data *data = iio_priv(indio_dev);
-	__be16 buffer[3];
+	u8 buffer[7];
 	int i, ret;
 
 	switch (mask) {
@@ -470,17 +491,37 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
 		if (ret < 0)
 			return ret;
 
-		*val = sign_extend32(be16_to_cpu(
-			buffer[chan->scan_index]) >> chan->scan_type.shift,
+		switch (chan->type) {
+		case IIO_ACCEL:
+			*val = sign_extend32(be16_to_cpu(
+			*(__be16 *)&buffer[2 * chan->scan_index])
+			>> chan->scan_type.shift,
 			chan->scan_type.realbits - 1);
+			return IIO_VAL_INT;
+		case IIO_TEMP:
+			if (!(FXLS8471_TEMP_EN_MASK & data->ctrl_reg6))
+				return -EINVAL;
+
+			*val = sign_extend32(buffer[6], 7);
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
 
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_SCALE:
-		i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK;
-		*val = data->chip_info->mma_scales[i][0];
-		*val2 = data->chip_info->mma_scales[i][1];
-
-		return IIO_VAL_INT_PLUS_MICRO;
+		switch (chan->type) {
+		case IIO_ACCEL:
+			i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK;
+			*val = data->chip_info->mma_scales[i][0];
+			*val2 = data->chip_info->mma_scales[i][1];
+			return IIO_VAL_INT_PLUS_MICRO;
+		case IIO_TEMP:
+			*val = 960;
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
 	case IIO_CHAN_INFO_SAMP_FREQ:
 		i = mma8452_get_odr_index(data);
 		*val = mma8452_samp_freq[i][0];
@@ -517,6 +558,12 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
 
 		*val = mma8452_os_ratio[ret][i];
 		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = 50; /* 0 LSB @ 25 degree C */
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_ENABLE:
+		*val = !!(data->ctrl_reg6 & FXLS8471_TEMP_EN_MASK);
+		return IIO_VAL_INT;
 	}
 
 	return -EINVAL;
@@ -731,6 +778,16 @@ static int mma8452_write_raw(struct iio_dev *indio_dev,
 			}
 		}
 		break;
+
+	case IIO_CHAN_INFO_ENABLE:
+		if (val)
+			data->ctrl_reg6 |= FXLS8471_TEMP_EN_MASK;
+		else
+			data->ctrl_reg6 &= ~FXLS8471_TEMP_EN_MASK;
+		/* Note: enabling temperature reduces ODR by a factor of 2. */
+		return mma8452_change_config(data, FXLS8471_CTRL_REG6,
+				data->ctrl_reg6);
+
 	default:
 		ret = -EINVAL;
 		break;
@@ -1003,10 +1060,10 @@ static irqreturn_t mma8452_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct mma8452_data *data = iio_priv(indio_dev);
-	u8 buffer[16]; /* 3 16-bit channels + padding + ts */
+	u8 buffer[16]; /* 3 16-bit channels + temp + padding + ts */
 	int ret;
 
-	ret = mma8452_read(data, (__be16 *)buffer);
+	ret = mma8452_read(data, buffer);
 	if (ret < 0)
 		goto done;
 
@@ -1159,6 +1216,19 @@ static struct attribute_group mma8452_event_attribute_group = {
 	.num_event_specs = ARRAY_SIZE(mma8452_motion_event), \
 }
 
+#define FXLS8471_TEMP_CHANNEL { \
+	.type = IIO_TEMP, \
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+		BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET) | \
+		BIT(IIO_CHAN_INFO_ENABLE), \
+	.scan_index = idx_temp, \
+	.scan_type = { \
+		.sign = 's', \
+		.realbits = 8, \
+		.storagebits = 8, \
+	}, \
+}
+
 static const struct iio_chan_spec mma8451_channels[] = {
 	MMA8452_CHANNEL(X, idx_x, 14),
 	MMA8452_CHANNEL(Y, idx_y, 14),
@@ -1199,6 +1269,15 @@ static const struct iio_chan_spec mma8653_channels[] = {
 	MMA8652_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z),
 };
 
+static const struct iio_chan_spec fxls8471_channels[] = {
+	MMA8452_CHANNEL(X, idx_x, 14),
+	MMA8452_CHANNEL(Y, idx_y, 14),
+	MMA8452_CHANNEL(Z, idx_z, 14),
+	FXLS8471_TEMP_CHANNEL,
+	IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
+	MMA8452_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z),
+};
+
 enum {
 	mma8451,
 	mma8452,
@@ -1213,6 +1292,7 @@ static const struct mma_chip_info mma_chip_info_table[] = {
 		.chip_id = MMA8451_DEVICE_ID,
 		.channels = mma8451_channels,
 		.num_channels = ARRAY_SIZE(mma8451_channels),
+		.available_scan_masks = {0x7, 0},
 		/*
 		 * Hardware has fullscale of -2G, -4G, -8G corresponding to
 		 * raw value -8192 for 14 bit, -2048 for 12 bit or -512 for 10
@@ -1237,6 +1317,7 @@ static const struct mma_chip_info mma_chip_info_table[] = {
 		.chip_id = MMA8452_DEVICE_ID,
 		.channels = mma8452_channels,
 		.num_channels = ARRAY_SIZE(mma8452_channels),
+		.available_scan_masks = {0x7, 0},
 		.mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} },
 		.ev_cfg = MMA8452_TRANSIENT_CFG,
 		.ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE,
@@ -1253,6 +1334,7 @@ static const struct mma_chip_info mma_chip_info_table[] = {
 		.chip_id = MMA8453_DEVICE_ID,
 		.channels = mma8453_channels,
 		.num_channels = ARRAY_SIZE(mma8453_channels),
+		.available_scan_masks = {0x7, 0},
 		.mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} },
 		.ev_cfg = MMA8452_TRANSIENT_CFG,
 		.ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE,
@@ -1269,6 +1351,7 @@ static const struct mma_chip_info mma_chip_info_table[] = {
 		.chip_id = MMA8652_DEVICE_ID,
 		.channels = mma8652_channels,
 		.num_channels = ARRAY_SIZE(mma8652_channels),
+		.available_scan_masks = {0x7, 0},
 		.mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} },
 		.ev_cfg = MMA8452_FF_MT_CFG,
 		.ev_cfg_ele = MMA8452_FF_MT_CFG_ELE,
@@ -1285,6 +1368,7 @@ static const struct mma_chip_info mma_chip_info_table[] = {
 		.chip_id = MMA8653_DEVICE_ID,
 		.channels = mma8653_channels,
 		.num_channels = ARRAY_SIZE(mma8653_channels),
+		.available_scan_masks = {0x7, 0},
 		.mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} },
 		.ev_cfg = MMA8452_FF_MT_CFG,
 		.ev_cfg_ele = MMA8452_FF_MT_CFG_ELE,
@@ -1299,8 +1383,9 @@ static const struct mma_chip_info mma_chip_info_table[] = {
 	},
 	[fxls8471] = {
 		.chip_id = FXLS8471_DEVICE_ID,
-		.channels = mma8451_channels,
-		.num_channels = ARRAY_SIZE(mma8451_channels),
+		.channels = fxls8471_channels,
+		.num_channels = ARRAY_SIZE(fxls8471_channels),
+		.available_scan_masks = {0xf, 0},
 		.mma_scales = { {0, 2394}, {0, 4788}, {0, 9577} },
 		.ev_cfg = MMA8452_TRANSIENT_CFG,
 		.ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE,
@@ -1340,8 +1425,6 @@ static const struct iio_info mma8452_info = {
 	.driver_module = THIS_MODULE,
 };
 
-static const unsigned long mma8452_scan_masks[] = {0x7, 0};
-
 static int mma8452_data_rdy_trigger_set_state(struct iio_trigger *trig,
 					      bool state)
 {
@@ -1487,7 +1570,7 @@ static int mma8452_probe(struct i2c_client *client,
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->channels = data->chip_info->channels;
 	indio_dev->num_channels = data->chip_info->num_channels;
-	indio_dev->available_scan_masks = mma8452_scan_masks;
+	indio_dev->available_scan_masks = data->chip_info->available_scan_masks;
 
 	ret = mma8452_reset(client);
 	if (ret < 0)
-- 
2.17.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