1 /*
2  * Copyright (c) 2019 Actinius
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT ti_opt3001
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 #include <zephyr/sys/__assert.h>
14 
15 #include "opt3001.h"
16 
17 LOG_MODULE_REGISTER(opt3001, CONFIG_SENSOR_LOG_LEVEL);
18 
opt3001_reg_read(const struct device * dev,uint8_t reg,uint16_t * val)19 static int opt3001_reg_read(const struct device *dev, uint8_t reg,
20 			    uint16_t *val)
21 {
22 	const struct opt3001_config *config = dev->config;
23 	uint8_t value[2];
24 
25 	if (i2c_burst_read_dt(&config->i2c, reg, value, 2) != 0) {
26 		return -EIO;
27 	}
28 
29 	*val = ((uint16_t)value[0] << 8) + value[1];
30 
31 	return 0;
32 }
33 
opt3001_reg_write(const struct device * dev,uint8_t reg,uint16_t val)34 static int opt3001_reg_write(const struct device *dev, uint8_t reg,
35 			     uint16_t val)
36 {
37 	const struct opt3001_config *config = dev->config;
38 	uint8_t new_value[2];
39 
40 	new_value[0] = val >> 8;
41 	new_value[1] = val & 0xff;
42 
43 	uint8_t tx_buf[3] = { reg, new_value[0], new_value[1] };
44 
45 	return i2c_write_dt(&config->i2c, tx_buf, sizeof(tx_buf));
46 }
47 
opt3001_reg_update(const struct device * dev,uint8_t reg,uint16_t mask,uint16_t val)48 static int opt3001_reg_update(const struct device *dev, uint8_t reg,
49 			      uint16_t mask, uint16_t val)
50 {
51 	uint16_t old_val;
52 	uint16_t new_val;
53 
54 	if (opt3001_reg_read(dev, reg, &old_val) != 0) {
55 		return -EIO;
56 	}
57 
58 	new_val = old_val & ~mask;
59 	new_val |= val & mask;
60 
61 	return opt3001_reg_write(dev, reg, new_val);
62 }
63 
opt3001_sample_fetch(const struct device * dev,enum sensor_channel chan)64 static int opt3001_sample_fetch(const struct device *dev,
65 				enum sensor_channel chan)
66 {
67 	struct opt3001_data *drv_data = dev->data;
68 	uint16_t value;
69 
70 	__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_LIGHT);
71 
72 	drv_data->sample = 0U;
73 
74 	if (opt3001_reg_read(dev, OPT3001_REG_RESULT, &value) != 0) {
75 		return -EIO;
76 	}
77 
78 	drv_data->sample = value;
79 
80 	return 0;
81 }
82 
opt3001_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)83 static int opt3001_channel_get(const struct device *dev,
84 			       enum sensor_channel chan,
85 			       struct sensor_value *val)
86 {
87 	struct opt3001_data *drv_data = dev->data;
88 	int32_t uval;
89 
90 	if (chan != SENSOR_CHAN_LIGHT) {
91 		return -ENOTSUP;
92 	}
93 
94 	/**
95 	 * sample consists of 4 bits of exponent and 12 bits of mantissa
96 	 * bits 15 to 12 are exponent bits
97 	 * bits 11 to 0 are the mantissa bits
98 	 *
99 	 * lux is the integer obtained using the following formula:
100 	 * (2^(exponent value)) * 0.01 * mantissa value
101 	 */
102 	uval = (1 << (drv_data->sample >> OPT3001_SAMPLE_EXPONENT_SHIFT))
103 		* (drv_data->sample & OPT3001_MANTISSA_MASK);
104 	val->val1 = uval / 100;
105 	val->val2 = (uval % 100) * 10000;
106 
107 	return 0;
108 }
109 
110 static DEVICE_API(sensor, opt3001_driver_api) = {
111 	.sample_fetch = opt3001_sample_fetch,
112 	.channel_get = opt3001_channel_get,
113 };
114 
opt3001_chip_init(const struct device * dev)115 static int opt3001_chip_init(const struct device *dev)
116 {
117 	const struct opt3001_config *config = dev->config;
118 	uint16_t value;
119 
120 	if (!device_is_ready(config->i2c.bus)) {
121 		LOG_ERR("Bus device is not ready");
122 		return -ENODEV;
123 	}
124 
125 	if (opt3001_reg_read(dev, OPT3001_REG_MANUFACTURER_ID, &value) != 0) {
126 		return -EIO;
127 	}
128 
129 	if (value != OPT3001_MANUFACTURER_ID_VALUE) {
130 		LOG_ERR("Bad manufacturer id 0x%x", value);
131 		return -ENOTSUP;
132 	}
133 
134 	if (opt3001_reg_read(dev, OPT3001_REG_DEVICE_ID, &value) != 0) {
135 		return -EIO;
136 	}
137 
138 	if (value != OPT3001_DEVICE_ID_VALUE) {
139 		LOG_ERR("Bad device id 0x%x", value);
140 		return -ENOTSUP;
141 	}
142 
143 	if (opt3001_reg_update(dev, OPT3001_REG_CONFIG,
144 			       OPT3001_CONVERSION_MODE_MASK,
145 			       OPT3001_CONVERSION_MODE_CONTINUOUS) != 0) {
146 		LOG_ERR("Failed to set mode to continuous conversion");
147 		return -EIO;
148 	}
149 
150 	return 0;
151 }
152 
opt3001_init(const struct device * dev)153 int opt3001_init(const struct device *dev)
154 {
155 	if (opt3001_chip_init(dev) < 0) {
156 		return -EINVAL;
157 	}
158 
159 	return 0;
160 }
161 
162 #define OPT3001_DEFINE(inst)									\
163 	static struct opt3001_data opt3001_data_##inst;						\
164 												\
165 	static const struct opt3001_config opt3001_config_##inst = {				\
166 		.i2c = I2C_DT_SPEC_INST_GET(inst),						\
167 	};											\
168 												\
169 	SENSOR_DEVICE_DT_INST_DEFINE(inst, opt3001_init, NULL,					\
170 			      &opt3001_data_##inst, &opt3001_config_##inst, POST_KERNEL,	\
171 			      CONFIG_SENSOR_INIT_PRIORITY, &opt3001_driver_api);		\
172 
173 DT_INST_FOREACH_STATUS_OKAY(OPT3001_DEFINE)
174