From nobody Mon Jun 8 07:22:49 2026 Received: from mail-wm1-f43.google.com (mail-wm1-f43.google.com [209.85.128.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 59B7A33F38A for ; Sun, 31 May 2026 19:58:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780257518; cv=none; b=QlesEEZ7Bw3hju7WQEG6Kto/HDzll1Oeo9dwO3BNrpI7bx2bbEYLxMAcAOlrwsCHqGDsf+Gf/r//+24w2uCQa9uiVVcRHbdAk/zrhPIKUfVvwPD+oHS+H7ZB4RchO5gQGr3Wdkk8ygS32ok8xSm/vBD2EjEEWjI/LFDGWfELNj0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780257518; c=relaxed/simple; bh=HJcKaiRHUPVVz44flDxq7RjqHlMgRL2UvrwWMWukkOU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ckbg/TS5L+0IuiPgh6AEPkiK1/Kh8YF4dwm7AmgLdUYE6HiNJH0V5JtteOX01IdwHpBJ+jgZPFmk3R8I0L4ZNWPZg+3QsIrtJ9cm7fbCYcVGc9IdihuKKW5/Ldrz1w3feICPSUoXl8FIUC4oHVVAzi2xcz8z+pSE02N9QcweqA8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=F1WVcK44; arc=none smtp.client-ip=209.85.128.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="F1WVcK44" Received: by mail-wm1-f43.google.com with SMTP id 5b1f17b1804b1-4906869f0cbso83659575e9.1 for ; Sun, 31 May 2026 12:58:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780257516; x=1780862316; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=28TrmenFX4jJrjlN6PZ1KHA15XnNjrQNxHUo4wAACFA=; b=F1WVcK44cICGoqTLOnFOqFDlvQuaz7EfWIUZA0oOdj0pbTpeWxq9k9P7BzRl4z0VVz SZbcbPzjYKUIClLz2RD1xYsU90mlGvqcLAj/wUyeuxNyp5eN12+1ypefM1nrBTOp548/ BBVwwwlozvzu2Tk7b8Isosj32j/36vP51ejMDzDDWgkU+6Fd48Fyr8vbtAjFuHcV2z1W sFHtUw+09xXCqcPtTq+TM9g1WOrUCb9D9CTw0sVBER8F9oXdgI1xCc+aIyTpAKKfk+WU 5RE+Y7AdaBwjC+fz7hMTpdrXlTZo+acjxPj+ijkYRh+3qMkUeOYK4ku4tqaVYX9magWx F6Xw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780257516; x=1780862316; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=28TrmenFX4jJrjlN6PZ1KHA15XnNjrQNxHUo4wAACFA=; b=hc9aIcbFiwugYxHutmHmUMUF5Ggp2tCNaKMnqQXrewxmXynVZbrTyrPufRx+qANZ9H xx2PXqIlCEsT7Evc7YhUFd6y506FlnGJt8CnVJ0TK86Ai0wyT1Q3YHMXyPumbk/vsglW GPfhXpVJHbLYKg/pBg+BKm0/3p0gv2eUziGHxYjUn1XEusOuEl6FHEaYbSzl5ZeKV0Ir RC8+dZ8VFp7mNVsdO9YtwTsdj5WXf8++hG0JleVIEnyeqwroNDfYMSkCSejr3XmW9nLZ gnXIqRa9/YTyAK4MXtdlJbvZnuHNTX0wc8yx1NtHmbeVvH70DC7557x8N8u30LtJydrv QPyg== X-Forwarded-Encrypted: i=1; AFNElJ/CYPLqj6LdTt3fn+YjcaE9CzyJy+MfryShFxtGge6xl1IB6gWPRjXkuqslTuyqReF+/NqMSYGppUqiE7Q=@vger.kernel.org X-Gm-Message-State: AOJu0YzeWDbXJysL+dbMHJQTPnUJowTphtop/Ni1qPiXlxM66egU1VkN qG/O6XvSyRD+e/J4kcy3g4tRQ/DxROmJFA83y2sJijCK/R+4q9VwlT+h X-Gm-Gg: Acq92OHaQ1wgxrs96GAGBFYdPEmVqg7iFzz/ibTHKq8VU1jXKR3IgSXgFebANQnVDja TwzdniJRpF3rP7+lKPjBeewg9s4Nb2GHiVtBDSH3KKBqv4k7SV2nEI8lEQ/EC7vOISB5ZAQMABF Zr972mJJwEvrrUIrqTVWc1+WgNSgJclzs73gZcFqvrTzKo6h9miS3yQEdWtZ3A8DZCk+uVfWPz0 LQAzMXDxyrHfedzdfHp4EV/7oCdXZDgK9SZm/lbv3CBkqCNBRMiRVXEnKrhJCv3T0xY0wy7IuT+ VA8I9MwGeqW8JRat9ExQMY6vg4E4WPsEdLUhVgNxAYaZ0hAevvcQs7dlbpFY/L761ZKo+jkcxLm Vc8chO6cNI64CZr7s+H0/vQwhknS9q0UdIVQUrQRxub7m90pDUGGuaOYGOxk8i2fVYp6XHt0V7R z3efOwMQvSZ6ckpzntJeVqGHjuyVgooYKYmmsr4Psxcq2dJsfB9w== X-Received: by 2002:a05:600c:1988:b0:490:44eb:c1dd with SMTP id 5b1f17b1804b1-490a294fe9cmr141548325e9.29.1780257515601; Sun, 31 May 2026 12:58:35 -0700 (PDT) Received: from [127.0.1.1] ([2001:4bb8:152:df59:bc17:a305:8902:fb31]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4909d7002e8sm220323775e9.15.2026.05.31.12.58.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 31 May 2026 12:58:35 -0700 (PDT) From: Javier Carrasco Date: Sun, 31 May 2026 21:58:21 +0200 Subject: [PATCH v4 1/4] dt-bindings: iio: light: veml6030: add veml6031x00 ALS series Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260531-veml6031x00-v4-1-e64f7fdce38d@gmail.com> References: <20260531-veml6031x00-v4-0-e64f7fdce38d@gmail.com> In-Reply-To: <20260531-veml6031x00-v4-0-e64f7fdce38d@gmail.com> To: Jonathan Cameron , Lars-Peter Clausen , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Rishi Gupta , David Lechner , =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko , Matti Vaittinen Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Javier Carrasco , Jonathan Cameron , Krzysztof Kozlowski X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780257511; l=3301; i=javier.carrasco.cruz@gmail.com; s=20260111; h=from:subject:message-id; bh=HJcKaiRHUPVVz44flDxq7RjqHlMgRL2UvrwWMWukkOU=; b=/PVpw15lZ0+TPX6JQq+JbCzNeahWAhBqe7SGtPcGK1AuPeTrd2dAbXBTKAoUni/6VfW3qwqvH I9kAFKTZAfAD/RQV5wU9HBWRcXpXKaM1KatsdHlWMZWOiOWPvSEWlYG X-Developer-Key: i=javier.carrasco.cruz@gmail.com; a=ed25519; pk=Lge8w8xidNSf/INy7JAIbAW+Hezkp3nsBh2OjKL7lLU= These ambient light sensors share their properties with the ones from the same manufacturer that are supported by this bindings. Note that only two datasheets are provided as every one of them covers two devices (veml6031x00/veml60311x00 and veml6031x01/veml60311x01). Reviewed-by: Krzysztof Kozlowski Signed-off-by: Javier Carrasco --- .../bindings/iio/light/vishay,veml6030.yaml | 23 ++++++++++++++++++= +++- MAINTAINERS | 5 +++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/light/vishay,veml6030.ya= ml b/Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml index 4ea69f1fdd63..e01e8747e47c 100644 --- a/Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml +++ b/Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml @@ -4,7 +4,9 @@ $id: http://devicetree.org/schemas/iio/light/vishay,veml6030.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# =20 -title: VEML3235, VEML6030, VEML6035 and VEML7700 Ambient Light Sensors (AL= S) +title: + VEML3235, VEML6030, VEML6031x00 series, VEML6035 and VEML7700 Ambient + Light Sensors (ALS) =20 maintainers: - Rishi Gupta @@ -22,12 +24,18 @@ description: | Specifications about the sensors can be found at: https://www.vishay.com/docs/80131/veml3235.pdf https://www.vishay.com/docs/84366/veml6030.pdf + https://www.vishay.com/docs/80007/veml6031x00.pdf + https://www.vishay.com/docs/80008/veml6031x01.pdf https://www.vishay.com/docs/84889/veml6035.pdf https://www.vishay.com/docs/84286/veml7700.pdf =20 properties: compatible: enum: + - vishay,veml6031x00 + - vishay,veml6031x01 + - vishay,veml60311x00 + - vishay,veml60311x01 - vishay,veml3235 - vishay,veml6030 - vishay,veml6035 @@ -67,6 +75,8 @@ allOf: properties: compatible: enum: + - vishay,veml6031x00 + - vishay,veml6031x01 - vishay,veml6035 then: properties: @@ -79,12 +89,23 @@ allOf: compatible: enum: - vishay,veml3235 + - vishay,veml60311x00 + - vishay,veml60311x01 - vishay,veml7700 then: properties: reg: enum: - 0x10 + + - if: + properties: + compatible: + enum: + - vishay,veml3235 + - vishay,veml7700 + then: + properties: interrupts: false =20 additionalProperties: false diff --git a/MAINTAINERS b/MAINTAINERS index 2fb1c75afd16..921da7584963 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -28375,6 +28375,11 @@ S: Maintained F: Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml F: drivers/iio/light/veml6030.c =20 +VISHAY VEML6031X00 AMBIENT LIGHT SENSOR DRIVER +M: Javier Carrasco +S: Maintained +F: Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml + VISHAY VEML6046X00 RGBIR COLOR SENSOR DRIVER M: Andreas Klinger S: Maintained --=20 2.43.0 From nobody Mon Jun 8 07:22:49 2026 Received: from mail-wm1-f41.google.com (mail-wm1-f41.google.com [209.85.128.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 441AF33DEC0 for ; Sun, 31 May 2026 19:58:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780257521; cv=none; b=L+eMyjtUkJHQj9+8buwowbV+QTTTH8Ztlnx0VWCwhfLgYZSlAeou1bY5wjl97MIHni5UC/jE1KEMjkvZg3QhstLP9P3s6o5C8WNIcWl/ATmkEoGYNQHlrAhQY3wkeNjf4vClewYGoIJExq/iqfhW+bTsbdVv0kef/YVFIvhLgoY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780257521; c=relaxed/simple; bh=dUeXI2B/ieLHS6AKK5iWOLKH86UnXfQa0fZpVX2ZWwQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=SIR6xn0qbT5NsUwuq1TTeXI8pLSm/JjR1peJJfAlNHkDTRt+RceyuF7RqoM4h8aCUXd8kaSzxgEpyPFeUwiswee6SRju8sf693qGtcTcd7mfCwopd+evhMwTdXAUq06+o67M42DXXLBWtnU0vLde6dXoa8nv7bnsHD7w7BReIzY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=PZRFsl8r; arc=none smtp.client-ip=209.85.128.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="PZRFsl8r" Received: by mail-wm1-f41.google.com with SMTP id 5b1f17b1804b1-49039a8851fso96725645e9.2 for ; Sun, 31 May 2026 12:58:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780257518; x=1780862318; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=yCnn3guwabCfpkvuleLlt1JUIHD9BUV2uNEUmZL7NLU=; b=PZRFsl8rIIeKIDcnonxinfjb3cq6dHI+XT1fAaHfpWG8tVZiFA3dUHh5BwN5cZHZ8b kztDIP4lICHQhf6eL49kavpVAekw1Mm7e13eXsm+rAVD1HqsSD/GKF+b+B/okIlmG4Je /LUlr6/pVooffaoZ42CyB5ZbbFDLHGsPpJ3kjN2488DuMeXKTWYmOBy8aGbvCYLOnGh/ fONzJAbdViEkSlDMDfoujiArH6YPfRZWOGz7R38r2hf7YMKEDOlXkdVy0melbyvpUl1Y Em6ClmDJiYIGDqvtKN/+u24JkviRbvczUgQ3YlOs4bcgx50bpsy7KiR1C2WZVBgjdIZ2 xIHw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780257518; x=1780862318; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=yCnn3guwabCfpkvuleLlt1JUIHD9BUV2uNEUmZL7NLU=; b=CMbw8m/yrqVfl+/Dccp19qTJCpkM/3tP1fu+UuAW7gVsr31cZgj64gpir/Ify+X77d 7oXmhUSN7YhW+jJ6lMjbk/vVJ/o1TFbBfYMjJa9gTXaAsGCaVlVf/z6DDGewrmcG4omX JWKBEgRRIjPHbhS5RLsd8ZrDFBmxd7m1yMvAKjuSCRBPgfKgQKiK/ksHubp64Ke1vvR9 2S7aO6poBXA2XWfO8Ar059GYcw35OYGmpqYtqQPSmwemjzh5A2BPOJBNGfHZgF+Ty8YD y2ESbnwBja5ecSi01knp1ypgUtuEaJ/WW+nO9emBGDnSiPKM7NurEqOsLJ5v6cLrJqq4 kx1A== X-Forwarded-Encrypted: i=1; AFNElJ/8gcSPxmjz3vfLPTj7kVzeAFeNzPCgA2ujJ95avuA5x07FuhwZ9XT4qQSsINILnjH9SvYrlZQo3AcLKEw=@vger.kernel.org X-Gm-Message-State: AOJu0YzlUIOK8Z9s8lGVjMTvSktpfHZ/Fy2XlKArEgiHf92b+P+qTv9v V8VumCsdiOiknpBHL9RtzNkuaGe6dubspQfDxAWyUc/Ypw3JzWAwBQzH X-Gm-Gg: Acq92OG4a22rfI3E84x3hLau/oWdMitc5+3/1KtIwdHyXaxfJpJai3wv2gLG0BY6hdI EGI4AIKzVQs4dod1xmyCGWuRFEOKADT4oYxfhxjeylBdpLDRvFh1cNXklK7xGrfNCRkex3tW8N2 XsjAGAgjaxDcHPE0Vdx8PbdwTGnjTyuH1B7d834IvWdUWPl7TyFAp0i1hCIB0BOzR1GjmxYfvWv /s8QJfyMQDzByZB2jyNwqwVxrkrIO31t8m57BeZOF8Ig+4yz3Q07KT4fOXhEpEwggEjfoS40inq W19Sblc7BS9V3t3RdG/c22QPcmXF8qt5o9ghHcLJ2gHexx4gBSqs8ddDf/LSEyXTx+sPg/+5o+a koUp68XkWILK/++tWmRggDfsFWHXU+0t2fc0ZgUShjPGSD7HjvZ8kfiIAwFub50XQuarYEFTZ2M N7pD5ag9hAyCsXiDoLfCQeKHbrxrf9Bf2diaOpVdhOwH5pYEYSnq45ihEnti0E X-Received: by 2002:a05:600d:844a:10b0:48a:5565:ec3d with SMTP id 5b1f17b1804b1-490a294935bmr110375065e9.22.1780257517494; Sun, 31 May 2026 12:58:37 -0700 (PDT) Received: from [127.0.1.1] ([2001:4bb8:152:df59:bc17:a305:8902:fb31]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4909d7002e8sm220323775e9.15.2026.05.31.12.58.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 31 May 2026 12:58:37 -0700 (PDT) From: Javier Carrasco Date: Sun, 31 May 2026 21:58:22 +0200 Subject: [PATCH v4 2/4] iio: light: add support for veml6031x00 ALS series Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260531-veml6031x00-v4-2-e64f7fdce38d@gmail.com> References: <20260531-veml6031x00-v4-0-e64f7fdce38d@gmail.com> In-Reply-To: <20260531-veml6031x00-v4-0-e64f7fdce38d@gmail.com> To: Jonathan Cameron , Lars-Peter Clausen , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Rishi Gupta , David Lechner , =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko , Matti Vaittinen Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Javier Carrasco , Jonathan Cameron X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780257511; l=21515; i=javier.carrasco.cruz@gmail.com; s=20260111; h=from:subject:message-id; bh=dUeXI2B/ieLHS6AKK5iWOLKH86UnXfQa0fZpVX2ZWwQ=; b=2Wrv93UTVZCArng5CDFqdZTsZVTEHTcv1PdReUXDVU/QAgoCv/3Ny5ShY1RHDQNzB3AD1d1BE VVamVvis8CSD/93iXLwjcPW+qRFO6kGInY0UsnhH4ilmbwLkyk5QFWN X-Developer-Key: i=javier.carrasco.cruz@gmail.com; a=ed25519; pk=Lge8w8xidNSf/INy7JAIbAW+Hezkp3nsBh2OjKL7lLU= These sensors provide two light channels (ALS and IR), I2C communication and a multiplexed interrupt line to signal data ready and configurable threshold alarms. This first implementation provides basic functionality (measurement configuration, raw reads and ID validation) and defines the different register regions in preparation for extended features in the subsequent patches of the series. Signed-off-by: Javier Carrasco --- MAINTAINERS | 1 + drivers/iio/light/Kconfig | 12 + drivers/iio/light/Makefile | 1 + drivers/iio/light/veml6031x00.c | 680 ++++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 694 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 921da7584963..db800537aefc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -28379,6 +28379,7 @@ VISHAY VEML6031X00 AMBIENT LIGHT SENSOR DRIVER M: Javier Carrasco S: Maintained F: Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml +F: drivers/iio/light/veml6031x00.c =20 VISHAY VEML6046X00 RGBIR COLOR SENSOR DRIVER M: Andreas Klinger diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index eff33e456c70..99a6ed80c7db 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -713,6 +713,18 @@ config VEML6030 To compile this driver as a module, choose M here: the module will be called veml6030. =20 +config VEML6031X00 + tristate "VEML6031X00 ambient light sensor series" + select REGMAP_I2C + select IIO_GTS_HELPER + depends on I2C + help + Say Y here if you want to build a driver for the Vishay VEML6031X00 + ambient light sensor series. + + To compile this driver as a module, choose M here: the + module will be called veml6031x00. + config VEML6040 tristate "VEML6040 RGBW light sensor" select REGMAP_I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index c0048e0d5ca8..a8cc03cfb6c2 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_VCNL4000) +=3D vcnl4000.o obj-$(CONFIG_VCNL4035) +=3D vcnl4035.o obj-$(CONFIG_VEML3235) +=3D veml3235.o obj-$(CONFIG_VEML6030) +=3D veml6030.o +obj-$(CONFIG_VEML6031X00) +=3D veml6031x00.o obj-$(CONFIG_VEML6040) +=3D veml6040.o obj-$(CONFIG_VEML6046X00) +=3D veml6046x00.o obj-$(CONFIG_VEML6070) +=3D veml6070.o diff --git a/drivers/iio/light/veml6031x00.c b/drivers/iio/light/veml6031x0= 0.c new file mode 100644 index 000000000000..6f9a7bad44d4 --- /dev/null +++ b/drivers/iio/light/veml6031x00.c @@ -0,0 +1,680 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * VEML6031X00 Ambient Light Sensor + * + * Copyright (c) 2026, Javier Carrasco + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Device registers */ +#define VEML6031X00_REG_CONF0 0x00 +#define VEML6031X00_REG_CONF1 0x01 +#define VEML6031X00_REG_ALS_L 0x10 +#define VEML6031X00_REG_ALS_H 0x11 +#define VEML6031X00_REG_IR_L 0x12 +#define VEML6031X00_REG_IR_H 0x13 +#define VEML6031X00_REG_ID_L 0x14 +#define VEML6031X00_REG_ID_H 0x15 + +/* Bit masks for specific functionality */ +#define VEML6031X00_CONF0_SD BIT(0) +#define VEML6031X00_CONF1_IR_SD BIT(7) + +struct veml6031x00_rf { + struct regmap_field *gain; + struct regmap_field *it; + struct regmap_field *pd_div4; +}; + +struct veml6031x00_chip { + const char *name; + const int part_id; +}; + +struct veml6031x00_data { + struct device *dev; + struct iio_gts gts; + struct regmap *regmap; + struct veml6031x00_rf rf; + const struct veml6031x00_chip *chip; + /* + * Serialize access to scale register fields scattered across multiple + * registers (rf.gain, rf.pd_div4, rf.it) to read and write them as a + * consistent set. + */ + struct mutex scale_lock; +}; + +static const struct iio_itime_sel_mul veml6031x00_it_sel[] =3D { + GAIN_SCALE_ITIME_US(3125, 0, 1), + GAIN_SCALE_ITIME_US(6250, 1, 2), + GAIN_SCALE_ITIME_US(12500, 2, 4), + GAIN_SCALE_ITIME_US(25000, 3, 8), + GAIN_SCALE_ITIME_US(50000, 4, 16), + GAIN_SCALE_ITIME_US(100000, 5, 32), + GAIN_SCALE_ITIME_US(200000, 6, 64), + GAIN_SCALE_ITIME_US(400000, 7, 128), +}; + +/* + * The gain selector encodes (PD_D4 << 2) | GAIN to identify each gain set= ting. + * Gains are multiplied by 8 to work with integers. The values in the iio-= gts + * tables don't need corrections because the maximum value of the scale re= fers + * to GAIN =3D x1, and the rest of the values are obtained from the result= ing + * linear function. + * TODO: add support for MILLI_GAIN_X165 and MILLI_GAIN_X660 + */ +#define VEML6031X00_SEL_MILLI_GAIN_X125 0x07 +#define VEML6031X00_SEL_MILLI_GAIN_X250 0x04 +#define VEML6031X00_SEL_MILLI_GAIN_X500 0x03 +#define VEML6031X00_SEL_MILLI_GAIN_X1000 0x00 +#define VEML6031X00_SEL_MILLI_GAIN_X2000 0x01 +static const struct iio_gain_sel_pair veml6031x00_gain_sel[] =3D { + GAIN_SCALE_GAIN(1, VEML6031X00_SEL_MILLI_GAIN_X125), + GAIN_SCALE_GAIN(2, VEML6031X00_SEL_MILLI_GAIN_X250), + GAIN_SCALE_GAIN(4, VEML6031X00_SEL_MILLI_GAIN_X500), + GAIN_SCALE_GAIN(8, VEML6031X00_SEL_MILLI_GAIN_X1000), + GAIN_SCALE_GAIN(16, VEML6031X00_SEL_MILLI_GAIN_X2000), +}; + +/* + * Two shutdown bits (SD and ALS_IR_SD) must be cleared to power on + * the device. + */ +static int veml6031x00_als_power_on(struct veml6031x00_data *data) +{ + int ret; + + ret =3D regmap_clear_bits(data->regmap, VEML6031X00_REG_CONF0, + VEML6031X00_CONF0_SD); + if (ret) + return ret; + + return regmap_clear_bits(data->regmap, VEML6031X00_REG_CONF1, + VEML6031X00_CONF1_IR_SD); +} + +/* + * Two shutdown bits (SD and ALS_IR_SD) must be set to power off + * the device. + */ +static int veml6031x00_als_shutdown(struct veml6031x00_data *data) +{ + int ret; + + ret =3D regmap_set_bits(data->regmap, VEML6031X00_REG_CONF0, + VEML6031X00_CONF0_SD); + if (ret) + return ret; + + return regmap_set_bits(data->regmap, VEML6031X00_REG_CONF1, + VEML6031X00_CONF1_IR_SD); +} + +static void veml6031x00_als_shutdown_action(void *data) +{ + veml6031x00_als_shutdown(data); +} + +static const struct iio_chan_spec veml6031x00_channels[] =3D { + { + .type =3D IIO_LIGHT, + .address =3D VEML6031X00_REG_ALS_L, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all =3D BIT(IIO_CHAN_INFO_INT_TIME), + .info_mask_shared_by_all_available =3D BIT(IIO_CHAN_INFO_INT_TIME), + .info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SCALE), + }, + { + .type =3D IIO_INTENSITY, + .address =3D VEML6031X00_REG_IR_L, + .modified =3D 1, + .channel2 =3D IIO_MOD_LIGHT_IR, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all =3D BIT(IIO_CHAN_INFO_INT_TIME), + .info_mask_shared_by_all_available =3D BIT(IIO_CHAN_INFO_INT_TIME), + }, +}; + +static const struct regmap_range veml6031x00_readable_ranges[] =3D { + regmap_reg_range(VEML6031X00_REG_CONF0, VEML6031X00_REG_CONF1), + regmap_reg_range(VEML6031X00_REG_ALS_L, VEML6031X00_REG_ID_H), +}; + +static const struct regmap_access_table veml6031x00_readable_table =3D { + .yes_ranges =3D veml6031x00_readable_ranges, + .n_yes_ranges =3D ARRAY_SIZE(veml6031x00_readable_ranges), +}; + +static const struct regmap_range veml6031x00_writable_ranges[] =3D { + regmap_reg_range(VEML6031X00_REG_CONF0, VEML6031X00_REG_CONF1), +}; + +static const struct regmap_access_table veml6031x00_writable_table =3D { + .yes_ranges =3D veml6031x00_writable_ranges, + .n_yes_ranges =3D ARRAY_SIZE(veml6031x00_writable_ranges), +}; + +static const struct regmap_range veml6031x00_volatile_ranges[] =3D { + regmap_reg_range(VEML6031X00_REG_ALS_L, VEML6031X00_REG_IR_H), +}; + +static const struct regmap_access_table veml6031x00_volatile_table =3D { + .yes_ranges =3D veml6031x00_volatile_ranges, + .n_yes_ranges =3D ARRAY_SIZE(veml6031x00_volatile_ranges), +}; + +static const struct regmap_config veml6031x00_regmap_config =3D { + .name =3D "veml6031x00_regmap", + .reg_bits =3D 8, + .val_bits =3D 8, + .rd_table =3D &veml6031x00_readable_table, + .wr_table =3D &veml6031x00_writable_table, + .volatile_table =3D &veml6031x00_volatile_table, + .max_register =3D VEML6031X00_REG_ID_H, + .cache_type =3D REGCACHE_MAPLE, +}; + +static const struct reg_field veml6031x00_rf_it =3D + REG_FIELD(VEML6031X00_REG_CONF0, 4, 6); + +static const struct reg_field veml6031x00_rf_gain =3D + REG_FIELD(VEML6031X00_REG_CONF1, 3, 4); + +static const struct reg_field veml6031x00_rf_pd_div4 =3D + REG_FIELD(VEML6031X00_REG_CONF1, 6, 6); + +static int veml6031x00_regfield_init(struct veml6031x00_data *data) +{ + struct regmap *regmap =3D data->regmap; + struct device *dev =3D data->dev; + struct regmap_field *rm_field; + struct veml6031x00_rf *rf =3D &data->rf; + + rm_field =3D devm_regmap_field_alloc(dev, regmap, veml6031x00_rf_gain); + if (IS_ERR(rm_field)) + return PTR_ERR(rm_field); + rf->gain =3D rm_field; + + rm_field =3D devm_regmap_field_alloc(dev, regmap, veml6031x00_rf_it); + if (IS_ERR(rm_field)) + return PTR_ERR(rm_field); + rf->it =3D rm_field; + + rm_field =3D devm_regmap_field_alloc(dev, regmap, veml6031x00_rf_pd_div4); + if (IS_ERR(rm_field)) + return PTR_ERR(rm_field); + rf->pd_div4 =3D rm_field; + + return 0; +} + +static int veml6031x00_get_it(struct veml6031x00_data *data, int *val2) +{ + int ret, it_idx; + + scoped_guard(mutex, &data->scale_lock) { + ret =3D regmap_field_read(data->rf.it, &it_idx); + if (ret) + return ret; + } + + ret =3D iio_gts_find_int_time_by_sel(&data->gts, it_idx); + if (ret < 0) + return ret; + + *val2 =3D ret; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int veml6031x00_set_it(struct iio_dev *iio, int val, int val2) +{ + struct veml6031x00_data *data =3D iio_priv(iio); + int ret, gain_sel, gain_reg, pd_div4, it_idx, new_gain, prev_gain, prev_i= t; + bool in_range; + + if (val || !iio_gts_valid_time(&data->gts, val2)) + return -EINVAL; + + guard(mutex)(&data->scale_lock); + + ret =3D regmap_field_read(data->rf.it, &it_idx); + if (ret) + return ret; + + ret =3D regmap_field_read(data->rf.gain, &gain_reg); + if (ret) + return ret; + + ret =3D regmap_field_read(data->rf.pd_div4, &pd_div4); + if (ret) + return ret; + + prev_it =3D iio_gts_find_int_time_by_sel(&data->gts, it_idx); + if (prev_it < 0) + return prev_it; + + if (prev_it =3D=3D val2) + return 0; + + prev_gain =3D iio_gts_find_gain_by_sel(&data->gts, (pd_div4 << 2) | gain_= reg); + if (prev_gain < 0) + return prev_gain; + + ret =3D iio_gts_find_new_gain_by_gain_time_min(&data->gts, prev_gain, pre= v_it, + val2, &new_gain, &in_range); + if (ret) + return ret; + + if (!in_range) + dev_dbg(data->dev, "Optimal gain out of range\n"); + + ret =3D iio_gts_find_sel_by_int_time(&data->gts, val2); + if (ret < 0) + return ret; + + ret =3D regmap_field_write(data->rf.it, ret); + if (ret) + return ret; + + gain_sel =3D iio_gts_find_sel_by_gain(&data->gts, new_gain); + if (gain_sel < 0) + return gain_sel; + + ret =3D regmap_field_write(data->rf.pd_div4, gain_sel >> 2); + if (ret) + return ret; + + return regmap_field_write(data->rf.gain, gain_sel & 0x03); +} + +static int veml6031x00_set_scale(struct iio_dev *iio, int val, int val2) +{ + struct veml6031x00_data *data =3D iio_priv(iio); + int gain_sel, it_sel, ret; + + ret =3D iio_gts_find_gain_time_sel_for_scale(&data->gts, val, val2, + &gain_sel, &it_sel); + if (ret) + return ret; + + guard(mutex)(&data->scale_lock); + + ret =3D regmap_field_write(data->rf.it, it_sel); + if (ret) + return ret; + + ret =3D regmap_field_write(data->rf.pd_div4, gain_sel >> 2); + if (ret) + return ret; + + return regmap_field_write(data->rf.gain, gain_sel & 0x03); +} + +static int veml6031x00_get_scale(struct veml6031x00_data *data, int *val, + int *val2) +{ + int gain, it, gain_reg, pd_div4, it_reg, ret, sel; + + scoped_guard(mutex, &data->scale_lock) { + ret =3D regmap_field_read(data->rf.gain, &gain_reg); + if (ret) + return ret; + + ret =3D regmap_field_read(data->rf.pd_div4, &pd_div4); + if (ret) + return ret; + + sel =3D (pd_div4 << 2) | gain_reg; + gain =3D iio_gts_find_gain_by_sel(&data->gts, sel); + if (gain < 0) + return gain; + + ret =3D regmap_field_read(data->rf.it, &it_reg); + if (ret) + return ret; + } + + it =3D iio_gts_find_int_time_by_sel(&data->gts, it_reg); + if (it < 0) + return it; + + ret =3D iio_gts_get_scale(&data->gts, gain, it, val, val2); + if (ret) + return ret; + + return IIO_VAL_INT_PLUS_NANO; +} + +static int veml6031x00_single_read(struct iio_dev *iio, enum iio_chan_type= type, + int *val) +{ + struct veml6031x00_data *data =3D iio_priv(iio); + int addr, it_usec, ret; + __le16 reg; + + switch (type) { + case IIO_LIGHT: + addr =3D VEML6031X00_REG_ALS_L; + break; + case IIO_INTENSITY: + addr =3D VEML6031X00_REG_IR_L; + break; + default: + return -EINVAL; + } + + PM_RUNTIME_ACQUIRE_AUTOSUSPEND(data->dev, pm); + ret =3D PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + ret =3D veml6031x00_get_it(data, &it_usec); + if (ret < 0) + return ret; + + /* integration time + 10 % to ensure completion */ + fsleep(it_usec + (it_usec / 10)); + + ret =3D regmap_bulk_read(data->regmap, addr, ®, sizeof(reg)); + if (ret) + return ret; + + *val =3D le16_to_cpu(reg); + return IIO_VAL_INT; +} + +static int veml6031x00_read_raw(struct iio_dev *iio, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct veml6031x00_data *data =3D iio_priv(iio); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return veml6031x00_single_read(iio, chan->type, val); + case IIO_CHAN_INFO_INT_TIME: + *val =3D 0; + return veml6031x00_get_it(data, val2); + case IIO_CHAN_INFO_SCALE: + return veml6031x00_get_scale(data, val, val2); + default: + return -EINVAL; + } +} + +static int veml6031x00_read_avail(struct iio_dev *iio, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct veml6031x00_data *data =3D iio_priv(iio); + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + return iio_gts_avail_times(&data->gts, vals, type, length); + case IIO_CHAN_INFO_SCALE: + return iio_gts_all_avail_scales(&data->gts, vals, type, length); + default: + return -EINVAL; + } +} + +static int veml6031x00_write_raw(struct iio_dev *iio, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + return veml6031x00_set_it(iio, val, val2); + case IIO_CHAN_INFO_SCALE: + return veml6031x00_set_scale(iio, val, val2); + default: + return -EINVAL; + } +} + +static int veml6031x00_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_INT_TIME: + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static const struct iio_info veml6031x00_info =3D { + .read_raw =3D veml6031x00_read_raw, + .read_avail =3D veml6031x00_read_avail, + .write_raw =3D veml6031x00_write_raw, + .write_raw_get_fmt =3D veml6031x00_write_raw_get_fmt, +}; + +static int veml6031x00_validate_part_id(struct veml6031x00_data *data) +{ + int part_id, ret; + __le16 reg; + + ret =3D regmap_bulk_read(data->regmap, VEML6031X00_REG_ID_L, ®, + sizeof(reg)); + if (ret) + return dev_err_probe(data->dev, ret, "Failed to read ID\n"); + + part_id =3D le16_to_cpu(reg); + if (part_id !=3D data->chip->part_id) + dev_warn(data->dev, "Unknown ID %04x\n", part_id); + + return 0; +} + +static int veml6031x00_hw_init(struct iio_dev *iio) +{ + struct veml6031x00_data *data =3D iio_priv(iio); + struct device *dev =3D data->dev; + int ret; + + /* Max resolution =3D 6.9632 lx/cnt for gain =3D 0.125 and IT =3D 3.125ms= */ + ret =3D devm_iio_init_iio_gts(dev, 6, 963200000, + veml6031x00_gain_sel, + ARRAY_SIZE(veml6031x00_gain_sel), + veml6031x00_it_sel, + ARRAY_SIZE(veml6031x00_it_sel), + &data->gts); + if (ret) + return dev_err_probe(dev, ret, "failed to init iio gts\n"); + + return 0; +} + +static int veml6031x00_probe(struct i2c_client *i2c) +{ + struct device *dev =3D &i2c->dev; + struct veml6031x00_data *data; + struct iio_dev *iio; + struct regmap *regmap; + int ret; + + regmap =3D devm_regmap_init_i2c(i2c, &veml6031x00_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to set regmap\n"); + + iio =3D devm_iio_device_alloc(dev, sizeof(*data)); + if (!iio) + return -ENOMEM; + + data =3D iio_priv(iio); + i2c_set_clientdata(i2c, iio); + data->dev =3D dev; + data->regmap =3D regmap; + + ret =3D devm_mutex_init(dev, &data->scale_lock); + if (ret) + return ret; + + ret =3D veml6031x00_regfield_init(data); + if (ret) + return dev_err_probe(dev, ret, "Failed to init regfield\n"); + + ret =3D devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable regulator\n"); + + data->chip =3D i2c_get_match_data(i2c); + if (!data->chip) + return dev_err_probe(dev, -EINVAL, "Failed to get chip data\n"); + + /* The device starts in power down mode by default */ + ret =3D veml6031x00_als_power_on(data); + if (ret) + return dev_err_probe(dev, ret, "Failed to power on the device\n"); + + ret =3D devm_add_action_or_reset(dev, veml6031x00_als_shutdown_action, da= ta); + if (ret) + return dev_err_probe(dev, ret, "Failed to add shutdown action\n"); + + pm_runtime_set_autosuspend_delay(dev, 2000); + pm_runtime_use_autosuspend(dev); + ret =3D devm_pm_runtime_set_active_enabled(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable runtime PM\n"); + + ret =3D devm_pm_runtime_get_noresume(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to get runtime PM\n"); + + ret =3D veml6031x00_validate_part_id(data); + if (ret) + return ret; + + iio->name =3D data->chip->name; + iio->channels =3D veml6031x00_channels; + iio->num_channels =3D ARRAY_SIZE(veml6031x00_channels); + iio->modes =3D INDIO_DIRECT_MODE; + iio->info =3D &veml6031x00_info; + + ret =3D veml6031x00_hw_init(iio); + if (ret) + return ret; + + pm_runtime_put_autosuspend(dev); + + ret =3D devm_iio_device_register(dev, iio); + if (ret) + return dev_err_probe(dev, ret, "Failed to register iio device\n"); + + return 0; +} + +static int veml6031x00_runtime_suspend(struct device *dev) +{ + struct veml6031x00_data *data =3D iio_priv(dev_get_drvdata(dev)); + + return veml6031x00_als_shutdown(data); +} + +static int veml6031x00_runtime_resume(struct device *dev) +{ + struct veml6031x00_data *data =3D iio_priv(dev_get_drvdata(dev)); + + return veml6031x00_als_power_on(data); +} + +static DEFINE_RUNTIME_DEV_PM_OPS(veml6031x00_pm_ops, veml6031x00_runtime_s= uspend, + veml6031x00_runtime_resume, NULL); + +static const struct veml6031x00_chip veml6031x00_chip =3D { + .name =3D "veml6031x00", + .part_id =3D 0x0001, +}; + +static const struct veml6031x00_chip veml6031x01_chip =3D { + .name =3D "veml6031x01", + .part_id =3D 0x0001, +}; + +static const struct veml6031x00_chip veml60311x00_chip =3D { + .name =3D "veml60311x00", + .part_id =3D 0x1001, +}; + +static const struct veml6031x00_chip veml60311x01_chip =3D { + .name =3D "veml60311x01", + .part_id =3D 0x1001, +}; + +static const struct of_device_id veml6031x00_of_match[] =3D { + { + .compatible =3D "vishay,veml6031x00", + .data =3D &veml6031x00_chip, + }, + { + .compatible =3D "vishay,veml6031x01", + .data =3D &veml6031x01_chip, + }, + { + .compatible =3D "vishay,veml60311x00", + .data =3D &veml60311x00_chip, + }, + { + .compatible =3D "vishay,veml60311x01", + .data =3D &veml60311x01_chip, + }, + { } +}; +MODULE_DEVICE_TABLE(of, veml6031x00_of_match); + +static const struct i2c_device_id veml6031x00_id[] =3D { + { + .name =3D "veml6031x00", + .driver_data =3D (kernel_ulong_t)&veml6031x00_chip + }, + { + .name =3D "veml6031x01", + .driver_data =3D (kernel_ulong_t)&veml6031x01_chip }, + { + .name =3D "veml60311x00", + .driver_data =3D (kernel_ulong_t)&veml60311x00_chip + }, + { + .name =3D "veml60311x01", + .driver_data =3D (kernel_ulong_t)&veml60311x01_chip + }, + { } +}; +MODULE_DEVICE_TABLE(i2c, veml6031x00_id); + +static struct i2c_driver veml6031x00_driver =3D { + .driver =3D { + .name =3D "veml6031x00", + .of_match_table =3D veml6031x00_of_match, + .pm =3D pm_ptr(&veml6031x00_pm_ops), + }, + .probe =3D veml6031x00_probe, + .id_table =3D veml6031x00_id, +}; +module_i2c_driver(veml6031x00_driver); + +MODULE_AUTHOR("Javier Carrasco "); +MODULE_DESCRIPTION("VEML6031X00 Ambient Light Sensor"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_GTS_HELPER"); --=20 2.43.0 From nobody Mon Jun 8 07:22:49 2026 Received: from mail-wm1-f50.google.com (mail-wm1-f50.google.com [209.85.128.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D102B33C52F for ; Sun, 31 May 2026 19:58:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780257522; cv=none; b=kk7DZPIsZDxEYm75ug+B6xZqzWgfqoxKUziJMa1G+ZYkhBIEbr+7Dkycimv37YnZj8ywM9AigJr5iVk2sDDdp1IgHsEXqBYfTZw1vTmWj8CDss7l1yHGArxhs9i9KDpb87kjC1f5aHIRDojEOimaxgy0V0TMjXrA+lwziZpt/Wk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780257522; c=relaxed/simple; bh=3rMinnWkSWj8Yetpk6Terpb21cTv9q5faLaxxlD4tao=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=IBe2uSmu57rCzYhNHJmmOq7aKnxQ8CidHXmOtON3rmG3rXtKwbNDnJGLzppReeue8nLOZViI9mHbbuQmgX5zm24dtO0G2iggTutluRQwiMHLv4dIQJHtMNiCUSTN9XiE75TGUyiP1BooIzAzldMD3RpxRHGfb1fWTOL4XqI4lGU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=PyyqinfU; arc=none smtp.client-ip=209.85.128.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="PyyqinfU" Received: by mail-wm1-f50.google.com with SMTP id 5b1f17b1804b1-4903d730b1fso84713355e9.2 for ; Sun, 31 May 2026 12:58:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780257519; x=1780862319; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=+RLJzSgogYFN8Zeh81kPrNPCUIj/QxMt/6mfJHqzi8Y=; b=PyyqinfU39OkDyLazwJCGI09ckLTvqPn4g69DpwHeMdchaxre2Bur9q8t/Zoojsivc UQVApTuKKRKHI8bGjli2lCdsGGYXr8TH5kRWopdtk2jYz/qxHVQBJ9LT0jgrr+36b9Xw aItcAmAeyKau2bWqrk5FUSRrzDk18Ud8/XHhIEZSzEk/ez+q0G7FgPFlA7YwiDCyZkGs +AVwTTz58MumBz6qA3vx+xbniUDCScNhIYMtwwo6EnkJOnBT4EE9Ge+EaiF9ooBGC72j FCgnMaEAX1eMEdckuizo6cuCWpK/7Sf7BaGukUuYkkDHru6WjGEzgdeZS8U26mPS6Dbq 46GQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780257519; x=1780862319; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=+RLJzSgogYFN8Zeh81kPrNPCUIj/QxMt/6mfJHqzi8Y=; b=m5BH9yfsiDcqaR4OjRJtcEvycPea22tHV4n9ShdyijS4vQ6c8ejtUHynSWyznCldZz uL4MFeGYzYimauLohdi3bUWVu/L72jUHllkuzX0NkKV8UuWMPZ3SjwQEF9QWDZx147gq Fsp+i4E5k9qxCsoRuMhYsJvPW8b3wOI2vVOoiG9TIwrwMBcq5zqPYh3SltmN21lwyctu tLyaW/ATVyTe8n6/jVPghNQLnDLJeXW8/0dmTXdJ4dENQ2KlnECBQT3qlxMFDyrYCo1R KKaKgtL6TlgEUsKdYcjAjX945jeUIiLWRvZHQrk+Lc+6CISVNcGDyrCmrIYznz+0DwIZ xvFg== X-Forwarded-Encrypted: i=1; AFNElJ+A8fpRKqbvU/sTkFxABX0vCMsJgRY3tOFoKehYPQry9ja45SpC/cRLNGo+BIPHu6yR0zClhJjjb+HtdhU=@vger.kernel.org X-Gm-Message-State: AOJu0YwIXGstzXIXpoDIbCEV/2gwien3O+AaGVKekgP74bFaPLaD+/z7 jwKIjMNwRE0tbtRz1PIDoxyQewci3eYBCAHCXAn1EK9pc2Bmf9CMpM7y X-Gm-Gg: Acq92OGaCZ9jAVajiIKpSWrpo7XV0MlfBEw7qfGcsL1PJVc9kxsslWNHaqiHNcswTGM g2c1jEIzrZ08OMxJ+wM4/g1+Sgy5ux9tryt7htciTHV85Vd9H7xhBYi1DuvQ8xOaS548vNB2B6p z0Hq9h5cemYjRorARBuNOXs/ZstrA5nehy3V8t80EsbeifveBkGCT0gGJLqKYXffhrPIVpYIPQq 61YuQ/hKgx7VaxBCWvRl0yP2nTa2dn9gewC58YBqpBpmjb86PfjjSt2TIwyfp7XiG98yt0qYUVX rNSI0eX9LuRljEYAFpOlyi/fsGE0e1buBgfxhH0yiB9J1yVVsQWlUty3GtAhcrPNGfQnnB21oHJ U3sBXfEAV27G+rA5i2Zlx74Pbu68j2Uc0XEfRH52zePiuM+4Hoywe6o6e+PNtIWPYTJNUlg+gX7 VDAaJQ4++yAvcS0D1wVf4mD7r+bI7LwW7uCFca7K0mFzrl68rIbA== X-Received: by 2002:a05:600c:a01:b0:490:46df:a87a with SMTP id 5b1f17b1804b1-490a2a847edmr152590355e9.1.1780257519146; Sun, 31 May 2026 12:58:39 -0700 (PDT) Received: from [127.0.1.1] ([2001:4bb8:152:df59:bc17:a305:8902:fb31]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4909d7002e8sm220323775e9.15.2026.05.31.12.58.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 31 May 2026 12:58:38 -0700 (PDT) From: Javier Carrasco Date: Sun, 31 May 2026 21:58:23 +0200 Subject: [PATCH v4 3/4] iio: light: veml6031x00: add support for triggered buffers Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260531-veml6031x00-v4-3-e64f7fdce38d@gmail.com> References: <20260531-veml6031x00-v4-0-e64f7fdce38d@gmail.com> In-Reply-To: <20260531-veml6031x00-v4-0-e64f7fdce38d@gmail.com> To: Jonathan Cameron , Lars-Peter Clausen , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Rishi Gupta , David Lechner , =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko , Matti Vaittinen Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Javier Carrasco , Jonathan Cameron X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780257511; l=5898; i=javier.carrasco.cruz@gmail.com; s=20260111; h=from:subject:message-id; bh=3rMinnWkSWj8Yetpk6Terpb21cTv9q5faLaxxlD4tao=; b=bgW5mAvM2uIi2Bcq0yv6vNGjRV1wg7bZm4RdzeK0rUdBHdL+FdE9xtXhDxSomsKi3t86TktKd LGzVW3WekG4A/VF4LqSyBfVgkJp5ArRIOUAPKr5C1wgUboW6s9BvkOZ X-Developer-Key: i=javier.carrasco.cruz@gmail.com; a=ed25519; pk=Lge8w8xidNSf/INy7JAIbAW+Hezkp3nsBh2OjKL7lLU= Add triggered buffer functionality for the two channels the device provides (ALS and IR). Signed-off-by: Javier Carrasco --- drivers/iio/light/Kconfig | 2 + drivers/iio/light/veml6031x00.c | 114 ++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 116 insertions(+) diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 99a6ed80c7db..ff71de8454bd 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -717,6 +717,8 @@ config VEML6031X00 tristate "VEML6031X00 ambient light sensor series" select REGMAP_I2C select IIO_GTS_HELPER + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER depends on I2C help Say Y here if you want to build a driver for the Vishay VEML6031X00 diff --git a/drivers/iio/light/veml6031x00.c b/drivers/iio/light/veml6031x0= 0.c index 6f9a7bad44d4..facb1b8e4241 100644 --- a/drivers/iio/light/veml6031x00.c +++ b/drivers/iio/light/veml6031x00.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include =20 /* Device registers */ #define VEML6031X00_REG_CONF0 0x00 @@ -31,6 +33,12 @@ #define VEML6031X00_CONF0_SD BIT(0) #define VEML6031X00_CONF1_IR_SD BIT(7) =20 +enum veml6031x00_scan { + VEML6031X00_SCAN_ALS, + VEML6031X00_SCAN_IR, + VEML6031X00_SCAN_TIMESTAMP, +}; + struct veml6031x00_rf { struct regmap_field *gain; struct regmap_field *it; @@ -136,6 +144,13 @@ static const struct iio_chan_spec veml6031x00_channels= [] =3D { .info_mask_shared_by_all =3D BIT(IIO_CHAN_INFO_INT_TIME), .info_mask_shared_by_all_available =3D BIT(IIO_CHAN_INFO_INT_TIME), .info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SCALE), + .scan_index =3D VEML6031X00_SCAN_ALS, + .scan_type =3D { + .sign =3D 'u', + .realbits =3D 16, + .storagebits =3D 16, + .endianness =3D IIO_LE, + }, }, { .type =3D IIO_INTENSITY, @@ -146,7 +161,15 @@ static const struct iio_chan_spec veml6031x00_channels= [] =3D { BIT(IIO_CHAN_INFO_SCALE), .info_mask_shared_by_all =3D BIT(IIO_CHAN_INFO_INT_TIME), .info_mask_shared_by_all_available =3D BIT(IIO_CHAN_INFO_INT_TIME), + .scan_index =3D VEML6031X00_SCAN_IR, + .scan_type =3D { + .sign =3D 'u', + .realbits =3D 16, + .storagebits =3D 16, + .endianness =3D IIO_LE, + }, }, + IIO_CHAN_SOFT_TIMESTAMP(VEML6031X00_SCAN_TIMESTAMP), }; =20 static const struct regmap_range veml6031x00_readable_ranges[] =3D { @@ -378,6 +401,10 @@ static int veml6031x00_single_read(struct iio_dev *iio= , enum iio_chan_type type, return -EINVAL; } =20 + IIO_DEV_ACQUIRE_DIRECT_MODE(iio, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + PM_RUNTIME_ACQUIRE_AUTOSUSPEND(data->dev, pm); ret =3D PM_RUNTIME_ACQUIRE_ERR(&pm); if (ret) @@ -438,6 +465,10 @@ static int veml6031x00_write_raw(struct iio_dev *iio, struct iio_chan_spec const *chan, int val, int val2, long mask) { + IIO_DEV_ACQUIRE_DIRECT_MODE(iio, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + switch (mask) { case IIO_CHAN_INFO_INT_TIME: return veml6031x00_set_it(iio, val, val2); @@ -469,6 +500,82 @@ static const struct iio_info veml6031x00_info =3D { .write_raw_get_fmt =3D veml6031x00_write_raw_get_fmt, }; =20 +static int veml6031x00_buffer_preenable(struct iio_dev *iio) +{ + struct veml6031x00_data *data =3D iio_priv(iio); + int ret, it_usec; + + ret =3D pm_runtime_resume_and_get(data->dev); + if (ret) + return ret; + + ret =3D veml6031x00_get_it(data, &it_usec); + if (ret < 0) { + pm_runtime_put_autosuspend(data->dev); + return ret; + } + + /* + * Wait one integration period + 10% margin so the first triggered + * read does not race with the sensor completing its first conversion + * after power-on. + */ + fsleep(it_usec + (it_usec / 10)); + + return 0; +} + +static int veml6031x00_buffer_postdisable(struct iio_dev *iio) +{ + struct veml6031x00_data *data =3D iio_priv(iio); + + pm_runtime_put_autosuspend(data->dev); + + return 0; +} + +static const struct iio_buffer_setup_ops veml6031x00_buffer_setup_ops =3D { + .preenable =3D veml6031x00_buffer_preenable, + .postdisable =3D veml6031x00_buffer_postdisable, +}; + +static irqreturn_t veml6031x00_trig_handler(int irq, void *p) +{ + struct iio_poll_func *pf =3D p; + struct iio_dev *iio =3D pf->indio_dev; + struct veml6031x00_data *data =3D iio_priv(iio); + int ch, ret, i =3D 0; + struct { + __le16 chans[2]; + aligned_s64 timestamp; + } scan =3D { }; + + if (test_bit(VEML6031X00_SCAN_ALS, iio->active_scan_mask) && + test_bit(VEML6031X00_SCAN_IR, iio->active_scan_mask)) { + ret =3D regmap_bulk_read(data->regmap, + VEML6031X00_REG_ALS_L, + &scan.chans, sizeof(scan.chans)); + if (ret) + goto done; + } else { + iio_for_each_active_channel(iio, ch) { + ret =3D regmap_bulk_read(data->regmap, + iio->channels[ch].address, + &scan.chans[i++], + sizeof(*scan.chans)); + if (ret) + goto done; + } + } + + iio_push_to_buffers_with_ts(iio, &scan, sizeof(scan), pf->timestamp); + +done: + iio_trigger_notify_done(iio->trig); + + return IRQ_HANDLED; +} + static int veml6031x00_validate_part_id(struct veml6031x00_data *data) { int part_id, ret; @@ -576,6 +683,13 @@ static int veml6031x00_probe(struct i2c_client *i2c) if (ret) return ret; =20 + ret =3D devm_iio_triggered_buffer_setup(dev, iio, NULL, + veml6031x00_trig_handler, + &veml6031x00_buffer_setup_ops); + if (ret) + return dev_err_probe(dev, ret, + "Failed to register triggered buffer\n"); + pm_runtime_put_autosuspend(dev); =20 ret =3D devm_iio_device_register(dev, iio); --=20 2.43.0 From nobody Mon Jun 8 07:22:49 2026 Received: from mail-wm1-f45.google.com (mail-wm1-f45.google.com [209.85.128.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D6A6230FF08 for ; Sun, 31 May 2026 19:58:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780257526; cv=none; b=WgCtQA/QnhefZyCD41pLGFrlTGfrcQjrQk85tPZDHfyPOyU94mvY2ej1cTp5wu5gNRnI9EnsgLhEJDenWta0TiQZ2RcgbyyGC34Sh67jBl1KW+l1C9L/huAsrRg6/uQXk8daLTwqUW757R8M50H08Ln6NlA+AL+1uNP8k+oEhj8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780257526; c=relaxed/simple; bh=C86evQzfb8UYj0OPE56Kty27MegZ2sBy4VTTimrvpdY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Dv/1k6gvf1KruFiX4/mL7rj7BPYLDLhz4PmWf32+yEV2L5yCXFkIWDmBdZhcDBg5WvaeApV1Fzr+2a/2/eOtPYsTTYR4zHB0S+POP9fNSEdA+ZpVuvIiYwHqV2YQzFsAS3nyyGrWa8OsnYdAuqwO0MNlq+3js6daVvi54pKSTI4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=jxJVbDhl; arc=none smtp.client-ip=209.85.128.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="jxJVbDhl" Received: by mail-wm1-f45.google.com with SMTP id 5b1f17b1804b1-490a765f47aso5118525e9.1 for ; Sun, 31 May 2026 12:58:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780257521; x=1780862321; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=0xpio9SdhGJ0it1p9rOfJz8bH6VQA/ZV8VgL4r5XQ98=; b=jxJVbDhlsJEy25nIfOGWOjaPmkmC1HUECK3E2U/L04aas28a6PeopB3teqiT+8ety1 LK701zkN9lR4y1YPSa7U9SwxX8Op+MxiCwx4CLFnct9vkMKHH8T3hhCF5jFhrTYVH+GB ziFsXIewbJAX1eQvOUvPKljLmnuuEalzy2G8NvMuicDMLZmYpHBK82jmGglKNqGLmzQe Bqx7hK54FyarAoTUYvO0AMSb2O0C5aK/RC8vbKTEMTovRQ+BkRsK5lKl/bCfvUPxZaOa +2HsXAzBo9i0Dh9YeBvUZzYF5+xS6fl8F9wrvadeKYQWpqKKeIX+NspkANhxHdSEAcZr C6ig== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780257521; x=1780862321; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=0xpio9SdhGJ0it1p9rOfJz8bH6VQA/ZV8VgL4r5XQ98=; b=LtGetKZstQFQPHENRllk9eyQJLeHEmqvQ3IEZAl3qwoQ7yk4Sne4oV7xsIh/83/lTT LoLJTLnG4QqrxxJse4c9/Ki7qLJENZMPPjWnCR2MSCEpI6VSOFczqx/bvI/L7CjpbTVG e/l6qZ7KzQztr180p5EzpOxfhCBVSj1vGc6OwgfKl3rlXd6t4gjsiC3x64bgBTLeEVyd p4n6/NXoHURduvVcRqh/B2WH01F8rOALz8InFc4I6fPLHf3zNHa/vZh/JLZg5jBcELX7 qL3ogPY43AffgCgPDn26bETkbU0lprsmwUIC9sC1XWP7jUl58xKw02uYfpte0F5gVkBI A++w== X-Forwarded-Encrypted: i=1; AFNElJ/KhO/cY/pyVYMMria4O8BOZDYYfC1skMc7Ez9tG2B5DbSPae0TVN27ElqdjFlA4ajFJmrxeu/HoAE0UDw=@vger.kernel.org X-Gm-Message-State: AOJu0YxMdrGr4/hXImTREXl1rh67VzQn8sLMPgG5lwY+Cex78Vf+YnsP FH4Aznw5LxtBngXepO7QVg1LS08nMCzyuW87CA9q6O79mAhOC7hOkhVc X-Gm-Gg: Acq92OEOQ7v6vZHUPCCY1xU3pqEVjOto/tcrLf3s9SvHVfBwXYzi6T0kyEuhdGMUbJY mSW/fuxigzDSxs5Bn6bXSqArv+SwX2joi5AJm+i7BOlrPGXPGcApv1wCMu1g6YKrhhh1N4FJmI6 z24IscBfxtEBp0fzlAJnopZczv0lETtUPuvq4Sfk6JsUokmcIj2P//53RLA2Bdpaaok3Vu8q8T2 nQtoKltVuV/FtJOQ/1rnKuqDGTw9xsLQPUNrPgDcD6FNB3ibEZ6C9bfRXmI6G+jIgKPRNw5apEn 6d7ujAJvl8HMjknrP+ovSbjBW9atlSDNTEL49WlG47/Gir79QEf3r7+56rWCF84ngpuH6urLwCK 2pbjwn+KCVJp1w31NuQbcbA8bsVTz8TqnIwtOhH1TN5X6wOafweUra7kl9JPzPRzcvMpSL5gGTH 3xjg3Xv1OX1kwU5kwHx3V2aBZVeQTB9bTnLJb9KDs2cUy15XpseA== X-Received: by 2002:a05:600c:5290:b0:48a:6798:52e9 with SMTP id 5b1f17b1804b1-490a28d4a5cmr141096825e9.0.1780257521133; Sun, 31 May 2026 12:58:41 -0700 (PDT) Received: from [127.0.1.1] ([2001:4bb8:152:df59:bc17:a305:8902:fb31]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4909d7002e8sm220323775e9.15.2026.05.31.12.58.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 31 May 2026 12:58:40 -0700 (PDT) From: Javier Carrasco Date: Sun, 31 May 2026 21:58:24 +0200 Subject: [PATCH v4 4/4] iio: light: veml6031x00: add support for events and trigger Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260531-veml6031x00-v4-4-e64f7fdce38d@gmail.com> References: <20260531-veml6031x00-v4-0-e64f7fdce38d@gmail.com> In-Reply-To: <20260531-veml6031x00-v4-0-e64f7fdce38d@gmail.com> To: Jonathan Cameron , Lars-Peter Clausen , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Rishi Gupta , David Lechner , =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko , Matti Vaittinen Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Javier Carrasco , Jonathan Cameron X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1780257511; l=20112; i=javier.carrasco.cruz@gmail.com; s=20260111; h=from:subject:message-id; bh=C86evQzfb8UYj0OPE56Kty27MegZ2sBy4VTTimrvpdY=; b=CETirkwTja4oJ4SuQpWL58npXMTZvXsl9YtytV2ms1VocxEddSS3FS809LepPz2pd1g7VhfnF fwXcfvp5JPnAyHarLn4odX2PZ+9W58tQWae9lykjyrlv4KMp821dCEb X-Developer-Key: i=javier.carrasco.cruz@gmail.com; a=ed25519; pk=Lge8w8xidNSf/INy7JAIbAW+Hezkp3nsBh2OjKL7lLU= The device provides a shared interrupt line for to notify events and data ready, which can be used as a trigger. The interrupt line is not a requirement for the device to work. Implement variants for the cases whether the interrupt line is provided or not. Signed-off-by: Javier Carrasco --- drivers/iio/light/veml6031x00.c | 442 ++++++++++++++++++++++++++++++++++++= +++- 1 file changed, 438 insertions(+), 4 deletions(-) diff --git a/drivers/iio/light/veml6031x00.c b/drivers/iio/light/veml6031x0= 0.c index facb1b8e4241..5e79eb942f09 100644 --- a/drivers/iio/light/veml6031x00.c +++ b/drivers/iio/light/veml6031x00.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -22,16 +26,29 @@ /* Device registers */ #define VEML6031X00_REG_CONF0 0x00 #define VEML6031X00_REG_CONF1 0x01 +#define VEML6031X00_REG_WH_L 0x04 +#define VEML6031X00_REG_WH_H 0x05 +#define VEML6031X00_REG_WL_L 0x06 +#define VEML6031X00_REG_WL_H 0x07 #define VEML6031X00_REG_ALS_L 0x10 #define VEML6031X00_REG_ALS_H 0x11 #define VEML6031X00_REG_IR_L 0x12 #define VEML6031X00_REG_IR_H 0x13 #define VEML6031X00_REG_ID_L 0x14 #define VEML6031X00_REG_ID_H 0x15 +#define VEML6031X00_REG_INT 0x17 =20 /* Bit masks for specific functionality */ #define VEML6031X00_CONF0_SD BIT(0) +#define VEML6031X00_CONF0_AF_TRIG BIT(2) +#define VEML6031X00_CONF0_AF BIT(3) #define VEML6031X00_CONF1_IR_SD BIT(7) +#define VEML6031X00_INT_TH_H BIT(1) +#define VEML6031X00_INT_TH_L BIT(2) +#define VEML6031X00_INT_DRDY BIT(3) +#define VEML6031X00_INT_MASK (VEML6031X00_INT_TH_L | \ + VEML6031X00_INT_TH_H | \ + VEML6031X00_INT_DRDY) =20 enum veml6031x00_scan { VEML6031X00_SCAN_ALS, @@ -41,8 +58,10 @@ enum veml6031x00_scan { =20 struct veml6031x00_rf { struct regmap_field *gain; + struct regmap_field *int_en; struct regmap_field *it; struct regmap_field *pd_div4; + struct regmap_field *pers; }; =20 struct veml6031x00_chip { @@ -54,6 +73,7 @@ struct veml6031x00_data { struct device *dev; struct iio_gts gts; struct regmap *regmap; + struct iio_trigger *trig; struct veml6031x00_rf rf; const struct veml6031x00_chip *chip; /* @@ -62,6 +82,11 @@ struct veml6031x00_data { * consistent set. */ struct mutex scale_lock; + /* serialize access to irq enable/disable by events and trigger */ + struct mutex irq_lock; + int int_users; + bool ev_en; + bool trig_en; }; =20 static const struct iio_itime_sel_mul veml6031x00_it_sel[] =3D { @@ -96,6 +121,17 @@ static const struct iio_gain_sel_pair veml6031x00_gain_= sel[] =3D { GAIN_SCALE_GAIN(16, VEML6031X00_SEL_MILLI_GAIN_X2000), }; =20 +static IIO_CONST_ATTR(in_illuminance_thresh_either_period_available, "1 2 = 4 8"); + +static struct attribute *veml6031x00_event_attributes[] =3D { + &iio_const_attr_in_illuminance_thresh_either_period_available.dev_attr.at= tr, + NULL +}; + +static const struct attribute_group veml6031x00_event_attr_group =3D { + .attrs =3D veml6031x00_event_attributes, +}; + /* * Two shutdown bits (SD and ALS_IR_SD) must be cleared to power on * the device. @@ -135,6 +171,23 @@ static void veml6031x00_als_shutdown_action(void *data) veml6031x00_als_shutdown(data); } =20 +static const struct iio_event_spec veml6031x00_event_spec[] =3D { + { + .type =3D IIO_EV_TYPE_THRESH, + .dir =3D IIO_EV_DIR_RISING, + .mask_separate =3D BIT(IIO_EV_INFO_VALUE), + }, { + .type =3D IIO_EV_TYPE_THRESH, + .dir =3D IIO_EV_DIR_FALLING, + .mask_separate =3D BIT(IIO_EV_INFO_VALUE), + }, { + .type =3D IIO_EV_TYPE_THRESH, + .dir =3D IIO_EV_DIR_EITHER, + .mask_separate =3D BIT(IIO_EV_INFO_PERIOD) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + static const struct iio_chan_spec veml6031x00_channels[] =3D { { .type =3D IIO_LIGHT, @@ -144,6 +197,8 @@ static const struct iio_chan_spec veml6031x00_channels[= ] =3D { .info_mask_shared_by_all =3D BIT(IIO_CHAN_INFO_INT_TIME), .info_mask_shared_by_all_available =3D BIT(IIO_CHAN_INFO_INT_TIME), .info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SCALE), + .event_spec =3D veml6031x00_event_spec, + .num_event_specs =3D ARRAY_SIZE(veml6031x00_event_spec), .scan_index =3D VEML6031X00_SCAN_ALS, .scan_type =3D { .sign =3D 'u', @@ -174,7 +229,9 @@ static const struct iio_chan_spec veml6031x00_channels[= ] =3D { =20 static const struct regmap_range veml6031x00_readable_ranges[] =3D { regmap_reg_range(VEML6031X00_REG_CONF0, VEML6031X00_REG_CONF1), + regmap_reg_range(VEML6031X00_REG_WH_L, VEML6031X00_REG_WL_H), regmap_reg_range(VEML6031X00_REG_ALS_L, VEML6031X00_REG_ID_H), + regmap_reg_range(VEML6031X00_REG_INT, VEML6031X00_REG_INT), }; =20 static const struct regmap_access_table veml6031x00_readable_table =3D { @@ -183,7 +240,7 @@ static const struct regmap_access_table veml6031x00_rea= dable_table =3D { }; =20 static const struct regmap_range veml6031x00_writable_ranges[] =3D { - regmap_reg_range(VEML6031X00_REG_CONF0, VEML6031X00_REG_CONF1), + regmap_reg_range(VEML6031X00_REG_CONF0, VEML6031X00_REG_WL_H), }; =20 static const struct regmap_access_table veml6031x00_writable_table =3D { @@ -193,6 +250,7 @@ static const struct regmap_access_table veml6031x00_wri= table_table =3D { =20 static const struct regmap_range veml6031x00_volatile_ranges[] =3D { regmap_reg_range(VEML6031X00_REG_ALS_L, VEML6031X00_REG_IR_H), + regmap_reg_range(VEML6031X00_REG_INT, VEML6031X00_REG_INT), }; =20 static const struct regmap_access_table veml6031x00_volatile_table =3D { @@ -200,6 +258,15 @@ static const struct regmap_access_table veml6031x00_vo= latile_table =3D { .n_yes_ranges =3D ARRAY_SIZE(veml6031x00_volatile_ranges), }; =20 +static const struct regmap_range veml6031x00_precious_ranges[] =3D { + regmap_reg_range(VEML6031X00_REG_INT, VEML6031X00_REG_INT), +}; + +static const struct regmap_access_table veml6031x00_precious_table =3D { + .yes_ranges =3D veml6031x00_precious_ranges, + .n_yes_ranges =3D ARRAY_SIZE(veml6031x00_precious_ranges), +}; + static const struct regmap_config veml6031x00_regmap_config =3D { .name =3D "veml6031x00_regmap", .reg_bits =3D 8, @@ -207,13 +274,20 @@ static const struct regmap_config veml6031x00_regmap_= config =3D { .rd_table =3D &veml6031x00_readable_table, .wr_table =3D &veml6031x00_writable_table, .volatile_table =3D &veml6031x00_volatile_table, - .max_register =3D VEML6031X00_REG_ID_H, + .precious_table =3D &veml6031x00_precious_table, + .max_register =3D VEML6031X00_REG_INT, .cache_type =3D REGCACHE_MAPLE, }; =20 +static const struct reg_field veml6031x00_rf_int_en =3D + REG_FIELD(VEML6031X00_REG_CONF0, 1, 1); + static const struct reg_field veml6031x00_rf_it =3D REG_FIELD(VEML6031X00_REG_CONF0, 4, 6); =20 +static const struct reg_field veml6031x00_rf_pers =3D + REG_FIELD(VEML6031X00_REG_CONF1, 1, 2); + static const struct reg_field veml6031x00_rf_gain =3D REG_FIELD(VEML6031X00_REG_CONF1, 3, 4); =20 @@ -232,6 +306,11 @@ static int veml6031x00_regfield_init(struct veml6031x0= 0_data *data) return PTR_ERR(rm_field); rf->gain =3D rm_field; =20 + rm_field =3D devm_regmap_field_alloc(dev, regmap, veml6031x00_rf_int_en); + if (IS_ERR(rm_field)) + return PTR_ERR(rm_field); + rf->int_en =3D rm_field; + rm_field =3D devm_regmap_field_alloc(dev, regmap, veml6031x00_rf_it); if (IS_ERR(rm_field)) return PTR_ERR(rm_field); @@ -242,6 +321,11 @@ static int veml6031x00_regfield_init(struct veml6031x0= 0_data *data) return PTR_ERR(rm_field); rf->pd_div4 =3D rm_field; =20 + rm_field =3D devm_regmap_field_alloc(dev, regmap, veml6031x00_rf_pers); + if (IS_ERR(rm_field)) + return PTR_ERR(rm_field); + rf->pers =3D rm_field; + return 0; } =20 @@ -325,6 +409,30 @@ static int veml6031x00_set_it(struct iio_dev *iio, int= val, int val2) return regmap_field_write(data->rf.gain, gain_sel & 0x03); } =20 +static int veml6031x00_read_period(struct iio_dev *iio, int *val) +{ + struct veml6031x00_data *data =3D iio_priv(iio); + int ret, reg; + + ret =3D regmap_field_read(data->rf.pers, ®); + if (ret) + return ret; + + *val =3D 1 << reg; + + return IIO_VAL_INT; +} + +static int veml6031x00_write_period(struct iio_dev *iio, int val) +{ + struct veml6031x00_data *data =3D iio_priv(iio); + + if (val < 0 || val > 8 || hweight8(val) !=3D 1) + return -EINVAL; + + return regmap_field_write(data->rf.pers, ffs(val) - 1); +} + static int veml6031x00_set_scale(struct iio_dev *iio, int val, int val2) { struct veml6031x00_data *data =3D iio_priv(iio); @@ -383,6 +491,51 @@ static int veml6031x00_get_scale(struct veml6031x00_da= ta *data, int *val, return IIO_VAL_INT_PLUS_NANO; } =20 +static int veml6031x00_read_th(struct iio_dev *iio, int *val, int *val2, i= nt dir) +{ + struct veml6031x00_data *data =3D iio_priv(iio); + __le16 reg; + int ret; + + if (dir =3D=3D IIO_EV_DIR_RISING) + ret =3D regmap_bulk_read(data->regmap, VEML6031X00_REG_WH_L, + ®, sizeof(reg)); + else + ret =3D regmap_bulk_read(data->regmap, VEML6031X00_REG_WL_L, + ®, sizeof(reg)); + if (ret) + return ret; + + *val =3D le16_to_cpu(reg); + + return IIO_VAL_INT; +} + +static int veml6031x00_write_th(struct iio_dev *iio, int val, int val2, in= t dir) +{ + struct veml6031x00_data *data =3D iio_priv(iio); + struct device *dev =3D data->dev; + __le16 reg =3D cpu_to_le16(val); + int ret; + + if (val < 0 || val > U16_MAX || val2) + return -EINVAL; + + if (dir =3D=3D IIO_EV_DIR_RISING) { + ret =3D regmap_bulk_write(data->regmap, VEML6031X00_REG_WH_L, + ®, sizeof(reg)); + if (ret) + dev_dbg(dev, "Failed to set high threshold %d\n", ret); + } else { + ret =3D regmap_bulk_write(data->regmap, VEML6031X00_REG_WL_L, + ®, sizeof(reg)); + if (ret) + dev_dbg(dev, "Failed to set low threshold %d\n", ret); + } + + return ret; +} + static int veml6031x00_single_read(struct iio_dev *iio, enum iio_chan_type= type, int *val) { @@ -493,13 +646,189 @@ static int veml6031x00_write_raw_get_fmt(struct iio_= dev *indio_dev, } } =20 +static int veml6031x00_set_interrupt(struct veml6031x00_data *data, bool s= tate) + __must_hold(&data->irq_lock) +{ + int ret; + + if (state) { + data->int_users++; + if (data->int_users > 1) + return 0; + } else { + data->int_users--; + if (data->int_users > 0) + return 0; + } + + ret =3D regmap_field_write(data->rf.int_en, state); + if (ret) { + if (state) + data->int_users--; + else + data->int_users++; + } + + return ret; +} + +static int veml6031x00_read_event_val(struct iio_dev *iio, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + switch (type) { + case IIO_EV_TYPE_THRESH: + if (dir =3D=3D IIO_EV_DIR_EITHER && info =3D=3D IIO_EV_INFO_PERIOD) + return veml6031x00_read_period(iio, val); + + return veml6031x00_read_th(iio, val, val2, dir); + default: + return -EINVAL; + } +} + +static int veml6031x00_write_event_val(struct iio_dev *iio, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + switch (info) { + case IIO_EV_INFO_VALUE: + return veml6031x00_write_th(iio, val, val2, dir); + case IIO_EV_INFO_PERIOD: + return veml6031x00_write_period(iio, val); + default: + return -EINVAL; + } +} + +static int veml6031x00_read_event_config(struct iio_dev *iio, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct veml6031x00_data *data =3D iio_priv(iio); + + guard(mutex)(&data->irq_lock); + + return data->ev_en; +} + +static int veml6031x00_write_event_config(struct iio_dev *iio, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + bool state) +{ + struct veml6031x00_data *data =3D iio_priv(iio); + int ret; + + guard(mutex)(&data->irq_lock); + + /* avoid multiple increments/decrements from one source */ + if (state =3D=3D data->ev_en) + return 0; + + if (state) { + ret =3D pm_runtime_resume_and_get(data->dev); + if (ret) + return ret; + } + + ret =3D veml6031x00_set_interrupt(data, state); + if (ret) { + if (state) + pm_runtime_put_autosuspend(data->dev); + return ret; + } + + data->ev_en =3D state; + + if (!state) + pm_runtime_put_autosuspend(data->dev); + + return 0; +} + static const struct iio_info veml6031x00_info =3D { .read_raw =3D veml6031x00_read_raw, .read_avail =3D veml6031x00_read_avail, .write_raw =3D veml6031x00_write_raw, .write_raw_get_fmt =3D veml6031x00_write_raw_get_fmt, + .read_event_value =3D veml6031x00_read_event_val, + .write_event_value =3D veml6031x00_write_event_val, + .read_event_config =3D veml6031x00_read_event_config, + .write_event_config =3D veml6031x00_write_event_config, + .event_attrs =3D &veml6031x00_event_attr_group, +}; + +static const struct iio_info veml6031x00_info_no_irq =3D { + .read_raw =3D veml6031x00_read_raw, + .read_avail =3D veml6031x00_read_avail, + .write_raw =3D veml6031x00_write_raw, + .write_raw_get_fmt =3D veml6031x00_write_raw_get_fmt, }; =20 +/* AF_TRIG is reset by hardware, but the rest of the fields are persistent= */ +static int veml6031x00_set_af_trig(struct veml6031x00_data *data, bool sta= te) +{ + regcache_drop_region(data->regmap, VEML6031X00_REG_CONF0, + VEML6031X00_REG_CONF0); + + return regmap_update_bits(data->regmap, VEML6031X00_REG_CONF0, + VEML6031X00_CONF0_AF_TRIG, + FIELD_PREP(VEML6031X00_CONF0_AF_TRIG, state)); +} + +static irqreturn_t veml6031x00_interrupt(int irq, void *private) +{ + struct iio_dev *iio =3D private; + struct veml6031x00_data *data =3D iio_priv(iio); + s64 timestamp; + int ret, reg; + + ret =3D regmap_read(data->regmap, VEML6031X00_REG_INT, ®); + if (ret) { + dev_err(data->dev, + "Failed to read interrupt register %d\n", ret); + return IRQ_NONE; + } + + if (!(reg & VEML6031X00_INT_MASK)) + return IRQ_NONE; + + guard(mutex)(&data->irq_lock); + + if ((reg & (VEML6031X00_INT_TH_H | VEML6031X00_INT_TH_L)) && data->ev_en)= { + timestamp =3D iio_get_time_ns(iio); + + if (reg & VEML6031X00_INT_TH_H) + iio_push_event(iio, IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + timestamp); + if (reg & VEML6031X00_INT_TH_L) + iio_push_event(iio, IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + timestamp); + } + + if ((reg & VEML6031X00_INT_DRDY) && data->trig_en) { + iio_trigger_poll_nested(data->trig); + ret =3D veml6031x00_set_af_trig(data, true); + if (ret) + dev_err(data->dev, "Failed to set trigger %d\n", ret); + } + + return IRQ_HANDLED; +} + static int veml6031x00_buffer_preenable(struct iio_dev *iio) { struct veml6031x00_data *data =3D iio_priv(iio); @@ -534,11 +863,54 @@ static int veml6031x00_buffer_postdisable(struct iio_= dev *iio) return 0; } =20 +static int veml6031x00_set_trigger_state(struct iio_trigger *trig, bool st= ate) +{ + struct iio_dev *iio =3D iio_trigger_get_drvdata(trig); + struct veml6031x00_data *data =3D iio_priv(iio); + int ret; + + guard(mutex)(&data->irq_lock); + + if (state =3D=3D data->trig_en) + return 0; + + ret =3D veml6031x00_set_interrupt(data, state); + if (ret) + return ret; + + /* The AF bit must be set before setting AF_TRIG */ + ret =3D regmap_update_bits(data->regmap, VEML6031X00_REG_CONF0, + VEML6031X00_CONF0_AF, + FIELD_PREP(VEML6031X00_CONF0_AF, state)); + if (ret) + goto err_disable_interrupt; + + ret =3D veml6031x00_set_af_trig(data, state); + if (ret) + goto err_clear_af; + + data->trig_en =3D state; + + return 0; + +err_clear_af: + regmap_update_bits(data->regmap, VEML6031X00_REG_CONF0, + VEML6031X00_CONF0_AF, + FIELD_PREP(VEML6031X00_CONF0_AF, !state)); +err_disable_interrupt: + veml6031x00_set_interrupt(data, !state); + return ret; +} + static const struct iio_buffer_setup_ops veml6031x00_buffer_setup_ops =3D { .preenable =3D veml6031x00_buffer_preenable, .postdisable =3D veml6031x00_buffer_postdisable, }; =20 +static const struct iio_trigger_ops veml6031x00_trigger_ops =3D { + .set_trigger_state =3D veml6031x00_set_trigger_state, +}; + static irqreturn_t veml6031x00_trig_handler(int irq, void *p) { struct iio_poll_func *pf =3D p; @@ -597,7 +969,8 @@ static int veml6031x00_hw_init(struct iio_dev *iio) { struct veml6031x00_data *data =3D iio_priv(iio); struct device *dev =3D data->dev; - int ret; + int ret, val; + __le16 reg; =20 /* Max resolution =3D 6.9632 lx/cnt for gain =3D 0.125 and IT =3D 3.125ms= */ ret =3D devm_iio_init_iio_gts(dev, 6, 963200000, @@ -609,6 +982,54 @@ static int veml6031x00_hw_init(struct iio_dev *iio) if (ret) return dev_err_probe(dev, ret, "failed to init iio gts\n"); =20 + reg =3D 0; + ret =3D regmap_bulk_write(data->regmap, VEML6031X00_REG_WL_L, ®, sizeo= f(reg)); + if (ret) + return dev_err_probe(dev, ret, "Failed to set low threshold\n"); + + reg =3D cpu_to_le16(U16_MAX); + ret =3D regmap_bulk_write(data->regmap, VEML6031X00_REG_WH_L, ®, sizeo= f(reg)); + if (ret) + return dev_err_probe(dev, ret, "Failed to set high threshold\n"); + + ret =3D regmap_field_write(data->rf.int_en, 0); + if (ret) + return ret; + + ret =3D regmap_read(data->regmap, VEML6031X00_REG_INT, &val); + if (ret) + return dev_err_probe(dev, ret, "Failed to clear interrupts\n"); + + return 0; +} + +static int veml6031x00_setup_irq(struct i2c_client *i2c, struct iio_dev *i= io) +{ + struct veml6031x00_data *data =3D iio_priv(iio); + struct device *dev =3D data->dev; + int ret; + + data->trig =3D devm_iio_trigger_alloc(dev, "%s-drdy%d", iio->name, + iio_device_id(iio)); + if (!data->trig) + return -ENOMEM; + + data->trig->ops =3D &veml6031x00_trigger_ops; + iio_trigger_set_drvdata(data->trig, iio); + + ret =3D devm_iio_trigger_register(dev, data->trig); + if (ret) + return ret; + + iio->trig =3D iio_trigger_get(data->trig); + ret =3D devm_request_threaded_irq(dev, i2c->irq, NULL, + veml6031x00_interrupt, + IRQF_ONESHOT, + iio->name, iio); + if (ret) + return dev_err_probe(dev, ret, "Failed to request irq %d\n", + i2c->irq); + return 0; } =20 @@ -638,6 +1059,10 @@ static int veml6031x00_probe(struct i2c_client *i2c) if (ret) return ret; =20 + ret =3D devm_mutex_init(dev, &data->irq_lock); + if (ret) + return ret; + ret =3D veml6031x00_regfield_init(data); if (ret) return dev_err_probe(dev, ret, "Failed to init regfield\n"); @@ -677,12 +1102,21 @@ static int veml6031x00_probe(struct i2c_client *i2c) iio->channels =3D veml6031x00_channels; iio->num_channels =3D ARRAY_SIZE(veml6031x00_channels); iio->modes =3D INDIO_DIRECT_MODE; - iio->info =3D &veml6031x00_info; =20 ret =3D veml6031x00_hw_init(iio); if (ret) return ret; =20 + if (i2c->irq) { + ret =3D veml6031x00_setup_irq(i2c, iio); + if (ret) + return ret; + + iio->info =3D &veml6031x00_info; + } else { + iio->info =3D &veml6031x00_info_no_irq; + } + ret =3D devm_iio_triggered_buffer_setup(dev, iio, NULL, veml6031x00_trig_handler, &veml6031x00_buffer_setup_ops); --=20 2.43.0