1 /*
2  * Copyright (c) 2019 Actinius
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT silabs_si7060
8 
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/drivers/sensor.h>
12 #include <zephyr/logging/log.h>
13 
14 #include "si7060.h"
15 
16 #define SIGN_BIT_MASK 0x7F
17 
18 LOG_MODULE_REGISTER(si7060, CONFIG_SENSOR_LOG_LEVEL);
19 
20 struct si7060_data {
21 	uint16_t temperature;
22 };
23 
24 struct si7060_config {
25 	struct i2c_dt_spec i2c;
26 };
27 
si7060_reg_read(const struct device * dev,uint8_t reg,uint8_t * val)28 static int si7060_reg_read(const struct device *dev, uint8_t reg, uint8_t *val)
29 {
30 	const struct si7060_config *config = dev->config;
31 
32 	if (i2c_reg_read_byte_dt(&config->i2c, reg, val)) {
33 		return -EIO;
34 	}
35 
36 	return 0;
37 }
38 
si7060_reg_write(const struct device * dev,uint8_t reg,uint8_t val)39 static int si7060_reg_write(const struct device *dev, uint8_t reg, uint8_t val)
40 {
41 	const struct si7060_config *config = dev->config;
42 
43 	return i2c_reg_write_byte_dt(&config->i2c, reg, val);
44 }
45 
si7060_sample_fetch(const struct device * dev,enum sensor_channel chan)46 static int si7060_sample_fetch(const struct device *dev,
47 			       enum sensor_channel chan)
48 {
49 	struct si7060_data *drv_data = dev->data;
50 
51 	if (si7060_reg_write(dev, SI7060_REG_CONFIG,
52 			     SI7060_ONE_BURST_VALUE) != 0) {
53 		return -EIO;
54 	}
55 
56 	int retval;
57 	uint8_t dspsigm;
58 	uint8_t dspsigl;
59 
60 	retval = si7060_reg_read(dev, SI7060_REG_TEMP_HIGH, &dspsigm);
61 	retval += si7060_reg_read(dev, SI7060_REG_TEMP_LOW, &dspsigl);
62 
63 	if (retval == 0) {
64 		drv_data->temperature = (256 * (dspsigm & SIGN_BIT_MASK))
65 		+ dspsigl;
66 	} else {
67 		LOG_ERR("Read register err");
68 	}
69 
70 	LOG_DBG("Sample_fetch retval: %d", retval);
71 
72 	return retval;
73 }
74 
si7060_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)75 static int si7060_channel_get(const struct device *dev,
76 			      enum sensor_channel chan,
77 			      struct sensor_value *val)
78 {
79 	struct si7060_data *drv_data = dev->data;
80 	int32_t uval;
81 
82 	if (chan == SENSOR_CHAN_AMBIENT_TEMP) {
83 		uval = ((55 * 160) + (drv_data->temperature - 16384)) >> 4;
84 		val->val1 = uval / 10;
85 		val->val2 = (uval % 10) * 100000;
86 
87 		LOG_DBG("Temperature = val1:%d, val2:%d", val->val1, val->val2);
88 
89 		return 0;
90 	} else {
91 		return -ENOTSUP;
92 	}
93 }
94 
95 static DEVICE_API(sensor, si7060_api) = {
96 	.sample_fetch = &si7060_sample_fetch,
97 	.channel_get = &si7060_channel_get,
98 };
99 
si7060_chip_init(const struct device * dev)100 static int si7060_chip_init(const struct device *dev)
101 {
102 	const struct si7060_config *config = dev->config;
103 	uint8_t value;
104 
105 	if (!device_is_ready(config->i2c.bus)) {
106 		LOG_ERR("Bus device is not ready");
107 		return -ENODEV;
108 	}
109 
110 	if (si7060_reg_read(dev, SI7060_REG_CHIP_INFO, &value) != 0) {
111 		return -EIO;
112 	}
113 
114 	if ((value >> 4) != SI7060_CHIP_ID_VALUE) {
115 		LOG_ERR("Bad chip id 0x%x", value);
116 		return -ENOTSUP;
117 	}
118 
119 	return 0;
120 }
121 
si7060_init(const struct device * dev)122 static int si7060_init(const struct device *dev)
123 {
124 	if (si7060_chip_init(dev) < 0) {
125 		return -EINVAL;
126 	}
127 
128 	return 0;
129 }
130 
131 #define SI7060_DEFINE(inst)								\
132 	static struct si7060_data si7060_data_##inst;					\
133 											\
134 	static const struct si7060_config si7060_config_##inst = {			\
135 		.i2c = I2C_DT_SPEC_INST_GET(inst),					\
136 	};										\
137 											\
138 	SENSOR_DEVICE_DT_INST_DEFINE(inst, si7060_init, NULL,				\
139 			      &si7060_data_##inst, &si7060_config_##inst, POST_KERNEL,	\
140 			      CONFIG_SENSOR_INIT_PRIORITY, &si7060_api);		\
141 
142 DT_INST_FOREACH_STATUS_OKAY(SI7060_DEFINE)
143