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