// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2024 Axis Communications AB
*
* Datasheet: https://www.ti.com/lit/gpn/opt4060
*
* Device driver for the Texas Instruments OPT4060 RGBW Color Sensor.
*/
#include <linux/bitfield.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/math64.h>
#include <linux/units.h>
#include <linux/limits.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/mutex.h>
#include <linux/regulator/consumer.h>
#include <linux/iio/events.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
/* OPT4060 register set */
#define OPT4060_RED_MSB 0x00
#define OPT4060_RED_LSB 0x01
#define OPT4060_GREEN_MSB 0x02
#define OPT4060_GREEN_LSB 0x03
#define OPT4060_BLUE_MSB 0x04
#define OPT4060_BLUE_LSB 0x05
#define OPT4060_CLEAR_MSB 0x06
#define OPT4060_CLEAR_LSB 0x07
#define OPT4060_THRESHOLD_LOW 0x08
#define OPT4060_THRESHOLD_HIGH 0x09
#define OPT4060_CTRL 0x0a
#define OPT4060_INT_CTRL 0x0b
#define OPT4060_RES_CTRL 0x0c
#define OPT4060_DEVICE_ID 0x11
/* OPT4060 register mask */
#define OPT4060_EXPONENT_MASK GENMASK(15, 12)
#define OPT4060_MSB_MASK GENMASK(11, 0)
#define OPT4060_LSB_MASK GENMASK(15, 8)
#define OPT4060_COUNTER_MASK GENMASK(7, 4)
#define OPT4060_CRC_MASK GENMASK(3, 0)
/* OPT4060 device id mask */
#define OPT4060_DEVICE_ID_MASK GENMASK(11, 0)
/* OPT4060 control register masks */
#define OPT4060_CTRL_QWAKE_MASK BIT(15)
#define OPT4060_CTRL_RANGE_MASK GENMASK(13, 10)
#define OPT4060_CTRL_CONV_TIME_MASK GENMASK(9, 6)
#define OPT4060_CTRL_OPER_MODE_MASK GENMASK(5, 4)
#define OPT4060_CTRL_LATCH_MASK BIT(3)
#define OPT4060_CTRL_INT_POL_MASK BIT(2)
#define OPT4060_CTRL_FAULT_COUNT_MASK GENMASK(1, 0)
/* OPT4060 interrupt control register masks */
#define OPT4060_INT_CTRL_THRESH_SEL GENMASK(6, 5)
#define OPT4060_INT_CTRL_OUTPUT BIT(4)
#define OPT4060_INT_CTRL_INT_CFG GENMASK(3, 2)
#define OPT4060_INT_CTRL_THRESHOLD 0x0
#define OPT4060_INT_CTRL_NEXT_CH 0x1
#define OPT4060_INT_CTRL_ALL_CH 0x3
/* OPT4060 result control register masks */
#define OPT4060_RES_CTRL_OVERLOAD BIT(3)
#define OPT4060_RES_CTRL_CONV_READY BIT(2)
#define OPT4060_RES_CTRL_FLAG_H BIT(1)
#define OPT4060_RES_CTRL_FLAG_L BIT(0)
/* OPT4060 constants */
#define OPT4060_DEVICE_ID_VAL 0x821
/* OPT4060 operating modes */
#define OPT4060_CTRL_OPER_MODE_OFF 0x0
#define OPT4060_CTRL_OPER_MODE_FORCED 0x1
#define OPT4060_CTRL_OPER_MODE_ONE_SHOT 0x2
#define OPT4060_CTRL_OPER_MODE_CONTINUOUS 0x3
/* OPT4060 conversion control register definitions */
#define OPT4060_CTRL_CONVERSION_0_6MS 0x0
#define OPT4060_CTRL_CONVERSION_1MS 0x1
#define OPT4060_CTRL_CONVERSION_1_8MS 0x2
#define OPT4060_CTRL_CONVERSION_3_4MS 0x3
#define OPT4060_CTRL_CONVERSION_6_5MS 0x4
#define OPT4060_CTRL_CONVERSION_12_7MS 0x5
#define OPT4060_CTRL_CONVERSION_25MS 0x6
#define OPT4060_CTRL_CONVERSION_50MS 0x7
#define OPT4060_CTRL_CONVERSION_100MS 0x8
#define OPT4060_CTRL_CONVERSION_200MS 0x9
#define OPT4060_CTRL_CONVERSION_400MS 0xa
#define OPT4060_CTRL_CONVERSION_800MS 0xb
/* OPT4060 fault count control register definitions */
#define OPT4060_CTRL_FAULT_COUNT_1 0x0
#define OPT4060_CTRL_FAULT_COUNT_2 0x1
#define OPT4060_CTRL_FAULT_COUNT_4 0x2
#define OPT4060_CTRL_FAULT_COUNT_8 0x3
/* OPT4060 scale light level range definitions */
#define OPT4060_CTRL_LIGHT_SCALE_AUTO 12
/* OPT4060 default values */
#define OPT4060_DEFAULT_CONVERSION_TIME OPT4060_CTRL_CONVERSION_50MS
/*
* enum opt4060_chan_type - OPT4060 channel types
* @OPT4060_RED: Red channel.
* @OPT4060_GREEN: Green channel.
* @OPT4060_BLUE: Blue channel.
* @OPT4060_CLEAR: Clear (white) channel.
* @OPT4060_ILLUM: Calculated illuminance channel.
* @OPT4060_NUM_CHANS: Number of channel types.
*/
enum opt4060_chan_type {
OPT4060_RED,
OPT4060_GREEN,
OPT4060_BLUE,
OPT4060_CLEAR,
OPT4060_ILLUM,
OPT4060_NUM_CHANS
};
struct opt4060_chip {
struct regmap *regmap;
struct device *dev;
struct iio_trigger *trig;
u8 int_time;
int irq;
/*
* Mutex for protecting sensor irq settings. Switching between interrupt
* on each sample and on thresholds needs to be synchronized.
*/
struct mutex irq_setting_lock;
/*
* Mutex for protecting event enabling.
*/
struct mutex event_enabling_lock;
struct completion completion;
bool thresh_event_lo_active;
bool thresh_event_hi_active;
};
struct opt4060_channel_factor {
u32 mul;
u32 div;
};
static const int opt4060_int_time_available[][2] = {
{ 0, 600 },
{ 0, 1000 },
{ 0, 1800 <