linux/drivers/iio/light/gp2ap002.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * These are the two Sharp GP2AP002 variants supported by this driver:
 * GP2AP002A00F Ambient Light and Proximity Sensor
 * GP2AP002S00F Proximity Sensor
 *
 * Copyright (C) 2020 Linaro Ltd.
 * Author: Linus Walleij <[email protected]>
 *
 * Based partly on the code in Sony Ericssons GP2AP00200F driver by
 * Courtney Cavin and Oskar Andero in drivers/input/misc/gp2ap002a00f.c
 * Based partly on a Samsung misc driver submitted by
 * Donggeun Kim & Minkyu Kang in 2011:
 * https://lore.kernel.org/lkml/[email protected]/
 * Based partly on a submission by
 * Jonathan Bakker and Paweł Chmiel in january 2019:
 * https://lore.kernel.org/linux-input/[email protected]/
 * Based partly on code from the Samsung GT-S7710 by <[email protected]>
 * Based partly on the code in LG Electronics GP2AP00200F driver by
 * Kenobi Lee <[email protected]> and EunYoung Cho <[email protected]>
 */
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/iio/consumer.h> /* To get our ADC channel */
#include <linux/iio/types.h> /* To deal with our ADC channel */
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/interrupt.h>
#include <linux/bits.h>
#include <linux/math64.h>
#include <linux/pm.h>

#define GP2AP002_PROX_CHANNEL
#define GP2AP002_ALS_CHANNEL

/* ------------------------------------------------------------------------ */
/* ADDRESS SYMBOL             DATA                                 Init R/W */
/*                   D7    D6    D5    D4    D3    D2    D1    D0           */
/* ------------------------------------------------------------------------ */
/*    0      PROX     X     X     X     X     X     X     X    VO  H'00   R */
/*    1      GAIN     X     X     X     X  LED0     X     X     X  H'00   W */
/*    2       HYS  HYSD HYSC1 HYSC0     X HYSF3 HYSF2 HYSF1 HYSF0  H'00   W */
/*    3     CYCLE     X     X CYCL2 CYCL1 CYCL0  OSC2     X     X  H'00   W */
/*    4     OPMOD     X     X     X   ASD     X     X  VCON   SSD  H'00   W */
/*    6       CON     X     X     X OCON1 OCON0     X     X     X  H'00   W */
/* ------------------------------------------------------------------------ */
/* VO   :Proximity sensing result(0: no detection, 1: detection)            */
/* LED0 :Select switch for LED driver's On-registence(0:2x higher, 1:normal)*/
/* HYSD/HYSF :Adjusts the receiver sensitivity                              */
/* OSC  :Select switch internal clocl frequency hoppling(0:effective)       */
/* CYCL :Determine the detection cycle(typically 8ms, up to 128x)           */
/* SSD  :Software Shutdown function(0:shutdown, 1:operating)                */
/* VCON :VOUT output method control(0:normal, 1:interrupt)                  */
/* ASD  :Select switch for analog sleep function(0:ineffective, 1:effective)*/
/* OCON :Select switch for enabling/disabling VOUT (00:enable, 11:disable)  */

#define GP2AP002_PROX
#define GP2AP002_GAIN
#define GP2AP002_HYS
#define GP2AP002_CYCLE
#define GP2AP002_OPMOD
#define GP2AP002_CON

#define GP2AP002_PROX_VO_DETECT

/* Setting this bit to 0 means 2x higher LED resistance */
#define GP2AP002_GAIN_LED_NORMAL

/*
 * These bits adjusts the proximity sensitivity, determining characteristics
 * of the detection distance and its hysteresis.
 */
#define GP2AP002_HYS_HYSD_SHIFT
#define GP2AP002_HYS_HYSD_MASK
#define GP2AP002_HYS_HYSC_SHIFT
#define GP2AP002_HYS_HYSC_MASK
#define GP2AP002_HYS_HYSF_SHIFT
#define GP2AP002_HYS_HYSF_MASK
#define GP2AP002_HYS_MASK

/*
 * These values determine the detection cycle response time
 * 0: 8ms, 1: 16ms, 2: 32ms, 3: 64ms, 4: 128ms,
 * 5: 256ms, 6: 512ms, 7: 1024ms
 */
#define GP2AP002_CYCLE_CYCL_SHIFT
#define GP2AP002_CYCLE_CYCL_MASK

/*
 * Select switch for internal clock frequency hopping
 *	0: effective,
 *	1: ineffective
 */
#define GP2AP002_CYCLE_OSC_EFFECTIVE
#define GP2AP002_CYCLE_OSC_INEFFECTIVE
#define GP2AP002_CYCLE_OSC_MASK

/* Analog sleep effective */
#define GP2AP002_OPMOD_ASD
/* Enable chip */
#define GP2AP002_OPMOD_SSD_OPERATING
/* IRQ mode */
#define GP2AP002_OPMOD_VCON_IRQ
#define GP2AP002_OPMOD_MASK

/*
 * Select switch for enabling/disabling Vout pin
 * 0: enable
 * 2: force to go Low
 * 3: force to go High
 */
#define GP2AP002_CON_OCON_SHIFT
#define GP2AP002_CON_OCON_ENABLE
#define GP2AP002_CON_OCON_LOW
#define GP2AP002_CON_OCON_HIGH
#define GP2AP002_CON_OCON_MASK

/**
 * struct gp2ap002 - GP2AP002 state
 * @map: regmap pointer for the i2c regmap
 * @dev: pointer to parent device
 * @vdd: regulator controlling VDD
 * @vio: regulator controlling VIO
 * @alsout: IIO ADC channel to convert the ALSOUT signal
 * @hys_far: hysteresis control from device tree
 * @hys_close: hysteresis control from device tree
 * @is_gp2ap002s00f: this is the GP2AP002F variant of the chip
 * @irq: the IRQ line used by this device
 * @enabled: we cannot read the status of the hardware so we need to
 * keep track of whether the event is enabled using this state variable
 */
struct gp2ap002 {};

static irqreturn_t gp2ap002_prox_irq(int irq, void *d)
{}

/*
 * This array maps current and lux.
 *
 * Ambient light sensing range is 3 to 55000 lux.
 *
 * This mapping is based on the following formula.
 * illuminance = 10 ^ (current[mA] / 10)
 *
 * When the ADC measures 0, return 0 lux.
 */
static const u16 gp2ap002_illuminance_table[] =;

static int gp2ap002_get_lux(struct gp2ap002 *gp2ap002)
{}

static int gp2ap002_read_raw(struct iio_dev *indio_dev,
			   struct iio_chan_spec const *chan,
			   int *val, int *val2, long mask)
{}

static int gp2ap002_init(struct gp2ap002 *gp2ap002)
{}

static int gp2ap002_read_event_config(struct iio_dev *indio_dev,
				      const struct iio_chan_spec *chan,
				      enum iio_event_type type,
				      enum iio_event_direction dir)
{}

static int gp2ap002_write_event_config(struct iio_dev *indio_dev,
				       const struct iio_chan_spec *chan,
				       enum iio_event_type type,
				       enum iio_event_direction dir,
				       int state)
{}

static const struct iio_info gp2ap002_info =;

static const struct iio_event_spec gp2ap002_events[] =;

static const struct iio_chan_spec gp2ap002_channels[] =;

/*
 * We need a special regmap because this hardware expects to
 * write single bytes to registers but read a 16bit word on some
 * variants and discard the lower 8 bits so combine
 * i2c_smbus_read_word_data() with i2c_smbus_write_byte_data()
 * selectively like this.
 */
static int gp2ap002_regmap_i2c_read(void *context, unsigned int reg,
				    unsigned int *val)
{}

static int gp2ap002_regmap_i2c_write(void *context, unsigned int reg,
				     unsigned int val)
{}

static const struct regmap_bus gp2ap002_regmap_bus =;

static int gp2ap002_probe(struct i2c_client *client)
{}

static void gp2ap002_remove(struct i2c_client *client)
{}

static int gp2ap002_runtime_suspend(struct device *dev)
{}

static int gp2ap002_runtime_resume(struct device *dev)
{}

static DEFINE_RUNTIME_DEV_PM_OPS(gp2ap002_dev_pm_ops, gp2ap002_runtime_suspend,
				 gp2ap002_runtime_resume, NULL);

static const struct i2c_device_id gp2ap002_id_table[] =;
MODULE_DEVICE_TABLE(i2c, gp2ap002_id_table);

static const struct of_device_id gp2ap002_of_match[] =;
MODULE_DEVICE_TABLE(of, gp2ap002_of_match);

static struct i2c_driver gp2ap002_driver =;
module_i2c_driver();

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();