/* * Copyright (c) 2023 Tridonic * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT ltr_f216a #include #include #include #include #include #include #include LOG_MODULE_REGISTER(ltrf216a, CONFIG_SENSOR_LOG_LEVEL); /* * Driver for I2C illuminance sensor LiteOn LTR-F216A. * * Datasheet: * * 7bit Address 0x53 * 8bit Address 0xA6 read * 8bit Address 0xA7 write * NOT IMPLEMENTED: * - Interrupt * - Modifying Gain (using default x3) * - Modifying Resolution (using default 100ms) * - Modifying Measurement Rate (using default 100ms) * - Modifying Window Factor (using default 1) */ #define LTRF216A_ALS_RESET_MASK BIT(4) #define LTRF216A_ALS_ENABLE_MASK BIT(1) #define LTRF216A_ALS_DATA_STATUS BIT(3) /* Part Number ID 7:4 0b1011 = 0xB */ /* Revision ID 3:0 0b0001 = 0x1*/ #define LTRF216A_PART_ID_VALUE 0xB1 #define LTRF216A_MAIN_CTRL 0x00 #define LTRF216A_ALS_MEAS_RES 0x04 #define LTRF216A_ALS_GAIN 0x05 #define LTRF216A_PART_ID 0x06 #define LTRF216A_MAIN_STATUS 0x07 #define LTRF216A_ALS_CLEAR_DATA_0 0x0a #define LTRF216A_ALS_CLEAR_DATA_1 0x0b #define LTRF216A_ALS_CLEAR_DATA_2 0x0c #define LTRF216A_ALS_DATA_0 0x0d #define LTRF216A_ALS_DATA_1 0x0e #define LTRF216A_ALS_DATA_2 0x0f #define LTRF216A_INT_CFG 0x19 #define LTRF216A_INT_PST 0x1a #define LTRF216A_ALS_THRES_UP_0 0x21 #define LTRF216A_ALS_THRES_UP_1 0x22 #define LTRF216A_ALS_THRES_UP_2 0x23 #define LTRF216A_ALS_THRES_LOW_0 0x24 #define LTRF216A_ALS_THRES_LOW_1 0x25 #define LTRF216A_ALS_THRES_LOW_2 0x26 #define LTRF216A_WIN_FAC 1 #define LTRF216A_NUMBER_DATA_REGISTERS 3 struct ltrf216a_data { uint8_t sample[3]; }; struct ltrf216a_config { struct i2c_dt_spec i2c; }; static int ltrf216a_sample_fetch(const struct device *dev, enum sensor_channel chan) { struct ltrf216a_data *drv_data = dev->data; const struct ltrf216a_config *config = dev->config; uint8_t status; int result; uint8_t value; __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_LIGHT); value = LTRF216A_ALS_ENABLE_MASK; result = i2c_reg_write_byte_dt(&config->i2c, LTRF216A_MAIN_CTRL, LTRF216A_ALS_ENABLE_MASK); if (result != 0) { LOG_ERR("ltfr216a: enable failed"); return result; } result = i2c_reg_read_byte_dt(&config->i2c, LTRF216A_MAIN_STATUS, &status); if (result != 0) { LOG_ERR("ltfr216a: read main status failed"); return -EIO; } if ((status & LTRF216A_ALS_DATA_STATUS) == 0) { LOG_WRN("ltfr216a: main status not ready"); return -EBUSY; } if (i2c_burst_read_dt(&config->i2c, LTRF216A_ALS_DATA_0, drv_data->sample, LTRF216A_NUMBER_DATA_REGISTERS) != 0) { LOG_ERR("ltfr216a: reading samples failed"); return -EIO; } return 0; } static int ltrf216a_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { struct ltrf216a_data *drv_data = dev->data; if (chan != SENSOR_CHAN_LIGHT) { return -ENOTSUP; } uint32_t greendata = sys_get_le24(drv_data->sample); /* * 0.45 -> 45 / 100, multiplied by 1000000 for millilux * gain 3 (default), integration time 100ms=1 */ uint64_t microlux = ((uint64_t)greendata * 45000 * LTRF216A_WIN_FAC * 10) / (3 * 1); val->val1 = microlux / 1000000; val->val2 = microlux % 1000000; return 0; } static const struct sensor_driver_api ltrf216a_driver_api = { .sample_fetch = ltrf216a_sample_fetch, .channel_get = ltrf216a_channel_get, }; static int ltrf216a_chip_init(const struct device *dev) { const struct ltrf216a_config *config = dev->config; uint8_t value; if (!i2c_is_ready_dt(&config->i2c)) { LOG_ERR("Bus device is not ready"); return -ENODEV; } if (i2c_reg_read_byte_dt(&config->i2c, LTRF216A_PART_ID, &value) != 0) { return -EIO; } if (value != LTRF216A_PART_ID_VALUE) { LOG_ERR("Bad manufacturer id 0x%x", value); return -ENOTSUP; } return 0; } #define LTRF216A_DEFINE(inst) \ static struct ltrf216a_data ltrf216a_data_##inst; \ \ static const struct ltrf216a_config ltrf216a_config_##inst = { \ .i2c = I2C_DT_SPEC_INST_GET(inst), \ }; \ \ SENSOR_DEVICE_DT_INST_DEFINE(inst, ltrf216a_chip_init, NULL, <rf216a_data_##inst, \ <rf216a_config_##inst, POST_KERNEL, \ CONFIG_SENSOR_INIT_PRIORITY, <rf216a_driver_api); DT_INST_FOREACH_STATUS_OKAY(LTRF216A_DEFINE)