diff --git a/drivers/iio/imu/bme680/bme680_core.c b/drivers/iio/imu/bme680/bme680_core.c
index a6d013d..05712de 100644
--- a/drivers/iio/imu/bme680/bme680_core.c
+++ b/drivers/iio/imu/bme680/bme680_core.c
@@ -6,15 +6,73 @@
 #include <linux/iio/iio.h>
 #include <linux/module.h>
 #include <linux/regmap.h>
+#include <linux/log2.h>
+#include <linux/iio/sysfs.h>
 
 #define BME680_REG_CHIP_I2C_ID	0xD0
 #define BME680_REG_CHIP_SPI_ID	0x50
 #define BME680_CHIP_ID_VAL	0x61
 #define BME680_SOFT_RESET	0xE0
 #define BME680_CMD_SOFTRESET	0xB6
+#define BME680_REG_MEAS_STAT	0x1D
+
+#define BME680_OSRS_TEMP_X(osrs_t)      ((osrs_t) << 5)
+#define BME680_OSRS_PRESS_X(osrs_p)     ((osrs_p) << 2)
+#define BME680_OSRS_HUMID_X(osrs_h)	((osrs_h) << 0)
+
+#define BME680_REG_TEMP_MSB		0x22
+#define BME680_REG_PRESS_MSB		0x1F
+#define BM6880_REG_HUMIDITY_MSB		0x25
+
+#define BME680_REG_CTRL_HUMIDITY	0x72
+#define BME680_OSRS_HUMIDITY_MASK       GENMASK(2, 0)
+
+#define BME680_REG_CTRL_MEAS		0x74
+#define BME680_OSRS_TEMP_MASK		GENMASK(7, 5)
+#define BME680_OSRS_PRESS_MASK		GENMASK(4, 2)
+#define BME680_MODE_MASK		GENMASK(1, 0)
+
+#define BME680_MODE_FORCED		BIT(0)
+
+#define BME680_REG_CONFIG		0x75
+#define BME680_FILTER_MASK		GENMASK(4, 2)
+#define BME680_FILTER_4X		BIT(2)
+
+/* TEMP/PRESS/HUMID reading skipped */
+#define BME680_MEAS_SKIPPED		0x8000
+
+/* 
+ * TODO: the following structs stores various calibration
+ * paramters which are read from the sensor's NVM and used in
+ * the compensation function to obtain processed output.
+ */
+struct bme680_calib {
+};
 
 struct bme680_data {
 	struct regmap *regmap;
+	struct device *dev;
+	const struct bme680_chip_info *chip_info;
+	struct bme680_calib bme680;
+	u8 oversampling_temp;
+	u8 oversampling_press;
+	u8 oversampling_humid;
+};
+
+struct bme680_chip_info {
+	const int *oversampling_temp_avail;
+	int num_oversampling_temp_avail;
+
+	const int *oversampling_press_avail;
+	int num_oversampling_press_avail;
+
+	const int *oversampling_humid_avail;
+	int num_oversampling_humid_avail;
+
+	int (*chip_config)(struct bme680_data *data);
+	int (*read_temp)(struct bme680_data *data, int *val);
+	int (*read_press)(struct bme680_data *data, int *val);
+	int (*read_humid)(struct bme680_data *data, int *val);
 };
 
 const struct regmap_config bme680_regmap_config = {
@@ -23,9 +81,339 @@ const struct regmap_config bme680_regmap_config = {
 };
 EXPORT_SYMBOL(bme680_regmap_config);
 
+static const struct iio_chan_spec bme680_channels[] = {
+	{
+		.type = IIO_TEMP,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+				      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+	},
+	{
+		.type = IIO_PRESSURE,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+				      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+	},
+	{
+		.type = IIO_HUMIDITYRELATIVE,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+				      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+	},
+};
+
+static const int bme680_oversampling_avail[] = { 1, 2, 4, 8, 16 };
+
+/* TODO: read calibration parameters from the sensor's NVM */
+static int bme680_read_calib(struct bme680_data *data,
+			     struct bme680_calib *calib)
+{
+	memset(calib, 0, sizeof(*calib));
+	return 0;
+}
+
+/* TODO: compensate raw temp readings using temp calibration parameters */
+static s16 bme680_compensate_temp(struct bme680_data *data,
+				  s32 adc_temp)
+{
+	return adc_temp;
+}
+
+/* TODO: compensate raw press readings using press calibration parameters */
+static u32 bme680_compensate_press(struct bme680_data *data,
+				   u32 adc_press)
+{
+	return adc_press;
+}
+
+/* TODO: compensate raw humid readings using humid calibration parameters */
+static u32 bme680_compensate_humid(struct bme680_data *data,
+				   u16 adc_humid)
+{
+	return adc_humid;
+}
+
+static int bme680_read_temp(struct bme680_data *data,
+			    int *val)
+{
+	int ret;
+	__be32 tmp = 0;
+	u32 adc_temp;
+	s16 comp_temp;
+
+	/* Set Forced Mode & sampling rate before reading raw data */
+	ret = data->chip_info->chip_config(data);
+	if (ret < 0) {
+		dev_err(data->dev,
+			"failed to set chip config %s\n", __func__);
+	}
+
+	ret = regmap_bulk_read(data->regmap, BME680_REG_TEMP_MSB,
+				(u8 *) &tmp, 3);
+	if (ret < 0) {
+		dev_err(data->dev, "failed to read temperature\n");
+		return ret;
+	}
+
+	adc_temp = be32_to_cpu(tmp) >> 12;
+	if (adc_temp == BME680_MEAS_SKIPPED) {
+		/* reading was skipped */
+		dev_err(data->dev, "reading temperature skipped\n");
+		return -EIO;
+	}
+	comp_temp = bme680_compensate_temp(data, adc_temp);
+
+	*val = comp_temp;
+	return IIO_VAL_INT;
+
+	return 0;
+}
+
+static int bme680_read_press(struct bme680_data *data,
+			     int *val)
+{
+	int ret;
+	__be32 tmp = 0;
+	u32 comp_press, adc_press;
+
+	ret = regmap_bulk_read(data->regmap, BME680_REG_PRESS_MSB,
+				(u8 *) &tmp, 3);
+	if (ret < 0) {
+		dev_err(data->dev, "failed to read pressure\n");
+		return ret;
+	}
+
+	adc_press = be32_to_cpu(tmp) >> 12;
+	if (adc_press == BME680_MEAS_SKIPPED) {
+		/* reading was skipped */
+		dev_err(data->dev, "reading pressure skipped\n");
+		return -EIO;
+	}
+	comp_press = bme680_compensate_press(data, adc_press);
+
+	*val = comp_press;
+	return IIO_VAL_INT;
+}
+
+static int bme680_read_humid(struct bme680_data *data,
+			     int *val)
+{
+	int ret;
+	__be16 tmp = 0;
+	u16 adc_humidity;
+	u32 comp_humidity;
+
+	ret = regmap_bulk_read(data->regmap, BM6880_REG_HUMIDITY_MSB,
+				(u8 *) &tmp, 2);
+	if (ret < 0) {
+		dev_err(data->dev, "failed to read humidity\n");
+		return ret;
+	}
+
+	adc_humidity = be16_to_cpu(tmp);
+	if (adc_humidity == BME680_MEAS_SKIPPED) {
+		/* reading was skipped */
+		dev_err(data->dev, "reading humidity skipped\n");
+		return -EIO;
+	}
+	comp_humidity = bme680_compensate_humid(data, adc_humidity);
+
+	*val = comp_humidity;
+	return IIO_VAL_INT;
+}
+
+static int bme680_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val, int *val2, long mask)
+{
+	struct bme680_data *data = iio_priv(indio_dev);
+	int ret = 0;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_PROCESSED:
+		switch (chan->type) {
+		case IIO_TEMP:
+			ret = data->chip_info->read_temp(data, val);
+			break;
+		case IIO_PRESSURE:
+			ret = data->chip_info->read_press(data, val);
+			break;
+		case IIO_HUMIDITYRELATIVE:
+			ret = data->chip_info->read_humid(data, val);
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+		break;
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+		switch (chan->type) {
+		case IIO_TEMP:
+			*val = 1 << data->oversampling_temp;
+			ret = IIO_VAL_INT;
+			break;
+		case IIO_PRESSURE:
+			*val = 1 << data->oversampling_press;
+			ret = IIO_VAL_INT;
+			break;
+		case IIO_HUMIDITYRELATIVE:
+			*val = 1 << data->oversampling_humid;
+			ret = IIO_VAL_INT;
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int bme680_write_oversampling_ratio_temp(struct bme680_data *data,
+						int val)
+{
+	const int *avail = data->chip_info->oversampling_temp_avail;
+	const int n = data->chip_info->num_oversampling_temp_avail;
+	int i;
+
+	for (i = 0; i < n; ++i) {
+		if (avail[i] == val) {
+			data->oversampling_temp = ilog2(val);
+
+			return data->chip_info->chip_config(data);
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int bme680_write_oversampling_ratio_press(struct bme680_data *data,
+						 int val)
+{
+	const int *avail = data->chip_info->oversampling_press_avail;
+	const int n = data->chip_info->num_oversampling_press_avail;
+	int i;
+
+	for (i = 0; i < n; ++i) {
+		if (avail[i] == val) {
+			data->oversampling_press = ilog2(val);
+
+			return data->chip_info->chip_config(data);
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int bme680_write_oversampling_ratio_humid(struct bme680_data *data,
+						 int val)
+{
+	const int *avail = data->chip_info->oversampling_humid_avail;
+	const int n = data->chip_info->num_oversampling_humid_avail;
+	int i;
+
+	for (i = 0; i < n; ++i) {
+		if (avail[i] == val) {
+			data->oversampling_humid = ilog2(val);
+
+		return data->chip_info->chip_config(data);
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int bme680_write_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int val, int val2, long mask)
+{
+	struct bme680_data *data = iio_priv(indio_dev);
+	int ret = 0;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+		switch (chan->type) {
+		case IIO_TEMP:
+			ret = bme680_write_oversampling_ratio_temp(data, val);
+			break;
+		case IIO_PRESSURE:
+			ret = bme680_write_oversampling_ratio_press(data, val);
+			break;
+		case IIO_HUMIDITYRELATIVE:
+			ret = bme680_write_oversampling_ratio_humid(data, val);
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static const char bme680_oversampling_ratio_show[] = "1 2 4 8 16";
+
+static IIO_CONST_ATTR(oversampling_ratio_available,
+			bme680_oversampling_ratio_show);
+
+static struct attribute *bme680_attributes[] = {
+	&iio_const_attr_oversampling_ratio_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group bme680_attribute_group = {
+	.attrs = bme680_attributes,
+};
+
 static const struct iio_info bme680_info = {
+	.read_raw = &bme680_read_raw,
+	.write_raw = &bme680_write_raw,
+	.attrs = &bme680_attribute_group,
 };
 
+static int bme680_chip_config(struct bme680_data *data)
+{
+	int ret;
+	u8 osrs = BME680_OSRS_HUMID_X(data->oversampling_humid + 1);
+
+	/*
+	 * Highly recommended to set oversampling of humidity before
+	 * temperature/pressure oversampling.
+	 */
+	ret = regmap_update_bits(data->regmap, BME680_REG_CTRL_HUMIDITY,
+				 BME680_OSRS_HUMIDITY_MASK, osrs);
+
+	if (ret < 0) {
+		dev_err(data->dev,
+			"failed to write Ctrl_hum register\n");
+		return ret;
+	}
+	osrs = BME680_OSRS_TEMP_X(data->oversampling_temp + 1) |
+		  BME680_OSRS_PRESS_X(data->oversampling_press + 1);
+
+	ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS,
+				BME680_OSRS_TEMP_MASK |
+				BME680_OSRS_PRESS_MASK |
+				BME680_MODE_MASK,
+				osrs | BME680_MODE_FORCED);
+	if (ret < 0) {
+		dev_err(data->dev,
+			"failed to write Ctrl_meas register\n");
+		return ret;
+	}
+
+	/* IIR filter settings */
+
+	ret = regmap_update_bits(data->regmap, BME680_REG_CONFIG,
+				 BME680_FILTER_MASK,
+				 BME680_FILTER_4X);
+
+	if (ret < 0) {
+		dev_err(data->dev,
+			"failed to write Config register\n");
+		return ret;
+	}
+
+	return ret;
+}
+
 static int bme680_chip_init(struct bme680_data *data, bool use_spi)
 {
 	struct device *dev = regmap_get_device(data->regmap);
@@ -33,15 +421,15 @@ static int bme680_chip_init(struct bme680_data *data, bool use_spi)
 	int ret;
 
 	/* Power on Soft Reset */
-	ret = regmap_write(data->regmap, BME680_SOFT_RESET, BME680_CMD_SOFTRESET);
+	ret = regmap_write(data->regmap, BME680_SOFT_RESET,
+			   BME680_CMD_SOFTRESET);
 	if (ret < 0)
 		return ret;
 
-	if (!use_spi) {
+	if (!use_spi)
 		ret = regmap_read(data->regmap, BME680_REG_CHIP_I2C_ID, &val);
-	} else {
+	else
 		ret = regmap_read(data->regmap, BME680_REG_CHIP_SPI_ID, &val);
-	}
 
 	if (ret < 0) {
 		dev_err(dev, "Error reading chip ID\n");
@@ -57,6 +445,22 @@ static int bme680_chip_init(struct bme680_data *data, bool use_spi)
 	return 0;
 }
 
+static const struct bme680_chip_info bme680_chip_info = {
+	.oversampling_temp_avail = bme680_oversampling_avail,
+	.num_oversampling_temp_avail = ARRAY_SIZE(bme680_oversampling_avail),
+
+	.oversampling_press_avail = bme680_oversampling_avail,
+	.num_oversampling_press_avail = ARRAY_SIZE(bme680_oversampling_avail),
+
+	.oversampling_humid_avail = bme680_oversampling_avail,
+	.num_oversampling_press_avail = ARRAY_SIZE(bme680_oversampling_avail),
+
+	.chip_config = bme680_chip_config,
+	.read_temp = bme680_read_temp,
+	.read_press = bme680_read_press,
+	.read_humid = bme680_read_humid,
+};
+
 int bme680_core_probe(struct device *dev, struct regmap *regmap,
 		      const char *name, bool use_spi)
 {
@@ -78,11 +482,33 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap,
 
 	indio_dev->dev.parent = dev;
 	indio_dev->name = name;
+	indio_dev->channels = bme680_channels;
+	indio_dev->num_channels = ARRAY_SIZE(bme680_channels);
 	indio_dev->info = &bme680_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	data->chip_info = &bme680_chip_info;
+	data->oversampling_humid = ilog2(16);
+	data->oversampling_press = ilog2(16);
+	data->oversampling_temp = ilog2(2);
+
+	ret = data->chip_info->chip_config(data);
+	if (ret < 0) {
+		dev_err(data->dev,
+			"failed to set chip_config data\n");
+		return ret;
+	}
+	ret = bme680_read_calib(data, &data->bme680);
+	if (ret < 0) {
+		dev_err(data->dev,
+			"failed to read calibration coefficients\n");
+		return ret;
+	}
 
 	ret = iio_device_register(indio_dev);
 	if (ret < 0)
 		return ret;
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(bme680_core_probe);
