diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 00cbc655e35b5dd..603cba27d742703 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -9,6 +9,7 @@ add_subdirectory_ifdef(CONFIG_ADXL362 adxl362) add_subdirectory_ifdef(CONFIG_ADXL372 adxl372) add_subdirectory_ifdef(CONFIG_AK8975 ak8975) add_subdirectory_ifdef(CONFIG_AKM09918C akm09918c) +add_subdirectory_ifdef(CONFIG_AMD_SB_TSI amd_sb_tsi) add_subdirectory_ifdef(CONFIG_AMG88XX amg88xx) add_subdirectory_ifdef(CONFIG_AMS_AS5600 ams_as5600) add_subdirectory_ifdef(CONFIG_AMS_IAQ_CORE ams_iAQcore) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 26787acf4e50a26..a799f637b96cdce 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -65,6 +65,7 @@ source "drivers/sensor/adxl362/Kconfig" source "drivers/sensor/adxl372/Kconfig" source "drivers/sensor/ak8975/Kconfig" source "drivers/sensor/akm09918c/Kconfig" +source "drivers/sensor/amd_sb_tsi/Kconfig" source "drivers/sensor/amg88xx/Kconfig" source "drivers/sensor/ams_as5600/Kconfig" source "drivers/sensor/ams_iAQcore/Kconfig" diff --git a/drivers/sensor/amd_sb_tsi/CMakeLists.txt b/drivers/sensor/amd_sb_tsi/CMakeLists.txt new file mode 100644 index 000000000000000..e9a33c445ae0a8b --- /dev/null +++ b/drivers/sensor/amd_sb_tsi/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_sources(sb_tsi.c) +zephyr_library_sources_ifdef(CONFIG_EMUL_AMD_SB_TSI sb_tsi_emul.c) diff --git a/drivers/sensor/amd_sb_tsi/Kconfig b/drivers/sensor/amd_sb_tsi/Kconfig new file mode 100644 index 000000000000000..93e7ddb52e1e069 --- /dev/null +++ b/drivers/sensor/amd_sb_tsi/Kconfig @@ -0,0 +1,21 @@ +# SB-TSI configuration options + +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config AMD_SB_TSI + bool "AMD SB Temperature Sensor Interface" + default y + depends on DT_HAS_AMD_SB_TSI_ENABLED + select I2C + help + Enable the driver for SB Temperature Sensor Interface. This + is an I2C temperature sensor on AMD SoCs. + +config EMUL_AMD_SB_TSI + bool "Emulator for AMD SB-TSI" + default y + depends on AMD_SB_TSI + depends on EMUL + help + Enable the hardware emulator for the AMD SB-TSI. diff --git a/drivers/sensor/amd_sb_tsi/sb_tsi.c b/drivers/sensor/amd_sb_tsi/sb_tsi.c new file mode 100644 index 000000000000000..30342f7200380c0 --- /dev/null +++ b/drivers/sensor/amd_sb_tsi/sb_tsi.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT amd_sb_tsi + +#include +#include +#include +#include +#include +#include +#include "sb_tsi.h" + +LOG_MODULE_REGISTER(AMD_SB_TSI, CONFIG_SENSOR_LOG_LEVEL); + +static int sb_tsi_sample_fetch(const struct device *dev, + enum sensor_channel chan) +{ + struct sb_tsi_data *data = dev->data; + const struct sb_tsi_config *config = dev->config; + enum pm_device_state pm_state; + int res; + + (void)pm_device_state_get(dev, &pm_state); + if (pm_state != PM_DEVICE_STATE_ACTIVE) { + return -EIO; + } + + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) { + return -ENOTSUP; + } + + /* + * ReadOrder specifies the order for atomically reading the temp. + * The reset value is 0, which means reading Int latches Dec. + */ + res = i2c_reg_read_byte_dt(&config->i2c, SB_TSI_TEMP_INT, &data->sample_int); + if (res) { + return res; + } + + res = i2c_reg_read_byte_dt(&config->i2c, SB_TSI_TEMP_DEC, &data->sample_dec); + if (res) { + return res; + } + + return 0; +} + +static int sb_tsi_channel_get(const struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + struct sb_tsi_data *data = dev->data; + + if (chan != SENSOR_CHAN_DIE_TEMP) { + return -ENOTSUP; + } + + val->val1 = data->sample_int; + val->val2 = (data->sample_dec >> SB_TSI_TEMP_DEC_SHIFT) * + (1000000 / SB_TSI_TEMP_DEC_SCALE); + + return 0; +} + +static const struct sensor_driver_api sb_tsi_driver_api = { + .sample_fetch = sb_tsi_sample_fetch, + .channel_get = sb_tsi_channel_get, +}; + +static int sb_tsi_init(const struct device *dev) +{ + const struct sb_tsi_config *config = dev->config; + int res = 0; + + if (!i2c_is_ready_dt(&config->i2c)) { + LOG_ERR("I2C device not ready"); + return -ENODEV; + } + +#ifdef CONFIG_PM_DEVICE_RUNTIME + pm_device_init_suspended(dev); + + res = pm_device_runtime_enable(dev); + if (res) { + LOG_ERR("Failed to enable runtime power management"); + } +#endif + + return res; +} + +#ifdef CONFIG_PM_DEVICE +static int sb_tsi_pm_action(const struct device *dev, enum pm_device_action action) +{ + switch (action) { + case PM_DEVICE_ACTION_TURN_ON: + case PM_DEVICE_ACTION_RESUME: + case PM_DEVICE_ACTION_TURN_OFF: + case PM_DEVICE_ACTION_SUSPEND: + return 0; + default: + return -ENOTSUP; + } +} +#endif + +#define SB_TSI_INST(inst) \ + static struct sb_tsi_data sb_tsi_data_##inst; \ + static const struct sb_tsi_config sb_tsi_config_##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }; \ + PM_DEVICE_DT_INST_DEFINE(inst, sb_tsi_pm_action); \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, sb_tsi_init, PM_DEVICE_DT_INST_GET(inst), \ + &sb_tsi_data_##inst, &sb_tsi_config_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &sb_tsi_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(SB_TSI_INST) diff --git a/drivers/sensor/amd_sb_tsi/sb_tsi.h b/drivers/sensor/amd_sb_tsi/sb_tsi.h new file mode 100644 index 000000000000000..d8a52c024785df7 --- /dev/null +++ b/drivers/sensor/amd_sb_tsi/sb_tsi.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_SB_TSI_SB_TSI_H_ +#define ZEPHYR_DRIVERS_SENSOR_SB_TSI_SB_TSI_H_ + +#include +#include + +#define SB_TSI_TEMP_INT 0x01 +#define SB_TSI_TEMP_DEC 0x10 +#define SB_TSI_TEMP_DEC_SHIFT 5 +#define SB_TSI_TEMP_DEC_SCALE 8 + +struct sb_tsi_data { + uint8_t sample_int; + uint8_t sample_dec; +}; + +struct sb_tsi_config { + struct i2c_dt_spec i2c; +}; + +#endif diff --git a/drivers/sensor/amd_sb_tsi/sb_tsi_emul.c b/drivers/sensor/amd_sb_tsi/sb_tsi_emul.c new file mode 100644 index 000000000000000..f8c04faf5aa65ab --- /dev/null +++ b/drivers/sensor/amd_sb_tsi/sb_tsi_emul.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT amd_sb_tsi + +#include +#include +#include +#include +#include +#include +#include "sb_tsi.h" + +LOG_MODULE_DECLARE(AMD_SB_TSI, CONFIG_SENSOR_LOG_LEVEL); + +#define NUM_REGS 128 + +struct sb_tsi_emul_data { + uint8_t reg[NUM_REGS]; +}; + +struct sb_tsi_emul_cfg { +}; + +static void sb_tsi_emul_set_reg(const struct emul *target, uint8_t reg, uint8_t val) +{ + struct sb_tsi_emul_data *data = target->data; + + __ASSERT_NO_MSG(reg < NUM_REGS); + data->reg[reg] = val; +} + +static uint8_t sb_tsi_emul_get_reg(const struct emul *target, uint8_t reg) +{ + struct sb_tsi_emul_data *data = target->data; + + __ASSERT_NO_MSG(reg < NUM_REGS); + return data->reg[reg]; +} + +static void sb_tsi_emul_reset(const struct emul *target) +{ + struct sb_tsi_emul_data *data = target->data; + + memset(data->reg, 0, NUM_REGS); +} + +static int sb_tsi_emul_transfer_i2c(const struct emul *target, struct i2c_msg *msgs, + int num_msgs, int addr) +{ + /* Largely copied from emul_bmi160.c */ + unsigned int val; + int reg; + + __ASSERT_NO_MSG(msgs && num_msgs); + + i2c_dump_msgs_rw("emul", msgs, num_msgs, addr, false); + switch (num_msgs) { + case 2: + if (msgs->flags & I2C_MSG_READ) { + LOG_ERR("Unexpected read"); + return -EIO; + } + if (msgs->len != 1) { + LOG_ERR("Unexpected msg0 length %d", msgs->len); + return -EIO; + } + reg = msgs->buf[0]; + + /* Now process the 'read' part of the message */ + msgs++; + if (msgs->flags & I2C_MSG_READ) { + switch (msgs->len) { + case 1: + val = sb_tsi_emul_get_reg(target, reg); + msgs->buf[0] = val; + break; + default: + LOG_ERR("Unexpected msg1 length %d", msgs->len); + return -EIO; + } + } else { + if (msgs->len != 1) { + LOG_ERR("Unexpected msg1 length %d", msgs->len); + } + sb_tsi_emul_set_reg(target, reg, msgs->buf[0]); + } + break; + default: + LOG_ERR("Invalid number of messages: %d", num_msgs); + return -EIO; + } + + return 0; +} + +static int sb_tsi_emul_init(const struct emul *target, const struct device *parent) +{ + sb_tsi_emul_reset(target); + return 0; +} + +static int sb_tsi_emul_set_channel(const struct emul *target, enum sensor_channel chan, + q31_t value, int8_t shift) +{ + struct sb_tsi_emul_data *data = target->data; + int64_t scaled_value; + int32_t millicelsius; + int32_t reg_value; + + if (chan != SENSOR_CHAN_DIE_TEMP) { + return -ENOTSUP; + } + + scaled_value = (int64_t)value << shift; + millicelsius = scaled_value * 1000 / ((int64_t)INT32_MAX + 1); + reg_value = CLAMP(millicelsius / 125, 0, 0x7ff); + + data->reg[SB_TSI_TEMP_INT] = reg_value >> 3; + data->reg[SB_TSI_TEMP_DEC] = (reg_value & 0x7) << 5; + + return 0; +} + +static int sb_tsi_emul_get_sample_range(const struct emul *target, enum sensor_channel chan, + q31_t *lower, q31_t *upper, q31_t *epsilon, int8_t *shift) +{ + if (chan != SENSOR_CHAN_DIE_TEMP) { + return -ENOTSUP; + } + + *shift = 8; + *lower = 0; + *upper = (int64_t)(255.875 * ((int64_t)INT32_MAX + 1)) >> *shift; + *epsilon = (int64_t)(0.125 * ((int64_t)INT32_MAX + 1)) >> *shift; + + return 0; +} + +static const struct i2c_emul_api sb_tsi_emul_api_i2c = { + .transfer = sb_tsi_emul_transfer_i2c, +}; + +static const struct emul_sensor_backend_api sb_tsi_emul_api_sensor = { + .set_channel = sb_tsi_emul_set_channel, + .get_sample_range = sb_tsi_emul_get_sample_range, +}; + +#define SB_TSI_EMUL(n) \ + const struct sb_tsi_emul_cfg sb_tsi_emul_cfg_##n; \ + struct sb_tsi_emul_data sb_tsi_emul_data_##n; \ + EMUL_DT_INST_DEFINE(n, sb_tsi_emul_init, &sb_tsi_emul_data_##n, \ + &sb_tsi_emul_cfg_##n, &sb_tsi_emul_api_i2c, \ + &sb_tsi_emul_api_sensor) + +DT_INST_FOREACH_STATUS_OKAY(SB_TSI_EMUL) diff --git a/dts/bindings/sensor/amd,sb-tsi.yaml b/dts/bindings/sensor/amd,sb-tsi.yaml new file mode 100644 index 000000000000000..f9204b79db23dbf --- /dev/null +++ b/dts/bindings/sensor/amd,sb-tsi.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: AMD SB Temperature Sensor Interface. + +compatible: "amd,sb-tsi" + +include: [sensor-device.yaml, i2c-device.yaml] diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index c45f47c492d2afe..961cd1924c270e6 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -744,3 +744,8 @@ test_i2c_ist8310@6f { reg = <0x6f>; status = "okay"; }; + +test_i2c_amd_sb_tsi: amd_sb_tsi@70 { + compatible = "amd,sb-tsi"; + reg = <0x70>; +};