aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Royer <nroyer@baylibre.com>2020-09-27 17:46:43 +0200
committernicola-mazzucato-arm <42373140+nicola-mazzucato-arm@users.noreply.github.com>2020-10-15 17:45:38 +0100
commitc96ddcce819116effc4f61d0bddc65aa56c99f6e (patch)
tree644e94dbf30785a3c849ef53d58261a2e2a15d22
parente88b03fd71f44a24bdf0cc72838f276404de7b0b (diff)
rcar/module: add rcar reg_sensor module
Change-Id: I59ba3eb358fcfc9b76e0b7daa7621abfaeec5028 Signed-off-by: Tsutomu Muroya <tsutomu.muroya.jy@bp.renesas.com> Signed-off-by: Chikara Asou <chikara.aso.uj@bp.renesas.com> Signed-off-by: Nicolas Royer <nroyer@baylibre.com>
-rw-r--r--product/rcar/module/rcar_reg_sensor/include/mod_rcar_reg_sensor.h154
-rw-r--r--product/rcar/module/rcar_reg_sensor/include/mod_reg_sensor.h19
-rw-r--r--product/rcar/module/rcar_reg_sensor/src/Makefile11
-rw-r--r--product/rcar/module/rcar_reg_sensor/src/mod_rcar_reg_sensor.c240
4 files changed, 424 insertions, 0 deletions
diff --git a/product/rcar/module/rcar_reg_sensor/include/mod_rcar_reg_sensor.h b/product/rcar/module/rcar_reg_sensor/include/mod_rcar_reg_sensor.h
new file mode 100644
index 00000000..5c57fec5
--- /dev/null
+++ b/product/rcar/module/rcar_reg_sensor/include/mod_rcar_reg_sensor.h
@@ -0,0 +1,154 @@
+/*
+ * Renesas SCP/MCP Software
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MOD_RCAR_REG_SENSOR_H
+#define MOD_RCAR_REG_SENSOR_H
+
+#include <mod_sensor.h>
+
+#include <stdint.h>
+
+/*!
+ * \addtogroup GroupRCARModule RCAR Product Modules
+ * @{
+ */
+
+/*!
+ * \defgroup GroupRCARRegSensor Register Sensor Driver
+ *
+ * \brief Driver for simple, register-based sensors.
+ * @{
+ */
+
+/*! \brief Element configuration */
+struct mod_reg_sensor_dev_config {
+ /*! Address of the sensor register */
+ uintptr_t reg;
+
+ /*! Auxiliary sensor information */
+ struct mod_sensor_info *info;
+};
+
+/*!
+ * @cond
+ */
+
+/* Register base */
+#define GEN3_THERMAL_BASE (PERIPHERAL_BASE + 0x198000)
+#define GEN3_THERMAL_OFFSET (0x8000)
+/* Register offsets */
+#define REG_GEN3_IRQSTR (0x04)
+#define REG_GEN3_IRQMSK (0x08)
+#define REG_GEN3_IRQCTL (0x0C)
+#define REG_GEN3_IRQEN (0x10)
+#define REG_GEN3_IRQTEMP1 (0x14)
+#define REG_GEN3_IRQTEMP2 (0x18)
+#define REG_GEN3_IRQTEMP3 (0x1C)
+#define REG_GEN3_CTSR (0x20)
+#define REG_GEN3_THCTR (0x20)
+#define REG_GEN3_TEMP (0x28)
+#define REG_GEN3_THCODE1 (0x50)
+#define REG_GEN3_THCODE2 (0x54)
+#define REG_GEN3_THCODE3 (0x58)
+#define REG_GEN3_PTAT1 (0x5C)
+#define REG_GEN3_PTAT2 (0x60)
+#define REG_GEN3_PTAT3 (0x64)
+#define REG_GEN3_THSCP (0x68)
+#define NEXT_REG_OFFSET (4)
+
+/* THCTR bits */
+#define THCTR_PONM BIT(6)
+#define THCTR_THSST BIT(0)
+
+#define CTEMP_MASK (0xFFF)
+#define MCELSIUS(temp) ((temp)*1000)
+
+#define AVAILABLE_HARDWARE_PARAM \
+ (mmio_read_32(GEN3_THERMAL_BASE + REG_GEN3_THSCP) == (0x03 << 14))
+
+/* Structure for thermal temperature calculation */
+struct equation_coefs {
+ int a1;
+ int b1;
+ int a2;
+ int b2;
+};
+
+struct rcar_gen3_thermal_tsc {
+ uintptr_t base;
+ struct thermal_zone_device *zone;
+ struct equation_coefs coef;
+ int low;
+ int high;
+ int tj_t;
+ int id; /* thermal channel id */
+};
+
+/*
+ * Linear approximation for temperature
+ *
+ * [reg] = [temp] * a + b => [temp] = ([reg] - b) / a
+ *
+ * The constants a and b are calculated using two triplets of int values PTAT
+ * and THCODE. PTAT and THCODE can either be read from hardware or use hard
+ * coded values from driver. The formula to calculate a and b are taken from
+ * BSP and sparsely documented and understood.
+ *
+ * Examining the linear formula and the formula used to calculate constants a
+ * and b while knowing that the span for PTAT and THCODE values are between
+ * 0x000 and 0xfff the largest integer possible is 0xfff * 0xfff == 0xffe001.
+ * Integer also needs to be signed so that leaves 7 bits for binary
+ * fixed point scaling.
+ */
+#define DIV_ROUND_CLOSEST(x, divisor) \
+ ({ \
+ __typeof(x) __x = x; \
+ __typeof(divisor) __d = divisor; \
+ (((__typeof(x)) - 1) > 0 || ((__typeof(divisor)) - 1) > 0 || \
+ (__x) > 0) ? \
+ (((__x) + ((__d) / 2)) / (__d)) : \
+ (((__x) - ((__d) / 2)) / (__d)); \
+ })
+#define FIXPT_SHIFT (7)
+#define FIXPT_INT(_x) ((_x) * (1 << FIXPT_SHIFT))
+#define INT_FIXPT(_x) ((_x) >> FIXPT_SHIFT)
+#define FIXPT_DIV(_a, _b) DIV_ROUND_CLOSEST(((_a) * (1 << FIXPT_SHIFT)), (_b))
+#define FIXPT_TO_MCELSIUS(_x) ((_x)*1000 >> FIXPT_SHIFT)
+
+#define RCAR3_THERMAL_GRAN (500) /* mili Celsius */
+
+#define TSC_MAX_NUM (3)
+#define TSC_PARAM_NUM (3)
+#define TEMP_UPPER_LIMIT (125)
+#define TEMP_LOWER_LIMIT (-40)
+
+/* no idea where these constants come from */
+#define TJ_1 (116)
+#define TJ_3 (-41)
+
+#define SENSOR_ADR_BASE (SENSOR_SOC_TEMP1 & SENSOR_SOC_TEMP2 & SENSOR_SOC_TEMP3)
+#define SENSOR_ADR_MASK \
+ ((SENSOR_SOC_TEMP1 | SENSOR_SOC_TEMP2 | SENSOR_SOC_TEMP3) - SENSOR_ADR_BASE)
+#define IS_SENSOR_ADR(adr) ((adr & ~SENSOR_ADR_MASK) == SENSOR_ADR_BASE)
+#define CV_ADR2INDEX(adr) (int)(((adr & SENSOR_ADR_MASK) >> 15) - 3)
+#define ADR2INDEX(adr) (IS_SENSOR_ADR(adr) ? CV_ADR2INDEX(adr) : (-1))
+
+void reg_sensor_resume();
+
+/*!
+ * @endcond
+ */
+
+/*!
+ * @}
+ */
+
+/*!
+ * @}
+ */
+
+#endif /* MOD_RCAR_REG_SENSOR_H */
diff --git a/product/rcar/module/rcar_reg_sensor/include/mod_reg_sensor.h b/product/rcar/module/rcar_reg_sensor/include/mod_reg_sensor.h
new file mode 100644
index 00000000..b42ff068
--- /dev/null
+++ b/product/rcar/module/rcar_reg_sensor/include/mod_reg_sensor.h
@@ -0,0 +1,19 @@
+/*
+ * Renesas SCP/MCP Software
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MOD_REG_SENSOR_H
+#define MOD_REG_SENSOR_H
+
+#include <mod_sensor.h>
+
+#include <stdint.h>
+
+#define FWK_MODULE_IDX_REG_SENSOR FWK_MODULE_IDX_RCAR_REG_SENSOR
+
+#include "mod_rcar_reg_sensor.h"
+
+#endif /* MOD_REG_SENSOR_H */
diff --git a/product/rcar/module/rcar_reg_sensor/src/Makefile b/product/rcar/module/rcar_reg_sensor/src/Makefile
new file mode 100644
index 00000000..9a7056e2
--- /dev/null
+++ b/product/rcar/module/rcar_reg_sensor/src/Makefile
@@ -0,0 +1,11 @@
+#
+# Renesas SCP/MCP Software
+# Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BS_LIB_NAME := rcar_reg_sensor
+BS_LIB_SOURCES := mod_rcar_reg_sensor.c
+
+include $(BS_DIR)/lib.mk
diff --git a/product/rcar/module/rcar_reg_sensor/src/mod_rcar_reg_sensor.c b/product/rcar/module/rcar_reg_sensor/src/mod_rcar_reg_sensor.c
new file mode 100644
index 00000000..554b93ac
--- /dev/null
+++ b/product/rcar/module/rcar_reg_sensor/src/mod_rcar_reg_sensor.c
@@ -0,0 +1,240 @@
+/*
+ * Renesas SCP/MCP Software
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <mmio.h>
+#include <system_mmap.h>
+
+#include <mod_reg_sensor.h>
+#include <mod_sensor.h>
+
+#include <fwk_assert.h>
+#include <fwk_id.h>
+#include <fwk_mm.h>
+#include <fwk_module.h>
+#include <fwk_status.h>
+
+#include <stdint.h>
+
+/* default values if FUSEs are missing */
+/* TODO: Read values from hardware on supported platforms */
+int ptat[3] = { 2631, 1509, 435 };
+int thcode[TSC_MAX_NUM][3] = {
+ { 3397, 2800, 2221 },
+ { 3393, 2795, 2216 },
+ { 3389, 2805, 2237 },
+};
+struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM];
+
+static struct mod_reg_sensor_dev_config **config_table;
+static const int rcar_gen3_ths_tj_1 = 126;
+
+static inline uint32_t rcar_gen3_thermal_read(
+ struct rcar_gen3_thermal_tsc *tsc,
+ uint32_t reg)
+{
+ return mmio_read_32(tsc->base + reg);
+}
+
+static inline void rcar_gen3_thermal_write(
+ struct rcar_gen3_thermal_tsc *tsc,
+ uint32_t reg,
+ uint32_t data)
+{
+ mmio_write_32(tsc->base + reg, data);
+}
+
+static void rcar_gen3_thermal_calc_coefs(
+ struct rcar_gen3_thermal_tsc *tsc,
+ int *ptat,
+ const int *thcode,
+ int ths_tj_1)
+{
+ /* TODO: Find documentation and document constant calculation formula */
+
+ /*
+ * Division is not scaled in BSP and if scaled it might overflow
+ * the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled
+ */
+ tsc->tj_t = (FIXPT_INT((ptat[1] - ptat[2]) * 157) / (ptat[0] - ptat[2])) +
+ FIXPT_INT(TJ_3);
+
+ tsc->coef.a1 = FIXPT_DIV(
+ FIXPT_INT(thcode[1] - thcode[2]), tsc->tj_t - FIXPT_INT(TJ_3));
+ tsc->coef.b1 = FIXPT_INT(thcode[2]) - tsc->coef.a1 * TJ_3;
+
+ tsc->coef.a2 = FIXPT_DIV(
+ FIXPT_INT(thcode[1] - thcode[0]), tsc->tj_t - FIXPT_INT(ths_tj_1));
+ tsc->coef.b2 = FIXPT_INT(thcode[0]) - tsc->coef.a2 * ths_tj_1;
+}
+
+static int rcar_gen3_thermal_round(int temp)
+{
+ int result, round_offs;
+
+ round_offs = temp >= 0 ? RCAR3_THERMAL_GRAN / 2 : -RCAR3_THERMAL_GRAN / 2;
+ result = (temp + round_offs) / RCAR3_THERMAL_GRAN;
+ return result * RCAR3_THERMAL_GRAN;
+}
+
+static int rcar_gen3_thermal_get_temp(void *devdata, int *temp)
+{
+ struct rcar_gen3_thermal_tsc *tsc = devdata;
+ int mcelsius, val;
+ int reg;
+
+ /* Read register and convert to mili Celsius */
+ reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK;
+
+ if (reg <= thcode[tsc->id][1])
+ val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1, tsc->coef.a1);
+ else
+ val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b2, tsc->coef.a2);
+ mcelsius = FIXPT_TO_MCELSIUS(val);
+
+ /* Make sure we are inside specifications */
+ if ((mcelsius < MCELSIUS(TEMP_LOWER_LIMIT)) ||
+ (mcelsius > MCELSIUS(TEMP_UPPER_LIMIT)))
+ return -1 /*-EIO*/;
+
+ /* Round value to device granularity setting */
+ *temp = rcar_gen3_thermal_round(mcelsius);
+
+ return 0;
+}
+
+/*
+ * Module API
+ */
+static int get_value(fwk_id_t id, uint64_t *value)
+{
+ int tmp;
+ int64_t *ivalue;
+
+ if (value == NULL) {
+ assert(false);
+ return FWK_E_PARAM;
+ }
+
+ if (rcar_gen3_thermal_get_temp(tscs[fwk_id_get_element_idx(id)], &tmp))
+ return FWK_E_DATA;
+
+ ivalue = (void *)value;
+ *ivalue = (int64_t)tmp;
+
+ return FWK_SUCCESS;
+}
+
+static int get_info(fwk_id_t id, struct mod_sensor_info *info)
+{
+ struct mod_reg_sensor_dev_config *config;
+
+ config = config_table[fwk_id_get_element_idx(id)];
+ fwk_assert(config != NULL);
+
+ if (info == NULL)
+ return FWK_E_PARAM;
+
+ *info = *(config->info);
+
+ return FWK_SUCCESS;
+}
+
+static const struct mod_sensor_driver_api reg_sensor_api = {
+ .get_value = get_value,
+ .get_info = get_info,
+};
+
+/*
+ * Framework handlers
+ */
+static int reg_sensor_start(fwk_id_t id)
+{
+ int eid, pid;
+ struct rcar_gen3_thermal_tsc *tsc;
+ struct mod_reg_sensor_dev_config *config;
+
+ /* for Module */
+ if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE))
+ return FWK_SUCCESS;
+
+ /* for Elements */
+ eid = fwk_id_get_element_idx(id);
+ tsc = fwk_mm_alloc(1, sizeof(*tsc));
+ if (!tsc)
+ return FWK_E_NOMEM;
+
+ config = config_table[eid];
+ pid = ADR2INDEX(config->reg);
+ if (pid < 0)
+ return FWK_E_DATA;
+ tsc->base = config->reg;
+ rcar_gen3_thermal_calc_coefs(tsc, ptat, thcode[pid], rcar_gen3_ths_tj_1);
+ tsc->id = pid;
+ tscs[eid] = tsc;
+ rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, THCTR_THSST);
+
+ return FWK_SUCCESS;
+}
+
+static int reg_sensor_init(
+ fwk_id_t module_id,
+ unsigned int element_count,
+ const void *unused)
+{
+ config_table = fwk_mm_alloc(element_count, sizeof(*config_table));
+ if (config_table == NULL)
+ return FWK_E_NOMEM;
+
+ return FWK_SUCCESS;
+}
+
+static int reg_sensor_element_init(
+ fwk_id_t element_id,
+ unsigned int sub_element_count,
+ const void *data)
+{
+ struct mod_reg_sensor_dev_config *config =
+ (struct mod_reg_sensor_dev_config *)data;
+
+ if (config->reg == 0)
+ return FWK_E_DATA;
+
+ config_table[fwk_id_get_element_idx(element_id)] = config;
+
+ return FWK_SUCCESS;
+}
+
+void reg_sensor_resume()
+{
+ int i;
+
+ for (i = 0; i < TSC_MAX_NUM; i++) {
+ if (tscs[i]) {
+ rcar_gen3_thermal_write(tscs[i], REG_GEN3_THCTR, THCTR_THSST);
+ }
+ }
+}
+
+static int reg_sensor_process_bind_request(
+ fwk_id_t source_id,
+ fwk_id_t target_id,
+ fwk_id_t api_type,
+ const void **api)
+{
+ *api = &reg_sensor_api;
+ return FWK_SUCCESS;
+}
+
+const struct fwk_module module_rcar_reg_sensor = {
+ .name = "Rcar Thermal Sensor",
+ .api_count = 1,
+ .type = FWK_MODULE_TYPE_DRIVER,
+ .init = reg_sensor_init,
+ .start = reg_sensor_start,
+ .element_init = reg_sensor_element_init,
+ .process_bind_request = reg_sensor_process_bind_request,
+};