Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers: sensor: add F75303 temperature sensor driver #60833

Merged
merged 2 commits into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/sensor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions drivers/sensor/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
5 changes: 5 additions & 0 deletions drivers/sensor/f75303/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(f75303.c)
zephyr_library_sources_ifdef(CONFIG_EMUL_F75303 f75303_emul.c)
22 changes: 22 additions & 0 deletions drivers/sensor/f75303/Kconfig
Original file line number Diff line number Diff line change
@@ -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 changes: 198 additions & 0 deletions drivers/sensor/f75303/f75303.c
Original file line number Diff line number Diff line change
@@ -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:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sort of thing is exactly why we need to support channel type and index pairs and not just channel type

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any open issues/proposals to to do this?
This could also be modeled as a multi-function device, with each temperature sensor nested under a parent device. But that seems a little heavyweight.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's being discussed in #61163, though to the best of my knowledge, there is no dedicated issue about this.

Copy link
Collaborator

@teburd teburd Aug 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#13718 #1387 both note the need for multiple channels of the same type, it is a long standing issue

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MFD for that seems incredibly overkill for this, device specific channels seems reasonable to close the gap and get the code in, easy enough to change it to subchannel later.

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 changes: 30 additions & 0 deletions drivers/sensor/f75303/f75303.h
Original file line number Diff line number Diff line change
@@ -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
Loading
Loading