From nobody Mon Jun 15 10:50:32 2026 Received: from mail-43101.protonmail.ch (mail-43101.protonmail.ch [185.70.43.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3995C2192FA for ; Thu, 9 Apr 2026 21:07:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.70.43.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775768847; cv=none; b=Ep4jDZxhujjWAyIXGrKnctNLiQgcTu74uQkVoqI6mRiapE/8LSNPfuky87/9ModxCtcVK/g/yFW4LEAJBl5nB9Fxdc280gM/zUjKJwhJ2+1unvSy+8OT24qgDd9kslYZ9r43QKJLEhEw66lOUNgNPFt8MTKYBWsJohUTza2CPCY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775768847; c=relaxed/simple; bh=rt69GKfvtm6r7L6ZdS0LmDtC2CKxY+kKDxYTToslLME=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=gL2SmcJunkCMHKf9bSAM/MmEK2XqMRQGrxI5ssat4UOOXJH6H4eqKuePw3Of0noT8XFT0Ug8wCMn+Uy/Agc81a+WJEWnmyZnfRAZBMC96zVtcWxnPV3dFoGA6Ar1S0Zq2N+ax9ewUXDvQgNRmwnYV82RpDE29l2cHkHzeyKC6M4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me; spf=pass smtp.mailfrom=pm.me; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b=h34GJ/ag; arc=none smtp.client-ip=185.70.43.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pm.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b="h34GJ/ag" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1775768844; x=1776028044; bh=W/g6MIBZ3+LHjZsDhg8NMVRAvD8105CPrmbxQAoiqUo=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=h34GJ/agGB0xDWzm/czd6f8cAs04Q5MlsvFAj419lIdFreINTKwOb6b+PjuOso4l0 OPS1dV9loKZME+/oPX1mM4zwNuvAiEyIT3+o+5C/mYSI9IBjkVSEJVZ/uI7174CDqd 6JHmEWGiLEqTtitdNpf++hi+7xgLpcdJC9/HTqQWK5BeO4os8jAbzEU+LZV8KmQxaB R6RnVDxvXb8lioq/7xPExeATIw5WCv4Er5WGzfh5wy+EqlrjVtjVfQN0ZA1gkuo+BA 3asb/XqS45JifNMLKxbd9EZs4hVDbLA4PP1kidYW/b/NxISb8NYIVrRRhVmIcFvhLw AW8vbx2O+Bhgw== Date: Thu, 09 Apr 2026 21:07:20 +0000 To: Greg Kroah-Hartman From: Hardik Phalet Cc: Jonathan Cameron , David Lechner , =?utf-8?Q?Nuno_S=C3=A1?= , Andy Shevchenko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Brigham Campbell , Shuah Khan , linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-staging@lists.linux.dev, Hardik Phalet Subject: [PATCH v2 1/4] dt-bindings: vendor-prefixes: Add QST Corporation Message-ID: <20260409210639.3197576-2-hardik.phalet@pm.me> In-Reply-To: <20260409210639.3197576-1-hardik.phalet@pm.me> References: <20260409210639.3197576-1-hardik.phalet@pm.me> Feedback-ID: 166659585:user:proton X-Pm-Message-ID: beca96a4de86b48d45a58fc9a7c37bd18ddf8222 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add the vendor prefix 'qst' for QST Corporation, a manufacturer of MEMS sensors. Signed-off-by: Hardik Phalet --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Docum= entation/devicetree/bindings/vendor-prefixes.yaml index 5d2a7a8d3ac6..71a1b9087c5e 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1244,6 +1244,8 @@ patternProperties: description: Shenzhen QiShenglong Industrialist Co., Ltd. "^qnap,.*": description: QNAP Systems, Inc. + "^qst,.*": + description: QST Corporation "^quanta,.*": description: Quanta Computer Inc. "^radxa,.*": --=20 2.53.0 From nobody Mon Jun 15 10:50:32 2026 Received: from mail-24418.protonmail.ch (mail-24418.protonmail.ch [109.224.244.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1418D371041 for ; Thu, 9 Apr 2026 21:07:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=109.224.244.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775768863; cv=none; b=VttmOrrpoWZKNjNcJkDhNf2qimvK0zhtz6vRcBaEPK0NCg0wApv4GxAUeW8+ZqGmYJPPaBgi5VmYCIeOOxzqI0XxzAJ256kAP16jaxAY9oZwI6QniUF/zvHl7U18OHK5YbKHlMJ5hDgrVfM8zSDAsdNA17e6XrM3By8ME9nJyv4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775768863; c=relaxed/simple; bh=FHqavf4x2LMnpKhwYIAJLhWWLpu5loE7rr7KuHjSJBs=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=H7D/VoX+GMcpijeVdyUccgUX8iiS7hdX7LmAwDBHwRxJXiH9ocOzDhca3G++TAVHksXaUEWArebtaxBlPhTOLjRcvNyJd6yrSCTfMCe+mrZvuDld8RNV5NWnFApMyLBLlkrWwdwuwXfEt7zptO9vZQ3D+OOxCg2EUqANJN6qupA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me; spf=pass smtp.mailfrom=pm.me; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b=auxNQoh/; arc=none smtp.client-ip=109.224.244.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pm.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b="auxNQoh/" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1775768854; x=1776028054; bh=MyqNqpuNtgV8td1byNhhPh0LwJSSFfPtn7H4KgGMCEY=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=auxNQoh/uBTonceBUuk8CdJFlCAkA7AnpFM1XQY7szCy8e/jSo6R++1WxPrfNBo16 IqSNlXv4GFcthHUQHX0nxnEiaw6JUWIRJXdQq0qO8jtlTY58girsltjPIGfzPpfewK 4ZWD67P6rqAPUjwNdySIOPbcW406CjGpMoX1VxMbchfkqyFiIHNj1gTe3OLa7vU46O cm6hDeguARvmb/3X0io6OInS0ge5ofpcszcJh5eG8ibe1ZtYpZjLWLNhvbgItRcWbI 08Pwyp7XaNWiGUeLYDHYtGjQWqaD0KEsNlcbLYmhv9TD8a8/WJDrr2bmLEfCnNVnSi Qgzw7pw30pkhA== Date: Thu, 09 Apr 2026 21:07:29 +0000 To: Greg Kroah-Hartman From: Hardik Phalet Cc: Jonathan Cameron , David Lechner , =?utf-8?Q?Nuno_S=C3=A1?= , Andy Shevchenko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Brigham Campbell , Shuah Khan , linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-staging@lists.linux.dev, Hardik Phalet Subject: [PATCH v2 2/4] dt-bindings: iio: magnetometer: Add binding for QST QMC5883P Message-ID: <20260409210639.3197576-3-hardik.phalet@pm.me> In-Reply-To: <20260409210639.3197576-1-hardik.phalet@pm.me> References: <20260409210639.3197576-1-hardik.phalet@pm.me> Feedback-ID: 166659585:user:proton X-Pm-Message-ID: 5065cdeae2b26d039d2a18d77f5426de938a9714 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add the device tree binding document for the QST QMC5883P, a 3-axis anisotropic magneto-resistive (AMR) sensor with a 16-bit ADC that communicates over I2C. The binding exposes the required 'compatible' and 'reg' properties along with an optional 'vdd-supply' for the 2.5 V=E2=80=933.6 V VDD rail. Signed-off-by: Hardik Phalet --- .../iio/magnetometer/qst,qmc5883p.yaml | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/magnetometer/qst,= qmc5883p.yaml diff --git a/Documentation/devicetree/bindings/iio/magnetometer/qst,qmc5883= p.yaml b/Documentation/devicetree/bindings/iio/magnetometer/qst,qmc5883p.ya= ml new file mode 100644 index 000000000000..84fec10d8b9a --- /dev/null +++ b/Documentation/devicetree/bindings/iio/magnetometer/qst,qmc5883p.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/magnetometer/qst,qmc5883p.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: QST QMC5883P 3-axis magnetometer + +maintainers: + - Hardik Phalet + +description: + The QMC5883P is a 3-axis anisotropic magneto-resistive (AMR) sensor with= a + 16-bit ADC. It communicates over I2C (standard and fast modes) and is + targeted at compass, navigation, and industrial applications. + +properties: + compatible: + const: qst,qmc5883p + + reg: + maxItems: 1 + description: I2C address of the device; the default address is 0x2c. + + vdd-supply: + description: + VDD power supply (2.5 V to 3.6 V). Powers all internal analog and + digital functional blocks. + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells =3D <1>; + #size-cells =3D <0>; + + magnetometer@2c { + compatible =3D "qst,qmc5883p"; + reg =3D <0x2c>; + vdd-supply =3D <&vdd_3v3>; + }; + }; +... --=20 2.53.0 From nobody Mon Jun 15 10:50:32 2026 Received: from mail-43103.protonmail.ch (mail-43103.protonmail.ch [185.70.43.103]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EAD36341AB1; Thu, 9 Apr 2026 21:07:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.70.43.103 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775768871; cv=none; b=QESmwLp6obFuXTm49e/DkoGVOQWHq+fhyxskjuyBuHEoazLG5zcqTvO8/mmu+TOjqbxm/zPeRhI2CuNgNtQY8NDj91PWKFkMdaml1cWoCK1UZ5HOSrZfhNg+4e7A4opaHWdJrZmn7M9s47IZOKY9bPn/wqH4SEYDdKtcE8AJpY8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775768871; c=relaxed/simple; bh=smeFTeg6UDKD9sJeBUokxORsOHwbjwTQM+7pvIGzx4k=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=CQqfWNfBZr+qhXeY0cpPfokIhoLUN8DvocNg4jvq70WA5gcHoGXO7QHTtunM/6vE+J6yzKz3E7ULgn7T8mkvWWcM3R+AoZvJKn+n6une3pAGYdfZSa6hGOEDW2AYaAFAXH9J0qTK3rha0DaOq2qzKF+U8ItjI2O+kv8E5uCawqM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me; spf=pass smtp.mailfrom=pm.me; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b=WaV8qlso; arc=none smtp.client-ip=185.70.43.103 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pm.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b="WaV8qlso" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1775768866; x=1776028066; bh=0e2OgVt4C/HAaVjgDJdLXacFCTp9hC+UxtTT13WvKFs=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=WaV8qlso76Q0o09868r9UrdkbAkRfjdjvnAFcrR+7XdVhBQo9OS00+CggNKk/Kn02 zUUFFW9Rj0QW+fKVkjrwMhcuqBgNuQBtyriDQGncdRMRCid6jF/iT+FbwzJggvqf/R 5onacMQ9HYf1Qo7ZoP+qI7e0Bl+KoaelthBkFv6nKmjpovFB555YXniZlQ5Jz+hVed nt2Vw03JHznC3dAAOlJE9fUL+U4i4fOqiIxn7sSqm8XBUJxOKb1nTbIg/PgLUHoElD XSAALk6QM7i8G9MBG1xhpvoMLiMMwjC3DeiGvEmiFsUSDO4QUZue1GSEv2K2+AUQuK e+9+6Xl9c8Oxg== Date: Thu, 09 Apr 2026 21:07:41 +0000 To: Greg Kroah-Hartman From: Hardik Phalet Cc: Jonathan Cameron , David Lechner , =?utf-8?Q?Nuno_S=C3=A1?= , Andy Shevchenko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Brigham Campbell , Shuah Khan , linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-staging@lists.linux.dev, Hardik Phalet Subject: [PATCH v2 3/4] staging: iio: magnetometer: Add QST QMC5883P driver Message-ID: <20260409210639.3197576-4-hardik.phalet@pm.me> In-Reply-To: <20260409210639.3197576-1-hardik.phalet@pm.me> References: <20260409210639.3197576-1-hardik.phalet@pm.me> Feedback-ID: 166659585:user:proton X-Pm-Message-ID: d57d62253e94bf7aa837ffbd43ea609fe5c31026 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add an IIO driver for the QST QMC5883P, a 3-axis anisotropic magneto-resistive (AMR) magnetometer with a 16-bit ADC, communicating over I2C. There is no existing upstream driver for this device. The driver supports: - Raw magnetic field readings on X, Y, and Z axes - Four full-scale ranges (+/-2 G, +/-8 G, +/-12 G, +/-30 G) - Configurable output data rate (10, 50, 100, 200 Hz) - Configurable oversampling ratio (1, 2, 4, 8) - Configurable downsampling ratio (1, 2, 4, 8) via a custom sysfs attribute - Optional vdd-supply regulator management - Runtime PM with a 2 s autosuspend delay - System suspend/resume with full chip reinitialisation and regmap cache resync to handle regulator power-loss Regmap with an rbtree cache is used throughout. CTRL_1 and CTRL_2 bit fields are accessed via regmap_field to avoid read-modify-write races. The STATUS register is marked precious so regmap never reads it speculatively and clears the DRDY/OVFL bits unexpectedly. The probe-time init sequence is: soft reset, wait 1 ms, deassert reset, configure SET/RESET control, apply default ODR/OSR/DSR/RNG, enter normal mode. This ordering was determined empirically on hardware to produce reliable, non-zero axis readings. Cleanup is fully devm-managed: devm_pm_runtime_enable() handles runtime PM teardown, and a devm action registered before devm_iio_device_register() puts the chip to sleep on removal, ensuring the IIO interface is unregistered before the hardware is suspended. The driver is placed under drivers/staging/iio/magnetometer/ with a TODO file tracking the remaining work before it can graduate: - Triggered buffer support (iio_triggered_buffer_setup) - DRDY interrupt support - Self-test implementation Signed-off-by: Hardik Phalet --- drivers/staging/iio/Kconfig | 1 + drivers/staging/iio/Makefile | 1 + drivers/staging/iio/magnetometer/Kconfig | 20 + drivers/staging/iio/magnetometer/Makefile | 7 + drivers/staging/iio/magnetometer/TODO | 5 + drivers/staging/iio/magnetometer/qmc5883p.c | 830 ++++++++++++++++++++ 6 files changed, 864 insertions(+) create mode 100644 drivers/staging/iio/magnetometer/Kconfig create mode 100644 drivers/staging/iio/magnetometer/Makefile create mode 100644 drivers/staging/iio/magnetometer/TODO create mode 100644 drivers/staging/iio/magnetometer/qmc5883p.c diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index a60631c1f449..d363e163d248 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -10,5 +10,6 @@ source "drivers/staging/iio/adc/Kconfig" source "drivers/staging/iio/addac/Kconfig" source "drivers/staging/iio/frequency/Kconfig" source "drivers/staging/iio/impedance-analyzer/Kconfig" +source "drivers/staging/iio/magnetometer/Kconfig" =20 endmenu diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile index 628583535393..7dcbb75d43f0 100644 --- a/drivers/staging/iio/Makefile +++ b/drivers/staging/iio/Makefile @@ -8,3 +8,4 @@ obj-y +=3D adc/ obj-y +=3D addac/ obj-y +=3D frequency/ obj-y +=3D impedance-analyzer/ +obj-y +=3D magnetometer/ diff --git a/drivers/staging/iio/magnetometer/Kconfig b/drivers/staging/iio= /magnetometer/Kconfig new file mode 100644 index 000000000000..d631da9578a1 --- /dev/null +++ b/drivers/staging/iio/magnetometer/Kconfig @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Magnetometer sensors +# +# When adding new entries keep the list in alphabetical order + +menu "Magnetometer sensors" + +config QMC5883P + tristate "QMC5883P 3-Axis Magnetometer" + depends on I2C + select REGMAP_I2C + help + Say yes here to build support for QMC5883P I2C-based + 3-axis magnetometer chip. + + To compile this driver as a module, choose M here: the + module will be called qmc5883p. + +endmenu diff --git a/drivers/staging/iio/magnetometer/Makefile b/drivers/staging/ii= o/magnetometer/Makefile new file mode 100644 index 000000000000..8e650f2e3b02 --- /dev/null +++ b/drivers/staging/iio/magnetometer/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for staging industrial I/O Magnetometer sensor devices +# +# When adding new entries keep the list in alphabetical order + +obj-$(CONFIG_QMC5883P) +=3D qmc5883p.o diff --git a/drivers/staging/iio/magnetometer/TODO b/drivers/staging/iio/ma= gnetometer/TODO new file mode 100644 index 000000000000..6a8084c0dded --- /dev/null +++ b/drivers/staging/iio/magnetometer/TODO @@ -0,0 +1,5 @@ +TODO +=3D=3D=3D=3D +- Implement triggered buffer support (iio_triggered_buffer_setup) +- Add interrupt (DRDY) support +- Implement self-test (selftest regmap field is unused) diff --git a/drivers/staging/iio/magnetometer/qmc5883p.c b/drivers/staging/= iio/magnetometer/qmc5883p.c new file mode 100644 index 000000000000..d9758f1e0f4d --- /dev/null +++ b/drivers/staging/iio/magnetometer/qmc5883p.c @@ -0,0 +1,830 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * qmc5883p.c - QMC5883P magnetometer driver + * + * Copyright 2026 Hardik Phalet + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register definition */ +#define QMC5883P_REG_CHIP_ID 0x00 +#define QMC5883P_REG_X_LSB 0x01 +#define QMC5883P_REG_X_MSB 0x02 +#define QMC5883P_REG_Y_LSB 0x03 +#define QMC5883P_REG_Y_MSB 0x04 +#define QMC5883P_REG_Z_LSB 0x05 +#define QMC5883P_REG_Z_MSB 0x06 +#define QMC5883P_REG_STATUS 0x09 +#define QMC5883P_REG_CTRL_1 0x0A +#define QMC5883P_REG_CTRL_2 0x0B + +/* Value definition */ +#define QMC5883P_MODE_SUSPEND 0x00 +#define QMC5883P_MODE_NORMAL 0x01 +#define QMC5883P_MODE_SINGLE 0x02 +#define QMC5883P_MODE_CONTINUOUS 0x03 + +/* Output data rate */ +#define QMC5883P_ODR_10 0x00 +#define QMC5883P_ODR_50 0x01 +#define QMC5883P_ODR_100 0x02 +#define QMC5883P_ODR_200 0x03 + +/* Oversampling rate */ +#define QMC5883P_OSR_8 0x00 +#define QMC5883P_OSR_4 0x01 +#define QMC5883P_OSR_2 0x02 +#define QMC5883P_OSR_1 0x03 + +/* Downsampling rate */ +#define QMC5883P_DSR_1 0x00 +#define QMC5883P_DSR_2 0x01 +#define QMC5883P_DSR_4 0x02 +#define QMC5883P_DSR_8 0x03 + +#define QMC5883P_RSTCTRL_SET_RESET \ + 0x00 /* Set and reset on, i.e. the offset of device is renewed */ +#define QMC5883P_RSTCTRL_SET_ONLY 0x01 /* Set only on */ +#define QMC5883P_RSTCTRL_OFF 0x02 /* Set and reset off */ + +#define QMC5883P_RNG_30G 0x00 +#define QMC5883P_RNG_12G 0x01 +#define QMC5883P_RNG_08G 0x02 +#define QMC5883P_RNG_02G 0x03 + +#define QMC5883P_DEFAULT_ODR QMC5883P_ODR_100 +#define QMC5883P_DEFAULT_OSR QMC5883P_OSR_4 +#define QMC5883P_DEFAULT_DSR QMC5883P_DSR_4 +#define QMC5883P_DEFAULT_RNG QMC5883P_RNG_08G + +#define QMC5883P_DRDY_POLL_US 1000 + +#define QMC5883P_CHIP_ID 0x80 + +#define QMC5883P_STATUS_DRDY BIT(0) +#define QMC5883P_STATUS_OVFL BIT(1) + +/* + * Scale factors in T/LSB for IIO_VAL_FRACTIONAL (val/val2), derived from + * datasheet Table 2 sensitivities (LSB/G) converted to LSB/T (1 G =3D 1e-= 4 T): + * sensitivity_T =3D sensitivity_G * 10000 + * scale =3D 1 / sensitivity_T + * + * Index matches register value: RNG<1:0> =3D 0b00..0b11 + */ +static const int qmc5883p_scale[][2] =3D { + [QMC5883P_RNG_30G] =3D { 1, 10000000 }, + [QMC5883P_RNG_12G] =3D { 1, 25000000 }, + [QMC5883P_RNG_08G] =3D { 1, 37500000 }, + [QMC5883P_RNG_02G] =3D { 1, 150000000 }, +}; + +static const int qmc5883p_odr[] =3D { + [QMC5883P_ODR_10] =3D 10, + [QMC5883P_ODR_50] =3D 50, + [QMC5883P_ODR_100] =3D 100, + [QMC5883P_ODR_200] =3D 200, +}; + +static const int qmc5883p_osr[] =3D { + [QMC5883P_OSR_1] =3D 1, + [QMC5883P_OSR_2] =3D 2, + [QMC5883P_OSR_4] =3D 4, + [QMC5883P_OSR_8] =3D 8, +}; + +static const unsigned int qmc5883p_dsr[] =3D { + [QMC5883P_DSR_1] =3D 1, + [QMC5883P_DSR_2] =3D 2, + [QMC5883P_DSR_4] =3D 4, + [QMC5883P_DSR_8] =3D 8, +}; + +struct qmc5883p_rf { + struct regmap_field *osr; + struct regmap_field *dsr; + struct regmap_field *odr; + struct regmap_field *mode; + struct regmap_field *rng; + struct regmap_field *rstctrl; + struct regmap_field *sftrst; + struct regmap_field *selftest; + struct regmap_field *chip_id; +}; + +static const struct regmap_range qmc5883p_readable_ranges[] =3D { + regmap_reg_range(QMC5883P_REG_CHIP_ID, QMC5883P_REG_STATUS), + regmap_reg_range(QMC5883P_REG_CTRL_1, QMC5883P_REG_CTRL_2), +}; + +static const struct regmap_range qmc5883p_writable_ranges[] =3D { + regmap_reg_range(QMC5883P_REG_CTRL_1, QMC5883P_REG_CTRL_2), +}; + +/* + * Volatile registers: hardware updates these independently of the driver. + * regmap will never serve these from cache. + */ +static const struct regmap_range qmc5883p_volatile_ranges[] =3D { + regmap_reg_range(QMC5883P_REG_X_LSB, QMC5883P_REG_Z_MSB), + regmap_reg_range(QMC5883P_REG_STATUS, QMC5883P_REG_STATUS), +}; + +/* + * Precious registers: reading has a side effect (clears DRDY/OVFL bits). + * regmap will never read these speculatively. + */ +static const struct regmap_range qmc5883p_precious_ranges[] =3D { + regmap_reg_range(QMC5883P_REG_STATUS, QMC5883P_REG_STATUS), +}; + +static const struct regmap_access_table qmc5883p_readable_table =3D { + .yes_ranges =3D qmc5883p_readable_ranges, + .n_yes_ranges =3D ARRAY_SIZE(qmc5883p_readable_ranges), +}; + +static const struct regmap_access_table qmc5883p_writable_table =3D { + .yes_ranges =3D qmc5883p_writable_ranges, + .n_yes_ranges =3D ARRAY_SIZE(qmc5883p_writable_ranges), +}; + +static const struct regmap_access_table qmc5883p_volatile_table =3D { + .yes_ranges =3D qmc5883p_volatile_ranges, + .n_yes_ranges =3D ARRAY_SIZE(qmc5883p_volatile_ranges), +}; + +static const struct regmap_access_table qmc5883p_precious_table =3D { + .yes_ranges =3D qmc5883p_precious_ranges, + .n_yes_ranges =3D ARRAY_SIZE(qmc5883p_precious_ranges), +}; + +static const struct regmap_config qmc5883p_regmap_config =3D { + .reg_bits =3D 8, + .val_bits =3D 8, + .max_register =3D 0x0B, + .cache_type =3D REGCACHE_RBTREE, + .rd_table =3D &qmc5883p_readable_table, + .wr_table =3D &qmc5883p_writable_table, + .volatile_table =3D &qmc5883p_volatile_table, + .precious_table =3D &qmc5883p_precious_table, +}; + +struct qmc5883p_data { + struct device *dev; + struct regmap *regmap; + struct mutex mutex; /* protects regmap and rf field accesses */ + struct qmc5883p_rf rf; +}; + +enum qmc5883p_channels { + AXIS_X =3D 0, + AXIS_Y, + AXIS_Z, +}; + +static const struct reg_field qmc5883p_rf_osr =3D + REG_FIELD(QMC5883P_REG_CTRL_1, 4, 5); +static const struct reg_field qmc5883p_rf_dsr =3D + REG_FIELD(QMC5883P_REG_CTRL_1, 6, 7); +static const struct reg_field qmc5883p_rf_odr =3D + REG_FIELD(QMC5883P_REG_CTRL_1, 2, 3); +static const struct reg_field qmc5883p_rf_mode =3D + REG_FIELD(QMC5883P_REG_CTRL_1, 0, 1); +static const struct reg_field qmc5883p_rf_rng =3D + REG_FIELD(QMC5883P_REG_CTRL_2, 2, 3); +static const struct reg_field qmc5883p_rf_rstctrl =3D + REG_FIELD(QMC5883P_REG_CTRL_2, 0, 1); +static const struct reg_field qmc5883p_rf_sftrst =3D + REG_FIELD(QMC5883P_REG_CTRL_2, 7, 7); +static const struct reg_field qmc5883p_rf_selftest =3D + REG_FIELD(QMC5883P_REG_CTRL_2, 6, 6); +static const struct reg_field qmc5883p_rf_chip_id =3D + REG_FIELD(QMC5883P_REG_CHIP_ID, 0, 7); + +static int qmc5883p_rf_init(struct qmc5883p_data *data) +{ + struct regmap *regmap =3D data->regmap; + struct device *dev =3D data->dev; + struct qmc5883p_rf *rf =3D &data->rf; + + rf->osr =3D devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_osr); + if (IS_ERR(rf->osr)) + return PTR_ERR(rf->osr); + + rf->dsr =3D devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_dsr); + if (IS_ERR(rf->dsr)) + return PTR_ERR(rf->dsr); + + rf->odr =3D devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_odr); + if (IS_ERR(rf->odr)) + return PTR_ERR(rf->odr); + + rf->mode =3D devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_mode); + if (IS_ERR(rf->mode)) + return PTR_ERR(rf->mode); + + rf->rng =3D devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_rng); + if (IS_ERR(rf->rng)) + return PTR_ERR(rf->rng); + + rf->rstctrl =3D devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_rstctrl); + if (IS_ERR(rf->rstctrl)) + return PTR_ERR(rf->rstctrl); + + rf->sftrst =3D devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_sftrst); + if (IS_ERR(rf->sftrst)) + return PTR_ERR(rf->sftrst); + + rf->selftest =3D + devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_selftest); + if (IS_ERR(rf->selftest)) + return PTR_ERR(rf->selftest); + + rf->chip_id =3D devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_chip_id); + if (IS_ERR(rf->chip_id)) + return PTR_ERR(rf->chip_id); + + return 0; +} + +static int qmc5883p_verify_chip_id(struct qmc5883p_data *data) +{ + int ret, regval; + + ret =3D regmap_field_read(data->rf.chip_id, ®val); + if (ret) + return dev_err_probe(data->dev, ret, + "failed to read chip ID\n"); + + if (regval !=3D QMC5883P_CHIP_ID) + return dev_err_probe(data->dev, -ENODEV, + "unexpected chip ID 0x%02x, expected 0x%02x\n", + regval, QMC5883P_CHIP_ID); + return ret; +} + +static int qmc5883p_chip_init(struct qmc5883p_data *data) +{ + int ret; + + ret =3D regmap_field_write(data->rf.sftrst, 1); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret =3D regmap_field_write(data->rf.sftrst, 0); + if (ret) + return ret; + + ret =3D regmap_field_write(data->rf.rstctrl, QMC5883P_RSTCTRL_SET_RESET); + if (ret) + return ret; + + ret =3D regmap_field_write(data->rf.rng, QMC5883P_DEFAULT_RNG); + if (ret) + return ret; + + ret =3D regmap_field_write(data->rf.osr, QMC5883P_DEFAULT_OSR); + if (ret) + return ret; + + ret =3D regmap_field_write(data->rf.dsr, QMC5883P_DEFAULT_DSR); + if (ret) + return ret; + + ret =3D regmap_field_write(data->rf.odr, QMC5883P_DEFAULT_ODR); + if (ret) + return ret; + + return regmap_field_write(data->rf.mode, QMC5883P_MODE_NORMAL); +} + +/* + * qmc5883p_get_measure - read all three axes. + * Must be called with data->mutex held. + * Handles PM internally: resumes device, reads data, schedules autosuspen= d. + */ +static int qmc5883p_get_measure(struct qmc5883p_data *data, s16 *x, s16 *y, + s16 *z) +{ + int ret; + u8 reg_data[6]; + unsigned int status; + + ret =3D pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; + + /* + * Poll the status register until DRDY is set or timeout. + * Read the whole register in one shot so that OVFL is captured from + * the same read: reading 0x09 clears both DRDY and OVFL, so a second + * read would always see OVFL=3D0. + * At ODR=3D10Hz one period is 100ms; use 150ms as a safe upper bound. + */ + ret =3D regmap_read_poll_timeout(data->regmap, QMC5883P_REG_STATUS, + status, status & QMC5883P_STATUS_DRDY, + QMC5883P_DRDY_POLL_US, 150000); + if (ret) + goto out; + + if (status & QMC5883P_STATUS_OVFL) { + dev_warn_ratelimited(data->dev, + "data overflow, consider reducing field range\n"); + ret =3D -ERANGE; + goto out; + } + + ret =3D regmap_bulk_read(data->regmap, QMC5883P_REG_X_LSB, reg_data, + ARRAY_SIZE(reg_data)); + if (ret) + goto out; + + *x =3D (s16)get_unaligned_le16(®_data[0]); + *y =3D (s16)get_unaligned_le16(®_data[2]); + *z =3D (s16)get_unaligned_le16(®_data[4]); + +out: + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); + return ret; +} + +static int qmc5883p_write_scale(struct qmc5883p_data *data, int val, int v= al2) +{ + int i; + + for (i =3D 0; i < ARRAY_SIZE(qmc5883p_scale); i++) { + if (qmc5883p_scale[i][0] =3D=3D val && qmc5883p_scale[i][1] =3D=3D val2) + return regmap_field_write(data->rf.rng, i); + } + + return -EINVAL; +} + +static int qmc5883p_write_odr(struct qmc5883p_data *data, int val) +{ + int i; + + for (i =3D 0; i < ARRAY_SIZE(qmc5883p_odr); i++) { + if (qmc5883p_odr[i] =3D=3D val) + return regmap_field_write(data->rf.odr, i); + } + + return -EINVAL; +} + +static int qmc5883p_write_osr(struct qmc5883p_data *data, int val) +{ + int i; + + for (i =3D 0; i < ARRAY_SIZE(qmc5883p_osr); i++) { + if (qmc5883p_osr[i] =3D=3D val) + return regmap_field_write(data->rf.osr, i); + } + + return -EINVAL; +} + +static ssize_t downsampling_ratio_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev =3D dev_get_drvdata(dev); + struct qmc5883p_data *data =3D iio_priv(indio_dev); + unsigned int regval; + int ret; + + guard(mutex)(&data->mutex); + + ret =3D regmap_field_read(data->rf.dsr, ®val); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", qmc5883p_dsr[regval]); +} + +static ssize_t downsampling_ratio_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev =3D dev_get_drvdata(dev); + struct qmc5883p_data *data =3D iio_priv(indio_dev); + unsigned int val; + int i, ret, restore; + + ret =3D kstrtouint(buf, 10, &val); + if (ret) + return ret; + + guard(mutex)(&data->mutex); + + ret =3D pm_runtime_resume_and_get(data->dev); + if (ret) + return ret; + + ret =3D regmap_field_write(data->rf.mode, QMC5883P_MODE_SUSPEND); + if (ret) + goto out; + + ret =3D -EINVAL; + for (i =3D 0; i < ARRAY_SIZE(qmc5883p_dsr); i++) { + if (qmc5883p_dsr[i] =3D=3D val) { + ret =3D regmap_field_write(data->rf.dsr, i); + break; + } + } + + restore =3D regmap_field_write(data->rf.mode, QMC5883P_MODE_NORMAL); + if (restore && !ret) + ret =3D restore; + +out: + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); + return ret ? ret : (ssize_t)len; +} + +static int qmc5883p_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int *val, + int *val2, long mask) +{ + s16 x, y, z; + struct qmc5883p_data *data =3D iio_priv(indio_dev); + int ret; + unsigned int regval; + + guard(mutex)(&data->mutex); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret =3D qmc5883p_get_measure(data, &x, &y, &z); + if (ret < 0) + return ret; + switch (chan->address) { + case AXIS_X: + *val =3D x; + break; + case AXIS_Y: + *val =3D y; + break; + case AXIS_Z: + *val =3D z; + break; + } + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + ret =3D regmap_field_read(data->rf.rng, ®val); + if (ret < 0) + return ret; + *val =3D qmc5883p_scale[regval][0]; + *val2 =3D qmc5883p_scale[regval][1]; + return IIO_VAL_FRACTIONAL; + + case IIO_CHAN_INFO_SAMP_FREQ: + ret =3D regmap_field_read(data->rf.odr, ®val); + if (ret < 0) + return ret; + *val =3D qmc5883p_odr[regval]; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + ret =3D regmap_field_read(data->rf.osr, ®val); + if (ret < 0) + return ret; + *val =3D qmc5883p_osr[regval]; + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static int qmc5883p_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct qmc5883p_data *data =3D iio_priv(indio_dev); + int ret, restore; + + guard(mutex)(&data->mutex); + + ret =3D pm_runtime_resume_and_get(data->dev); + if (ret) + return ret; + + ret =3D regmap_field_write(data->rf.mode, QMC5883P_MODE_SUSPEND); + if (ret) + goto out; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + ret =3D qmc5883p_write_odr(data, val); + break; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + ret =3D qmc5883p_write_osr(data, val); + break; + case IIO_CHAN_INFO_SCALE: + ret =3D qmc5883p_write_scale(data, val, val2); + break; + default: + ret =3D -EINVAL; + break; + } + + restore =3D regmap_field_write(data->rf.mode, QMC5883P_MODE_NORMAL); + if (restore && !ret) + ret =3D restore; + +out: + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); + return ret; +} + +/* + * qmc5883p_read_avail - expose available values to userspace. + * + * Creates the _available sysfs attributes automatically: + * in_magn_sampling_frequency_available + * in_magn_oversampling_ratio_available + * in_magn_scale_available + */ +static int qmc5883p_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *vals =3D qmc5883p_odr; + *type =3D IIO_VAL_INT; + *length =3D ARRAY_SIZE(qmc5883p_odr); + return IIO_AVAIL_LIST; + + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *vals =3D qmc5883p_osr; + *type =3D IIO_VAL_INT; + *length =3D ARRAY_SIZE(qmc5883p_osr); + return IIO_AVAIL_LIST; + + case IIO_CHAN_INFO_SCALE: + *vals =3D (const int *)qmc5883p_scale; + *type =3D IIO_VAL_FRACTIONAL; + *length =3D ARRAY_SIZE(qmc5883p_scale) * 2; + return IIO_AVAIL_LIST; + + default: + return -EINVAL; + } +} + +static IIO_DEVICE_ATTR(downsampling_ratio, 0644, downsampling_ratio_show, + downsampling_ratio_store, 0); +static IIO_CONST_ATTR(downsampling_ratio_available, "1 2 4 8"); + +static struct attribute *qmc5883p_attributes[] =3D { + &iio_dev_attr_downsampling_ratio.dev_attr.attr, + &iio_const_attr_downsampling_ratio_available.dev_attr.attr, NULL +}; + +static const struct attribute_group qmc5883p_attribute_group =3D { + .attrs =3D qmc5883p_attributes, +}; + +static const struct iio_info qmc5883p_info =3D { + .attrs =3D &qmc5883p_attribute_group, + .read_raw =3D qmc5883p_read_raw, + .write_raw =3D qmc5883p_write_raw, + .read_avail =3D qmc5883p_read_avail, +}; + +static const struct iio_chan_spec qmc5883p_channels[] =3D { + { + .type =3D IIO_MAGN, + .channel2 =3D IIO_MOD_X, + .modified =3D 1, + .address =3D AXIS_X, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_type =3D + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_type_available =3D + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + }, + { + .type =3D IIO_MAGN, + .channel2 =3D IIO_MOD_Y, + .modified =3D 1, + .address =3D AXIS_Y, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_type =3D + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_type_available =3D + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + }, + { + .type =3D IIO_MAGN, + .channel2 =3D IIO_MOD_Z, + .modified =3D 1, + .address =3D AXIS_Z, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_type =3D + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_type_available =3D + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + }, +}; + +static void qmc5883p_suspend_action(void *arg) +{ + struct qmc5883p_data *data =3D arg; + + regmap_field_write(data->rf.mode, QMC5883P_MODE_SUSPEND); +} + +static int qmc5883p_probe(struct i2c_client *client) +{ + struct device *dev =3D &client->dev; + struct qmc5883p_data *data; + struct iio_dev *indio_dev; + struct regmap *regmap; + int ret; + + indio_dev =3D devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + regmap =3D devm_regmap_init_i2c(client, &qmc5883p_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "regmap initialization failed\n"); + + data =3D iio_priv(indio_dev); + data->dev =3D dev; + data->regmap =3D regmap; + mutex_init(&data->mutex); + + ret =3D devm_regulator_get_enable_optional(dev, "vdd"); + if (ret && ret !=3D -ENODEV) + return dev_err_probe(dev, ret, + "failed to get vdd regulator\n"); + + /* Datasheet specifies up to 50 ms supply ramp + 250 us POR time. */ + fsleep(50000); + + i2c_set_clientdata(client, indio_dev); + + ret =3D qmc5883p_rf_init(data); + if (ret) + return dev_err_probe(dev, ret, + "failed to initialize regmap fields\n"); + + ret =3D qmc5883p_verify_chip_id(data); + if (ret) + return ret; + + ret =3D qmc5883p_chip_init(data); + if (ret) + return dev_err_probe(dev, ret, "failed to initialize chip\n"); + + indio_dev->name =3D "qmc5883p"; + indio_dev->info =3D &qmc5883p_info; + indio_dev->modes =3D INDIO_DIRECT_MODE; + indio_dev->channels =3D qmc5883p_channels; + indio_dev->num_channels =3D ARRAY_SIZE(qmc5883p_channels); + + pm_runtime_set_autosuspend_delay(dev, 2000); + pm_runtime_use_autosuspend(dev); + + pm_runtime_set_active(dev); + + ret =3D devm_pm_runtime_enable(dev); + if (ret) + return ret; + + pm_runtime_mark_last_busy(dev); + + ret =3D devm_add_action_or_reset(dev, qmc5883p_suspend_action, data); + if (ret) + return ret; + + ret =3D devm_iio_device_register(dev, indio_dev); + if (ret) + return dev_err_probe(dev, ret, + "failed to register IIO device\n"); + return 0; +} + +static int qmc5883p_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev =3D dev_get_drvdata(dev); + struct qmc5883p_data *data =3D iio_priv(indio_dev); + + return regmap_field_write(data->rf.mode, QMC5883P_MODE_SUSPEND); +} + +static int qmc5883p_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev =3D dev_get_drvdata(dev); + struct qmc5883p_data *data =3D iio_priv(indio_dev); + int ret; + + ret =3D regmap_field_write(data->rf.mode, QMC5883P_MODE_NORMAL); + if (ret) + return ret; + + usleep_range(10000, 11000); + return 0; +} + +static int qmc5883p_system_suspend(struct device *dev) +{ + return pm_runtime_force_suspend(dev); +} + +static int qmc5883p_system_resume(struct device *dev) +{ + struct iio_dev *indio_dev =3D dev_get_drvdata(dev); + struct qmc5883p_data *data =3D iio_priv(indio_dev); + int ret; + + ret =3D pm_runtime_force_resume(dev); + if (ret) + return ret; + + /* + * If the regulator was cut during system suspend, POR will have + * reset all registers. Reinitialise the chip and resync the + * regmap cache so that cached control register values are pushed + * back to hardware. + */ + ret =3D qmc5883p_chip_init(data); + if (ret) + return ret; + + regcache_mark_dirty(data->regmap); + return regcache_sync(data->regmap); +} + +static const struct dev_pm_ops qmc5883p_dev_pm_ops =3D { + SYSTEM_SLEEP_PM_OPS(qmc5883p_system_suspend, qmc5883p_system_resume) + RUNTIME_PM_OPS(qmc5883p_runtime_suspend, qmc5883p_runtime_resume, NULL) +}; + +static const struct of_device_id qmc5883p_of_match[] =3D { + { .compatible =3D "qst,qmc5883p" }, + {} +}; +MODULE_DEVICE_TABLE(of, qmc5883p_of_match); + +static const struct i2c_device_id qmc5883p_id[] =3D { + { "qmc5883p", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, qmc5883p_id); + +static struct i2c_driver qmc5883p_driver =3D { + .driver =3D { + .name =3D "qmc5883p", + .of_match_table =3D qmc5883p_of_match, + .pm =3D pm_ptr(&qmc5883p_dev_pm_ops), + }, + .probe =3D qmc5883p_probe, + .id_table =3D qmc5883p_id, +}; +module_i2c_driver(qmc5883p_driver); + +MODULE_AUTHOR("Hardik Phalet "); +MODULE_DESCRIPTION("QMC5883P magnetic sensor driver"); +MODULE_LICENSE("GPL"); --=20 2.53.0 From nobody Mon Jun 15 10:50:32 2026 Received: from mail-244122.protonmail.ch (mail-244122.protonmail.ch [109.224.244.122]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6AD43341AB1 for ; Thu, 9 Apr 2026 21:08:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=109.224.244.122 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775768881; cv=none; b=nc5+Bn9mWDGj8yIn4Tpbyy8HfLy0VYaAkOkwnux75vRnPuD86k16WBRxdzJx+hQ9oOGfuToK+NUqZi3jwCOcIJWB40IoVUwRCS6zFpNJgXC6NAKlJFO8UovauRMEx9o+oVTlCs6NkUvB1JQojbT/IGkHO83zMTT039YF6XqCysQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775768881; c=relaxed/simple; bh=1pxZBrLmy2pMWIo0LdsENmdYtsvl8jy8EOqABhANfgE=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=SfN2hCfnalXOKx6XukUCdHp8VscmIm/+SrYE9hPXDQqJp2n9CTHMq8nU11EPbsysHNmAZwKe7GGom8uGcvqqZeI1FgK+rg2Ul8WhbnyMkG1S/4pVguJhMk8QXhOIOzPH79cjPN4fXgW4o8IOMFFTBhajsRsr2po+v0HTYPtWVKA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me; spf=pass smtp.mailfrom=pm.me; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b=KSBHuaOe; arc=none smtp.client-ip=109.224.244.122 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pm.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b="KSBHuaOe" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1775768878; x=1776028078; bh=1pxZBrLmy2pMWIo0LdsENmdYtsvl8jy8EOqABhANfgE=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=KSBHuaOeuOGUAYf9I+42K6s2n7ZmMStQOE0W+V48xxOm+3NFiR22Ff81ZsLT6Z/+2 qkeQtrsEYU+xt8U/LSLc9wKU+DKpPZRw2G5DDzDpT/cP7d9Oj5wVmhT+Ib2AjZuHXm uwkh55NmTkg6qTQWpJV/0lQHlSlYmNCE7ESFnJHv7k8NxJE6ndYcov7hbcKVkD6Yi4 dWzydMIzHwO5QjOsBQB3tnpPW17Z1eOC2CBL85qlQBBmEFgRPChL4ADX6UB1LCb5TW P8fJdl2vXsECCTmYCQq2+X7KKnaWiuPJAX4tMy39dyDuhBwaE+5qW9/qObMj631Kpv A1ZkaqBPCqd1w== Date: Thu, 09 Apr 2026 21:07:52 +0000 To: Greg Kroah-Hartman From: Hardik Phalet Cc: Jonathan Cameron , David Lechner , =?utf-8?Q?Nuno_S=C3=A1?= , Andy Shevchenko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Brigham Campbell , Shuah Khan , linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-staging@lists.linux.dev, Hardik Phalet Subject: [PATCH v2 4/4] MAINTAINERS: Add entry for QST QMC5883P magnetometer driver Message-ID: <20260409210639.3197576-5-hardik.phalet@pm.me> In-Reply-To: <20260409210639.3197576-1-hardik.phalet@pm.me> References: <20260409210639.3197576-1-hardik.phalet@pm.me> Feedback-ID: 166659585:user:proton X-Pm-Message-ID: bcd1d8ec985241d919eb7e370ca903db6e73bbdd Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a MAINTAINERS entry for the QST QMC5883P staging IIO driver, covering the driver source and its device tree binding. Signed-off-by: Hardik Phalet --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index a92290fffa16..d0b9bfceb283 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20274,6 +20274,13 @@ F: Documentation/networking/device_drivers/etherne= t/freescale/dpaa2/overview.rst F: drivers/bus/fsl-mc/ F: include/uapi/linux/fsl_mc.h =20 +QST QMC5883P MAGNETOMETER DRIVER +M: Hardik Phalet +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/magnetometer/qst,qmc5883p.yaml +F: drivers/staging/iio/magnetometer/ + QT1010 MEDIA DRIVER L: linux-media@vger.kernel.org S: Orphan --=20 2.53.0