From patchwork Fri Oct 25 09:49:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Angelo Dureghello X-Patchwork-Id: 13850361 Received: from mail-wm1-f49.google.com (mail-wm1-f49.google.com [209.85.128.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DE9991D4159 for ; Fri, 25 Oct 2024 09:50:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729849860; cv=none; b=PXVZqRVJEyowoVu2pBXRq2kPQJaiDi763JrGxSF2HdwHPIO1LQzNC+y6EmC8JUEqhaByzvwOMsGStf0mlQ7QUEFlRD3WmZ+1LlZMMmJfMAexz+Rlrvb9iJVvKJwDXpy+BpRixJJrKOb+GXrSdUedCN/w1ld6aDe9aZxBm7bPOjg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729849860; c=relaxed/simple; bh=MA2oG/y7V1+Goz7xziXlVN+hyrEb/+ZFaEcTpQoHM1s=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=LT2CxOFJ6ZwP4Jktx2KFxLt7B197Ain1usErcJWdWG0pAg0Kcj2Suq1xvtZO6eq2Wyjk0JAgk/WodF2x+4vOKB1DD1MWan66fprm8c8j9T7tmfBEQslVjcPQr89VsIWV/r42d5cPrYUs6SXVAukiePG3Y5rij8cE0t6Gr+pxEuQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=jG3qPu3w; arc=none smtp.client-ip=209.85.128.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="jG3qPu3w" Received: by mail-wm1-f49.google.com with SMTP id 5b1f17b1804b1-43162cf1eaaso24442735e9.0 for ; Fri, 25 Oct 2024 02:50:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1729849856; x=1730454656; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=y3Jl9+VGm0G8JZ+DzIDolKuvv4I1MhBsGUOVMggicwA=; b=jG3qPu3w6hjd7ymVPk20n8xJK37iBchpm2hF9xM5c4UQTtgIGwW9Nl3D570U21fWyF tx9nKQ3jymp2JtGjqxwV5s+6MKJgcN105VtFz2nIOemGH80mJtO31WkrXuWbygjAtLhv vQhxha7aaz4Px2ptYtefUWMMrqB5UrlQ9gG8LnkUE1hk9Eo85Faytgfv9h6v3gVRC4Su uro6OzS/3/+w8dz2TsUau/U+ZRdCULFNWsjPxlzP7iOBmH6+3O2iv6lvNBoVXepkgdjH r2TRN80mGumKWAA4kG8eXRv8qtriItv4BHfcu0D2b2qVQqDpAbgTLOQH3RV9W5IJOKMR InEg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1729849856; x=1730454656; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=y3Jl9+VGm0G8JZ+DzIDolKuvv4I1MhBsGUOVMggicwA=; b=Q4vyIMu7iERFZHlolhoO2a/y//LBAjWVsvVuAut1w34/ULE06kMeZ+64EqDM4rGc2s zpjM9EwFNKaaXXmiiZFyzpsBV3Cak4E0eNo6LOXW/wJAf/tNg88TqpkwJmDsB0rwOB3f u2E9sbWyAD2jhTU6yu8UH8lSGfmsbOzmmnxYE9s6ahPWvXA2KYo6FGA6tIyU3JYY08aU Hwp/xTk11f0oC2F9xwfqgazXrqnJ1v7j3BqVawDVLuTw1kEas1di/dlgrDea33OC+zfG phEuN5pw96G1FC/swKH/bT7zzd3PtSzVUAYEtkJDkPqFuDqy0vvxrMrkCtsB3a2tnn/7 6L7A== X-Gm-Message-State: AOJu0Yyh9UdgI4ZEvCZNuHKcpPBOm5hRBjSRoDpuPZ23F/xoE3Jfca5u 3tx8BznKKGB8VLTq0aNE0V5l0cPsGXxYsmTYnzhgVOL2d8jw9WR+jT+JQd2Y/GfOfs5YiS7YXf9 gi5PGHA== X-Google-Smtp-Source: AGHT+IGp6FOLRzHC4WGgiEzptHXcfUuJz06Ojf2vMBCrTO1PWzKMoH/swRVXT64yBEJHdmEx2htglA== X-Received: by 2002:a05:600c:3543:b0:42c:b508:750e with SMTP id 5b1f17b1804b1-43184201ddemr84270515e9.11.1729849855699; Fri, 25 Oct 2024 02:50:55 -0700 (PDT) Received: from [127.0.1.1] (host-79-41-194-153.retail.telecomitalia.it. [79.41.194.153]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-431935f6df1sm12895085e9.35.2024.10.25.02.50.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Oct 2024 02:50:55 -0700 (PDT) From: Angelo Dureghello X-Google-Original-From: Angelo Dureghello Date: Fri, 25 Oct 2024 11:49:34 +0200 Subject: [PATCH v8 1/8] dt-bindings: iio: dac: ad3552r: add iio backend support Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-1-74ca7dd60567@baylibre.com> References: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-0-74ca7dd60567@baylibre.com> In-Reply-To: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-0-74ca7dd60567@baylibre.com> To: Lars-Peter Clausen , Michael Hennerich , =?utf-8?q?Nuno_S=C3=A1?= , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Mark Brown , dlechner@baylibre.com, Angelo Dureghello , Conor Dooley X-Mailer: b4 0.14.1 From: Angelo Dureghello There is a version of AXI DAC IP block (for FPGAs) that provides a physical QSPI bus for AD3552R and similar chips, so supporting spi-controller functionalities. For this case, the binding is modified to include some additional properties. Acked-by: Conor Dooley Signed-off-by: Angelo Dureghello --- Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml index 41fe00034742..2d2561a52683 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml @@ -60,6 +60,12 @@ properties: $ref: /schemas/types.yaml#/definitions/uint32 enum: [0, 1, 2, 3] + io-backends: + description: The iio backend reference. + Device can be optionally connected to the "axi-ad3552r IP" fpga-based + QSPI + DDR (Double Data Rate) controller to reach high speed transfers. + maxItems: 1 + '#address-cells': const: 1 @@ -128,6 +134,7 @@ patternProperties: - custom-output-range-config allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# - if: properties: compatible: From patchwork Fri Oct 25 09:49:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Angelo Dureghello X-Patchwork-Id: 13850362 Received: from mail-wm1-f68.google.com (mail-wm1-f68.google.com [209.85.128.68]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 802B61D966F for ; Fri, 25 Oct 2024 09:51:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.68 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729849862; cv=none; b=ZMvW8crljXhDi4cdDg3Gwn8uN4EnbkDW1N4rWlrBlr1nudY2PgTH9uY4HbCnUl23CE56f6GFfMN0Zk1uDafLnbLYLP5gdz/cHsnV98w3DyRc3JP5K4fvTe8EbeIWWCwCh97qRES9amHvMLMmKC1HCkSxdW+QoD1ejIefh/wIU/U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729849862; c=relaxed/simple; bh=ojKSNyD2EVe/IEDwrN7wNa8IQCtyeU4dv9gi0XQu3WA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=s/VrGWzrP4f+GEVJ5pFUXFVV9deAowB5g6rhDvShhW3PBCqqGEp1vCZ69sYDDTZbekiltqYNjK81l+Kyfej+ay74+Mj1bjAGWVZwJp06UWYTC0/5FnFF+jLebbxZBdmnZ4+BypDKL6NxoLbVZ/bsBZgmPea6B1GsPNs8tJFrqeM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=Ft5xk7zE; arc=none smtp.client-ip=209.85.128.68 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="Ft5xk7zE" Received: by mail-wm1-f68.google.com with SMTP id 5b1f17b1804b1-4316f3d3c21so18161025e9.3 for ; Fri, 25 Oct 2024 02:51:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1729849858; x=1730454658; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=6D/EkgzRCNFr6KoXbaTUBYL2k31iFO9iPQDbeDyGB5w=; b=Ft5xk7zE3nekx2+aWnDPPFJ+Ft9/CgUtKSUPaAaDiNRcI5lJ0XZGDHgzSy7S/yOk2z 7gWKcyBmbM3+HSIVOGoTbpMKQZu18/EywWFk9CNqeTAZLOFEJRTba37JbTvKTtXwsTNK E08/AMGEC8RLxWKEUBXWiHGkHqyZ8wBa1NZ3kdmnOQF3nrBkRYB/YpsaDeHKFBVG/zTd FRknN6C12GH3njC8U7OGWfAtZsgMonMk7KASVA8xMnUpMXbKg/FLTqrTxz0alD0G6U/e 6eAV1AEnNRCpRW5AHjmbEBLrNMUlOWifMkI+ikQZUapmUzDEBNEgyduRXfsa+xZcFXKj UUfw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1729849858; x=1730454658; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=6D/EkgzRCNFr6KoXbaTUBYL2k31iFO9iPQDbeDyGB5w=; b=ROfBQMRMxoFRwE7HAphmSJIlYYaY1FhX3tDCSrP+efRmG4DEvkCH1CxNT5Ogu/sb4N gmfoXqJGVIFabqPbwElhsmJ3UOPb2B1HKgzKM3QeRH4tW+TjS3MmDcsG2DuvvxM6F9AT 9Ya8z2mRps8fjjfrACId2f5u3gpmqoBsgf7nE3L7p9FiNoLNfcCfN4kL9Ajy9TXrtwKW Ep5fnqQMu9Gc1OU2MxIpMXVQL2nnfxAzYYBWnHR6LmvIRpB3D8mg1xtY38xq3lbpmZTc PCLgeZuGS+o0O3se10iywdwQEPlDHNtcoUAZxf7MniNMxtKVkYhhonsx+7GmB6RytigQ cvtw== X-Gm-Message-State: AOJu0Yx9lBPdK6m1VXtPw96zncHcnr9yliAeZMF3POisxO9oXhlPcFEO 4RBOZZ4hufrLFZCv4BvlE3iGPc49SiF9sZNOZbbMNJv9vl8vAy6romKzqomSQ/LtIQlN2D2SNKv i5jVmtWo7 X-Google-Smtp-Source: AGHT+IE114LR0WTlntFSwYvAPrjadnxcQND4J2U/6Kz2h7quT6UCFbT41wRpZHjBSlJ4bfiRzrBrrg== X-Received: by 2002:a05:600c:35cd:b0:430:4db0:3fef with SMTP id 5b1f17b1804b1-4318415a2eemr70391325e9.15.1729849858237; Fri, 25 Oct 2024 02:50:58 -0700 (PDT) Received: from [127.0.1.1] (host-79-41-194-153.retail.telecomitalia.it. [79.41.194.153]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-431935f6df1sm12895085e9.35.2024.10.25.02.50.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Oct 2024 02:50:56 -0700 (PDT) From: Angelo Dureghello X-Google-Original-From: Angelo Dureghello Date: Fri, 25 Oct 2024 11:49:35 +0200 Subject: [PATCH v8 2/8] dt-bindings: iio: dac: adi-axi-dac: add ad3552r axi variant Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-2-74ca7dd60567@baylibre.com> References: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-0-74ca7dd60567@baylibre.com> In-Reply-To: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-0-74ca7dd60567@baylibre.com> To: Lars-Peter Clausen , Michael Hennerich , =?utf-8?q?Nuno_S=C3=A1?= , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Mark Brown , dlechner@baylibre.com, Angelo Dureghello X-Mailer: b4 0.14.1 From: Angelo Dureghello Add a new compatible and related bindigns for the fpga-based "ad3552r" AXI IP core, a variant of the generic AXI DAC IP. The AXI "ad3552r" IP is a very similar HDL (fpga) variant of the generic AXI "DAC" IP, intended to control ad3552r and similar chips, mainly to reach high speed transfer rates using a QSPI DDR (dobule-data-rate) interface. The ad3552r device is defined as a child of the AXI DAC, that in this case is acting as an SPI controller. Note, #io-backend is present because it is possible (in theory anyway) to use a separate controller for the control path than that used for the datapath. Signed-off-by: Angelo Dureghello --- .../devicetree/bindings/iio/dac/adi,axi-dac.yaml | 69 +++++++++++++++++++++- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml b/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml index a55e9bfc66d7..1adba9aceeb1 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml @@ -19,11 +19,13 @@ description: | memory via DMA into the DAC. https://wiki.analog.com/resources/fpga/docs/axi_dac_ip + https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html properties: compatible: enum: - adi,axi-dac-9.1.b + - adi,axi-ad3552r reg: maxItems: 1 @@ -36,7 +38,14 @@ properties: - const: tx clocks: - maxItems: 1 + minItems: 1 + maxItems: 2 + + clock-names: + items: + - const: s_axi_aclk + - const: dac_clk + minItems: 1 '#io-backend-cells': const: 0 @@ -47,7 +56,29 @@ required: - reg - clocks -additionalProperties: false +allOf: + - if: + properties: + compatible: + contains: + const: adi,axi-ad3552r + then: + $ref: /schemas/spi/spi-controller.yaml# + properties: + clocks: + minItems: 2 + clock-names: + minItems: 2 + required: + - clock-names + else: + properties: + clocks: + maxItems: 1 + clock-names: + maxItems: 1 + +unevaluatedProperties: false examples: - | @@ -57,6 +88,38 @@ examples: dmas = <&tx_dma 0>; dma-names = "tx"; #io-backend-cells = <0>; - clocks = <&axi_clk>; + clocks = <&clkc 15>; + clock-names = "s_axi_aclk"; + }; + + - | + #include + axi_dac: spi@44a70000 { + compatible = "adi,axi-ad3552r"; + reg = <0x44a70000 0x1000>; + dmas = <&dac_tx_dma 0>; + dma-names = "tx"; + #io-backend-cells = <0>; + clocks = <&clkc 15>, <&ref_clk>; + clock-names = "s_axi_aclk", "dac_clk"; + + #address-cells = <1>; + #size-cells = <0>; + + dac@0 { + compatible = "adi,ad3552r"; + reg = <0>; + reset-gpios = <&gpio0 92 GPIO_ACTIVE_HIGH>; + io-backends = <&axi_dac>; + spi-max-frequency = <20000000>; + + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + adi,output-range-microvolt = <(-10000000) (10000000)>; + }; + }; }; ... From patchwork Fri Oct 25 09:49:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Angelo Dureghello X-Patchwork-Id: 13850363 Received: from mail-wm1-f53.google.com (mail-wm1-f53.google.com [209.85.128.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C5A3B1DB356 for ; Fri, 25 Oct 2024 09:51:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729849864; cv=none; b=fIj0owcgoRCXjfJ1IjF3UZ+3l3vY/p9ZRHzYEVUD/3/4hUGMZQXOvqRh5M73JIYwjWWlF3eC+z6Ufa9/pQFD+tYBEhG8HT53HAHUvhNIoaibUN+Bfh5MBm5ZG7qW5IguriMbbkntSAMvoJ7dAFhlmWxHnzeSvQeE3Zrk5gg9+OY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729849864; c=relaxed/simple; bh=I2hKyJkE5lSaVfqcBggLmA5y3mTRzqksloo07yQRvt0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=lN0HYB8lDFRBc2/GWkwYWlqTPJmhR/28U7uyVbqme73DnNsUeVHUyHcpC+2kUzF3tjr2nNM1E7eFM5nvlUS2nk84V0zAnO/zdOXCB9j3Uz/dmGp2S6TFZeR1MApfKK7iK0kiFOeKAq9lJvMEmfJSZxLW5QB4AWoG2GPE8EIAR34= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=i3iQK5dm; arc=none smtp.client-ip=209.85.128.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="i3iQK5dm" Received: by mail-wm1-f53.google.com with SMTP id 5b1f17b1804b1-4316f3d3c21so18161185e9.3 for ; Fri, 25 Oct 2024 02:51:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1729849860; x=1730454660; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=tXD9nM+zJf+baf8I1HJHQEo8iyVRn909PphK3Jj4Bu4=; b=i3iQK5dmUNIgOUjP4m3NfVGKF0bEq8ARhAeyImmRj4q1FMvPYB7cwBt62fr/7QbxhB BWqB7E2pq7JI+ayHV9eHJ0N4zGl9a95C2pCQmSORPwNPFdmMSzlhu/b+xMcNkENko4cy e8QEXSgjTVdRLvx2C7YYGn3DDd3vQxXtiqUTDQ0egawJHfraBD+D3vi11J+oWMTiWNb/ lQeESqdKX8dkJFmxshigPmrEnhlH9wrwtSVeOd3DL9yCRWoKaqD2pUXqMcK6SrsuTKLo D79acEXDYBWei54aRVDYr5CjgeZliX4eOhJOltBwsEslnawfcuDcJcMDZVpnJhAq8d+W B4ug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1729849860; x=1730454660; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=tXD9nM+zJf+baf8I1HJHQEo8iyVRn909PphK3Jj4Bu4=; b=IX8jwifRAxcMUrVXV3d8Dhji8UagKTEQSkvU7RL8fwkPnnOvjwP58i+3P5KbFBXQUf LlO5toqvBCUxCPRAylXpZoMIt4xiYGOIzyi80Q/3rSRX1OHhTkpfRe1VQ2qLuMjh9WvT AtcFQj3MBipJTzD2ADpKYkdb3V3uOSzTFfySoEhh08TtSu1M04ULcHm5e1rUO4ptbu0K ViSy/9opIgNGrrXfKezpRJBfrOYnHBMGlxVUAYDYcQSUzZZjIbmw7wIkW9NGmrSuSVkM Mq+JSiDNAXIYqv8ySaFL7bxv2KHIgNgoHuDiFKi5EoBdGZqXTBZndgfwU87ybF8Pn/6u UsFA== X-Gm-Message-State: AOJu0YzBJQKj5U5jaHHidmtY5CvyV6Y3/xBHioe1L4jyGPJ+rp5uyHKy sknRBuoXH5Ditq0xBOtc2rfqeOMOWo8tR4EFxHrfR00wh30yOV3mn7u0Z70EgwPbDVPan7CBtKV rCjfvqw== X-Google-Smtp-Source: AGHT+IGbhpft/eVvHp9ifhRbhCWE7pXkG3hpaj8mQK5Pwr2t5UHFmVNJAkHsRXcE6u3rqZxJ1q8PFg== X-Received: by 2002:a05:600c:3b9c:b0:431:60ac:9aef with SMTP id 5b1f17b1804b1-431841a3e07mr83444495e9.29.1729849859843; Fri, 25 Oct 2024 02:50:59 -0700 (PDT) Received: from [127.0.1.1] (host-79-41-194-153.retail.telecomitalia.it. [79.41.194.153]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-431935f6df1sm12895085e9.35.2024.10.25.02.50.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Oct 2024 02:50:59 -0700 (PDT) From: Angelo Dureghello X-Google-Original-From: Angelo Dureghello Date: Fri, 25 Oct 2024 11:49:36 +0200 Subject: [PATCH v8 3/8] iio: backend: extend features Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-3-74ca7dd60567@baylibre.com> References: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-0-74ca7dd60567@baylibre.com> In-Reply-To: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-0-74ca7dd60567@baylibre.com> To: Lars-Peter Clausen , Michael Hennerich , =?utf-8?q?Nuno_S=C3=A1?= , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Mark Brown , dlechner@baylibre.com, Angelo Dureghello X-Mailer: b4 0.14.1 From: Angelo Dureghello Extend backend features with new calls needed later on this patchset from axi version of ad3552r. The follwoing calls are added: iio_backend_ddr_enable() enable ddr bus transfer iio_backend_ddr_disable() disable ddr bus transfer iio_backend_data_stream_enable() enable data stream over bus interface iio_backend_data_stream_disable() disable data stream over bus interface iio_backend_data_transfer_addr() define the target register address where the DAC sample will be written. Reviewed-by: Nuno Sa Signed-off-by: Angelo Dureghello --- drivers/iio/industrialio-backend.c | 78 ++++++++++++++++++++++++++++++++++++++ include/linux/iio/backend.h | 17 +++++++++ 2 files changed, 95 insertions(+) diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c index 20b3b5212da7..81f3d24f0c50 100644 --- a/drivers/iio/industrialio-backend.c +++ b/drivers/iio/industrialio-backend.c @@ -718,6 +718,84 @@ static int __devm_iio_backend_get(struct device *dev, struct iio_backend *back) return 0; } +/** + * iio_backend_ddr_enable - Enable interface DDR (Double Data Rate) mode + * @back: Backend device + * + * Enable DDR, data is generated by the IP at each front (raising and falling) + * of the bus clock signal. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_ddr_enable(struct iio_backend *back) +{ + return iio_backend_op_call(back, ddr_enable); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_enable, IIO_BACKEND); + +/** + * iio_backend_ddr_disable - Disable interface DDR (Double Data Rate) mode + * @back: Backend device + * + * Disable DDR, setting into SDR mode (Single Data Rate). + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_ddr_disable(struct iio_backend *back) +{ + return iio_backend_op_call(back, ddr_disable); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_disable, IIO_BACKEND); + +/** + * iio_backend_data_stream_enable - Enable data stream + * @back: Backend device + * + * Enable data stream over the bus interface. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_data_stream_enable(struct iio_backend *back) +{ + return iio_backend_op_call(back, data_stream_enable); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_data_stream_enable, IIO_BACKEND); + +/** + * iio_backend_data_stream_disable - Disable data stream + * @back: Backend device + * + * Disable data stream over the bus interface. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_data_stream_disable(struct iio_backend *back) +{ + return iio_backend_op_call(back, data_stream_disable); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_data_stream_disable, IIO_BACKEND); + +/** + * iio_backend_data_transfer_addr - Set data address. + * @back: Backend device + * @address: Data register address + * + * Some devices may need to inform the backend about an address + * where to read or write the data. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_data_transfer_addr(struct iio_backend *back, u32 address) +{ + return iio_backend_op_call(back, data_transfer_addr, address); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_data_transfer_addr, IIO_BACKEND); + static struct iio_backend *__devm_iio_backend_fwnode_get(struct device *dev, const char *name, struct fwnode_handle *fwnode) { diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h index 37d56914d485..10be00f3b120 100644 --- a/include/linux/iio/backend.h +++ b/include/linux/iio/backend.h @@ -14,12 +14,14 @@ struct iio_dev; enum iio_backend_data_type { IIO_BACKEND_TWOS_COMPLEMENT, IIO_BACKEND_OFFSET_BINARY, + IIO_BACKEND_DATA_UNSIGNED, IIO_BACKEND_DATA_TYPE_MAX }; enum iio_backend_data_source { IIO_BACKEND_INTERNAL_CONTINUOUS_WAVE, IIO_BACKEND_EXTERNAL, + IIO_BACKEND_INTERNAL_RAMP_16BIT, IIO_BACKEND_DATA_SOURCE_MAX }; @@ -89,6 +91,11 @@ enum iio_backend_sample_trigger { * @read_raw: Read a channel attribute from a backend device * @debugfs_print_chan_status: Print channel status into a buffer. * @debugfs_reg_access: Read or write register value of backend. + * @ddr_enable: Enable interface DDR (Double Data Rate) mode. + * @ddr_disable: Disable interface DDR (Double Data Rate) mode. + * @data_stream_enable: Enable data stream. + * @data_stream_disable: Disable data stream. + * @data_transfer_addr: Set data address. **/ struct iio_backend_ops { int (*enable)(struct iio_backend *back); @@ -129,6 +136,11 @@ struct iio_backend_ops { size_t len); int (*debugfs_reg_access)(struct iio_backend *back, unsigned int reg, unsigned int writeval, unsigned int *readval); + int (*ddr_enable)(struct iio_backend *back); + int (*ddr_disable)(struct iio_backend *back); + int (*data_stream_enable)(struct iio_backend *back); + int (*data_stream_disable)(struct iio_backend *back); + int (*data_transfer_addr)(struct iio_backend *back, u32 address); }; /** @@ -164,6 +176,11 @@ int iio_backend_data_sample_trigger(struct iio_backend *back, int devm_iio_backend_request_buffer(struct device *dev, struct iio_backend *back, struct iio_dev *indio_dev); +int iio_backend_ddr_enable(struct iio_backend *back); +int iio_backend_ddr_disable(struct iio_backend *back); +int iio_backend_data_stream_enable(struct iio_backend *back); +int iio_backend_data_stream_disable(struct iio_backend *back); +int iio_backend_data_transfer_addr(struct iio_backend *back, u32 address); ssize_t iio_backend_ext_info_set(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, const char *buf, size_t len); From patchwork Fri Oct 25 09:49:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Angelo Dureghello X-Patchwork-Id: 13850364 Received: from mail-wm1-f50.google.com (mail-wm1-f50.google.com [209.85.128.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B601C1D4359 for ; Fri, 25 Oct 2024 09:51:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729849866; cv=none; b=AnsxRsvOw1szs67wPuFp0brX66QmWnk7D3rRoS43CGiLxyw5N+mQ1h9xXVXtVPo7DzcZ4+k81Z59ppuS0zfwjWLMT5kS3/pnRaeEWJmYezMJAxBXczdarZqPXb4mW2OPW/f6m2Tuz9Fx3Vr218TFHbAtqzrP2ogCvOoeHX1kwMg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729849866; c=relaxed/simple; bh=t/dNoYyPsk00WJ+Z6LTzlPuEDhwOCIV9BshnuK45DGI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=SaJ/gT1GzyI68wtEay2ykwtYHcpsfxaliSNWYr0oAlWCC7qdtqyCp5IM6Q6pHKMH9DXxVu34JPR0+LMx7r2YU/IDPoGGC1tCKX55MzHTxxdXUqXKwcdV4Iw2hB21CfAxN5/V1Kg4xOBjokzYDlUysq2Fnx7WBzFsBfZCg7MfJWs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=DU/GrUv+; arc=none smtp.client-ip=209.85.128.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="DU/GrUv+" Received: by mail-wm1-f50.google.com with SMTP id 5b1f17b1804b1-43163667f0eso18486065e9.0 for ; Fri, 25 Oct 2024 02:51:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1729849861; x=1730454661; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=BOBvdaI9wOm6bo6Pimz4bWwq5Ue/5MCX88NLsjKCtoo=; b=DU/GrUv+24uI1u3qDUFeZpeDaXF+K4BN0tBpFoDKBLZVfoLJkk80kAk4FvDhQuBJLw dmpT2OrHF5mqcLRrTk/LeDA08s2dvbc58aiOsx8KMElA3RpaFvDK12fsh5rN6B4DtcDi Bg11jiQ1RO2mLBkRpITWCO4OkQO+KOoliedTtTHaNmtWbEEr+q1VdIHuaDzA8v4vpEYX QKOpfbf3lGQf2fMQyhMDTPtGwJA2H+/qUUk9oR6HXlkMgiPa6pJbozDyljFEKp5jhXn/ xnQYmzNANLG6qnbCJVYWwYePhoIxdgatuLK8150vhiS4vr/1V6Rxbov3B6kqzrQ/p8A0 miGg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1729849861; x=1730454661; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BOBvdaI9wOm6bo6Pimz4bWwq5Ue/5MCX88NLsjKCtoo=; b=HhaLIrDwFPSOJmns/HAH3DCZfbPfJswlWBvg7pXYnwKxkC1YO4v9mNCmjnVlDxks9E X6DJkFedcLlqrv45UFCV6/DiDqogofUZuq1vpvWnttOg0qkgWz9Qv9/TDWCR5Im+hw+t AXucjL+7z99XGpWYdY0qRO1LgO2HOyiY+qtmLpU9PLc2CpAAoa/DTzKw3lPBzCb8NnIA uNDPdv2vgutSVPKZj0p2/ptJa17CP0wjZtS+3esH4C71s5D/HAxyCvhFl1W3myYMlCA3 lbeg6Y+t2PUKIcDGuGMG97DK/E28hQDKwsPwAzXdxOmp+Nh55ZAnZkOG26Zw0x3t7g0y TbFA== X-Gm-Message-State: AOJu0Yy1qpy5aeAWU8mnU4+HVCmT/SVcEFyA3dDJPBM3fgDIR6tu8WDJ D6aBwO2nS6Socx1GGuBghDHVE6UcWMlMmYQPHd0KTgdDRf3RB+suTZ5RSDQnm7/QK4bgshJpH3y 1BoJ6Hg== X-Google-Smtp-Source: AGHT+IEVEDI5gj+9cjjnpyCT0zgfpeqe8wK0CM2ImfbEj7cmUKRIDteZ1Ki39Fy1cRMnS1GLHteolg== X-Received: by 2002:a05:600c:1c0f:b0:431:3b53:105e with SMTP id 5b1f17b1804b1-431841fda82mr74719375e9.9.1729849861407; Fri, 25 Oct 2024 02:51:01 -0700 (PDT) Received: from [127.0.1.1] (host-79-41-194-153.retail.telecomitalia.it. [79.41.194.153]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-431935f6df1sm12895085e9.35.2024.10.25.02.51.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Oct 2024 02:51:00 -0700 (PDT) From: Angelo Dureghello X-Google-Original-From: Angelo Dureghello Date: Fri, 25 Oct 2024 11:49:37 +0200 Subject: [PATCH v8 4/8] iio: dac: adi-axi-dac: extend features Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-4-74ca7dd60567@baylibre.com> References: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-0-74ca7dd60567@baylibre.com> In-Reply-To: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-0-74ca7dd60567@baylibre.com> To: Lars-Peter Clausen , Michael Hennerich , =?utf-8?q?Nuno_S=C3=A1?= , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Mark Brown , dlechner@baylibre.com, Angelo Dureghello X-Mailer: b4 0.14.1 From: Angelo Dureghello Extend AXI-DAC backend with new features required to interface to the ad3552r DAC. Mainly, a new compatible string is added to support the ad3552r-axi DAC IP, very similar to the generic DAC IP but with some customizations to work with the ad3552r. Then, a series of generic functions has been added to match with ad3552r needs. Function names has been kept generic as much as possible, to allow re-utilization from other frontend drivers. Signed-off-by: Angelo Dureghello --- drivers/iio/dac/adi-axi-dac.c | 244 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 230 insertions(+), 14 deletions(-) diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c index 04193a98616e..148e40a8ab2a 100644 --- a/drivers/iio/dac/adi-axi-dac.c +++ b/drivers/iio/dac/adi-axi-dac.c @@ -46,9 +46,28 @@ #define AXI_DAC_CNTRL_1_REG 0x0044 #define AXI_DAC_CNTRL_1_SYNC BIT(0) #define AXI_DAC_CNTRL_2_REG 0x0048 +#define AXI_DAC_CNTRL_2_SDR_DDR_N BIT(16) +#define AXI_DAC_CNTRL_2_SYMB_8B BIT(14) #define ADI_DAC_CNTRL_2_R1_MODE BIT(5) +#define AXI_DAC_CNTRL_2_UNSIGNED_DATA BIT(4) +#define AXI_DAC_STATUS_1_REG 0x0054 +#define AXI_DAC_STATUS_2_REG 0x0058 #define AXI_DAC_DRP_STATUS_REG 0x0074 #define AXI_DAC_DRP_STATUS_DRP_LOCKED BIT(17) +#define AXI_DAC_CUSTOM_RD_REG 0x0080 +#define AXI_DAC_CUSTOM_WR_REG 0x0084 +#define AXI_DAC_CUSTOM_WR_DATA_8 GENMASK(23, 16) +#define AXI_DAC_CUSTOM_WR_DATA_16 GENMASK(23, 8) +#define AXI_DAC_UI_STATUS_REG 0x0088 +#define AXI_DAC_UI_STATUS_IF_BUSY BIT(4) +#define AXI_DAC_CUSTOM_CTRL_REG 0x008C +#define AXI_DAC_CUSTOM_CTRL_ADDRESS GENMASK(31, 24) +#define AXI_DAC_CUSTOM_CTRL_SYNCED_TRANSFER BIT(2) +#define AXI_DAC_CUSTOM_CTRL_STREAM BIT(1) +#define AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA BIT(0) + +#define AXI_DAC_CUSTOM_CTRL_STREAM_ENABLE (AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA | \ + AXI_DAC_CUSTOM_CTRL_STREAM) /* DAC Channel controls */ #define AXI_DAC_CHAN_CNTRL_1_REG(c) (0x0400 + (c) * 0x40) @@ -63,12 +82,21 @@ #define AXI_DAC_CHAN_CNTRL_7_REG(c) (0x0418 + (c) * 0x40) #define AXI_DAC_CHAN_CNTRL_7_DATA_SEL GENMASK(3, 0) +#define AXI_DAC_RD_ADDR(x) (BIT(7) | (x)) + /* 360 degrees in rad */ #define AXI_DAC_2_PI_MEGA 6283190 enum { AXI_DAC_DATA_INTERNAL_TONE, AXI_DAC_DATA_DMA = 2, + AXI_DAC_DATA_INTERNAL_RAMP_16BIT = 11, +}; + +struct axi_dac_info { + unsigned int version; + const struct iio_backend_info *backend_info; + bool has_dac_clk; }; struct axi_dac_state { @@ -79,9 +107,11 @@ struct axi_dac_state { * data/variables. */ struct mutex lock; + const struct axi_dac_info *info; u64 dac_clk; u32 reg_config; bool int_tone; + int dac_clk_rate; }; static int axi_dac_enable(struct iio_backend *back) @@ -471,6 +501,11 @@ static int axi_dac_data_source_set(struct iio_backend *back, unsigned int chan, AXI_DAC_CHAN_CNTRL_7_REG(chan), AXI_DAC_CHAN_CNTRL_7_DATA_SEL, AXI_DAC_DATA_DMA); + case IIO_BACKEND_INTERNAL_RAMP_16BIT: + return regmap_update_bits(st->regmap, + AXI_DAC_CHAN_CNTRL_7_REG(chan), + AXI_DAC_CHAN_CNTRL_7_DATA_SEL, + AXI_DAC_DATA_INTERNAL_RAMP_16BIT); default: return -EINVAL; } @@ -528,6 +563,142 @@ static int axi_dac_reg_access(struct iio_backend *back, unsigned int reg, return regmap_write(st->regmap, reg, writeval); } +static int axi_dac_ddr_enable(struct iio_backend *back) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + return regmap_clear_bits(st->regmap, AXI_DAC_CNTRL_2_REG, + AXI_DAC_CNTRL_2_SDR_DDR_N); +} + +static int axi_dac_ddr_disable(struct iio_backend *back) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + return regmap_set_bits(st->regmap, AXI_DAC_CNTRL_2_REG, + AXI_DAC_CNTRL_2_SDR_DDR_N); +} + +static int axi_dac_data_stream_enable(struct iio_backend *back) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + return regmap_set_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG, + AXI_DAC_CUSTOM_CTRL_STREAM_ENABLE); +} + +static int axi_dac_data_stream_disable(struct iio_backend *back) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + return regmap_clear_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG, + AXI_DAC_CUSTOM_CTRL_STREAM_ENABLE); +} + +static int axi_dac_data_transfer_addr(struct iio_backend *back, u32 address) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + if (address > FIELD_MAX(AXI_DAC_CUSTOM_CTRL_ADDRESS)) + return -EINVAL; + + /* + * Sample register address, when the DAC is configured, or stream + * start address when the FSM is in stream state. + */ + return regmap_update_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG, + AXI_DAC_CUSTOM_CTRL_ADDRESS, + FIELD_PREP(AXI_DAC_CUSTOM_CTRL_ADDRESS, + address)); +} + +static int axi_dac_data_format_set(struct iio_backend *back, unsigned int ch, + const struct iio_backend_data_fmt *data) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + switch (data->type) { + case IIO_BACKEND_DATA_UNSIGNED: + return regmap_clear_bits(st->regmap, AXI_DAC_CNTRL_2_REG, + AXI_DAC_CNTRL_2_UNSIGNED_DATA); + default: + return -EINVAL; + } +} + +static int axi_dac_bus_reg_write(struct iio_backend *back, u32 reg, u32 val, + size_t data_size) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + int ret; + u32 ival; + + /* + * Both AXI_DAC_CNTRL_2_REG and AXI_DAC_CUSTOM_WR_REG need to know + * the data size. So keeping data size control here only, + * since data size is mandatory for the current transfer. + * DDR state handled separately by specific backend calls, + * generally all raw register writes are SDR. + */ + if (data_size == sizeof(u16)) + ival = FIELD_PREP(AXI_DAC_CUSTOM_WR_DATA_16, val); + else + ival = FIELD_PREP(AXI_DAC_CUSTOM_WR_DATA_8, val); + + ret = regmap_write(st->regmap, AXI_DAC_CUSTOM_WR_REG, ival); + if (ret) + return ret; + + if (data_size == sizeof(u8)) + ret = regmap_set_bits(st->regmap, AXI_DAC_CNTRL_2_REG, + AXI_DAC_CNTRL_2_SYMB_8B); + else + ret = regmap_clear_bits(st->regmap, AXI_DAC_CNTRL_2_REG, + AXI_DAC_CNTRL_2_SYMB_8B); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG, + AXI_DAC_CUSTOM_CTRL_ADDRESS, + FIELD_PREP(AXI_DAC_CUSTOM_CTRL_ADDRESS, reg)); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG, + AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA, + AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA); + if (ret) + return ret; + + ret = regmap_read_poll_timeout(st->regmap, + AXI_DAC_UI_STATUS_REG, ival, + FIELD_GET(AXI_DAC_UI_STATUS_IF_BUSY, ival) == 0, + 10, 100 * KILO); + if (ret == -ETIMEDOUT) + dev_err(st->dev, "AXI read timeout\n"); + + /* Cleaning always AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA */ + return regmap_clear_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG, + AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA); +} + +static int axi_dac_bus_reg_read(struct iio_backend *back, u32 reg, u32 *val, + size_t data_size) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + int ret; + + /* + * SPI, we write with read flag, then we read just at the AXI + * io address space to get data read. + */ + ret = axi_dac_bus_reg_write(back, AXI_DAC_RD_ADDR(reg), 0, data_size); + if (ret) + return ret; + + return regmap_read(st->regmap, AXI_DAC_CUSTOM_RD_REG, val); +} + static const struct iio_backend_ops axi_dac_generic_ops = { .enable = axi_dac_enable, .disable = axi_dac_disable, @@ -541,11 +712,30 @@ static const struct iio_backend_ops axi_dac_generic_ops = { .debugfs_reg_access = iio_backend_debugfs_ptr(axi_dac_reg_access), }; +static const struct iio_backend_ops axi_ad3552r_ops = { + .enable = axi_dac_enable, + .disable = axi_dac_disable, + .request_buffer = axi_dac_request_buffer, + .free_buffer = axi_dac_free_buffer, + .data_source_set = axi_dac_data_source_set, + .ddr_enable = axi_dac_ddr_enable, + .ddr_disable = axi_dac_ddr_disable, + .data_stream_enable = axi_dac_data_stream_enable, + .data_stream_disable = axi_dac_data_stream_disable, + .data_format_set = axi_dac_data_format_set, + .data_transfer_addr = axi_dac_data_transfer_addr, +}; + static const struct iio_backend_info axi_dac_generic = { .name = "axi-dac", .ops = &axi_dac_generic_ops, }; +static const struct iio_backend_info axi_ad3552r = { + .name = "axi-ad3552r", + .ops = &axi_ad3552r_ops, +}; + static const struct regmap_config axi_dac_regmap_config = { .val_bits = 32, .reg_bits = 32, @@ -555,7 +745,6 @@ static const struct regmap_config axi_dac_regmap_config = { static int axi_dac_probe(struct platform_device *pdev) { - const unsigned int *expected_ver; struct axi_dac_state *st; void __iomem *base; unsigned int ver; @@ -566,14 +755,29 @@ static int axi_dac_probe(struct platform_device *pdev) if (!st) return -ENOMEM; - expected_ver = device_get_match_data(&pdev->dev); - if (!expected_ver) + st->info = device_get_match_data(&pdev->dev); + if (!st->info) return -ENODEV; + clk = devm_clk_get_enabled(&pdev->dev, "s_axi_aclk"); + if (IS_ERR(clk)) { + /* Backward compat., old fdt versions without clock-names. */ + clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(clk), + "failed to get clock\n"); + } + + if (st->info->has_dac_clk) { + struct clk *dac_clk; - clk = devm_clk_get_enabled(&pdev->dev, NULL); - if (IS_ERR(clk)) - return dev_err_probe(&pdev->dev, PTR_ERR(clk), - "failed to get clock\n"); + dac_clk = devm_clk_get_enabled(&pdev->dev, "dac_clk"); + if (IS_ERR(dac_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(dac_clk), + "failed to get dac_clk clock\n"); + + /* We only care about the streaming mode rate */ + st->dac_clk_rate = clk_get_rate(dac_clk) / 2; + } base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) @@ -598,12 +802,13 @@ static int axi_dac_probe(struct platform_device *pdev) if (ret) return ret; - if (ADI_AXI_PCORE_VER_MAJOR(ver) != ADI_AXI_PCORE_VER_MAJOR(*expected_ver)) { + if (ADI_AXI_PCORE_VER_MAJOR(ver) != + ADI_AXI_PCORE_VER_MAJOR(st->info->version)) { dev_err(&pdev->dev, "Major version mismatch. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n", - ADI_AXI_PCORE_VER_MAJOR(*expected_ver), - ADI_AXI_PCORE_VER_MINOR(*expected_ver), - ADI_AXI_PCORE_VER_PATCH(*expected_ver), + ADI_AXI_PCORE_VER_MAJOR(st->info->version), + ADI_AXI_PCORE_VER_MINOR(st->info->version), + ADI_AXI_PCORE_VER_PATCH(st->info->version), ADI_AXI_PCORE_VER_MAJOR(ver), ADI_AXI_PCORE_VER_MINOR(ver), ADI_AXI_PCORE_VER_PATCH(ver)); @@ -629,7 +834,8 @@ static int axi_dac_probe(struct platform_device *pdev) return ret; mutex_init(&st->lock); - ret = devm_iio_backend_register(&pdev->dev, &axi_dac_generic, st); + + ret = devm_iio_backend_register(&pdev->dev, st->info->backend_info, st); if (ret) return dev_err_probe(&pdev->dev, ret, "failed to register iio backend\n"); @@ -642,10 +848,20 @@ static int axi_dac_probe(struct platform_device *pdev) return 0; } -static unsigned int axi_dac_9_1_b_info = ADI_AXI_PCORE_VER(9, 1, 'b'); +static const struct axi_dac_info dac_generic = { + .version = ADI_AXI_PCORE_VER(9, 1, 'b'), + .backend_info = &axi_dac_generic, +}; + +static const struct axi_dac_info dac_ad3552r = { + .version = ADI_AXI_PCORE_VER(9, 1, 'b'), + .backend_info = &axi_ad3552r, + .has_dac_clk = true, +}; static const struct of_device_id axi_dac_of_match[] = { - { .compatible = "adi,axi-dac-9.1.b", .data = &axi_dac_9_1_b_info }, + { .compatible = "adi,axi-dac-9.1.b", .data = &dac_generic }, + { .compatible = "adi,axi-ad3552r", .data = &dac_ad3552r }, {} }; MODULE_DEVICE_TABLE(of, axi_dac_of_match); From patchwork Fri Oct 25 09:49:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Angelo Dureghello X-Patchwork-Id: 13850365 Received: from mail-wr1-f46.google.com (mail-wr1-f46.google.com [209.85.221.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F1E291DD0FA for ; Fri, 25 Oct 2024 09:51:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729849867; cv=none; b=frtlltVaxSpLlo2O5913yrAJqrprsW+iy+u1NTCnXGrDO0nFRX8jzx9+JsFhOJRNtjSYI+Fm0TArcfwHqJjbgaRCdFwdrtzVTLR3UQbvbg8g1z6HrUTO5jLINMlfgbPeb7kl3C8CDfN87kClDtQpNApye79IWYXORi149Pg38RY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729849867; c=relaxed/simple; bh=eFRAax/jOYknJj+mA1u9Mi7x/uS5Vdo459FAQVQK0bc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=B418sMBqgqxJNr9L+IQfPGB10iqWw9QAh7/p78K5WefRy0rhntCCsabtuc8K8HGFNHxklOjp3eWzQ8D1Hxelva1sCbz6UWGkggZ7y1agYSlk6QK7F1M+z2KYpuPTVaqb700gX6TvXfM/E5dlF7DehjCc79BXYpcScRFot/ShYrQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=kylSqFJr; arc=none smtp.client-ip=209.85.221.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="kylSqFJr" Received: by mail-wr1-f46.google.com with SMTP id ffacd0b85a97d-37d3ecad390so2155881f8f.1 for ; Fri, 25 Oct 2024 02:51:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1729849863; x=1730454663; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=18Q0SNLrrGnD6lWyi8jFtTa7c779FJJMLTMpd23PZS4=; b=kylSqFJrekBxAXifacbWibBEj4CzCNwn8JUGRr0FEqr9MK1ZUT6Zbkmlm9uDlGjglI FyL/moV1+nFNg2PPh+RW7oIs0o2Z2IENoGd9D8pxdcow49Q9aJyoYj/w9FwutxUkxWS/ bIf2aMk/1YE7iqDjRmiADRt8Np+nXwxRbui+A5hEHenVkLMPo8kVNv0GNo4zKvcsiigz UHrCv5lU6OXt9Pi7Lm0VoUA39F7OSIat/XfwxqRcHDVP1fWTETDxV5mTJpVKkJS/IFnz GVBqxMHk0HsWz1iCWtnocC5XKyJUnRYtRgZgCquerzCc5NigqcXPBXDsMfkwNN75J30z Q09g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1729849863; x=1730454663; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=18Q0SNLrrGnD6lWyi8jFtTa7c779FJJMLTMpd23PZS4=; b=gwvhli1dEt6CJFuyF2op/br4xR7viH+DcxtzuE7YW8IU0omh5+Bh7g01MCpyBTE5Er HHLUl6T6/kL1eqTXKlHJPedwcHZukyIBikgQeaSmXC6PFLxCo0Yhw0VgJcg04E8mpPdI EGO2neQd4gledWgm7dDLcmBzKhD2hBi7V4ylku/WM2ZfG7pmj4ia7SQGzIdxT9BeaQ6T 2eB213yXcrpC1h4TcK1/9khXtMJGw/r/V/kZBexlFkYTPOybR7CgU4IStMk72PvJBre4 Eqk9ablOsq76FvoEYD2QdgnmMRwEMjYinxJfx8hfMt5LUvK7+yRZANgbwhlR7UdPhPQd EZew== X-Gm-Message-State: AOJu0YxtxhkwbD6M86F7isCKv5WP2sl4L8OhGxLN2rcfj7O/LchDOh/4 pcaEENgmWajco1p6JJZYJ7fynW7oCvXQQT5CaDGbBKkHExgMtK5tc+ubXmTsWmQgkd1HjRlNhaz qb2PqwA== X-Google-Smtp-Source: AGHT+IEFJ+OD12S0zbYeS8PMN9ei3Zm9b7ttX/BfsVKj/cQwLbMevgytncV30ARV8VCaOS85DvHOlQ== X-Received: by 2002:a05:6000:e04:b0:37d:46ad:127f with SMTP id ffacd0b85a97d-38045883804mr3726326f8f.26.1729849862955; Fri, 25 Oct 2024 02:51:02 -0700 (PDT) Received: from [127.0.1.1] (host-79-41-194-153.retail.telecomitalia.it. [79.41.194.153]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-431935f6df1sm12895085e9.35.2024.10.25.02.51.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Oct 2024 02:51:02 -0700 (PDT) From: Angelo Dureghello X-Google-Original-From: Angelo Dureghello Date: Fri, 25 Oct 2024 11:49:38 +0200 Subject: [PATCH v8 5/8] iio: dac: ad3552r: changes to use FIELD_PREP Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-5-74ca7dd60567@baylibre.com> References: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-0-74ca7dd60567@baylibre.com> In-Reply-To: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-0-74ca7dd60567@baylibre.com> To: Lars-Peter Clausen , Michael Hennerich , =?utf-8?q?Nuno_S=C3=A1?= , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Mark Brown , dlechner@baylibre.com, Angelo Dureghello X-Mailer: b4 0.14.1 From: Angelo Dureghello Changes to use FIELD_PREP, so that driver-specific ad3552r_field_prep is removed. Variables (arrays) that was used to call ad3552r_field_prep are removed too. Signed-off-by: Angelo Dureghello --- drivers/iio/dac/ad3552r.c | 166 ++++++++++++++-------------------------------- 1 file changed, 49 insertions(+), 117 deletions(-) diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c index 7d61b2fe6624..75825d6a398b 100644 --- a/drivers/iio/dac/ad3552r.c +++ b/drivers/iio/dac/ad3552r.c @@ -210,46 +210,6 @@ static const s32 gains_scaling_table[] = { [AD3552R_CH_GAIN_SCALING_0_125] = 125 }; -enum ad3552r_dev_attributes { - /* - Direct register values */ - /* From 0-3 */ - AD3552R_SDO_DRIVE_STRENGTH, - /* - * 0 -> Internal Vref, vref_io pin floating (default) - * 1 -> Internal Vref, vref_io driven by internal vref - * 2 or 3 -> External Vref - */ - AD3552R_VREF_SELECT, - /* Read registers in ascending order if set. Else descending */ - AD3552R_ADDR_ASCENSION, -}; - -enum ad3552r_ch_attributes { - /* DAC powerdown */ - AD3552R_CH_DAC_POWERDOWN, - /* DAC amplifier powerdown */ - AD3552R_CH_AMPLIFIER_POWERDOWN, - /* Select the output range. Select from enum ad3552r_ch_output_range */ - AD3552R_CH_OUTPUT_RANGE_SEL, - /* - * Over-rider the range selector in order to manually set the output - * voltage range - */ - AD3552R_CH_RANGE_OVERRIDE, - /* Manually set the offset voltage */ - AD3552R_CH_GAIN_OFFSET, - /* Sets the polarity of the offset. */ - AD3552R_CH_GAIN_OFFSET_POLARITY, - /* PDAC gain scaling */ - AD3552R_CH_GAIN_SCALING_P, - /* NDAC gain scaling */ - AD3552R_CH_GAIN_SCALING_N, - /* Rfb value */ - AD3552R_CH_RFB, - /* Channel select. When set allow Input -> DAC and Mask -> DAC */ - AD3552R_CH_SELECT, -}; - struct ad3552r_ch_data { s32 scale_int; s32 scale_dec; @@ -285,45 +245,6 @@ struct ad3552r_desc { unsigned int num_ch; }; -static const u16 addr_mask_map[][2] = { - [AD3552R_ADDR_ASCENSION] = { - AD3552R_REG_ADDR_INTERFACE_CONFIG_A, - AD3552R_MASK_ADDR_ASCENSION - }, - [AD3552R_SDO_DRIVE_STRENGTH] = { - AD3552R_REG_ADDR_INTERFACE_CONFIG_D, - AD3552R_MASK_SDO_DRIVE_STRENGTH - }, - [AD3552R_VREF_SELECT] = { - AD3552R_REG_ADDR_SH_REFERENCE_CONFIG, - AD3552R_MASK_REFERENCE_VOLTAGE_SEL - }, -}; - -/* 0 -> reg addr, 1->ch0 mask, 2->ch1 mask */ -static const u16 addr_mask_map_ch[][3] = { - [AD3552R_CH_DAC_POWERDOWN] = { - AD3552R_REG_ADDR_POWERDOWN_CONFIG, - AD3552R_MASK_CH_DAC_POWERDOWN(0), - AD3552R_MASK_CH_DAC_POWERDOWN(1) - }, - [AD3552R_CH_AMPLIFIER_POWERDOWN] = { - AD3552R_REG_ADDR_POWERDOWN_CONFIG, - AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(0), - AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(1) - }, - [AD3552R_CH_OUTPUT_RANGE_SEL] = { - AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE, - AD3552R_MASK_CH_OUTPUT_RANGE_SEL(0), - AD3552R_MASK_CH_OUTPUT_RANGE_SEL(1) - }, - [AD3552R_CH_SELECT] = { - AD3552R_REG_ADDR_CH_SELECT_16B, - AD3552R_MASK_CH(0), - AD3552R_MASK_CH(1) - } -}; - static u8 _ad3552r_reg_len(u8 addr) { switch (addr) { @@ -399,11 +320,6 @@ static int ad3552r_read_reg(struct ad3552r_desc *dac, u8 addr, u16 *val) return 0; } -static u16 ad3552r_field_prep(u16 val, u16 mask) -{ - return (val << __ffs(mask)) & mask; -} - /* Update field of a register, shift val if needed */ static int ad3552r_update_reg_field(struct ad3552r_desc *dac, u8 addr, u16 mask, u16 val) @@ -416,21 +332,11 @@ static int ad3552r_update_reg_field(struct ad3552r_desc *dac, u8 addr, u16 mask, return ret; reg &= ~mask; - reg |= ad3552r_field_prep(val, mask); + reg |= val; return ad3552r_write_reg(dac, addr, reg); } -static int ad3552r_set_ch_value(struct ad3552r_desc *dac, - enum ad3552r_ch_attributes attr, - u8 ch, - u16 val) -{ - /* Update register related to attributes in chip */ - return ad3552r_update_reg_field(dac, addr_mask_map_ch[attr][0], - addr_mask_map_ch[attr][ch + 1], val); -} - #define AD3552R_CH_DAC(_idx) ((struct iio_chan_spec) { \ .type = IIO_VOLTAGE, \ .output = true, \ @@ -510,8 +416,14 @@ static int ad3552r_write_raw(struct iio_dev *indio_dev, val); break; case IIO_CHAN_INFO_ENABLE: - err = ad3552r_set_ch_value(dac, AD3552R_CH_DAC_POWERDOWN, - chan->channel, !val); + if (chan->channel == 0) + val = FIELD_PREP(AD3552R_MASK_CH_DAC_POWERDOWN(0), !val); + else + val = FIELD_PREP(AD3552R_MASK_CH_DAC_POWERDOWN(1), !val); + + err = ad3552r_update_reg_field(dac, AD3552R_REG_ADDR_POWERDOWN_CONFIG, + AD3552R_MASK_CH_DAC_POWERDOWN(chan->channel), + val); break; default: err = -EINVAL; @@ -715,9 +627,9 @@ static int ad3552r_reset(struct ad3552r_desc *dac) } return ad3552r_update_reg_field(dac, - addr_mask_map[AD3552R_ADDR_ASCENSION][0], - addr_mask_map[AD3552R_ADDR_ASCENSION][1], - val); + AD3552R_REG_ADDR_INTERFACE_CONFIG_A, + AD3552R_MASK_ADDR_ASCENSION, + FIELD_PREP(AD3552R_MASK_ADDR_ASCENSION, val)); } static void ad3552r_get_custom_range(struct ad3552r_desc *dac, s32 i, s32 *v_min, @@ -812,20 +724,20 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac, "mandatory custom-output-range-config property missing\n"); dac->ch_data[ch].range_override = 1; - reg |= ad3552r_field_prep(1, AD3552R_MASK_CH_RANGE_OVERRIDE); + reg |= FIELD_PREP(AD3552R_MASK_CH_RANGE_OVERRIDE, 1); err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val); if (err) return dev_err_probe(dev, err, "mandatory adi,gain-scaling-p property missing\n"); - reg |= ad3552r_field_prep(val, AD3552R_MASK_CH_GAIN_SCALING_P); + reg |= FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_P, val); dac->ch_data[ch].p = val; err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val); if (err) return dev_err_probe(dev, err, "mandatory adi,gain-scaling-n property missing\n"); - reg |= ad3552r_field_prep(val, AD3552R_MASK_CH_GAIN_SCALING_N); + reg |= FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_N, val); dac->ch_data[ch].n = val; err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val); @@ -841,9 +753,9 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac, dac->ch_data[ch].gain_offset = val; offset = abs((s32)val); - reg |= ad3552r_field_prep((offset >> 8), AD3552R_MASK_CH_OFFSET_BIT_8); + reg |= FIELD_PREP(AD3552R_MASK_CH_OFFSET_BIT_8, (offset >> 8)); - reg |= ad3552r_field_prep((s32)val < 0, AD3552R_MASK_CH_OFFSET_POLARITY); + reg |= FIELD_PREP(AD3552R_MASK_CH_OFFSET_POLARITY, (s32)val < 0); addr = AD3552R_REG_ADDR_CH_GAIN(ch); err = ad3552r_write_reg(dac, addr, offset & AD3552R_MASK_CH_OFFSET_BITS_0_7); @@ -886,9 +798,9 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) } err = ad3552r_update_reg_field(dac, - addr_mask_map[AD3552R_VREF_SELECT][0], - addr_mask_map[AD3552R_VREF_SELECT][1], - val); + AD3552R_REG_ADDR_SH_REFERENCE_CONFIG, + AD3552R_MASK_REFERENCE_VOLTAGE_SEL, + FIELD_PREP(AD3552R_MASK_REFERENCE_VOLTAGE_SEL, val)); if (err) return err; @@ -900,9 +812,9 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) } err = ad3552r_update_reg_field(dac, - addr_mask_map[AD3552R_SDO_DRIVE_STRENGTH][0], - addr_mask_map[AD3552R_SDO_DRIVE_STRENGTH][1], - val); + AD3552R_REG_ADDR_INTERFACE_CONFIG_D, + AD3552R_MASK_SDO_DRIVE_STRENGTH, + FIELD_PREP(AD3552R_MASK_SDO_DRIVE_STRENGTH, val)); if (err) return err; } @@ -938,9 +850,15 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) "Invalid adi,output-range-microvolt value\n"); val = err; - err = ad3552r_set_ch_value(dac, - AD3552R_CH_OUTPUT_RANGE_SEL, - ch, val); + if (ch == 0) + val = FIELD_PREP(AD3552R_MASK_CH_OUTPUT_RANGE_SEL(0), val); + else + val = FIELD_PREP(AD3552R_MASK_CH_OUTPUT_RANGE_SEL(1), val); + + err = ad3552r_update_reg_field(dac, + AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE, + AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch), + val); if (err) return err; @@ -958,7 +876,14 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) ad3552r_calc_gain_and_offset(dac, ch); dac->enabled_ch |= BIT(ch); - err = ad3552r_set_ch_value(dac, AD3552R_CH_SELECT, ch, 1); + if (ch == 0) + val = FIELD_PREP(AD3552R_MASK_CH(0), 1); + else + val = FIELD_PREP(AD3552R_MASK_CH(1), 1); + + err = ad3552r_update_reg_field(dac, + AD3552R_REG_ADDR_CH_SELECT_16B, + AD3552R_MASK_CH(ch), val); if (err < 0) return err; @@ -970,8 +895,15 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) /* Disable unused channels */ for_each_clear_bit(ch, &dac->enabled_ch, dac->model_data->num_hw_channels) { - err = ad3552r_set_ch_value(dac, AD3552R_CH_AMPLIFIER_POWERDOWN, - ch, 1); + if (ch == 0) + val = FIELD_PREP(AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(0), 1); + else + val = FIELD_PREP(AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(1), 1); + + err = ad3552r_update_reg_field(dac, + AD3552R_REG_ADDR_POWERDOWN_CONFIG, + AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch), + val); if (err) return err; } From patchwork Fri Oct 25 09:49:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Angelo Dureghello X-Patchwork-Id: 13850367 Received: from mail-lf1-f48.google.com (mail-lf1-f48.google.com [209.85.167.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 31C361DD0FA for ; Fri, 25 Oct 2024 09:51:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729849873; cv=none; b=nvxhcDeHbRF96SDcpHvbqom2EdYJSXDWXR6iK4dNKWlLJLc7Jbop9SNh1MPHcd/gsXsPYbqWcze28hebcPPz15Bvohw/phRYYni4I3umtM717+eBCGCExGykrJCe8G75DIC3OSOiGZgG/fZ0DnTIGGdvHiFlr/lvLgbAi8Xdox8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729849873; c=relaxed/simple; bh=z3pMsYq/WCjJ5cGi5DZHS/I9h7QpOytsVxUzZssEfU8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=a6KUP+8ed9EDTAZEDkl749mlyTHuqZaL7TPslAZ/Uzz9T08hT8B9YED8Tz6Q5Mcr3Sqme1OqM4IFWb786JajT5SNL8FzH6Ena6Vv0+qTdkG//q0B0k0LKm5MRtW5j1Mf2Nw5oCpXEU4Max+l6LiDIJUrPmA7wRVckNmRJKBIKnI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=CjdFySvN; arc=none smtp.client-ip=209.85.167.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="CjdFySvN" Received: by mail-lf1-f48.google.com with SMTP id 2adb3069b0e04-539e13375d3so2195207e87.3 for ; Fri, 25 Oct 2024 02:51:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1729849866; x=1730454666; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=3LP2SK3ImgeSsfc3Kk3d1CrxyYM7oitcHbek/7ETa9o=; b=CjdFySvN+EDGjbOO8IA82ZswCOoqCo/ubjbquDhkAD6yJrrgPItgLcTAYP41NYjVbV 4Qh+MhOuiXqmfqfMn94jo1u5I63WqxbAqJf7X8wncgxd/YJPwvVpGBAitQXcgaiEuPQ2 UC/A43NWJKySU2hfSKdbMA49EoXN8n43PpVuCUBXrsIiAfOngwoRmR6vru+rzzl7MXKz WuIHUkZxiwSoULDgUQi8cdLnEPPQso62ydm1x394oKKP2bpac3487cnvbQwaYJV7rAip l7Tkj9Ug93RB3vRu5iSAw6thGu/wvYt+2lO4X4a7Vrov+jqG/2iAmGGt9PyaeNPPhewk Ci9g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1729849866; x=1730454666; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=3LP2SK3ImgeSsfc3Kk3d1CrxyYM7oitcHbek/7ETa9o=; b=nWFaJHiYC8r1PnYF7aD6QYYdVIXAahge7NH94YceNFlbcarv7xDu74L2TI3GkAMcW3 eQDV2byupQ6EVNNPtxV50G/sUeXg5lBJLcja7J5oSseUPjN3nbCXjkVVfkVMEgm9k5mW j0Rp7l6nezKIjarbBPZqi2g6O4PMXI4AUc1otPHHo2NYooxfPrtf0DAQ6byJJF3+96IV EvvqjhGZkyXrSUyKQc/+1GcPGt29cRXy/nNyFrGvXlRBa8d28KJ1OBLsU3/wkO1RvUHj 9MGfczwK5Y7ZJ4hQlkIN06rizoXEe/EmmidnrbWNVgxWL2QHomBCrefRBbgY5esDRS24 Z2Jw== X-Gm-Message-State: AOJu0YwTeVQQRJO9MrUCiufmweGubnDLWDqQUVQ1bgtfftKX86hKhb2S KFFlnfNRN37nRyeQa34sUMNjub1JvjFIbHLTIZVXUGCKt9ZA2Ig1Vd/meIuTbPn+Iwo7r22QtTo zyEjbtQ== X-Google-Smtp-Source: AGHT+IGeKTIiekGEU2YXwtNJbKm4AdvByUFDKwaN7aLcVEwW3v81Sh+lpNL8Ji+hyT4LVxwJ6S+xrA== X-Received: by 2002:a05:651c:1508:b0:2fb:351c:c3c9 with SMTP id 38308e7fff4ca-2fc9d5982bdmr50368471fa.44.1729849865633; Fri, 25 Oct 2024 02:51:05 -0700 (PDT) Received: from [127.0.1.1] (host-79-41-194-153.retail.telecomitalia.it. [79.41.194.153]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-431935f6df1sm12895085e9.35.2024.10.25.02.51.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Oct 2024 02:51:05 -0700 (PDT) From: Angelo Dureghello X-Google-Original-From: Angelo Dureghello Date: Fri, 25 Oct 2024 11:49:39 +0200 Subject: [PATCH v8 6/8] iio: dac: ad3552r: extract common code (no changes in behavior intended) Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-6-74ca7dd60567@baylibre.com> References: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-0-74ca7dd60567@baylibre.com> In-Reply-To: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-0-74ca7dd60567@baylibre.com> To: Lars-Peter Clausen , Michael Hennerich , =?utf-8?q?Nuno_S=C3=A1?= , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Mark Brown , dlechner@baylibre.com, Angelo Dureghello X-Mailer: b4 0.14.1 From: Angelo Dureghello Extracting common code, to share common code to be used later by the AXI driver version (ad3552r-axi.c). Signed-off-by: Angelo Dureghello --- drivers/iio/dac/Makefile | 2 +- drivers/iio/dac/ad3552r-common.c | 248 ++++++++++++++++++++++++ drivers/iio/dac/ad3552r.c | 398 +++------------------------------------ drivers/iio/dac/ad3552r.h | 226 ++++++++++++++++++++++ 4 files changed, 502 insertions(+), 372 deletions(-) diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 621d553bd6e3..c92de0366238 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -4,7 +4,7 @@ # # When adding new entries keep the list in alphabetical order -obj-$(CONFIG_AD3552R) += ad3552r.o +obj-$(CONFIG_AD3552R) += ad3552r.o ad3552r-common.o obj-$(CONFIG_AD5360) += ad5360.o obj-$(CONFIG_AD5380) += ad5380.o obj-$(CONFIG_AD5421) += ad5421.o diff --git a/drivers/iio/dac/ad3552r-common.c b/drivers/iio/dac/ad3552r-common.c new file mode 100644 index 000000000000..672f0284bc05 --- /dev/null +++ b/drivers/iio/dac/ad3552r-common.c @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (c) 2010-2024 Analog Devices Inc. +// Copyright (c) 2024 Baylibre, SAS + +#include +#include +#include +#include + +#include "ad3552r.h" + +const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2] = { + [AD3552R_CH_OUTPUT_RANGE_0__2P5V] = { 0, 2500 }, + [AD3552R_CH_OUTPUT_RANGE_0__5V] = { 0, 5000 }, + [AD3552R_CH_OUTPUT_RANGE_0__10V] = { 0, 10000 }, + [AD3552R_CH_OUTPUT_RANGE_NEG_5__5V] = { -5000, 5000 }, + [AD3552R_CH_OUTPUT_RANGE_NEG_10__10V] = { -10000, 10000 } +}; +EXPORT_SYMBOL_NS_GPL(ad3552r_ch_ranges, IIO_AD3552R); + +const s32 ad3542r_ch_ranges[AD3542R_MAX_RANGES][2] = { + [AD3542R_CH_OUTPUT_RANGE_0__2P5V] = { 0, 2500 }, + [AD3542R_CH_OUTPUT_RANGE_0__3V] = { 0, 3000 }, + [AD3542R_CH_OUTPUT_RANGE_0__5V] = { 0, 5000 }, + [AD3542R_CH_OUTPUT_RANGE_0__10V] = { 0, 10000 }, + [AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V] = { -2500, 7500 }, + [AD3542R_CH_OUTPUT_RANGE_NEG_5__5V] = { -5000, 5000 } +}; +EXPORT_SYMBOL_NS_GPL(ad3542r_ch_ranges, IIO_AD3552R); + +/* Gain * AD3552R_GAIN_SCALE */ +static const s32 gains_scaling_table[] = { + [AD3552R_CH_GAIN_SCALING_1] = 1000, + [AD3552R_CH_GAIN_SCALING_0_5] = 500, + [AD3552R_CH_GAIN_SCALING_0_25] = 250, + [AD3552R_CH_GAIN_SCALING_0_125] = 125 +}; + +u16 ad3552r_calc_custom_gain(u8 p, u8 n, s16 goffs) +{ + return FIELD_PREP(AD3552R_MASK_CH_RANGE_OVERRIDE, 1) | + FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_P, p) | + FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_N, n) | + FIELD_PREP(AD3552R_MASK_CH_OFFSET_BIT_8, abs(goffs)) | + FIELD_PREP(AD3552R_MASK_CH_OFFSET_POLARITY, goffs < 0); +} +EXPORT_SYMBOL_NS_GPL(ad3552r_calc_custom_gain, IIO_AD3552R); + +static void ad3552r_get_custom_range(struct ad3552r_ch_data *ch_data, + s32 *v_min, s32 *v_max) +{ + s64 vref, tmp, common, offset, gn, gp; + /* + * From datasheet formula (In Volts): + * Vmin = 2.5 + [(GainN + Offset / 1024) * 2.5 * Rfb * 1.03] + * Vmax = 2.5 - [(GainP + Offset / 1024) * 2.5 * Rfb * 1.03] + * Calculus are converted to milivolts + */ + vref = 2500; + /* 2.5 * 1.03 * 1000 (To mV) */ + common = 2575 * ch_data->rfb; + offset = ch_data->gain_offset; + + gn = gains_scaling_table[ch_data->n]; + tmp = (1024 * gn + AD3552R_GAIN_SCALE * offset) * common; + tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE); + *v_max = vref + tmp; + + gp = gains_scaling_table[ch_data->p]; + tmp = (1024 * gp - AD3552R_GAIN_SCALE * offset) * common; + tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE); + *v_min = vref - tmp; +} + +void ad3552r_calc_gain_and_offset(struct ad3552r_ch_data *ch_data, + const struct ad3552r_model_data *model_data) +{ + s32 idx, v_max, v_min, span, rem; + s64 tmp; + + if (ch_data->range_override) { + ad3552r_get_custom_range(ch_data, &v_min, &v_max); + } else { + /* Normal range */ + idx = ch_data->range; + v_min = model_data->ranges_table[idx][0]; + v_max = model_data->ranges_table[idx][1]; + } + + /* + * From datasheet formula: + * Vout = Span * (D / 65536) + Vmin + * Converted to scale and offset: + * Scale = Span / 65536 + * Offset = 65536 * Vmin / Span + * + * Reminders are in micros in order to be printed as + * IIO_VAL_INT_PLUS_MICRO + */ + span = v_max - v_min; + ch_data->scale_int = div_s64_rem(span, 65536, &rem); + /* Do operations in microvolts */ + ch_data->scale_dec = DIV_ROUND_CLOSEST((s64)rem * 1000000, 65536); + + ch_data->offset_int = div_s64_rem(v_min * 65536, span, &rem); + tmp = (s64)rem * 1000000; + ch_data->offset_dec = div_s64(tmp, span); +} +EXPORT_SYMBOL_NS_GPL(ad3552r_calc_gain_and_offset, IIO_AD3552R); + +int ad3552r_get_ref_voltage(struct device *dev, u32 *val) +{ + int voltage; + int delta = 100000; + + voltage = devm_regulator_get_enable_read_voltage(dev, "vref"); + if (voltage < 0 && voltage != -ENODEV) + return dev_err_probe(dev, voltage, + "Error getting vref voltage\n"); + + if (voltage == -ENODEV) { + if (device_property_read_bool(dev, "adi,vref-out-en")) + *val = AD3552R_INTERNAL_VREF_PIN_2P5V; + else + *val = AD3552R_INTERNAL_VREF_PIN_FLOATING; + + return 0; + } + + if (voltage > 2500000 + delta || voltage < 2500000 - delta) { + dev_warn(dev, "vref-supply must be 2.5V"); + return -EINVAL; + } + + *val = AD3552R_EXTERNAL_VREF_PIN_INPUT; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ad3552r_get_ref_voltage, IIO_AD3552R); + +int ad3552r_get_drive_strength(struct device *dev, u32 *val) +{ + int err; + u32 drive_strength; + + err = device_property_read_u32(dev, "adi,sdo-drive-strength", + &drive_strength); + if (err) + return err; + + if (drive_strength > 3) { + dev_err_probe(dev, -EINVAL, + "adi,sdo-drive-strength must be less than 4\n"); + return -EINVAL; + } + + *val = drive_strength; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ad3552r_get_drive_strength, IIO_AD3552R); + +int ad3552r_get_custom_gain(struct device *dev, struct fwnode_handle *child, + u8 *gs_p, u8 *gs_n, u16 *rfb, s16 *goffs) +{ + int err; + u32 val; + struct fwnode_handle *gain_child __free(fwnode_handle) = + fwnode_get_named_child_node(child, + "custom-output-range-config"); + + if (!gain_child) + return dev_err_probe(dev, -EINVAL, + "custom-output-range-config mandatory\n"); + + err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val); + if (err) + return dev_err_probe(dev, err, + "adi,gain-scaling-p mandatory\n"); + *gs_p = val; + + err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val); + if (err) + return dev_err_probe(dev, err, + "adi,gain-scaling-n property mandatory\n"); + *gs_n = val; + + err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val); + if (err) + return dev_err_probe(dev, err, + "adi,rfb-ohms mandatory\n"); + *rfb = val; + + err = fwnode_property_read_u32(gain_child, "adi,gain-offset", &val); + if (err) + return dev_err_probe(dev, err, + "adi,gain-offset mandatory\n"); + *goffs = val; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ad3552r_get_custom_gain, IIO_AD3552R); + +static int ad3552r_find_range(const struct ad3552r_model_data *model_info, + s32 *vals) +{ + int i; + + for (i = 0; i < model_info->num_ranges; i++) + if (vals[0] == model_info->ranges_table[i][0] * 1000 && + vals[1] == model_info->ranges_table[i][1] * 1000) + return i; + + return -EINVAL; +} + +int ad3552r_get_output_range(struct device *dev, + const struct ad3552r_model_data *model_info, + struct fwnode_handle *child, u32 *val) +{ + int ret; + s32 vals[2]; + + /* This property is optional, so returning -ENOENT if missing */ + if (!fwnode_property_present(child, "adi,output-range-microvolt")) + return -ENOENT; + + ret = fwnode_property_read_u32_array(child, + "adi,output-range-microvolt", + vals, 2); + if (ret) + return dev_err_probe(dev, ret, + "invalid adi,output-range-microvolt\n"); + + ret = ad3552r_find_range(model_info, vals); + if (ret < 0) + return dev_err_probe(dev, ret, + "invalid adi,output-range-microvolt value\n"); + + *val = ret; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ad3552r_get_output_range, IIO_AD3552R); + +MODULE_DESCRIPTION("ad3552r common functions"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c index 75825d6a398b..bbfb451a5da1 100644 --- a/drivers/iio/dac/ad3552r.c +++ b/drivers/iio/dac/ad3552r.c @@ -11,226 +11,9 @@ #include #include #include -#include #include -/* Register addresses */ -/* Primary address space */ -#define AD3552R_REG_ADDR_INTERFACE_CONFIG_A 0x00 -#define AD3552R_MASK_SOFTWARE_RESET (BIT(7) | BIT(0)) -#define AD3552R_MASK_ADDR_ASCENSION BIT(5) -#define AD3552R_MASK_SDO_ACTIVE BIT(4) -#define AD3552R_REG_ADDR_INTERFACE_CONFIG_B 0x01 -#define AD3552R_MASK_SINGLE_INST BIT(7) -#define AD3552R_MASK_SHORT_INSTRUCTION BIT(3) -#define AD3552R_REG_ADDR_DEVICE_CONFIG 0x02 -#define AD3552R_MASK_DEVICE_STATUS(n) BIT(4 + (n)) -#define AD3552R_MASK_CUSTOM_MODES GENMASK(3, 2) -#define AD3552R_MASK_OPERATING_MODES GENMASK(1, 0) -#define AD3552R_REG_ADDR_CHIP_TYPE 0x03 -#define AD3552R_MASK_CLASS GENMASK(7, 0) -#define AD3552R_REG_ADDR_PRODUCT_ID_L 0x04 -#define AD3552R_REG_ADDR_PRODUCT_ID_H 0x05 -#define AD3552R_REG_ADDR_CHIP_GRADE 0x06 -#define AD3552R_MASK_GRADE GENMASK(7, 4) -#define AD3552R_MASK_DEVICE_REVISION GENMASK(3, 0) -#define AD3552R_REG_ADDR_SCRATCH_PAD 0x0A -#define AD3552R_REG_ADDR_SPI_REVISION 0x0B -#define AD3552R_REG_ADDR_VENDOR_L 0x0C -#define AD3552R_REG_ADDR_VENDOR_H 0x0D -#define AD3552R_REG_ADDR_STREAM_MODE 0x0E -#define AD3552R_MASK_LENGTH GENMASK(7, 0) -#define AD3552R_REG_ADDR_TRANSFER_REGISTER 0x0F -#define AD3552R_MASK_MULTI_IO_MODE GENMASK(7, 6) -#define AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE BIT(2) -#define AD3552R_REG_ADDR_INTERFACE_CONFIG_C 0x10 -#define AD3552R_MASK_CRC_ENABLE (GENMASK(7, 6) |\ - GENMASK(1, 0)) -#define AD3552R_MASK_STRICT_REGISTER_ACCESS BIT(5) -#define AD3552R_REG_ADDR_INTERFACE_STATUS_A 0x11 -#define AD3552R_MASK_INTERFACE_NOT_READY BIT(7) -#define AD3552R_MASK_CLOCK_COUNTING_ERROR BIT(5) -#define AD3552R_MASK_INVALID_OR_NO_CRC BIT(3) -#define AD3552R_MASK_WRITE_TO_READ_ONLY_REGISTER BIT(2) -#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS BIT(1) -#define AD3552R_MASK_REGISTER_ADDRESS_INVALID BIT(0) -#define AD3552R_REG_ADDR_INTERFACE_CONFIG_D 0x14 -#define AD3552R_MASK_ALERT_ENABLE_PULLUP BIT(6) -#define AD3552R_MASK_MEM_CRC_EN BIT(4) -#define AD3552R_MASK_SDO_DRIVE_STRENGTH GENMASK(3, 2) -#define AD3552R_MASK_DUAL_SPI_SYNCHROUNOUS_EN BIT(1) -#define AD3552R_MASK_SPI_CONFIG_DDR BIT(0) -#define AD3552R_REG_ADDR_SH_REFERENCE_CONFIG 0x15 -#define AD3552R_MASK_IDUMP_FAST_MODE BIT(6) -#define AD3552R_MASK_SAMPLE_HOLD_DIFFERENTIAL_USER_EN BIT(5) -#define AD3552R_MASK_SAMPLE_HOLD_USER_TRIM GENMASK(4, 3) -#define AD3552R_MASK_SAMPLE_HOLD_USER_ENABLE BIT(2) -#define AD3552R_MASK_REFERENCE_VOLTAGE_SEL GENMASK(1, 0) -#define AD3552R_REG_ADDR_ERR_ALARM_MASK 0x16 -#define AD3552R_MASK_REF_RANGE_ALARM BIT(6) -#define AD3552R_MASK_CLOCK_COUNT_ERR_ALARM BIT(5) -#define AD3552R_MASK_MEM_CRC_ERR_ALARM BIT(4) -#define AD3552R_MASK_SPI_CRC_ERR_ALARM BIT(3) -#define AD3552R_MASK_WRITE_TO_READ_ONLY_ALARM BIT(2) -#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS_ALARM BIT(1) -#define AD3552R_MASK_REGISTER_ADDRESS_INVALID_ALARM BIT(0) -#define AD3552R_REG_ADDR_ERR_STATUS 0x17 -#define AD3552R_MASK_REF_RANGE_ERR_STATUS BIT(6) -#define AD3552R_MASK_DUAL_SPI_STREAM_EXCEEDS_DAC_ERR_STATUS BIT(5) -#define AD3552R_MASK_MEM_CRC_ERR_STATUS BIT(4) -#define AD3552R_MASK_RESET_STATUS BIT(0) -#define AD3552R_REG_ADDR_POWERDOWN_CONFIG 0x18 -#define AD3552R_MASK_CH_DAC_POWERDOWN(ch) BIT(4 + (ch)) -#define AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch) BIT(ch) -#define AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE 0x19 -#define AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch) ((ch) ? GENMASK(7, 4) :\ - GENMASK(3, 0)) -#define AD3552R_REG_ADDR_CH_OFFSET(ch) (0x1B + (ch) * 2) -#define AD3552R_MASK_CH_OFFSET_BITS_0_7 GENMASK(7, 0) -#define AD3552R_REG_ADDR_CH_GAIN(ch) (0x1C + (ch) * 2) -#define AD3552R_MASK_CH_RANGE_OVERRIDE BIT(7) -#define AD3552R_MASK_CH_GAIN_SCALING_N GENMASK(6, 5) -#define AD3552R_MASK_CH_GAIN_SCALING_P GENMASK(4, 3) -#define AD3552R_MASK_CH_OFFSET_POLARITY BIT(2) -#define AD3552R_MASK_CH_OFFSET_BIT_8 BIT(0) -/* - * Secondary region - * For multibyte registers specify the highest address because the access is - * done in descending order - */ -#define AD3552R_SECONDARY_REGION_START 0x28 -#define AD3552R_REG_ADDR_HW_LDAC_16B 0x28 -#define AD3552R_REG_ADDR_CH_DAC_16B(ch) (0x2C - (1 - ch) * 2) -#define AD3552R_REG_ADDR_DAC_PAGE_MASK_16B 0x2E -#define AD3552R_REG_ADDR_CH_SELECT_16B 0x2F -#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_16B 0x31 -#define AD3552R_REG_ADDR_SW_LDAC_16B 0x32 -#define AD3552R_REG_ADDR_CH_INPUT_16B(ch) (0x36 - (1 - ch) * 2) -/* 3 bytes registers */ -#define AD3552R_REG_START_24B 0x37 -#define AD3552R_REG_ADDR_HW_LDAC_24B 0x37 -#define AD3552R_REG_ADDR_CH_DAC_24B(ch) (0x3D - (1 - ch) * 3) -#define AD3552R_REG_ADDR_DAC_PAGE_MASK_24B 0x40 -#define AD3552R_REG_ADDR_CH_SELECT_24B 0x41 -#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_24B 0x44 -#define AD3552R_REG_ADDR_SW_LDAC_24B 0x45 -#define AD3552R_REG_ADDR_CH_INPUT_24B(ch) (0x4B - (1 - ch) * 3) - -/* Useful defines */ -#define AD3552R_MAX_CH 2 -#define AD3552R_MASK_CH(ch) BIT(ch) -#define AD3552R_MASK_ALL_CH GENMASK(1, 0) -#define AD3552R_MAX_REG_SIZE 3 -#define AD3552R_READ_BIT BIT(7) -#define AD3552R_ADDR_MASK GENMASK(6, 0) -#define AD3552R_MASK_DAC_12B 0xFFF0 -#define AD3552R_DEFAULT_CONFIG_B_VALUE 0x8 -#define AD3552R_SCRATCH_PAD_TEST_VAL1 0x34 -#define AD3552R_SCRATCH_PAD_TEST_VAL2 0xB2 -#define AD3552R_GAIN_SCALE 1000 -#define AD3552R_LDAC_PULSE_US 100 - -enum ad3552r_ch_vref_select { - /* Internal source with Vref I/O floating */ - AD3552R_INTERNAL_VREF_PIN_FLOATING, - /* Internal source with Vref I/O at 2.5V */ - AD3552R_INTERNAL_VREF_PIN_2P5V, - /* External source with Vref I/O as input */ - AD3552R_EXTERNAL_VREF_PIN_INPUT -}; - -enum ad3552r_id { - AD3541R_ID = 0x400b, - AD3542R_ID = 0x4009, - AD3551R_ID = 0x400a, - AD3552R_ID = 0x4008, -}; - -enum ad3552r_ch_output_range { - /* Range from 0 V to 2.5 V. Requires Rfb1x connection */ - AD3552R_CH_OUTPUT_RANGE_0__2P5V, - /* Range from 0 V to 5 V. Requires Rfb1x connection */ - AD3552R_CH_OUTPUT_RANGE_0__5V, - /* Range from 0 V to 10 V. Requires Rfb2x connection */ - AD3552R_CH_OUTPUT_RANGE_0__10V, - /* Range from -5 V to 5 V. Requires Rfb2x connection */ - AD3552R_CH_OUTPUT_RANGE_NEG_5__5V, - /* Range from -10 V to 10 V. Requires Rfb4x connection */ - AD3552R_CH_OUTPUT_RANGE_NEG_10__10V, -}; - -static const s32 ad3552r_ch_ranges[][2] = { - [AD3552R_CH_OUTPUT_RANGE_0__2P5V] = {0, 2500}, - [AD3552R_CH_OUTPUT_RANGE_0__5V] = {0, 5000}, - [AD3552R_CH_OUTPUT_RANGE_0__10V] = {0, 10000}, - [AD3552R_CH_OUTPUT_RANGE_NEG_5__5V] = {-5000, 5000}, - [AD3552R_CH_OUTPUT_RANGE_NEG_10__10V] = {-10000, 10000} -}; - -enum ad3542r_ch_output_range { - /* Range from 0 V to 2.5 V. Requires Rfb1x connection */ - AD3542R_CH_OUTPUT_RANGE_0__2P5V, - /* Range from 0 V to 3 V. Requires Rfb1x connection */ - AD3542R_CH_OUTPUT_RANGE_0__3V, - /* Range from 0 V to 5 V. Requires Rfb1x connection */ - AD3542R_CH_OUTPUT_RANGE_0__5V, - /* Range from 0 V to 10 V. Requires Rfb2x connection */ - AD3542R_CH_OUTPUT_RANGE_0__10V, - /* Range from -2.5 V to 7.5 V. Requires Rfb2x connection */ - AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V, - /* Range from -5 V to 5 V. Requires Rfb2x connection */ - AD3542R_CH_OUTPUT_RANGE_NEG_5__5V, -}; - -static const s32 ad3542r_ch_ranges[][2] = { - [AD3542R_CH_OUTPUT_RANGE_0__2P5V] = {0, 2500}, - [AD3542R_CH_OUTPUT_RANGE_0__3V] = {0, 3000}, - [AD3542R_CH_OUTPUT_RANGE_0__5V] = {0, 5000}, - [AD3542R_CH_OUTPUT_RANGE_0__10V] = {0, 10000}, - [AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V] = {-2500, 7500}, - [AD3542R_CH_OUTPUT_RANGE_NEG_5__5V] = {-5000, 5000} -}; - -enum ad3552r_ch_gain_scaling { - /* Gain scaling of 1 */ - AD3552R_CH_GAIN_SCALING_1, - /* Gain scaling of 0.5 */ - AD3552R_CH_GAIN_SCALING_0_5, - /* Gain scaling of 0.25 */ - AD3552R_CH_GAIN_SCALING_0_25, - /* Gain scaling of 0.125 */ - AD3552R_CH_GAIN_SCALING_0_125, -}; - -/* Gain * AD3552R_GAIN_SCALE */ -static const s32 gains_scaling_table[] = { - [AD3552R_CH_GAIN_SCALING_1] = 1000, - [AD3552R_CH_GAIN_SCALING_0_5] = 500, - [AD3552R_CH_GAIN_SCALING_0_25] = 250, - [AD3552R_CH_GAIN_SCALING_0_125] = 125 -}; - -struct ad3552r_ch_data { - s32 scale_int; - s32 scale_dec; - s32 offset_int; - s32 offset_dec; - s16 gain_offset; - u16 rfb; - u8 n; - u8 p; - u8 range; - bool range_override; -}; - -struct ad3552r_model_data { - const char *model_name; - enum ad3552r_id chip_id; - unsigned int num_hw_channels; - const s32 (*ranges_table)[2]; - int num_ranges; - bool requires_output_range; -}; +#include "ad3552r.h" struct ad3552r_desc { const struct ad3552r_model_data *model_data; @@ -632,136 +415,35 @@ static int ad3552r_reset(struct ad3552r_desc *dac) FIELD_PREP(AD3552R_MASK_ADDR_ASCENSION, val)); } -static void ad3552r_get_custom_range(struct ad3552r_desc *dac, s32 i, s32 *v_min, - s32 *v_max) -{ - s64 vref, tmp, common, offset, gn, gp; - /* - * From datasheet formula (In Volts): - * Vmin = 2.5 + [(GainN + Offset / 1024) * 2.5 * Rfb * 1.03] - * Vmax = 2.5 - [(GainP + Offset / 1024) * 2.5 * Rfb * 1.03] - * Calculus are converted to milivolts - */ - vref = 2500; - /* 2.5 * 1.03 * 1000 (To mV) */ - common = 2575 * dac->ch_data[i].rfb; - offset = dac->ch_data[i].gain_offset; - - gn = gains_scaling_table[dac->ch_data[i].n]; - tmp = (1024 * gn + AD3552R_GAIN_SCALE * offset) * common; - tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE); - *v_max = vref + tmp; - - gp = gains_scaling_table[dac->ch_data[i].p]; - tmp = (1024 * gp - AD3552R_GAIN_SCALE * offset) * common; - tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE); - *v_min = vref - tmp; -} - -static void ad3552r_calc_gain_and_offset(struct ad3552r_desc *dac, s32 ch) -{ - s32 idx, v_max, v_min, span, rem; - s64 tmp; - - if (dac->ch_data[ch].range_override) { - ad3552r_get_custom_range(dac, ch, &v_min, &v_max); - } else { - /* Normal range */ - idx = dac->ch_data[ch].range; - v_min = dac->model_data->ranges_table[idx][0]; - v_max = dac->model_data->ranges_table[idx][1]; - } - - /* - * From datasheet formula: - * Vout = Span * (D / 65536) + Vmin - * Converted to scale and offset: - * Scale = Span / 65536 - * Offset = 65536 * Vmin / Span - * - * Reminders are in micros in order to be printed as - * IIO_VAL_INT_PLUS_MICRO - */ - span = v_max - v_min; - dac->ch_data[ch].scale_int = div_s64_rem(span, 65536, &rem); - /* Do operations in microvolts */ - dac->ch_data[ch].scale_dec = DIV_ROUND_CLOSEST((s64)rem * 1000000, - 65536); - - dac->ch_data[ch].offset_int = div_s64_rem(v_min * 65536, span, &rem); - tmp = (s64)rem * 1000000; - dac->ch_data[ch].offset_dec = div_s64(tmp, span); -} - -static int ad3552r_find_range(const struct ad3552r_model_data *model_data, - s32 *vals) -{ - int i; - - for (i = 0; i < model_data->num_ranges; i++) - if (vals[0] == model_data->ranges_table[i][0] * 1000 && - vals[1] == model_data->ranges_table[i][1] * 1000) - return i; - - return -EINVAL; -} - static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac, struct fwnode_handle *child, u32 ch) { struct device *dev = &dac->spi->dev; - u32 val; int err; u8 addr; - u16 reg = 0, offset; - - struct fwnode_handle *gain_child __free(fwnode_handle) - = fwnode_get_named_child_node(child, - "custom-output-range-config"); - if (!gain_child) - return dev_err_probe(dev, -EINVAL, - "mandatory custom-output-range-config property missing\n"); - - dac->ch_data[ch].range_override = 1; - reg |= FIELD_PREP(AD3552R_MASK_CH_RANGE_OVERRIDE, 1); - - err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val); - if (err) - return dev_err_probe(dev, err, - "mandatory adi,gain-scaling-p property missing\n"); - reg |= FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_P, val); - dac->ch_data[ch].p = val; - - err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val); - if (err) - return dev_err_probe(dev, err, - "mandatory adi,gain-scaling-n property missing\n"); - reg |= FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_N, val); - dac->ch_data[ch].n = val; - - err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val); - if (err) - return dev_err_probe(dev, err, - "mandatory adi,rfb-ohms property missing\n"); - dac->ch_data[ch].rfb = val; + u16 reg; - err = fwnode_property_read_u32(gain_child, "adi,gain-offset", &val); + err = ad3552r_get_custom_gain(dev, child, + &dac->ch_data[ch].p, + &dac->ch_data[ch].n, + &dac->ch_data[ch].rfb, + &dac->ch_data[ch].gain_offset); if (err) - return dev_err_probe(dev, err, - "mandatory adi,gain-offset property missing\n"); - dac->ch_data[ch].gain_offset = val; + return err; - offset = abs((s32)val); - reg |= FIELD_PREP(AD3552R_MASK_CH_OFFSET_BIT_8, (offset >> 8)); + dac->ch_data[ch].range_override = 1; - reg |= FIELD_PREP(AD3552R_MASK_CH_OFFSET_POLARITY, (s32)val < 0); addr = AD3552R_REG_ADDR_CH_GAIN(ch); err = ad3552r_write_reg(dac, addr, - offset & AD3552R_MASK_CH_OFFSET_BITS_0_7); + abs((s32)dac->ch_data[ch].gain_offset) & + AD3552R_MASK_CH_OFFSET_BITS_0_7); if (err) return dev_err_probe(dev, err, "Error writing register\n"); + reg = ad3552r_calc_custom_gain(dac->ch_data[ch].p, dac->ch_data[ch].n, + dac->ch_data[ch].gain_offset); + err = ad3552r_write_reg(dac, addr, reg); if (err) return dev_err_probe(dev, err, "Error writing register\n"); @@ -772,30 +454,17 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac, static int ad3552r_configure_device(struct ad3552r_desc *dac) { struct device *dev = &dac->spi->dev; - int err, cnt = 0, voltage, delta = 100000; - u32 vals[2], val, ch; + int err, cnt = 0; + u32 val, ch; dac->gpio_ldac = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_HIGH); if (IS_ERR(dac->gpio_ldac)) return dev_err_probe(dev, PTR_ERR(dac->gpio_ldac), "Error getting gpio ldac"); - voltage = devm_regulator_get_enable_read_voltage(dev, "vref"); - if (voltage < 0 && voltage != -ENODEV) - return dev_err_probe(dev, voltage, "Error getting vref voltage\n"); - - if (voltage == -ENODEV) { - if (device_property_read_bool(dev, "adi,vref-out-en")) - val = AD3552R_INTERNAL_VREF_PIN_2P5V; - else - val = AD3552R_INTERNAL_VREF_PIN_FLOATING; - } else { - if (voltage > 2500000 + delta || voltage < 2500000 - delta) { - dev_warn(dev, "vref-supply must be 2.5V"); - return -EINVAL; - } - val = AD3552R_EXTERNAL_VREF_PIN_INPUT; - } + err = ad3552r_get_ref_voltage(dev, &val); + if (err < 0) + return err; err = ad3552r_update_reg_field(dac, AD3552R_REG_ADDR_SH_REFERENCE_CONFIG, @@ -804,13 +473,8 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) if (err) return err; - err = device_property_read_u32(dev, "adi,sdo-drive-strength", &val); + err = ad3552r_get_drive_strength(dev, &val); if (!err) { - if (val > 3) { - dev_err(dev, "adi,sdo-drive-strength must be less than 4\n"); - return -EINVAL; - } - err = ad3552r_update_reg_field(dac, AD3552R_REG_ADDR_INTERFACE_CONFIG_D, AD3552R_MASK_SDO_DRIVE_STRENGTH, @@ -835,21 +499,12 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) "reg must be less than %d\n", dac->model_data->num_hw_channels); - if (fwnode_property_present(child, "adi,output-range-microvolt")) { - err = fwnode_property_read_u32_array(child, - "adi,output-range-microvolt", - vals, - 2); - if (err) - return dev_err_probe(dev, err, - "adi,output-range-microvolt property could not be parsed\n"); - - err = ad3552r_find_range(dac->model_data, vals); - if (err < 0) - return dev_err_probe(dev, err, - "Invalid adi,output-range-microvolt value\n"); + err = ad3552r_get_output_range(dev, dac->model_data, + child, &val); + if (err && err != -ENOENT) + return err; - val = err; + if (!err) { if (ch == 0) val = FIELD_PREP(AD3552R_MASK_CH_OUTPUT_RANGE_SEL(0), val); else @@ -873,7 +528,7 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) return err; } - ad3552r_calc_gain_and_offset(dac, ch); + ad3552r_calc_gain_and_offset(&dac->ch_data[ch], dac->model_data); dac->enabled_ch |= BIT(ch); if (ch == 0) @@ -1072,3 +727,4 @@ module_spi_driver(ad3552r_driver); MODULE_AUTHOR("Mihail Chindris "); MODULE_DESCRIPTION("Analog Device AD3552R DAC"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_AD3552R); diff --git a/drivers/iio/dac/ad3552r.h b/drivers/iio/dac/ad3552r.h new file mode 100644 index 000000000000..22bd9ad27c65 --- /dev/null +++ b/drivers/iio/dac/ad3552r.h @@ -0,0 +1,226 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * AD3552R Digital <-> Analog converters common header + * + * Copyright 2021-2024 Analog Devices Inc. + * Author: Angelo Dureghello + */ + +#ifndef __DRIVERS_IIO_DAC_AD3552R_H__ +#define __DRIVERS_IIO_DAC_AD3552R_H__ + +/* Register addresses */ +/* Primary address space */ +#define AD3552R_REG_ADDR_INTERFACE_CONFIG_A 0x00 +#define AD3552R_MASK_SOFTWARE_RESET (BIT(7) | BIT(0)) +#define AD3552R_MASK_ADDR_ASCENSION BIT(5) +#define AD3552R_MASK_SDO_ACTIVE BIT(4) +#define AD3552R_REG_ADDR_INTERFACE_CONFIG_B 0x01 +#define AD3552R_MASK_SINGLE_INST BIT(7) +#define AD3552R_MASK_SHORT_INSTRUCTION BIT(3) +#define AD3552R_REG_ADDR_DEVICE_CONFIG 0x02 +#define AD3552R_MASK_DEVICE_STATUS(n) BIT(4 + (n)) +#define AD3552R_MASK_CUSTOM_MODES GENMASK(3, 2) +#define AD3552R_MASK_OPERATING_MODES GENMASK(1, 0) +#define AD3552R_REG_ADDR_CHIP_TYPE 0x03 +#define AD3552R_MASK_CLASS GENMASK(7, 0) +#define AD3552R_REG_ADDR_PRODUCT_ID_L 0x04 +#define AD3552R_REG_ADDR_PRODUCT_ID_H 0x05 +#define AD3552R_REG_ADDR_CHIP_GRADE 0x06 +#define AD3552R_MASK_GRADE GENMASK(7, 4) +#define AD3552R_MASK_DEVICE_REVISION GENMASK(3, 0) +#define AD3552R_REG_ADDR_SCRATCH_PAD 0x0A +#define AD3552R_REG_ADDR_SPI_REVISION 0x0B +#define AD3552R_REG_ADDR_VENDOR_L 0x0C +#define AD3552R_REG_ADDR_VENDOR_H 0x0D +#define AD3552R_REG_ADDR_STREAM_MODE 0x0E +#define AD3552R_MASK_LENGTH GENMASK(7, 0) +#define AD3552R_REG_ADDR_TRANSFER_REGISTER 0x0F +#define AD3552R_MASK_MULTI_IO_MODE GENMASK(7, 6) +#define AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE BIT(2) +#define AD3552R_REG_ADDR_INTERFACE_CONFIG_C 0x10 +#define AD3552R_MASK_CRC_ENABLE (GENMASK(7, 6) |\ + GENMASK(1, 0)) +#define AD3552R_MASK_STRICT_REGISTER_ACCESS BIT(5) +#define AD3552R_REG_ADDR_INTERFACE_STATUS_A 0x11 +#define AD3552R_MASK_INTERFACE_NOT_READY BIT(7) +#define AD3552R_MASK_CLOCK_COUNTING_ERROR BIT(5) +#define AD3552R_MASK_INVALID_OR_NO_CRC BIT(3) +#define AD3552R_MASK_WRITE_TO_READ_ONLY_REGISTER BIT(2) +#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS BIT(1) +#define AD3552R_MASK_REGISTER_ADDRESS_INVALID BIT(0) +#define AD3552R_REG_ADDR_INTERFACE_CONFIG_D 0x14 +#define AD3552R_MASK_ALERT_ENABLE_PULLUP BIT(6) +#define AD3552R_MASK_MEM_CRC_EN BIT(4) +#define AD3552R_MASK_SDO_DRIVE_STRENGTH GENMASK(3, 2) +#define AD3552R_MASK_DUAL_SPI_SYNCHROUNOUS_EN BIT(1) +#define AD3552R_MASK_SPI_CONFIG_DDR BIT(0) +#define AD3552R_REG_ADDR_SH_REFERENCE_CONFIG 0x15 +#define AD3552R_MASK_IDUMP_FAST_MODE BIT(6) +#define AD3552R_MASK_SAMPLE_HOLD_DIFF_USER_EN BIT(5) +#define AD3552R_MASK_SAMPLE_HOLD_USER_TRIM GENMASK(4, 3) +#define AD3552R_MASK_SAMPLE_HOLD_USER_ENABLE BIT(2) +#define AD3552R_MASK_REFERENCE_VOLTAGE_SEL GENMASK(1, 0) +#define AD3552R_REG_ADDR_ERR_ALARM_MASK 0x16 +#define AD3552R_MASK_REF_RANGE_ALARM BIT(6) +#define AD3552R_MASK_CLOCK_COUNT_ERR_ALARM BIT(5) +#define AD3552R_MASK_MEM_CRC_ERR_ALARM BIT(4) +#define AD3552R_MASK_SPI_CRC_ERR_ALARM BIT(3) +#define AD3552R_MASK_WRITE_TO_READ_ONLY_ALARM BIT(2) +#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS_ALARM BIT(1) +#define AD3552R_MASK_REGISTER_ADDRESS_INVALID_ALARM BIT(0) +#define AD3552R_REG_ADDR_ERR_STATUS 0x17 +#define AD3552R_MASK_REF_RANGE_ERR_STATUS BIT(6) +#define AD3552R_MASK_STREAM_EXCEEDS_DAC_ERR_STATUS BIT(5) +#define AD3552R_MASK_MEM_CRC_ERR_STATUS BIT(4) +#define AD3552R_MASK_RESET_STATUS BIT(0) +#define AD3552R_REG_ADDR_POWERDOWN_CONFIG 0x18 +#define AD3552R_MASK_CH_DAC_POWERDOWN(ch) BIT(4 + (ch)) +#define AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch) BIT(ch) +#define AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE 0x19 +#define AD3552R_MASK_CH0_RANGE GENMASK(2, 0) +#define AD3552R_MASK_CH1_RANGE GENMASK(6, 4) +#define AD3552R_MASK_CH_OUTPUT_RANGE GENMASK(7, 0) +#define AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch) ((ch) ? \ + GENMASK(7, 4) : \ + GENMASK(3, 0)) +#define AD3552R_REG_ADDR_CH_OFFSET(ch) (0x1B + (ch) * 2) +#define AD3552R_MASK_CH_OFFSET_BITS_0_7 GENMASK(7, 0) +#define AD3552R_REG_ADDR_CH_GAIN(ch) (0x1C + (ch) * 2) +#define AD3552R_MASK_CH_RANGE_OVERRIDE BIT(7) +#define AD3552R_MASK_CH_GAIN_SCALING_N GENMASK(6, 5) +#define AD3552R_MASK_CH_GAIN_SCALING_P GENMASK(4, 3) +#define AD3552R_MASK_CH_OFFSET_POLARITY BIT(2) +#define AD3552R_MASK_CH_OFFSET_BIT_8 BIT(8) +/* + * Secondary region + * For multibyte registers specify the highest address because the access is + * done in descending order + */ +#define AD3552R_SECONDARY_REGION_START 0x28 +#define AD3552R_REG_ADDR_HW_LDAC_16B 0x28 +#define AD3552R_REG_ADDR_CH_DAC_16B(ch) (0x2C - (1 - (ch)) * 2) +#define AD3552R_REG_ADDR_DAC_PAGE_MASK_16B 0x2E +#define AD3552R_REG_ADDR_CH_SELECT_16B 0x2F +#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_16B 0x31 +#define AD3552R_REG_ADDR_SW_LDAC_16B 0x32 +#define AD3552R_REG_ADDR_CH_INPUT_16B(ch) (0x36 - (1 - (ch)) * 2) +/* 3 bytes registers */ +#define AD3552R_REG_START_24B 0x37 +#define AD3552R_REG_ADDR_HW_LDAC_24B 0x37 +#define AD3552R_REG_ADDR_CH_DAC_24B(ch) (0x3D - (1 - (ch)) * 3) +#define AD3552R_REG_ADDR_DAC_PAGE_MASK_24B 0x40 +#define AD3552R_REG_ADDR_CH_SELECT_24B 0x41 +#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_24B 0x44 +#define AD3552R_REG_ADDR_SW_LDAC_24B 0x45 +#define AD3552R_REG_ADDR_CH_INPUT_24B(ch) (0x4B - (1 - (ch)) * 3) + +/* Useful defines */ +#define AD3552R_MAX_CH 2 +#define AD3552R_MASK_CH(ch) BIT(ch) +#define AD3552R_MASK_ALL_CH GENMASK(1, 0) +#define AD3552R_MAX_REG_SIZE 3 +#define AD3552R_READ_BIT BIT(7) +#define AD3552R_ADDR_MASK GENMASK(6, 0) +#define AD3552R_MASK_DAC_12B GENMASK(15, 4) +#define AD3552R_DEFAULT_CONFIG_B_VALUE 0x8 +#define AD3552R_SCRATCH_PAD_TEST_VAL1 0x34 +#define AD3552R_SCRATCH_PAD_TEST_VAL2 0xB2 +#define AD3552R_GAIN_SCALE 1000 +#define AD3552R_LDAC_PULSE_US 100 + +#define AD3552R_MAX_RANGES 5 +#define AD3542R_MAX_RANGES 6 + +extern const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2]; +extern const s32 ad3542r_ch_ranges[AD3542R_MAX_RANGES][2]; + +enum ad3552r_id { + AD3541R_ID = 0x400b, + AD3542R_ID = 0x4009, + AD3551R_ID = 0x400a, + AD3552R_ID = 0x4008, +}; + +struct ad3552r_model_data { + const char *model_name; + enum ad3552r_id chip_id; + unsigned int num_hw_channels; + const s32 (*ranges_table)[2]; + int num_ranges; + bool requires_output_range; +}; + +struct ad3552r_ch_data { + s32 scale_int; + s32 scale_dec; + s32 offset_int; + s32 offset_dec; + s16 gain_offset; + u16 rfb; + u8 n; + u8 p; + u8 range; + bool range_override; +}; + +enum ad3552r_ch_gain_scaling { + /* Gain scaling of 1 */ + AD3552R_CH_GAIN_SCALING_1, + /* Gain scaling of 0.5 */ + AD3552R_CH_GAIN_SCALING_0_5, + /* Gain scaling of 0.25 */ + AD3552R_CH_GAIN_SCALING_0_25, + /* Gain scaling of 0.125 */ + AD3552R_CH_GAIN_SCALING_0_125, +}; + +enum ad3552r_ch_vref_select { + /* Internal source with Vref I/O floating */ + AD3552R_INTERNAL_VREF_PIN_FLOATING, + /* Internal source with Vref I/O at 2.5V */ + AD3552R_INTERNAL_VREF_PIN_2P5V, + /* External source with Vref I/O as input */ + AD3552R_EXTERNAL_VREF_PIN_INPUT +}; + +enum ad3542r_ch_output_range { + /* Range from 0 V to 2.5 V. Requires Rfb1x connection */ + AD3542R_CH_OUTPUT_RANGE_0__2P5V, + /* Range from 0 V to 3 V. Requires Rfb1x connection */ + AD3542R_CH_OUTPUT_RANGE_0__3V, + /* Range from 0 V to 5 V. Requires Rfb1x connection */ + AD3542R_CH_OUTPUT_RANGE_0__5V, + /* Range from 0 V to 10 V. Requires Rfb2x connection */ + AD3542R_CH_OUTPUT_RANGE_0__10V, + /* Range from -2.5 V to 7.5 V. Requires Rfb2x connection */ + AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V, + /* Range from -5 V to 5 V. Requires Rfb2x connection */ + AD3542R_CH_OUTPUT_RANGE_NEG_5__5V, +}; + +enum ad3552r_ch_output_range { + /* Range from 0 V to 2.5 V. Requires Rfb1x connection */ + AD3552R_CH_OUTPUT_RANGE_0__2P5V, + /* Range from 0 V to 5 V. Requires Rfb1x connection */ + AD3552R_CH_OUTPUT_RANGE_0__5V, + /* Range from 0 V to 10 V. Requires Rfb2x connection */ + AD3552R_CH_OUTPUT_RANGE_0__10V, + /* Range from -5 V to 5 V. Requires Rfb2x connection */ + AD3552R_CH_OUTPUT_RANGE_NEG_5__5V, + /* Range from -10 V to 10 V. Requires Rfb4x connection */ + AD3552R_CH_OUTPUT_RANGE_NEG_10__10V, +}; + +int ad3552r_get_output_range(struct device *dev, + const struct ad3552r_model_data *model_info, + struct fwnode_handle *child, u32 *val); +int ad3552r_get_custom_gain(struct device *dev, struct fwnode_handle *child, + u8 *gs_p, u8 *gs_n, u16 *rfb, s16 *goffs); +u16 ad3552r_calc_custom_gain(u8 p, u8 n, s16 goffs); +int ad3552r_get_ref_voltage(struct device *dev, u32 *val); +int ad3552r_get_drive_strength(struct device *dev, u32 *val); +void ad3552r_calc_gain_and_offset(struct ad3552r_ch_data *ch_data, + const struct ad3552r_model_data *model_data); + +#endif /* __DRIVERS_IIO_DAC_AD3552R_H__ */ From patchwork Fri Oct 25 09:49:40 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Angelo Dureghello X-Patchwork-Id: 13850366 Received: from mail-wm1-f45.google.com (mail-wm1-f45.google.com [209.85.128.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7FC071F76DA for ; Fri, 25 Oct 2024 09:51:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729849873; cv=none; b=HO+3toPRZcWbLvEjYDTvzl3F1JnVKyqmzEZx8l+jisvPK8RgqjJRHUQwXW3n+tVFsatAyp01GnsWQxJ+BvNU6jUvFrwf5X/TdGPdrkaK5CKXfqE3ICyRMNAG2Q7q3wDga9UV5TPLSqOgCohgqii603tbv96h/DkekD8wZeNmyIc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729849873; c=relaxed/simple; bh=k6NxrbPPV+3TsE+0kPdH++6+FKnRgi4/WpMqJWIPfnk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=b/ZG/9Eo0quu8qrprTgcxRaRl4nX85OUfcpQw75oW5/DMG+DReCnEl669x4k1ZMGouzGOzIz5bfOuVc/izHQOmV4ixam7VaXil6/RpEAVUhd3m0Qhup7BllnHstM3Etozlqp2xap0yvF5TiSxgQwxmwlYy4DVelVjZaOapiWbuY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=v/0B3sjj; arc=none smtp.client-ip=209.85.128.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="v/0B3sjj" Received: by mail-wm1-f45.google.com with SMTP id 5b1f17b1804b1-4315abed18aso18302915e9.2 for ; Fri, 25 Oct 2024 02:51:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1729849867; x=1730454667; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=siAwky4CpOcOlpposx4qq6tNZ/dIGbt2wEJ7EfyXuto=; b=v/0B3sjj9YGJOIo1NCBJ5gQd0vLjbVTXq90NDbPgC9YuakJWvUfYsuiklacddz8Lfe kE1F8saXwXY3W+MNNk+kjpndZP5kmzCg7oc8BAT3KCnYMYhBHPb1g7MqVuBIfJLtY+sw pVAUL0Et6WXQKaV2aotMTpB141NLIBzyyfvV3a1BUsR/qFExsac5vK7F3hjpYpXT0+fA NiJQofRMGdPDqMZXmaABjB9adtbQa5zmR+CLya3otvf+6izpUqBlMjB2IlD3XpAr+DiI eHQ4mIzmZx+Yv/RIyJxzGSMh+6ViFgcr7IHuOzlLbJ1XWo/aq2SUZNq4RfE03o4mW20s CMtQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1729849867; x=1730454667; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=siAwky4CpOcOlpposx4qq6tNZ/dIGbt2wEJ7EfyXuto=; b=tEsA0eO5dFDmORHA+u0fVw4N5yNCe7rNEfj49uJuNL7JqxAmWX+hUnvheSrrXw655D bHfsin7U7d0PWVofemUme94Hoos3Ope707BqpM4orihPgVtTY5eb5boWWwBecT1XURv3 D+F83QoEAe3PP/sl3reKtYktU99gzyXoXFUfdS7TjfwA/BtTZkOmR71SzsNk4XhVhT/U CrlgR6EAzMfT02FMm0fCqMsEh+Gtb0eRMrxQGQjAuI8VFihpEoQ3ulPPdYWGK7CGGKXm /4yFfvNAodb67NY+ReaOIisI1HLS6sRh86NLtXsdf+evlrx9GZfCYVmrpltK5qh4imIf +WUw== X-Gm-Message-State: AOJu0Yz4CUBDxPuaw2RDSeHUF3lQ1joGWnurOhxnJgpV1DvdL44Q9K3D uaU+kwDBIuLPhr19X/wJIIC5dkvrBR0qbEQNYlcYys/UsRBY6DJlQ04fQYDJe/gRxh56BR0nDag t+BfOPQ== X-Google-Smtp-Source: AGHT+IEuEzV8Ovb9uKN8qRkRSNZZ7V4lxVvydlp6A/BI9smXyaLqEJ1LEmail4q9X6oCXMbxGb8QQg== X-Received: by 2002:a05:600c:3556:b0:42c:bae0:f065 with SMTP id 5b1f17b1804b1-431841e1786mr78863045e9.5.1729849867391; Fri, 25 Oct 2024 02:51:07 -0700 (PDT) Received: from [127.0.1.1] (host-79-41-194-153.retail.telecomitalia.it. [79.41.194.153]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-431935f6df1sm12895085e9.35.2024.10.25.02.51.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Oct 2024 02:51:06 -0700 (PDT) From: Angelo Dureghello X-Google-Original-From: Angelo Dureghello Date: Fri, 25 Oct 2024 11:49:40 +0200 Subject: [PATCH v8 7/8] iio: dac: ad3552r: add high-speed platform driver Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-7-74ca7dd60567@baylibre.com> References: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-0-74ca7dd60567@baylibre.com> In-Reply-To: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-0-74ca7dd60567@baylibre.com> To: Lars-Peter Clausen , Michael Hennerich , =?utf-8?q?Nuno_S=C3=A1?= , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Mark Brown , dlechner@baylibre.com, Angelo Dureghello X-Mailer: b4 0.14.1 From: Angelo Dureghello Add High Speed ad3552r platform driver. The ad3552r DAC is controlled by a custom (fpga-based) DAC IP through the current AXI backend, or similar alternative IIO backend. Compared to the existing driver (ad3552r.c), that is a simple SPI driver, this driver is coupled with a DAC IIO backend that finally controls the ad3552r by a fpga-based "QSPI+DDR" interface, to reach maximum transfer rate of 33MUPS using dma stream capabilities. All commands involving QSPI bus read/write are delegated to the backend through the provided APIs for bus read/write. Signed-off-by: Angelo Dureghello --- drivers/iio/dac/Kconfig | 14 ++ drivers/iio/dac/Makefile | 1 + drivers/iio/dac/ad3552r-hs.c | 530 +++++++++++++++++++++++++++++++++++++++++++ drivers/iio/dac/ad3552r-hs.h | 19 ++ drivers/iio/dac/ad3552r.h | 4 + 5 files changed, 568 insertions(+) diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 26f9de55b79f..f76eaba140d8 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -6,6 +6,20 @@ menu "Digital to analog converters" +config AD3552R_HS + tristate "Analog Devices AD3552R DAC High Speed driver" + select ADI_AXI_DAC + help + Say yes here to build support for Analog Devices AD3552R + Digital to Analog Converter High Speed driver. + + The driver requires the assistance of an IP core to operate, + since data is streamed into target device via DMA, sent over a + QSPI + DDR (Double Data Rate) bus. + + To compile this driver as a module, choose M here: the + module will be called ad3552r-hs. + config AD3552R tristate "Analog Devices AD3552R DAC driver" depends on SPI_MASTER diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index c92de0366238..d92e08ca93ca 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -4,6 +4,7 @@ # # When adding new entries keep the list in alphabetical order +obj-$(CONFIG_AD3552R_HS) += ad3552r-hs.o ad3552r-common.o obj-$(CONFIG_AD3552R) += ad3552r.o ad3552r-common.o obj-$(CONFIG_AD5360) += ad5360.o obj-$(CONFIG_AD5380) += ad5380.o diff --git a/drivers/iio/dac/ad3552r-hs.c b/drivers/iio/dac/ad3552r-hs.c new file mode 100644 index 000000000000..97dfc598aec6 --- /dev/null +++ b/drivers/iio/dac/ad3552r-hs.c @@ -0,0 +1,530 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices AD3552R + * Digital to Analog converter driver, High Speed version + * + * Copyright 2024 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ad3552r.h" +#include "ad3552r-hs.h" + +struct ad3552r_hs_state { + const struct ad3552r_model_data *model_data; + struct gpio_desc *reset_gpio; + struct device *dev; + struct iio_backend *back; + bool single_channel; + struct ad3552r_ch_data ch_data[AD3552R_MAX_CH]; + struct ad3552r_hs_platform_data *data; +}; + +static int ad3552r_qspi_update_reg_bits(struct ad3552r_hs_state *st, + u32 reg, u32 mask, u32 val, + size_t xfer_size) +{ + u32 rval; + int ret; + + ret = st->data->bus_reg_read(st->back, reg, &rval, xfer_size); + if (ret) + return ret; + + rval = (rval & ~mask) | val; + + return st->data->bus_reg_write(st->back, reg, rval, xfer_size); +} + +static int ad3552r_hs_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ad3552r_hs_state *st = iio_priv(indio_dev); + int ret; + int ch = chan->channel; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + /* + * Using 4 lanes (QSPI), then using 2 as DDR mode is + * considered always on (considering buffering mode always). + */ + *val = DIV_ROUND_CLOSEST(st->data->bus_sample_data_clock_hz * + 4 * 2, chan->scan_type.realbits); + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_RAW: + ret = st->data->bus_reg_read(st->back, + AD3552R_REG_ADDR_CH_DAC_16B(chan->channel), + val, 2); + if (ret) + return ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = st->ch_data[ch].scale_int; + *val2 = st->ch_data[ch].scale_dec; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OFFSET: + *val = st->ch_data[ch].offset_int; + *val2 = st->ch_data[ch].offset_dec; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int ad3552r_hs_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ad3552r_hs_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + return st->data->bus_reg_write(st->back, + AD3552R_REG_ADDR_CH_DAC_16B(chan->channel), + val, 2); + } + unreachable(); + default: + return -EINVAL; + } +} + +static int ad3552r_hs_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad3552r_hs_state *st = iio_priv(indio_dev); + struct iio_backend_data_fmt fmt = { + .type = IIO_BACKEND_DATA_UNSIGNED + }; + int loop_len, val, ret; + + switch (*indio_dev->active_scan_mask) { + case AD3552R_CH0_ACTIVE: + st->single_channel = true; + loop_len = 2; + val = AD3552R_REG_ADDR_CH_DAC_16B(0); + break; + case AD3552R_CH1_ACTIVE: + st->single_channel = true; + loop_len = 2; + val = AD3552R_REG_ADDR_CH_DAC_16B(1); + break; + case AD3552R_CH0_ACTIVE | AD3552R_CH1_ACTIVE: + st->single_channel = false; + loop_len = 4; + val = AD3552R_REG_ADDR_CH_DAC_16B(1); + break; + default: + return -EINVAL; + } + + ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_STREAM_MODE, + loop_len, 1); + if (ret) + return ret; + + /* Inform DAC chip to switch into DDR mode */ + ret = ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_INTERFACE_CONFIG_D, + AD3552R_MASK_SPI_CONFIG_DDR, + AD3552R_MASK_SPI_CONFIG_DDR, 1); + if (ret) + return ret; + + /* Inform DAC IP to go for DDR mode from now on */ + ret = iio_backend_ddr_enable(st->back); + if (ret) { + dev_err(st->dev, "could not set DDR mode, not streaming"); + goto exit_err; + } + + ret = iio_backend_data_transfer_addr(st->back, val); + if (ret) + goto exit_err; + + ret = iio_backend_data_format_set(st->back, 0, &fmt); + if (ret) + goto exit_err; + + ret = iio_backend_data_stream_enable(st->back); + if (ret) + goto exit_err; + + return 0; + +exit_err: + ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_INTERFACE_CONFIG_D, + AD3552R_MASK_SPI_CONFIG_DDR, + 0, 1); + + iio_backend_ddr_disable(st->back); + + return ret; +} + +static int ad3552r_hs_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ad3552r_hs_state *st = iio_priv(indio_dev); + int ret; + + ret = iio_backend_data_stream_disable(st->back); + if (ret) + return ret; + + /* Inform DAC to set in SDR mode */ + ret = ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_INTERFACE_CONFIG_D, + AD3552R_MASK_SPI_CONFIG_DDR, + 0, 1); + if (ret) + return ret; + + ret = iio_backend_ddr_disable(st->back); + if (ret) + return ret; + + return 0; +} + +static inline int ad3552r_hs_set_output_range(struct ad3552r_hs_state *st, + int ch, unsigned int mode) +{ + int val; + + if (ch == 0) + val = FIELD_PREP(AD3552R_MASK_CH0_RANGE, mode); + else + val = FIELD_PREP(AD3552R_MASK_CH1_RANGE, mode); + + return ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE, + AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch), + val, 1); +} + +static int ad3552r_hs_reset(struct ad3552r_hs_state *st) +{ + int ret; + + st->reset_gpio = devm_gpiod_get_optional(st->dev, + "reset", GPIOD_OUT_HIGH); + if (IS_ERR(st->reset_gpio)) + return PTR_ERR(st->reset_gpio); + + if (st->reset_gpio) { + fsleep(10); + gpiod_set_value_cansleep(st->reset_gpio, 0); + } else { + ret = ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_INTERFACE_CONFIG_A, + AD3552R_MASK_SOFTWARE_RESET, + AD3552R_MASK_SOFTWARE_RESET, 1); + if (ret) + return ret; + } + msleep(100); + + return 0; +} + +static int ad3552r_hs_scratch_pad_test(struct ad3552r_hs_state *st) +{ + int ret, val; + + ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_SCRATCH_PAD, + AD3552R_SCRATCH_PAD_TEST_VAL1, 1); + if (ret) + return ret; + + ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_SCRATCH_PAD, + &val, 1); + if (ret) + return ret; + + if (val != AD3552R_SCRATCH_PAD_TEST_VAL1) + return dev_err_probe(st->dev, -EIO, + "SCRATCH_PAD_TEST mismatch. Expected 0x%x, Read 0x%x\n", + AD3552R_SCRATCH_PAD_TEST_VAL1, val); + + ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_SCRATCH_PAD, + AD3552R_SCRATCH_PAD_TEST_VAL2, 1); + if (ret) + return ret; + + ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_SCRATCH_PAD, + &val, 1); + if (ret) + return ret; + + if (val != AD3552R_SCRATCH_PAD_TEST_VAL2) + return dev_err_probe(st->dev, -EIO, + "SCRATCH_PAD_TEST mismatch. Expected 0x%x, Read 0x%x\n", + AD3552R_SCRATCH_PAD_TEST_VAL2, val); + + return 0; +} + +static int ad3552r_hs_setup_custom_gain(struct ad3552r_hs_state *st, + int ch, u16 gain, u16 offset) +{ + int ret; + + ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_CH_OFFSET(ch), + offset, 1); + if (ret) + return ret; + + return st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_CH_GAIN(ch), + gain, 1); +} + +static int ad3552r_hs_setup(struct ad3552r_hs_state *st) +{ + s16 goffs; + u16 id; + u16 gain = 0, offset = 0; + u32 ch, val, range; + int ret; + + ret = ad3552r_hs_reset(st); + if (ret) + return ret; + + ret = iio_backend_ddr_disable(st->back); + if (ret) + return ret; + + ret = ad3552r_hs_scratch_pad_test(st); + if (ret) + return ret; + + ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_PRODUCT_ID_L, + &val, 1); + if (ret) + return ret; + + id = val; + + ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_PRODUCT_ID_H, + &val, 1); + if (ret) + return ret; + + id |= val << 8; + if (id != st->model_data->chip_id) + dev_info(st->dev, "Chip ID error. Expected 0x%x, Read 0x%x\n", + AD3552R_ID, id); + + ret = st->data->bus_reg_write(st->back, + AD3552R_REG_ADDR_SH_REFERENCE_CONFIG, + 0, 1); + if (ret) + return ret; + + ret = st->data->bus_reg_write(st->back, + AD3552R_REG_ADDR_TRANSFER_REGISTER, + FIELD_PREP(AD3552R_MASK_MULTI_IO_MODE, + AD3552R_QUAD_SPI) | + AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE, 1); + if (ret) + return ret; + + ret = iio_backend_data_source_set(st->back, 0, IIO_BACKEND_EXTERNAL); + if (ret) + return ret; + + ret = iio_backend_data_source_set(st->back, 1, IIO_BACKEND_EXTERNAL); + if (ret) + return ret; + + ret = ad3552r_get_ref_voltage(st->dev, &val); + if (ret < 0) + return ret; + + val = ret; + + ret = ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_SH_REFERENCE_CONFIG, + AD3552R_MASK_REFERENCE_VOLTAGE_SEL, + val, 1); + if (ret) + return ret; + + ret = ad3552r_get_drive_strength(st->dev, &val); + if (!ret) { + ret = ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_INTERFACE_CONFIG_D, + AD3552R_MASK_SDO_DRIVE_STRENGTH, + val, 1); + if (ret) + return ret; + } + + device_for_each_child_node_scoped(st->dev, child) { + ret = fwnode_property_read_u32(child, "reg", &ch); + if (ret) + return dev_err_probe(st->dev, ret, + "reg property missing\n"); + + ret = ad3552r_get_output_range(st->dev, st->model_data, child, + &range); + if (ret && ret != -ENOENT) + return ret; + if (ret == -ENOENT) { + ret = ad3552r_get_custom_gain(st->dev, child, + &st->ch_data[ch].p, + &st->ch_data[ch].n, + &st->ch_data[ch].rfb, + &st->ch_data[ch].gain_offset); + if (ret) + return ret; + + gain = ad3552r_calc_custom_gain(st->ch_data[ch].p, + st->ch_data[ch].n, + st->ch_data[ch].gain_offset); + offset = abs(goffs); + + st->ch_data[ch].range_override = 1; + + ret = ad3552r_hs_setup_custom_gain(st, ch, gain, + offset); + if (ret) + return ret; + } else { + st->ch_data[ch].range = range; + + ret = ad3552r_hs_set_output_range(st, ch, range); + if (ret) + return ret; + } + + ad3552r_calc_gain_and_offset(&st->ch_data[ch], st->model_data); + } + + return 0; +} + +static const struct iio_buffer_setup_ops ad3552r_hs_buffer_setup_ops = { + .postenable = ad3552r_hs_buffer_postenable, + .predisable = ad3552r_hs_buffer_predisable, +}; + +#define AD3552R_CHANNEL(ch) { \ + .type = IIO_VOLTAGE, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .output = 1, \ + .indexed = 1, \ + .channel = (ch), \ + .scan_index = (ch), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + } \ +} + +static const struct iio_chan_spec ad3552r_hs_channels[] = { + AD3552R_CHANNEL(0), + AD3552R_CHANNEL(1), +}; + +static const struct iio_info ad3552r_hs_info = { + .read_raw = &ad3552r_hs_read_raw, + .write_raw = &ad3552r_hs_write_raw, +}; + +static int ad3552r_hs_probe(struct platform_device *pdev) +{ + struct ad3552r_hs_state *st; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->dev = &pdev->dev; + + st->data = dev_get_platdata(st->dev); + if (!st->data) + return dev_err_probe(st->dev, -ENODEV, "No platform data !"); + + st->back = devm_iio_backend_get(&pdev->dev, NULL); + if (IS_ERR(st->back)) + return PTR_ERR(st->back); + + ret = devm_iio_backend_enable(&pdev->dev, st->back); + if (ret) + return ret; + + st->model_data = device_get_match_data(&pdev->dev); + if (!st->model_data) + return -ENODEV; + + indio_dev->name = "ad3552r"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->setup_ops = &ad3552r_hs_buffer_setup_ops; + indio_dev->channels = ad3552r_hs_channels; + indio_dev->num_channels = ARRAY_SIZE(ad3552r_hs_channels); + indio_dev->info = &ad3552r_hs_info; + + ret = devm_iio_backend_request_buffer(&pdev->dev, st->back, indio_dev); + if (ret) + return ret; + + ret = ad3552r_hs_setup(st); + if (ret) + return ret; + + return devm_iio_device_register(&pdev->dev, indio_dev); +} + +static const struct ad3552r_model_data ad3552r_model_data = { + .model_name = "ad3552r", + .chip_id = AD3552R_ID, + .num_hw_channels = 2, + .ranges_table = ad3552r_ch_ranges, + .num_ranges = ARRAY_SIZE(ad3552r_ch_ranges), +}; + +static const struct of_device_id ad3552r_hs_of_id[] = { + { .compatible = "adi,ad3552r", .data = &ad3552r_model_data }, + { } +}; +MODULE_DEVICE_TABLE(of, ad3552r_hs_of_id); + +static struct platform_driver ad3552r_hs_driver = { + .driver = { + .name = "ad3552r-hs", + .of_match_table = ad3552r_hs_of_id, + }, + .probe = ad3552r_hs_probe, +}; +module_platform_driver(ad3552r_hs_driver); + +MODULE_AUTHOR("Dragos Bogdan "); +MODULE_AUTHOR("Angelo Dureghello "); +MODULE_DESCRIPTION("AD3552R Driver - High Speed version"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_BACKEND); +MODULE_IMPORT_NS(IIO_AD3552R); diff --git a/drivers/iio/dac/ad3552r-hs.h b/drivers/iio/dac/ad3552r-hs.h new file mode 100644 index 000000000000..724261d38dea --- /dev/null +++ b/drivers/iio/dac/ad3552r-hs.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Analog Devices Inc. + * Copyright (c) 2024 Baylibre, SAS + */ +#ifndef __LINUX_PLATFORM_DATA_AD3552R_HS_H__ +#define __LINUX_PLATFORM_DATA_AD3552R_HS_H__ + +struct iio_backend; + +struct ad3552r_hs_platform_data { + int (*bus_reg_read)(struct iio_backend *back, u32 reg, u32 *val, + size_t data_size); + int (*bus_reg_write)(struct iio_backend *back, u32 reg, u32 val, + size_t data_size); + u32 bus_sample_data_clock_hz; +}; + +#endif /* __LINUX_PLATFORM_DATA_AD3552R_HS_H__ */ diff --git a/drivers/iio/dac/ad3552r.h b/drivers/iio/dac/ad3552r.h index 22bd9ad27c65..6120a08e08a4 100644 --- a/drivers/iio/dac/ad3552r.h +++ b/drivers/iio/dac/ad3552r.h @@ -129,8 +129,12 @@ #define AD3552R_GAIN_SCALE 1000 #define AD3552R_LDAC_PULSE_US 100 +#define AD3552R_CH0_ACTIVE BIT(0) +#define AD3552R_CH1_ACTIVE BIT(1) + #define AD3552R_MAX_RANGES 5 #define AD3542R_MAX_RANGES 6 +#define AD3552R_QUAD_SPI 2 extern const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2]; extern const s32 ad3542r_ch_ranges[AD3542R_MAX_RANGES][2]; From patchwork Fri Oct 25 09:49:41 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Angelo Dureghello X-Patchwork-Id: 13850368 Received: from mail-wm1-f66.google.com (mail-wm1-f66.google.com [209.85.128.66]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 23C211F8180 for ; Fri, 25 Oct 2024 09:51:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.66 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729849873; cv=none; b=Mijsz0avIvL2kSHvBKlBuwULboak6tK1fuBEXlyLL36NWlTBjN6O2Abx7QmsBfir9sdLk0bG/wVQE0RUToXnOIbIO8Dny7zl9oAJt6fKECDV60otCmWFqpqPuR78snRuAOlJ2M967oHCWA3od7LWmGO7A8/PYiuqNpVU3tk0J/Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729849873; c=relaxed/simple; bh=qkX0nl5rvNFAD4t3iDzIThyb/2D3UDTKreCfkCePaGQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=eqfhuHAvSU2VMB9rMZZ/lIMm2CclOgQM79w7n3HcmAyyIWfkTVmP2sqhF1B1Zv3FhZnQz3+9G4kYSZ7O7LpkC1GY4oIl4tV7O7aP4TAJVMaEZE7UeMfFq9p2PeHGTMIb6orEt1MIzTKbxrgOIM2V+/XNDMWHvG64VSNou36d6Ls= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=lA1tg0Eh; arc=none smtp.client-ip=209.85.128.66 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="lA1tg0Eh" Received: by mail-wm1-f66.google.com with SMTP id 5b1f17b1804b1-43155afca99so19829335e9.1 for ; Fri, 25 Oct 2024 02:51:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1729849869; x=1730454669; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=/aYRx10LIx18s/5vpjDGgULjxldPzrrAdUjt9qoc4a4=; b=lA1tg0EhCp6dO/I9egv8EA6rqK5v5UKRopaxlzw/CCC+vuhqwi8BhgIcEgCAVsk30U J6tgfhaSfiC9Y7x6nIuM9+ygZyY0fIr7znJEKTZ9uBOqc0bkcdaTXfN0N8BRlV09EWQP whCWCoikJtiCtJfI3MAEqQ9HBqVSZ0miFMnV2GsxdexoV+ahKaH7CashNJVW8+/c2EH8 8IaLPN8Ck8PMDeOow48W2nJtfK7Njcw+RM9SZCVtfv7msRebn6pAGydqDxpyOUT3r+c9 69PT0R10ybEyuRPtyde7q2yn/kUngvs1C8UpuJVanT6xl+A4+FZZeJ+aZY/kO8OeVHDE fTnQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1729849869; x=1730454669; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=/aYRx10LIx18s/5vpjDGgULjxldPzrrAdUjt9qoc4a4=; b=otFvqahpdBAOdt9itX+5+R4ZHXvjAzNl7ueRnIYPY8aQda4kf12nYMito/WYytL2XH 5ZYM4MJnAENJfuqPX+7QY2DWpLTu0Q4aUeURyNkNBqNxA/MxCwVqCfTicmuMON1T38G4 nJgAk+rXdqbcCUWGpHzgkkyY+K6hwdCt2gx/IgxuGFe0PX+joRhurZuhVOcFB/V6mSp+ 0HGg6qUtCuOm/PImKKMoht5mUFi6do3id2F7GablSNp69Ca//ZCORJ4Mhv6HJtN1MZRj 2PNzSXdqU87V+MrUE4vKNMxJOhbM+G2ENfMkPF7GG1lc5XChvP2n3azsiFpdHpveATzB X8uQ== X-Gm-Message-State: AOJu0Yzdj2ZnBusNdwiMYwCcG8wMr6HrR2jgZoKfq32p1vDrIkCryIKg ku7i7ddG6DT84T1fMcajQq1dLErwk9UBewZx59Iw+bdek9C0Z65zjoS2Hj9lhI56/3qBbBaq6g2 +meBFaURb X-Google-Smtp-Source: AGHT+IHmwWsFrbMw/Bs+MM2teeITRSFYRP5Geof+tpjdxm9iyQ5zs+9wro7UoDvxoKjOKk3Hp1Cmvg== X-Received: by 2002:a05:600c:35d5:b0:431:52da:9d89 with SMTP id 5b1f17b1804b1-4318b5b0cf5mr36654655e9.1.1729849869003; Fri, 25 Oct 2024 02:51:09 -0700 (PDT) Received: from [127.0.1.1] (host-79-41-194-153.retail.telecomitalia.it. [79.41.194.153]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-431935f6df1sm12895085e9.35.2024.10.25.02.51.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Oct 2024 02:51:08 -0700 (PDT) From: Angelo Dureghello X-Google-Original-From: Angelo Dureghello Date: Fri, 25 Oct 2024 11:49:41 +0200 Subject: [PATCH v8 8/8] iio: dac: adi-axi-dac: add registering of child fdt node Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-8-74ca7dd60567@baylibre.com> References: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-0-74ca7dd60567@baylibre.com> In-Reply-To: <20241025-wip-bl-ad3552r-axi-v0-iio-testing-v8-0-74ca7dd60567@baylibre.com> To: Lars-Peter Clausen , Michael Hennerich , =?utf-8?q?Nuno_S=C3=A1?= , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Mark Brown , dlechner@baylibre.com, Angelo Dureghello X-Mailer: b4 0.14.1 From: Angelo Dureghello Change to obtain the fdt use case as reported in the adi,ad3552r.yaml file in this patchset. The DAC device is defined as a child node of the backend. Registering the child fdt node as a platform devices. Signed-off-by: Angelo Dureghello --- drivers/iio/dac/adi-axi-dac.c | 56 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c index 148e40a8ab2a..dc9f881bf9ce 100644 --- a/drivers/iio/dac/adi-axi-dac.c +++ b/drivers/iio/dac/adi-axi-dac.c @@ -29,6 +29,8 @@ #include #include +#include "ad3552r-hs.h" + /* * Register definitions: * https://wiki.analog.com/resources/fpga/docs/axi_dac_ip#register_map @@ -97,6 +99,7 @@ struct axi_dac_info { unsigned int version; const struct iio_backend_info *backend_info; bool has_dac_clk; + bool has_child_nodes; }; struct axi_dac_state { @@ -699,6 +702,36 @@ static int axi_dac_bus_reg_read(struct iio_backend *back, u32 reg, u32 *val, return regmap_read(st->regmap, AXI_DAC_CUSTOM_RD_REG, val); } +static void axi_dac_child_remove(void *data) +{ + platform_device_unregister(data); +} + +static int axi_dac_create_platform_device(struct axi_dac_state *st, + struct fwnode_handle *child) +{ + struct ad3552r_hs_platform_data pdata = { + .bus_reg_read = axi_dac_bus_reg_read, + .bus_reg_write = axi_dac_bus_reg_write, + .bus_sample_data_clock_hz = st->dac_clk_rate, + }; + struct platform_device_info pi = { + .parent = st->dev, + .name = fwnode_get_name(child), + .id = PLATFORM_DEVID_AUTO, + .fwnode = child, + .data = &pdata, + .size_data = sizeof(pdata), + }; + struct platform_device *pdev; + + pdev = platform_device_register_full(&pi); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return devm_add_action_or_reset(st->dev, axi_dac_child_remove, pdev); +} + static const struct iio_backend_ops axi_dac_generic_ops = { .enable = axi_dac_enable, .disable = axi_dac_disable, @@ -840,6 +873,28 @@ static int axi_dac_probe(struct platform_device *pdev) return dev_err_probe(&pdev->dev, ret, "failed to register iio backend\n"); + device_for_each_child_node_scoped(&pdev->dev, child) { + int val; + + if (!st->info->has_child_nodes) + return dev_err_probe(&pdev->dev, -EINVAL, + "invalid fdt axi-dac compatible."); + + /* Processing only reg 0 node */ + ret = fwnode_property_read_u32(child, "reg", &val); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "invalid reg property."); + if (val != 0) + return dev_err_probe(&pdev->dev, -EINVAL, + "invalid node address."); + + ret = axi_dac_create_platform_device(st, child); + if (ret) + return dev_err_probe(&pdev->dev, -EINVAL, + "cannot create device."); + } + dev_info(&pdev->dev, "AXI DAC IP core (%d.%.2d.%c) probed\n", ADI_AXI_PCORE_VER_MAJOR(ver), ADI_AXI_PCORE_VER_MINOR(ver), @@ -857,6 +912,7 @@ static const struct axi_dac_info dac_ad3552r = { .version = ADI_AXI_PCORE_VER(9, 1, 'b'), .backend_info = &axi_ad3552r, .has_dac_clk = true, + .has_child_nodes = true, }; static const struct of_device_id axi_dac_of_match[] = {