// 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(…) …;