diff options
Diffstat (limited to 'driver/als_opt3001.c')
-rw-r--r-- | driver/als_opt3001.c | 211 |
1 files changed, 210 insertions, 1 deletions
diff --git a/driver/als_opt3001.c b/driver/als_opt3001.c index bbf61a1064..7e080e8c89 100644 --- a/driver/als_opt3001.c +++ b/driver/als_opt3001.c @@ -8,6 +8,7 @@ #include "driver/als_opt3001.h" #include "i2c.h" +#ifdef HAS_TASK_ALS /** * Read register from OPT3001 light sensor. */ @@ -98,4 +99,212 @@ struct i2c_stress_test_dev opt3001_i2c_stress_test_dev = { .i2c_read_dev = &opt3001_i2c_read, .i2c_write_dev = &opt3001_i2c_write, }; -#endif /* CONFIG_CMD_I2C_STRESS_TEST_ALS */ +#endif /* CONFIG_CMD_I2C_STRESS_TEST_ALS */ +#else /* HAS_TASK_ALS */ +#include "accelgyro.h" +#include "math_util.h" + +/** + * Read register from OPT3001 light sensor. + */ +static int opt3001_i2c_read(const int port, const int addr, const int reg, + int *data_ptr) +{ + int ret; + + ret = i2c_read16(port, addr, reg, data_ptr); + if (!ret) + *data_ptr = ((*data_ptr << 8) & 0xFF00) | + ((*data_ptr >> 8) & 0x00FF); + + return ret; +} + +/** + * Write register to OPT3001 light sensor. + */ +static int opt3001_i2c_write(const int port, const int addr, const int reg, + int data) +{ + data = ((data << 8) & 0xFF00) | ((data >> 8) & 0x00FF); + return i2c_write16(port, addr, reg, data); +} + +/** + * Read OPT3001 light sensor data. + */ +int opt3001_read_lux(const struct motion_sensor_t *s, vector_3_t v) +{ + struct opt3001_drv_data_t *drv_data = OPT3001_GET_DATA(s); + int ret; + int data; + + ret = opt3001_i2c_read(s->port, s->addr, OPT3001_REG_RESULT, &data); + if (ret) + return ret; + + /* + * The default power-on values will give 12 bits of precision: + * 0x0000-0x0fff indicates 0 to 1310.40 lux. We multiply the sensor + * value by a scaling factor to account for attenuation by glass, + * tinting, etc. + */ + + /* + * lux = 2EXP[3:0] × R[11:0] / 100 + */ + v[0] = ((1 << ((data & 0xF000) >> 12)) * (data & 0x0FFF) * + drv_data->attenuation) / 100; + v[1] = 0; + v[2] = 0; + + /* + * Return an error when nothing change to prevent filling the + * fifo with useless data. + */ + if (v[0] == drv_data->last_value) + return EC_ERROR_UNCHANGED; + else + return EC_SUCCESS; +} + +static int opt3001_set_range(const struct motion_sensor_t *s, int range, + int rnd) +{ + int rv; + int reg; + struct opt3001_drv_data_t *drv_data = OPT3001_GET_DATA(s); + + if (range < 0 || range > OPT3001_RANGE_AUTOMATIC_FULL_SCALE) + return EC_ERROR_INVAL; + + rv = opt3001_i2c_read(s->port, s->addr, OPT3001_REG_CONFIGURE, ®); + if (rv) + return rv; + + rv = opt3001_i2c_write(s->port, s->addr, OPT3001_REG_CONFIGURE, + (reg & OPT3001_RANGE_MASK) | + (range << OPT3001_RANGE_OFFSET)); + if (rv) + return rv; + + drv_data->range = range; + + return EC_SUCCESS; +} + +static int opt3001_get_range(const struct motion_sensor_t *s) +{ + struct opt3001_drv_data_t *drv_data = OPT3001_GET_DATA(s); + + return drv_data->range; +} + +static int opt3001_set_data_rate(const struct motion_sensor_t *s, + int rate, int roundup) +{ + struct opt3001_drv_data_t *drv_data = OPT3001_GET_DATA(s); + int rv; + int reg; + enum opt3001_mode mode; + + if (rate == 0) { + /* + * Suspend driver: + */ + mode = OPT3001_MODE_SUSPEND; + } else { + mode = OPT3001_MODE_CONTINUOUS; + /* + * We set the sensor for continuous mode, + * integrating over 800ms. + * Do not allow range higher than 1Hz. + */ + if (rate > 1000) + rate = 1000; + } + rv = opt3001_i2c_read(s->port, s->addr, OPT3001_REG_CONFIGURE, ®); + if (rv) + return rv; + + rv = opt3001_i2c_write(s->port, s->addr, OPT3001_REG_CONFIGURE, + (reg & OPT3001_MODE_MASK) | + (mode << OPT3001_MODE_OFFSET)); + if (rv) + return rv; + + drv_data->rate = rate; + return EC_SUCCESS; +} + +static int opt3001_get_data_rate(const struct motion_sensor_t *s) +{ + struct opt3001_drv_data_t *drv_data = OPT3001_GET_DATA(s); + + return drv_data->rate; +} + +static int opt3001_set_offset(const struct motion_sensor_t *s, + const int16_t *offset, + int16_t temp) +{ + return EC_RES_INVALID_COMMAND; +} + +static int opt3001_get_offset(const struct motion_sensor_t *s, + int16_t *offset, + int16_t *temp) +{ + return EC_RES_INVALID_COMMAND; +} +/** + * Initialise OPT3001 light sensor. + */ +static int opt3001_init(const struct motion_sensor_t *s) +{ + int data; + int ret; + + ret = opt3001_i2c_read(s->port, s->addr, OPT3001_REG_MAN_ID, &data); + if (ret) + return ret; + if (data != OPT3001_MANUFACTURER_ID) + return EC_ERROR_ACCESS_DENIED; + + ret = opt3001_i2c_read(s->port, s->addr, OPT3001_REG_DEV_ID, &data); + if (ret) + return ret; + if (data != OPT3001_DEVICE_ID) + return EC_ERROR_ACCESS_DENIED; + + /* + * [11] : 1b Conversion time 800ms + * [4] : 1b Latched window-style comparison operation + */ + opt3001_i2c_write(s->port, s->addr, OPT3001_REG_CONFIGURE, 0x810); + return opt3001_set_range(s, s->default_range, 0); +} + +const struct accelgyro_drv opt3001_drv = { + .init = opt3001_init, + .read = opt3001_read_lux, + .set_range = opt3001_set_range, + .get_range = opt3001_get_range, + .set_offset = opt3001_set_offset, + .get_offset = opt3001_get_offset, + .set_data_rate = opt3001_set_data_rate, + .get_data_rate = opt3001_get_data_rate, +}; + +#ifdef CONFIG_CMD_I2C_STRESS_TEST_ALS +struct i2c_stress_test_dev opt3001_i2c_stress_test_dev = { + .reg_info = { + .read_reg = OPT3001_REG_DEV_ID, + .read_val = OPT3001_DEVICE_ID, + .write_reg = OPT3001_REG_INT_LIMIT_LSB, + }, + .i2c_read = &opt3001_i2c_read, + .i2c_write = &opt3001_i2c_write, +}; +#endif /* CONFIG_CMD_I2C_STRESS_TEST_ALS */ +#endif /* HAS_TASK_ALS */ |