1 /*
2 * Copyright (c) 2022, Michal Morsisko
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT rohm_bh1750
8
9 #include <zephyr/drivers/sensor.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/logging/log.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/devicetree.h>
14 #include <zephyr/sys/byteorder.h>
15 #include <zephyr/sys/__assert.h>
16
17 LOG_MODULE_REGISTER(BH1750, CONFIG_SENSOR_LOG_LEVEL);
18
19 #define BH1750_CONTINUOUS_HIGH_RES_MODE 0x10
20 #define BH1750_CONTINUOUS_HIGH_RES_MODE_2 0x11
21 #define BH1750_CONTINUOUS_LOW_RES_MODE 0x13
22 #define BH1750_ONE_TIME_HIGH_RES_MODE 0x20
23 #define BH1750_ONE_TIME_HIGH_RES_MODE_2 0x21
24 #define BH1750_ONE_TIME_LOW_RES_MODE 0x23
25 #define BH1750_MTREG_HIGH_BYTE 0x40
26 #define BH1750_MTREG_LOW_BYTE 0x60
27 #define BH1750_MTREG_HIGH_BYTE_MASK 0xE0
28 #define BH1750_MTREG_LOW_BYTE_MASK 0x1F
29
30 #define BH1750_DEFAULT_MTREG 69U
31 #define BH1750_LOW_RES_MODE_MAX_WAIT 24U
32 #define BH1750_HIGH_RES_MODE_MAX_WAIT 180U
33 #define BH1750_LOW_RES_MODE_TYPICAL_WAIT 16U
34 #define BH1750_HIGH_RES_MODE_TYPICAL_WAIT 120U
35
36 #define BH1750_LOW_RES_DTS_ENUM 0U
37 #define BH1750_HIGH_RES_DTS_ENUM 1U
38 #define BH1750_HIGH_RES_2_DTS_ENUM 2U
39
40 struct bh1750_dev_config {
41 struct i2c_dt_spec bus;
42 uint8_t resolution;
43 uint8_t mtreg;
44 };
45
46 struct bh1750_data {
47 uint16_t sample;
48 };
49
bh1750_opcode_read(const struct device * dev,uint8_t opcode,uint16_t * val)50 static int bh1750_opcode_read(const struct device *dev, uint8_t opcode,
51 uint16_t *val)
52 {
53 const struct bh1750_dev_config *cfg = dev->config;
54 int rc;
55
56 rc = i2c_burst_read_dt(&cfg->bus, opcode, (uint8_t *)val, 2);
57 if (rc < 0) {
58 return rc;
59 }
60
61 *val = sys_be16_to_cpu(*val);
62 return 0;
63 }
64
bh1750_opcode_write(const struct device * dev,uint8_t opcode)65 static int bh1750_opcode_write(const struct device *dev, uint8_t opcode)
66 {
67 const struct bh1750_dev_config *cfg = dev->config;
68
69 return i2c_write_dt(&cfg->bus, &opcode, 1);
70 }
71
bh1750_mtreg_write(const struct device * dev,uint8_t mtreg)72 static int bh1750_mtreg_write(const struct device *dev, uint8_t mtreg)
73 {
74 int rc;
75 uint8_t high_byte = mtreg & BH1750_MTREG_HIGH_BYTE_MASK;
76 uint8_t low_byte = mtreg & BH1750_MTREG_LOW_BYTE_MASK;
77
78 rc = bh1750_opcode_write(dev, BH1750_MTREG_HIGH_BYTE | (high_byte >> 5));
79 if (rc < 0) {
80 LOG_ERR("%s, Failed to write high byte of mtreg!",
81 dev->name);
82 return rc;
83 }
84
85 rc = bh1750_opcode_write(dev, BH1750_MTREG_LOW_BYTE | low_byte);
86 if (rc < 0) {
87 LOG_ERR("%s, Failed to write low byte of mtreg!",
88 dev->name);
89 return rc;
90 }
91
92 return 0;
93 }
94
bh1750_get_mode_from_dts_device(const struct device * dev)95 static uint8_t bh1750_get_mode_from_dts_device(const struct device *dev)
96 {
97 const struct bh1750_dev_config *cfg = dev->config;
98
99 if (cfg->resolution == BH1750_HIGH_RES_2_DTS_ENUM) {
100 return BH1750_ONE_TIME_HIGH_RES_MODE_2;
101 } else if (cfg->resolution == BH1750_HIGH_RES_DTS_ENUM) {
102 return BH1750_ONE_TIME_HIGH_RES_MODE;
103 } else {
104 return BH1750_ONE_TIME_LOW_RES_MODE;
105 }
106 }
107
bh1750_get_wait_time_from_dts_device(const struct device * dev)108 static int bh1750_get_wait_time_from_dts_device(const struct device *dev)
109 {
110 const struct bh1750_dev_config *cfg = dev->config;
111
112 if (cfg->resolution == BH1750_HIGH_RES_2_DTS_ENUM) {
113 return BH1750_HIGH_RES_MODE_MAX_WAIT;
114 } else if (cfg->resolution == BH1750_HIGH_RES_DTS_ENUM) {
115 return BH1750_HIGH_RES_MODE_MAX_WAIT;
116 } else {
117 return BH1750_LOW_RES_MODE_MAX_WAIT;
118 }
119 }
120
bh1750_sample_fetch(const struct device * dev,enum sensor_channel chan)121 static int bh1750_sample_fetch(const struct device *dev,
122 enum sensor_channel chan)
123 {
124 const struct bh1750_dev_config *cfg = dev->config;
125 struct bh1750_data *drv_data = dev->data;
126 const int max_wait = bh1750_get_wait_time_from_dts_device(dev);
127 const uint8_t mode = bh1750_get_mode_from_dts_device(dev);
128 int rc;
129 int wait_time;
130
131 if (chan != SENSOR_CHAN_ALL &&
132 chan != SENSOR_CHAN_LIGHT) {
133 return -ENOTSUP;
134 }
135
136 /* Start the measurement */
137 rc = bh1750_opcode_write(dev, mode);
138 if (rc < 0) {
139 LOG_ERR("%s, Failed to start measurement!",
140 dev->name);
141 return rc;
142 }
143
144 /* Calculate measurement time */
145 wait_time = (max_wait * (cfg->mtreg * 10000 / BH1750_DEFAULT_MTREG)) / 10000;
146
147 /* Wait for the measurement to be stored in the sensor memory */
148 k_msleep(wait_time);
149
150 /* Fetch result */
151 rc = bh1750_opcode_read(dev, mode, &drv_data->sample);
152 if (rc < 0) {
153 LOG_ERR("%s: Failed to read measurement result!",
154 dev->name);
155 return rc;
156 }
157
158 return 0;
159 }
160
bh1750_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)161 static int bh1750_channel_get(const struct device *dev,
162 enum sensor_channel chan,
163 struct sensor_value *val)
164 {
165 const struct bh1750_dev_config *cfg = dev->config;
166 struct bh1750_data *drv_data = dev->data;
167 uint32_t tmp;
168
169 if (chan != SENSOR_CHAN_ALL &&
170 chan != SENSOR_CHAN_LIGHT) {
171 return -ENOTSUP;
172 }
173
174 /* See datasheet (Technical note 11046EDT01), page 11
175 * https://www.mouser.com/datasheet/2/348/Rohm_11162017_ROHMS34826-1-1279292.pdf
176 * for more information how to convert raw sample to lx
177 */
178 tmp = (drv_data->sample * 1000 / 12) * (BH1750_DEFAULT_MTREG * 100 / cfg->mtreg);
179
180 if (cfg->resolution == BH1750_HIGH_RES_2_DTS_ENUM) {
181 tmp /= 2;
182 }
183
184 val->val1 = tmp / 10000;
185 val->val2 = (tmp % 10000) * 100;
186
187 return 0;
188 }
189
190 static const struct sensor_driver_api bh1750_driver_api = {
191 .sample_fetch = bh1750_sample_fetch,
192 .channel_get = bh1750_channel_get
193 };
194
bh1750_init(const struct device * dev)195 static int bh1750_init(const struct device *dev)
196 {
197 const struct bh1750_dev_config *cfg = dev->config;
198
199 if (!device_is_ready(cfg->bus.bus)) {
200 LOG_ERR("I2C dev %s not ready", cfg->bus.bus->name);
201 return -ENODEV;
202 }
203
204 if (cfg->mtreg != BH1750_DEFAULT_MTREG) {
205 bh1750_mtreg_write(dev, cfg->mtreg);
206 }
207
208 return 0;
209 }
210
211 #define DEFINE_BH1750(_num) \
212 static struct bh1750_data bh1750_data_##_num; \
213 static const struct bh1750_dev_config bh1750_config_##_num = { \
214 .bus = I2C_DT_SPEC_INST_GET(_num), \
215 .mtreg = DT_INST_PROP(_num, mtreg), \
216 .resolution = DT_INST_PROP(_num, resolution) \
217 }; \
218 SENSOR_DEVICE_DT_INST_DEFINE(_num, bh1750_init, NULL, \
219 &bh1750_data_##_num, &bh1750_config_##_num, POST_KERNEL, \
220 CONFIG_SENSOR_INIT_PRIORITY, &bh1750_driver_api);
221
222 DT_INST_FOREACH_STATUS_OKAY(DEFINE_BH1750)
223