/*
* ltr501.c - Support for Lite-On LTR501 ambient light and proximity sensor
*
* Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net>
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*
* 7-bit I2C slave address 0x23
*
* TODO: IR LED characteristics
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/regmap.h>
#include <linux/acpi.h>
#include <linux/iio/iio.h>
#include <linux/iio/events.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/buffer.h>
#include <linux/iio/triggered_buffer.h>
#define LTR501_DRV_NAME "ltr501"
#define LTR501_ALS_CONTR 0x80 /* ALS operation mode, SW reset */
#define LTR501_PS_CONTR 0x81 /* PS operation mode */
#define LTR501_PS_MEAS_RATE 0x84 /* measurement rate*/
#define LTR501_ALS_MEAS_RATE 0x85 /* ALS integ time, measurement rate*/
#define LTR501_PART_ID 0x86
#define LTR501_MANUFAC_ID 0x87
#define LTR501_ALS_DATA1 0x88 /* 16-bit, little endian */
#define LTR501_ALS_DATA0 0x8a /* 16-bit, little endian */
#define LTR501_ALS_PS_STATUS 0x8c
#define LTR501_PS_DATA 0x8d /* 16-bit, little endian */
#define LTR501_INTR 0x8f /* output mode, polarity, mode */
#define LTR501_PS_THRESH_UP 0x90 /* 11 bit, ps upper threshold */
#define LTR501_PS_THRESH_LOW 0x92 /* 11 bit, ps lower threshold */
#define LTR501_ALS_THRESH_UP 0x97 /* 16 bit, ALS upper threshold */
#define LTR501_ALS_THRESH_LOW 0x99 /* 16 bit, ALS lower threshold */
#define LTR501_INTR_PRST 0x9e /* ps thresh, als thresh */
#define LTR501_MAX_REG 0x9f
#define LTR501_ALS_CONTR_SW_RESET BIT(2)
#define LTR501_CONTR_PS_GAIN_MASK (BIT(3) | BIT(2))
#define LTR501_CONTR_PS_GAIN_SHIFT 2
#define LTR501_CONTR_ALS_GAIN_MASK BIT(3)
#define LTR501_CONTR_ACTIVE BIT(1)
#define LTR501_STATUS_ALS_INTR BIT(3)
#define LTR501_STATUS_ALS_RDY BIT(2)
#define LTR501_STATUS_PS_INTR BIT(1)
#define LTR501_STATUS_PS_RDY BIT(0)
#define LTR501_PS_DATA_MASK 0x7ff
#define LTR501_PS_THRESH_MASK 0x7ff
#define LTR501_ALS_THRESH_MASK 0xffff
#define LTR501_ALS_DEF_PERIOD 500000
#define LTR501_PS_DEF_PERIOD 100000
#define LTR501_REGMAP_NAME "ltr501_regmap"
#define LTR501_LUX_CONV(vis_coeff, vis_data, ir_coeff, ir_data) \
((vis_coeff * vis_data) - (ir_coeff * ir_data))
static const int int_time_mapping[] = {100000, 50000, 200000, 400000};
static const struct reg_field reg_field_it =
REG_FIELD(LTR501_ALS_MEAS_RATE, 3, 4);
static const struct reg_field reg_field_als_intr =
REG_FIELD(LTR501_INTR, 1, 1);
static const struct reg_field reg_field_ps_intr =
REG_FIELD(LTR501_INTR, 0, 0);
static const struct reg_field reg_field_als_rate =
REG_FIELD(LTR501_ALS_MEAS_RATE, 0, 2);
static const struct reg_field reg_field_ps_rate =
REG_FIELD(LTR501_PS_MEAS_RATE, 0, 3);
static const struct reg_field reg_field_als_prst =
REG_FIELD(LTR501_INTR_PRST, 0, 3);
static const struct reg_field reg_field_ps_prst =
REG_FIELD(LTR501_INTR_PRST, 4, 7);
struct ltr501_samp_table {
int freq_val; /* repetition frequency in micro HZ*/
int time_val; /* repetition rate in micro seconds */
};
#define LTR501_RESERVED_GAIN -1
enum {
ltr501 = 0,
ltr559,
ltr301,
};
struct ltr501_gain {
int scale;
int uscale;
};
static struct ltr501_gain ltr501_als_gain_tbl[] = {
{1, 0},
{0, 5000},
};
static struct ltr501_gain ltr559_als_gain_tbl[] = {
{1, 0},
{0, 500000},
{0, 250000},
{0, 125000},
{LTR501_RESERVED_GAIN, LTR501_RESERVED_GAIN},
{LTR501_RESERVED_GAIN, LTR501_RESERVED_GAIN},
{0, 20000},
{0, 10000},
};
static struct ltr501_gain ltr501_ps_gain_tbl[] = {
{1, 0},
{0, 250000},
{0, 125000},
{0, 62500},
};
static struct ltr501_gain ltr559_ps_gain_tbl[] = {
{0, 62500}, /* x16 gain */
{0, 31250}, /* x32 gain */
{0, 15625}, /* bits X1 are for x64 gain */
{0, 15624},
};
struct ltr501_chip_info {
u8 partid;
struct ltr501_gain *als_gain;
int als_gain_tbl_size;
struct ltr501_gain *ps_gain;
int ps_gain_tbl_size;
u8 als_mode_active;
u8 als_gain_mask;
u8 als_gain_shift;
struct iio_chan_spec const *channels;
const int no_channels;
const struct iio_info *info;
const struct iio_info *info_no_irq;
};
struct ltr501_data {
struct i2c_client *client;
struct mutex lock_als, lock_ps;
struct ltr501_chip_info *chip_info;
u8 als_contr, ps_contr;
int als_period, ps_period; /* period in micro seconds */
struct regmap *regmap;
struct regmap_field *reg_it;
struct regmap_field *reg_als_intr;
struct regmap_field *reg_ps_intr;
struct regmap_field *reg_als_rate;
struct regmap_field *reg_ps_rate;
struct regmap_field *reg_als_prst;
struct regmap_field *reg_ps_prst;
};
static const struct ltr501_samp_table ltr501_als_samp_table[] = {
{20000000, 50000}, {10000000, 100000},
{5000000, 200000}, {2000000, 500000},
{1000000, 1000000}, {500000, 2000000},
{500000, 2000000}, {500000, 2000000}
};
static const struct ltr501_samp_table ltr501_ps_samp_table[] = {
{20000000, 50000}, {14285714, 70000},
{10000000, 100000}, {5000000, 2
|