-
Notifications
You must be signed in to change notification settings - Fork 6.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
drivers: sensor: Add driver for SB-TSI
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 8, 2023
1 parent
959e0e8
commit 2472f26
Showing
9 changed files
with
344 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
/* | ||
* 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; | ||
int res; | ||
|
||
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) { | ||
return -ENOTSUP; | ||
} | ||
|
||
res = pm_device_runtime_get(dev); | ||
if (res) { | ||
return res; | ||
} | ||
|
||
/* | ||
* 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) { | ||
res = i2c_reg_read_byte_dt(&config->i2c, SB_TSI_TEMP_DEC, &data->sample_dec); | ||
} | ||
|
||
(void)pm_device_runtime_put(dev); | ||
|
||
return res; | ||
} | ||
|
||
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters