/*
 * Copyright (c) 2016 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <i2c.h>
#include <init.h>
#include <misc/__assert.h>
#include <misc/byteorder.h>
#include <sensor.h>
#include <string.h>
#include <logging/log.h>

#include "hts221.h"

#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL
LOG_MODULE_REGISTER(HTS221);

static const char * const hts221_odr_strings[] = {
	"1", "7", "12.5"
};

static int hts221_channel_get(struct device *dev,
			       enum sensor_channel chan,
			       struct sensor_value *val)
{
	struct hts221_data *drv_data = dev->driver_data;
	s32_t conv_val;

	__ASSERT_NO_MSG(chan == SENSOR_CHAN_AMBIENT_TEMP ||
			chan == SENSOR_CHAN_HUMIDITY);

	/*
	 * see "Interpreting humidity and temperature readings" document
	 * for more details
	 */
	if (chan == SENSOR_CHAN_AMBIENT_TEMP) {
		conv_val = (s32_t)(drv_data->t1_degc_x8 -
				     drv_data->t0_degc_x8) *
			   (drv_data->t_sample - drv_data->t0_out) /
			   (drv_data->t1_out - drv_data->t0_out) +
			   drv_data->t0_degc_x8;

		/* convert temperature x8 to degrees Celsius */
		val->val1 = conv_val / 8;
		val->val2 = (conv_val % 8) * (1000000 / 8);
	} else { /* SENSOR_CHAN_HUMIDITY */
		conv_val = (s32_t)(drv_data->h1_rh_x2 - drv_data->h0_rh_x2) *
			   (drv_data->rh_sample - drv_data->h0_t0_out) /
			   (drv_data->h1_t0_out - drv_data->h0_t0_out) +
			   drv_data->h0_rh_x2;

		/* convert humidity x2 to percent */
		val->val1 = conv_val / 2;
		val->val2 = (conv_val % 2) * 500000;
	}

	return 0;
}

static int hts221_sample_fetch(struct device *dev, enum sensor_channel chan)
{
	struct hts221_data *drv_data = dev->driver_data;
	u8_t buf[4];

	__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);

	if (i2c_burst_read(drv_data->i2c, DT_ST_HTS221_0_BASE_ADDRESS,
			   HTS221_REG_DATA_START | HTS221_AUTOINCREMENT_ADDR,
			   buf, 4) < 0) {
		LOG_ERR("Failed to fetch data sample.");
		return -EIO;
	}

	drv_data->rh_sample = sys_le16_to_cpu(buf[0] | (buf[1] << 8));
	drv_data->t_sample = sys_le16_to_cpu(buf[2] | (buf[3] << 8));

	return 0;
}

static int hts221_read_conversion_data(struct hts221_data *drv_data)
{
	u8_t buf[16];

	if (i2c_burst_read(drv_data->i2c, DT_ST_HTS221_0_BASE_ADDRESS,
			   HTS221_REG_CONVERSION_START |
			   HTS221_AUTOINCREMENT_ADDR, buf, 16) < 0) {
		LOG_ERR("Failed to read conversion data.");
		return -EIO;
	}

	drv_data->h0_rh_x2 = buf[0];
	drv_data->h1_rh_x2 = buf[1];
	drv_data->t0_degc_x8 = sys_le16_to_cpu(buf[2] | ((buf[5] & 0x3) << 8));
	drv_data->t1_degc_x8 = sys_le16_to_cpu(buf[3] | ((buf[5] & 0xC) << 6));
	drv_data->h0_t0_out = sys_le16_to_cpu(buf[6] | (buf[7] << 8));
	drv_data->h1_t0_out = sys_le16_to_cpu(buf[10] | (buf[11] << 8));
	drv_data->t0_out = sys_le16_to_cpu(buf[12] | (buf[13] << 8));
	drv_data->t1_out = sys_le16_to_cpu(buf[14] | (buf[15] << 8));

	return 0;
}

static const struct sensor_driver_api hts221_driver_api = {
#if CONFIG_HTS221_TRIGGER
	.trigger_set = hts221_trigger_set,
#endif
	.sample_fetch = hts221_sample_fetch,
	.channel_get = hts221_channel_get,
};

int hts221_init(struct device *dev)
{
	struct hts221_data *drv_data = dev->driver_data;
	u8_t id, idx;

	drv_data->i2c = device_get_binding(DT_ST_HTS221_0_BUS_NAME);
	if (drv_data->i2c == NULL) {
		LOG_ERR("Could not get pointer to %s device.",
			    DT_ST_HTS221_0_BUS_NAME);
		return -EINVAL;
	}

	/* check chip ID */
	if (i2c_reg_read_byte(drv_data->i2c, DT_ST_HTS221_0_BASE_ADDRESS,
			      HTS221_REG_WHO_AM_I, &id) < 0) {
		LOG_ERR("Failed to read chip ID.");
		return -EIO;
	}

	if (id != HTS221_CHIP_ID) {
		LOG_ERR("Invalid chip ID.");
		return -EINVAL;
	}

	/* check if CONFIG_HTS221_ODR is valid */
	for (idx = 0U; idx < ARRAY_SIZE(hts221_odr_strings); idx++) {
		if (!strcmp(hts221_odr_strings[idx], CONFIG_HTS221_ODR)) {
			break;
		}
	}

	if (idx == ARRAY_SIZE(hts221_odr_strings)) {
		LOG_ERR("Invalid ODR value.");
		return -EINVAL;
	}

	if (i2c_reg_write_byte(drv_data->i2c, DT_ST_HTS221_0_BASE_ADDRESS,
			       HTS221_REG_CTRL1,
			       (idx + 1) << HTS221_ODR_SHIFT | HTS221_BDU_BIT |
			       HTS221_PD_BIT) < 0) {
		LOG_ERR("Failed to configure chip.");
		return -EIO;
	}

	/*
	 * the device requires about 2.2 ms to download the flash content
	 * into the volatile mem
	 */
	k_sleep(3);

	if (hts221_read_conversion_data(drv_data) < 0) {
		LOG_ERR("Failed to read conversion data.");
		return -EINVAL;
	}

#ifdef CONFIG_HTS221_TRIGGER
	if (hts221_init_interrupt(dev) < 0) {
		LOG_ERR("Failed to initialize interrupt.");
		return -EIO;
	}
#endif

	return 0;
}

struct hts221_data hts221_driver;

DEVICE_AND_API_INIT(hts221, DT_ST_HTS221_0_LABEL, hts221_init, &hts221_driver,
		    NULL, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,
		    &hts221_driver_api);
