From nobody Fri Feb 13 19:27:03 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C5962C04AB7 for ; Wed, 20 Sep 2023 17:03:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235029AbjITRDd (ORCPT ); Wed, 20 Sep 2023 13:03:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45204 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234588AbjITRDa (ORCPT ); Wed, 20 Sep 2023 13:03:30 -0400 Received: from mail-wr1-x432.google.com (mail-wr1-x432.google.com [IPv6:2a00:1450:4864:20::432]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 67D90C6 for ; Wed, 20 Sep 2023 10:03:22 -0700 (PDT) Received: by mail-wr1-x432.google.com with SMTP id ffacd0b85a97d-313e742a787so827649f8f.1 for ; Wed, 20 Sep 2023 10:03:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1695229401; x=1695834201; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=7UwBoraJ2UyiNBA95miiJOkVeBFDlpiyzSKW0JhpuxY=; b=dczXK0NjEeB4k5HsB/IIKEVhuY2etLZSk7XPSxzeXkLgijIaBqtlEea+7jqOgT9BPp 0YieHbR4OHoLKX34KwIzMo+u2J+hulgopnTiHceR0JCu+MB7SCgyxmYfMVU97KkGtA75 QskXiAvxIQqay80slY52Pl6yuT8J+AyUkOK7A6xWEW6pDZltHh4kIBh4d/VEMC84Hi5X cMKEvdBFmSkp321n8SC5TkLNqhiL0P95J1xFLHDlBNtmnx4k2PMeNi80aG/A7jaqUoEF opcXdLbPSkpW9NGHTAB6AWxJl82XcDS4FiDd4g9a1xaXmLNfsjyAsllZp9FQ0VaOJvSF 9Ssg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1695229401; x=1695834201; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=7UwBoraJ2UyiNBA95miiJOkVeBFDlpiyzSKW0JhpuxY=; b=sOQTK5AaD0XCbOFcOvYM+3UpMjX6K7yCxJhH1Ohrt8njv9fzmMaIyQRctQzYOS17Aw IT3Q+g+VaSe9I39rQ8pSdYGVtmNC4Q4yeur4zT6ADtTvHHqMYexDIZ4NaoIiS1DA9zLC FrN8t+0YZwIY+E5E4HNHrFNinS9KZfpUN2dEUCVvfNHq9+cS0KT634DoZXuMMdOEuF2+ Xf1/VM3u8gYrtPpozZNAByrL/XO3ZwioolXe8V34tTrXytx06bnxl8GIE+Ez8H6ZOayb c7kLxknljsvQNDpPfk2rIS31Xt0YIeTqHPOlspO0Unuj5CyggPOEVNpibeoTExkMALHK H8rA== X-Gm-Message-State: AOJu0YxZdTIJwZyAB5xV0PrbO1lTUVA/eXh4xROGIzLfaMZH6r+eEzSC R8IWfpOyew1itvG/Lv7L4DaHsQ== X-Google-Smtp-Source: AGHT+IGfv6ycigK3zstaVUGeKXS+WIWHwXO3vhnmRWYtvJp0cuxzGiHam065zhtkLr4iMwyDcKEuFg== X-Received: by 2002:a5d:4b87:0:b0:31f:6e29:df8d with SMTP id b7-20020a5d4b87000000b0031f6e29df8dmr2465786wrt.6.1695229400529; Wed, 20 Sep 2023 10:03:20 -0700 (PDT) Received: from localhost.localdomain (abordeaux-655-1-129-86.w90-5.abo.wanadoo.fr. [90.5.10.86]) by smtp.gmail.com with ESMTPSA id g10-20020adff3ca000000b003200c918c81sm11221089wrp.112.2023.09.20.10.03.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 20 Sep 2023 10:03:20 -0700 (PDT) From: David Lechner To: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-staging@lists.linux.dev Cc: David Lechner , linux-kernel@vger.kernel.org, Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Michael Hennerich , =?UTF-8?q?Nuno=20S=C3=A1?= , Axel Haslam , Philip Molloy , Apelete Seketeli Subject: [PATCH 1/4] dt-bindings: iio: resolver: add devicetree bindings for ad2s1210 Date: Wed, 20 Sep 2023 12:02:50 -0500 Message-Id: <20230920170253.203395-2-dlechner@baylibre.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230920170253.203395-1-dlechner@baylibre.com> References: <20230920170253.203395-1-dlechner@baylibre.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This adds new DeviceTree bindings for the Analog Devices, Inc. AD2S1210 resolver-to-digital converter. Signed-off-by: Apelete Seketeli Signed-off-by: David Lechner --- .../bindings/iio/resolver/adi,ad2s1210.yaml | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/resolver/adi,ad2s= 1210.yaml diff --git a/Documentation/devicetree/bindings/iio/resolver/adi,ad2s1210.ya= ml b/Documentation/devicetree/bindings/iio/resolver/adi,ad2s1210.yaml new file mode 100644 index 000000000000..cf6838710e52 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/resolver/adi,ad2s1210.yaml @@ -0,0 +1,150 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/resolver/adi,ad2s1210.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD2S1210 Resolver-to-Digital Converter + +maintainers: + - Michael Hennerich + +description: | + The AD2S1210 is a complete 10-bit to 16-bit resolution tracking + resolver-to-digital converter, integrating an on-board programmable + sinusoidal oscillator that provides sine wave excitation for + resolvers. + + The AD2S1210 allows the user to read the angular position or the + angular velocity data directly from the parallel outputs or through + the serial interface. + + A1 A0 Result + 0 0 Normal mode - position output + 0 1 Normal mode - velocity output + 1 0 Reserved + 1 1 Configuration mode + + In normal mode, the resolution of the digital output is selected using + the RES0 and RES1 input pins. In configuration mode, the resolution is + selected by setting the RES0 and RES1 bits in the control register. + + RES1 RES0 Resolution (Bits) + 0 0 10 + 0 1 12 + 1 0 14 + 1 1 16 + + Note on SPI connections: The CS line on the AD2S1210 should hard-wired to + logic low and the WR/FSYNC line on the AD2S1210 should be connected to t= he + SPI CSn output of the SPI controller. + + Datasheet: + https://www.analog.com/media/en/technical-documentation/data-sheets/ad2s= 1210.pdf + +properties: + compatible: + const: adi,ad2s1210 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 25000000 + + spi-cpha: true + + clocks: + maxItems: 1 + description: External oscillator clock (CLKIN). + + reset-gpios: + description: + GPIO connected to the /RESET pin. As the line needs to be low for the + reset to be active, it should be configured as GPIO_ACTIVE_LOW. + maxItems: 1 + + sample-gpios: + description: | + GPIO connected to the /SAMPLE pin. As the line needs to be low to tr= igger + a sample, it should be configured as GPIO_ACTIVE_LOW. + maxItems: 1 + + mode-gpios: + description: | + GPIO lines connected to the A0 and A1 pins. These pins select the da= ta + transfer mode. + minItems: 2 + maxItems: 2 + + resolution-gpios: + description: | + GPIO lines connected to the RES0 and RES1 pins. These pins select the + resolution of the digital output. If omitted, it is assumed that the + RES0 and RES1 pins are hard-wired to match the assigned-resolution-b= its + property. + minItems: 2 + maxItems: 2 + + fault-gpios: + description: | + GPIO lines connected to the LOT and DOS pins. These pins combined in= dicate + the type of fault present, if any. As these pins a pulled low to ind= icate + a fault condition, they should be configured as GPIO_ACTIVE_LOW. + minItems: 2 + maxItems: 2 + + adi,fixed-mode: + description: | + This is used to indicate the selected mode if A0 and A1 are hard-wir= ed + instead of connected to GPIOS (i.e. mode-gpios is omitted). + $ref: /schemas/types.yaml#/definitions/string + enum: ["config", "velocity", "position"] + + assigned-resolution-bits: + description: | + Resolution of the digital output required by the application. This + determines the precision of the angle and/or the maximum speed that = can + be measured. If resolution-gpios is omitted, it is assumed that RES0= and + RES1 are hard-wired to match this value. + enum: [10, 12, 14, 16] + +required: + - compatible + - reg + - spi-cpha + - clocks + - sample-gpios + - assigned-resolution-bits + +oneOf: + - required: + - mode-gpios + - required: + - adi,fixed-mode + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + + spi { + #address-cells =3D <1>; + #size-cells =3D <0>; + + resolver@0 { + compatible =3D "adi,ad2s1210"; + reg =3D <0>; + spi-max-frequency =3D <20000000>; + spi-cpha; + clocks =3D <&ext_osc>; + sample-gpios =3D <&gpio0 90 GPIO_ACTIVE_LOW>; + mode-gpios =3D <&gpio0 86 0>, <&gpio0 87 0>; + resolution-gpios =3D <&gpio0 88 0>, <&gpio0 89 0>; + assigned-resolution-bits =3D <16>; + }; + }; --=20 2.34.1 From nobody Fri Feb 13 19:27:03 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 906B9C04AB4 for ; Wed, 20 Sep 2023 17:03:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235003AbjITRDb (ORCPT ); Wed, 20 Sep 2023 13:03:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45192 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234157AbjITRD3 (ORCPT ); Wed, 20 Sep 2023 13:03:29 -0400 Received: from mail-wr1-x435.google.com (mail-wr1-x435.google.com [IPv6:2a00:1450:4864:20::435]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F1210CA for ; Wed, 20 Sep 2023 10:03:22 -0700 (PDT) Received: by mail-wr1-x435.google.com with SMTP id ffacd0b85a97d-3200257b9a3so25490f8f.3 for ; Wed, 20 Sep 2023 10:03:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1695229401; x=1695834201; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=aHyufdv37O6S8ZmknToS8IWvP33+rDz8dd7rQRoiFOI=; b=KP9aHxWaZhXlVlNIRB3+T0QZnZ5b9vMs/w1TCxRev6FWiykYqLh5FowfmBVEIplrc4 5CzYIrxjN4Iv85lIgI6B2taeHkDunL9TWA3pVQxSVtPGyqHATtefNe1eIKLPmj096Dw7 XuGMC6VQZlUZ7g1XBXGHsU9/KXxp6cY+a32qXW5R3cP1cgmEOzNSK69AWjKSpVSUbseE FbDQdck2IqDki4vzsrIq5FJQc8XALTwwemOGW16BYdIZ4xarlwl6+nNwO59rMtHfVzPU YTtFLEk/jtRKE2Y4lH33+OppoYXyN+JHzLvHiTonWgDNmjr2Yq7QBAdkhT1JpGCRlu36 tu5A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1695229401; x=1695834201; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=aHyufdv37O6S8ZmknToS8IWvP33+rDz8dd7rQRoiFOI=; b=h3bj4pweuCjCSZNxqc35EBDKVIGJzBhcWg3H1li2q8076wsHzk5zSbICJVSxNjvob+ mkK7qqIqaeT/WKs/npcnVKdl8R6XsX9oBDRhnTn7FNL/P4tKiCgfHGGuPBPblpJvT5lY XfWd/f6MbU3C9aRt0O1pRHCxEW42TBXXNCc6G8Q0BiPtpC1oDyWMUbTfZFd60rs/A8An r4j2m1ZtNVC3pNLaff97wDG8NtuGJHmI/OeuSRFr96uJUx7hnEhP+UwnW5qnTxJVMmeM 7TZ+aRO5NDPIZeQwL4OHllpejbQfscpKy2i0T0bqYT8lnmfK+k71dYIdcobBpU71BL1i yRxg== X-Gm-Message-State: AOJu0Yz7VuFfSQuKH2NGKmaGiEuxPrmrrA5LBKAaBZ45DjPHLxGwGgwZ rlvNk4GYMt5TL5sefmZMeDdbKA== X-Google-Smtp-Source: AGHT+IEeDYURcssAVtKkHWXgELiscbELYLxLWtKeReqzbYPINC/mwrr6PKnp6JmuUytIY6KCPgVkdw== X-Received: by 2002:a5d:4bc1:0:b0:319:7472:f0b6 with SMTP id l1-20020a5d4bc1000000b003197472f0b6mr3079743wrt.15.1695229401308; Wed, 20 Sep 2023 10:03:21 -0700 (PDT) Received: from localhost.localdomain (abordeaux-655-1-129-86.w90-5.abo.wanadoo.fr. [90.5.10.86]) by smtp.gmail.com with ESMTPSA id g10-20020adff3ca000000b003200c918c81sm11221089wrp.112.2023.09.20.10.03.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 20 Sep 2023 10:03:21 -0700 (PDT) From: David Lechner To: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-staging@lists.linux.dev Cc: David Lechner , linux-kernel@vger.kernel.org, Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Michael Hennerich , =?UTF-8?q?Nuno=20S=C3=A1?= , Axel Haslam , Philip Molloy Subject: [PATCH 2/4] iio: sysfs: add IIO_DEVICE_ATTR_NAMED_RW macro Date: Wed, 20 Sep 2023 12:02:51 -0500 Message-Id: <20230920170253.203395-3-dlechner@baylibre.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230920170253.203395-1-dlechner@baylibre.com> References: <20230920170253.203395-1-dlechner@baylibre.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This adds a new IIO_DEVICE_ATTR_NAMED_RW to handle the case where multiple attributes share a common implementation so the attribute name and the function names need to be different. Signed-off-by: David Lechner --- include/linux/iio/sysfs.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/iio/sysfs.h b/include/linux/iio/sysfs.h index de5bb125815c..ab20c5294e52 100644 --- a/include/linux/iio/sysfs.h +++ b/include/linux/iio/sysfs.h @@ -87,6 +87,10 @@ struct iio_const_attr { struct iio_dev_attr iio_dev_attr_##_vname \ =3D IIO_ATTR(_name, _mode, _show, _store, _addr) =20 +#define IIO_DEVICE_ATTR_NAMED_RW(_vname, _name, _addr) \ + struct iio_dev_attr iio_dev_attr_##_vname \ + =3D IIO_ATTR_RW(_name, _addr) + #define IIO_CONST_ATTR(_name, _string) \ struct iio_const_attr iio_const_attr_##_name \ =3D { .string =3D _string, \ --=20 2.34.1 From nobody Fri Feb 13 19:27:03 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4D17CC0031C for ; Wed, 20 Sep 2023 17:03:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235143AbjITRDg (ORCPT ); Wed, 20 Sep 2023 13:03:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45268 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235034AbjITRDd (ORCPT ); Wed, 20 Sep 2023 13:03:33 -0400 Received: from mail-wm1-x331.google.com (mail-wm1-x331.google.com [IPv6:2a00:1450:4864:20::331]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 37ACCD7 for ; Wed, 20 Sep 2023 10:03:24 -0700 (PDT) Received: by mail-wm1-x331.google.com with SMTP id 5b1f17b1804b1-40528376459so257735e9.3 for ; Wed, 20 Sep 2023 10:03:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1695229402; x=1695834202; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=I0qi+KbLecqFKhPv3lS1tkBt/BnZ4XVrImU5Wur+NK0=; b=bEGB4AcMMYeEkrsP3MWy9LN2HdwVqKV6iwa/U3j1tuCxLrL61CWTYIC1LOXKHEsKzx khZZMQVZyorzA+nsbKY1wpNCC/kjQG/XlNEXEnRUa6M15c1VYDz/eKo5a3obQnec78Om /ia1JMb6PigujqvinHzuwMYMbohEjB1OG1wqbJ37kb0krhUqljgMsM9uMzoMuQVK+M/x tWu8oqetCywpD0Mz3/sHlEbHt7FP4xXm+xg066WSetZe4xsyGxVMPdlMLDz5rkXfDhYJ odz7GvoaXRqlqxbudz3uS19MhdmDp6wP62Ge5CuQvl+s7nV1CaRXScJGS82BVFW7eU0A ewYw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1695229402; x=1695834202; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=I0qi+KbLecqFKhPv3lS1tkBt/BnZ4XVrImU5Wur+NK0=; b=G2pGXelbONClakZiwNh73xaXZBAV76hZWSCZOTeFEgBy8JwrwFYTVowItSoodEfjrT fb9RN+Jzx8i9sx9Cm0f5q+1IOT1dLRcZfwGwjoQrKzjCIYr8YMm8ZrFFgo3/XuwYmri6 M0d+g0/7guEFS/9DV10hMlLZqRoH193L2VbDT9h4+zMKRuA7obKmaztRrsF040vFkbDA FvHlFJGykgvpY9EUsvyxYxmk51E1svJf1wFFhCWXI2Nyn5tnkvgZBweLxNovBycjwaGP d7aTNz1RxBZEIcSha9ZJnSdCwk5coEIq8pQiMBVQkWUntC5SWUZ+lpAmZaTHre2LsjOM +J5A== X-Gm-Message-State: AOJu0YyCHc45Y+PZaY8on02H/1rD8c4fgsF2QaVrLfimbMKe5h7QdSE5 Jb5U7E6fiyt291K8taFTstc4nw== X-Google-Smtp-Source: AGHT+IHWn8HSO3o4m52y0ff1wXqC4uY9vLIafgCIvOpsgkokz5ae5HWBtPK72dyqhcON6OFbiEftig== X-Received: by 2002:a5d:58cd:0:b0:321:4de3:fd5c with SMTP id o13-20020a5d58cd000000b003214de3fd5cmr2929754wrf.51.1695229402288; Wed, 20 Sep 2023 10:03:22 -0700 (PDT) Received: from localhost.localdomain (abordeaux-655-1-129-86.w90-5.abo.wanadoo.fr. [90.5.10.86]) by smtp.gmail.com with ESMTPSA id g10-20020adff3ca000000b003200c918c81sm11221089wrp.112.2023.09.20.10.03.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 20 Sep 2023 10:03:21 -0700 (PDT) From: David Lechner To: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-staging@lists.linux.dev Cc: David Lechner , linux-kernel@vger.kernel.org, Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Michael Hennerich , =?UTF-8?q?Nuno=20S=C3=A1?= , Axel Haslam , Philip Molloy Subject: [PATCH 3/4] staging: iio: resolver: remove ad2s1210 driver Date: Wed, 20 Sep 2023 12:02:52 -0500 Message-Id: <20230920170253.203395-4-dlechner@baylibre.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230920170253.203395-1-dlechner@baylibre.com> References: <20230920170253.203395-1-dlechner@baylibre.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This removes the AD2S1210 resolver driver from staging. It will be improved and resubmitted out of staging. Signed-off-by: David Lechner --- drivers/staging/iio/Kconfig | 1 - drivers/staging/iio/Makefile | 1 - drivers/staging/iio/resolver/Kconfig | 18 - drivers/staging/iio/resolver/Makefile | 6 - drivers/staging/iio/resolver/ad2s1210.c | 716 ------------------------ 5 files changed, 742 deletions(-) delete mode 100644 drivers/staging/iio/resolver/Kconfig delete mode 100644 drivers/staging/iio/resolver/Makefile delete mode 100644 drivers/staging/iio/resolver/ad2s1210.c diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index d3968fe2ebb8..a60631c1f449 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -10,6 +10,5 @@ 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/resolver/Kconfig" =20 endmenu diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile index c50f1019f829..628583535393 100644 --- a/drivers/staging/iio/Makefile +++ b/drivers/staging/iio/Makefile @@ -8,4 +8,3 @@ obj-y +=3D adc/ obj-y +=3D addac/ obj-y +=3D frequency/ obj-y +=3D impedance-analyzer/ -obj-y +=3D resolver/ diff --git a/drivers/staging/iio/resolver/Kconfig b/drivers/staging/iio/res= olver/Kconfig deleted file mode 100644 index 6d1e2622e0b0..000000000000 --- a/drivers/staging/iio/resolver/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Resolver/Synchro drivers -# -menu "Resolver to digital converters" - -config AD2S1210 - tristate "Analog Devices ad2s1210 driver" - depends on SPI - depends on GPIOLIB || COMPILE_TEST - help - Say yes here to build support for Analog Devices spi resolver - to digital converters, ad2s1210, provides direct access via sysfs. - - To compile this driver as a module, choose M here: the - module will be called ad2s1210. - -endmenu diff --git a/drivers/staging/iio/resolver/Makefile b/drivers/staging/iio/re= solver/Makefile deleted file mode 100644 index 398631f7e79b..000000000000 --- a/drivers/staging/iio/resolver/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for Resolver/Synchro drivers -# - -obj-$(CONFIG_AD2S1210) +=3D ad2s1210.o diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/= resolver/ad2s1210.c deleted file mode 100644 index 06de5823eb8e..000000000000 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ /dev/null @@ -1,716 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * ad2s1210.c support for the ADI Resolver to Digital Converters: AD2S1210 - * - * Copyright (c) 2010-2010 Analog Devices Inc. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define DRV_NAME "ad2s1210" - -#define AD2S1210_DEF_CONTROL 0x7E - -#define AD2S1210_MSB_IS_HIGH 0x80 -#define AD2S1210_MSB_IS_LOW 0x7F -#define AD2S1210_PHASE_LOCK_RANGE_44 0x20 -#define AD2S1210_ENABLE_HYSTERESIS 0x10 -#define AD2S1210_SET_ENRES1 0x08 -#define AD2S1210_SET_ENRES0 0x04 -#define AD2S1210_SET_RES1 0x02 -#define AD2S1210_SET_RES0 0x01 - -#define AD2S1210_SET_RESOLUTION (AD2S1210_SET_RES1 | AD2S1210_SET_RES0) - -#define AD2S1210_REG_POSITION 0x80 -#define AD2S1210_REG_VELOCITY 0x82 -#define AD2S1210_REG_LOS_THRD 0x88 -#define AD2S1210_REG_DOS_OVR_THRD 0x89 -#define AD2S1210_REG_DOS_MIS_THRD 0x8A -#define AD2S1210_REG_DOS_RST_MAX_THRD 0x8B -#define AD2S1210_REG_DOS_RST_MIN_THRD 0x8C -#define AD2S1210_REG_LOT_HIGH_THRD 0x8D -#define AD2S1210_REG_LOT_LOW_THRD 0x8E -#define AD2S1210_REG_EXCIT_FREQ 0x91 -#define AD2S1210_REG_CONTROL 0x92 -#define AD2S1210_REG_SOFT_RESET 0xF0 -#define AD2S1210_REG_FAULT 0xFF - -#define AD2S1210_MIN_CLKIN 6144000 -#define AD2S1210_MAX_CLKIN 10240000 -#define AD2S1210_MIN_EXCIT 2000 -#define AD2S1210_MAX_EXCIT 20000 -#define AD2S1210_MIN_FCW 0x4 -#define AD2S1210_MAX_FCW 0x50 - -#define AD2S1210_DEF_EXCIT 10000 - -enum ad2s1210_mode { - MOD_POS =3D 0, - MOD_VEL, - MOD_CONFIG, - MOD_RESERVED, -}; - -enum ad2s1210_gpios { - AD2S1210_SAMPLE, - AD2S1210_A0, - AD2S1210_A1, - AD2S1210_RES0, - AD2S1210_RES1, -}; - -struct ad2s1210_gpio { - const char *name; - unsigned long flags; -}; - -static const struct ad2s1210_gpio gpios[] =3D { - [AD2S1210_SAMPLE] =3D { .name =3D "adi,sample", .flags =3D GPIOD_OUT_LOW = }, - [AD2S1210_A0] =3D { .name =3D "adi,a0", .flags =3D GPIOD_OUT_LOW }, - [AD2S1210_A1] =3D { .name =3D "adi,a1", .flags =3D GPIOD_OUT_LOW }, - [AD2S1210_RES0] =3D { .name =3D "adi,res0", .flags =3D GPIOD_OUT_LOW }, - [AD2S1210_RES1] =3D { .name =3D "adi,res1", .flags =3D GPIOD_OUT_LOW }, -}; - -static const unsigned int ad2s1210_resolution_value[] =3D { 10, 12, 14, 16= }; - -struct ad2s1210_state { - struct mutex lock; - struct spi_device *sdev; - struct gpio_desc *gpios[5]; - unsigned int fclkin; - unsigned int fexcit; - bool hysteresis; - u8 resolution; - enum ad2s1210_mode mode; - u8 rx[2] __aligned(IIO_DMA_MINALIGN); - u8 tx[2]; -}; - -static const int ad2s1210_mode_vals[4][2] =3D { - [MOD_POS] =3D { 0, 0 }, - [MOD_VEL] =3D { 0, 1 }, - [MOD_CONFIG] =3D { 1, 1 }, -}; - -static inline void ad2s1210_set_mode(enum ad2s1210_mode mode, - struct ad2s1210_state *st) -{ - gpiod_set_value(st->gpios[AD2S1210_A0], ad2s1210_mode_vals[mode][0]); - gpiod_set_value(st->gpios[AD2S1210_A1], ad2s1210_mode_vals[mode][1]); - st->mode =3D mode; -} - -/* write 1 bytes (address or data) to the chip */ -static int ad2s1210_config_write(struct ad2s1210_state *st, u8 data) -{ - int ret; - - ad2s1210_set_mode(MOD_CONFIG, st); - st->tx[0] =3D data; - ret =3D spi_write(st->sdev, st->tx, 1); - if (ret < 0) - return ret; - - return 0; -} - -/* read value from one of the registers */ -static int ad2s1210_config_read(struct ad2s1210_state *st, - unsigned char address) -{ - struct spi_transfer xfers[] =3D { - { - .len =3D 1, - .rx_buf =3D &st->rx[0], - .tx_buf =3D &st->tx[0], - .cs_change =3D 1, - }, { - .len =3D 1, - .rx_buf =3D &st->rx[1], - .tx_buf =3D &st->tx[1], - }, - }; - int ret =3D 0; - - ad2s1210_set_mode(MOD_CONFIG, st); - st->tx[0] =3D address | AD2S1210_MSB_IS_HIGH; - st->tx[1] =3D AD2S1210_REG_FAULT; - ret =3D spi_sync_transfer(st->sdev, xfers, 2); - if (ret < 0) - return ret; - - return st->rx[1]; -} - -static inline -int ad2s1210_update_frequency_control_word(struct ad2s1210_state *st) -{ - int ret; - unsigned char fcw; - - fcw =3D (unsigned char)(st->fexcit * (1 << 15) / st->fclkin); - if (fcw < AD2S1210_MIN_FCW || fcw > AD2S1210_MAX_FCW) { - dev_err(&st->sdev->dev, "ad2s1210: FCW out of range\n"); - return -ERANGE; - } - - ret =3D ad2s1210_config_write(st, AD2S1210_REG_EXCIT_FREQ); - if (ret < 0) - return ret; - - return ad2s1210_config_write(st, fcw); -} - -static const int ad2s1210_res_pins[4][2] =3D { - { 0, 0 }, {0, 1}, {1, 0}, {1, 1} -}; - -static inline void ad2s1210_set_resolution_pin(struct ad2s1210_state *st) -{ - gpiod_set_value(st->gpios[AD2S1210_RES0], - ad2s1210_res_pins[(st->resolution - 10) / 2][0]); - gpiod_set_value(st->gpios[AD2S1210_RES1], - ad2s1210_res_pins[(st->resolution - 10) / 2][1]); -} - -static inline int ad2s1210_soft_reset(struct ad2s1210_state *st) -{ - int ret; - - ret =3D ad2s1210_config_write(st, AD2S1210_REG_SOFT_RESET); - if (ret < 0) - return ret; - - return ad2s1210_config_write(st, 0x0); -} - -static ssize_t ad2s1210_show_fclkin(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); - - return sprintf(buf, "%u\n", st->fclkin); -} - -static ssize_t ad2s1210_store_fclkin(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); - unsigned int fclkin; - int ret; - - ret =3D kstrtouint(buf, 10, &fclkin); - if (ret) - return ret; - if (fclkin < AD2S1210_MIN_CLKIN || fclkin > AD2S1210_MAX_CLKIN) { - dev_err(dev, "ad2s1210: fclkin out of range\n"); - return -EINVAL; - } - - mutex_lock(&st->lock); - st->fclkin =3D fclkin; - - ret =3D ad2s1210_update_frequency_control_word(st); - if (ret < 0) - goto error_ret; - ret =3D ad2s1210_soft_reset(st); -error_ret: - mutex_unlock(&st->lock); - - return ret < 0 ? ret : len; -} - -static ssize_t ad2s1210_show_fexcit(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); - - return sprintf(buf, "%u\n", st->fexcit); -} - -static ssize_t ad2s1210_store_fexcit(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); - unsigned int fexcit; - int ret; - - ret =3D kstrtouint(buf, 10, &fexcit); - if (ret < 0) - return ret; - if (fexcit < AD2S1210_MIN_EXCIT || fexcit > AD2S1210_MAX_EXCIT) { - dev_err(dev, - "ad2s1210: excitation frequency out of range\n"); - return -EINVAL; - } - mutex_lock(&st->lock); - st->fexcit =3D fexcit; - ret =3D ad2s1210_update_frequency_control_word(st); - if (ret < 0) - goto error_ret; - ret =3D ad2s1210_soft_reset(st); -error_ret: - mutex_unlock(&st->lock); - - return ret < 0 ? ret : len; -} - -static ssize_t ad2s1210_show_control(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); - int ret; - - mutex_lock(&st->lock); - ret =3D ad2s1210_config_read(st, AD2S1210_REG_CONTROL); - mutex_unlock(&st->lock); - return ret < 0 ? ret : sprintf(buf, "0x%x\n", ret); -} - -static ssize_t ad2s1210_store_control(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); - unsigned char udata; - unsigned char data; - int ret; - - ret =3D kstrtou8(buf, 16, &udata); - if (ret) - return -EINVAL; - - mutex_lock(&st->lock); - ret =3D ad2s1210_config_write(st, AD2S1210_REG_CONTROL); - if (ret < 0) - goto error_ret; - data =3D udata & AD2S1210_MSB_IS_LOW; - ret =3D ad2s1210_config_write(st, data); - if (ret < 0) - goto error_ret; - - ret =3D ad2s1210_config_read(st, AD2S1210_REG_CONTROL); - if (ret < 0) - goto error_ret; - if (ret & AD2S1210_MSB_IS_HIGH) { - ret =3D -EIO; - dev_err(dev, - "ad2s1210: write control register fail\n"); - goto error_ret; - } - st->resolution =3D - ad2s1210_resolution_value[data & AD2S1210_SET_RESOLUTION]; - ad2s1210_set_resolution_pin(st); - ret =3D len; - st->hysteresis =3D !!(data & AD2S1210_ENABLE_HYSTERESIS); - -error_ret: - mutex_unlock(&st->lock); - return ret; -} - -static ssize_t ad2s1210_show_resolution(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); - - return sprintf(buf, "%d\n", st->resolution); -} - -static ssize_t ad2s1210_store_resolution(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); - unsigned char data; - unsigned char udata; - int ret; - - ret =3D kstrtou8(buf, 10, &udata); - if (ret || udata < 10 || udata > 16) { - dev_err(dev, "ad2s1210: resolution out of range\n"); - return -EINVAL; - } - mutex_lock(&st->lock); - ret =3D ad2s1210_config_read(st, AD2S1210_REG_CONTROL); - if (ret < 0) - goto error_ret; - data =3D ret; - data &=3D ~AD2S1210_SET_RESOLUTION; - data |=3D (udata - 10) >> 1; - ret =3D ad2s1210_config_write(st, AD2S1210_REG_CONTROL); - if (ret < 0) - goto error_ret; - ret =3D ad2s1210_config_write(st, data & AD2S1210_MSB_IS_LOW); - if (ret < 0) - goto error_ret; - ret =3D ad2s1210_config_read(st, AD2S1210_REG_CONTROL); - if (ret < 0) - goto error_ret; - data =3D ret; - if (data & AD2S1210_MSB_IS_HIGH) { - ret =3D -EIO; - dev_err(dev, "ad2s1210: setting resolution fail\n"); - goto error_ret; - } - st->resolution =3D - ad2s1210_resolution_value[data & AD2S1210_SET_RESOLUTION]; - ad2s1210_set_resolution_pin(st); - ret =3D len; -error_ret: - mutex_unlock(&st->lock); - return ret; -} - -/* read the fault register since last sample */ -static ssize_t ad2s1210_show_fault(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); - int ret; - - mutex_lock(&st->lock); - ret =3D ad2s1210_config_read(st, AD2S1210_REG_FAULT); - mutex_unlock(&st->lock); - - return ret ? ret : sprintf(buf, "0x%x\n", ret); -} - -static ssize_t ad2s1210_clear_fault(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); - int ret; - - mutex_lock(&st->lock); - gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 0); - /* delay (2 * tck + 20) nano seconds */ - udelay(1); - gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 1); - ret =3D ad2s1210_config_read(st, AD2S1210_REG_FAULT); - if (ret < 0) - goto error_ret; - gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 0); - gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 1); -error_ret: - mutex_unlock(&st->lock); - - return ret < 0 ? ret : len; -} - -static ssize_t ad2s1210_show_reg(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); - struct iio_dev_attr *iattr =3D to_iio_dev_attr(attr); - int ret; - - mutex_lock(&st->lock); - ret =3D ad2s1210_config_read(st, iattr->address); - mutex_unlock(&st->lock); - - return ret < 0 ? ret : sprintf(buf, "%d\n", ret); -} - -static ssize_t ad2s1210_store_reg(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); - unsigned char data; - int ret; - struct iio_dev_attr *iattr =3D to_iio_dev_attr(attr); - - ret =3D kstrtou8(buf, 10, &data); - if (ret) - return -EINVAL; - mutex_lock(&st->lock); - ret =3D ad2s1210_config_write(st, iattr->address); - if (ret < 0) - goto error_ret; - ret =3D ad2s1210_config_write(st, data & AD2S1210_MSB_IS_LOW); -error_ret: - mutex_unlock(&st->lock); - return ret < 0 ? ret : len; -} - -static int ad2s1210_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long m) -{ - struct ad2s1210_state *st =3D iio_priv(indio_dev); - u16 negative; - int ret =3D 0; - u16 pos; - s16 vel; - - mutex_lock(&st->lock); - gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 0); - /* delay (6 * tck + 20) nano seconds */ - udelay(1); - - switch (chan->type) { - case IIO_ANGL: - ad2s1210_set_mode(MOD_POS, st); - break; - case IIO_ANGL_VEL: - ad2s1210_set_mode(MOD_VEL, st); - break; - default: - ret =3D -EINVAL; - break; - } - if (ret < 0) - goto error_ret; - ret =3D spi_read(st->sdev, st->rx, 2); - if (ret < 0) - goto error_ret; - - switch (chan->type) { - case IIO_ANGL: - pos =3D be16_to_cpup((__be16 *)st->rx); - if (st->hysteresis) - pos >>=3D 16 - st->resolution; - *val =3D pos; - ret =3D IIO_VAL_INT; - break; - case IIO_ANGL_VEL: - vel =3D be16_to_cpup((__be16 *)st->rx); - vel >>=3D 16 - st->resolution; - if (vel & 0x8000) { - negative =3D (0xffff >> st->resolution) << st->resolution; - vel |=3D negative; - } - *val =3D vel; - ret =3D IIO_VAL_INT; - break; - default: - mutex_unlock(&st->lock); - return -EINVAL; - } - -error_ret: - gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 1); - /* delay (2 * tck + 20) nano seconds */ - udelay(1); - mutex_unlock(&st->lock); - return ret; -} - -static IIO_DEVICE_ATTR(fclkin, 0644, - ad2s1210_show_fclkin, ad2s1210_store_fclkin, 0); -static IIO_DEVICE_ATTR(fexcit, 0644, - ad2s1210_show_fexcit, ad2s1210_store_fexcit, 0); -static IIO_DEVICE_ATTR(control, 0644, - ad2s1210_show_control, ad2s1210_store_control, 0); -static IIO_DEVICE_ATTR(bits, 0644, - ad2s1210_show_resolution, ad2s1210_store_resolution, 0); -static IIO_DEVICE_ATTR(fault, 0644, - ad2s1210_show_fault, ad2s1210_clear_fault, 0); - -static IIO_DEVICE_ATTR(los_thrd, 0644, - ad2s1210_show_reg, ad2s1210_store_reg, - AD2S1210_REG_LOS_THRD); -static IIO_DEVICE_ATTR(dos_ovr_thrd, 0644, - ad2s1210_show_reg, ad2s1210_store_reg, - AD2S1210_REG_DOS_OVR_THRD); -static IIO_DEVICE_ATTR(dos_mis_thrd, 0644, - ad2s1210_show_reg, ad2s1210_store_reg, - AD2S1210_REG_DOS_MIS_THRD); -static IIO_DEVICE_ATTR(dos_rst_max_thrd, 0644, - ad2s1210_show_reg, ad2s1210_store_reg, - AD2S1210_REG_DOS_RST_MAX_THRD); -static IIO_DEVICE_ATTR(dos_rst_min_thrd, 0644, - ad2s1210_show_reg, ad2s1210_store_reg, - AD2S1210_REG_DOS_RST_MIN_THRD); -static IIO_DEVICE_ATTR(lot_high_thrd, 0644, - ad2s1210_show_reg, ad2s1210_store_reg, - AD2S1210_REG_LOT_HIGH_THRD); -static IIO_DEVICE_ATTR(lot_low_thrd, 0644, - ad2s1210_show_reg, ad2s1210_store_reg, - AD2S1210_REG_LOT_LOW_THRD); - -static const struct iio_chan_spec ad2s1210_channels[] =3D { - { - .type =3D IIO_ANGL, - .indexed =3D 1, - .channel =3D 0, - .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), - }, { - .type =3D IIO_ANGL_VEL, - .indexed =3D 1, - .channel =3D 0, - .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), - } -}; - -static struct attribute *ad2s1210_attributes[] =3D { - &iio_dev_attr_fclkin.dev_attr.attr, - &iio_dev_attr_fexcit.dev_attr.attr, - &iio_dev_attr_control.dev_attr.attr, - &iio_dev_attr_bits.dev_attr.attr, - &iio_dev_attr_fault.dev_attr.attr, - &iio_dev_attr_los_thrd.dev_attr.attr, - &iio_dev_attr_dos_ovr_thrd.dev_attr.attr, - &iio_dev_attr_dos_mis_thrd.dev_attr.attr, - &iio_dev_attr_dos_rst_max_thrd.dev_attr.attr, - &iio_dev_attr_dos_rst_min_thrd.dev_attr.attr, - &iio_dev_attr_lot_high_thrd.dev_attr.attr, - &iio_dev_attr_lot_low_thrd.dev_attr.attr, - NULL, -}; - -static const struct attribute_group ad2s1210_attribute_group =3D { - .attrs =3D ad2s1210_attributes, -}; - -static int ad2s1210_initial(struct ad2s1210_state *st) -{ - unsigned char data; - int ret; - - mutex_lock(&st->lock); - ad2s1210_set_resolution_pin(st); - - ret =3D ad2s1210_config_write(st, AD2S1210_REG_CONTROL); - if (ret < 0) - goto error_ret; - data =3D AD2S1210_DEF_CONTROL & ~(AD2S1210_SET_RESOLUTION); - data |=3D (st->resolution - 10) >> 1; - ret =3D ad2s1210_config_write(st, data); - if (ret < 0) - goto error_ret; - ret =3D ad2s1210_config_read(st, AD2S1210_REG_CONTROL); - if (ret < 0) - goto error_ret; - - if (ret & AD2S1210_MSB_IS_HIGH) { - ret =3D -EIO; - goto error_ret; - } - - ret =3D ad2s1210_update_frequency_control_word(st); - if (ret < 0) - goto error_ret; - ret =3D ad2s1210_soft_reset(st); -error_ret: - mutex_unlock(&st->lock); - return ret; -} - -static const struct iio_info ad2s1210_info =3D { - .read_raw =3D ad2s1210_read_raw, - .attrs =3D &ad2s1210_attribute_group, -}; - -static int ad2s1210_setup_gpios(struct ad2s1210_state *st) -{ - struct spi_device *spi =3D st->sdev; - int i, ret; - - for (i =3D 0; i < ARRAY_SIZE(gpios); i++) { - st->gpios[i] =3D devm_gpiod_get(&spi->dev, gpios[i].name, - gpios[i].flags); - if (IS_ERR(st->gpios[i])) { - ret =3D PTR_ERR(st->gpios[i]); - dev_err(&spi->dev, - "ad2s1210: failed to request %s GPIO: %d\n", - gpios[i].name, ret); - return ret; - } - } - - return 0; -} - -static int ad2s1210_probe(struct spi_device *spi) -{ - struct iio_dev *indio_dev; - struct ad2s1210_state *st; - int ret; - - indio_dev =3D devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (!indio_dev) - return -ENOMEM; - st =3D iio_priv(indio_dev); - ret =3D ad2s1210_setup_gpios(st); - if (ret < 0) - return ret; - - spi_set_drvdata(spi, indio_dev); - - mutex_init(&st->lock); - st->sdev =3D spi; - st->hysteresis =3D true; - st->mode =3D MOD_CONFIG; - st->resolution =3D 12; - st->fexcit =3D AD2S1210_DEF_EXCIT; - - indio_dev->info =3D &ad2s1210_info; - indio_dev->modes =3D INDIO_DIRECT_MODE; - indio_dev->channels =3D ad2s1210_channels; - indio_dev->num_channels =3D ARRAY_SIZE(ad2s1210_channels); - indio_dev->name =3D spi_get_device_id(spi)->name; - - ret =3D devm_iio_device_register(&spi->dev, indio_dev); - if (ret) - return ret; - - st->fclkin =3D spi->max_speed_hz; - spi->mode =3D SPI_MODE_3; - spi_setup(spi); - ad2s1210_initial(st); - - return 0; -} - -static const struct of_device_id ad2s1210_of_match[] =3D { - { .compatible =3D "adi,ad2s1210", }, - { } -}; -MODULE_DEVICE_TABLE(of, ad2s1210_of_match); - -static const struct spi_device_id ad2s1210_id[] =3D { - { "ad2s1210" }, - {} -}; -MODULE_DEVICE_TABLE(spi, ad2s1210_id); - -static struct spi_driver ad2s1210_driver =3D { - .driver =3D { - .name =3D DRV_NAME, - .of_match_table =3D of_match_ptr(ad2s1210_of_match), - }, - .probe =3D ad2s1210_probe, - .id_table =3D ad2s1210_id, -}; -module_spi_driver(ad2s1210_driver); - -MODULE_AUTHOR("Graff Yang "); -MODULE_DESCRIPTION("Analog Devices AD2S1210 Resolver to Digital SPI driver= "); -MODULE_LICENSE("GPL v2"); --=20 2.34.1 From nobody Fri Feb 13 19:27:03 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0FBA3C0031C for ; Wed, 20 Sep 2023 17:03:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235239AbjITRDo (ORCPT ); Wed, 20 Sep 2023 13:03:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33492 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235100AbjITRDe (ORCPT ); Wed, 20 Sep 2023 13:03:34 -0400 Received: from mail-wm1-x32b.google.com (mail-wm1-x32b.google.com [IPv6:2a00:1450:4864:20::32b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 14D0EAB for ; Wed, 20 Sep 2023 10:03:25 -0700 (PDT) Received: by mail-wm1-x32b.google.com with SMTP id 5b1f17b1804b1-4052755d5bbso277255e9.2 for ; Wed, 20 Sep 2023 10:03:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1695229403; x=1695834203; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ZinPJ5PYB2eid5QoM+L4lgEz+bW8cvHUuVjkVPgA4pk=; b=j8UUajMdGwVtd3l/SeAm2L6p/J1g9XQXmUeYFIppqIZ4FRz05OWah4K7Ec9DU7YaYV fWKVjx5LBU6kzJ3M0kumbwQUou/mfWz2RlhTe7hYgm4bX5xuiHePnjAu0rhqunpEyAcB gzaH0X+5J/48OyR53vJOkW31k0g3hC7sz/MLPfi4h3giA5t352SANaS8nKEILQzf3jBn NTWKjPhrT50lJrmE13VgQ2NN/rorl74vOtDs1aBwUoLLqqRjrfz0xzdcPuha/gw+OmTM vMSsZfVfTUugFEl1FujCYXAeJ0Q/MQ5yvh4LFOWtmKyj1DF21wWGw3A4stn9C2KBeblP ozlQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1695229403; x=1695834203; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ZinPJ5PYB2eid5QoM+L4lgEz+bW8cvHUuVjkVPgA4pk=; b=OWx4dMNJiRJ7nJTpBZ5AL3l06tmKlSCzE9l3LVYCU9y2JH4YaUTsUzECCTCRUaWMaE T4pagj4DdwUzgXFVTkvd2nCBqQZtPVu0ivilIkGAhRUL49Vsffy3WCkbYyIkDb/8zSzw Fd2cZdYe/1TiwoBrdYuwDF7lBN5p6PHLMZ9httqHLx1vI1A+1ES8YS6cOc7PcJuwztRM c66x3+YNc3VBZhEv4sGYY9MHlbcUZ3H8YRPAvLw84M+4wpDu3FcQHOTexeNk6kPuJ8IG cuJ+OACwswRAhwD/MPQzv9uY37Oi9hCYzS4mpgfyAkpVXpl4lEekWpgqHKPdsYEWNVT5 094A== X-Gm-Message-State: AOJu0Yy6JUjV7YNFK+iz7U2HXhXbNEHEmTRWE2gpX2R8QGtyjzwoifVf LBMm5QOKGUhRJNXzHqoSo9PF5w== X-Google-Smtp-Source: AGHT+IHkKZGhqZcw0k0xvwEozSAZi6uSahTQ7XYP5azIWJt3sy24MLTbjVNR1j+0gncdx74Uc44lNA== X-Received: by 2002:a5d:6b88:0:b0:317:5168:c21f with SMTP id n8-20020a5d6b88000000b003175168c21fmr2838659wrx.31.1695229403189; Wed, 20 Sep 2023 10:03:23 -0700 (PDT) Received: from localhost.localdomain (abordeaux-655-1-129-86.w90-5.abo.wanadoo.fr. [90.5.10.86]) by smtp.gmail.com with ESMTPSA id g10-20020adff3ca000000b003200c918c81sm11221089wrp.112.2023.09.20.10.03.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 20 Sep 2023 10:03:22 -0700 (PDT) From: David Lechner To: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-staging@lists.linux.dev Cc: David Lechner , linux-kernel@vger.kernel.org, Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Michael Hennerich , =?UTF-8?q?Nuno=20S=C3=A1?= , Axel Haslam , Philip Molloy Subject: [PATCH 4/4] iio: resolver: add new driver for AD2S1210 Date: Wed, 20 Sep 2023 12:02:53 -0500 Message-Id: <20230920170253.203395-5-dlechner@baylibre.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230920170253.203395-1-dlechner@baylibre.com> References: <20230920170253.203395-1-dlechner@baylibre.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This adds a new driver for Analog Devices, Inc. AD2S1210 resolver to digital converter. The driver is based on the staging driver with the following improvements: Fixes: - Fix use before initialization bug in probe. - Fix not checking error returns in probe. - Remove spi_setup() and spi_set_drvdata() from probe. - Fix ordering of devm_iio_device_register() - Remove incorrect hysteresis logic Changes: - Use BIT/GENMASK macros. - Use devicetree to get CLKIN frequency (was sysfs attribute). - No longer bit-shift the raw value for IIO_CHAN_INFO_RAW. - Use regmap for register access. - Remove config sysfs attribute. - Use gpio array for mode and resolution gpios. - Invert sample gpio logic and use GPIO_ACTIVE_LOW in devicetree. - Change hysteresis to use IIO_CHAN_INFO_HYSTERESIS instead of custom device attribute. - Rename fexcit attribute to excitation_frequency. - Use devicetree to specify resolution instead of sysfs attribute. Additions: - Implement IIO_CHAN_INFO_SCALE. - Implement debugfs register access. - Add phase_lock_range attribute. - Add triggered buffer support. Signed-off-by: David Lechner --- .../testing/sysfs-bus-iio-resolver-ad2s1210 | 109 ++ drivers/iio/resolver/Kconfig | 13 + drivers/iio/resolver/Makefile | 1 + drivers/iio/resolver/ad2s1210.c | 948 ++++++++++++++++++ 4 files changed, 1071 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-resolver-ad2s12= 10 create mode 100644 drivers/iio/resolver/ad2s1210.c diff --git a/Documentation/ABI/testing/sysfs-bus-iio-resolver-ad2s1210 b/Do= cumentation/ABI/testing/sysfs-bus-iio-resolver-ad2s1210 new file mode 100644 index 000000000000..32890c85168e --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-resolver-ad2s1210 @@ -0,0 +1,109 @@ +What: /sys/bus/iio/devices/iio:deviceX/dos_mis_thrd +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Reading returns the current Degradation of Signal Mismatch + Threshold value. Writing sets the value. Valid values are 0 (0V) + to 127 (4.826V). To convert the value to volts, multiply by + 0.038. + +What: /sys/bus/iio/devices/iio:deviceX/dos_ovr_thrd +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Reading returns the current Degradation of Signal Overrange + Threshold value. Writing sets the value. Valid values are 0 (0V) + to 127 (4.826V). To convert the value to volts, multiply by + 0.038. + +What: /sys/bus/iio/devices/iio:deviceX/dos_rst_max_thrd +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Reading returns the current Degradation of Signal Reset Maximum + Threshold value. Writing sets the value. Valid values are 0 (0V) + to 127 (4.826V). To convert the value to volts, multiply by + 0.038. + +What: /sys/bus/iio/devices/iio:deviceX/dos_rst_min_thrd +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Reading returns the current Degradation of Signal Reset Minimum + Threshold value. Writing sets the value. Valid values are 0 (0V) + to 127 (4.826V). To convert the value to volts, multiply by + 0.038. + +What: /sys/bus/iio/devices/iio:deviceX/fault +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Reading returns a hex value containing the fault bit flags. + + Bit Description + --- ----------- + D7 Sine/cosine inputs clipped + D6 Sine/cosine inputs below LOS threshold + D5 Sine/cosine inputs exceed DOS overrange threshold + D4 Sine/cosine inputs exceed DOS mismatch threshold + D3 Tracking error exceeds LOT threshold + D2 Velocity exceeds maximum tracking rate + D1 Phase error exceeds phase lock range + D0 Configuration parity error + + Writing any value will clear any fault conditions. + +What: /sys/bus/iio/devices/iio:deviceX/excitation_frequency +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Reading returns the current Excitation Frequency in Hz. Writing + sets the Excitation Frequency and performs a software reset on + the device to apply the change. Valid values are 2000 (2kHz) to + 20000 (20kHz). + +What: /sys/bus/iio/devices/iio:deviceX/los_thrd +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Reading returns the current Loss of Signal Reset Threshold + value. Writing sets the value. Valid values are 0 (0V) to + 127 (4.826V). To convert the value to volts, multiply by 0.038. + +What: /sys/bus/iio/devices/iio:deviceX/lot_high_thrd +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Reading returns the current Loss of Position Tracking Detection + High Threshold value. Writing sets the value. Valid values are + 0 (0 deg) to 127 (9/18/45 deg). The interpretation of the value + depends on the selected resolution. To convert the value to + degrees, multiply by 0.35 for 10-bit resolution, multiply by + 0.14 for 12-bit resolution or multiply by 0.09 for 14 and 16-bit + resolution. + +What: /sys/bus/iio/devices/iio:deviceX/lot_low_thrd +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Reading returns the current Loss of Position Tracking Detection + Low Threshold value. Writing sets the value. Valid values are + 0 (0 deg) to 127 (9/18/45 deg). The interpretation of the value + depends on the selected resolution. To convert the value to + degrees, multiply by 0.35 for 10-bit resolution, multiply by + 0.14 for 12-bit resolution or multiply by 0.09 for 14 and 16-bit + resolution. + +What: /sys/bus/iio/devices/iio:deviceX/phase_lock_range +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Reading returns the current Phase lock range in degrees. Writing + sets the value in the configuration register. + +What: /sys/bus/iio/devices/iio:deviceX/phase_lock_range_available +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Reading returns the possible values for the phase_lock_range + attribute, namely 44 and 360. diff --git a/drivers/iio/resolver/Kconfig b/drivers/iio/resolver/Kconfig index 47dbfead9b31..424529d36080 100644 --- a/drivers/iio/resolver/Kconfig +++ b/drivers/iio/resolver/Kconfig @@ -25,4 +25,17 @@ config AD2S1200 =20 To compile this driver as a module, choose M here: the module will be called ad2s1200. + +config AD2S1210 + tristate "Analog Devices ad2s1210 driver" + depends on SPI + depends on COMMON_CLK + depends on GPIOLIB || COMPILE_TEST + help + Say yes here to build support for Analog Devices spi resolver + to digital converters, ad2s1210, provides direct access via sysfs. + + To compile this driver as a module, choose M here: the + module will be called ad2s1210. + endmenu diff --git a/drivers/iio/resolver/Makefile b/drivers/iio/resolver/Makefile index fa558138ce45..7f6c876c35ae 100644 --- a/drivers/iio/resolver/Makefile +++ b/drivers/iio/resolver/Makefile @@ -5,3 +5,4 @@ =20 obj-$(CONFIG_AD2S90) +=3D ad2s90.o obj-$(CONFIG_AD2S1200) +=3D ad2s1200.o +obj-$(CONFIG_AD2S1210) +=3D ad2s1210.o diff --git a/drivers/iio/resolver/ad2s1210.c b/drivers/iio/resolver/ad2s121= 0.c new file mode 100644 index 000000000000..97833fbcbf7a --- /dev/null +++ b/drivers/iio/resolver/ad2s1210.c @@ -0,0 +1,948 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ad2s1210.c support for the ADI Resolver to Digital Converters: AD2S1210 + * + * Copyright (c) 2010-2010 Analog Devices Inc. + * Copyright (C) 2023 BayLibre, SAS + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define DRV_NAME "ad2s1210" + +/* default value of control register on powerup */ +#define AD2S1210_DEF_CONTROL 0x7E + +/* control register flags */ +#define AD2S1210_ADDRESS_DATA BIT(7) +#define AD2S1210_PHASE_LOCK_RANGE_44 BIT(5) +#define AD2S1210_ENABLE_HYSTERESIS BIT(4) +#define AD2S1210_SET_ENRES GENMASK(3, 2) +#define AD2S1210_SET_RES GENMASK(1, 0) + +#define AD2S1210_REG_POSITION_MSB 0x80 +#define AD2S1210_REG_POSITION_LSB 0x81 +#define AD2S1210_REG_VELOCITY_MSB 0x82 +#define AD2S1210_REG_VELOCITY_LSB 0x83 +#define AD2S1210_REG_LOS_THRD 0x88 +#define AD2S1210_REG_DOS_OVR_THRD 0x89 +#define AD2S1210_REG_DOS_MIS_THRD 0x8A +#define AD2S1210_REG_DOS_RST_MAX_THRD 0x8B +#define AD2S1210_REG_DOS_RST_MIN_THRD 0x8C +#define AD2S1210_REG_LOT_HIGH_THRD 0x8D +#define AD2S1210_REG_LOT_LOW_THRD 0x8E +#define AD2S1210_REG_EXCIT_FREQ 0x91 +#define AD2S1210_REG_CONTROL 0x92 +#define AD2S1210_REG_SOFT_RESET 0xF0 +#define AD2S1210_REG_FAULT 0xFF + +#define AD2S1210_MIN_CLKIN 6144000 +#define AD2S1210_MAX_CLKIN 10240000 +#define AD2S1210_MIN_EXCIT 2000 +#define AD2S1210_DEF_EXCIT 10000 +#define AD2S1210_MAX_EXCIT 20000 +#define AD2S1210_MIN_FCW 0x4 +#define AD2S1210_MAX_FCW 0x50 + +enum ad2s1210_mode { + AD2S1210_MODE_POS =3D 0b00, + AD2S1210_MODE_VEL =3D 0b01, + AD2S1210_MODE_CONFIG =3D 0b11, +}; + +enum ad2s1210_resolution { + AD2S1210_RES_10 =3D 0b00, + AD2S1210_RES_12 =3D 0b01, + AD2S1210_RES_14 =3D 0b10, + AD2S1210_RES_16 =3D 0b11, +}; + +struct ad2s1210_state { + struct mutex lock; + struct spi_device *sdev; + /** GPIO pin connected to SAMPLE line. */ + struct gpio_desc *sample_gpio; + /** GPIO pins connected to A0 and A1 lines. */ + struct gpio_descs *mode_gpios; + /** Used to access config registers. */ + struct regmap *regmap; + /** The external oscillator frequency in Hz. */ + unsigned long fclkin; + /** The selected resolution */ + enum ad2s1210_resolution resolution; + /* Scan buffer */ + struct { + __be16 chan[2]; + /* Ensure timestamp is naturally aligned. */ + s64 timestamp __aligned(8); + } scan; + u8 rx[2] __aligned(IIO_DMA_MINALIGN); + u8 tx[2]; +}; + +static int ad2s1210_set_mode(struct ad2s1210_state *st, enum ad2s1210_mode= mode) +{ + struct gpio_descs *gpios =3D st->mode_gpios; + DECLARE_BITMAP(bitmap, 2); + + bitmap[0] =3D mode; + + return gpiod_set_array_value(gpios->ndescs, gpios->desc, gpios->info, + bitmap); +} + +/** + * Writes the given data to the given register address. + * + * If the mode is configurable, the device will first be placed in + * configuration mode. + */ +static int ad2s1210_regmap_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + struct ad2s1210_state *st =3D context; + struct spi_transfer xfers[] =3D { + { + .len =3D 1, + .rx_buf =3D &st->rx[0], + .tx_buf =3D &st->tx[0], + .cs_change =3D 1, + }, { + .len =3D 1, + .rx_buf =3D &st->rx[1], + .tx_buf =3D &st->tx[1], + }, + }; + int ret; + + /* values can only be 7 bits, the MSB indicates an address */ + if (val & ~0x7F) + return -EINVAL; + + st->tx[0] =3D reg; + st->tx[1] =3D val; + + ret =3D ad2s1210_set_mode(st, AD2S1210_MODE_CONFIG); + if (ret < 0) + return ret; + + return spi_sync_transfer(st->sdev, xfers, ARRAY_SIZE(xfers)); +} + +/** + * Reads value from one of the registers. + * + * If the mode is configurable, the device will first be placed in + * configuration mode. + */ +static int ad2s1210_regmap_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct ad2s1210_state *st =3D context; + struct spi_transfer xfers[] =3D { + { + .len =3D 1, + .rx_buf =3D &st->rx[0], + .tx_buf =3D &st->tx[0], + .cs_change =3D 1, + }, { + .len =3D 1, + .rx_buf =3D &st->rx[1], + .tx_buf =3D &st->tx[1], + }, + }; + int ret; + + ret =3D ad2s1210_set_mode(st, AD2S1210_MODE_CONFIG); + if (ret < 0) + return ret; + + st->tx[0] =3D reg; + /* Must be valid register address here otherwise this could write data. + * It doesn't matter which one. + */ + st->tx[1] =3D AD2S1210_REG_FAULT; + + ret =3D spi_sync_transfer(st->sdev, xfers, ARRAY_SIZE(xfers)); + if (ret < 0) + return ret; + + /* If the D7 bit is set on any read/write register, it indicates a + * parity error. The fault register is read-only and the D7 bit means + * something else there. + */ + if (reg !=3D AD2S1210_REG_FAULT && st->rx[1] & AD2S1210_ADDRESS_DATA) + return -EBADMSG; + + *val =3D st->rx[1]; + + return 0; +} + +/** + * Sets the excitation frequency and performs software reset. + * + * Must be called with lock held. + */ +static int ad2s1210_set_excitation_frequency(struct ad2s1210_state *st, + u16 fexcit) +{ + int ret; + u8 fcw; + + fcw =3D fexcit * (1 << 15) / st->fclkin; + if (fcw < AD2S1210_MIN_FCW || fcw > AD2S1210_MAX_FCW) + return -ERANGE; + + ret =3D regmap_write(st->regmap, AD2S1210_REG_EXCIT_FREQ, fcw); + if (ret < 0) + return ret; + + /* software reset reinitializes the excitation frequency output */ + return regmap_write(st->regmap, AD2S1210_REG_SOFT_RESET, 0); +} + +static ssize_t excitation_frequency_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); + unsigned int value; + u16 fexcit; + int ret; + + mutex_lock(&st->lock); + ret =3D regmap_read(st->regmap, AD2S1210_REG_EXCIT_FREQ, &value); + if (ret < 0) + goto error_ret; + + fexcit =3D value * st->fclkin / (1 << 15); + + ret =3D sysfs_emit(buf, "%u\n", fexcit); + +error_ret: + mutex_unlock(&st->lock); + return ret; +} + +static ssize_t excitation_frequency_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); + u16 fexcit; + int ret; + + ret =3D kstrtou16(buf, 10, &fexcit); + if (ret < 0 || fexcit < AD2S1210_MIN_EXCIT || fexcit > AD2S1210_MAX_EXCIT) + return -EINVAL; + + mutex_lock(&st->lock); + ret =3D ad2s1210_set_excitation_frequency(st, fexcit); + if (ret < 0) + goto error_ret; + + ret =3D len; + +error_ret: + mutex_unlock(&st->lock); + + return ret; +} + +static ssize_t phase_lock_range_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); + int ret; + + mutex_lock(&st->lock); + ret =3D regmap_test_bits(st->regmap, AD2S1210_REG_CONTROL, + AD2S1210_PHASE_LOCK_RANGE_44); + if (ret < 0) + goto error_ret; + + ret =3D sysfs_emit(buf, "%d\n", ret ? 44 : 360); + +error_ret: + mutex_unlock(&st->lock); + return ret; +} + +static ssize_t phase_lock_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); + u16 udata; + int ret; + + ret =3D kstrtou16(buf, 10, &udata); + if (ret < 0 || (udata !=3D 44 && udata !=3D 360)) + return -EINVAL; + + mutex_lock(&st->lock); + + ret =3D regmap_update_bits(st->regmap, AD2S1210_REG_CONTROL, + AD2S1210_PHASE_LOCK_RANGE_44, + udata =3D=3D 44 ? AD2S1210_PHASE_LOCK_RANGE_44 : 0); + if (ret < 0) + goto error_ret; + + ret =3D len; + +error_ret: + mutex_unlock(&st->lock); + return ret; +} + +static ssize_t phase_lock_range_available_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "44 360\n"); +} + +/* read the fault register since last sample */ +static ssize_t fault_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); + unsigned int value; + int ret; + + mutex_lock(&st->lock); + ret =3D regmap_read(st->regmap, AD2S1210_REG_FAULT, &value); + mutex_unlock(&st->lock); + + return ret < 0 ? ret : sysfs_emit(buf, "0x%02x\n", value); +} + +static ssize_t fault_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); + unsigned int value; + int ret; + + mutex_lock(&st->lock); + + gpiod_set_value(st->sample_gpio, 1); + /* delay (2 * tck + 20) nano seconds */ + udelay(1); + gpiod_set_value(st->sample_gpio, 0); + + ret =3D regmap_read(st->regmap, AD2S1210_REG_FAULT, &value); + if (ret < 0) + goto error_ret; + + gpiod_set_value(st->sample_gpio, 1); + gpiod_set_value(st->sample_gpio, 0); + +error_ret: + mutex_unlock(&st->lock); + + return ret < 0 ? ret : len; +} + +static ssize_t reg_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); + struct iio_dev_attr *iattr =3D to_iio_dev_attr(attr); + unsigned int value; + int ret; + + mutex_lock(&st->lock); + ret =3D regmap_read(st->regmap, iattr->address, &value); + mutex_unlock(&st->lock); + + return ret < 0 ? ret : sysfs_emit(buf, "%d\n", value); +} + +static ssize_t reg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct ad2s1210_state *st =3D iio_priv(dev_to_iio_dev(dev)); + unsigned char data; + int ret; + struct iio_dev_attr *iattr =3D to_iio_dev_attr(attr); + + ret =3D kstrtou8(buf, 10, &data); + if (ret < 0) + return -EINVAL; + + mutex_lock(&st->lock); + ret =3D regmap_write(st->regmap, iattr->address, data); + mutex_unlock(&st->lock); + return ret < 0 ? ret : len; +} + +static const int ad2s1210_velocity_scale[] =3D { + 17089132, /* 8.192MHz / (2*pi * 2500 / 2^15) */ + 42722830, /* 8.192MHz / (2*pi * 1000 / 2^15) */ + 85445659, /* 8.192MHz / (2*pi * 500 / 2^15) */ + 341782638, /* 8.192MHz / (2*pi * 125 / 2^15) */ +}; + +static int ad2s1210_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + struct ad2s1210_state *st =3D iio_priv(indio_dev); + int ret =3D 0; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&st->lock); + gpiod_set_value(st->sample_gpio, 1); + /* delay (6 * tck + 20) nano seconds */ + udelay(1); + + switch (chan->type) { + case IIO_ANGL: + ret =3D ad2s1210_set_mode(st, AD2S1210_MODE_POS); + break; + case IIO_ANGL_VEL: + ret =3D ad2s1210_set_mode(st, AD2S1210_MODE_VEL); + break; + default: + ret =3D -EINVAL; + break; + } + if (ret < 0) + goto error_info_raw; + ret =3D spi_read(st->sdev, st->rx, 2); + if (ret < 0) + goto error_info_raw; + + switch (chan->type) { + case IIO_ANGL: + *val =3D be16_to_cpup((__be16 *)st->rx); + ret =3D IIO_VAL_INT; + break; + case IIO_ANGL_VEL: + *val =3D (s16)be16_to_cpup((__be16 *)st->rx); + ret =3D IIO_VAL_INT; + break; + default: + ret =3D -EINVAL; + break; + } + +error_info_raw: + gpiod_set_value(st->sample_gpio, 0); + /* delay (2 * tck + 20) nano seconds */ + udelay(1); + mutex_unlock(&st->lock); + break; + + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_ANGL: + /* approx 0.3 arc min converted to radians */ + *val =3D 0; + *val2 =3D 95874; + ret =3D IIO_VAL_INT_PLUS_NANO; + break; + case IIO_ANGL_VEL: + *val =3D st->fclkin; + *val2 =3D ad2s1210_velocity_scale[st->resolution]; + ret =3D IIO_VAL_FRACTIONAL; + break; + default: + ret =3D -EINVAL; + break; + } + break; + + case IIO_CHAN_INFO_HYSTERESIS: + switch (chan->type) { + case IIO_ANGL: + mutex_lock(&st->lock); + ret =3D regmap_test_bits(st->regmap, AD2S1210_REG_CONTROL, + AD2S1210_ENABLE_HYSTERESIS); + if (ret < 0) + goto error_info_hysteresis; + + *val =3D !!ret; + ret =3D IIO_VAL_INT; + +error_info_hysteresis: + mutex_unlock(&st->lock); + break; + default: + ret =3D -EINVAL; + break; + } + break; + + default: + ret =3D -EINVAL; + break; + } + + return ret; +} + +static int ad2s1210_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, + int *length, long mask) +{ + static const int available[] =3D { 0, 1 }; + int ret =3D -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_HYSTERESIS: + switch (chan->type) { + case IIO_ANGL: + *vals =3D available; + *type =3D IIO_VAL_INT; + *length =3D ARRAY_SIZE(available); + ret =3D IIO_AVAIL_LIST; + break; + default: + break; + } + default: + break; + } + + return ret; +} + +static int ad2s1210_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ad2s1210_state *st =3D iio_priv(indio_dev); + int ret =3D -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_HYSTERESIS: + switch (chan->type) { + case IIO_ANGL: + mutex_lock(&st->lock); + ret =3D regmap_update_bits(st->regmap, AD2S1210_REG_CONTROL, + AD2S1210_ENABLE_HYSTERESIS, + val ? AD2S1210_ENABLE_HYSTERESIS + : 0); + mutex_unlock(&st->lock); + break; + + default: + break; + } + break; + + default: + break; + } + + return ret; +} + +static IIO_DEVICE_ATTR_RW(excitation_frequency, 0); +static IIO_DEVICE_ATTR_RW(phase_lock_range, 0); +static IIO_DEVICE_ATTR_RO(phase_lock_range_available, 0); +static IIO_DEVICE_ATTR_RW(fault, 0); +static IIO_DEVICE_ATTR_NAMED_RW(los_thrd, reg, AD2S1210_REG_LOS_THRD); +static IIO_DEVICE_ATTR_NAMED_RW(dos_ovr_thrd, reg, AD2S1210_REG_DOS_OVR_TH= RD); +static IIO_DEVICE_ATTR_NAMED_RW(dos_mis_thrd, reg, AD2S1210_REG_DOS_MIS_TH= RD); +static IIO_DEVICE_ATTR_NAMED_RW(dos_rst_max_thrd, reg, + AD2S1210_REG_DOS_RST_MAX_THRD); +static IIO_DEVICE_ATTR_NAMED_RW(dos_rst_min_thrd, reg, + AD2S1210_REG_DOS_RST_MIN_THRD); +static IIO_DEVICE_ATTR_NAMED_RW(lot_high_thrd, reg, AD2S1210_REG_LOT_HIGH_= THRD); +static IIO_DEVICE_ATTR_NAMED_RW(lot_low_thrd, reg, AD2S1210_REG_LOT_LOW_TH= RD); + +static const struct iio_chan_spec ad2s1210_channels[] =3D { + { + .type =3D IIO_ANGL, + .indexed =3D 1, + .channel =3D 0, + .scan_index =3D 0, + .scan_type =3D { + .sign =3D 'u', + .realbits =3D 16, + .storagebits =3D 16, + .endianness =3D IIO_BE, + }, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_HYSTERESIS), + .info_mask_separate_available =3D + BIT(IIO_CHAN_INFO_HYSTERESIS), + .datasheet_name =3D "position", + }, { + .type =3D IIO_ANGL_VEL, + .indexed =3D 1, + .channel =3D 0, + .scan_index =3D 1, + .scan_type =3D { + .sign =3D 's', + .realbits =3D 16, + .storagebits =3D 16, + .endianness =3D IIO_BE, + }, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .datasheet_name =3D "velocity", + }, + IIO_CHAN_SOFT_TIMESTAMP(2), +}; + +static struct attribute *ad2s1210_attributes[] =3D { + &iio_dev_attr_excitation_frequency.dev_attr.attr, + &iio_dev_attr_phase_lock_range.dev_attr.attr, + &iio_dev_attr_phase_lock_range_available.dev_attr.attr, + &iio_dev_attr_fault.dev_attr.attr, + &iio_dev_attr_los_thrd.dev_attr.attr, + &iio_dev_attr_dos_ovr_thrd.dev_attr.attr, + &iio_dev_attr_dos_mis_thrd.dev_attr.attr, + &iio_dev_attr_dos_rst_max_thrd.dev_attr.attr, + &iio_dev_attr_dos_rst_min_thrd.dev_attr.attr, + &iio_dev_attr_lot_high_thrd.dev_attr.attr, + &iio_dev_attr_lot_low_thrd.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad2s1210_attribute_group =3D { + .attrs =3D ad2s1210_attributes, +}; + +static int ad2s1210_debugfs_reg_access(struct iio_dev *indio_dev, + unsigned int reg, unsigned int writeval, + unsigned int *readval) +{ + struct ad2s1210_state *st =3D iio_priv(indio_dev); + int ret; + + mutex_lock(&st->lock); + + if (readval) + ret =3D regmap_read(st->regmap, reg, readval); + else + ret =3D regmap_write(st->regmap, reg, writeval); + + mutex_unlock(&st->lock); + + return ret; +} + +static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf =3D p; + struct iio_dev *indio_dev =3D pf->indio_dev; + struct ad2s1210_state *st =3D iio_priv(indio_dev); + size_t chan =3D 0; + int ret; + + mutex_lock(&st->lock); + + memset(&st->scan, 0, sizeof(st->scan)); + gpiod_set_value(st->sample_gpio, 1); + + if (test_bit(0, indio_dev->active_scan_mask)) { + ret =3D ad2s1210_set_mode(st, AD2S1210_MODE_POS); + if (ret < 0) + goto error_ret; + + /* REVIST: we can read 3 bytes here and also get fault flags */ + ret =3D spi_read(st->sdev, st->rx, 2); + if (ret < 0) + goto error_ret; + + memcpy(&st->scan.chan[chan++], st->rx, 2); + } + + if (test_bit(1, indio_dev->active_scan_mask)) { + ret =3D ad2s1210_set_mode(st, AD2S1210_MODE_VEL); + if (ret < 0) + goto error_ret; + + /* REVIST: we can read 3 bytes here and also get fault flags */ + ret =3D spi_read(st->sdev, st->rx, 2); + if (ret < 0) + goto error_ret; + + memcpy(&st->scan.chan[chan++], st->rx, 2); + } + + iio_push_to_buffers_with_timestamp(indio_dev, &st->scan, pf->timestamp); + +error_ret: + gpiod_set_value(st->sample_gpio, 0); + mutex_unlock(&st->lock); + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static const struct iio_info ad2s1210_info =3D { + .read_raw =3D ad2s1210_read_raw, + .read_avail =3D ad2s1210_read_avail, + .write_raw =3D ad2s1210_write_raw, + .attrs =3D &ad2s1210_attribute_group, + .debugfs_reg_access =3D &ad2s1210_debugfs_reg_access, +}; + +static int ad2s1210_setup_properties(struct ad2s1210_state *st) +{ + struct device *dev =3D &st->sdev->dev; + u32 val; + int ret; + + ret =3D device_property_read_u32(dev, "assigned-resolution-bits", &val); + if (ret < 0) + return dev_err_probe(dev, ret, + "failed to read assigned-resolution-bits property\n"); + + if (val < 10 || val > 16) + return dev_err_probe(dev, -EINVAL, + "resolution out of range: %u\n", val); + + st->resolution =3D (val - 10) >> 1; + + return 0; +} + +static int ad2s1210_setup_clocks(struct ad2s1210_state *st) +{ + struct device *dev =3D &st->sdev->dev; + struct clk *clk; + + clk =3D devm_clk_get_enabled(dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n"); + + st->fclkin =3D clk_get_rate(clk); + if (st->fclkin < AD2S1210_MIN_CLKIN || st->fclkin > AD2S1210_MAX_CLKIN) + return dev_err_probe(dev, -EINVAL, + "clock frequency out of range: %lu\n", + st->fclkin); + + return 0; +} + +static int ad2s1210_setup_gpios(struct ad2s1210_state *st) +{ + struct device *dev =3D &st->sdev->dev; + struct gpio_descs *resolution_gpios; + DECLARE_BITMAP(bitmap, 2); + int ret; + + /* should not be sampling on startup */ + st->sample_gpio =3D devm_gpiod_get(dev, "sample", GPIOD_OUT_LOW); + if (IS_ERR(st->sample_gpio)) + return dev_err_probe(dev, PTR_ERR(st->sample_gpio), + "failed to request sample GPIO\n"); + + /* both pins high means that we start in config mode */ + st->mode_gpios =3D devm_gpiod_get_array(dev, "mode", GPIOD_OUT_HIGH); + if (IS_ERR(st->mode_gpios)) + return dev_err_probe(dev, PTR_ERR(st->mode_gpios), + "failed to request mode GPIOs\n"); + + if (st->mode_gpios->ndescs !=3D 2) + return dev_err_probe(dev, -EINVAL, + "requires exactly 2 mode-gpios\n"); + + /* If resolution gpios are provided, they get set to the required + * resolution, otherwise it is assumed the RES0 and RES1 pins are + * hard-wired to match the resolution indicated in the devicetree. + */ + resolution_gpios =3D devm_gpiod_get_array_optional(dev, "resolution", + GPIOD_ASIS); + if (IS_ERR(resolution_gpios)) + return dev_err_probe(dev, PTR_ERR(resolution_gpios), + "failed to request resolution GPIOs\n"); + + if (resolution_gpios) { + if (resolution_gpios->ndescs !=3D 2) + return dev_err_probe(dev, -EINVAL, + "requires exactly 2 resolution-gpios\n"); + + bitmap[0] =3D st->resolution; + + ret =3D gpiod_set_array_value(resolution_gpios->ndescs, + resolution_gpios->desc, + resolution_gpios->info, + bitmap); + if (ret < 0) + return dev_err_probe(dev, ret, + "failed to set resolution gpios\n"); + } + + return 0; +} + +static const struct regmap_range ad2s1210_regmap_readable_ranges[] =3D { + regmap_reg_range(AD2S1210_REG_POSITION_MSB, AD2S1210_REG_VELOCITY_LSB), + regmap_reg_range(AD2S1210_REG_LOS_THRD, AD2S1210_REG_LOT_LOW_THRD), + regmap_reg_range(AD2S1210_REG_EXCIT_FREQ, AD2S1210_REG_CONTROL), + regmap_reg_range(AD2S1210_REG_FAULT, AD2S1210_REG_FAULT), +}; + +static const struct regmap_access_table ad2s1210_regmap_rd_table =3D { + .yes_ranges =3D ad2s1210_regmap_readable_ranges, + .n_yes_ranges =3D ARRAY_SIZE(ad2s1210_regmap_readable_ranges), +}; + +static const struct regmap_range ad2s1210_regmap_writeable_ranges[] =3D { + regmap_reg_range(AD2S1210_REG_LOS_THRD, AD2S1210_REG_LOT_LOW_THRD), + regmap_reg_range(AD2S1210_REG_EXCIT_FREQ, AD2S1210_REG_CONTROL), + regmap_reg_range(AD2S1210_REG_SOFT_RESET, AD2S1210_REG_SOFT_RESET), + regmap_reg_range(AD2S1210_REG_FAULT, AD2S1210_REG_FAULT), +}; + +static const struct regmap_access_table ad2s1210_regmap_wr_table =3D { + .yes_ranges =3D ad2s1210_regmap_writeable_ranges, + .n_yes_ranges =3D ARRAY_SIZE(ad2s1210_regmap_writeable_ranges), +}; + +static int ad2s1210_setup_regmap(struct ad2s1210_state *st) +{ + struct device *dev =3D &st->sdev->dev; + const struct regmap_config config =3D { + .reg_bits =3D 8, + .val_bits =3D 8, + .disable_locking =3D true, + .reg_read =3D ad2s1210_regmap_reg_read, + .reg_write =3D ad2s1210_regmap_reg_write, + .rd_table =3D &ad2s1210_regmap_rd_table, + .wr_table =3D &ad2s1210_regmap_wr_table, + .can_sleep =3D true, + }; + + st->regmap =3D devm_regmap_init(dev, NULL, st, &config); + if (IS_ERR(st->regmap)) + return dev_err_probe(dev, PTR_ERR(st->regmap), + "failed to allocate register map\n"); + + return 0; +} + +static int ad2s1210_init(struct ad2s1210_state *st) +{ + unsigned char data; + int ret; + + mutex_lock(&st->lock); + + data =3D AD2S1210_DEF_CONTROL & ~AD2S1210_SET_RES; + data |=3D st->resolution; + + ret =3D regmap_write(st->regmap, AD2S1210_REG_CONTROL, data); + if (ret < 0) + goto error_ret; + + ret =3D ad2s1210_set_excitation_frequency(st, AD2S1210_DEF_EXCIT); + +error_ret: + mutex_unlock(&st->lock); + return ret; +} + +static int ad2s1210_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct ad2s1210_state *st; + int ret; + + indio_dev =3D devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st =3D iio_priv(indio_dev); + + mutex_init(&st->lock); + st->sdev =3D spi; + + ret =3D ad2s1210_setup_properties(st); + if (ret < 0) + return ret; + + ret =3D ad2s1210_setup_clocks(st); + if (ret < 0) + return ret; + + ret =3D ad2s1210_setup_gpios(st); + if (ret < 0) + return ret; + + ret =3D ad2s1210_setup_regmap(st); + if (ret < 0) + return ret; + + ret =3D ad2s1210_init(st); + if (ret < 0) + return ret; + + indio_dev->info =3D &ad2s1210_info; + indio_dev->modes =3D INDIO_DIRECT_MODE; + indio_dev->channels =3D ad2s1210_channels; + indio_dev->num_channels =3D ARRAY_SIZE(ad2s1210_channels); + indio_dev->name =3D spi_get_device_id(spi)->name; + + ret =3D devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, + &iio_pollfunc_store_time, + &ad2s1210_trigger_handler, NULL); + if (ret < 0) + return dev_err_probe(&spi->dev, ret, + "iio triggered buffer setup failed\n"); + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct of_device_id ad2s1210_of_match[] =3D { + { .compatible =3D "adi,ad2s1210", }, + { } +}; +MODULE_DEVICE_TABLE(of, ad2s1210_of_match); + +static const struct spi_device_id ad2s1210_id[] =3D { + { "ad2s1210" }, + { } +}; +MODULE_DEVICE_TABLE(spi, ad2s1210_id); + +static struct spi_driver ad2s1210_driver =3D { + .driver =3D { + .name =3D DRV_NAME, + .of_match_table =3D ad2s1210_of_match, + }, + .probe =3D ad2s1210_probe, + .id_table =3D ad2s1210_id, +}; +module_spi_driver(ad2s1210_driver); + +MODULE_AUTHOR("Graff Yang "); +MODULE_DESCRIPTION("Analog Devices AD2S1210 Resolver to Digital SPI driver= "); +MODULE_LICENSE("GPL v2"); --=20 2.34.1