199 lines
4.5 KiB
C
199 lines
4.5 KiB
C
/*
|
|
* 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)
|