blob: b870fabfbd0bacdab200e34e71cf617a4831c84e [file] [log] [blame]
/*
* Device driver for monitoring ambient light intensity in (lux)
* proximity detection (prox), Gesture, and Beam functionality within the
* AMS-TAOS TMG399X family of devices.
*
* Copyright (c) 2013, AMS-TAOS USA, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __TMG399X_H
#define __TMG399X_H
#include <linux/types.h>
#include <linux/timer.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
/* Max number of segments allowable in LUX table */
#define TMG399X_MAX_LUX_TABLE_SIZE 9
#define MAX_DEFAULT_TABLE_BYTES (sizeof(int) * TMG399X_MAX_LUX_TABLE_SIZE)
/* Default LUX and Color coefficients */
#define D_Factor 241
#define R_Coef 144
#define G_Coef 1000
#define B_Coef 400
#define CT_Coef (3972)
#define CT_Offset (1672)
#define D_Factor1 1375
#define R_Coef1 -5
#define G_Coef1 1000
#define B_Coef1 452
#define CT_Coef1 5111
#define CT_Offset1 547
/* Default Beam configuration */
#define IRBEAM_CFG 0x29
#define IRBEAM_CARR 0x00
#define IRBEAM_NS 0x0A
#define IRBEAM_ISD 0x31
#define IRBEAM_NP 0x0A
#define IRBEAM_IPD 0x32
#define IRBEAM_DIV 0x32
#define IRBEAM_MAX_NUM_HOPS 15
/* Proximity threshold definition */
#define PROX_THRESH_LOW 50
#define PROX_THRESH_HIGH 80
struct device;
#define TMG399X_CMD_IRBEAM_INT_CLR 0xE3
#define TMG399X_CMD_PROX_INT_CLR 0xE5
#define TMG399X_CMD_ALS_INT_CLR 0xE6
#define TMG399X_CMD_NON_GES_INT_CLR 0xE7
#define PRX_PERSIST(p) (((p) & 0xf) << 4)
#define ALS_PERSIST(p) (((p) & 0xf) << 0)
#define PRX_PULSE_CNT(p) (((p-1) & 0x3f) << 0)
#define GES_PULSE_CNT(p) (((p-1) & 0x3f) << 0)
#define INT2OFFSET(offset, value) do {\
if (value < 0)\
offset = 128 - value; \
else \
offset = value; \
} while (0)
#define I2C_ADDR_OFFSET 0x80
enum tmg399x_regs {
TMG399X_CONTROL,
TMG399X_ALS_TIME,
TMG399X_RESV_1,
TMG399X_WAIT_TIME,
TMG399X_ALS_MINTHRESHLO,
TMG399X_ALS_MINTHRESHHI,
TMG399X_ALS_MAXTHRESHLO,
TMG399X_ALS_MAXTHRESHHI,
TMG399X_RESV_2,
TMG399X_PRX_MINTHRESHLO,
TMG399X_RESV_3,
TMG399X_PRX_MAXTHRESHHI,
TMG399X_PERSISTENCE,
TMG399X_CONFIG_1,
TMG399X_PRX_PULSE,
TMG399X_GAIN,
TMG399X_CONFIG_2,
TMG399X_REVID,
TMG399X_CHIPID,
TMG399X_STATUS,
TMG399X_CLR_CHANLO,
TMG399X_CLR_CHANHI,
TMG399X_RED_CHANLO,
TMG399X_RED_CHANHI,
TMG399X_GRN_CHANLO,
TMG399X_GRN_CHANHI,
TMG399X_BLU_CHANLO,
TMG399X_BLU_CHANHI,
TMG399X_PRX_CHAN,
TMG399X_PRX_OFFSET_NE,
TMG399X_PRX_OFFSET_SW,
TMG399X_CONFIG_3,
TMG399X_GES_ENTH,
TMG399X_GES_EXTH,
TMG399X_GES_CFG_1,
TMG399X_GES_CFG_2,
TMG399X_GES_OFFSET_N,
TMG399X_GES_OFFSET_S,
TMG399X_GES_PULSE,
TMG399X_GES_OFFSET_W,
TMG399X_GES_RESV,
TMG399X_GES_OFFSET_E,
TMG399X_GES_CFG_3,
TMG399X_GES_CFG_4,
TMG399X_RESV_4,
TMG399X_RESV_5,
TMG399X_GES_FLVL,
TMG399X_GES_STAT,
TMG399X_REG_MAX,
};
enum tmg399x_gesfifo_regs {
TMG399X_GES_NFIFO = 0x7C,
TMG399X_GES_SFIFO,
TMG399X_GES_WFIFO,
TMG399X_GES_EFIFO,
};
enum tmg399x_irbeam_regs {
TMG399X_IRBEAM_CFG = 0x20,
TMG399X_IRBEAM_CARR,
TMG399X_IRBEAM_NS,
TMG399X_IRBEAM_ISD,
TMG399X_IRBEAM_NP,
TMG399X_IRBEAM_IPD,
TMG399X_IRBEAM_DIV,
TMG399X_IRBEAM_LEN,
TMG399X_IRBEAM_STAT,
};
enum tmg399x_remote_regs {
TMG399X_REMOTE_CFG = 0x20,
TMG399X_REMOTE_CARR,
TMG399X_REMOTE_NS,
TMG399X_REMOTE_DLY2T,
TMG399X_REMOTE_NCP,
TMG399X_REMOTE_CPOFF,
TMG399X_REMOTE_DIV,
TMG399X_REMOTE_LEN,
TMG399X_REMOTE_STAT,
TMG399X_REMOTE_SLEN,
};
enum tmg399x_pwr_state {
POWER_ON,
POWER_OFF,
POWER_STANDBY,
};
enum tmg399x_en_reg {
TMG399X_EN_PWR_ON = (1 << 0),
TMG399X_EN_ALS = (1 << 1),
TMG399X_EN_PRX = (1 << 2),
TMG399X_EN_WAIT = (1 << 3),
TMG399X_EN_ALS_IRQ = (1 << 4),
TMG399X_EN_PRX_IRQ = (1 << 5),
TMG399X_EN_GES = (1 << 6),
TMG399X_EN_BEAM = (1 << 7),
};
enum tmg399x_cfgl_reg {
WLONG = (1 << 1),
};
enum tmg399x_ppulse_reg {
PPLEN_4US = (0 << 6),
PPLEN_8US = (1 << 6),
PPLEN_16US = (2 << 6),
PPLEN_32US = (3 << 6),
};
enum tmg399x_ctrl_reg {
AGAIN_1 = (0 << 0),
AGAIN_4 = (1 << 0),
AGAIN_16 = (2 << 0),
AGAIN_64 = (3 << 0),
PGAIN_1 = (0 << 2),
PGAIN_2 = (1 << 2),
PGAIN_4 = (2 << 2),
PGAIN_8 = (3 << 2),
PDRIVE_100MA = (0 << 6),
PDRIVE_50MA = (1 << 6),
PDRIVE_25MA = (2 << 6),
PDRIVE_12MA = (3 << 6),
};
enum tmg399x_cfg2_reg {
LEDBOOST_100 = (0 << 4),
LEDBOOST_150 = (1 << 4),
LEDBOOST_200 = (2 << 4),
LEDBOOST_300 = (3 << 4),
CPSIEN = (1 << 6),
PSIEN = (1 << 7),
};
enum tmg399x_status {
TMG399X_ST_ALS_VALID = (1 << 0),
TMG399X_ST_PRX_VALID = (1 << 1),
TMG399X_ST_GES_IRQ = (1 << 2),
TMG399X_ST_BEAM_IRQ = (1 << 3),
TMG399X_ST_ALS_IRQ = (1 << 4),
TMG399X_ST_PRX_IRQ = (1 << 5),
TMG399X_ST_PRX_SAT = (1 << 6),
TMG399X_ST_CP_SAT = (1 << 7),
};
enum tmg399x_cfg3_reg {
PMASK_E = (1 << 0),
PMASK_W = (1 << 1),
PMASK_S = (1 << 2),
PMASK_N = (1 << 3),
SAI = (1 << 4),
PCMP = (1 << 5),
};
enum tmg399x_ges_cfg1_reg {
GEXPERS_1 = (0 << 0),
GEXPERS_2 = (1 << 0),
GEXPERS_4 = (2 << 0),
GEXPERS_7 = (3 << 0),
GEXMSK_E = (1 << 2),
GEXMSK_W = (1 << 3),
GEXMSK_S = (1 << 4),
GEXMSK_N = (1 << 5),
GEXMSK_ALL = (0xF << 2),
FIFOTH_1 = (0 << 6),
FIFOTH_4 = (1 << 6),
FIFOTH_8 = (2 << 6),
FIFOTH_16 = (3 << 6),
};
enum tmg399x_ges_cfg2_reg {
GWTIME_0 = (0 << 0),
GWTIME_3 = (1 << 0),
GWTIME_6 = (2 << 0),
GWTIME_8 = (3 << 0),
GWTIME_14 = (4 << 0),
GWTIME_22 = (5 << 0),
GWTIME_30 = (6 << 0),
GWTIME_39 = (7 << 0),
GLDRIVE_100 = (0 << 3),
GLDRIVE_50 = (1 << 3),
GLDRIVE_25 = (2 << 3),
GLDRIVE_12 = (3 << 3),
GGAIN_1 = (0 << 5),
GGAIN_2 = (1 << 5),
GGAIN_4 = (2 << 5),
GGAIN_8 = (3 << 5),
};
enum tmg399x_gpulse_reg {
GPLEN_4US = (0 << 6),
GPLEN_8US = (1 << 6),
GPLEN_16US = (2 << 6),
GPLEN_32US = (3 << 6),
};
enum tmg399x_ges_cfg3_reg {
GBOTH_PAIR = (0 << 0),
GONLY_NS = (1 << 0),
GONLY_WE = (2 << 0),
};
enum tmg399x_ges_cfg4 {
TMG399X_GES_MODE = (1 << 0),
TMG399X_GES_EN_IRQ = (1 << 1),
TMG399X_GES_INT_CLR = (1 << 2),
};
enum tmg399x_ges_status {
TMG399X_GES_VALID = (1 << 0),
TMG399X_GES_FOV = (1 << 1),
};
enum {
TMG399X_ALS_GAIN_MASK = (3 << 0),
TMG399X_PRX_GAIN_MASK = (3 << 2),
TMG399X_LDRIVE_MASK = (3 << 6),
TMG399X_ALS_AGL_MASK = (1 << 2),
TMG399X_ALS_AGL_BOOST = 2,
TMG399X_ATIME_PER_100 = 278,
SCALE_SHIFT = 11,
RATIO_SHIFT = 10,
MAX_ALS_VALUE = 0xffff,
MIN_ALS_VALUE = 10,
GAIN_SWITCH_LEVEL = 100,
TMG399X_GES_ST_MASK = (3 << 0),
};
enum tmg399x_caloffsetstates {
START_CALOFF,
CHECK_PROX_NE,
CHECK_PROX_SW,
CHECK_NSWE_ZERO,
CALOFF_OK
};
enum tmg399x_caloffsetdirections {
DIR_NONE,
DIR_UP,
DIR_DOWN
};
enum tmg399x_datatypes {
PROX_DATA,
GES_DATA,
RGBC_DATA
};
struct tmg399x_als_info {
u32 cpl;
u32 saturation;
u16 clear_raw;
u16 red_raw;
u16 green_raw;
u16 blue_raw;
u16 lux;
u16 cct;
s16 ir;
};
struct tmg399x_prox_info {
int raw;
int detected;
};
struct tmg399x_parameters {
u8 gpio_irq;
u8 als_time;
u8 als_gain;
u8 wait_time;
u8 prox_th_min;
u8 prox_th_max;
u8 persist;
u8 als_prox_cfg1;
u8 prox_pulse;
u8 prox_gain;
u8 ldrive;
u8 als_prox_cfg2;
s8 prox_offset_ne;
s8 prox_offset_sw;
u8 als_prox_cfg3;
u8 ges_entry_th;
u8 ges_exit_th;
u8 ges_cfg1;
u8 ges_cfg2;
s8 ges_offset_n;
s8 ges_offset_s;
u8 ges_pulse;
s8 ges_offset_w;
s8 ges_offset_e;
u8 ges_dimension;
};
struct tmg399x_ges_nswe {
u8 north;
u8 south;
u8 west;
u8 east;
};
struct tmg399x_beam_settings {
u8 beam_cfg;
u8 beam_carr;
u8 beam_ns;
u8 beam_isd;
u8 beam_np;
u8 beam_ipd;
u8 beam_div;
};
struct tmg399x_chip {
struct mutex lock;
struct i2c_client *client;
struct work_struct irq_work;
struct work_struct beam_work;
struct tmg399x_prox_info prx_inf;
struct tmg399x_als_info als_inf;
struct tmg399x_parameters params;
struct tmg399x_beam_settings beam_settings;
struct tmg399x_beam_settings beam_hop[15];
struct tmg399x_i2c_platform_data *pdata;
#ifdef CONFIG_HAS_EARLYSUSPEND
struct early_suspend suspend_desc;
#endif
u8 shadow[48];
struct input_dev *p_idev;
struct input_dev *a_idev;
struct timer_list rgbc_timer;
int in_suspend;
int wake_irq;
int irq_pending;
bool unpowered;
bool als_enabled;
bool wait_enabled;
bool prx_enabled;
bool beam_enabled;
bool ges_enabled;
bool rgbc_poll_flag;
struct tmg399x_ges_nswe ges_raw_data[32];
struct lux_segment *segment;
int segment_num;
int seg_num_max;
bool als_gain_auto;
u8 device_index;
u8 pre_beam_xmit_state;
u8 bc_symbol_table[128];
u16 bc_nibbles;
u16 hop_count;
u8 hop_next_slot;
u8 hop_index;
};
struct lux_segment {
int d_factor;
int r_coef;
int g_coef;
int b_coef;
int ct_coef;
int ct_offset;
};
struct tmg399x_i2c_platform_data {
/* The following callback for power events received and handled by
the driver. Currently only for SUSPEND and RESUME */
int (*platform_power)(struct device *dev, enum tmg399x_pwr_state state);
int (*platform_init)(void);
void (*platform_teardown)(struct device *dev);
char const *prox_name;
char const *als_name;
struct tmg399x_parameters parameters;
struct tmg399x_beam_settings beam_settings;
struct tmg3993_beam_settings *beam_hop[15];
bool proximity_can_wake;
bool als_can_wake;
struct lux_segment *segment;
int segment_num;
};
#endif /* __TMG399X_H */