// SPDX-License-Identifier: GPL-2.0-or-later
/*
* APDS-9306/APDS-9306-065 Ambient Light Sensor
* I2C Address: 0x52
* Datasheet: https://docs.broadcom.com/doc/AV02-4755EN
*
* Copyright (C) 2024 Subhajit Ghosh <subhajit.ghosh@tweaklogic.com>
*/
#include <linux/bits.h>
#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/types.h>
#include <linux/units.h>
#include <linux/iio/iio.h>
#include <linux/iio/iio-gts-helper.h>
#include <linux/iio/events.h>
#include <linux/iio/sysfs.h>
#include <linux/unaligned.h>
#define APDS9306_MAIN_CTRL_REG 0x00
#define APDS9306_ALS_MEAS_RATE_REG 0x04
#define APDS9306_ALS_GAIN_REG 0x05
#define APDS9306_PART_ID_REG 0x06
#define APDS9306_MAIN_STATUS_REG 0x07
#define APDS9306_CLEAR_DATA_0_REG 0x0A
#define APDS9306_CLEAR_DATA_1_REG 0x0B
#define APDS9306_CLEAR_DATA_2_REG 0x0C
#define APDS9306_ALS_DATA_0_REG 0x0D
#define APDS9306_ALS_DATA_1_REG 0x0E
#define APDS9306_ALS_DATA_2_REG 0x0F
#define APDS9306_INT_CFG_REG 0x19
#define APDS9306_INT_PERSISTENCE_REG 0x1A
#define APDS9306_ALS_THRES_UP_0_REG 0x21
#define APDS9306_ALS_THRES_UP_1_REG 0x22
#define APDS9306_ALS_THRES_UP_2_REG 0x23
#define APDS9306_ALS_THRES_LOW_0_REG 0x24
#define APDS9306_ALS_THRES_LOW_1_REG 0x25
#define APDS9306_ALS_THRES_LOW_2_REG 0x26
#define APDS9306_ALS_THRES_VAR_REG 0x27
#define APDS9306_ALS_INT_STAT_MASK BIT(4)
#define APDS9306_ALS_DATA_STAT_MASK BIT(3)
#define APDS9306_ALS_THRES_VAL_MAX (BIT(20) - 1)
#define APDS9306_ALS_THRES_VAR_NUM_VALS 8
#define APDS9306_ALS_PERSIST_NUM_VALS 16
#define APDS9306_ALS_READ_DATA_DELAY_US (20 * USEC_PER_MSEC)
#define APDS9306_NUM_REPEAT_RATES 7
#define APDS9306_INT_SRC_CLEAR 0
#define APDS9306_INT_SRC_ALS 1
#define APDS9306_SAMP_FREQ_10HZ 0
/**
* struct part_id_gts_multiplier - Part no. and corresponding gts multiplier
*
* GTS (Gain Time Scale) are helper functions for Light sensors which along
* with hardware gains also has gains associated with Integration times.
*
* There are two variants of the device with slightly different characteristics,
* they have same ADC count for different Lux levels as mentioned in the
* datasheet. This multiplier array is used to store the derived Lux per count
* value for the two variants to be used by the GTS helper functions.
*
* @part_id: Part ID of the device
* @max_scale_int: Multiplier for iio_init_iio_gts()
* @max_scale_nano: Multiplier for iio_init_iio_gts()
*/
struct part_id_gts_multiplier {
int part_id;
int max_scale_int;
int max_scale_nano;
};
/*
* As per the datasheet, at HW Gain = 3x, Integration time 100mS (32x),
* typical 2000 ADC counts are observed for 49.8 uW per sq cm (340.134 lux)
* for apds9306 and 43 uW per sq cm (293.69 lux) for apds9306-065.
* Assuming lux per count is linear across all integration time ranges.
*
* Lux = (raw + offset) * scale; offset can be any value by userspace.
* HG = Hardware Gain; ITG = Gain by changing integration time.
* Scale table by IIO GTS Helpers = (1 / HG) * (1 / ITG) * Multiplier.
*
* The Lux values provided in the datasheet are at ITG=32x and HG=3x,
* at typical 2000 count for both variants of the device.
*
* Lux per ADC count at 3x and 32x for apds9306 = 340.134 / 2000
* Lux per ADC count at 3x and 32x for apds9306-065 = 293.69 / 2000
*
* The Multiplier for the scale table provided to userspace:
* IIO GTS scale Multiplier for apds9306 = (340.134 / 2000) * 32 * 3 = 16.326432
* and for apds9306-065 = (293.69 / 2000) * 32 * 3 = 14.09712
*/
static const struct part_id_gts_multiplier apds9306_gts_mul[] = {
{
.part_id = 0xB1,
.max_scale_int = 16,
.max_scale_nano = 3264320,
}, {
.part_id = 0xB3,
.max_scale_int = 14,
.max_scale_nano = 9712000,
},
};
static const int apds9306_repeat_rate_freq[APDS9306_NUM_REPEAT_RATES][2] = {
{ 40, 0 },
{ 20, 0 },
{ 10, 0 },
{ 5, 0 },
{ 2, 0 },
{ 1, 0 },
{