Skip to content

Commit

Permalink
drivers: sensor: Add driver for SB-TSI
Browse files Browse the repository at this point in the history
Add a driver for the SB Temperature Sensor Interface. This is an I2C
temperature sensor on AMD SoCs.

Signed-off-by: Paweł Anikiel <[email protected]>
  • Loading branch information
Paweł Anikiel committed Aug 9, 2023
1 parent 959e0e8 commit 2afbdb7
Show file tree
Hide file tree
Showing 9 changed files with 348 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/sensor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions drivers/sensor/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
5 changes: 5 additions & 0 deletions drivers/sensor/amd_sb_tsi/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
21 changes: 21 additions & 0 deletions drivers/sensor/amd_sb_tsi/Kconfig
Original file line number Diff line number Diff line change
@@ -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.
122 changes: 122 additions & 0 deletions drivers/sensor/amd_sb_tsi/sb_tsi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright (c) 2023 Google LLC
*
* SPDX-License-Identifier: Apache-2.0
*/

#define DT_DRV_COMPAT amd_sb_tsi

#include <zephyr/device.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/device_runtime.h>
#include <zephyr/logging/log.h>
#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)
27 changes: 27 additions & 0 deletions drivers/sensor/amd_sb_tsi/sb_tsi.h
Original file line number Diff line number Diff line change
@@ -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 <zephyr/device.h>
#include <zephyr/sys/util.h>

#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
158 changes: 158 additions & 0 deletions drivers/sensor/amd_sb_tsi/sb_tsi_emul.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*
* Copyright (c) 2023 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

#define DT_DRV_COMPAT amd_sb_tsi

#include <zephyr/device.h>
#include <zephyr/drivers/emul.h>
#include <zephyr/drivers/emul_sensor.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/i2c_emul.h>
#include <zephyr/logging/log.h>
#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)
8 changes: 8 additions & 0 deletions dts/bindings/sensor/amd,sb-tsi.yaml
Original file line number Diff line number Diff line change
@@ -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]
5 changes: 5 additions & 0 deletions tests/drivers/build_all/sensor/i2c.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
};

0 comments on commit 2afbdb7

Please sign in to comment.