sensors: Add attribute configuration for icm42688

Implement the attribute get/set for the icm426888

Signed-off-by: Yuval Peress <peress@google.com>
diff --git a/drivers/sensor/icm42688/icm42688.c b/drivers/sensor/icm42688/icm42688.c
index 23e1136..77d72c9 100644
--- a/drivers/sensor/icm42688/icm42688.c
+++ b/drivers/sensor/icm42688/icm42688.c
@@ -124,13 +124,94 @@
 static int icm42688_attr_set(const struct device *dev, enum sensor_channel chan,
 			     enum sensor_attribute attr, const struct sensor_value *val)
 {
-	return -ENOTSUP;
+	const struct icm42688_sensor_data *data = dev->data;
+	struct icm42688_cfg new_config = data->dev_data.cfg;
+	int res = 0;
+
+	__ASSERT_NO_MSG(val != NULL);
+
+	switch (chan) {
+	case SENSOR_CHAN_ACCEL_X:
+	case SENSOR_CHAN_ACCEL_Y:
+	case SENSOR_CHAN_ACCEL_Z:
+	case SENSOR_CHAN_ACCEL_XYZ:
+		if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) {
+			new_config.accel_odr = icm42688_accel_hz_to_reg(val->val1);
+		} else if (attr == SENSOR_ATTR_FULL_SCALE) {
+			new_config.accel_fs = icm42688_accel_fs_to_reg(sensor_ms2_to_g(val));
+		} else {
+			LOG_ERR("Unsupported attribute");
+			res = -ENOTSUP;
+		}
+		break;
+	case SENSOR_CHAN_GYRO_X:
+	case SENSOR_CHAN_GYRO_Y:
+	case SENSOR_CHAN_GYRO_Z:
+	case SENSOR_CHAN_GYRO_XYZ:
+		if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) {
+			new_config.gyro_odr = icm42688_gyro_odr_to_reg(val->val1);
+		} else if (attr == SENSOR_ATTR_FULL_SCALE) {
+			new_config.gyro_fs = icm42688_gyro_fs_to_reg(sensor_rad_to_degrees(val));
+		} else {
+			LOG_ERR("Unsupported attribute");
+			res = -EINVAL;
+		}
+		break;
+	default:
+		LOG_ERR("Unsupported channel");
+		res = -EINVAL;
+		break;
+	}
+
+	if (res) {
+		return res;
+	}
+	return icm42688_configure(dev, &new_config);
 }
 
 static int icm42688_attr_get(const struct device *dev, enum sensor_channel chan,
 			     enum sensor_attribute attr, struct sensor_value *val)
 {
-	return -ENOTSUP;
+	const struct icm42688_sensor_data *data = dev->data;
+	const struct icm42688_cfg *cfg = &data->dev_data.cfg;
+	int res = 0;
+
+	__ASSERT_NO_MSG(val != NULL);
+
+	switch (chan) {
+	case SENSOR_CHAN_ACCEL_X:
+	case SENSOR_CHAN_ACCEL_Y:
+	case SENSOR_CHAN_ACCEL_Z:
+	case SENSOR_CHAN_ACCEL_XYZ:
+		if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) {
+			icm42688_accel_reg_to_hz(cfg->accel_odr, val);
+		} else if (attr == SENSOR_ATTR_FULL_SCALE) {
+			icm42688_accel_reg_to_fs(cfg->accel_fs, val);
+		} else {
+			LOG_ERR("Unsupported attribute");
+			res = -EINVAL;
+		}
+		break;
+	case SENSOR_CHAN_GYRO_X:
+	case SENSOR_CHAN_GYRO_Y:
+	case SENSOR_CHAN_GYRO_Z:
+	case SENSOR_CHAN_GYRO_XYZ:
+		if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) {
+			icm42688_gyro_reg_to_odr(cfg->gyro_odr, val);
+		} else if (attr == SENSOR_ATTR_FULL_SCALE) {
+			icm42688_gyro_reg_to_fs(cfg->gyro_fs, val);
+		} else {
+			LOG_ERR("Unsupported attribute");
+			res = -EINVAL;
+		}
+		break;
+	default:
+		LOG_ERR("Unsupported channel");
+		res = -EINVAL;
+		break;
+	}
+
+	return res;
 }
 
 static const struct sensor_driver_api icm42688_driver_api = {
diff --git a/drivers/sensor/icm42688/icm42688.h b/drivers/sensor/icm42688/icm42688.h
index 6caff21..17c607e 100644
--- a/drivers/sensor/icm42688/icm42688.h
+++ b/drivers/sensor/icm42688/icm42688.h
@@ -42,6 +42,37 @@
 	ICM42688_ACCEL_FS_2G,
 };
 
+static inline enum icm42688_accel_fs icm42688_accel_fs_to_reg(uint8_t g)
+{
+	if (g >= 16) {
+		return ICM42688_ACCEL_FS_16G;
+	} else if (g >= 8) {
+		return ICM42688_ACCEL_FS_8G;
+	} else if (g >= 4) {
+		return ICM42688_ACCEL_FS_4G;
+	} else {
+		return ICM42688_ACCEL_FS_2G;
+	}
+}
+
+static inline void icm42688_accel_reg_to_fs(enum icm42688_accel_fs fs, struct sensor_value *out)
+{
+	switch (fs) {
+	case ICM42688_ACCEL_FS_16G:
+		sensor_g_to_ms2(16, out);
+		return;
+	case ICM42688_ACCEL_FS_8G:
+		sensor_g_to_ms2(8, out);
+		return;
+	case ICM42688_ACCEL_FS_4G:
+		sensor_g_to_ms2(4, out);
+		return;
+	case ICM42688_ACCEL_FS_2G:
+		sensor_g_to_ms2(2, out);
+		return;
+	}
+}
+
 /**
  * @brief Gyroscope scale options
  */
@@ -56,6 +87,57 @@
 	ICM42688_GYRO_FS_15_625,
 };
 
+static inline enum icm42688_gyro_fs icm42688_gyro_fs_to_reg(uint16_t dps)
+{
+	if (dps >= 2000) {
+		return ICM42688_GYRO_FS_2000;
+	} else if (dps >= 1000) {
+		return ICM42688_GYRO_FS_1000;
+	} else if (dps >= 500) {
+		return ICM42688_GYRO_FS_500;
+	} else if (dps >= 250) {
+		return ICM42688_GYRO_FS_250;
+	} else if (dps >= 125) {
+		return ICM42688_GYRO_FS_125;
+	} else if (dps >= 62) {
+		return ICM42688_GYRO_FS_62_5;
+	} else if (dps >= 31) {
+		return ICM42688_GYRO_FS_31_25;
+	} else {
+		return ICM42688_GYRO_FS_15_625;
+	}
+}
+
+static inline void icm42688_gyro_reg_to_fs(enum icm42688_gyro_fs fs, struct sensor_value *out)
+{
+	switch (fs) {
+	case ICM42688_GYRO_FS_2000:
+		sensor_degrees_to_rad(2000, out);
+		return;
+	case ICM42688_GYRO_FS_1000:
+		sensor_degrees_to_rad(1000, out);
+		return;
+	case ICM42688_GYRO_FS_500:
+		sensor_degrees_to_rad(500, out);
+		return;
+	case ICM42688_GYRO_FS_250:
+		sensor_degrees_to_rad(250, out);
+		return;
+	case ICM42688_GYRO_FS_125:
+		sensor_degrees_to_rad(125, out);
+		return;
+	case ICM42688_GYRO_FS_62_5:
+		sensor_10udegrees_to_rad(6250000, out);
+		return;
+	case ICM42688_GYRO_FS_31_25:
+		sensor_10udegrees_to_rad(3125000, out);
+		return;
+	case ICM42688_GYRO_FS_15_625:
+		sensor_10udegrees_to_rad(1562500, out);
+		return;
+	}
+}
+
 /**
  * @brief Accelerometer data rate options
  */
@@ -77,6 +159,107 @@
 	ICM42688_ACCEL_ODR_500,
 };
 
+static inline enum icm42688_accel_odr icm42688_accel_hz_to_reg(uint16_t hz)
+{
+	if (hz >= 32000) {
+		return ICM42688_ACCEL_ODR_32000;
+	} else if (hz >= 16000) {
+		return ICM42688_ACCEL_ODR_16000;
+	} else if (hz >= 8000) {
+		return ICM42688_ACCEL_ODR_8000;
+	} else if (hz >= 4000) {
+		return ICM42688_ACCEL_ODR_4000;
+	} else if (hz >= 2000) {
+		return ICM42688_ACCEL_ODR_2000;
+	} else if (hz >= 1000) {
+		return ICM42688_ACCEL_ODR_1000;
+	} else if (hz >= 500) {
+		return ICM42688_ACCEL_ODR_500;
+	} else if (hz >= 200) {
+		return ICM42688_ACCEL_ODR_200;
+	} else if (hz >= 100) {
+		return ICM42688_ACCEL_ODR_100;
+	} else if (hz >= 50) {
+		return ICM42688_ACCEL_ODR_50;
+	} else if (hz >= 25) {
+		return ICM42688_ACCEL_ODR_25;
+	} else if (hz >= 12) {
+		return ICM42688_ACCEL_ODR_12_5;
+	} else if (hz >= 6) {
+		return ICM42688_ACCEL_ODR_6_25;
+	} else if (hz >= 3) {
+		return ICM42688_ACCEL_ODR_3_125;
+	} else {
+		return ICM42688_ACCEL_ODR_1_5625;
+	}
+}
+
+static inline void icm42688_accel_reg_to_hz(enum icm42688_accel_odr odr, struct sensor_value *out)
+{
+	switch (odr) {
+	case ICM42688_ACCEL_ODR_32000:
+		out->val1 = 32000;
+		out->val2 = 0;
+		return;
+	case ICM42688_ACCEL_ODR_16000:
+		out->val1 = 1600;
+		out->val2 = 0;
+		return;
+	case ICM42688_ACCEL_ODR_8000:
+		out->val1 = 8000;
+		out->val2 = 0;
+		return;
+	case ICM42688_ACCEL_ODR_4000:
+		out->val1 = 4000;
+		out->val2 = 0;
+		return;
+	case ICM42688_ACCEL_ODR_2000:
+		out->val1 = 2000;
+		out->val2 = 0;
+		return;
+	case ICM42688_ACCEL_ODR_1000:
+		out->val1 = 1000;
+		out->val2 = 0;
+		return;
+	case ICM42688_ACCEL_ODR_500:
+		out->val1 = 500;
+		out->val2 = 0;
+		return;
+	case ICM42688_ACCEL_ODR_200:
+		out->val1 = 200;
+		out->val2 = 0;
+		return;
+	case ICM42688_ACCEL_ODR_100:
+		out->val1 = 100;
+		out->val2 = 0;
+		return;
+	case ICM42688_ACCEL_ODR_50:
+		out->val1 = 50;
+		out->val2 = 0;
+		return;
+	case ICM42688_ACCEL_ODR_25:
+		out->val1 = 25;
+		out->val2 = 0;
+		return;
+	case ICM42688_ACCEL_ODR_12_5:
+		out->val1 = 12;
+		out->val2 = 500000;
+		return;
+	case ICM42688_ACCEL_ODR_6_25:
+		out->val1 = 6;
+		out->val2 = 250000;
+		return;
+	case ICM42688_ACCEL_ODR_3_125:
+		out->val1 = 3;
+		out->val2 = 125000;
+		return;
+	case ICM42688_ACCEL_ODR_1_5625:
+		out->val1 = 1;
+		out->val2 = 562500;
+		return;
+	}
+}
+
 /**
  * @brief Gyroscope data rate options
  */
@@ -95,6 +278,89 @@
 	ICM42688_GYRO_ODR_500 = 0xF
 };
 
+static inline enum icm42688_gyro_odr icm42688_gyro_odr_to_reg(uint16_t hz)
+{
+	if (hz >= 32000) {
+		return ICM42688_GYRO_ODR_32000;
+	} else if (hz >= 16000) {
+		return ICM42688_GYRO_ODR_16000;
+	} else if (hz >= 8000) {
+		return ICM42688_GYRO_ODR_8000;
+	} else if (hz >= 4000) {
+		return ICM42688_GYRO_ODR_4000;
+	} else if (hz >= 2000) {
+		return ICM42688_GYRO_ODR_2000;
+	} else if (hz >= 1000) {
+		return ICM42688_GYRO_ODR_1000;
+	} else if (hz >= 500) {
+		return ICM42688_GYRO_ODR_500;
+	} else if (hz >= 200) {
+		return ICM42688_GYRO_ODR_200;
+	} else if (hz >= 100) {
+		return ICM42688_GYRO_ODR_100;
+	} else if (hz >= 50) {
+		return ICM42688_GYRO_ODR_50;
+	} else if (hz >= 25) {
+		return ICM42688_GYRO_ODR_25;
+	} else {
+		return ICM42688_GYRO_ODR_12_5;
+	}
+}
+
+static inline void icm42688_gyro_reg_to_odr(enum icm42688_gyro_odr odr, struct sensor_value *out)
+{
+	switch (odr) {
+	case ICM42688_GYRO_ODR_32000:
+		out->val1 = 32000;
+		out->val2 = 0;
+		return;
+	case ICM42688_GYRO_ODR_16000:
+		out->val1 = 16000;
+		out->val2 = 0;
+		return;
+	case ICM42688_GYRO_ODR_8000:
+		out->val1 = 8000;
+		out->val2 = 0;
+		return;
+	case ICM42688_GYRO_ODR_4000:
+		out->val1 = 4000;
+		out->val2 = 0;
+		return;
+	case ICM42688_GYRO_ODR_2000:
+		out->val1 = 2000;
+		out->val2 = 0;
+		return;
+	case ICM42688_GYRO_ODR_1000:
+		out->val1 = 1000;
+		out->val2 = 0;
+		return;
+	case ICM42688_GYRO_ODR_500:
+		out->val1 = 500;
+		out->val2 = 0;
+		return;
+	case ICM42688_GYRO_ODR_200:
+		out->val1 = 200;
+		out->val2 = 0;
+		return;
+	case ICM42688_GYRO_ODR_100:
+		out->val1 = 100;
+		out->val2 = 0;
+		return;
+	case ICM42688_GYRO_ODR_50:
+		out->val1 = 50;
+		out->val2 = 0;
+		return;
+	case ICM42688_GYRO_ODR_25:
+		out->val1 = 25;
+		out->val2 = 0;
+		return;
+	case ICM42688_GYRO_ODR_12_5:
+		out->val1 = 12;
+		out->val2 = 500000;
+		return;
+	}
+}
+
 /**
  * @brief All sensor configuration options
  */
diff --git a/drivers/sensor/icm42688/icm42688_common.c b/drivers/sensor/icm42688/icm42688_common.c
index 882eb3d..3768b83 100644
--- a/drivers/sensor/icm42688/icm42688_common.c
+++ b/drivers/sensor/icm42688/icm42688_common.c
@@ -103,6 +103,9 @@
 		LOG_ERR("Error writing PWR_MGMT0");
 		return -EINVAL;
 	}
+	dev_data->cfg.gyro_mode = cfg->gyro_mode;
+	dev_data->cfg.accel_mode = cfg->accel_mode;
+	dev_data->cfg.temp_dis = cfg->temp_dis;
 
 	/* Need to wait at least 200us before updating more registers
 	 * see datasheet 14.36
@@ -117,6 +120,8 @@
 		LOG_ERR("Error writing ACCEL_CONFIG0");
 		return -EINVAL;
 	}
+	dev_data->cfg.accel_odr = cfg->accel_odr;
+	dev_data->cfg.accel_fs = cfg->accel_fs;
 
 	res = icm42688_spi_single_write(&dev_cfg->spi, REG_GYRO_CONFIG0,
 					FIELD_PREP(MASK_GYRO_ODR, cfg->gyro_odr) |
@@ -126,6 +131,8 @@
 		LOG_ERR("Error writing GYRO_CONFIG0");
 		return -EINVAL;
 	}
+	dev_data->cfg.gyro_odr = cfg->gyro_odr;
+	dev_data->cfg.gyro_fs = cfg->gyro_fs;
 
 	/*
 	 * Accelerometer sensor need at least 10ms startup time
@@ -151,6 +158,7 @@
 			LOG_ERR("Error writing FIFO_CONFIG3");
 			return -EINVAL;
 		}
+		dev_data->cfg.fifo_wm = cfg->fifo_wm;
 
 		/* TODO we have two interrupt lines, either can be used for watermark, choose 1 for
 		 *   now...
@@ -176,10 +184,12 @@
 			LOG_ERR("Error writing FIFO_CONFIG1");
 			return -EINVAL;
 		}
+		dev_data->cfg.fifo_hires = cfg->fifo_hires;
 
 		/* Begin streaming */
 		res = icm42688_spi_single_write(&dev_cfg->spi, REG_FIFO_CONFIG,
 						FIELD_PREP(MASK_FIFO_MODE, BIT_FIFO_MODE_STREAM));
+		dev_data->cfg.fifo_en = true;
 	}
 
 	return res;