Skip to content

Commit 2f26479

Browse files
committed
drivers: sensor: Add ROHM BH1750 driver
This adds support for ROHM BH1750 the i2c light sensor. Signed-off-by: Gaël PORTAY <[email protected]>
1 parent fcd60cf commit 2f26479

File tree

7 files changed

+262
-0
lines changed

7 files changed

+262
-0
lines changed

drivers/sensor/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ add_subdirectory_ifdef(CONFIG_AMG88XX amg88xx)
99
add_subdirectory_ifdef(CONFIG_AMS_AS5600 ams_as5600)
1010
add_subdirectory_ifdef(CONFIG_AMS_IAQ_CORE ams_iAQcore)
1111
add_subdirectory_ifdef(CONFIG_APDS9960 apds9960)
12+
add_subdirectory_ifdef(CONFIG_BH1750 bh1750)
1213
add_subdirectory_ifdef(CONFIG_BMA280 bma280)
1314
add_subdirectory_ifdef(CONFIG_BMC150_MAGN bmc150_magn)
1415
add_subdirectory_ifdef(CONFIG_BME280 bme280)

drivers/sensor/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ source "drivers/sensor/ams_iAQcore/Kconfig"
5959

6060
source "drivers/sensor/apds9960/Kconfig"
6161

62+
source "drivers/sensor/bh1750/Kconfig"
63+
6264
source "drivers/sensor/bma280/Kconfig"
6365

6466
source "drivers/sensor/bmc150_magn/Kconfig"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
zephyr_library()
4+
5+
zephyr_library_sources(bh1750.c)

drivers/sensor/bh1750/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# BH1750 light sensor configuration options
2+
3+
# Copyright (c) 2022 Gaël PORTAY
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
config BH1750
7+
bool "BH1750 sensor"
8+
default y
9+
depends on DT_HAS_ROHM_BH1750_ENABLED
10+
select I2C
11+
help
12+
Enable driver for BH1750 I2C-based light sensor.

drivers/sensor/bh1750/bh1750.c

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
/* bh1750.c - Driver for BH1750 light sensor */
2+
3+
/*
4+
* Copyright (c) 2022 Gaël PORTAY
5+
*
6+
* SPDX-License-Identifier: Apache-2.0
7+
*/
8+
9+
#define DT_DRV_COMPAT rohm_bh1750
10+
11+
#include <zephyr/kernel.h>
12+
#include <zephyr/device.h>
13+
#include <zephyr/devicetree.h>
14+
#include <zephyr/drivers/sensor.h>
15+
#include <zephyr/drivers/i2c.h>
16+
#include <zephyr/init.h>
17+
#include <zephyr/pm/device.h>
18+
#include <zephyr/sys/byteorder.h>
19+
#include <zephyr/sys/__assert.h>
20+
21+
#include <zephyr/logging/log.h>
22+
23+
LOG_MODULE_REGISTER(BH1750, CONFIG_SENSOR_LOG_LEVEL);
24+
25+
#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0
26+
#warning "BH1750 driver enabled without any devices"
27+
#endif
28+
29+
#define BH1750_POWER_DOWN 0x00
30+
#define BH1750_POWER_ON 0x01
31+
#define BH1750_RESET 0x07
32+
#define BH1750_CONTINUOUSLY_HIGH_RESOLUTION_MODE 0x10
33+
#define BH1750_CONTINUOUSLY_HIGH_RESOLUTION_MODE_2 0x11
34+
#define BH1750_CONTINUOUSLY_LOW_RESOLUTION_MODE 0x13
35+
#define BH1750_ONE_TIME_HIGH_RESOLUTION_MODE 0x20
36+
#define BH1750_ONE_TIME_HIGH_RESOLUTION_MODE_2 0x21
37+
#define BH1750_ONE_TIME_LOW_RESOLUTION_MODE 0x23
38+
#define BH1750_CHANGE_MEASUREMENT_TIME_HIGH 0x40
39+
#define BH1750_CHANGE_MEASUREMENT_TIME_LOW 0x60
40+
41+
struct bh1750_data {
42+
uint16_t raw_val;
43+
};
44+
45+
struct bh1750_config {
46+
struct i2c_dt_spec i2c;
47+
};
48+
49+
static inline int bh1750_is_ready(const struct device *dev)
50+
{
51+
const struct bh1750_config *cfg = dev->config;
52+
53+
return device_is_ready(cfg->i2c.bus) ? 0 : -ENODEV;
54+
}
55+
56+
static inline int bh1750_read(const struct device *dev, uint8_t *buf, int size)
57+
{
58+
const struct bh1750_config *cfg = dev->config;
59+
60+
return i2c_read_dt(&cfg->i2c, buf, size);
61+
}
62+
63+
static inline int bh1750_write(const struct device *dev, uint8_t val)
64+
{
65+
const struct bh1750_config *cfg = dev->config;
66+
uint8_t buf = val;
67+
68+
return i2c_write_dt(&cfg->i2c, &buf, sizeof(buf));
69+
}
70+
71+
static int bh1750_sample_fetch(const struct device *dev,
72+
enum sensor_channel chan)
73+
{
74+
struct bh1750_data *data = dev->data;
75+
uint8_t buf[2];
76+
int ret;
77+
78+
__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);
79+
80+
#ifdef CONFIG_PM_DEVICE
81+
enum pm_device_state state;
82+
(void)pm_device_state_get(dev, &state);
83+
/* Do not allow sample fetching from suspended state */
84+
if (state == PM_DEVICE_STATE_SUSPENDED) {
85+
return -EIO;
86+
}
87+
#endif
88+
89+
ret = bh1750_write(dev, BH1750_ONE_TIME_HIGH_RESOLUTION_MODE);
90+
if (ret < 0) {
91+
LOG_DBG("One time high resolution mode failed: %d", ret);
92+
return ret;
93+
}
94+
95+
/* Wait for the measure to be ready */
96+
k_sleep(K_MSEC(180)); /* Max for H-Resolution Mode */
97+
98+
ret = bh1750_read(dev, buf, sizeof(buf));
99+
if (ret < 0) {
100+
LOG_DBG("Read failed: %d", ret);
101+
return ret;
102+
}
103+
104+
data->raw_val = sys_get_be16(&buf[0]);
105+
106+
return 0;
107+
}
108+
109+
static int bh1750_channel_get(const struct device *dev,
110+
enum sensor_channel chan,
111+
struct sensor_value *val)
112+
{
113+
struct bh1750_data *data = dev->data;
114+
double tmp;
115+
int ret;
116+
117+
switch (chan) {
118+
case SENSOR_CHAN_LIGHT:
119+
/*
120+
* The documentation says the following about the calculation
121+
* at section Measurement sequence example from "Write
122+
* instruction" to "Read measurement result" p.17:
123+
*
124+
* How to calculate when the data High Byte is "10000011" and
125+
* Low Byte is "10010000"
126+
*
127+
* (2^15 + 2^9 + 2^8 + 2^7 + 2^4) / 1.2 = 28067 [lx]
128+
*
129+
* Which means:
130+
*
131+
* lx = Slx / 1.2
132+
*/
133+
tmp = data->raw_val / 1.2;
134+
ret = sensor_value_from_double(val, tmp);
135+
break;
136+
default:
137+
return -EINVAL;
138+
}
139+
140+
return ret;
141+
}
142+
143+
static const struct sensor_driver_api bh1750_api_funcs = {
144+
.sample_fetch = bh1750_sample_fetch,
145+
.channel_get = bh1750_channel_get,
146+
};
147+
148+
static int bh1750_chip_init(const struct device *dev)
149+
{
150+
int ret;
151+
152+
ret = bh1750_is_ready(dev);
153+
if (ret < 0) {
154+
LOG_DBG("I2C bus check failed: %d", ret);
155+
return ret;
156+
}
157+
158+
/*
159+
* Make sure chip is in power on mode before reset.
160+
*
161+
* The documentation says the following about the reset command:
162+
*
163+
* Reset command is for only reset Illuminance data register (reset
164+
* value is '0'). It is not necessary even power supply sequence. It is
165+
* used for removing previous measurement result. This command is not
166+
* working in power down mode, so that please set the power on mode
167+
* before input this command.
168+
*/
169+
ret = bh1750_write(dev, BH1750_POWER_ON);
170+
if (ret < 0) {
171+
LOG_DBG("Power on failed: %d", ret);
172+
return ret;
173+
}
174+
175+
ret = bh1750_write(dev, BH1750_RESET);
176+
if (ret < 0) {
177+
LOG_DBG("Reset failed: %d", ret);
178+
return ret;
179+
}
180+
181+
LOG_DBG("\"%s\" OK", dev->name);
182+
return 0;
183+
}
184+
185+
#ifdef CONFIG_PM_DEVICE
186+
static int bh1750_pm_action(const struct device *dev,
187+
enum pm_device_action action)
188+
{
189+
int ret = 0;
190+
191+
switch (action) {
192+
case PM_DEVICE_ACTION_RESUME:
193+
/* Put the chip into power up mode and reset */
194+
ret = bh1750_chip_init(dev);
195+
break;
196+
case PM_DEVICE_ACTION_SUSPEND:
197+
/* Put the chip into power down mode */
198+
ret = bh1750_write(dev, BH1750_POWER_DOWN);
199+
if (ret < 0) {
200+
LOG_DBG("Power down failed: %d", ret);
201+
return ret;
202+
}
203+
break;
204+
default:
205+
return -ENOTSUP;
206+
}
207+
208+
return ret;
209+
}
210+
#endif /* CONFIG_PM_DEVICE */
211+
212+
#define BH1750_DEFINE(inst) \
213+
static struct bh1750_data bh1750_data_##inst; \
214+
static const struct bh1750_config bh1750_config_##inst = { \
215+
.i2c = I2C_DT_SPEC_INST_GET(inst), \
216+
}; \
217+
\
218+
PM_DEVICE_DT_INST_DEFINE(inst, bh1750_pm_action); \
219+
\
220+
DEVICE_DT_INST_DEFINE(inst, \
221+
bh1750_chip_init, \
222+
PM_DEVICE_DT_INST_GET(inst), \
223+
&bh1750_data_##inst, \
224+
&bh1750_config_##inst, \
225+
POST_KERNEL, \
226+
CONFIG_SENSOR_INIT_PRIORITY, \
227+
&bh1750_api_funcs);
228+
229+
/* Create the struct device for every status "okay" node in the devicetree. */
230+
DT_INST_FOREACH_STATUS_OKAY(BH1750_DEFINE)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
description: ROHM integrated light sensor
4+
5+
compatible: "rohm,bh1750"
6+
7+
include: [sensor-device.yaml, i2c-device.yaml]

tests/drivers/build_all/sensor/i2c.dtsi

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,3 +646,8 @@ test_i2c_as5600: as5600@64 {
646646
compatible = "ams,as5600";
647647
reg = <0x64>;
648648
};
649+
650+
test_i2c_bh1750: bh1750@23 {
651+
compatible = "rohm,bh1750";
652+
reg = <0x23>;
653+
};

0 commit comments

Comments
 (0)