From: Linus Walleij <linusw@kernel.org>
To: linux-iio@vger.kernel.org, "Jonathan Cameron" <jic23@kernel.org>,
"David Lechner" <dlechner@baylibre.com>,
"Nuno Sá" <nuno.sa@analog.com>,
"Andy Shevchenko" <andy@kernel.org>,
"Rob Herring" <robh@kernel.org>,
"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
"Conor Dooley" <conor+dt@kernel.org>,
"Kyungmin Park" <kyungmin.park@samsung.com>
Cc: devicetree@vger.kernel.org, Linus Walleij <linusw@kernel.org>
Subject: [PATCH 4/4] iio: light: gp2ap020a00f: Add GP2AP030A00F support
Date: Sun, 08 Nov 2026 00:31:36 +0100 [thread overview]
Message-ID: <20261108-gp2ap030-v1-4-55314eb7055b@kernel.org> (raw)
In-Reply-To: <20261108-gp2ap030-v1-0-55314eb7055b@kernel.org>
The GP2AP030A00F has the same register addresses and interrupt modes
as the GP2AP020A00F, but does not implement its automatic
illuminance calculation or selectable ambient-light cancellation.
Datasheet: https://jp.sharp/products/device/doc/opto/gp2ap030a00f_appl_e.pdf
Signed-off-by: Linus Walleij <linusw@kernel.org>
---
drivers/iio/light/Kconfig | 6 +--
drivers/iio/light/gp2ap020a00f.c | 80 ++++++++++++++++++++++++++++++++++++----
2 files changed, 76 insertions(+), 10 deletions(-)
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 462fff1ddef2..549f644994df 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -259,15 +259,15 @@ config GP2AP002
module will be called gp2ap002.
config GP2AP020A00F
- tristate "Sharp GP2AP020A00F Proximity/ALS sensor"
+ tristate "Sharp GP2AP020A00F/GP2AP030A00F Proximity/ALS sensors"
depends on I2C
select REGMAP_I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select IRQ_WORK
help
- Say Y here if you have a Sharp GP2AP020A00F proximity/ALS combo-chip
- hooked to an I2C bus.
+ Say Y here if you have a Sharp GP2AP020A00F or GP2AP030A00F
+ proximity/ALS combo-chip hooked to an I2C bus.
To compile this driver as a module, choose M here: the
module will be called gp2ap020a00f.
diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c
index 62c4beb20cce..3ea1ec273e7f 100644
--- a/drivers/iio/light/gp2ap020a00f.c
+++ b/drivers/iio/light/gp2ap020a00f.c
@@ -54,6 +54,11 @@
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
+/*
+ * The GP2AP030A00F shares the register layout, but has no TYPE or ALC bit.
+ * Its D0 and D1 registers always contain raw clear and infrared counts.
+ */
+
/* Registers */
#define GP2AP020A00F_OP_REG 0x00 /* Basic operations */
#define GP2AP020A00F_ALS_REG 0x01 /* ALS related settings */
@@ -137,6 +142,7 @@
#define GP2AP020A00F_RES_P_6_25ms_x2 0x28
#define GP2AP020A00F_RES_P_1_56ms_x2 0x30
#define GP2AP020A00F_RES_P_0_39ms_x2 0x38
+#define GP2AP030A00F_RES_P_1_56ms_x2 0x18
#define GP2AP020A00F_RANGE_P_MASK 0x07 /* PS: Max measurable range */
#define GP2AP020A00F_RANGE_P_x1 0x00
#define GP2AP020A00F_RANGE_P_x2 0x01
@@ -158,6 +164,7 @@
#define GP2AP020A00F_IS_27_5mA 0x10
#define GP2AP020A00F_IS_55mA 0x20
#define GP2AP020A00F_IS_110mA 0x30
+#define GP2AP030A00F_IS_130mA 0x30
#define GP2AP020A00F_PIN_MASK 0x0c /* INT terminal setting */
#define GP2AP020A00F_PIN_ALS_OR_PS 0x00
#define GP2AP020A00F_PIN_ALS 0x04
@@ -234,7 +241,14 @@ enum gp2ap020a00f_thresh_val_id {
GP2AP020A00F_THRESH_PH,
};
+struct gp2ap020a00f_chip_info {
+ const char *name;
+ const u8 *reg_init_tab;
+ bool has_als_auto;
+};
+
struct gp2ap020a00f_data {
+ const struct gp2ap020a00f_chip_info *chip_info;
struct i2c_client *client;
struct mutex lock;
char *buffer;
@@ -268,6 +282,28 @@ static const u8 gp2ap020a00f_reg_init_tab[] = {
[GP2AP020A00F_PH_H_REG] = 0,
};
+static const u8 gp2ap030a00f_reg_init_tab[ARRAY_SIZE(gp2ap020a00f_reg_init_tab)] = {
+ [GP2AP020A00F_OP_REG] = GP2AP020A00F_OP3_SHUTDOWN,
+ [GP2AP020A00F_ALS_REG] = GP2AP020A00F_RES_A_100ms |
+ GP2AP020A00F_RANGE_A_x8,
+ [GP2AP020A00F_PS_REG] = GP2AP030A00F_RES_P_1_56ms_x2 |
+ GP2AP020A00F_RANGE_P_x4,
+ [GP2AP020A00F_LED_REG] = GP2AP020A00F_INTVAL_0 |
+ GP2AP030A00F_IS_130mA |
+ GP2AP020A00F_FREQ_327_5kHz,
+};
+
+static const struct gp2ap020a00f_chip_info gp2ap020a00f_chip_info = {
+ .name = "gp2ap020a00f",
+ .reg_init_tab = gp2ap020a00f_reg_init_tab,
+ .has_als_auto = true,
+};
+
+static const struct gp2ap020a00f_chip_info gp2ap030a00f_chip_info = {
+ .name = "gp2ap030a00f",
+ .reg_init_tab = gp2ap030a00f_reg_init_tab,
+};
+
static bool gp2ap020a00f_is_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
@@ -364,6 +400,7 @@ static int gp2ap020a00f_set_operation_mode(struct gp2ap020a00f_data *data,
enum gp2ap020a00f_opmode op)
{
unsigned int op_reg_val;
+ u8 op_reg = opmode_regs_settings[op].op_reg;
int err;
if (op != GP2AP020A00F_OPMODE_SHUTDOWN) {
@@ -401,12 +438,16 @@ static int gp2ap020a00f_set_operation_mode(struct gp2ap020a00f_data *data,
return err;
}
+ /* Bit 0 is reserved on the GP2AP030A00F. */
+ if (!data->chip_info->has_als_auto)
+ op_reg &= ~GP2AP020A00F_TYPE_MASK;
+
/* Set OP_REG and apply operation mode (power on / off) */
err = regmap_update_bits(data->regmap,
GP2AP020A00F_OP_REG,
GP2AP020A00F_OP_MASK | GP2AP020A00F_OP2_MASK |
GP2AP020A00F_OP3_MASK | GP2AP020A00F_TYPE_MASK,
- opmode_regs_settings[op].op_reg);
+ op_reg);
if (err < 0)
return err;
@@ -438,6 +479,8 @@ static int gp2ap020a00f_write_event_threshold(struct gp2ap020a00f_data *data,
if (!enable)
thresh_reg_val = 0;
+ else if (!data->chip_info->has_als_auto)
+ thresh_reg_val = min(data->thresh_val[th_val_id], 65535U);
else if (test_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags) &&
th_val_id != GP2AP020A00F_THRESH_PL &&
th_val_id != GP2AP020A00F_THRESH_PH)
@@ -701,6 +744,10 @@ static bool gp2ap020a00f_adjust_lux_mode(struct gp2ap020a00f_data *data,
u8 new_range = 0xff;
int err;
+ /* GP2AP030A00F thresholds and samples are raw counts at a fixed range. */
+ if (!data->chip_info->has_als_auto)
+ return false;
+
if (!test_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags)) {
if (output_val > 16000) {
set_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags);
@@ -1401,7 +1448,7 @@ static const struct iio_buffer_setup_ops gp2ap020a00f_buffer_setup_ops = {
static int gp2ap020a00f_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
+ struct iio_chan_spec *channels;
struct device *dev = &client->dev;
struct gp2ap020a00f_data *data;
struct iio_dev *indio_dev;
@@ -1413,6 +1460,7 @@ static int gp2ap020a00f_probe(struct i2c_client *client)
return -ENOMEM;
data = iio_priv(indio_dev);
+ data->chip_info = i2c_get_match_data(client);
err = devm_regulator_get_enable_optional(dev, "vdd");
if (err && err != -ENODEV)
@@ -1437,9 +1485,12 @@ static int gp2ap020a00f_probe(struct i2c_client *client)
goto error_regulator_disable;
}
+ if (!data->chip_info->has_als_auto)
+ usleep_range(1000, 2000);
+
/* Initialize device registers */
err = regmap_bulk_write(regmap, GP2AP020A00F_OP_REG,
- gp2ap020a00f_reg_init_tab,
+ data->chip_info->reg_init_tab,
ARRAY_SIZE(gp2ap020a00f_reg_init_tab));
if (err < 0) {
@@ -1456,9 +1507,20 @@ static int gp2ap020a00f_probe(struct i2c_client *client)
mutex_init(&data->lock);
indio_dev->channels = gp2ap020a00f_channels;
+ if (!data->chip_info->has_als_auto) {
+ channels = devm_kmemdup(dev, gp2ap020a00f_channels,
+ sizeof(gp2ap020a00f_channels), GFP_KERNEL);
+ if (!channels) {
+ err = -ENOMEM;
+ goto error_regulator_disable;
+ }
+ channels[GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR].scan_type.realbits = 16;
+ channels[GP2AP020A00F_SCAN_MODE_LIGHT_IR].scan_type.realbits = 16;
+ indio_dev->channels = channels;
+ }
indio_dev->num_channels = ARRAY_SIZE(gp2ap020a00f_channels);
indio_dev->info = &gp2ap020a00f_info;
- indio_dev->name = id->name;
+ indio_dev->name = data->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
/* Allocate buffer */
@@ -1534,13 +1596,17 @@ static void gp2ap020a00f_remove(struct i2c_client *client)
}
static const struct i2c_device_id gp2ap020a00f_id[] = {
- { .name = "gp2ap020a00f" },
+ { .name = "gp2ap020a00f",
+ .driver_data = (kernel_ulong_t)&gp2ap020a00f_chip_info },
+ { .name = "gp2ap030a00f",
+ .driver_data = (kernel_ulong_t)&gp2ap030a00f_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, gp2ap020a00f_id);
static const struct of_device_id gp2ap020a00f_of_match[] = {
- { .compatible = "sharp,gp2ap020a00f" },
+ { .compatible = "sharp,gp2ap020a00f", .data = &gp2ap020a00f_chip_info },
+ { .compatible = "sharp,gp2ap030a00f", .data = &gp2ap030a00f_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, gp2ap020a00f_of_match);
@@ -1557,5 +1623,5 @@ static struct i2c_driver gp2ap020a00f_driver = {
module_i2c_driver(gp2ap020a00f_driver);
MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
-MODULE_DESCRIPTION("Sharp GP2AP020A00F Proximity/ALS sensor driver");
+MODULE_DESCRIPTION("Sharp GP2AP020A00F/GP2AP030A00F proximity/ALS sensor driver");
MODULE_LICENSE("GPL v2");
--
2.56.0
next prev parent reply other threads:[~2026-11-07 23:31 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-07 23:31 [PATCH 0/4] iio: light: gp2ap020a00f: Add supplies and GP2AP030A00F support Linus Walleij
2026-11-07 23:31 ` [PATCH 1/4] dt-bindings: iio: light: sharp,gp2ap020a00f: Add supplies Linus Walleij
2026-11-07 23:58 ` Jonathan Cameron
2026-11-08 16:08 ` Linus Walleij
2026-11-07 23:31 ` [PATCH 2/4] dt-bindings: iio: light: sharp,gp2ap020a00f: Add GP2AP030A00F Linus Walleij
2026-11-08 0:02 ` Jonathan Cameron
2026-11-07 23:31 ` [PATCH 3/4] iio: light: gp2ap020a00f: Enable the core and I/O supplies Linus Walleij
2026-11-08 0:03 ` Jonathan Cameron
2026-11-07 23:31 ` Linus Walleij [this message]
2026-11-08 0:21 ` [PATCH 4/4] iio: light: gp2ap020a00f: Add GP2AP030A00F support Jonathan Cameron
2026-11-08 21:13 ` Linus Walleij
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261108-gp2ap030-v1-4-55314eb7055b@kernel.org \
--to=linusw@kernel.org \
--cc=andy@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=dlechner@baylibre.com \
--cc=jic23@kernel.org \
--cc=krzk+dt@kernel.org \
--cc=kyungmin.park@samsung.com \
--cc=linux-iio@vger.kernel.org \
--cc=nuno.sa@analog.com \
--cc=robh@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox