1 /*
2  * Copyright (c) 2023 Google LLC
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #define DT_DRV_COMPAT fintek_f75303
7 
8 #include <zephyr/device.h>
9 #include <zephyr/drivers/emul.h>
10 #include <zephyr/drivers/emul_sensor.h>
11 #include <zephyr/drivers/i2c.h>
12 #include <zephyr/drivers/i2c_emul.h>
13 #include <zephyr/logging/log.h>
14 #include <zephyr/drivers/sensor/f75303.h>
15 #include "f75303.h"
16 
17 LOG_MODULE_DECLARE(F75303, CONFIG_SENSOR_LOG_LEVEL);
18 
19 #define NUM_REGS 128
20 
21 struct f75303_emul_data {
22 	uint8_t reg[NUM_REGS];
23 };
24 
25 struct f75303_emul_cfg {
26 };
27 
f75303_emul_set_reg(const struct emul * target,uint8_t reg,uint8_t val)28 static void f75303_emul_set_reg(const struct emul *target, uint8_t reg, uint8_t val)
29 {
30 	struct f75303_emul_data *data = target->data;
31 
32 	__ASSERT_NO_MSG(reg < NUM_REGS);
33 	data->reg[reg] = val;
34 }
35 
f75303_emul_get_reg(const struct emul * target,uint8_t reg)36 static uint8_t f75303_emul_get_reg(const struct emul *target, uint8_t reg)
37 {
38 	struct f75303_emul_data *data = target->data;
39 
40 	__ASSERT_NO_MSG(reg < NUM_REGS);
41 	return data->reg[reg];
42 }
43 
f75303_emul_reset(const struct emul * target)44 static void f75303_emul_reset(const struct emul *target)
45 {
46 	struct f75303_emul_data *data = target->data;
47 
48 	memset(data->reg, 0, NUM_REGS);
49 }
50 
f75303_emul_transfer_i2c(const struct emul * target,struct i2c_msg * msgs,int num_msgs,int addr)51 static int f75303_emul_transfer_i2c(const struct emul *target, struct i2c_msg *msgs,
52 				    int num_msgs, int addr)
53 {
54 	/* Largely copied from emul_bmi160.c */
55 	unsigned int val;
56 	int reg;
57 
58 	__ASSERT_NO_MSG(msgs && num_msgs);
59 
60 	i2c_dump_msgs_rw(target->dev, msgs, num_msgs, addr, false);
61 	switch (num_msgs) {
62 	case 2:
63 		if (msgs->flags & I2C_MSG_READ) {
64 			LOG_ERR("Unexpected read");
65 			return -EIO;
66 		}
67 		if (msgs->len != 1) {
68 			LOG_ERR("Unexpected msg0 length %d", msgs->len);
69 			return -EIO;
70 		}
71 		reg = msgs->buf[0];
72 
73 		/* Now process the 'read' part of the message */
74 		msgs++;
75 		if (msgs->flags & I2C_MSG_READ) {
76 			switch (msgs->len) {
77 			case 1:
78 				val = f75303_emul_get_reg(target, reg);
79 				msgs->buf[0] = val;
80 				break;
81 			default:
82 				LOG_ERR("Unexpected msg1 length %d", msgs->len);
83 				return -EIO;
84 			}
85 		} else {
86 			if (msgs->len != 1) {
87 				LOG_ERR("Unexpected msg1 length %d", msgs->len);
88 			}
89 			f75303_emul_set_reg(target, reg, msgs->buf[0]);
90 		}
91 		break;
92 	default:
93 		LOG_ERR("Invalid number of messages: %d", num_msgs);
94 		return -EIO;
95 	}
96 
97 	return 0;
98 }
99 
f75303_emul_init(const struct emul * target,const struct device * parent)100 static int f75303_emul_init(const struct emul *target, const struct device *parent)
101 {
102 	f75303_emul_reset(target);
103 	return 0;
104 }
105 
f75303_emul_set_channel(const struct emul * target,struct sensor_chan_spec ch,const q31_t * value,int8_t shift)106 static int f75303_emul_set_channel(const struct emul *target, struct sensor_chan_spec ch,
107 				   const q31_t *value, int8_t shift)
108 {
109 	struct f75303_emul_data *data = target->data;
110 	int64_t scaled_value;
111 	int32_t millicelsius;
112 	int32_t reg_value;
113 	uint8_t reg_h, reg_l;
114 
115 	switch ((int32_t)ch.chan_type) {
116 	case SENSOR_CHAN_AMBIENT_TEMP:
117 		reg_h = F75303_LOCAL_TEMP_H;
118 		reg_l = F75303_LOCAL_TEMP_L;
119 		break;
120 	case SENSOR_CHAN_F75303_REMOTE1:
121 		reg_h = F75303_REMOTE1_TEMP_H;
122 		reg_l = F75303_REMOTE1_TEMP_L;
123 		break;
124 	case SENSOR_CHAN_F75303_REMOTE2:
125 		reg_h = F75303_REMOTE2_TEMP_H;
126 		reg_l = F75303_REMOTE2_TEMP_L;
127 		break;
128 	default:
129 		return -ENOTSUP;
130 	}
131 
132 	scaled_value = (int64_t)*value << shift;
133 	millicelsius = scaled_value * 1000 / ((int64_t)INT32_MAX + 1);
134 	reg_value = CLAMP(millicelsius / 125, 0, 0x7ff);
135 
136 	data->reg[reg_h] = reg_value >> 3;
137 	data->reg[reg_l] = (reg_value & 0x7) << 5;
138 
139 	return 0;
140 }
141 
f75303_emul_get_sample_range(const struct emul * target,struct sensor_chan_spec ch,q31_t * lower,q31_t * upper,q31_t * epsilon,int8_t * shift)142 static int f75303_emul_get_sample_range(const struct emul *target, struct sensor_chan_spec ch,
143 					q31_t *lower, q31_t *upper, q31_t *epsilon, int8_t *shift)
144 {
145 	if (ch.chan_type != SENSOR_CHAN_AMBIENT_TEMP &&
146 	    ch.chan_type != (enum sensor_channel)SENSOR_CHAN_F75303_REMOTE1 &&
147 	    ch.chan_type != (enum sensor_channel)SENSOR_CHAN_F75303_REMOTE2) {
148 		return -ENOTSUP;
149 	}
150 
151 	*shift = 8;
152 	*lower = 0;
153 	*upper = (int64_t)(255.875 * ((int64_t)INT32_MAX + 1)) >> *shift;
154 	*epsilon = (int64_t)(0.125 * ((int64_t)INT32_MAX + 1)) >> *shift;
155 
156 	return 0;
157 }
158 
159 static const struct i2c_emul_api f75303_emul_api_i2c = {
160 	.transfer = f75303_emul_transfer_i2c,
161 };
162 
163 static const struct emul_sensor_driver_api f75303_emul_api_sensor = {
164 	.set_channel = f75303_emul_set_channel,
165 	.get_sample_range = f75303_emul_get_sample_range,
166 };
167 
168 
169 #define F75303_EMUL(n)								\
170 	const struct f75303_emul_cfg f75303_emul_cfg_##n;			\
171 	struct f75303_emul_data f75303_emul_data_##n;				\
172 	EMUL_DT_INST_DEFINE(n, f75303_emul_init, &f75303_emul_data_##n,		\
173 			    &f75303_emul_cfg_##n, &f75303_emul_api_i2c,		\
174 			    &f75303_emul_api_sensor);
175 
176 DT_INST_FOREACH_STATUS_OKAY(F75303_EMUL)
177