Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/sensor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ add_subdirectory_ifdef(CONFIG_AMG88XX amg88xx)
add_subdirectory_ifdef(CONFIG_AMS_AS5600 ams_as5600)
add_subdirectory_ifdef(CONFIG_AMS_IAQ_CORE ams_iAQcore)
add_subdirectory_ifdef(CONFIG_APDS9960 apds9960)
add_subdirectory_ifdef(CONFIG_BH1750 bh1750)
add_subdirectory_ifdef(CONFIG_BMA280 bma280)
add_subdirectory_ifdef(CONFIG_BMC150_MAGN bmc150_magn)
add_subdirectory_ifdef(CONFIG_BME280 bme280)
Expand Down
2 changes: 2 additions & 0 deletions drivers/sensor/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ source "drivers/sensor/ams_iAQcore/Kconfig"

source "drivers/sensor/apds9960/Kconfig"

source "drivers/sensor/bh1750/Kconfig"

source "drivers/sensor/bma280/Kconfig"

source "drivers/sensor/bmc150_magn/Kconfig"
Expand Down
5 changes: 5 additions & 0 deletions drivers/sensor/bh1750/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# SPDX-License-Identifier: Apache-2.0

zephyr_library()

zephyr_library_sources(bh1750.c)
12 changes: 12 additions & 0 deletions drivers/sensor/bh1750/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# BH1750 ambient light sensor configuration options

# Copyright (c) 2022 Michal Morsisko
# SPDX-License-Identifier: Apache-2.0

config BH1750
bool "BH1750 ambient light sensor"
default y
depends on DT_HAS_ROHM_BH1750_ENABLED
select I2C
help
Enable driver for BH1750 ambient light sensor.
222 changes: 222 additions & 0 deletions drivers/sensor/bh1750/bh1750.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
/*
* Copyright (c) 2022, Michal Morsisko
*
* SPDX-License-Identifier: Apache-2.0
*/

#define DT_DRV_COMPAT rohm_bh1750

#include <zephyr/drivers/sensor.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/logging/log.h>
#include <zephyr/kernel.h>
#include <zephyr/devicetree.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/__assert.h>

LOG_MODULE_REGISTER(BH1750, CONFIG_SENSOR_LOG_LEVEL);

#define BH1750_CONTINUOUS_HIGH_RES_MODE 0x10
#define BH1750_CONTINUOUS_HIGH_RES_MODE_2 0x11
#define BH1750_CONTINUOUS_LOW_RES_MODE 0x13
#define BH1750_ONE_TIME_HIGH_RES_MODE 0x20
#define BH1750_ONE_TIME_HIGH_RES_MODE_2 0x21
#define BH1750_ONE_TIME_LOW_RES_MODE 0x23
#define BH1750_MTREG_HIGH_BYTE 0x40
#define BH1750_MTREG_LOW_BYTE 0x60
#define BH1750_MTREG_HIGH_BYTE_MASK 0xE0
#define BH1750_MTREG_LOW_BYTE_MASK 0x1F

#define BH1750_DEFAULT_MTREG 69U
#define BH1750_LOW_RES_MODE_MAX_WAIT 24U
#define BH1750_HIGH_RES_MODE_MAX_WAIT 180U
#define BH1750_LOW_RES_MODE_TYPICAL_WAIT 16U
#define BH1750_HIGH_RES_MODE_TYPICAL_WAIT 120U

#define BH1750_LOW_RES_DTS_ENUM 0U
#define BH1750_HIGH_RES_DTS_ENUM 1U
#define BH1750_HIGH_RES_2_DTS_ENUM 2U

struct bh1750_dev_config {
struct i2c_dt_spec bus;
uint8_t resolution;
uint8_t mtreg;
};

struct bh1750_data {
uint16_t sample;
};

static int bh1750_opcode_read(const struct device *dev, uint8_t opcode,
uint16_t *val)
{
const struct bh1750_dev_config *cfg = dev->config;
int rc;

rc = i2c_burst_read_dt(&cfg->bus, opcode, (uint8_t *)val, 2);
if (rc < 0) {
return rc;
}

*val = sys_be16_to_cpu(*val);
return 0;
}

static int bh1750_opcode_write(const struct device *dev, uint8_t opcode)
{
const struct bh1750_dev_config *cfg = dev->config;

return i2c_write_dt(&cfg->bus, &opcode, 1);
}

static int bh1750_mtreg_write(const struct device *dev, uint8_t mtreg)
{
int rc;
uint8_t high_byte = mtreg & BH1750_MTREG_HIGH_BYTE_MASK;
uint8_t low_byte = mtreg & BH1750_MTREG_LOW_BYTE_MASK;

rc = bh1750_opcode_write(dev, BH1750_MTREG_HIGH_BYTE | (high_byte >> 5));
if (rc < 0) {
LOG_ERR("%s, Failed to write high byte of mtreg!",
dev->name);
return rc;
}

rc = bh1750_opcode_write(dev, BH1750_MTREG_LOW_BYTE | low_byte);
if (rc < 0) {
LOG_ERR("%s, Failed to write low byte of mtreg!",
dev->name);
return rc;
}

return 0;
}

static uint8_t bh1750_get_mode_from_dts_device(const struct device *dev)
{
const struct bh1750_dev_config *cfg = dev->config;

if (cfg->resolution == BH1750_HIGH_RES_2_DTS_ENUM) {
return BH1750_ONE_TIME_HIGH_RES_MODE_2;
} else if (cfg->resolution == BH1750_HIGH_RES_DTS_ENUM) {
return BH1750_ONE_TIME_HIGH_RES_MODE;
} else {
return BH1750_ONE_TIME_LOW_RES_MODE;
}
}

static int bh1750_get_wait_time_from_dts_device(const struct device *dev)
{
const struct bh1750_dev_config *cfg = dev->config;

if (cfg->resolution == BH1750_HIGH_RES_2_DTS_ENUM) {
return BH1750_HIGH_RES_MODE_MAX_WAIT;
} else if (cfg->resolution == BH1750_HIGH_RES_DTS_ENUM) {
return BH1750_HIGH_RES_MODE_MAX_WAIT;
} else {
return BH1750_LOW_RES_MODE_MAX_WAIT;
}
}

static int bh1750_sample_fetch(const struct device *dev,
enum sensor_channel chan)
{
const struct bh1750_dev_config *cfg = dev->config;
struct bh1750_data *drv_data = dev->data;
const int max_wait = bh1750_get_wait_time_from_dts_device(dev);
const uint8_t mode = bh1750_get_mode_from_dts_device(dev);
int rc;
int wait_time;

if (chan != SENSOR_CHAN_ALL &&
chan != SENSOR_CHAN_LIGHT) {
return -ENOTSUP;
}

/* Start the measurement */
rc = bh1750_opcode_write(dev, mode);
if (rc < 0) {
LOG_ERR("%s, Failed to start measurement!",
dev->name);
return rc;
}

/* Calculate measurement time */
wait_time = (max_wait * (cfg->mtreg * 10000 / BH1750_DEFAULT_MTREG)) / 10000;

/* Wait for the measurement to be stored in the sensor memory */
k_msleep(wait_time);

/* Fetch result */
rc = bh1750_opcode_read(dev, mode, &drv_data->sample);
if (rc < 0) {
LOG_ERR("%s: Failed to read measurement result!",
dev->name);
return rc;
}

return 0;
}

static int bh1750_channel_get(const struct device *dev,
enum sensor_channel chan,
struct sensor_value *val)
{
const struct bh1750_dev_config *cfg = dev->config;
struct bh1750_data *drv_data = dev->data;
uint32_t tmp;

if (chan != SENSOR_CHAN_ALL &&
chan != SENSOR_CHAN_LIGHT) {
return -ENOTSUP;
}

/* See datasheet (Technical note 11046EDT01), page 11
* https://www.mouser.com/datasheet/2/348/Rohm_11162017_ROHMS34826-1-1279292.pdf
* for more information how to convert raw sample to lx
*/
tmp = (drv_data->sample * 1000 / 12) * (BH1750_DEFAULT_MTREG * 100 / cfg->mtreg);

if (cfg->resolution == BH1750_HIGH_RES_2_DTS_ENUM) {
tmp /= 2;
}

val->val1 = tmp / 10000;
val->val2 = (tmp % 10000) * 100;

return 0;
}

static const struct sensor_driver_api bh1750_driver_api = {
.sample_fetch = bh1750_sample_fetch,
.channel_get = bh1750_channel_get
};

static int bh1750_init(const struct device *dev)
{
const struct bh1750_dev_config *cfg = dev->config;

if (!device_is_ready(cfg->bus.bus)) {
LOG_ERR("I2C dev %s not ready", cfg->bus.bus->name);
return -ENODEV;
}

if (cfg->mtreg != BH1750_DEFAULT_MTREG) {
bh1750_mtreg_write(dev, cfg->mtreg);
}

return 0;
}

#define DEFINE_BH1750(_num) \
static struct bh1750_data bh1750_data_##_num; \
static const struct bh1750_dev_config bh1750_config_##_num = { \
.bus = I2C_DT_SPEC_INST_GET(_num), \
.mtreg = DT_INST_PROP(_num, mtreg), \
.resolution = DT_INST_PROP(_num, resolution) \
}; \
SENSOR_DEVICE_DT_INST_DEFINE(_num, bh1750_init, NULL, \
&bh1750_data_##_num, &bh1750_config_##_num, POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, &bh1750_driver_api);

DT_INST_FOREACH_STATUS_OKAY(DEFINE_BH1750)
37 changes: 37 additions & 0 deletions dts/bindings/sensor/rohm,bh1750.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Copyright (c) 2022, Michal Morsisko
# SPDX-License-Identifier: Apache-2.0

description: Rohm BH1750 ambient light sensor.

compatible: "rohm,bh1750"

include: [sensor-device.yaml, i2c-device.yaml]

properties:
resolution:
type: int
default: 1
description: |
Resolution of the measurement result
0 = low resolution
1 = high resolution
2 = high resolution 2
The default mode number 1 is mentioned
in the datasheet as recommended by the
sensor manufacturer. One should pick
other mode, if higher or lower resolution
is desired.
enum:
- 0
- 1
- 2
mtreg:
type: int
default: 69
description: |
Duration of single measurement process.
The greater the value, the longer the duration
and greater accuracy. After sensor power-on
mtreg register is set to default value of
this property (chosen by sensor manufacturer): 69.
Valid values are in range 31-254 (inclusive).
5 changes: 5 additions & 0 deletions tests/drivers/build_all/sensor/i2c.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -646,3 +646,8 @@ test_i2c_as5600: as5600@64 {
compatible = "ams,as5600";
reg = <0x64>;
};

test_i2c_bh1750: bh1750@65 {
compatible = "rohm,bh1750";
reg = <0x65>;
};