1  /*
2   * Copyright (c) 2023 Google LLC
3   *
4   * SPDX-License-Identifier: Apache-2.0
5   */
6  
7  #define DT_DRV_COMPAT fintek_f75303
8  
9  #include <zephyr/device.h>
10  #include <zephyr/drivers/i2c.h>
11  #include <zephyr/drivers/sensor.h>
12  #include <zephyr/pm/device.h>
13  #include <zephyr/pm/device_runtime.h>
14  #include <zephyr/logging/log.h>
15  #include <zephyr/drivers/sensor/f75303.h>
16  #include "f75303.h"
17  
18  #define F75303_SAMPLE_INT_SHIFT 3
19  #define F75303_SAMPLE_FRAC_MASK GENMASK(2, 0)
20  #define F75303_SAMPLE_MICROCELSIUS_PER_BIT 125000
21  
22  LOG_MODULE_REGISTER(F75303, CONFIG_SENSOR_LOG_LEVEL);
23  
f75303_fetch(const struct i2c_dt_spec * i2c,uint8_t off_h,uint8_t off_l,uint16_t * sample)24  static int f75303_fetch(const struct i2c_dt_spec *i2c,
25  			uint8_t off_h, uint8_t off_l, uint16_t *sample)
26  {
27  	uint8_t val_h;
28  	uint8_t val_l;
29  	int res;
30  
31  	res = i2c_reg_read_byte_dt(i2c, off_h, &val_h);
32  	if (res) {
33  		return res;
34  	}
35  
36  	res = i2c_reg_read_byte_dt(i2c, off_l, &val_l);
37  	if (res) {
38  		return res;
39  	}
40  
41  	*sample = val_h << 3 | val_l >> 5;
42  
43  	return 0;
44  }
45  
f75303_fetch_local(const struct device * dev)46  static int f75303_fetch_local(const struct device *dev)
47  {
48  	struct f75303_data *data = dev->data;
49  	const struct f75303_config *config = dev->config;
50  
51  	return f75303_fetch(&config->i2c,
52  			    F75303_LOCAL_TEMP_H,
53  			    F75303_LOCAL_TEMP_L,
54  			    &data->sample_local);
55  }
56  
f75303_fetch_remote1(const struct device * dev)57  static int f75303_fetch_remote1(const struct device *dev)
58  {
59  	struct f75303_data *data = dev->data;
60  	const struct f75303_config *config = dev->config;
61  
62  	return f75303_fetch(&config->i2c,
63  			    F75303_REMOTE1_TEMP_H,
64  			    F75303_REMOTE1_TEMP_L,
65  			    &data->sample_remote1);
66  }
67  
f75303_fetch_remote2(const struct device * dev)68  static int f75303_fetch_remote2(const struct device *dev)
69  {
70  	struct f75303_data *data = dev->data;
71  	const struct f75303_config *config = dev->config;
72  
73  	return f75303_fetch(&config->i2c,
74  			    F75303_REMOTE2_TEMP_H,
75  			    F75303_REMOTE2_TEMP_L,
76  			    &data->sample_remote2);
77  }
78  
f75303_sample_fetch(const struct device * dev,enum sensor_channel chan)79  static int f75303_sample_fetch(const struct device *dev,
80  			       enum sensor_channel chan)
81  {
82  	enum pm_device_state pm_state;
83  	int res;
84  
85  	(void)pm_device_state_get(dev, &pm_state);
86  	if (pm_state != PM_DEVICE_STATE_ACTIVE) {
87  		return -EIO;
88  	}
89  
90  	switch ((uint32_t)chan) {
91  	case SENSOR_CHAN_ALL:
92  		res = f75303_fetch_local(dev);
93  		if (res) {
94  			break;
95  		}
96  		res = f75303_fetch_remote1(dev);
97  		if (res) {
98  			break;
99  		}
100  		res = f75303_fetch_remote2(dev);
101  		break;
102  	case SENSOR_CHAN_AMBIENT_TEMP:
103  		return f75303_fetch_local(dev);
104  	case SENSOR_CHAN_F75303_REMOTE1:
105  		return f75303_fetch_remote1(dev);
106  	case SENSOR_CHAN_F75303_REMOTE2:
107  		return f75303_fetch_remote2(dev);
108  	default:
109  		return -ENOTSUP;
110  	}
111  
112  	return res;
113  }
114  
f75303_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)115  static int f75303_channel_get(const struct device *dev,
116  			      enum sensor_channel chan,
117  			      struct sensor_value *val)
118  {
119  	struct f75303_data *data = dev->data;
120  	uint16_t sample;
121  
122  	switch ((uint32_t)chan) {
123  	case SENSOR_CHAN_AMBIENT_TEMP:
124  		sample = data->sample_local;
125  		break;
126  	case SENSOR_CHAN_F75303_REMOTE1:
127  		sample = data->sample_remote1;
128  		break;
129  	case SENSOR_CHAN_F75303_REMOTE2:
130  		sample = data->sample_remote2;
131  		break;
132  	default:
133  		return -ENOTSUP;
134  	}
135  
136  	/*
137  	 * The reading is given in steps of 0.125 degrees celsius, i.e. the
138  	 * temperature in degrees celsius is equal to sample / 8.
139  	 */
140  	val->val1 = sample >> F75303_SAMPLE_INT_SHIFT;
141  	val->val2 = (sample & F75303_SAMPLE_FRAC_MASK) * F75303_SAMPLE_MICROCELSIUS_PER_BIT;
142  
143  	return 0;
144  }
145  
146  static DEVICE_API(sensor, f75303_driver_api) = {
147  	.sample_fetch = f75303_sample_fetch,
148  	.channel_get = f75303_channel_get,
149  };
150  
f75303_init(const struct device * dev)151  static int f75303_init(const struct device *dev)
152  {
153  	const struct f75303_config *config = dev->config;
154  	int res = 0;
155  
156  	if (!i2c_is_ready_dt(&config->i2c)) {
157  		LOG_ERR("I2C device not ready");
158  		return -ENODEV;
159  	}
160  
161  #ifdef CONFIG_PM_DEVICE_RUNTIME
162  	pm_device_init_suspended(dev);
163  
164  	res = pm_device_runtime_enable(dev);
165  	if (res) {
166  		LOG_ERR("Failed to enable runtime power management");
167  	}
168  #endif
169  
170  	return res;
171  }
172  
173  #ifdef CONFIG_PM_DEVICE
f75303_pm_action(const struct device * dev,enum pm_device_action action)174  static int f75303_pm_action(const struct device *dev, enum pm_device_action action)
175  {
176  	switch (action) {
177  	case PM_DEVICE_ACTION_TURN_ON:
178  	case PM_DEVICE_ACTION_RESUME:
179  	case PM_DEVICE_ACTION_TURN_OFF:
180  	case PM_DEVICE_ACTION_SUSPEND:
181  		return 0;
182  	default:
183  		return -ENOTSUP;
184  	}
185  }
186  #endif
187  
188  #define F75303_INST(inst)								\
189  	static struct f75303_data f75303_data_##inst;					\
190  	static const struct f75303_config f75303_config_##inst = {			\
191  		.i2c = I2C_DT_SPEC_INST_GET(inst),					\
192  	};										\
193  	PM_DEVICE_DT_INST_DEFINE(inst, f75303_pm_action);				\
194  	SENSOR_DEVICE_DT_INST_DEFINE(inst, f75303_init, PM_DEVICE_DT_INST_GET(inst),	\
195  			      &f75303_data_##inst, &f75303_config_##inst, POST_KERNEL,	\
196  			      CONFIG_SENSOR_INIT_PRIORITY, &f75303_driver_api);
197  
198  DT_INST_FOREACH_STATUS_OKAY(F75303_INST)
199