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