drivers: sensor: Add F75303 driver
Add driver for F75303 temperature sensor IC. Signed-off-by: Paweł Anikiel <pan@semihalf.com>
This commit is contained in:
parent
f020aa41fc
commit
43668c6416
|
@ -32,6 +32,7 @@ add_subdirectory_ifdef(CONFIG_DPS310 dps310)
|
|||
add_subdirectory_ifdef(CONFIG_DS18B20 ds18b20)
|
||||
add_subdirectory_ifdef(CONFIG_ENS210 ens210)
|
||||
add_subdirectory_ifdef(CONFIG_ESP32_TEMP esp32_temp)
|
||||
add_subdirectory_ifdef(CONFIG_F75303 f75303)
|
||||
add_subdirectory_ifdef(CONFIG_FDC2X1X fdc2x1x)
|
||||
add_subdirectory_ifdef(CONFIG_FXAS21002 fxas21002)
|
||||
add_subdirectory_ifdef(CONFIG_FXOS8700 fxos8700)
|
||||
|
|
|
@ -88,6 +88,7 @@ source "drivers/sensor/dps310/Kconfig"
|
|||
source "drivers/sensor/ds18b20/Kconfig"
|
||||
source "drivers/sensor/ens210/Kconfig"
|
||||
source "drivers/sensor/esp32_temp/Kconfig"
|
||||
source "drivers/sensor/f75303/Kconfig"
|
||||
source "drivers/sensor/fdc2x1x/Kconfig"
|
||||
source "drivers/sensor/fxas21002/Kconfig"
|
||||
source "drivers/sensor/fxos8700/Kconfig"
|
||||
|
|
5
drivers/sensor/f75303/CMakeLists.txt
Normal file
5
drivers/sensor/f75303/CMakeLists.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_library()
|
||||
zephyr_library_sources(f75303.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_EMUL_F75303 f75303_emul.c)
|
22
drivers/sensor/f75303/Kconfig
Normal file
22
drivers/sensor/f75303/Kconfig
Normal file
|
@ -0,0 +1,22 @@
|
|||
# F75303 temperature sensor configuration options
|
||||
|
||||
# Copyright (c) 2023 Google LLC
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config F75303
|
||||
bool "F75303 Temperature Sensor"
|
||||
default y
|
||||
depends on DT_HAS_FINTEK_F75303_ENABLED
|
||||
select I2C
|
||||
help
|
||||
Enable the driver for Fintek F75303 Temperature Sensor.
|
||||
This device has three temperature channels - one local (on-chip),
|
||||
and two remote.
|
||||
|
||||
config EMUL_F75303
|
||||
bool "Emulator for F75303"
|
||||
default y
|
||||
depends on F75303
|
||||
depends on EMUL
|
||||
help
|
||||
Enable the hardware emulator for F75303 Temperature Sensor.
|
198
drivers/sensor/f75303/f75303.c
Normal file
198
drivers/sensor/f75303/f75303.c
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Google LLC
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT fintek_f75303
|
||||
|
||||
#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 <zephyr/drivers/sensor/f75303.h>
|
||||
#include "f75303.h"
|
||||
|
||||
#define F75303_SAMPLE_INT_SHIFT 3
|
||||
#define F75303_SAMPLE_FRAC_MASK GENMASK(2, 0)
|
||||
#define F75303_SAMPLE_MICROCELSIUS_PER_BIT 125000
|
||||
|
||||
LOG_MODULE_REGISTER(F75303, CONFIG_SENSOR_LOG_LEVEL);
|
||||
|
||||
static int f75303_fetch(const struct i2c_dt_spec *i2c,
|
||||
uint8_t off_h, uint8_t off_l, uint16_t *sample)
|
||||
{
|
||||
uint8_t val_h;
|
||||
uint8_t val_l;
|
||||
int res;
|
||||
|
||||
res = i2c_reg_read_byte_dt(i2c, off_h, &val_h);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
res = i2c_reg_read_byte_dt(i2c, off_l, &val_l);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
*sample = val_h << 3 | val_l >> 5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int f75303_fetch_local(const struct device *dev)
|
||||
{
|
||||
struct f75303_data *data = dev->data;
|
||||
const struct f75303_config *config = dev->config;
|
||||
|
||||
return f75303_fetch(&config->i2c,
|
||||
F75303_LOCAL_TEMP_H,
|
||||
F75303_LOCAL_TEMP_L,
|
||||
&data->sample_local);
|
||||
}
|
||||
|
||||
static int f75303_fetch_remote1(const struct device *dev)
|
||||
{
|
||||
struct f75303_data *data = dev->data;
|
||||
const struct f75303_config *config = dev->config;
|
||||
|
||||
return f75303_fetch(&config->i2c,
|
||||
F75303_REMOTE1_TEMP_H,
|
||||
F75303_REMOTE1_TEMP_L,
|
||||
&data->sample_remote1);
|
||||
}
|
||||
|
||||
static int f75303_fetch_remote2(const struct device *dev)
|
||||
{
|
||||
struct f75303_data *data = dev->data;
|
||||
const struct f75303_config *config = dev->config;
|
||||
|
||||
return f75303_fetch(&config->i2c,
|
||||
F75303_REMOTE2_TEMP_H,
|
||||
F75303_REMOTE2_TEMP_L,
|
||||
&data->sample_remote2);
|
||||
}
|
||||
|
||||
static int f75303_sample_fetch(const struct device *dev,
|
||||
enum sensor_channel chan)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
switch ((uint32_t)chan) {
|
||||
case SENSOR_CHAN_ALL:
|
||||
res = f75303_fetch_local(dev);
|
||||
if (res) {
|
||||
break;
|
||||
}
|
||||
res = f75303_fetch_remote1(dev);
|
||||
if (res) {
|
||||
break;
|
||||
}
|
||||
res = f75303_fetch_remote2(dev);
|
||||
break;
|
||||
case SENSOR_CHAN_AMBIENT_TEMP:
|
||||
return f75303_fetch_local(dev);
|
||||
case SENSOR_CHAN_F75303_REMOTE1:
|
||||
return f75303_fetch_remote1(dev);
|
||||
case SENSOR_CHAN_F75303_REMOTE2:
|
||||
return f75303_fetch_remote2(dev);
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int f75303_channel_get(const struct device *dev,
|
||||
enum sensor_channel chan,
|
||||
struct sensor_value *val)
|
||||
{
|
||||
struct f75303_data *data = dev->data;
|
||||
uint16_t sample;
|
||||
|
||||
switch ((uint32_t)chan) {
|
||||
case SENSOR_CHAN_AMBIENT_TEMP:
|
||||
sample = data->sample_local;
|
||||
break;
|
||||
case SENSOR_CHAN_F75303_REMOTE1:
|
||||
sample = data->sample_remote1;
|
||||
break;
|
||||
case SENSOR_CHAN_F75303_REMOTE2:
|
||||
sample = data->sample_remote2;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/*
|
||||
* The reading is given in steps of 0.125 degrees celsius, i.e. the
|
||||
* temperature in degrees celsius is equal to sample / 8.
|
||||
*/
|
||||
val->val1 = sample >> F75303_SAMPLE_INT_SHIFT;
|
||||
val->val2 = (sample & F75303_SAMPLE_FRAC_MASK) * F75303_SAMPLE_MICROCELSIUS_PER_BIT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct sensor_driver_api f75303_driver_api = {
|
||||
.sample_fetch = f75303_sample_fetch,
|
||||
.channel_get = f75303_channel_get,
|
||||
};
|
||||
|
||||
static int f75303_init(const struct device *dev)
|
||||
{
|
||||
const struct f75303_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 f75303_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 F75303_INST(inst) \
|
||||
static struct f75303_data f75303_data_##inst; \
|
||||
static const struct f75303_config f75303_config_##inst = { \
|
||||
.i2c = I2C_DT_SPEC_INST_GET(inst), \
|
||||
}; \
|
||||
PM_DEVICE_DT_INST_DEFINE(inst, f75303_pm_action); \
|
||||
SENSOR_DEVICE_DT_INST_DEFINE(inst, f75303_init, PM_DEVICE_DT_INST_GET(inst), \
|
||||
&f75303_data_##inst, &f75303_config_##inst, POST_KERNEL, \
|
||||
CONFIG_SENSOR_INIT_PRIORITY, &f75303_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(F75303_INST)
|
30
drivers/sensor/f75303/f75303.h
Normal file
30
drivers/sensor/f75303/f75303.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Google LLC
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_DRIVERS_SENSOR_F75303_F75303_H_
|
||||
#define ZEPHYR_DRIVERS_SENSOR_F75303_F75303_H_
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#define F75303_LOCAL_TEMP_H 0x00
|
||||
#define F75303_REMOTE1_TEMP_H 0x01
|
||||
#define F75303_REMOTE1_TEMP_L 0x10
|
||||
#define F75303_REMOTE2_TEMP_H 0x23
|
||||
#define F75303_REMOTE2_TEMP_L 0x24
|
||||
#define F75303_LOCAL_TEMP_L 0x29
|
||||
|
||||
struct f75303_data {
|
||||
uint16_t sample_local;
|
||||
uint16_t sample_remote1;
|
||||
uint16_t sample_remote2;
|
||||
};
|
||||
|
||||
struct f75303_config {
|
||||
struct i2c_dt_spec i2c;
|
||||
};
|
||||
|
||||
#endif
|
176
drivers/sensor/f75303/f75303_emul.c
Normal file
176
drivers/sensor/f75303/f75303_emul.c
Normal file
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT fintek_f75303
|
||||
|
||||
#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 <zephyr/drivers/sensor/f75303.h>
|
||||
#include "f75303.h"
|
||||
|
||||
LOG_MODULE_DECLARE(F75303, CONFIG_SENSOR_LOG_LEVEL);
|
||||
|
||||
#define NUM_REGS 128
|
||||
|
||||
struct f75303_emul_data {
|
||||
uint8_t reg[NUM_REGS];
|
||||
};
|
||||
|
||||
struct f75303_emul_cfg {
|
||||
};
|
||||
|
||||
static void f75303_emul_set_reg(const struct emul *target, uint8_t reg, uint8_t val)
|
||||
{
|
||||
struct f75303_emul_data *data = target->data;
|
||||
|
||||
__ASSERT_NO_MSG(reg < NUM_REGS);
|
||||
data->reg[reg] = val;
|
||||
}
|
||||
|
||||
static uint8_t f75303_emul_get_reg(const struct emul *target, uint8_t reg)
|
||||
{
|
||||
struct f75303_emul_data *data = target->data;
|
||||
|
||||
__ASSERT_NO_MSG(reg < NUM_REGS);
|
||||
return data->reg[reg];
|
||||
}
|
||||
|
||||
static void f75303_emul_reset(const struct emul *target)
|
||||
{
|
||||
struct f75303_emul_data *data = target->data;
|
||||
|
||||
memset(data->reg, 0, NUM_REGS);
|
||||
}
|
||||
|
||||
static int f75303_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 = f75303_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);
|
||||
}
|
||||
f75303_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 f75303_emul_init(const struct emul *target, const struct device *parent)
|
||||
{
|
||||
f75303_emul_reset(target);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int f75303_emul_set_channel(const struct emul *target, enum sensor_channel chan,
|
||||
q31_t value, int8_t shift)
|
||||
{
|
||||
struct f75303_emul_data *data = target->data;
|
||||
int64_t scaled_value;
|
||||
int32_t millicelsius;
|
||||
int32_t reg_value;
|
||||
uint8_t reg_h, reg_l;
|
||||
|
||||
switch ((int32_t)chan) {
|
||||
case SENSOR_CHAN_AMBIENT_TEMP:
|
||||
reg_h = F75303_LOCAL_TEMP_H;
|
||||
reg_l = F75303_LOCAL_TEMP_L;
|
||||
break;
|
||||
case SENSOR_CHAN_F75303_REMOTE1:
|
||||
reg_h = F75303_REMOTE1_TEMP_H;
|
||||
reg_l = F75303_REMOTE1_TEMP_L;
|
||||
break;
|
||||
case SENSOR_CHAN_F75303_REMOTE2:
|
||||
reg_h = F75303_REMOTE2_TEMP_H;
|
||||
reg_l = F75303_REMOTE2_TEMP_L;
|
||||
break;
|
||||
default:
|
||||
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[reg_h] = reg_value >> 3;
|
||||
data->reg[reg_l] = (reg_value & 0x7) << 5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int f75303_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_AMBIENT_TEMP &&
|
||||
chan != (enum sensor_channel)SENSOR_CHAN_F75303_REMOTE1 &&
|
||||
chan != (enum sensor_channel)SENSOR_CHAN_F75303_REMOTE2) {
|
||||
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 f75303_emul_api_i2c = {
|
||||
.transfer = f75303_emul_transfer_i2c,
|
||||
};
|
||||
|
||||
static const struct emul_sensor_backend_api f75303_emul_api_sensor = {
|
||||
.set_channel = f75303_emul_set_channel,
|
||||
.get_sample_range = f75303_emul_get_sample_range,
|
||||
};
|
||||
|
||||
|
||||
#define F75303_EMUL(n) \
|
||||
const struct f75303_emul_cfg f75303_emul_cfg_##n; \
|
||||
struct f75303_emul_data f75303_emul_data_##n; \
|
||||
EMUL_DT_INST_DEFINE(n, f75303_emul_init, &f75303_emul_data_##n, \
|
||||
&f75303_emul_cfg_##n, &f75303_emul_api_i2c, \
|
||||
&f75303_emul_api_sensor);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(F75303_EMUL)
|
10
dts/bindings/sensor/fintek,f75303.yaml
Normal file
10
dts/bindings/sensor/fintek,f75303.yaml
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Copyright (c) 2023 Google LLC
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: |
|
||||
F75303 temperature sensor IC. This device has three temperature
|
||||
channels - one local (on-chip), and two remote.
|
||||
|
||||
compatible: "fintek,f75303"
|
||||
|
||||
include: [sensor-device.yaml, i2c-device.yaml]
|
17
include/zephyr/drivers/sensor/f75303.h
Normal file
17
include/zephyr/drivers/sensor/f75303.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_F75303_H_
|
||||
#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_F75303_H_
|
||||
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
|
||||
/* F75303 specific channels */
|
||||
enum sensor_channel_f75303 {
|
||||
SENSOR_CHAN_F75303_REMOTE1 = SENSOR_CHAN_PRIV_START,
|
||||
SENSOR_CHAN_F75303_REMOTE2,
|
||||
};
|
||||
|
||||
#endif
|
|
@ -740,3 +740,8 @@ test_i2c_ist8310@6f {
|
|||
reg = <0x6f>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
test_i2c_f75303: f75303@70 {
|
||||
compatible = "fintek,f75303";
|
||||
reg = <0x70>;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue